flowcloudai-ui 0.1.5 → 0.1.7

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/index.css CHANGED
@@ -1846,8 +1846,6 @@
1846
1846
  --tab-active-color: var(--fc-color-primary);
1847
1847
  --tab-active-bg: var(--fc-color-bg);
1848
1848
  --tab-active-indicator: var(--fc-color-primary);
1849
- --tab-min-width: 8rem;
1850
- --tab-max-width: 18rem;
1851
1849
  --tab-bar-radius-tl: var(--fc-radius-md);
1852
1850
  --tab-bar-radius-tr: var(--fc-radius-md);
1853
1851
  --tab-bar-radius-br: 0px;
@@ -1893,23 +1891,29 @@
1893
1891
  .fc-tab-bar__nav-outer {
1894
1892
  display: flex;
1895
1893
  align-items: stretch;
1894
+ flex: 1;
1895
+ min-width: 0;
1896
+ }
1897
+ .fc-tab-bar__nav-outer[data-tauri-drag-region] {
1898
+ -webkit-app-region: drag;
1896
1899
  }
1897
1900
  .fc-tab-bar__nav-wrap {
1898
1901
  display: flex;
1899
1902
  align-items: stretch;
1900
- }
1901
- .fc-tab-bar__nav-wrap--scroll {
1902
1903
  flex: 1;
1903
1904
  min-width: 0;
1904
1905
  overflow-x: auto;
1905
1906
  scrollbar-width: none;
1906
1907
  }
