@arronqzy/react-view 1.0.19 → 1.0.21
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/styles.css +45 -0
- package/package.json +8 -8
- package/src/panel/ReactViewPanel.tsx +20 -18
- package/src/panel/ai/applyAssistantAction.ts +1 -0
- package/src/panel/components/ElementsLayer.tsx +67 -16
- package/src/panel/components/MaterialSidebar.tsx +18 -11
- package/src/panel/components/PanelConfigSidebar.tsx +139 -1
- package/src/panel/components/WorkspaceConfigSidebar.tsx +1 -0
- package/src/panel/hooks/usePanelElements.ts +10 -4
- package/src/panel/library/capture-preview-snapshot.ts +538 -38
- package/src/panel/library/preview-snapshot.ts +25 -11
- package/src/panel/types.ts +4 -0
- package/src/panel/utils/panelElementDefaults.ts +10 -0
- package/src/panel/utils/panelElementNodes.ts +5 -3
- package/src/panel/utils/viewportPlacement.ts +73 -0
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
resolvePreviewLayerElements,
|
|
6
6
|
} from "../utils/panelStateIO";
|
|
7
7
|
import {
|
|
8
|
+
capturePreviewLayerSnapshot,
|
|
8
9
|
capturePreviewSceneElement,
|
|
9
10
|
scaleDataUrl,
|
|
10
11
|
type CapturePreviewSceneOptions,
|
|
@@ -223,16 +224,29 @@ export async function getPreviewSnapshot(
|
|
|
223
224
|
export async function captureEditorPreviewSnapshot(
|
|
224
225
|
options: BuildEditorPreviewSnapshotSceneOptions & GetPreviewSnapshotOptions
|
|
225
226
|
): Promise<string | null> {
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
227
|
+
const retryCount = options.retryCount ?? 0;
|
|
228
|
+
const layerElements = resolvePreviewLayerElements(
|
|
229
|
+
options.allElements,
|
|
230
|
+
options.layers,
|
|
231
|
+
options.activeLayerId
|
|
232
|
+
);
|
|
233
|
+
if (!layerElements.length) return null;
|
|
234
|
+
|
|
235
|
+
const mountedCount = layerElements.filter((el) =>
|
|
236
|
+
Boolean(options.canvasRoot?.querySelector(`[data-element-id="${el.id}"]`))
|
|
237
|
+
).length;
|
|
238
|
+
if (mountedCount < layerElements.length && retryCount < 20) {
|
|
239
|
+
await new Promise((resolve) => window.setTimeout(resolve, 80));
|
|
240
|
+
return captureEditorPreviewSnapshot({ ...options, retryCount: retryCount + 1 });
|
|
237
241
|
}
|
|
242
|
+
|
|
243
|
+
return capturePreviewLayerSnapshot({
|
|
244
|
+
canvasRoot: options.canvasRoot,
|
|
245
|
+
elements: layerElements,
|
|
246
|
+
backgroundColor: options.backgroundColor,
|
|
247
|
+
maxWidth: options.maxWidth,
|
|
248
|
+
maxHeight: options.maxHeight,
|
|
249
|
+
mimeType: options.mimeType,
|
|
250
|
+
quality: options.quality,
|
|
251
|
+
});
|
|
238
252
|
}
|
package/src/panel/types.ts
CHANGED
|
@@ -54,6 +54,8 @@ export type PanelElementStyle = {
|
|
|
54
54
|
|
|
55
55
|
export type ReferenceCopyMode = "shallow" | "deep";
|
|
56
56
|
|
|
57
|
+
export type ViewportOverflowMode = "scroll-x" | "scroll-y" | "scroll" | "clip";
|
|
58
|
+
|
|
57
59
|
import type { PanelTableConfig } from "@arronqzy/view-table";
|
|
58
60
|
import type { Scene3dConfig } from "@arronqzy/view-scene3d";
|
|
59
61
|
|
|
@@ -83,6 +85,8 @@ export type PanelElement = {
|
|
|
83
85
|
gridPadding?: number;
|
|
84
86
|
gridSnapThreshold?: number;
|
|
85
87
|
parentGridId?: string;
|
|
88
|
+
/** 视窗节点:只显示自身尺寸内的引用图层内容,超出部分滚动或裁剪 */
|
|
89
|
+
viewportOverflow?: ViewportOverflowMode;
|
|
86
90
|
gridSlotIndex?: number;
|
|
87
91
|
gridColSpan?: number;
|
|
88
92
|
gridRowSpan?: number;
|
|
@@ -17,6 +17,7 @@ const DEFAULT_NODE_NAME_KEYS: Record<string, string> = {
|
|
|
17
17
|
funnel: "panel.defaults.funnel",
|
|
18
18
|
text: "panel.defaults.text",
|
|
19
19
|
grid: "panel.defaults.grid",
|
|
20
|
+
viewport: "panel.defaults.viewport",
|
|
20
21
|
image: "panel.defaults.image",
|
|
21
22
|
video: "panel.defaults.video",
|
|
22
23
|
audio: "panel.defaults.audio",
|
|
@@ -70,6 +71,8 @@ export function getDefaultSizeByMaterial(materialType: string) {
|
|
|
70
71
|
return { width: 180, height: 120 };
|
|
71
72
|
case "grid":
|
|
72
73
|
return { width: 320, height: 220 };
|
|
74
|
+
case "viewport":
|
|
75
|
+
return { width: 360, height: 240 };
|
|
73
76
|
case "image":
|
|
74
77
|
return { width: 220, height: 140 };
|
|
75
78
|
case "video":
|
|
@@ -141,6 +144,13 @@ export function getDefaultGridConfig(materialType: string) {
|
|
|
141
144
|
} as const;
|
|
142
145
|
}
|
|
143
146
|
|
|
147
|
+
export function getDefaultViewportConfig(materialType: string) {
|
|
148
|
+
if (materialType !== "viewport") return {};
|
|
149
|
+
return {
|
|
150
|
+
viewportOverflow: "clip" as const,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
144
154
|
export function getDefaultChartConfig(
|
|
145
155
|
materialType: string,
|
|
146
156
|
t: TranslateFn = tFallback
|
|
@@ -26,9 +26,11 @@ export function buildDeepReferenceSnapshot(
|
|
|
26
26
|
const layerNodes = allElements.filter((el) => el.layerId === layerId);
|
|
27
27
|
return layerNodes.map((el) => {
|
|
28
28
|
const cloned = clonePanelElement(el);
|
|
29
|
-
if (cloned.materialType === "reference"
|
|
30
|
-
cloned.
|
|
31
|
-
|
|
29
|
+
if (cloned.materialType === "reference" || cloned.materialType === "viewport") {
|
|
30
|
+
if (cloned.refLayerId) {
|
|
31
|
+
cloned.refCopyMode = "deep";
|
|
32
|
+
cloned.refSnapshot = buildDeepReferenceSnapshot(allElements, cloned.refLayerId, nextVisited);
|
|
33
|
+
}
|
|
32
34
|
}
|
|
33
35
|
return cloned;
|
|
34
36
|
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export const VIEWPORT_OVERFLOW_MODES = [
|
|
2
|
+
"scroll-x",
|
|
3
|
+
"scroll-y",
|
|
4
|
+
"scroll",
|
|
5
|
+
"clip",
|
|
6
|
+
] as const;
|
|
7
|
+
|
|
8
|
+
export type ViewportOverflowMode = (typeof VIEWPORT_OVERFLOW_MODES)[number];
|
|
9
|
+
|
|
10
|
+
export const DEFAULT_VIEWPORT_OVERFLOW: ViewportOverflowMode = "clip";
|
|
11
|
+
|
|
12
|
+
export function isViewportOverflowMode(
|
|
13
|
+
value: unknown
|
|
14
|
+
): value is ViewportOverflowMode {
|
|
15
|
+
return (
|
|
16
|
+
value === "scroll-x" ||
|
|
17
|
+
value === "scroll-y" ||
|
|
18
|
+
value === "scroll" ||
|
|
19
|
+
value === "clip"
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function normalizeViewportOverflow(
|
|
24
|
+
value: unknown
|
|
25
|
+
): ViewportOverflowMode {
|
|
26
|
+
return isViewportOverflowMode(value) ? value : DEFAULT_VIEWPORT_OVERFLOW;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function viewportOverflowStyle(mode: ViewportOverflowMode): {
|
|
30
|
+
overflowX: "hidden" | "auto";
|
|
31
|
+
overflowY: "hidden" | "auto";
|
|
32
|
+
} {
|
|
33
|
+
switch (mode) {
|
|
34
|
+
case "scroll-x":
|
|
35
|
+
return { overflowX: "auto", overflowY: "hidden" };
|
|
36
|
+
case "scroll-y":
|
|
37
|
+
return { overflowX: "hidden", overflowY: "auto" };
|
|
38
|
+
case "scroll":
|
|
39
|
+
return { overflowX: "auto", overflowY: "auto" };
|
|
40
|
+
default:
|
|
41
|
+
return { overflowX: "hidden", overflowY: "hidden" };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function isViewportNode(
|
|
46
|
+
el: { materialType?: string } | undefined
|
|
47
|
+
): boolean {
|
|
48
|
+
return el?.materialType === "viewport";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** 引用节点与视窗节点都通过选择图层来预览内容 */
|
|
52
|
+
export function isLayerPreviewNode(
|
|
53
|
+
el: { materialType?: string } | undefined
|
|
54
|
+
): boolean {
|
|
55
|
+
return el?.materialType === "reference" || el?.materialType === "viewport";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 视窗按自身宽高开窗;预览里节点会被整体拉满视口,
|
|
60
|
+
* 内部引用内容必须用同一套缩放,滚动比例才和编辑态一致。
|
|
61
|
+
*/
|
|
62
|
+
export function viewportWindowContentScale(
|
|
63
|
+
current: { id: string; width: number; height: number },
|
|
64
|
+
originals: ReadonlyArray<{ id: string; width: number; height: number }>
|
|
65
|
+
): { scaleX: number; scaleY: number } {
|
|
66
|
+
const original = originals.find((n) => n.id === current.id);
|
|
67
|
+
const ow = Math.max(1, original?.width ?? current.width);
|
|
68
|
+
const oh = Math.max(1, original?.height ?? current.height);
|
|
69
|
+
return {
|
|
70
|
+
scaleX: Math.max(1, current.width) / ow,
|
|
71
|
+
scaleY: Math.max(1, current.height) / oh,
|
|
72
|
+
};
|
|
73
|
+
}
|