@bifrostui/react 1.4.2 → 1.4.3

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.
@@ -30,6 +30,7 @@
30
30
  }
31
31
  .bui-input-input {
32
32
  flex: 1;
33
+ min-width: 0;
33
34
  display: flex;
34
35
  align-items: center;
35
36
  padding: 0;
@@ -39,16 +40,11 @@
39
40
  outline: none;
40
41
  background-color: var(--background-color);
41
42
  font-size: var(--bui-text-size-2);
42
- width: auto;
43
- overflow: hidden;
44
- text-overflow: ellipsis;
45
- white-space: nowrap;
46
43
  }
47
44
  .bui-input-input::placeholder {
48
45
  color: var(--bui-color-fg-subtle);
49
46
  }
50
47
  .bui-input-disabled {
51
- pointer-events: none;
52
48
  background-color: var(--disabled-background-color);
53
49
  }
54
50
  .bui-input-disabled .bui-input-input {
@@ -12,5 +12,5 @@ declare const Modal: React.ForwardRefExoticComponent<Omit<ViewProps & {
12
12
  keepMounted?: boolean;
13
13
  } & import("@bifrostui/types").ICommonProps & Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
14
14
  ref?: React.Ref<HTMLDivElement>;
15
- }, "open" | keyof import("@bifrostui/types").ICommonProps | "container" | "disablePortal" | "hideBackdrop" | "BackdropProps" | "onClose" | "disableScrollLock" | "keepMounted">, "ref"> & React.RefAttributes<HTMLDivElement>>;
15
+ }, "open" | keyof import("@bifrostui/types").ICommonProps | "container" | "BackdropProps" | "onClose" | "keepMounted" | "disablePortal" | "hideBackdrop" | "disableScrollLock">, "ref"> & React.RefAttributes<HTMLDivElement>>;
16
16
  export default Modal;
@@ -3,7 +3,7 @@
3
3
  --localtion-position: var(--bui-popover-localtion-position, 8PX);
4
4
  --max-width: var(--bui-popover-max-width, 350px);
5
5
  --content-min-width: var(--bui-popover-content-min-width, 30px);
6
- --content-padding: var(--bui-popover-content-padding, 0);
6
+ --content-padding: var(--bui-popover-content-padding, 6px 8px);
7
7
  max-width: var(--max-width);
8
8
  font-size: var(--bui-text-size-1);
9
9
  position: absolute;
