@baishuyun/ai-design 2.0.36 → 2.0.38
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @baishuyun/ai-design
|
|
2
2
|
|
|
3
|
+
## 2.0.38
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- bugfix
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @baishuyun/ai-feat-utils@2.0.34
|
|
10
|
+
- @baishuyun/types@3.0.31
|
|
11
|
+
|
|
12
|
+
## 2.0.37
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- 移动端优化
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
- @baishuyun/ai-feat-utils@2.0.33
|
|
19
|
+
|
|
3
20
|
## 2.0.36
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@baishuyun/ai-design",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.38",
|
|
4
4
|
"description": "AI 功能 UI 组件库 - 所有 AI 功能的 UI 表现唯一真相来源",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"tw-animate-css": "^1.4.0",
|
|
61
61
|
"vaul": "^1.1.2",
|
|
62
62
|
"zod": "^4.1.13",
|
|
63
|
-
"@baishuyun/ai-feat-utils": "2.0.
|
|
64
|
-
"@baishuyun/types": "3.0.
|
|
63
|
+
"@baishuyun/ai-feat-utils": "2.0.34",
|
|
64
|
+
"@baishuyun/types": "3.0.31"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"react": "^19.0.0",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"vite": "^5.1.4",
|
|
85
85
|
"vite-plugin-dts": "^4.5.4",
|
|
86
86
|
"@baishuyun/tailwind-config": "3.0.9",
|
|
87
|
-
"@baishuyun/types": "3.0.
|
|
87
|
+
"@baishuyun/types": "3.0.31",
|
|
88
88
|
"@baishuyun/typescript-config": "2.0.9"
|
|
89
89
|
},
|
|
90
90
|
"keywords": [],
|
|
@@ -28,8 +28,10 @@ function createFieldTagDom(label: string): HTMLSpanElement {
|
|
|
28
28
|
|
|
29
29
|
function resolveFieldWidgetInfo(
|
|
30
30
|
fields: IField[],
|
|
31
|
-
|
|
31
|
+
fullKey: string,
|
|
32
32
|
): { widgetName: string; label: string } | undefined {
|
|
33
|
+
const key = fullKey.replace('virtual.', '');
|
|
34
|
+
|
|
33
35
|
const dotIndex = key.indexOf('.');
|
|
34
36
|
if (dotIndex > 0) {
|
|
35
37
|
const parentName = key.substring(0, dotIndex);
|
|
@@ -41,13 +43,13 @@ function resolveFieldWidgetInfo(
|
|
|
41
43
|
'widget' in item && item.widget?.widgetName === childName,
|
|
42
44
|
);
|
|
43
45
|
if (child) {
|
|
44
|
-
return { widgetName:
|
|
46
|
+
return { widgetName: fullKey, label: child.label };
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
} else {
|
|
48
50
|
const field = fields.find((f) => f.widget?.widgetName === key);
|
|
49
51
|
if (field) {
|
|
50
|
-
return { widgetName:
|
|
52
|
+
return { widgetName: fullKey, label: field.label };
|
|
51
53
|
}
|
|
52
54
|
}
|
|
53
55
|
return undefined;
|
|
@@ -63,7 +65,11 @@ function addFieldToCM(
|
|
|
63
65
|
cm.replaceSelection('${' + widgetName + '}');
|
|
64
66
|
const to = cm.getCursor();
|
|
65
67
|
|
|
66
|
-
const
|
|
68
|
+
const isVirtual = widgetName?.includes("virtual");
|
|
69
|
+
|
|
70
|
+
const label = isVirtual ? `触发行.${displayLabel}` : displayLabel;
|
|
71
|
+
|
|
72
|
+
const tagNode = createFieldTagDom(label);
|
|
67
73
|
tagNode.setAttribute('data-field-key', widgetName);
|
|
68
74
|
|
|
69
75
|
cm.markText(from, to, {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FC, useCallback, useEffect, useRef } from 'react';
|
|
1
|
+
import { FC, useCallback, useEffect, useLayoutEffect, useRef } from 'react';
|
|
2
2
|
import { useResizableWidth } from '../hooks/use-resizable-width';
|
|
3
3
|
import { useColumnAppear } from '../hooks/use-column-appear';
|
|
4
4
|
import classNames from 'classnames';
|
|
@@ -57,6 +57,11 @@ export const OfficeContainer: FC<IOfficeContainerProps> = ({
|
|
|
57
57
|
const transitioningRef = useRef(false);
|
|
58
58
|
const mountRef = useRef(true);
|
|
59
59
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
60
|
+
const onResizeRef = useRef(onResize);
|
|
61
|
+
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
onResizeRef.current = onResize;
|
|
64
|
+
}, [onResize]);
|
|
60
65
|
|
|
61
66
|
const { width, handleMouseDown, isDragging } = useResizableWidth({
|
|
62
67
|
range: activeRange,
|
|
@@ -107,24 +112,43 @@ export const OfficeContainer: FC<IOfficeContainerProps> = ({
|
|
|
107
112
|
return `calc(100% - ${width}px)`;
|
|
108
113
|
}, [hideLeftCol, isLeftFullscreen, isRightFullscreen, isRightResizable, width]);
|
|
109
114
|
|
|
110
|
-
|
|
115
|
+
const getTargetColWidths = useCallback((): [number, number] => {
|
|
116
|
+
const containerWidth = containerRef.current?.offsetWidth ?? 0;
|
|
117
|
+
|
|
118
|
+
if (isLeftFullscreen) return [containerWidth, 0];
|
|
119
|
+
if (isRightFullscreen) return [0, containerWidth];
|
|
120
|
+
|
|
121
|
+
if (hideLeftCol) {
|
|
122
|
+
if (isRightResizable) return [0, width];
|
|
123
|
+
return [0, Math.max(containerWidth - width, 0)];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (isRightResizable) {
|
|
127
|
+
return [Math.max(containerWidth - width, 0), width];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return [width, Math.max(containerWidth - width, 0)];
|
|
131
|
+
}, [hideLeftCol, isLeftFullscreen, isRightFullscreen, isRightResizable, width]);
|
|
132
|
+
|
|
133
|
+
useLayoutEffect(() => {
|
|
111
134
|
if (!onResize || transitioningRef.current) return;
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
onResize(leftW, rightW);
|
|
116
|
-
});
|
|
117
|
-
return () => cancelAnimationFrame(raf);
|
|
135
|
+
const leftW = leftColRef.current?.offsetWidth ?? 0;
|
|
136
|
+
const rightW = rightColRef.current?.offsetWidth ?? 0;
|
|
137
|
+
onResize(leftW, rightW);
|
|
118
138
|
}, [width, fullscreenPart, hideLeftCol, isRightResizable, onResize]);
|
|
119
139
|
|
|
120
140
|
// Set guard when fullscreen/hide triggers CSS transitions. Skip mount.
|
|
121
|
-
|
|
141
|
+
// Immediately report the final target widths so the host portal can size
|
|
142
|
+
// itself before paint, instead of waiting for the width transition to end.
|
|
143
|
+
useLayoutEffect(() => {
|
|
122
144
|
if (mountRef.current) {
|
|
123
145
|
mountRef.current = false;
|
|
124
146
|
return;
|
|
125
147
|
}
|
|
126
148
|
transitioningRef.current = true;
|
|
127
|
-
|
|
149
|
+
const [leftW, rightW] = getTargetColWidths();
|
|
150
|
+
onResizeRef.current?.(leftW, rightW);
|
|
151
|
+
}, [fullscreenPart, hideLeftCol, getTargetColWidths]);
|
|
128
152
|
|
|
129
153
|
// Fire onResize after CSS width transitions complete
|
|
130
154
|
useEffect(() => {
|
|
@@ -20,7 +20,7 @@ const PopoverContent = React.forwardRef<
|
|
|
20
20
|
PopoverContentProps
|
|
21
21
|
>(
|
|
22
22
|
(
|
|
23
|
-
{ className, align = 'start', sideOffset = 4, portalContainer, style, onWheel, ...props },
|
|
23
|
+
{ className, align = 'start', sideOffset = 4, portalContainer, style, onWheel, onOpenAutoFocus, ...props },
|
|
24
24
|
ref
|
|
25
25
|
) => {
|
|
26
26
|
const handleWheel = portalContainer
|
|
@@ -45,6 +45,12 @@ const PopoverContent = React.forwardRef<
|
|
|
45
45
|
}
|
|
46
46
|
: onWheel;
|
|
47
47
|
|
|
48
|
+
// 默认阻止 Radix 打开浮层时自动聚焦内部第一个可聚焦元素(通常是搜索框),
|
|
49
|
+
// 移动端会因此唤起软键盘,不是期望的交互;调用方仍可显式传 onOpenAutoFocus 覆盖
|
|
50
|
+
const handleOpenAutoFocus = onOpenAutoFocus ?? ((event: Event) => {
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
});
|
|
53
|
+
|
|
48
54
|
return (
|
|
49
55
|
<PopoverPrimitive.Portal container={portalContainer ?? undefined}>
|
|
50
56
|
<PopoverPrimitive.Content
|
|
@@ -52,6 +58,7 @@ const PopoverContent = React.forwardRef<
|
|
|
52
58
|
align={align}
|
|
53
59
|
sideOffset={sideOffset}
|
|
54
60
|
onWheel={handleWheel}
|
|
61
|
+
onOpenAutoFocus={handleOpenAutoFocus}
|
|
55
62
|
className={cn(
|
|
56
63
|
'z-50 w-60 rounded-[8px] bg-white p-1 text-[#121111] shadow-[0px_6px_16px_rgba(0,0,0,0.06)] outline-none',
|
|
57
64
|
'data-[state=open]:animate-in data-[state=closed]:animate-out',
|