@sia.soul/sia-react-ui 0.1.39 → 0.1.41

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/core.cjs CHANGED
@@ -1831,505 +1831,162 @@ function Tag({
1831
1831
  }
1832
1832
 
1833
1833
  // src/components/Tabs.tsx
1834
- var import_react12 = require("react");
1835
-
1836
- // src/components/FloatingScrollbarProvider.tsx
1837
- var import_react11 = require("react");
1838
-
1839
- // src/components/useScrollbarProximity.ts
1840
1834
  var import_react10 = require("react");
1841
- var users = 0;
1842
- var cleanup;
1843
- function useScrollbarProximity() {
1835
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1836
+ var import_react11 = require("react");
1837
+ function Tabs({
1838
+ items,
1839
+ activeKey,
1840
+ defaultActiveKey,
1841
+ onChange,
1842
+ onAfterChange,
1843
+ deferContent = false,
1844
+ type = "line",
1845
+ size = "medium",
1846
+ tabPosition,
1847
+ orientation = "horizontal",
1848
+ centered = false,
1849
+ tabBarTitle,
1850
+ tabBarExtraContent,
1851
+ contentGap,
1852
+ destroyInactiveTabPane = true,
1853
+ closable = false,
1854
+ onEdit,
1855
+ tabContextMenu,
1856
+ onTabContextMenuClick,
1857
+ className = "",
1858
+ ...props
1859
+ }) {
1860
+ const firstEnabledKey = items.find((item) => !item.disabled)?.key ?? "";
1861
+ const [internalActiveKey, setInternalActiveKey] = (0, import_react10.useState)(defaultActiveKey ?? firstEnabledKey);
1862
+ const currentKey = activeKey ?? internalActiveKey;
1863
+ const selectedKey = items.some((item) => item.key === currentKey && !item.disabled) ? currentKey : firstEnabledKey;
1864
+ const baseId = (0, import_react10.useId)().replace(/:/g, "");
1865
+ const enabledItems = (0, import_react10.useMemo)(() => items.filter((item) => !item.disabled), [items]);
1866
+ const resolvedPosition = tabPosition ?? (orientation === "vertical" ? "left" : "top");
1867
+ const resolvedOrientation = resolvedPosition === "left" || resolvedPosition === "right" ? "vertical" : "horizontal";
1868
+ const sliding = ["capsule", "line", "underline", "tech", "tech-line"].includes(type);
1869
+ const listRef = (0, import_react10.useRef)(null);
1870
+ const indicatorRef = (0, import_react10.useRef)(null);
1871
+ const moreRef = (0, import_react10.useRef)(null);
1872
+ const [overflow, setOverflow] = (0, import_react10.useState)({ count: items.length, width: 0 });
1873
+ const [moreOpen, setMoreOpen] = (0, import_react10.useState)(false);
1874
+ const visibleCount = resolvedOrientation === "horizontal" ? overflow.count : items.length;
1875
+ const hiddenItems = items.slice(visibleCount);
1876
+ (0, import_react10.useLayoutEffect)(() => {
1877
+ const list = listRef.current;
1878
+ if (!list || resolvedOrientation !== "horizontal") return;
1879
+ const entries = Array.from(list.children).filter((node) => node instanceof HTMLElement && node.hasAttribute("data-tab-entry"));
1880
+ const measure = () => {
1881
+ const css = getComputedStyle(list);
1882
+ const gap = parseFloat(css.columnGap) || 0;
1883
+ const padding = (parseFloat(css.paddingLeft) || 0) + (parseFloat(css.paddingRight) || 0);
1884
+ const widths = entries.map((node) => node.getBoundingClientRect().width);
1885
+ const total = widths.reduce((sum, width2) => sum + width2, 0) + gap * Math.max(0, widths.length - 1);
1886
+ const available = Math.max(0, list.clientWidth - padding);
1887
+ let count = widths.length;
1888
+ if (total > available + 0.5) {
1889
+ const moreWidth = moreRef.current?.getBoundingClientRect().width ?? 36;
1890
+ let used = moreWidth;
1891
+ count = 0;
1892
+ for (const width2 of widths) {
1893
+ if (used + gap + width2 > available + 0.5) break;
1894
+ used += gap + width2;
1895
+ count++;
1896
+ }
1897
+ }
1898
+ const width = Math.ceil(total + padding + (parseFloat(css.borderLeftWidth) || 0) + (parseFloat(css.borderRightWidth) || 0));
1899
+ setOverflow((previous) => previous.count === count && previous.width === width ? previous : { count, width });
1900
+ };
1901
+ measure();
1902
+ const observer = new ResizeObserver(measure);
1903
+ observer.observe(list);
1904
+ entries.forEach((entry) => observer.observe(entry));
1905
+ return () => observer.disconnect();
1906
+ }, [items, type, size, closable, resolvedOrientation, tabBarTitle, tabBarExtraContent]);
1907
+ const [contentState, setContentState] = (0, import_react10.useState)(() => ({ key: selectedKey, visited: /* @__PURE__ */ new Set([selectedKey]) }));
1908
+ const settledKeyRef = (0, import_react10.useRef)(selectedKey);
1909
+ const afterChangeRef = (0, import_react10.useRef)(onAfterChange);
1910
+ (0, import_react10.useLayoutEffect)(() => {
1911
+ afterChangeRef.current = onAfterChange;
1912
+ }, [onAfterChange]);
1913
+ (0, import_react10.useLayoutEffect)(() => {
1914
+ if (!sliding) return;
1915
+ const list = listRef.current;
1916
+ const indicator = indicatorRef.current;
1917
+ if (!list || !indicator) return;
1918
+ function updateIndicator() {
1919
+ if (!list || !indicator) return;
1920
+ const active = list.querySelector('[role="tab"][aria-selected="true"]');
1921
+ if (!active || active.closest('[data-tab-hidden="true"]')) {
1922
+ indicator.style.visibility = "hidden";
1923
+ return;
1924
+ }
1925
+ const listRect = list.getBoundingClientRect();
1926
+ const rect = active.getBoundingClientRect();
1927
+ const currentRect = active.getBoundingClientRect();
1928
+ indicator.style.transform = `translate(${currentRect.left - listRect.left - list.clientLeft + list.scrollLeft}px, ${currentRect.top - listRect.top - list.clientTop + list.scrollTop}px)`;
1929
+ indicator.style.width = `${rect.width}px`;
1930
+ indicator.style.height = `${rect.height}px`;
1931
+ indicator.style.visibility = "visible";
1932
+ if (!indicator.dataset.ready) {
1933
+ indicator.getBoundingClientRect();
1934
+ indicator.dataset.ready = "true";
1935
+ }
1936
+ }
1937
+ updateIndicator();
1938
+ const observer = new ResizeObserver(updateIndicator);
1939
+ observer.observe(list);
1940
+ list.querySelectorAll('[role="tab"]').forEach((tab) => observer.observe(tab));
1941
+ return () => observer.disconnect();
1942
+ }, [sliding, type, selectedKey, items, size, resolvedPosition, centered, closable, visibleCount]);
1844
1943
  (0, import_react10.useEffect)(() => {
1845
- if (users++ === 0) {
1846
- let frame = 0;
1847
- let x = -Infinity;
1848
- let y = -Infinity;
1849
- const nearby = /* @__PURE__ */ new Set();
1850
- const clear = () => {
1851
- nearby.forEach((track) => track.removeAttribute("data-scrollbar-near"));
1852
- nearby.clear();
1853
- };
1854
- const update = () => {
1855
- frame = 0;
1856
- const next = /* @__PURE__ */ new Set();
1857
- document.querySelectorAll(".sia-scrollbar-track").forEach((track) => {
1858
- const rect = track.getBoundingClientRect();
1859
- const proximity = Number.parseFloat(getComputedStyle(track).getPropertyValue("--sia-scrollbar-proximity")) || 16;
1860
- if (rect.width && rect.height && x >= rect.left - proximity && x <= rect.right + proximity && y >= rect.top - proximity && y <= rect.bottom + proximity) {
1861
- next.add(track);
1862
- if (!nearby.has(track)) track.setAttribute("data-scrollbar-near", "true");
1863
- }
1864
- });
1865
- nearby.forEach((track) => {
1866
- if (!next.has(track)) track.removeAttribute("data-scrollbar-near");
1867
- });
1868
- nearby.clear();
1869
- next.forEach((track) => nearby.add(track));
1870
- };
1871
- const move = (event) => {
1872
- if (event.pointerType === "touch") return;
1873
- x = event.clientX;
1874
- y = event.clientY;
1875
- if (!frame) frame = requestAnimationFrame(update);
1876
- };
1877
- const leave = () => {
1878
- x = y = -Infinity;
1879
- clear();
1880
- };
1881
- document.addEventListener("pointermove", move, { passive: true });
1882
- document.documentElement.addEventListener("pointerleave", leave);
1883
- window.addEventListener("blur", leave);
1884
- cleanup = () => {
1885
- if (frame) cancelAnimationFrame(frame);
1886
- document.removeEventListener("pointermove", move);
1887
- document.documentElement.removeEventListener("pointerleave", leave);
1888
- window.removeEventListener("blur", leave);
1889
- clear();
1944
+ let cancelled = false;
1945
+ let frame = 0;
1946
+ frame = requestAnimationFrame(() => {
1947
+ const indicator = indicatorRef.current;
1948
+ if (indicator) getComputedStyle(indicator).transform;
1949
+ const animations = indicator?.getAnimations() ?? [];
1950
+ const complete = () => {
1951
+ if (cancelled) return;
1952
+ setContentState((previous) => ({ key: selectedKey, visited: new Set([...previous.visited].filter((key) => items.some((item) => item.key === key))).add(selectedKey) }));
1953
+ if (settledKeyRef.current !== selectedKey) {
1954
+ settledKeyRef.current = selectedKey;
1955
+ afterChangeRef.current?.(selectedKey);
1956
+ }
1890
1957
  };
1891
- }
1958
+ if (!animations.length) complete();
1959
+ else Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {
1960
+ if (!cancelled) frame = requestAnimationFrame(complete);
1961
+ });
1962
+ });
1892
1963
  return () => {
1893
- if (--users === 0) {
1894
- cleanup?.();
1895
- cleanup = void 0;
1896
- }
1964
+ cancelled = true;
1965
+ cancelAnimationFrame(frame);
1897
1966
  };
1898
- }, []);
1899
- }
1900
-
1901
- // src/components/FloatingScrollbarProvider.tsx
1902
- var scrollableOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay"]);
1903
- var clippingOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay", "hidden", "clip"]);
1904
- function isRootScroller(target) {
1905
- return target === document.scrollingElement || target === document.documentElement;
1906
- }
1907
- function canScroll(target, axis) {
1908
- if (target.matches(".sia-table__viewport, [data-sia-native-scrollbar]")) return false;
1909
- if (isRootScroller(target)) {
1910
- return axis === "horizontal" ? target.scrollWidth > target.clientWidth + 1 : target.scrollHeight > target.clientHeight + 1;
1967
+ }, [selectedKey, type, deferContent]);
1968
+ const contentKey = deferContent ? contentState.key : selectedKey;
1969
+ function selectTab(key) {
1970
+ if (key === selectedKey) return;
1971
+ if (activeKey === void 0) setInternalActiveKey(key);
1972
+ onChange?.(key);
1911
1973
  }
1912
- const style = getComputedStyle(target);
1913
- const overflow = axis === "horizontal" ? style.overflowX : style.overflowY;
1914
- const hasOverflow = axis === "horizontal" ? target.scrollWidth > target.clientWidth + 1 : target.scrollHeight > target.clientHeight + 1;
1915
- return hasOverflow && scrollableOverflow.has(overflow);
1916
- }
1917
- function visibleRect(target) {
1918
- if (isRootScroller(target)) {
1919
- return { top: 0, right: window.innerWidth, bottom: window.innerHeight, left: 0, width: window.innerWidth, height: window.innerHeight };
1974
+ function focusAndSelect(key) {
1975
+ selectTab(key);
1976
+ if (items.findIndex((item) => item.key === key) >= visibleCount) moreRef.current?.focus();
1977
+ else document.getElementById(`${baseId}-tab-${key}`)?.focus();
1920
1978
  }
1921
- const ownRect = target.getBoundingClientRect();
1922
- let top = Math.max(0, ownRect.top);
1923
- let right = Math.min(window.innerWidth, ownRect.right);
1924
- let bottom = Math.min(window.innerHeight, ownRect.bottom);
1925
- let left = Math.max(0, ownRect.left);
1926
- let parent = target.parentElement;
1927
- while (parent && parent !== document.body && parent !== document.documentElement) {
1928
- const style = getComputedStyle(parent);
1929
- const clipX = clippingOverflow.has(style.overflowX);
1930
- const clipY = clippingOverflow.has(style.overflowY);
1931
- if (clipX || clipY) {
1932
- const rect = parent.getBoundingClientRect();
1933
- if (clipX) {
1934
- left = Math.max(left, rect.left);
1935
- right = Math.min(right, rect.right);
1936
- }
1937
- if (clipY) {
1938
- top = Math.max(top, rect.top);
1939
- bottom = Math.min(bottom, rect.bottom);
1940
- }
1941
- }
1942
- parent = parent.parentElement;
1943
- }
1944
- return {
1945
- top,
1946
- right,
1947
- bottom,
1948
- left,
1949
- width: Math.max(0, right - left),
1950
- height: Math.max(0, bottom - top)
1951
- };
1952
- }
1953
- function createTrack(axis) {
1954
- const track = document.createElement("div");
1955
- const thumb = document.createElement("div");
1956
- track.className = `sia-scrollbar-track sia-floating-scrollbar sia-floating-scrollbar--${axis}`;
1957
- thumb.className = "sia-floating-scrollbar__thumb";
1958
- track.dataset.axis = axis;
1959
- track.setAttribute("aria-hidden", "true");
1960
- track.append(thumb);
1961
- return { track, thumb };
1962
- }
1963
- function FloatingScrollbarProvider({ disabled = false, targetRef }) {
1964
- useScrollbarProximity();
1965
- (0, import_react11.useEffect)(() => {
1966
- if (disabled) return;
1967
- const layer = document.createElement("div");
1968
- layer.className = "sia-floating-scrollbar-layer";
1969
- layer.setAttribute("aria-hidden", "true");
1970
- document.body.append(layer);
1971
- const entries = /* @__PURE__ */ new Map();
1972
- let scanFrame = 0;
1973
- let updateFrame = 0;
1974
- const setEntryVisible = (entry, visible) => {
1975
- entry.horizontalTrack.classList.toggle("sia-floating-scrollbar--visible", visible);
1976
- entry.verticalTrack.classList.toggle("sia-floating-scrollbar--visible", visible);
1977
- };
1978
- const showEntry = (entry) => {
1979
- if (entry.hideTimer !== null) window.clearTimeout(entry.hideTimer);
1980
- entry.hideTimer = null;
1981
- setEntryVisible(entry, true);
1982
- };
1983
- const scheduleHide = (entry, delay = 500) => {
1984
- if (entry.hideTimer !== null) window.clearTimeout(entry.hideTimer);
1985
- entry.hideTimer = window.setTimeout(() => {
1986
- entry.hideTimer = null;
1987
- if (!entry.hoveringTarget && !entry.hoveringTrack && !entry.dragging) setEntryVisible(entry, false);
1988
- }, delay);
1989
- };
1990
- const updateEntry = (entry) => {
1991
- const { target, horizontalTrack, horizontalThumb, verticalTrack, verticalThumb } = entry;
1992
- const hasHorizontal = canScroll(target, "horizontal");
1993
- const hasVertical = canScroll(target, "vertical");
1994
- const rect = visibleRect(target);
1995
- const thickness = 10;
1996
- horizontalTrack.hidden = !hasHorizontal || rect.width <= thickness || rect.height <= 0;
1997
- verticalTrack.hidden = !hasVertical || rect.height <= thickness || rect.width <= 0;
1998
- if (!horizontalTrack.hidden) {
1999
- const trackWidth = Math.max(0, rect.width - (hasVertical ? thickness : 0));
2000
- const thumbWidth = Math.max(24, Math.min(trackWidth, trackWidth * target.clientWidth / target.scrollWidth));
2001
- const travel = Math.max(0, trackWidth - thumbWidth);
2002
- const maxScroll = Math.max(1, target.scrollWidth - target.clientWidth);
2003
- horizontalTrack.style.left = `${rect.left}px`;
2004
- horizontalTrack.style.top = `${rect.bottom - thickness}px`;
2005
- horizontalTrack.style.width = `${trackWidth}px`;
2006
- horizontalTrack.style.height = `${thickness}px`;
2007
- horizontalThumb.style.width = `${thumbWidth}px`;
2008
- horizontalThumb.style.transform = `translate3d(${travel * target.scrollLeft / maxScroll}px, 0, 0)`;
2009
- }
2010
- if (!verticalTrack.hidden) {
2011
- const trackHeight = Math.max(0, rect.height - (hasHorizontal ? thickness : 0));
2012
- const thumbHeight = Math.max(24, Math.min(trackHeight, trackHeight * target.clientHeight / target.scrollHeight));
2013
- const travel = Math.max(0, trackHeight - thumbHeight);
2014
- const maxScroll = Math.max(1, target.scrollHeight - target.clientHeight);
2015
- verticalTrack.style.left = `${rect.right - thickness}px`;
2016
- verticalTrack.style.top = `${rect.top}px`;
2017
- verticalTrack.style.width = `${thickness}px`;
2018
- verticalTrack.style.height = `${trackHeight}px`;
2019
- verticalThumb.style.height = `${thumbHeight}px`;
2020
- verticalThumb.style.transform = `translate3d(0, ${travel * target.scrollTop / maxScroll}px, 0)`;
2021
- }
2022
- };
2023
- const scheduleUpdateAll = () => {
2024
- if (updateFrame) return;
2025
- updateFrame = window.requestAnimationFrame(() => {
2026
- updateFrame = 0;
2027
- entries.forEach(updateEntry);
2028
- });
2029
- };
2030
- const bindTrackDrag = (entry, axis, track, thumb) => {
2031
- const target = entry.target;
2032
- const onTrackPointerEnter = () => {
2033
- entry.hoveringTrack = true;
2034
- showEntry(entry);
2035
- };
2036
- const onTrackPointerLeave = () => {
2037
- entry.hoveringTrack = false;
2038
- scheduleHide(entry);
2039
- };
2040
- const onTrackPointerDown = (event) => {
2041
- if (event.target === thumb || event.button !== 0) return;
2042
- event.preventDefault();
2043
- event.stopPropagation();
2044
- const trackRect = track.getBoundingClientRect();
2045
- const thumbRect = thumb.getBoundingClientRect();
2046
- const trackLength = axis === "vertical" ? trackRect.height : trackRect.width;
2047
- const thumbLength = axis === "vertical" ? thumbRect.height : thumbRect.width;
2048
- const pointer = axis === "vertical" ? event.clientY - trackRect.top : event.clientX - trackRect.left;
2049
- const ratio = Math.max(0, Math.min(1, (pointer - thumbLength / 2) / Math.max(1, trackLength - thumbLength)));
2050
- if (axis === "vertical") target.scrollTop = ratio * (target.scrollHeight - target.clientHeight);
2051
- else target.scrollLeft = ratio * (target.scrollWidth - target.clientWidth);
2052
- };
2053
- const onThumbPointerDown = (event) => {
2054
- if (event.button !== 0) return;
2055
- event.preventDefault();
2056
- event.stopPropagation();
2057
- entry.dragging = true;
2058
- showEntry(entry);
2059
- thumb.setPointerCapture(event.pointerId);
2060
- const startPointer = axis === "vertical" ? event.clientY : event.clientX;
2061
- const startScroll = axis === "vertical" ? target.scrollTop : target.scrollLeft;
2062
- const trackRect = track.getBoundingClientRect();
2063
- const thumbRect = thumb.getBoundingClientRect();
2064
- const trackLength = axis === "vertical" ? trackRect.height : trackRect.width;
2065
- const thumbLength = axis === "vertical" ? thumbRect.height : thumbRect.width;
2066
- const maxScroll = axis === "vertical" ? target.scrollHeight - target.clientHeight : target.scrollWidth - target.clientWidth;
2067
- const travel = Math.max(1, trackLength - thumbLength);
2068
- const onPointerMove = (moveEvent) => {
2069
- if (moveEvent.pointerId !== event.pointerId) return;
2070
- const pointer = axis === "vertical" ? moveEvent.clientY : moveEvent.clientX;
2071
- const nextScroll = startScroll + (pointer - startPointer) * maxScroll / travel;
2072
- if (axis === "vertical") target.scrollTop = nextScroll;
2073
- else target.scrollLeft = nextScroll;
2074
- };
2075
- const onPointerUp = (upEvent) => {
2076
- if (upEvent.pointerId !== event.pointerId) return;
2077
- entry.dragging = false;
2078
- thumb.releasePointerCapture(event.pointerId);
2079
- window.removeEventListener("pointermove", onPointerMove);
2080
- window.removeEventListener("pointerup", onPointerUp);
2081
- window.removeEventListener("pointercancel", onPointerUp);
2082
- scheduleHide(entry);
2083
- };
2084
- window.addEventListener("pointermove", onPointerMove);
2085
- window.addEventListener("pointerup", onPointerUp);
2086
- window.addEventListener("pointercancel", onPointerUp);
2087
- };
2088
- track.addEventListener("pointerenter", onTrackPointerEnter);
2089
- track.addEventListener("pointerleave", onTrackPointerLeave);
2090
- track.addEventListener("pointerdown", onTrackPointerDown);
2091
- thumb.addEventListener("pointerdown", onThumbPointerDown);
2092
- return () => {
2093
- track.removeEventListener("pointerenter", onTrackPointerEnter);
2094
- track.removeEventListener("pointerleave", onTrackPointerLeave);
2095
- track.removeEventListener("pointerdown", onTrackPointerDown);
2096
- thumb.removeEventListener("pointerdown", onThumbPointerDown);
2097
- };
2098
- };
2099
- const resizeObserver = new ResizeObserver((observedEntries) => {
2100
- observedEntries.forEach(({ target }) => {
2101
- const entry = entries.get(target);
2102
- if (entry) updateEntry(entry);
2103
- });
2104
- });
2105
- const addTarget = (target) => {
2106
- if (entries.has(target)) return;
2107
- const horizontal = createTrack("horizontal");
2108
- const vertical = createTrack("vertical");
2109
- layer.append(horizontal.track, vertical.track);
2110
- const onPointerEnter = () => {
2111
- const entry2 = entries.get(target);
2112
- if (!entry2) return;
2113
- entry2.hoveringTarget = true;
2114
- showEntry(entry2);
2115
- };
2116
- const onPointerLeave = () => {
2117
- const entry2 = entries.get(target);
2118
- if (!entry2) return;
2119
- entry2.hoveringTarget = false;
2120
- scheduleHide(entry2);
2121
- };
2122
- const onScroll = () => {
2123
- const entry2 = entries.get(target);
2124
- if (!entry2) return;
2125
- updateEntry(entry2);
2126
- showEntry(entry2);
2127
- scheduleHide(entry2, 700);
2128
- };
2129
- target.addEventListener("pointerenter", onPointerEnter);
2130
- target.addEventListener("pointerleave", onPointerLeave);
2131
- target.addEventListener("scroll", onScroll, { passive: true });
2132
- const entry = {
2133
- target,
2134
- horizontalTrack: horizontal.track,
2135
- horizontalThumb: horizontal.thumb,
2136
- verticalTrack: vertical.track,
2137
- verticalThumb: vertical.thumb,
2138
- hideTimer: null,
2139
- hoveringTarget: target.matches(":hover"),
2140
- hoveringTrack: false,
2141
- dragging: false,
2142
- cleanup: () => void 0
2143
- };
2144
- const cleanupHorizontal = bindTrackDrag(entry, "horizontal", horizontal.track, horizontal.thumb);
2145
- const cleanupVertical = bindTrackDrag(entry, "vertical", vertical.track, vertical.thumb);
2146
- entry.cleanup = () => {
2147
- if (entry.hideTimer !== null) window.clearTimeout(entry.hideTimer);
2148
- cleanupHorizontal();
2149
- cleanupVertical();
2150
- target.removeEventListener("pointerenter", onPointerEnter);
2151
- target.removeEventListener("pointerleave", onPointerLeave);
2152
- target.removeEventListener("scroll", onScroll);
2153
- resizeObserver.unobserve(target);
2154
- target.removeAttribute("data-sia-floating-scrollbar");
2155
- horizontal.track.remove();
2156
- vertical.track.remove();
2157
- };
2158
- entries.set(target, entry);
2159
- target.setAttribute("data-sia-floating-scrollbar", "");
2160
- resizeObserver.observe(target);
2161
- updateEntry(entry);
2162
- if (entry.hoveringTarget) showEntry(entry);
2163
- };
2164
- const removeTarget = (target) => {
2165
- const entry = entries.get(target);
2166
- if (!entry) return;
2167
- entry.cleanup();
2168
- entries.delete(target);
2169
- };
2170
- const scanTargets = () => {
2171
- scanFrame = 0;
2172
- const candidates = (targetRef ? [targetRef.current] : [document.scrollingElement, ...document.querySelectorAll("*")]).filter((target) => target instanceof HTMLElement);
2173
- const nextTargets = /* @__PURE__ */ new Set();
2174
- candidates.forEach((target) => {
2175
- if (canScroll(target, "horizontal") || canScroll(target, "vertical")) {
2176
- nextTargets.add(target);
2177
- if (entries.has(target) || !target.hasAttribute("data-sia-floating-scrollbar")) addTarget(target);
2178
- }
2179
- });
2180
- entries.forEach((_entry, target) => {
2181
- if (!target.isConnected || !nextTargets.has(target)) removeTarget(target);
2182
- else updateEntry(_entry);
2183
- });
2184
- };
2185
- const scheduleScan = () => {
2186
- if (scanFrame) return;
2187
- scanFrame = window.requestAnimationFrame(scanTargets);
2188
- };
2189
- const mutationObserver = new MutationObserver((mutations) => {
2190
- if (mutations.some((mutation) => !layer.contains(mutation.target))) scheduleScan();
2191
- });
2192
- mutationObserver.observe(document.documentElement, { subtree: true, childList: true, attributes: true });
2193
- window.addEventListener("resize", scheduleScan);
2194
- window.addEventListener("scroll", scheduleUpdateAll, true);
2195
- scheduleScan();
2196
- return () => {
2197
- mutationObserver.disconnect();
2198
- resizeObserver.disconnect();
2199
- window.removeEventListener("resize", scheduleScan);
2200
- window.removeEventListener("scroll", scheduleUpdateAll, true);
2201
- if (scanFrame) window.cancelAnimationFrame(scanFrame);
2202
- if (updateFrame) window.cancelAnimationFrame(updateFrame);
2203
- entries.forEach((entry) => entry.cleanup());
2204
- entries.clear();
2205
- layer.remove();
2206
- };
2207
- }, [disabled, targetRef]);
2208
- return null;
2209
- }
2210
-
2211
- // src/components/Tabs.tsx
2212
- var import_jsx_runtime11 = require("react/jsx-runtime");
2213
- function Tabs({
2214
- items,
2215
- activeKey,
2216
- defaultActiveKey,
2217
- onChange,
2218
- onAfterChange,
2219
- deferContent = false,
2220
- type = "line",
2221
- size = "medium",
2222
- tabPosition,
2223
- orientation = "horizontal",
2224
- centered = false,
2225
- tabBarTitle,
2226
- tabBarExtraContent,
2227
- contentGap,
2228
- destroyInactiveTabPane = true,
2229
- closable = false,
2230
- onEdit,
2231
- tabContextMenu,
2232
- onTabContextMenuClick,
2233
- className = "",
2234
- ...props
2235
- }) {
2236
- const firstEnabledKey = items.find((item) => !item.disabled)?.key ?? "";
2237
- const [internalActiveKey, setInternalActiveKey] = (0, import_react12.useState)(defaultActiveKey ?? firstEnabledKey);
2238
- const currentKey = activeKey ?? internalActiveKey;
2239
- const selectedKey = items.some((item) => item.key === currentKey && !item.disabled) ? currentKey : firstEnabledKey;
2240
- const baseId = (0, import_react12.useId)().replace(/:/g, "");
2241
- const enabledItems = (0, import_react12.useMemo)(() => items.filter((item) => !item.disabled), [items]);
2242
- const resolvedPosition = tabPosition ?? (orientation === "vertical" ? "left" : "top");
2243
- const resolvedOrientation = resolvedPosition === "left" || resolvedPosition === "right" ? "vertical" : "horizontal";
2244
- const sliding = ["capsule", "line", "underline", "tech", "tech-line"].includes(type);
2245
- const listRef = (0, import_react12.useRef)(null);
2246
- const indicatorRef = (0, import_react12.useRef)(null);
2247
- const [contentState, setContentState] = (0, import_react12.useState)(() => ({ key: selectedKey, visited: /* @__PURE__ */ new Set([selectedKey]) }));
2248
- const settledKeyRef = (0, import_react12.useRef)(selectedKey);
2249
- const afterChangeRef = (0, import_react12.useRef)(onAfterChange);
2250
- (0, import_react12.useLayoutEffect)(() => {
2251
- afterChangeRef.current = onAfterChange;
2252
- }, [onAfterChange]);
2253
- (0, import_react12.useLayoutEffect)(() => {
2254
- if (!sliding) return;
2255
- const list = listRef.current;
2256
- const indicator = indicatorRef.current;
2257
- if (!list || !indicator) return;
2258
- function updateIndicator() {
2259
- if (!list || !indicator) return;
2260
- const active = list.querySelector('[role="tab"][aria-selected="true"]');
2261
- if (!active) {
2262
- indicator.style.visibility = "hidden";
2263
- return;
2264
- }
2265
- const listRect = list.getBoundingClientRect();
2266
- const rect = active.getBoundingClientRect();
2267
- if (type === "tech-line" && resolvedOrientation === "horizontal") {
2268
- if (rect.left < listRect.left) list.scrollLeft += rect.left - listRect.left;
2269
- else if (rect.right > listRect.right) list.scrollLeft += rect.right - listRect.right;
2270
- }
2271
- const currentRect = active.getBoundingClientRect();
2272
- indicator.style.transform = `translate(${currentRect.left - listRect.left - list.clientLeft + list.scrollLeft}px, ${currentRect.top - listRect.top - list.clientTop + list.scrollTop}px)`;
2273
- indicator.style.width = `${rect.width}px`;
2274
- indicator.style.height = `${rect.height}px`;
2275
- indicator.style.visibility = "visible";
2276
- if (!indicator.dataset.ready) {
2277
- indicator.getBoundingClientRect();
2278
- indicator.dataset.ready = "true";
2279
- }
2280
- }
2281
- updateIndicator();
2282
- const observer = new ResizeObserver(updateIndicator);
2283
- observer.observe(list);
2284
- list.querySelectorAll('[role="tab"]').forEach((tab) => observer.observe(tab));
2285
- return () => observer.disconnect();
2286
- }, [sliding, type, selectedKey, items, size, resolvedPosition, centered, closable]);
2287
- (0, import_react12.useEffect)(() => {
2288
- let cancelled = false;
2289
- let frame = 0;
2290
- frame = requestAnimationFrame(() => {
2291
- const indicator = indicatorRef.current;
2292
- if (indicator) getComputedStyle(indicator).transform;
2293
- const animations = indicator?.getAnimations() ?? [];
2294
- const complete = () => {
2295
- if (cancelled) return;
2296
- setContentState((previous) => ({ key: selectedKey, visited: new Set([...previous.visited].filter((key) => items.some((item) => item.key === key))).add(selectedKey) }));
2297
- if (settledKeyRef.current !== selectedKey) {
2298
- settledKeyRef.current = selectedKey;
2299
- afterChangeRef.current?.(selectedKey);
2300
- }
2301
- };
2302
- if (!animations.length) complete();
2303
- else Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {
2304
- if (!cancelled) frame = requestAnimationFrame(complete);
2305
- });
2306
- });
2307
- return () => {
2308
- cancelled = true;
2309
- cancelAnimationFrame(frame);
2310
- };
2311
- }, [selectedKey, type, deferContent]);
2312
- const contentKey = deferContent ? contentState.key : selectedKey;
2313
- function selectTab(key) {
2314
- if (key === selectedKey) return;
2315
- if (activeKey === void 0) setInternalActiveKey(key);
2316
- onChange?.(key);
2317
- }
2318
- function focusAndSelect(key) {
2319
- selectTab(key);
2320
- document.getElementById(`${baseId}-tab-${key}`)?.focus();
2321
- }
2322
- function handleKeyDown(event, key) {
2323
- const previousKey = resolvedOrientation === "horizontal" ? "ArrowLeft" : "ArrowUp";
2324
- const nextKey = resolvedOrientation === "horizontal" ? "ArrowRight" : "ArrowDown";
2325
- if (![previousKey, nextKey, "Home", "End"].includes(event.key) || enabledItems.length === 0) return;
2326
- event.preventDefault();
2327
- const currentIndex = Math.max(0, enabledItems.findIndex((item) => item.key === key));
2328
- if (event.key === "Home") return focusAndSelect(enabledItems[0].key);
2329
- if (event.key === "End") return focusAndSelect(enabledItems[enabledItems.length - 1].key);
2330
- const offset = event.key === nextKey ? 1 : -1;
2331
- const nextIndex = (currentIndex + offset + enabledItems.length) % enabledItems.length;
2332
- focusAndSelect(enabledItems[nextIndex].key);
1979
+ function handleKeyDown(event, key) {
1980
+ const previousKey = resolvedOrientation === "horizontal" ? "ArrowLeft" : "ArrowUp";
1981
+ const nextKey = resolvedOrientation === "horizontal" ? "ArrowRight" : "ArrowDown";
1982
+ if (![previousKey, nextKey, "Home", "End"].includes(event.key) || enabledItems.length === 0) return;
1983
+ event.preventDefault();
1984
+ const currentIndex = Math.max(0, enabledItems.findIndex((item) => item.key === key));
1985
+ if (event.key === "Home") return focusAndSelect(enabledItems[0].key);
1986
+ if (event.key === "End") return focusAndSelect(enabledItems[enabledItems.length - 1].key);
1987
+ const offset = event.key === nextKey ? 1 : -1;
1988
+ const nextIndex = (currentIndex + offset + enabledItems.length) % enabledItems.length;
1989
+ focusAndSelect(enabledItems[nextIndex].key);
2333
1990
  }
2334
1991
  const hasPanels = items.some((item) => item.children !== void 0);
2335
1992
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
@@ -2339,54 +1996,53 @@ function Tabs({
2339
1996
  ...withTitleTooltip(props),
2340
1997
  children: [
2341
1998
  /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "sia-tabs__header", children: [
2342
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(FloatingScrollbarProvider, { targetRef: listRef, disabled: type !== "tech-line" || resolvedOrientation !== "horizontal" }),
2343
1999
  tabBarTitle ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "sia-tabs__title", children: [
2344
2000
  tabBarTitle,
2345
2001
  type === "tech-line" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "sia-tabs__title-connector", viewBox: "0 0 32 40", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M0 39.25 H5 Q8 39.25 10 35.25 L28 3.75 Q29 1.75 32 1.75", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinejoin: "round" }) }) : null
2346
2002
  ] }) : null,
2347
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { ref: listRef, className: `sia-tabs__list${sliding ? " sia-tabs__list--sliding" : ""}`, role: "tablist", "aria-orientation": resolvedOrientation, children: [
2003
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { ref: listRef, style: resolvedOrientation === "horizontal" && overflow.width ? { width: overflow.width } : void 0, className: `sia-tabs__list${sliding ? " sia-tabs__list--sliding" : ""}`, role: "tablist", "aria-orientation": resolvedOrientation, children: [
2348
2004
  sliding ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { ref: indicatorRef, className: `sia-tabs__indicator${type === "capsule" ? " sia-tabs__capsule-indicator" : ""}`, "aria-hidden": "true", children: type === "tech-line" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "sia-tabs__indicator-shape", "aria-hidden": "true" }) : null }, type) : null,
2349
- items.map((item) => {
2005
+ items.map((item, index) => {
2350
2006
  const selected = item.key === selectedKey;
2351
2007
  const canClose = item.closable ?? closable;
2352
- const tabNode = /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: `sia-tabs__tab-wrap${canClose ? " is-closable" : ""}`, children: [
2353
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2354
- "button",
2355
- {
2356
- id: `${baseId}-tab-${item.key}`,
2357
- type: "button",
2358
- className: "sia-tabs__tab",
2359
- role: "tab",
2360
- "aria-selected": selected,
2361
- "aria-controls": hasPanels ? `${baseId}-panel-${item.key}` : void 0,
2362
- tabIndex: selected ? 0 : -1,
2363
- disabled: item.disabled,
2364
- onClick: () => selectTab(item.key),
2365
- onKeyDown: (event) => handleKeyDown(event, item.key),
2366
- children: [
2367
- type === "tech-line" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "sia-tabs__tab-shape", "aria-hidden": "true" }) : null,
2368
- item.icon ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "sia-tabs__icon", children: item.icon }) : null,
2369
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: item.label })
2370
- ]
2371
- }
2372
- ),
2373
- canClose ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2374
- "button",
2375
- {
2376
- type: "button",
2377
- className: "sia-tabs__close",
2378
- "aria-label": `\u5173\u95ED${typeof item.label === "string" ? item.label : "\u6807\u7B7E\u9875"}`,
2379
- disabled: item.disabled,
2380
- onClick: () => onEdit?.(item.key, "remove"),
2381
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { name: "close", size: 12 })
2382
- }
2383
- ) : null
2384
- ] }, item.key);
2385
2008
  const contextMenuItems = typeof tabContextMenu === "function" ? tabContextMenu(item) : tabContextMenu;
