@sia.soul/sia-react-ui 0.1.32 → 0.1.34

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
@@ -175,6 +175,7 @@ function installTitleTooltips(doc) {
175
175
  documents.add(doc);
176
176
  let hovered = null;
177
177
  let focused = null;
178
+ let keyboardFocus = true;
178
179
  let active = null;
179
180
  let pending = null;
180
181
  let timer;
@@ -265,19 +266,30 @@ function installTitleTooltips(doc) {
265
266
  else show(hovered ?? focused);
266
267
  }, true);
267
268
  doc.addEventListener("focusin", (event) => {
268
- focused = candidate(event.target);
269
+ focused = keyboardFocus ? candidate(event.target) : null;
269
270
  if (hasExplicitTooltip(event.target)) hide();
270
- else show(focused ?? hovered);
271
+ else if (keyboardFocus) show(focused ?? hovered);
271
272
  }, true);
272
273
  doc.addEventListener("focusout", (event) => {
273
- focused = candidate(event.relatedTarget);
274
+ focused = keyboardFocus ? candidate(event.relatedTarget) : null;
274
275
  show(hovered ?? focused);
275
276
  }, true);
276
- doc.addEventListener("pointerdown", hide, true);
277
+ doc.addEventListener("pointerdown", () => {
278
+ keyboardFocus = false;
279
+ focused = null;
280
+ hide();
281
+ }, true);
277
282
  doc.addEventListener("keydown", (event) => {
278
283
  if (event.key === "Escape") hide();
284
+ else if (event.key === "Tab") keyboardFocus = true;
279
285
  }, true);
280
286
  doc.addEventListener("scroll", hide, true);
