@pascal-app/editor 1.0.7 → 1.1.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.
Files changed (336) hide show
  1. package/package.json +9 -15
  2. package/src/components/editor/action-menu-button.tsx +1 -1
  3. package/src/components/editor/alignment-3d-guide-layer.tsx +1 -1
  4. package/src/components/editor/custom-camera-controls.tsx +101 -45
  5. package/src/components/editor/duplicate-node.ts +2 -1
  6. package/src/components/editor/editor-layout-v2.tsx +1 -1
  7. package/src/components/editor/elevation-3d-guide-layer.tsx +1 -1
  8. package/src/components/editor/first-person-controls.tsx +20 -1983
  9. package/src/components/editor/fit-scene-framing.test.ts +318 -0
  10. package/src/components/editor/fit-scene-framing.ts +142 -0
  11. package/src/components/editor/floating-action-menu.tsx +5 -3
  12. package/src/components/editor/floating-building-action-menu.tsx +1 -1
  13. package/src/components/editor/floor-openings-overlay.tsx +1 -1
  14. package/src/components/editor/floor-region-controls.tsx +8 -4
  15. package/src/components/editor/floorplan-navigation-presentation.test.ts +0 -40
  16. package/src/components/editor/floorplan-navigation-presentation.ts +0 -66
  17. package/src/components/editor/floorplan-panel.tsx +199 -30
  18. package/src/components/editor/floorplan-wall-typing-keys.test.tsx +152 -0
  19. package/src/components/editor/floorplan-wall-typing-keys.ts +79 -0
  20. package/src/components/editor/follow-pascal.test.tsx +1 -2
  21. package/src/components/editor/follow-pascal.tsx +1 -1
  22. package/src/components/editor/footprint-height-handle.tsx +2 -2
  23. package/src/components/editor/group-actions.ts +1 -2
  24. package/src/components/editor/group-floating-action-menu.tsx +1 -1
  25. package/src/components/editor/group-move-3d.ts +1 -2
  26. package/src/components/editor/group-rotate-handle.tsx +1 -2
  27. package/src/components/editor/group-transform-shared.ts +3 -1
  28. package/src/components/editor/handles/use-handle-drag.ts +1 -2
  29. package/src/components/editor/index.tsx +43 -13
  30. package/src/components/editor/inspector-extension-actions.tsx +1 -1
  31. package/src/components/editor/measurement-pill.tsx +1 -1
  32. package/src/components/editor/node-arrow-handles.tsx +2 -2
  33. package/src/components/editor/open-wall-ends-3d-layer.tsx +2 -3
  34. package/src/components/editor/open-wall-ends-hint.tsx +1 -1
  35. package/src/components/editor/opening-guides-3d-layer.tsx +1 -1
  36. package/src/components/editor/quick-measurement-card.tsx +1 -1
  37. package/src/components/editor/room-controls.tsx +10 -6
  38. package/src/components/editor/room-handles-2d.tsx +3 -3
  39. package/src/components/editor/room-handles.tsx +4 -5
  40. package/src/components/editor/room-highlight.tsx +6 -105
  41. package/src/components/editor/room-labels.test.ts +8 -822
  42. package/src/components/editor/room-labels.tsx +41 -1670
  43. package/src/components/editor/room-webgpu-materials.test.ts +1 -1
  44. package/src/components/editor/selection-manager.tsx +5 -3
  45. package/src/components/editor/site-edge-labels.tsx +7 -3
  46. package/src/components/editor/snapshot-capture-overlay.tsx +2 -5
  47. package/src/components/editor/use-floorplan-background-placement.ts +2 -1
  48. package/src/components/editor/views/plugins-view.tsx +1 -1
  49. package/src/components/editor/views/view-bar.tsx +9 -9
  50. package/src/components/editor/wall-measurement-label.tsx +31 -15
  51. package/src/components/editor/wall-move-side-handles.tsx +11 -7
  52. package/src/components/editor/wall-pull-grip.tsx +2 -2
  53. package/src/components/editor/wall-region-handles.tsx +2 -2
  54. package/src/components/editor/wall-snap-beacon-layer.tsx +53 -32
  55. package/src/components/editor-2d/floorplan-group-move.tsx +3 -4
  56. package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +13 -13
  57. package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +2 -3
  58. package/src/components/editor-2d/floorplan-registry-action-menu.tsx +2 -1
  59. package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +23 -6
  60. package/src/components/editor-2d/renderers/floorplan-annotation-layout.test.ts +0 -37
  61. package/src/components/editor-2d/renderers/floorplan-annotation-layout.ts +0 -30
  62. package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +13 -3
  63. package/src/components/editor-2d/renderers/floorplan-draft-measurement.tsx +7 -1
  64. package/src/components/editor-2d/renderers/floorplan-placement-preview-layer.tsx +14 -3
  65. package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.test.tsx +35 -0
  66. package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.tsx +65 -0
  67. package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +30 -10
  68. package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +39 -35
  69. package/src/components/systems/roof/roof-edit-system.test.tsx +15 -1
  70. package/src/components/systems/roof/roof-edit-system.tsx +33 -21
  71. package/src/components/tools/distribution/distribution-run-tool.test.tsx +371 -3
  72. package/src/components/tools/distribution/distribution-run-tool.tsx +151 -33
  73. package/src/components/tools/item/move-tool.tsx +1 -6
  74. package/src/components/tools/item/placement-history.test.tsx +1 -1
  75. package/src/components/tools/item/use-placement-coordinator.tsx +3 -4
  76. package/src/components/tools/paint-region/wall-paint-region-tool.tsx +7 -3
  77. package/src/components/tools/registry/move-registry-node-tool.test.ts +42 -1
  78. package/src/components/tools/registry/move-registry-node-tool.tsx +39 -16
  79. package/src/components/tools/shared/cursor-sphere.tsx +1 -1
  80. package/src/components/tools/shared/draft-measurement-label.tsx +1 -1
  81. package/src/components/tools/shared/placement-box.tsx +2 -6
  82. package/src/components/tools/shared/placement-coordinate-input.tsx +94 -0
  83. package/src/components/tools/shared/placement-dimension-guides.tsx +1 -1
  84. package/src/components/tools/shared/segment-angle.ts +0 -4
  85. package/src/components/tools/site/terrain-brush-cursor.tsx +1 -1
  86. package/src/components/tools/tool-manager.tsx +1 -24
  87. package/src/components/tools/wall/wall-typed-entry.test.ts +99 -0
  88. package/src/components/tools/wall/wall-typed-entry.ts +70 -0
  89. package/src/components/ui/action-menu/camera-actions.tsx +2 -2
  90. package/src/components/ui/action-menu/control-modes.tsx +1 -1
  91. package/src/components/ui/action-menu/follow-pascal-pill.tsx +1 -1
  92. package/src/components/ui/action-menu/index.tsx +3 -3
  93. package/src/components/ui/action-menu/measurement-control.tsx +3 -3
  94. package/src/components/ui/action-menu/placement.ts +0 -18
  95. package/src/components/ui/action-menu/point-ask-button.tsx +1 -1
  96. package/src/components/ui/action-menu/view-toggles.tsx +5 -5
  97. package/src/components/ui/controls/finish-swatch.tsx +1 -1
  98. package/src/components/ui/controls/material-paint-panel.tsx +2 -2
  99. package/src/components/ui/controls/scene-material-list.tsx +2 -2
  100. package/src/components/ui/controls/select-control.tsx +1 -1
  101. package/src/components/ui/controls/slider-control.tsx +18 -6
  102. package/src/components/ui/controls/terrain-sculpt-panel.tsx +1 -1
  103. package/src/components/ui/controls/tool-options-panel.tsx +74 -44
  104. package/src/components/ui/floating-level-selector.tsx +3 -3
  105. package/src/components/ui/helpers/contextual-helper-panel.tsx +1 -1
  106. package/src/components/ui/helpers/helper-manager.test.tsx +54 -1
  107. package/src/components/ui/helpers/helper-manager.tsx +55 -1
  108. package/src/components/ui/level-duplicate-dialog.tsx +1 -1
  109. package/src/components/ui/panels/collections/collections-popover.tsx +2 -2
  110. package/src/components/ui/panels/floor-foundation-panel.tsx +3 -3
  111. package/src/components/ui/panels/floor-opening-panel.tsx +5 -5
  112. package/src/components/ui/panels/mobile-selection-bar.tsx +28 -24
  113. package/src/components/ui/panels/multi-height-mode.tsx +3 -3
  114. package/src/components/ui/panels/multi-selection-panel.tsx +1 -1
  115. package/src/components/ui/panels/node-display.ts +1 -1
  116. package/src/components/ui/panels/panel-manager.tsx +5 -3
  117. package/src/components/ui/panels/panel-wrapper.tsx +42 -19
  118. package/src/components/ui/panels/parametric-inspector.tsx +1 -1
  119. package/src/components/ui/panels/room-construction-rows.tsx +7 -7
  120. package/src/components/ui/panels/room-name-options.ts +1 -5
  121. package/src/components/ui/panels/room-openings-field.tsx +1 -1
  122. package/src/components/ui/panels/room-panel.tsx +7 -9
  123. package/src/components/ui/primitives/color-dot.tsx +2 -2
  124. package/src/components/ui/primitives/opacity-control.tsx +2 -2
  125. package/src/components/ui/primitives/sidebar.tsx +3 -3
  126. package/src/components/ui/right-stack.test.ts +13 -6
  127. package/src/components/ui/right-stack.tsx +22 -11
  128. package/src/components/ui/sidebar/icon-rail.tsx +1 -1
  129. package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +1 -1
  130. package/src/components/ui/sidebar/panels/settings-panel/audio-settings-dialog.tsx +2 -2
  131. package/src/components/ui/sidebar/panels/settings-panel/construction-animation-setting.tsx +1 -1
  132. package/src/components/ui/sidebar/panels/settings-panel/index.tsx +2 -2
  133. package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +1 -1
  134. package/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx +2 -6
  135. package/src/components/ui/sidebar/panels/settings-panel/print-export-button.tsx +1 -1
  136. package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +1 -1
  137. package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +1 -1
  138. package/src/components/ui/sidebar/panels/site-panel/index.tsx +3 -10
  139. package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +1 -1
  140. package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +1 -1
  141. package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +46 -7
  142. package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +1 -1
  143. package/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +1 -1
  144. package/src/components/ui/sidebar/panels/site-panel/tree-node-drag.tsx +14 -5
  145. package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +2 -2
  146. package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +1 -1
  147. package/src/components/ui/sidebar/panels/zone-panel/index.tsx +3 -3
  148. package/src/components/ui/sidebar/tab-bar.tsx +1 -1
  149. package/src/components/ui/wall-type/wall-type-editor-dialog.tsx +2 -2
  150. package/src/components/ui/wall-type/wall-type-menu.tsx +1 -1
  151. package/src/components/viewer-overlay.tsx +1 -2
  152. package/src/hooks/use-auto-frame.ts +1 -2
  153. package/src/hooks/use-keyboard.ts +1 -2
  154. package/src/hooks/use-selected-room.ts +5 -7
  155. package/src/i18n/floor-footprint-name.ts +1 -1
  156. package/src/i18n/locales/en/messages.po +1036 -306
  157. package/src/i18n/locales/en/messages.ts +1 -1
  158. package/src/i18n/locales/en-XA/messages.ts +1 -1
  159. package/src/i18n/locales/es/messages.po +2267 -439
  160. package/src/i18n/locales/fr/messages.po +2267 -439
  161. package/src/i18n/locales/ja/messages.po +2267 -439
  162. package/src/i18n/locales/zh-CN/messages.po +2267 -439
  163. package/src/i18n/locales.test.ts +1 -1
  164. package/src/index.tsx +183 -178
  165. package/src/lib/below-grade.test.tsx +4 -4
  166. package/src/lib/camera-facing.test.ts +1 -1
  167. package/src/lib/camera-facing.ts +2 -3
  168. package/src/lib/contextual-help.ts +6 -0
  169. package/src/lib/editor-level-display.ts +1 -1
  170. package/src/lib/elevation-guides.ts +21 -6
  171. package/src/lib/elevator-support.ts +1 -72
  172. package/src/lib/floor-footprints.test.ts +3 -3
  173. package/src/lib/floor-footprints.ts +1 -9
  174. package/src/lib/floor-foundation-support.test.ts +8 -3
  175. package/src/lib/floor-opening-draft.ts +2 -2
  176. package/src/lib/floor-region-session.ts +1 -1
  177. package/src/lib/floorplan/annotation-visibility.test.ts +1 -1
  178. package/src/lib/floorplan/annotation-visibility.ts +1 -1
  179. package/src/lib/floorplan/floorplan-export.test.ts +1 -1
  180. package/src/lib/floorplan/floorplan-export.tsx +8 -11
  181. package/src/lib/floorplan/floorplan-extension.ts +4 -157
  182. package/src/lib/floorplan/floorplan-mode.ts +2 -1
  183. package/src/lib/floorplan/floorplan-pdfkit-renderer.test.ts +1 -1
  184. package/src/lib/floorplan/floorplan-pdfkit-renderer.ts +8 -6
  185. package/src/lib/floorplan/floorplan-plugin-install.test.tsx +3 -4
  186. package/src/lib/floorplan/geometry.ts +2 -112
  187. package/src/lib/floorplan/index.ts +0 -9
  188. package/src/lib/floorplan/items.ts +2 -1
  189. package/src/lib/floorplan/open-wall-ends.ts +2 -1
  190. package/src/lib/floorplan/schedules.ts +6 -3
  191. package/src/lib/floorplan/sheet-export.ts +7 -3
  192. package/src/lib/floorplan/site-plan/site-parts.ts +7 -1
  193. package/src/lib/floorplan/site-plan/site-plan-layer.tsx +1 -1
  194. package/src/lib/follow-pascal-presentation.ts +1 -1
  195. package/src/lib/gesture-lifecycle.ts +3 -1
  196. package/src/lib/glb-export.ts +1 -1
  197. package/src/lib/interaction/scope.ts +1 -0
  198. package/src/lib/layer-thickness.ts +1 -1
  199. package/src/lib/level-selection.test.ts +18 -2
  200. package/src/lib/level-selection.ts +31 -8
  201. package/src/lib/linear-display.ts +1 -1
  202. package/src/lib/live-gesture-round-trip.test.ts +1 -1
  203. package/src/lib/material-paint.ts +1 -1
  204. package/src/lib/measurement-label.test.ts +1 -1
  205. package/src/lib/measurements.test.ts +7 -5
  206. package/src/lib/mezzanine-selection.test.ts +1 -1
  207. package/src/lib/node-action-movement.test.tsx +115 -0
  208. package/src/lib/node-action-movement.ts +2 -0
  209. package/src/lib/paint-region-mode.ts +1 -1
  210. package/src/lib/placement-metadata.ts +4 -0
  211. package/src/lib/point-ask/describe-target.ts +6 -8
  212. package/src/lib/point-ask/region.ts +1 -1
  213. package/src/lib/point-ask/session.ts +1 -2
  214. package/src/lib/print-shell-compiler.ts +12 -1
  215. package/src/lib/print-wall-solids.test.ts +11 -0
  216. package/src/lib/print-wall-solids.ts +9 -0
  217. package/src/lib/roof-duplication.test.ts +100 -0
  218. package/src/lib/roof-duplication.ts +30 -5
  219. package/src/lib/room-built-on.test.ts +2 -5
  220. package/src/lib/room-built-on.ts +1 -15
  221. package/src/lib/room-construction-commands.ts +3 -2
  222. package/src/lib/room-controls-phase6.test.ts +1 -1
  223. package/src/lib/room-handle-drag.ts +8 -37
  224. package/src/lib/room-name-catalog.test.ts +2 -1
  225. package/src/lib/room-name-messages.test.ts +2 -1
  226. package/src/lib/room-name-messages.ts +1 -118
  227. package/src/lib/room-name-storage.test.ts +2 -1
  228. package/src/lib/room-push-dimensions.test.ts +1 -1
  229. package/src/lib/room-selection-commands.ts +2 -2
  230. package/src/lib/room-selection.test.ts +6 -6
  231. package/src/lib/room-transform-session.ts +1 -2
  232. package/src/lib/room-zone-routing.ts +2 -2
  233. package/src/lib/scene-clipboard.ts +2 -1
  234. package/src/lib/selection-routing.test.ts +0 -28
  235. package/src/lib/selection-routing.ts +1 -40
  236. package/src/lib/sfx-bus.ts +8 -32
  237. package/src/lib/sfx-player.test.ts +72 -1
  238. package/src/lib/sfx-player.ts +49 -337
  239. package/src/lib/snapping-mode.test.ts +23 -1
  240. package/src/lib/viewer-selection.test.ts +38 -10
  241. package/src/lib/wall-pull.test.ts +1 -1
  242. package/src/lib/wall-pull.ts +1 -27
  243. package/src/lib/wall-region-list.ts +3 -1
  244. package/src/lib/window-interaction.test.ts +4 -2
  245. package/src/store/use-editor.tsx +22 -26
  246. package/src/store/use-floorplan-annotation-visibility.ts +5 -5
  247. package/src/store/use-placement-typing.test.ts +165 -0
  248. package/src/store/use-placement-typing.ts +186 -0
  249. package/src/store/use-wall-region-handles-selection.ts +1 -2
  250. package/src/components/editor/__bench__/room-label-placement.bench.ts +0 -108
  251. package/src/components/editor/first-person/build-collider-world.test.ts +0 -596
  252. package/src/components/editor/first-person/build-collider-world.ts +0 -549
  253. package/src/components/editor/first-person/ground-holes.test.ts +0 -128
  254. package/src/components/editor/first-person/ground-holes.ts +0 -130
  255. package/src/components/editor/first-person/mechanism-targets.test.ts +0 -162
  256. package/src/components/editor/first-person/mechanism-targets.ts +0 -88
  257. package/src/components/editor/first-person/terrain-collider.test.ts +0 -132
  258. package/src/components/editor/first-person/terrain-collider.ts +0 -212
  259. package/src/components/editor/floorplan-camera-sync.test.ts +0 -249
  260. package/src/components/editor/floorplan-camera-sync.ts +0 -213
  261. package/src/components/editor/localized-html.tsx +0 -22
  262. package/src/components/editor-2d/renderers/floorplan-dimension-renderer.test.tsx +0 -236
  263. package/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx +0 -708
  264. package/src/components/editor-2d/renderers/floorplan-geometry-renderer.test.tsx +0 -385
  265. package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +0 -670
  266. package/src/components/editor-2d/renderers/floorplan-label-angle.test.ts +0 -89
  267. package/src/components/editor-2d/renderers/floorplan-label-angle.ts +0 -106
  268. package/src/components/editor-2d/svg-paths.ts +0 -124
  269. package/src/components/tools/elevator/elevator-defaults.ts +0 -8
  270. package/src/components/tools/elevator/elevator-tool.tsx +0 -372
  271. package/src/components/tools/elevator/move-elevator-tool.tsx +0 -262
  272. package/src/components/ui/action-menu/action-button.tsx +0 -89
  273. package/src/components/ui/action-menu/follow-pascal-toggle.tsx +0 -42
  274. package/src/components/ui/primitives/button.tsx +0 -69
  275. package/src/components/ui/primitives/dropdown-menu.tsx +0 -232
  276. package/src/components/ui/primitives/popover.tsx +0 -42
  277. package/src/components/ui/primitives/switch.tsx +0 -29
  278. package/src/components/ui/primitives/tooltip.tsx +0 -57
  279. package/src/components/ui/scene-loader.tsx +0 -73
  280. package/src/components/viewer/floorplan-compass-button.tsx +0 -67
  281. package/src/components/viewer/floorplan-preview-geometry.test.ts +0 -107
  282. package/src/components/viewer/floorplan-preview-geometry.ts +0 -281
  283. package/src/components/viewer/floorplan-preview-navigation.test.ts +0 -43
  284. package/src/components/viewer/floorplan-preview-navigation.ts +0 -62
  285. package/src/components/viewer/floorplan-preview-visibility.test.ts +0 -35
  286. package/src/components/viewer/floorplan-preview-visibility.ts +0 -19
  287. package/src/components/viewer/floorplan-preview.tsx +0 -1065
  288. package/src/components/viewer/render-settings-menu.tsx +0 -294
  289. package/src/components/viewer/sky-control.tsx +0 -710
  290. package/src/components/viewer/use-viewer-camera-navigation-sync.ts +0 -140
  291. package/src/components/viewer/use-viewer-ui-sounds.test.ts +0 -15
  292. package/src/components/viewer/use-viewer-ui-sounds.ts +0 -46
  293. package/src/components/viewer/viewer-controls-bar.tsx +0 -496
  294. package/src/components/viewer/viewer-hover-label.tsx +0 -42
  295. package/src/components/viewer/viewer-rooms.tsx +0 -248
  296. package/src/components/viewer/viewer-scene-header.tsx +0 -286
  297. package/src/components/viewer/viewer-selection-manager.tsx +0 -124
  298. package/src/components/viewer/viewer-stage-modes.test.ts +0 -38
  299. package/src/components/viewer/viewer-stage-modes.ts +0 -49
  300. package/src/components/viewer/viewer-stage-switcher.tsx +0 -97
  301. package/src/components/viewer/viewer-stage.test.tsx +0 -47
  302. package/src/components/viewer/viewer-stage.tsx +0 -221
  303. package/src/components/walkthrough-hud.tsx +0 -193
  304. package/src/hooks/use-mobile.ts +0 -19
  305. package/src/i18n/level-name.ts +0 -39
  306. package/src/i18n/scene-theme-name.ts +0 -16
  307. package/src/lib/below-grade.ts +0 -133
  308. package/src/lib/camera-pose.test.ts +0 -237
  309. package/src/lib/camera-pose.ts +0 -172
  310. package/src/lib/door-interaction.ts +0 -102
  311. package/src/lib/floorplan/floorplan-extension.test.ts +0 -42
  312. package/src/lib/floorplan/floorplan-readonly.test.ts +0 -47
  313. package/src/lib/floorplan/floorplan-readonly.ts +0 -95
  314. package/src/lib/floorplan/marks.test.ts +0 -213
  315. package/src/lib/floorplan/marks.ts +0 -238
  316. package/src/lib/measurement-label.ts +0 -68
  317. package/src/lib/measurements.ts +0 -225
  318. package/src/lib/node-display-label.ts +0 -37
  319. package/src/lib/room-assembly-overlay.test.ts +0 -275
  320. package/src/lib/room-assembly-overlay.ts +0 -265
  321. package/src/lib/room-selection.ts +0 -417
  322. package/src/lib/scene-bounds.test.ts +0 -183
  323. package/src/lib/scene-bounds.ts +0 -169
  324. package/src/lib/typing-target.ts +0 -9
  325. package/src/lib/viewer-selection.ts +0 -595
  326. package/src/lib/window-interaction.ts +0 -142
  327. package/src/lib/zone-content.ts +0 -133
  328. package/src/store/camera-pose-store.test.ts +0 -29
  329. package/src/store/camera-pose-store.ts +0 -27
  330. package/src/store/navigation-sync-pose-store.test.ts +0 -34
  331. package/src/store/navigation-sync-pose-store.ts +0 -27
  332. package/src/store/use-audio.test.ts +0 -146
  333. package/src/store/use-audio.tsx +0 -169
  334. package/src/store/use-first-person-hud.ts +0 -40
  335. package/src/store/use-follow-pascal.test.ts +0 -62
  336. package/src/store/use-follow-pascal.ts +0 -53
