@pascal-app/nodes 1.0.0 → 1.0.1
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/box-vent/panel.js +4 -4
- package/dist/cabinet/appliance-layout.d.ts +26 -0
- package/dist/cabinet/appliance-layout.d.ts.map +1 -0
- package/dist/cabinet/appliance-layout.js +52 -0
- package/dist/cabinet/countertop-layout.d.ts +173 -0
- package/dist/cabinet/countertop-layout.d.ts.map +1 -0
- package/dist/cabinet/countertop-layout.js +80 -0
- package/dist/cabinet/definition.d.ts.map +1 -1
- package/dist/cabinet/definition.js +15 -8
- package/dist/cabinet/geometry/cooktop.d.ts.map +1 -1
- package/dist/cabinet/geometry/cooktop.js +2 -2
- package/dist/cabinet/geometry/run.d.ts.map +1 -1
- package/dist/cabinet/geometry/run.js +10 -71
- package/dist/cabinet/geometry/sink.d.ts +2 -12
- package/dist/cabinet/geometry/sink.d.ts.map +1 -1
- package/dist/cabinet/geometry/sink.js +8 -39
- package/dist/cabinet/hosted-resize.d.ts +8 -0
- package/dist/cabinet/hosted-resize.d.ts.map +1 -0
- package/dist/cabinet/hosted-resize.js +158 -0
- package/dist/cabinet/run-layout.d.ts +8 -1
- package/dist/cabinet/run-layout.d.ts.map +1 -1
- package/dist/cabinet/run-layout.js +22 -14
- package/dist/cabinet/run-ops.d.ts +3 -3
- package/dist/cabinet/run-ops.js +3 -3
- package/dist/cabinet/run-panel.d.ts +1 -1
- package/dist/cabinet/run-panel.d.ts.map +1 -1
- package/dist/cabinet/run-panel.js +16 -7
- package/dist/cabinet/surfaces.d.ts +4 -0
- package/dist/cabinet/surfaces.d.ts.map +1 -0
- package/dist/cabinet/surfaces.js +101 -0
- package/dist/cabinet/tree-structure.d.ts.map +1 -1
- package/dist/cabinet/tree-structure.js +10 -9
- package/dist/ceiling/definition.js +1 -1
- package/dist/ceiling/floorplan-affordances.d.ts +4 -4
- package/dist/ceiling/panel.js +1 -1
- package/dist/chimney/panel.js +9 -9
- package/dist/cupola/panel.js +1 -1
- package/dist/door/panel.js +12 -12
- package/dist/dormer/panel-position-section.js +2 -2
- package/dist/dormer/panel.js +1 -1
- package/dist/duct-segment/parametrics.d.ts.map +1 -1
- package/dist/duct-segment/parametrics.js +5 -1
- package/dist/duct-segment/tool.d.ts +1 -0
- package/dist/duct-segment/tool.d.ts.map +1 -1
- package/dist/duct-segment/tool.js +10 -8
- package/dist/eyebrow-vent/panel.js +1 -1
- package/dist/fence/inspector-editors.js +1 -1
- package/dist/imported-mesh/definition.d.ts +5 -0
- package/dist/imported-mesh/definition.d.ts.map +1 -0
- package/dist/imported-mesh/definition.js +38 -0
- package/dist/imported-mesh/floorplan.d.ts +4 -0
- package/dist/imported-mesh/floorplan.d.ts.map +1 -0
- package/dist/imported-mesh/floorplan.js +34 -0
- package/dist/imported-mesh/geometry.d.ts +5 -0
- package/dist/imported-mesh/geometry.d.ts.map +1 -0
- package/dist/imported-mesh/geometry.js +34 -0
- package/dist/imported-mesh/index.d.ts +4 -0
- package/dist/imported-mesh/index.d.ts.map +1 -0
- package/dist/imported-mesh/index.js +3 -0
- package/dist/imported-mesh/schema.d.ts +2 -0
- package/dist/imported-mesh/schema.d.ts.map +1 -0
- package/dist/imported-mesh/schema.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/item/floorplan-move.d.ts +9 -1
- package/dist/item/floorplan-move.d.ts.map +1 -1
- package/dist/item/floorplan-move.js +55 -2
- package/dist/item/floorplan.d.ts.map +1 -1
- package/dist/item/floorplan.js +11 -0
- package/dist/item/move-tool.js +1 -1
- package/dist/item/panel.js +1 -1
- package/dist/pipe-segment/parametrics.d.ts.map +1 -1
- package/dist/pipe-segment/parametrics.js +5 -1
- package/dist/procedural-item/definition.d.ts +4 -0
- package/dist/procedural-item/definition.d.ts.map +1 -0
- package/dist/procedural-item/definition.js +254 -0
- package/dist/procedural-item/geometry.d.ts +31 -0
- package/dist/procedural-item/geometry.d.ts.map +1 -0
- package/dist/procedural-item/geometry.js +88 -0
- package/dist/procedural-item/index.d.ts +3 -0
- package/dist/procedural-item/index.d.ts.map +1 -0
- package/dist/procedural-item/index.js +2 -0
- package/dist/procedural-item/move-session.d.ts +15 -0
- package/dist/procedural-item/move-session.d.ts.map +1 -0
- package/dist/procedural-item/move-session.js +197 -0
- package/dist/procedural-item/move-tool.d.ts +5 -0
- package/dist/procedural-item/move-tool.d.ts.map +1 -0
- package/dist/procedural-item/move-tool.js +193 -0
- package/dist/procedural-item/renderer.d.ts +5 -0
- package/dist/procedural-item/renderer.d.ts.map +1 -0
- package/dist/procedural-item/renderer.js +66 -0
- package/dist/ridge-vent/panel.js +4 -4
- package/dist/roof/panel.d.ts.map +1 -1
- package/dist/roof/panel.js +7 -5
- package/dist/roof-segment/panel.d.ts.map +1 -1
- package/dist/roof-segment/panel.js +5 -5
- package/dist/shared/automatic-run-end-cap.d.ts +1 -0
- package/dist/shared/automatic-run-end-cap.d.ts.map +1 -1
- package/dist/shared/automatic-run-end-cap.js +10 -0
- package/dist/shared/distribution-run-tool.d.ts +10 -0
- package/dist/shared/distribution-run-tool.d.ts.map +1 -1
- package/dist/shared/distribution-run-tool.js +56 -11
- package/dist/shared/panel-fields.d.ts +15 -0
- package/dist/shared/panel-fields.d.ts.map +1 -0
- package/dist/shared/panel-fields.js +31 -0
- package/dist/shared/resting-surface-plan.d.ts +3 -0
- package/dist/shared/resting-surface-plan.d.ts.map +1 -0
- package/dist/shared/resting-surface-plan.js +28 -0
- package/dist/shelf/definition.d.ts.map +1 -1
- package/dist/shelf/definition.js +2 -1
- package/dist/shelf/floorplan-affordances.d.ts.map +1 -1
- package/dist/shelf/floorplan-affordances.js +5 -3
- package/dist/shelf/floorplan-move.d.ts.map +1 -1
- package/dist/shelf/floorplan-move.js +3 -2
- package/dist/shelf/geometry.d.ts.map +1 -1
- package/dist/shelf/geometry.js +2 -10
- package/dist/skylight/panel.js +6 -6
- package/dist/slab/panel.js +1 -1
- package/dist/solar-panel/panel.js +2 -2
- package/dist/spawn/panel.js +1 -1
- package/dist/stair/panel.d.ts.map +1 -1
- package/dist/stair/panel.js +9 -7
- package/dist/stair-segment/panel.js +4 -4
- package/dist/turbine-vent/panel.js +1 -1
- package/dist/unit/definition.d.ts +10 -0
- package/dist/unit/definition.d.ts.map +1 -0
- package/dist/unit/definition.js +38 -0
- package/dist/unit/index.d.ts +2 -0
- package/dist/unit/index.d.ts.map +1 -0
- package/dist/unit/index.js +1 -0
- package/dist/unit/parametrics.d.ts +3 -0
- package/dist/unit/parametrics.d.ts.map +1 -0
- package/dist/unit/parametrics.js +4 -0
- package/dist/unit/schema.d.ts +2 -0
- package/dist/unit/schema.d.ts.map +1 -0
- package/dist/unit/schema.js +1 -0
- package/dist/unit/unit-panel.d.ts +5 -0
- package/dist/unit/unit-panel.d.ts.map +1 -0
- package/dist/unit/unit-panel.js +61 -0
- package/dist/window/panel.js +6 -6
- package/dist/zone/definition.d.ts.map +1 -1
- package/dist/zone/definition.js +7 -1
- package/dist/zone/floorplan.d.ts +1 -3
- package/dist/zone/floorplan.d.ts.map +1 -1
- package/dist/zone/floorplan.js +43 -28
- package/dist/zone/quantities-panel.d.ts.map +1 -1
- package/dist/zone/quantities-panel.js +33 -29
- package/dist/zone/renderer.d.ts.map +1 -1
- package/dist/zone/renderer.js +20 -6
- package/dist/zone/unit-membership.d.ts +12 -0
- package/dist/zone/unit-membership.d.ts.map +1 -0
- package/dist/zone/unit-membership.js +22 -0
- package/package.json +14 -8
package/dist/ridge-vent/panel.js
CHANGED
|
@@ -102,17 +102,17 @@ export default function RidgeVentPanel() {
|
|
|
102
102
|
], value: node.style ?? 'standard' }), _jsx(SegmentedControl, { onChange: (v) => handleUpdate({ endCaps: v === 'yes' }), options: [
|
|
103
103
|
{ label: 'End Caps', value: 'yes' },
|
|
104
104
|
{ label: 'Open', value: 'no' },
|
|
105
|
-
], value: (node.endCaps ?? true) ? 'yes' : 'no' })] }), _jsxs(PanelSection, { title: "Dimensions", children: [_jsx(SliderControl, { label: "Length", max: 1000, min: 0.5, onChange: (v) => handleUpdate({ length: v }), onCommit: (v) => handleUpdate({ length: v }), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value:
|
|
105
|
+
], value: (node.endCaps ?? true) ? 'yes' : 'no' })] }), _jsxs(PanelSection, { title: "Dimensions", children: [_jsx(SliderControl, { label: "Length", max: 1000, min: 0.5, onChange: (v) => handleUpdate({ length: v }), onCommit: (v) => handleUpdate({ length: v }), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value: node.length }), _jsx(SliderControl, { label: "Width", max: 0.6, min: 0.1, onChange: (v) => handleUpdate({ width: v }), onCommit: (v) => handleUpdate({ width: v }), precision: 2, restoreOnCommit: false, step: 0.01, unit: "m", value: node.width }), _jsx(SliderControl, { label: "Height", max: 0.2, min: 0.03, onChange: (v) => handleUpdate({ height: v }), onCommit: (v) => handleUpdate({ height: v }), precision: 3, restoreOnCommit: false, step: 0.005, unit: "m", value: node.height })] }), _jsxs(PanelSection, { title: "Position", children: [_jsx(SliderControl, { label: "X", max: halfW, min: -halfW, onChange: (v) => handleUpdate({
|
|
106
106
|
position: [v, node.position[1] ?? 0, node.position[2] ?? 0],
|
|
107
107
|
}), onCommit: (v) => handleUpdate({
|
|
108
108
|
position: [v, node.position[1] ?? 0, node.position[2] ?? 0],
|
|
109
|
-
}), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value:
|
|
109
|
+
}), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value: node.position[0] ?? 0 }), _jsx(SliderControl, { label: "Y", onChange: (v) => handleUpdate({
|
|
110
110
|
position: [node.position[0] ?? 0, v, node.position[2] ?? 0],
|
|
111
111
|
}), onCommit: (v) => handleUpdate({
|
|
112
112
|
position: [node.position[0] ?? 0, v, node.position[2] ?? 0],
|
|
113
|
-
}), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value:
|
|
113
|
+
}), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value: node.position[1] ?? 0 }), _jsx(SliderControl, { label: "Z", max: halfD, min: -halfD, onChange: (v) => handleUpdate({
|
|
114
114
|
position: [node.position[0] ?? 0, node.position[1] ?? 0, v],
|
|
115
115
|
}), onCommit: (v) => handleUpdate({
|
|
116
116
|
position: [node.position[0] ?? 0, node.position[1] ?? 0, v],
|
|
117
|
-
}), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value:
|
|
117
|
+
}), precision: 2, restoreOnCommit: false, step: 0.05, unit: "m", value: node.position[2] ?? 0 }), _jsx(SliderControl, { label: "Rotation", max: 180, min: -180, onChange: (deg) => handleUpdate({ rotation: (deg * Math.PI) / 180 }), onCommit: (deg) => handleUpdate({ rotation: (deg * Math.PI) / 180 }), precision: 0, restoreOnCommit: false, step: 1, unit: "\u00B0", value: Math.round(((node.rotation ?? 0) * 180) / Math.PI) })] }), _jsx(PanelSection, { title: "Actions", children: _jsxs(ActionGroup, { children: [_jsx(ActionButton, { icon: _jsx(Move, { className: "h-3.5 w-3.5" }), label: "Move", onClick: handleMove }), _jsx(ActionButton, { icon: _jsx(Copy, { className: "h-3.5 w-3.5" }), label: "Duplicate", onClick: handleDuplicate }), _jsx(ActionButton, { className: "hover:bg-red-500/20", icon: _jsx(Trash2, { className: "h-3.5 w-3.5 text-red-400" }), label: "Delete", onClick: handleDelete })] }) })] }));
|
|
118
118
|
}
|
package/dist/roof/panel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/roof/panel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/roof/panel.tsx"],"names":[],"mappings":"AAkCA,MAAM,CAAC,OAAO,UAAU,SAAS,uCA4gBhC"}
|
package/dist/roof/panel.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useScene, } from '@pascal-app/core';
|
|
4
|
-
import { ActionButton, ActionGroup, duplicateRoofSubtree, PanelSection, PanelWrapper, SegmentedControl, SliderControl, triggerSFX, useEditor, } from '@pascal-app/editor';
|
|
4
|
+
import { ActionButton, ActionGroup, duplicateRoofSubtree, formatLinearMeasurement, PanelSection, PanelWrapper, SegmentedControl, SliderControl, triggerSFX, useEditor, } from '@pascal-app/editor';
|
|
5
5
|
import { useViewer } from '@pascal-app/viewer';
|
|
6
6
|
import { Copy, Move, Plus, Trash2 } from 'lucide-react';
|
|
7
7
|
import { useCallback, useState } from 'react';
|
|
@@ -9,6 +9,8 @@ import { useShallow } from 'zustand/react/shallow';
|
|
|
9
9
|
export default function RoofPanel() {
|
|
10
10
|
const [ventType, setVentType] = useState('box-vent');
|
|
11
11
|
const selectedId = useViewer((s) => s.selection.selectedIds[0]);
|
|
12
|
+
const unit = useViewer((s) => s.unit);
|
|
13
|
+
const metricNotation = useViewer((s) => s.metricNotation);
|
|
12
14
|
const setSelection = useViewer((s) => s.setSelection);
|
|
13
15
|
const updateNode = useScene((s) => s.updateNode);
|
|
14
16
|
const setMovingNode = useEditor((s) => s.setMovingNode);
|
|
@@ -169,10 +171,10 @@ export default function RoofPanel() {
|
|
|
169
171
|
const pos = [...node.position];
|
|
170
172
|
pos[0] = v;
|
|
171
173
|
handleUpdate({ position: pos });
|
|
172
|
-
}, precision: 2, step: 0.05, unit: "m", value:
|
|
174
|
+
}, precision: 2, step: 0.05, unit: "m", value: node.position[0] }), node.support?.kind !== 'roof' && (_jsx(SegmentedControl, { onChange: (mode) => handleUpdate({ support: { kind: mode === 'walls' ? 'walls' : 'level' } }), options: [
|
|
173
175
|
{ label: 'Follows walls', value: 'walls' },
|
|
174
176
|
{ label: 'Custom', value: 'custom' },
|
|
175
|
-
], value: node.support?.kind === 'walls' ? 'walls' : 'custom' })), node.support?.kind === 'walls' ? (_jsxs("div", { className: "px-1 text-[11px] text-muted-foreground", children: ["Currently ",
|
|
177
|
+
], value: node.support?.kind === 'walls' ? 'walls' : 'custom' })), node.support?.kind === 'walls' ? (_jsxs("div", { className: "px-1 text-[11px] text-muted-foreground", children: ["Currently ", formatLinearMeasurement(node.position[1], unit, metricNotation)] })) : (_jsx(SliderControl, { label: "Y", onChange: (v) => {
|
|
176
178
|
const pos = [...node.position];
|
|
177
179
|
pos[1] = v;
|
|
178
180
|
const current = useScene.getState().nodes[node.id];
|
|
@@ -184,11 +186,11 @@ export default function RoofPanel() {
|
|
|
184
186
|
? { support: { kind: 'level' } }
|
|
185
187
|
: {}),
|
|
186
188
|
});
|
|
187
|
-
}, precision: 2, step: 0.05, unit: "m", value:
|
|
189
|
+
}, precision: 2, step: 0.05, unit: "m", value: node.position[1] })), _jsx(SliderControl, { label: "Z", onChange: (v) => {
|
|
188
190
|
const pos = [...node.position];
|
|
189
191
|
pos[2] = v;
|
|
190
192
|
handleUpdate({ position: pos });
|
|
191
|
-
}, precision: 2, step: 0.05, unit: "m", value:
|
|
193
|
+
}, precision: 2, step: 0.05, unit: "m", value: node.position[2] }), _jsx(SliderControl, { label: "Rotation", max: 180, min: -180, onChange: (degrees) => {
|
|
192
194
|
handleUpdate({ rotation: (degrees * Math.PI) / 180 });
|
|
193
195
|
}, precision: 0, step: 1, unit: "\u00B0", value: Math.round((node.rotation * 180) / Math.PI) }), _jsxs("div", { className: "flex gap-1.5 px-1 pt-2 pb-1", children: [_jsx(ActionButton, { label: "-45\u00B0", onClick: () => {
|
|
194
196
|
triggerSFX('sfx:item-rotate');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/roof-segment/panel.tsx"],"names":[],"mappings":"AAkGA,MAAM,CAAC,OAAO,UAAU,gBAAgB,
|
|
1
|
+
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/roof-segment/panel.tsx"],"names":[],"mappings":"AAkGA,MAAM,CAAC,OAAO,UAAU,gBAAgB,uCAsoBvC"}
|
|
@@ -249,21 +249,21 @@ export default function RoofSegmentPanel() {
|
|
|
249
249
|
const showTrimPlanes = shouldShowTrimPlanes(node.metadata);
|
|
250
250
|
const managedLeanToRoofSegment = isManagedLeanToRoofSegment(node.metadata);
|
|
251
251
|
const conicalCoverage = getConicalRoofCoverage(node);
|
|
252
|
-
return (_jsxs(PanelWrapper, { icon: "/icons/roof.webp", onBack: handleBack, onClose: handleClose, title: node.name || 'Roof Segment', width: 300, children: [_jsxs(PanelSection, { title: "Roof Type", children: [_jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS, value: node.roofType, disabled: managedLeanToRoofSegment }), _jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS_2, value: node.roofType, disabled: managedLeanToRoofSegment }), _jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS_3, value: node.roofType, disabled: managedLeanToRoofSegment })] }), node.roofType !== 'conical' && (_jsxs(PanelSection, { title: "Trim", children: [_jsxs(ActionGroup, { children: [_jsx(ActionButton, { icon: showTrimPlanes ? (_jsx(Check, { className: "h-3.5 w-3.5" })) : (_jsx(Pencil, { className: "h-3.5 w-3.5" })), label: showTrimPlanes ? 'Done editing' : 'Edit footprint', onClick: () => (showTrimPlanes ? handleBack() : handleTrimEditing(true)) }), _jsx(ActionButton, { className: "disabled:cursor-not-allowed disabled:opacity-40", disabled: !hasSegmentTrim(node), icon: _jsx(RotateCcw, { className: "h-3.5 w-3.5" }), label: "Reset", onClick: handleResetTrim })] }), node.roofType !== 'shed' && node.roofType !== 'flat' && (_jsx(ToggleControl, { checked: autoRidgeVentEnabled, label: "Auto ridge vent", onChange: handleAutoRidgeVentToggle }))] })), node.roofType !== 'conical' && (_jsx(PanelSection, { title: "Drainage", children: _jsx(ToggleControl, { checked: autoGutterEnabled, label: "Auto gutters", onChange: handleAutoGutterToggle }) })), _jsx(PanelSection, { title: "Footprint", children: node.roofType === 'conical' ? (_jsx(SliderControl, { label: "Diameter", max: 1000, min: 0.5, onChange: (v) => handleUpdate({ width: v, depth: v }), precision: 2, step: 0.5, unit: "m", value:
|
|
252
|
+
return (_jsxs(PanelWrapper, { icon: "/icons/roof.webp", onBack: handleBack, onClose: handleClose, title: node.name || 'Roof Segment', width: 300, children: [_jsxs(PanelSection, { title: "Roof Type", children: [_jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS, value: node.roofType, disabled: managedLeanToRoofSegment }), _jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS_2, value: node.roofType, disabled: managedLeanToRoofSegment }), _jsx(SegmentedControl, { onChange: (v) => handleRoofTypeChange(v), options: ROOF_TYPE_OPTIONS_3, value: node.roofType, disabled: managedLeanToRoofSegment })] }), node.roofType !== 'conical' && (_jsxs(PanelSection, { title: "Trim", children: [_jsxs(ActionGroup, { children: [_jsx(ActionButton, { icon: showTrimPlanes ? (_jsx(Check, { className: "h-3.5 w-3.5" })) : (_jsx(Pencil, { className: "h-3.5 w-3.5" })), label: showTrimPlanes ? 'Done editing' : 'Edit footprint', onClick: () => (showTrimPlanes ? handleBack() : handleTrimEditing(true)) }), _jsx(ActionButton, { className: "disabled:cursor-not-allowed disabled:opacity-40", disabled: !hasSegmentTrim(node), icon: _jsx(RotateCcw, { className: "h-3.5 w-3.5" }), label: "Reset", onClick: handleResetTrim })] }), node.roofType !== 'shed' && node.roofType !== 'flat' && (_jsx(ToggleControl, { checked: autoRidgeVentEnabled, label: "Auto ridge vent", onChange: handleAutoRidgeVentToggle }))] })), node.roofType !== 'conical' && (_jsx(PanelSection, { title: "Drainage", children: _jsx(ToggleControl, { checked: autoGutterEnabled, label: "Auto gutters", onChange: handleAutoGutterToggle }) })), _jsx(PanelSection, { title: "Footprint", children: node.roofType === 'conical' ? (_jsx(SliderControl, { label: "Diameter", max: 1000, min: 0.5, onChange: (v) => handleUpdate({ width: v, depth: v }), precision: 2, step: 0.5, unit: "m", value: node.width })) : (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: "Width", max: 1000, min: 0.5, onChange: (v) => handleUpdate({ width: v }), precision: 2, step: 0.5, unit: "m", value: node.width }), _jsx(SliderControl, { label: "Depth", max: 1000, min: 0.5, onChange: (v) => handleUpdate({ depth: v }), precision: 2, step: 0.5, unit: "m", value: node.depth })] })) }), node.roofType === 'conical' && (_jsxs(PanelSection, { title: "Conical Shape", children: [_jsx(ToggleControl, { checked: !conicalCoverage.fullCircle, label: "Clipped version", onChange: (checked) => handleUpdate({ conicalFullCircle: !checked }) }), !conicalCoverage.fullCircle && (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: "Start Angle", max: 180, min: -180, onChange: (degrees) => handleUpdate({ conicalStartAngle: (degrees * Math.PI) / 180 }), precision: 0, step: 1, unit: "\u00B0", value: Math.round((conicalCoverage.startAngle * 180) / Math.PI) }), _jsx(SliderControl, { label: "Arc", max: 345, min: 15, onChange: (degrees) => handleUpdate({
|
|
253
253
|
conicalSweepAngle: (Math.sign(conicalCoverage.sweepAngle) * degrees * Math.PI) / 180,
|
|
254
|
-
}), precision: 0, step: 1, unit: "\u00B0", value: Math.round((Math.abs(conicalCoverage.sweepAngle) * 180) / Math.PI) })] }))] })), _jsx(PanelSection, { title: "Wall Height", children: _jsx(SliderControl, { label: "Wall", max: 1000, min: 0, onChange: (v) => handleUpdate({ wallHeight: v }), precision: 2, step: 0.1, unit: "m", value:
|
|
254
|
+
}), precision: 0, step: 1, unit: "\u00B0", value: Math.round((Math.abs(conicalCoverage.sweepAngle) * 180) / Math.PI) })] }))] })), _jsx(PanelSection, { title: "Wall Height", children: _jsx(SliderControl, { label: "Wall", max: 1000, min: 0, onChange: (v) => handleUpdate({ wallHeight: v }), precision: 2, step: 0.1, unit: "m", value: node.wallHeight }) }), _jsxs(PanelSection, { title: "Pitch", children: [_jsx(SliderControl, { label: "Angle", max: 60, min: 0, onChange: (v) => handleUpdate({ pitch: v }), precision: 0, step: 1, unit: "\u00B0", value: Math.round(node.pitch) }), _jsx("div", { className: "flex gap-1.5 px-1 pt-2 pb-1", children: PITCH_PRESETS.map((preset) => (_jsx(ActionButton, { label: preset.label, onClick: () => handleUpdate({ pitch: preset.deg }) }, preset.label))) })] }), node.roofType === 'gambrel' && (_jsxs(PanelSection, { title: "Shape", children: [_jsx(SliderControl, { label: "Kink Depth", max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ gambrelLowerWidthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.gambrelLowerWidthRatio * 100) / 100 }), _jsx(SliderControl, { label: "Kink Height", max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ gambrelLowerHeightRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.gambrelLowerHeightRatio * 100) / 100 })] })), node.roofType === 'mansard' && (_jsxs(PanelSection, { title: "Shape", children: [_jsx(SliderControl, { label: "Waist Width", max: 0.45, min: 0.05, onChange: (v) => handleUpdate({ mansardSteepWidthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.mansardSteepWidthRatio * 100) / 100 }), _jsx(SliderControl, { label: "Waist Height", max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ mansardSteepHeightRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.mansardSteepHeightRatio * 100) / 100 })] })), node.roofType === 'dutch' && (_jsxs(PanelSection, { title: "Shape", children: [_jsx(SliderControl, { label: "Waist Width", max: 0.45, min: 0.05, onChange: (v) => handleUpdate({ dutchHipWidthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.dutchHipWidthRatio * 100) / 100 }), _jsx(SliderControl, { label: "Waist Height", max: 0.9, min: 0.1, onChange: (v) => handleUpdate({ dutchHipHeightRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round(node.dutchHipHeightRatio * 100) / 100 }), _jsx(SliderControl, { label: "Waist Length", max: 1, min: 0.1, onChange: (v) => handleUpdate({ dutchWaistLengthRatio: v }), precision: 2, step: 0.01, unit: "", value: Math.round((node.dutchWaistLengthRatio ?? ROOF_SHAPE_DEFAULTS.dutchWaistLengthRatio) * 100) / 100 }), _jsx(SliderControl, { label: "Top Rake Thick.", max: 0.5, min: 0.01, onChange: (v) => handleUpdate({ dutchTopRakeThickness: v }), precision: 2, step: 0.01, unit: "m", value: node.dutchTopRakeThickness ?? ROOF_SHAPE_DEFAULTS.dutchTopRakeThickness }), _jsx(SliderControl, { label: "Top Rake Length", max: 3, min: 0, onChange: (v) => handleUpdate({ dutchGabletRake: v }), precision: 2, step: 0.01, unit: "m", value: node.dutchGabletRake ?? ROOF_SHAPE_DEFAULTS.dutchGabletRake })] })), _jsxs(PanelSection, { title: "Structure", children: [_jsx(SliderControl, { label: "Wall Thick.", max: 1, min: 0.05, onChange: (v) => handleUpdate({ wallThickness: v }), precision: 2, step: 0.05, unit: "m", value: node.wallThickness }), _jsx(SliderControl, { label: "Deck Thick.", max: 0.3, min: 0.04, onChange: (v) => handleUpdate({ deckThickness: v }), precision: 2, step: 0.01, unit: "m", value: node.deckThickness }), _jsx(SliderControl, { label: "Overhang", max: 1, min: 0, onChange: (v) => handleUpdate({ overhang: v }), precision: 2, step: 0.05, unit: "m", value: node.overhang }), _jsx(SliderControl, { label: "Shingle Thick.", max: 0.3, min: 0.02, onChange: (v) => handleUpdate({ shingleThickness: v }), precision: 2, step: 0.01, unit: "m", value: node.shingleThickness })] }), _jsxs(PanelSection, { title: "Position", children: [_jsx(SliderControl, { label: "X", onChange: (v) => {
|
|
255
255
|
const pos = [...node.position];
|
|
256
256
|
pos[0] = v;
|
|
257
257
|
handleUpdate({ position: pos });
|
|
258
|
-
}, precision: 2, step: 0.05, unit: "m", value:
|
|
258
|
+
}, precision: 2, step: 0.05, unit: "m", value: node.position[0] }), _jsx(SliderControl, { label: "Y", onChange: (v) => {
|
|
259
259
|
const pos = [...node.position];
|
|
260
260
|
pos[1] = v;
|
|
261
261
|
handleUpdate({ position: pos });
|
|
262
|
-
}, precision: 2, step: 0.05, unit: "m", value:
|
|
262
|
+
}, precision: 2, step: 0.05, unit: "m", value: node.position[1] }), _jsx(SliderControl, { label: "Z", onChange: (v) => {
|
|
263
263
|
const pos = [...node.position];
|
|
264
264
|
pos[2] = v;
|
|
265
265
|
handleUpdate({ position: pos });
|
|
266
|
-
}, precision: 2, step: 0.05, unit: "m", value:
|
|
266
|
+
}, precision: 2, step: 0.05, unit: "m", value: node.position[2] }), (node.roofType !== 'conical' || !conicalCoverage.fullCircle) && (_jsxs(_Fragment, { children: [_jsx(SliderControl, { label: "Rotation", max: 180, min: -180, onChange: (degrees) => {
|
|
267
267
|
handleUpdate({ rotation: (degrees * Math.PI) / 180 });
|
|
268
268
|
}, precision: 0, step: 1, unit: "\u00B0", value: Math.round((node.rotation * 180) / Math.PI) }), _jsxs("div", { className: "flex gap-1.5 px-1 pt-2 pb-1", children: [_jsx(ActionButton, { label: "-45\u00B0", onClick: () => {
|
|
269
269
|
triggerSFX('sfx:item-rotate');
|
|
@@ -4,6 +4,7 @@ export declare function createDuctRunEndCap(duct: DuctSegmentNode, endpoint?: 's
|
|
|
4
4
|
export declare function createPipeRunEndCap(pipe: PipeSegmentNode, endpoint?: 'start' | 'end'): PipeFittingNode | null;
|
|
5
5
|
export declare function isRunEndCapPort(port: ScenePort, nodes: Readonly<Record<string, AnyNode>>): boolean;
|
|
6
6
|
export declare function findMatedRunEndCapIds(source: ScenePort | null, nodes: Readonly<Record<string, AnyNode>>, fittingKind: 'duct-fitting' | 'pipe-fitting'): AnyNodeId[];
|
|
7
|
+
export declare function findAutomaticRunEndCapIds(runId: AnyNodeId, nodes: Readonly<Record<string, AnyNode>>, fittingKind: 'duct-fitting' | 'pipe-fitting'): AnyNodeId[];
|
|
7
8
|
export declare function planRunEndCapFollowUpdates(originalRun: DuctSegmentNode | PipeSegmentNode, nextRun: DuctSegmentNode | PipeSegmentNode, endpoint: 'start' | 'end', nodes: Readonly<Record<string, AnyNode>>): {
|
|
8
9
|
id: AnyNodeId;
|
|
9
10
|
data: Partial<AnyNode>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"automatic-run-end-cap.d.ts","sourceRoot":"","sources":["../../src/shared/automatic-run-end-cap.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,eAAe,EACf,KAAK,eAAe,EACpB,eAAe,EACf,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAA;AAMzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAyCxC,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,eAAe,EACrB,QAAQ,GAAE,OAAO,GAAG,KAAa,GAChC,eAAe,GAAG,IAAI,CAwCxB;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,eAAe,EACrB,QAAQ,GAAE,OAAO,GAAG,KAAa,GAChC,eAAe,GAAG,IAAI,CAgCxB;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,OAAO,CAMT;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,GAAG,IAAI,EACxB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,WAAW,EAAE,cAAc,GAAG,cAAc,GAC3C,SAAS,EAAE,CAgBb;AAED,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,eAAe,GAAG,eAAe,EAC9C,OAAO,EAAE,eAAe,GAAG,eAAe,EAC1C,QAAQ,EAAE,OAAO,GAAG,KAAK,EACzB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC;IAAE,EAAE,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,EAAE,CAwB7C"}
|
|
1
|
+
{"version":3,"file":"automatic-run-end-cap.d.ts","sourceRoot":"","sources":["../../src/shared/automatic-run-end-cap.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,eAAe,EACf,KAAK,eAAe,EACpB,eAAe,EACf,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAA;AAMzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAyCxC,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,eAAe,EACrB,QAAQ,GAAE,OAAO,GAAG,KAAa,GAChC,eAAe,GAAG,IAAI,CAwCxB;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,eAAe,EACrB,QAAQ,GAAE,OAAO,GAAG,KAAa,GAChC,eAAe,GAAG,IAAI,CAgCxB;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,OAAO,CAMT;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,GAAG,IAAI,EACxB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,WAAW,EAAE,cAAc,GAAG,cAAc,GAC3C,SAAS,EAAE,CAgBb;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,WAAW,EAAE,cAAc,GAAG,cAAc,GAC3C,SAAS,EAAE,CAWb;AAED,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,eAAe,GAAG,eAAe,EAC9C,OAAO,EAAE,eAAe,GAAG,eAAe,EAC1C,QAAQ,EAAE,OAAO,GAAG,KAAK,EACzB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC;IAAE,EAAE,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,EAAE,CAwB7C"}
|
|
@@ -130,6 +130,16 @@ export function findMatedRunEndCapIds(source, nodes, fittingKind) {
|
|
|
130
130
|
}
|
|
131
131
|
return ids;
|
|
132
132
|
}
|
|
133
|
+
export function findAutomaticRunEndCapIds(runId, nodes, fittingKind) {
|
|
134
|
+
return Object.values(nodes).flatMap((node) => {
|
|
135
|
+
if (!node ||
|
|
136
|
+
node.type !== fittingKind ||
|
|
137
|
+
node.fittingType !== 'end-cap' ||
|
|
138
|
+
node.metadata[END_CAP_OWNER_ID_KEY] !== runId)
|
|
139
|
+
return [];
|
|
140
|
+
return [node.id];
|
|
141
|
+
});
|
|
142
|
+
}
|
|
133
143
|
export function planRunEndCapFollowUpdates(originalRun, nextRun, endpoint, nodes) {
|
|
134
144
|
if (originalRun.type !== nextRun.type)
|
|
135
145
|
return [];
|
|
@@ -29,6 +29,16 @@ export type CameraDirectionProjection = {
|
|
|
29
29
|
point: RunPoint;
|
|
30
30
|
direction: RunPoint;
|
|
31
31
|
};
|
|
32
|
+
type RunWallSurfaceTarget = Extract<RunSurfaceTarget, {
|
|
33
|
+
kind: 'wall';
|
|
34
|
+
}>;
|
|
35
|
+
export declare function shouldLockRunWallSurface(target: RunSurfaceTarget | null | undefined, connection: RunConnection): target is RunWallSurfaceTarget;
|
|
36
|
+
export declare function isSameRunWallSurface(target: RunWallSurfaceTarget, hit: {
|
|
37
|
+
kind?: string;
|
|
38
|
+
hostId?: string;
|
|
39
|
+
face?: string;
|
|
40
|
+
side?: string;
|
|
41
|
+
} | undefined): boolean;
|
|
32
42
|
/** Build a stable 2D drawing frame for a floor, wall, ceiling, or sloped face. */
|
|
33
43
|
export declare function createRunSurfaceFrame(origin: readonly number[], surfaceNormal?: readonly number[]): RunSurfaceFrame;
|
|
34
44
|
export declare function projectRunPointToSurface(point: readonly number[], frame: RunSurfaceFrame): RunPoint;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"distribution-run-tool.d.ts","sourceRoot":"","sources":["../../src/shared/distribution-run-tool.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAoD,MAAM,kBAAkB,CAAA;AACnG,OAAO,EAIL,KAAK,iBAAiB,EAUvB,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EAAE,KAAK,SAAS,EAA4C,MAAM,OAAO,CAAA;AAEhF,OAAO,EAAE,KAAK,KAAK,EAAW,MAAM,OAAO,CAAA;AAC3C,OAAO,KAAK,EAAoB,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAErF,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAEpD,OAAO,EAEL,KAAK,gBAAgB,EAGtB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGtE,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE/C,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,QAAQ,CAAA;IAChB,MAAM,EAAE,QAAQ,CAAA;IAChB,OAAO,EAAE,QAAQ,CAAA;IACjB,SAAS,EAAE,QAAQ,CAAA;CACpB,CAAA;AAID,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,SAAS,GAAG,IAAI,CAAA;IACtB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,QAAQ,CAAA;IACnB,cAAc,EAAE,aAAa,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,QAAQ,CAAA;IAChB,SAAS,EAAE,QAAQ,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,EAAE,QAAQ,CAAA;IACf,SAAS,EAAE,QAAQ,CAAA;CACpB,CAAA;
|
|
1
|
+
{"version":3,"file":"distribution-run-tool.d.ts","sourceRoot":"","sources":["../../src/shared/distribution-run-tool.tsx"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,15 @@ import { resolveRunCursorPlane } from './run-cursor';
|
|
|
12
12
|
import { RunDirectionFeedback, run3DDirectionCandidates, runHorizontalDirectionCandidates, } from './run-direction-feedback';
|
|
13
13
|
import { findScreenPort } from './run-port-snap';
|
|
14
14
|
import { chooseScreenDirection, screenDirectionScore } from './run-screen-direction';
|
|
15
|
+
export function shouldLockRunWallSurface(target, connection) {
|
|
16
|
+
return target?.kind === 'wall' && !connection.port && !connection.body;
|
|
17
|
+
}
|
|
18
|
+
export function isSameRunWallSurface(target, hit) {
|
|
19
|
+
return (hit?.kind === 'wall' &&
|
|
20
|
+
hit.hostId === target.hostId &&
|
|
21
|
+
hit.face === 'side' &&
|
|
22
|
+
hit.side === target.side);
|
|
23
|
+
}
|
|
15
24
|
const UP = [0, 1, 0];
|
|
16
25
|
const X_AXIS = [1, 0, 0];
|
|
17
26
|
const Z_AXIS = [0, 0, 1];
|
|
@@ -347,6 +356,7 @@ export function useDistributionRunTool(config) {
|
|
|
347
356
|
const refreshCursorRef = useRef(() => { });
|
|
348
357
|
const lastClientYRef = useRef(null);
|
|
349
358
|
const lastResolvedRef = useRef(null);
|
|
359
|
+
const lockedWallTargetRef = useRef(null);
|
|
350
360
|
const forcedDirectionRef = useRef(null);
|
|
351
361
|
const hoveredDirectionRef = useRef(null);
|
|
352
362
|
const lengthInputRef = useRef('');
|
|
@@ -409,17 +419,29 @@ export function useDistributionRunTool(config) {
|
|
|
409
419
|
const hit = surfacePointFromEvent(event, adapter.levelId);
|
|
410
420
|
const currentStart = startRef.current;
|
|
411
421
|
const previous = lastResolvedRef.current;
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
422
|
+
const lockedWallTarget = currentStart ? lockedWallTargetRef.current : null;
|
|
423
|
+
const lockedWallHit = lockedWallTarget && isSameRunWallSurface(lockedWallTarget, event.surfaceHit);
|
|
424
|
+
const working = lockedWallTarget
|
|
425
|
+
? {
|
|
426
|
+
...lockedWallTarget.frame,
|
|
427
|
+
origin: lockedWallTarget.frame.origin.map((value, index) => value +
|
|
428
|
+
lockedWallTarget.frame.normal[index] *
|
|
429
|
+
(adapter.surfaceClearance?.(lockedWallTarget) ?? 0)),
|
|
430
|
+
}
|
|
431
|
+
: !event.surfaceHit && previous?.surfaceTarget?.kind === 'wall' && currentStart
|
|
432
|
+
? createRunSurfaceFrame(currentStart, UP)
|
|
433
|
+
: (previous?.frame ?? (currentStart ? createRunSurfaceFrame(currentStart) : null));
|
|
419
434
|
const hasSurface = !!event.surfaceHit || !working || !event.localRay;
|
|
420
|
-
const target = hasSurface ? hit.target : null;
|
|
435
|
+
const target = lockedWallTarget ?? (hasSurface ? hit.target : null);
|
|
436
|
+
const hitForCursor = lockedWallTarget
|
|
437
|
+
? lockedWallHit
|
|
438
|
+
? { point: hit.point, frame: lockedWallTarget.frame }
|
|
439
|
+
: null
|
|
440
|
+
: hasSurface
|
|
441
|
+
? { point: hit.point, frame: hit.frame }
|
|
442
|
+
: null;
|
|
421
443
|
const resolved = resolveRunCursorPlane({
|
|
422
|
-
hit:
|
|
444
|
+
hit: hitForCursor,
|
|
423
445
|
working,
|
|
424
446
|
ray: event.localRay,
|
|
425
447
|
fallback: previous?.point ?? currentStart ?? hit.point,
|
|
@@ -592,7 +614,7 @@ export function useDistributionRunTool(config) {
|
|
|
592
614
|
resolved = {
|
|
593
615
|
...resolved,
|
|
594
616
|
frame: { ...lastResolvedRef.current.frame, origin: resolved.point },
|
|
595
|
-
surfaceTarget:
|
|
617
|
+
surfaceTarget: lockedWallTargetRef.current,
|
|
596
618
|
};
|
|
597
619
|
lastResolvedRef.current = resolved;
|
|
598
620
|
const currentStart = startRef.current;
|
|
@@ -654,6 +676,24 @@ export function useDistributionRunTool(config) {
|
|
|
654
676
|
setValidationMessage('Fitting clearance is too small for this connection');
|
|
655
677
|
return;
|
|
656
678
|
}
|
|
679
|
+
const lockedWallTarget = lockedWallTargetRef.current;
|
|
680
|
+
if (lockedWallTarget) {
|
|
681
|
+
const offset = result.nextStart.map((value, index) => value - lockedWallTarget.frame.origin[index]);
|
|
682
|
+
const clearance = configRef.current.surfaceClearance?.(lockedWallTarget) ?? 0;
|
|
683
|
+
if (Math.abs(dotRun(offset, lockedWallTarget.frame.normal) - clearance) > 1e-4) {
|
|
684
|
+
lockedWallTargetRef.current = null;
|
|
685
|
+
lastResolvedRef.current = {
|
|
686
|
+
point: result.nextStart,
|
|
687
|
+
frame: createRunSurfaceFrame(result.nextStart),
|
|
688
|
+
surfaceTarget: null,
|
|
689
|
+
snapped: null,
|
|
690
|
+
directionMode: 'free',
|
|
691
|
+
port: null,
|
|
692
|
+
body: null,
|
|
693
|
+
};
|
|
694
|
+
clearPlacementSurface();
|
|
695
|
+
}
|
|
696
|
+
}
|
|
657
697
|
triggerSFX('sfx:item-place');
|
|
658
698
|
startRef.current = result.nextStart;
|
|
659
699
|
setStart(result.nextStart);
|
|
@@ -706,11 +746,14 @@ export function useDistributionRunTool(config) {
|
|
|
706
746
|
const resolved = applyTypedLength(resolvePoint(event));
|
|
707
747
|
updateCursor(resolved);
|
|
708
748
|
if (!currentStart) {
|
|
709
|
-
triggerSFX('sfx:grid-snap');
|
|
710
749
|
const connection = {
|
|
711
750
|
port: resolved.port,
|
|
712
751
|
body: resolved.port ? null : resolved.body,
|
|
713
752
|
};
|
|
753
|
+
if (shouldLockRunWallSurface(resolved.surfaceTarget, connection)) {
|
|
754
|
+
lockedWallTargetRef.current = resolved.surfaceTarget;
|
|
755
|
+
}
|
|
756
|
+
triggerSFX('sfx:grid-snap');
|
|
714
757
|
startConnectionRef.current = connection;
|
|
715
758
|
configRef.current.inheritFromConnection?.(connection);
|
|
716
759
|
startRef.current = resolved.point;
|
|
@@ -805,6 +848,7 @@ export function useDistributionRunTool(config) {
|
|
|
805
848
|
setDirectionMode('free');
|
|
806
849
|
};
|
|
807
850
|
const onCancel = () => {
|
|
851
|
+
lockedWallTargetRef.current = null;
|
|
808
852
|
clearDrawAlignment();
|
|
809
853
|
if (!startRef.current)
|
|
810
854
|
return;
|
|
@@ -857,6 +901,7 @@ export function useDistributionRunTool(config) {
|
|
|
857
901
|
window.removeEventListener('keyup', onKeyUp);
|
|
858
902
|
altAnchorRef.current = null;
|
|
859
903
|
lastPointerRef.current = null;
|
|
904
|
+
lockedWallTargetRef.current = null;
|
|
860
905
|
refreshCursorRef.current = () => { };
|
|
861
906
|
clearPlacementSurface();
|
|
862
907
|
clearDrawAlignment();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare function PanelTextField({ label, onCommit, value, }: {
|
|
2
|
+
label: string;
|
|
3
|
+
onCommit: (value: string) => void;
|
|
4
|
+
value: string;
|
|
5
|
+
}): import("react").JSX.Element;
|
|
6
|
+
export declare function PanelSelect({ label, onChange, options, value, }: {
|
|
7
|
+
label: string;
|
|
8
|
+
onChange: (value: string) => void;
|
|
9
|
+
options: ReadonlyArray<{
|
|
10
|
+
label: string;
|
|
11
|
+
value: string;
|
|
12
|
+
}>;
|
|
13
|
+
value: string;
|
|
14
|
+
}): import("react").JSX.Element;
|
|
15
|
+
//# sourceMappingURL=panel-fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panel-fields.d.ts","sourceRoot":"","sources":["../../src/shared/panel-fields.tsx"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,QAAQ,EACR,KAAK,GACN,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,KAAK,EAAE,MAAM,CAAA;CACd,+BAoCA;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,OAAO,EACP,KAAK,GACN,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,OAAO,EAAE,aAAa,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxD,KAAK,EAAE,MAAM,CAAA;CACd,+BAiBA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
export function PanelTextField({ label, onCommit, value, }) {
|
|
5
|
+
const [draft, setDraft] = useState(value);
|
|
6
|
+
const cancelRef = useRef(false);
|
|
7
|
+
useEffect(() => setDraft(value), [value]);
|
|
8
|
+
const commit = () => {
|
|
9
|
+
if (cancelRef.current) {
|
|
10
|
+
cancelRef.current = false;
|
|
11
|
+
setDraft(value);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const next = draft.trim();
|
|
15
|
+
if (next !== value)
|
|
16
|
+
onCommit(next);
|
|
17
|
+
else
|
|
18
|
+
setDraft(value);
|
|
19
|
+
};
|
|
20
|
+
return (_jsxs("label", { className: "flex h-10 items-center gap-3 rounded-lg border border-border/50 bg-[#2C2C2E] px-3 text-sm", children: [_jsx("span", { className: "shrink-0 text-muted-foreground", children: label }), _jsx("input", { className: "min-w-0 flex-1 bg-transparent text-right text-foreground outline-none selection:bg-primary/30", onBlur: commit, onChange: (event) => setDraft(event.target.value), onKeyDown: (event) => {
|
|
21
|
+
if (event.key === 'Enter')
|
|
22
|
+
event.currentTarget.blur();
|
|
23
|
+
if (event.key === 'Escape') {
|
|
24
|
+
cancelRef.current = true;
|
|
25
|
+
event.currentTarget.blur();
|
|
26
|
+
}
|
|
27
|
+
}, type: "text", value: draft })] }));
|
|
28
|
+
}
|
|
29
|
+
export function PanelSelect({ label, onChange, options, value, }) {
|
|
30
|
+
return (_jsxs("label", { className: "flex h-10 items-center justify-between gap-3 rounded-lg border border-border/50 bg-[#2C2C2E] px-3 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: label }), _jsx("select", { className: "min-w-0 rounded-md border border-border/50 bg-[#232325] px-2 py-1 text-foreground text-xs outline-none", onChange: (event) => onChange(event.target.value), value: value, children: options.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value))) })] }));
|
|
31
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type AnyNode, type AnyNodeId } from '@pascal-app/core';
|
|
2
|
+
export declare function restingNodePlanFrame(node: AnyNode, resolve: (id: AnyNodeId) => AnyNode | undefined): import("@pascal-app/core/procedural-items").Frame;
|
|
3
|
+
//# sourceMappingURL=resting-surface-plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resting-surface-plan.d.ts","sourceRoot":"","sources":["../../src/shared/resting-surface-plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAAuC,MAAM,kBAAkB,CAAA;AAGpG,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,GAAG,SAAS,qDAwBhD"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { getEffectiveNode, useLiveTransforms } from '@pascal-app/core';
|
|
2
|
+
import { nodeLevelFrame } from '@pascal-app/core/procedural-items';
|
|
3
|
+
export function restingNodePlanFrame(node, resolve) {
|
|
4
|
+
const nodes = { [node.id]: node };
|
|
5
|
+
let id = node.parentId;
|
|
6
|
+
const visited = new Set([node.id]);
|
|
7
|
+
while (id && !visited.has(id)) {
|
|
8
|
+
visited.add(id);
|
|
9
|
+
const parent = resolve(id);
|
|
10
|
+
if (!parent)
|
|
11
|
+
break;
|
|
12
|
+
const effective = getEffectiveNode(parent);
|
|
13
|
+
const live = useLiveTransforms.getState().get(parent.id);
|
|
14
|
+
nodes[id] =
|
|
15
|
+
live &&
|
|
16
|
+
(parent.type === 'shelf' || parent.type === 'cabinet' || parent.type === 'procedural-item')
|
|
17
|
+
? {
|
|
18
|
+
...effective,
|
|
19
|
+
position: live.position,
|
|
20
|
+
rotation: parent.type === 'cabinet' ? live.rotation : [0, live.rotation, 0],
|
|
21
|
+
}
|
|
22
|
+
: effective;
|
|
23
|
+
if (parent.type === 'level')
|
|
24
|
+
break;
|
|
25
|
+
id = parent.parentId;
|
|
26
|
+
}
|
|
27
|
+
return nodeLevelFrame(node.id, nodes);
|
|
28
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/shelf/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,cAAc,EAA8B,MAAM,kBAAkB,CAAA;AAQpG,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AA4HpC,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,OAAO,SAAS,
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/shelf/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,cAAc,EAA8B,MAAM,kBAAkB,CAAA;AAQpG,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AA4HpC,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,OAAO,SAAS,CAwJ5D,CAAA"}
|
package/dist/shelf/definition.js
CHANGED
|
@@ -194,7 +194,7 @@ export const shelfDefinition = {
|
|
|
194
194
|
// declared here so the placement coordinator's shelf strategy can
|
|
195
195
|
// confirm parent-kind compatibility before reparenting.
|
|
196
196
|
relations: {
|
|
197
|
-
hosts: ['item'],
|
|
197
|
+
hosts: ['item', 'procedural-item'],
|
|
198
198
|
cascadeDelete: 'descendants',
|
|
199
199
|
},
|
|
200
200
|
parametrics: shelfParametrics,
|
|
@@ -209,6 +209,7 @@ export const shelfDefinition = {
|
|
|
209
209
|
// Boards/posts/back depend only on these fields — never on hosted
|
|
210
210
|
// `children`. Lets <GeometrySystem> skip the dispose+rebuild (and the
|
|
211
211
|
// pointer enter/leave churn it causes) when an item reparents onto a row.
|
|
212
|
+
geometryChildTypes: [],
|
|
212
213
|
geometryKey: (n) => {
|
|
213
214
|
const s = sanitizeShelfDimensions(n);
|
|
214
215
|
return JSON.stringify([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/shelf/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/shelf/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,SAAS,EAGf,MAAM,kBAAkB,CAAA;AASzB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,OAAO,GAAG,OAAO,CAAA;IAGtB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC3B,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,mBAAmB,CAAC,SAAS,CAoChE,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,EAAE,mBAAmB,CAAC,SAAS,CAkChE,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
1
|
+
import { cascadeDirty, createSceneApi, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
2
2
|
import { isAngleSnapActive } from '@pascal-app/editor';
|
|
3
3
|
import { rotateAffordanceDelta } from '../shared/rotate-affordance';
|
|
4
4
|
// Mirror the 3D handles in `shelf/definition.ts` so a drag can't push a
|
|
@@ -32,7 +32,8 @@ export const shelfResizeAffordance = {
|
|
|
32
32
|
lastPatch = { depth: Math.max(MIN_SHELF_DEPTH, initialDepth + 2 * projDelta) };
|
|
33
33
|
}
|
|
34
34
|
useLiveNodeOverrides.getState().set(shelfId, lastPatch);
|
|
35
|
-
|
|
35
|
+
for (const id of cascadeDirty(shelfId, { scene: createSceneApi(useScene) }))
|
|
36
|
+
useScene.getState().markDirty(id);
|
|
36
37
|
},
|
|
37
38
|
canCommit() {
|
|
38
39
|
return true;
|
|
@@ -79,7 +80,8 @@ export const shelfRotateAffordance = {
|
|
|
79
80
|
const newRotationY = initialRotationY - delta;
|
|
80
81
|
lastRotation = [r[0], newRotationY, r[2]];
|
|
81
82
|
useLiveNodeOverrides.getState().set(shelfId, { rotation: lastRotation });
|
|
82
|
-
|
|
83
|
+
for (const id of cascadeDirty(shelfId, { scene: createSceneApi(useScene) }))
|
|
84
|
+
useScene.getState().markDirty(id);
|
|
83
85
|
},
|
|
84
86
|
canCommit() {
|
|
85
87
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/shelf/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/shelf/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,mBAAmB,EAGxB,KAAK,SAAS,EAGf,MAAM,kBAAkB,CAAA;AAYzB;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,EAAE,mBAAmB,CAAC,SAAS,CAsEnE,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { collectAlignmentAnchors, movingFootprintAnchors, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
1
|
+
import { cascadeDirty, collectAlignmentAnchors, createSceneApi, movingFootprintAnchors, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
2
2
|
import { applyFloorplanAlignment, getFloorStackPreviewPosition, getSegmentGridStep, isGridSnapActive, isMagneticSnapActive, triggerSFX, } from '@pascal-app/editor';
|
|
3
3
|
import { createFloorplanCursorResolver } from '../shared/floorplan-cursor';
|
|
4
4
|
/**
|
|
@@ -52,7 +52,8 @@ export const shelfFloorplanMoveTarget = ({ node, nodes }) => {
|
|
|
52
52
|
});
|
|
53
53
|
lastVisualPosition = visualPosition;
|
|
54
54
|
useLiveNodeOverrides.getState().set(shelfId, { position: visualPosition });
|
|
55
|
-
|
|
55
|
+
for (const id of cascadeDirty(shelfId, { scene: createSceneApi(useScene) }))
|
|
56
|
+
useScene.getState().markDirty(id);
|
|
56
57
|
},
|
|
57
58
|
canCommit() {
|
|
58
59
|
const live = useScene.getState().nodes[shelfId];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../src/shelf/geometry.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../src/shelf/geometry.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EAGrB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAIL,KAAK,aAAa,EAEnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAe,KAAK,EAAuB,MAAM,OAAO,CAAA;AAE/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AA0EzC,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,SAAS,EAClB,GAAG,CAAC,EAAE,eAAe,EACrB,OAAO,GAAE,aAA0B,GAClC,KAAK,CAkCP;AAySD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,EAAE,CAM3D"}
|
package/dist/shelf/geometry.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getMaterialPresetByRef } from '@pascal-app/core';
|
|
1
|
+
import { SHELF_BOARD_INSET as BOARD_INSET, getMaterialPresetByRef, shelfBoardDimensions, } from '@pascal-app/core';
|
|
2
2
|
import { applyMaterialPresetToMaterials, createDefaultMaterial, createMaterial, resolveMaterialRef, } from '@pascal-app/viewer';
|
|
3
3
|
import { BoxGeometry, Group, Mesh } from 'three';
|
|
4
4
|
import { sanitizeShelfDimensions } from './dimensions';
|
|
@@ -27,14 +27,6 @@ function stampShelfSlot(mesh, slotId) {
|
|
|
27
27
|
mesh.userData.slotId = slotId;
|
|
28
28
|
return mesh;
|
|
29
29
|
}
|
|
30
|
-
// A board's front/back faces land on the frame's outer faces (posts / back panel)
|
|
31
|
-
// — coplanar surfaces the depth buffer can't separate, which flickers as z-fighting.
|
|
32
|
-
// Recess 1mm so the board sits just inside: the meshes still overlap (no gap), but
|
|
33
|
-
// no faces are coplanar. Depth is always recessed (boards reach into the back panel
|
|
34
|
-
// / posts). Width is recessed only at call sites where boards span OVER posts
|
|
35
|
-
// (open-rack / no-sides bookshelf); boards that ABUT side panels keep full width so
|
|
36
|
-
// they meet the sides flush — abutting faces are back-to-back and never fight.
|
|
37
|
-
const BOARD_INSET = 0.001;
|
|
38
30
|
// Frame members that pass under the top board (dividers / back / corner posts) reach
|
|
39
31
|
// y=unitHeight, coplanar with the top board's top face → z-fighting. Drop their top 1mm so
|
|
40
32
|
// the board cleanly caps them; their bottom stays on the floor.
|
|
@@ -44,7 +36,7 @@ function cappedFrameY(unitHeight) {
|
|
|
44
36
|
return { height, centerY: height / 2 };
|
|
45
37
|
}
|
|
46
38
|
function boardGeometry(width, thickness, depth, insetWidth = false) {
|
|
47
|
-
return new BoxGeometry(
|
|
39
|
+
return new BoxGeometry(...shelfBoardDimensions(width, thickness, depth, insetWidth));
|
|
48
40
|
}
|
|
49
41
|
export function buildShelfGeometry(rawNode, ctx, shading = 'rendered') {
|
|
50
42
|
const node = sanitizeShelfDimensions(rawNode);
|