2009
+ const entryProps = { "data-tab-entry": "", "data-tab-hidden": index >= visibleCount, "aria-hidden": index >= visibleCount || void 0 };
2010
+ const tabNode = /* @__PURE__ */ (0, import_react11.createElement)("span", { ...!contextMenuItems?.length ? entryProps : {}, className: `sia-tabs__tab-wrap${canClose ? " is-closable" : ""}`, key: item.key }, /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2011
+ "button",
2012
+ {
2013
+ id: `${baseId}-tab-${item.key}`,
2014
+ type: "button",
2015
+ className: "sia-tabs__tab",
2016
+ role: "tab",
2017
+ "aria-selected": selected,
2018
+ "aria-controls": hasPanels ? `${baseId}-panel-${item.key}` : void 0,
2019
+ tabIndex: selected ? 0 : -1,
2020
+ disabled: item.disabled,
2021
+ onClick: () => selectTab(item.key),
2022
+ onKeyDown: (event) => handleKeyDown(event, item.key),
2023
+ children: [
2024
+ type === "tech-line" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "sia-tabs__tab-shape", "aria-hidden": "true" }) : null,
2025
+ item.icon ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "sia-tabs__icon", children: item.icon }) : null,
2026
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: item.label })
2027
+ ]
2028
+ }
2029
+ ), canClose ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2030
+ "button",
2031
+ {
2032
+ type: "button",
2033
+ className: "sia-tabs__close",
2034
+ "aria-label": `\u5173\u95ED${typeof item.label === "string" ? item.label : "\u6807\u7B7E\u9875"}`,
2035
+ disabled: item.disabled,
2036
+ onClick: () => onEdit?.(item.key, "remove"),
2037
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { name: "close", size: 12 })
2038
+ }
2039
+ ) : null);
2386
2040
  if (!contextMenuItems?.length) return tabNode;