287
+ doc.addEventListener("visibilitychange", () => {
288
+ if (doc.hidden) {
289
+ hovered = focused = null;
290
+ hide();
291
+ }
292
+ });
281
293
  doc.defaultView?.addEventListener("blur", () => {
282
294
  hovered = focused = null;
283
295
  hide();
@@ -1815,6 +1827,8 @@ function Tabs({
1815
1827
  activeKey,
1816
1828
  defaultActiveKey,
1817
1829
  onChange,
1830
+ onAfterChange,
1831
+ deferContent = false,
1818
1832
  type = "line",
1819
1833
  size = "medium",
1820
1834
  tabPosition,
@@ -1822,6 +1836,7 @@ function Tabs({
1822
1836
  centered = false,
1823
1837
  tabBarTitle,
1824
1838
  tabBarExtraContent,
1839
+ contentGap,
1825
1840
  destroyInactiveTabPane = true,
1826
1841
  closable = false,
1827
1842
  onEdit,
@@ -1841,6 +1856,12 @@ function Tabs({
1841
1856
  const sliding = ["capsule", "line", "underline", "tech", "tech-line"].includes(type);
1842
1857
  const listRef = (0, import_react10.useRef)(null);
1843
1858
  const indicatorRef = (0, import_react10.useRef)(null);
1859
+ const [contentState, setContentState] = (0, import_react10.useState)(() => ({ key: selectedKey, visited: /* @__PURE__ */ new Set([selectedKey]) }));
1860
+ const settledKeyRef = (0, import_react10.useRef)(selectedKey);
1861
+ const afterChangeRef = (0, import_react10.useRef)(onAfterChange);
1862
+ (0, import_react10.useLayoutEffect)(() => {
1863
+ afterChangeRef.current = onAfterChange;
1864
+ }, [onAfterChange]);
1844
1865
  (0, import_react10.useLayoutEffect)(() => {
1845
1866
  if (!sliding) return;
1846
1867
  const list = listRef.current;
@@ -1870,6 +1891,32 @@ function Tabs({
1870
1891
  list.querySelectorAll('[role="tab"]').forEach((tab) => observer.observe(tab));
1871
1892
  return () => observer.disconnect();
1872
1893
  }, [sliding, type, selectedKey, items, size, resolvedPosition, centered, closable]);
1894
+ (0, import_react10.useEffect)(() => {
1895
+ let cancelled = false;
1896
+ let frame = 0;
1897
+ frame = requestAnimationFrame(() => {
1898
+ const indicator = indicatorRef.current;
1899
+ if (indicator) getComputedStyle(indicator).transform;
1900
+ const animations = indicator?.getAnimations() ?? [];
1901
+ const complete = () => {
1902
+ if (cancelled) return;
1903
+ setContentState((previous) => ({ key: selectedKey, visited: new Set([...previous.visited].filter((key) => items.some((item) => item.key === key))).add(selectedKey) }));
1904
+ if (settledKeyRef.current !== selectedKey) {
1905
+ settledKeyRef.current = selectedKey;
1906
+ afterChangeRef.current?.(selectedKey);
1907
+ }
1908
+ };
1909
+ if (!animations.length) complete();
1910
+ else Promise.allSettled(animations.map((animation) => animation.finished)).then(() => {
1911
+ if (!cancelled) frame = requestAnimationFrame(complete);
1912
+ });
1913
+ });
1914
+ return () => {
1915
+ cancelled = true;
1916
+ cancelAnimationFrame(frame);
1917
+ };
1918
+ }, [selectedKey, type, deferContent]);
1919
+ const contentKey = deferContent ? contentState.key : selectedKey;
1873
1920
  function selectTab(key) {
1874
1921
  if (key === selectedKey) return;
1875
1922
  if (activeKey === void 0) setInternalActiveKey(key);
@@ -1901,26 +1948,10 @@ function Tabs({
1901
1948
  /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "sia-tabs__header", children: [
1902
1949
  tabBarTitle ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "sia-tabs__title", children: [
1903
1950
  tabBarTitle,
1904
- 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 H5 Q8 39 10 35 L28 3 Q29 1 32 1", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }) }) : null
1951
+ 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
1905
1952
  ] }) : null,
1906
1953
  /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { ref: listRef, className: `sia-tabs__list${sliding ? " sia-tabs__list--sliding" : ""}`, role: "tablist", "aria-orientation": resolvedOrientation, children: [
1907
- 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.jsxs)("svg", { className: "sia-tabs__indicator-shape", viewBox: "0 0 100 34", preserveAspectRatio: "none", "aria-hidden": "true", children: [
1908
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("linearGradient", { id: `${baseId}-tab-fill-indicator`, x1: "0", y1: "0", x2: "1", y2: "0", children: [
1909
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("stop", { offset: "0", stopColor: "var(--sia-tabs-line-fill-edge, var(--sia-tabs-line-fill))" }),
1910
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("stop", { offset: ".53", stopColor: "var(--sia-tabs-line-fill-center, var(--sia-tabs-line-fill))" }),
1911
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("stop", { offset: "1", stopColor: "var(--sia-tabs-line-fill-edge, var(--sia-tabs-line-fill))" })
1912
- ] }) }),
1913
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1914
- "path",
1915
- {
1916
- d: "M19 1 H96 Q99 1 97.5 4 L83.5 30 Q82 33 79 33 H4 Q1 33 2.5 30 L16.5 4 Q18 1 19 1 Z",
1917
- fill: `url(#${baseId}-tab-fill-indicator)`,
1918
- stroke: "currentColor",
1919
- strokeWidth: "1.5",
1920
- vectorEffect: "non-scaling-stroke"
1921
- }
1922
- )
1923
- ] }) : null }, type) : null,
1954
+ 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,
1924
1955
  items.map((item) => {
1925
1956
  const selected = item.key === selectedKey;
1926
1957
  const canClose = item.closable ?? closable;
@@ -1939,23 +1970,7 @@ function Tabs({
1939
1970
  onClick: () => selectTab(item.key),
1940
1971
  onKeyDown: (event) => handleKeyDown(event, item.key),
1941
1972
  children: [
1942
- type === "tech-line" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("svg", { className: "sia-tabs__tab-shape", viewBox: "0 0 100 34", preserveAspectRatio: "none", "aria-hidden": "true", children: [
1943
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("linearGradient", { id: `${baseId}-tab-fill-${item.key}`, x1: "0", y1: "0", x2: "1", y2: "0", children: [
1944
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("stop", { offset: "0", stopColor: "var(--sia-tabs-line-fill-edge, var(--sia-tabs-line-fill))" }),
1945
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("stop", { offset: ".53", stopColor: "var(--sia-tabs-line-fill-center, var(--sia-tabs-line-fill))" }),
1946
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("stop", { offset: "1", stopColor: "var(--sia-tabs-line-fill-edge, var(--sia-tabs-line-fill))" })
1947
- ] }) }),
1948
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1949
- "path",
1950
- {
1951
- d: "M19 1 H96 Q99 1 97.5 4 L83.5 30 Q82 33 79 33 H4 Q1 33 2.5 30 L16.5 4 Q18 1 19 1 Z",
1952
- fill: `url(#${baseId}-tab-fill-${item.key})`,
1953
- stroke: "currentColor",
1954
- strokeWidth: "1.5",
1955
- vectorEffect: "non-scaling-stroke"
1956
- }
1957
- )
1958
- ] }) : null,
1973
+ type === "tech-line" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "sia-tabs__tab-shape", "aria-hidden": "true" }) : null,
1959
1974
  item.icon ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "sia-tabs__icon", children: item.icon }) : null,
1960
1975
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: item.label })
1961
1976
  ]
@@ -1995,9 +2010,13 @@ function Tabs({
1995
2010
  ] }),
1996
2011
  tabBarExtraContent ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "sia-tabs__extra", children: tabBarExtraContent }) : null
1997
2012
  ] }),
1998
- hasPanels ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "sia-tabs__panels", children: items.map((item) => {
1999
- const selected = item.key === selectedKey;
2013
+ hasPanels ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "sia-tabs__panels", style: contentGap === void 0 ? void 0 : {
2014
+ // 仅设置面板靠近导航的一侧,保留各方向布局原有的其余边界。
2015
+ [resolvedPosition === "top" ? "paddingTop" : resolvedPosition === "bottom" ? "paddingBottom" : resolvedPosition === "left" ? "paddingLeft" : "paddingRight"]: contentGap
2016
+ }, "aria-busy": deferContent && contentKey !== selectedKey || void 0, children: items.map((item) => {
2017
+ const selected = item.key === contentKey;
2000
2018
  if (destroyInactiveTabPane && !selected) return null;
2019
+ if (deferContent && !selected && !contentState.visited.has(item.key)) return null;
2001
2020
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2002
2021
  "div",
2003
2022
  {