@arronqzy/react-view 1.0.20 → 1.0.22
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 +5 -5
- package/readme.md +6 -1
- package/src/panel/I18nRoot.tsx +14 -2
- package/src/panel/ReactViewOnlinePreview.tsx +29 -18
- package/src/panel/ReactViewPanel.tsx +65 -59
- 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/hooks/useWorkspaceProjects.ts +112 -34
- package/src/panel/index.tsx +15 -1
- package/src/panel/library/capture-preview-snapshot.ts +4 -2
- package/src/panel/library/parse-workspace-data.ts +142 -0
- package/src/panel/library/workspace-project-cache.ts +13 -4
- package/src/panel/library/workspace-project-db.ts +24 -13
- package/src/panel/library/workspace-project-sync.ts +17 -6
- package/src/panel/types.ts +4 -0
- package/src/panel/utils/outputScale.ts +9 -4
- package/src/panel/utils/panelElementDefaults.ts +10 -0
- package/src/panel/utils/panelElementNodes.ts +5 -3
- package/src/panel/utils/panelStateIO.ts +18 -0
- package/src/panel/utils/viewportPlacement.ts +73 -0
|
@@ -6,6 +6,12 @@ import { buildChartOption, CHART_TYPES } from "../utils/chartOptionBuilder";
|
|
|
6
6
|
import { PREVIEW_LAYOUT_EVENT } from "../utils/panelStateIO";
|
|
7
7
|
import { TableNodeContent, type TableCellActionHandler } from "./table/TableNodeContent";
|
|
8
8
|
import { comparePanelElementsPaintOrder } from "../utils/gridPlacement";
|
|
9
|
+
import {
|
|
10
|
+
isViewportNode,
|
|
11
|
+
normalizeViewportOverflow,
|
|
12
|
+
viewportOverflowStyle,
|
|
13
|
+
viewportWindowContentScale,
|
|
14
|
+
} from "../utils/viewportPlacement";
|
|
9
15
|
import { cssTextLineHeight, cssTextAlignStyle } from "../utils/panelElementDefaults";
|
|
10
16
|
import { mergeScene3dConfig } from "@arronqzy/view-scene3d";
|
|
11
17
|
import { Scene3dNodeContent } from "@arronqzy/view-scene3d/react";
|
|
@@ -724,18 +730,30 @@ function ReferenceNodeContent({
|
|
|
724
730
|
|
|
725
731
|
const innerW = Math.max(1, element.width);
|
|
726
732
|
const innerH = Math.max(1, element.height);
|
|
727
|
-
const
|
|
728
|
-
const
|
|
729
|
-
|
|
733
|
+
const windowFit = isViewportNode(element);
|
|
734
|
+
const windowScale = windowFit
|
|
735
|
+
? viewportWindowContentScale(element, allElements)
|
|
736
|
+
: { scaleX: 1, scaleY: 1 };
|
|
737
|
+
const scaleX = windowFit
|
|
738
|
+
? windowScale.scaleX
|
|
739
|
+
: Math.max(0.05, Math.min(innerW / sourceWidth, innerH / sourceHeight));
|
|
740
|
+
const scaleY = windowFit
|
|
741
|
+
? windowScale.scaleY
|
|
742
|
+
: scaleX;
|
|
743
|
+
const mappedW = sourceWidth * scaleX;
|
|
744
|
+
const mappedH = sourceHeight * scaleY;
|
|
730
745
|
|
|
731
746
|
return {
|
|
732
747
|
minX,
|
|
733
748
|
minY,
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
749
|
+
scaleX,
|
|
750
|
+
scaleY,
|
|
751
|
+
sourceWidth: mappedW,
|
|
752
|
+
sourceHeight: mappedH,
|
|
753
|
+
offsetX: windowFit ? 0 : (innerW - mappedW) / 2,
|
|
754
|
+
offsetY: windowFit ? 0 : (innerH - mappedH) / 2,
|
|
737
755
|
};
|
|
738
|
-
}, [
|
|
756
|
+
}, [allElements, element, sourceNodes]);
|
|
739
757
|
|
|
740
758
|
if (!layout || sourceNodes.length === 0) {
|
|
741
759
|
const hintText = element.refLayerId ? t("panel.config.refLayerEmpty") : t("panel.config.selectRefLayer");
|
|
@@ -748,20 +766,50 @@ function ReferenceNodeContent({
|
|
|
748
766
|
);
|
|
749
767
|
}
|
|
750
768
|
|
|
769
|
+
const overflowCss = isViewportNode(element)
|
|
770
|
+
? viewportOverflowStyle(normalizeViewportOverflow(element.viewportOverflow))
|
|
771
|
+
: { overflowX: "hidden" as const, overflowY: "hidden" as const };
|
|
772
|
+
const canScroll =
|
|
773
|
+
isViewportNode(element) &&
|
|
774
|
+
(overflowCss.overflowX === "auto" || overflowCss.overflowY === "auto");
|
|
775
|
+
|
|
751
776
|
return (
|
|
752
|
-
<div
|
|
777
|
+
<div
|
|
778
|
+
className="relative h-full w-full"
|
|
779
|
+
style={{
|
|
780
|
+
overflowX: overflowCss.overflowX,
|
|
781
|
+
overflowY: overflowCss.overflowY,
|
|
782
|
+
pointerEvents: isViewportNode(element) ? "auto" : "none",
|
|
783
|
+
}}
|
|
784
|
+
onWheel={canScroll ? (e) => e.stopPropagation() : undefined}
|
|
785
|
+
>
|
|
786
|
+
<div
|
|
787
|
+
className="pointer-events-none relative"
|
|
788
|
+
data-viewport-sizer={isViewportNode(element) ? "true" : undefined}
|
|
789
|
+
style={
|
|
790
|
+
isViewportNode(element)
|
|
791
|
+
? {
|
|
792
|
+
width: layout.sourceWidth,
|
|
793
|
+
height: layout.sourceHeight,
|
|
794
|
+
minWidth: "100%",
|
|
795
|
+
minHeight: "100%",
|
|
796
|
+
}
|
|
797
|
+
: { width: "100%", height: "100%" }
|
|
798
|
+
}
|
|
799
|
+
>
|
|
753
800
|
{sourceNodes.map((node) => {
|
|
754
801
|
const box = getNodeAABB(node);
|
|
755
|
-
const left = layout.offsetX + (box.left - layout.minX) * layout.
|
|
756
|
-
const top = layout.offsetY + (box.top - layout.minY) * layout.
|
|
757
|
-
const width = Math.max(12, node.width * layout.
|
|
758
|
-
const height = Math.max(10, node.height * layout.
|
|
759
|
-
const boxWidth = Math.max(12, (box.right - box.left) * layout.
|
|
760
|
-
const boxHeight = Math.max(10, (box.bottom - box.top) * layout.
|
|
802
|
+
const left = layout.offsetX + (box.left - layout.minX) * layout.scaleX;
|
|
803
|
+
const top = layout.offsetY + (box.top - layout.minY) * layout.scaleY;
|
|
804
|
+
const width = Math.max(12, node.width * layout.scaleX);
|
|
805
|
+
const height = Math.max(10, node.height * layout.scaleY);
|
|
806
|
+
const boxWidth = Math.max(12, (box.right - box.left) * layout.scaleX);
|
|
807
|
+
const boxHeight = Math.max(10, (box.bottom - box.top) * layout.scaleY);
|
|
761
808
|
return (
|
|
762
809
|
<div
|
|
763
810
|
key={node.id}
|
|
764
811
|
className="absolute overflow-visible"
|
|
812
|
+
data-viewport-item={isViewportNode(element) ? "true" : undefined}
|
|
765
813
|
style={{
|
|
766
814
|
left,
|
|
767
815
|
top,
|
|
@@ -771,6 +819,7 @@ function ReferenceNodeContent({
|
|
|
771
819
|
>
|
|
772
820
|
<div
|
|
773
821
|
className="absolute"
|
|
822
|
+
data-viewport-item={isViewportNode(element) ? "true" : undefined}
|
|
774
823
|
style={{
|
|
775
824
|
left: (boxWidth - width) / 2,
|
|
776
825
|
top: (boxHeight - height) / 2,
|
|
@@ -783,7 +832,7 @@ function ReferenceNodeContent({
|
|
|
783
832
|
>
|
|
784
833
|
{CHART_TYPES.has(node.materialType ?? "") ? (
|
|
785
834
|
<ChartNodeContent element={node} />
|
|
786
|
-
) : node.materialType === "reference" ? (
|
|
835
|
+
) : node.materialType === "reference" || node.materialType === "viewport" ? (
|
|
787
836
|
<ReferenceNodeContent
|
|
788
837
|
element={node}
|
|
789
838
|
allElements={allElements}
|
|
@@ -803,6 +852,7 @@ function ReferenceNodeContent({
|
|
|
803
852
|
</div>
|
|
804
853
|
);
|
|
805
854
|
})}
|
|
855
|
+
</div>
|
|
806
856
|
</div>
|
|
807
857
|
);
|
|
808
858
|
}
|
|
@@ -887,6 +937,7 @@ export const ElementsLayer = React.memo(function ElementsLayer({
|
|
|
887
937
|
zIndex: el.zIndex ?? 1,
|
|
888
938
|
transform: `rotate(${el.rotate ?? 0}deg)`,
|
|
889
939
|
transformOrigin: "center center",
|
|
940
|
+
overflow: el.materialType === "viewport" ? "hidden" : undefined,
|
|
890
941
|
boxSizing: "border-box",
|
|
891
942
|
...getNodeVisualStyle(el),
|
|
892
943
|
}}
|
|
@@ -897,7 +948,7 @@ export const ElementsLayer = React.memo(function ElementsLayer({
|
|
|
897
948
|
previewLayoutKey={previewLayoutKey}
|
|
898
949
|
previewMode={previewMode}
|
|
899
950
|
/>
|
|
900
|
-
) : el.materialType === "reference" ? (
|
|
951
|
+
) : el.materialType === "reference" || el.materialType === "viewport" ? (
|
|
901
952
|
<ReferenceNodeContent element={el} allElements={allElements} />
|
|
902
953
|
) : el.materialType === "grid" ? (
|
|
903
954
|
<GridNodeContent
|
|
@@ -63,6 +63,7 @@ const MATERIAL_LABEL_KEYS: Record<string, string> = {
|
|
|
63
63
|
text: "panel.material.text",
|
|
64
64
|
rect: "panel.material.rect",
|
|
65
65
|
grid: "panel.material.grid",
|
|
66
|
+
viewport: "panel.material.viewport",
|
|
66
67
|
image: "panel.material.image",
|
|
67
68
|
video: "panel.material.video",
|
|
68
69
|
audio: "panel.material.audio",
|
|
@@ -374,6 +375,18 @@ function MaterialPreview({ id }: { id: string }) {
|
|
|
374
375
|
</div>
|
|
375
376
|
);
|
|
376
377
|
}
|
|
378
|
+
if (id === "viewport") {
|
|
379
|
+
return (
|
|
380
|
+
<div className={common}>
|
|
381
|
+
<div className="absolute inset-1.5 overflow-hidden rounded-sm border border-primary/70 bg-primary/10">
|
|
382
|
+
<div className="absolute left-1 top-1 h-6 w-8 rounded-[2px] bg-primary/45" />
|
|
383
|
+
<div className="absolute left-6 top-4 h-7 w-10 rounded-[2px] bg-primary/30" />
|
|
384
|
+
<div className="absolute bottom-0 right-0 h-1.5 w-6 rounded-tl bg-primary/55" />
|
|
385
|
+
<div className="absolute bottom-0 right-0 top-2 w-1.5 rounded-l bg-primary/40" />
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
);
|
|
389
|
+
}
|
|
377
390
|
|
|
378
391
|
return <div className={common} />;
|
|
379
392
|
}
|
|
@@ -403,6 +416,7 @@ function getDefaultCategories(t: (key: string) => string): MaterialCategory[] {
|
|
|
403
416
|
{ id: "geometry", title: t("panel.material.geometry") },
|
|
404
417
|
{ id: "scene3d", title: t("panel.material.scene3d") },
|
|
405
418
|
{ id: "grid", title: t("panel.material.grid") },
|
|
419
|
+
{ id: "viewport", title: t("panel.material.viewport") },
|
|
406
420
|
{ id: "image", title: t("panel.material.image") },
|
|
407
421
|
{ id: "reference", title: t("panel.material.reference") },
|
|
408
422
|
],
|
|
@@ -568,9 +582,8 @@ export function MaterialSidebar({
|
|
|
568
582
|
};
|
|
569
583
|
|
|
570
584
|
const getNodeChildren = (node: PanelElement, sourceOverride?: PanelElement[]) => {
|
|
571
|
-
const isRef = node.materialType === "reference";
|
|
585
|
+
const isRef = node.materialType === "reference" || node.materialType === "viewport";
|
|
572
586
|
const isGrid = node.materialType === "grid";
|
|
573
|
-
// 必须用节点自身所在图层查找子节点;外层传入的 layerId 在深嵌套/引用子树中会错位,导致子节点不显示在对应网格下
|
|
574
587
|
const gridChildren = isGrid
|
|
575
588
|
? [...(childrenByGridByLayer.get(node.layerId)?.get(node.id) ?? [])].sort(
|
|
576
589
|
compareGridTreeChildOrder
|
|
@@ -611,7 +624,7 @@ export function MaterialSidebar({
|
|
|
611
624
|
) => {
|
|
612
625
|
const selected = selectedIds.includes(node.id);
|
|
613
626
|
if (!nodeMatchesTreeSearch(node, visited, sourceOverride)) return null;
|
|
614
|
-
const isRef = node.materialType === "reference";
|
|
627
|
+
const isRef = node.materialType === "reference" || node.materialType === "viewport";
|
|
615
628
|
const refMode = node.refCopyMode ?? "shallow";
|
|
616
629
|
const isDeepRef = isRef && refMode === "deep";
|
|
617
630
|
const children = getNodeChildren(node, sourceOverride);
|
|
@@ -829,17 +842,11 @@ export function MaterialSidebar({
|
|
|
829
842
|
};
|
|
830
843
|
|
|
831
844
|
const hasRefInSubtree = (node: PanelElement, visited: Set<string>): boolean => {
|
|
832
|
-
if (node.materialType === "reference") return true;
|
|
833
|
-
if (node.materialType !== "reference") return false;
|
|
845
|
+
if (node.materialType === "reference" || node.materialType === "viewport") return true;
|
|
834
846
|
if (visited.has(node.id)) return false;
|
|
835
847
|
const nextVisited = new Set(visited);
|
|
836
848
|
nextVisited.add(node.id);
|
|
837
|
-
const children =
|
|
838
|
-
node.refCopyMode === "deep"
|
|
839
|
-
? node.refSnapshot ?? []
|
|
840
|
-
: node.refLayerId
|
|
841
|
-
? elementsByLayer.get(node.refLayerId) ?? []
|
|
842
|
-
: [];
|
|
849
|
+
const children = getNodeChildren(node);
|
|
843
850
|
return children.some((child) => hasRefInSubtree(child, nextVisited));
|
|
844
851
|
};
|
|
845
852
|
|
|
@@ -28,6 +28,11 @@ import type {
|
|
|
28
28
|
ReferenceCopyMode,
|
|
29
29
|
} from "../types";
|
|
30
30
|
import { buildChartOption, CHART_TYPES, getChartLabelsDisplayText, getChartValuesDisplayText } from "../utils/chartOptionBuilder";
|
|
31
|
+
import {
|
|
32
|
+
VIEWPORT_OVERFLOW_MODES,
|
|
33
|
+
normalizeViewportOverflow,
|
|
34
|
+
type ViewportOverflowMode,
|
|
35
|
+
} from "../utils/viewportPlacement";
|
|
31
36
|
import type { PanelLayer } from "../types";
|
|
32
37
|
import { getPanelMessages } from "../constants/messages";
|
|
33
38
|
import { ViewElementScopePanel } from "./ViewElementScopePanel";
|
|
@@ -1863,7 +1868,7 @@ export function PanelConfigSidebar({
|
|
|
1863
1868
|
</label>
|
|
1864
1869
|
</div>
|
|
1865
1870
|
) : null}
|
|
1866
|
-
{el.materialType === "reference" ? (
|
|
1871
|
+
{el.materialType === "reference" || el.materialType === "viewport" ? (
|
|
1867
1872
|
<div className="grid grid-cols-2 gap-2">
|
|
1868
1873
|
<label className="block space-y-1.5">
|
|
1869
1874
|
<div>{t("panel.config.refLayer")}</div>
|
|
@@ -1895,6 +1900,34 @@ export function PanelConfigSidebar({
|
|
|
1895
1900
|
</label>
|
|
1896
1901
|
</div>
|
|
1897
1902
|
) : null}
|
|
1903
|
+
{el.materialType === "viewport" ? (
|
|
1904
|
+
<label className="block space-y-1.5">
|
|
1905
|
+
<div>{t("panel.config.viewportOverflow")}</div>
|
|
1906
|
+
<Select
|
|
1907
|
+
value={normalizeViewportOverflow(el.viewportOverflow)}
|
|
1908
|
+
onValueChange={(value) =>
|
|
1909
|
+
updateElement(el.id, {
|
|
1910
|
+
viewportOverflow: value as ViewportOverflowMode,
|
|
1911
|
+
})
|
|
1912
|
+
}
|
|
1913
|
+
>
|
|
1914
|
+
<SelectTrigger className="h-7"><SelectValue /></SelectTrigger>
|
|
1915
|
+
<SelectContent>
|
|
1916
|
+
{VIEWPORT_OVERFLOW_MODES.map((mode) => (
|
|
1917
|
+
<SelectItem key={mode} value={mode}>
|
|
1918
|
+
{mode === "scroll-x"
|
|
1919
|
+
? t("panel.config.viewportOverflowScrollX")
|
|
1920
|
+
: mode === "scroll-y"
|
|
1921
|
+
? t("panel.config.viewportOverflowScrollY")
|
|
1922
|
+
: mode === "scroll"
|
|
1923
|
+
? t("panel.config.viewportOverflowScroll")
|
|
1924
|
+
: t("panel.config.viewportOverflowClip")}
|
|
1925
|
+
</SelectItem>
|
|
1926
|
+
))}
|
|
1927
|
+
</SelectContent>
|
|
1928
|
+
</Select>
|
|
1929
|
+
</label>
|
|
1930
|
+
) : null}
|
|
1898
1931
|
</div>
|
|
1899
1932
|
</fieldset>
|
|
1900
1933
|
</CardContent>
|
|
@@ -3603,6 +3636,111 @@ export function PanelConfigSidebar({
|
|
|
3603
3636
|
{t("panel.config.gridHint")}
|
|
3604
3637
|
</>
|
|
3605
3638
|
)
|
|
3639
|
+
) : selectedElement.materialType === "viewport" ? (
|
|
3640
|
+
renderSection(
|
|
3641
|
+
"viewportConfig",
|
|
3642
|
+
t("panel.config.sectionViewport"),
|
|
3643
|
+
<>
|
|
3644
|
+
{renderFieldGroup(
|
|
3645
|
+
t("panel.config.groupRefSource"),
|
|
3646
|
+
<label className="block space-y-1">
|
|
3647
|
+
<div>{t("panel.config.refLayer")}</div>
|
|
3648
|
+
<Select
|
|
3649
|
+
value={selectedElement.refLayerId ?? "__none__"}
|
|
3650
|
+
onValueChange={(value) =>
|
|
3651
|
+
updateElement(selectedElement.id, {
|
|
3652
|
+
refLayerId: value === "__none__" ? undefined : value,
|
|
3653
|
+
})
|
|
3654
|
+
}
|
|
3655
|
+
>
|
|
3656
|
+
<SelectTrigger className="h-7">
|
|
3657
|
+
<SelectValue placeholder={t("panel.config.pleaseSelectLayer")} />
|
|
3658
|
+
</SelectTrigger>
|
|
3659
|
+
<SelectContent>
|
|
3660
|
+
<SelectItem value="__none__">{t("panel.config.noneNoRef")}</SelectItem>
|
|
3661
|
+
{layers
|
|
3662
|
+
.filter((l) => l.id !== selectedElement.layerId)
|
|
3663
|
+
.map((l) => (
|
|
3664
|
+
<SelectItem key={l.id} value={l.id}>
|
|
3665
|
+
{l.name}
|
|
3666
|
+
</SelectItem>
|
|
3667
|
+
))}
|
|
3668
|
+
</SelectContent>
|
|
3669
|
+
</Select>
|
|
3670
|
+
</label>
|
|
3671
|
+
)}
|
|
3672
|
+
{renderFieldGroup(
|
|
3673
|
+
t("panel.config.groupCopyStrategy"),
|
|
3674
|
+
<>
|
|
3675
|
+
<label className="block space-y-1">
|
|
3676
|
+
<div>{t("panel.config.copyMode")}</div>
|
|
3677
|
+
<Select
|
|
3678
|
+
value={selectedElement.refCopyMode ?? "shallow"}
|
|
3679
|
+
onValueChange={(value) =>
|
|
3680
|
+
setReferenceCopyMode?.(
|
|
3681
|
+
selectedElement.id,
|
|
3682
|
+
value as ReferenceCopyMode
|
|
3683
|
+
)
|
|
3684
|
+
}
|
|
3685
|
+
>
|
|
3686
|
+
<SelectTrigger className="h-7">
|
|
3687
|
+
<SelectValue placeholder={t("panel.config.selectCopyMode")} />
|
|
3688
|
+
</SelectTrigger>
|
|
3689
|
+
<SelectContent>
|
|
3690
|
+
<SelectItem value="shallow">{t("panel.config.shallowFollow")}</SelectItem>
|
|
3691
|
+
<SelectItem value="deep">{t("panel.config.deepFreeze")}</SelectItem>
|
|
3692
|
+
</SelectContent>
|
|
3693
|
+
</Select>
|
|
3694
|
+
</label>
|
|
3695
|
+
</>,
|
|
3696
|
+
<>{t("panel.config.copyStrategyHint")}</>,
|
|
3697
|
+
{ groupKey: "viewportCopyStrategy", defaultOpen: false }
|
|
3698
|
+
)}
|
|
3699
|
+
{renderFieldGroup(
|
|
3700
|
+
t("panel.config.groupViewportOverflow"),
|
|
3701
|
+
<label className="block space-y-1">
|
|
3702
|
+
<div>{t("panel.config.viewportOverflow")}</div>
|
|
3703
|
+
<Select
|
|
3704
|
+
value={normalizeViewportOverflow(selectedElement.viewportOverflow)}
|
|
3705
|
+
onValueChange={(value) =>
|
|
3706
|
+
updateElement(selectedElement.id, {
|
|
3707
|
+
viewportOverflow: value as ViewportOverflowMode,
|
|
3708
|
+
})
|
|
3709
|
+
}
|
|
3710
|
+
>
|
|
3711
|
+
<SelectTrigger className="h-7">
|
|
3712
|
+
<SelectValue placeholder={t("panel.config.viewportOverflow")} />
|
|
3713
|
+
</SelectTrigger>
|
|
3714
|
+
<SelectContent>
|
|
3715
|
+
{VIEWPORT_OVERFLOW_MODES.map((mode) => (
|
|
3716
|
+
<SelectItem key={mode} value={mode}>
|
|
3717
|
+
{mode === "scroll-x"
|
|
3718
|
+
? t("panel.config.viewportOverflowScrollX")
|
|
3719
|
+
: mode === "scroll-y"
|
|
3720
|
+
? t("panel.config.viewportOverflowScrollY")
|
|
3721
|
+
: mode === "scroll"
|
|
3722
|
+
? t("panel.config.viewportOverflowScroll")
|
|
3723
|
+
: t("panel.config.viewportOverflowClip")}
|
|
3724
|
+
</SelectItem>
|
|
3725
|
+
))}
|
|
3726
|
+
</SelectContent>
|
|
3727
|
+
</Select>
|
|
3728
|
+
</label>
|
|
3729
|
+
)}
|
|
3730
|
+
</>,
|
|
3731
|
+
true,
|
|
3732
|
+
[
|
|
3733
|
+
t("panel.config.searchKwViewport"),
|
|
3734
|
+
"viewport",
|
|
3735
|
+
t("panel.config.refLayer"),
|
|
3736
|
+
t("panel.config.viewportOverflow"),
|
|
3737
|
+
t("panel.config.viewportOverflowScrollX"),
|
|
3738
|
+
t("panel.config.viewportOverflowClip"),
|
|
3739
|
+
t("panel.material.shallowCopy"),
|
|
3740
|
+
t("panel.material.deepCopy"),
|
|
3741
|
+
],
|
|
3742
|
+
<>{t("panel.config.viewportHint")}</>
|
|
3743
|
+
)
|
|
3606
3744
|
) : selectedElement.materialType === "reference" ? (
|
|
3607
3745
|
renderSection(
|
|
3608
3746
|
"reference",
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
getDefaultChartConfig,
|
|
17
17
|
getDefaultTableConfig,
|
|
18
18
|
getDefaultGridConfig,
|
|
19
|
+
getDefaultViewportConfig,
|
|
19
20
|
getDefaultLayer,
|
|
20
21
|
getDefaultNodeName,
|
|
21
22
|
getDefaultScene3dConfigForMaterial,
|
|
@@ -552,7 +553,10 @@ export function usePanelElements() {
|
|
|
552
553
|
.filter((n) => isPanelElementNode(n) && n.props)
|
|
553
554
|
.map((n) => n.props as PanelElement);
|
|
554
555
|
const desiredMode = options?.referenceCopyMode;
|
|
555
|
-
if (
|
|
556
|
+
if (
|
|
557
|
+
(nextProps.materialType === "reference" || nextProps.materialType === "viewport") &&
|
|
558
|
+
desiredMode
|
|
559
|
+
) {
|
|
556
560
|
if (desiredMode === "deep" && nextProps.refLayerId) {
|
|
557
561
|
nextProps.refCopyMode = "deep";
|
|
558
562
|
nextProps.refSnapshot = buildDeepReferenceSnapshot(all, nextProps.refLayerId);
|
|
@@ -596,7 +600,9 @@ export function usePanelElements() {
|
|
|
596
600
|
name: getDefaultNodeName(materialType, t),
|
|
597
601
|
...getDefaultTextContent(materialType, t),
|
|
598
602
|
...getDefaultGridConfig(materialType),
|
|
599
|
-
|
|
603
|
+
...getDefaultViewportConfig(materialType),
|
|
604
|
+
refCopyMode:
|
|
605
|
+
materialType === "reference" || materialType === "viewport" ? "shallow" : undefined,
|
|
600
606
|
chart: getDefaultChartConfig(materialType, t),
|
|
601
607
|
table: getDefaultTableConfig(materialType, t),
|
|
602
608
|
geometryShape: materialType === "geometry" ? "rect" : undefined,
|
|
@@ -700,7 +706,7 @@ export function usePanelElements() {
|
|
|
700
706
|
.filter((n) => isPanelElementNode(n) && n.props)
|
|
701
707
|
.map((n) => n.props as PanelElement);
|
|
702
708
|
const target = all.find((el) => el.id === id);
|
|
703
|
-
if (!target || target.materialType !== "reference") return;
|
|
709
|
+
if (!target || (target.materialType !== "reference" && target.materialType !== "viewport")) return;
|
|
704
710
|
const currentLayers =
|
|
705
711
|
(current.variables?.layers as PanelLayer[] | undefined) ?? [DEFAULT_LAYER];
|
|
706
712
|
const layer = currentLayers.find((l) => l.id === target.layerId);
|
|
@@ -895,7 +901,7 @@ export function usePanelElements() {
|
|
|
895
901
|
if (target.isMapping) return false;
|
|
896
902
|
const willBeDeleted = mode === "remove" && el.layerId === layerId;
|
|
897
903
|
if (willBeDeleted) return false;
|
|
898
|
-
if (el.materialType !== "reference") return false;
|
|
904
|
+
if (el.materialType !== "reference" && el.materialType !== "viewport") return false;
|
|
899
905
|
if (el.refLayerId !== layerId) return false;
|
|
900
906
|
return (el.refCopyMode ?? "shallow") !== "deep";
|
|
901
907
|
});
|