2387
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2041
+ return /* @__PURE__ */ (0, import_react11.createElement)(
2388
2042
  Dropdown,
2389
2043
  {
2044
+ ...entryProps,
2045
+ key: item.key,
2390
2046
  className: "sia-tabs__tab-context-trigger",
2391
2047
  popupClassName: "sia-tabs__tab-context-menu",
2392
2048
  trigger: ["contextMenu"],
@@ -2395,12 +2051,26 @@ function Tabs({
2395
2051
  items: contextMenuItems,
2396
2052
  selectable: false,
2397
2053
  onClick: (info) => onTabContextMenuClick?.({ ...info, tabKey: item.key, tab: item })
2398
- },
2399
- children: tabNode
2054
+ }
2400
2055
  },
2401
- item.key
2056
+ tabNode
2402
2057
  );
2403
- })
2058
+ }),
2059
+ resolvedOrientation === "horizontal" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2060
+ Dropdown,
2061
+ {
2062
+ className: "sia-tabs__more",
2063
+ "data-tab-hidden": !hiddenItems.length,
2064
+ trigger: ["hover", "click"],
2065
+ placement: "bottomRight",
2066
+ showTriggerIcon: false,
2067
+ autoFocus: true,
2068
+ open: moreOpen && hiddenItems.length > 0,
2069
+ onOpenChange: setMoreOpen,
2070
+ menu: { items: hiddenItems.map((item) => ({ key: item.key, label: item.label, icon: item.icon, disabled: item.disabled })), selectedKeys: [selectedKey], onClick: (info) => selectTab(info.key) },
2071
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Button, { ref: moreRef, variant: "text", icon: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { name: "more-horizontal" }), "aria-label": "\u66F4\u591A\u9009\u9879\u5361", onKeyDown: (event) => handleKeyDown(event, selectedKey), className: hiddenItems.some((item) => item.key === selectedKey) ? "is-active" : void 0 })
2072
+ }
2073
+ ) : null
2404
2074
  ] }),
2405
2075
  tabBarExtraContent ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "sia-tabs__extra", children: tabBarExtraContent }) : null
2406
2076
  ] }),
