@pascal-app/viewer 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 (270) hide show
  1. package/README.md +209 -19
  2. package/dist/components/viewer/drone-controller.d.ts.map +1 -1
  3. package/dist/components/viewer/drone-controller.js +1 -5
  4. package/dist/components/viewer/first-person/build-collider-world.d.ts +14 -0
  5. package/dist/components/viewer/first-person/build-collider-world.d.ts.map +1 -0
  6. package/dist/components/viewer/first-person/build-collider-world.js +426 -0
  7. package/dist/components/viewer/first-person/ground-holes.d.ts +22 -0
  8. package/dist/components/viewer/first-person/ground-holes.d.ts.map +1 -0
  9. package/dist/components/viewer/first-person/ground-holes.js +116 -0
  10. package/dist/components/viewer/first-person/mechanism-targets.d.ts +27 -0
  11. package/dist/components/viewer/first-person/mechanism-targets.d.ts.map +1 -0
  12. package/dist/components/viewer/first-person/mechanism-targets.js +79 -0
  13. package/dist/components/viewer/first-person/terrain-collider.d.ts +32 -0
  14. package/dist/components/viewer/first-person/terrain-collider.d.ts.map +1 -0
  15. package/dist/components/viewer/first-person/terrain-collider.js +175 -0
  16. package/dist/components/viewer/glb-replace-instances.d.ts +6 -3
  17. package/dist/components/viewer/glb-replace-instances.d.ts.map +1 -1
  18. package/dist/components/viewer/glb-replace-instances.js +5 -4
  19. package/dist/components/viewer/glb-scene.d.ts +3 -1
  20. package/dist/components/viewer/glb-scene.d.ts.map +1 -1
  21. package/dist/components/viewer/glb-scene.js +2 -1
  22. package/dist/components/viewer/glb-walkthrough-controller.d.ts +1 -1
  23. package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -1
  24. package/dist/components/viewer/glb-walkthrough-controller.js +3 -4
  25. package/dist/components/viewer/index.d.ts.map +1 -1
  26. package/dist/components/viewer/index.js +8 -4
  27. package/dist/components/viewer/live-walkthrough-controller.d.ts +17 -0
  28. package/dist/components/viewer/live-walkthrough-controller.d.ts.map +1 -0
  29. package/dist/components/viewer/live-walkthrough-controller.js +1449 -0
  30. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  31. package/dist/components/viewer/post-processing.js +22 -1
  32. package/dist/components/viewer/registered-systems.d.ts.map +1 -1
  33. package/dist/components/viewer/registered-systems.js +2 -2
  34. package/dist/components/viewer/unsupported-gpu-fallback.d.ts.map +1 -1
  35. package/dist/components/viewer/unsupported-gpu-fallback.js +21 -1
  36. package/dist/components/viewer/use-daylight-rooms.d.ts.map +1 -1
  37. package/dist/components/viewer/use-daylight-rooms.js +75 -33
  38. package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
  39. package/dist/hooks/use-gltf-ktx2.js +2 -1
  40. package/dist/index.d.ts +8 -1
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +8 -1
  43. package/dist/lib/asset-url.d.ts +0 -1
  44. package/dist/lib/asset-url.d.ts.map +1 -1
  45. package/dist/lib/asset-url.js +3 -3
  46. package/dist/lib/daylight/room-context.d.ts.map +1 -1
  47. package/dist/lib/daylight/room-context.js +3 -2
  48. package/dist/lib/daylight/room-map.d.ts +149 -0
  49. package/dist/lib/daylight/room-map.d.ts.map +1 -0
  50. package/dist/lib/daylight/room-map.js +813 -0
  51. package/dist/lib/daylight/room-scene.d.ts +4 -2
  52. package/dist/lib/daylight/room-scene.d.ts.map +1 -1
  53. package/dist/lib/daylight/room-scene.js +81 -40
  54. package/dist/lib/daylight/rooms.d.ts +71 -32
  55. package/dist/lib/daylight/rooms.d.ts.map +1 -1
  56. package/dist/lib/daylight/rooms.js +371 -286
  57. package/dist/lib/ktx2-loader.d.ts.map +1 -1
  58. package/dist/lib/ktx2-loader.js +2 -1
  59. package/dist/lib/measurement-label.d.ts +4 -0
  60. package/dist/lib/measurement-label.d.ts.map +1 -0
  61. package/dist/lib/measurement-label.js +54 -0
  62. package/dist/lib/measurement-presentation.d.ts +7 -0
  63. package/dist/lib/measurement-presentation.d.ts.map +1 -0
  64. package/dist/lib/measurement-presentation.js +14 -0
  65. package/dist/lib/pointer-events.d.ts.map +1 -1
  66. package/dist/lib/pointer-events.js +3 -3
  67. package/dist/lib/texture-reference.d.ts.map +1 -1
  68. package/dist/lib/texture-reference.js +4 -3
  69. package/dist/lib/typing-target.d.ts +2 -0
  70. package/dist/lib/typing-target.d.ts.map +1 -0
  71. package/dist/lib/typing-target.js +7 -0
  72. package/dist/lib/viewer-config.d.ts +27 -0
  73. package/dist/lib/viewer-config.d.ts.map +1 -0
  74. package/dist/lib/viewer-config.js +23 -0
  75. package/dist/lib/viewer-preference-storage.d.ts +7 -0
  76. package/dist/lib/viewer-preference-storage.d.ts.map +1 -0
  77. package/dist/lib/viewer-preference-storage.js +23 -0
  78. package/dist/sfx/audio-settings.d.ts +81 -0
  79. package/dist/sfx/audio-settings.d.ts.map +1 -0
  80. package/dist/sfx/audio-settings.js +166 -0
  81. package/dist/sfx/index.d.ts +6 -0
  82. package/dist/sfx/index.d.ts.map +1 -0
  83. package/dist/sfx/index.js +5 -0
  84. package/dist/sfx/interaction-sounds.d.ts +7 -0
  85. package/dist/sfx/interaction-sounds.d.ts.map +1 -0
  86. package/dist/sfx/interaction-sounds.js +39 -0
  87. package/dist/sfx/player.d.ts +31 -0
  88. package/dist/sfx/player.d.ts.map +1 -0
  89. package/dist/sfx/player.js +255 -0
  90. package/dist/sfx/sounds.d.ts +60 -0
  91. package/dist/sfx/sounds.d.ts.map +1 -0
  92. package/dist/sfx/sounds.js +25 -0
  93. package/dist/sfx/use-viewer-ui-sounds.d.ts +8 -0
  94. package/dist/sfx/use-viewer-ui-sounds.d.ts.map +1 -0
  95. package/dist/sfx/use-viewer-ui-sounds.js +42 -0
  96. package/dist/store/use-first-person-hud.d.ts +13 -0
  97. package/dist/store/use-first-person-hud.d.ts.map +1 -0
  98. package/dist/store/use-first-person-hud.js +21 -0
  99. package/dist/store/use-viewer.d.ts +2 -56
  100. package/dist/store/use-viewer.d.ts.map +1 -1
  101. package/dist/store/use-viewer.js +3 -1
  102. package/dist/systems/elevator/elevator-interaction-system.d.ts +16 -2
  103. package/dist/systems/elevator/elevator-interaction-system.d.ts.map +1 -1
  104. package/dist/systems/elevator/elevator-interaction-system.js +41 -8
  105. package/dist/systems/geometry/geometry-status.d.ts +8 -0
  106. package/dist/systems/geometry/geometry-status.d.ts.map +1 -0
  107. package/dist/systems/geometry/geometry-status.js +24 -0
  108. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  109. package/dist/systems/roof/roof-system.js +134 -78
  110. package/dist/systems/wall/wall-system.d.ts +11 -0
  111. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  112. package/dist/systems/wall/wall-system.js +56 -10
  113. package/dist/ui/components/action-button.d.ts +14 -0
  114. package/dist/ui/components/action-button.d.ts.map +1 -0
  115. package/dist/ui/components/action-button.js +21 -0
  116. package/dist/ui/components/action-menu-placement.d.ts +7 -0
  117. package/dist/ui/components/action-menu-placement.d.ts.map +1 -0
  118. package/dist/ui/components/action-menu-placement.js +10 -0
  119. package/dist/ui/components/floorplan-compass-button.d.ts +10 -0
  120. package/dist/ui/components/floorplan-compass-button.d.ts.map +1 -0
  121. package/dist/ui/components/floorplan-compass-button.js +22 -0
  122. package/dist/ui/components/follow-pascal-toggle.d.ts +6 -0
  123. package/dist/ui/components/follow-pascal-toggle.d.ts.map +1 -0
  124. package/dist/ui/components/follow-pascal-toggle.js +21 -0
  125. package/dist/ui/components/localized-html.d.ts +9 -0
  126. package/dist/ui/components/localized-html.d.ts.map +1 -0
  127. package/dist/ui/components/localized-html.js +16 -0
  128. package/dist/ui/components/render-settings-menu.d.ts +9 -0
  129. package/dist/ui/components/render-settings-menu.d.ts.map +1 -0
  130. package/dist/ui/components/render-settings-menu.js +145 -0
  131. package/dist/ui/components/rooms/room-highlight.d.ts +10 -0
  132. package/dist/ui/components/rooms/room-highlight.d.ts.map +1 -0
  133. package/dist/ui/components/rooms/room-highlight.js +56 -0
  134. package/dist/ui/components/rooms/room-labels.d.ts +278 -0
  135. package/dist/ui/components/rooms/room-labels.d.ts.map +1 -0
  136. package/dist/ui/components/rooms/room-labels.js +1295 -0
  137. package/dist/ui/components/rooms/viewer-rooms.d.ts +14 -0
  138. package/dist/ui/components/rooms/viewer-rooms.d.ts.map +1 -0
  139. package/dist/ui/components/rooms/viewer-rooms.js +123 -0
  140. package/dist/ui/components/scene-loader.d.ts +18 -0
  141. package/dist/ui/components/scene-loader.d.ts.map +1 -0
  142. package/dist/ui/components/scene-loader.js +29 -0
  143. package/dist/ui/components/sky-control.d.ts +37 -0
  144. package/dist/ui/components/sky-control.d.ts.map +1 -0
  145. package/dist/ui/components/sky-control.js +382 -0
  146. package/dist/ui/components/use-viewer-camera-navigation-sync.d.ts +4 -0
  147. package/dist/ui/components/use-viewer-camera-navigation-sync.d.ts.map +1 -0
  148. package/dist/ui/components/use-viewer-camera-navigation-sync.js +117 -0
  149. package/dist/ui/components/viewer-controls-bar.d.ts +20 -0
  150. package/dist/ui/components/viewer-controls-bar.d.ts.map +1 -0
  151. package/dist/ui/components/viewer-controls-bar.js +130 -0
  152. package/dist/ui/components/viewer-hover-label.d.ts +14 -0
  153. package/dist/ui/components/viewer-hover-label.d.ts.map +1 -0
  154. package/dist/ui/components/viewer-hover-label.js +28 -0
  155. package/dist/ui/components/viewer-scene-header.d.ts +34 -0
  156. package/dist/ui/components/viewer-scene-header.d.ts.map +1 -0
  157. package/dist/ui/components/viewer-scene-header.js +92 -0
  158. package/dist/ui/components/viewer-selection-manager.d.ts +7 -0
  159. package/dist/ui/components/viewer-selection-manager.d.ts.map +1 -0
  160. package/dist/ui/components/viewer-selection-manager.js +116 -0
  161. package/dist/ui/components/viewer-stage-modes.d.ts +7 -0
  162. package/dist/ui/components/viewer-stage-modes.d.ts.map +1 -0
  163. package/dist/ui/components/viewer-stage-modes.js +42 -0
  164. package/dist/ui/components/viewer-stage-switcher.d.ts +10 -0
  165. package/dist/ui/components/viewer-stage-switcher.d.ts.map +1 -0
  166. package/dist/ui/components/viewer-stage-switcher.js +16 -0
  167. package/dist/ui/components/viewer-stage.d.ts +25 -0
  168. package/dist/ui/components/viewer-stage.d.ts.map +1 -0
  169. package/dist/ui/components/viewer-stage.js +107 -0
  170. package/dist/ui/components/walkthrough-hud.d.ts +29 -0
  171. package/dist/ui/components/walkthrough-hud.d.ts.map +1 -0
  172. package/dist/ui/components/walkthrough-hud.js +55 -0
  173. package/dist/ui/floorplan/floorplan-camera-sync.d.ts +22 -0
  174. package/dist/ui/floorplan/floorplan-camera-sync.d.ts.map +1 -0
  175. package/dist/ui/floorplan/floorplan-camera-sync.js +157 -0
  176. package/dist/ui/floorplan/floorplan-dimension-renderer.d.ts +61 -0
  177. package/dist/ui/floorplan/floorplan-dimension-renderer.d.ts.map +1 -0
  178. package/dist/ui/floorplan/floorplan-dimension-renderer.js +280 -0
  179. package/dist/ui/floorplan/floorplan-geometry-renderer.d.ts +54 -0
  180. package/dist/ui/floorplan/floorplan-geometry-renderer.d.ts.map +1 -0
  181. package/dist/ui/floorplan/floorplan-geometry-renderer.js +317 -0
  182. package/dist/ui/floorplan/floorplan-label-angle.d.ts +24 -0
  183. package/dist/ui/floorplan/floorplan-label-angle.d.ts.map +1 -0
  184. package/dist/ui/floorplan/floorplan-label-angle.js +60 -0
  185. package/dist/ui/floorplan/floorplan-navigation-sync.d.ts +18 -0
  186. package/dist/ui/floorplan/floorplan-navigation-sync.d.ts.map +1 -0
  187. package/dist/ui/floorplan/floorplan-navigation-sync.js +41 -0
  188. package/dist/ui/floorplan/floorplan-preview-geometry.d.ts +26 -0
  189. package/dist/ui/floorplan/floorplan-preview-geometry.d.ts.map +1 -0
  190. package/dist/ui/floorplan/floorplan-preview-geometry.js +173 -0
  191. package/dist/ui/floorplan/floorplan-preview-navigation.d.ts +22 -0
  192. package/dist/ui/floorplan/floorplan-preview-navigation.d.ts.map +1 -0
  193. package/dist/ui/floorplan/floorplan-preview-navigation.js +41 -0
  194. package/dist/ui/floorplan/floorplan-preview-visibility.d.ts +8 -0
  195. package/dist/ui/floorplan/floorplan-preview-visibility.d.ts.map +1 -0
  196. package/dist/ui/floorplan/floorplan-preview-visibility.js +21 -0
  197. package/dist/ui/floorplan/floorplan-preview.d.ts +19 -0
  198. package/dist/ui/floorplan/floorplan-preview.d.ts.map +1 -0
  199. package/dist/ui/floorplan/floorplan-preview.js +700 -0
  200. package/dist/ui/hooks/use-mobile.d.ts +2 -0
  201. package/dist/ui/hooks/use-mobile.d.ts.map +1 -0
  202. package/dist/ui/hooks/use-mobile.js +14 -0
  203. package/dist/ui/index.d.ts +49 -0
  204. package/dist/ui/index.d.ts.map +1 -0
  205. package/dist/ui/index.js +48 -0
  206. package/dist/ui/lib/below-grade.d.ts +38 -0
  207. package/dist/ui/lib/below-grade.d.ts.map +1 -0
  208. package/dist/ui/lib/below-grade.js +102 -0
  209. package/dist/ui/lib/camera-pose.d.ts +19 -0
  210. package/dist/ui/lib/camera-pose.d.ts.map +1 -0
  211. package/dist/ui/lib/camera-pose.js +113 -0
  212. package/dist/ui/lib/cn.d.ts +3 -0
  213. package/dist/ui/lib/cn.d.ts.map +1 -0
  214. package/dist/ui/lib/cn.js +5 -0
  215. package/dist/ui/lib/level-name.d.ts +10 -0
  216. package/dist/ui/lib/level-name.d.ts.map +1 -0
  217. package/dist/ui/lib/level-name.js +33 -0
  218. package/dist/ui/lib/node-display-label.d.ts +8 -0
  219. package/dist/ui/lib/node-display-label.d.ts.map +1 -0
  220. package/dist/ui/lib/node-display-label.js +36 -0
  221. package/dist/ui/lib/room-area.d.ts +3 -0
  222. package/dist/ui/lib/room-area.d.ts.map +1 -0
  223. package/dist/ui/lib/room-area.js +8 -0
  224. package/dist/ui/lib/room-assembly-overlay.d.ts +46 -0
  225. package/dist/ui/lib/room-assembly-overlay.d.ts.map +1 -0
  226. package/dist/ui/lib/room-assembly-overlay.js +222 -0
  227. package/dist/ui/lib/room-name-messages.d.ts +28 -0
  228. package/dist/ui/lib/room-name-messages.d.ts.map +1 -0
  229. package/dist/ui/lib/room-name-messages.js +112 -0
  230. package/dist/ui/lib/room-selection.d.ts +58 -0
  231. package/dist/ui/lib/room-selection.d.ts.map +1 -0
  232. package/dist/ui/lib/room-selection.js +297 -0
  233. package/dist/ui/lib/scene-theme-name.d.ts +4 -0
  234. package/dist/ui/lib/scene-theme-name.d.ts.map +1 -0
  235. package/dist/ui/lib/scene-theme-name.js +22 -0
  236. package/dist/ui/lib/selection-modifiers.d.ts +20 -0
  237. package/dist/ui/lib/selection-modifiers.d.ts.map +1 -0
  238. package/dist/ui/lib/selection-modifiers.js +15 -0
  239. package/dist/ui/lib/viewer-selection.d.ts +132 -0
  240. package/dist/ui/lib/viewer-selection.d.ts.map +1 -0
  241. package/dist/ui/lib/viewer-selection.js +462 -0
  242. package/dist/ui/lib/zone-content.d.ts +6 -0
  243. package/dist/ui/lib/zone-content.d.ts.map +1 -0
  244. package/dist/ui/lib/zone-content.js +96 -0
  245. package/dist/ui/primitives/button.d.ts +11 -0
  246. package/dist/ui/primitives/button.d.ts.map +1 -0
  247. package/dist/ui/primitives/button.js +35 -0
  248. package/dist/ui/primitives/dropdown-menu.d.ts +26 -0
  249. package/dist/ui/primitives/dropdown-menu.d.ts.map +1 -0
  250. package/dist/ui/primitives/dropdown-menu.js +53 -0
  251. package/dist/ui/primitives/popover.d.ts +8 -0
  252. package/dist/ui/primitives/popover.d.ts.map +1 -0
  253. package/dist/ui/primitives/popover.js +17 -0
  254. package/dist/ui/primitives/switch.d.ts +5 -0
  255. package/dist/ui/primitives/switch.d.ts.map +1 -0
  256. package/dist/ui/primitives/switch.js +8 -0
  257. package/dist/ui/primitives/tooltip.d.ts +8 -0
  258. package/dist/ui/primitives/tooltip.d.ts.map +1 -0
  259. package/dist/ui/primitives/tooltip.js +17 -0
  260. package/dist/ui/store/camera-pose-store.d.ts +17 -0
  261. package/dist/ui/store/camera-pose-store.d.ts.map +1 -0
  262. package/dist/ui/store/camera-pose-store.js +15 -0
  263. package/dist/ui/store/navigation-sync-pose-store.d.ts +26 -0
  264. package/dist/ui/store/navigation-sync-pose-store.d.ts.map +1 -0
  265. package/dist/ui/store/navigation-sync-pose-store.js +16 -0
  266. package/dist/ui/store/use-follow-pascal.d.ts +30 -0
  267. package/dist/ui/store/use-follow-pascal.d.ts.map +1 -0
  268. package/dist/ui/store/use-follow-pascal.js +28 -0
  269. package/dist/ui/theme.css +339 -0
  270. package/package.json +34 -7
