@treasuryspatial/viewer-react 0.1.47 → 0.1.48

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.
@@ -32,6 +32,17 @@ export type ViewControlsWidget = {
32
32
  export type ViewControlsProps = {
33
33
  activeLightingPreset: string;
34
34
  onLightingChange: (preset: string) => void;
35
+ /**
36
+ * When environment/rig options are provided, the single LIGHTING chip is
37
+ * replaced by ENVIRONMENT + RIG axis chips (lighting-preset catalog
38
+ * restructure). Consumers that omit them keep the legacy single chip.
39
+ */
40
+ environmentOptions?: LightingOption[];
41
+ activeEnvironmentId?: string;
42
+ onEnvironmentChange?: (environmentId: string) => void;
43
+ rigOptions?: LightingOption[];
44
+ activeRigId?: string;
45
+ onRigChange?: (rigId: string) => void;
35
46
  materialOptions?: MaterialOption[];
36
47
  activeMaterialPreset?: string;
37
48
  onMaterialChange?: (preset: string) => void;
@@ -39,6 +50,12 @@ export type ViewControlsProps = {
39
50
  skyOptions: SkyOption[];
40
51
  activeSkyId: string;
41
52
  onSkyChange: (skyId: string) => void;
53
+ /**
54
+ * BACKDROP gate (owner final spec 2026-07-11): while an ENVIRONMENT (HDR
55
+ * photo world) owns light + sky, the BACKDROP menu is disabled — the
56
+ * generated worlds only apply once the environment is cleared to none.
57
+ */
58
+ skyDisabled?: boolean;
42
59
  lightingOptions: LightingOption[];
43
60
  extraActions?: ViewControlsAction[];
44
61
  extraWidgets?: ViewControlsWidget[];
@@ -46,5 +63,5 @@ export type ViewControlsProps = {
46
63
  onToggleVeils?: () => void;
47
64
  onResetRender?: () => void;
48
65
  };
49
- export default function ViewControls({ activeLightingPreset, onLightingChange, materialOptions, activeMaterialPreset, onMaterialChange, onCameraViewChange, skyOptions, activeSkyId, onSkyChange, lightingOptions, extraActions, extraWidgets, veilsEnabled, onToggleVeils, onResetRender, }: ViewControlsProps): import("react/jsx-runtime").JSX.Element;
66
+ export default function ViewControls({ activeLightingPreset, onLightingChange, environmentOptions, activeEnvironmentId, onEnvironmentChange, rigOptions, activeRigId, onRigChange, materialOptions, activeMaterialPreset, onMaterialChange, onCameraViewChange, skyOptions, activeSkyId, onSkyChange, skyDisabled, lightingOptions, extraActions, extraWidgets, veilsEnabled, onToggleVeils, onResetRender, }: ViewControlsProps): import("react/jsx-runtime").JSX.Element;
50
67
  //# sourceMappingURL=ViewControls.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ViewControls.d.ts","sourceRoot":"","sources":["../src/ViewControls.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAEpE,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B,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,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,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,kBAAkB,EAAE,CAAC;IACpC,YAAY,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B,CAAC;AA+FF,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,YAAiB,EACjB,YAAiB,EACjB,YAAmB,EACnB,aAAa,EACb,aAAa,GACd,EAAE,iBAAiB,2CA0anB"}
1
+ {"version":3,"file":"ViewControls.d.ts","sourceRoot":"","sources":["../src/ViewControls.tsx"],"names":[],"mappings":"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"}
@@ -85,44 +85,89 @@ const shouldShowGroupLabel = (items, index) => {
85
85
  return true;
86
86
  return items[index - 1]?.group !== current;
87
87
  };
88
- export default function ViewControls({ activeLightingPreset, onLightingChange, materialOptions, activeMaterialPreset, onMaterialChange, onCameraViewChange, skyOptions, activeSkyId, onSkyChange, lightingOptions, extraActions = [], extraWidgets = [], veilsEnabled = true, onToggleVeils, onResetRender, }) {
88
+ const dropdownHeaderStyle = {
89
+ padding: "4px 10px 8px",
90
+ fontSize: "10px",
91
+ fontWeight: 700,
92
+ letterSpacing: "0.14em",
93
+ textTransform: "uppercase",
94
+ color: "var(--viewer-ui-color-text-subtle, rgba(100,116,139,0.85))",
95
+ textAlign: "left",
96
+ borderBottom: "1px solid var(--viewer-ui-color-panel-border, #e2e8f0)",
97
+ marginBottom: "4px",
98
+ };
99
+ function AxisDropdownChip({ caption, options, activeId, onSelect, expanded, menuRef, onToggle, onClose, disabled = false, disabledHint, }) {
100
+ const active = options.find((option) => option.id === activeId) ?? options[0];
101
+ return (_jsx("div", { ref: menuRef, children: _jsxs("div", { style: { ...cardStyle, opacity: disabled ? 0.45 : 1 }, children: [expanded && !disabled ? (_jsxs("div", { style: dropdownStyle, children: [_jsx("div", { style: dropdownHeaderStyle, children: caption }), options.map((option, index) => (_jsxs(React.Fragment, { children: [shouldShowGroupLabel(options, index) ? (_jsx("div", { style: menuGroupLabelStyle, children: option.group })) : null, _jsxs("button", { type: "button", onClick: () => {
102
+ onSelect(option.id);
103
+ onClose();
104
+ }, style: menuButtonStyle(option.id === activeId), 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", disabled: disabled, "aria-disabled": disabled, title: disabled ? disabledHint : undefined, onClick: () => {
105
+ if (disabled)
106
+ return;
107
+ onToggle();
108
+ }, style: {
109
+ display: "flex",
110
+ alignItems: "center",
111
+ justifyContent: "space-between",
112
+ gap: "10px",
113
+ padding: "8px 12px",
114
+ border: "none",
115
+ background: "transparent",
116
+ width: "100%",
117
+ minWidth: "128px",
118
+ cursor: disabled ? "not-allowed" : "pointer",
119
+ }, children: [_jsx("span", { style: labelStyle, children: active?.label ?? activeId }), _jsx("span", { style: { fontSize: "11px", color: "var(--viewer-ui-color-text-muted, #64748b)" }, children: disabled ? "" : expanded ? "▼" : "▲" })] })] }) }));
120
+ }
121
+ export default function ViewControls({ activeLightingPreset, onLightingChange, environmentOptions, activeEnvironmentId, onEnvironmentChange, rigOptions, activeRigId, onRigChange, materialOptions, activeMaterialPreset, onMaterialChange, onCameraViewChange, skyOptions, activeSkyId, onSkyChange, skyDisabled = false, lightingOptions, extraActions = [], extraWidgets = [], veilsEnabled = true, onToggleVeils, onResetRender, }) {
89
122
  const lightingMenuRef = useRef(null);
123
+ const environmentMenuRef = useRef(null);
124
+ const rigMenuRef = useRef(null);
90
125
  const materialMenuRef = useRef(null);
91
126
  const skyMenuRef = useRef(null);
92
127
  const [lightingExpanded, setLightingExpanded] = useState(false);
128
+ const [environmentExpanded, setEnvironmentExpanded] = useState(false);
129
+ const [rigExpanded, setRigExpanded] = useState(false);
93
130
  const [materialExpanded, setMaterialExpanded] = useState(false);
94
131
  const [skyExpanded, setSkyExpanded] = useState(false);
95
132
  const [lightingHover, setLightingHover] = useState(false);
96
133
  const [materialHover, setMaterialHover] = useState(false);
97
134
  const [skyHover, setSkyHover] = useState(false);
98
135
  const [viewHover, setViewHover] = useState(false);
136
+ const showAxisChips = Boolean(environmentOptions?.length && rigOptions?.length && onEnvironmentChange && onRigChange);
99
137
  const activeLighting = useMemo(() => lightingOptions.find((option) => option.id === activeLightingPreset) ?? lightingOptions[0], [lightingOptions, activeLightingPreset]);
100
138
  const activeSky = useMemo(() => skyOptions.find((option) => option.id === activeSkyId) ?? skyOptions[0], [skyOptions, activeSkyId]);
101
139
  const activeMaterial = useMemo(() => materialOptions?.find((option) => option.id === activeMaterialPreset) ??
102
140
  materialOptions?.[0], [materialOptions, activeMaterialPreset]);
103
141
  useEffect(() => {
104
- if (!lightingExpanded && !skyExpanded && !materialExpanded)
142
+ if (!lightingExpanded && !environmentExpanded && !rigExpanded && !skyExpanded && !materialExpanded)
105
143
  return;
144
+ const closeAll = () => {
145
+ setLightingExpanded(false);
146
+ setEnvironmentExpanded(false);
147
+ setRigExpanded(false);
148
+ setMaterialExpanded(false);
149
+ setSkyExpanded(false);
150
+ };
106
151
  const onMouseDown = (event) => {
107
152
  const target = event.target;
108
153
  if (!target)
109
154
  return;
110
155
  if (lightingMenuRef.current?.contains(target))
111
156
  return;
157
+ if (environmentMenuRef.current?.contains(target))
158
+ return;
159
+ if (rigMenuRef.current?.contains(target))
160
+ return;
112
161
  if (materialMenuRef.current?.contains(target))
113
162
  return;
114
163
  if (skyMenuRef.current?.contains(target))
115
164
  return;
116
- setLightingExpanded(false);
117
- setMaterialExpanded(false);
118
- setSkyExpanded(false);
165
+ closeAll();
119
166
  };
120
167
  const onKeyDown = (event) => {
121
168
  if (event.key !== "Escape")
122
169
  return;
123
- setLightingExpanded(false);
124
- setMaterialExpanded(false);
125
- setSkyExpanded(false);
170
+ closeAll();
126
171
  };
127
172
  window.addEventListener("mousedown", onMouseDown);
128
173
  window.addEventListener("keydown", onKeyDown);
@@ -130,8 +175,43 @@ export default function ViewControls({ activeLightingPreset, onLightingChange, m
130
175
  window.removeEventListener("mousedown", onMouseDown);
131
176
  window.removeEventListener("keydown", onKeyDown);
132
177
  };
133
- }, [lightingExpanded, materialExpanded, skyExpanded]);
134
- 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, index) => (_jsxs(React.Fragment, { children: [shouldShowGroupLabel(lightingOptions, index) ? (_jsx("div", { style: menuGroupLabelStyle, children: option.group })) : null, _jsxs("button", { type: "button", onClick: () => {
178
+ }, [environmentExpanded, lightingExpanded, materialExpanded, rigExpanded, skyExpanded]);
179
+ return (_jsxs("div", { style: { display: "flex", gap: "10px", alignItems: "flex-end" }, children: [showAxisChips && skyOptions.length ? (_jsx(AxisDropdownChip, { caption: "BACKGROUND", options: skyOptions, activeId: activeSkyId, onSelect: (id) => onSkyChange(id), expanded: skyExpanded, menuRef: skyMenuRef, onToggle: () => {
180
+ setSkyExpanded((prev) => !prev);
181
+ setEnvironmentExpanded(false);
182
+ setRigExpanded(false);
183
+ setMaterialExpanded(false);
184
+ }, onClose: () => setSkyExpanded(false), disabled: skyDisabled, disabledHint: "environment owns the scene \u2014 set environment to none/white to use a background" })) : skyOptions.length ? (_jsx("div", { ref: skyMenuRef, children: _jsxs("div", { style: cardStyle, onMouseEnter: () => setSkyHover(true), onMouseLeave: () => setSkyHover(false), children: [skyExpanded ? (_jsx("div", { style: dropdownStyle, children: skyOptions.map((option, index) => (_jsxs(React.Fragment, { children: [shouldShowGroupLabel(skyOptions, index) ? (_jsx("div", { style: menuGroupLabelStyle, children: option.group })) : null, _jsxs("button", { type: "button", onClick: () => {
185
+ onSkyChange(option.id);
186
+ setSkyExpanded(false);
187
+ }, style: menuButtonStyle(option.id === activeSkyId), children: [_jsx("span", { children: option.label }), option.description ? (_jsx("span", { style: { fontSize: "10px", opacity: 0.7 }, children: option.description })) : null] })] }, option.id))) })) : null, _jsxs("button", { type: "button", onClick: () => {
188
+ setSkyExpanded((prev) => !prev);
189
+ setLightingExpanded(false);
190
+ }, style: {
191
+ display: "flex",
192
+ alignItems: "center",
193
+ justifyContent: "space-between",
194
+ gap: "10px",
195
+ padding: "8px 12px",
196
+ border: "none",
197
+ background: "transparent",
198
+ width: "100%",
199
+ cursor: "pointer",
200
+ }, children: [_jsx("span", { style: {
201
+ ...labelStyle,
202
+ opacity: !veilsEnabled || skyExpanded || skyHover ? 1 : 0,
203
+ transition: "opacity 0.2s ease",
204
+ }, children: activeSky?.label ?? "preset dome" }), _jsx("span", { style: {
205
+ fontSize: "11px",
206
+ color: "var(--viewer-ui-color-text-muted, #64748b)",
207
+ opacity: !veilsEnabled || skyExpanded || skyHover ? 1 : 0,
208
+ transition: "opacity 0.2s ease",
209
+ }, children: skyExpanded ? "▼" : "▲" })] }), veilsEnabled && !skyExpanded && !skyHover ? _jsx("div", { style: veilStyle, children: "BACKGROUND" }) : null] }) })) : null, showAxisChips ? (_jsx(AxisDropdownChip, { caption: "LIGHT", options: rigOptions ?? [], activeId: activeRigId, onSelect: (id) => onRigChange?.(id), expanded: rigExpanded, menuRef: rigMenuRef, onToggle: () => {
210
+ setRigExpanded((prev) => !prev);
211
+ setEnvironmentExpanded(false);
212
+ setMaterialExpanded(false);
213
+ setSkyExpanded(false);
214
+ }, onClose: () => setRigExpanded(false) })) : (_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, index) => (_jsxs(React.Fragment, { children: [shouldShowGroupLabel(lightingOptions, index) ? (_jsx("div", { style: menuGroupLabelStyle, children: option.group })) : null, _jsxs("button", { type: "button", onClick: () => {
135
215
  onLightingChange(option.id);
136
216
  setLightingExpanded(false);
137
217
  }, style: menuButtonStyle(option.id === activeLightingPreset), 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: () => {
@@ -156,10 +236,10 @@ export default function ViewControls({ activeLightingPreset, onLightingChange, m
156
236
  color: "var(--viewer-ui-color-text-muted, #64748b)",
157
237
  opacity: !veilsEnabled || lightingExpanded || lightingHover ? 1 : 0,
158
238
  transition: "opacity 0.2s ease",
159
- }, 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, index) => (_jsxs(React.Fragment, { children: [shouldShowGroupLabel(materialOptions, index) ? (_jsx("div", { style: menuGroupLabelStyle, children: option.group })) : null, _jsxs("button", { type: "button", onClick: () => {
160
- onMaterialChange(option.id);
161
- setMaterialExpanded(false);
162
- }, style: menuButtonStyle(option.id === activeMaterialPreset), children: [_jsx("span", { children: option.label }), option.summary ? (_jsx("span", { style: { fontSize: "10px", opacity: 0.7 }, children: option.summary })) : null, option.swatches && option.swatches.length ? (_jsx("div", { style: swatchRowStyle, children: option.swatches.map((color, swatchIndex) => (_jsx("span", { style: swatchStyle(color) }, `${option.id}-${swatchIndex}`))) })) : null] })] }, option.id))) })) : null, _jsxs("button", { type: "button", onClick: () => {
239
+ }, 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 ? (_jsxs("div", { style: dropdownStyle, children: [_jsx("div", { style: dropdownHeaderStyle, children: "SURFACES" }), materialOptions.map((option, index) => (_jsxs(React.Fragment, { children: [shouldShowGroupLabel(materialOptions, index) ? (_jsx("div", { style: menuGroupLabelStyle, children: option.group })) : null, _jsxs("button", { type: "button", onClick: () => {
240
+ onMaterialChange(option.id);
241
+ setMaterialExpanded(false);
242
+ }, style: menuButtonStyle(option.id === activeMaterialPreset), children: [_jsx("span", { children: option.label }), option.summary ? (_jsx("span", { style: { fontSize: "10px", opacity: 0.7 }, children: option.summary })) : null, option.swatches && option.swatches.length ? (_jsx("div", { style: swatchRowStyle, children: option.swatches.map((color, swatchIndex) => (_jsx("span", { style: swatchStyle(color) }, `${option.id}-${swatchIndex}`))) })) : null] })] }, option.id)))] })) : null, _jsxs("button", { type: "button", onClick: () => {
163
243
  setMaterialExpanded((prev) => !prev);
164
244
  setLightingExpanded(false);
165
245
  setSkyExpanded(false);
@@ -182,7 +262,12 @@ export default function ViewControls({ activeLightingPreset, onLightingChange, m
182
262
  color: "var(--viewer-ui-color-text-muted, #64748b)",
183
263
  opacity: !veilsEnabled || materialExpanded || materialHover ? 1 : 0,
184
264
  transition: "opacity 0.2s ease",
185
- }, children: materialExpanded ? "▼" : "▲" })] }), veilsEnabled && !materialExpanded && !materialHover ? _jsx("div", { style: veilStyle, children: "MATERIALS" }) : null] }) })) : null, onCameraViewChange ? (_jsxs("div", { style: { ...cardStyle, display: "flex" }, onMouseEnter: () => setViewHover(true), onMouseLeave: () => setViewHover(false), children: [_jsx("button", { type: "button", onClick: () => onCameraViewChange("interior"), style: {
265
+ }, children: materialExpanded ? "▼" : "▲" })] }), veilsEnabled && !materialExpanded && !materialHover ? _jsx("div", { style: veilStyle, children: "SURFACES" }) : null] }) })) : null, showAxisChips ? (_jsx(AxisDropdownChip, { caption: "ENVIRONMENT", options: environmentOptions ?? [], activeId: activeEnvironmentId, onSelect: (id) => onEnvironmentChange?.(id), expanded: environmentExpanded, menuRef: environmentMenuRef, onToggle: () => {
266
+ setEnvironmentExpanded((prev) => !prev);
267
+ setRigExpanded(false);
268
+ setMaterialExpanded(false);
269
+ setSkyExpanded(false);
270
+ }, onClose: () => setEnvironmentExpanded(false) })) : null, onCameraViewChange ? (_jsxs("div", { style: { ...cardStyle, display: "flex" }, onMouseEnter: () => setViewHover(true), onMouseLeave: () => setViewHover(false), children: [_jsx("button", { type: "button", onClick: () => onCameraViewChange("interior"), style: {
186
271
  padding: "8px 12px",
187
272
  border: "none",
188
273
  borderRight: "1px solid var(--viewer-ui-color-panel-border, #e2e8f0)",
@@ -199,32 +284,7 @@ export default function ViewControls({ activeLightingPreset, onLightingChange, m
199
284
  minWidth: "84px",
200
285
  ...labelStyle,
201
286
  color: !veilsEnabled || viewHover ? "var(--viewer-ui-color-text-muted, #475569)" : "transparent",
202
- }, children: "perspective" }), veilsEnabled && !viewHover ? _jsx("div", { style: veilStyle, children: "VIEW" }) : null] })) : null, skyOptions.length ? (_jsx("div", { ref: skyMenuRef, children: _jsxs("div", { style: cardStyle, onMouseEnter: () => setSkyHover(true), onMouseLeave: () => setSkyHover(false), children: [skyExpanded ? (_jsx("div", { style: dropdownStyle, children: skyOptions.map((option, index) => (_jsxs(React.Fragment, { children: [shouldShowGroupLabel(skyOptions, index) ? (_jsx("div", { style: menuGroupLabelStyle, children: option.group })) : null, _jsxs("button", { type: "button", onClick: () => {
203
- onSkyChange(option.id);
204
- setSkyExpanded(false);
205
- }, style: menuButtonStyle(option.id === activeSkyId), children: [_jsx("span", { children: option.label }), option.description ? (_jsx("span", { style: { fontSize: "10px", opacity: 0.7 }, children: option.description })) : null] })] }, option.id))) })) : null, _jsxs("button", { type: "button", onClick: () => {
206
- setSkyExpanded((prev) => !prev);
207
- setLightingExpanded(false);
208
- }, style: {
209
- display: "flex",
210
- alignItems: "center",
211
- justifyContent: "space-between",
212
- gap: "10px",
213
- padding: "8px 12px",
214
- border: "none",
215
- background: "transparent",
216
- width: "100%",
217
- cursor: "pointer",
218
- }, children: [_jsx("span", { style: {
219
- ...labelStyle,
220
- opacity: !veilsEnabled || skyExpanded || skyHover ? 1 : 0,
221
- transition: "opacity 0.2s ease",
222
- }, children: activeSky?.label ?? "preset dome" }), _jsx("span", { style: {
223
- fontSize: "11px",
224
- color: "var(--viewer-ui-color-text-muted, #64748b)",
225
- opacity: !veilsEnabled || skyExpanded || skyHover ? 1 : 0,
226
- transition: "opacity 0.2s ease",
227
- }, children: skyExpanded ? "▼" : "▲" })] }), veilsEnabled && !skyExpanded && !skyHover ? _jsx("div", { style: veilStyle, children: "BACKGROUND" }) : null] }) })) : null, extraActions.map((action) => (_jsx("div", { children: _jsx("div", { style: {
287
+ }, children: "perspective" }), veilsEnabled && !viewHover ? _jsx("div", { style: veilStyle, children: "VIEW" }) : null] })) : null, extraActions.map((action) => (_jsx("div", { children: _jsx("div", { style: {
228
288
  ...cardStyle,
229
289
  border: action.active ? "1px solid transparent" : cardStyle.border,
230
290
  }, children: _jsx("button", { type: "button", onClick: action.onClick, style: {