1907
- .fc-tab-bar__nav-wrap--scroll::-webkit-scrollbar {
1908
+ .fc-tab-bar__nav-wrap::-webkit-scrollbar {
1908
1909
  display: none;
1909
1910
  }
1910
1911
  .fc-tab-bar__tab {
1912
+ flex: var(--tab-fill-width, 1) 1 0;
1913
+ min-width: var(--tab-min-width, 80px);
1914
+ max-width: var(--tab-max-width, 200px);
1911
1915
  position: relative;
1912
- display: inline-flex;
1916
+ display: flex;
1913
1917
  align-items: center;
1914
1918
  gap: var(--fc-space-sm, 8px);
1915
1919
  padding: var(--fc-space-sm, 8px) var(--fc-space-lg, 16px);
@@ -1921,14 +1925,11 @@
1921
1925
  white-space: nowrap;
1922
1926
  border: none;
1923
1927
  user-select: none;
1928
+ box-sizing: border-box;
1924
1929
  border-radius: var(--tab-item-radius-tl) var(--tab-item-radius-tr) var(--tab-item-radius-br) var(--tab-item-radius-bl);
1925
- flex: 1 1 var(--tab-max-width);
1926
- min-width: var(--tab-min-width);
1927
- max-width: var(--tab-max-width);
1928
1930
  overflow: hidden;
1929
- box-sizing: border-box;
1930
1931
  }
1931
- .fc-tab-bar__tab:hover:not(.fc-tab-bar__tab--disabled):not(.fc-tab-bar__tab--dragging):not(.fc-tab-bar__tab--active) {
1932
+ .fc-tab-bar__tab:hover:not(.fc-tab-bar__tab--disabled):not(.fc-tab-bar__tab--dragging) {
1932
1933
  color: var(--tab-hover-color);
1933
1934
  background-color: var(--tab-hover-bg);
1934
1935
  }
@@ -1946,7 +1947,18 @@
1946
1947
  min-width: 0;
1947
1948
  overflow: hidden;
1948
1949
  white-space: nowrap;
1949
- text-overflow: ellipsis;
1950
+ -webkit-mask-image:
1951
+ linear-gradient(
1952
+ to right,
1953
+ black 0%,
1954
+ black calc(100% - 20px),
1955
+ transparent 100%);
1956
+ mask-image:
1957
+ linear-gradient(
1958
+ to right,
1959
+ black 0%,
1960
+ black calc(100% - 20px),
1961
+ transparent 100%);
1950
1962
  }
1951
1963
  .fc-tab-bar--attached {
1952
1964
  border-bottom: 2px solid var(--fc-color-border);
@@ -2024,11 +2036,6 @@
2024
2036
  .fc-tab-bar__add-btn {
2025
2037
  -webkit-app-region: no-drag;
2026
2038
  }
2027
- .fc-tab-bar__drag-handle {
2028
- flex: 0 0 0px;
2029
- overflow: hidden;
2030
- -webkit-app-region: drag;
2031
- }
2032
2039
  .fc-tab-bar__tab--draggable {
2033
2040
  cursor: default;
2034
2041
  }
@@ -2053,11 +2060,13 @@
2053
2060
  background-color: var(--fc-color-border-light);
2054
2061
  }
2055
2062
  .fc-tab-bar__add-btn {
2063
+ position: sticky;
2064
+ right: 0;
2065
+ flex-shrink: 0;
2056
2066
  display: inline-flex;
2057
2067
  align-items: center;
2058
2068
  justify-content: center;
2059
2069
  width: 32px;
2060
- flex-shrink: 0;
2061
2070
  margin: 0 var(--fc-space-sm, 8px);
2062
2071
  font-size: 20px;
2063
2072
  font-weight: bold;
@@ -2066,6 +2075,7 @@
2066
2075
  cursor: pointer;
2067
2076
  transition: all var(--fc-transition, 150ms ease);
2068
2077
  border-radius: var(--fc-radius-sm, 4px);
2078
+ background-color: var(--tab-bar-bg);
2069
2079
  }
2070
2080
  .fc-tab-bar__add-btn:hover {
2071
2081
  color: var(--fc-color-primary);
@@ -2074,9 +2084,24 @@
2074
2084
  .fc-tab-bar--floating .fc-tab-bar__add-btn {
2075
2085
  border-radius: var(--fc-radius-full, 9999px);
2076
2086
  }
2087
+ [data-theme=dark] .fc-tab-bar--attached {
2088
+ border-bottom-color: var(--fc-color-border);
2089
+ }
2090
+ [data-theme=dark] .fc-tab-bar__tab--active {
2091
+ background-color: var(--tab-active-bg);
2092
+ }
2093
+ [data-theme=dark] .fc-tab-bar__tab:hover:not(.fc-tab-bar__tab--disabled) {
2094
+ background-color: var(--tab-hover-bg);
2095
+ }
2077
2096
  [data-theme=dark] .fc-tab-bar--floating .fc-tab-bar__tab--active {
2078
2097
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2);
2079
2098
  }
2099
+ [data-theme=dark] .fc-tab-bar__add-btn:hover {
2100
+ background-color: var(--fc-color-bg-tertiary);
2101
+ }
2102
+ [data-theme=dark] .fc-tab-bar__tab-close:hover {
2103
+ background-color: var(--fc-color-border-light);
2104
+ }
2080
2105
  @media (max-width: 768px) {
2081
2106
  .fc-tab-bar__tab {
2082
2107
  padding: var(--fc-space-xs, 6px) var(--fc-space-md, 12px);
package/dist/index.d.ts CHANGED
@@ -423,41 +423,95 @@ interface CardProps {
423
423
  declare const Card: ({ image, imageSlot, imageHeight, title, description, actions, extraInfo, variant, hoverable, disabled, className, style, onClick, }: CardProps) => react_jsx_runtime.JSX.Element;
424
424
 
425
425
  interface TabItem {
426
+ /** 唯一标识 */
426
427
  key: string;
428
+ /** 标签显示内容 */
427
429
  label: React__default.ReactNode;
430
+ /** 是否禁用 */
428
431
  disabled?: boolean;
432
+ /** 是否可关闭(覆盖全局 closable) */
429
433
  closable?: boolean;
430
434
  }
431
435
  interface TabBarProps {
436
+ /** Tab 列表(受控) */
432
437
  items: TabItem[];
438
+ /** 当前激活的 Tab key(受控) */
433
439
  activeKey: string;
440
+ /**
441
+ * 布局变体
442
+ * - attached: 贴合模式 — 标签底部紧贴导航栏下边缘,底部线条作为激活指示器
443
+ * - floating: 悬浮模式 — 标签垂直居中悬浮,胶囊形态,背景填充作为激活指示器
444
+ * @default 'attached'
445
+ */
434
446
  variant?: 'attached' | 'floating';
447
+ /** TabBar 容器圆角 */
435
448
  radius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
449
+ /** 单个 Tab 项的圆角(仅在 floating 模式下或需要四周圆角时使用) */
436
450
  tabRadius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
451
+ /** 是否显示关闭按钮 */
437
452
  closable?: boolean;
453
+ /** 是否显示添加按钮 */
438
454
  addable?: boolean;
455
+ /** 是否启用拖拽排序 */
439
456
  draggable?: boolean;
440
- minTabWidth?: number;
441
- maxTabWidth?: number;
457
+ /**
458
+ * Tab 最小宽度比例(相对 screen.width)。
459
+ * Tab 压缩至此宽度后触发横向滚动。
460
+ * @default 0.07
461
+ */
462
+ minWidthRatio?: number;
463
+ /**
464
+ * Tab 最大宽度比例(相对 screen.width)。
465
+ * Tab 较少时不超过此宽度。
466
+ * @default 0.15
467
+ */
468
+ maxTabWidthRatio?: number;
469
+ /**
470
+ * 控制 Tab 是否自动填充容器宽度。
471
+ * - true: flex: 1 1 0,Tab 会自动拉伸填满导航栏(默认行为)
472
+ * - false: flex: 0 1 auto,Tab 只占内容宽度,剩余空间留白
473
+ * 当 tauriDragRegion 为 true 且 fillWidth 为 false 时,空白区域可作为窗口拖拽区。
474
+ * @default true
475
+ */
476
+ fillWidth?: boolean;
442
477
  onChange: (activeKey: string) => void;
443
478
  onClose?: (key: string) => void;
444
479
  onAdd?: () => void;
445
480
  onReorder?: (reorderedItems: TabItem[]) => void;
481
+ /** 每个 Tab 的自定义 className */
446
482
  tabClassName?: string;
483
+ /** 激活态 Tab 的额外 className */
447
484
  activeTabClassName?: string;
485
+ /** 每个 Tab 的自定义 inline style */
448
486
  tabStyle?: React__default.CSSProperties;
487
+ /** 激活态 Tab 的自定义 inline style(会合并到 tabStyle 之上) */
449
488
  activeTabStyle?: React__default.CSSProperties;
489
+ /** 自定义关闭图标渲染 */
450
490
  renderCloseIcon?: (key: string) => React__default.ReactNode;
491
+ /** 自定义添加按钮渲染 */
451
492
  renderAddButton?: () => React__default.ReactNode;
452
493
  className?: string;
453
494
  style?: React__default.CSSProperties;
495
+ /** 容器背景色 */
454
496
  background?: string;
497
+ /** 标签默认文字色 */
455
498
  tabColor?: string;
499
+ /** 标签 hover 文字色 */
456
500
  tabHoverColor?: string;
501
+ /** 标签 hover 背景色 */
457
502
  tabHoverBackground?: string;
503
+ /** 激活态文字色 */
458
504
  tabActiveColor?: string;
505
+ /** 激活态背景色 */
459
506
  tabActiveBackground?: string;
507
+ /** 激活态指示器颜色(attached 模式底线 / floating 模式无效) */
460
508
  activeIndicatorColor?: string;
509
+ /**
510
+ * 将 TabBar 空白区域标记为 Tauri 窗口拖拽区域。
511
+ * 开启后,标签之外的空白处可拖动窗口;标签、关闭、添加按钮已内置 no-drag 保护。
512
+ * @default false
513
+ */
514
+ tauriDragRegion?: boolean;
461
515
  }
462
516
  declare const TabBar: React__default.NamedExoticComponent<TabBarProps>;
463
517
 
package/dist/index.js CHANGED
@@ -2098,8 +2098,9 @@ var TabBar = memo4(({
2098
2098
  closable = false,
2099
2099
  addable = false,
2100
2100
  draggable = false,
2101
- minTabWidth = 8,
2102
- maxTabWidth = 18,
2101
+ minWidthRatio = 0.07,
2102
+ maxTabWidthRatio = 0.15,
2103
+ fillWidth = true,
2103
2104
  onChange,
2104
2105
  onClose,
2105
2106
  onAdd,
@@ -2112,6 +2113,7 @@ var TabBar = memo4(({
2112
2113
  renderAddButton,
2113
2114
  className = "",
2114
2115
  style,
2116
+ tauriDragRegion = false,
2115
2117
  background,
2116
2118
  tabColor,
2117
2119
  tabHoverColor,
@@ -2120,75 +2122,85 @@ var TabBar = memo4(({
2120
2122
  tabActiveBackground,
2121
2123
  activeIndicatorColor
2122
2124
  }) => {
2123
- const cssVarMap = {
2125
+ const colorVars = {
2124
2126
  "--tab-bar-bg": background,
2125
2127
  "--tab-color": tabColor,
2126
2128
  "--tab-hover-color": tabHoverColor,
2127
2129
  "--tab-hover-bg": tabHoverBackground,
2128
2130
  "--tab-active-color": tabActiveColor,
2129
2131
  "--tab-active-bg": tabActiveBackground,
2130
- "--tab-active-indicator": activeIndicatorColor,
2131
- "--tab-min-width": `${minTabWidth}rem`,
2132
- "--tab-max-width": `${maxTabWidth}rem`
2132
+ "--tab-active-indicator": activeIndicatorColor
2133
2133
  };
2134
- const cssVars = {};
2135
- for (const [k, v] of Object.entries(cssVarMap)) {
2136
- if (v !== void 0) cssVars[k] = v;
2134
+ const overrideStyle = {};
2135
+ for (const [key, value] of Object.entries(colorVars)) {
2136
+ if (value !== void 0) {
2137
+ overrideStyle[key] = value;
2138
+ }
2137
2139
  }
2138
- const mergedStyle = { ...cssVars, ...style };
2139
- const navOuterRef = useRef7(null);
2140
- const addBtnRef = useRef7(null);
2141
- const navWrapRef = useRef7(null);
2140
+ const mergedStyle = { ...overrideStyle, ...style };
2142
2141
  const dragKeyRef = useRef7(null);
2142
+ const navRef = useRef7(null);
2143
+ const prevItemsLengthRef = useRef7(items.length);
2143
2144
  useEffect8(() => {
2144
- const el = navWrapRef.current;
2145
- if (!el) return;
2146
- const handler = (e) => {
2147
- if (e.deltaY === 0 || e.deltaX !== 0) return;
2148
- el.scrollLeft += e.deltaY;
2149
- e.preventDefault();
2150
- };
2151
- el.addEventListener("wheel", handler, { passive: false });
2152
- return () => el.removeEventListener("wheel", handler);
2153
- }, []);
2154
- const prevLenRef = useRef7(items.length);
2155
- useEffect8(() => {
2156
- const prev = prevLenRef.current;
2157
- prevLenRef.current = items.length;
2145
+ const prev = prevItemsLengthRef.current;
2146
+ prevItemsLengthRef.current = items.length;
2158
2147
  if (items.length <= prev) return;
2159
- const el = navWrapRef.current;
2160
- if (!el) return;
2148
+ const nav = navRef.current;
2149
+ if (!nav) return;
2161
2150
  requestAnimationFrame(() => {
2162
- el.scrollLeft = el.scrollWidth;
2151
+ nav.scrollLeft = nav.scrollWidth;
2163
2152
  });
2164
2153
  }, [items.length]);
2165
- const handleClick = useCallback8((key) => onChange(key), [onChange]);
2166
- const handleClose = useCallback8((e, key) => {
2167
- e.stopPropagation();
2168
- onClose?.(key);
2169
- }, [onClose]);
2170
- const handleDragStart = useCallback8((e, key) => {
2171
- dragKeyRef.current = key;
2172
- e.dataTransfer.effectAllowed = "move";
2173
- const target = e.currentTarget;
2174
- requestAnimationFrame(() => target.classList.add("fc-tab-bar__tab--dragging"));
2154
+ useEffect8(() => {
2155
+ const nav = navRef.current;
2156
+ if (!nav) return;
2157
+ const handleWheel = (e) => {
2158
+ if (e.deltaY === 0) return;
2159
+ e.preventDefault();
2160
+ nav.scrollLeft += Number(e.deltaY);
2161
+ };
2162
+ nav.addEventListener("wheel", handleWheel, { passive: false });
2163
+ return () => nav.removeEventListener("wheel", handleWheel);
2175
2164
  }, []);
2165
+ const handleClick = useCallback8(
2166
+ (key) => onChange(key),
2167
+ [onChange]
2168
+ );
2169
+ const handleClose = useCallback8(
2170
+ (e, key) => {
2171
+ e.stopPropagation();
2172
+ onClose?.(key);
2173
+ },
2174
+ [onClose]
2175
+ );
2176
+ const handleDragStart = useCallback8(
2177
+ (e, key) => {
2178
+ dragKeyRef.current = key;
2179
+ e.dataTransfer.effectAllowed = "move";
2180
+ const target = e.currentTarget;
2181
+ requestAnimationFrame(() => target.classList.add("fc-tab-bar__tab--dragging"));
2182
+ },
2183
+ []
2184
+ );
2176
2185
  const handleDragOver = useCallback8((e) => {
2177
2186
  e.preventDefault();
2178
2187
  e.dataTransfer.dropEffect = "move";
2179
2188
  }, []);
2180
- const handleDrop = useCallback8((e, targetKey) => {
2181
- e.preventDefault();
2182
- const dragKey = dragKeyRef.current;
2183
- if (!dragKey || dragKey === targetKey || !onReorder) return;
2184
- const from = items.findIndex((i) => i.key === dragKey);
2185
- const to = items.findIndex((i) => i.key === targetKey);
2186
- if (from === -1 || to === -1) return;
2187
- const reordered = [...items];
2188
- const [moved] = reordered.splice(from, 1);
2189
- reordered.splice(to, 0, moved);
2190
- onReorder(reordered);
2191
- }, [items, onReorder]);
2189
+ const handleDrop = useCallback8(
2190
+ (e, targetKey) => {
2191
+ e.preventDefault();
2192
+ const dragKey = dragKeyRef.current;
2193
+ if (!dragKey || dragKey === targetKey || !onReorder) return;
2194
+ const fromIndex = items.findIndex((i) => i.key === dragKey);
2195
+ const toIndex = items.findIndex((i) => i.key === targetKey);
2196
+ if (fromIndex === -1 || toIndex === -1) return;
2197
+ const reordered = [...items];
2198
+ const [moved] = reordered.splice(fromIndex, 1);
2199
+ reordered.splice(toIndex, 0, moved);
2200
+ onReorder(reordered);
2201
+ },
2202
+ [items, onReorder]
2203
+ );
2192
2204
  const handleDragEnd = useCallback8((e) => {
2193
2205
  dragKeyRef.current = null;
2194
2206
  e.currentTarget.classList.remove("fc-tab-bar__tab--dragging");
@@ -2200,13 +2212,14 @@ var TabBar = memo4(({
2200
2212
  tabRadius && `fc-tab-bar--tab-radius-${tabRadius}`,
2201
2213
  className
2202
2214
  ].filter(Boolean).join(" ");
2203
- const navWrapClasses = [
2204
- "fc-tab-bar__nav-wrap",
2205
- "fc-tab-bar__nav-wrap--scroll"
2206
- // 始终启用滚动模式,由 CSS 控制
2207
- ].filter(Boolean).join(" ");
2208
- return /* @__PURE__ */ jsx18("div", { className: rootClasses, style: mergedStyle, role: "tablist", children: /* @__PURE__ */ jsxs13("div", { className: "fc-tab-bar__nav-outer", ref: navOuterRef, children: [
2209
- /* @__PURE__ */ jsx18("div", { className: navWrapClasses, ref: navWrapRef, children: items.map((item) => /* @__PURE__ */ jsx18(
2215
+ const navWrapStyle = {
2216
+ "--tab-min-width": `${Math.round(screen.width * minWidthRatio)}px`,
2217
+ "--tab-max-width": `${Math.round(screen.width * maxTabWidthRatio)}px`,
2218
+ "--tab-fill-width": fillWidth ? "1" : "0"
2219
+ };
2220
+ const dragRegion = tauriDragRegion ? { "data-tauri-drag-region": "" } : {};
2221
+ return /* @__PURE__ */ jsx18("div", { className: rootClasses, style: mergedStyle, role: "tablist", ...dragRegion, children: /* @__PURE__ */ jsx18("div", { className: "fc-tab-bar__nav-outer", ...dragRegion, children: /* @__PURE__ */ jsxs13("div", { className: "fc-tab-bar__nav-wrap", ref: navRef, style: navWrapStyle, children: [
2222
+ items.map((item) => /* @__PURE__ */ jsx18(
2210
2223
  TabItemView,
2211
2224
  {
2212
2225
  item,
@@ -2226,20 +2239,18 @@ var TabBar = memo4(({
2226
2239
  onDragEnd: handleDragEnd
2227
2240
  },
2228
2241
  item.key
2229
- )) }),
2242
+ )),
2230
2243
  addable && /* @__PURE__ */ jsx18(
2231
2244
  "div",
2232
2245
  {
2233
2246
  className: "fc-tab-bar__add-btn",
2234
- ref: addBtnRef,
2235
2247
  onClick: onAdd,
2236
2248
  role: "button",
2237
2249
  "aria-label": "\u6DFB\u52A0\u6807\u7B7E",
2238
2250
  children: renderAddButton ? renderAddButton() : "+"
2239
2251
  }
2240
- ),
2241
- /* @__PURE__ */ jsx18("div", { className: "fc-tab-bar__drag-handle", "data-tauri-drag-region": true })
2242
- ] }) });
2252
+ )
2253
+ ] }) }) });
2243
2254
  });
2244
2255
  TabBar.displayName = "TabBar";
2245
2256
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowcloudai-ui",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "author": "flowcloudai",
6
6
  "module": "dist/index.js",