@@ -70,6 +70,7 @@ const Popover = /* @__PURE__ */ import_react.default.forwardRef((props, ref) =>
70
70
  title,
71
71
  content,
72
72
  defaultOpen,
73
+ offsetSpacing = 0,
73
74
  placement = "top",
74
75
  trigger = "click",
75
76
  onOpenChange,
@@ -82,6 +83,7 @@ const Popover = /* @__PURE__ */ import_react.default.forwardRef((props, ref) =>
82
83
  "title",
83
84
  "content",
84
85
  "defaultOpen",
86
+ "offsetSpacing",
85
87
  "placement",
86
88
  "trigger",
87
89
  "onOpenChange",
@@ -89,15 +91,7 @@ const Popover = /* @__PURE__ */ import_react.default.forwardRef((props, ref) =>
89
91
  "hideArrow"
90
92
  ]);
91
93
  const controlByUser = typeof open !== "undefined";
92
- const positionArr = placement.split(/([A-Z])/);
93
- const direction = positionArr[0];
94
- let location;
95
- if (positionArr.length > 1) {
96
- positionArr.splice(0, 1);
97
- location = positionArr.join("").toLowerCase();
98
- } else {
99
- location = "center";
100
- }
94
+ const { direction, location = "center" } = (0, import_utils.parsePlacement)(placement);
101
95
  const childrenRef = (0, import_react.useRef)();
102
96
  const [openStatus, setOpenStatus] = (0, import_react.useState)(defaultOpen);
103
97
  const [arrowDirection, setArrowDirection] = (0, import_react.useState)(direction);
@@ -132,10 +126,15 @@ const Popover = /* @__PURE__ */ import_react.default.forwardRef((props, ref) =>
132
126
  hidePopover(event);
133
127
  };
134
128
  const onRootElementMouted = (0, import_utils.throttle)(() => {
129
+ const {
130
+ direction: newParsedDirection,
131
+ location: newParsedLocation = "center"
132
+ } = (0, import_utils.parsePlacement)(placement);
135
133
  const result = (0, import_utils.getStylesAndLocation)({
136
134
  childrenRef,
137
- arrowDirection,
138
- arrowLocation,
135
+ arrowDirection: newParsedDirection,
136
+ arrowLocation: newParsedLocation,
137
+ offsetSpacing,
139
138
  selector: `[data-id="tt_${ttId}"]`
140
139
  });
141
140
  if (!result)
@@ -25,6 +25,10 @@ export type PopoverProps<D extends React.ElementType = 'div', P = {}> = Override
25
25
  * @default false
26
26
  */
27
27
  hideArrow?: boolean;
28
+ /**
29
+ * 用于控制浮层和目标元素偏移量
30
+ */
31
+ offsetSpacing?: number;
28
32
  /**
29
33
  * 气泡框位置
30
34
  * @default 'top'
@@ -3,11 +3,6 @@
3
3
  --mini-width: var(--bui-select-min-width, 100px);
4
4
  --font-size: var(--bui-select-font-size, var(--bui-title-size-3));
5
5
  --padding: var(--bui-select-selector-container, 0 14px);
6
- --option-container-padding: var(--bui-select-option-container-padding, 3px 0);
7
- --option-container-margin-top: var(--bui-select-option-margin-top, 6px);
8
- --option-padding: var(--bui-select-option-padding, 0 14px);
9
- --option-margin: var(--bui-select-option-margin, 0 3px);
10
- --option-height: var(--bui-select-option-height, 27px);
11
6
  position: relative;
12
7
  cursor: pointer;
13
8
  height: var(--height);
@@ -16,8 +11,8 @@
16
11
  border-radius: 5px;
17
12
  background-color: var(--bui-color-bg-view);
18
13
  font-family: var(--bui-font-family);
14
+ -webkit-tap-highlight-color: transparent;
19
15
  }
20
- .bui-select:active,
21
16
  .bui-select-active {
22
17
  box-shadow: 0 0 0 2px var(--bui-color-bg-default);
23
18
  }
@@ -32,6 +27,7 @@
32
27
  height: 0;
33
28
  border: 0;
34
29
  opacity: 0;
30
+ pointer-events: none;
35
31
  }
36
32
  .bui-select-placeholder {
37
33
  color: var(--bui-color-fg-disabled);
@@ -55,20 +51,32 @@
55
51
  top: 100%;
56
52
  left: 0;
57
53
  width: 100%;
58
- z-index: var(--bui-z-index-dropdown);
59
- margin-top: var(--option-container-margin-top);
54
+ font-size: var(--bui-select-font-size, var(--bui-title-size-3));
55
+ z-index: var(--bui-z-index-tooltip);
60
56
  border-radius: 3px;
61
57
  background-color: var(--bui-color-bg-view);
62
58
  padding: 2px;
63
59
  overflow: hidden;
64
60
  }
61
+ .bui-select-option-container-top {
62
+ margin-top: -6px;
63
+ }
64
+ .bui-select-option-container-bottom {
65
+ margin-top: 6px;
66
+ }
67
+ .bui-select-option-container-hide {
68
+ pointer-events: none;
69
+ }
65
70
  .bui-select-option-main {
66
71
  border-radius: 3px;
67
- padding: var(--option-container-padding);
72
+ padding: var(--bui-select-option-container-padding, 3px 0);
68
73
  box-shadow: 0 0 0 2px var(--bui-color-bg-default);
69
74
  overflow: hidden;
70
75
  }
71
76
  .bui-select-option {
77
+ --option-padding: var(--bui-select-option-padding, 0 14px);
78
+ --option-margin: var(--bui-select-option-margin, 0 3px);
79
+ --option-height: var(--bui-select-option-height, 27px);
72
80
  display: flex;
73
81
  align-items: center;
74
82
  height: var(--option-height);
@@ -67,8 +67,10 @@ var import_Fade = __toESM(require("../Fade"));
67
67
  var import_Slide = __toESM(require("../Slide"));
68
68
  var import_selectContext = __toESM(require("./selectContext"));
69
69
  var import_Backdrop = __toESM(require("../Backdrop"));
70
+ var import_Portal = __toESM(require("../Portal"));
70
71
  var import_Select2 = require("./Select.css");
71
72
  const prefixCls = "bui-select";
73
+ const defaultPlacement = "bottom";
72
74
  const Select = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
73
75
  const _a = props, {
74
76
  className,
@@ -83,6 +85,7 @@ const Select = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
83
85
  placeholder,
84
86
  icon,
85
87
  open,
88
+ scrollContainer,
86
89
  onChange,
87
90
  onClose,
88
91
  onOpen,
@@ -100,6 +103,7 @@ const Select = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
100
103
  "placeholder",
101
104
  "icon",
102
105
  "open",
106
+ "scrollContainer",
103
107
  "onChange",
104
108
  "onClose",
105
109
  "onOpen",
@@ -110,19 +114,49 @@ const Select = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
110
114
  defaultValue,
111
115
  onChange
112
116
  });
113
- const [isOpen, setIsOpen] = (0, import_react.useState)(false);
117
+ const [internalOpen, setInternalOpen] = (0, import_react.useState)(false);
114
118
  const [renderValue, setRenderValue] = (0, import_react.useState)("");
115
- const defaultIcon = isOpen ? /* @__PURE__ */ import_react.default.createElement(import_icons.CaretUpIcon, { className: `${prefixCls}-selector-icon`, htmlColor: "#9c9ca5" }) : /* @__PURE__ */ import_react.default.createElement(
116
- import_icons.CaretDownIcon,
117
- {
118
- className: `${prefixCls}-selector-icon`,
119
- htmlColor: "#9c9ca5"
119
+ const [placement, setPlacement] = (0, import_react.useState)(defaultPlacement);
120
+ const [optionStyle, setOptionStyle] = (0, import_react.useState)({});
121
+ const isOpen = open !== void 0 ? open : internalOpen;
122
+ const locatorRef = (0, import_react.useRef)(null);
123
+ const rootRef = (0, import_utils.useForkRef)(ref, locatorRef);
124
+ const ttId = (0, import_utils.useUniqueId)();
125
+ const dataId = `${prefixCls}-tt-${ttId}`;
126
+ const updateOptionStyle = (0, import_utils.throttle)(() => {
127
+ const curScrollRoot = scrollContainer();
128
+ if (!import_utils.isMini && curScrollRoot) {
129
+ const result = (0, import_utils.getStylesAndLocation)({
130
+ scrollRoot: curScrollRoot,
131
+ childrenRef: locatorRef,
132
+ arrowDirection: defaultPlacement,
133
+ arrowLocation: "none",
134
+ selector: `[data-id="${dataId}"]`,
135
+ offsetSpacing: 0
136
+ });
137
+ if (!result)
138
+ return;
139
+ const { styles, childrenStyle, newArrowDirection } = result;
140
+ setPlacement(newArrowDirection);
141
+ setOptionStyle(__spreadProps(__spreadValues({}, styles), { width: childrenStyle.width }));
120
142
  }
121
- );
143
+ }, 100);
144
+ const changeOpen = (newOpen) => {
145
+ if (newOpen) {
146
+ updateOptionStyle();
147
+ setTimeout(() => {
148
+ setInternalOpen(newOpen);
149
+ onOpen == null ? void 0 : onOpen();
150
+ }, 100);
151
+ } else {
152
+ onClose == null ? void 0 : onClose();
153
+ setInternalOpen(newOpen);
154
+ }
155
+ };
122
156
  const handleSelectClick = (e) => {
123
157
  if (disabled)
124
158
  return;
125
- setIsOpen(!isOpen);
159
+ changeOpen(!isOpen);
126
160
  if (typeof onClick === "function")
127
161
  onClick(e);
128
162
  };
@@ -133,28 +167,70 @@ const Select = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
133
167
  } else {
134
168
  onChange == null ? void 0 : onChange(e, { value: optionValue });
135
169
  }
136
- setIsOpen(false);
170
+ changeOpen(false);
137
171
  };
138
- const handleBackdropTouchStart = () => {
139
- if (isOpen) {
140
- setIsOpen(false);
141
- }
172
+ const handleBackdropClick = () => {
173
+ changeOpen(false);
142
174
  };
143
175
  const selectContext = (0, import_react.useMemo)(
144
176
  () => ({ selectValue, setRenderValue, handleOptionClick }),
145
177
  [selectValue, onChange, setRenderValue]
146
178
  );
147
179
  (0, import_react.useEffect)(() => {
148
- if (open !== void 0)
149
- setIsOpen(open);
150
- }, [open]);
151
- (0, import_react.useEffect)(() => {
152
- if (isOpen) {
153
- onOpen == null ? void 0 : onOpen();
154
- } else {
155
- onClose == null ? void 0 : onClose();
180
+ if (!import_utils.isMini) {
181
+ window.addEventListener("resize", updateOptionStyle);
182
+ return () => {
183
+ window.removeEventListener("resize", updateOptionStyle);
184
+ };
156
185
  }
157
- }, [isOpen]);
186
+ }, []);
187
+ const defaultIcon = isOpen ? /* @__PURE__ */ import_react.default.createElement(import_icons.CaretUpIcon, { className: `${prefixCls}-selector-icon`, htmlColor: "#9c9ca5" }) : /* @__PURE__ */ import_react.default.createElement(
188
+ import_icons.CaretDownIcon,
189
+ {
190
+ className: `${prefixCls}-selector-icon`,
191
+ htmlColor: "#9c9ca5"
192
+ }
193
+ );
194
+ const renderOptions = () => {
195
+ var _a2;
196
+ return /* @__PURE__ */ import_react.default.createElement(
197
+ import_Fade.default,
198
+ {
199
+ in: isOpen,
200
+ timeout: {
201
+ enter: 150,
202
+ exit: 150
203
+ }
204
+ },
205
+ /* @__PURE__ */ import_react.default.createElement(
206
+ "div",
207
+ {
208
+ className: (0, import_clsx.default)(
209
+ `${prefixCls}-option-container`,
210
+ ...((_a2 = className == null ? void 0 : className.split(/\s+/)) == null ? void 0 : _a2.map((cls) => `${cls}-option-container`)) || [],
211
+ `${prefixCls}-option-container-${placement}`,
212
+ {
213
+ [`${prefixCls}-option-container-hide`]: !isOpen
214
+ }
215
+ ),
216
+ "data-id": dataId,
217
+ style: optionStyle
218
+ },
219
+ /* @__PURE__ */ import_react.default.createElement(
220
+ import_Slide.default,
221
+ {
222
+ in: isOpen,
223
+ direction: placement === "bottom" ? "down" : "up",
224
+ timeout: {
225
+ enter: 150,
226
+ exit: 150
227
+ }
228
+ },
229
+ /* @__PURE__ */ import_react.default.createElement("div", { className: (0, import_clsx.default)(`${prefixCls}-option-main`) }, children)
230
+ )
231
+ )
232
+ );
233
+ };
158
234
  return /* @__PURE__ */ import_react.default.createElement(import_selectContext.default.Provider, { value: selectContext }, /* @__PURE__ */ import_react.default.createElement(
159
235
  "div",
160
236
  __spreadProps(__spreadValues({
@@ -162,7 +238,7 @@ const Select = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
162
238
  [`${prefixCls}-disabled`]: disabled,
163
239
  [`${prefixCls}-active`]: isOpen
164
240
  }),
165
- ref
241
+ ref: rootRef
166
242
  }, others), {
167
243
  onClick: handleSelectClick
168
244
  }),
@@ -179,34 +255,14 @@ const Select = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
179
255
  })