@@ -2431,26 +2101,26 @@ function Tabs({
2431
2101
  }
2432
2102
 
2433
2103
  // src/components/Feedback.tsx
2434
- var import_react15 = require("react");
2104
+ var import_react14 = require("react");
2435
2105
  var import_react_dom3 = require("react-dom");
2436
2106
  var import_client2 = require("react-dom/client");
2437
2107
 
2438
2108
  // src/components/FloatingDisplay.tsx
2439
- var import_react14 = require("react");
2109
+ var import_react13 = require("react");
2440
2110
  var import_react_dom2 = require("react-dom");
2441
2111
 
2442
2112
  // src/components/Checkbox.tsx
2443
- var import_react13 = require("react");
2113
+ var import_react12 = require("react");
2444
2114
  var import_jsx_runtime12 = require("react/jsx-runtime");
2445
- var CheckboxGroupContext = (0, import_react13.createContext)(null);
2446
- var CheckboxRoot = (0, import_react13.forwardRef)(function Checkbox({ value, size: sizeProp, indeterminate = false, children, disabled, checked, defaultChecked, className = "", onChange, ...props }, forwardedRef) {
2115
+ var CheckboxGroupContext = (0, import_react12.createContext)(null);
2116
+ var CheckboxRoot = (0, import_react12.forwardRef)(function Checkbox({ value, size: sizeProp, indeterminate = false, children, disabled, checked, defaultChecked, className = "", onChange, ...props }, forwardedRef) {
2447
2117
  const size = useControlSize(sizeProp);
2448
- const group = (0, import_react13.useContext)(CheckboxGroupContext);
2449
- const localRef = (0, import_react13.useRef)(null);
2450
- const fallbackId = (0, import_react13.useId)();
2118
+ const group = (0, import_react12.useContext)(CheckboxGroupContext);
2119
+ const localRef = (0, import_react12.useRef)(null);
2120
+ const fallbackId = (0, import_react12.useId)();
2451
2121
  const grouped = group !== null && value !== void 0;
2452
2122
  const currentChecked = grouped ? group.values.includes(value) : checked;
2453
- (0, import_react13.useEffect)(() => {
2123
+ (0, import_react12.useEffect)(() => {
2454
2124
  if (localRef.current) localRef.current.indeterminate = indeterminate;
2455
2125
  }, [indeterminate]);
2456
2126
  function setRef(node) {
@@ -2503,7 +2173,7 @@ function CheckboxGroup({
2503
2173
  gap: gap === void 0 ? void 0 : typeof gap === "number" ? Math.max(0, gap) : `${Math.max(0, gap[0])}px ${Math.max(0, gap[1])}px`
2504
2174
  };
2505
2175
  const [values, setValues] = useControllableState({ value, defaultValue, onChange });
2506
- const context = (0, import_react13.useMemo)(() => ({
2176
+ const context = (0, import_react12.useMemo)(() => ({
2507
2177
  values,
2508
2178
  disabled,
2509
2179
  name,
@@ -2534,38 +2204,66 @@ var activeTooltipClose;
2534
2204
  function clampFloating(value, min, max) {
2535
2205
  return Math.min(Math.max(value, min), Math.max(min, max));
2536
2206
  }
2537
- function resolveFloatingPosition(trigger, overlay, placement) {
2207
+ function normalizeFloatingPlacement(placement) {
2208
+ const aliases = {
2209
+ topLeft: "top-start",
2210
+ topRight: "top-end",
2211
+ bottomLeft: "bottom-start",
2212
+ bottomRight: "bottom-end",
2213
+ leftTop: "left-start",
2214
+ leftBottom: "left-end",
2215
+ rightTop: "right-start",
2216
+ rightBottom: "right-end"
2217
+ };
2218
+ return aliases[placement] ?? placement;
2219
+ }
2220
+ function resolveFloatingPosition(trigger, overlay, placement, pointAtCenter, adjust) {
2538
2221
  const viewportWidth = document.documentElement.clientWidth;
2539
2222
  const viewportHeight = document.documentElement.clientHeight;
2540
- let resolvedPlacement = placement;
2541
- if (placement.startsWith("top") && trigger.top - overlay.height - FLOATING_GAP < FLOATING_VIEWPORT_PADDING && trigger.bottom + overlay.height + FLOATING_GAP <= viewportHeight - FLOATING_VIEWPORT_PADDING) {
2542
- resolvedPlacement = placement.replace("top", "bottom");
2543
- } else if (placement.startsWith("bottom") && trigger.bottom + overlay.height + FLOATING_GAP > viewportHeight - FLOATING_VIEWPORT_PADDING && trigger.top - overlay.height - FLOATING_GAP >= FLOATING_VIEWPORT_PADDING) {
2544
- resolvedPlacement = placement.replace("bottom", "top");
2545
- } else if (placement === "left" && trigger.left - overlay.width - FLOATING_GAP < FLOATING_VIEWPORT_PADDING && trigger.right + overlay.width + FLOATING_GAP <= viewportWidth - FLOATING_VIEWPORT_PADDING) {
2546
- resolvedPlacement = "right";
2547
- } else if (placement === "right" && trigger.right + overlay.width + FLOATING_GAP > viewportWidth - FLOATING_VIEWPORT_PADDING && trigger.left - overlay.width - FLOATING_GAP >= FLOATING_VIEWPORT_PADDING) {
2548
- resolvedPlacement = "left";
2223
+ let resolvedPlacement = normalizeFloatingPlacement(placement);
2224
+ const side = resolvedPlacement.split("-")[0];
2225
+ const available = { top: trigger.top, bottom: viewportHeight - trigger.bottom, left: trigger.left, right: viewportWidth - trigger.right };
2226
+ const opposite = { top: "bottom", bottom: "top", left: "right", right: "left" };
2227
+ const preferred = side;
2228
+ const other = opposite[preferred];
2229
+ const needed = (side === "top" || side === "bottom" ? overlay.height : overlay.width) + FLOATING_GAP + FLOATING_VIEWPORT_PADDING;
2230
+ if (adjust && available[preferred] < needed && available[other] > available[preferred]) {
2231
+ resolvedPlacement = resolvedPlacement.replace(preferred, other);
2549
2232
  }
2550
- let top = trigger.top;
2551
- let left = trigger.left;
2552
- if (resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom")) {
2553
- top = resolvedPlacement.startsWith("top") ? trigger.top - overlay.height - FLOATING_GAP : trigger.bottom + FLOATING_GAP;
2554
- left = resolvedPlacement.endsWith("-start") ? trigger.left : resolvedPlacement.endsWith("-end") ? trigger.right - overlay.width : trigger.left + (trigger.width - overlay.width) / 2;
2555
- } else {
2556
- top = trigger.top + (trigger.height - overlay.height) / 2;
2557
- left = resolvedPlacement === "left" ? trigger.left - overlay.width - FLOATING_GAP : trigger.right + FLOATING_GAP;
2233
+ const vertical = resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom");
2234
+ const start = resolvedPlacement.endsWith("-start");
2235
+ const end = resolvedPlacement.endsWith("-end");
2236
+ 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;
2237
+ 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;
2238
+ if (adjust) {
2239
+ if (vertical) left = clampFloating(left, FLOATING_VIEWPORT_PADDING, viewportWidth - overlay.width - FLOATING_VIEWPORT_PADDING);
2240
+ else top = clampFloating(top, FLOATING_VIEWPORT_PADDING, viewportHeight - overlay.height - FLOATING_VIEWPORT_PADDING);
2558
2241
  }
2559
- top = clampFloating(top, FLOATING_VIEWPORT_PADDING, viewportHeight - overlay.height - FLOATING_VIEWPORT_PADDING);
2560
- left = clampFloating(left, FLOATING_VIEWPORT_PADDING, viewportWidth - overlay.width - FLOATING_VIEWPORT_PADDING);
2561
2242
  const result = { top, left, placement: resolvedPlacement };
2562
- if (resolvedPlacement.startsWith("top") || resolvedPlacement.startsWith("bottom")) {
2563
- result.arrowX = resolvedPlacement.endsWith("-start") ? clampFloating(FLOATING_ARROW_EDGE_OFFSET, 8, overlay.width - 16) : resolvedPlacement.endsWith("-end") ? clampFloating(overlay.width - FLOATING_ARROW_EDGE_OFFSET - 8, 8, overlay.width - 16) : clampFloating(trigger.left + trigger.width / 2 - left - 4, 8, overlay.width - 16);
2564
- } else {
2565
- result.arrowY = clampFloating(trigger.top + trigger.height / 2 - top - 4, 8, overlay.height - 16);
2566
- }
2243
+ const size = vertical ? trigger.width : trigger.height;
2244
+ const anchorStart = vertical ? trigger.left : trigger.top;
2245
+ const edge = Math.min(size / 2, FLOATING_ARROW_EDGE_OFFSET + 4);
2246
+ const target = anchorStart + (pointAtCenter || !start && !end ? size / 2 : start ? edge : size - edge);
2247
+ if (vertical) result.arrowX = clampFloating(target - left - 4, 8, overlay.width - 16);
2248
+ else result.arrowY = clampFloating(target - top - 4, 8, overlay.height - 16);
2567
2249
  return result;
2568
2250
  }
2251
+ function isFloatingAnchorHidden(anchor, rect) {
2252
+ let left = 0, top = 0, right = document.documentElement.clientWidth, bottom = document.documentElement.clientHeight;
2253
+ for (let parent = anchor.parentElement; parent; parent = parent.parentElement) {
2254
+ const css = getComputedStyle(parent);
2255
+ const bounds = parent.getBoundingClientRect();
2256
+ if (/(auto|scroll|hidden|clip)/.test(css.overflowX)) {
2257
+ left = Math.max(left, bounds.left);
2258
+ right = Math.min(right, bounds.right);
2259
+ }
2260
+ if (/(auto|scroll|hidden|clip)/.test(css.overflowY)) {
2261
+ top = Math.max(top, bounds.top);
2262
+ bottom = Math.min(bottom, bounds.bottom);
2263
+ }
2264
+ }
2265
+ return rect.right <= left || rect.left >= right || rect.bottom <= top || rect.top >= bottom;
2266
+ }
2569
2267
  function Floating({
2570
2268
  children,
2571
2269
  content,
@@ -2576,23 +2274,25 @@ function Floating({
2576
2274
  mouseEnterDelay = 0.1,
2577
2275
  mouseLeaveDelay = 0.1,
2578
2276
  arrow = true,
2277
+ autoAdjustOverflow = true,
2579
2278
  color,
2580
2279
  className = "",
2581
2280
  overlayClassName = "",
2582
2281
  role = "tooltip",
2583
2282
  onOpenChange
2584
2283
  }) {
2585
- const rootRef = (0, import_react14.useRef)(null);
2586
- const overlayRef = (0, import_react14.useRef)(null);
2587
- const enterTimer = (0, import_react14.useRef)();
2588
- const leaveTimer = (0, import_react14.useRef)();
2589
- const contentId = (0, import_react14.useId)();
2284
+ const rootRef = (0, import_react13.useRef)(null);
2285
+ const triggerElementRef = (0, import_react13.useRef)(null);
2286
+ const overlayRef = (0, import_react13.useRef)(null);
2287
+ const enterTimer = (0, import_react13.useRef)();
2288
+ const leaveTimer = (0, import_react13.useRef)();
2289
+ const contentId = (0, import_react13.useId)();
2590
2290
  const triggers = Array.isArray(trigger) ? trigger : [trigger];
2591
2291
  const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
2592
- const [position, setPosition] = (0, import_react14.useState)();
2593
- const setVisibleRef = (0, import_react14.useRef)(setVisible);
2292
+ const [position, setPosition] = (0, import_react13.useState)();
2293
+ const setVisibleRef = (0, import_react13.useRef)(setVisible);
2594
2294
  setVisibleRef.current = setVisible;
2595
- const closeSelfRef = (0, import_react14.useRef)();
2295
+ const closeSelfRef = (0, import_react13.useRef)();
2596
2296
  if (!closeSelfRef.current) closeSelfRef.current = () => setVisibleRef.current(false);
2597
2297
  const exclusiveTooltip = role === "tooltip" && triggers.includes("hover");
2598
2298
  function openNow() {
@@ -2620,7 +2320,7 @@ function Floating({
2620
2320
  if (delay <= 0) closeNow();
2621
2321
  else leaveTimer.current = window.setTimeout(closeNow, delay * 1e3);
2622
2322
  }
2623
- (0, import_react14.useEffect)(() => {
2323
+ (0, import_react13.useEffect)(() => {
2624
2324
  if (!visible || !triggers.includes("click")) return;
2625
2325
  const close = (event) => {
2626
2326
  const target = event.target;
@@ -2629,33 +2329,47 @@ function Floating({
2629
2329
  document.addEventListener("pointerdown", close);
2630
2330
  return () => document.removeEventListener("pointerdown", close);
2631
2331
  }, [triggers.join("|"), visible]);
2632
- (0, import_react14.useLayoutEffect)(() => {
2332
+ (0, import_react13.useLayoutEffect)(() => {
2633
2333
  if (!visible) {
2634
2334
  setPosition(void 0);
2635
2335
  return;
2636
2336
  }
2337
+ const getAnchor = () => {
2338
+ const root = rootRef.current;
2339
+ const target = triggerElementRef.current;
2340
+ return target && root?.contains(target) ? target : root?.firstElementChild ?? root;
2341
+ };
2637
2342
  const update = () => {
2638
2343
  if (!rootRef.current || !overlayRef.current) return;
2639
- setPosition(resolveFloatingPosition(rootRef.current.getBoundingClientRect(), overlayRef.current.getBoundingClientRect(), placement));
2344
+ const anchor2 = getAnchor();
2345
+ if (anchor2) {
2346
+ const rect = anchor2.getBoundingClientRect();
2347
+ const next = resolveFloatingPosition(rect, overlayRef.current.getBoundingClientRect(), placement, typeof arrow === "object" && !!arrow.pointAtCenter, autoAdjustOverflow);
2348
+ next.hidden = isFloatingAnchorHidden(anchor2, rect);
2349
+ setPosition(next);
2350
+ }
2640
2351
  };
2641
2352
  update();
2642
2353
  window.addEventListener("resize", update);
2643
2354
  window.addEventListener("scroll", update, true);
2644
2355
  const observer = new ResizeObserver(update);
2645
2356
  if (rootRef.current) observer.observe(rootRef.current);
2357
+ const anchor = getAnchor();
2358
+ if (anchor) observer.observe(anchor);
2646
2359
  if (overlayRef.current) observer.observe(overlayRef.current);
2647
2360
  return () => {
2648
2361
  window.removeEventListener("resize", update);
2649
2362
  window.removeEventListener("scroll", update, true);
2650
2363
  observer.disconnect();
2651
2364
  };
2652
- }, [children, content, placement, visible]);
2653
- (0, import_react14.useEffect)(() => () => {
2365
+ }, [children, content, placement, visible, autoAdjustOverflow, typeof arrow === "object" && arrow.pointAtCenter]);
2366
+ (0, import_react13.useEffect)(() => () => {
2654
2367
  clearTimers();
2655
2368
  if (activeTooltipClose === closeSelfRef.current) activeTooltipClose = void 0;
2656
2369
  }, []);
2657
- const child = (0, import_react14.cloneElement)(children, {
2370
+ const child = (0, import_react13.cloneElement)(children, {
2658
2371
  ...triggers.includes("hover") ? { onMouseEnter: (event) => {
2372
+ triggerElementRef.current = event.currentTarget;
2659
2373
  children.props.onMouseEnter?.(event);
2660
2374
  show(mouseEnterDelay);
2661
2375
  }, onMouseLeave: (event) => {
@@ -2663,6 +2377,7 @@ function Floating({
2663
2377
  hide(mouseLeaveDelay);
2664
2378
  } } : {},
2665
2379
  ...triggers.includes("focus") ? { onFocus: (event) => {
2380
+ triggerElementRef.current = event.currentTarget;
2666
2381
  children.props.onFocus?.(event);
2667
2382
  show();
2668
2383
  }, onBlur: (event) => {
@@ -2670,6 +2385,7 @@ function Floating({
2670
2385
  hide();
2671
2386
  } } : {},
2672
2387
  ...triggers.includes("click") ? { onClick: (event) => {
2388
+ triggerElementRef.current = event.currentTarget;
2673
2389
  children.props.onClick?.(event);
2674
2390
  if (visible) closeNow();
2675
2391
  else openNow();
@@ -2684,14 +2400,14 @@ function Floating({
2684
2400
  id: contentId,
2685
2401
  role,
2686
2402
  "data-custom-color": color ? "" : void 0,
2687
- className: `sia-floating__overlay sia-floating__overlay--${position?.placement ?? placement} ${overlayClassName}`.trim(),
2403
+ className: `sia-floating__overlay sia-floating__overlay--${position?.placement ?? normalizeFloatingPlacement(placement)} ${overlayClassName}`.trim(),
2688
2404
  style: {
2689
2405
  "--sia-floating-color": color,
2690
2406
  "--sia-floating-arrow-x": position?.arrowX == null ? void 0 : `${position.arrowX}px`,
2691
2407
  "--sia-floating-arrow-y": position?.arrowY == null ? void 0 : `${position.arrowY}px`,
2692
2408
  top: position?.top ?? 0,
2693
2409
  left: position?.left ?? 0,
2694
- visibility: position ? "visible" : "hidden"
2410
+ visibility: position && !position.hidden ? "visible" : "hidden"
2695
2411
  },
2696
2412
  onMouseEnter: triggers.includes("hover") ? () => show() : void 0,
2697
2413
  onMouseLeave: triggers.includes("hover") ? () => hide(mouseLeaveDelay) : void 0,
@@ -2759,11 +2475,11 @@ function Progress({
2759
2475
  }
2760
2476
 
2761
2477
  // src/components/DataDisplay.tsx
2762
- var import_react17 = require("react");
2478
+ var import_react16 = require("react");
2763
2479
  var import_react_dom5 = require("react-dom");
2764
2480
 
2765
2481
  // src/components/Overlay.tsx
2766
- var import_react16 = require("react");
2482
+ var import_react15 = require("react");
2767
2483
  var import_react_dom4 = require("react-dom");
2768
2484
  var bodyLockCount = 0;
2769
2485
  var previousBodyOverflow = "";
@@ -2785,10 +2501,10 @@ function focusableElements(container) {
2785
2501
  )].filter((element) => !element.hidden && element.getAttribute("aria-hidden") !== "true");
2786
2502
  }
2787
2503
  function useOverlayLifecycle(open, panelRef, onRequestClose, keyboard = true) {
2788
- const overlayIdRef = (0, import_react16.useRef)(/* @__PURE__ */ Symbol("sia-overlay"));
2789
- const closeRef = (0, import_react16.useRef)(onRequestClose);
2504
+ const overlayIdRef = (0, import_react15.useRef)(/* @__PURE__ */ Symbol("sia-overlay"));
2505
+ const closeRef = (0, import_react15.useRef)(onRequestClose);
2790
2506
  closeRef.current = onRequestClose;
2791
- (0, import_react16.useEffect)(() => {
2507
+ (0, import_react15.useEffect)(() => {
2792
2508
  if (!open || typeof document === "undefined") return void 0;
2793
2509
  const overlayId = overlayIdRef.current;
2794
2510
  const previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
@@ -2871,8 +2587,8 @@ function CollapsePanel({
2871
2587
  destroyInactivePanel = false,
2872
2588
  children
2873
2589
  }) {
2874
- const [keepChildren, setKeepChildren] = (0, import_react17.useState)(open || forceRender || !destroyInactivePanel);
2875
- (0, import_react17.useEffect)(() => {
2590
+ const [keepChildren, setKeepChildren] = (0, import_react16.useState)(open || forceRender || !destroyInactivePanel);
2591
+ (0, import_react16.useEffect)(() => {
2876
2592
  if (open || forceRender || !destroyInactivePanel) {
2877
2593
  setKeepChildren(true);
2878
2594
  return void 0;
@@ -2886,7 +2602,7 @@ function CollapsePanel({
2886
2602
  function Collapse({ items, activeKey, defaultActiveKey = [], accordion = false, bordered = true, ghost = false, destroyInactivePanel = false, expandIconPosition = "start", onChange, className = "", ...props }) {
2887
2603
  const normalize = (key) => Array.isArray(key) ? [...key] : key === void 0 ? [] : [key];
2888
2604
  const controlled = activeKey !== void 0;
2889
- const [internal, setInternal] = (0, import_react17.useState)(normalize(defaultActiveKey));
2605
+ const [internal, setInternal] = (0, import_react16.useState)(normalize(defaultActiveKey));
2890
2606
  const openKeys = controlled ? normalize(activeKey) : internal;
2891
2607
  function toggle(item) {
2892
2608
  if (item.disabled || item.collapsible === "disabled") return;
@@ -2916,16 +2632,16 @@ function Collapse({ items, activeKey, defaultActiveKey = [], accordion = false,
2916
2632
  }) });
2917
2633
  }
2918
2634
  function ImagePreview({ open, src, alt = "", onOpenChange }) {
2919
- const previewRef = (0, import_react17.useRef)(null);
2920
- const stageRef = (0, import_react17.useRef)(null);
2921
- const [natural, setNatural] = (0, import_react17.useState)({ src: "", width: 0, height: 0 });
2922
- const [area, setArea] = (0, import_react17.useState)({ width: 0, height: 0 });
2923
- const [zoom, setZoom] = (0, import_react17.useState)(1);
2924
- const [rotation, setRotation] = (0, import_react17.useState)(0);
2925
- const [flip, setFlip] = (0, import_react17.useState)({ x: 1, y: 1 });
2926
- const [pan, setPan] = (0, import_react17.useState)({ x: 0, y: 0 });
2927
- const [failed, setFailed] = (0, import_react17.useState)(false);
2928
- const drag = (0, import_react17.useRef)();
2635
+ const previewRef = (0, import_react16.useRef)(null);
2636
+ const stageRef = (0, import_react16.useRef)(null);
2637
+ const [natural, setNatural] = (0, import_react16.useState)({ src: "", width: 0, height: 0 });
2638
+ const [area, setArea] = (0, import_react16.useState)({ width: 0, height: 0 });
2639
+ const [zoom, setZoom] = (0, import_react16.useState)(1);
2640
+ const [rotation, setRotation] = (0, import_react16.useState)(0);
2641
+ const [flip, setFlip] = (0, import_react16.useState)({ x: 1, y: 1 });
2642
+ const [pan, setPan] = (0, import_react16.useState)({ x: 0, y: 0 });
2643
+ const [failed, setFailed] = (0, import_react16.useState)(false);
2644
+ const drag = (0, import_react16.useRef)();
2929
2645
  useOverlayLifecycle(open, previewRef, () => onOpenChange(false));
2930
2646
  const reset = () => {
2931
2647
  setZoom(1);
@@ -2934,11 +2650,11 @@ function ImagePreview({ open, src, alt = "", onOpenChange }) {
2934
2650
  setPan({ x: 0, y: 0 });
2935
2651
  drag.current = void 0;
2936
2652
  };
2937
- (0, import_react17.useEffect)(() => {
2653
+ (0, import_react16.useEffect)(() => {
2938
2654
  reset();
2939
2655
  setFailed(false);
2940
2656
  }, [open, src]);
2941
- (0, import_react17.useEffect)(() => {
2657
+ (0, import_react16.useEffect)(() => {
2942
2658
  const stage = stageRef.current;
2943
2659
  if (!open || !stage) return;
2944
2660
  const measure = () => {
@@ -3024,10 +2740,10 @@ function useFloatingPlaceholder({ mode, placeholder, filled, active = false }) {
3024
2740
  }
3025
2741
 
3026
2742
  // src/components/Select.tsx
3027
- var import_react22 = require("react");
2743
+ var import_react23 = require("react");
3028
2744
 
3029
2745
  // src/components/Modal.tsx
3030
- var import_react18 = require("react");
2746
+ var import_react17 = require("react");
3031
2747
  var import_client3 = require("react-dom/client");
3032
2748
  var import_jsx_runtime17 = require("react/jsx-runtime");
3033
2749
  var modalHandles = /* @__PURE__ */ new Set();
@@ -3039,7 +2755,7 @@ var typeIcons = {
3039
2755
  error: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Icon, { name: "circle-close", size: 23 }),
3040
2756
  confirm: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Icon, { name: "question", size: 23 })
3041
2757
  };
3042
- var ModalRoot = (0, import_react18.forwardRef)(function Modal({
2758
+ var ModalRoot = (0, import_react17.forwardRef)(function Modal({
3043
2759
  open,
3044
2760
  title,
3045
2761
  children,
@@ -3065,302 +2781,679 @@ var ModalRoot = (0, import_react18.forwardRef)(function Modal({
3065
2781
  onOpenChange,
3066
2782
  afterOpenChange,
3067
2783
  className = "",
3068
- style,
2784
+ style,
2785
+ ...props
2786
+ }, forwardedRef) {
2787
+ const localRef = (0, import_react17.useRef)(null);
2788
+ const titleId = (0, import_react17.useId)();
2789
+ const [submitting, setSubmitting] = (0, import_react17.useState)(false);
2790
+ const [rendered, setRendered] = (0, import_react17.useState)(open);
2791
+ const [closing, setClosing] = (0, import_react17.useState)(false);
2792
+ const afterOpenChangeRef = (0, import_react17.useRef)(afterOpenChange);
2793
+ afterOpenChangeRef.current = afterOpenChange;
2794
+ const submitLock = (0, import_react17.useRef)(false);
2795
+ (0, import_react17.useEffect)(() => {
2796
+ if (!open || !rendered) return void 0;
2797
+ const timer = window.setTimeout(() => afterOpenChangeRef.current?.(true), MODAL_MOTION_DURATION);
2798
+ return () => window.clearTimeout(timer);
2799
+ }, [open, rendered]);
2800
+ (0, import_react17.useEffect)(() => {
2801
+ if (open) {
2802
+ setRendered(true);
2803
+ setClosing(false);
2804
+ return void 0;
2805
+ }
2806
+ if (!rendered) return void 0;
2807
+ setClosing(true);
2808
+ const timer = window.setTimeout(() => {
2809
+ setRendered(false);
2810
+ setClosing(false);
2811
+ afterOpenChangeRef.current?.(false);
2812
+ }, MODAL_MOTION_DURATION);
2813
+ return () => window.clearTimeout(timer);
2814
+ }, [open, rendered]);
2815
+ function setRef(node) {
2816
+ localRef.current = node;
2817
+ if (typeof forwardedRef === "function") forwardedRef(node);
2818
+ else if (forwardedRef) forwardedRef.current = node;
2819
+ }
2820
+ function requestClose() {
2821
+ if (submitting || confirmLoading) return;
2822
+ onCancel?.();
2823
+ onOpenChange?.(false);
2824
+ }
2825
+ async function handleOk() {
2826
+ if (submitLock.current || confirmLoading) return;
2827
+ submitLock.current = true;
2828
+ if (!onOk) {
2829
+ onOpenChange?.(false);
2830
+ submitLock.current = false;
2831
+ return;
2832
+ }
2833
+ try {
2834
+ const result = onOk();
2835
+ if (result instanceof Promise) {
2836
+ setSubmitting(true);
2837
+ const resolved = await result;
2838
+ if (resolved !== false) onOpenChange?.(false);
2839
+ } else if (result !== false) {
2840
+ onOpenChange?.(false);
2841
+ }
2842
+ } catch {
2843
+ return;
2844
+ } finally {
2845
+ submitLock.current = false;
2846
+ setSubmitting(false);
2847
+ }
2848
+ }
2849
+ useOverlayLifecycle(rendered, localRef, requestClose, keyboard);
2850
+ if (!rendered) return null;
2851
+ const mergedStyle = {
2852
+ ...height !== void 0 ? { display: "flex", flexDirection: "column", height, maxHeight: "calc(100dvh - 48px)" } : {},
2853
+ ...style,
2854
+ "--sia-modal-width": typeof width === "number" ? `${width}px` : width
2855
+ };
2856
+ const loading = submitting || confirmLoading;
2857
+ const defaultFooter = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2858
+ showCancel ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { ...cancelButtonProps, onClick: requestClose, disabled: loading || cancelButtonProps?.disabled, children: cancelText }) : null,
2859
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { variant: "primary", ...okButtonProps, onClick: handleOk, loading, children: okText })
2860
+ ] });
2861
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(OverlayPortal, { container: getContainer, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2862
+ "div",
2863
+ {
2864
+ className: `sia-modal-root${centered ? " sia-modal-root--centered" : ""}`,
2865
+ "data-state": closing ? "closing" : "open",
2866
+ style: { zIndex },
2867
+ onMouseDown: (event) => {
2868
+ if (event.target === event.currentTarget && maskClosable) requestClose();
2869
+ },
2870
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2871
+ "div",
2872
+ {
2873
+ ref: setRef,
2874
+ className: `sia-modal sia-modal--${type} ${className}`.trim(),
2875
+ style: mergedStyle,
2876
+ role: "dialog",
2877
+ "aria-modal": "true",
2878
+ "aria-labelledby": title ? titleId : void 0,
2879
+ tabIndex: -1,
2880
+ ...withTitleTooltip(props),
2881
+ children: [
2882
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "sia-modal__header", style: height !== void 0 ? { flexShrink: 0 } : void 0, children: [
2883
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "sia-modal__heading", children: [
2884
+ typeIcons[type] ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "sia-modal__type-icon", "aria-hidden": "true", children: typeIcons[type] }) : null,
2885
+ title ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { id: titleId, children: title }) : null
2886
+ ] }),
2887
+ closable ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: "sia-modal__close", "aria-label": "\u5173\u95ED\u5BF9\u8BDD\u6846", onClick: requestClose, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Icon, { name: "close", size: 17 }) }) : null
2888
+ ] }),
2889
+ children !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "sia-modal__body", style: height !== void 0 ? { flex: 1, minHeight: 0, overflow: "auto" } : void 0, children }) : null,
2890
+ footer !== null ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "sia-modal__footer", style: height !== void 0 ? { flexShrink: 0 } : void 0, children: [
2891
+ footer === void 0 && footerExtra != null ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { marginRight: "auto" }, children: footerExtra }) : null,
2892
+ footer ?? defaultFooter
2893
+ ] }) : null
2894
+ ]
2895
+ }
2896
+ )
2897
+ }
2898
+ ) });
2899
+ });
2900
+ function openModal(config) {
2901
+ if (typeof document === "undefined") return { destroy() {
2902
+ }, update() {
2903
+ } };
2904
+ const container = document.createElement("div");
2905
+ container.className = "sia-modal-api-host";
2906
+ document.body.appendChild(container);
2907
+ const root = (0, import_client3.createRoot)(container);
2908
+ let currentConfig = config;
2909
+ let currentOpen = true;
2910
+ let destroyed = false;
2911
+ let cleanupTimer;
2912
+ function cleanup2() {
2913
+ if (destroyed) return;
2914
+ destroyed = true;
2915
+ if (cleanupTimer !== void 0) window.clearTimeout(cleanupTimer);
2916
+ root.unmount();
2917
+ container.remove();
2918
+ modalHandles.delete(handle);
2919
+ }
2920
+ function closeWithMotion() {
2921
+ if (destroyed || !currentOpen) return;
2922
+ currentOpen = false;
2923
+ render();
2924
+ cleanupTimer = window.setTimeout(cleanup2, MODAL_MOTION_DURATION);
2925
+ }
2926
+ function render() {
2927
+ root.render(/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ModalRoot, { ...currentConfig, open: currentOpen, onOpenChange: (nextOpen) => {
2928
+ currentConfig.onOpenChange?.(nextOpen);
2929
+ if (!nextOpen) closeWithMotion();
2930
+ } }));
2931
+ }
2932
+ const handle = {
2933
+ destroy: closeWithMotion,
2934
+ update(next) {
2935
+ if (destroyed) return;
2936
+ currentConfig = { ...currentConfig, ...next };
2937
+ render();
2938
+ }
2939
+ };
2940
+ modalHandles.add(handle);
2941
+ render();
2942
+ return handle;
2943
+ }
2944
+ function preset(type, defaults = {}) {
2945
+ return (config) => openModal({
2946
+ okText: type === "confirm" ? "\u786E\u5B9A" : "\u77E5\u9053\u4E86",
2947
+ showCancel: type === "confirm",
2948
+ closable: type !== "confirm",
2949
+ maskClosable: type !== "confirm",
2950
+ ...defaults,
2951
+ ...config,
2952
+ type
2953
+ });
2954
+ }
2955
+ var Modal2 = Object.assign(ModalRoot, {
2956
+ /** 直接打开实例,返回可用于更新或关闭的操作句柄。 */
2957
+ open: openModal,
2958
+ /** 显示普通信息提示。 */
2959
+ info: preset("info", { title: "\u63D0\u793A" }),
2960
+ /** 显示成功提示。 */
2961
+ success: preset("success", { title: "\u64CD\u4F5C\u6210\u529F" }),
2962
+ /** 显示警告提示。 */
2963
+ warning: preset("warning", { title: "\u8BF7\u6CE8\u610F" }),
2964
+ /** 显示错误提示。 */
2965
+ error: preset("error", { title: "\u64CD\u4F5C\u5931\u8D25" }),
2966
+ /** 打开确认弹框,支持异步确认;返回 false 可阻止关闭。 */
2967
+ confirm: preset("confirm", { title: "\u786E\u8BA4\u64CD\u4F5C" }),
2968
+ /** 关闭由此 API 打开的所有弹层。 */
2969
+ destroyAll() {
2970
+ [...modalHandles].forEach((handle) => handle.destroy());
2971
+ }
2972
+ });
2973
+
2974
+ // src/components/Input.tsx
2975
+ var import_react18 = require("react");
2976
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2977
+ var Input = (0, import_react18.forwardRef)(function Input2({
2978
+ label,
2979
+ hint,
2980
+ status = "default",
2981
+ size: sizeProp,
2982
+ prefix,
2983
+ suffix,
2984
+ allowClear = true,
2985
+ onClear,
2986
+ showCount = false,
2987
+ placeholderMode,
2988
+ placeholder,
2989
+ className = "",
2990
+ id,
2991
+ disabled,
2992
+ value,
2993
+ defaultValue,
2994
+ maxLength,
2995
+ onChange,
3069
2996
  ...props
3070
2997
  }, forwardedRef) {
2998
+ const size = useControlSize(sizeProp);
2999
+ const fallbackId = (0, import_react18.useId)();
3000
+ const inputId = id ?? fallbackId;
3071
3001
  const localRef = (0, import_react18.useRef)(null);
3072
- const titleId = (0, import_react18.useId)();
3073
- const [submitting, setSubmitting] = (0, import_react18.useState)(false);
3074
- const [rendered, setRendered] = (0, import_react18.useState)(open);
3075
- const [closing, setClosing] = (0, import_react18.useState)(false);
3076
- const afterOpenChangeRef = (0, import_react18.useRef)(afterOpenChange);
3077
- afterOpenChangeRef.current = afterOpenChange;
3078
- const submitLock = (0, import_react18.useRef)(false);
3079
- (0, import_react18.useEffect)(() => {
3080
- if (!open || !rendered) return void 0;
3081
- const timer = window.setTimeout(() => afterOpenChangeRef.current?.(true), MODAL_MOTION_DURATION);
3082
- return () => window.clearTimeout(timer);
3083
- }, [open, rendered]);
3084
- (0, import_react18.useEffect)(() => {
3085
- if (open) {
3086
- setRendered(true);
3087
- setClosing(false);
3088
- return void 0;
3089
- }
3090
- if (!rendered) return void 0;
3091
- setClosing(true);
3092
- const timer = window.setTimeout(() => {
3093
- setRendered(false);
3094
- setClosing(false);
3095
- afterOpenChangeRef.current?.(false);
3096
- }, MODAL_MOTION_DURATION);
3097
- return () => window.clearTimeout(timer);
3098
- }, [open, rendered]);
3002
+ const [uncontrolledValue, setUncontrolledValue] = (0, import_react18.useState)(() => defaultValue === void 0 ? "" : String(defaultValue));
3003
+ const currentText = value !== void 0 ? String(value) : uncontrolledValue;
3004
+ const hasValue = currentText.length > 0;
3005
+ const floatingPlaceholder = usePlaceholderMode(placeholderMode) === "floating" && Boolean(placeholder);
3006
+ const hintId = `${inputId}-hint`;
3007
+ const describedBy = [props["aria-describedby"], hint ? hintId : null].filter(Boolean).join(" ") || void 0;
3099
3008
  function setRef(node) {
3100
3009
  localRef.current = node;
3101
3010
  if (typeof forwardedRef === "function") forwardedRef(node);
3102
3011
  else if (forwardedRef) forwardedRef.current = node;
3103
3012
  }
3104
- function requestClose() {
3105
- if (submitting || confirmLoading) return;
3106
- onCancel?.();
3107
- onOpenChange?.(false);
3013
+ function handleChange(event) {
3014
+ if (maxLength !== void 0 && maxLength >= 0 && event.target.value.length > maxLength) {
3015
+ const valueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
3016
+ valueSetter?.call(event.target, event.target.value.slice(0, maxLength));
3017
+ }
3018
+ setUncontrolledValue(event.target.value);
3019
+ onChange?.(event);
3108
3020
  }
3109
- async function handleOk() {
3110
- if (submitLock.current || confirmLoading) return;
3111
- submitLock.current = true;
3112
- if (!onOk) {
3113
- onOpenChange?.(false);
3114
- submitLock.current = false;
3115
- return;
3021
+ function clearValue() {
3022
+ const input2 = localRef.current;
3023
+ if (!input2 || disabled) return;
3024
+ const valueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
3025
+ valueSetter?.call(input2, "");
3026
+ input2.dispatchEvent(new Event("input", { bubbles: true }));
3027
+ setUncontrolledValue("");
3028
+ input2.focus();
3029
+ onClear?.();
3030
+ }
3031
+ function handleControlMouseDown(event) {
3032
+ if (disabled || event.defaultPrevented || event.button !== 0) return;
3033
+ const target = event.target;
3034
+ if (!(target instanceof Element)) return;
3035
+ const interactive = target.closest("input, textarea, select, button, a[href], [tabindex], [contenteditable]:not([contenteditable='false']), [role='button'], [role='link']");
3036
+ if (interactive && event.currentTarget.contains(interactive) && !interactive.classList.contains("sia-input-control__clear")) return;
3037
+ event.preventDefault();
3038
+ localRef.current?.focus({ preventScroll: true });
3039
+ }
3040
+ const input = /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3041
+ "input",
3042
+ {
3043
+ ...withTitleTooltip(props),
3044
+ ref: setRef,
3045
+ id: inputId,
3046
+ className: "sia-input",
3047
+ disabled,
3048
+ value,
3049
+ defaultValue,
3050
+ maxLength,
3051
+ placeholder,
3052
+ "aria-describedby": describedBy,
3053
+ "aria-invalid": status === "error" || void 0,
3054
+ onChange: handleChange
3116
3055
  }
3117
- try {
3118
- const result = onOk();
3119
- if (result instanceof Promise) {
3120
- setSubmitting(true);
3121
- const resolved = await result;
3122
- if (resolved !== false) onOpenChange?.(false);
3123
- } else if (result !== false) {
3124
- onOpenChange?.(false);
3056
+ );
3057
+ const control = /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { onMouseDown: handleControlMouseDown, className: `sia-input-control sia-input-control--${size} sia-input-control--${status}${floatingPlaceholder ? " sia-input-control--floating" : ""}${floatingPlaceholder && hasValue ? " is-filled" : ""}${disabled ? " is-disabled" : ""}`, children: [
3058
+ prefix ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "sia-input-control__affix", children: prefix }) : null,
3059
+ floatingPlaceholder ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "sia-input-control__input-wrap", children: [
3060
+ input,
3061
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "sia-input-control__floating-placeholder", "aria-hidden": "true", children: placeholder })
3062
+ ] }) : input,
3063
+ allowClear && hasValue && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { className: "sia-input-control__clear", type: "button", "aria-label": "\u6E05\u7A7A\u8F93\u5165", onClick: clearValue, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Icon, { name: "circle-close", variant: "filled", size: 15 }) }) : null,
3064
+ suffix ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "sia-input-control__affix", children: suffix }) : null,
3065
+ showCount ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: `sia-input-control__count${maxLength !== void 0 && currentText.length >= maxLength ? " is-limit" : ""}`, "aria-live": "polite", children: [
3066
+ currentText.length,
3067
+ maxLength !== void 0 ? `/${maxLength}` : null
3068
+ ] }) : null
3069
+ ] });
3070
+ if (!label && !hint) return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: `sia-field ${className}`.trim(), children: control });
3071
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: `sia-field ${className}`.trim(), children: [
3072
+ label ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { className: "sia-field__label", htmlFor: inputId, children: label }) : null,
3073
+ control,
3074
+ hint ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { id: hintId, className: `sia-field__hint sia-field__hint--${status}`, children: hint }) : null
3075
+ ] });
3076
+ });
3077
+
3078
+ // src/components/SelectionPanel.tsx
3079
+ var import_react21 = require("react");
3080
+
3081
+ // src/components/FloatingScrollbarProvider.tsx
3082
+ var import_react20 = require("react");
3083
+
3084
+ // src/components/useScrollbarProximity.ts
3085
+ var import_react19 = require("react");
3086
+ var users = 0;
3087
+ var cleanup;
3088
+ function useScrollbarProximity() {
3089
+ (0, import_react19.useEffect)(() => {
3090
+ if (users++ === 0) {
3091
+ let frame = 0;
3092
+ let x = -Infinity;
3093
+ let y = -Infinity;
3094
+ const nearby = /* @__PURE__ */ new Set();
3095
+ const clear = () => {
3096
+ nearby.forEach((track) => track.removeAttribute("data-scrollbar-near"));
3097
+ nearby.clear();
3098
+ };
3099
+ const update = () => {
3100
+ frame = 0;
3101
+ const next = /* @__PURE__ */ new Set();
3102
+ document.querySelectorAll(".sia-scrollbar-track").forEach((track) => {
3103
+ const rect = track.getBoundingClientRect();
3104
+ const proximity = Number.parseFloat(getComputedStyle(track).getPropertyValue("--sia-scrollbar-proximity")) || 16;
3105
+ if (rect.width && rect.height && x >= rect.left - proximity && x <= rect.right + proximity && y >= rect.top - proximity && y <= rect.bottom + proximity) {
3106
+ next.add(track);
3107
+ if (!nearby.has(track)) track.setAttribute("data-scrollbar-near", "true");
3108
+ }
3109
+ });
3110
+ nearby.forEach((track) => {
3111
+ if (!next.has(track)) track.removeAttribute("data-scrollbar-near");
3112
+ });
3113
+ nearby.clear();
3114
+ next.forEach((track) => nearby.add(track));
3115
+ };
3116
+ const move = (event) => {
3117
+ if (event.pointerType === "touch") return;
3118
+ x = event.clientX;
3119
+ y = event.clientY;
3120
+ if (!frame) frame = requestAnimationFrame(update);
3121
+ };
3122
+ const leave = () => {
3123
+ x = y = -Infinity;
3124
+ clear();
3125
+ };
3126
+ document.addEventListener("pointermove", move, { passive: true });
3127
+ document.documentElement.addEventListener("pointerleave", leave);
3128
+ window.addEventListener("blur", leave);
3129
+ cleanup = () => {
3130
+ if (frame) cancelAnimationFrame(frame);
3131
+ document.removeEventListener("pointermove", move);
3132
+ document.documentElement.removeEventListener("pointerleave", leave);
3133
+ window.removeEventListener("blur", leave);
3134
+ clear();
3135
+ };
3136
+ }
3137
+ return () => {
3138
+ if (--users === 0) {
3139
+ cleanup?.();
3140
+ cleanup = void 0;
3141
+ }
3142
+ };
3143
+ }, []);
3144
+ }
3145
+
3146
+ // src/components/FloatingScrollbarProvider.tsx
3147
+ var scrollableOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay"]);
3148
+ var clippingOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay", "hidden", "clip"]);
3149
+ function isRootScroller(target) {
3150
+ return target === document.scrollingElement || target === document.documentElement;
3151
+ }
3152
+ function canScroll(target, axis) {
3153
+ if (target.matches(".sia-table__viewport, [data-sia-native-scrollbar]")) return false;
3154
+ if (isRootScroller(target)) {
3155
+ return axis === "horizontal" ? target.scrollWidth > target.clientWidth + 1 : target.scrollHeight > target.clientHeight + 1;
3156
+ }
3157
+ const style = getComputedStyle(target);
3158
+ const overflow = axis === "horizontal" ? style.overflowX : style.overflowY;
3159
+ const hasOverflow = axis === "horizontal" ? target.scrollWidth > target.clientWidth + 1 : target.scrollHeight > target.clientHeight + 1;
3160
+ return hasOverflow && scrollableOverflow.has(overflow);
3161
+ }
3162
+ function visibleRect(target) {
3163
+ if (isRootScroller(target)) {
3164
+ return { top: 0, right: window.innerWidth, bottom: window.innerHeight, left: 0, width: window.innerWidth, height: window.innerHeight };
3165
+ }
3166
+ const ownRect = target.getBoundingClientRect();
3167
+ let top = Math.max(0, ownRect.top);
3168
+ let right = Math.min(window.innerWidth, ownRect.right);
3169
+ let bottom = Math.min(window.innerHeight, ownRect.bottom);
3170
+ let left = Math.max(0, ownRect.left);
3171
+ let parent = target.parentElement;
3172
+ while (parent && parent !== document.body && parent !== document.documentElement) {
3173
+ const style = getComputedStyle(parent);
3174
+ const clipX = clippingOverflow.has(style.overflowX);
3175
+ const clipY = clippingOverflow.has(style.overflowY);
3176
+ if (clipX || clipY) {
3177
+ const rect = parent.getBoundingClientRect();
3178
+ if (clipX) {
3179
+ left = Math.max(left, rect.left);
3180
+ right = Math.min(right, rect.right);
3181
+ }
3182
+ if (clipY) {
3183
+ top = Math.max(top, rect.top);
3184
+ bottom = Math.min(bottom, rect.bottom);
3125
3185
  }
3126
- } catch {
3127
- return;
3128
- } finally {
3129
- submitLock.current = false;
3130
- setSubmitting(false);
3131
3186
  }
3187
+ parent = parent.parentElement;
3132
3188
  }
3133
- useOverlayLifecycle(rendered, localRef, requestClose, keyboard);
3134
- if (!rendered) return null;
3135
- const mergedStyle = {
3136
- ...height !== void 0 ? { display: "flex", flexDirection: "column", height, maxHeight: "calc(100dvh - 48px)" } : {},
3137
- ...style,
3138
- "--sia-modal-width": typeof width === "number" ? `${width}px` : width
3189
+ return {
3190
+ top,
3191
+ right,
3192
+ bottom,
3193
+ left,
3194
+ width: Math.max(0, right - left),
3195
+ height: Math.max(0, bottom - top)
3139
3196
  };
3140
- const loading = submitting || confirmLoading;
3141
- const defaultFooter = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
3142
- showCancel ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { ...cancelButtonProps, onClick: requestClose, disabled: loading || cancelButtonProps?.disabled, children: cancelText }) : null,
3143
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { variant: "primary", ...okButtonProps, onClick: handleOk, loading, children: okText })
3144
- ] });
3145
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(OverlayPortal, { container: getContainer, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3146
- "div",
3147
- {
3148
- className: `sia-modal-root${centered ? " sia-modal-root--centered" : ""}`,
3149
- "data-state": closing ? "closing" : "open",
3150
- style: { zIndex },
3151
- onMouseDown: (event) => {
3152
- if (event.target === event.currentTarget && maskClosable) requestClose();
3153
- },
3154
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
3155
- "div",
3156
- {
3157
- ref: setRef,
3158
- className: `sia-modal sia-modal--${type} ${className}`.trim(),
3159
- style: mergedStyle,
3160
- role: "dialog",
3161
- "aria-modal": "true",
3162
- "aria-labelledby": title ? titleId : void 0,
3163
- tabIndex: -1,
3164
- ...withTitleTooltip(props),
3165
- children: [
3166
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "sia-modal__header", style: height !== void 0 ? { flexShrink: 0 } : void 0, children: [
3167
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "sia-modal__heading", children: [
3168
- typeIcons[type] ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "sia-modal__type-icon", "aria-hidden": "true", children: typeIcons[type] }) : null,
3169
- title ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { id: titleId, children: title }) : null
3170
- ] }),
3171
- closable ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", className: "sia-modal__close", "aria-label": "\u5173\u95ED\u5BF9\u8BDD\u6846", onClick: requestClose, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Icon, { name: "close", size: 17 }) }) : null
3172
- ] }),
3173
- children !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "sia-modal__body", style: height !== void 0 ? { flex: 1, minHeight: 0, overflow: "auto" } : void 0, children }) : null,
3174
- footer !== null ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "sia-modal__footer", style: height !== void 0 ? { flexShrink: 0 } : void 0, children: [
3175
- footer === void 0 && footerExtra != null ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { marginRight: "auto" }, children: footerExtra }) : null,
3176
- footer ?? defaultFooter
3177
- ] }) : null
3178
- ]
3197
+ }
3198
+ function createTrack(axis) {
3199
+ const track = document.createElement("div");
3200
+ const thumb = document.createElement("div");
3201
+ track.className = `sia-scrollbar-track sia-floating-scrollbar sia-floating-scrollbar--${axis}`;
3202
+ thumb.className = "sia-floating-scrollbar__thumb";
3203
+ track.dataset.axis = axis;
3204
+ track.setAttribute("aria-hidden", "true");
3205
+ track.append(thumb);
3206
+ return { track, thumb };
3207
+ }
3208
+ function FloatingScrollbarProvider({ disabled = false, targetRef }) {
3209
+ useScrollbarProximity();
3210
+ (0, import_react20.useEffect)(() => {
3211
+ if (disabled) return;
3212
+ const layer = document.createElement("div");
3213
+ layer.className = "sia-floating-scrollbar-layer";
3214
+ layer.setAttribute("aria-hidden", "true");
3215
+ document.body.append(layer);
3216
+ const entries = /* @__PURE__ */ new Map();
3217
+ let scanFrame = 0;
3218
+ let updateFrame = 0;
3219
+ const setEntryVisible = (entry, visible) => {
3220
+ entry.horizontalTrack.classList.toggle("sia-floating-scrollbar--visible", visible);
3221
+ entry.verticalTrack.classList.toggle("sia-floating-scrollbar--visible", visible);
3222
+ };
3223
+ const showEntry = (entry) => {
3224
+ if (entry.hideTimer !== null) window.clearTimeout(entry.hideTimer);
3225
+ entry.hideTimer = null;
3226
+ setEntryVisible(entry, true);
3227
+ };
3228
+ const scheduleHide = (entry, delay = 500) => {
3229
+ if (entry.hideTimer !== null) window.clearTimeout(entry.hideTimer);
3230
+ entry.hideTimer = window.setTimeout(() => {
3231
+ entry.hideTimer = null;
3232
+ if (!entry.hoveringTarget && !entry.hoveringTrack && !entry.dragging) setEntryVisible(entry, false);
3233
+ }, delay);
3234
+ };
3235
+ const updateEntry = (entry) => {
3236
+ const { target, horizontalTrack, horizontalThumb, verticalTrack, verticalThumb } = entry;
3237
+ const hasHorizontal = canScroll(target, "horizontal");
3238
+ const hasVertical = canScroll(target, "vertical");
3239
+ const rect = visibleRect(target);
3240
+ const thickness = 10;
3241
+ horizontalTrack.hidden = !hasHorizontal || rect.width <= thickness || rect.height <= 0;
3242
+ verticalTrack.hidden = !hasVertical || rect.height <= thickness || rect.width <= 0;
3243
+ if (!horizontalTrack.hidden) {
3244
+ const trackWidth = Math.max(0, rect.width - (hasVertical ? thickness : 0));
3245
+ const thumbWidth = Math.max(24, Math.min(trackWidth, trackWidth * target.clientWidth / target.scrollWidth));
3246
+ const travel = Math.max(0, trackWidth - thumbWidth);
3247
+ const maxScroll = Math.max(1, target.scrollWidth - target.clientWidth);
3248
+ horizontalTrack.style.left = `${rect.left}px`;
3249
+ horizontalTrack.style.top = `${rect.bottom - thickness}px`;
3250
+ horizontalTrack.style.width = `${trackWidth}px`;
3251
+ horizontalTrack.style.height = `${thickness}px`;
3252
+ horizontalThumb.style.width = `${thumbWidth}px`;
3253
+ horizontalThumb.style.transform = `translate3d(${travel * target.scrollLeft / maxScroll}px, 0, 0)`;
3254
+ }
3255
+ if (!verticalTrack.hidden) {
3256
+ const trackHeight = Math.max(0, rect.height - (hasHorizontal ? thickness : 0));
3257
+ const thumbHeight = Math.max(24, Math.min(trackHeight, trackHeight * target.clientHeight / target.scrollHeight));
3258
+ const travel = Math.max(0, trackHeight - thumbHeight);
3259
+ const maxScroll = Math.max(1, target.scrollHeight - target.clientHeight);
3260
+ verticalTrack.style.left = `${rect.right - thickness}px`;
3261
+ verticalTrack.style.top = `${rect.top}px`;
3262
+ verticalTrack.style.width = `${thickness}px`;
3263
+ verticalTrack.style.height = `${trackHeight}px`;
3264
+ verticalThumb.style.height = `${thumbHeight}px`;
3265
+ verticalThumb.style.transform = `translate3d(0, ${travel * target.scrollTop / maxScroll}px, 0)`;
3266
+ }
3267
+ };
3268
+ const scheduleUpdateAll = () => {
3269
+ if (updateFrame) return;
3270
+ updateFrame = window.requestAnimationFrame(() => {
3271
+ updateFrame = 0;
3272
+ entries.forEach(updateEntry);
3273
+ });
3274
+ };
3275
+ const bindTrackDrag = (entry, axis, track, thumb) => {
3276
+ const target = entry.target;
3277
+ const onTrackPointerEnter = () => {
3278
+ entry.hoveringTrack = true;
3279
+ showEntry(entry);
3280
+ };
3281
+ const onTrackPointerLeave = () => {
3282
+ entry.hoveringTrack = false;
3283
+ scheduleHide(entry);
3284
+ };
3285
+ const onTrackPointerDown = (event) => {
3286
+ if (event.target === thumb || event.button !== 0) return;
3287
+ event.preventDefault();
3288
+ event.stopPropagation();
3289
+ const trackRect = track.getBoundingClientRect();
3290
+ const thumbRect = thumb.getBoundingClientRect();
3291
+ const trackLength = axis === "vertical" ? trackRect.height : trackRect.width;
3292
+ const thumbLength = axis === "vertical" ? thumbRect.height : thumbRect.width;
3293
+ const pointer = axis === "vertical" ? event.clientY - trackRect.top : event.clientX - trackRect.left;
3294
+ const ratio = Math.max(0, Math.min(1, (pointer - thumbLength / 2) / Math.max(1, trackLength - thumbLength)));
3295
+ if (axis === "vertical") target.scrollTop = ratio * (target.scrollHeight - target.clientHeight);
3296
+ else target.scrollLeft = ratio * (target.scrollWidth - target.clientWidth);
3297
+ };
3298
+ const onThumbPointerDown = (event) => {
3299
+ if (event.button !== 0) return;
3300
+ event.preventDefault();
3301
+ event.stopPropagation();
3302
+ entry.dragging = true;
3303
+ showEntry(entry);
3304
+ thumb.setPointerCapture(event.pointerId);
3305
+ const startPointer = axis === "vertical" ? event.clientY : event.clientX;
3306
+ const startScroll = axis === "vertical" ? target.scrollTop : target.scrollLeft;
3307
+ const trackRect = track.getBoundingClientRect();
3308
+ const thumbRect = thumb.getBoundingClientRect();
3309
+ const trackLength = axis === "vertical" ? trackRect.height : trackRect.width;
3310
+ const thumbLength = axis === "vertical" ? thumbRect.height : thumbRect.width;
3311
+ const maxScroll = axis === "vertical" ? target.scrollHeight - target.clientHeight : target.scrollWidth - target.clientWidth;
3312
+ const travel = Math.max(1, trackLength - thumbLength);
3313
+ const onPointerMove = (moveEvent) => {
3314
+ if (moveEvent.pointerId !== event.pointerId) return;
3315
+ const pointer = axis === "vertical" ? moveEvent.clientY : moveEvent.clientX;
3316
+ const nextScroll = startScroll + (pointer - startPointer) * maxScroll / travel;
3317
+ if (axis === "vertical") target.scrollTop = nextScroll;
3318
+ else target.scrollLeft = nextScroll;
3319
+ };
3320
+ const onPointerUp = (upEvent) => {
3321
+ if (upEvent.pointerId !== event.pointerId) return;
3322
+ entry.dragging = false;
3323
+ thumb.releasePointerCapture(event.pointerId);
3324
+ window.removeEventListener("pointermove", onPointerMove);
3325
+ window.removeEventListener("pointerup", onPointerUp);
3326
+ window.removeEventListener("pointercancel", onPointerUp);
3327
+ scheduleHide(entry);
3328
+ };
3329
+ window.addEventListener("pointermove", onPointerMove);
3330
+ window.addEventListener("pointerup", onPointerUp);
3331
+ window.addEventListener("pointercancel", onPointerUp);
3332
+ };
3333
+ track.addEventListener("pointerenter", onTrackPointerEnter);
3334
+ track.addEventListener("pointerleave", onTrackPointerLeave);
3335
+ track.addEventListener("pointerdown", onTrackPointerDown);
3336
+ thumb.addEventListener("pointerdown", onThumbPointerDown);
3337
+ return () => {
3338
+ track.removeEventListener("pointerenter", onTrackPointerEnter);
3339
+ track.removeEventListener("pointerleave", onTrackPointerLeave);
3340
+ track.removeEventListener("pointerdown", onTrackPointerDown);
3341
+ thumb.removeEventListener("pointerdown", onThumbPointerDown);
3342
+ };
3343
+ };
3344
+ const resizeObserver = new ResizeObserver((observedEntries) => {
3345
+ observedEntries.forEach(({ target }) => {
3346
+ const entry = entries.get(target);
3347
+ if (entry) updateEntry(entry);
3348
+ });
3349
+ });
3350
+ const addTarget = (target) => {
3351
+ if (entries.has(target)) return;
3352
+ const horizontal = createTrack("horizontal");
3353
+ const vertical = createTrack("vertical");
3354
+ layer.append(horizontal.track, vertical.track);
3355
+ const onPointerEnter = () => {
3356
+ const entry2 = entries.get(target);
3357
+ if (!entry2) return;
3358
+ entry2.hoveringTarget = true;
3359
+ showEntry(entry2);
3360
+ };
3361
+ const onPointerLeave = () => {
3362
+ const entry2 = entries.get(target);
3363
+ if (!entry2) return;
3364
+ entry2.hoveringTarget = false;
3365
+ scheduleHide(entry2);
3366
+ };
3367
+ const onScroll = () => {
3368
+ const entry2 = entries.get(target);
3369
+ if (!entry2) return;
3370
+ updateEntry(entry2);
3371
+ showEntry(entry2);
3372
+ scheduleHide(entry2, 700);
3373
+ };
3374
+ target.addEventListener("pointerenter", onPointerEnter);
3375
+ target.addEventListener("pointerleave", onPointerLeave);
3376
+ target.addEventListener("scroll", onScroll, { passive: true });
3377
+ const entry = {
3378
+ target,
3379
+ horizontalTrack: horizontal.track,
3380
+ horizontalThumb: horizontal.thumb,
3381
+ verticalTrack: vertical.track,
3382
+ verticalThumb: vertical.thumb,
3383
+ hideTimer: null,
3384
+ hoveringTarget: target.matches(":hover"),
3385
+ hoveringTrack: false,
3386
+ dragging: false,
3387
+ cleanup: () => void 0
3388
+ };
3389
+ const cleanupHorizontal = bindTrackDrag(entry, "horizontal", horizontal.track, horizontal.thumb);
3390
+ const cleanupVertical = bindTrackDrag(entry, "vertical", vertical.track, vertical.thumb);
3391
+ entry.cleanup = () => {
3392
+ if (entry.hideTimer !== null) window.clearTimeout(entry.hideTimer);
3393
+ cleanupHorizontal();
3394
+ cleanupVertical();
3395
+ target.removeEventListener("pointerenter", onPointerEnter);
3396
+ target.removeEventListener("pointerleave", onPointerLeave);
3397
+ target.removeEventListener("scroll", onScroll);
3398
+ resizeObserver.unobserve(target);
3399
+ target.removeAttribute("data-sia-floating-scrollbar");
3400
+ horizontal.track.remove();
3401
+ vertical.track.remove();
3402
+ };
3403
+ entries.set(target, entry);
3404
+ target.setAttribute("data-sia-floating-scrollbar", "");
3405
+ resizeObserver.observe(target);
3406
+ updateEntry(entry);
3407
+ if (entry.hoveringTarget) showEntry(entry);
3408
+ };
3409
+ const removeTarget = (target) => {
3410
+ const entry = entries.get(target);
3411
+ if (!entry) return;
3412
+ entry.cleanup();
3413
+ entries.delete(target);
3414
+ };
3415
+ const scanTargets = () => {
3416
+ scanFrame = 0;
3417
+ const candidates = (targetRef ? [targetRef.current] : [document.scrollingElement, ...document.querySelectorAll("*")]).filter((target) => target instanceof HTMLElement);
3418
+ const nextTargets = /* @__PURE__ */ new Set();
3419
+ candidates.forEach((target) => {
3420
+ if (canScroll(target, "horizontal") || canScroll(target, "vertical")) {
3421
+ nextTargets.add(target);
3422
+ if (entries.has(target) || !target.hasAttribute("data-sia-floating-scrollbar")) addTarget(target);
3179
3423
  }
3180
- )
3181
- }
3182
- ) });
3183
- });
3184
- function openModal(config) {
3185
- if (typeof document === "undefined") return { destroy() {
3186
- }, update() {
3187
- } };
3188
- const container = document.createElement("div");
3189
- container.className = "sia-modal-api-host";
3190
- document.body.appendChild(container);
3191
- const root = (0, import_client3.createRoot)(container);
3192
- let currentConfig = config;
3193
- let currentOpen = true;
3194
- let destroyed = false;
3195
- let cleanupTimer;
3196
- function cleanup2() {
3197
- if (destroyed) return;
3198
- destroyed = true;
3199
- if (cleanupTimer !== void 0) window.clearTimeout(cleanupTimer);
3200
- root.unmount();
3201
- container.remove();
3202
- modalHandles.delete(handle);
3203
- }
3204
- function closeWithMotion() {
3205
- if (destroyed || !currentOpen) return;
3206
- currentOpen = false;
3207
- render();
3208
- cleanupTimer = window.setTimeout(cleanup2, MODAL_MOTION_DURATION);
3209
- }
3210
- function render() {
3211
- root.render(/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ModalRoot, { ...currentConfig, open: currentOpen, onOpenChange: (nextOpen) => {
3212
- currentConfig.onOpenChange?.(nextOpen);
3213
- if (!nextOpen) closeWithMotion();
3214
- } }));
3215
- }
3216
- const handle = {
3217
- destroy: closeWithMotion,
3218
- update(next) {
3219
- if (destroyed) return;
3220
- currentConfig = { ...currentConfig, ...next };
3221
- render();
3222
- }
3223
- };
3224
- modalHandles.add(handle);
3225
- render();
3226
- return handle;
3227
- }
3228
- function preset(type, defaults = {}) {
3229
- return (config) => openModal({
3230
- okText: type === "confirm" ? "\u786E\u5B9A" : "\u77E5\u9053\u4E86",
3231
- showCancel: type === "confirm",
3232
- closable: type !== "confirm",
3233
- maskClosable: type !== "confirm",
3234
- ...defaults,
3235
- ...config,
3236
- type
3237
- });
3424
+ });
3425
+ entries.forEach((_entry, target) => {
3426
+ if (!target.isConnected || !nextTargets.has(target)) removeTarget(target);
3427
+ else updateEntry(_entry);
3428
+ });
3429
+ };
3430
+ const scheduleScan = () => {
3431
+ if (scanFrame) return;
3432
+ scanFrame = window.requestAnimationFrame(scanTargets);
3433
+ };
3434
+ const mutationObserver = new MutationObserver((mutations) => {
3435
+ if (mutations.some((mutation) => !layer.contains(mutation.target))) scheduleScan();
3436
+ });
3437
+ mutationObserver.observe(document.documentElement, { subtree: true, childList: true, attributes: true });
3438
+ window.addEventListener("resize", scheduleScan);
3439
+ window.addEventListener("scroll", scheduleUpdateAll, true);
3440
+ scheduleScan();
3441
+ return () => {
3442
+ mutationObserver.disconnect();
3443
+ resizeObserver.disconnect();
3444
+ window.removeEventListener("resize", scheduleScan);
3445
+ window.removeEventListener("scroll", scheduleUpdateAll, true);
3446
+ if (scanFrame) window.cancelAnimationFrame(scanFrame);
3447
+ if (updateFrame) window.cancelAnimationFrame(updateFrame);
3448
+ entries.forEach((entry) => entry.cleanup());
3449
+ entries.clear();
3450
+ layer.remove();
3451
+ };
3452
+ }, [disabled, targetRef]);
3453
+ return null;
3238
3454
  }
3239
- var Modal2 = Object.assign(ModalRoot, {
3240
- /** 直接打开实例,返回可用于更新或关闭的操作句柄。 */
3241
- open: openModal,
3242
- /** 显示普通信息提示。 */
3243
- info: preset("info", { title: "\u63D0\u793A" }),
3244
- /** 显示成功提示。 */
3245
- success: preset("success", { title: "\u64CD\u4F5C\u6210\u529F" }),
3246
- /** 显示警告提示。 */
3247
- warning: preset("warning", { title: "\u8BF7\u6CE8\u610F" }),
3248
- /** 显示错误提示。 */
3249
- error: preset("error", { title: "\u64CD\u4F5C\u5931\u8D25" }),
3250
- /** 打开确认弹框,支持异步确认;返回 false 可阻止关闭。 */
3251
- confirm: preset("confirm", { title: "\u786E\u8BA4\u64CD\u4F5C" }),
3252
- /** 关闭由此 API 打开的所有弹层。 */
3253
- destroyAll() {
3254
- [...modalHandles].forEach((handle) => handle.destroy());
3255
- }
3256
- });
3257
-
3258
- // src/components/Input.tsx
3259
- var import_react19 = require("react");
3260
- var import_jsx_runtime18 = require("react/jsx-runtime");
3261
- var Input = (0, import_react19.forwardRef)(function Input2({
3262
- label,
3263
- hint,
3264
- status = "default",
3265
- size: sizeProp,
3266
- prefix,
3267
- suffix,
3268
- allowClear = true,
3269
- onClear,
3270
- showCount = false,
3271
- placeholderMode,
3272
- placeholder,
3273
- className = "",
3274
- id,
3275
- disabled,
3276
- value,
3277
- defaultValue,
3278
- maxLength,
3279
- onChange,
3280
- ...props
3281
- }, forwardedRef) {
3282
- const size = useControlSize(sizeProp);
3283
- const fallbackId = (0, import_react19.useId)();
3284
- const inputId = id ?? fallbackId;
3285
- const localRef = (0, import_react19.useRef)(null);
3286
- const [uncontrolledValue, setUncontrolledValue] = (0, import_react19.useState)(() => defaultValue === void 0 ? "" : String(defaultValue));
3287
- const currentText = value !== void 0 ? String(value) : uncontrolledValue;
3288
- const hasValue = currentText.length > 0;
3289
- const floatingPlaceholder = usePlaceholderMode(placeholderMode) === "floating" && Boolean(placeholder);
3290
- const hintId = `${inputId}-hint`;
3291
- const describedBy = [props["aria-describedby"], hint ? hintId : null].filter(Boolean).join(" ") || void 0;
3292
- function setRef(node) {
3293
- localRef.current = node;
3294
- if (typeof forwardedRef === "function") forwardedRef(node);
3295
- else if (forwardedRef) forwardedRef.current = node;
3296
- }
3297
- function handleChange(event) {
3298
- if (maxLength !== void 0 && maxLength >= 0 && event.target.value.length > maxLength) {
3299
- const valueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
3300
- valueSetter?.call(event.target, event.target.value.slice(0, maxLength));
3301
- }
3302
- setUncontrolledValue(event.target.value);
3303
- onChange?.(event);
3304
- }
3305
- function clearValue() {
3306
- const input2 = localRef.current;
3307
- if (!input2 || disabled) return;
3308
- const valueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
3309
- valueSetter?.call(input2, "");
3310
- input2.dispatchEvent(new Event("input", { bubbles: true }));
3311
- setUncontrolledValue("");
3312
- input2.focus();
3313
- onClear?.();
3314
- }
3315
- function handleControlMouseDown(event) {
3316
- if (disabled || event.defaultPrevented || event.button !== 0) return;
3317
- const target = event.target;
3318
- if (!(target instanceof Element)) return;
3319
- const interactive = target.closest("input, textarea, select, button, a[href], [tabindex], [contenteditable]:not([contenteditable='false']), [role='button'], [role='link']");
3320
- if (interactive && event.currentTarget.contains(interactive) && !interactive.classList.contains("sia-input-control__clear")) return;
3321
- event.preventDefault();
3322
- localRef.current?.focus({ preventScroll: true });
3323
- }
3324
- const input = /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3325
- "input",
3326
- {
3327
- ...withTitleTooltip(props),
3328
- ref: setRef,
3329
- id: inputId,
3330
- className: "sia-input",
3331
- disabled,
3332
- value,
3333
- defaultValue,
3334
- maxLength,
3335
- placeholder,
3336
- "aria-describedby": describedBy,
3337
- "aria-invalid": status === "error" || void 0,
3338
- onChange: handleChange
3339
- }
3340
- );
3341
- const control = /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { onMouseDown: handleControlMouseDown, className: `sia-input-control sia-input-control--${size} sia-input-control--${status}${floatingPlaceholder ? " sia-input-control--floating" : ""}${floatingPlaceholder && hasValue ? " is-filled" : ""}${disabled ? " is-disabled" : ""}`, children: [
3342
- prefix ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "sia-input-control__affix", children: prefix }) : null,
3343
- floatingPlaceholder ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "sia-input-control__input-wrap", children: [
3344
- input,
3345
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "sia-input-control__floating-placeholder", "aria-hidden": "true", children: placeholder })
3346
- ] }) : input,
3347
- allowClear && hasValue && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { className: "sia-input-control__clear", type: "button", "aria-label": "\u6E05\u7A7A\u8F93\u5165", onClick: clearValue, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Icon, { name: "circle-close", variant: "filled", size: 15 }) }) : null,
3348
- suffix ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "sia-input-control__affix", children: suffix }) : null,
3349
- showCount ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: `sia-input-control__count${maxLength !== void 0 && currentText.length >= maxLength ? " is-limit" : ""}`, "aria-live": "polite", children: [
3350
- currentText.length,
3351
- maxLength !== void 0 ? `/${maxLength}` : null
3352
- ] }) : null
3353
- ] });
3354
- if (!label && !hint) return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: `sia-field ${className}`.trim(), children: control });
3355
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: `sia-field ${className}`.trim(), children: [
3356
- label ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { className: "sia-field__label", htmlFor: inputId, children: label }) : null,
3357
- control,
3358
- hint ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { id: hintId, className: `sia-field__hint sia-field__hint--${status}`, children: hint }) : null
3359
- ] });
3360
- });
3361
3455
 
