sellmate-design-system-react 9.0.0-beta.94 → 9.0.0-beta.97
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 +21 -2
- 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 +743 -462
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +743 -462
- package/dist/index.js.map +1 -1
- package/dist/lib/row-motion.d.ts +56 -0
- package/dist/lib/tree-row.d.ts +11 -0
- package/dist/llms-full.txt +37 -3
- package/dist/llms.txt +21 -2
- package/dist/styles.css +9 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -7731,6 +7731,13 @@ var TREE_LABEL_TYPOGRAPHY = {
|
|
|
7731
7731
|
rowHeight: "h-[32px]"
|
|
7732
7732
|
}
|
|
7733
7733
|
};
|
|
7734
|
+
var TREE_BRANCH_MOTION = { duration: 200, easing: "cubic-bezier(0, 0, 0.2, 1)" };
|
|
7735
|
+
function canAnimateTreeBranch() {
|
|
7736
|
+
if (typeof window === "undefined" || typeof HTMLElement.prototype.animate !== "function") {
|
|
7737
|
+
return false;
|
|
7738
|
+
}
|
|
7739
|
+
return !window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
7740
|
+
}
|
|
7734
7741
|
var TREE_ROW_CLASS = "group/tree-item box-border flex w-full items-center gap-(--cmp-tree-item-rowGap) overflow-hidden bg-(--cmp-tree-item-bg-default) px-(--cmp-tree-item-paddingX) text-left hover:bg-(--cmp-tree-item-bg-hover)";
|
|
7735
7742
|
var TREE_ROW_BORDER_CLASS = "border-b-(length:--cmp-tree-item-border-width-default) border-(--cmp-tree-item-border-default)";
|
|
7736
7743
|
var TREE_ROW_ACTIVE_CLASS = "bg-(--cmp-tree-item-bg-hover)";
|
|
@@ -15679,6 +15686,93 @@ function SCalendarBoard({
|
|
|
15679
15686
|
);
|
|
15680
15687
|
}
|
|
15681
15688
|
|
|
15689
|
+
// src/lib/row-motion.ts
|
|
15690
|
+
var EXPAND_MOTION = { duration: 220, easing: "ease-out" };
|
|
15691
|
+
var COLLAPSE_MOTION = { duration: 140, easing: "ease-in" };
|
|
15692
|
+
function sameKeys(a, b) {
|
|
15693
|
+
return a.size === b.size && [...a].every((key) => b.has(key));
|
|
15694
|
+
}
|
|
15695
|
+
function motionAllowed() {
|
|
15696
|
+
if (typeof window === "undefined" || typeof Element.prototype.animate !== "function")
|
|
15697
|
+
return false;
|
|
15698
|
+
return !window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
15699
|
+
}
|
|
15700
|
+
function startRowMotion({
|
|
15701
|
+
scrollEl,
|
|
15702
|
+
isInBlock,
|
|
15703
|
+
blockKeys,
|
|
15704
|
+
from,
|
|
15705
|
+
to
|
|
15706
|
+
}) {
|
|
15707
|
+
const spec = to === 1 ? EXPAND_MOTION : COLLAPSE_MOTION;
|
|
15708
|
+
const duration = spec.duration * Math.abs(to - from);
|
|
15709
|
+
if (duration < 1) return null;
|
|
15710
|
+
const trs = [
|
|
15711
|
+
...scrollEl.querySelectorAll("tr[data-row-index], tr[data-expansion-row]")
|
|
15712
|
+
].map((tr) => ({ tr, inBlock: isInBlock(tr), height: tr.getBoundingClientRect().height }));
|
|
15713
|
+
const viewBottom = scrollEl.scrollTop + scrollEl.clientHeight;
|
|
15714
|
+
const openAt = (offset) => from + (to - from) * offset;
|
|
15715
|
+
const translate = (shift2, s) => `translateY(${-shift2 * (1 - s)}px)`;
|
|
15716
|
+
const timing = {
|
|
15717
|
+
duration,
|
|
15718
|
+
easing: spec.easing,
|
|
15719
|
+
// 접힘은 남겨 둔 행이 빠질 때까지 끝 위치를 붙잡는다 — 놓으면 그 사이 한 프레임 제자리로 튄다
|
|
15720
|
+
fill: to === 0 ? "forwards" : "none"
|
|
15721
|
+
};
|
|
15722
|
+
const animations = [];
|
|
15723
|
+
let shift = 0;
|
|
15724
|
+
let blockHeight = 0;
|
|
15725
|
+
let y = 0;
|
|
15726
|
+
trs.forEach(({ tr, inBlock, height }, i) => {
|
|
15727
|
+
if (inBlock && !trs[i - 1]?.inBlock) {
|
|
15728
|
+
blockHeight = 0;
|
|
15729
|
+
for (let j = i; j < trs.length && trs[j].inBlock; j++) blockHeight += trs[j].height;
|
|
15730
|
+
shift += blockHeight;
|
|
15731
|
+
y = 0;
|
|
15732
|
+
}
|
|
15733
|
+
if (shift === 0 || tr.offsetTop - shift > viewBottom) return;
|
|
15734
|
+
if (!inBlock) {
|
|
15735
|
+
animations.push(
|
|
15736
|
+
tr.animate(
|
|
15737
|
+
[{ transform: translate(shift, from) }, { transform: translate(shift, to) }],
|
|
15738
|
+
timing
|
|
15739
|
+
)
|
|
15740
|
+
);
|
|
15741
|
+
return;
|
|
15742
|
+
}
|
|
15743
|
+
const rowY = y;
|
|
15744
|
+
const clipAt = (s) => Math.min(height, Math.max(0, blockHeight * (1 - s) - rowY));
|
|
15745
|
+
const bends = [1 - rowY / blockHeight, 1 - (rowY + height) / blockHeight].map((s) => (s - from) / (to - from)).filter((offset) => offset > 0 && offset < 1);
|
|
15746
|
+
const offsets = [0, ...bends, 1].sort((a, b) => a - b);
|
|
15747
|
+
animations.push(
|
|
15748
|
+
tr.animate(
|
|
15749
|
+
offsets.map((offset) => ({
|
|
15750
|
+
offset,
|
|
15751
|
+
transform: translate(shift, openAt(offset)),
|
|
15752
|
+
clipPath: `inset(${clipAt(openAt(offset))}px 0 0 0)`
|
|
15753
|
+
})),
|
|
15754
|
+
timing
|
|
15755
|
+
)
|
|
15756
|
+
);
|
|
15757
|
+
y += height;
|
|
15758
|
+
});
|
|
15759
|
+
if (animations.length === 0) return null;
|
|
15760
|
+
return {
|
|
15761
|
+
keys: blockKeys,
|
|
15762
|
+
to,
|
|
15763
|
+
done: false,
|
|
15764
|
+
finished: Promise.all(animations.map((animation) => animation.finished)).then(
|
|
15765
|
+
() => true,
|
|
15766
|
+
() => false
|
|
15767
|
+
),
|
|
15768
|
+
openness: () => {
|
|
15769
|
+
const progress = animations[0].effect?.getComputedTiming().progress;
|
|
15770
|
+
return progress == null ? to : openAt(progress);
|
|
15771
|
+
},
|
|
15772
|
+
cancel: () => animations.forEach((animation) => animation.cancel())
|
|
15773
|
+
};
|
|
15774
|
+
}
|
|
15775
|
+
|
|
15682
15776
|
// src/lib/row-metrics.ts
|
|
15683
15777
|
function createRowMetrics(count, estimate) {
|
|
15684
15778
|
const safeCount = Math.max(0, Math.floor(count));
|
|
@@ -16098,6 +16192,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
16098
16192
|
onSearchChange,
|
|
16099
16193
|
searchDebounce = DEFAULT_SEARCH_DEBOUNCE,
|
|
16100
16194
|
label,
|
|
16195
|
+
ariaLabel,
|
|
16101
16196
|
labelPosition,
|
|
16102
16197
|
subLabel,
|
|
16103
16198
|
labelWidth,
|
|
@@ -16127,6 +16222,21 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
16127
16222
|
const [focusedIndex, setFocusedIndex] = react.useState(-1);
|
|
16128
16223
|
const [expanded, setExpanded] = react.useState(() => /* @__PURE__ */ new Set());
|
|
16129
16224
|
const [searchCollapsed, setSearchCollapsed] = react.useState(NO_SEARCH_COLLAPSED);
|
|
16225
|
+
const [treeMotion, setTreeMotion] = react.useState(null);
|
|
16226
|
+
const treeMotionTimerRef = react.useRef(null);
|
|
16227
|
+
const pendingCollapseRef = react.useRef(null);
|
|
16228
|
+
const cancelTreeMotion = () => {
|
|
16229
|
+
if (treeMotionTimerRef.current != null) clearTimeout(treeMotionTimerRef.current);
|
|
16230
|
+
treeMotionTimerRef.current = null;
|
|
16231
|
+
pendingCollapseRef.current = null;
|
|
16232
|
+
setTreeMotion(null);
|
|
16233
|
+
};
|
|
16234
|
+
react.useEffect(
|
|
16235
|
+
() => () => {
|
|
16236
|
+
if (treeMotionTimerRef.current != null) clearTimeout(treeMotionTimerRef.current);
|
|
16237
|
+
},
|
|
16238
|
+
[]
|
|
16239
|
+
);
|
|
16130
16240
|
const baseId = react.useId();
|
|
16131
16241
|
const listboxId = `${baseId}-listbox`;
|
|
16132
16242
|
const activeOptionId = `${baseId}-active-option`;
|
|
@@ -16194,6 +16304,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
16194
16304
|
const commitOpen = (next, valueForRules) => {
|
|
16195
16305
|
setOpen(next);
|
|
16196
16306
|
onOpenChange?.(next);
|
|
16307
|
+
cancelTreeMotion();
|
|
16197
16308
|
if (next) {
|
|
16198
16309
|
dismissedByPointerRef.current = false;
|
|
16199
16310
|
alignSelectedTopRef.current = true;
|
|
@@ -16264,6 +16375,10 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
16264
16375
|
(groupValue) => treeSearching ? !searchCollapsed.has(groupValue) : expanded.has(groupValue),
|
|
16265
16376
|
[expanded, searchCollapsed, treeSearching]
|
|
16266
16377
|
);
|
|
16378
|
+
const isGroupShownExpanded = react.useCallback(
|
|
16379
|
+
(groupValue) => isGroupExpanded(groupValue) && !(treeMotion != null && !treeMotion.opening && treeMotion.group === groupValue),
|
|
16380
|
+
[isGroupExpanded, treeMotion]
|
|
16381
|
+
);
|
|
16267
16382
|
const treeRows = react.useMemo(
|
|
16268
16383
|
() => isTree ? visibleTreeRows(searched, (row) => isGroupExpanded(row.value)) : null,
|
|
16269
16384
|
[isGroupExpanded, isTree, searched]
|
|
@@ -16553,6 +16668,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
16553
16668
|
const handleSearchChange = (next) => {
|
|
16554
16669
|
setSearch(next);
|
|
16555
16670
|
setSearchCollapsed(NO_SEARCH_COLLAPSED);
|
|
16671
|
+
cancelTreeMotion();
|
|
16556
16672
|
};
|
|
16557
16673
|
const handleToggleExpand = (groupValue) => {
|
|
16558
16674
|
rangeAnchorRef.current = null;
|
|
@@ -16562,8 +16678,41 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
16562
16678
|
else next.add(groupValue);
|
|
16563
16679
|
return next;
|
|
16564
16680
|
};
|
|
16565
|
-
|
|
16566
|
-
|
|
16681
|
+
const applyToggle = treeSearching ? () => setSearchCollapsed(toggle) : () => setExpanded(toggle);
|
|
16682
|
+
if (treeMotionTimerRef.current != null) clearTimeout(treeMotionTimerRef.current);
|
|
16683
|
+
treeMotionTimerRef.current = null;
|
|
16684
|
+
const pendingCollapse = pendingCollapseRef.current;
|
|
16685
|
+
pendingCollapseRef.current = null;
|
|
16686
|
+
if (treeMotion?.group === groupValue && !treeMotion.opening) {
|
|
16687
|
+
setTreeMotion({ group: groupValue, opening: true });
|
|
16688
|
+
treeMotionTimerRef.current = setTimeout(
|
|
16689
|
+
() => setTreeMotion(null),
|
|
16690
|
+
TREE_BRANCH_MOTION.duration
|
|
16691
|
+
);
|
|
16692
|
+
return;
|
|
16693
|
+
}
|
|
16694
|
+
pendingCollapse?.();
|
|
16695
|
+
if (!canAnimateTreeBranch()) {
|
|
16696
|
+
setTreeMotion(null);
|
|
16697
|
+
applyToggle();
|
|
16698
|
+
return;
|
|
16699
|
+
}
|
|
16700
|
+
if (isGroupExpanded(groupValue)) {
|
|
16701
|
+
setTreeMotion({ group: groupValue, opening: false });
|
|
16702
|
+
pendingCollapseRef.current = applyToggle;
|
|
16703
|
+
treeMotionTimerRef.current = setTimeout(() => {
|
|
16704
|
+
pendingCollapseRef.current = null;
|
|
16705
|
+
setTreeMotion(null);
|
|
16706
|
+
applyToggle();
|
|
16707
|
+
}, TREE_BRANCH_MOTION.duration);
|
|
16708
|
+
} else {
|
|
16709
|
+
applyToggle();
|
|
16710
|
+
setTreeMotion({ group: groupValue, opening: true });
|
|
16711
|
+
treeMotionTimerRef.current = setTimeout(
|
|
16712
|
+
() => setTreeMotion(null),
|
|
16713
|
+
TREE_BRANCH_MOTION.duration
|
|
16714
|
+
);
|
|
16715
|
+
}
|
|
16567
16716
|
};
|
|
16568
16717
|
const handleToggleGroup = (leafValues) => {
|
|
16569
16718
|
if (leafValues.length === 0) return;
|
|
@@ -16673,7 +16822,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
16673
16822
|
const row = rowIndex != null ? filtered[rowIndex] : void 0;
|
|
16674
16823
|
if (rowIndex == null || row == null) return;
|
|
16675
16824
|
event.preventDefault();
|
|
16676
|
-
const rowExpanded = row.isGroup &&
|
|
16825
|
+
const rowExpanded = row.isGroup && isGroupShownExpanded(row.value);
|
|
16677
16826
|
if (event.key === "ArrowRight") {
|
|
16678
16827
|
if (!row.isGroup) return;
|
|
16679
16828
|
if (!rowExpanded) {
|
|
@@ -16746,6 +16895,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
16746
16895
|
style,
|
|
16747
16896
|
children: [
|
|
16748
16897
|
name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: selected.join(",") }),
|
|
16898
|
+
!label && ariaLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { id: `${triggerId}-aria-label`, hidden: true, children: ariaLabel }),
|
|
16749
16899
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
16750
16900
|
"div",
|
|
16751
16901
|
{
|
|
@@ -16754,7 +16904,7 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
16754
16904
|
role: "combobox",
|
|
16755
16905
|
tabIndex: effectiveDisabled ? -1 : 0,
|
|
16756
16906
|
"aria-disabled": effectiveDisabled || void 0,
|
|
16757
|
-
"aria-labelledby": label ? `${fieldLabelId(triggerId)} ${triggerId}` : triggerId,
|
|
16907
|
+
"aria-labelledby": label ? `${fieldLabelId(triggerId)} ${triggerId}` : ariaLabel ? `${triggerId}-aria-label ${triggerId}` : triggerId,
|
|
16758
16908
|
"aria-haspopup": isTree ? "tree" : "listbox",
|
|
16759
16909
|
"aria-expanded": open,
|
|
16760
16910
|
"aria-controls": open ? listboxId : void 0,
|
|
@@ -16918,8 +17068,9 @@ var SSelectImpl = /* @__PURE__ */ react.forwardRef(function SSelect({
|
|
|
16918
17068
|
setSize: isDepth || isTree ? void 0 : rowCount,
|
|
16919
17069
|
multi,
|
|
16920
17070
|
tree: isTree,
|
|
16921
|
-
isExpanded:
|
|
17071
|
+
isExpanded: isGroupShownExpanded,
|
|
16922
17072
|
onToggleExpand: handleToggleExpand,
|
|
17073
|
+
treeMotion,
|
|
16923
17074
|
treeLines,
|
|
16924
17075
|
selected,
|
|
16925
17076
|
groupLeafValues,
|
|
@@ -16976,6 +17127,7 @@ function ItemList({
|
|
|
16976
17127
|
tree,
|
|
16977
17128
|
isExpanded,
|
|
16978
17129
|
onToggleExpand,
|
|
17130
|
+
treeMotion,
|
|
16979
17131
|
treeLines,
|
|
16980
17132
|
selected,
|
|
16981
17133
|
groupLeafValues,
|
|
@@ -16996,295 +17148,322 @@ function ItemList({
|
|
|
16996
17148
|
"disabled:cursor-not-allowed disabled:text-[color:var(--cmp-listBoxItem-content-disabled)]"
|
|
16997
17149
|
);
|
|
16998
17150
|
const activeClass = "hover:bg-[var(--cmp-listBoxItem-bg-hover)] hover:text-[color:var(--cmp-listBoxItem-content-hover)] focus-visible:bg-[var(--cmp-listBoxItem-bg-hover)] focus-visible:text-[color:var(--cmp-listBoxItem-content-hover)]";
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
|
|
17004
|
-
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
|
|
17008
|
-
|
|
17009
|
-
|
|
17010
|
-
|
|
17011
|
-
|
|
17012
|
-
|
|
17013
|
-
|
|
17014
|
-
|
|
17015
|
-
|
|
17016
|
-
onToggle: onSelectAll
|
|
17017
|
-
}
|
|
17018
|
-
)
|
|
17019
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17020
|
-
"button",
|
|
17151
|
+
const wrapTreeMotion = (nodes) => {
|
|
17152
|
+
if (!tree || treeMotion == null) return nodes;
|
|
17153
|
+
const start = items.findIndex((o) => o.isGroup && o.value === treeMotion.group);
|
|
17154
|
+
if (start < 0) return nodes;
|
|
17155
|
+
let end = start + 1;
|
|
17156
|
+
while (end < items.length && items[end].depth > items[start].depth) end++;
|
|
17157
|
+
if (end === start + 1) return nodes;
|
|
17158
|
+
return [
|
|
17159
|
+
...nodes.slice(0, start + 1),
|
|
17160
|
+
/* @__PURE__ */ jsxRuntime.jsx(TreeRowsMotion, { opening: treeMotion.opening, children: nodes.slice(start + 1, end) }, `__motion_${treeMotion.group}__`),
|
|
17161
|
+
...nodes.slice(end)
|
|
17162
|
+
];
|
|
17163
|
+
};
|
|
17164
|
+
const selectAllRow = showSelectAll && (tree ? (
|
|
17165
|
+
// 트리의 전체선택 줄은 STree 의 "전체" 줄 그대로다 (lib/tree-row).
|
|
17166
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17167
|
+
TreeAllRow,
|
|
17021
17168
|
{
|
|
17022
|
-
type: "button",
|
|
17023
17169
|
"data-select-all-row": true,
|
|
17024
17170
|
id: focusedValue === "__select_all__" ? activeOptionId : void 0,
|
|
17025
17171
|
"data-select-focused": focusedValue === "__select_all__" ? "true" : void 0,
|
|
17026
17172
|
"data-select-active": focusedValue === "__select_all__" ? "true" : void 0,
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
|
|
17030
|
-
|
|
17031
|
-
|
|
17173
|
+
tabIndex: -1,
|
|
17174
|
+
label: selectAllLabel,
|
|
17175
|
+
selected: selectAllSelected,
|
|
17176
|
+
active: focusedValue === "__select_all__",
|
|
17177
|
+
className: "select-none",
|
|
17032
17178
|
onMouseEnter: () => onHoverValue("__select_all__"),
|
|
17033
17179
|
onMouseLeave: () => onHoverValue(null),
|
|
17034
|
-
|
|
17035
|
-
children: [
|
|
17036
|
-
/* @__PURE__ */ jsxRuntime.jsx(CheckboxBox, { state: selectAllSelected, focused: focusedValue === "__select_all__" }),
|
|
17037
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: selectAllLabel })
|
|
17038
|
-
]
|
|
17180
|
+
onToggle: onSelectAll
|
|
17039
17181
|
}
|
|
17040
|
-
)
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
17052
|
-
|
|
17053
|
-
|
|
17054
|
-
|
|
17055
|
-
|
|
17056
|
-
|
|
17057
|
-
|
|
17058
|
-
|
|
17059
|
-
|
|
17060
|
-
|
|
17061
|
-
|
|
17062
|
-
|
|
17063
|
-
|
|
17064
|
-
|
|
17065
|
-
|
|
17066
|
-
|
|
17067
|
-
|
|
17068
|
-
|
|
17069
|
-
|
|
17070
|
-
|
|
17071
|
-
|
|
17072
|
-
|
|
17073
|
-
|
|
17074
|
-
|
|
17075
|
-
|
|
17076
|
-
|
|
17077
|
-
|
|
17078
|
-
|
|
17079
|
-
|
|
17080
|
-
|
|
17081
|
-
|
|
17082
|
-
|
|
17083
|
-
|
|
17084
|
-
|
|
17085
|
-
|
|
17086
|
-
|
|
17087
|
-
|
|
17088
|
-
|
|
17089
|
-
|
|
17090
|
-
|
|
17091
|
-
|
|
17092
|
-
|
|
17093
|
-
|
|
17094
|
-
|
|
17095
|
-
|
|
17096
|
-
|
|
17097
|
-
|
|
17098
|
-
|
|
17099
|
-
|
|
17100
|
-
|
|
17101
|
-
|
|
17102
|
-
|
|
17103
|
-
|
|
17104
|
-
|
|
17105
|
-
|
|
17106
|
-
|
|
17107
|
-
|
|
17108
|
-
|
|
17109
|
-
|
|
17110
|
-
|
|
17111
|
-
|
|
17112
|
-
|
|
17113
|
-
|
|
17114
|
-
|
|
17115
|
-
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
selectable: true,
|
|
17122
|
-
disabled: rowDisabled,
|
|
17123
|
-
control: multi && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17124
|
-
"span",
|
|
17125
|
-
{
|
|
17126
|
-
"data-tree-control": true,
|
|
17127
|
-
className: "flex shrink-0",
|
|
17128
|
-
onPointerDownCapture: (event) => {
|
|
17129
|
-
checkboxShiftRef.current = event.shiftKey;
|
|
17130
|
-
},
|
|
17131
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
17132
|
-
SCheckbox,
|
|
17133
|
-
{
|
|
17134
|
-
value: checkState,
|
|
17135
|
-
disabled: rowDisabled,
|
|
17136
|
-
onValueChange: toggle
|
|
17137
|
-
}
|
|
17138
|
-
)
|
|
17139
|
-
}
|
|
17140
|
-
),
|
|
17141
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
17142
|
-
OptionLabel,
|
|
17143
|
-
{
|
|
17144
|
-
label: o.label,
|
|
17145
|
-
className: treeLabelClass("sm", {
|
|
17146
|
-
// 고른 줄은 굵게 — multi_tree 는 일부만 고른 그룹도 굵다 (STree 와 같다)
|
|
17147
|
-
emphasized: checkState !== false,
|
|
17148
|
-
disabled: rowDisabled,
|
|
17149
|
-
selectable: true
|
|
17150
|
-
})
|
|
17151
|
-
}
|
|
17152
|
-
)
|
|
17153
|
-
}
|
|
17154
|
-
)
|
|
17155
|
-
] })
|
|
17156
|
-
]
|
|
17182
|
+
)
|
|
17183
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17184
|
+
"button",
|
|
17185
|
+
{
|
|
17186
|
+
type: "button",
|
|
17187
|
+
"data-select-all-row": true,
|
|
17188
|
+
id: focusedValue === "__select_all__" ? activeOptionId : void 0,
|
|
17189
|
+
"data-select-focused": focusedValue === "__select_all__" ? "true" : void 0,
|
|
17190
|
+
"data-select-active": focusedValue === "__select_all__" ? "true" : void 0,
|
|
17191
|
+
className: cn(
|
|
17192
|
+
itemBase,
|
|
17193
|
+
focusedValue === "__select_all__" && "bg-[var(--cmp-listBoxItem-bg-hover)] text-[color:var(--cmp-listBoxItem-content-hover)]"
|
|
17194
|
+
),
|
|
17195
|
+
style: { ...LIST_BOX_ITEM_PADDING_Y_RIGHT, paddingLeft: LIST_BOX_ITEM_PADDING_LEFT[1] },
|
|
17196
|
+
onMouseEnter: () => onHoverValue("__select_all__"),
|
|
17197
|
+
onMouseLeave: () => onHoverValue(null),
|
|
17198
|
+
onClick: onSelectAll,
|
|
17199
|
+
children: [
|
|
17200
|
+
/* @__PURE__ */ jsxRuntime.jsx(CheckboxBox, { state: selectAllSelected, focused: focusedValue === "__select_all__" }),
|
|
17201
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: selectAllLabel })
|
|
17202
|
+
]
|
|
17203
|
+
}
|
|
17204
|
+
));
|
|
17205
|
+
const rowNodes = items.map((o, windowIndex) => {
|
|
17206
|
+
const idx = windowIndex + indexOffset;
|
|
17207
|
+
const padLeft = LIST_BOX_ITEM_PADDING_LEFT[o.depth === 1 ? 1 : o.depth === 2 ? 2 : 3];
|
|
17208
|
+
const rowKey = `${o.value}-${idx}`;
|
|
17209
|
+
if (tree) {
|
|
17210
|
+
const togglesLeaves = multi && o.isGroup;
|
|
17211
|
+
const leafValues = togglesLeaves ? groupLeafValues.get(idx) ?? [] : [];
|
|
17212
|
+
const total = leafValues.length;
|
|
17213
|
+
const selectedCount = leafValues.reduce((n, v) => selectedSet.has(v) ? n + 1 : n, 0);
|
|
17214
|
+
const isSelected2 = selectedSet.has(o.value);
|
|
17215
|
+
const checkState = togglesLeaves ? total === 0 || selectedCount === 0 ? false : selectedCount === total ? true : null : isSelected2;
|
|
17216
|
+
const rowDisabled = o.disabled || togglesLeaves && total === 0;
|
|
17217
|
+
const focusKey = togglesLeaves ? `__group_${idx}__` : o.value;
|
|
17218
|
+
const focused = focusedValue === focusKey;
|
|
17219
|
+
const expanded = o.isGroup && isExpanded(o.value);
|
|
17220
|
+
const line = treeLines[idx];
|
|
17221
|
+
const toggle = () => {
|
|
17222
|
+
if (rowDisabled) return;
|
|
17223
|
+
if (togglesLeaves) onToggleGroup(leafValues);
|
|
17224
|
+
else onSelect(o.value, idx, checkboxShiftRef.current);
|
|
17225
|
+
};
|
|
17226
|
+
return (
|
|
17227
|
+
// eslint-disable-next-line jsx-a11y/click-events-have-key-events -- 키보드는 트리거(또는 검색 입력)가 aria-activedescendant 로 맡는다. 줄로 포커스를 옮기지 않는다
|
|
17228
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
17229
|
+
"div",
|
|
17230
|
+
{
|
|
17231
|
+
tabIndex: -1,
|
|
17232
|
+
"data-select-row": true,
|
|
17233
|
+
"data-index": idx,
|
|
17234
|
+
id: focused ? activeOptionId : void 0,
|
|
17235
|
+
role: "treeitem",
|
|
17236
|
+
"aria-level": o.depth,
|
|
17237
|
+
"aria-posinset": line?.posInSet,
|
|
17238
|
+
"aria-setsize": line?.setSize,
|
|
17239
|
+
"aria-expanded": o.isGroup ? expanded : void 0,
|
|
17240
|
+
"aria-selected": checkState === true,
|
|
17241
|
+
"aria-disabled": rowDisabled || void 0,
|
|
17242
|
+
"data-select-focused": focused ? "true" : void 0,
|
|
17243
|
+
"data-select-active": focused ? "true" : void 0,
|
|
17244
|
+
className: cn(
|
|
17245
|
+
TREE_ROW_CLASS,
|
|
17246
|
+
TREE_LABEL_TYPOGRAPHY.sm.rowHeight,
|
|
17247
|
+
TREE_ROW_BORDER_CLASS,
|
|
17248
|
+
"select-none",
|
|
17249
|
+
o.isGroup && "cursor-pointer",
|
|
17250
|
+
focused && TREE_ROW_ACTIVE_CLASS
|
|
17251
|
+
),
|
|
17252
|
+
onMouseEnter: () => onHoverValue(focusKey),
|
|
17253
|
+
onMouseLeave: () => onHoverValue(null),
|
|
17254
|
+
onClick: (event) => {
|
|
17255
|
+
if (isRowControlClick(event)) return;
|
|
17256
|
+
if (isRowSelectClick(event)) {
|
|
17257
|
+
if (rowDisabled) return;
|
|
17258
|
+
if (togglesLeaves) onToggleGroup(leafValues);
|
|
17259
|
+
else onSelect(o.value, idx, event.shiftKey);
|
|
17260
|
+
return;
|
|
17261
|
+
}
|
|
17262
|
+
if (o.isGroup) onToggleExpand(o.value);
|
|
17157
17263
|
},
|
|
17158
|
-
|
|
17159
|
-
|
|
17160
|
-
|
|
17161
|
-
|
|
17162
|
-
|
|
17163
|
-
|
|
17164
|
-
|
|
17165
|
-
|
|
17166
|
-
|
|
17167
|
-
|
|
17168
|
-
|
|
17169
|
-
if (multi) {
|
|
17170
|
-
const leafValues = groupLeafValues.get(idx) ?? [];
|
|
17171
|
-
const total = leafValues.length;
|
|
17172
|
-
const selectedCount = leafValues.reduce((n, v) => selectedSet.has(v) ? n + 1 : n, 0);
|
|
17173
|
-
const groupState = total === 0 || selectedCount === 0 ? false : selectedCount === total ? true : null;
|
|
17174
|
-
const groupDisabled = o.disabled || total === 0;
|
|
17175
|
-
const groupFocused = focusedValue === `__group_${idx}__`;
|
|
17176
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17177
|
-
"button",
|
|
17178
|
-
{
|
|
17179
|
-
type: "button",
|
|
17180
|
-
"data-select-row": true,
|
|
17181
|
-
"data-index": idx,
|
|
17182
|
-
id: groupFocused ? activeOptionId : void 0,
|
|
17183
|
-
role: "option",
|
|
17184
|
-
"aria-selected": groupState === true,
|
|
17185
|
-
disabled: groupDisabled,
|
|
17186
|
-
"data-select-focused": groupFocused ? "true" : void 0,
|
|
17187
|
-
"data-select-active": groupFocused ? "true" : void 0,
|
|
17188
|
-
className: cn(
|
|
17189
|
-
"flex w-full select-none items-center gap-(--cmp-listBoxItem-gap) border-none py-(--cmp-listBoxItem-paddingY) pr-(--cmp-listBoxItem-paddingRight) text-left typo-field-sm-default text-[color:var(--cmp-listBoxItem-content-default)]",
|
|
17190
|
-
groupTone,
|
|
17191
|
-
groupDisabled ? "cursor-not-allowed text-[color:var(--cmp-listBoxItem-content-disabled)]" : "cursor-pointer",
|
|
17192
|
-
groupDisabled && isDepth1 && "bg-[var(--cmp-listBoxItem-depth1-bg-disabled)]",
|
|
17193
|
-
// 포커스 하이라이트는 depth 배경보다 뒤에 둬 tailwind-merge 로 이기게 한다.
|
|
17194
|
-
groupFocused && !groupDisabled && "bg-[var(--cmp-listBoxItem-bg-hover)] text-[color:var(--cmp-listBoxItem-content-hover)]"
|
|
17264
|
+
children: [
|
|
17265
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17266
|
+
TreeConnector,
|
|
17267
|
+
{
|
|
17268
|
+
guideline: true,
|
|
17269
|
+
size: "sm",
|
|
17270
|
+
depth: o.depth,
|
|
17271
|
+
hasChildren: o.isGroup,
|
|
17272
|
+
isLast: line?.isLast ?? true,
|
|
17273
|
+
ancestorLast: line?.ancestorLast ?? []
|
|
17274
|
+
}
|
|
17195
17275
|
),
|
|
17196
|
-
|
|
17197
|
-
|
|
17198
|
-
|
|
17199
|
-
|
|
17200
|
-
|
|
17201
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17202
|
-
|
|
17203
|
-
total > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17204
|
-
"span",
|
|
17276
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: TREE_CONTENT_CLASS, children: [
|
|
17277
|
+
o.isGroup ? (
|
|
17278
|
+
// 비활성 그룹도 접고 편다 — 그룹이 비활성이어도 아래에 고를 수 있는 자식이 있을 수 있다.
|
|
17279
|
+
/* @__PURE__ */ jsxRuntime.jsx(TreeCaret, { expanded, onToggle: () => onToggleExpand(o.value) })
|
|
17280
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(TreeCaretSpacer, {}),
|
|
17281
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17282
|
+
TreeSelectZone,
|
|
17205
17283
|
{
|
|
17206
|
-
|
|
17207
|
-
|
|
17208
|
-
|
|
17284
|
+
selectable: true,
|
|
17285
|
+
disabled: rowDisabled,
|
|
17286
|
+
control: multi && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17287
|
+
"span",
|
|
17288
|
+
{
|
|
17289
|
+
"data-tree-control": true,
|
|
17290
|
+
className: "flex shrink-0",
|
|
17291
|
+
onPointerDownCapture: (event) => {
|
|
17292
|
+
checkboxShiftRef.current = event.shiftKey;
|
|
17293
|
+
},
|
|
17294
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SCheckbox, { value: checkState, disabled: rowDisabled, onValueChange: toggle })
|
|
17295
|
+
}
|
|
17209
17296
|
),
|
|
17210
|
-
children:
|
|
17211
|
-
|
|
17212
|
-
|
|
17213
|
-
|
|
17214
|
-
|
|
17215
|
-
|
|
17216
|
-
|
|
17297
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
17298
|
+
OptionLabel,
|
|
17299
|
+
{
|
|
17300
|
+
label: o.label,
|
|
17301
|
+
className: treeLabelClass("sm", {
|
|
17302
|
+
// 고른 줄은 굵게 — multi_tree 는 일부만 고른 그룹도 굵다 (STree 와 같다)
|
|
17303
|
+
emphasized: checkState !== false,
|
|
17304
|
+
disabled: rowDisabled,
|
|
17305
|
+
selectable: true
|
|
17306
|
+
})
|
|
17307
|
+
}
|
|
17308
|
+
)
|
|
17217
17309
|
}
|
|
17218
17310
|
)
|
|
17219
|
-
]
|
|
17220
|
-
|
|
17221
|
-
|
|
17222
|
-
|
|
17223
|
-
|
|
17224
|
-
|
|
17225
|
-
|
|
17311
|
+
] })
|
|
17312
|
+
]
|
|
17313
|
+
},
|
|
17314
|
+
rowKey
|
|
17315
|
+
)
|
|
17316
|
+
);
|
|
17317
|
+
}
|
|
17318
|
+
if (o.isGroup) {
|
|
17319
|
+
const isDepth1 = o.depth === 1;
|
|
17320
|
+
const isFirstRow = idx === 0 && !showSelectAll;
|
|
17321
|
+
const groupTone = cn(
|
|
17322
|
+
isDepth1 ? "bg-[var(--cmp-listBoxItem-depth1-bg-default)] font-bold" : "bg-[var(--cmp-listBoxItem-depth2-middle-bg)] font-medium",
|
|
17323
|
+
isDepth1 && !isFirstRow && "border-t border-solid border-[color:var(--cmp-listBoxItem-depth1-border-color)]"
|
|
17324
|
+
);
|
|
17325
|
+
if (multi) {
|
|
17326
|
+
const leafValues = groupLeafValues.get(idx) ?? [];
|
|
17327
|
+
const total = leafValues.length;
|
|
17328
|
+
const selectedCount = leafValues.reduce((n, v) => selectedSet.has(v) ? n + 1 : n, 0);
|
|
17329
|
+
const groupState = total === 0 || selectedCount === 0 ? false : selectedCount === total ? true : null;
|
|
17330
|
+
const groupDisabled = o.disabled || total === 0;
|
|
17331
|
+
const groupFocused = focusedValue === `__group_${idx}__`;
|
|
17332
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17333
|
+
"button",
|
|
17226
17334
|
{
|
|
17335
|
+
type: "button",
|
|
17227
17336
|
"data-select-row": true,
|
|
17228
17337
|
"data-index": idx,
|
|
17338
|
+
id: groupFocused ? activeOptionId : void 0,
|
|
17339
|
+
role: "option",
|
|
17340
|
+
"aria-selected": groupState === true,
|
|
17341
|
+
disabled: groupDisabled,
|
|
17342
|
+
"data-select-focused": groupFocused ? "true" : void 0,
|
|
17343
|
+
"data-select-active": groupFocused ? "true" : void 0,
|
|
17229
17344
|
className: cn(
|
|
17230
|
-
"select-none py-(--cmp-listBoxItem-paddingY) pr-(--cmp-listBoxItem-paddingRight) typo-field-sm-default text-[color:var(--cmp-listBoxItem-content-default)]",
|
|
17345
|
+
"flex w-full select-none items-center gap-(--cmp-listBoxItem-gap) border-none py-(--cmp-listBoxItem-paddingY) pr-(--cmp-listBoxItem-paddingRight) text-left typo-field-sm-default text-[color:var(--cmp-listBoxItem-content-default)]",
|
|
17231
17346
|
groupTone,
|
|
17232
|
-
|
|
17233
|
-
|
|
17234
|
-
|
|
17235
|
-
|
|
17347
|
+
groupDisabled ? "cursor-not-allowed text-[color:var(--cmp-listBoxItem-content-disabled)]" : "cursor-pointer",
|
|
17348
|
+
groupDisabled && isDepth1 && "bg-[var(--cmp-listBoxItem-depth1-bg-disabled)]",
|
|
17349
|
+
// 포커스 하이라이트는 depth 배경보다 뒤에 둬 tailwind-merge 로 이기게 한다.
|
|
17350
|
+
groupFocused && !groupDisabled && "bg-[var(--cmp-listBoxItem-bg-hover)] text-[color:var(--cmp-listBoxItem-content-hover)]"
|
|
17236
17351
|
),
|
|
17237
17352
|
style: { paddingLeft: padLeft },
|
|
17238
|
-
|
|
17353
|
+
onMouseEnter: () => onHoverValue(`__group_${idx}__`),
|
|
17354
|
+
onMouseLeave: () => onHoverValue(null),
|
|
17355
|
+
onClick: () => onToggleGroup(leafValues),
|
|
17356
|
+
children: [
|
|
17357
|
+
/* @__PURE__ */ jsxRuntime.jsx(CheckboxBox, { state: groupState, disabled: groupDisabled, focused: groupFocused }),
|
|
17358
|
+
/* @__PURE__ */ jsxRuntime.jsx(OptionLabel, { label: o.label, className: "min-w-0 truncate" }),
|
|
17359
|
+
total > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17360
|
+
"span",
|
|
17361
|
+
{
|
|
17362
|
+
className: cn(
|
|
17363
|
+
"shrink-0 font-medium",
|
|
17364
|
+
groupFocused ? "text-white" : "text-[color:var(--cmp-listBoxItem-content-disabled)]"
|
|
17365
|
+
),
|
|
17366
|
+
children: [
|
|
17367
|
+
"(",
|
|
17368
|
+
selectedCount,
|
|
17369
|
+
"/",
|
|
17370
|
+
total,
|
|
17371
|
+
")"
|
|
17372
|
+
]
|
|
17373
|
+
}
|
|
17374
|
+
)
|
|
17375
|
+
]
|
|
17239
17376
|
},
|
|
17240
17377
|
rowKey
|
|
17241
17378
|
);
|
|
17242
17379
|
}
|
|
17243
|
-
|
|
17244
|
-
|
|
17245
|
-
"button",
|
|
17380
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17381
|
+
"div",
|
|
17246
17382
|
{
|
|
17247
|
-
type: "button",
|
|
17248
17383
|
"data-select-row": true,
|
|
17249
17384
|
"data-index": idx,
|
|
17250
|
-
id: focusedValue === o.value ? activeOptionId : void 0,
|
|
17251
|
-
disabled: o.disabled,
|
|
17252
|
-
role: "option",
|
|
17253
|
-
"aria-selected": isSelected,
|
|
17254
|
-
"aria-setsize": setSize,
|
|
17255
|
-
"aria-posinset": setSize != null ? idx + 1 : void 0,
|
|
17256
|
-
"data-select-focused": focusedValue === o.value ? "true" : void 0,
|
|
17257
|
-
"data-select-active": focusedValue === o.value ? "true" : void 0,
|
|
17258
17385
|
className: cn(
|
|
17259
|
-
|
|
17260
|
-
|
|
17261
|
-
|
|
17262
|
-
//
|
|
17263
|
-
|
|
17264
|
-
|
|
17386
|
+
"select-none py-(--cmp-listBoxItem-paddingY) pr-(--cmp-listBoxItem-paddingRight) typo-field-sm-default text-[color:var(--cmp-listBoxItem-content-default)]",
|
|
17387
|
+
groupTone,
|
|
17388
|
+
// 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
|
|
17389
|
+
// 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
|
|
17390
|
+
o.disabled && "cursor-not-allowed text-[color:var(--cmp-listBoxItem-content-disabled)]",
|
|
17391
|
+
o.disabled && isDepth1 && "bg-[var(--cmp-listBoxItem-depth1-bg-disabled)]"
|
|
17265
17392
|
),
|
|
17266
|
-
style: {
|
|
17267
|
-
|
|
17268
|
-
onMouseLeave: () => onHoverValue(null),
|
|
17269
|
-
onClick: (event) => onSelect(o.value, idx, event.shiftKey),
|
|
17270
|
-
children: [
|
|
17271
|
-
multi && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17272
|
-
CheckboxBox,
|
|
17273
|
-
{
|
|
17274
|
-
state: isSelected,
|
|
17275
|
-
disabled: o.disabled,
|
|
17276
|
-
focused: focusedValue === o.value
|
|
17277
|
-
}
|
|
17278
|
-
),
|
|
17279
|
-
/* @__PURE__ */ jsxRuntime.jsx(OptionLabel, { label: o.label, className: "flex-1 truncate" })
|
|
17280
|
-
]
|
|
17393
|
+
style: { paddingLeft: padLeft },
|
|
17394
|
+
children: o.label
|
|
17281
17395
|
},
|
|
17282
17396
|
rowKey
|
|
17283
17397
|
);
|
|
17284
|
-
}
|
|
17398
|
+
}
|
|
17399
|
+
const isSelected = selected.includes(o.value);
|
|
17400
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17401
|
+
"button",
|
|
17402
|
+
{
|
|
17403
|
+
type: "button",
|
|
17404
|
+
"data-select-row": true,
|
|
17405
|
+
"data-index": idx,
|
|
17406
|
+
id: focusedValue === o.value ? activeOptionId : void 0,
|
|
17407
|
+
disabled: o.disabled,
|
|
17408
|
+
role: "option",
|
|
17409
|
+
"aria-selected": isSelected,
|
|
17410
|
+
"aria-setsize": setSize,
|
|
17411
|
+
"aria-posinset": setSize != null ? idx + 1 : void 0,
|
|
17412
|
+
"data-select-focused": focusedValue === o.value ? "true" : void 0,
|
|
17413
|
+
"data-select-active": focusedValue === o.value ? "true" : void 0,
|
|
17414
|
+
className: cn(
|
|
17415
|
+
itemBase,
|
|
17416
|
+
isSelected && !multi && "font-bold text-[color:var(--cmp-listBoxItem-content-selected)]",
|
|
17417
|
+
focusedValue === o.value && "bg-[var(--cmp-listBoxItem-bg-hover)] text-[color:var(--cmp-listBoxItem-content-hover)]",
|
|
17418
|
+
// 비활성 항목은 hover/focus 스타일 대상에서 제외한다.
|
|
17419
|
+
// (:hover 는 disabled 버튼에도 매칭되므로 클래스 자체를 붙이지 않아야 한다)
|
|
17420
|
+
!o.disabled && activeClass
|
|
17421
|
+
),
|
|
17422
|
+
style: { ...LIST_BOX_ITEM_PADDING_Y_RIGHT, paddingLeft: padLeft },
|
|
17423
|
+
onMouseEnter: () => onHoverValue(o.value),
|
|
17424
|
+
onMouseLeave: () => onHoverValue(null),
|
|
17425
|
+
onClick: (event) => onSelect(o.value, idx, event.shiftKey),
|
|
17426
|
+
children: [
|
|
17427
|
+
multi && /* @__PURE__ */ jsxRuntime.jsx(
|
|
17428
|
+
CheckboxBox,
|
|
17429
|
+
{
|
|
17430
|
+
state: isSelected,
|
|
17431
|
+
disabled: o.disabled,
|
|
17432
|
+
focused: focusedValue === o.value
|
|
17433
|
+
}
|
|
17434
|
+
),
|
|
17435
|
+
/* @__PURE__ */ jsxRuntime.jsx(OptionLabel, { label: o.label, className: "flex-1 truncate" })
|
|
17436
|
+
]
|
|
17437
|
+
},
|
|
17438
|
+
rowKey
|
|
17439
|
+
);
|
|
17440
|
+
});
|
|
17441
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: listboxId, role: tree ? "tree" : "listbox", "aria-multiselectable": multi || void 0, children: [
|
|
17442
|
+
selectAllRow,
|
|
17443
|
+
topSpacer > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, style: { height: topSpacer } }),
|
|
17444
|
+
wrapTreeMotion(rowNodes),
|
|
17285
17445
|
bottomSpacer > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, style: { height: bottomSpacer } })
|
|
17286
17446
|
] });
|
|
17287
17447
|
}
|
|
17448
|
+
function TreeRowsMotion({ opening, children }) {
|
|
17449
|
+
const ref = react.useRef(null);
|
|
17450
|
+
const animationRef = react.useRef(null);
|
|
17451
|
+
const mountedRef = react.useRef(false);
|
|
17452
|
+
react.useLayoutEffect(() => {
|
|
17453
|
+
const el = ref.current;
|
|
17454
|
+
if (el == null || typeof el.animate !== "function") return;
|
|
17455
|
+
const from = !mountedRef.current && opening ? 0 : el.getBoundingClientRect().height;
|
|
17456
|
+
mountedRef.current = true;
|
|
17457
|
+
animationRef.current?.cancel();
|
|
17458
|
+
animationRef.current = el.animate(
|
|
17459
|
+
[{ height: `${from}px` }, { height: opening ? `${el.scrollHeight}px` : "0px" }],
|
|
17460
|
+
// 접힌 뒤 줄이 목록에서 빠질 때까지 0 으로 붙잡아 둔다. 편 뒤에는 제 높이(auto)로 돌아간다
|
|
17461
|
+
{ ...TREE_BRANCH_MOTION, fill: opening ? "none" : "forwards" }
|
|
17462
|
+
);
|
|
17463
|
+
}, [opening]);
|
|
17464
|
+
react.useEffect(() => () => animationRef.current?.cancel(), []);
|
|
17465
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: "overflow-hidden", "aria-hidden": opening ? void 0 : true, children });
|
|
17466
|
+
}
|
|
17288
17467
|
function OptionLabel({ label, className }) {
|
|
17289
17468
|
return isHtmlLabel(label) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className, dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(label) } }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className, children: label });
|
|
17290
17469
|
}
|
|
@@ -17333,6 +17512,7 @@ function CheckboxBox({
|
|
|
17333
17512
|
}
|
|
17334
17513
|
);
|
|
17335
17514
|
}
|
|
17515
|
+
var NO_KEYS = /* @__PURE__ */ new Set();
|
|
17336
17516
|
var DEFAULT_ROW_HEIGHT = 44;
|
|
17337
17517
|
var DENSE_ROW_HEIGHT = 32;
|
|
17338
17518
|
var SELECTABLE_COLUMN_WIDTH = 48;
|
|
@@ -17363,6 +17543,11 @@ var CONTEXT_MENU_ITEM_CLASS = cn(
|
|
|
17363
17543
|
"data-[highlighted]:bg-[var(--sys-color-bg-accent)] data-[highlighted]:text-[color:var(--sys-color-fg-inverse)]"
|
|
17364
17544
|
);
|
|
17365
17545
|
var ROW_INTERACTIVE_SELECTOR = 'button, a, input, select, textarea, label, [role="button"], [role="checkbox"], [contenteditable="true"]';
|
|
17546
|
+
function rowBlockHeight(tr) {
|
|
17547
|
+
const next = tr.nextElementSibling;
|
|
17548
|
+
const expansion = next instanceof HTMLElement && next.dataset.expansionRow != null ? next.offsetHeight : 0;
|
|
17549
|
+
return tr.offsetHeight + expansion;
|
|
17550
|
+
}
|
|
17366
17551
|
var colWidthFromDef = (c) => {
|
|
17367
17552
|
if (c.autoWidth) return 0;
|
|
17368
17553
|
if (c.width == null) return DEFAULT_COLUMN_WIDTH;
|
|
@@ -17375,6 +17560,8 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
17375
17560
|
rows = [],
|
|
17376
17561
|
rowKey = "id",
|
|
17377
17562
|
selectable = false,
|
|
17563
|
+
rowSelectLabel,
|
|
17564
|
+
selectAllLabel = "\uC804\uCCB4 \uC120\uD0DD",
|
|
17378
17565
|
dragSelectable = false,
|
|
17379
17566
|
contextMenuItems,
|
|
17380
17567
|
onContextMenuItemClick,
|
|
@@ -17413,6 +17600,11 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
17413
17600
|
tableId,
|
|
17414
17601
|
onRowClick,
|
|
17415
17602
|
onRowDoubleClick,
|
|
17603
|
+
renderExpansion,
|
|
17604
|
+
expansionColumn,
|
|
17605
|
+
expandedKeys,
|
|
17606
|
+
defaultExpandedKeys,
|
|
17607
|
+
onExpandedChange,
|
|
17416
17608
|
className,
|
|
17417
17609
|
style
|
|
17418
17610
|
}, ref) {
|
|
@@ -17427,6 +17619,44 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
17427
17619
|
onDenseChange?.(next);
|
|
17428
17620
|
};
|
|
17429
17621
|
const visibleCols = react.useMemo(() => columns.filter((c) => c.visible !== false), [columns]);
|
|
17622
|
+
const expansionOn = renderExpansion != null;
|
|
17623
|
+
const [innerExpandedKeys, setInnerExpandedKeys] = react.useState(
|
|
17624
|
+
() => defaultExpandedKeys ?? []
|
|
17625
|
+
);
|
|
17626
|
+
const currentExpandedKeys = expandedKeys ?? innerExpandedKeys;
|
|
17627
|
+
const expandedSet = react.useMemo(() => new Set(currentExpandedKeys), [currentExpandedKeys]);
|
|
17628
|
+
const isRowExpanded = (row) => expansionOn && expandedSet.has(row[rowKey]);
|
|
17629
|
+
const [closingKeys, setClosingKeys] = react.useState(NO_KEYS);
|
|
17630
|
+
const [prevExpandedSet, setPrevExpandedSet] = react.useState(expandedSet);
|
|
17631
|
+
if (prevExpandedSet !== expandedSet) {
|
|
17632
|
+
setPrevExpandedSet(expandedSet);
|
|
17633
|
+
let nextClosing = NO_KEYS;
|
|
17634
|
+
if (expansionOn && motionAllowed()) {
|
|
17635
|
+
const collapsed = [...prevExpandedSet].filter((key) => !expandedSet.has(key));
|
|
17636
|
+
const opened = [...expandedSet].filter((key) => !prevExpandedSet.has(key));
|
|
17637
|
+
if (collapsed.length > 0 && opened.length === 0) nextClosing = new Set(collapsed);
|
|
17638
|
+
}
|
|
17639
|
+
if (nextClosing !== closingKeys) setClosingKeys(nextClosing);
|
|
17640
|
+
}
|
|
17641
|
+
const shownExpansionSet = react.useMemo(
|
|
17642
|
+
() => closingKeys.size === 0 ? expandedSet : /* @__PURE__ */ new Set([...expandedSet, ...closingKeys]),
|
|
17643
|
+
[expandedSet, closingKeys]
|
|
17644
|
+
);
|
|
17645
|
+
const toggleExpanded = (row) => {
|
|
17646
|
+
const key = row[rowKey];
|
|
17647
|
+
const next = expandedSet.has(key) ? currentExpandedKeys.filter((k) => k !== key) : [...currentExpandedKeys, key];
|
|
17648
|
+
if (expandedKeys === void 0) setInnerExpandedKeys(next);
|
|
17649
|
+
onExpandedChange?.(next, row);
|
|
17650
|
+
};
|
|
17651
|
+
const expansionColIndex = !expansionOn ? -1 : expansionColumn == null ? 0 : visibleCols.findIndex((c) => c.name === expansionColumn);
|
|
17652
|
+
if (expansionColIndex >= 0) {
|
|
17653
|
+
const col = visibleCols[expansionColIndex];
|
|
17654
|
+
if (col?.renderCell) {
|
|
17655
|
+
throw new Error(
|
|
17656
|
+
`[STable] \uD3BC\uCE68 \uCEEC\uB7FC(${col.name})\uC5D0\uB294 renderCell \uC744 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. render \uB97C \uC4F0\uC138\uC694.`
|
|
17657
|
+
);
|
|
17658
|
+
}
|
|
17659
|
+
}
|
|
17430
17660
|
const headerGroupInfo = react.useMemo(() => {
|
|
17431
17661
|
if (!headerGroups || headerGroups.length === 0) return null;
|
|
17432
17662
|
const indexByName = new Map(visibleCols.map((col, index) => [col.name, index]));
|
|
@@ -17531,6 +17761,7 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
17531
17761
|
metricsRef.current ?? (metricsRef.current = createRowMetrics(0, effectiveRowHeight));
|
|
17532
17762
|
const metrics = metricsRef.current;
|
|
17533
17763
|
const measuredKeyRef = react.useRef("");
|
|
17764
|
+
const measuredExpansionRef = react.useRef(shownExpansionSet);
|
|
17534
17765
|
const pendingRowRef = react.useRef(null);
|
|
17535
17766
|
const pinnedTopRef = react.useRef(-1);
|
|
17536
17767
|
const lastEstimateRef = react.useRef(effectiveRowHeight);
|
|
@@ -17544,6 +17775,7 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
17544
17775
|
}
|
|
17545
17776
|
const [scrolledLeft, setScrolledLeft] = react.useState(false);
|
|
17546
17777
|
const [scrolledRight, setScrolledRight] = react.useState(false);
|
|
17778
|
+
const [viewportWidth, setViewportWidth] = react.useState(0);
|
|
17547
17779
|
const setRowCount = react.useCallback((count) => {
|
|
17548
17780
|
const safe = Math.max(0, Math.floor(Number.isFinite(count) ? count : 0));
|
|
17549
17781
|
lastReachEndRef.current = -1;
|
|
@@ -17569,6 +17801,7 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
17569
17801
|
setHeaderHeight(headerH);
|
|
17570
17802
|
setScrolledLeft(el.scrollLeft > 0);
|
|
17571
17803
|
setScrolledRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
|
|
17804
|
+
setViewportWidth(el.clientWidth);
|
|
17572
17805
|
if (virtualScroll) {
|
|
17573
17806
|
const { start, end } = calcRange(el.scrollTop, el.clientHeight - headerH);
|
|
17574
17807
|
setVsRange((prev) => prev.start === start && prev.end === end ? prev : { start, end });
|
|
@@ -17586,6 +17819,13 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
17586
17819
|
react.useEffect(() => {
|
|
17587
17820
|
handleScroll();
|
|
17588
17821
|
}, [handleScroll, rowCount, columnWidths, loading2, height]);
|
|
17822
|
+
react.useEffect(() => {
|
|
17823
|
+
const el = scrollRef.current;
|
|
17824
|
+
if (!expansionOn || !el || typeof ResizeObserver === "undefined") return;
|
|
17825
|
+
const observer = new ResizeObserver(() => handleScroll());
|
|
17826
|
+
observer.observe(el);
|
|
17827
|
+
return () => observer.disconnect();
|
|
17828
|
+
}, [expansionOn, handleScroll]);
|
|
17589
17829
|
const handleScrollRef = react.useRef(handleScroll);
|
|
17590
17830
|
handleScrollRef.current = handleScroll;
|
|
17591
17831
|
useIsomorphicLayoutEffect(() => {
|
|
@@ -17595,9 +17835,10 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
17595
17835
|
if (!el || m == null) return;
|
|
17596
17836
|
const pending2 = pendingRowRef.current;
|
|
17597
17837
|
const key = `${vsRange.start}:${vsRange.end}:${rowCount}`;
|
|
17598
|
-
const alreadyMeasured = measuredKeyRef.current === key;
|
|
17838
|
+
const alreadyMeasured = measuredKeyRef.current === key && measuredExpansionRef.current === shownExpansionSet;
|
|
17599
17839
|
if (alreadyMeasured && pending2 == null) return;
|
|
17600
17840
|
measuredKeyRef.current = key;
|
|
17841
|
+
measuredExpansionRef.current = shownExpansionSet;
|
|
17601
17842
|
const anchor = vsRange.start;
|
|
17602
17843
|
const anchorBefore = offsetOf(m, anchor);
|
|
17603
17844
|
let changed = false;
|
|
@@ -17605,7 +17846,7 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
17605
17846
|
for (const tr of el.querySelectorAll("tr[data-row-index]")) {
|
|
17606
17847
|
const index = Number(tr.dataset.rowIndex);
|
|
17607
17848
|
if (!Number.isInteger(index)) continue;
|
|
17608
|
-
const h = tr
|
|
17849
|
+
const h = rowBlockHeight(tr);
|
|
17609
17850
|
if (h <= 0) continue;
|
|
17610
17851
|
if (setRowSize(m, index, h)) changed = true;
|
|
17611
17852
|
}
|
|
@@ -17627,6 +17868,54 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
17627
17868
|
if (delta !== 0 && el.scrollTop > 0) el.scrollTop += delta;
|
|
17628
17869
|
handleScrollRef.current();
|
|
17629
17870
|
});
|
|
17871
|
+
const expansionMotionRef = react.useRef(null);
|
|
17872
|
+
const prevExpansionRef = react.useRef(null);
|
|
17873
|
+
useIsomorphicLayoutEffect(() => {
|
|
17874
|
+
if (!expansionOn) return;
|
|
17875
|
+
const prev = prevExpansionRef.current;
|
|
17876
|
+
prevExpansionRef.current = { rows, keys: expandedSet };
|
|
17877
|
+
const running = expansionMotionRef.current;
|
|
17878
|
+
if (running?.done) {
|
|
17879
|
+
running.cancel();
|
|
17880
|
+
expansionMotionRef.current = null;
|
|
17881
|
+
}
|
|
17882
|
+
if (!prev || prev.keys === expandedSet) return;
|
|
17883
|
+
const added = new Set([...expandedSet].filter((key) => !prev.keys.has(key)));
|
|
17884
|
+
const removed = new Set([...prev.keys].filter((key) => !expandedSet.has(key)));
|
|
17885
|
+
if (added.size === 0 && removed.size === 0) return;
|
|
17886
|
+
let from = added.size > 0 ? 0 : 1;
|
|
17887
|
+
if (expansionMotionRef.current) {
|
|
17888
|
+
const current = expansionMotionRef.current;
|
|
17889
|
+
const reversing = current.to === 0 && sameKeys(added, current.keys) || current.to === 1 && sameKeys(removed, current.keys);
|
|
17890
|
+
if (reversing) from = current.openness();
|
|
17891
|
+
current.cancel();
|
|
17892
|
+
expansionMotionRef.current = null;
|
|
17893
|
+
}
|
|
17894
|
+
const scrollEl = scrollRef.current;
|
|
17895
|
+
const keys = added.size > 0 ? added : removed;
|
|
17896
|
+
const keyNames = new Set([...keys].map(String));
|
|
17897
|
+
const canAnimate = scrollEl != null && prev.rows === rows && motionAllowed() && (added.size === 0 || removed.size === 0);
|
|
17898
|
+
const motion = canAnimate ? startRowMotion({
|
|
17899
|
+
scrollEl,
|
|
17900
|
+
isInBlock: (tr) => tr.dataset.expansionRow != null && keyNames.has(tr.dataset.expansionKey ?? ""),
|
|
17901
|
+
blockKeys: keys,
|
|
17902
|
+
from,
|
|
17903
|
+
to: added.size > 0 ? 1 : 0
|
|
17904
|
+
}) : null;
|
|
17905
|
+
if (motion) {
|
|
17906
|
+
expansionMotionRef.current = motion;
|
|
17907
|
+
if (motion.to === 0) {
|
|
17908
|
+
void motion.finished.then((completed) => {
|
|
17909
|
+
if (!completed || expansionMotionRef.current !== motion) return;
|
|
17910
|
+
motion.done = true;
|
|
17911
|
+
setClosingKeys(NO_KEYS);
|
|
17912
|
+
});
|
|
17913
|
+
}
|
|
17914
|
+
} else if (closingKeys.size > 0) {
|
|
17915
|
+
setClosingKeys(NO_KEYS);
|
|
17916
|
+
}
|
|
17917
|
+
}, [expandedSet, closingKeys]);
|
|
17918
|
+
react.useEffect(() => () => expansionMotionRef.current?.cancel(), []);
|
|
17630
17919
|
react.useEffect(() => {
|
|
17631
17920
|
if (!virtualScroll) return;
|
|
17632
17921
|
cbRef.current.onVirtualUpdate?.({ from: vsRange.start, to: vsRange.end });
|
|
@@ -17683,7 +17972,7 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
17683
17972
|
if (virtualScroll && m != null) return indexAtOffset(m, el.scrollTop);
|
|
17684
17973
|
const top = el.scrollTop;
|
|
17685
17974
|
for (const tr of el.querySelectorAll("tr[data-row-index]")) {
|
|
17686
|
-
if (tr.offsetTop + tr
|
|
17975
|
+
if (tr.offsetTop + rowBlockHeight(tr) > top) return Number(tr.dataset.rowIndex) || 0;
|
|
17687
17976
|
}
|
|
17688
17977
|
return 0;
|
|
17689
17978
|
},
|
|
@@ -18011,7 +18300,8 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
18011
18300
|
{
|
|
18012
18301
|
value: headerCheck,
|
|
18013
18302
|
disabled: !hasSelectableRow,
|
|
18014
|
-
onValueChange: toggleAll
|
|
18303
|
+
onValueChange: toggleAll,
|
|
18304
|
+
ariaLabel: selectAllLabel
|
|
18015
18305
|
}
|
|
18016
18306
|
) })
|
|
18017
18307
|
}
|
|
@@ -18057,7 +18347,8 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
18057
18347
|
{
|
|
18058
18348
|
value: headerCheck,
|
|
18059
18349
|
disabled: !hasSelectableRow,
|
|
18060
|
-
onValueChange: toggleAll
|
|
18350
|
+
onValueChange: toggleAll,
|
|
18351
|
+
ariaLabel: selectAllLabel
|
|
18061
18352
|
}
|
|
18062
18353
|
) }),
|
|
18063
18354
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -18257,112 +18548,168 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
18257
18548
|
const rowLocked = (selectable || dragSelectable) && !canSelectRow(row);
|
|
18258
18549
|
const rowBg = "bg-white";
|
|
18259
18550
|
const rowHover = hoverable && !rowLocked;
|
|
18260
|
-
|
|
18261
|
-
|
|
18262
|
-
|
|
18263
|
-
"
|
|
18264
|
-
|
|
18265
|
-
|
|
18266
|
-
|
|
18267
|
-
|
|
18268
|
-
|
|
18269
|
-
|
|
18270
|
-
|
|
18271
|
-
|
|
18272
|
-
|
|
18273
|
-
|
|
18274
|
-
|
|
18275
|
-
|
|
18276
|
-
(
|
|
18277
|
-
dragSelectOn
|
|
18278
|
-
|
|
18279
|
-
|
|
18280
|
-
|
|
18281
|
-
|
|
18282
|
-
|
|
18283
|
-
"
|
|
18284
|
-
|
|
18285
|
-
|
|
18286
|
-
|
|
18287
|
-
|
|
18551
|
+
const expansionShown = expansionOn && shownExpansionSet.has(row[rowKey]);
|
|
18552
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
|
|
18553
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
18554
|
+
"tr",
|
|
18555
|
+
{
|
|
18556
|
+
"data-row-index": rowIndex,
|
|
18557
|
+
onClick: onRowClick ? (event) => {
|
|
18558
|
+
const target = event.target;
|
|
18559
|
+
if (target.closest(ROW_INTERACTIVE_SELECTOR)) return;
|
|
18560
|
+
onRowClick(row);
|
|
18561
|
+
} : void 0,
|
|
18562
|
+
onDoubleClick: onRowDoubleClick ? (event) => {
|
|
18563
|
+
const target = event.target;
|
|
18564
|
+
if (target.closest(ROW_INTERACTIVE_SELECTOR)) return;
|
|
18565
|
+
onRowDoubleClick(row);
|
|
18566
|
+
} : void 0,
|
|
18567
|
+
onMouseDown: dragSelectOn ? (event) => startDragSelect(rowIndex, event) : void 0,
|
|
18568
|
+
onMouseEnter: dragSelectOn ? () => extendDragSelect(rowIndex) : void 0,
|
|
18569
|
+
onContextMenu: contextMenuOn ? (event) => openContextMenu(row, event) : void 0,
|
|
18570
|
+
className: cn(
|
|
18571
|
+
"group/table-row",
|
|
18572
|
+
rowHover && "hover:bg-[var(--color-grey-05)]",
|
|
18573
|
+
(onRowClick || onRowDoubleClick) && "cursor-pointer",
|
|
18574
|
+
dragSelectOn && "select-none",
|
|
18575
|
+
rowClassName?.(row)
|
|
18576
|
+
),
|
|
18577
|
+
style: { height: virtualScroll ? effectiveRowHeight : rowH },
|
|
18578
|
+
children: [
|
|
18579
|
+
selectable && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18580
|
+
"td",
|
|
18581
|
+
{
|
|
18582
|
+
className: cn(
|
|
18583
|
+
// 원본 .td--selected: 48px 고정폭, 항상 left sticky, 체크박스 중앙정렬
|
|
18584
|
+
"sticky left-0 z-[2] border-b border-solid border-[color:var(--cmp-table-border-color)] align-middle",
|
|
18585
|
+
rowBg,
|
|
18586
|
+
rowHover && "group-hover/table-row:bg-[var(--color-grey-05)]",
|
|
18587
|
+
stickyLeft === 0 && scrolledLeft && "shadow-[5px_0_8px_0_rgba(34,34,34,0.1)]"
|
|
18588
|
+
),
|
|
18589
|
+
style: {
|
|
18590
|
+
width: SELECTABLE_COLUMN_WIDTH,
|
|
18591
|
+
minWidth: SELECTABLE_COLUMN_WIDTH,
|
|
18592
|
+
maxWidth: SELECTABLE_COLUMN_WIDTH,
|
|
18593
|
+
// 선택 열도 행의 일부다 — 여기만 희지 않으면 회색 줄이 끊긴다
|
|
18594
|
+
background: rowLocked ? LOCKED_BG : void 0
|
|
18595
|
+
},
|
|
18596
|
+
onClick: (e) => e.stopPropagation(),
|
|
18597
|
+
onDoubleClick: (e) => e.stopPropagation(),
|
|
18598
|
+
onClickCapture: (e) => {
|
|
18599
|
+
shiftPressedRef.current = e.shiftKey;
|
|
18600
|
+
if (e.shiftKey) window.getSelection()?.removeAllRanges();
|
|
18601
|
+
},
|
|
18602
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex select-none items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18603
|
+
SCheckbox,
|
|
18604
|
+
{
|
|
18605
|
+
value: isSel || !isRowIndeterminate?.(row) ? isSel : null,
|
|
18606
|
+
disabled: !canSelectRow(row),
|
|
18607
|
+
onValueChange: () => toggleRow(row, rowOffset + ri),
|
|
18608
|
+
ariaLabel: rowSelectLabel?.(row) ?? "\uD589 \uC120\uD0DD"
|
|
18609
|
+
}
|
|
18610
|
+
) })
|
|
18611
|
+
}
|
|
18612
|
+
),
|
|
18613
|
+
visibleCols.map((col, i) => {
|
|
18614
|
+
const tdClassName = cn(
|
|
18615
|
+
// 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
|
|
18616
|
+
// 셀 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
|
|
18617
|
+
"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)]",
|
|
18288
18618
|
rowBg,
|
|
18289
18619
|
rowHover && "group-hover/table-row:bg-[var(--color-grey-05)]",
|
|
18290
|
-
|
|
18291
|
-
)
|
|
18292
|
-
|
|
18293
|
-
|
|
18294
|
-
|
|
18295
|
-
|
|
18296
|
-
|
|
18297
|
-
|
|
18298
|
-
|
|
18299
|
-
|
|
18300
|
-
|
|
18301
|
-
|
|
18302
|
-
|
|
18303
|
-
|
|
18304
|
-
|
|
18305
|
-
|
|
18306
|
-
|
|
18620
|
+
typeof col.tdClass === "function" ? col.tdClass(row) : col.tdClass
|
|
18621
|
+
);
|
|
18622
|
+
const tdPadX = cellPadXOf(col);
|
|
18623
|
+
const dragEdges = dragSel ? [
|
|
18624
|
+
dragTop && `inset 0 ${DRAG_EDGE_W} 0 0 ${DRAG_EDGE_C}`,
|
|
18625
|
+
dragBottom && `inset 0 ${DRAG_EDGE_NEG_W} 0 0 ${DRAG_EDGE_C}`,
|
|
18626
|
+
i === 0 && `inset ${DRAG_EDGE_W} 0 0 0 ${DRAG_EDGE_C}`,
|
|
18627
|
+
i === visibleCols.length - 1 && `inset ${DRAG_EDGE_NEG_W} 0 0 0 ${DRAG_EDGE_C}`
|
|
18628
|
+
].filter(Boolean) : [];
|
|
18629
|
+
const shadows = [...dragEdges, stickyShadowValue(i)].filter(Boolean);
|
|
18630
|
+
const tdStyle = {
|
|
18631
|
+
paddingLeft: tdPadX,
|
|
18632
|
+
paddingRight: tdPadX,
|
|
18633
|
+
paddingTop: cellPadY,
|
|
18634
|
+
paddingBottom: cellPadY,
|
|
18635
|
+
textAlign: col.align ?? "left",
|
|
18636
|
+
// 인라인이라 hover 배경보다 세다 — 고른 행은 hover 로 흐려지지 않는다.
|
|
18637
|
+
background: dragSel ? DRAG_BG : rowLocked ? LOCKED_BG : void 0,
|
|
18638
|
+
// 클래스의 기본 글자색을 덮는다. 셀이 자기 색을 정한 내용(SIcon 의
|
|
18639
|
+
// color, STag 등)까지는 닿지 않는다 — 그건 소비 앱 몫이다.
|
|
18640
|
+
color: rowLocked ? LOCKED_CONTENT : void 0,
|
|
18641
|
+
boxShadow: shadows.length > 0 ? shadows.join(", ") : void 0,
|
|
18642
|
+
...cellStyle(i)
|
|
18643
|
+
};
|
|
18644
|
+
if (col.renderCell) {
|
|
18645
|
+
const cell = col.renderCell({
|
|
18646
|
+
row,
|
|
18647
|
+
value: cellValue(col, row),
|
|
18648
|
+
column: col,
|
|
18649
|
+
colIndex: i,
|
|
18650
|
+
rowIndex: ri,
|
|
18651
|
+
isSelected: isSel,
|
|
18652
|
+
className: tdClassName,
|
|
18653
|
+
style: tdStyle
|
|
18654
|
+
});
|
|
18655
|
+
if (cell == null || cell === false) return null;
|
|
18656
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react.Fragment, { children: cell }, col.name);
|
|
18657
|
+
}
|
|
18658
|
+
const content = col.render ? col.render(row, cellValue(col, row)) : cellValue(col, row);
|
|
18659
|
+
if (i === expansionColIndex) {
|
|
18660
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
18661
|
+
"td",
|
|
18662
|
+
{
|
|
18663
|
+
className: cn(tdClassName, "cursor-pointer"),
|
|
18664
|
+
style: tdStyle,
|
|
18665
|
+
onClick: (event) => {
|
|
18666
|
+
if (isOwnControl(event.target, event.currentTarget)) return;
|
|
18667
|
+
event.stopPropagation();
|
|
18668
|
+
toggleExpanded(row);
|
|
18669
|
+
},
|
|
18670
|
+
onDoubleClick: (event) => event.stopPropagation(),
|
|
18671
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ExpansionToggleCell, { expanded: isRowExpanded(row), children: content })
|
|
18672
|
+
},
|
|
18673
|
+
col.name
|
|
18674
|
+
);
|
|
18675
|
+
}
|
|
18676
|
+
return /* @__PURE__ */ jsxRuntime.jsx("td", { className: tdClassName, style: tdStyle, children: content }, col.name);
|
|
18677
|
+
})
|
|
18678
|
+
]
|
|
18679
|
+
}
|
|
18680
|
+
),
|
|
18681
|
+
expansionShown && // 상세 영역 — 행이 아니므로 data-row-index 를 달지 않는다 (행 수·선택·실측 대상 밖)
|
|
18682
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18683
|
+
"tr",
|
|
18684
|
+
{
|
|
18685
|
+
"data-expansion-row": "",
|
|
18686
|
+
"data-expansion-key": String(row[rowKey]),
|
|
18687
|
+
className: expandedSet.has(row[rowKey]) ? void 0 : "pointer-events-none",
|
|
18688
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18689
|
+
"td",
|
|
18690
|
+
{
|
|
18691
|
+
colSpan: totalColSpan,
|
|
18692
|
+
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)]",
|
|
18693
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18694
|
+
"div",
|
|
18307
18695
|
{
|
|
18308
|
-
|
|
18309
|
-
|
|
18310
|
-
|
|
18696
|
+
className: "sticky left-0 box-border min-w-0",
|
|
18697
|
+
style: {
|
|
18698
|
+
// 가로 스크롤이 있어도 보이는 폭에 머문다. 재기 전(0)에는 표 폭을 따른다
|
|
18699
|
+
width: viewportWidth > 0 ? viewportWidth : void 0,
|
|
18700
|
+
paddingLeft: "var(--cmp-table-body-paddingX-wide)",
|
|
18701
|
+
paddingRight: "var(--cmp-table-body-paddingX-wide)",
|
|
18702
|
+
paddingTop: cellPadY,
|
|
18703
|
+
paddingBottom: cellPadY
|
|
18704
|
+
},
|
|
18705
|
+
children: renderExpansion?.(row)
|
|
18311
18706
|
}
|
|
18312
|
-
)
|
|
18313
|
-
}
|
|
18314
|
-
),
|
|
18315
|
-
visibleCols.map((col, i) => {
|
|
18316
|
-
const tdClassName = cn(
|
|
18317
|
-
// 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
|
|
18318
|
-
// 셀 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
|
|
18319
|
-
"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)]",
|
|
18320
|
-
rowBg,
|
|
18321
|
-
rowHover && "group-hover/table-row:bg-[var(--color-grey-05)]",
|
|
18322
|
-
typeof col.tdClass === "function" ? col.tdClass(row) : col.tdClass
|
|
18323
|
-
);
|
|
18324
|
-
const tdPadX = cellPadXOf(col);
|
|
18325
|
-
const dragEdges = dragSel ? [
|
|
18326
|
-
dragTop && `inset 0 ${DRAG_EDGE_W} 0 0 ${DRAG_EDGE_C}`,
|
|
18327
|
-
dragBottom && `inset 0 ${DRAG_EDGE_NEG_W} 0 0 ${DRAG_EDGE_C}`,
|
|
18328
|
-
i === 0 && `inset ${DRAG_EDGE_W} 0 0 0 ${DRAG_EDGE_C}`,
|
|
18329
|
-
i === visibleCols.length - 1 && `inset ${DRAG_EDGE_NEG_W} 0 0 0 ${DRAG_EDGE_C}`
|
|
18330
|
-
].filter(Boolean) : [];
|
|
18331
|
-
const shadows = [...dragEdges, stickyShadowValue(i)].filter(Boolean);
|
|
18332
|
-
const tdStyle = {
|
|
18333
|
-
paddingLeft: tdPadX,
|
|
18334
|
-
paddingRight: tdPadX,
|
|
18335
|
-
paddingTop: cellPadY,
|
|
18336
|
-
paddingBottom: cellPadY,
|
|
18337
|
-
textAlign: col.align ?? "left",
|
|
18338
|
-
// 인라인이라 hover 배경보다 세다 — 고른 행은 hover 로 흐려지지 않는다.
|
|
18339
|
-
background: dragSel ? DRAG_BG : rowLocked ? LOCKED_BG : void 0,
|
|
18340
|
-
// 클래스의 기본 글자색을 덮는다. 셀이 자기 색을 정한 내용(SIcon 의
|
|
18341
|
-
// color, STag 등)까지는 닿지 않는다 — 그건 소비 앱 몫이다.
|
|
18342
|
-
color: rowLocked ? LOCKED_CONTENT : void 0,
|
|
18343
|
-
boxShadow: shadows.length > 0 ? shadows.join(", ") : void 0,
|
|
18344
|
-
...cellStyle(i)
|
|
18345
|
-
};
|
|
18346
|
-
if (col.renderCell) {
|
|
18347
|
-
const cell = col.renderCell({
|
|
18348
|
-
row,
|
|
18349
|
-
value: cellValue(col, row),
|
|
18350
|
-
column: col,
|
|
18351
|
-
colIndex: i,
|
|
18352
|
-
rowIndex: ri,
|
|
18353
|
-
isSelected: isSel,
|
|
18354
|
-
className: tdClassName,
|
|
18355
|
-
style: tdStyle
|
|
18356
|
-
});
|
|
18357
|
-
if (cell == null || cell === false) return null;
|
|
18358
|
-
return /* @__PURE__ */ jsxRuntime.jsx(react.Fragment, { children: cell }, col.name);
|
|
18707
|
+
)
|
|
18359
18708
|
}
|
|
18360
|
-
|
|
18361
|
-
|
|
18362
|
-
|
|
18363
|
-
|
|
18364
|
-
row[rowKey] ?? ri
|
|
18365
|
-
);
|
|
18709
|
+
)
|
|
18710
|
+
}
|
|
18711
|
+
)
|
|
18712
|
+
] }, row[rowKey] ?? ri);
|
|
18366
18713
|
}),
|
|
18367
18714
|
virtualScroll && bottomSpacer > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-hidden": true, style: { height: bottomSpacer }, children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: totalColSpan, className: "p-0" }) })
|
|
18368
18715
|
] })
|
|
@@ -18488,6 +18835,26 @@ var STableImpl = /* @__PURE__ */ react.forwardRef(function STable({
|
|
|
18488
18835
|
);
|
|
18489
18836
|
});
|
|
18490
18837
|
var STable2 = STableImpl;
|
|
18838
|
+
function isOwnControl(target, cell) {
|
|
18839
|
+
if (!(target instanceof Element)) return false;
|
|
18840
|
+
if (target.closest("[data-expansion-toggle]")) return false;
|
|
18841
|
+
const control = target.closest(ROW_INTERACTIVE_SELECTOR);
|
|
18842
|
+
return control != null && cell.contains(control);
|
|
18843
|
+
}
|
|
18844
|
+
function ExpansionToggleCell({ expanded, children }) {
|
|
18845
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-(--cmp-tree-item-contentGap)", children: [
|
|
18846
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "data-expansion-toggle": true, className: "flex shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
18847
|
+
SGhostButton,
|
|
18848
|
+
{
|
|
18849
|
+
icon: expanded ? "caretDown" : "caretRight",
|
|
18850
|
+
size: "xxs",
|
|
18851
|
+
ariaLabel: expanded ? "collapse row" : "expand row",
|
|
18852
|
+
ariaExpanded: expanded
|
|
18853
|
+
}
|
|
18854
|
+
) }),
|
|
18855
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children })
|
|
18856
|
+
] });
|
|
18857
|
+
}
|
|
18491
18858
|
var COUNT_NULL = "var(--cmp-table-bar-count-null)";
|
|
18492
18859
|
var totalColor = (n) => n > 0 ? "var(--cmp-table-bar-count-total)" : COUNT_NULL;
|
|
18493
18860
|
var selectedColor = (n) => n > 0 ? "var(--color-brilliantblue-75)" : COUNT_NULL;
|
|
@@ -18556,9 +18923,7 @@ var STableBar = /* @__PURE__ */ react.forwardRef(function STableBar2({ title, to
|
|
|
18556
18923
|
}
|
|
18557
18924
|
);
|
|
18558
18925
|
});
|
|
18559
|
-
var
|
|
18560
|
-
var EXPAND_MOTION = { duration: 220, easing: "ease-out" };
|
|
18561
|
-
var COLLAPSE_MOTION = { duration: 140, easing: "ease-in" };
|
|
18926
|
+
var NO_KEYS2 = /* @__PURE__ */ new Set();
|
|
18562
18927
|
function STreeTable({
|
|
18563
18928
|
rows = [],
|
|
18564
18929
|
columns = [],
|
|
@@ -18611,11 +18976,11 @@ function STreeTable({
|
|
|
18611
18976
|
[rows, expandedSet, rowKey, childrenKey]
|
|
18612
18977
|
);
|
|
18613
18978
|
const tableRef = react.useRef(null);
|
|
18614
|
-
const [closingKeys, setClosingKeys] = react.useState(
|
|
18979
|
+
const [closingKeys, setClosingKeys] = react.useState(NO_KEYS2);
|
|
18615
18980
|
const [prevExpand, setPrevExpand] = react.useState({ rows, expandedSet });
|
|
18616
18981
|
if (prevExpand.rows !== rows || prevExpand.expandedSet !== expandedSet) {
|
|
18617
18982
|
setPrevExpand({ rows, expandedSet });
|
|
18618
|
-
let nextClosing =
|
|
18983
|
+
let nextClosing = NO_KEYS2;
|
|
18619
18984
|
if (prevExpand.rows === rows && motionAllowed()) {
|
|
18620
18985
|
const collapsed = [...prevExpand.expandedSet].filter((key) => !expandedSet.has(key));
|
|
18621
18986
|
const expanded = [...expandedSet].filter((key) => !prevExpand.expandedSet.has(key));
|
|
@@ -18664,11 +19029,15 @@ function STreeTable({
|
|
|
18664
19029
|
motionRef.current = null;
|
|
18665
19030
|
}
|
|
18666
19031
|
const scrollEl = tableRef.current?.getScrollElement();
|
|
19032
|
+
const rowKeys = renderedRows.map(keyOf);
|
|
18667
19033
|
const keys = added.size > 0 ? added : removed;
|
|
18668
19034
|
const canAnimate = scrollEl != null && motionAllowed() && (added.size === 0 || removed.size === 0);
|
|
18669
19035
|
const motion = canAnimate ? startRowMotion({
|
|
18670
19036
|
scrollEl,
|
|
18671
|
-
|
|
19037
|
+
isInBlock: (tr) => {
|
|
19038
|
+
const key = rowKeys[Number(tr.dataset.rowIndex)];
|
|
19039
|
+
return key !== void 0 && keys.has(key);
|
|
19040
|
+
},
|
|
18672
19041
|
blockKeys: keys,
|
|
18673
19042
|
from,
|
|
18674
19043
|
to: added.size > 0 ? 1 : 0
|
|
@@ -18679,11 +19048,11 @@ function STreeTable({
|
|
|
18679
19048
|
void motion.finished.then((completed) => {
|
|
18680
19049
|
if (!completed || motionRef.current !== motion) return;
|
|
18681
19050
|
motion.done = true;
|
|
18682
|
-
setClosingKeys(
|
|
19051
|
+
setClosingKeys(NO_KEYS2);
|
|
18683
19052
|
});
|
|
18684
19053
|
}
|
|
18685
19054
|
} else if (closingKeys.size > 0) {
|
|
18686
|
-
setClosingKeys(
|
|
19055
|
+
setClosingKeys(NO_KEYS2);
|
|
18687
19056
|
}
|
|
18688
19057
|
}, [renderedRows]);
|
|
18689
19058
|
react.useEffect(() => () => motionRef.current?.cancel(), []);
|
|
@@ -18756,7 +19125,7 @@ function STreeTable({
|
|
|
18756
19125
|
className: cn(className, hasChildren && "cursor-pointer"),
|
|
18757
19126
|
style,
|
|
18758
19127
|
onClick: hasChildren ? (event) => {
|
|
18759
|
-
if (
|
|
19128
|
+
if (isOwnControl2(event.target, event.currentTarget)) return;
|
|
18760
19129
|
event.stopPropagation();
|
|
18761
19130
|
toggleExpanded(row);
|
|
18762
19131
|
} : void 0,
|
|
@@ -18811,96 +19180,8 @@ function flattenRows(nodes, isOpen, childrenOf) {
|
|
|
18811
19180
|
walk(nodes);
|
|
18812
19181
|
return out;
|
|
18813
19182
|
}
|
|
18814
|
-
function sameKeys(a, b) {
|
|
18815
|
-
return a.size === b.size && [...a].every((key) => b.has(key));
|
|
18816
|
-
}
|
|
18817
|
-
function motionAllowed() {
|
|
18818
|
-
if (typeof window === "undefined" || typeof Element.prototype.animate !== "function")
|
|
18819
|
-
return false;
|
|
18820
|
-
return !window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
18821
|
-
}
|
|
18822
|
-
function startRowMotion({
|
|
18823
|
-
scrollEl,
|
|
18824
|
-
rowKeys,
|
|
18825
|
-
blockKeys,
|
|
18826
|
-
from,
|
|
18827
|
-
to
|
|
18828
|
-
}) {
|
|
18829
|
-
const spec = to === 1 ? EXPAND_MOTION : COLLAPSE_MOTION;
|
|
18830
|
-
const duration = spec.duration * Math.abs(to - from);
|
|
18831
|
-
if (duration < 1) return null;
|
|
18832
|
-
const trs = [...scrollEl.querySelectorAll("tr[data-row-index]")].map((tr) => {
|
|
18833
|
-
const key = rowKeys[Number(tr.dataset.rowIndex)];
|
|
18834
|
-
return {
|
|
18835
|
-
tr,
|
|
18836
|
-
inBlock: key !== void 0 && blockKeys.has(key),
|
|
18837
|
-
height: tr.getBoundingClientRect().height
|
|
18838
|
-
};
|
|
18839
|
-
});
|
|
18840
|
-
const viewBottom = scrollEl.scrollTop + scrollEl.clientHeight;
|
|
18841
|
-
const openAt = (offset) => from + (to - from) * offset;
|
|
18842
|
-
const translate = (shift2, s) => `translateY(${-shift2 * (1 - s)}px)`;
|
|
18843
|
-
const timing = {
|
|
18844
|
-
duration,
|
|
18845
|
-
easing: spec.easing,
|
|
18846
|
-
// 접힘은 남겨 둔 행이 빠질 때까지 끝 위치를 붙잡는다 — 놓으면 그 사이 한 프레임 제자리로 튄다
|
|
18847
|
-
fill: to === 0 ? "forwards" : "none"
|
|
18848
|
-
};
|
|
18849
|
-
const animations = [];
|
|
18850
|
-
let shift = 0;
|
|
18851
|
-
let blockHeight = 0;
|
|
18852
|
-
let y = 0;
|
|
18853
|
-
trs.forEach(({ tr, inBlock, height }, i) => {
|
|
18854
|
-
if (inBlock && !trs[i - 1]?.inBlock) {
|
|
18855
|
-
blockHeight = 0;
|
|
18856
|
-
for (let j = i; j < trs.length && trs[j].inBlock; j++) blockHeight += trs[j].height;
|
|
18857
|
-
shift += blockHeight;
|
|
18858
|
-
y = 0;
|
|
18859
|
-
}
|
|
18860
|
-
if (shift === 0 || tr.offsetTop - shift > viewBottom) return;
|
|
18861
|
-
if (!inBlock) {
|
|
18862
|
-
animations.push(
|
|
18863
|
-
tr.animate(
|
|
18864
|
-
[{ transform: translate(shift, from) }, { transform: translate(shift, to) }],
|
|
18865
|
-
timing
|
|
18866
|
-
)
|
|
18867
|
-
);
|
|
18868
|
-
return;
|
|
18869
|
-
}
|
|
18870
|
-
const rowY = y;
|
|
18871
|
-
const clipAt = (s) => Math.min(height, Math.max(0, blockHeight * (1 - s) - rowY));
|
|
18872
|
-
const bends = [1 - rowY / blockHeight, 1 - (rowY + height) / blockHeight].map((s) => (s - from) / (to - from)).filter((offset) => offset > 0 && offset < 1);
|
|
18873
|
-
const offsets = [0, ...bends, 1].sort((a, b) => a - b);
|
|
18874
|
-
animations.push(
|
|
18875
|
-
tr.animate(
|
|
18876
|
-
offsets.map((offset) => ({
|
|
18877
|
-
offset,
|
|
18878
|
-
transform: translate(shift, openAt(offset)),
|
|
18879
|
-
clipPath: `inset(${clipAt(openAt(offset))}px 0 0 0)`
|
|
18880
|
-
})),
|
|
18881
|
-
timing
|
|
18882
|
-
)
|
|
18883
|
-
);
|
|
18884
|
-
y += height;
|
|
18885
|
-
});
|
|
18886
|
-
if (animations.length === 0) return null;
|
|
18887
|
-
return {
|
|
18888
|
-
keys: blockKeys,
|
|
18889
|
-
to,
|
|
18890
|
-
done: false,
|
|
18891
|
-
finished: Promise.all(animations.map((animation) => animation.finished)).then(
|
|
18892
|
-
() => true,
|
|
18893
|
-
() => false
|
|
18894
|
-
),
|
|
18895
|
-
openness: () => {
|
|
18896
|
-
const progress = animations[0].effect?.getComputedTiming().progress;
|
|
18897
|
-
return progress == null ? to : openAt(progress);
|
|
18898
|
-
},
|
|
18899
|
-
cancel: () => animations.forEach((animation) => animation.cancel())
|
|
18900
|
-
};
|
|
18901
|
-
}
|
|
18902
19183
|
var OWN_CONTROL_SELECTOR = 'a, button, input, select, textarea, label, [role="button"], [role="checkbox"], [contenteditable="true"]';
|
|
18903
|
-
function
|
|
19184
|
+
function isOwnControl2(target, cell) {
|
|
18904
19185
|
if (!(target instanceof Element)) return false;
|
|
18905
19186
|
if (target.closest("[data-tree-toggle]")) return false;
|
|
18906
19187
|
const control = target.closest(OWN_CONTROL_SELECTOR);
|