180
256
  })
181
257
  ), icon || defaultIcon),
182
- /* @__PURE__ */ import_react.default.createElement(
183
- import_Fade.default,
184
- {
185
- in: isOpen,
186
- timeout: {
187
- enter: 150,
188
- exit: 150
189
- }
190
- },
191
- /* @__PURE__ */ import_react.default.createElement("div", { className: (0, import_clsx.default)(`${prefixCls}-option-container`) }, /* @__PURE__ */ import_react.default.createElement(
192
- import_Slide.default,
193
- {
194
- in: isOpen,
195
- timeout: {
196
- enter: 150,
197
- exit: 150
198
- }
199
- },
200
- /* @__PURE__ */ import_react.default.createElement("div", { className: (0, import_clsx.default)(`${prefixCls}-option-main`) }, children)
201
- ))
202
- )
203
- ), /* @__PURE__ */ import_react.default.createElement(
258
+ import_utils.isMini && renderOptions()
259
+ ), !import_utils.isMini && /* @__PURE__ */ import_react.default.createElement(import_Portal.default, { onRootElementMouted: updateOptionStyle }, renderOptions()), /* @__PURE__ */ import_react.default.createElement(
204
260
  import_Backdrop.default,
205
261
  __spreadProps(__spreadValues({
206
262
  open: isOpen,
207
263
  invisible: true,
208
- onTouchStart: handleBackdropTouchStart,
209
- onClick: handleBackdropTouchStart
264
+ onTouchStart: handleBackdropClick,
265
+ onClick: handleBackdropClick
210
266
  }, BackdropProps), {
211
267
  className: (0, import_clsx.default)(`${prefixCls}-backdrop`, {
212
268
  [BackdropProps == null ? void 0 : BackdropProps.className]: BackdropProps == null ? void 0 : BackdropProps.className
@@ -216,6 +272,9 @@ const Select = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
216
272
  });
217
273
  Select.displayName = "BuiSelect";
218
274
  Select.defaultProps = {
219
- defaultValue: ""
275
+ defaultValue: "",
276
+ scrollContainer: () => {
277
+ return import_utils.isMini ? null : document.body;
278
+ }
220
279
  };
221
280
  var Select_default = Select;
@@ -76,6 +76,12 @@ export type SelectProps<D extends React.ElementType = 'div', P = {}> = OverrideP
76
76
  * 是否展开下拉框
77
77
  */
78
78
  open?: boolean;
79
+ /**
80
+ * 滚动容器
81
+ * 下拉框元素和children将会被append到scrollContainer中
82
+ * 默认是页面的根节点
83
+ */
84
+ scrollContainer?: () => Element | null;
79
85
  /**
80
86
  * 自定义选中后展示的内容
81
87
  */
@@ -61,7 +61,19 @@ var import_react = __toESM(require("react"));
61
61
  var import_TabPanel = require("./TabPanel.css");
62
62
  const prefixCls = "bui-tabpanel";
63
63
  const TabPanel = (0, import_react.forwardRef)((props, ref) => {
64
- const _a = props, { className, children, value, index, keepMounted } = _a, others = __objRest(_a, ["className", "children", "value", "index", "keepMounted"]);
64
+ const _a = props, {
65
+ className,
66
+ children,
67
+ value,
68
+ index,
69
+ keepMounted = false
70
+ } = _a, others = __objRest(_a, [
71
+ "className",
72
+ "children",
73
+ "value",
74
+ "index",
75
+ "keepMounted"
76
+ ]);
65
77
  const keepActiveDom = keepMounted ? children : null;
66
78
  return /* @__PURE__ */ import_react.default.createElement(
67
79
  "div",
@@ -76,7 +88,4 @@ const TabPanel = (0, import_react.forwardRef)((props, ref) => {
76
88
  );
77
89
  });
78
90
  TabPanel.displayName = "BuiTabPanel";
79
- TabPanel.defaultProps = {
80
- keepMounted: false
81
- };
82
91
  var TabPanel_default = TabPanel;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import './Tabs.less';
3
2
  import { TabsProps } from './Tabs.types';
3
+ import './Tabs.less';
4
4
  declare const Tabs: React.ForwardRefExoticComponent<Omit<TabsProps<"div", {}>, "ref"> & React.RefAttributes<HTMLDivElement>>;
5
5
  export default Tabs;
package/dist/Tabs/Tabs.js CHANGED
@@ -60,9 +60,9 @@ var import_utils = require("@bifrostui/utils");
60
60
  var import_clsx = __toESM(require("clsx"));
61
61
  var import_react = __toESM(require("react"));
62
62
  var import_Tab = __toESM(require("./Tab"));
63
- var import_Tabs = require("./Tabs.css");
64
63
  var import_TabsContext = require("./TabsContext");
65
64
  var import_bound = __toESM(require("./utils/bound"));
65
+ var import_Tabs2 = require("./Tabs.css");
66
66
  const prefixCls = "bui-tabs";
67
67
  const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
68
68
  const _a = props, { children, className, value, tabs, align, onChange } = _a, others = __objRest(_a, ["children", "className", "value", "tabs", "align", "onChange"]);
@@ -81,16 +81,13 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
81
81
  const container = tabsRef.current;
82
82
  if (!container)
83
83
  return;
84
- const activeIndex = !!tabs.length && tabs.findIndex((item) => {
85
- var _a2;
86
- return item.index === (active || ((_a2 = tabs[0]) == null ? void 0 : _a2.index));
87
- });
84
+ const activeIndex = !!tabs.length && tabs.findIndex((item) => item.index === active);
88
85
  const activeLine = activeLineRef.current;
89
86
  if (!activeLine)
90
87
  return;
91
88
  let activeTab;
92
89
  if (tabs.length) {
93
- activeTab = container.childNodes[activeIndex + 1];
90
+ activeTab = activeIndex > -1 ? container.childNodes[activeIndex + 1] : void 0;
94
91
  } else {
95
92
  activeTab = [...container.childNodes].find((child) => {
96
93
  if (import_utils.isMini) {
@@ -101,20 +98,26 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
101
98
  return [...child.classList].includes("bui-tab-active");
102
99
  });
103
100
  }
104
- if (!activeTab)
105
- return;
106
- const activeTabLeft = activeTab.offsetLeft;
107
- const activeTabWidth = activeTab.offsetWidth;
108
- const containerWidth = container.offsetWidth;
109
- const containerScrollWidth = container.scrollWidth;
110
- const activeLineWidth = activeLine.offsetWidth;
111
- const x = activeTabLeft + (activeTabWidth - activeLineWidth) / 2;
101
+ let activeTabLeft = 0;
102
+ let activeTabWidth = 0;
103
+ let containerWidth = 0;
104
+ let containerScrollWidth = 0;
105
+ let activeLineWidth = 0;
106
+ let x = 0;
107
+ if (activeTab) {
108
+ activeTabLeft = activeTab.offsetLeft;
109
+ activeTabWidth = activeTab.offsetWidth;
110
+ containerWidth = container.offsetWidth;
111
+ containerScrollWidth = container.scrollWidth;
112
+ activeLineWidth = activeLine.offsetWidth;
113
+ x = activeTabLeft + (activeTabWidth - activeLineWidth) / 2;
114
+ }
112
115
  setLineData({
113
116
  x,
114
117
  transitionInUse
115
118
  });
116
119
  const maxScrollDistance = containerScrollWidth - containerWidth;
117
- if (maxScrollDistance <= 0)
120
+ if (maxScrollDistance <= 0 || !activeTab)
118
121
  return;
119
122
  const nextScrollLeft = (0, import_bound.default)(
120
123
  activeTabLeft - (containerWidth - activeTabWidth) / 2,
@@ -126,8 +129,7 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
126
129
  }
127
130
  };
128
131
  (0, import_react.useEffect)(() => {
129
- const defaultIndex = safeValue();
130
- setActive(defaultIndex);
132
+ setActive(value);
131
133
  }, [value]);
132
134
  (0, import_react.useLayoutEffect)(() => {
133
135
  animate({ transitionInUse: false });
@@ -145,26 +147,6 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
145
147
  (0, import_utils.useDidMountEffect)(() => {
146
148
  animate({ transitionInUse: true });
147
149
  }, [active, tabs, children]);
148
- const safeValue = () => {
149
- var _a2;
150
- let defaultIndex = value;
151
- const childs = import_react.default.Children.toArray(children);
152
- const hasSameChild = !!childs.length && childs.some(
153
- (child) => {
154
- var _a3;
155
- return import_react.default.isValidElement(child) && ((_a3 = child == null ? void 0 : child.props) == null ? void 0 : _a3.index) === value;
156
- }
157
- );
158
- if (!!tabs.length && !tabs.some((item) => item.index === value)) {
159
- defaultIndex = (_a2 = tabs[0]) == null ? void 0 : _a2.index;
160
- } else if (children && !hasSameChild) {
161
- const childNode = childs[0];
162
- if (import_react.default.isValidElement(childNode)) {
163
- defaultIndex = childNode.props.index;
164
- }
165
- }
166
- return defaultIndex;
167
- };
168
150
  const updateMask = (0, import_react.useMemo)(
169
151
  () => (0, import_utils.throttle)(
170
152
  () => {
@@ -205,8 +187,7 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
205
187
  }
206
188
  };
207
189
  const providerValue = (0, import_react.useMemo)(() => {
208
- const v = safeValue();
209
- return { value: v, align, triggerChange: handleClick };
190
+ return { value, align, triggerChange: handleClick };
210
191
  }, [value, align, children, handleClick]);
211
192
  return /* @__PURE__ */ import_react.default.createElement("div", __spreadValues({ ref, className: (0, import_clsx.default)(prefixCls, className) }, others), /* @__PURE__ */ import_react.default.createElement(
212
193
  "div",
@@ -229,7 +210,7 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
229
210
  {
230
211
  ref: activeLineRef,
231
212
  className: (0, import_clsx.default)(`${prefixCls}-tabline`, {
232
- "bui-tabline-invisible": import_utils.isMini
213
+ "bui-tabline-invisible": import_utils.isMini || !lineData.x
233
214
  }),
234
215
  style: {
235
216
  transition: lineData.transitionInUse ? "transform 0.25s ease-in-out" : void 0,
@@ -69,6 +69,7 @@ const Tooltip = /* @__PURE__ */ import_react.default.forwardRef((props, ref) =>
69
69
  children,
70
70
  title,
71
71
  defaultOpen,
72
+ offsetSpacing = 0,
72
73
  placement = "top",
73
74
  trigger = "click",
74
75
  onOpenChange,
@@ -79,21 +80,14 @@ const Tooltip = /* @__PURE__ */ import_react.default.forwardRef((props, ref) =>
79
80
  "children",
80
81
  "title",
81
82
  "defaultOpen",
83
+ "offsetSpacing",
82
84
  "placement",
83
85
  "trigger",
84
86
  "onOpenChange",
85
87
  "open"
86
88
  ]);
87
89
  const controlByUser = typeof open !== "undefined";
88
- const positionArr = placement.split(/([A-Z])/);
89
- const direction = positionArr[0];
90
- let location;
91
- if (positionArr.length > 1) {
92
- positionArr.splice(0, 1);
93
- location = positionArr.join("").toLowerCase();
94
- } else {
95
- location = "center";
96
- }
90
+ const { direction, location = "center" } = (0, import_utils.parsePlacement)(placement);
97
91
  const childrenRef = (0, import_react.useRef)();
98
92
  const [openStatus, setOpenStatus] = (0, import_react.useState)(defaultOpen);
99
93
  const [arrowDirection, setArrowDirection] = (0, import_react.useState)(direction);
@@ -128,10 +122,15 @@ const Tooltip = /* @__PURE__ */ import_react.default.forwardRef((props, ref) =>
128
122
  hideTooltip(event);
129
123
  };
130
124
  const onRootElementMouted = (0, import_utils.throttle)(() => {
125
+ const {
126
+ direction: newParsedDirection,
127
+ location: newParsedLocation = "center"
128
+ } = (0, import_utils.parsePlacement)(placement);
131
129
  const result = (0, import_utils.getStylesAndLocation)({
132
130
  childrenRef,
133
- arrowDirection,
134
- arrowLocation,
131
+ arrowDirection: newParsedDirection,
132
+ arrowLocation: newParsedLocation,
133
+ offsetSpacing,
135
134
  selector: `[data-id="tt_${ttId}"]`
136
135
  });
137
136
  if (!result)
@@ -16,6 +16,10 @@ export type TooltipProps<D extends React.ElementType = 'div', P = {}> = Override
16
16
  * 用于手动控制气泡浮层显隐
17
17
  */
18
18
  open?: boolean;
19
+ /**
20
+ * 用于控制气泡浮层和目标元素偏移量
21
+ */
22
+ offsetSpacing?: number;
19
23
  /**
20
24
  * 气泡框位置
21
25
  * @default 'top'
@@ -30,6 +30,7 @@
30
30
  }
31
31
  .bui-input-input {
32
32
  flex: 1;
33
+ min-width: 0;
33
34
  display: flex;
34
35
  align-items: center;
35
36
  padding: 0;
@@ -39,16 +40,11 @@
39
40
  outline: none;
40
41
  background-color: var(--background-color);
41
42
  font-size: var(--bui-text-size-2);
42
- width: auto;
43
- overflow: hidden;
44
- text-overflow: ellipsis;
45
- white-space: nowrap;
46
43
  }
47
44
  .bui-input-input::placeholder {
48
45
  color: var(--bui-color-fg-subtle);
49
46
  }
50
47
  .bui-input-disabled {
51
- pointer-events: none;
52
48
  background-color: var(--disabled-background-color);
53
49
  }
54
50
  .bui-input-disabled .bui-input-input {
@@ -3,7 +3,7 @@
3
3
  --localtion-position: var(--bui-popover-localtion-position, 8PX);
4
4
  --max-width: var(--bui-popover-max-width, 350px);
5
5
  --content-min-width: var(--bui-popover-content-min-width, 30px);
6
- --content-padding: var(--bui-popover-content-padding, 0);
6
+ --content-padding: var(--bui-popover-content-padding, 6px 8px);
7
7
  max-width: var(--max-width);
8
8
  font-size: var(--bui-text-size-1);
9
9
  position: absolute;
@@ -31,6 +31,7 @@ import React, { useState, useRef, useEffect } from "react";
31
31
  import {
32
32
  getStylesAndLocation,
33
33
  triggerEventTransform,
34
+ parsePlacement,
34
35
  useUniqueId,
35
36
  throttle
36
37
  } from "@bifrostui/utils";
@@ -45,6 +46,7 @@ const Popover = /* @__PURE__ */ React.forwardRef((props, ref) => {
45
46
  title,
46
47
  content,
47
48
  defaultOpen,
49
+ offsetSpacing = 0,
48
50
  placement = "top",
49
51
  trigger = "click",
50
52
  onOpenChange,
@@ -57,6 +59,7 @@ const Popover = /* @__PURE__ */ React.forwardRef((props, ref) => {
57
59
  "title",
58
60
  "content",
59
61
  "defaultOpen",
62
+ "offsetSpacing",
60
63
  "placement",
61
64
  "trigger",
62
65
  "onOpenChange",
@@ -64,15 +67,7 @@ const Popover = /* @__PURE__ */ React.forwardRef((props, ref) => {
64
67
  "hideArrow"
65
68
  ]);
66
69
  const controlByUser = typeof open !== "undefined";
67
- const positionArr = placement.split(/([A-Z])/);
68
- const direction = positionArr[0];
69
- let location;
70
- if (positionArr.length > 1) {
71
- positionArr.splice(0, 1);
72
- location = positionArr.join("").toLowerCase();
73
- } else {
74
- location = "center";
75
- }
70
+ const { direction, location = "center" } = parsePlacement(placement);
76
71
  const childrenRef = useRef();
77
72
  const [openStatus, setOpenStatus] = useState(defaultOpen);
78
73
  const [arrowDirection, setArrowDirection] = useState(direction);
@@ -107,10 +102,15 @@ const Popover = /* @__PURE__ */ React.forwardRef((props, ref) => {
107
102
  hidePopover(event);
108
103
  };
109
104
  const onRootElementMouted = throttle(() => {
105
+ const {
106
+ direction: newParsedDirection,
107
+ location: newParsedLocation = "center"
108
+ } = parsePlacement(placement);
110
109
  const result = getStylesAndLocation({
111
110
  childrenRef,
112
- arrowDirection,
113
- arrowLocation,
111
+ arrowDirection: newParsedDirection,
112
+ arrowLocation: newParsedLocation,
113
+ offsetSpacing,
114
114
  selector: `[data-id="tt_${ttId}"]`
115
115
  });
116
116
  if (!result)
@@ -25,6 +25,10 @@ export type PopoverProps<D extends React.ElementType = 'div', P = {}> = Override
25
25
  * @default false
26
26
  */
27
27
  hideArrow?: boolean;
28
+ /**
29
+ * 用于控制浮层和目标元素偏移量
30
+ */
31
+ offsetSpacing?: number;
28
32
  /**
29
33
  * 气泡框位置
30
34
  * @default 'top'
@@ -3,11 +3,6 @@
3
3
  --mini-width: var(--bui-select-min-width, 100px);
4
4
  --font-size: var(--bui-select-font-size, var(--bui-title-size-3));
5
5
  --padding: var(--bui-select-selector-container, 0 14px);
6
- --option-container-padding: var(--bui-select-option-container-padding, 3px 0);
7
- --option-container-margin-top: var(--bui-select-option-margin-top, 6px);
8
- --option-padding: var(--bui-select-option-padding, 0 14px);
9
- --option-margin: var(--bui-select-option-margin, 0 3px);
10
- --option-height: var(--bui-select-option-height, 27px);
11
6
  position: relative;
12
7
  cursor: pointer;
13
8
  height: var(--height);
@@ -16,8 +11,8 @@
16
11
  border-radius: 5px;
17
12
  background-color: var(--bui-color-bg-view);
18
13
  font-family: var(--bui-font-family);
14
+ -webkit-tap-highlight-color: transparent;
19
15
  }
20
- .bui-select:active,
21
16
  .bui-select-active {
22
17
  box-shadow: 0 0 0 2px var(--bui-color-bg-default);
23
18
  }
@@ -32,6 +27,7 @@
32
27
  height: 0;
33
28
  border: 0;
34
29
  opacity: 0;
30
+ pointer-events: none;
35
31
  }
36
32
  .bui-select-placeholder {
37
33
  color: var(--bui-color-fg-disabled);
@@ -55,20 +51,32 @@
55
51
  top: 100%;
56
52
  left: 0;
57
53
  width: 100%;
58
- z-index: var(--bui-z-index-dropdown);
59
- margin-top: var(--option-container-margin-top);
54
+ font-size: var(--bui-select-font-size, var(--bui-title-size-3));
55
+ z-index: var(--bui-z-index-tooltip);
60
56
  border-radius: 3px;
61
57
  background-color: var(--bui-color-bg-view);
62
58
  padding: 2px;
63
59
  overflow: hidden;
64
60
  }
61
+ .bui-select-option-container-top {
62
+ margin-top: -6px;
63
+ }
64
+ .bui-select-option-container-bottom {
65
+ margin-top: 6px;
66
+ }
67
+ .bui-select-option-container-hide {
68
+ pointer-events: none;
69
+ }
65
70
  .bui-select-option-main {
66
71
  border-radius: 3px;
67
- padding: var(--option-container-padding);
72
+ padding: var(--bui-select-option-container-padding, 3px 0);
68
73
  box-shadow: 0 0 0 2px var(--bui-color-bg-default);
69
74
  overflow: hidden;
70
75
  }
71
76
  .bui-select-option {
77
+ --option-padding: var(--bui-select-option-padding, 0 14px);
78
+ --option-margin: var(--bui-select-option-margin, 0 3px);
79
+ --option-height: var(--bui-select-option-height, 27px);
72
80
  display: flex;
73
81
  align-items: center;
74
82
  height: var(--option-height);
@@ -30,15 +30,24 @@ var __objRest = (source, exclude) => {
30
30
  return target;
31
31
  };
32
32
  import { CaretDownIcon, CaretUpIcon } from "@bifrostui/icons";
33
- import { useValue } from "@bifrostui/utils";
33
+ import {
34
+ getStylesAndLocation,
35
+ isMini,
36
+ throttle,
37
+ useForkRef,
38
+ useUniqueId,
39
+ useValue
40
+ } from "@bifrostui/utils";
34
41
  import clsx from "clsx";
35
- import React, { useEffect, useMemo, useState } from "react";
42
+ import React, { useEffect, useMemo, useRef, useState } from "react";
36
43
  import Fade from "../Fade";
37
44
  import Slide from "../Slide";
38
45
  import BuiSelectContext from "./selectContext";
39
46
  import Backdrop from "../Backdrop";
47
+ import Portal from "../Portal";
40
48
  import "./Select.css";
41
49
  const prefixCls = "bui-select";
50
+ const defaultPlacement = "bottom";
42
51
  const Select = /* @__PURE__ */ React.forwardRef((props, ref) => {
43
52
  const _a = props, {
44
53
  className,
@@ -53,6 +62,7 @@ const Select = /* @__PURE__ */ React.forwardRef((props, ref) => {
53
62
  placeholder,
54
63
  icon,
55
64
  open,
65
+ scrollContainer,
56
66
  onChange,
57
67
  onClose,
58
68
  onOpen,
@@ -70,6 +80,7 @@ const Select = /* @__PURE__ */ React.forwardRef((props, ref) => {
70
80
  "placeholder",
71
81
  "icon",
72
82
  "open",
83
+ "scrollContainer",
73
84
  "onChange",
74
85
  "onClose",
75
86
  "onOpen",
@@ -80,19 +91,49 @@ const Select = /* @__PURE__ */ React.forwardRef((props, ref) => {
80
91
  defaultValue,
81
92
  onChange
82
93
  });
83
- const [isOpen, setIsOpen] = useState(false);
94
+ const [internalOpen, setInternalOpen] = useState(false);
84
95
  const [renderValue, setRenderValue] = useState("");
85
- const defaultIcon = isOpen ? /* @__PURE__ */ React.createElement(CaretUpIcon, { className: `${prefixCls}-selector-icon`, htmlColor: "#9c9ca5" }) : /* @__PURE__ */ React.createElement(
86
- CaretDownIcon,
87
- {
88
- className: `${prefixCls}-selector-icon`,
89
- htmlColor: "#9c9ca5"
96
+ const [placement, setPlacement] = useState(defaultPlacement);
97
+ const [optionStyle, setOptionStyle] = useState({});
98
+ const isOpen = open !== void 0 ? open : internalOpen;
99
+ const locatorRef = useRef(null);
100
+ const rootRef = useForkRef(ref, locatorRef);
101
+ const ttId = useUniqueId();
102
+ const dataId = `${prefixCls}-tt-${ttId}`;
103
+ const updateOptionStyle = throttle(() => {
104
+ const curScrollRoot = scrollContainer();
105
+ if (!isMini && curScrollRoot) {
106
+ const result = getStylesAndLocation({
107
+ scrollRoot: curScrollRoot,
108
+ childrenRef: locatorRef,
109
+ arrowDirection: defaultPlacement,
110
+ arrowLocation: "none",
111
+ selector: `[data-id="${dataId}"]`,
112
+ offsetSpacing: 0
113
+ });
114
+ if (!result)
115
+ return;
116
+ const { styles, childrenStyle, newArrowDirection } = result;
117
+ setPlacement(newArrowDirection);
118
+ setOptionStyle(__spreadProps(__spreadValues({}, styles), { width: childrenStyle.width }));
90
119
  }
91
- );
120
+ }, 100);
121
+ const changeOpen = (newOpen) => {
122
+ if (newOpen) {
123
+ updateOptionStyle();
124
+ setTimeout(() => {
125
+ setInternalOpen(newOpen);
126
+ onOpen == null ? void 0 : onOpen();
127
+ }, 100);
128
+ } else {
129
+ onClose == null ? void 0 : onClose();
130
+ setInternalOpen(newOpen);
131
+ }
132
+ };
92
133
  const handleSelectClick = (e) => {
93
134
  if (disabled)
94
135
  return;
95
- setIsOpen(!isOpen);
136
+ changeOpen(!isOpen);
96
137
  if (typeof onClick === "function")
97
138
  onClick(e);
98
139
  };
@@ -103,28 +144,70 @@ const Select = /* @__PURE__ */ React.forwardRef((props, ref) => {
103
144
  } else {
104
145
  onChange == null ? void 0 : onChange(e, { value: optionValue });
105
146
  }
106
- setIsOpen(false);
147
+ changeOpen(false);
107
148
  };
108
- const handleBackdropTouchStart = () => {
109
- if (isOpen) {
110
- setIsOpen(false);
111
- }
149
+ const handleBackdropClick = () => {
150
+ changeOpen(false);
112
151
  };
113
152
  const selectContext = useMemo(
114
153
  () => ({ selectValue, setRenderValue, handleOptionClick }),
115
154
  [selectValue, onChange, setRenderValue]
116
155
  );
117
156
  useEffect(() => {
118
- if (open !== void 0)
119
- setIsOpen(open);
120
- }, [open]);
121
- useEffect(() => {
122
- if (isOpen) {
123
- onOpen == null ? void 0 : onOpen();
124
- } else {
125
- onClose == null ? void 0 : onClose();
157
+ if (!isMini) {
158
+ window.addEventListener("resize", updateOptionStyle);
159
+ return () => {
160
+ window.removeEventListener("resize", updateOptionStyle);
161
+ };
162
+ }
163
+ }, []);
164
+ const defaultIcon = isOpen ? /* @__PURE__ */ React.createElement(CaretUpIcon, { className: `${prefixCls}-selector-icon`, htmlColor: "#9c9ca5" }) : /* @__PURE__ */ React.createElement(
165
+ CaretDownIcon,
166
+ {
167
+ className: `${prefixCls}-selector-icon`,
168
+ htmlColor: "#9c9ca5"
126
169
  }
127
- }, [isOpen]);
170
+ );
171
+ const renderOptions = () => {
172
+ var _a2;
173
+ return /* @__PURE__ */ React.createElement(
174
+ Fade,
175
+ {
176
+ in: isOpen,
177
+ timeout: {
178
+ enter: 150,
179
+ exit: 150
180
+ }
181
+ },
182
+ /* @__PURE__ */ React.createElement(
183
+ "div",
184
+ {
185
+ className: clsx(
186
+ `${prefixCls}-option-container`,
187
+ ...((_a2 = className == null ? void 0 : className.split(/\s+/)) == null ? void 0 : _a2.map((cls) => `${cls}-option-container`)) || [],
188
+ `${prefixCls}-option-container-${placement}`,
189
+ {
190
+ [`${prefixCls}-option-container-hide`]: !isOpen
191
+ }
192
+ ),
193
+ "data-id": dataId,
194
+ style: optionStyle
195
+ },
196
+ /* @__PURE__ */ React.createElement(
197
+ Slide,
198
+ {
199
+ in: isOpen,
200
+ direction: placement === "bottom" ? "down" : "up",
201
+ timeout: {
202
+ enter: 150,
203
+ exit: 150
204
+ }
205
+ },
206
+ /* @__PURE__ */ React.createElement("div", { className: clsx(`${prefixCls}-option-main`) }, children)
207
+ )
208
+ )
209
+ );
210
+ };
128
211
  return /* @__PURE__ */ React.createElement(BuiSelectContext.Provider, { value: selectContext }, /* @__PURE__ */ React.createElement(
129
212
  "div",
130
213
  __spreadProps(__spreadValues({
@@ -132,7 +215,7 @@ const Select = /* @__PURE__ */ React.forwardRef((props, ref) => {
132
215
  [`${prefixCls}-disabled`]: disabled,
133
216
  [`${prefixCls}-active`]: isOpen
134
217
  }),
135
- ref
218
+ ref: rootRef
136
219
  }, others), {
137
220
  onClick: handleSelectClick
138
221
  }),
@@ -149,34 +232,14 @@ const Select = /* @__PURE__ */ React.forwardRef((props, ref) => {
149
232
  })
150
233
  })
151
234
  ), icon || defaultIcon),
152
- /* @__PURE__ */ React.createElement(
153
- Fade,
154
- {
155
- in: isOpen,
156
- timeout: {
157
- enter: 150,
158
- exit: 150
159
- }
160
- },
161
- /* @__PURE__ */ React.createElement("div", { className: clsx(`${prefixCls}-option-container`) }, /* @__PURE__ */ React.createElement(
162
- Slide,
163
- {
164
- in: isOpen,
165
- timeout: {
166
- enter: 150,
167
- exit: 150
168
- }
169
- },
170
- /* @__PURE__ */ React.createElement("div", { className: clsx(`${prefixCls}-option-main`) }, children)
171
- ))
172
- )
173
- ), /* @__PURE__ */ React.createElement(
235
+ isMini && renderOptions()
236
+ ), !isMini && /* @__PURE__ */ React.createElement(Portal, { onRootElementMouted: updateOptionStyle }, renderOptions()), /* @__PURE__ */ React.createElement(
174
237
  Backdrop,
175
238
  __spreadProps(__spreadValues({
176
239
  open: isOpen,
177
240
  invisible: true,
178
- onTouchStart: handleBackdropTouchStart,
179
- onClick: handleBackdropTouchStart
241
+ onTouchStart: handleBackdropClick,
242
+ onClick: handleBackdropClick
180
243
  }, BackdropProps), {
181
244
  className: clsx(`${prefixCls}-backdrop`, {
182
245
  [BackdropProps == null ? void 0 : BackdropProps.className]: BackdropProps == null ? void 0 : BackdropProps.className
@@ -186,7 +249,10 @@ const Select = /* @__PURE__ */ React.forwardRef((props, ref) => {
186
249
  });
187
250
  Select.displayName = "BuiSelect";
188
251
  Select.defaultProps = {
189
- defaultValue: ""
252
+ defaultValue: "",
253
+ scrollContainer: () => {
254
+ return isMini ? null : document.body;
255
+ }
190
256
  };
191
257
  var Select_default = Select;
192
258
  export {
@@ -76,6 +76,12 @@ export type SelectProps<D extends React.ElementType = 'div', P = {}> = OverrideP
76
76
  * 是否展开下拉框
77
77
  */
78
78
  open?: boolean;
79
+ /**
80
+ * 滚动容器
81
+ * 下拉框元素和children将会被append到scrollContainer中
82
+ * 默认是页面的根节点
83
+ */
84
+ scrollContainer?: () => Element | null;
79
85
  /**
80
86
  * 自定义选中后展示的内容
81
87
  */
@@ -31,7 +31,19 @@ import React, { forwardRef } from "react";
31
31
  import "./TabPanel.css";
32
32
  const prefixCls = "bui-tabpanel";
33
33
  const TabPanel = forwardRef((props, ref) => {
34
- const _a = props, { className, children, value, index, keepMounted } = _a, others = __objRest(_a, ["className", "children", "value", "index", "keepMounted"]);
34
+ const _a = props, {
35
+ className,
36
+ children,
37
+ value,
38
+ index,
39
+ keepMounted = false
40
+ } = _a, others = __objRest(_a, [
41
+ "className",
42
+ "children",
43
+ "value",
44
+ "index",
45
+ "keepMounted"
46
+ ]);
35
47
  const keepActiveDom = keepMounted ? children : null;
36
48
  return /* @__PURE__ */ React.createElement(
37
49
  "div",
@@ -46,9 +58,6 @@ const TabPanel = forwardRef((props, ref) => {
46
58
  );
47
59
  });
48
60
  TabPanel.displayName = "BuiTabPanel";
49
- TabPanel.defaultProps = {
50
- keepMounted: false
51
- };
52
61
  var TabPanel_default = TabPanel;
53
62
  export {
54
63
  TabPanel_default as default
package/es/Tabs/Tabs.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import './Tabs.less';
3
2
  import { TabsProps } from './Tabs.types';
3
+ import './Tabs.less';
4
4
  declare const Tabs: React.ForwardRefExoticComponent<Omit<TabsProps<"div", {}>, "ref"> & React.RefAttributes<HTMLDivElement>>;
5
5
  export default Tabs;
package/es/Tabs/Tabs.js CHANGED
@@ -41,9 +41,9 @@ import React, {
41
41
  useState
42
42
  } from "react";
43
43
  import Tab from "./Tab";
44
- import "./Tabs.css";
45
44
  import { TabsContextProvider } from "./TabsContext";
46
45
  import bound from "./utils/bound";
46
+ import "./Tabs.css";
47
47
  const prefixCls = "bui-tabs";
48
48
  const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
49
49
  const _a = props, { children, className, value, tabs, align, onChange } = _a, others = __objRest(_a, ["children", "className", "value", "tabs", "align", "onChange"]);
@@ -62,16 +62,13 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
62
62
  const container = tabsRef.current;
63
63
  if (!container)
64
64
  return;
65
- const activeIndex = !!tabs.length && tabs.findIndex((item) => {
66
- var _a2;
67
- return item.index === (active || ((_a2 = tabs[0]) == null ? void 0 : _a2.index));
68
- });
65
+ const activeIndex = !!tabs.length && tabs.findIndex((item) => item.index === active);
69
66
  const activeLine = activeLineRef.current;
70
67
  if (!activeLine)
71
68
  return;
72
69
  let activeTab;
73
70
  if (tabs.length) {
74
- activeTab = container.childNodes[activeIndex + 1];
71
+ activeTab = activeIndex > -1 ? container.childNodes[activeIndex + 1] : void 0;
75
72
  } else {
76
73
  activeTab = [...container.childNodes].find((child) => {
77
74
  if (isMini) {
@@ -82,20 +79,26 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
82
79
  return [...child.classList].includes("bui-tab-active");
83
80
  });
84
81
  }
85
- if (!activeTab)
86
- return;
87
- const activeTabLeft = activeTab.offsetLeft;
88
- const activeTabWidth = activeTab.offsetWidth;
89
- const containerWidth = container.offsetWidth;
90
- const containerScrollWidth = container.scrollWidth;
91
- const activeLineWidth = activeLine.offsetWidth;
92
- const x = activeTabLeft + (activeTabWidth - activeLineWidth) / 2;
82
+ let activeTabLeft = 0;
83
+ let activeTabWidth = 0;
84
+ let containerWidth = 0;
85
+ let containerScrollWidth = 0;
86
+ let activeLineWidth = 0;
87
+ let x = 0;
88
+ if (activeTab) {
89
+ activeTabLeft = activeTab.offsetLeft;
90
+ activeTabWidth = activeTab.offsetWidth;
91
+ containerWidth = container.offsetWidth;
92
+ containerScrollWidth = container.scrollWidth;
93
+ activeLineWidth = activeLine.offsetWidth;
94
+ x = activeTabLeft + (activeTabWidth - activeLineWidth) / 2;
95
+ }
93
96
  setLineData({
94
97
  x,
95
98
  transitionInUse
96
99
  });
97
100
  const maxScrollDistance = containerScrollWidth - containerWidth;
98
- if (maxScrollDistance <= 0)
101
+ if (maxScrollDistance <= 0 || !activeTab)
99
102
  return;
100
103
  const nextScrollLeft = bound(
101
104
  activeTabLeft - (containerWidth - activeTabWidth) / 2,
@@ -107,8 +110,7 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
107
110
  }
108
111
  };
109
112
  useEffect(() => {
110
- const defaultIndex = safeValue();
111
- setActive(defaultIndex);
113
+ setActive(value);
112
114
  }, [value]);
113
115
  useLayoutEffect(() => {
114
116
  animate({ transitionInUse: false });
@@ -126,26 +128,6 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
126
128
  useDidMountEffect(() => {
127
129
  animate({ transitionInUse: true });
128
130
  }, [active, tabs, children]);
129
- const safeValue = () => {
130
- var _a2;
131
- let defaultIndex = value;
132
- const childs = React.Children.toArray(children);
133
- const hasSameChild = !!childs.length && childs.some(
134
- (child) => {
135
- var _a3;
136
- return React.isValidElement(child) && ((_a3 = child == null ? void 0 : child.props) == null ? void 0 : _a3.index) === value;
137
- }
138
- );
139
- if (!!tabs.length && !tabs.some((item) => item.index === value)) {
140
- defaultIndex = (_a2 = tabs[0]) == null ? void 0 : _a2.index;
141
- } else if (children && !hasSameChild) {
142
- const childNode = childs[0];
143
- if (React.isValidElement(childNode)) {
144
- defaultIndex = childNode.props.index;
145
- }
146
- }
147
- return defaultIndex;
148
- };
149
131
  const updateMask = useMemo(
150
132
  () => throttle(
151
133
  () => {
@@ -186,8 +168,7 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
186
168
  }
187
169
  };
188
170
  const providerValue = useMemo(() => {
189
- const v = safeValue();
190
- return { value: v, align, triggerChange: handleClick };
171
+ return { value, align, triggerChange: handleClick };
191
172
  }, [value, align, children, handleClick]);
192
173
  return /* @__PURE__ */ React.createElement("div", __spreadValues({ ref, className: clsx(prefixCls, className) }, others), /* @__PURE__ */ React.createElement(
193
174
  "div",
@@ -210,7 +191,7 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
210
191
  {
211
192
  ref: activeLineRef,
212
193
  className: clsx(`${prefixCls}-tabline`, {
213
- "bui-tabline-invisible": isMini
194
+ "bui-tabline-invisible": isMini || !lineData.x
214
195
  }),
215
196
  style: {
216
197
  transition: lineData.transitionInUse ? "transform 0.25s ease-in-out" : void 0,
@@ -31,6 +31,7 @@ import React, { useState, useRef, useEffect } from "react";
31
31
  import {
32
32
  getStylesAndLocation,
33
33
  triggerEventTransform,
34
+ parsePlacement,
34
35
  useUniqueId,
35
36
  throttle
36
37
  } from "@bifrostui/utils";
@@ -44,6 +45,7 @@ const Tooltip = /* @__PURE__ */ React.forwardRef((props, ref) => {
44
45
  children,
45
46
  title,
46
47
  defaultOpen,
48
+ offsetSpacing = 0,
47
49
  placement = "top",
48
50
  trigger = "click",
49
51
  onOpenChange,
@@ -54,21 +56,14 @@ const Tooltip = /* @__PURE__ */ React.forwardRef((props, ref) => {
54
56
  "children",
55
57
  "title",
56
58
  "defaultOpen",
59
+ "offsetSpacing",
57
60
  "placement",
58
61
  "trigger",
59
62
  "onOpenChange",
60
63
  "open"
61
64
  ]);
62
65
  const controlByUser = typeof open !== "undefined";
63
- const positionArr = placement.split(/([A-Z])/);
64
- const direction = positionArr[0];
65
- let location;
66
- if (positionArr.length > 1) {
67
- positionArr.splice(0, 1);
68
- location = positionArr.join("").toLowerCase();
69
- } else {
70
- location = "center";
71
- }
66
+ const { direction, location = "center" } = parsePlacement(placement);
72
67
  const childrenRef = useRef();
73
68
  const [openStatus, setOpenStatus] = useState(defaultOpen);
74
69
  const [arrowDirection, setArrowDirection] = useState(direction);
@@ -103,10 +98,15 @@ const Tooltip = /* @__PURE__ */ React.forwardRef((props, ref) => {
103
98
  hideTooltip(event);
104
99
  };
105
100
  const onRootElementMouted = throttle(() => {
101
+ const {
102
+ direction: newParsedDirection,
103
+ location: newParsedLocation = "center"
104
+ } = parsePlacement(placement);
106
105
  const result = getStylesAndLocation({
107
106
  childrenRef,
108
- arrowDirection,
109
- arrowLocation,
107
+ arrowDirection: newParsedDirection,
108
+ arrowLocation: newParsedLocation,
109
+ offsetSpacing,
110
110
  selector: `[data-id="tt_${ttId}"]`
111
111
  });
112
112
  if (!result)
@@ -16,6 +16,10 @@ export type TooltipProps<D extends React.ElementType = 'div', P = {}> = Override
16
16
  * 用于手动控制气泡浮层显隐
17
17
  */
18
18
  open?: boolean;
19
+ /**
20
+ * 用于控制气泡浮层和目标元素偏移量
21
+ */
22
+ offsetSpacing?: number;
19
23
  /**
20
24
  * 气泡框位置
21
25
  * @default 'top'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bifrostui/react",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "React components for building mobile application",
5
5
  "homepage": "http://bui.taopiaopiao.com",
6
6
  "license": "MIT",
@@ -33,10 +33,10 @@
33
33
  "clsx": "^1.2.1",
34
34
  "dayjs": "^1.11.7",
35
35
  "swiper": "^8.1.5",
36
- "@bifrostui/icons": "1.4.2",
37
- "@bifrostui/styles": "1.4.2",
38
- "@bifrostui/types": "1.4.2",
39
- "@bifrostui/utils": "1.4.2"
36
+ "@bifrostui/icons": "1.4.3",
37
+ "@bifrostui/styles": "1.4.3",
38
+ "@bifrostui/types": "1.4.3",
39
+ "@bifrostui/utils": "1.4.3"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@tarojs/components": "^3.0.0",