@base2datadesign/viewer-react 0.1.3 → 0.1.5

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.
@@ -3,6 +3,11 @@ export type LightingOption = {
3
3
  label: string;
4
4
  summary?: string;
5
5
  };
6
+ export type MaterialOption = {
7
+ id: string;
8
+ label: string;
9
+ summary?: string;
10
+ };
6
11
  export type SkyOption = {
7
12
  id: string;
8
13
  label: string;
@@ -11,6 +16,9 @@ export type SkyOption = {
11
16
  export type ViewControlsProps = {
12
17
  activeLightingPreset: string;
13
18
  onLightingChange: (preset: string) => void;
19
+ materialOptions?: MaterialOption[];
20
+ activeMaterialPreset?: string;
21
+ onMaterialChange?: (preset: string) => void;
14
22
  onCameraViewChange: (view: string) => void;
15
23
  skyOptions: SkyOption[];
16
24
  activeSkyId: string;
@@ -19,5 +27,5 @@ export type ViewControlsProps = {
19
27
  veilsEnabled?: boolean;
20
28
  onToggleVeils?: () => void;
21
29
  };
22
- export default function ViewControls({ activeLightingPreset, onLightingChange, onCameraViewChange, skyOptions, activeSkyId, onSkyChange, lightingOptions, veilsEnabled, onToggleVeils, }: ViewControlsProps): import("react/jsx-runtime").JSX.Element;
30
+ export default function ViewControls({ activeLightingPreset, onLightingChange, materialOptions, activeMaterialPreset, onMaterialChange, onCameraViewChange, skyOptions, activeSkyId, onSkyChange, lightingOptions, veilsEnabled, onToggleVeils, }: ViewControlsProps): import("react/jsx-runtime").JSX.Element;
23
31
  //# sourceMappingURL=ViewControls.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ViewControls.d.ts","sourceRoot":"","sources":["../src/ViewControls.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B,CAAC;AA2CF,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,WAAW,EACX,eAAe,EACf,YAAmB,EACnB,aAAa,GACd,EAAE,iBAAiB,2CA6QnB"}
1
+ {"version":3,"file":"ViewControls.d.ts","sourceRoot":"","sources":["../src/ViewControls.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B,CAAC;AA2CF,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,WAAW,EACX,eAAe,EACf,YAAmB,EACnB,aAAa,GACd,EAAE,iBAAiB,2CA8WnB"}
@@ -37,18 +37,23 @@ const dropdownStyle = {
37
37
  minWidth: "220px",
38
38
  zIndex: 60,
39
39
  };
40
- export default function ViewControls({ activeLightingPreset, onLightingChange, onCameraViewChange, skyOptions, activeSkyId, onSkyChange, lightingOptions, veilsEnabled = true, onToggleVeils, }) {
40
+ export default function ViewControls({ activeLightingPreset, onLightingChange, materialOptions, activeMaterialPreset, onMaterialChange, onCameraViewChange, skyOptions, activeSkyId, onSkyChange, lightingOptions, veilsEnabled = true, onToggleVeils, }) {
41
41
  const lightingMenuRef = useRef(null);
42
+ const materialMenuRef = useRef(null);
42
43
  const skyMenuRef = useRef(null);
43
44
  const [lightingExpanded, setLightingExpanded] = useState(false);
45
+ const [materialExpanded, setMaterialExpanded] = useState(false);
44
46
  const [skyExpanded, setSkyExpanded] = useState(false);
45
47
  const [lightingHover, setLightingHover] = useState(false);
48
+ const [materialHover, setMaterialHover] = useState(false);
46
49
  const [skyHover, setSkyHover] = useState(false);
47
50
  const [viewHover, setViewHover] = useState(false);
48
51
  const activeLighting = useMemo(() => lightingOptions.find((option) => option.id === activeLightingPreset) ?? lightingOptions[0], [lightingOptions, activeLightingPreset]);
49
52
  const activeSky = useMemo(() => skyOptions.find((option) => option.id === activeSkyId) ?? skyOptions[0], [skyOptions, activeSkyId]);
53
+ const activeMaterial = useMemo(() => materialOptions?.find((option) => option.id === activeMaterialPreset) ??
54
+ materialOptions?.[0], [materialOptions, activeMaterialPreset]);
50
55
  useEffect(() => {
51
- if (!lightingExpanded && !skyExpanded)
56
+ if (!lightingExpanded && !skyExpanded && !materialExpanded)
52
57
  return;
53
58
  const onMouseDown = (event) => {
54
59
  const target = event.target;
@@ -56,15 +61,19 @@ export default function ViewControls({ activeLightingPreset, onLightingChange, o
56
61
  return;
57
62
  if (lightingMenuRef.current?.contains(target))
58
63
  return;
64
+ if (materialMenuRef.current?.contains(target))
65
+ return;
59
66
  if (skyMenuRef.current?.contains(target))
60
67
  return;
61
68
  setLightingExpanded(false);
69
+ setMaterialExpanded(false);
62
70
  setSkyExpanded(false);
63
71
  };
64
72
  const onKeyDown = (event) => {
65
73
  if (event.key !== "Escape")
66
74
  return;
67
75
  setLightingExpanded(false);
76
+ setMaterialExpanded(false);
68
77
  setSkyExpanded(false);
69
78
  };
70
79
  window.addEventListener("mousedown", onMouseDown);
@@ -73,7 +82,7 @@ export default function ViewControls({ activeLightingPreset, onLightingChange, o
73
82
  window.removeEventListener("mousedown", onMouseDown);
74
83
  window.removeEventListener("keydown", onKeyDown);
75
84
  };
76
- }, [lightingExpanded, skyExpanded]);
85
+ }, [lightingExpanded, materialExpanded, skyExpanded]);
77
86
  return (_jsxs("div", { style: { display: "flex", gap: "10px", alignItems: "flex-end" }, children: [_jsx("div", { ref: lightingMenuRef, children: _jsxs("div", { style: cardStyle, onMouseEnter: () => setLightingHover(true), onMouseLeave: () => setLightingHover(false), children: [lightingExpanded ? (_jsx("div", { style: dropdownStyle, children: lightingOptions.map((option) => (_jsxs("button", { type: "button", onClick: () => {
78
87
  onLightingChange(option.id);
79
88
  setLightingExpanded(false);
@@ -113,7 +122,47 @@ export default function ViewControls({ activeLightingPreset, onLightingChange, o
113
122
  color: "#64748b",
114
123
  opacity: !veilsEnabled || lightingExpanded || lightingHover ? 1 : 0,
115
124
  transition: "opacity 0.2s ease",
116
- }, children: lightingExpanded ? "▼" : "▲" })] }), veilsEnabled && !lightingExpanded && !lightingHover ? _jsx("div", { style: veilStyle, children: "LIGHTING" }) : null] }) }), _jsxs("div", { style: { ...cardStyle, display: "flex" }, onMouseEnter: () => setViewHover(true), onMouseLeave: () => setViewHover(false), children: [_jsx("button", { type: "button", onClick: () => onCameraViewChange("interior"), style: {
125
+ }, children: lightingExpanded ? "▼" : "▲" })] }), veilsEnabled && !lightingExpanded && !lightingHover ? _jsx("div", { style: veilStyle, children: "LIGHTING" }) : null] }) }), materialOptions && materialOptions.length && onMaterialChange ? (_jsx("div", { ref: materialMenuRef, children: _jsxs("div", { style: cardStyle, onMouseEnter: () => setMaterialHover(true), onMouseLeave: () => setMaterialHover(false), children: [materialExpanded ? (_jsx("div", { style: dropdownStyle, children: materialOptions.map((option) => (_jsxs("button", { type: "button", onClick: () => {
126
+ onMaterialChange(option.id);
127
+ setMaterialExpanded(false);
128
+ }, style: {
129
+ width: "100%",
130
+ border: "none",
131
+ borderRadius: "8px",
132
+ padding: "8px 10px",
133
+ textAlign: "left",
134
+ background: option.id === activeMaterialPreset ? "rgba(49,67,144,0.12)" : "transparent",
135
+ color: option.id === activeMaterialPreset ? "#314390" : "#475569",
136
+ cursor: "pointer",
137
+ display: "flex",
138
+ flexDirection: "column",
139
+ gap: "2px",
140
+ fontSize: "12px",
141
+ textTransform: "lowercase",
142
+ }, children: [_jsx("span", { children: option.label }), option.summary ? (_jsx("span", { style: { fontSize: "10px", opacity: 0.7 }, children: option.summary })) : null] }, option.id))) })) : null, _jsxs("button", { type: "button", onClick: () => {
143
+ setMaterialExpanded((prev) => !prev);
144
+ setLightingExpanded(false);
145
+ setSkyExpanded(false);
146
+ }, style: {
147
+ display: "flex",
148
+ alignItems: "center",
149
+ justifyContent: "space-between",
150
+ gap: "10px",
151
+ padding: "8px 12px",
152
+ border: "none",
153
+ background: "transparent",
154
+ width: "100%",
155
+ cursor: "pointer",
156
+ }, children: [_jsx("span", { style: {
157
+ ...labelStyle,
158
+ opacity: !veilsEnabled || materialExpanded || materialHover ? 1 : 0,
159
+ transition: "opacity 0.2s ease",
160
+ }, children: activeMaterial?.label ?? activeMaterialPreset ?? "materials" }), _jsx("span", { style: {
161
+ fontSize: "11px",
162
+ color: "#64748b",
163
+ opacity: !veilsEnabled || materialExpanded || materialHover ? 1 : 0,
164
+ transition: "opacity 0.2s ease",
165
+ }, children: materialExpanded ? "▼" : "▲" })] }), veilsEnabled && !materialExpanded && !materialHover ? _jsx("div", { style: veilStyle, children: "MATERIALS" }) : null] }) })) : null, _jsxs("div", { style: { ...cardStyle, display: "flex" }, onMouseEnter: () => setViewHover(true), onMouseLeave: () => setViewHover(false), children: [_jsx("button", { type: "button", onClick: () => onCameraViewChange("interior"), style: {
117
166
  padding: "8px 12px",
118
167
  border: "none",
119
168
  borderRight: "1px solid #e2e8f0",
@@ -1 +1 @@
1
- {"version":3,"file":"ViewerCanvas.d.ts","sourceRoot":"","sources":["../src/ViewerCanvas.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEpG,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,aAAa,CAAC,EAAE,mBAAmB,CAAC,eAAe,CAAC,CAAC;IACrD,MAAM,CAAC,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACvC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAC3C,iBAAiB,CAAC,EAAE,mBAAmB,CAAC,mBAAmB,CAAC,CAAC;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,KAAK,IAAI,CAAC;CACjD,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,QAAQ,EACR,OAAO,EACP,aAAa,EACb,MAAM,EACN,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,OAAO,GACR,EAAE,iBAAiB,2CA8InB"}
1
+ {"version":3,"file":"ViewerCanvas.d.ts","sourceRoot":"","sources":["../src/ViewerCanvas.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEpG,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,aAAa,CAAC,EAAE,mBAAmB,CAAC,eAAe,CAAC,CAAC;IACrD,MAAM,CAAC,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACvC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAC3C,iBAAiB,CAAC,EAAE,mBAAmB,CAAC,mBAAmB,CAAC,CAAC;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,KAAK,IAAI,CAAC;CACjD,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,QAAQ,EACR,OAAO,EACP,aAAa,EACb,MAAM,EACN,QAAQ,EACR,iBAAiB,EACjB,SAAS,EACT,OAAO,GACR,EAAE,iBAAiB,2CAqInB"}
@@ -30,7 +30,6 @@ export default function ViewerCanvas({ presetId, presets, assetResolver, camera,
30
30
  let resizeObserver = null;
31
31
  let sizeObserver = null;
32
32
  let rafId = null;
33
- let handleResize = null;
34
33
  let handle = null;
35
34
  const cleanup = () => {
36
35
  disposed = true;
@@ -42,10 +41,6 @@ export default function ViewerCanvas({ presetId, presets, assetResolver, camera,
42
41
  sizeObserver = null;
43
42
  resizeObserver?.disconnect();
44
43
  resizeObserver = null;
45
- if (handleResize) {
46
- window.removeEventListener("resize", handleResize);
47
- handleResize = null;
48
- }
49
44
  if (handle) {
50
45
  handle.stop();
51
46
  handle.dispose();
@@ -86,10 +81,7 @@ export default function ViewerCanvas({ presetId, presets, assetResolver, camera,
86
81
  handle.__viewerId = instanceId;
87
82
  console.log("[viewer-react] create", { viewerId: instanceId });
88
83
  handle.start();
89
- const onResize = () => handle?.resize();
90
- handleResize = onResize;
91
- window.addEventListener("resize", onResize);
92
- onResize();
84
+ handle.resize();
93
85
  if (typeof ResizeObserver !== "undefined") {
94
86
  resizeObserver = new ResizeObserver(() => handle?.resize());
95
87
  resizeObserver.observe(container);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base2datadesign/viewer-react",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "main": "./dist/index.js",