@@ -0,0 +1,462 @@
1
+ import { area, buildUnitReport, containsPoint, DEFAULT_LEVEL_HEIGHT, emitter, getLevelDisplayName, resolveSelectionProxyId, roomFloorElevation, sceneRegistry, } from '@pascal-app/core';
2
+ import { useEffect } from 'react';
3
+ import { Box3, Sphere, Vector3, } from 'three';
4
+ import useViewer from '../../store/use-viewer';
5
+ import { useBelowGrade } from './below-grade';
6
+ import { nodeDisplayLabel } from './node-display-label';
7
+ import { displayRoomName } from './room-name-messages';
8
+ import { RoomSelectionIndex, resolveRoomHit } from './room-selection';
9
+ const NO_MODIFIERS = { alt: false, ctrl: false, meta: false, shift: false };
10
+ /** Surfaces a room is picked through, room first: its walls, its floor, its ceiling. */
11
+ const ROOM_SURFACES = new Set(['wall', 'slab', 'ceiling']);
12
+ /** Kinds a viewer click never lands on: they pass the pointer to what lies behind. */
13
+ export const VIEWER_PASS_THROUGH_KINDS = new Set([
14
+ 'site',
15
+ 'building',
16
+ 'level',
17
+ 'zone',
18
+ 'ceiling',
19
+ 'scan',
20
+ 'guide',
21
+ 'spawn',
22
+ ]);
23
+ const indexes = new WeakMap();
24
+ function roomIndex(levelId, nodes) {
25
+ let levels = indexes.get(nodes);
26
+ if (!levels) {
27
+ levels = new Map();
28
+ indexes.set(nodes, levels);
29
+ }
30
+ let index = levels.get(levelId);
31
+ if (!index) {
32
+ index = new RoomSelectionIndex(levelId);
33
+ levels.set(levelId, index);
34
+ }
35
+ index.update(nodes);
36
+ return index;
37
+ }
38
+ /** The rooms the walls of a level close, as the editor detects them. */
39
+ export function viewerRooms(levelId, nodes) {
40
+ return roomIndex(levelId, nodes).update(nodes);
41
+ }
42
+ export function levelOfNode(nodeId, nodes) {
43
+ const seen = new Set();
44
+ let current = nodes[nodeId];
45
+ while (current && !seen.has(current.id)) {
46
+ if (current.type === 'level')
47
+ return current.id;
48
+ seen.add(current.id);
49
+ current = current.parentId ? nodes[current.parentId] : undefined;
50
+ }
51
+ return null;
52
+ }
53
+ function buildingOfLevel(levelId, nodes) {
54
+ const level = levelId ? nodes[levelId] : undefined;
55
+ const parent = level?.parentId ? nodes[level.parentId] : undefined;
56
+ if (parent?.type === 'building')
57
+ return parent.id;
58
+ const building = Object.values(nodes).find((node) => node.type === 'building');
59
+ return building?.id ?? null;
60
+ }
61
+ const hitPoint = new Vector3();
62
+ /**
63
+ * The parametric hit source: a node event as a pick, with the hit in its
64
+ * level's local XZ. A hit on a hidden floor, or on a kind a click passes
65
+ * through, is no pick: the pointer goes on to what lies behind it.
66
+ */
67
+ export function viewerPickFromNodeEvent(event, nodes) {
68
+ if (VIEWER_PASS_THROUGH_KINDS.has(event.node.type))
69
+ return null;
70
+ const levelId = levelOfNode(event.node.id, nodes);
71
+ const level = levelId ? sceneRegistry.nodes.get(levelId) : undefined;
72
+ if (level?.visible === false)
73
+ return null;
74
+ if (!level)
75
+ return { nodeId: event.node.id, point: null };
76
+ level.updateWorldMatrix(true, false);
77
+ hitPoint.set(...event.position);
78
+ level.worldToLocal(hitPoint);
79
+ return { nodeId: event.node.id, point: [hitPoint.x, hitPoint.z] };
80
+ }
81
+ /**
82
+ * What a pick acts on. A wall, floor or ceiling picks the room it bounds;
83
+ * once that room is selected, its own surfaces are picked as themselves.
84
+ * Anything else (an item, a door, a stair) is picked directly. Alt, Shift,
85
+ * Ctrl and Meta skip the room, as in the editor.
86
+ */
87
+ export function resolveViewerTarget(selection, pick, nodes, modifiers = NO_MODIFIERS) {
88
+ const node = nodes[pick.nodeId];
89
+ if (!node || VIEWER_PASS_THROUGH_KINDS.has(node.type))
90
+ return null;
91
+ const levelId = levelOfNode(node.id, nodes);
92
+ const bypass = modifiers.alt || modifiers.shift || modifiers.ctrl || modifiers.meta;
93
+ if (!bypass && levelId && pick.point && ROOM_SURFACES.has(node.type)) {
94
+ const room = resolveRoomHit(roomIndex(levelId, nodes), levelId, node, [pick.point[0], pick.point[1]], '3d');
95
+ if (room) {
96
+ const { zoneId } = room.key;
97
+ return selection.zoneId === zoneId
98
+ ? { kind: 'node', levelId, nodeId: node.id, zoneId }
99
+ : { kind: 'room', levelId, zoneId };
100
+ }
101
+ }
102
+ const parent = node.parentId ? nodes[node.parentId] : undefined;
103
+ // A roof selects whole: its segments and its faces of other kinds (`capabilities.roofs`).
104
+ const owner = parent?.type === 'roof' ? parent : node;
105
+ const nodeId = resolveSelectionProxyId(owner, nodes);
106
+ return { kind: 'node', levelId, nodeId, zoneId: null };
107
+ }
108
+ /**
109
+ * The selection a click makes. Empty space clears the room and the element
110
+ * and keeps the floor; nothing pops the user up a level.
111
+ */
112
+ export function resolveViewerClick(selection, pick, nodes, modifiers = NO_MODIFIERS) {
113
+ const target = pick ? resolveViewerTarget(selection, pick, nodes, modifiers) : null;
114
+ if (!target)
115
+ return { ...selection, zoneId: null, selectedIds: [] };
116
+ const levelId = target.levelId ?? selection.levelId;
117
+ const buildingId = buildingOfLevel(levelId, nodes) ?? selection.buildingId;
118
+ if (target.kind === 'room') {
119
+ return { buildingId, levelId, zoneId: target.zoneId, selectedIds: [] };
120
+ }
121
+ const toggles = modifiers.shift || modifiers.ctrl || modifiers.meta;
122
+ const sameFloor = levelId === selection.levelId;
123
+ const selectedIds = toggles && sameFloor
124
+ ? selection.selectedIds.includes(target.nodeId)
125
+ ? selection.selectedIds.filter((id) => id !== target.nodeId)
126
+ : [...selection.selectedIds, target.nodeId]
127
+ : [target.nodeId];
128
+ return {
129
+ buildingId,
130
+ levelId,
131
+ zoneId: target.zoneId,
132
+ selectedIds,
133
+ };
134
+ }
135
+ /** What a hover would select: a room's id (its highlight) or the element's (its outline). */
136
+ export function resolveViewerHover(selection, pick, nodes) {
137
+ const target = pick ? resolveViewerTarget(selection, pick, nodes) : null;
138
+ if (!target)
139
+ return null;
140
+ return target.kind === 'room' ? target.zoneId : target.nodeId;
141
+ }
142
+ /**
143
+ * The current floor reads as the editor shows it: the levels above it step
144
+ * aside (in the stacked display) so its rooms are in view and in reach, and the
145
+ * ground is veiled over it when it lies below grade. Mount it in the surface's DOM tree,
146
+ * beside the editor's own level display, so one hands the flag to the other in
147
+ * order.
148
+ */
149
+ export function useViewerFloorDisplay() {
150
+ // A walkthrough tours the whole building.
151
+ const walking = useViewer((s) => s.walkthroughMode);
152
+ useBelowGrade(!walking);
153
+ useEffect(() => {
154
+ if (walking)
155
+ return;
156
+ useViewer.setState({ hideLevelsAboveSelection: true });
157
+ return () => {
158
+ useViewer.setState({ hideLevelsAboveSelection: false });
159
+ };
160
+ }, [walking]);
161
+ }
162
+ // ── Applying it to the shared store ──────────────────────────────────────────
163
+ function writeSelection(selection) {
164
+ const viewer = useViewer.getState();
165
+ viewer.setSelection(selection);
166
+ if (viewer.focusedUnitId)
167
+ viewer.setFocusedUnit(null);
168
+ viewer.setHoveredId(null);
169
+ }
170
+ export function applyViewerClick(pick, nodes, modifiers = NO_MODIFIERS) {
171
+ writeSelection(resolveViewerClick(useViewer.getState().selection, pick, nodes, modifiers));
172
+ }
173
+ export function applyViewerHover(pick, nodes) {
174
+ const viewer = useViewer.getState();
175
+ const hovered = resolveViewerHover(viewer.selection, pick, nodes);
176
+ viewer.setHoveredId(hovered);
177
+ }
178
+ /** A floor from the floor list: the floor alone, framed. */
179
+ export function selectViewerLevel(levelId, source) {
180
+ writeSelection({
181
+ buildingId: buildingOfLevel(levelId, source.nodes),
182
+ levelId: levelId,
183
+ zoneId: null,
184
+ selectedIds: [],
185
+ });
186
+ frameViewerNode(levelId, source);
187
+ }
188
+ /** The whole building again, framed. */
189
+ export function selectViewerBuilding(source) {
190
+ const buildingId = buildingOfLevel(null, source.nodes);
191
+ writeSelection({ buildingId, levelId: null, zoneId: null, selectedIds: [] });
192
+ if (buildingId)
193
+ frameViewerNode(buildingId, source);
194
+ }
195
+ /** A room or zone from its pill, the bar or the sidebar: selected on its floor, framed. */
196
+ export function selectViewerRoom(zoneId, source) {
197
+ const zone = source.nodes[zoneId];
198
+ if (zone?.type !== 'zone' || !zone.parentId)
199
+ return;
200
+ const levelId = zone.parentId;
201
+ writeSelection({
202
+ buildingId: buildingOfLevel(levelId, source.nodes),
203
+ levelId,
204
+ zoneId: zone.id,
205
+ selectedIds: [],
206
+ });
207
+ frameViewerNode(zone.id, source);
208
+ }
209
+ /**
210
+ * A unit from the sidebar: its rooms highlighted and framed. The floor stays
211
+ * when it holds one of the unit's rooms, else the unit's lowest floor shows.
212
+ */
213
+ export function selectViewerUnit(unitId, source) {
214
+ const unit = source.nodes[unitId];
215
+ if (unit?.type !== 'unit')
216
+ return;
217
+ const viewer = useViewer.getState();
218
+ const levels = unitLevels(unit, source.nodes);
219
+ const current = viewer.selection.levelId;
220
+ const levelId = (current && levels.includes(current) ? current : (levels[0] ?? current));
221
+ viewer.setSelection({
222
+ buildingId: buildingOfLevel(levelId, source.nodes),
223
+ levelId,
224
+ zoneId: null,
225
+ selectedIds: [],
226
+ });
227
+ viewer.setHoveredId(null);
228
+ viewer.setFocusedUnit(unit.id);
229
+ frameViewerNode(unit.id, source);
230
+ }
231
+ function unitLevels(unit, nodes) {
232
+ const ordinals = new Map();
233
+ for (const member of buildUnitReport(unit, nodes).members) {
234
+ if (member.levelId && member.levelOrdinal !== null)
235
+ ordinals.set(member.levelId, member.levelOrdinal);
236
+ }
237
+ return [...ordinals.entries()].sort((a, b) => a[1] - b[1]).map(([id]) => id);
238
+ }
239
+ // ── Framing ──────────────────────────────────────────────────────────────────
240
+ const corner = new Vector3();
241
+ const box = new Box3();
242
+ function expandByZone(target, zone, source) {
243
+ const level = zone.parentId ? source.objectFor(zone.parentId) : undefined;
244
+ level?.updateWorldMatrix(true, false);
245
+ const floorY = roomFloorElevation(source.nodes, zone.id);
246
+ for (const [x, z] of zone.polygon) {
247
+ for (const y of [floorY, floorY + DEFAULT_LEVEL_HEIGHT]) {
248
+ corner.set(x, y, z);
249
+ if (level)
250
+ corner.applyMatrix4(level.matrixWorld);
251
+ target.expandByPoint(corner);
252
+ }
253
+ }
254
+ }
255
+ /** The frame request for a node: the box it spans, and its saved view when it has one. */
256
+ function viewerFrameEvent(id, source) {
257
+ const node = source.nodes[id];
258
+ if (!node)
259
+ return null;
260
+ const saved = node.camera;
261
+ const pose = saved?.position && saved.target ? { position: saved.position, target: saved.target } : null;
262
+ box.makeEmpty();
263
+ if (node.type === 'zone')
264
+ expandByZone(box, node, source);
265
+ else if (node.type === 'unit') {
266
+ for (const memberId of node.members) {
267
+ const member = source.nodes[memberId];
268
+ if (member?.type === 'zone')
269
+ expandByZone(box, member, source);
270
+ }
271
+ }
272
+ else {
273
+ const object = source.objectFor(id);
274
+ if (object)
275
+ box.setFromObject(object);
276
+ }
277
+ const bounds = box.isEmpty() ? null : { min: box.min.toArray(), max: box.max.toArray() };
278
+ if (pose)
279
+ return { bounds, pose };
280
+ return bounds ? { bounds } : null;
281
+ }
282
+ /** Framing glides to its pose, or jumps there when the person asks for reduced motion. */
283
+ export function framingAnimates() {
284
+ return !(typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches);
285
+ }
286
+ export function frameViewerNode(id, source) {
287
+ const event = viewerFrameEvent(id, source);
288
+ if (event)
289
+ emitter.emit('camera-controls:frame', event);
290
+ }
291
+ /**
292
+ * Where a camera frames a box: about 45° above it, far enough for the box to
293
+ * fill the view, along the heading the camera already has so the scene does
294
+ * not swing round.
295
+ */
296
+ export function framedLookAt(event, from, fovDegrees = 50) {
297
+ if (event.pose)
298
+ return event.pose;
299
+ if (!event.bounds)
300
+ return null;
301
+ const { min, max } = event.bounds;
302
+ const center = [(min[0] + max[0]) / 2, (min[1] + max[1]) / 2, (min[2] + max[2]) / 2];
303
+ const radius = Math.max(Math.hypot(max[0] - min[0], max[1] - min[1], max[2] - min[2]) / 2, 1);
304
+ const halfFov = (Math.min(Math.max(fovDegrees, 10), 120) * Math.PI) / 360;
305
+ const distance = Math.max((radius / Math.sin(halfFov)) * 1.6, 6);
306
+ const dx = from.position[0] - from.target[0];
307
+ const dz = from.position[2] - from.target[2];
308
+ const heading = Math.hypot(dx, dz) > 1e-6 ? Math.atan2(dx, dz) : Math.PI / 4;
309
+ const elevation = Math.PI / 4;
310
+ const flat = Math.cos(elevation) * distance;
311
+ return {
312
+ position: [
313
+ center[0] + Math.sin(heading) * flat,
314
+ center[1] + Math.sin(elevation) * distance,
315
+ center[2] + Math.cos(heading) * flat,
316
+ ],
317
+ target: center,
318
+ };
319
+ }
320
+ const framePosition = new Vector3();
321
+ const frameTarget = new Vector3();
322
+ const frameSphere = new Sphere();
323
+ /** Apply the shared framing pose, fitting the orthographic viewport as well. */
324
+ export function frameViewerCamera(control, camera, event) {
325
+ control.getPosition(framePosition);
326
+ control.getTarget(frameTarget);
327
+ const pose = framedLookAt(event, { position: framePosition.toArray(), target: frameTarget.toArray() }, camera.isPerspectiveCamera
328
+ ? camera.fov
329
+ : undefined);
330
+ if (!pose)
331
+ return;
332
+ const animate = framingAnimates();
333
+ control.setLookAt(...pose.position, ...pose.target, animate);
334
+ if (camera.isOrthographicCamera && event.bounds && !event.pose) {
335
+ box.min.set(...event.bounds.min);
336
+ box.max.set(...event.bounds.max);
337
+ box.getBoundingSphere(frameSphere);
338
+ frameSphere.radius = Math.max(frameSphere.radius * 1.3, 1);
339
+ control.fitToSphere(frameSphere, animate);
340
+ }
341
+ }
342
+ /**
343
+ * The viewer chrome's name for a zone, in the editor's UI language (the scene
344
+ * keeps its stored name). `i18n` is the caller's scoped `usePascalI18n()`.
345
+ */
346
+ export function zoneLabel(zone, i18n) {
347
+ const name = zone.name?.trim();
348
+ if (name)
349
+ return displayRoomName(name, i18n);
350
+ return zone.spaceRole === 'room'
351
+ ? i18n._({ id: 'editor.roomLabel.room', message: 'Room' })
352
+ : i18n._({ id: 'editor.roomLabel.zone', message: 'Zone' });
353
+ }
354
+ /**
355
+ * The bar: building › floor › room › element. An element inside a room shows
356
+ * that room (`roomOf`) without selecting it; a focused unit stands where the
357
+ * room would.
358
+ */
359
+ export function viewerBreadcrumb(selection, focusedUnitId, nodes, i18n, roomOf = () => null) {
360
+ const crumbs = [];
361
+ const elementId = selection.selectedIds[0] ?? null;
362
+ const element = elementId ? nodes[elementId] : undefined;
363
+ const levelId = selection.levelId ?? (element ? levelOfNode(element.id, nodes) : null);
364
+ const buildingId = selection.buildingId ?? buildingOfLevel(levelId, nodes);
365
+ const building = buildingId ? nodes[buildingId] : undefined;
366
+ if (building?.type === 'building') {
367
+ crumbs.push({ kind: 'building', id: building.id, label: building.name || 'Building' });
368
+ }
369
+ const level = levelId ? nodes[levelId] : undefined;
370
+ if (level?.type !== 'level')
371
+ return crumbs;
372
+ crumbs.push({ kind: 'level', id: level.id, label: getLevelDisplayName(level) });
373
+ const unit = focusedUnitId ? nodes[focusedUnitId] : undefined;
374
+ if (unit?.type === 'unit')
375
+ crumbs.push({ kind: 'unit', id: unit.id, label: unit.name });
376
+ const roomId = selection.zoneId ?? (element ? roomOf(element.id, level.id) : null);
377
+ const room = roomId ? nodes[roomId] : undefined;
378
+ if (room?.type === 'zone')
379
+ crumbs.push({ kind: 'room', id: room.id, label: zoneLabel(room, i18n) });
380
+ if (element)
381
+ crumbs.push({ kind: 'node', id: element.id, label: nodeDisplayLabel(element) });
382
+ return crumbs;
383
+ }
384
+ /** The room or zone of a level around a level-local point: a detected room first. */
385
+ function roomAtLevelPoint(levelId, point, nodes) {
386
+ const at = [point[0], point[1]];
387
+ const room = roomIndex(levelId, nodes).roomAtPoint(levelId, at);
388
+ if (room)
389
+ return room.key.zoneId;
390
+ for (const node of Object.values(nodes)) {
391
+ if (node.type !== 'zone' || node.parentId !== levelId || node.polygon.length < 3)
392
+ continue;
393
+ if (containsPoint([{ outer: node.polygon, holes: node.holes ?? [] }], at))
394
+ return node.id;
395
+ }
396
+ return null;
397
+ }
398
+ const center = new Vector3();
399
+ /** The room an element stands in, from where its object sits on its floor. */
400
+ export function roomOfObject(nodeId, levelId, source) {
401
+ const object = source.objectFor(nodeId);
402
+ const level = source.objectFor(levelId);
403
+ if (!(object && level))
404
+ return null;
405
+ box.setFromObject(object);
406
+ if (box.isEmpty())
407
+ object.getWorldPosition(center);
408
+ else
409
+ box.getCenter(center);
410
+ level.updateWorldMatrix(true, false);
411
+ level.worldToLocal(center);
412
+ return roomAtLevelPoint(levelId, [center.x, center.z], source.nodes);
413
+ }
414
+ /**
415
+ * What sits under the current floor: its units, its rooms, its other zones.
416
+ * An empty section is left out.
417
+ */
418
+ export function viewerSidebarSections(levelId, nodes, i18n) {
419
+ const zones = Object.values(nodes).filter((node) => node.type === 'zone' && node.parentId === levelId && node.visible !== false);
420
+ const zoneRow = (zone) => ({
421
+ id: zone.id,
422
+ label: zoneLabel(zone, i18n),
423
+ color: zone.color,
424
+ areaM2: area([{ outer: zone.polygon, holes: zone.holes ?? [] }]),
425
+ });
426
+ const byName = (a, b) => a.label.localeCompare(b.label);
427
+ const units = Object.values(nodes)
428
+ .filter((node) => node.type === 'unit')
429
+ .flatMap((unit) => {
430
+ const report = buildUnitReport(unit, nodes);
431
+ const here = report.members.filter((member) => member.levelId === levelId);
432
+ if (here.length === 0)
433
+ return [];
434
+ return [
435
+ {
436
+ id: unit.id,
437
+ label: unit.name,
438
+ color: unit.color,
439
+ areaM2: here.reduce((sum, member) => sum + member.areaM2, 0),
440
+ },
441
+ ];
442
+ })
443
+ .sort(byName);
444
+ const sections = [
445
+ { kind: 'units', rows: units },
446
+ {
447
+ kind: 'rooms',
448
+ rows: zones
449
+ .filter((zone) => zone.spaceRole === 'room')
450
+ .map(zoneRow)
451
+ .sort(byName),
452
+ },
453
+ {
454
+ kind: 'zones',
455
+ rows: zones
456
+ .filter((zone) => zone.spaceRole !== 'room')
457
+ .map(zoneRow)
458
+ .sort(byName),
459
+ },
460
+ ];
461
+ return sections.filter((section) => section.rows.length > 0);
462
+ }
@@ -0,0 +1,6 @@
1
+ import { type AnyNode, type AnyNodeId, type ZoneNode } from '@pascal-app/core';
2
+ type Point2D = [number, number];
3
+ export declare function polygonMatchesZoneFootprint(surfacePolygon: Point2D[], footprint: Point2D[]): boolean;
4
+ export declare function collectZoneContentIds(nodes: Readonly<Record<AnyNodeId, AnyNode>>, zone: ZoneNode): AnyNodeId[];
5
+ export {};
6
+ //# sourceMappingURL=zone-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zone-content.d.ts","sourceRoot":"","sources":["../../../src/ui/lib/zone-content.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EAOd,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AAEzB,KAAK,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAwC/B,wBAAgB,2BAA2B,CACzC,cAAc,EAAE,OAAO,EAAE,EACzB,SAAS,EAAE,OAAO,EAAE,GACnB,OAAO,CAMT;AAwCD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,EAC3C,IAAI,EAAE,QAAQ,GACb,SAAS,EAAE,CA4Bb"}
@@ -0,0 +1,96 @@
1
+ import { pointInPolygon2D, pointOnSegment, } from '@pascal-app/core';
2
+ const POINT_TOLERANCE = 0.5;
3
+ const COLLINEAR_TOLERANCE = 1e-6;
4
+ const SURFACE_POLYGON_TOLERANCE = 0.15;
5
+ function getPointToSegmentDistance(point, start, end) {
6
+ const dx = end[0] - start[0];
7
+ const dz = end[1] - start[1];
8
+ const lengthSq = dx * dx + dz * dz;
9
+ if (lengthSq === 0)
10
+ return Math.hypot(point[0] - start[0], point[1] - start[1]);
11
+ const rawT = ((point[0] - start[0]) * dx + (point[1] - start[1]) * dz) / lengthSq;
12
+ const t = Math.max(0, Math.min(1, rawT));
13
+ const projected = [start[0] + t * dx, start[1] + t * dz];
14
+ return Math.hypot(point[0] - projected[0], point[1] - projected[1]);
15
+ }
16
+ function pointInPolygonWithTolerance(point, polygon) {
17
+ if (pointInPolygon2D(point, polygon, { includeBoundary: true }))
18
+ return true;
19
+ return polygon.some((start, index) => {
20
+ const end = polygon[(index + 1) % polygon.length];
21
+ return end ? getPointToSegmentDistance(point, start, end) <= POINT_TOLERANCE : false;
22
+ });
23
+ }
24
+ function polygonContainsWithTolerance(outer, inner, tolerance) {
25
+ return inner.every((point) => {
26
+ if (pointInPolygon2D(point, outer, { includeBoundary: true }))
27
+ return true;
28
+ return outer.some((start, index) => {
29
+ const end = outer[(index + 1) % outer.length];
30
+ return end ? getPointToSegmentDistance(point, start, end) <= tolerance : false;
31
+ });
32
+ });
33
+ }
34
+ export function polygonMatchesZoneFootprint(surfacePolygon, footprint) {
35
+ if (surfacePolygon.length < 3)
36
+ return false;
37
+ return (polygonContainsWithTolerance(footprint, surfacePolygon, SURFACE_POLYGON_TOLERANCE) &&
38
+ polygonContainsWithTolerance(surfacePolygon, footprint, SURFACE_POLYGON_TOLERANCE));
39
+ }
40
+ function areSegmentsCollinear(a, b, c, d) {
41
+ const abx = b[0] - a[0];
42
+ const abz = b[1] - a[1];
43
+ const acx = c[0] - a[0];
44
+ const acz = c[1] - a[1];
45
+ const adx = d[0] - a[0];
46
+ const adz = d[1] - a[1];
47
+ const crossC = abx * acz - abz * acx;
48
+ const crossD = abx * adz - abz * adx;
49
+ return Math.abs(crossC) <= COLLINEAR_TOLERANCE && Math.abs(crossD) <= COLLINEAR_TOLERANCE;
50
+ }
51
+ function segmentsOverlap(a, b, c, d) {
52
+ const useX = Math.abs(b[0] - a[0]) >= Math.abs(b[1] - a[1]);
53
+ const a0 = useX ? a[0] : a[1];
54
+ const a1 = useX ? b[0] : b[1];
55
+ const c0 = useX ? c[0] : c[1];
56
+ const c1 = useX ? d[0] : d[1];
57
+ const minA = Math.min(a0, a1);
58
+ const maxA = Math.max(a0, a1);
59
+ const minC = Math.min(c0, c1);
60
+ const maxC = Math.max(c0, c1);
61
+ return Math.max(minA, minC) <= Math.min(maxA, maxC) + COLLINEAR_TOLERANCE;
62
+ }
63
+ function wallLiesOnZoneBoundary(wall, polygon) {
64
+ return polygon.some((start, index) => {
65
+ const end = polygon[(index + 1) % polygon.length];
66
+ if (!end)
67
+ return false;
68
+ return (areSegmentsCollinear(wall.start, wall.end, start, end) &&
69
+ segmentsOverlap(wall.start, wall.end, start, end) &&
70
+ pointOnSegment(wall.start, start, end, POINT_TOLERANCE) &&
71
+ pointOnSegment(wall.end, start, end, POINT_TOLERANCE));
72
+ });
73
+ }
74
+ export function collectZoneContentIds(nodes, zone) {
75
+ const levelId = zone.parentId;
76
+ if (!levelId)
77
+ return [];
78
+ const footprint = zone.polygon.map((point) => [point[0], point[1]]);
79
+ const boundaryWalls = Object.values(nodes)
80
+ .filter((node) => node.type === 'wall' && node.parentId === levelId)
81
+ .filter((wall) => wallLiesOnZoneBoundary(wall, footprint));
82
+ const surfaces = Object.values(nodes)
83
+ .filter((node) => (node.type === 'slab' || node.type === 'ceiling') && node.parentId === levelId)
84
+ .filter((surface) => {
85
+ const polygon = surface.polygon.map((point) => [point[0], point[1]]);
86
+ return polygonMatchesZoneFootprint(polygon, footprint);
87
+ });
88
+ const floorItems = Object.values(nodes)
89
+ .filter((node) => node.type === 'item' && node.parentId === levelId)
90
+ .filter((item) => pointInPolygonWithTolerance([item.position[0], item.position[2]], footprint));
91
+ return Array.from(new Set([
92
+ ...boundaryWalls.map((wall) => wall.id),
93
+ ...surfaces.map((surface) => surface.id),
94
+ ...floorItems.map((item) => item.id),
95
+ ]));
96
+ }
@@ -0,0 +1,11 @@
1
+ import { type VariantProps } from 'class-variance-authority';
2
+ import type * as React from 'react';
3
+ declare const buttonVariants: (props?: ({
4
+ variant?: "default" | "destructive" | "ghost" | "link" | "outline" | "secondary" | null | undefined;
5
+ size?: "default" | "icon" | "icon-lg" | "icon-sm" | "lg" | "sm" | null | undefined;
6
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
+ declare function Button({ className, variant, size, asChild, ref, ...props }: React.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
8
+ asChild?: boolean;
9
+ }): React.JSX.Element;
10
+ export { Button, buttonVariants };
11
+ //# sourceMappingURL=button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../src/ui/primitives/button.tsx"],"names":[],"mappings":"AACA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AAInC,QAAA,MAAM,cAAc;;;8EA4BnB,CAAA;AAED,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,OAAO,EACP,IAAI,EACJ,OAAe,EACf,GAAG,EACH,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAC/B,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,qBAoBF;AAED,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,35 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Slot } from '@radix-ui/react-slot';
3
+ import { cva } from 'class-variance-authority';
4
+ import { cn } from '../lib/cn';
5
+ const buttonVariants = cva("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", {
6
+ variants: {
7
+ variant: {
8
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90',
9
+ destructive: 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40',
10
+ outline: 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50',
11
+ secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
12
+ ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
13
+ link: 'text-primary underline-offset-4 hover:underline',
14
+ },
15
+ size: {
16
+ default: 'h-9 px-4 py-2 has-[>svg]:px-3',
17
+ sm: 'h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5',
18
+ lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
19
+ icon: 'size-9',
20
+ 'icon-sm': 'size-8',
21
+ 'icon-lg': 'size-10',
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ variant: 'default',
26
+ size: 'default',
27
+ },
28
+ });
29
+ function Button({ className, variant, size, asChild = false, ref, ...props }) {
30
+ if (asChild) {
31
+ return (_jsx(Slot, { className: cn(buttonVariants({ variant, size, className })), "data-slot": "button", ref: ref, ...props }));
32
+ }
33
+ return (_jsx("button", { className: cn(buttonVariants({ variant, size, className })), "data-slot": "button", ref: ref, ...props }));
34
+ }
35
+ export { Button, buttonVariants };
@@ -0,0 +1,26 @@
1
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
2
+ import type * as React from 'react';
3
+ declare function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>): React.JSX.Element;
4
+ declare function DropdownMenuPortal({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>): React.JSX.Element;
5
+ declare function DropdownMenuTrigger({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>): React.JSX.Element;
6
+ declare function DropdownMenuContent({ className, sideOffset, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>): React.JSX.Element;
7
+ declare function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>): React.JSX.Element;
8
+ declare function DropdownMenuItem({ className, inset, variant, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
9
+ inset?: boolean;
10
+ variant?: 'default' | 'destructive';
11
+ }): React.JSX.Element;
12
+ declare function DropdownMenuCheckboxItem({ className, children, checked, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>): React.JSX.Element;
13
+ declare function DropdownMenuRadioGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>): React.JSX.Element;
14
+ declare function DropdownMenuRadioItem({ className, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>): React.JSX.Element;
15
+ declare function DropdownMenuLabel({ className, inset, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
16
+ inset?: boolean;
17
+ }): React.JSX.Element;
18
+ declare function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>): React.JSX.Element;
19
+ declare function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>): React.JSX.Element;
20
+ declare function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>): React.JSX.Element;
21
+ declare function DropdownMenuSubTrigger({ className, inset, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
22
+ inset?: boolean;
23
+ }): React.JSX.Element;
24
+ declare function DropdownMenuSubContent({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>): React.JSX.Element;
25
+ export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, };
26
+ //# sourceMappingURL=dropdown-menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dropdown-menu.d.ts","sourceRoot":"","sources":["../../../src/ui/primitives/dropdown-menu.tsx"],"names":[],"mappings":"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"}