@@ -1,262 +0,0 @@
1
- import {
2
- type AnyNodeId,
3
- type BuildingNode,
4
- type ElevatorNode,
5
- ElevatorNode as ElevatorNodeSchema,
6
- emitter,
7
- type GridEvent,
8
- type LevelNode,
9
- pauseSceneHistory,
10
- resumeSceneHistory,
11
- sceneRegistry,
12
- useLiveTransforms,
13
- useScene,
14
- } from '@pascal-app/core'
15
- import { useCallback, useEffect, useRef, useState } from 'react'
16
- import { markToolCancelConsumed } from '../../../hooks/use-keyboard'
17
- import { resolveElevatorSupportY } from '../../../lib/elevator-support'
18
- import { consumePlacementDragRelease } from '../../../lib/placement-drag-release'
19
- import { sfxEmitter } from '../../../lib/sfx-bus'
20
- import { isTypingTarget } from '../../../lib/typing-target'
21
- import useEditor from '../../../store/use-editor'
22
- import { CursorSphere } from '../shared/cursor-sphere'
23
-
24
- function stripMoveMetadata(metadata: ElevatorNode['metadata']) {
25
- if (typeof metadata !== 'object' || metadata === null || Array.isArray(metadata)) {
26
- return metadata
27
- }
28
-
29
- const nextMeta = { ...(metadata as Record<string, unknown>) }
30
- delete nextMeta.isNew
31
- delete nextMeta.isTransient
32
- return nextMeta as ElevatorNode['metadata']
33
- }
34
-
35
- export function MoveElevatorTool({
36
- node: movingNode,
37
- onCommitted,
38
- }: {
39
- node: ElevatorNode
40
- onCommitted?: (nodeId: AnyNodeId) => void
41
- }) {
42
- const onCommittedRef = useRef(onCommitted)
43
- const historyPausedRef = useRef(false)
44
- const previousGridPosRef = useRef<[number, number] | null>(null)
45
- const dragAnchorRef = useRef<[number, number] | null>(null)
46
- const previewPositionRef = useRef<ElevatorNode['position']>([
47
- movingNode.position[0],
48
- movingNode.position[1],
49
- movingNode.position[2],
50
- ])
51
- const [cursorPosition, setCursorPosition] = useState<[number, number, number]>(() => [
52
- movingNode.position[0],
53
- movingNode.position[1],
54
- movingNode.position[2],
55
- ])
56
-
57
- const exitMoveMode = useCallback(() => {
58
- useEditor.getState().setMovingNode(null)
59
- }, [])
60
-
61
- useEffect(() => {
62
- onCommittedRef.current = onCommitted
63
- }, [onCommitted])
64
-
65
- useEffect(() => {
66
- const pauseHistory = () => {
67
- const temporal = useScene.temporal.getState()
68
- if (historyPausedRef.current || !temporal.isTracking) return
69
- pauseSceneHistory(useScene)
70
- historyPausedRef.current = true
71
- }
72
- const resumeHistory = () => {
73
- if (!historyPausedRef.current) return
74
- resumeSceneHistory(useScene)
75
- historyPausedRef.current = false
76
- }
77
-
78
- pauseHistory()
79
- dragAnchorRef.current = null
80
- previousGridPosRef.current = null
81
- const movingNodeId = (movingNode as { id?: ElevatorNode['id'] }).id
82
-
83
- const meta =
84
- typeof movingNode.metadata === 'object' && movingNode.metadata !== null
85
- ? (movingNode.metadata as Record<string, unknown>)
86
- : {}
87
- const isNew = !!meta.isNew
88
- const committedMeta = stripMoveMetadata(movingNode.metadata)
89
- const original = {
90
- position: [...movingNode.position] as ElevatorNode['position'],
91
- rotation: movingNode.rotation,
92
- metadata: movingNode.metadata,
93
- }
94
-
95
- let wasCommitted = false
96
- let wasCancelled = false
97
- let pendingRotation = movingNode.rotation
98
- const supportBuildingId = movingNode.parentId as BuildingNode['id'] | null | undefined
99
- const supportLevelId = (movingNode.fromLevelId ?? movingNode.defaultLevelId) as
100
- | LevelNode['id']
101
- | null
102
-
103
- const applyPreview = (
104
- position: ElevatorNode['position'],
105
- rotation: ElevatorNode['rotation'],
106
- ) => {
107
- if (movingNodeId) {
108
- useLiveTransforms.getState().set(movingNodeId, { position, rotation })
109
- }
110
-
111
- const object = movingNodeId ? sceneRegistry.nodes.get(movingNodeId) : null
112
- if (object) {
113
- object.position.set(position[0], position[1], position[2])
114
- object.rotation.y = rotation
115
- }
116
- }
117
-
118
- const resetObject = (
119
- position: ElevatorNode['position'],
120
- rotation: ElevatorNode['rotation'],
121
- ) => {
122
- const object = movingNodeId ? sceneRegistry.nodes.get(movingNodeId) : null
123
- if (object) {
124
- object.position.set(position[0], position[1], position[2])
125
- object.rotation.y = rotation
126
- }
127
- }
128
-
129
- const clearPreview = () => {
130
- if (movingNodeId) {
131
- useLiveTransforms.getState().clear(movingNodeId)
132
- }
133
- }
134
-
135
- const onGridMove = (event: GridEvent) => {
136
- const bypassSnap = event.nativeEvent?.shiftKey === true
137
- const rawX = bypassSnap ? event.localPosition[0] : Math.round(event.localPosition[0] * 2) / 2
138
- const rawZ = bypassSnap ? event.localPosition[2] : Math.round(event.localPosition[2] * 2) / 2
139
- const anchor = dragAnchorRef.current ?? [rawX, rawZ]
140
- dragAnchorRef.current = anchor
141
- const gridX = movingNode.position[0] + (rawX - anchor[0])
142
- const gridZ = movingNode.position[2] + (rawZ - anchor[1])
143
- const supportY = resolveElevatorSupportY({
144
- buildingId: supportBuildingId,
145
- preferredLevelId: supportLevelId,
146
- x: gridX,
147
- z: gridZ,
148
- })
149
-
150
- if (
151
- !bypassSnap &&
152
- previousGridPosRef.current &&
153
- (gridX !== previousGridPosRef.current[0] || gridZ !== previousGridPosRef.current[1])
154
- ) {
155
- sfxEmitter.emit('sfx:grid-snap')
156
- }
157
-
158
- previousGridPosRef.current = [gridX, gridZ]
159
- setCursorPosition([gridX, supportY, gridZ])
160
- previewPositionRef.current = [gridX, supportY, gridZ]
161
- applyPreview(previewPositionRef.current, pendingRotation)
162
- }
163
-
164
- const onGridClick = (event: GridEvent) => {
165
- if (wasCommitted) return
166
- const nextPosition: ElevatorNode['position'] = [...previewPositionRef.current]
167
-
168
- wasCommitted = true
169
- clearPreview()
170
- resumeHistory()
171
- if (movingNodeId && useScene.getState().nodes[movingNodeId as AnyNodeId]) {
172
- useScene.getState().updateNode(movingNodeId as AnyNodeId, {
173
- position: nextPosition,
174
- rotation: pendingRotation,
175
- metadata: committedMeta,
176
- })
177
- onCommittedRef.current?.(movingNodeId as AnyNodeId)
178
- } else if (movingNode.parentId) {
179
- const elevator = ElevatorNodeSchema.parse({
180
- ...movingNode,
181
- id: undefined,
182
- position: nextPosition,
183
- rotation: pendingRotation,
184
- metadata: committedMeta,
185
- })
186
- useScene.getState().createNode(elevator, movingNode.parentId as AnyNodeId)
187
- onCommittedRef.current?.(elevator.id as AnyNodeId)
188
- }
189
-
190
- sfxEmitter.emit('sfx:item-place')
191
- exitMoveMode()
192
- event.nativeEvent?.stopPropagation?.()
193
- }
194
-
195
- const onPlacementDragPointerUp = (event: PointerEvent) => {
196
- if (!consumePlacementDragRelease(event)) return
197
- onGridClick({ nativeEvent: event } as unknown as GridEvent)
198
- }
199
-
200
- const onCancel = () => {
201
- wasCancelled = true
202
- clearPreview()
203
- if (isNew && movingNodeId) {
204
- useScene.getState().deleteNode(movingNodeId as AnyNodeId)
205
- } else {
206
- if (movingNodeId) {
207
- useScene.getState().updateNode(movingNodeId as AnyNodeId, {
208
- position: original.position,
209
- rotation: original.rotation,
210
- metadata: original.metadata,
211
- })
212
- }
213
- }
214
- resetObject(original.position, original.rotation)
215
- resumeHistory()
216
- markToolCancelConsumed()
217
- exitMoveMode()
218
- }
219
-
220
- const onKeyDown = (event: KeyboardEvent) => {
221
- if (isTypingTarget(event.target)) return
222
-
223
- const ROTATION_STEP = Math.PI / 4
224
- let rotationDelta = 0
225
- if (event.key === 'r' || event.key === 'R') rotationDelta = ROTATION_STEP
226
- else if (event.key === 't' || event.key === 'T') rotationDelta = -ROTATION_STEP
227
-
228
- if (rotationDelta !== 0) {
229
- event.preventDefault()
230
- sfxEmitter.emit('sfx:item-rotate')
231
- pendingRotation += rotationDelta
232
- applyPreview(previewPositionRef.current, pendingRotation)
233
- }
234
- }
235
-
236
- emitter.on('grid:move', onGridMove)
237
- emitter.on('grid:click', onGridClick)
238
- emitter.on('tool:cancel', onCancel)
239
- window.addEventListener('keydown', onKeyDown)
240
- window.addEventListener('pointerup', onPlacementDragPointerUp)
241
-
242
- return () => {
243
- clearPreview()
244
- if (!(wasCommitted || wasCancelled || isNew) && movingNodeId) {
245
- useScene.getState().updateNode(movingNodeId as AnyNodeId, {
246
- position: original.position,
247
- rotation: original.rotation,
248
- metadata: original.metadata,
249
- })
250
- resetObject(original.position, original.rotation)
251
- }
252
- resumeHistory()
253
- emitter.off('grid:move', onGridMove)
254
- emitter.off('grid:click', onGridClick)
255
- emitter.off('tool:cancel', onCancel)
256
- window.removeEventListener('keydown', onKeyDown)
257
- window.removeEventListener('pointerup', onPlacementDragPointerUp)
258
- }
259
- }, [movingNode, exitMoveMode])
260
-
261
- return <CursorSphere position={cursorPosition} showTooltip={false} />
262
- }
@@ -1,89 +0,0 @@
1
- import * as React from 'react'
2
- import { Button } from './../../../components/ui/primitives/button'
3
- import {
4
- Tooltip,
5
- TooltipContent,
6
- TooltipTrigger,
7
- } from './../../../components/ui/primitives/tooltip'
8
- import { triggerSFX } from './../../../lib/sfx-bus'
9
- import { cn } from './../../../lib/utils'
10
- import { useActionMenuPopupSide } from './placement'
11
-
12
- interface ActionButtonProps extends React.ComponentProps<typeof Button> {
13
- label: string
14
- shortcut?: string
15
- isActive?: boolean
16
- tooltipContent?: React.ReactNode
17
- tooltipSide?: 'top' | 'right' | 'bottom' | 'left'
18
- /** The tooltip portals to `<body>`, so a button in a themed scope passes the scope here. */
19
- tooltipClassName?: string
20
- }
21
-
22
- export const ActionButton = React.forwardRef<HTMLButtonElement, ActionButtonProps>(
23
- (
24
- {
25
- className,
26
- children,
27
- label,
28
- shortcut,
29
- isActive,
30
- tooltipContent,
31
- tooltipSide,
32
- tooltipClassName,
33
- onClick,
34
- onMouseEnter,
35
- ...props
36
- },
37
- ref,
38
- ) => {
39
- const popupSide = useActionMenuPopupSide()
40
- return (
41
- <Tooltip>
42
- <TooltipTrigger asChild>
43
- <Button
44
- // These are toggles, not commands: the armed/unarmed state has to be
45
- // readable without decoding the active-state styling.
46
- aria-pressed={isActive}
47
- // Icon-only: the tooltip text is the button's name.
48
- aria-label={label}
49
- className={cn('relative h-11 w-11 transition-all', className)}
50
- onClick={(event) => {
51
- triggerSFX('sfx:menu-click')
52
- onClick?.(event)
53
- }}
54
- onMouseEnter={(event) => {
55
- triggerSFX('sfx:menu-hover')
56
- onMouseEnter?.(event)
57
- }}
58
- ref={ref}
59
- {...props}
60
- >
61
- <div
62
- className={cn(
63
- 'flex h-full w-full items-center justify-center transition-transform',
64
- shortcut && '-translate-x-0.5 -translate-y-0.5',
65
- )}
66
- >
67
- {children}
68
- </div>
69
- {shortcut && (
70
- <div className="absolute right-1 bottom-1 rounded border border-border/40 bg-background/40 px-1 py-[2px] backdrop-blur-md">
71
- <span className="block font-medium font-mono text-[9px] text-muted-foreground/70 leading-none">
72
- {shortcut}
73
- </span>
74
- </div>
75
- )}
76
- </Button>
77
- </TooltipTrigger>
78
- <TooltipContent className={tooltipClassName} side={tooltipSide ?? popupSide}>
79
- {tooltipContent || (
80
- <p>
81
- {label} {shortcut && `(${shortcut})`}
82
- </p>
83
- )}
84
- </TooltipContent>
85
- </Tooltip>
86
- )
87
- },
88
- )
89
- ActionButton.displayName = 'ActionButton'
@@ -1,42 +0,0 @@
1
- 'use client'
2
-
3
- import { usePascalI18n } from '@pascal-app/core'
4
- import { Video } from 'lucide-react'
5
- import { cn } from '../../../lib/utils'
6
- import useFollowPascal from '../../../store/use-follow-pascal'
7
- import { ActionButton } from './action-button'
8
-
9
- /** The toolbar's switch for Follow Pascal: the camera follows what the agent builds. */
10
- export function FollowPascalToggle({
11
- className,
12
- tooltipClassName,
13
- }: {
14
- className?: string
15
- tooltipClassName?: string
16
- }) {
17
- const i18n = usePascalI18n()
18
- const on = useFollowPascal((state) => state.on)
19
- const setOn = useFollowPascal((state) => state.setOn)
20
- return (
21
- <ActionButton
22
- aria-pressed={on}
23
- className={cn(
24
- on
25
- ? 'bg-violet-500/20 text-violet-600 dark:text-violet-300 dark:hover:text-accent-foreground'
26
- : 'hover:bg-black/4 hover:text-violet-600 dark:hover:text-violet-300',
27
- className,
28
- )}
29
- label={
30
- on
31
- ? i18n._({ id: 'editor.actionMenu.followPascalToggle.on', message: 'Follow Pascal: On' })
32
- : i18n._({ id: 'editor.actionMenu.followPascalToggle.off', message: 'Follow Pascal: Off' })
33
- }
34
- onClick={() => setOn(!on)}
35
- size="icon"
36
- tooltipClassName={tooltipClassName}
37
- variant="ghost"
38
- >
39
- <Video className="h-6 w-6" />
40
- </ActionButton>
41
- )
42
- }
@@ -1,69 +0,0 @@
1
- import { Slot } from '@radix-ui/react-slot'
2
- import { cva, type VariantProps } from 'class-variance-authority'
3
- import type * as React from 'react'
4
-
5
- import { cn } from '../../../lib/utils'
6
-
7
- const buttonVariants = cva(
8
- "inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md font-barlow font-medium text-sm outline-none transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
9
- {
10
- variants: {
11
- variant: {
12
- default: 'bg-primary text-primary-foreground hover:bg-primary/90',
13
- destructive:
14
- 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40',
15
- outline:
16
- 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50',
17
- secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
18
- ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
19
- link: 'text-primary underline-offset-4 hover:underline',
20
- },
21
- size: {
22
- default: 'h-9 px-4 py-2 has-[>svg]:px-3',
23
- sm: 'h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5',
24
- lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
25
- icon: 'size-9',
26
- 'icon-sm': 'size-8',
27
- 'icon-lg': 'size-10',
28
- },
29
- },
30
- defaultVariants: {
31
- variant: 'default',
32
- size: 'default',
33
- },
34
- },
35
- )
36
-
37
- function Button({
38
- className,
39
- variant,
40
- size,
41
- asChild = false,
42
- ref,
43
- ...props
44
- }: React.ComponentProps<'button'> &
45
- VariantProps<typeof buttonVariants> & {
46
- asChild?: boolean
47
- }) {
48
- if (asChild) {
49
- return (
50
- <Slot
51
- className={cn(buttonVariants({ variant, size, className }))}
52
- data-slot="button"
53
- ref={ref as never}
54
- {...props}
55
- />
56
- )
57
- }
58
-
59
- return (
60
- <button
61
- className={cn(buttonVariants({ variant, size, className }))}
62
- data-slot="button"
63
- ref={ref}
64
- {...props}
65
- />
66
- )
67
- }
68
-
69
- export { Button, buttonVariants }
@@ -1,232 +0,0 @@
1
- 'use client'
2
-
3
- import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
4
- import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react'
5
- import type * as React from 'react'
6
-
7
- import { cn } from '../../../lib/utils'
8
-
9
- function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
10
- return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
11
- }
12
-
13
- function DropdownMenuPortal({
14
- ...props
15
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
16
- return <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
17
- }
18
-
19
- function DropdownMenuTrigger({
20
- ...props
21
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
22
- return <DropdownMenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />
23
- }
24
-
25
- function DropdownMenuContent({
26
- className,
27
- sideOffset = 4,
28
- ...props
29
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
30
- return (
31
- <DropdownMenuPrimitive.Portal>
32
- <DropdownMenuPrimitive.Content
33
- className={cn(
34
- 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=open]:animate-in',
35
- className,
36
- )}
37
- data-slot="dropdown-menu-content"
38
- sideOffset={sideOffset}
39
- {...props}
40
- />
41
- </DropdownMenuPrimitive.Portal>
42
- )
43
- }
44
-
45
- function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
46
- return <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
47
- }
48
-
49
- function DropdownMenuItem({
50
- className,
51
- inset,
52
- variant = 'default',
53
- ...props
54
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
55
- inset?: boolean
56
- variant?: 'default' | 'destructive'
57
- }) {
58
- return (
59
- <DropdownMenuPrimitive.Item
60
- className={cn(
61
- "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 font-barlow text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-inset:pl-8 data-[variant=destructive]:text-destructive data-disabled:opacity-50 data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 data-[variant=destructive]:*:[svg]:text-destructive!",
62
- className,
63
- )}
64
- data-inset={inset}
65
- data-slot="dropdown-menu-item"
66
- data-variant={variant}
67
- {...props}
68
- />
69
- )
70
- }
71
-
72
- function DropdownMenuCheckboxItem({
73
- className,
74
- children,
75
- checked,
76
- ...props
77
- }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
78
- return (
79
- <DropdownMenuPrimitive.CheckboxItem
80
- checked={checked}
81
- className={cn(
82
- "relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 font-barlow text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
83
- className,
84
- )}
85
- data-slot="dropdown-menu-checkbox-item"
86
- {...props}
87
- >
88
- <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
89
- <DropdownMenuPrimitive.ItemIndicator>
90
- <CheckIcon className="size-4" />
91
- </DropdownMenuPrimitive.ItemIndicator>
92
- </span>
93
- {children}
94
- </DropdownMenuPrimitive.CheckboxItem>
95
- )
96
- }
97
-
98
- function DropdownMenuRadioGroup({
99
- ...props
100
- }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
101
- return <DropdownMenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />
102
- }
103
-
104
- function DropdownMenuRadioItem({
105
- className,
106
- children,
107
- ...props
108
- }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
109
- return (
110
- <DropdownMenuPrimitive.RadioItem
111
- className={cn(
112
- "relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 font-barlow text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
113
- className,
114
- )}
115
- data-slot="dropdown-menu-radio-item"
116
- {...props}
117
- >
118
- <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
119
- <DropdownMenuPrimitive.ItemIndicator>
120
- <CircleIcon className="size-2 fill-current" />
121
- </DropdownMenuPrimitive.ItemIndicator>
122
- </span>
123
- {children}
124
- </DropdownMenuPrimitive.RadioItem>
125
- )
126
- }
127
-
128
- function DropdownMenuLabel({
129
- className,
130
- inset,
131
- ...props
132
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
133
- inset?: boolean
134
- }) {
135
- return (
136
- <DropdownMenuPrimitive.Label
137
- className={cn('px-2 py-1.5 font-barlow font-medium text-sm data-inset:pl-8', className)}
138
- data-inset={inset}
139
- data-slot="dropdown-menu-label"
140
- {...props}
141
- />
142
- )
143
- }
144
-
145
- function DropdownMenuSeparator({
146
- className,
147
- ...props
148
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
149
- return (
150
- <DropdownMenuPrimitive.Separator
151
- className={cn('-mx-1 my-1 h-px bg-border', className)}
152
- data-slot="dropdown-menu-separator"
153
- {...props}
154
- />
155
- )
156
- }
157
-
158
- function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) {
159
- return (
160
- <span
161
- className={cn('ml-auto text-muted-foreground text-xs tracking-widest', className)}
162
- data-slot="dropdown-menu-shortcut"
163
- {...props}
164
- />
165
- )
166
- }
167
-
168
- function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
169
- return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
170
- }
171
-
172
- function DropdownMenuSubTrigger({
173
- className,
174
- inset,
175
- children,
176
- ...props
177
- }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
178
- inset?: boolean
179
- }) {
180
- return (
181
- <DropdownMenuPrimitive.SubTrigger
182
- className={cn(
183
- "flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 font-barlow text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-inset:pl-8 data-[state=open]:text-accent-foreground [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0",
184
- className,
185
- )}
186
- data-inset={inset}
187
- data-slot="dropdown-menu-sub-trigger"
188
- {...props}
189
- >
190
- {children}
191
- <ChevronRightIcon className="ml-auto size-4" />
192
- </DropdownMenuPrimitive.SubTrigger>
193
- )
194
- }
195
-
196
- function DropdownMenuSubContent({
197
- className,
198
- ...props
199
- }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
200
- // Portalled so the side-opening submenu escapes the parent content's
201
- // `overflow-x-hidden` clip (otherwise it renders but is invisible).
202
- return (
203
- <DropdownMenuPrimitive.Portal>
204
- <DropdownMenuPrimitive.SubContent
205
- className={cn(
206
- 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-32 origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=closed]:animate-out data-[state=open]:animate-in',
207
- className,
208
- )}
209
- data-slot="dropdown-menu-sub-content"
210
- {...props}
211
- />
212
- </DropdownMenuPrimitive.Portal>
213
- )
214
- }
215
-
216
- export {
217
- DropdownMenu,
218
- DropdownMenuPortal,
219
- DropdownMenuTrigger,
220
- DropdownMenuContent,
221
- DropdownMenuGroup,
222
- DropdownMenuLabel,
223
- DropdownMenuItem,
224
- DropdownMenuCheckboxItem,
225
- DropdownMenuRadioGroup,
226
- DropdownMenuRadioItem,
227
- DropdownMenuSeparator,
228
- DropdownMenuShortcut,
229
- DropdownMenuSub,
230
- DropdownMenuSubTrigger,
231
- DropdownMenuSubContent,
232
- }