@pascal-app/editor 1.0.5 → 1.0.7

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.
Files changed (317) hide show
  1. package/package.json +20 -17
  2. package/src/components/editor/action-menu-button.tsx +4 -1
  3. package/src/components/editor/alignment-3d-guide-layer.tsx +102 -11
  4. package/src/components/editor/bake-thumbnail.tsx +3 -2
  5. package/src/components/editor/custom-camera-controls.tsx +20 -8
  6. package/src/components/editor/elevation-3d-guide-layer.tsx +1 -1
  7. package/src/components/editor/first-person-controls.tsx +72 -61
  8. package/src/components/editor/floating-action-menu.tsx +27 -9
  9. package/src/components/editor/floating-building-action-menu.tsx +1 -1
  10. package/src/components/editor/floorplan-panel.test.ts +220 -0
  11. package/src/components/editor/floorplan-panel.tsx +285 -132
  12. package/src/components/editor/footprint-height-handle.tsx +1 -1
  13. package/src/components/editor/grid.tsx +24 -15
  14. package/src/components/editor/group-actions.ts +19 -1
  15. package/src/components/editor/group-floating-action-menu.tsx +1 -1
  16. package/src/components/editor/group-move-3d.ts +27 -2
  17. package/src/components/editor/group-selection-box-3d.tsx +4 -1
  18. package/src/components/editor/group-transform-shared.ts +20 -0
  19. package/src/components/editor/index.tsx +130 -20
  20. package/src/components/editor/inspector-extension-actions.tsx +36 -0
  21. package/src/components/editor/localized-html.tsx +22 -0
  22. package/src/components/editor/node-action-menu.tsx +46 -12
  23. package/src/components/editor/node-arrow-handles.tsx +1 -2
  24. package/src/components/editor/open-wall-ends-3d-layer.tsx +1 -1
  25. package/src/components/editor/opening-guides-3d-layer.tsx +1 -1
  26. package/src/components/editor/registry-action-contributions.test.tsx +67 -6
  27. package/src/components/editor/registry-action-contributions.tsx +115 -15
  28. package/src/components/editor/riser-diagram-panel.tsx +59 -9
  29. package/src/components/editor/room-controls.tsx +1 -1
  30. package/src/components/editor/room-handles-2d.tsx +156 -6
  31. package/src/components/editor/room-handles.tsx +241 -51
  32. package/src/components/editor/room-highlight.tsx +2 -0
  33. package/src/components/editor/room-labels.tsx +29 -15
  34. package/src/components/editor/selection-manager.tsx +15 -102
  35. package/src/components/editor/separator-end-grip.tsx +74 -0
  36. package/src/components/editor/site-edge-labels.tsx +1 -1
  37. package/src/components/editor/thumbnail-generator.test.ts +15 -6
  38. package/src/components/editor/thumbnail-generator.tsx +26 -1
  39. package/src/components/editor/use-floorplan-background-placement.ts +55 -52
  40. package/src/components/editor/views/view-bar.tsx +111 -26
  41. package/src/components/editor/wall-measurement-label.tsx +1 -1
  42. package/src/components/editor/wall-move-side-handles.tsx +5 -1
  43. package/src/components/editor/wall-pull-grip.tsx +193 -0
  44. package/src/components/editor/wall-snap-beacon-layer.tsx +81 -1
  45. package/src/components/editor-2d/floorplan-adjacent-walls-layer.test.ts +76 -0
  46. package/src/components/editor-2d/floorplan-adjacent-walls-layer.tsx +186 -0
  47. package/src/components/editor-2d/floorplan-alignment-guide-layer.tsx +63 -3
  48. package/src/components/editor-2d/floorplan-group-move.tsx +31 -3
  49. package/src/components/editor-2d/floorplan-measurement-tool-layer.test.ts +6 -0
  50. package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +22 -13
  51. package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +11 -3
  52. package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +7 -1
  53. package/src/components/editor-2d/floorplan-snap-beacon-layer.tsx +96 -4
  54. package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +52 -12
  55. package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +12 -1
  56. package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +197 -37
  57. package/src/components/procedural-items/inspector.tsx +59 -12
  58. package/src/components/systems/ceiling/ceiling-bracket-batch.test.ts +2 -0
  59. package/src/components/systems/ceiling/ceiling-system.test.ts +141 -0
  60. package/src/components/systems/ceiling/ceiling-system.tsx +53 -18
  61. package/src/components/tools/distribution/distribution-run-tool.tsx +50 -26
  62. package/src/components/tools/item/placement-history.test.tsx +1 -1
  63. package/src/components/tools/item/placement-strategies.test.ts +64 -1
  64. package/src/components/tools/item/placement-strategies.ts +5 -9
  65. package/src/components/tools/item/use-placement-coordinator.tsx +30 -34
  66. package/src/components/tools/registry/item-surface-move.test.ts +11 -0
  67. package/src/components/tools/select/select-candidates.test.ts +45 -0
  68. package/src/components/tools/select/select-candidates.ts +13 -2
  69. package/src/components/tools/shared/cursor-sphere.tsx +10 -3
  70. package/src/components/tools/shared/draft-measurement-label.tsx +1 -1
  71. package/src/components/tools/shared/placement-box.tsx +1 -1
  72. package/src/components/tools/shared/placement-dimension-guides.tsx +1 -1
  73. package/src/components/tools/site/terrain-brush-cursor.tsx +1 -1
  74. package/src/components/tools/wall/wall-drafting.test.ts +299 -23
  75. package/src/components/tools/wall/wall-drafting.ts +132 -24
  76. package/src/components/tools/wall/wall-pull-snap.test.ts +274 -0
  77. package/src/components/tools/wall/wall-pull-snap.ts +563 -0
  78. package/src/components/tools/wall/wall-snap-geometry.test.ts +113 -1
  79. package/src/components/tools/wall/wall-snap-geometry.ts +137 -0
  80. package/src/components/tools/zone/zone-tool.tsx +3 -3
  81. package/src/components/ui/action-menu/action-button.tsx +2 -0
  82. package/src/components/ui/action-menu/camera-actions.tsx +8 -7
  83. package/src/components/ui/action-menu/control-modes.tsx +9 -5
  84. package/src/components/ui/action-menu/follow-pascal-pill.tsx +3 -1
  85. package/src/components/ui/action-menu/follow-pascal-toggle.tsx +7 -1
  86. package/src/components/ui/action-menu/furnish-tools.tsx +7 -6
  87. package/src/components/ui/action-menu/index.tsx +1 -0
  88. package/src/components/ui/action-menu/measurement-control.tsx +35 -29
  89. package/src/components/ui/action-menu/point-ask-button.tsx +4 -3
  90. package/src/components/ui/action-menu/structure-tools.tsx +25 -23
  91. package/src/components/ui/action-menu/view-toggles.test.ts +18 -0
  92. package/src/components/ui/action-menu/view-toggles.tsx +256 -51
  93. package/src/components/ui/build-panel/build-panel.tsx +163 -25
  94. package/src/components/ui/command-palette/editor-commands.tsx +38 -11
  95. package/src/components/ui/controls/finish-swatch.tsx +45 -19
  96. package/src/components/ui/controls/material-picker.tsx +24 -17
  97. package/src/components/ui/controls/metric-control.test.ts +52 -0
  98. package/src/components/ui/controls/metric-control.tsx +62 -24
  99. package/src/components/ui/controls/segmented-control.tsx +5 -2
  100. package/src/components/ui/controls/slider-control.test.tsx +23 -0
  101. package/src/components/ui/controls/slider-control.tsx +30 -14
  102. package/src/components/ui/floating-level-selector.tsx +100 -48
  103. package/src/components/ui/helpers/building-helper.tsx +5 -3
  104. package/src/components/ui/helpers/contextual-helper-panel.tsx +97 -37
  105. package/src/components/ui/helpers/helper-manager.test.tsx +53 -3
  106. package/src/components/ui/helpers/helper-manager.tsx +82 -57
  107. package/src/components/ui/helpers/item-helper.tsx +6 -4
  108. package/src/components/ui/helpers/registered-tool-helper.tsx +3 -1
  109. package/src/components/ui/level-duplicate-dialog.tsx +32 -23
  110. package/src/components/ui/level-wall-copy-prompt.tsx +124 -0
  111. package/src/components/ui/panels/collections/collections-popover.tsx +11 -11
  112. package/src/components/ui/panels/deck-boards-fields.tsx +136 -0
  113. package/src/components/ui/panels/floor-foundation-panel.tsx +113 -38
  114. package/src/components/ui/panels/floor-opening-panel.tsx +73 -25
  115. package/src/components/ui/panels/inspector-extensions.tsx +66 -0
  116. package/src/components/ui/panels/mobile-panel-sheet.tsx +3 -1
  117. package/src/components/ui/panels/mobile-selection-bar.tsx +8 -6
  118. package/src/components/ui/panels/multi-field-value.test.ts +27 -0
  119. package/src/components/ui/panels/multi-field-value.ts +20 -1
  120. package/src/components/ui/panels/multi-height-mode.tsx +8 -7
  121. package/src/components/ui/panels/multi-parametric-inspector.tsx +122 -34
  122. package/src/components/ui/panels/multi-selection-panel.tsx +75 -35
  123. package/src/components/ui/panels/node-display.ts +35 -24
  124. package/src/components/ui/panels/panel-manager.tsx +5 -3
  125. package/src/components/ui/panels/panel-wrapper.tsx +22 -109
  126. package/src/components/ui/panels/parametric-field-control.tsx +13 -10
  127. package/src/components/ui/panels/parametric-inspector.tsx +18 -12
  128. package/src/components/ui/panels/reference-panel.tsx +51 -35
  129. package/src/components/ui/panels/room-construction-rows.tsx +464 -65
  130. package/src/components/ui/panels/room-name-options.test.ts +36 -3
  131. package/src/components/ui/panels/room-name-options.ts +110 -11
  132. package/src/components/ui/panels/room-openings-field.tsx +21 -12
  133. package/src/components/ui/panels/room-panel.tsx +206 -99
  134. package/src/components/ui/panels/shape-choice.tsx +7 -5
  135. package/src/components/ui/panels/wall-region-list.tsx +7 -7
  136. package/src/components/ui/primitives/shortcut-token.tsx +10 -6
  137. package/src/components/ui/sidebar/icon-rail.tsx +11 -9
  138. package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +10 -10
  139. package/src/components/ui/sidebar/panels/items-panel/index.tsx +10 -9
  140. package/src/components/ui/sidebar/panels/settings-panel/index.tsx +3 -0
  141. package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +102 -32
  142. package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +4 -3
  143. package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +4 -2
  144. package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +4 -2
  145. package/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +7 -5
  146. package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +4 -2
  147. package/src/components/ui/sidebar/panels/site-panel/default-names.ts +75 -0
  148. package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +4 -2
  149. package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +4 -2
  150. package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +4 -2
  151. package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +4 -2
  152. package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +4 -2
  153. package/src/components/ui/sidebar/panels/site-panel/index.tsx +117 -64
  154. package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +36 -3
  155. package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +4 -2
  156. package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +7 -4
  157. package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +8 -2
  158. package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +8 -5
  159. package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +4 -2
  160. package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +8 -3
  161. package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +4 -2
  162. package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +4 -2
  163. package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +8 -7
  164. package/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +7 -6
  165. package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +16 -1
  166. package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +15 -8
  167. package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +4 -2
  168. package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +4 -2
  169. package/src/components/ui/sidebar/panels/site-panel/zone-membership-checkbox.tsx +3 -1
  170. package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +18 -8
  171. package/src/components/ui/sidebar/panels/zone-panel/index.tsx +25 -14
  172. package/src/components/ui/sidebar/tab-bar.tsx +4 -1
  173. package/src/components/ui/sidebar/use-plugin-panels.tsx +19 -10
  174. package/src/components/ui/snap-target-badge.tsx +7 -6
  175. package/src/components/ui/wall-type/wall-type-editor-dialog.tsx +721 -0
  176. package/src/components/ui/wall-type/wall-type-menu.tsx +167 -0
  177. package/src/components/viewer/floorplan-compass-button.tsx +12 -3
  178. package/src/components/viewer/floorplan-preview.tsx +27 -19
  179. package/src/components/viewer/render-settings-menu.tsx +294 -0
  180. package/src/components/viewer/sky-control.tsx +710 -0
  181. package/src/components/viewer/use-viewer-ui-sounds.test.ts +15 -0
  182. package/src/components/viewer/use-viewer-ui-sounds.ts +46 -0
  183. package/src/components/viewer/viewer-controls-bar.tsx +278 -260
  184. package/src/components/viewer/viewer-hover-label.tsx +12 -4
  185. package/src/components/viewer/viewer-rooms.tsx +61 -4
  186. package/src/components/viewer/viewer-scene-header.tsx +28 -17
  187. package/src/components/viewer/viewer-stage-switcher.tsx +4 -2
  188. package/src/components/viewer-overlay.tsx +8 -0
  189. package/src/components/walkthrough-hud.tsx +75 -2
  190. package/src/hooks/use-keyboard.test.ts +85 -4
  191. package/src/hooks/use-keyboard.ts +65 -7
  192. package/src/hooks/use-selected-room.ts +12 -1
  193. package/src/i18n/floor-footprint-name.ts +30 -0
  194. package/src/i18n/level-name.ts +39 -0
  195. package/src/i18n/locales/en/messages.po +15117 -0
  196. package/src/i18n/locales/en/messages.ts +1 -0
  197. package/src/i18n/locales/en-XA/messages.ts +1 -0
  198. package/src/i18n/locales/es/messages.po +37501 -0
  199. package/src/i18n/locales/es/messages.ts +1 -0
  200. package/src/i18n/locales/fr/messages.po +37501 -0
  201. package/src/i18n/locales/fr/messages.ts +1 -0
  202. package/src/i18n/locales/ja/messages.po +37501 -0
  203. package/src/i18n/locales/ja/messages.ts +1 -0
  204. package/src/i18n/locales/zh-CN/messages.po +37501 -0
  205. package/src/i18n/locales/zh-CN/messages.ts +1 -0
  206. package/src/i18n/locales.test.ts +63 -0
  207. package/src/i18n/locales.ts +32 -0
  208. package/src/i18n/message-slot.tsx +25 -0
  209. package/src/i18n/node-messages.ts +169 -0
  210. package/src/i18n/pseudo-locale.ts +17 -0
  211. package/src/i18n/published-entry.test.ts +17 -0
  212. package/src/i18n/scene-theme-name.ts +16 -0
  213. package/src/index.tsx +156 -4
  214. package/src/lib/add-storey.test.ts +3 -3
  215. package/src/lib/contextual-help.test.ts +20 -1
  216. package/src/lib/contextual-help.ts +95 -19
  217. package/src/lib/continuation.ts +38 -11
  218. package/src/lib/floor-footprints.test.ts +2 -1
  219. package/src/lib/floor-foundation-support.test.ts +7 -3
  220. package/src/lib/floorplan/dimension-drive.test.ts +36 -2
  221. package/src/lib/floorplan/dimension-drive.ts +68 -3
  222. package/src/lib/floorplan/floorplan-export.test.ts +16 -5
  223. package/src/lib/floorplan/floorplan-export.tsx +13 -16
  224. package/src/lib/floorplan/floorplan-extension.test.ts +11 -12
  225. package/src/lib/floorplan/floorplan-extension.ts +37 -18
  226. package/src/lib/floorplan/floorplan-mode.test.ts +13 -6
  227. package/src/lib/floorplan/floorplan-mode.ts +14 -12
  228. package/src/lib/floorplan/floorplan-plugin-install.test.tsx +1 -1
  229. package/src/lib/floorplan/floorplan-readonly.ts +3 -3
  230. package/src/lib/floorplan/schedules.ts +10 -6
  231. package/src/lib/floorplan/site-plan/site-annotations.test.ts +46 -1
  232. package/src/lib/floorplan/site-plan/site-annotations.ts +3 -0
  233. package/src/lib/floorplan/site-plan/site-parts.ts +6 -3
  234. package/src/lib/geometry-script/author.test.ts +114 -0
  235. package/src/lib/geometry-script/author.ts +55 -23
  236. package/src/lib/geometry-script/client.ts +3 -0
  237. package/src/lib/geometry-script/finish-scripts.ts +7 -7
  238. package/src/lib/glb-export.test.ts +327 -0
  239. package/src/lib/glb-export.ts +70 -2
  240. package/src/lib/grid-frame.test.ts +56 -3
  241. package/src/lib/grid-frame.ts +28 -1
  242. package/src/lib/history.test.ts +2 -1
  243. package/src/lib/hud-title.ts +48 -24
  244. package/src/lib/ifc-export.test.ts +41 -1
  245. package/src/lib/inspector-card-mode.test.ts +3 -31
  246. package/src/lib/inspector-card-mode.ts +5 -10
  247. package/src/lib/inspector-expanded.test.ts +13 -0
  248. package/src/lib/inspector-expanded.ts +13 -1
  249. package/src/lib/keyboard-pan.test.ts +7 -0
  250. package/src/lib/keyboard-pan.ts +9 -2
  251. package/src/lib/layer-thickness.test.ts +22 -0
  252. package/src/lib/layer-thickness.ts +79 -0
  253. package/src/lib/lot/drop-in.test.ts +59 -1
  254. package/src/lib/lot/drop-in.ts +42 -50
  255. package/src/lib/material-swatch-style.ts +24 -0
  256. package/src/lib/measurement-parser.ts +7 -3
  257. package/src/lib/measurements.test.ts +17 -0
  258. package/src/lib/measurements.ts +20 -5
  259. package/src/lib/mezzanine-selection.test.ts +3 -1
  260. package/src/lib/orbit-near-plane.test.ts +12 -0
  261. package/src/lib/orbit-near-plane.ts +13 -0
  262. package/src/lib/paint-regions.test.ts +8 -5
  263. package/src/lib/paint-scope.test.ts +53 -0
  264. package/src/lib/paint-scope.ts +18 -4
  265. package/src/lib/panel-rows.ts +17 -8
  266. package/src/lib/reference-scale.ts +83 -0
  267. package/src/lib/room-built-on.test.ts +26 -12
  268. package/src/lib/room-built-on.ts +20 -2
  269. package/src/lib/room-construction.test.ts +28 -1
  270. package/src/lib/room-construction.ts +14 -0
  271. package/src/lib/room-controls-phase6.test.ts +140 -0
  272. package/src/lib/room-handle-drag.ts +557 -42
  273. package/src/lib/room-name-catalog.test.ts +8 -0
  274. package/src/lib/room-name-catalog.ts +8 -1
  275. package/src/lib/room-name-messages.test.ts +132 -0
  276. package/src/lib/room-name-messages.ts +147 -0
  277. package/src/lib/room-name-storage.test.ts +334 -0
  278. package/src/lib/room-push-dimensions.test.ts +37 -0
  279. package/src/lib/room-push-dimensions.ts +226 -2
  280. package/src/lib/room-selection.test.ts +23 -6
  281. package/src/lib/scene-clipboard.test.ts +70 -49
  282. package/src/lib/scene-clipboard.ts +9 -4
  283. package/src/lib/selection-cycle.ts +63 -0
  284. package/src/lib/separator-edit.test.ts +431 -0
  285. package/src/lib/separator-edit.ts +179 -0
  286. package/src/lib/separator-lines.ts +38 -0
  287. package/src/lib/sfx-bus.ts +27 -1
  288. package/src/lib/sfx-player.ts +16 -0
  289. package/src/lib/tool-cursor-icon.ts +5 -1
  290. package/src/lib/tool-shortcuts.ts +130 -0
  291. package/src/lib/viewer-selection.test.ts +28 -24
  292. package/src/lib/viewer-selection.ts +20 -5
  293. package/src/lib/wall-draw-variant.test.ts +7 -6
  294. package/src/lib/wall-draw-variant.ts +107 -6
  295. package/src/lib/wall-nudge.test.ts +44 -0
  296. package/src/lib/wall-nudge.ts +131 -0
  297. package/src/lib/wall-parallel-snap.test.ts +83 -0
  298. package/src/lib/wall-parallel-snap.ts +176 -0
  299. package/src/lib/wall-placement-pointer.test.ts +23 -0
  300. package/src/lib/wall-placement-pointer.ts +18 -0
  301. package/src/lib/wall-pull.test.ts +245 -0
  302. package/src/lib/wall-pull.ts +209 -0
  303. package/src/lib/wall-push-line-up.test.ts +132 -0
  304. package/src/lib/wall-region-list.ts +14 -5
  305. package/src/lib/wall-run-snap.test.ts +188 -0
  306. package/src/lib/wall-run-snap.ts +83 -0
  307. package/src/lib/wall-type.test.ts +125 -0
  308. package/src/lib/wall-type.ts +119 -0
  309. package/src/lib/window-interaction.test.ts +42 -0
  310. package/src/lib/window-interaction.ts +47 -5
  311. package/src/lib/world-grid-snap.test.ts +139 -2
  312. package/src/lib/world-grid-snap.ts +102 -105
  313. package/src/store/use-alignment-guides.ts +27 -1
  314. package/src/store/use-editor.tsx +48 -0
  315. package/src/store/use-floorplan-annotation-visibility.test.ts +64 -0
  316. package/src/store/use-floorplan-annotation-visibility.ts +47 -22
  317. package/src/store/use-wall-snap-indicator.ts +15 -2
