@sia.soul/sia-react-ui 0.1.63 → 0.1.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-F4XMRO6G.js → chunk-B42RCR7O.js} +1300 -1198
- package/dist/{chunk-NV4QPQSP.js → chunk-NKSPPR2A.js} +1 -1
- package/dist/{chunk-7CAQPLKC.js → chunk-VGIGEDUP.js} +1 -1
- package/dist/{core-BemUqBUF.d.ts → core-DrNZuMER.d.ts} +19 -4
- package/dist/{core-C4ayGoM8.d.cts → core-hpkUd4EO.d.cts} +19 -4
- package/dist/core.cjs +1229 -1231
- package/dist/core.css +51 -2
- package/dist/core.d.cts +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +2 -2
- package/dist/index.cjs +882 -775
- package/dist/index.css +51 -2
- package/dist/index.d.cts +8 -6
- package/dist/index.d.ts +8 -6
- package/dist/index.js +12 -9
- package/dist/select-date-range.js +2 -2
- package/package.json +1 -1
|
@@ -101,1259 +101,1361 @@ var Checkbox2 = Object.assign(CheckboxRoot, {
|
|
|
101
101
|
Group: CheckboxGroup
|
|
102
102
|
});
|
|
103
103
|
|
|
104
|
-
// src/components/
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
104
|
+
// src/components/FloatingScrollbarProvider.tsx
|
|
105
|
+
import { useEffect as useEffect3 } from "react";
|
|
106
|
+
|
|
107
|
+
// src/components/useScrollbarProximity.ts
|
|
108
|
+
import { useEffect as useEffect2 } from "react";
|
|
109
|
+
var users = 0;
|
|
110
|
+
var cleanup;
|
|
111
|
+
function useScrollbarProximity() {
|
|
112
|
+
useEffect2(() => {
|
|
113
|
+
if (users++ === 0) {
|
|
114
|
+
let frame = 0;
|
|
115
|
+
let x = -Infinity;
|
|
116
|
+
let y = -Infinity;
|
|
117
|
+
const nearby = /* @__PURE__ */ new Set();
|
|
118
|
+
const clear = () => {
|
|
119
|
+
nearby.forEach((track) => track.removeAttribute("data-scrollbar-near"));
|
|
120
|
+
nearby.clear();
|
|
121
|
+
};
|
|
122
|
+
const update = () => {
|
|
123
|
+
frame = 0;
|
|
124
|
+
const next = /* @__PURE__ */ new Set();
|
|
125
|
+
document.querySelectorAll(".sia-scrollbar-track").forEach((track) => {
|
|
126
|
+
const rect = track.getBoundingClientRect();
|
|
127
|
+
const proximity = Number.parseFloat(getComputedStyle(track).getPropertyValue("--sia-scrollbar-proximity")) || 16;
|
|
128
|
+
if (rect.width && rect.height && x >= rect.left - proximity && x <= rect.right + proximity && y >= rect.top - proximity && y <= rect.bottom + proximity) {
|
|
129
|
+
next.add(track);
|
|
130
|
+
if (!nearby.has(track)) track.setAttribute("data-scrollbar-near", "true");
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
nearby.forEach((track) => {
|
|
134
|
+
if (!next.has(track)) track.removeAttribute("data-scrollbar-near");
|
|
135
|
+
});
|
|
136
|
+
nearby.clear();
|
|
137
|
+
next.forEach((track) => nearby.add(track));
|
|
138
|
+
};
|
|
139
|
+
const move = (event) => {
|
|
140
|
+
if (event.pointerType === "touch") return;
|
|
141
|
+
x = event.clientX;
|
|
142
|
+
y = event.clientY;
|
|
143
|
+
if (!frame) frame = requestAnimationFrame(update);
|
|
144
|
+
};
|
|
145
|
+
const leave = () => {
|
|
146
|
+
x = y = -Infinity;
|
|
147
|
+
clear();
|
|
148
|
+
};
|
|
149
|
+
document.addEventListener("pointermove", move, { passive: true });
|
|
150
|
+
document.documentElement.addEventListener("pointerleave", leave);
|
|
151
|
+
window.addEventListener("blur", leave);
|
|
152
|
+
cleanup = () => {
|
|
153
|
+
if (frame) cancelAnimationFrame(frame);
|
|
154
|
+
document.removeEventListener("pointermove", move);
|
|
155
|
+
document.documentElement.removeEventListener("pointerleave", leave);
|
|
156
|
+
window.removeEventListener("blur", leave);
|
|
157
|
+
clear();
|
|
158
|
+
};
|
|
131
159
|
}
|
|
132
|
-
return
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
function toggleTreeCheck(nodes, keys, node, strictly = false) {
|
|
138
|
-
const state = getTreeCheckState(nodes, keys, strictly);
|
|
139
|
-
const next = new Set(state.checked);
|
|
140
|
-
const checked = !next.has(node.key);
|
|
141
|
-
if (node.disabled || node.disableCheckbox || node.checkable === false) return { ...state, checkedValue: !checked };
|
|
142
|
-
(strictly ? [node.key] : affectedKeys(node)).forEach((key) => checked ? next.add(key) : next.delete(key));
|
|
143
|
-
if (!strictly && !checked) {
|
|
144
|
-
let removeParents2 = function(items) {
|
|
145
|
-
let found = false;
|
|
146
|
-
for (const item of items) {
|
|
147
|
-
const childFound = item.children ? removeParents2(item.children) : false;
|
|
148
|
-
if (childFound) next.delete(item.key);
|
|
149
|
-
if (item.key === node.key || childFound) found = true;
|
|
160
|
+
return () => {
|
|
161
|
+
if (--users === 0) {
|
|
162
|
+
cleanup?.();
|
|
163
|
+
cleanup = void 0;
|
|
150
164
|
}
|
|
151
|
-
return found;
|
|
152
165
|
};
|
|
153
|
-
|
|
154
|
-
removeParents2(nodes);
|
|
155
|
-
}
|
|
156
|
-
return { ...getTreeCheckState(nodes, [...next], strictly), checkedValue: checked };
|
|
166
|
+
}, []);
|
|
157
167
|
}
|
|
158
168
|
|
|
159
|
-
// src/components/
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
var FLOATING_VIEWPORT_PADDING = 8;
|
|
165
|
-
var FLOATING_ARROW_EDGE_OFFSET = 16;
|
|
166
|
-
var activeTooltipClose;
|
|
167
|
-
function clampFloating(value, min, max) {
|
|
168
|
-
return Math.min(Math.max(value, min), Math.max(min, max));
|
|
169
|
-
}
|
|
170
|
-
function normalizeFloatingPlacement(placement) {
|
|
171
|
-
const aliases = {
|
|
172
|
-
topLeft: "top-start",
|
|
173
|
-
topRight: "top-end",
|
|
174
|
-
bottomLeft: "bottom-start",
|
|
175
|
-
bottomRight: "bottom-end",
|
|
176
|
-
leftTop: "left-start",
|
|
177
|
-
leftBottom: "left-end",
|
|
178
|
-
rightTop: "right-start",
|
|
179
|
-
rightBottom: "right-end"
|
|
180
|
-
};
|
|
181
|
-
return aliases[placement] ?? placement;
|
|
169
|
+
// src/components/FloatingScrollbarProvider.tsx
|
|
170
|
+
var scrollableOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay"]);
|
|
171
|
+
var clippingOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay", "hidden", "clip"]);
|
|
172
|
+
function isRootScroller(target) {
|
|
173
|
+
return target === document.scrollingElement || target === document.documentElement;
|
|
182
174
|
}
|
|
183
|
-
function
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const side = resolvedPlacement.split("-")[0];
|
|
188
|
-
const available = { top: trigger.top, bottom: viewportHeight - trigger.bottom, left: trigger.left, right: viewportWidth - trigger.right };
|
|
189
|
-
const opposite = { top: "bottom", bottom: "top", left: "right", right: "left" };
|
|
190
|
-
const preferred = side;
|
|
191
|
-
const other = opposite[preferred];
|
|
192
|
-
const needed = (side === "top" || side === "bottom" ? overlay.height : overlay.width) + FLOATING_GAP + FLOATING_VIEWPORT_PADDING;
|
|
193
|
-
if (adjust && available[preferred] < needed && available[other] > available[preferred]) {
|
|
194
|
-
resolvedPlacement = resolvedPlacement.replace(preferred, other);
|
|
195
|
-
}
|
|
196
|
-
const vertical = resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom");
|
|
197
|
-
const start = resolvedPlacement.endsWith("-start");
|
|
198
|
-
const end = resolvedPlacement.endsWith("-end");
|
|
199
|
-
let top = vertical ? resolvedPlacement.startsWith("top") ? trigger.top - overlay.height - FLOATING_GAP : trigger.bottom + FLOATING_GAP : start ? trigger.top : end ? trigger.bottom - overlay.height : trigger.top + (trigger.height - overlay.height) / 2;
|
|
200
|
-
let left = vertical ? start ? trigger.left : end ? trigger.right - overlay.width : trigger.left + (trigger.width - overlay.width) / 2 : resolvedPlacement.startsWith("left") ? trigger.left - overlay.width - FLOATING_GAP : trigger.right + FLOATING_GAP;
|
|
201
|
-
if (adjust) {
|
|
202
|
-
if (vertical) left = clampFloating(left, FLOATING_VIEWPORT_PADDING, viewportWidth - overlay.width - FLOATING_VIEWPORT_PADDING);
|
|
203
|
-
else top = clampFloating(top, FLOATING_VIEWPORT_PADDING, viewportHeight - overlay.height - FLOATING_VIEWPORT_PADDING);
|
|
175
|
+
function canScroll(target, axis) {
|
|
176
|
+
if (target.matches(".sia-table__viewport, [data-sia-native-scrollbar]")) return false;
|
|
177
|
+
if (isRootScroller(target)) {
|
|
178
|
+
return axis === "horizontal" ? target.scrollWidth > target.clientWidth + 1 : target.scrollHeight > target.clientHeight + 1;
|
|
204
179
|
}
|
|
205
|
-
const
|
|
206
|
-
const
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
const target = anchorStart + (pointAtCenter || !start && !end ? size / 2 : start ? edge : size - edge);
|
|
210
|
-
if (vertical) result.arrowX = clampFloating(target - left - 4, 8, overlay.width - 16);
|
|
211
|
-
else result.arrowY = clampFloating(target - top - 4, 8, overlay.height - 16);
|
|
212
|
-
return result;
|
|
180
|
+
const style = getComputedStyle(target);
|
|
181
|
+
const overflow = axis === "horizontal" ? style.overflowX : style.overflowY;
|
|
182
|
+
const hasOverflow = axis === "horizontal" ? target.scrollWidth > target.clientWidth + 1 : target.scrollHeight > target.clientHeight + 1;
|
|
183
|
+
return hasOverflow && scrollableOverflow.has(overflow);
|
|
213
184
|
}
|
|
214
|
-
function
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const css = getComputedStyle(parent);
|
|
218
|
-
const bounds = parent.getBoundingClientRect();
|
|
219
|
-
if (/(auto|scroll|hidden|clip)/.test(css.overflowX)) {
|
|
220
|
-
left = Math.max(left, bounds.left);
|
|
221
|
-
right = Math.min(right, bounds.right);
|
|
222
|
-
}
|
|
223
|
-
if (/(auto|scroll|hidden|clip)/.test(css.overflowY)) {
|
|
224
|
-
top = Math.max(top, bounds.top);
|
|
225
|
-
bottom = Math.min(bottom, bounds.bottom);
|
|
226
|
-
}
|
|
185
|
+
function visibleRect(target) {
|
|
186
|
+
if (isRootScroller(target)) {
|
|
187
|
+
return { top: 0, right: window.innerWidth, bottom: window.innerHeight, left: 0, width: window.innerWidth, height: window.innerHeight };
|
|
227
188
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const triggerElementRef = useRef2(null);
|
|
249
|
-
const overlayRef = useRef2(null);
|
|
250
|
-
const enterTimer = useRef2();
|
|
251
|
-
const leaveTimer = useRef2();
|
|
252
|
-
const contentId = useId2();
|
|
253
|
-
const triggers = Array.isArray(trigger) ? trigger : [trigger];
|
|
254
|
-
const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
|
|
255
|
-
const [position, setPosition] = useState();
|
|
256
|
-
const [portalContainer, setPortalContainer] = useState(null);
|
|
257
|
-
useLayoutEffect(() => {
|
|
258
|
-
if (!visible) return;
|
|
259
|
-
setPortalContainer(rootRef.current?.closest(".sia-modal-root, .sia-drawer-root") ?? document.body);
|
|
260
|
-
});
|
|
261
|
-
const setVisibleRef = useRef2(setVisible);
|
|
262
|
-
setVisibleRef.current = setVisible;
|
|
263
|
-
const closeSelfRef = useRef2();
|
|
264
|
-
if (!closeSelfRef.current) closeSelfRef.current = () => setVisibleRef.current(false);
|
|
265
|
-
const exclusiveTooltip = role === "tooltip" && triggers.includes("hover");
|
|
266
|
-
function openNow() {
|
|
267
|
-
if (exclusiveTooltip && activeTooltipClose !== closeSelfRef.current) {
|
|
268
|
-
activeTooltipClose?.();
|
|
269
|
-
activeTooltipClose = closeSelfRef.current;
|
|
189
|
+
const ownRect = target.getBoundingClientRect();
|
|
190
|
+
let top = Math.max(0, ownRect.top);
|
|
191
|
+
let right = Math.min(window.innerWidth, ownRect.right);
|
|
192
|
+
let bottom = Math.min(window.innerHeight, ownRect.bottom);
|
|
193
|
+
let left = Math.max(0, ownRect.left);
|
|
194
|
+
let parent = target.parentElement;
|
|
195
|
+
while (parent && parent !== document.body && parent !== document.documentElement) {
|
|
196
|
+
const style = getComputedStyle(parent);
|
|
197
|
+
const clipX = clippingOverflow.has(style.overflowX);
|
|
198
|
+
const clipY = clippingOverflow.has(style.overflowY);
|
|
199
|
+
if (clipX || clipY) {
|
|
200
|
+
const rect = parent.getBoundingClientRect();
|
|
201
|
+
if (clipX) {
|
|
202
|
+
left = Math.max(left, rect.left);
|
|
203
|
+
right = Math.min(right, rect.right);
|
|
204
|
+
}
|
|
205
|
+
if (clipY) {
|
|
206
|
+
top = Math.max(top, rect.top);
|
|
207
|
+
bottom = Math.min(bottom, rect.bottom);
|
|
208
|
+
}
|
|
270
209
|
}
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
function closeNow() {
|
|
274
|
-
if (activeTooltipClose === closeSelfRef.current) activeTooltipClose = void 0;
|
|
275
|
-
setVisible(false);
|
|
210
|
+
parent = parent.parentElement;
|
|
276
211
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
212
|
+
return {
|
|
213
|
+
top,
|
|
214
|
+
right,
|
|
215
|
+
bottom,
|
|
216
|
+
left,
|
|
217
|
+
width: Math.max(0, right - left),
|
|
218
|
+
height: Math.max(0, bottom - top)
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function createTrack(axis) {
|
|
222
|
+
const track = document.createElement("div");
|
|
223
|
+
const thumb = document.createElement("div");
|
|
224
|
+
track.className = `sia-scrollbar-track sia-floating-scrollbar sia-floating-scrollbar--${axis}`;
|
|
225
|
+
thumb.className = "sia-floating-scrollbar__thumb";
|
|
226
|
+
track.dataset.axis = axis;
|
|
227
|
+
track.setAttribute("aria-hidden", "true");
|
|
228
|
+
track.append(thumb);
|
|
229
|
+
return { track, thumb };
|
|
230
|
+
}
|
|
231
|
+
function FloatingScrollbarProvider({ disabled = false, targetRef }) {
|
|
232
|
+
useScrollbarProximity();
|
|
233
|
+
useEffect3(() => {
|
|
234
|
+
if (disabled) return;
|
|
235
|
+
const layer = document.createElement("div");
|
|
236
|
+
layer.className = "sia-floating-scrollbar-layer";
|
|
237
|
+
layer.setAttribute("aria-hidden", "true");
|
|
238
|
+
document.body.append(layer);
|
|
239
|
+
const entries = /* @__PURE__ */ new Map();
|
|
240
|
+
let scanFrame = 0;
|
|
241
|
+
let updateFrame = 0;
|
|
242
|
+
const setEntryVisible = (entry, visible) => {
|
|
243
|
+
entry.horizontalTrack.classList.toggle("sia-floating-scrollbar--visible", visible);
|
|
244
|
+
entry.verticalTrack.classList.toggle("sia-floating-scrollbar--visible", visible);
|
|
296
245
|
};
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
if (!visible) {
|
|
302
|
-
setPosition(void 0);
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
const getAnchor = () => {
|
|
306
|
-
const root = rootRef.current;
|
|
307
|
-
const target = triggerElementRef.current;
|
|
308
|
-
return target && root?.contains(target) ? target : root?.firstElementChild ?? root;
|
|
246
|
+
const showEntry = (entry) => {
|
|
247
|
+
if (entry.hideTimer !== null) window.clearTimeout(entry.hideTimer);
|
|
248
|
+
entry.hideTimer = null;
|
|
249
|
+
setEntryVisible(entry, true);
|
|
309
250
|
};
|
|
310
|
-
const
|
|
311
|
-
if (
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
251
|
+
const scheduleHide = (entry, delay = 500) => {
|
|
252
|
+
if (entry.hideTimer !== null) window.clearTimeout(entry.hideTimer);
|
|
253
|
+
entry.hideTimer = window.setTimeout(() => {
|
|
254
|
+
entry.hideTimer = null;
|
|
255
|
+
if (!entry.hoveringTarget && !entry.hoveringTrack && !entry.dragging) setEntryVisible(entry, false);
|
|
256
|
+
}, delay);
|
|
257
|
+
};
|
|
258
|
+
const updateEntry = (entry) => {
|
|
259
|
+
const { target, horizontalTrack, horizontalThumb, verticalTrack, verticalThumb } = entry;
|
|
260
|
+
const hasHorizontal = canScroll(target, "horizontal");
|
|
261
|
+
const hasVertical = canScroll(target, "vertical");
|
|
262
|
+
const rect = visibleRect(target);
|
|
263
|
+
const thickness = 10;
|
|
264
|
+
horizontalTrack.hidden = !hasHorizontal || rect.width <= thickness || rect.height <= 0;
|
|
265
|
+
verticalTrack.hidden = !hasVertical || rect.height <= thickness || rect.width <= 0;
|
|
266
|
+
if (!horizontalTrack.hidden) {
|
|
267
|
+
const trackWidth = Math.max(0, rect.width - (hasVertical ? thickness : 0));
|
|
268
|
+
const thumbWidth = Math.max(24, Math.min(trackWidth, trackWidth * target.clientWidth / target.scrollWidth));
|
|
269
|
+
const travel = Math.max(0, trackWidth - thumbWidth);
|
|
270
|
+
const maxScroll = Math.max(1, target.scrollWidth - target.clientWidth);
|
|
271
|
+
horizontalTrack.style.left = `${rect.left}px`;
|
|
272
|
+
horizontalTrack.style.top = `${rect.bottom - thickness}px`;
|
|
273
|
+
horizontalTrack.style.width = `${trackWidth}px`;
|
|
274
|
+
horizontalTrack.style.height = `${thickness}px`;
|
|
275
|
+
horizontalThumb.style.width = `${thumbWidth}px`;
|
|
276
|
+
horizontalThumb.style.transform = `translate3d(${travel * target.scrollLeft / maxScroll}px, 0, 0)`;
|
|
277
|
+
}
|
|
278
|
+
if (!verticalTrack.hidden) {
|
|
279
|
+
const trackHeight = Math.max(0, rect.height - (hasHorizontal ? thickness : 0));
|
|
280
|
+
const thumbHeight = Math.max(24, Math.min(trackHeight, trackHeight * target.clientHeight / target.scrollHeight));
|
|
281
|
+
const travel = Math.max(0, trackHeight - thumbHeight);
|
|
282
|
+
const maxScroll = Math.max(1, target.scrollHeight - target.clientHeight);
|
|
283
|
+
verticalTrack.style.left = `${rect.right - thickness}px`;
|
|
284
|
+
verticalTrack.style.top = `${rect.top}px`;
|
|
285
|
+
verticalTrack.style.width = `${thickness}px`;
|
|
286
|
+
verticalTrack.style.height = `${trackHeight}px`;
|
|
287
|
+
verticalThumb.style.height = `${thumbHeight}px`;
|
|
288
|
+
verticalThumb.style.transform = `translate3d(0, ${travel * target.scrollTop / maxScroll}px, 0)`;
|
|
318
289
|
}
|
|
319
290
|
};
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
if (rootRef.current) observer.observe(rootRef.current);
|
|
327
|
-
const anchor = getAnchor();
|
|
328
|
-
if (anchor) observer.observe(anchor);
|
|
329
|
-
if (overlayRef.current) observer.observe(overlayRef.current);
|
|
330
|
-
return () => {
|
|
331
|
-
window.removeEventListener("resize", update);
|
|
332
|
-
window.removeEventListener("scroll", update, true);
|
|
333
|
-
window.removeEventListener("animationend", update, true);
|
|
334
|
-
window.removeEventListener("transitionend", update, true);
|
|
335
|
-
observer.disconnect();
|
|
291
|
+
const scheduleUpdateAll = () => {
|
|
292
|
+
if (updateFrame) return;
|
|
293
|
+
updateFrame = window.requestAnimationFrame(() => {
|
|
294
|
+
updateFrame = 0;
|
|
295
|
+
entries.forEach(updateEntry);
|
|
296
|
+
});
|
|
336
297
|
};
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
"
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (reverse) values.reverse();
|
|
411
|
-
return /* @__PURE__ */ jsx2("ul", { className: `sia-timeline sia-timeline--${mode} ${className}`.trim(), ...withTitleTooltip(props), children: values.map((item, index) => {
|
|
412
|
-
const position = item.position ?? (mode === "alternate" ? index % 2 ? "right" : "left" : mode);
|
|
413
|
-
return /* @__PURE__ */ jsxs2("li", { className: `sia-timeline__item sia-timeline__item--${position}`, children: [
|
|
414
|
-
item.label ? /* @__PURE__ */ jsx2("span", { className: "sia-timeline__label", children: item.label }) : null,
|
|
415
|
-
/* @__PURE__ */ jsx2("span", { className: "sia-timeline__rail", children: /* @__PURE__ */ jsx2("span", { className: "sia-timeline__dot", style: { color: item.color && !["blue", "red", "green", "gray"].includes(item.color) ? item.color : void 0 }, "data-color": item.color ?? "blue", children: item.dot }) }),
|
|
416
|
-
/* @__PURE__ */ jsx2("span", { className: "sia-timeline__content", children: item.children })
|
|
417
|
-
] }, index);
|
|
418
|
-
}) });
|
|
419
|
-
}
|
|
420
|
-
function collectKeys(nodes, branchOnly = false, result = []) {
|
|
421
|
-
nodes.forEach((node) => {
|
|
422
|
-
if (!branchOnly || node.children?.length) result.push(node.key);
|
|
423
|
-
if (node.children) collectKeys(node.children, branchOnly, result);
|
|
424
|
-
});
|
|
425
|
-
return result;
|
|
426
|
-
}
|
|
427
|
-
function Tree({
|
|
428
|
-
treeData,
|
|
429
|
-
selectedKeys,
|
|
430
|
-
defaultSelectedKeys = [],
|
|
431
|
-
expandedKeys,
|
|
432
|
-
defaultExpandedKeys = [],
|
|
433
|
-
defaultExpandAll = false,
|
|
434
|
-
checkedKeys,
|
|
435
|
-
defaultCheckedKeys = [],
|
|
436
|
-
loadingKeys = [],
|
|
437
|
-
checkable = false,
|
|
438
|
-
checkStrictly = false,
|
|
439
|
-
multiple = false,
|
|
440
|
-
selectable = true,
|
|
441
|
-
showLine = false,
|
|
442
|
-
showIcon = false,
|
|
443
|
-
blockNode = false,
|
|
444
|
-
indentSize = 20,
|
|
445
|
-
switcherWidth = 24,
|
|
446
|
-
stickyAncestors = false,
|
|
447
|
-
stickyRowHeight = 34,
|
|
448
|
-
draggable = false,
|
|
449
|
-
loadData,
|
|
450
|
-
onSelect,
|
|
451
|
-
onCheck,
|
|
452
|
-
onExpand,
|
|
453
|
-
onDrop,
|
|
454
|
-
className = "",
|
|
455
|
-
...props
|
|
456
|
-
}) {
|
|
457
|
-
const [selected, setSelected] = useControllableState({ value: selectedKeys, defaultValue: defaultSelectedKeys });
|
|
458
|
-
const [expanded, setExpanded] = useControllableState({ value: expandedKeys, defaultValue: defaultExpandAll ? collectKeys(treeData, true) : defaultExpandedKeys });
|
|
459
|
-
const [checked, setChecked] = useControllableState({ value: checkedKeys, defaultValue: defaultCheckedKeys });
|
|
460
|
-
const [loading, setLoading] = useState(/* @__PURE__ */ new Set());
|
|
461
|
-
const controlledLoading = useMemo2(() => new Set(loadingKeys), [loadingKeys]);
|
|
462
|
-
const selectedKeySet = useMemo2(() => new Set(selected), [selected]);
|
|
463
|
-
const selectedAncestorKeys = useMemo2(() => {
|
|
464
|
-
const ancestors = /* @__PURE__ */ new Set();
|
|
465
|
-
const visit = (nodes, parentKeys) => {
|
|
466
|
-
nodes.forEach((node) => {
|
|
467
|
-
if (selectedKeySet.has(node.key)) parentKeys.forEach((key) => ancestors.add(key));
|
|
468
|
-
if (node.children?.length) visit(node.children, [...parentKeys, node.key]);
|
|
298
|
+
const bindTrackDrag = (entry, axis, track, thumb) => {
|
|
299
|
+
const target = entry.target;
|
|
300
|
+
const onTrackPointerEnter = () => {
|
|
301
|
+
entry.hoveringTrack = true;
|
|
302
|
+
showEntry(entry);
|
|
303
|
+
};
|
|
304
|
+
const onTrackPointerLeave = () => {
|
|
305
|
+
entry.hoveringTrack = false;
|
|
306
|
+
scheduleHide(entry);
|
|
307
|
+
};
|
|
308
|
+
const onTrackPointerDown = (event) => {
|
|
309
|
+
if (event.target === thumb || event.button !== 0) return;
|
|
310
|
+
event.preventDefault();
|
|
311
|
+
event.stopPropagation();
|
|
312
|
+
const trackRect = track.getBoundingClientRect();
|
|
313
|
+
const thumbRect = thumb.getBoundingClientRect();
|
|
314
|
+
const trackLength = axis === "vertical" ? trackRect.height : trackRect.width;
|
|
315
|
+
const thumbLength = axis === "vertical" ? thumbRect.height : thumbRect.width;
|
|
316
|
+
const pointer = axis === "vertical" ? event.clientY - trackRect.top : event.clientX - trackRect.left;
|
|
317
|
+
const ratio = Math.max(0, Math.min(1, (pointer - thumbLength / 2) / Math.max(1, trackLength - thumbLength)));
|
|
318
|
+
if (axis === "vertical") target.scrollTop = ratio * (target.scrollHeight - target.clientHeight);
|
|
319
|
+
else target.scrollLeft = ratio * (target.scrollWidth - target.clientWidth);
|
|
320
|
+
};
|
|
321
|
+
const onThumbPointerDown = (event) => {
|
|
322
|
+
if (event.button !== 0) return;
|
|
323
|
+
event.preventDefault();
|
|
324
|
+
event.stopPropagation();
|
|
325
|
+
entry.dragging = true;
|
|
326
|
+
showEntry(entry);
|
|
327
|
+
thumb.setPointerCapture(event.pointerId);
|
|
328
|
+
const startPointer = axis === "vertical" ? event.clientY : event.clientX;
|
|
329
|
+
const startScroll = axis === "vertical" ? target.scrollTop : target.scrollLeft;
|
|
330
|
+
const trackRect = track.getBoundingClientRect();
|
|
331
|
+
const thumbRect = thumb.getBoundingClientRect();
|
|
332
|
+
const trackLength = axis === "vertical" ? trackRect.height : trackRect.width;
|
|
333
|
+
const thumbLength = axis === "vertical" ? thumbRect.height : thumbRect.width;
|
|
334
|
+
const maxScroll = axis === "vertical" ? target.scrollHeight - target.clientHeight : target.scrollWidth - target.clientWidth;
|
|
335
|
+
const travel = Math.max(1, trackLength - thumbLength);
|
|
336
|
+
const onPointerMove = (moveEvent) => {
|
|
337
|
+
if (moveEvent.pointerId !== event.pointerId) return;
|
|
338
|
+
const pointer = axis === "vertical" ? moveEvent.clientY : moveEvent.clientX;
|
|
339
|
+
const nextScroll = startScroll + (pointer - startPointer) * maxScroll / travel;
|
|
340
|
+
if (axis === "vertical") target.scrollTop = nextScroll;
|
|
341
|
+
else target.scrollLeft = nextScroll;
|
|
342
|
+
};
|
|
343
|
+
const onPointerUp = (upEvent) => {
|
|
344
|
+
if (upEvent.pointerId !== event.pointerId) return;
|
|
345
|
+
entry.dragging = false;
|
|
346
|
+
thumb.releasePointerCapture(event.pointerId);
|
|
347
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
348
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
349
|
+
window.removeEventListener("pointercancel", onPointerUp);
|
|
350
|
+
scheduleHide(entry);
|
|
351
|
+
};
|
|
352
|
+
window.addEventListener("pointermove", onPointerMove);
|
|
353
|
+
window.addEventListener("pointerup", onPointerUp);
|
|
354
|
+
window.addEventListener("pointercancel", onPointerUp);
|
|
355
|
+
};
|
|
356
|
+
track.addEventListener("pointerenter", onTrackPointerEnter);
|
|
357
|
+
track.addEventListener("pointerleave", onTrackPointerLeave);
|
|
358
|
+
track.addEventListener("pointerdown", onTrackPointerDown);
|
|
359
|
+
thumb.addEventListener("pointerdown", onThumbPointerDown);
|
|
360
|
+
return () => {
|
|
361
|
+
track.removeEventListener("pointerenter", onTrackPointerEnter);
|
|
362
|
+
track.removeEventListener("pointerleave", onTrackPointerLeave);
|
|
363
|
+
track.removeEventListener("pointerdown", onTrackPointerDown);
|
|
364
|
+
thumb.removeEventListener("pointerdown", onThumbPointerDown);
|
|
365
|
+
};
|
|
366
|
+
};
|
|
367
|
+
const resizeObserver = new ResizeObserver((observedEntries) => {
|
|
368
|
+
observedEntries.forEach(({ target }) => {
|
|
369
|
+
const entry = entries.get(target);
|
|
370
|
+
if (entry) updateEntry(entry);
|
|
469
371
|
});
|
|
372
|
+
});
|
|
373
|
+
const addTarget = (target) => {
|
|
374
|
+
if (entries.has(target)) return;
|
|
375
|
+
const horizontal = createTrack("horizontal");
|
|
376
|
+
const vertical = createTrack("vertical");
|
|
377
|
+
layer.append(horizontal.track, vertical.track);
|
|
378
|
+
const onPointerEnter = () => {
|
|
379
|
+
const entry2 = entries.get(target);
|
|
380
|
+
if (!entry2) return;
|
|
381
|
+
entry2.hoveringTarget = true;
|
|
382
|
+
showEntry(entry2);
|
|
383
|
+
};
|
|
384
|
+
const onPointerLeave = () => {
|
|
385
|
+
const entry2 = entries.get(target);
|
|
386
|
+
if (!entry2) return;
|
|
387
|
+
entry2.hoveringTarget = false;
|
|
388
|
+
scheduleHide(entry2);
|
|
389
|
+
};
|
|
390
|
+
const onScroll = () => {
|
|
391
|
+
const entry2 = entries.get(target);
|
|
392
|
+
if (!entry2) return;
|
|
393
|
+
updateEntry(entry2);
|
|
394
|
+
showEntry(entry2);
|
|
395
|
+
scheduleHide(entry2, 700);
|
|
396
|
+
};
|
|
397
|
+
target.addEventListener("pointerenter", onPointerEnter);
|
|
398
|
+
target.addEventListener("pointerleave", onPointerLeave);
|
|
399
|
+
target.addEventListener("scroll", onScroll, { passive: true });
|
|
400
|
+
const entry = {
|
|
401
|
+
target,
|
|
402
|
+
horizontalTrack: horizontal.track,
|
|
403
|
+
horizontalThumb: horizontal.thumb,
|
|
404
|
+
verticalTrack: vertical.track,
|
|
405
|
+
verticalThumb: vertical.thumb,
|
|
406
|
+
hideTimer: null,
|
|
407
|
+
hoveringTarget: target.matches(":hover"),
|
|
408
|
+
hoveringTrack: false,
|
|
409
|
+
dragging: false,
|
|
410
|
+
cleanup: () => void 0
|
|
411
|
+
};
|
|
412
|
+
const cleanupHorizontal = bindTrackDrag(entry, "horizontal", horizontal.track, horizontal.thumb);
|
|
413
|
+
const cleanupVertical = bindTrackDrag(entry, "vertical", vertical.track, vertical.thumb);
|
|
414
|
+
entry.cleanup = () => {
|
|
415
|
+
if (entry.hideTimer !== null) window.clearTimeout(entry.hideTimer);
|
|
416
|
+
cleanupHorizontal();
|
|
417
|
+
cleanupVertical();
|
|
418
|
+
target.removeEventListener("pointerenter", onPointerEnter);
|
|
419
|
+
target.removeEventListener("pointerleave", onPointerLeave);
|
|
420
|
+
target.removeEventListener("scroll", onScroll);
|
|
421
|
+
resizeObserver.unobserve(target);
|
|
422
|
+
target.removeAttribute("data-sia-floating-scrollbar");
|
|
423
|
+
horizontal.track.remove();
|
|
424
|
+
vertical.track.remove();
|
|
425
|
+
};
|
|
426
|
+
entries.set(target, entry);
|
|
427
|
+
target.setAttribute("data-sia-floating-scrollbar", "");
|
|
428
|
+
resizeObserver.observe(target);
|
|
429
|
+
updateEntry(entry);
|
|
430
|
+
if (entry.hoveringTarget) showEntry(entry);
|
|
470
431
|
};
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
await loadData(node);
|
|
485
|
-
} finally {
|
|
486
|
-
setLoading((keys) => {
|
|
487
|
-
const next2 = new Set(keys);
|
|
488
|
-
next2.delete(node.key);
|
|
489
|
-
return next2;
|
|
432
|
+
const removeTarget = (target) => {
|
|
433
|
+
const entry = entries.get(target);
|
|
434
|
+
if (!entry) return;
|
|
435
|
+
entry.cleanup();
|
|
436
|
+
entries.delete(target);
|
|
437
|
+
};
|
|
438
|
+
const scanTargets = () => {
|
|
439
|
+
scanFrame = 0;
|
|
440
|
+
const managedSelector = ".sia-table__viewport, [data-sia-native-scrollbar], .sia-scrollbar-track, .sia-floating-scrollbar-layer";
|
|
441
|
+
const discovered = [];
|
|
442
|
+
if (!targetRef) {
|
|
443
|
+
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, {
|
|
444
|
+
acceptNode: (node) => node.matches(managedSelector) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT
|
|
490
445
|
});
|
|
446
|
+
for (let node = walker.nextNode(); node; node = walker.nextNode()) {
|
|
447
|
+
if (node instanceof HTMLElement) discovered.push(node);
|
|
448
|
+
}
|
|
491
449
|
}
|
|
450
|
+
const candidates = (targetRef ? [targetRef.current] : [document.scrollingElement, ...discovered]).filter((target) => target instanceof HTMLElement);
|
|
451
|
+
const nextTargets = /* @__PURE__ */ new Set();
|
|
452
|
+
candidates.forEach((target) => {
|
|
453
|
+
if (canScroll(target, "horizontal") || canScroll(target, "vertical")) {
|
|
454
|
+
nextTargets.add(target);
|
|
455
|
+
if (entries.has(target) || !target.hasAttribute("data-sia-floating-scrollbar")) addTarget(target);
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
entries.forEach((_entry, target) => {
|
|
459
|
+
if (!target.isConnected || !nextTargets.has(target)) removeTarget(target);
|
|
460
|
+
else updateEntry(_entry);
|
|
461
|
+
});
|
|
462
|
+
};
|
|
463
|
+
const scheduleScan = () => {
|
|
464
|
+
if (scanFrame) return;
|
|
465
|
+
scanFrame = window.requestAnimationFrame(scanTargets);
|
|
466
|
+
};
|
|
467
|
+
const mutationObserver = new MutationObserver((mutations) => {
|
|
468
|
+
if (mutations.some((mutation) => {
|
|
469
|
+
const target = mutation.target instanceof Element ? mutation.target : mutation.target.parentElement;
|
|
470
|
+
return target && !layer.contains(target) && !target.closest(".sia-table__viewport, [data-sia-native-scrollbar], .sia-scrollbar-track");
|
|
471
|
+
})) scheduleScan();
|
|
472
|
+
});
|
|
473
|
+
mutationObserver.observe(document.documentElement, { subtree: true, childList: true, attributes: true, attributeFilter: ["class", "style", "hidden"] });
|
|
474
|
+
window.addEventListener("resize", scheduleScan);
|
|
475
|
+
window.addEventListener("scroll", scheduleUpdateAll, true);
|
|
476
|
+
scheduleScan();
|
|
477
|
+
return () => {
|
|
478
|
+
mutationObserver.disconnect();
|
|
479
|
+
resizeObserver.disconnect();
|
|
480
|
+
window.removeEventListener("resize", scheduleScan);
|
|
481
|
+
window.removeEventListener("scroll", scheduleUpdateAll, true);
|
|
482
|
+
if (scanFrame) window.cancelAnimationFrame(scanFrame);
|
|
483
|
+
if (updateFrame) window.cancelAnimationFrame(updateFrame);
|
|
484
|
+
entries.forEach((entry) => entry.cleanup());
|
|
485
|
+
entries.clear();
|
|
486
|
+
layer.remove();
|
|
487
|
+
};
|
|
488
|
+
}, [disabled, targetRef]);
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/components/treeCheckState.ts
|
|
493
|
+
function affectedKeys(node) {
|
|
494
|
+
if (node.disabled || node.disableCheckbox) return [];
|
|
495
|
+
return [...node.checkable === false ? [] : [node.key], ...node.children?.flatMap(affectedKeys) ?? []];
|
|
496
|
+
}
|
|
497
|
+
function getTreeCheckState(nodes, keys, strictly = false) {
|
|
498
|
+
const checked = new Set(keys);
|
|
499
|
+
const halfChecked = /* @__PURE__ */ new Set();
|
|
500
|
+
if (strictly) return { checked, halfChecked };
|
|
501
|
+
const explicit = new Set(keys);
|
|
502
|
+
function expand(items) {
|
|
503
|
+
for (const node of items) {
|
|
504
|
+
if (explicit.has(node.key)) affectedKeys(node).forEach((key) => checked.add(key));
|
|
505
|
+
if (node.children) expand(node.children);
|
|
492
506
|
}
|
|
493
|
-
const next = nextExpanded ? [...expanded, node.key] : expanded.filter((key) => key !== node.key);
|
|
494
|
-
setExpanded(next);
|
|
495
|
-
onExpand?.([...next], { expanded: nextExpanded, node });
|
|
496
507
|
}
|
|
497
|
-
|
|
498
|
-
function
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
|
|
508
|
+
expand(nodes);
|
|
509
|
+
function fold(node) {
|
|
510
|
+
const children = node.children?.map(fold).filter((value) => value !== void 0) ?? [];
|
|
511
|
+
if (node.disabled || node.disableCheckbox) return void 0;
|
|
512
|
+
if (!children.length) return { checked: checked.has(node.key), partial: false };
|
|
513
|
+
const all = children.every((child) => child.checked);
|
|
514
|
+
const some = children.some((child) => child.checked || child.partial);
|
|
515
|
+
if (node.checkable !== false) {
|
|
516
|
+
if (all) checked.add(node.key);
|
|
517
|
+
else checked.delete(node.key);
|
|
518
|
+
if (!all && some) halfChecked.add(node.key);
|
|
519
|
+
}
|
|
520
|
+
return { checked: all, partial: !all && some };
|
|
502
521
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
}
|
|
522
|
-
return void 0;
|
|
523
|
-
}
|
|
524
|
-
function getPointerDropTarget(clientX, clientY, dragNode) {
|
|
525
|
-
const targetElement = document.elementFromPoint(clientX, clientY)?.closest("[data-sia-tree-drop-key]");
|
|
526
|
-
if (!targetElement) return void 0;
|
|
527
|
-
const targetNode = targetElement?.dataset.siaTreeDropKey ? findNode(targetElement.dataset.siaTreeDropKey) : void 0;
|
|
528
|
-
if (!targetNode || targetNode.key === dragNode.key || targetNode.disabled || targetNode.droppable === false) return void 0;
|
|
529
|
-
const bounds = targetElement.getBoundingClientRect();
|
|
530
|
-
const relativeY = bounds.height > 0 ? (clientY - bounds.top) / bounds.height : 0.5;
|
|
531
|
-
const dropPosition = relativeY < 0.25 ? "before" : relativeY > 0.75 ? "after" : "inside";
|
|
532
|
-
return { node: targetNode, dropPosition };
|
|
533
|
-
}
|
|
534
|
-
function beginPointerDrag(node, event) {
|
|
535
|
-
if (event.button !== 0) return;
|
|
536
|
-
pointerDragRef.current = {
|
|
537
|
-
node,
|
|
538
|
-
pointerId: event.pointerId,
|
|
539
|
-
startX: event.clientX,
|
|
540
|
-
startY: event.clientY,
|
|
541
|
-
active: false
|
|
522
|
+
nodes.forEach(fold);
|
|
523
|
+
return { checked, halfChecked };
|
|
524
|
+
}
|
|
525
|
+
function toggleTreeCheck(nodes, keys, node, strictly = false) {
|
|
526
|
+
const state = getTreeCheckState(nodes, keys, strictly);
|
|
527
|
+
const next = new Set(state.checked);
|
|
528
|
+
const checked = !next.has(node.key);
|
|
529
|
+
if (node.disabled || node.disableCheckbox || node.checkable === false) return { ...state, checkedValue: !checked };
|
|
530
|
+
(strictly ? [node.key] : affectedKeys(node)).forEach((key) => checked ? next.add(key) : next.delete(key));
|
|
531
|
+
if (!strictly && !checked) {
|
|
532
|
+
let removeParents2 = function(items) {
|
|
533
|
+
let found = false;
|
|
534
|
+
for (const item of items) {
|
|
535
|
+
const childFound = item.children ? removeParents2(item.children) : false;
|
|
536
|
+
if (childFound) next.delete(item.key);
|
|
537
|
+
if (item.key === node.key || childFound) found = true;
|
|
538
|
+
}
|
|
539
|
+
return found;
|
|
542
540
|
};
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
function movePointerDrag(event) {
|
|
546
|
-
const pointerDrag = pointerDragRef.current;
|
|
547
|
-
if (!pointerDrag || pointerDrag.pointerId !== event.pointerId) return;
|
|
548
|
-
if (!pointerDrag.active && Math.hypot(event.clientX - pointerDrag.startX, event.clientY - pointerDrag.startY) < 5) return;
|
|
549
|
-
pointerDrag.active = true;
|
|
550
|
-
dragNodeRef.current = pointerDrag.node;
|
|
551
|
-
event.preventDefault();
|
|
552
|
-
const target = getPointerDropTarget(event.clientX, event.clientY, pointerDrag.node);
|
|
553
|
-
setDragOver(target ? { key: target.node.key, position: target.dropPosition } : void 0);
|
|
554
|
-
}
|
|
555
|
-
function finishPointerDrag(event) {
|
|
556
|
-
const pointerDrag = pointerDragRef.current;
|
|
557
|
-
if (!pointerDrag || pointerDrag.pointerId !== event.pointerId) return;
|
|
558
|
-
if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
|
|
559
|
-
if (pointerDrag.active) {
|
|
560
|
-
event.preventDefault();
|
|
561
|
-
suppressClickRef.current = true;
|
|
562
|
-
const target = getPointerDropTarget(event.clientX, event.clientY, pointerDrag.node);
|
|
563
|
-
if (target) onDrop?.({ dragNode: pointerDrag.node, node: target.node, dropPosition: target.dropPosition });
|
|
564
|
-
window.setTimeout(() => {
|
|
565
|
-
suppressClickRef.current = false;
|
|
566
|
-
}, 0);
|
|
567
|
-
}
|
|
568
|
-
pointerDragRef.current = void 0;
|
|
569
|
-
dragNodeRef.current = void 0;
|
|
570
|
-
setDragOver(void 0);
|
|
571
|
-
}
|
|
572
|
-
function cancelPointerDrag(event) {
|
|
573
|
-
const pointerDrag = pointerDragRef.current;
|
|
574
|
-
if (!pointerDrag || pointerDrag.pointerId !== event.pointerId) return;
|
|
575
|
-
pointerDragRef.current = void 0;
|
|
576
|
-
dragNodeRef.current = void 0;
|
|
577
|
-
setDragOver(void 0);
|
|
578
|
-
}
|
|
579
|
-
function render(nodes, depth = 0) {
|
|
580
|
-
return nodes.map((node) => {
|
|
581
|
-
const open = expanded.includes(node.key);
|
|
582
|
-
const isSelected = selected.includes(node.key);
|
|
583
|
-
const isSelectedAncestor = selectedAncestorKeys.has(node.key);
|
|
584
|
-
const isChecked = checkState.checked.has(node.key);
|
|
585
|
-
const isHalfChecked = checkState.halfChecked.has(node.key);
|
|
586
|
-
const hasChildren = Boolean(node.children?.length || node.isLeaf === false);
|
|
587
|
-
const nodeLoading = loading.has(node.key) || controlledLoading.has(node.key);
|
|
588
|
-
const sticky = stickyAncestors && hasChildren && open;
|
|
589
|
-
const canDrag = draggable && node.draggable !== false && !node.disabled;
|
|
590
|
-
const { className: rowClassName = "", style: rowStyle, onClick: onRowClick, ...rowProps } = node.rowProps ?? {};
|
|
591
|
-
const unloaded = hasChildren && node.loaded === false;
|
|
592
|
-
const dropPosition = dragOver?.key === node.key ? dragOver.position : void 0;
|
|
593
|
-
return /* @__PURE__ */ jsxs2("div", { className: `sia-tree__node${isSelected ? " is-selected" : ""}${isSelectedAncestor ? " is-selected-ancestor" : ""}${dropPosition ? ` is-drag-over-${dropPosition}` : ""}${node.disabled ? " is-disabled" : ""}${unloaded ? " is-unloaded" : ""}`, role: "treeitem", "aria-expanded": hasChildren ? open : void 0, "aria-selected": isSelected, children: [
|
|
594
|
-
/* @__PURE__ */ jsx2(
|
|
595
|
-
"div",
|
|
596
|
-
{
|
|
597
|
-
...withTitleTooltip(rowProps),
|
|
598
|
-
className: `sia-tree__row${blockNode ? " sia-tree__row--block" : ""}${sticky ? " sia-tree__row--sticky" : ""} ${rowClassName}`.trim(),
|
|
599
|
-
style: {
|
|
600
|
-
...rowStyle,
|
|
601
|
-
paddingInlineStart: depth * Math.max(0, indentSize),
|
|
602
|
-
top: sticky ? depth * Math.max(1, stickyRowHeight) : rowStyle?.top,
|
|
603
|
-
zIndex: sticky ? Math.max(1, 100 - depth) : rowStyle?.zIndex
|
|
604
|
-
},
|
|
605
|
-
"aria-busy": nodeLoading || void 0,
|
|
606
|
-
"data-sia-tree-drop-key": String(node.key),
|
|
607
|
-
"data-sia-tree-draggable": canDrag || void 0,
|
|
608
|
-
onClick: (event) => {
|
|
609
|
-
onRowClick?.(event);
|
|
610
|
-
if (event.defaultPrevented || suppressClickRef.current || node.disabled) return;
|
|
611
|
-
select(node, event);
|
|
612
|
-
if (hasChildren) void toggleExpand(node);
|
|
613
|
-
},
|
|
614
|
-
children: (() => {
|
|
615
|
-
const content = /* @__PURE__ */ jsxs2("span", { className: "sia-tree__context-content", children: [
|
|
616
|
-
hasChildren ? /* @__PURE__ */ jsx2("button", { type: "button", className: "sia-tree__switcher", "aria-label": open ? "\u6536\u8D77\u8282\u70B9" : "\u5C55\u5F00\u8282\u70B9", "aria-expanded": open, style: { width: normalizedSwitcherWidth, flexBasis: normalizedSwitcherWidth }, disabled: node.disabled, onClick: (event) => {
|
|
617
|
-
event.stopPropagation();
|
|
618
|
-
void toggleExpand(node);
|
|
619
|
-
}, children: nodeLoading ? /* @__PURE__ */ jsx2(Icon, { name: "loader", className: "sia-spin-icon", size: 13 }) : /* @__PURE__ */ jsx2(Icon, { name: open ? "chevron-down" : "chevron-right", size: 13 }) }) : /* @__PURE__ */ jsx2("span", { className: "sia-tree__switcher", "aria-label": open ? "\u6536\u8D77\u8282\u70B9" : "\u5C55\u5F00\u8282\u70B9", "aria-expanded": open, style: { width: normalizedSwitcherWidth, flexBasis: normalizedSwitcherWidth }, "aria-hidden": "true" }),
|
|
620
|
-
checkable || node.checkable ? /* @__PURE__ */ jsx2("span", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx2(Checkbox2, { checked: isChecked, indeterminate: isHalfChecked, disabled: node.disabled || node.disableCheckbox, onChange: () => check(node) }) }) : null,
|
|
621
|
-
node.prefix ? /* @__PURE__ */ jsx2("span", { className: "sia-tree__prefix", onClick: (event) => event.stopPropagation(), children: node.prefix }) : null,
|
|
622
|
-
showIcon ? /* @__PURE__ */ jsx2("span", { className: "sia-tree__icon", children: node.icon ?? /* @__PURE__ */ jsx2(Icon, { name: hasChildren ? "folder" : "file", size: 15 }) }) : null,
|
|
623
|
-
/* @__PURE__ */ jsx2(
|
|
624
|
-
"button",
|
|
625
|
-
{
|
|
626
|
-
type: "button",
|
|
627
|
-
className: "sia-tree__title",
|
|
628
|
-
disabled: node.disabled,
|
|
629
|
-
onPointerDown: canDrag ? (event) => beginPointerDrag(node, event) : void 0,
|
|
630
|
-
onPointerMove: canDrag ? movePointerDrag : void 0,
|
|
631
|
-
onPointerUp: canDrag ? finishPointerDrag : void 0,
|
|
632
|
-
onPointerCancel: canDrag ? cancelPointerDrag : void 0,
|
|
633
|
-
children: node.title
|
|
634
|
-
}
|
|
635
|
-
),
|
|
636
|
-
nodeLoading ? /* @__PURE__ */ jsx2("span", { className: "sia-tree__loading-text", role: "status", children: node.loadingText ?? "\u6B63\u5728\u52A0\u8F7D\u2026" }) : null,
|
|
637
|
-
node.extra ? /* @__PURE__ */ jsx2("span", { className: "sia-tree__extra", onClick: (event) => event.stopPropagation(), children: node.extra }) : null
|
|
638
|
-
] });
|
|
639
|
-
return node.contextMenu ? /* @__PURE__ */ jsx2(
|
|
640
|
-
Dropdown,
|
|
641
|
-
{
|
|
642
|
-
className: "sia-tree__context-trigger",
|
|
643
|
-
popupClassName: node.contextMenuPopupClassName,
|
|
644
|
-
trigger: ["contextMenu"],
|
|
645
|
-
menu: node.contextMenu,
|
|
646
|
-
onContextMenu: (event) => selectForContextMenu(node, event),
|
|
647
|
-
children: content
|
|
648
|
-
}
|
|
649
|
-
) : content;
|
|
650
|
-
})()
|
|
651
|
-
}
|
|
652
|
-
),
|
|
653
|
-
open && node.children?.length ? /* @__PURE__ */ jsx2("div", { className: "sia-tree__children", role: "group", children: render(node.children, depth + 1) }) : null
|
|
654
|
-
] }, node.key);
|
|
655
|
-
});
|
|
541
|
+
var removeParents = removeParents2;
|
|
542
|
+
removeParents2(nodes);
|
|
656
543
|
}
|
|
657
|
-
return
|
|
544
|
+
return { ...getTreeCheckState(nodes, [...next], strictly), checkedValue: checked };
|
|
658
545
|
}
|
|
659
546
|
|
|
660
|
-
// src/components/
|
|
661
|
-
import {
|
|
662
|
-
import {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
var
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
547
|
+
// src/components/FloatingDisplay.tsx
|
|
548
|
+
import { cloneElement, useEffect as useEffect4, useId as useId2, useLayoutEffect, useMemo as useMemo2, useRef as useRef2, useState } from "react";
|
|
549
|
+
import { createPortal } from "react-dom";
|
|
550
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
551
|
+
var FLOATING_GAP = 9;
|
|
552
|
+
var FLOATING_VIEWPORT_PADDING = 8;
|
|
553
|
+
var FLOATING_ARROW_EDGE_OFFSET = 16;
|
|
554
|
+
var activeTooltipClose;
|
|
555
|
+
function clampFloating(value, min, max) {
|
|
556
|
+
return Math.min(Math.max(value, min), Math.max(min, max));
|
|
557
|
+
}
|
|
558
|
+
function normalizeFloatingPlacement(placement) {
|
|
559
|
+
const aliases = {
|
|
560
|
+
topLeft: "top-start",
|
|
561
|
+
topRight: "top-end",
|
|
562
|
+
bottomLeft: "bottom-start",
|
|
563
|
+
bottomRight: "bottom-end",
|
|
564
|
+
leftTop: "left-start",
|
|
565
|
+
leftBottom: "left-end",
|
|
566
|
+
rightTop: "right-start",
|
|
567
|
+
rightBottom: "right-end"
|
|
679
568
|
};
|
|
569
|
+
return aliases[placement] ?? placement;
|
|
680
570
|
}
|
|
681
|
-
function
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
571
|
+
function resolveFloatingPosition(trigger, overlay, placement, pointAtCenter, adjust) {
|
|
572
|
+
const viewportWidth = document.documentElement.clientWidth;
|
|
573
|
+
const viewportHeight = document.documentElement.clientHeight;
|
|
574
|
+
let resolvedPlacement = normalizeFloatingPlacement(placement);
|
|
575
|
+
const side = resolvedPlacement.split("-")[0];
|
|
576
|
+
const available = { top: trigger.top, bottom: viewportHeight - trigger.bottom, left: trigger.left, right: viewportWidth - trigger.right };
|
|
577
|
+
const opposite = { top: "bottom", bottom: "top", left: "right", right: "left" };
|
|
578
|
+
const preferred = side;
|
|
579
|
+
const other = opposite[preferred];
|
|
580
|
+
const needed = (side === "top" || side === "bottom" ? overlay.height : overlay.width) + FLOATING_GAP + FLOATING_VIEWPORT_PADDING;
|
|
581
|
+
if (adjust && available[preferred] < needed && available[other] > available[preferred]) {
|
|
582
|
+
resolvedPlacement = resolvedPlacement.replace(preferred, other);
|
|
583
|
+
}
|
|
584
|
+
const vertical = resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom");
|
|
585
|
+
const start = resolvedPlacement.endsWith("-start");
|
|
586
|
+
const end = resolvedPlacement.endsWith("-end");
|
|
587
|
+
let top = vertical ? resolvedPlacement.startsWith("top") ? trigger.top - overlay.height - FLOATING_GAP : trigger.bottom + FLOATING_GAP : start ? trigger.top : end ? trigger.bottom - overlay.height : trigger.top + (trigger.height - overlay.height) / 2;
|
|
588
|
+
let left = vertical ? start ? trigger.left : end ? trigger.right - overlay.width : trigger.left + (trigger.width - overlay.width) / 2 : resolvedPlacement.startsWith("left") ? trigger.left - overlay.width - FLOATING_GAP : trigger.right + FLOATING_GAP;
|
|
589
|
+
if (adjust) {
|
|
590
|
+
if (vertical) left = clampFloating(left, FLOATING_VIEWPORT_PADDING, viewportWidth - overlay.width - FLOATING_VIEWPORT_PADDING);
|
|
591
|
+
else top = clampFloating(top, FLOATING_VIEWPORT_PADDING, viewportHeight - overlay.height - FLOATING_VIEWPORT_PADDING);
|
|
592
|
+
}
|
|
593
|
+
const result = { top, left, placement: resolvedPlacement };
|
|
594
|
+
const size = vertical ? trigger.width : trigger.height;
|
|
595
|
+
const anchorStart = vertical ? trigger.left : trigger.top;
|
|
596
|
+
const edge = Math.min(size / 2, FLOATING_ARROW_EDGE_OFFSET + 4);
|
|
597
|
+
const target = anchorStart + (pointAtCenter || !start && !end ? size / 2 : start ? edge : size - edge);
|
|
598
|
+
if (vertical) result.arrowX = clampFloating(target - left - 4, 8, overlay.width - 16);
|
|
599
|
+
else result.arrowY = clampFloating(target - top - 4, 8, overlay.height - 16);
|
|
600
|
+
return result;
|
|
685
601
|
}
|
|
686
|
-
function
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
if (
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
overlayStack.push(overlayId);
|
|
695
|
-
const unlockBody = lockBodyScroll();
|
|
696
|
-
const focusTimer = window.setTimeout(() => {
|
|
697
|
-
const panel = panelRef.current;
|
|
698
|
-
if (!panel) return;
|
|
699
|
-
const [firstFocusable] = focusableElements(panel);
|
|
700
|
-
(firstFocusable ?? panel).focus({ preventScroll: true });
|
|
701
|
-
}, 0);
|
|
702
|
-
function handleKeyDown(event) {
|
|
703
|
-
if (overlayStack.at(-1) !== overlayId) return;
|
|
704
|
-
if (event.key === "Escape" && keyboard) {
|
|
705
|
-
event.preventDefault();
|
|
706
|
-
closeRef.current();
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
if (event.key !== "Tab" || !panelRef.current) return;
|
|
710
|
-
const focusable = focusableElements(panelRef.current);
|
|
711
|
-
if (focusable.length === 0) {
|
|
712
|
-
event.preventDefault();
|
|
713
|
-
panelRef.current.focus();
|
|
714
|
-
return;
|
|
715
|
-
}
|
|
716
|
-
const first = focusable[0];
|
|
717
|
-
const last = focusable.at(-1);
|
|
718
|
-
if (event.shiftKey && document.activeElement === first) {
|
|
719
|
-
event.preventDefault();
|
|
720
|
-
last.focus();
|
|
721
|
-
} else if (!event.shiftKey && document.activeElement === last) {
|
|
722
|
-
event.preventDefault();
|
|
723
|
-
first.focus();
|
|
724
|
-
}
|
|
602
|
+
function isFloatingAnchorHidden(anchor, rect) {
|
|
603
|
+
let left = 0, top = 0, right = document.documentElement.clientWidth, bottom = document.documentElement.clientHeight;
|
|
604
|
+
for (let parent = anchor.parentElement; parent; parent = parent.parentElement) {
|
|
605
|
+
const css = getComputedStyle(parent);
|
|
606
|
+
const bounds = parent.getBoundingClientRect();
|
|
607
|
+
if (/(auto|scroll|hidden|clip)/.test(css.overflowX)) {
|
|
608
|
+
left = Math.max(left, bounds.left);
|
|
609
|
+
right = Math.min(right, bounds.right);
|
|
725
610
|
}
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
unlockBody();
|
|
733
|
-
previouslyFocused?.focus({ preventScroll: true });
|
|
734
|
-
};
|
|
735
|
-
}, [keyboard, open, panelRef]);
|
|
736
|
-
}
|
|
737
|
-
function OverlayPortal({ children, container }) {
|
|
738
|
-
if (typeof document === "undefined") return null;
|
|
739
|
-
const target = typeof container === "function" ? container() : container ?? document.body;
|
|
740
|
-
return createPortal2(children, target);
|
|
611
|
+
if (/(auto|scroll|hidden|clip)/.test(css.overflowY)) {
|
|
612
|
+
top = Math.max(top, bounds.top);
|
|
613
|
+
bottom = Math.min(bottom, bounds.bottom);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
return rect.right <= left || rect.left >= right || rect.bottom <= top || rect.top >= bottom;
|
|
741
617
|
}
|
|
742
|
-
|
|
743
|
-
// src/components/Modal.tsx
|
|
744
|
-
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
745
|
-
var modalHandles = /* @__PURE__ */ new Set();
|
|
746
|
-
var MODAL_MOTION_DURATION = 220;
|
|
747
|
-
var typeIcons = {
|
|
748
|
-
info: /* @__PURE__ */ jsx3(Icon, { name: "info", size: 23 }),
|
|
749
|
-
success: /* @__PURE__ */ jsx3(Icon, { name: "circle-check", size: 23 }),
|
|
750
|
-
warning: /* @__PURE__ */ jsx3(Icon, { name: "warning", size: 23 }),
|
|
751
|
-
error: /* @__PURE__ */ jsx3(Icon, { name: "circle-close", size: 23 }),
|
|
752
|
-
confirm: /* @__PURE__ */ jsx3(Icon, { name: "question", size: 23 })
|
|
753
|
-
};
|
|
754
|
-
var ModalRoot = forwardRef2(function Modal({
|
|
755
|
-
open,
|
|
756
|
-
title,
|
|
618
|
+
function Floating({
|
|
757
619
|
children,
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
maskClosable = true,
|
|
769
|
-
keyboard = true,
|
|
770
|
-
centered = false,
|
|
771
|
-
width = 520,
|
|
772
|
-
height,
|
|
773
|
-
zIndex = 1e3,
|
|
774
|
-
getContainer,
|
|
775
|
-
onOk,
|
|
776
|
-
onCancel,
|
|
777
|
-
onOpenChange,
|
|
778
|
-
afterOpenChange,
|
|
620
|
+
content,
|
|
621
|
+
placement = "top",
|
|
622
|
+
trigger = "hover",
|
|
623
|
+
open,
|
|
624
|
+
defaultOpen = false,
|
|
625
|
+
mouseEnterDelay = 0.1,
|
|
626
|
+
mouseLeaveDelay = 0.1,
|
|
627
|
+
arrow = true,
|
|
628
|
+
autoAdjustOverflow = true,
|
|
629
|
+
color,
|
|
779
630
|
className = "",
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
const
|
|
785
|
-
const
|
|
786
|
-
const
|
|
787
|
-
const
|
|
788
|
-
const
|
|
789
|
-
|
|
790
|
-
const
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
631
|
+
overlayClassName = "",
|
|
632
|
+
role = "tooltip",
|
|
633
|
+
onOpenChange
|
|
634
|
+
}) {
|
|
635
|
+
const rootRef = useRef2(null);
|
|
636
|
+
const triggerElementRef = useRef2(null);
|
|
637
|
+
const overlayRef = useRef2(null);
|
|
638
|
+
const enterTimer = useRef2();
|
|
639
|
+
const leaveTimer = useRef2();
|
|
640
|
+
const contentId = useId2();
|
|
641
|
+
const triggers = Array.isArray(trigger) ? trigger : [trigger];
|
|
642
|
+
const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
|
|
643
|
+
const [position, setPosition] = useState();
|
|
644
|
+
const [portalContainer, setPortalContainer] = useState(null);
|
|
645
|
+
useLayoutEffect(() => {
|
|
646
|
+
if (!visible) return;
|
|
647
|
+
setPortalContainer(rootRef.current?.closest(".sia-modal-root, .sia-drawer-root") ?? document.body);
|
|
648
|
+
});
|
|
649
|
+
const setVisibleRef = useRef2(setVisible);
|
|
650
|
+
setVisibleRef.current = setVisible;
|
|
651
|
+
const closeSelfRef = useRef2();
|
|
652
|
+
if (!closeSelfRef.current) closeSelfRef.current = () => setVisibleRef.current(false);
|
|
653
|
+
const exclusiveTooltip = role === "tooltip" && triggers.includes("hover");
|
|
654
|
+
function openNow() {
|
|
655
|
+
if (exclusiveTooltip && activeTooltipClose !== closeSelfRef.current) {
|
|
656
|
+
activeTooltipClose?.();
|
|
657
|
+
activeTooltipClose = closeSelfRef.current;
|
|
801
658
|
}
|
|
802
|
-
|
|
803
|
-
setClosing(true);
|
|
804
|
-
const timer = window.setTimeout(() => {
|
|
805
|
-
setRendered(false);
|
|
806
|
-
setClosing(false);
|
|
807
|
-
afterOpenChangeRef.current?.(false);
|
|
808
|
-
}, MODAL_MOTION_DURATION);
|
|
809
|
-
return () => window.clearTimeout(timer);
|
|
810
|
-
}, [open, rendered]);
|
|
811
|
-
function setRef(node) {
|
|
812
|
-
localRef.current = node;
|
|
813
|
-
if (typeof forwardedRef === "function") forwardedRef(node);
|
|
814
|
-
else if (forwardedRef) forwardedRef.current = node;
|
|
815
|
-
}
|
|
816
|
-
function requestClose() {
|
|
817
|
-
if (submitting || confirmLoading) return;
|
|
818
|
-
onCancel?.();
|
|
819
|
-
onOpenChange?.(false);
|
|
659
|
+
setVisible(true);
|
|
820
660
|
}
|
|
821
|
-
|
|
822
|
-
if (
|
|
823
|
-
|
|
824
|
-
if (!onOk) {
|
|
825
|
-
onOpenChange?.(false);
|
|
826
|
-
submitLock.current = false;
|
|
827
|
-
return;
|
|
828
|
-
}
|
|
829
|
-
try {
|
|
830
|
-
const result = onOk();
|
|
831
|
-
if (result instanceof Promise) {
|
|
832
|
-
setSubmitting(true);
|
|
833
|
-
const resolved = await result;
|
|
834
|
-
if (resolved !== false) onOpenChange?.(false);
|
|
835
|
-
} else if (result !== false) {
|
|
836
|
-
onOpenChange?.(false);
|
|
837
|
-
}
|
|
838
|
-
} catch {
|
|
839
|
-
return;
|
|
840
|
-
} finally {
|
|
841
|
-
submitLock.current = false;
|
|
842
|
-
setSubmitting(false);
|
|
843
|
-
}
|
|
661
|
+
function closeNow() {
|
|
662
|
+
if (activeTooltipClose === closeSelfRef.current) activeTooltipClose = void 0;
|
|
663
|
+
setVisible(false);
|
|
844
664
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
...height !== void 0 ? { display: "flex", flexDirection: "column", height, maxHeight: "calc(100dvh - 48px)" } : {},
|
|
849
|
-
...style,
|
|
850
|
-
"--sia-modal-width": typeof width === "number" ? `${width}px` : width
|
|
851
|
-
};
|
|
852
|
-
const loading = submitting || confirmLoading;
|
|
853
|
-
const defaultFooter = /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
854
|
-
showCancel ? /* @__PURE__ */ jsx3(Button, { ...cancelButtonProps, onClick: requestClose, disabled: loading || cancelButtonProps?.disabled, children: cancelText }) : null,
|
|
855
|
-
/* @__PURE__ */ jsx3(Button, { variant: "primary", ...okButtonProps, onClick: handleOk, loading, children: okText })
|
|
856
|
-
] });
|
|
857
|
-
return /* @__PURE__ */ jsx3(OverlayPortal, { container: getContainer, children: /* @__PURE__ */ jsx3(
|
|
858
|
-
"div",
|
|
859
|
-
{
|
|
860
|
-
className: `sia-modal-root${centered ? " sia-modal-root--centered" : ""}`,
|
|
861
|
-
"data-state": closing ? "closing" : "open",
|
|
862
|
-
style: { zIndex },
|
|
863
|
-
onMouseDown: (event) => {
|
|
864
|
-
if (event.target === event.currentTarget && maskClosable) requestClose();
|
|
865
|
-
},
|
|
866
|
-
children: /* @__PURE__ */ jsxs3(
|
|
867
|
-
"div",
|
|
868
|
-
{
|
|
869
|
-
ref: setRef,
|
|
870
|
-
className: `sia-modal sia-modal--${type} ${className}`.trim(),
|
|
871
|
-
style: mergedStyle,
|
|
872
|
-
role: "dialog",
|
|
873
|
-
"aria-modal": "true",
|
|
874
|
-
"aria-labelledby": title ? titleId : void 0,
|
|
875
|
-
tabIndex: -1,
|
|
876
|
-
...withTitleTooltip(props),
|
|
877
|
-
children: [
|
|
878
|
-
/* @__PURE__ */ jsxs3("div", { className: "sia-modal__header", style: height !== void 0 ? { flexShrink: 0 } : void 0, children: [
|
|
879
|
-
/* @__PURE__ */ jsxs3("div", { className: "sia-modal__heading", children: [
|
|
880
|
-
typeIcons[type] ? /* @__PURE__ */ jsx3("span", { className: "sia-modal__type-icon", "aria-hidden": "true", children: typeIcons[type] }) : null,
|
|
881
|
-
title ? /* @__PURE__ */ jsx3("strong", { id: titleId, children: title }) : null
|
|
882
|
-
] }),
|
|
883
|
-
closable ? /* @__PURE__ */ jsx3("button", { type: "button", className: "sia-modal__close", "aria-label": "\u5173\u95ED\u5BF9\u8BDD\u6846", onClick: requestClose, children: /* @__PURE__ */ jsx3(Icon, { name: "close", size: 17 }) }) : null
|
|
884
|
-
] }),
|
|
885
|
-
children !== void 0 ? /* @__PURE__ */ jsx3("div", { className: "sia-modal__body", style: height !== void 0 ? { flex: 1, minHeight: 0, overflow: "auto" } : void 0, children }) : null,
|
|
886
|
-
footer !== null ? /* @__PURE__ */ jsxs3("div", { className: "sia-modal__footer", style: height !== void 0 ? { flexShrink: 0 } : void 0, children: [
|
|
887
|
-
footer === void 0 && footerExtra != null ? /* @__PURE__ */ jsx3("div", { style: { marginRight: "auto" }, children: footerExtra }) : null,
|
|
888
|
-
footer ?? defaultFooter
|
|
889
|
-
] }) : null
|
|
890
|
-
]
|
|
891
|
-
}
|
|
892
|
-
)
|
|
893
|
-
}
|
|
894
|
-
) });
|
|
895
|
-
});
|
|
896
|
-
function openModal(config) {
|
|
897
|
-
if (typeof document === "undefined") return { destroy() {
|
|
898
|
-
}, update() {
|
|
899
|
-
} };
|
|
900
|
-
const container = document.createElement("div");
|
|
901
|
-
container.className = "sia-modal-api-host";
|
|
902
|
-
document.body.appendChild(container);
|
|
903
|
-
const root = createRoot(container);
|
|
904
|
-
let currentConfig = config;
|
|
905
|
-
let currentOpen = true;
|
|
906
|
-
let destroyed = false;
|
|
907
|
-
let cleanupTimer;
|
|
908
|
-
function cleanup2() {
|
|
909
|
-
if (destroyed) return;
|
|
910
|
-
destroyed = true;
|
|
911
|
-
if (cleanupTimer !== void 0) window.clearTimeout(cleanupTimer);
|
|
912
|
-
root.unmount();
|
|
913
|
-
container.remove();
|
|
914
|
-
modalHandles.delete(handle);
|
|
665
|
+
function clearTimers() {
|
|
666
|
+
window.clearTimeout(enterTimer.current);
|
|
667
|
+
window.clearTimeout(leaveTimer.current);
|
|
915
668
|
}
|
|
916
|
-
function
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
cleanupTimer = window.setTimeout(cleanup2, MODAL_MOTION_DURATION);
|
|
669
|
+
function show(delay = 0) {
|
|
670
|
+
clearTimers();
|
|
671
|
+
if (delay <= 0) openNow();
|
|
672
|
+
else enterTimer.current = window.setTimeout(openNow, delay * 1e3);
|
|
921
673
|
}
|
|
922
|
-
function
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
} }));
|
|
674
|
+
function hide(delay = 0) {
|
|
675
|
+
clearTimers();
|
|
676
|
+
if (delay <= 0) closeNow();
|
|
677
|
+
else leaveTimer.current = window.setTimeout(closeNow, delay * 1e3);
|
|
927
678
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
679
|
+
useEffect4(() => {
|
|
680
|
+
if (!visible || !triggers.includes("click")) return;
|
|
681
|
+
const close = (event) => {
|
|
682
|
+
const target = event.target;
|
|
683
|
+
if (!rootRef.current?.contains(target) && !overlayRef.current?.contains(target)) closeNow();
|
|
684
|
+
};
|
|
685
|
+
document.addEventListener("pointerdown", close);
|
|
686
|
+
return () => document.removeEventListener("pointerdown", close);
|
|
687
|
+
}, [triggers.join("|"), visible]);
|
|
688
|
+
useLayoutEffect(() => {
|
|
689
|
+
if (!visible) {
|
|
690
|
+
setPosition(void 0);
|
|
691
|
+
return;
|
|
934
692
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
type
|
|
949
|
-
});
|
|
950
|
-
}
|
|
951
|
-
var Modal2 = Object.assign(ModalRoot, {
|
|
952
|
-
/** 直接打开实例,返回可用于更新或关闭的操作句柄。 */
|
|
953
|
-
open: openModal,
|
|
954
|
-
/** 显示普通信息提示。 */
|
|
955
|
-
info: preset("info", { title: "\u63D0\u793A" }),
|
|
956
|
-
/** 显示成功提示。 */
|
|
957
|
-
success: preset("success", { title: "\u64CD\u4F5C\u6210\u529F" }),
|
|
958
|
-
/** 显示警告提示。 */
|
|
959
|
-
warning: preset("warning", { title: "\u8BF7\u6CE8\u610F" }),
|
|
960
|
-
/** 显示错误提示。 */
|
|
961
|
-
error: preset("error", { title: "\u64CD\u4F5C\u5931\u8D25" }),
|
|
962
|
-
/** 打开确认弹框,支持异步确认;返回 false 可阻止关闭。 */
|
|
963
|
-
confirm: preset("confirm", { title: "\u786E\u8BA4\u64CD\u4F5C" }),
|
|
964
|
-
/** 关闭由此 API 打开的所有弹层。 */
|
|
965
|
-
destroyAll() {
|
|
966
|
-
[...modalHandles].forEach((handle) => handle.destroy());
|
|
967
|
-
}
|
|
968
|
-
});
|
|
969
|
-
|
|
970
|
-
// src/components/FloatingScrollbarProvider.tsx
|
|
971
|
-
import { useEffect as useEffect6 } from "react";
|
|
972
|
-
|
|
973
|
-
// src/components/useScrollbarProximity.ts
|
|
974
|
-
import { useEffect as useEffect5 } from "react";
|
|
975
|
-
var users = 0;
|
|
976
|
-
var cleanup;
|
|
977
|
-
function useScrollbarProximity() {
|
|
978
|
-
useEffect5(() => {
|
|
979
|
-
if (users++ === 0) {
|
|
980
|
-
let frame = 0;
|
|
981
|
-
let x = -Infinity;
|
|
982
|
-
let y = -Infinity;
|
|
983
|
-
const nearby = /* @__PURE__ */ new Set();
|
|
984
|
-
const clear = () => {
|
|
985
|
-
nearby.forEach((track) => track.removeAttribute("data-scrollbar-near"));
|
|
986
|
-
nearby.clear();
|
|
987
|
-
};
|
|
988
|
-
const update = () => {
|
|
989
|
-
frame = 0;
|
|
990
|
-
const next = /* @__PURE__ */ new Set();
|
|
991
|
-
document.querySelectorAll(".sia-scrollbar-track").forEach((track) => {
|
|
992
|
-
const rect = track.getBoundingClientRect();
|
|
993
|
-
const proximity = Number.parseFloat(getComputedStyle(track).getPropertyValue("--sia-scrollbar-proximity")) || 16;
|
|
994
|
-
if (rect.width && rect.height && x >= rect.left - proximity && x <= rect.right + proximity && y >= rect.top - proximity && y <= rect.bottom + proximity) {
|
|
995
|
-
next.add(track);
|
|
996
|
-
if (!nearby.has(track)) track.setAttribute("data-scrollbar-near", "true");
|
|
997
|
-
}
|
|
998
|
-
});
|
|
999
|
-
nearby.forEach((track) => {
|
|
1000
|
-
if (!next.has(track)) track.removeAttribute("data-scrollbar-near");
|
|
1001
|
-
});
|
|
1002
|
-
nearby.clear();
|
|
1003
|
-
next.forEach((track) => nearby.add(track));
|
|
1004
|
-
};
|
|
1005
|
-
const move = (event) => {
|
|
1006
|
-
if (event.pointerType === "touch") return;
|
|
1007
|
-
x = event.clientX;
|
|
1008
|
-
y = event.clientY;
|
|
1009
|
-
if (!frame) frame = requestAnimationFrame(update);
|
|
1010
|
-
};
|
|
1011
|
-
const leave = () => {
|
|
1012
|
-
x = y = -Infinity;
|
|
1013
|
-
clear();
|
|
1014
|
-
};
|
|
1015
|
-
document.addEventListener("pointermove", move, { passive: true });
|
|
1016
|
-
document.documentElement.addEventListener("pointerleave", leave);
|
|
1017
|
-
window.addEventListener("blur", leave);
|
|
1018
|
-
cleanup = () => {
|
|
1019
|
-
if (frame) cancelAnimationFrame(frame);
|
|
1020
|
-
document.removeEventListener("pointermove", move);
|
|
1021
|
-
document.documentElement.removeEventListener("pointerleave", leave);
|
|
1022
|
-
window.removeEventListener("blur", leave);
|
|
1023
|
-
clear();
|
|
1024
|
-
};
|
|
1025
|
-
}
|
|
1026
|
-
return () => {
|
|
1027
|
-
if (--users === 0) {
|
|
1028
|
-
cleanup?.();
|
|
1029
|
-
cleanup = void 0;
|
|
693
|
+
const getAnchor = () => {
|
|
694
|
+
const root = rootRef.current;
|
|
695
|
+
const target = triggerElementRef.current;
|
|
696
|
+
return target && root?.contains(target) ? target : root?.firstElementChild ?? root;
|
|
697
|
+
};
|
|
698
|
+
const update = () => {
|
|
699
|
+
if (!rootRef.current || !overlayRef.current) return;
|
|
700
|
+
const anchor2 = getAnchor();
|
|
701
|
+
if (anchor2) {
|
|
702
|
+
const rect = anchor2.getBoundingClientRect();
|
|
703
|
+
const next = resolveFloatingPosition(rect, overlayRef.current.getBoundingClientRect(), placement, typeof arrow === "object" && !!arrow.pointAtCenter, autoAdjustOverflow);
|
|
704
|
+
next.hidden = isFloatingAnchorHidden(anchor2, rect);
|
|
705
|
+
setPosition(next);
|
|
1030
706
|
}
|
|
1031
707
|
};
|
|
708
|
+
update();
|
|
709
|
+
window.addEventListener("resize", update);
|
|
710
|
+
window.addEventListener("scroll", update, true);
|
|
711
|
+
window.addEventListener("animationend", update, true);
|
|
712
|
+
window.addEventListener("transitionend", update, true);
|
|
713
|
+
const observer = new ResizeObserver(update);
|
|
714
|
+
if (rootRef.current) observer.observe(rootRef.current);
|
|
715
|
+
const anchor = getAnchor();
|
|
716
|
+
if (anchor) observer.observe(anchor);
|
|
717
|
+
if (overlayRef.current) observer.observe(overlayRef.current);
|
|
718
|
+
return () => {
|
|
719
|
+
window.removeEventListener("resize", update);
|
|
720
|
+
window.removeEventListener("scroll", update, true);
|
|
721
|
+
window.removeEventListener("animationend", update, true);
|
|
722
|
+
window.removeEventListener("transitionend", update, true);
|
|
723
|
+
observer.disconnect();
|
|
724
|
+
};
|
|
725
|
+
}, [children, content, placement, visible, portalContainer, autoAdjustOverflow, typeof arrow === "object" && arrow.pointAtCenter]);
|
|
726
|
+
useEffect4(() => () => {
|
|
727
|
+
clearTimers();
|
|
728
|
+
if (activeTooltipClose === closeSelfRef.current) activeTooltipClose = void 0;
|
|
1032
729
|
}, []);
|
|
730
|
+
const child = cloneElement(children, {
|
|
731
|
+
...triggers.includes("hover") ? { onMouseEnter: (event) => {
|
|
732
|
+
triggerElementRef.current = event.currentTarget;
|
|
733
|
+
children.props.onMouseEnter?.(event);
|
|
734
|
+
show(mouseEnterDelay);
|
|
735
|
+
}, onMouseLeave: (event) => {
|
|
736
|
+
children.props.onMouseLeave?.(event);
|
|
737
|
+
hide(mouseLeaveDelay);
|
|
738
|
+
} } : {},
|
|
739
|
+
...triggers.includes("focus") ? { onFocus: (event) => {
|
|
740
|
+
triggerElementRef.current = event.currentTarget;
|
|
741
|
+
children.props.onFocus?.(event);
|
|
742
|
+
show();
|
|
743
|
+
}, onBlur: (event) => {
|
|
744
|
+
children.props.onBlur?.(event);
|
|
745
|
+
hide();
|
|
746
|
+
} } : {},
|
|
747
|
+
...triggers.includes("click") ? { onClick: (event) => {
|
|
748
|
+
triggerElementRef.current = event.currentTarget;
|
|
749
|
+
children.props.onClick?.(event);
|
|
750
|
+
if (visible) closeNow();
|
|
751
|
+
else openNow();
|
|
752
|
+
} } : {},
|
|
753
|
+
"aria-describedby": visible ? contentId : void 0
|
|
754
|
+
});
|
|
755
|
+
const overlay = visible && content !== null && content !== void 0 && typeof document !== "undefined" ? createPortal(
|
|
756
|
+
/* @__PURE__ */ jsxs2(
|
|
757
|
+
"span",
|
|
758
|
+
{
|
|
759
|
+
ref: overlayRef,
|
|
760
|
+
id: contentId,
|
|
761
|
+
role,
|
|
762
|
+
"data-custom-color": color ? "" : void 0,
|
|
763
|
+
className: `sia-floating__overlay sia-floating__overlay--${position?.placement ?? normalizeFloatingPlacement(placement)} ${overlayClassName}`.trim(),
|
|
764
|
+
style: {
|
|
765
|
+
"--sia-floating-color": color,
|
|
766
|
+
"--sia-floating-arrow-x": position?.arrowX == null ? void 0 : `${position.arrowX}px`,
|
|
767
|
+
"--sia-floating-arrow-y": position?.arrowY == null ? void 0 : `${position.arrowY}px`,
|
|
768
|
+
top: position?.top ?? 0,
|
|
769
|
+
left: position?.left ?? 0,
|
|
770
|
+
visibility: position && !position.hidden ? "visible" : "hidden"
|
|
771
|
+
},
|
|
772
|
+
onMouseEnter: triggers.includes("hover") ? () => show() : void 0,
|
|
773
|
+
onMouseLeave: triggers.includes("hover") ? () => hide(mouseLeaveDelay) : void 0,
|
|
774
|
+
children: [
|
|
775
|
+
content,
|
|
776
|
+
arrow ? /* @__PURE__ */ jsx2("span", { className: "sia-floating__arrow" }) : null
|
|
777
|
+
]
|
|
778
|
+
}
|
|
779
|
+
),
|
|
780
|
+
portalContainer ?? document.body
|
|
781
|
+
) : null;
|
|
782
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
783
|
+
/* @__PURE__ */ jsx2("span", { ref: rootRef, className: `sia-floating ${className}`.trim(), children: child }),
|
|
784
|
+
overlay
|
|
785
|
+
] });
|
|
1033
786
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
var scrollableOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay"]);
|
|
1037
|
-
var clippingOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay", "hidden", "clip"]);
|
|
1038
|
-
function isRootScroller(target) {
|
|
1039
|
-
return target === document.scrollingElement || target === document.documentElement;
|
|
787
|
+
function Tooltip(props) {
|
|
788
|
+
return /* @__PURE__ */ jsx2(Floating, { ...props, content: props.title });
|
|
1040
789
|
}
|
|
1041
|
-
function
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
}
|
|
1046
|
-
const style = getComputedStyle(target);
|
|
1047
|
-
const overflow = axis === "horizontal" ? style.overflowX : style.overflowY;
|
|
1048
|
-
const hasOverflow = axis === "horizontal" ? target.scrollWidth > target.clientWidth + 1 : target.scrollHeight > target.clientHeight + 1;
|
|
1049
|
-
return hasOverflow && scrollableOverflow.has(overflow);
|
|
790
|
+
function Popover({ title, content, trigger = "click", overlayClassName = "", ...props }) {
|
|
791
|
+
return /* @__PURE__ */ jsx2(Floating, { ...props, trigger, role: "dialog", overlayClassName: `sia-popover ${overlayClassName}`.trim(), content: /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
792
|
+
title ? /* @__PURE__ */ jsx2("strong", { className: "sia-popover__title", children: title }) : null,
|
|
793
|
+
/* @__PURE__ */ jsx2("span", { className: "sia-popover__content", children: content })
|
|
794
|
+
] }) });
|
|
1050
795
|
}
|
|
1051
|
-
function
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
const style = getComputedStyle(parent);
|
|
1063
|
-
const clipX = clippingOverflow.has(style.overflowX);
|
|
1064
|
-
const clipY = clippingOverflow.has(style.overflowY);
|
|
1065
|
-
if (clipX || clipY) {
|
|
1066
|
-
const rect = parent.getBoundingClientRect();
|
|
1067
|
-
if (clipX) {
|
|
1068
|
-
left = Math.max(left, rect.left);
|
|
1069
|
-
right = Math.min(right, rect.right);
|
|
1070
|
-
}
|
|
1071
|
-
if (clipY) {
|
|
1072
|
-
top = Math.max(top, rect.top);
|
|
1073
|
-
bottom = Math.min(bottom, rect.bottom);
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
parent = parent.parentElement;
|
|
1077
|
-
}
|
|
1078
|
-
return {
|
|
1079
|
-
top,
|
|
1080
|
-
right,
|
|
1081
|
-
bottom,
|
|
1082
|
-
left,
|
|
1083
|
-
width: Math.max(0, right - left),
|
|
1084
|
-
height: Math.max(0, bottom - top)
|
|
1085
|
-
};
|
|
796
|
+
function Timeline({ items = [], mode = "left", pending = false, pendingDot, reverse = false, className = "", ...props }) {
|
|
797
|
+
const values = [...items, ...pending ? [{ children: pending === true ? "\u52A0\u8F7D\u4E2D..." : pending, dot: pendingDot ?? /* @__PURE__ */ jsx2(Icon, { name: "loader", className: "sia-spin-icon" }) }] : []];
|
|
798
|
+
if (reverse) values.reverse();
|
|
799
|
+
return /* @__PURE__ */ jsx2("ul", { className: `sia-timeline sia-timeline--${mode} ${className}`.trim(), ...withTitleTooltip(props), children: values.map((item, index) => {
|
|
800
|
+
const position = item.position ?? (mode === "alternate" ? index % 2 ? "right" : "left" : mode);
|
|
801
|
+
return /* @__PURE__ */ jsxs2("li", { className: `sia-timeline__item sia-timeline__item--${position}`, children: [
|
|
802
|
+
item.label ? /* @__PURE__ */ jsx2("span", { className: "sia-timeline__label", children: item.label }) : null,
|
|
803
|
+
/* @__PURE__ */ jsx2("span", { className: "sia-timeline__rail", children: /* @__PURE__ */ jsx2("span", { className: "sia-timeline__dot", style: { color: item.color && !["blue", "red", "green", "gray"].includes(item.color) ? item.color : void 0 }, "data-color": item.color ?? "blue", children: item.dot }) }),
|
|
804
|
+
/* @__PURE__ */ jsx2("span", { className: "sia-timeline__content", children: item.children })
|
|
805
|
+
] }, index);
|
|
806
|
+
}) });
|
|
1086
807
|
}
|
|
1087
|
-
function
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
track.setAttribute("aria-hidden", "true");
|
|
1094
|
-
track.append(thumb);
|
|
1095
|
-
return { track, thumb };
|
|
808
|
+
function collectKeys(nodes, branchOnly = false, result = []) {
|
|
809
|
+
nodes.forEach((node) => {
|
|
810
|
+
if (!branchOnly || node.children?.length) result.push(node.key);
|
|
811
|
+
if (node.children) collectKeys(node.children, branchOnly, result);
|
|
812
|
+
});
|
|
813
|
+
return result;
|
|
1096
814
|
}
|
|
1097
|
-
function
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
if (
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
const
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
};
|
|
1164
|
-
const bindTrackDrag = (entry, axis, track, thumb) => {
|
|
1165
|
-
const target = entry.target;
|
|
1166
|
-
const onTrackPointerEnter = () => {
|
|
1167
|
-
entry.hoveringTrack = true;
|
|
1168
|
-
showEntry(entry);
|
|
1169
|
-
};
|
|
1170
|
-
const onTrackPointerLeave = () => {
|
|
1171
|
-
entry.hoveringTrack = false;
|
|
1172
|
-
scheduleHide(entry);
|
|
1173
|
-
};
|
|
1174
|
-
const onTrackPointerDown = (event) => {
|
|
1175
|
-
if (event.target === thumb || event.button !== 0) return;
|
|
1176
|
-
event.preventDefault();
|
|
1177
|
-
event.stopPropagation();
|
|
1178
|
-
const trackRect = track.getBoundingClientRect();
|
|
1179
|
-
const thumbRect = thumb.getBoundingClientRect();
|
|
1180
|
-
const trackLength = axis === "vertical" ? trackRect.height : trackRect.width;
|
|
1181
|
-
const thumbLength = axis === "vertical" ? thumbRect.height : thumbRect.width;
|
|
1182
|
-
const pointer = axis === "vertical" ? event.clientY - trackRect.top : event.clientX - trackRect.left;
|
|
1183
|
-
const ratio = Math.max(0, Math.min(1, (pointer - thumbLength / 2) / Math.max(1, trackLength - thumbLength)));
|
|
1184
|
-
if (axis === "vertical") target.scrollTop = ratio * (target.scrollHeight - target.clientHeight);
|
|
1185
|
-
else target.scrollLeft = ratio * (target.scrollWidth - target.clientWidth);
|
|
1186
|
-
};
|
|
1187
|
-
const onThumbPointerDown = (event) => {
|
|
1188
|
-
if (event.button !== 0) return;
|
|
1189
|
-
event.preventDefault();
|
|
1190
|
-
event.stopPropagation();
|
|
1191
|
-
entry.dragging = true;
|
|
1192
|
-
showEntry(entry);
|
|
1193
|
-
thumb.setPointerCapture(event.pointerId);
|
|
1194
|
-
const startPointer = axis === "vertical" ? event.clientY : event.clientX;
|
|
1195
|
-
const startScroll = axis === "vertical" ? target.scrollTop : target.scrollLeft;
|
|
1196
|
-
const trackRect = track.getBoundingClientRect();
|
|
1197
|
-
const thumbRect = thumb.getBoundingClientRect();
|
|
1198
|
-
const trackLength = axis === "vertical" ? trackRect.height : trackRect.width;
|
|
1199
|
-
const thumbLength = axis === "vertical" ? thumbRect.height : thumbRect.width;
|
|
1200
|
-
const maxScroll = axis === "vertical" ? target.scrollHeight - target.clientHeight : target.scrollWidth - target.clientWidth;
|
|
1201
|
-
const travel = Math.max(1, trackLength - thumbLength);
|
|
1202
|
-
const onPointerMove = (moveEvent) => {
|
|
1203
|
-
if (moveEvent.pointerId !== event.pointerId) return;
|
|
1204
|
-
const pointer = axis === "vertical" ? moveEvent.clientY : moveEvent.clientX;
|
|
1205
|
-
const nextScroll = startScroll + (pointer - startPointer) * maxScroll / travel;
|
|
1206
|
-
if (axis === "vertical") target.scrollTop = nextScroll;
|
|
1207
|
-
else target.scrollLeft = nextScroll;
|
|
1208
|
-
};
|
|
1209
|
-
const onPointerUp = (upEvent) => {
|
|
1210
|
-
if (upEvent.pointerId !== event.pointerId) return;
|
|
1211
|
-
entry.dragging = false;
|
|
1212
|
-
thumb.releasePointerCapture(event.pointerId);
|
|
1213
|
-
window.removeEventListener("pointermove", onPointerMove);
|
|
1214
|
-
window.removeEventListener("pointerup", onPointerUp);
|
|
1215
|
-
window.removeEventListener("pointercancel", onPointerUp);
|
|
1216
|
-
scheduleHide(entry);
|
|
1217
|
-
};
|
|
1218
|
-
window.addEventListener("pointermove", onPointerMove);
|
|
1219
|
-
window.addEventListener("pointerup", onPointerUp);
|
|
1220
|
-
window.addEventListener("pointercancel", onPointerUp);
|
|
1221
|
-
};
|
|
1222
|
-
track.addEventListener("pointerenter", onTrackPointerEnter);
|
|
1223
|
-
track.addEventListener("pointerleave", onTrackPointerLeave);
|
|
1224
|
-
track.addEventListener("pointerdown", onTrackPointerDown);
|
|
1225
|
-
thumb.addEventListener("pointerdown", onThumbPointerDown);
|
|
1226
|
-
return () => {
|
|
1227
|
-
track.removeEventListener("pointerenter", onTrackPointerEnter);
|
|
1228
|
-
track.removeEventListener("pointerleave", onTrackPointerLeave);
|
|
1229
|
-
track.removeEventListener("pointerdown", onTrackPointerDown);
|
|
1230
|
-
thumb.removeEventListener("pointerdown", onThumbPointerDown);
|
|
1231
|
-
};
|
|
1232
|
-
};
|
|
1233
|
-
const resizeObserver = new ResizeObserver((observedEntries) => {
|
|
1234
|
-
observedEntries.forEach(({ target }) => {
|
|
1235
|
-
const entry = entries.get(target);
|
|
1236
|
-
if (entry) updateEntry(entry);
|
|
1237
|
-
});
|
|
1238
|
-
});
|
|
1239
|
-
const addTarget = (target) => {
|
|
1240
|
-
if (entries.has(target)) return;
|
|
1241
|
-
const horizontal = createTrack("horizontal");
|
|
1242
|
-
const vertical = createTrack("vertical");
|
|
1243
|
-
layer.append(horizontal.track, vertical.track);
|
|
1244
|
-
const onPointerEnter = () => {
|
|
1245
|
-
const entry2 = entries.get(target);
|
|
1246
|
-
if (!entry2) return;
|
|
1247
|
-
entry2.hoveringTarget = true;
|
|
1248
|
-
showEntry(entry2);
|
|
1249
|
-
};
|
|
1250
|
-
const onPointerLeave = () => {
|
|
1251
|
-
const entry2 = entries.get(target);
|
|
1252
|
-
if (!entry2) return;
|
|
1253
|
-
entry2.hoveringTarget = false;
|
|
1254
|
-
scheduleHide(entry2);
|
|
1255
|
-
};
|
|
1256
|
-
const onScroll = () => {
|
|
1257
|
-
const entry2 = entries.get(target);
|
|
1258
|
-
if (!entry2) return;
|
|
1259
|
-
updateEntry(entry2);
|
|
1260
|
-
showEntry(entry2);
|
|
1261
|
-
scheduleHide(entry2, 700);
|
|
1262
|
-
};
|
|
1263
|
-
target.addEventListener("pointerenter", onPointerEnter);
|
|
1264
|
-
target.addEventListener("pointerleave", onPointerLeave);
|
|
1265
|
-
target.addEventListener("scroll", onScroll, { passive: true });
|
|
1266
|
-
const entry = {
|
|
1267
|
-
target,
|
|
1268
|
-
horizontalTrack: horizontal.track,
|
|
1269
|
-
horizontalThumb: horizontal.thumb,
|
|
1270
|
-
verticalTrack: vertical.track,
|
|
1271
|
-
verticalThumb: vertical.thumb,
|
|
1272
|
-
hideTimer: null,
|
|
1273
|
-
hoveringTarget: target.matches(":hover"),
|
|
1274
|
-
hoveringTrack: false,
|
|
1275
|
-
dragging: false,
|
|
1276
|
-
cleanup: () => void 0
|
|
1277
|
-
};
|
|
1278
|
-
const cleanupHorizontal = bindTrackDrag(entry, "horizontal", horizontal.track, horizontal.thumb);
|
|
1279
|
-
const cleanupVertical = bindTrackDrag(entry, "vertical", vertical.track, vertical.thumb);
|
|
1280
|
-
entry.cleanup = () => {
|
|
1281
|
-
if (entry.hideTimer !== null) window.clearTimeout(entry.hideTimer);
|
|
1282
|
-
cleanupHorizontal();
|
|
1283
|
-
cleanupVertical();
|
|
1284
|
-
target.removeEventListener("pointerenter", onPointerEnter);
|
|
1285
|
-
target.removeEventListener("pointerleave", onPointerLeave);
|
|
1286
|
-
target.removeEventListener("scroll", onScroll);
|
|
1287
|
-
resizeObserver.unobserve(target);
|
|
1288
|
-
target.removeAttribute("data-sia-floating-scrollbar");
|
|
1289
|
-
horizontal.track.remove();
|
|
1290
|
-
vertical.track.remove();
|
|
1291
|
-
};
|
|
1292
|
-
entries.set(target, entry);
|
|
1293
|
-
target.setAttribute("data-sia-floating-scrollbar", "");
|
|
1294
|
-
resizeObserver.observe(target);
|
|
1295
|
-
updateEntry(entry);
|
|
1296
|
-
if (entry.hoveringTarget) showEntry(entry);
|
|
815
|
+
function flattenVisibleTree(nodes, expandedKeys, depth = 0, ancestorKeys = [], result = []) {
|
|
816
|
+
nodes.forEach((node, siblingIndex) => {
|
|
817
|
+
result.push({ node, depth, ancestorKeys, index: result.length, positionInSet: siblingIndex + 1, setSize: nodes.length });
|
|
818
|
+
if (expandedKeys.has(node.key) && node.children?.length) {
|
|
819
|
+
flattenVisibleTree(node.children, expandedKeys, depth + 1, [...ancestorKeys, node.key], result);
|
|
820
|
+
}
|
|
821
|
+
});
|
|
822
|
+
return result;
|
|
823
|
+
}
|
|
824
|
+
function Tree({
|
|
825
|
+
treeData,
|
|
826
|
+
selectedKeys,
|
|
827
|
+
defaultSelectedKeys = [],
|
|
828
|
+
expandedKeys,
|
|
829
|
+
defaultExpandedKeys = [],
|
|
830
|
+
defaultExpandAll = false,
|
|
831
|
+
checkedKeys,
|
|
832
|
+
defaultCheckedKeys = [],
|
|
833
|
+
loadingKeys = [],
|
|
834
|
+
checkable = false,
|
|
835
|
+
checkStrictly = false,
|
|
836
|
+
multiple = false,
|
|
837
|
+
selectable = true,
|
|
838
|
+
showLine = false,
|
|
839
|
+
showIcon = false,
|
|
840
|
+
blockNode = false,
|
|
841
|
+
indentSize = 20,
|
|
842
|
+
switcherWidth = 24,
|
|
843
|
+
stickyAncestors = false,
|
|
844
|
+
stickyRowHeight = 34,
|
|
845
|
+
virtual = true,
|
|
846
|
+
virtualThreshold = 100,
|
|
847
|
+
virtualItemHeight,
|
|
848
|
+
draggable = false,
|
|
849
|
+
loadData,
|
|
850
|
+
onSelect,
|
|
851
|
+
onCheck,
|
|
852
|
+
onExpand,
|
|
853
|
+
onDrop,
|
|
854
|
+
className = "",
|
|
855
|
+
...props
|
|
856
|
+
}) {
|
|
857
|
+
const scrollRef = useRef2(null);
|
|
858
|
+
const [selected, setSelected] = useControllableState({ value: selectedKeys, defaultValue: defaultSelectedKeys });
|
|
859
|
+
const [expanded, setExpanded] = useControllableState({ value: expandedKeys, defaultValue: defaultExpandAll ? collectKeys(treeData, true) : defaultExpandedKeys });
|
|
860
|
+
const [checked, setChecked] = useControllableState({ value: checkedKeys, defaultValue: defaultCheckedKeys });
|
|
861
|
+
const [loading, setLoading] = useState(/* @__PURE__ */ new Set());
|
|
862
|
+
const controlledLoading = useMemo2(() => new Set(loadingKeys), [loadingKeys]);
|
|
863
|
+
const selectedKeySet = useMemo2(() => new Set(selected), [selected]);
|
|
864
|
+
const expandedKeySet = useMemo2(() => new Set(expanded), [expanded]);
|
|
865
|
+
const flatNodes = useMemo2(() => flattenVisibleTree(treeData, expandedKeySet), [expandedKeySet, treeData]);
|
|
866
|
+
const normalizedVirtualThreshold = Math.max(1, Math.floor(virtualThreshold));
|
|
867
|
+
const normalizedVirtualItemHeight = Math.max(1, virtualItemHeight ?? stickyRowHeight);
|
|
868
|
+
const wantsVirtualScroll = virtual && flatNodes.length >= normalizedVirtualThreshold;
|
|
869
|
+
const [virtualViewport, setVirtualViewport] = useState({ height: 0, scrollTop: 0, ownsScroll: true });
|
|
870
|
+
useLayoutEffect(() => {
|
|
871
|
+
if (!wantsVirtualScroll) return void 0;
|
|
872
|
+
const element = scrollRef.current;
|
|
873
|
+
if (!element) return void 0;
|
|
874
|
+
let animationFrame = 0;
|
|
875
|
+
const updateViewport = () => {
|
|
876
|
+
animationFrame = 0;
|
|
877
|
+
const overflowY = window.getComputedStyle(element).overflowY;
|
|
878
|
+
const ownsScroll = overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay";
|
|
879
|
+
const next = { height: element.clientHeight, scrollTop: element.scrollTop, ownsScroll };
|
|
880
|
+
setVirtualViewport((current) => current.height === next.height && current.scrollTop === next.scrollTop && current.ownsScroll === next.ownsScroll ? current : next);
|
|
1297
881
|
};
|
|
1298
|
-
const
|
|
1299
|
-
|
|
1300
|
-
if (!entry) return;
|
|
1301
|
-
entry.cleanup();
|
|
1302
|
-
entries.delete(target);
|
|
882
|
+
const scheduleViewportUpdate = () => {
|
|
883
|
+
if (!animationFrame) animationFrame = window.requestAnimationFrame(updateViewport);
|
|
1303
884
|
};
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
885
|
+
updateViewport();
|
|
886
|
+
element.addEventListener("scroll", scheduleViewportUpdate, { passive: true });
|
|
887
|
+
const resizeObserver = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(scheduleViewportUpdate);
|
|
888
|
+
resizeObserver?.observe(element);
|
|
889
|
+
return () => {
|
|
890
|
+
element.removeEventListener("scroll", scheduleViewportUpdate);
|
|
891
|
+
resizeObserver?.disconnect();
|
|
892
|
+
if (animationFrame) window.cancelAnimationFrame(animationFrame);
|
|
893
|
+
};
|
|
894
|
+
}, [className, props.style, wantsVirtualScroll]);
|
|
895
|
+
const virtualEnabled = wantsVirtualScroll && virtualViewport.ownsScroll;
|
|
896
|
+
const virtualWindow = useMemo2(() => {
|
|
897
|
+
if (!virtualEnabled) return { start: 0, end: flatNodes.length };
|
|
898
|
+
const overscan = 8;
|
|
899
|
+
const viewportHeight = virtualViewport.height || normalizedVirtualItemHeight * 12;
|
|
900
|
+
const maxStart = Math.max(0, flatNodes.length - 1);
|
|
901
|
+
const start = Math.min(maxStart, Math.max(0, Math.floor(virtualViewport.scrollTop / normalizedVirtualItemHeight) - overscan));
|
|
902
|
+
const end = Math.min(flatNodes.length, Math.ceil((virtualViewport.scrollTop + viewportHeight) / normalizedVirtualItemHeight) + overscan);
|
|
903
|
+
return { start, end };
|
|
904
|
+
}, [flatNodes.length, normalizedVirtualItemHeight, virtualEnabled, virtualViewport.height, virtualViewport.scrollTop]);
|
|
905
|
+
const flatNodeByKey = useMemo2(() => new Map(flatNodes.map((item) => [item.node.key, item])), [flatNodes]);
|
|
906
|
+
const virtualStickyNodes = useMemo2(() => {
|
|
907
|
+
if (!virtualEnabled || !stickyAncestors || !flatNodes.length) return [];
|
|
908
|
+
const anchorIndex = Math.min(flatNodes.length - 1, Math.max(0, Math.floor(virtualViewport.scrollTop / normalizedVirtualItemHeight)));
|
|
909
|
+
return flatNodes[anchorIndex].ancestorKeys.map((key) => flatNodeByKey.get(key)).filter((item) => Boolean(item));
|
|
910
|
+
}, [flatNodeByKey, flatNodes, normalizedVirtualItemHeight, stickyAncestors, virtualEnabled, virtualViewport.scrollTop]);
|
|
911
|
+
const selectedAncestorKeys = useMemo2(() => {
|
|
912
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
913
|
+
const visit = (nodes, parentKeys) => {
|
|
914
|
+
nodes.forEach((node) => {
|
|
915
|
+
if (selectedKeySet.has(node.key)) parentKeys.forEach((key) => ancestors.add(key));
|
|
916
|
+
if (node.children?.length) visit(node.children, [...parentKeys, node.key]);
|
|
1327
917
|
});
|
|
1328
918
|
};
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
919
|
+
visit(treeData, []);
|
|
920
|
+
return ancestors;
|
|
921
|
+
}, [selectedKeySet, treeData]);
|
|
922
|
+
const dragNodeRef = useRef2();
|
|
923
|
+
const pointerDragRef = useRef2();
|
|
924
|
+
const suppressClickRef = useRef2(false);
|
|
925
|
+
const [dragOver, setDragOver] = useState();
|
|
926
|
+
const normalizedSwitcherWidth = Math.max(0, switcherWidth);
|
|
927
|
+
async function toggleExpand(node) {
|
|
928
|
+
const nextExpanded = !expanded.includes(node.key);
|
|
929
|
+
if (nextExpanded && node.loaded !== true && !node.children?.length && node.isLeaf === false && loadData) {
|
|
930
|
+
setLoading((keys) => new Set(keys).add(node.key));
|
|
931
|
+
try {
|
|
932
|
+
await loadData(node);
|
|
933
|
+
} finally {
|
|
934
|
+
setLoading((keys) => {
|
|
935
|
+
const next2 = new Set(keys);
|
|
936
|
+
next2.delete(node.key);
|
|
937
|
+
return next2;
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
const next = nextExpanded ? [...expanded, node.key] : expanded.filter((key) => key !== node.key);
|
|
942
|
+
setExpanded(next);
|
|
943
|
+
onExpand?.([...next], { expanded: nextExpanded, node });
|
|
944
|
+
}
|
|
945
|
+
const checkState = useMemo2(() => getTreeCheckState(treeData, checked, checkStrictly), [treeData, checked, checkStrictly]);
|
|
946
|
+
function check(node) {
|
|
947
|
+
const next = toggleTreeCheck(treeData, checked, node, checkStrictly);
|
|
948
|
+
setChecked([...next.checked]);
|
|
949
|
+
onCheck?.([...next.checked], { checked: next.checkedValue, halfCheckedKeys: [...next.halfChecked], node });
|
|
950
|
+
}
|
|
951
|
+
function select(node, event) {
|
|
952
|
+
if (!selectable || node.selectable === false || node.disabled) return;
|
|
953
|
+
const exists = selected.includes(node.key);
|
|
954
|
+
const next = multiple ? exists ? selected.filter((key) => key !== node.key) : [...selected, node.key] : exists ? [] : [node.key];
|
|
955
|
+
setSelected(next);
|
|
956
|
+
onSelect?.([...next], { selected: !exists, node, nativeEvent: event });
|
|
957
|
+
}
|
|
958
|
+
function selectForContextMenu(node, event) {
|
|
959
|
+
if (!selectable || node.selectable === false || node.disabled || selected.includes(node.key)) return;
|
|
960
|
+
const next = [node.key];
|
|
961
|
+
setSelected(next);
|
|
962
|
+
onSelect?.(next, { selected: true, node, nativeEvent: event });
|
|
963
|
+
}
|
|
964
|
+
function findNode(key, nodes = treeData) {
|
|
965
|
+
for (const node of nodes) {
|
|
966
|
+
if (String(node.key) === key) return node;
|
|
967
|
+
const child = node.children?.length ? findNode(key, node.children) : void 0;
|
|
968
|
+
if (child) return child;
|
|
969
|
+
}
|
|
970
|
+
return void 0;
|
|
971
|
+
}
|
|
972
|
+
function getPointerDropTarget(clientX, clientY, dragNode) {
|
|
973
|
+
const targetElement = document.elementFromPoint(clientX, clientY)?.closest("[data-sia-tree-drop-key]");
|
|
974
|
+
if (!targetElement) return void 0;
|
|
975
|
+
const targetNode = targetElement?.dataset.siaTreeDropKey ? findNode(targetElement.dataset.siaTreeDropKey) : void 0;
|
|
976
|
+
if (!targetNode || targetNode.key === dragNode.key || targetNode.disabled || targetNode.droppable === false) return void 0;
|
|
977
|
+
const bounds = targetElement.getBoundingClientRect();
|
|
978
|
+
const relativeY = bounds.height > 0 ? (clientY - bounds.top) / bounds.height : 0.5;
|
|
979
|
+
const dropPosition = relativeY < 0.25 ? "before" : relativeY > 0.75 ? "after" : "inside";
|
|
980
|
+
return { node: targetNode, dropPosition };
|
|
981
|
+
}
|
|
982
|
+
function beginPointerDrag(node, event) {
|
|
983
|
+
if (event.button !== 0) return;
|
|
984
|
+
pointerDragRef.current = {
|
|
985
|
+
node,
|
|
986
|
+
pointerId: event.pointerId,
|
|
987
|
+
startX: event.clientX,
|
|
988
|
+
startY: event.clientY,
|
|
989
|
+
active: false
|
|
1332
990
|
};
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
991
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
992
|
+
}
|
|
993
|
+
function movePointerDrag(event) {
|
|
994
|
+
const pointerDrag = pointerDragRef.current;
|
|
995
|
+
if (!pointerDrag || pointerDrag.pointerId !== event.pointerId) return;
|
|
996
|
+
if (!pointerDrag.active && Math.hypot(event.clientX - pointerDrag.startX, event.clientY - pointerDrag.startY) < 5) return;
|
|
997
|
+
pointerDrag.active = true;
|
|
998
|
+
dragNodeRef.current = pointerDrag.node;
|
|
999
|
+
event.preventDefault();
|
|
1000
|
+
const target = getPointerDropTarget(event.clientX, event.clientY, pointerDrag.node);
|
|
1001
|
+
setDragOver(target ? { key: target.node.key, position: target.dropPosition } : void 0);
|
|
1002
|
+
}
|
|
1003
|
+
function finishPointerDrag(event) {
|
|
1004
|
+
const pointerDrag = pointerDragRef.current;
|
|
1005
|
+
if (!pointerDrag || pointerDrag.pointerId !== event.pointerId) return;
|
|
1006
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
|
|
1007
|
+
if (pointerDrag.active) {
|
|
1008
|
+
event.preventDefault();
|
|
1009
|
+
suppressClickRef.current = true;
|
|
1010
|
+
const target = getPointerDropTarget(event.clientX, event.clientY, pointerDrag.node);
|
|
1011
|
+
if (target) onDrop?.({ dragNode: pointerDrag.node, node: target.node, dropPosition: target.dropPosition });
|
|
1012
|
+
window.setTimeout(() => {
|
|
1013
|
+
suppressClickRef.current = false;
|
|
1014
|
+
}, 0);
|
|
1015
|
+
}
|
|
1016
|
+
pointerDragRef.current = void 0;
|
|
1017
|
+
dragNodeRef.current = void 0;
|
|
1018
|
+
setDragOver(void 0);
|
|
1019
|
+
}
|
|
1020
|
+
function cancelPointerDrag(event) {
|
|
1021
|
+
const pointerDrag = pointerDragRef.current;
|
|
1022
|
+
if (!pointerDrag || pointerDrag.pointerId !== event.pointerId) return;
|
|
1023
|
+
pointerDragRef.current = void 0;
|
|
1024
|
+
dragNodeRef.current = void 0;
|
|
1025
|
+
setDragOver(void 0);
|
|
1026
|
+
}
|
|
1027
|
+
function renderNode(node, depth, options = {}) {
|
|
1028
|
+
const open = expandedKeySet.has(node.key);
|
|
1029
|
+
const isSelected = selected.includes(node.key);
|
|
1030
|
+
const isSelectedAncestor = selectedAncestorKeys.has(node.key);
|
|
1031
|
+
const isChecked = checkState.checked.has(node.key);
|
|
1032
|
+
const isHalfChecked = checkState.halfChecked.has(node.key);
|
|
1033
|
+
const hasChildren = Boolean(node.children?.length || node.isLeaf === false);
|
|
1034
|
+
const nodeLoading = loading.has(node.key) || controlledLoading.has(node.key);
|
|
1035
|
+
const virtualizedNode = options.virtualTop !== void 0 || options.stickySlot !== void 0;
|
|
1036
|
+
const sticky = !virtualizedNode && stickyAncestors && hasChildren && open;
|
|
1037
|
+
const canDrag = draggable && node.draggable !== false && !node.disabled;
|
|
1038
|
+
const { className: rowClassName = "", style: rowStyle, onClick: onRowClick, ...rowProps } = node.rowProps ?? {};
|
|
1039
|
+
const unloaded = hasChildren && node.loaded === false;
|
|
1040
|
+
const dropPosition = dragOver?.key === node.key ? dragOver.position : void 0;
|
|
1041
|
+
const virtualNodeClassName = options.stickySlot !== void 0 ? " sia-tree__virtual-sticky-node" : options.virtualTop !== void 0 ? " sia-tree__virtual-node" : "";
|
|
1042
|
+
const virtualNodeStyle = options.stickySlot !== void 0 ? { top: options.stickySlot * normalizedVirtualItemHeight, height: normalizedVirtualItemHeight } : options.virtualTop !== void 0 ? { transform: `translateY(${options.virtualTop}px)`, height: normalizedVirtualItemHeight } : void 0;
|
|
1043
|
+
return /* @__PURE__ */ jsxs2(
|
|
1044
|
+
"div",
|
|
1045
|
+
{
|
|
1046
|
+
className: `sia-tree__node${virtualNodeClassName}${isSelected ? " is-selected" : ""}${isSelectedAncestor ? " is-selected-ancestor" : ""}${dropPosition ? ` is-drag-over-${dropPosition}` : ""}${node.disabled ? " is-disabled" : ""}${unloaded ? " is-unloaded" : ""}`,
|
|
1047
|
+
style: virtualNodeStyle,
|
|
1048
|
+
role: "treeitem",
|
|
1049
|
+
"aria-expanded": hasChildren ? open : void 0,
|
|
1050
|
+
"aria-selected": isSelected,
|
|
1051
|
+
"aria-level": depth + 1,
|
|
1052
|
+
"aria-posinset": options.positionInSet,
|
|
1053
|
+
"aria-setsize": options.setSize,
|
|
1054
|
+
children: [
|
|
1055
|
+
virtualizedNode && showLine && depth > 0 ? /* @__PURE__ */ jsx2("span", { className: "sia-tree__virtual-guides", "aria-hidden": "true", children: Array.from({ length: depth }, (_, guideDepth) => /* @__PURE__ */ jsx2("span", { className: "sia-tree__virtual-guide", style: { insetInlineStart: (guideDepth + 1) * Math.max(0, indentSize) } }, guideDepth)) }) : null,
|
|
1056
|
+
/* @__PURE__ */ jsx2(
|
|
1057
|
+
"div",
|
|
1058
|
+
{
|
|
1059
|
+
...withTitleTooltip(rowProps),
|
|
1060
|
+
className: `sia-tree__row${blockNode ? " sia-tree__row--block" : ""}${sticky ? " sia-tree__row--sticky" : ""} ${rowClassName}`.trim(),
|
|
1061
|
+
style: {
|
|
1062
|
+
...rowStyle,
|
|
1063
|
+
height: virtualizedNode ? "100%" : rowStyle?.height,
|
|
1064
|
+
paddingInlineStart: depth * Math.max(0, indentSize),
|
|
1065
|
+
top: sticky ? depth * Math.max(1, stickyRowHeight) : rowStyle?.top,
|
|
1066
|
+
zIndex: sticky ? Math.max(1, 100 - depth) : rowStyle?.zIndex
|
|
1067
|
+
},
|
|
1068
|
+
"aria-busy": nodeLoading || void 0,
|
|
1069
|
+
"data-sia-tree-drop-key": String(node.key),
|
|
1070
|
+
"data-sia-tree-draggable": canDrag || void 0,
|
|
1071
|
+
onClick: (event) => {
|
|
1072
|
+
onRowClick?.(event);
|
|
1073
|
+
if (event.defaultPrevented || suppressClickRef.current || node.disabled) return;
|
|
1074
|
+
select(node, event);
|
|
1075
|
+
if (hasChildren) void toggleExpand(node);
|
|
1076
|
+
},
|
|
1077
|
+
children: (() => {
|
|
1078
|
+
const content = /* @__PURE__ */ jsxs2("span", { className: "sia-tree__context-content", children: [
|
|
1079
|
+
hasChildren ? /* @__PURE__ */ jsx2("button", { type: "button", className: "sia-tree__switcher", "aria-label": open ? "\u6536\u8D77\u8282\u70B9" : "\u5C55\u5F00\u8282\u70B9", "aria-expanded": open, style: { width: normalizedSwitcherWidth, flexBasis: normalizedSwitcherWidth }, disabled: node.disabled, onClick: (event) => {
|
|
1080
|
+
event.stopPropagation();
|
|
1081
|
+
void toggleExpand(node);
|
|
1082
|
+
}, children: nodeLoading ? /* @__PURE__ */ jsx2(Icon, { name: "loader", className: "sia-spin-icon", size: 13 }) : /* @__PURE__ */ jsx2(Icon, { name: open ? "chevron-down" : "chevron-right", size: 13 }) }) : /* @__PURE__ */ jsx2("span", { className: "sia-tree__switcher", "aria-label": open ? "\u6536\u8D77\u8282\u70B9" : "\u5C55\u5F00\u8282\u70B9", "aria-expanded": open, style: { width: normalizedSwitcherWidth, flexBasis: normalizedSwitcherWidth }, "aria-hidden": "true" }),
|
|
1083
|
+
checkable || node.checkable ? /* @__PURE__ */ jsx2("span", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx2(Checkbox2, { checked: isChecked, indeterminate: isHalfChecked, disabled: node.disabled || node.disableCheckbox, onChange: () => check(node) }) }) : null,
|
|
1084
|
+
node.prefix ? /* @__PURE__ */ jsx2("span", { className: "sia-tree__prefix", onClick: (event) => event.stopPropagation(), children: node.prefix }) : null,
|
|
1085
|
+
showIcon ? /* @__PURE__ */ jsx2("span", { className: "sia-tree__icon", children: node.icon ?? /* @__PURE__ */ jsx2(Icon, { name: hasChildren ? "folder" : "file", size: 15 }) }) : null,
|
|
1086
|
+
/* @__PURE__ */ jsx2(
|
|
1087
|
+
"button",
|
|
1088
|
+
{
|
|
1089
|
+
type: "button",
|
|
1090
|
+
className: "sia-tree__title",
|
|
1091
|
+
disabled: node.disabled,
|
|
1092
|
+
onPointerDown: canDrag ? (event) => beginPointerDrag(node, event) : void 0,
|
|
1093
|
+
onPointerMove: canDrag ? movePointerDrag : void 0,
|
|
1094
|
+
onPointerUp: canDrag ? finishPointerDrag : void 0,
|
|
1095
|
+
onPointerCancel: canDrag ? cancelPointerDrag : void 0,
|
|
1096
|
+
children: node.title
|
|
1097
|
+
}
|
|
1098
|
+
),
|
|
1099
|
+
nodeLoading ? /* @__PURE__ */ jsx2("span", { className: "sia-tree__loading-text", role: "status", children: node.loadingText ?? "\u6B63\u5728\u52A0\u8F7D\u2026" }) : null,
|
|
1100
|
+
node.extra ? /* @__PURE__ */ jsx2("span", { className: "sia-tree__extra", onClick: (event) => event.stopPropagation(), children: node.extra }) : null
|
|
1101
|
+
] });
|
|
1102
|
+
return node.contextMenu ? /* @__PURE__ */ jsx2(
|
|
1103
|
+
Dropdown,
|
|
1104
|
+
{
|
|
1105
|
+
className: "sia-tree__context-trigger",
|
|
1106
|
+
popupClassName: node.contextMenuPopupClassName,
|
|
1107
|
+
trigger: ["contextMenu"],
|
|
1108
|
+
menu: node.contextMenu,
|
|
1109
|
+
onContextMenu: (event) => selectForContextMenu(node, event),
|
|
1110
|
+
children: content
|
|
1111
|
+
}
|
|
1112
|
+
) : content;
|
|
1113
|
+
})()
|
|
1114
|
+
}
|
|
1115
|
+
),
|
|
1116
|
+
options.children
|
|
1117
|
+
]
|
|
1118
|
+
},
|
|
1119
|
+
options.reactKey ?? node.key
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
function render(nodes, depth = 0) {
|
|
1123
|
+
return nodes.map((node, siblingIndex) => renderNode(node, depth, {
|
|
1124
|
+
positionInSet: siblingIndex + 1,
|
|
1125
|
+
setSize: nodes.length,
|
|
1126
|
+
children: expandedKeySet.has(node.key) && node.children?.length ? /* @__PURE__ */ jsx2("div", { className: "sia-tree__children", role: "group", children: render(node.children, depth + 1) }) : null
|
|
1127
|
+
}));
|
|
1128
|
+
}
|
|
1129
|
+
const stickyVirtualKeySet = new Set(virtualStickyNodes.map((item) => item.node.key));
|
|
1130
|
+
const virtualContent = virtualEnabled ? /* @__PURE__ */ jsxs2("div", { className: "sia-tree__virtual-space", style: { height: flatNodes.length * normalizedVirtualItemHeight }, children: [
|
|
1131
|
+
virtualStickyNodes.length ? /* @__PURE__ */ jsx2("div", { className: "sia-tree__virtual-sticky-layer", children: virtualStickyNodes.map((item, stickySlot) => renderNode(item.node, item.depth, {
|
|
1132
|
+
reactKey: `sticky-${String(item.node.key)}`,
|
|
1133
|
+
stickySlot,
|
|
1134
|
+
positionInSet: item.positionInSet,
|
|
1135
|
+
setSize: item.setSize
|
|
1136
|
+
})) }) : null,
|
|
1137
|
+
flatNodes.slice(virtualWindow.start, virtualWindow.end).filter((item) => !stickyVirtualKeySet.has(item.node.key)).map((item) => renderNode(item.node, item.depth, {
|
|
1138
|
+
reactKey: `virtual-${String(item.node.key)}`,
|
|
1139
|
+
virtualTop: item.index * normalizedVirtualItemHeight,
|
|
1140
|
+
positionInSet: item.positionInSet,
|
|
1141
|
+
setSize: item.setSize
|
|
1142
|
+
}))
|
|
1143
|
+
] }) : render(treeData);
|
|
1144
|
+
return /* @__PURE__ */ jsxs2("div", { ref: scrollRef, className: `sia-tree${showLine ? " sia-tree--line" : ""}${stickyAncestors ? " sia-tree--sticky-ancestors" : ""}${virtualEnabled ? " sia-tree--virtual" : ""} ${className}`.trim(), role: "tree", "aria-multiselectable": multiple || void 0, "data-sia-tree-virtualized": virtualEnabled || void 0, ...withTitleTooltip(props), children: [
|
|
1145
|
+
virtualContent,
|
|
1146
|
+
/* @__PURE__ */ jsx2(FloatingScrollbarProvider, { targetRef: scrollRef })
|
|
1147
|
+
] });
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
// src/components/Modal.tsx
|
|
1151
|
+
import { forwardRef as forwardRef2, useEffect as useEffect6, useId as useId3, useRef as useRef4, useState as useState2 } from "react";
|
|
1152
|
+
import { createRoot } from "react-dom/client";
|
|
1153
|
+
|
|
1154
|
+
// src/components/Overlay.tsx
|
|
1155
|
+
import { useEffect as useEffect5, useRef as useRef3 } from "react";
|
|
1156
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
1157
|
+
var bodyLockCount = 0;
|
|
1158
|
+
var previousBodyOverflow = "";
|
|
1159
|
+
var overlayStack = [];
|
|
1160
|
+
function lockBodyScroll() {
|
|
1161
|
+
if (bodyLockCount === 0) {
|
|
1162
|
+
previousBodyOverflow = document.body.style.overflow;
|
|
1163
|
+
document.body.style.overflow = "hidden";
|
|
1164
|
+
}
|
|
1165
|
+
bodyLockCount += 1;
|
|
1166
|
+
return () => {
|
|
1167
|
+
bodyLockCount = Math.max(0, bodyLockCount - 1);
|
|
1168
|
+
if (bodyLockCount === 0) document.body.style.overflow = previousBodyOverflow;
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
function focusableElements(container) {
|
|
1172
|
+
return [...container.querySelectorAll(
|
|
1173
|
+
'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
|
|
1174
|
+
)].filter((element) => !element.hidden && element.getAttribute("aria-hidden") !== "true");
|
|
1175
|
+
}
|
|
1176
|
+
function useOverlayLifecycle(open, panelRef, onRequestClose, keyboard = true) {
|
|
1177
|
+
const overlayIdRef = useRef3(/* @__PURE__ */ Symbol("sia-overlay"));
|
|
1178
|
+
const closeRef = useRef3(onRequestClose);
|
|
1179
|
+
closeRef.current = onRequestClose;
|
|
1180
|
+
useEffect5(() => {
|
|
1181
|
+
if (!open || typeof document === "undefined") return void 0;
|
|
1182
|
+
const overlayId = overlayIdRef.current;
|
|
1183
|
+
const previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
1184
|
+
overlayStack.push(overlayId);
|
|
1185
|
+
const unlockBody = lockBodyScroll();
|
|
1186
|
+
const focusTimer = window.setTimeout(() => {
|
|
1187
|
+
const panel = panelRef.current;
|
|
1188
|
+
if (!panel) return;
|
|
1189
|
+
const [firstFocusable] = focusableElements(panel);
|
|
1190
|
+
(firstFocusable ?? panel).focus({ preventScroll: true });
|
|
1191
|
+
}, 0);
|
|
1192
|
+
function handleKeyDown(event) {
|
|
1193
|
+
if (overlayStack.at(-1) !== overlayId) return;
|
|
1194
|
+
if (event.key === "Escape" && keyboard) {
|
|
1195
|
+
event.preventDefault();
|
|
1196
|
+
closeRef.current();
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
if (event.key !== "Tab" || !panelRef.current) return;
|
|
1200
|
+
const focusable = focusableElements(panelRef.current);
|
|
1201
|
+
if (focusable.length === 0) {
|
|
1202
|
+
event.preventDefault();
|
|
1203
|
+
panelRef.current.focus();
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
const first = focusable[0];
|
|
1207
|
+
const last = focusable.at(-1);
|
|
1208
|
+
if (event.shiftKey && document.activeElement === first) {
|
|
1209
|
+
event.preventDefault();
|
|
1210
|
+
last.focus();
|
|
1211
|
+
} else if (!event.shiftKey && document.activeElement === last) {
|
|
1212
|
+
event.preventDefault();
|
|
1213
|
+
first.focus();
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
1343
1217
|
return () => {
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
entries.forEach((entry) => entry.cleanup());
|
|
1351
|
-
entries.clear();
|
|
1352
|
-
layer.remove();
|
|
1218
|
+
window.clearTimeout(focusTimer);
|
|
1219
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
1220
|
+
const index = overlayStack.lastIndexOf(overlayId);
|
|
1221
|
+
if (index >= 0) overlayStack.splice(index, 1);
|
|
1222
|
+
unlockBody();
|
|
1223
|
+
previouslyFocused?.focus({ preventScroll: true });
|
|
1353
1224
|
};
|
|
1354
|
-
}, [
|
|
1355
|
-
|
|
1225
|
+
}, [keyboard, open, panelRef]);
|
|
1226
|
+
}
|
|
1227
|
+
function OverlayPortal({ children, container }) {
|
|
1228
|
+
if (typeof document === "undefined") return null;
|
|
1229
|
+
const target = typeof container === "function" ? container() : container ?? document.body;
|
|
1230
|
+
return createPortal2(children, target);
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// src/components/Modal.tsx
|
|
1234
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1235
|
+
var modalHandles = /* @__PURE__ */ new Set();
|
|
1236
|
+
var MODAL_MOTION_DURATION = 220;
|
|
1237
|
+
var typeIcons = {
|
|
1238
|
+
info: /* @__PURE__ */ jsx3(Icon, { name: "info", size: 23 }),
|
|
1239
|
+
success: /* @__PURE__ */ jsx3(Icon, { name: "circle-check", size: 23 }),
|
|
1240
|
+
warning: /* @__PURE__ */ jsx3(Icon, { name: "warning", size: 23 }),
|
|
1241
|
+
error: /* @__PURE__ */ jsx3(Icon, { name: "circle-close", size: 23 }),
|
|
1242
|
+
confirm: /* @__PURE__ */ jsx3(Icon, { name: "question", size: 23 })
|
|
1243
|
+
};
|
|
1244
|
+
var ModalRoot = forwardRef2(function Modal({
|
|
1245
|
+
open,
|
|
1246
|
+
title,
|
|
1247
|
+
children,
|
|
1248
|
+
footer,
|
|
1249
|
+
footerExtra,
|
|
1250
|
+
type = "default",
|
|
1251
|
+
okText = "\u786E\u5B9A",
|
|
1252
|
+
cancelText = "\u53D6\u6D88",
|
|
1253
|
+
showCancel = type === "default" || type === "confirm",
|
|
1254
|
+
confirmLoading = false,
|
|
1255
|
+
okButtonProps,
|
|
1256
|
+
cancelButtonProps,
|
|
1257
|
+
closable = true,
|
|
1258
|
+
maskClosable = true,
|
|
1259
|
+
keyboard = true,
|
|
1260
|
+
centered = false,
|
|
1261
|
+
width = 520,
|
|
1262
|
+
height,
|
|
1263
|
+
zIndex = 1e3,
|
|
1264
|
+
getContainer,
|
|
1265
|
+
onOk,
|
|
1266
|
+
onCancel,
|
|
1267
|
+
onOpenChange,
|
|
1268
|
+
afterOpenChange,
|
|
1269
|
+
className = "",
|
|
1270
|
+
style,
|
|
1271
|
+
...props
|
|
1272
|
+
}, forwardedRef) {
|
|
1273
|
+
const localRef = useRef4(null);
|
|
1274
|
+
const titleId = useId3();
|
|
1275
|
+
const [submitting, setSubmitting] = useState2(false);
|
|
1276
|
+
const [rendered, setRendered] = useState2(open);
|
|
1277
|
+
const [closing, setClosing] = useState2(false);
|
|
1278
|
+
const afterOpenChangeRef = useRef4(afterOpenChange);
|
|
1279
|
+
afterOpenChangeRef.current = afterOpenChange;
|
|
1280
|
+
const submitLock = useRef4(false);
|
|
1281
|
+
useEffect6(() => {
|
|
1282
|
+
if (!open || !rendered) return void 0;
|
|
1283
|
+
const timer = window.setTimeout(() => afterOpenChangeRef.current?.(true), MODAL_MOTION_DURATION);
|
|
1284
|
+
return () => window.clearTimeout(timer);
|
|
1285
|
+
}, [open, rendered]);
|
|
1286
|
+
useEffect6(() => {
|
|
1287
|
+
if (open) {
|
|
1288
|
+
setRendered(true);
|
|
1289
|
+
setClosing(false);
|
|
1290
|
+
return void 0;
|
|
1291
|
+
}
|
|
1292
|
+
if (!rendered) return void 0;
|
|
1293
|
+
setClosing(true);
|
|
1294
|
+
const timer = window.setTimeout(() => {
|
|
1295
|
+
setRendered(false);
|
|
1296
|
+
setClosing(false);
|
|
1297
|
+
afterOpenChangeRef.current?.(false);
|
|
1298
|
+
}, MODAL_MOTION_DURATION);
|
|
1299
|
+
return () => window.clearTimeout(timer);
|
|
1300
|
+
}, [open, rendered]);
|
|
1301
|
+
function setRef(node) {
|
|
1302
|
+
localRef.current = node;
|
|
1303
|
+
if (typeof forwardedRef === "function") forwardedRef(node);
|
|
1304
|
+
else if (forwardedRef) forwardedRef.current = node;
|
|
1305
|
+
}
|
|
1306
|
+
function requestClose() {
|
|
1307
|
+
if (submitting || confirmLoading) return;
|
|
1308
|
+
onCancel?.();
|
|
1309
|
+
onOpenChange?.(false);
|
|
1310
|
+
}
|
|
1311
|
+
async function handleOk() {
|
|
1312
|
+
if (submitLock.current || confirmLoading) return;
|
|
1313
|
+
submitLock.current = true;
|
|
1314
|
+
if (!onOk) {
|
|
1315
|
+
onOpenChange?.(false);
|
|
1316
|
+
submitLock.current = false;
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
try {
|
|
1320
|
+
const result = onOk();
|
|
1321
|
+
if (result instanceof Promise) {
|
|
1322
|
+
setSubmitting(true);
|
|
1323
|
+
const resolved = await result;
|
|
1324
|
+
if (resolved !== false) onOpenChange?.(false);
|
|
1325
|
+
} else if (result !== false) {
|
|
1326
|
+
onOpenChange?.(false);
|
|
1327
|
+
}
|
|
1328
|
+
} catch {
|
|
1329
|
+
return;
|
|
1330
|
+
} finally {
|
|
1331
|
+
submitLock.current = false;
|
|
1332
|
+
setSubmitting(false);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
useOverlayLifecycle(rendered, localRef, requestClose, keyboard);
|
|
1336
|
+
if (!rendered) return null;
|
|
1337
|
+
const mergedStyle = {
|
|
1338
|
+
...height !== void 0 ? { display: "flex", flexDirection: "column", height, maxHeight: "calc(100dvh - 48px)" } : {},
|
|
1339
|
+
...style,
|
|
1340
|
+
"--sia-modal-width": typeof width === "number" ? `${width}px` : width
|
|
1341
|
+
};
|
|
1342
|
+
const loading = submitting || confirmLoading;
|
|
1343
|
+
const defaultFooter = /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1344
|
+
showCancel ? /* @__PURE__ */ jsx3(Button, { ...cancelButtonProps, onClick: requestClose, disabled: loading || cancelButtonProps?.disabled, children: cancelText }) : null,
|
|
1345
|
+
/* @__PURE__ */ jsx3(Button, { variant: "primary", ...okButtonProps, onClick: handleOk, loading, children: okText })
|
|
1346
|
+
] });
|
|
1347
|
+
return /* @__PURE__ */ jsx3(OverlayPortal, { container: getContainer, children: /* @__PURE__ */ jsx3(
|
|
1348
|
+
"div",
|
|
1349
|
+
{
|
|
1350
|
+
className: `sia-modal-root${centered ? " sia-modal-root--centered" : ""}`,
|
|
1351
|
+
"data-state": closing ? "closing" : "open",
|
|
1352
|
+
style: { zIndex },
|
|
1353
|
+
onMouseDown: (event) => {
|
|
1354
|
+
if (event.target === event.currentTarget && maskClosable) requestClose();
|
|
1355
|
+
},
|
|
1356
|
+
children: /* @__PURE__ */ jsxs3(
|
|
1357
|
+
"div",
|
|
1358
|
+
{
|
|
1359
|
+
ref: setRef,
|
|
1360
|
+
className: `sia-modal sia-modal--${type} ${className}`.trim(),
|
|
1361
|
+
style: mergedStyle,
|
|
1362
|
+
role: "dialog",
|
|
1363
|
+
"aria-modal": "true",
|
|
1364
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
1365
|
+
tabIndex: -1,
|
|
1366
|
+
...withTitleTooltip(props),
|
|
1367
|
+
children: [
|
|
1368
|
+
/* @__PURE__ */ jsxs3("div", { className: "sia-modal__header", style: height !== void 0 ? { flexShrink: 0 } : void 0, children: [
|
|
1369
|
+
/* @__PURE__ */ jsxs3("div", { className: "sia-modal__heading", children: [
|
|
1370
|
+
typeIcons[type] ? /* @__PURE__ */ jsx3("span", { className: "sia-modal__type-icon", "aria-hidden": "true", children: typeIcons[type] }) : null,
|
|
1371
|
+
title ? /* @__PURE__ */ jsx3("strong", { id: titleId, children: title }) : null
|
|
1372
|
+
] }),
|
|
1373
|
+
closable ? /* @__PURE__ */ jsx3("button", { type: "button", className: "sia-modal__close", "aria-label": "\u5173\u95ED\u5BF9\u8BDD\u6846", onClick: requestClose, children: /* @__PURE__ */ jsx3(Icon, { name: "close", size: 17 }) }) : null
|
|
1374
|
+
] }),
|
|
1375
|
+
children !== void 0 ? /* @__PURE__ */ jsx3("div", { className: "sia-modal__body", style: height !== void 0 ? { flex: 1, minHeight: 0, overflow: "auto" } : void 0, children }) : null,
|
|
1376
|
+
footer !== null ? /* @__PURE__ */ jsxs3("div", { className: "sia-modal__footer", style: height !== void 0 ? { flexShrink: 0 } : void 0, children: [
|
|
1377
|
+
footer === void 0 && footerExtra != null ? /* @__PURE__ */ jsx3("div", { style: { marginRight: "auto" }, children: footerExtra }) : null,
|
|
1378
|
+
footer ?? defaultFooter
|
|
1379
|
+
] }) : null
|
|
1380
|
+
]
|
|
1381
|
+
}
|
|
1382
|
+
)
|
|
1383
|
+
}
|
|
1384
|
+
) });
|
|
1385
|
+
});
|
|
1386
|
+
function openModal(config) {
|
|
1387
|
+
if (typeof document === "undefined") return { destroy() {
|
|
1388
|
+
}, update() {
|
|
1389
|
+
} };
|
|
1390
|
+
const container = document.createElement("div");
|
|
1391
|
+
container.className = "sia-modal-api-host";
|
|
1392
|
+
document.body.appendChild(container);
|
|
1393
|
+
const root = createRoot(container);
|
|
1394
|
+
let currentConfig = config;
|
|
1395
|
+
let currentOpen = true;
|
|
1396
|
+
let destroyed = false;
|
|
1397
|
+
let cleanupTimer;
|
|
1398
|
+
function cleanup2() {
|
|
1399
|
+
if (destroyed) return;
|
|
1400
|
+
destroyed = true;
|
|
1401
|
+
if (cleanupTimer !== void 0) window.clearTimeout(cleanupTimer);
|
|
1402
|
+
root.unmount();
|
|
1403
|
+
container.remove();
|
|
1404
|
+
modalHandles.delete(handle);
|
|
1405
|
+
}
|
|
1406
|
+
function closeWithMotion() {
|
|
1407
|
+
if (destroyed || !currentOpen) return;
|
|
1408
|
+
currentOpen = false;
|
|
1409
|
+
render();
|
|
1410
|
+
cleanupTimer = window.setTimeout(cleanup2, MODAL_MOTION_DURATION);
|
|
1411
|
+
}
|
|
1412
|
+
function render() {
|
|
1413
|
+
root.render(/* @__PURE__ */ jsx3(ModalRoot, { ...currentConfig, open: currentOpen, onOpenChange: (nextOpen) => {
|
|
1414
|
+
currentConfig.onOpenChange?.(nextOpen);
|
|
1415
|
+
if (!nextOpen) closeWithMotion();
|
|
1416
|
+
} }));
|
|
1417
|
+
}
|
|
1418
|
+
const handle = {
|
|
1419
|
+
destroy: closeWithMotion,
|
|
1420
|
+
update(next) {
|
|
1421
|
+
if (destroyed) return;
|
|
1422
|
+
currentConfig = { ...currentConfig, ...next };
|
|
1423
|
+
render();
|
|
1424
|
+
}
|
|
1425
|
+
};
|
|
1426
|
+
modalHandles.add(handle);
|
|
1427
|
+
render();
|
|
1428
|
+
return handle;
|
|
1429
|
+
}
|
|
1430
|
+
function preset(type, defaults = {}) {
|
|
1431
|
+
return (config) => openModal({
|
|
1432
|
+
okText: type === "confirm" ? "\u786E\u5B9A" : "\u77E5\u9053\u4E86",
|
|
1433
|
+
showCancel: type === "confirm",
|
|
1434
|
+
closable: type !== "confirm",
|
|
1435
|
+
maskClosable: type !== "confirm",
|
|
1436
|
+
...defaults,
|
|
1437
|
+
...config,
|
|
1438
|
+
type
|
|
1439
|
+
});
|
|
1356
1440
|
}
|
|
1441
|
+
var Modal2 = Object.assign(ModalRoot, {
|
|
1442
|
+
/** 直接打开实例,返回可用于更新或关闭的操作句柄。 */
|
|
1443
|
+
open: openModal,
|
|
1444
|
+
/** 显示普通信息提示。 */
|
|
1445
|
+
info: preset("info", { title: "\u63D0\u793A" }),
|
|
1446
|
+
/** 显示成功提示。 */
|
|
1447
|
+
success: preset("success", { title: "\u64CD\u4F5C\u6210\u529F" }),
|
|
1448
|
+
/** 显示警告提示。 */
|
|
1449
|
+
warning: preset("warning", { title: "\u8BF7\u6CE8\u610F" }),
|
|
1450
|
+
/** 显示错误提示。 */
|
|
1451
|
+
error: preset("error", { title: "\u64CD\u4F5C\u5931\u8D25" }),
|
|
1452
|
+
/** 打开确认弹框,支持异步确认;返回 false 可阻止关闭。 */
|
|
1453
|
+
confirm: preset("confirm", { title: "\u786E\u8BA4\u64CD\u4F5C" }),
|
|
1454
|
+
/** 关闭由此 API 打开的所有弹层。 */
|
|
1455
|
+
destroyAll() {
|
|
1456
|
+
[...modalHandles].forEach((handle) => handle.destroy());
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1357
1459
|
|
|
1358
1460
|
// src/components/SelectionPanel.tsx
|
|
1359
1461
|
import { useEffect as useEffect7, useId as useId4, useMemo as useMemo3, useRef as useRef5, useState as useState3 } from "react";
|
|
@@ -2075,6 +2177,8 @@ var Select = forwardRef3(function Select2({
|
|
|
2075
2177
|
|
|
2076
2178
|
export {
|
|
2077
2179
|
Checkbox2 as Checkbox,
|
|
2180
|
+
useScrollbarProximity,
|
|
2181
|
+
FloatingScrollbarProvider,
|
|
2078
2182
|
Tooltip,
|
|
2079
2183
|
Popover,
|
|
2080
2184
|
Timeline,
|
|
@@ -2082,8 +2186,6 @@ export {
|
|
|
2082
2186
|
useOverlayLifecycle,
|
|
2083
2187
|
OverlayPortal,
|
|
2084
2188
|
Modal2 as Modal,
|
|
2085
|
-
useScrollbarProximity,
|
|
2086
|
-
FloatingScrollbarProvider,
|
|
2087
2189
|
SelectionPanel,
|
|
2088
2190
|
OverflowTags,
|
|
2089
2191
|
Select
|