3362
3456
  // src/components/SelectionPanel.tsx
3363
- var import_react20 = require("react");
3364
3457
  var import_jsx_runtime19 = require("react/jsx-runtime");
3365
3458
  function SelectionPanel({
3366
3459
  options,
@@ -3382,26 +3475,26 @@ function SelectionPanel({
3382
3475
  maxHeight = 250,
3383
3476
  autoFocusSearch = false
3384
3477
  }) {
3385
- const [localSearch, setLocalSearch] = (0, import_react20.useState)("");
3478
+ const [localSearch, setLocalSearch] = (0, import_react21.useState)("");
3386
3479
  const search = searchValue ?? localSearch;
3387
- const [scrollTop, setScrollTop] = (0, import_react20.useState)(0);
3388
- const [active, setActive] = (0, import_react20.useState)();
3389
- const [keyboardActive, setKeyboardActive] = (0, import_react20.useState)(false);
3390
- const [deselectedHover, setDeselectedHover] = (0, import_react20.useState)();
3391
- const listRef = (0, import_react20.useRef)(null);
3392
- const id = (0, import_react20.useId)();
3393
- const selected = (0, import_react20.useMemo)(() => new Set(value), [value]);
3480
+ const [scrollTop, setScrollTop] = (0, import_react21.useState)(0);
3481
+ const [active, setActive] = (0, import_react21.useState)();
3482
+ const [keyboardActive, setKeyboardActive] = (0, import_react21.useState)(false);
3483
+ const [deselectedHover, setDeselectedHover] = (0, import_react21.useState)();
3484
+ const listRef = (0, import_react21.useRef)(null);
3485
+ const id = (0, import_react21.useId)();
3486
+ const selected = (0, import_react21.useMemo)(() => new Set(value), [value]);
3394
3487
  const count = Math.max(1, Math.floor(columns));
3395
- const allOptions = (0, import_react20.useMemo)(() => {
3488
+ const allOptions = (0, import_react21.useMemo)(() => {
3396
3489
  if (!includeUnknownValues) return [...options];
3397
3490
  const known = new Set(options.filter((option) => option.optionType !== "divider").map((option) => option.value));
3398
3491
  return [...value.filter((item) => !known.has(item)).map((item) => ({ value: item, label: String(item), group: "\u81EA\u5B9A\u4E49\u503C" })), ...options];
3399
3492
  }, [options, value, includeUnknownValues]);
3400
- const filtered = (0, import_react20.useMemo)(
3493
+ const filtered = (0, import_react21.useMemo)(
3401
3494
  () => allOptions.filter((option) => (!selectedOnly || selected.has(option.value)) && (!search || option.optionType !== "divider" && [option.label, option.value].some((text) => String(text ?? "").toLowerCase().includes(search.toLowerCase())))),
3402
3495
  [allOptions, selectedOnly, selected, search]
3403
3496
  );
3404
- const rows = (0, import_react20.useMemo)(() => {
3497
+ const rows = (0, import_react21.useMemo)(() => {
3405
3498
  const groups = /* @__PURE__ */ new Map();
3406
3499
  filtered.forEach((option) => {
3407
3500
  const items = groups.get(option.group) ?? [];
@@ -3427,7 +3520,7 @@ function SelectionPanel({
3427
3520
  const virtual = filtered.length > 100;
3428
3521
  const renderedRows = virtual ? rows.filter((row) => row.top + row.height >= scrollTop - 100 && row.top <= scrollTop + maxHeight + 100) : rows;
3429
3522
  const enabled = filtered.filter((option) => !option.disabled && option.optionType !== "divider");
3430
- (0, import_react20.useEffect)(() => {
3523
+ (0, import_react21.useEffect)(() => {
3431
3524
  setScrollTop(0);
3432
3525
  if (listRef.current) listRef.current.scrollTop = 0;
3433
3526
  setActive(void 0);
@@ -3552,14 +3645,14 @@ function SelectionPanel({
3552
3645
  }
3553
3646
 
3554
3647
  // src/components/OverflowTags.tsx
3555
- var import_react21 = require("react");
3648
+ var import_react22 = require("react");
3556
3649
  var import_jsx_runtime20 = require("react/jsx-runtime");
3557
3650
  function OverflowTags({ items, maxCount: maxCount2, className = "", tagClassName, restClassName = "" }) {
3558
- const rootRef = (0, import_react21.useRef)(null);
3559
- const measureRef = (0, import_react21.useRef)(null);
3651
+ const rootRef = (0, import_react22.useRef)(null);
3652
+ const measureRef = (0, import_react22.useRef)(null);
3560
3653
  const limit = Math.min(items.length, Math.max(0, Math.floor(maxCount2) || 0));
3561
- const [visibleCount, setVisibleCount] = (0, import_react21.useState)(0);
3562
- (0, import_react21.useLayoutEffect)(() => {
3654
+ const [visibleCount, setVisibleCount] = (0, import_react22.useState)(0);
3655
+ (0, import_react22.useLayoutEffect)(() => {
3563
3656
  const root = rootRef.current;
3564
3657
  const measure = measureRef.current;
3565
3658
  if (!root || !measure) return;
@@ -3604,7 +3697,7 @@ function defaultFilterOption(query, option) {
3604
3697
  const keyword = query.toLowerCase();
3605
3698
  return [option.label, option.value].some((value) => String(value).toLowerCase().includes(keyword));
3606
3699
  }
3607
- var Select = (0, import_react22.forwardRef)(function Select2({
3700
+ var Select = (0, import_react23.forwardRef)(function Select2({
3608
3701
  options,
3609
3702
  mode = "single",
3610
3703
  popupMode: popupModeProp,
@@ -3642,27 +3735,27 @@ var Select = (0, import_react22.forwardRef)(function Select2({
3642
3735
  ...props
3643
3736
  }, forwardedRef) {
3644
3737
  const size = useControlSize(sizeProp);
3645
- const fallbackId = (0, import_react22.useId)();
3738
+ const fallbackId = (0, import_react23.useId)();
3646
3739
  const selectId = id ?? fallbackId;
3647
3740
  const listboxId = `${selectId}-listbox`;
3648
- const rootRef = (0, import_react22.useRef)(null);
3649
- const popupRef = (0, import_react22.useRef)(null);
3650
- const searchRef = (0, import_react22.useRef)(null);
3651
- const listRef = (0, import_react22.useRef)(null);
3652
- const [open, setOpen] = (0, import_react22.useState)(false);
3741
+ const rootRef = (0, import_react23.useRef)(null);
3742
+ const popupRef = (0, import_react23.useRef)(null);
3743
+ const searchRef = (0, import_react23.useRef)(null);
3744
+ const listRef = (0, import_react23.useRef)(null);
3745
+ const [open, setOpen] = (0, import_react23.useState)(false);
3653
3746
  const automaticMode = popupModeProp ?? (options.length > modalThreshold ? "modal" : "dropdown");
3654
- const [openedMode, setOpenedMode] = (0, import_react22.useState)(automaticMode);
3747
+ const [openedMode, setOpenedMode] = (0, import_react23.useState)(automaticMode);
3655
3748
  const popupMode = open ? openedMode : automaticMode;
3656
- const [modalValues, setModalValues] = (0, import_react22.useState)([]);
3657
- const [modalSubmitting, setModalSubmitting] = (0, import_react22.useState)(false);
3658
- const modalSubmitLock = (0, import_react22.useRef)(false);
3659
- const [selectedOnly, setSelectedOnly] = (0, import_react22.useState)(false);
3660
- const [query, setQuery] = (0, import_react22.useState)("");
3661
- const [activeIndex, setActiveIndex] = (0, import_react22.useState)(-1);
3662
- const [scrollTop, setScrollTop] = (0, import_react22.useState)(0);
3663
- const [dropdownFontSize, setDropdownFontSize] = (0, import_react22.useState)();
3664
- const pendingSelectedScroll = (0, import_react22.useRef)(false);
3665
- const deferredQuery = (0, import_react22.useDeferredValue)(query.trim());
3749
+ const [modalValues, setModalValues] = (0, import_react23.useState)([]);
3750
+ const [modalSubmitting, setModalSubmitting] = (0, import_react23.useState)(false);
3751
+ const modalSubmitLock = (0, import_react23.useRef)(false);
3752
+ const [selectedOnly, setSelectedOnly] = (0, import_react23.useState)(false);
3753
+ const [query, setQuery] = (0, import_react23.useState)("");
3754
+ const [activeIndex, setActiveIndex] = (0, import_react23.useState)(-1);
3755
+ const [scrollTop, setScrollTop] = (0, import_react23.useState)(0);
3756
+ const [dropdownFontSize, setDropdownFontSize] = (0, import_react23.useState)();
3757
+ const pendingSelectedScroll = (0, import_react23.useRef)(false);
3758
+ const deferredQuery = (0, import_react23.useDeferredValue)(query.trim());
3666
3759
  const initialValue = defaultValue === void 0 ? mode === "multiple" ? [] : null : defaultValue;
3667
3760
  const [currentValue, setCurrentValue] = useControllableState({
3668
3761
  value,
@@ -3677,20 +3770,20 @@ var Select = (0, import_react22.forwardRef)(function Select2({
3677
3770
  }
3678
3771
  }
3679
3772
  });
3680
- const selectedValues = (0, import_react22.useMemo)(() => {
3773
+ const selectedValues = (0, import_react23.useMemo)(() => {
3681
3774
  if (currentValue == null || currentValue === "" && !options.some((option) => option.value === "")) return [];
3682
3775
  if (mode === "multiple") return Array.isArray(currentValue) ? currentValue : currentValue === null ? [] : [currentValue];
3683
3776
  return Array.isArray(currentValue) ? currentValue.slice(0, 1) : currentValue === null ? [] : [currentValue];
3684
3777
  }, [currentValue, mode, options]);
3685
- const selectedValueSet = (0, import_react22.useMemo)(() => new Set(selectedValues), [selectedValues]);
3686
- const availableOptions = (0, import_react22.useMemo)(() => {
3778
+ const selectedValueSet = (0, import_react23.useMemo)(() => new Set(selectedValues), [selectedValues]);
3779
+ const availableOptions = (0, import_react23.useMemo)(() => {
3687
3780
  if (!allowInput) return options;
3688
3781
  const optionValueSet = new Set(options.map((option) => option.value));
3689
3782
  const selectedCustomOptions = selectedValues.filter((selectedValue) => !optionValueSet.has(selectedValue)).map((selectedValue) => ({ label: String(selectedValue), value: selectedValue }));
3690
3783
  return selectedCustomOptions.length ? [...selectedCustomOptions, ...options] : options;
3691
3784
  }, [allowInput, options, selectedValues]);
3692
- const selectedOptions = (0, import_react22.useMemo)(() => selectedValues.map((selectedValue) => availableOptions.find((option) => option.value === selectedValue)).filter((option) => option !== void 0), [availableOptions, selectedValues]);
3693
- const filteredOptions = (0, import_react22.useMemo)(() => deferredQuery ? availableOptions.filter((option) => filterOption(deferredQuery, option)) : availableOptions, [availableOptions, deferredQuery, filterOption]);
3785
+ const selectedOptions = (0, import_react23.useMemo)(() => selectedValues.map((selectedValue) => availableOptions.find((option) => option.value === selectedValue)).filter((option) => option !== void 0), [availableOptions, selectedValues]);
3786
+ const filteredOptions = (0, import_react23.useMemo)(() => deferredQuery ? availableOptions.filter((option) => filterOption(deferredQuery, option)) : availableOptions, [availableOptions, deferredQuery, filterOption]);
3694
3787
  const inputValue = query.trim();
3695
3788
  const exactInputOption = inputValue ? availableOptions.find((option) => String(option.value).toLowerCase() === inputValue.toLowerCase() || typeof option.label === "string" && option.label.toLowerCase() === inputValue.toLowerCase()) : void 0;
3696
3789
  const canSubmitInput = allowInput && Boolean(inputValue) && !exactInputOption;
@@ -3704,7 +3797,7 @@ var Select = (0, import_react22.forwardRef)(function Select2({
3704
3797
  const renderedOptions = virtualEnabled ? filteredOptions.slice(virtualStart, virtualEnd) : filteredOptions;
3705
3798
  const enabledFilteredOptions = filteredOptions.filter((option) => !option.disabled);
3706
3799
  const allFilteredSelected = enabledFilteredOptions.length > 0 && enabledFilteredOptions.every((option) => selectedValueSet.has(option.value));
3707
- (0, import_react22.useEffect)(() => {
3800
+ (0, import_react23.useEffect)(() => {
3708
3801
  if (!open || popupMode === "modal") return void 0;
3709
3802
  function closeFromOutside(event) {
3710
3803
  const target = event.target;
@@ -3713,13 +3806,13 @@ var Select = (0, import_react22.forwardRef)(function Select2({
3713
3806
  document.addEventListener("mousedown", closeFromOutside);
3714
3807
  return () => document.removeEventListener("mousedown", closeFromOutside);
3715
3808
  }, [open, popupMode]);
3716
- (0, import_react22.useEffect)(() => {
3809
+ (0, import_react23.useEffect)(() => {
3717
3810
  if (open && (showSearch || allowInput)) searchRef.current?.focus();
3718
3811
  }, [allowInput, open, showSearch]);
3719
- (0, import_react22.useEffect)(() => {
3812
+ (0, import_react23.useEffect)(() => {
3720
3813
  if (disabled || loading) closeDropdown();
3721
3814
  }, [disabled, loading]);
3722
- (0, import_react22.useEffect)(() => {
3815
+ (0, import_react23.useEffect)(() => {
3723
3816
  if (!open || popupMode !== "dropdown" || !pendingSelectedScroll.current || query) return;
3724
3817
  const index = filteredOptions.findIndex((option) => selectedValueSet.has(option.value));
3725
3818
  if (index < 0) return;
@@ -3734,7 +3827,7 @@ var Select = (0, import_react22.forwardRef)(function Select2({
3734
3827
  });
3735
3828
  return () => cancelAnimationFrame(frame);
3736
3829
  }, [open, popupMode, filteredOptions, selectedValueSet, virtualEnabled, optionHeight, query]);
3737
- (0, import_react22.useLayoutEffect)(() => {
3830
+ (0, import_react23.useLayoutEffect)(() => {
3738
3831
  if (!open || popupMode !== "dropdown") return;
3739
3832
  const trigger = rootRef.current?.querySelector(".sia-select__trigger");
3740
3833
  if (trigger) setDropdownFontSize(getComputedStyle(trigger).fontSize);
@@ -4075,7 +4168,7 @@ var Select = (0, import_react22.forwardRef)(function Select2({
4075
4168
  });
4076
4169
 
4077
4170
  // src/components/Upload.tsx
4078
- var import_react23 = require("react");
4171
+ var import_react24 = require("react");
4079
4172
 
4080
4173
  // src/components/uploadFiles.ts
4081
4174
  function acceptsUploadFile(file, accept) {
@@ -4314,8 +4407,8 @@ var message = {
4314
4407
  var import_jsx_runtime23 = require("react/jsx-runtime");
4315
4408
  var LIST_IGNORE = /* @__PURE__ */ Symbol("SIA_UPLOAD_LIST_IGNORE");
4316
4409
  function useThumbnail(file, accept) {
4317
- const [local, setLocal] = (0, import_react23.useState)();
4318
- (0, import_react23.useEffect)(() => {
4410
+ const [local, setLocal] = (0, import_react24.useState)();
4411
+ (0, import_react24.useEffect)(() => {
4319
4412
  if (!file?.thumbUrl && file?.originFileObj?.type.startsWith("image/")) {
4320
4413
  const url = URL.createObjectURL(file.originFileObj);
4321
4414
  setLocal(url);
@@ -4327,9 +4420,9 @@ function useThumbnail(file, accept) {
4327
4420
  }
4328
4421
  function UploadItem({ file, files, props, actions }) {
4329
4422
  const source = useThumbnail(file, props.accept);
4330
- const [failed, setFailed] = (0, import_react23.useState)(false);
4331
- const [downloading, setDownloading] = (0, import_react23.useState)(false);
4332
- const downloadingRef = (0, import_react23.useRef)(false);
4423
+ const [failed, setFailed] = (0, import_react24.useState)(false);
4424
+ const [downloading, setDownloading] = (0, import_react24.useState)(false);
4425
+ const downloadingRef = (0, import_react24.useRef)(false);
4333
4426
  const canPreview = !!(source || file.url || file.originFileObj || props.onPreview);
4334
4427
  const canDownload = !!(file.url || file.originFileObj || props.downloadRequest);
4335
4428
  async function download() {
@@ -4345,7 +4438,7 @@ function UploadItem({ file, files, props, actions }) {
4345
4438
  setDownloading(false);
4346
4439
  }
4347
4440
  }
4348
- (0, import_react23.useEffect)(() => setFailed(false), [source]);
4441
+ (0, import_react24.useEffect)(() => setFailed(false), [source]);
4349
4442
  const node = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: `sia-upload__item sia-upload__item--${file.status ?? "ready"}`, children: [
4350
4443
  props.listType !== "text" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Button, { variant: "text", className: "sia-upload__thumbnail", "aria-label": `\u9884\u89C8\u7F29\u7565\u56FE ${file.name}`, onClick: actions.preview, disabled: !canPreview, children: source && !failed ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("img", { src: source, alt: file.name, onError: () => setFailed(true) }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Icon, { name: file.type?.startsWith("image/") ? "image" : "file", size: 28 }) }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Icon, { name: file.status === "done" ? "circle-check" : "file", size: 16 }),
4351
4444
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "sia-upload__name", ...withTitleTooltip({ title: file.relativePath || file.name }), children: file.url ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("a", { href: file.url, target: "_blank", rel: "noreferrer", children: file.name }) : file.name }),
@@ -4366,7 +4459,7 @@ function UploadItem({ file, files, props, actions }) {
4366
4459
  ] });
4367
4460
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_jsx_runtime23.Fragment, { children: props.itemRender ? props.itemRender(node, file, files, actions) : node });
4368
4461
  }
4369
- var UploadRoot = (0, import_react23.forwardRef)(function UploadRoot2({
4462
+ var UploadRoot = (0, import_react24.forwardRef)(function UploadRoot2({
4370
4463
  accept,
4371
4464
  multiple = false,
4372
4465
  directory = false,
@@ -4404,19 +4497,19 @@ var UploadRoot = (0, import_react23.forwardRef)(function UploadRoot2({
4404
4497
  const cardWidth = cardDimension(typeof cardSize === "number" ? cardSize : cardSize?.width);
4405
4498
  const cardHeight = cardDimension(typeof cardSize === "number" ? cardSize : cardSize?.height);
4406
4499
  const compactCard = listType === "picture-card" && (cardWidth < 88 || cardHeight < 88);
4407
- const inputRef = (0, import_react23.useRef)(null);
4408
- const [internalFiles, setInternalFiles] = (0, import_react23.useState)(defaultFileList);
4500
+ const inputRef = (0, import_react24.useRef)(null);
4501
+ const [internalFiles, setInternalFiles] = (0, import_react24.useState)(defaultFileList);
4409
4502
  const files = fileList ?? internalFiles;
4410
- const filesRef = (0, import_react23.useRef)(files);
4503
+ const filesRef = (0, import_react24.useRef)(files);
4411
4504
  filesRef.current = files;
4412
- const tasks = (0, import_react23.useRef)(/* @__PURE__ */ new Map());
4413
- const mounted = (0, import_react23.useRef)(true);
4414
- const [dragging, setDragging] = (0, import_react23.useState)(false);
4415
- const [preview, setPreview] = (0, import_react23.useState)();
4505
+ const tasks = (0, import_react24.useRef)(/* @__PURE__ */ new Map());
4506
+ const mounted = (0, import_react24.useRef)(true);
4507
+ const [dragging, setDragging] = (0, import_react24.useState)(false);
4508
+ const [preview, setPreview] = (0, import_react24.useState)();
4416
4509
  const previewSource = useThumbnail(preview, accept);
4417
4510
  const limit = maxCount2 === void 0 || !Number.isFinite(maxCount2) ? Infinity : Math.max(0, Math.floor(maxCount2));
4418
4511
  const full = files.length >= limit;
4419
- const current = (0, import_react23.useRef)({ disabled, directory, recursive });
4512
+ const current = (0, import_react24.useRef)({ disabled, directory, recursive });
4420
4513
  current.current = { disabled, directory, recursive };
4421
4514
  function cancel(uid) {
4422
4515
  const task = tasks.current.get(uid);
@@ -4428,14 +4521,14 @@ var UploadRoot = (0, import_react23.forwardRef)(function UploadRoot2({
4428
4521
  }
4429
4522
  task?.finish();
4430
4523
  }
4431
- (0, import_react23.useEffect)(() => {
4524
+ (0, import_react24.useEffect)(() => {
4432
4525
  mounted.current = true;
4433
4526
  return () => {
4434
4527
  mounted.current = false;
4435
4528
  [...tasks.current.keys()].forEach(cancel);
4436
4529
  };
4437
4530
  }, []);
4438
- (0, import_react23.useEffect)(() => {
4531
+ (0, import_react24.useEffect)(() => {
4439
4532
  for (const uid of tasks.current.keys()) if (!files.some((file) => file.uid === uid)) cancel(uid);
4440
4533
  if (preview && !files.some((file) => file.uid === preview.uid)) setPreview(void 0);
4441
4534
  }, [files, preview]);
@@ -4541,7 +4634,7 @@ var UploadRoot = (0, import_react23.forwardRef)(function UploadRoot2({
4541
4634
  } catch {
4542
4635
  }
4543
4636
  }
4544
- (0, import_react23.useImperativeHandle)(ref, () => ({
4637
+ (0, import_react24.useImperativeHandle)(ref, () => ({
4545
4638
  upload: async (uid) => {
4546
4639
  await Promise.all(filesRef.current.filter((file) => (!uid || file.uid === uid) && file.status !== "done").map(start));
4547
4640
  },
@@ -4663,7 +4756,7 @@ var UploadRoot = (0, import_react23.forwardRef)(function UploadRoot2({
4663
4756
  }
4664
4757
  );
4665
4758
  });
4666
- var UploadDragger = (0, import_react23.forwardRef)(function UploadDragger2({ hint = "\u652F\u6301\u5355\u4E2A\u6216\u6279\u91CF\u4E0A\u4F20", children, className = "", ...props }, ref) {
4759
+ var UploadDragger = (0, import_react24.forwardRef)(function UploadDragger2({ hint = "\u652F\u6301\u5355\u4E2A\u6216\u6279\u91CF\u4E0A\u4F20", children, className = "", ...props }, ref) {
4667
4760
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(UploadRoot, { ...props, ref, className: `sia-upload-dragger ${className}`.trim(), children: children ?? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: "sia-upload-dragger__content", children: [
4668
4761
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Icon, { name: "upload", size: 32 }),
4669
4762
  /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("strong", { children: [
@@ -4704,12 +4797,12 @@ function Breadcrumb({ items, separator = "/", itemRender, className = "", ...pro
4704
4797
  }
4705
4798
 
4706
4799
  // src/components/Typography.tsx
4707
- var import_react25 = require("react");
4800
+ var import_react26 = require("react");
4708
4801
 
4709
4802
  // src/components/TextArea.tsx
4710
- var import_react24 = require("react");
4803
+ var import_react25 = require("react");
4711
4804
  var import_jsx_runtime25 = require("react/jsx-runtime");
4712
- var TextArea = (0, import_react24.forwardRef)(function TextArea2({
4805
+ var TextArea = (0, import_react25.forwardRef)(function TextArea2({
4713
4806
  label,
4714
4807
  hint,
4715
4808
  status = "default",
@@ -4727,9 +4820,9 @@ var TextArea = (0, import_react24.forwardRef)(function TextArea2({
4727
4820
  ...props
4728
4821
  }, ref) {
4729
4822
  const size = useControlSize(sizeProp);
4730
- const fallbackId = (0, import_react24.useId)();
4823
+ const fallbackId = (0, import_react25.useId)();
4731
4824
  const textAreaId = id ?? fallbackId;
4732
- const [uncontrolledValue, setUncontrolledValue] = (0, import_react24.useState)(() => defaultValue === void 0 ? "" : String(defaultValue));
4825
+ const [uncontrolledValue, setUncontrolledValue] = (0, import_react25.useState)(() => defaultValue === void 0 ? "" : String(defaultValue));
4733
4826
  const currentText = value !== void 0 ? String(value) : uncontrolledValue;
4734
4827
  const floating = useFloatingPlaceholder({ mode: placeholderMode, placeholder, filled: currentText.length > 0 });
4735
4828
  const hintId = `${textAreaId}-hint`;
@@ -4790,26 +4883,26 @@ function TypographyContent({
4790
4883
  className = "",
4791
4884
  ...props
4792
4885
  }) {
4793
- const contentRef = (0, import_react25.useRef)(null);
4794
- const editRef = (0, import_react25.useRef)(null);
4795
- const timer = (0, import_react25.useRef)();
4796
- const [localText, setLocalText] = (0, import_react25.useState)();
4797
- const [draft, setDraft] = (0, import_react25.useState)("");
4798
- const [editing, setEditing] = (0, import_react25.useState)(false);
4799
- const [copied, setCopied] = (0, import_react25.useState)(false);
4800
- const [copyError, setCopyError] = (0, import_react25.useState)(false);
4801
- const [expanded, setExpanded] = (0, import_react25.useState)(false);
4802
- const [overflow, setOverflow] = (0, import_react25.useState)(false);
4886
+ const contentRef = (0, import_react26.useRef)(null);
4887
+ const editRef = (0, import_react26.useRef)(null);
4888
+ const timer = (0, import_react26.useRef)();
4889
+ const [localText, setLocalText] = (0, import_react26.useState)();
4890
+ const [draft, setDraft] = (0, import_react26.useState)("");
4891
+ const [editing, setEditing] = (0, import_react26.useState)(false);
4892
+ const [copied, setCopied] = (0, import_react26.useState)(false);
4893
+ const [copyError, setCopyError] = (0, import_react26.useState)(false);
4894
+ const [expanded, setExpanded] = (0, import_react26.useState)(false);
4895
+ const [overflow, setOverflow] = (0, import_react26.useState)(false);
4803
4896
  const editConfig = typeof editable === "object" ? editable : void 0;
4804
4897
  const content = editConfig?.text ?? localText ?? children;
4805
4898
  const requestedRows = typeof ellipsis === "object" ? ellipsis.rows ?? 1 : 1;
4806
4899
  const rows = Number.isFinite(requestedRows) ? Math.max(1, Math.floor(requestedRows)) : 1;
4807
4900
  const expandable = typeof ellipsis === "object" && ellipsis.expandable;
4808
- (0, import_react25.useEffect)(() => {
4901
+ (0, import_react26.useEffect)(() => {
4809
4902
  setLocalText(void 0);
4810
4903
  }, [children]);
4811
- (0, import_react25.useEffect)(() => () => clearTimeout(timer.current), []);
4812
- (0, import_react25.useLayoutEffect)(() => {
4904
+ (0, import_react26.useEffect)(() => () => clearTimeout(timer.current), []);
4905
+ (0, import_react26.useLayoutEffect)(() => {
4813
4906
  const element = contentRef.current;
4814
4907
  if (!element || !ellipsis || editing || expanded) return;
4815
4908
  const measure = () => setOverflow(element.scrollHeight > element.clientHeight + 1 || element.scrollWidth > element.clientWidth + 1);
@@ -4927,10 +5020,10 @@ var Typography = Object.assign(TypographyRoot, {
4927
5020
  });
4928
5021
 
4929
5022
  // src/components/FloatButton.tsx
4930
- var import_react26 = require("react");
5023
+ var import_react27 = require("react");
4931
5024
  var import_jsx_runtime27 = require("react/jsx-runtime");
4932
- var GroupShape = (0, import_react26.createContext)(void 0);
4933
- var FloatButtonRoot = (0, import_react26.forwardRef)(function FloatButton({
5025
+ var GroupShape = (0, import_react27.createContext)(void 0);
5026
+ var FloatButtonRoot = (0, import_react27.forwardRef)(function FloatButton({
4934
5027
  icon,
4935
5028
  description,
4936
5029
  tooltip,
@@ -4943,7 +5036,7 @@ var FloatButtonRoot = (0, import_react26.forwardRef)(function FloatButton({
4943
5036
  children,
4944
5037
  ...props
4945
5038
  }, ref) {
4946
- const groupShape = (0, import_react26.useContext)(GroupShape);
5039
+ const groupShape = (0, import_react27.useContext)(GroupShape);
4947
5040
  const label = props["aria-label"] ?? (typeof tooltip === "string" ? tooltip : typeof description === "string" ? description : "\u60AC\u6D6E\u64CD\u4F5C");
4948
5041
  const button = /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
4949
5042
  "button",
@@ -4981,10 +5074,10 @@ function FloatButtonGroup({
4981
5074
  ...props
4982
5075
  }) {
4983
5076
  const [visible, setVisible] = useControllableState({ value: open, defaultValue: defaultOpen, onChange: onOpenChange });
4984
- const rootRef = (0, import_react26.useRef)(null);
4985
- const triggerRef = (0, import_react26.useRef)(null);
4986
- const id = (0, import_react26.useId)();
4987
- (0, import_react26.useEffect)(() => {
5077
+ const rootRef = (0, import_react27.useRef)(null);
5078
+ const triggerRef = (0, import_react27.useRef)(null);
5079
+ const id = (0, import_react27.useId)();
5080
+ (0, import_react27.useEffect)(() => {
4988
5081
  if (!trigger || !visible) return;
4989
5082
  const close = (event) => {
4990
5083
  if (!rootRef.current?.contains(event.target)) setVisible(false);
@@ -5038,8 +5131,8 @@ function FloatButtonGroup({
5038
5131
  ) });
5039
5132
  }
5040
5133
  function FloatButtonBackTop({ target, visibilityHeight = 400, behavior = "smooth", onClick, icon, tooltip = "\u8FD4\u56DE\u9876\u90E8", ...props }) {
5041
- const [visible, setVisible] = (0, import_react26.useState)(false);
5042
- (0, import_react26.useEffect)(() => {
5134
+ const [visible, setVisible] = (0, import_react27.useState)(false);
5135
+ (0, import_react27.useEffect)(() => {
5043
5136
  const element = target ? target() : window;
5044
5137
  if (!element) return;
5045
5138
  const update = () => setVisible((element === window ? window.scrollY : element.scrollTop) >= visibilityHeight);