package/src/index.tsx CHANGED
@@ -2,11 +2,21 @@
2
2
  // own shells on top of `@pascal-app/editor` (community-app, embedders)
3
3
  // don't have to learn three separate package imports. The canonical
4
4
  // definitions still live in `@pascal-app/core` / `@pascal-app/viewer`.
5
+ import { registerCompiledMessages as registerEditorMessages } from '@pascal-app/core'
6
+ import { messages as editorEnglishMessages } from './i18n/locales/en/messages'
7
+
8
+ // Published-package consumers need compiled English too: Lingui cannot
9
+ // interpolate a raw fallback literal in production. Other bundled locales
10
+ // remain explicitly host-registered through `@pascal-app/editor/locales`.
11
+ registerEditorMessages('en', '', editorEnglishMessages)
12
+
5
13
  export {
6
14
  type ApplySceneSnapshotOptions,
7
15
  acquireSceneReadOnlyLease,
8
16
  applyScenePatch,
9
17
  applySceneSnapshot,
18
+ type CompiledTranslationMessages,
19
+ createI18n,
10
20
  DEFAULT_CURVED_STAIR_INNER_RADIUS,
11
21
  DEFAULT_CURVED_STAIR_SWEEP_ANGLE,
12
22
  DEFAULT_SPIRAL_SHOW_CENTER_COLUMN,
@@ -22,6 +32,16 @@ export {
22
32
  DEFAULT_STAIR_THICKNESS,
23
33
  DEFAULT_STAIR_TYPE,
24
34
  DEFAULT_STAIR_WIDTH,
35
+ defaultI18n,
36
+ formatLength,
37
+ formatNumber,
38
+ getLocale,
39
+ normalizeDecimalInput,
40
+ type PascalI18n,
41
+ PascalI18nProvider,
42
+ parseLocalizedNumber,
43
+ registerCompiledMessages,
44
+ registerMessages,
25
45
  type SceneCommit,
26
46
  type SceneCommitListener,
27
47
  type SceneCommitOrigin,
@@ -29,7 +49,15 @@ export {
29
49
  type SceneNodePatch,
30
50
  type ScenePatch,
31
51
  type SceneSnapshot,
52
+ setLocale,
53
+ subscribe,
32
54
  subscribeSceneCommits,
55
+ type TranslationMessage,
56
+ type TranslationMessages,
57
+ type TranslationParams,
58
+ translate,
59
+ useLocale,
60
+ usePascalI18n,
33
61
  useScene,
34
62
  } from '@pascal-app/core'
35
63
  export { useViewer } from '@pascal-app/viewer'
@@ -68,6 +96,7 @@ export { FloatingActionMenu as FloatingMenu } from './components/editor/floating
68
96
  // flags. Tools place onto `useViewer.selection.levelId`, so the host must set a
69
97
  // building + level selection first.
70
98
  export { EDITOR_GRID_INPUT_NAME, Grid } from './components/editor/grid'
99
+ export { Html as LocalizedHtml } from './components/editor/localized-html'
71
100
  export {
72
101
  DimensionPill,
73
102
  type DimensionPillPart,
@@ -98,12 +127,15 @@ export {
98
127
  } from './components/editor/node-arrow-handles'
99
128
  export { QuickMeasurementCard } from './components/editor/quick-measurement-card'
100
129
  export { SelectionManager } from './components/editor/selection-manager'
130
+ export { SeparatorEndGrip } from './components/editor/separator-end-grip'
101
131
  export {
102
132
  type SnapshotCameraData,
103
133
  ThumbnailGenerator,
104
134
  } from './components/editor/thumbnail-generator'
105
135
  export { PLUGINS_VIEW_ID } from './components/editor/views/use-editor-views'
106
136
  export { WallMoveSideHandles } from './components/editor/wall-move-side-handles'
137
+ export { WallPushArrow } from './components/editor/wall-push-arrow'
138
+ export { useWallsBelowSetting } from './components/editor-2d/floorplan-adjacent-walls-layer'
107
139
  export { useFloorplanRender } from './components/editor-2d/floorplan-render-context'
108
140
  export { FloorplanDimensionRenderer } from './components/editor-2d/renderers/floorplan-dimension-renderer'
109
141
  export {
@@ -124,6 +156,7 @@ export {
124
156
  buildSvgArrowHeadPoints,
125
157
  getArcPlanPoint,
126
158
  } from './components/editor-2d/svg-paths'
159
+ export { useCeilingsSetting } from './components/systems/ceiling/ceiling-system'
127
160
  export type {
128
161
  SelectionAffordanceHistoryApi,
129
162
  SelectionAffordanceInteractionApi,
@@ -154,7 +187,10 @@ export {
154
187
  usePlacementCoordinator,
155
188
  } from './components/tools/item/use-placement-coordinator'
156
189
  export { MoveRegistryNodeTool } from './components/tools/registry/move-registry-node-tool'
157
- export { useRegistryToolContext } from './components/tools/registry-tool-context'
190
+ export {
191
+ RegistryToolProvider,
192
+ useRegistryToolContext,
193
+ } from './components/tools/registry-tool-context'
158
194
  export { CursorSphere } from './components/tools/shared/cursor-sphere'
159
195
  export {
160
196
  DRAFT_LABEL_Y_OFFSET,
@@ -195,6 +231,7 @@ export {
195
231
  export { preloadRegistryToolModules, ToolManager } from './components/tools/tool-manager'
196
232
  export {
197
233
  chainEndJoinsExistingWall,
234
+ createInvisibleWallOnCurrentLevel,
198
235
  createWallOnCurrentLevel,
199
236
  findWallSnapTarget,
200
237
  getSegmentGridStep,
@@ -212,6 +249,21 @@ export {
212
249
  type WallPlanPoint,
213
250
  type WallSnapRadii,
214
251
  } from './components/tools/wall/wall-drafting'
252
+ export {
253
+ lockWallPullDirection,
254
+ snapWallPullPoint,
255
+ WALL_PULL_ANGLE_STEP,
256
+ WALL_PULL_LOCK_TOLERANCE,
257
+ WALL_PULL_SNAP_LABELS,
258
+ WALL_PULL_SNAP_RADII,
259
+ type WallPullDirectionLock,
260
+ type WallPullGuide,
261
+ type WallPullGuideKind,
262
+ type WallPullSnapInput,
263
+ type WallPullSnapKind,
264
+ type WallPullSnapRadii,
265
+ type WallPullSnapResult,
266
+ } from './components/tools/wall/wall-pull-snap'
215
267
  // `ToolbarLeft` / `ToolbarRight` alias `ViewerToolbarLeft` / `ViewerToolbarRight`
216
268
  // (same components) under the names headless hosts compose their toolbars with.
217
269
  export {
@@ -234,6 +286,8 @@ export {
234
286
  } from './components/ui/build-panel/build-panel'
235
287
  export { useCommandPalette } from './components/ui/command-palette'
236
288
  export { ActionButton, ActionGroup } from './components/ui/controls/action-button'
289
+ // A finish row in a node panel: the paint tool's picker and its write for one paint role.
290
+ export { FinishSwatch } from './components/ui/controls/finish-swatch'
237
291
  export {
238
292
  MaterialPaintPanel,
239
293
  type MaterialPaintPanelProps,
@@ -275,13 +329,17 @@ export { applyMultiHeightMode } from './components/ui/panels/multi-height-mode'
275
329
  // a kind-owned panel and need PanelWrapper for the chrome.
276
330
  export { PanelWrapper } from './components/ui/panels/panel-wrapper'
277
331
  export { ParametricInspector as Inspector } from './components/ui/panels/parametric-inspector'
332
+ // A floor's script (a room's, a slab's): its code to read and a way to take it off.
333
+ export { ScriptedFinishRow } from './components/ui/panels/room-panel'
278
334
  export { ShapeChoice } from './components/ui/panels/shape-choice'
279
335
  export { WallPaintRegionList } from './components/ui/panels/wall-region-list'
280
336
  export { PALETTE_COLORS } from './components/ui/primitives/color-dot'
281
337
  export {
282
338
  DropdownMenu,
283
339
  DropdownMenuContent,
340
+ DropdownMenuGroup,
284
341
  DropdownMenuItem,
342
+ DropdownMenuLabel,
285
343
  DropdownMenuSeparator,
286
344
  DropdownMenuSub,
287
345
  DropdownMenuSubContent,
@@ -316,6 +374,8 @@ export {
316
374
  SnapTargetBadge,
317
375
  SnapTargetIcon,
318
376
  } from './components/ui/snap-target-badge'
377
+ // A wall's project wall types: new, edit, duplicate (the wall panel's Assembly).
378
+ export { WallTypeMenu } from './components/ui/wall-type/wall-type-menu'
319
379
  export {
320
380
  FloorplanCompassButton,
321
381
  type FloorplanCompassButtonProps,
@@ -325,7 +385,14 @@ export {
325
385
  type FloorplanPreviewProps,
326
386
  type FloorplanPreviewScene,
327
387
  } from './components/viewer/floorplan-preview'
388
+ export {
389
+ DaylightMenu,
390
+ EdgesToggleItem,
391
+ QualityMenu,
392
+ } from './components/viewer/render-settings-menu'
393
+ export { openSkyPanel, SkyControl, useSkyPanel } from './components/viewer/sky-control'
328
394
  export { useViewerCameraNavigationSync } from './components/viewer/use-viewer-camera-navigation-sync'
395
+ export { useViewerUiSounds } from './components/viewer/use-viewer-ui-sounds'
329
396
  export {
330
397
  ViewerControlsBar,
331
398
  type ViewerControlsBarProps,
@@ -351,6 +418,7 @@ export {
351
418
  type ViewerStageSwitcherProps,
352
419
  } from './components/viewer/viewer-stage-switcher'
353
420
  export {
421
+ DroneHud,
354
422
  WalkthroughHud,
355
423
  type WalkthroughHudProps,
356
424
  type WalkthroughInteract,
@@ -366,6 +434,18 @@ export { usePlacementNotice } from './hooks/use-placement-notice'
366
434
  export { useReducedMotion } from './hooks/use-reduced-motion'
367
435
  export { useSelectedRoom } from './hooks/use-selected-room'
368
436
  export { type Selection, useSelection } from './hooks/use-selection'
437
+ export { localizedLevelName } from './i18n/level-name'
438
+ export {
439
+ messageSlug,
440
+ nodeDescriptionDescriptor,
441
+ nodeLabel,
442
+ nodeLabelDescriptor,
443
+ toolHintChipLabel,
444
+ toolHintDescriptor,
445
+ toolHintKey,
446
+ toolHintLabel,
447
+ } from './i18n/node-messages'
448
+ export { sceneThemeName } from './i18n/scene-theme-name'
369
449
  export {
370
450
  clearPlacementSurface,
371
451
  getPlacementSurface,
@@ -491,6 +571,7 @@ export {
491
571
  type FloorplanSchedule,
492
572
  type FloorplanToolContext,
493
573
  type FloorplanToolMode,
574
+ type FloorplanWallDimensionFaces,
494
575
  floorplanGeometryMetadata,
495
576
  getFloorplanNodeExtension,
496
577
  readFloorplanContext,
@@ -620,6 +701,11 @@ export {
620
701
  scopeNodeId,
621
702
  } from './lib/interaction/scope'
622
703
  export { isEditableKeyboardTarget } from './lib/keyboard-pan'
704
+ export {
705
+ formatLayerDepth,
706
+ formatLayerThickness,
707
+ parseLayerThickness,
708
+ } from './lib/layer-thickness'
623
709
  export { selectPlacedNode } from './lib/level-selection'
624
710
  // Lot drop-in — address → parcel → streets → front edge → setbacks, on the
625
711
  // site node, through the parcel provider the host sets.
@@ -695,6 +781,7 @@ export {
695
781
  measurementFloorplanPresentationColor,
696
782
  measurementPresentationColor,
697
783
  metersToLinearUnit,
784
+ parseLinearMeasurementInput,
698
785
  squareMetersToAreaUnit,
699
786
  } from './lib/measurements'
700
787
  export type {
@@ -713,6 +800,7 @@ export {
713
800
  } from './lib/paint-scope'
714
801
  export {
715
802
  getNodePanelModel,
803
+ type MultiPanelControl,
716
804
  type NodePanelModel,
717
805
  PANEL_MODEL_EXTENSION,
718
806
  type PanelAction,
@@ -773,7 +861,14 @@ export { clearRoofDuplicateMetadata, duplicateRoofSubtree } from './lib/roof-dup
773
861
  // kind-owned door / window tools in `@pascal-app/nodes` and the item
774
862
  // placement coordinator's roof-wall strategy.
775
863
  export { hasRoofFaceChildOverlap, type RoofWallHit, resolveRoofWallHit } from './lib/roof-wall-hit'
776
- export { WALL_PUSH_AFFORDANCE, type WallPushArrowPayload } from './lib/room-handle-drag'
864
+ export {
865
+ selectedWallDimensions,
866
+ separatorFloorElevation,
867
+ separatorPushHandles,
868
+ WALL_PUSH_AFFORDANCE,
869
+ type WallPushArrowPayload,
870
+ } from './lib/room-handle-drag'
871
+ export { displayRoomName } from './lib/room-name-messages'
777
872
  export type { RoomKey, RoomSelectionRecord } from './lib/room-selection'
778
873
  export { popRoomSelection, selectRoom } from './lib/room-selection-commands'
779
874
  export {
@@ -790,8 +885,13 @@ export {
790
885
  remapSceneMaterialRefs,
791
886
  sceneMaterialUsageCounts,
792
887
  } from './lib/scene-material-refs'
888
+ export {
889
+ beginSeparatorEndDrag,
890
+ runSeparatorEndDrag,
891
+ type SeparatorEndDrag,
892
+ } from './lib/separator-edit'
793
893
  export { movementSfxStepKey } from './lib/sfx/movement-tick'
794
- export { emitDeleteSFX, triggerSFX } from './lib/sfx-bus'
894
+ export { emitDeleteSFX, initSFXBus, triggerSFX } from './lib/sfx-bus'
795
895
  export { playSFX, type SFXName, type SFXPlaybackOptions } from './lib/sfx-player'
796
896
  export { showSidebarPanel } from './lib/sidebar-panel'
797
897
  export {
@@ -848,6 +948,7 @@ export {
848
948
  sculptFieldForSite,
849
949
  terrainPointInsideSite,
850
950
  } from './lib/terrain-sculpt'
951
+ export { withToolShortcut } from './lib/tool-shortcuts'
851
952
  export { isTypingTarget } from './lib/typing-target'
852
953
  export { enterUnitFocus } from './lib/units'
853
954
  export { exportSceneToUsdz, type UsdzExportOptions } from './lib/usdz-export'
@@ -868,10 +969,27 @@ export {
868
969
  } from './lib/viewer-selection'
869
970
  export {
870
971
  getWallDrawVariant,
972
+ getWallLineKind,
973
+ INVISIBLE_WALL_DRAFT_THICKNESS,
974
+ invisibleWallDraftSnapLines,
871
975
  selectWallDrawVariant,
976
+ selectWallKind,
977
+ useWallDraftThickness,
872
978
  useWallDrawVariant,
979
+ useWallKind,
980
+ WALL_KINDS,
873
981
  type WallDrawVariant,
982
+ type WallKind,
983
+ type WallLineKind,
874
984
  } from './lib/wall-draw-variant'
985
+ export {
986
+ nearestWallParallelTarget,
987
+ nudgeWallPosition,
988
+ publishWallParallelGuide,
989
+ WALL_PARALLEL_SNAP_RADIUS,
990
+ type WallParallelTarget,
991
+ wallParallelTargets,
992
+ } from './lib/wall-parallel-snap'
875
993
  export {
876
994
  createWallPointerTracker,
877
995
  wallPointerInParent,
@@ -884,12 +1002,42 @@ export {
884
1002
  startWallPolygonDraft,
885
1003
  wallPolygonDraftWalls,
886
1004
  } from './lib/wall-polygon-draft'
1005
+ export {
1006
+ endWallPullRun,
1007
+ releaseWallPullDrag,
1008
+ startWallPull,
1009
+ useWallPullRun,
1010
+ WALL_PULL_AFFORDANCE,
1011
+ WALL_PULL_GRIP_TITLE,
1012
+ type WallPullGripPayload,
1013
+ type WallPullRun,
1014
+ wallDraftIsRun,
1015
+ wallPullSeed,
1016
+ wallPullTypePatch,
1017
+ } from './lib/wall-pull'
1018
+ export {
1019
+ isWallRunFree,
1020
+ publishWallRunFeedback,
1021
+ snapWallRunDraftPoint,
1022
+ wallRunDirection,
1023
+ } from './lib/wall-run-snap'
1024
+ export {
1025
+ deleteProjectWallType,
1026
+ saveProjectWallType,
1027
+ useProjectWallTypes,
1028
+ type WallTypePlacement,
1029
+ wallTypePlacementOf,
1030
+ } from './lib/wall-type'
887
1031
  export { writeWindowChanges } from './lib/window-changes'
888
1032
  export {
889
1033
  closeWindowOpenState,
1034
+ getDisplayedWindowShutterValue,
890
1035
  getDisplayedWindowValue,
891
1036
  isOperableWindowType,
892
1037
  openWindowOpenState,
1038
+ setWindowShuttersOpenState,
1039
+ type WindowOpenAnimationOptions,
1040
+ type WindowShutterField,
893
1041
  } from './lib/window-interaction'
894
1042
  export {
895
1043
  getActiveBuildingPose,
@@ -900,7 +1048,11 @@ export {
900
1048
  snapWorldXZForActiveBuilding,
901
1049
  } from './lib/world-grid-snap'
902
1050
  export { subscribeCameraPose } from './store/camera-pose-store'
903
- export { default as useAlignmentGuides } from './store/use-alignment-guides'
1051
+ export {
1052
+ type DraftGuideLine,
1053
+ type DraftGuides,
1054
+ default as useAlignmentGuides,
1055
+ } from './store/use-alignment-guides'
904
1056
  export { default as useAudio } from './store/use-audio'
905
1057
  export { type CameraHintAction, useCameraHintFocus } from './store/use-camera-hint-focus'
906
1058
  export { type CommandAction, useCommandRegistry } from './store/use-command-registry'
@@ -145,11 +145,11 @@ describe('setGroundFloor', () => {
145
145
 
146
146
  const standing = (id: string) => levelGradeStanding(useScene.getState().nodes, id)
147
147
 
148
- test('seats the building so the level stands 8 in over grade, the ones under it below it, in one undo step', () => {
148
+ test('seats the building so the level stands on grade, the ones under it below it, in one undo step', () => {
149
149
  expect(standing('level_lower')).toBe('at-grade')
150
150
  expect(setGroundFloor('level_reception' as LevelNode['id'])).toBe(true)
151
151
  const nodes = useScene.getState().nodes
152
- expect((nodes[BUILDING as AnyNodeId] as BuildingNode).position).toEqual([0, -3.197, 0])
152
+ expect((nodes[BUILDING as AnyNodeId] as BuildingNode).position).toEqual([0, -3.4, 0])
153
153
  expect((nodes[BUILDING as AnyNodeId] as BuildingNode).groundLevelId).toBe('level_reception')
154
154
  expect(standing('level_reception')).toBe('at-grade')
155
155
  expect(standing('level_lower')).toBe('below-grade')
@@ -172,6 +172,6 @@ describe('setGroundFloor', () => {
172
172
  const basement = addStoreyBelow(BUILDING)
173
173
  expect(basement.level).toBe(-3)
174
174
  expect(standing(basement.id)).toBe('below-grade')
175
- expect(levelFloorWorldY(useScene.getState().nodes, 'level_reception')).toBeCloseTo(0.203, 9)
175
+ expect(levelFloorWorldY(useScene.getState().nodes, 'level_reception')).toBeCloseTo(0, 9)
176
176
  })
177
177
  })
@@ -1,5 +1,24 @@
1
1
  import { describe, expect, test } from 'bun:test'
2
- import { resolveRotateHandleHelpHints, resolveSelectModeHelpHints } from './contextual-help'
2
+ import type { MessageDescriptor } from '@pascal-app/core'
3
+ import {
4
+ type ContextualShortcutHint,
5
+ resolveRotateHandleHelpHints as rotateHints,
6
+ resolveSelectModeHelpHints as selectHints,
7
+ } from './contextual-help'
8
+
9
+ // Hints carry message descriptors; these tests read their English.
10
+ const text = (value: MessageDescriptor | string) =>
11
+ typeof value === 'string' ? value : value.message
12
+ const english = (hints: ContextualShortcutHint[]) =>
13
+ hints.map(({ label, subtitle, ...hint }) => ({
14
+ ...hint,
15
+ label: text(label),
16
+ ...(subtitle ? { subtitle: text(subtitle) } : {}),
17
+ }))
18
+ const resolveRotateHandleHelpHints = (...args: Parameters<typeof rotateHints>) =>
19
+ english(rotateHints(...args))
20
+ const resolveSelectModeHelpHints = (...args: Parameters<typeof selectHints>) =>
21
+ english(selectHints(...args))
3
22
 
4
23
  test('rotation advertises Alt as the temporary free-rotation override', () => {
5
24
  expect(resolveRotateHandleHelpHints(false)).toEqual([
@@ -1,12 +1,14 @@
1
+ import type { MessageDescriptor } from '@pascal-app/core'
2
+
1
3
  export type ContextualShortcutHint = {
2
4
  // A combo of keys pressed together (rendered joined by "+"). An entry may
3
5
  // itself be an array of alternatives (rendered joined by "/"), e.g.
4
6
  // [['Cmd/Ctrl', 'Shift'], 'Left click'] → "⌘ / ⇧ + click".
5
7
  keys: Array<string | string[]>
6
- label: string
8
+ label: MessageDescriptor | string
7
9
  // Optional secondary line under the label for a terser qualifier
8
10
  // (e.g. "disable 15° snap"). The HUD wraps both lines rather than truncating.
9
- subtitle?: string
11
+ subtitle?: MessageDescriptor | string
10
12
  active?: boolean
11
13
  }
12
14
 
@@ -33,7 +35,15 @@ export function resolveRotateHandleHelpHints(altPressed: boolean): ContextualSho
33
35
  return [
34
36
  {
35
37
  keys: [ALT_KEY],
36
- label: altPressed ? 'Rotating freely (no angle step)' : 'Hold to rotate freely',
38
+ label: altPressed
39
+ ? /* i18n */ {
40
+ id: 'editor.lib.contextualHelp.rotatingFreely',
41
+ message: 'Rotating freely (no angle step)',
42
+ }
43
+ : /* i18n */ {
44
+ id: 'editor.lib.contextualHelp.holdToRotateFreely',
45
+ message: 'Hold to rotate freely',
46
+ },
37
47
  active: altPressed,
38
48
  },
39
49
  ]
@@ -77,7 +87,10 @@ export function resolveSelectModeHelpHints({
77
87
 
78
88
  hints.push({
79
89
  keys: [[COMMAND_KEY, SHIFT_KEY], LEFT_CLICK],
80
- label: 'Add or remove objects from the selection',
90
+ label: /* i18n */ {
91
+ id: 'editor.lib.contextualHelp.addOrRemoveObjectsFromThe',
92
+ message: 'Add or remove objects from the selection',
93
+ },
81
94
  active: true,
82
95
  })
83
96
  return hints
@@ -89,23 +102,47 @@ export function resolveSelectModeHelpHints({
89
102
  if (selectedCount > 1) {
90
103
  hints.push({
91
104
  keys: [LEFT_CLICK],
92
- label: 'Click or drag the selection to move it as one',
105
+ label: /* i18n */ {
106
+ id: 'editor.lib.contextualHelp.clickOrDragTheSelectionTo',
107
+ message: 'Click or drag the selection to move it as one',
108
+ },
109
+ })
110
+ hints.push({
111
+ keys: [ROTATE_KEYS],
112
+ label: /* i18n */ {
113
+ id: 'editor.lib.contextualHelp.rotateTheSelection45',
114
+ message: 'Rotate the selection ±45°',
115
+ },
93
116
  })
94
- hints.push({ keys: [ROTATE_KEYS], label: 'Rotate the selection ±45°' })
95
117
  hints.push({
96
118
  keys: [COMMAND_KEY, 'G'],
97
- label: 'Group selection (session only)',
119
+ label: /* i18n */ {
120
+ id: 'editor.lib.contextualHelp.groupSelectionSessionOnly',
121
+ message: 'Group selection (session only)',
122
+ },
98
123
  })
99
124
  hints.push({
100
125
  keys: [COMMAND_KEY, SHIFT_KEY, 'G'],
101
- label: 'Ungroup session selection',
126
+ label: /* i18n */ {
127
+ id: 'editor.lib.contextualHelp.ungroupSessionSelection',
128
+ message: 'Ungroup session selection',
129
+ },
102
130
  })
103
131
  hints.push({
104
132
  keys: [[COMMAND_KEY, SHIFT_KEY], LEFT_CLICK],
105
- label: 'Add or remove objects from the selection',
133
+ label: /* i18n */ {
134
+ id: 'editor.lib.contextualHelp.addOrRemoveObjectsFromThe',
135
+ message: 'Add or remove objects from the selection',
136
+ },
106
137
  active: commandPressed || shiftPressed,
107
138
  })
108
- hints.push({ keys: [ESC_KEY], label: 'Clear the selection (or click outside)' })
139
+ hints.push({
140
+ keys: [ESC_KEY],
141
+ label: /* i18n */ {
142
+ id: 'editor.lib.contextualHelp.clearTheSelectionOrClickOutside',
143
+ message: 'Clear the selection (or click outside)',
144
+ },
145
+ })
109
146
  return hints
110
147
  }
111
148
 
@@ -115,12 +152,39 @@ export function resolveSelectModeHelpHints({
115
152
  // detaches the joint mid-drag; a fitting's cluster adds rotate arcs, with
116
153
  // R / T (and Alt to switch axis) for keyboard rotation.
117
154
  if (mepSelection === 'run') {
118
- hints.push({ keys: [CLICK], label: 'Click a handle dot to show move arrows' })
119
- hints.push({ keys: [ALT_KEY], label: 'Detach the joint while dragging an arrow' })
155
+ hints.push({
156
+ keys: [CLICK],
157
+ label: /* i18n */ {
158
+ id: 'editor.lib.contextualHelp.clickAHandleDotToShow',
159
+ message: 'Click a handle dot to show move arrows',
160
+ },
161
+ })
162
+ hints.push({
163
+ keys: [ALT_KEY],
164
+ label: /* i18n */ {
165
+ id: 'editor.lib.contextualHelp.detachTheJointWhileDraggingAn',
166
+ message: 'Detach the joint while dragging an arrow',
167
+ },
168
+ })
120
169
  } else if (mepSelection === 'fitting') {
121
- hints.push({ keys: [CLICK], label: 'Click the handle dot to show move + rotate handles' })
122
- hints.push({ keys: [ROTATE_KEYS], label: 'Rotate ±45°' })
123
- hints.push({ keys: [ALT_KEY], label: 'Switch the rotation axis (Y → X → Z)' })
170
+ hints.push({
171
+ keys: [CLICK],
172
+ label: /* i18n */ {
173
+ id: 'editor.lib.contextualHelp.clickTheHandleDotToShow',
174
+ message: 'Click the handle dot to show move + rotate handles',
175
+ },
176
+ })
177
+ hints.push({
178
+ keys: [ROTATE_KEYS],
179
+ label: /* i18n */ { id: 'editor.lib.contextualHelp.rotate45', message: 'Rotate ±45°' },
180
+ })
181
+ hints.push({
182
+ keys: [ALT_KEY],
183
+ label: /* i18n */ {
184
+ id: 'editor.lib.contextualHelp.switchTheRotationAxisYX',
185
+ message: 'Switch the rotation axis (Y → X → Z)',
186
+ },
187
+ })
124
188
  }
125
189
 
126
190
  // The rows are the same whatever modifier is held — guides/snapping are
@@ -130,28 +194,40 @@ export function resolveSelectModeHelpHints({
130
194
  if (hasMovableSelection) {
131
195
  hints.push({
132
196
  keys: [LEFT_CLICK],
133
- label: 'Drag selected movable object',
197
+ label: /* i18n */ {
198
+ id: 'editor.lib.contextualHelp.dragSelectedMovableObject',
199
+ message: 'Drag selected movable object',
200
+ },
134
201
  })
135
202
  }
136
203
 
137
204
  if (hasRotatableSelection) {
138
205
  hints.push({
139
206
  keys: [COMMAND_KEY, RIGHT_CLICK],
140
- label: 'Drag left or right to rotate selected object',
207
+ label: /* i18n */ {
208
+ id: 'editor.lib.contextualHelp.dragLeftOrRightToRotate',
209
+ message: 'Drag left or right to rotate selected object',
210
+ },
141
211
  })
142
212
  }
143
213
 
144
214
  if (hasOpeningRadiusSelection) {
145
215
  hints.push({
146
216
  keys: [SHIFT_KEY],
147
- label: 'Adjust one side’s corner radius',
217
+ label: /* i18n */ {
218
+ id: 'editor.lib.contextualHelp.adjustOneSideSCornerRadius',
219
+ message: 'Adjust one side’s corner radius',
220
+ },
148
221
  active: shiftPressed,
149
222
  })
150
223
  }
151
224
 
152
225
  hints.push({
153
226
  keys: [[COMMAND_KEY, SHIFT_KEY], LEFT_CLICK],
154
- label: 'Add or remove objects from the selection',
227
+ label: /* i18n */ {
228
+ id: 'editor.lib.contextualHelp.addOrRemoveObjectsFromThe',
229
+ message: 'Add or remove objects from the selection',
230
+ },
155
231
  active: commandPressed || shiftPressed,
156
232
  })
157
233
 
@@ -1,3 +1,4 @@
1
+ import type { MessageDescriptor } from '@pascal-app/core'
1
2
  export type ContinuationContext = 'wall' | 'fence' | 'point' | 'cabinet' | 'canopy'
2
3
  export type ContinuationMode = string
3
4
 
@@ -6,7 +7,7 @@ export const CONTINUATION_PROFILES: Record<
6
7
  {
7
8
  options: ContinuationMode[]
8
9
  default: ContinuationMode
9
- labels: Record<string, string>
10
+ labels: Record<string, MessageDescriptor>
10
11
  icons: Record<string, string>
11
12
  /**
12
13
  * Picked once from the Build panel before drawing (`wall-draw-variant.ts`),
@@ -17,11 +18,19 @@ export const CONTINUATION_PROFILES: Record<
17
18
  > = {
18
19
  // The wall tool's drawing mode: a chain that closes into a room ('room', the
19
20
  // Build panel's Polygon), one wall per two clicks ('single', Walls), or a
20
- // two-corner box of four walls ('rectangle', Rectangle).
21
+ // two-corner box of four walls ('rectangle', Rectangle). The last one picked
22
+ // is what B arms; Rectangle until one is.
21
23
  wall: {
22
24
  options: ['room', 'single', 'rectangle'],
23
- default: 'room',
24
- labels: { room: 'Polygon room', single: 'Walls', rectangle: 'Rectangle room' },
25
+ default: 'rectangle',
26
+ labels: {
27
+ room: /* i18n */ { id: 'editor.lib.continuation.polygonRoom', message: 'Polygon room' },
28
+ single: /* i18n */ { id: 'editor.lib.continuation.walls', message: 'Walls' },
29
+ rectangle: /* i18n */ {
30
+ id: 'editor.lib.continuation.rectangleRoom',
31
+ message: 'Rectangle room',
32
+ },
33
+ },
25
34
  icons: { room: 'lucide:pentagon', single: 'lucide:minus', rectangle: 'lucide:square' },
26
35
  chosenInPanel: true,
27
36
  },
@@ -29,10 +38,13 @@ export const CONTINUATION_PROFILES: Record<
29
38
  options: ['single', 'continuous', 'curved', 'freehand'],
30
39
  default: 'continuous',
31
40
  labels: {
32
- continuous: 'Continuous',
33
- single: 'Single fence',
34
- curved: 'Curved fence',
35
- freehand: 'Freehand fence',
41
+ continuous: /* i18n */ { id: 'editor.lib.continuation.continuous', message: 'Continuous' },
42
+ single: /* i18n */ { id: 'editor.lib.continuation.singleFence', message: 'Single fence' },
43
+ curved: /* i18n */ { id: 'editor.lib.continuation.curvedFence', message: 'Curved fence' },
44
+ freehand: /* i18n */ {
45
+ id: 'editor.lib.continuation.freehandFence',
46
+ message: 'Freehand fence',
47
+ },
36
48
  },
37
49
  icons: {
38
50
  continuous: 'lucide:waypoints',
@@ -44,19 +56,34 @@ export const CONTINUATION_PROFILES: Record<
44
56
  point: {
45
57
  options: ['once', 'repeat'],
46
58
  default: 'once',
47
- labels: { once: 'Place once', repeat: 'Place multiple' },
59
+ labels: {
60
+ once: /* i18n */ { id: 'editor.lib.continuation.placeOnce', message: 'Place once' },
61
+ repeat: /* i18n */ { id: 'editor.lib.continuation.placeMultiple', message: 'Place multiple' },
62
+ },
48
63
  icons: { once: 'lucide:target', repeat: 'lucide:copy-plus' },
49
64
  },
50
65
  cabinet: {
51
66
  options: ['single', 'continuous'],
52
67
  default: 'single',
53
- labels: { single: 'Single cabinet', continuous: 'Continuous run' },
68
+ labels: {
69
+ single: /* i18n */ { id: 'editor.lib.continuation.singleCabinet', message: 'Single cabinet' },
70
+ continuous: /* i18n */ {
71
+ id: 'editor.lib.continuation.continuousRun',
72
+ message: 'Continuous run',
73
+ },
74
+ },
54
75
  icons: { single: 'lucide:minus', continuous: 'lucide:waypoints' },
55
76
  },
56
77
  canopy: {
57
78
  options: ['single', 'continuous'],
58
79
  default: 'single',
59
- labels: { single: 'Single canopy', continuous: 'Continuous canopy' },
80
+ labels: {
81
+ single: /* i18n */ { id: 'editor.lib.continuation.singleCanopy', message: 'Single canopy' },
82
+ continuous: /* i18n */ {
83
+ id: 'editor.lib.continuation.continuousCanopy',
84
+ message: 'Continuous canopy',
85
+ },
86
+ },
60
87
  icons: { single: 'lucide:minus', continuous: 'lucide:waypoints' },
61
88
  },
62
89
  }