@vamos-ui/react 0.0.0-stage → 0.3.0

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 (704) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +27 -2
  3. package/dist/blocks/block-heading.d.ts +29 -0
  4. package/dist/blocks/block-heading.js +39 -0
  5. package/dist/blocks/block-image.d.ts +52 -0
  6. package/dist/blocks/block-image.js +48 -0
  7. package/dist/blocks/block-link.d.ts +30 -0
  8. package/dist/blocks/block-link.js +36 -0
  9. package/dist/blocks/create-blocks.d.ts +54 -0
  10. package/dist/blocks/create-blocks.js +52 -0
  11. package/dist/blocks/index.d.ts +55 -0
  12. package/dist/blocks/index.js +59 -0
  13. package/dist/blocks/json-ld.d.ts +18 -0
  14. package/dist/blocks/json-ld.js +44 -0
  15. package/dist/blocks/labels.d.ts +20 -0
  16. package/dist/blocks/labels.js +43 -0
  17. package/dist/blocks/rich-text.d.ts +36 -0
  18. package/dist/blocks/rich-text.js +106 -0
  19. package/dist/blocks/schema/define-block.d.ts +151 -0
  20. package/dist/blocks/schema/define-block.js +120 -0
  21. package/dist/blocks/schema/emphasis.d.ts +17 -0
  22. package/dist/blocks/schema/emphasis.js +69 -0
  23. package/dist/blocks/schema/fields.d.ts +497 -0
  24. package/dist/blocks/schema/fields.js +240 -0
  25. package/dist/blocks/schema/icons.d.ts +2 -0
  26. package/dist/blocks/schema/icons.js +26 -0
  27. package/dist/blocks/schema/index.d.ts +18 -0
  28. package/dist/blocks/schema/index.js +21 -0
  29. package/dist/blocks/schema/lint-types.d.ts +16 -0
  30. package/dist/blocks/schema/lint-types.js +2 -0
  31. package/dist/blocks/schema/lint.d.ts +32 -0
  32. package/dist/blocks/schema/lint.js +164 -0
  33. package/dist/blocks/schema/localize.d.ts +20 -0
  34. package/dist/blocks/schema/localize.js +29 -0
  35. package/dist/blocks/schema/localized.d.ts +25 -0
  36. package/dist/blocks/schema/localized.js +53 -0
  37. package/dist/blocks/schema/migrate.d.ts +24 -0
  38. package/dist/blocks/schema/migrate.js +75 -0
  39. package/dist/blocks/schema/nodes.d.ts +196 -0
  40. package/dist/blocks/schema/nodes.js +78 -0
  41. package/dist/blocks/schema/rich-doc-schema.d.ts +32 -0
  42. package/dist/blocks/schema/rich-doc-schema.js +66 -0
  43. package/dist/blocks/schema/rich-doc.d.ts +90 -0
  44. package/dist/blocks/schema/rich-doc.js +62 -0
  45. package/dist/blocks/schema/safety.d.ts +20 -0
  46. package/dist/blocks/schema/safety.js +49 -0
  47. package/dist/blocks/schema/types.d.ts +172 -0
  48. package/dist/blocks/schema/types.js +3 -0
  49. package/dist/blocks/schema/validate.d.ts +17 -0
  50. package/dist/blocks/schema/validate.js +32 -0
  51. package/dist/blocks/schema/walk.d.ts +22 -0
  52. package/dist/blocks/schema/walk.js +60 -0
  53. package/dist/blocks/section-header.d.ts +38 -0
  54. package/dist/blocks/section-header.js +22 -0
  55. package/dist/blocks/section.d.ts +59 -0
  56. package/dist/blocks/section.js +66 -0
  57. package/dist/blocks/site/_kit-1.d.ts +101 -0
  58. package/dist/blocks/site/_kit-1.js +137 -0
  59. package/dist/blocks/site/_site-icon-1.d.ts +6 -0
  60. package/dist/blocks/site/_site-icon-1.js +15 -0
  61. package/dist/blocks/site/announcement-bar.d.ts +42 -0
  62. package/dist/blocks/site/announcement-bar.js +38 -0
  63. package/dist/blocks/site/announcement-dismiss.d.ts +18 -0
  64. package/dist/blocks/site/announcement-dismiss.js +28 -0
  65. package/dist/blocks/site/article-layout.d.ts +65 -0
  66. package/dist/blocks/site/article-layout.js +88 -0
  67. package/dist/blocks/site/blog-list.d.ts +79 -0
  68. package/dist/blocks/site/blog-list.js +78 -0
  69. package/dist/blocks/site/comparison-table.d.ts +54 -0
  70. package/dist/blocks/site/comparison-table.js +38 -0
  71. package/dist/blocks/site/consent-banner.d.ts +52 -0
  72. package/dist/blocks/site/consent-banner.js +33 -0
  73. package/dist/blocks/site/contact-dock.d.ts +52 -0
  74. package/dist/blocks/site/contact-dock.js +55 -0
  75. package/dist/blocks/site/contact-form.d.ts +60 -0
  76. package/dist/blocks/site/contact-form.js +45 -0
  77. package/dist/blocks/site/cta-booking.d.ts +43 -0
  78. package/dist/blocks/site/cta-booking.js +69 -0
  79. package/dist/blocks/site/cta.d.ts +74 -0
  80. package/dist/blocks/site/cta.js +113 -0
  81. package/dist/blocks/site/embed-facade.d.ts +20 -0
  82. package/dist/blocks/site/embed-facade.js +21 -0
  83. package/dist/blocks/site/faq.d.ts +48 -0
  84. package/dist/blocks/site/faq.js +52 -0
  85. package/dist/blocks/site/feature-grid.d.ts +46 -0
  86. package/dist/blocks/site/feature-grid.js +50 -0
  87. package/dist/blocks/site/feature-tabs.d.ts +22 -0
  88. package/dist/blocks/site/feature-tabs.js +11 -0
  89. package/dist/blocks/site/footer.d.ts +68 -0
  90. package/dist/blocks/site/footer.js +61 -0
  91. package/dist/blocks/site/gallery-section.d.ts +42 -0
  92. package/dist/blocks/site/gallery-section.js +48 -0
  93. package/dist/blocks/site/hero-video.d.ts +15 -0
  94. package/dist/blocks/site/hero-video.js +31 -0
  95. package/dist/blocks/site/hero.d.ts +64 -0
  96. package/dist/blocks/site/hero.js +73 -0
  97. package/dist/blocks/site/logo-strip.d.ts +44 -0
  98. package/dist/blocks/site/logo-strip.js +27 -0
  99. package/dist/blocks/site/map-hours.d.ts +83 -0
  100. package/dist/blocks/site/map-hours.js +125 -0
  101. package/dist/blocks/site/media-text.d.ts +45 -0
  102. package/dist/blocks/site/media-text.js +56 -0
  103. package/dist/blocks/site/menu-list.d.ts +74 -0
  104. package/dist/blocks/site/menu-list.js +84 -0
  105. package/dist/blocks/site/navbar-submenu.d.ts +18 -0
  106. package/dist/blocks/site/navbar-submenu.js +51 -0
  107. package/dist/blocks/site/navbar.d.ts +67 -0
  108. package/dist/blocks/site/navbar.js +64 -0
  109. package/dist/blocks/site/not-found.d.ts +40 -0
  110. package/dist/blocks/site/not-found.js +38 -0
  111. package/dist/blocks/site/page-intro.d.ts +46 -0
  112. package/dist/blocks/site/page-intro.js +44 -0
  113. package/dist/blocks/site/pricing-table.d.ts +67 -0
  114. package/dist/blocks/site/pricing-table.js +83 -0
  115. package/dist/blocks/site/process.d.ts +36 -0
  116. package/dist/blocks/site/process.js +42 -0
  117. package/dist/blocks/site/registry-1.d.ts +720 -0
  118. package/dist/blocks/site/registry-1.js +783 -0
  119. package/dist/blocks/site/registry-2.d.ts +914 -0
  120. package/dist/blocks/site/registry-2.js +563 -0
  121. package/dist/blocks/site/rich-text-section.d.ts +34 -0
  122. package/dist/blocks/site/rich-text-section.js +32 -0
  123. package/dist/blocks/site/shared/brand-icons.d.ts +21 -0
  124. package/dist/blocks/site/shared/brand-icons.js +56 -0
  125. package/dist/blocks/site/shared/consent-gate.d.ts +41 -0
  126. package/dist/blocks/site/shared/consent-gate.js +43 -0
  127. package/dist/blocks/site/shared/consent-island.d.ts +38 -0
  128. package/dist/blocks/site/shared/consent-island.js +63 -0
  129. package/dist/blocks/site/shared/consent.d.ts +49 -0
  130. package/dist/blocks/site/shared/consent.js +130 -0
  131. package/dist/blocks/site/shared/contact-form-island.d.ts +41 -0
  132. package/dist/blocks/site/shared/contact-form-island.js +100 -0
  133. package/dist/blocks/site/shared/copy-link.d.ts +10 -0
  134. package/dist/blocks/site/shared/copy-link.js +25 -0
  135. package/dist/blocks/site/shared/dock-avoid.d.ts +15 -0
  136. package/dist/blocks/site/shared/dock-avoid.js +107 -0
  137. package/dist/blocks/site/shared/dock-hours.d.ts +13 -0
  138. package/dist/blocks/site/shared/dock-hours.js +25 -0
  139. package/dist/blocks/site/shared/gallery-lightbox.d.ts +12 -0
  140. package/dist/blocks/site/shared/gallery-lightbox.js +10 -0
  141. package/dist/blocks/site/shared/island-keys.d.ts +10 -0
  142. package/dist/blocks/site/shared/island-keys.js +44 -0
  143. package/dist/blocks/site/shared/kit-2.d.ts +55 -0
  144. package/dist/blocks/site/shared/kit-2.js +84 -0
  145. package/dist/blocks/site/shared/labels-2.d.ts +209 -0
  146. package/dist/blocks/site/shared/labels-2.js +427 -0
  147. package/dist/blocks/site/shared/open-now.d.ts +22 -0
  148. package/dist/blocks/site/shared/open-now.js +27 -0
  149. package/dist/blocks/site/shared/opening-hours.d.ts +117 -0
  150. package/dist/blocks/site/shared/opening-hours.js +245 -0
  151. package/dist/blocks/site/shared/site-accent.d.ts +48 -0
  152. package/dist/blocks/site/shared/site-accent.js +249 -0
  153. package/dist/blocks/site/shared/site-form.d.ts +79 -0
  154. package/dist/blocks/site/shared/site-form.js +111 -0
  155. package/dist/blocks/site/shared/site-routing.d.ts +54 -0
  156. package/dist/blocks/site/shared/site-routing.js +86 -0
  157. package/dist/blocks/site/shared/testimonials-carousel.d.ts +17 -0
  158. package/dist/blocks/site/shared/testimonials-carousel.js +64 -0
  159. package/dist/blocks/site/site-shell.d.ts +108 -0
  160. package/dist/blocks/site/site-shell.js +254 -0
  161. package/dist/blocks/site/stats-band.d.ts +42 -0
  162. package/dist/blocks/site/stats-band.js +45 -0
  163. package/dist/blocks/site/team.d.ts +44 -0
  164. package/dist/blocks/site/team.js +48 -0
  165. package/dist/blocks/site/testimonials.d.ts +68 -0
  166. package/dist/blocks/site/testimonials.js +66 -0
  167. package/dist/blocks/types.d.ts +63 -0
  168. package/dist/blocks/types.js +2 -0
  169. package/dist/business/approval-flow.d.ts +152 -0
  170. package/dist/business/approval-flow.js +221 -0
  171. package/dist/business/export-core.d.ts +55 -0
  172. package/dist/business/export-core.js +101 -0
  173. package/dist/business/export.d.ts +148 -0
  174. package/dist/business/export.js +264 -0
  175. package/dist/business/import-core.d.ts +104 -0
  176. package/dist/business/import-core.js +281 -0
  177. package/dist/business/import-wizard.d.ts +186 -0
  178. package/dist/business/import-wizard.js +401 -0
  179. package/dist/business/index.d.ts +12 -0
  180. package/dist/business/index.js +22 -0
  181. package/dist/business/line-items-core.d.ts +129 -0
  182. package/dist/business/line-items-core.js +183 -0
  183. package/dist/business/line-items.d.ts +119 -0
  184. package/dist/business/line-items.js +299 -0
  185. package/dist/business/multi-step-form.d.ts +131 -0
  186. package/dist/business/multi-step-form.js +337 -0
  187. package/dist/business/permission-core.d.ts +59 -0
  188. package/dist/business/permission-core.js +99 -0
  189. package/dist/business/permission-matrix.d.ts +158 -0
  190. package/dist/business/permission-matrix.js +341 -0
  191. package/dist/business/setup-checklist.d.ts +80 -0
  192. package/dist/business/setup-checklist.js +92 -0
  193. package/dist/business/signer-status.d.ts +53 -0
  194. package/dist/business/signer-status.js +76 -0
  195. package/dist/charts/area-chart.d.ts +35 -0
  196. package/dist/charts/area-chart.js +33 -0
  197. package/dist/charts/bar-chart.d.ts +27 -0
  198. package/dist/charts/bar-chart.js +46 -0
  199. package/dist/charts/bar-list.d.ts +47 -0
  200. package/dist/charts/bar-list.js +60 -0
  201. package/dist/charts/chart-shell.d.ts +173 -0
  202. package/dist/charts/chart-shell.js +205 -0
  203. package/dist/charts/chart.d.ts +73 -0
  204. package/dist/charts/chart.js +106 -0
  205. package/dist/charts/combo-chart.d.ts +29 -0
  206. package/dist/charts/combo-chart.js +47 -0
  207. package/dist/charts/donut-chart.d.ts +33 -0
  208. package/dist/charts/donut-chart.js +113 -0
  209. package/dist/charts/funnel.d.ts +51 -0
  210. package/dist/charts/funnel.js +69 -0
  211. package/dist/charts/gauge.d.ts +62 -0
  212. package/dist/charts/gauge.js +104 -0
  213. package/dist/charts/heatmap.d.ts +81 -0
  214. package/dist/charts/heatmap.js +338 -0
  215. package/dist/charts/index.d.ts +12 -0
  216. package/dist/charts/index.js +14 -0
  217. package/dist/charts/line-chart.d.ts +21 -0
  218. package/dist/charts/line-chart.js +36 -0
  219. package/dist/charts/test-utils.d.ts +2 -0
  220. package/dist/charts/test-utils.js +38 -0
  221. package/dist/charts/utils.d.ts +130 -0
  222. package/dist/charts/utils.js +262 -0
  223. package/dist/components/_qr-core.d.ts +26 -0
  224. package/dist/components/_qr-core.js +376 -0
  225. package/dist/components/accordion.d.ts +47 -0
  226. package/dist/components/accordion.js +70 -0
  227. package/dist/components/activity-timeline.d.ts +149 -0
  228. package/dist/components/activity-timeline.js +122 -0
  229. package/dist/components/address-field.d.ts +116 -0
  230. package/dist/components/address-field.js +219 -0
  231. package/dist/components/alert-dialog.d.ts +99 -0
  232. package/dist/components/alert-dialog.js +192 -0
  233. package/dist/components/alert.d.ts +42 -0
  234. package/dist/components/alert.js +82 -0
  235. package/dist/components/app-shell.d.ts +159 -0
  236. package/dist/components/app-shell.js +289 -0
  237. package/dist/components/attachment-list.d.ts +96 -0
  238. package/dist/components/attachment-list.js +196 -0
  239. package/dist/components/audit-log.d.ts +150 -0
  240. package/dist/components/audit-log.js +205 -0
  241. package/dist/components/avatar.d.ts +87 -0
  242. package/dist/components/avatar.js +126 -0
  243. package/dist/components/backup-codes.d.ts +42 -0
  244. package/dist/components/backup-codes.js +67 -0
  245. package/dist/components/badge.d.ts +41 -0
  246. package/dist/components/badge.js +68 -0
  247. package/dist/components/breadcrumb.d.ts +78 -0
  248. package/dist/components/breadcrumb.js +106 -0
  249. package/dist/components/button-group.d.ts +52 -0
  250. package/dist/components/button-group.js +77 -0
  251. package/dist/components/button.d.ts +58 -0
  252. package/dist/components/button.js +107 -0
  253. package/dist/components/calendar.d.ts +240 -0
  254. package/dist/components/calendar.js +483 -0
  255. package/dist/components/card.d.ts +66 -0
  256. package/dist/components/card.js +76 -0
  257. package/dist/components/carousel.d.ts +170 -0
  258. package/dist/components/carousel.js +348 -0
  259. package/dist/components/checkbox.d.ts +78 -0
  260. package/dist/components/checkbox.js +138 -0
  261. package/dist/components/color-picker.d.ts +112 -0
  262. package/dist/components/color-picker.js +235 -0
  263. package/dist/components/combobox.d.ts +136 -0
  264. package/dist/components/combobox.js +294 -0
  265. package/dist/components/command.d.ts +281 -0
  266. package/dist/components/command.js +498 -0
  267. package/dist/components/comment-thread.d.ts +252 -0
  268. package/dist/components/comment-thread.js +449 -0
  269. package/dist/components/context-menu.d.ts +77 -0
  270. package/dist/components/context-menu.js +82 -0
  271. package/dist/components/currency-input.d.ts +43 -0
  272. package/dist/components/currency-input.js +85 -0
  273. package/dist/components/date-picker.d.ts +141 -0
  274. package/dist/components/date-picker.js +241 -0
  275. package/dist/components/date-range-picker.d.ts +91 -0
  276. package/dist/components/date-range-picker.js +251 -0
  277. package/dist/components/description-list.d.ts +92 -0
  278. package/dist/components/description-list.js +42 -0
  279. package/dist/components/dialog.d.ts +139 -0
  280. package/dist/components/dialog.js +185 -0
  281. package/dist/components/dropdown-menu.d.ts +100 -0
  282. package/dist/components/dropdown-menu.js +102 -0
  283. package/dist/components/editor-layout.d.ts +166 -0
  284. package/dist/components/editor-layout.js +237 -0
  285. package/dist/components/empty-state.d.ts +49 -0
  286. package/dist/components/empty-state.js +68 -0
  287. package/dist/components/entity-card.d.ts +83 -0
  288. package/dist/components/entity-card.js +92 -0
  289. package/dist/components/file-upload.d.ts +256 -0
  290. package/dist/components/file-upload.js +490 -0
  291. package/dist/components/formatted-input.d.ts +177 -0
  292. package/dist/components/formatted-input.js +399 -0
  293. package/dist/components/hierarchy-chart.d.ts +190 -0
  294. package/dist/components/hierarchy-chart.js +890 -0
  295. package/dist/components/hover-card.d.ts +21 -0
  296. package/dist/components/hover-card.js +32 -0
  297. package/dist/components/iban-input.d.ts +38 -0
  298. package/dist/components/iban-input.js +112 -0
  299. package/dist/components/id-input.d.ts +65 -0
  300. package/dist/components/id-input.js +130 -0
  301. package/dist/components/image.d.ts +130 -0
  302. package/dist/components/image.js +168 -0
  303. package/dist/components/input-otp.d.ts +62 -0
  304. package/dist/components/input-otp.js +73 -0
  305. package/dist/components/input.d.ts +141 -0
  306. package/dist/components/input.js +187 -0
  307. package/dist/components/item.d.ts +96 -0
  308. package/dist/components/item.js +113 -0
  309. package/dist/components/kbd.d.ts +64 -0
  310. package/dist/components/kbd.js +119 -0
  311. package/dist/components/list-layout.d.ts +144 -0
  312. package/dist/components/list-layout.js +210 -0
  313. package/dist/components/native-select.d.ts +33 -0
  314. package/dist/components/native-select.js +48 -0
  315. package/dist/components/navigation-menu.d.ts +127 -0
  316. package/dist/components/navigation-menu.js +129 -0
  317. package/dist/components/notification-center.d.ts +164 -0
  318. package/dist/components/notification-center.js +399 -0
  319. package/dist/components/page-header.d.ts +60 -0
  320. package/dist/components/page-header.js +60 -0
  321. package/dist/components/pagination.d.ts +121 -0
  322. package/dist/components/pagination.js +174 -0
  323. package/dist/components/phone-input.d.ts +49 -0
  324. package/dist/components/phone-input.js +266 -0
  325. package/dist/components/pin-map.d.ts +58 -0
  326. package/dist/components/pin-map.js +167 -0
  327. package/dist/components/popover.d.ts +38 -0
  328. package/dist/components/popover.js +69 -0
  329. package/dist/components/progress.d.ts +79 -0
  330. package/dist/components/progress.js +97 -0
  331. package/dist/components/qr-code.d.ts +36 -0
  332. package/dist/components/qr-code.js +27 -0
  333. package/dist/components/radio-group.d.ts +43 -0
  334. package/dist/components/radio-group.js +81 -0
  335. package/dist/components/record-detail-layout.d.ts +167 -0
  336. package/dist/components/record-detail-layout.js +233 -0
  337. package/dist/components/record-picker.d.ts +199 -0
  338. package/dist/components/record-picker.js +650 -0
  339. package/dist/components/resizable.d.ts +50 -0
  340. package/dist/components/resizable.js +88 -0
  341. package/dist/components/scroll-area.d.ts +40 -0
  342. package/dist/components/scroll-area.js +56 -0
  343. package/dist/components/select.d.ts +126 -0
  344. package/dist/components/select.js +137 -0
  345. package/dist/components/separator.d.ts +31 -0
  346. package/dist/components/separator.js +41 -0
  347. package/dist/components/settings-layout.d.ts +134 -0
  348. package/dist/components/settings-layout.js +180 -0
  349. package/dist/components/sheet.d.ts +103 -0
  350. package/dist/components/sheet.js +165 -0
  351. package/dist/components/sidebar.d.ts +171 -0
  352. package/dist/components/sidebar.js +421 -0
  353. package/dist/components/signature-pad.d.ts +85 -0
  354. package/dist/components/signature-pad.js +283 -0
  355. package/dist/components/skeleton.d.ts +64 -0
  356. package/dist/components/skeleton.js +53 -0
  357. package/dist/components/sla-timer.d.ts +75 -0
  358. package/dist/components/sla-timer.js +142 -0
  359. package/dist/components/slider.d.ts +57 -0
  360. package/dist/components/slider.js +133 -0
  361. package/dist/components/slug-input.d.ts +69 -0
  362. package/dist/components/slug-input.js +201 -0
  363. package/dist/components/sparkline.d.ts +54 -0
  364. package/dist/components/sparkline.js +122 -0
  365. package/dist/components/spinner.d.ts +34 -0
  366. package/dist/components/spinner.js +34 -0
  367. package/dist/components/stat.d.ts +135 -0
  368. package/dist/components/stat.js +130 -0
  369. package/dist/components/status-picker.d.ts +107 -0
  370. package/dist/components/status-picker.js +175 -0
  371. package/dist/components/stepper.d.ts +86 -0
  372. package/dist/components/stepper.js +103 -0
  373. package/dist/components/switch.d.ts +34 -0
  374. package/dist/components/switch.js +70 -0
  375. package/dist/components/table.d.ts +101 -0
  376. package/dist/components/table.js +72 -0
  377. package/dist/components/tabs.d.ts +103 -0
  378. package/dist/components/tabs.js +173 -0
  379. package/dist/components/tag-input.d.ts +77 -0
  380. package/dist/components/tag-input.js +305 -0
  381. package/dist/components/task-list.d.ts +89 -0
  382. package/dist/components/task-list.js +238 -0
  383. package/dist/components/time-picker.d.ts +119 -0
  384. package/dist/components/time-picker.js +399 -0
  385. package/dist/components/toast.d.ts +87 -0
  386. package/dist/components/toast.js +142 -0
  387. package/dist/components/toggle.d.ts +77 -0
  388. package/dist/components/toggle.js +109 -0
  389. package/dist/components/tooltip.d.ts +69 -0
  390. package/dist/components/tooltip.js +105 -0
  391. package/dist/components/top-bar.d.ts +87 -0
  392. package/dist/components/top-bar.js +99 -0
  393. package/dist/components/tour.d.ts +60 -0
  394. package/dist/components/tour.js +139 -0
  395. package/dist/components/tree-select.d.ts +89 -0
  396. package/dist/components/tree-select.js +243 -0
  397. package/dist/components/tree-view.d.ts +109 -0
  398. package/dist/components/tree-view.js +170 -0
  399. package/dist/components/typography.d.ts +107 -0
  400. package/dist/components/typography.js +128 -0
  401. package/dist/components/user-picker.d.ts +89 -0
  402. package/dist/components/user-picker.js +162 -0
  403. package/dist/components/version-history.d.ts +191 -0
  404. package/dist/components/version-history.js +431 -0
  405. package/dist/data-table/csv.d.ts +27 -0
  406. package/dist/data-table/csv.js +68 -0
  407. package/dist/data-table/data-table.d.ts +423 -0
  408. package/dist/data-table/data-table.js +1259 -0
  409. package/dist/data-table/filter-bar.d.ts +146 -0
  410. package/dist/data-table/filter-bar.js +569 -0
  411. package/dist/data-table/filter-fns.d.ts +65 -0
  412. package/dist/data-table/filter-fns.js +382 -0
  413. package/dist/data-table/index.d.ts +8 -0
  414. package/dist/data-table/index.js +9 -0
  415. package/dist/data-table/saved-views.d.ts +100 -0
  416. package/dist/data-table/saved-views.js +251 -0
  417. package/dist/data-table/types.d.ts +168 -0
  418. package/dist/data-table/types.js +87 -0
  419. package/dist/data-table/url-state.d.ts +94 -0
  420. package/dist/data-table/url-state.js +303 -0
  421. package/dist/data-table/view-state.d.ts +16 -0
  422. package/dist/data-table/view-state.js +81 -0
  423. package/dist/editor/_test-setup.d.ts +1 -0
  424. package/dist/editor/_test-setup.js +33 -0
  425. package/dist/editor/block-editor.d.ts +137 -0
  426. package/dist/editor/block-editor.js +280 -0
  427. package/dist/editor/commands.d.ts +31 -0
  428. package/dist/editor/commands.js +150 -0
  429. package/dist/editor/context.d.ts +108 -0
  430. package/dist/editor/context.js +30 -0
  431. package/dist/editor/convert.d.ts +66 -0
  432. package/dist/editor/convert.js +567 -0
  433. package/dist/editor/drag-handle.d.ts +10 -0
  434. package/dist/editor/drag-handle.js +69 -0
  435. package/dist/editor/extensions.d.ts +34 -0
  436. package/dist/editor/extensions.js +239 -0
  437. package/dist/editor/index.d.ts +14 -0
  438. package/dist/editor/index.js +17 -0
  439. package/dist/editor/inserter.d.ts +12 -0
  440. package/dist/editor/inserter.js +88 -0
  441. package/dist/editor/inspector.d.ts +17 -0
  442. package/dist/editor/inspector.js +65 -0
  443. package/dist/editor/items.d.ts +62 -0
  444. package/dist/editor/items.js +195 -0
  445. package/dist/editor/labels.d.ts +119 -0
  446. package/dist/editor/labels.js +130 -0
  447. package/dist/editor/markdown.d.ts +14 -0
  448. package/dist/editor/markdown.js +209 -0
  449. package/dist/editor/menus.d.ts +20 -0
  450. package/dist/editor/menus.js +236 -0
  451. package/dist/editor/nodes.d.ts +14 -0
  452. package/dist/editor/nodes.js +201 -0
  453. package/dist/editor/outline.d.ts +11 -0
  454. package/dist/editor/outline.js +52 -0
  455. package/dist/editor/schema-form.d.ts +64 -0
  456. package/dist/editor/schema-form.js +290 -0
  457. package/dist/editor/slash-menu.d.ts +15 -0
  458. package/dist/editor/slash-menu.js +119 -0
  459. package/dist/fonts/catalog.d.ts +53 -0
  460. package/dist/fonts/catalog.js +121 -0
  461. package/dist/fonts/font-picker.d.ts +70 -0
  462. package/dist/fonts/font-picker.js +225 -0
  463. package/dist/fonts/index.d.ts +6 -0
  464. package/dist/fonts/index.js +7 -0
  465. package/dist/fonts/loader.d.ts +66 -0
  466. package/dist/fonts/loader.js +161 -0
  467. package/dist/fonts/pairing-picker.d.ts +31 -0
  468. package/dist/fonts/pairing-picker.js +81 -0
  469. package/dist/fonts/pairings.d.ts +84 -0
  470. package/dist/fonts/pairings.js +149 -0
  471. package/dist/fonts/provider.d.ts +34 -0
  472. package/dist/fonts/provider.js +51 -0
  473. package/dist/form/index.d.ts +1 -0
  474. package/dist/form/index.js +1 -0
  475. package/dist/format/core.d.ts +149 -0
  476. package/dist/format/core.js +357 -0
  477. package/dist/format/index.d.ts +4 -0
  478. package/dist/format/index.js +5 -0
  479. package/dist/format/use-format.d.ts +1 -0
  480. package/dist/format/use-format.js +3 -0
  481. package/dist/index.d.ts +91 -0
  482. package/dist/index.js +92 -0
  483. package/dist/lib/cn.d.ts +3 -0
  484. package/dist/lib/cn.js +16 -0
  485. package/dist/lib/color.d.ts +64 -0
  486. package/dist/lib/color.js +177 -0
  487. package/dist/lib/compose-refs.d.ts +24 -0
  488. package/dist/lib/compose-refs.js +45 -0
  489. package/dist/lib/data-islands.d.ts +194 -0
  490. package/dist/lib/data-islands.js +368 -0
  491. package/dist/lib/date.d.ts +129 -0
  492. package/dist/lib/date.js +386 -0
  493. package/dist/lib/field-context.d.ts +64 -0
  494. package/dist/lib/field-context.js +62 -0
  495. package/dist/lib/floating-arrow.d.ts +18 -0
  496. package/dist/lib/floating-arrow.js +15 -0
  497. package/dist/lib/islands.d.ts +38 -0
  498. package/dist/lib/islands.js +40 -0
  499. package/dist/lib/labels.d.ts +51 -0
  500. package/dist/lib/labels.js +56 -0
  501. package/dist/lib/layer.d.ts +36 -0
  502. package/dist/lib/layer.js +42 -0
  503. package/dist/lib/locale.d.ts +85 -0
  504. package/dist/lib/locale.js +105 -0
  505. package/dist/lib/menu.d.ts +58 -0
  506. package/dist/lib/menu.js +99 -0
  507. package/dist/lib/message-format.d.ts +20 -0
  508. package/dist/lib/message-format.js +116 -0
  509. package/dist/lib/nav.d.ts +132 -0
  510. package/dist/lib/nav.js +178 -0
  511. package/dist/lib/provider.d.ts +100 -0
  512. package/dist/lib/provider.js +105 -0
  513. package/dist/lib/public.d.ts +23 -0
  514. package/dist/lib/public.js +34 -0
  515. package/dist/lib/sr-name.d.ts +18 -0
  516. package/dist/lib/sr-name.js +17 -0
  517. package/dist/lib/text.d.ts +100 -0
  518. package/dist/lib/text.js +233 -0
  519. package/dist/lib/theme-scope.d.ts +58 -0
  520. package/dist/lib/theme-scope.js +59 -0
  521. package/dist/lib/use-async-list.d.ts +60 -0
  522. package/dist/lib/use-async-list.js +119 -0
  523. package/dist/lib/use-container-width.d.ts +19 -0
  524. package/dist/lib/use-container-width.js +39 -0
  525. package/dist/lib/use-controllable-state.d.ts +33 -0
  526. package/dist/lib/use-controllable-state.js +56 -0
  527. package/dist/lib/use-edge-fade.d.ts +13 -0
  528. package/dist/lib/use-edge-fade.js +43 -0
  529. package/dist/lib/use-formatted-input.d.ts +69 -0
  530. package/dist/lib/use-formatted-input.js +152 -0
  531. package/dist/lib/use-hotkeys.d.ts +80 -0
  532. package/dist/lib/use-hotkeys.js +221 -0
  533. package/dist/lib/use-hover-intent.d.ts +44 -0
  534. package/dist/lib/use-hover-intent.js +119 -0
  535. package/dist/lib/use-media-query.d.ts +21 -0
  536. package/dist/lib/use-media-query.js +28 -0
  537. package/dist/lib/use-reduced-motion.d.ts +8 -0
  538. package/dist/lib/use-reduced-motion.js +13 -0
  539. package/dist/lib/use-tree.d.ts +153 -0
  540. package/dist/lib/use-tree.js +534 -0
  541. package/dist/lib/value-format.d.ts +25 -0
  542. package/dist/lib/value-format.js +56 -0
  543. package/dist/lib/variants.d.ts +131 -0
  544. package/dist/lib/variants.js +109 -0
  545. package/dist/locale-data/core/date.d.ts +24 -0
  546. package/dist/locale-data/core/date.js +68 -0
  547. package/dist/locale-data/core/decimal.d.ts +19 -0
  548. package/dist/locale-data/core/decimal.js +79 -0
  549. package/dist/locale-data/core/holidays.d.ts +30 -0
  550. package/dist/locale-data/core/holidays.js +79 -0
  551. package/dist/locale-data/core/iban.d.ts +29 -0
  552. package/dist/locale-data/core/iban.js +74 -0
  553. package/dist/locale-data/core/index.d.ts +7 -0
  554. package/dist/locale-data/core/index.js +6 -0
  555. package/dist/locale-data/core/types.d.ts +173 -0
  556. package/dist/locale-data/core/types.js +6 -0
  557. package/dist/locale-data/core/week-info.d.ts +23 -0
  558. package/dist/locale-data/core/week-info.js +85 -0
  559. package/dist/locale-data/core/working-days.d.ts +27 -0
  560. package/dist/locale-data/core/working-days.js +133 -0
  561. package/dist/locale-data/index.d.ts +2 -0
  562. package/dist/locale-data/index.js +4 -0
  563. package/dist/locale-data/tr/address-tr.json +1 -0
  564. package/dist/locale-data/tr/address.d.ts +23 -0
  565. package/dist/locale-data/tr/address.js +52 -0
  566. package/dist/locale-data/tr/holidays.d.ts +31 -0
  567. package/dist/locale-data/tr/holidays.js +81 -0
  568. package/dist/locale-data/tr/iban.d.ts +21 -0
  569. package/dist/locale-data/tr/iban.js +45 -0
  570. package/dist/locale-data/tr/id.d.ts +36 -0
  571. package/dist/locale-data/tr/id.js +120 -0
  572. package/dist/locale-data/tr/index.d.ts +12 -0
  573. package/dist/locale-data/tr/index.js +33 -0
  574. package/dist/locale-data/tr/kdv.d.ts +91 -0
  575. package/dist/locale-data/tr/kdv.js +222 -0
  576. package/dist/locales/en.d.ts +2102 -0
  577. package/dist/locales/en.js +2088 -0
  578. package/dist/locales/tr.d.ts +2086 -0
  579. package/dist/locales/tr.js +2087 -0
  580. package/dist/media/focal-point.d.ts +42 -0
  581. package/dist/media/focal-point.js +96 -0
  582. package/dist/media/gallery-layout.d.ts +19 -0
  583. package/dist/media/gallery-layout.js +61 -0
  584. package/dist/media/gallery.d.ts +64 -0
  585. package/dist/media/gallery.js +140 -0
  586. package/dist/media/image-cropper.d.ts +86 -0
  587. package/dist/media/image-cropper.js +170 -0
  588. package/dist/media/image-field.d.ts +115 -0
  589. package/dist/media/image-field.js +212 -0
  590. package/dist/media/index.d.ts +19 -0
  591. package/dist/media/index.js +23 -0
  592. package/dist/media/lightbox.d.ts +82 -0
  593. package/dist/media/lightbox.js +171 -0
  594. package/dist/media/link-preview.d.ts +97 -0
  595. package/dist/media/link-preview.js +177 -0
  596. package/dist/media/media-library.d.ts +244 -0
  597. package/dist/media/media-library.js +776 -0
  598. package/dist/media/media-picker.d.ts +96 -0
  599. package/dist/media/media-picker.js +209 -0
  600. package/dist/media/media-provider.d.ts +23 -0
  601. package/dist/media/media-provider.js +44 -0
  602. package/dist/media/media-utils.d.ts +39 -0
  603. package/dist/media/media-utils.js +145 -0
  604. package/dist/media/memory-adapter.d.ts +22 -0
  605. package/dist/media/memory-adapter.js +162 -0
  606. package/dist/media/rest-adapter.d.ts +90 -0
  607. package/dist/media/rest-adapter.js +208 -0
  608. package/dist/media/serp.d.ts +62 -0
  609. package/dist/media/serp.js +108 -0
  610. package/dist/media/test-fixtures.d.ts +3 -0
  611. package/dist/media/test-fixtures.js +37 -0
  612. package/dist/media/types.d.ts +183 -0
  613. package/dist/media/types.js +3 -0
  614. package/dist/media/use-pan-zoom.d.ts +51 -0
  615. package/dist/media/use-pan-zoom.js +156 -0
  616. package/dist/media/use-upload-queue.d.ts +64 -0
  617. package/dist/media/use-upload-queue.js +115 -0
  618. package/dist/media/video-player.d.ts +135 -0
  619. package/dist/media/video-player.js +319 -0
  620. package/dist/motion/core.d.ts +32 -0
  621. package/dist/motion/core.js +77 -0
  622. package/dist/motion/count-up.d.ts +29 -0
  623. package/dist/motion/count-up.js +92 -0
  624. package/dist/motion/index.d.ts +11 -0
  625. package/dist/motion/index.js +13 -0
  626. package/dist/motion/motion-scope.d.ts +17 -0
  627. package/dist/motion/motion-scope.js +16 -0
  628. package/dist/motion/page-transition.d.ts +33 -0
  629. package/dist/motion/page-transition.js +61 -0
  630. package/dist/motion/parallax.d.ts +37 -0
  631. package/dist/motion/parallax.js +90 -0
  632. package/dist/motion/pointer.d.ts +38 -0
  633. package/dist/motion/pointer.js +117 -0
  634. package/dist/motion/reveal.d.ts +72 -0
  635. package/dist/motion/reveal.js +133 -0
  636. package/dist/motion/scroll-shrink.d.ts +18 -0
  637. package/dist/motion/scroll-shrink.js +47 -0
  638. package/dist/motion/skeleton-swap.d.ts +17 -0
  639. package/dist/motion/skeleton-swap.js +43 -0
  640. package/dist/motion/text-reveal.d.ts +30 -0
  641. package/dist/motion/text-reveal.js +29 -0
  642. package/dist/motion/ticker.d.ts +35 -0
  643. package/dist/motion/ticker.js +16 -0
  644. package/dist/next/index.d.ts +42 -0
  645. package/dist/next/index.js +36 -0
  646. package/dist/render/block-renderer.d.ts +56 -0
  647. package/dist/render/block-renderer.js +137 -0
  648. package/dist/render/index.d.ts +6 -0
  649. package/dist/render/index.js +7 -0
  650. package/dist/render/prepare.d.ts +61 -0
  651. package/dist/render/prepare.js +119 -0
  652. package/dist/scheduler/core/duration.d.ts +83 -0
  653. package/dist/scheduler/core/duration.js +174 -0
  654. package/dist/scheduler/core/gantt.d.ts +63 -0
  655. package/dist/scheduler/core/gantt.js +226 -0
  656. package/dist/scheduler/core/index.d.ts +6 -0
  657. package/dist/scheduler/core/index.js +7 -0
  658. package/dist/scheduler/core/layout.d.ts +97 -0
  659. package/dist/scheduler/core/layout.js +249 -0
  660. package/dist/scheduler/core/time-scale.d.ts +89 -0
  661. package/dist/scheduler/core/time-scale.js +173 -0
  662. package/dist/scheduler/gantt.d.ts +125 -0
  663. package/dist/scheduler/gantt.js +532 -0
  664. package/dist/scheduler/index.d.ts +6 -0
  665. package/dist/scheduler/index.js +7 -0
  666. package/dist/scheduler/resource-calendar.d.ts +218 -0
  667. package/dist/scheduler/resource-calendar.js +661 -0
  668. package/dist/scheduler/scheduler.d.ts +168 -0
  669. package/dist/scheduler/scheduler.js +768 -0
  670. package/dist/scheduler/shared.d.ts +63 -0
  671. package/dist/scheduler/shared.js +145 -0
  672. package/dist/scheduler/time-tracker.d.ts +138 -0
  673. package/dist/scheduler/time-tracker.js +403 -0
  674. package/dist/sortable/core.d.ts +67 -0
  675. package/dist/sortable/core.js +167 -0
  676. package/dist/sortable/index.d.ts +8 -0
  677. package/dist/sortable/index.js +10 -0
  678. package/dist/sortable/kanban-core.d.ts +70 -0
  679. package/dist/sortable/kanban-core.js +67 -0
  680. package/dist/sortable/kanban.d.ts +147 -0
  681. package/dist/sortable/kanban.js +472 -0
  682. package/dist/sortable/sortable-list.d.ts +71 -0
  683. package/dist/sortable/sortable-list.js +76 -0
  684. package/dist/sortable/sortable-tree.d.ts +105 -0
  685. package/dist/sortable/sortable-tree.js +462 -0
  686. package/dist/sortable/sortable.d.ts +188 -0
  687. package/dist/sortable/sortable.js +485 -0
  688. package/dist/sortable/use-pointer-drag.d.ts +75 -0
  689. package/dist/sortable/use-pointer-drag.js +173 -0
  690. package/dist/sortable/use-time-scale.d.ts +11 -0
  691. package/dist/sortable/use-time-scale.js +19 -0
  692. package/dist/styles/base.css +51 -0
  693. package/dist/styles/blocks.css +949 -0
  694. package/dist/styles/calendar.css +642 -0
  695. package/dist/styles/charts.css +264 -0
  696. package/dist/styles/data.css +474 -0
  697. package/dist/styles/editors.css +1022 -0
  698. package/dist/styles/forms.css +406 -0
  699. package/dist/styles/media.css +515 -0
  700. package/dist/styles/motion.css +389 -0
  701. package/dist/styles/navigation.css +293 -0
  702. package/dist/styles/overlays.css +244 -0
  703. package/dist/styles.css +743 -0
  704. package/package.json +160 -4
@@ -0,0 +1,890 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /**
4
+ * Hierarchy chart: a pannable, zoomable tidy-tree diagram (org chart, partner network, site
5
+ * structure). Collapsible subtrees, search highlight, focus-to-node, drag-to-reparent with a
6
+ * "Change parent…" alternative, viewport culling for large trees, SVG / PNG export and a list
7
+ * view. The accessible model is the Tree view pattern, shared by both views.
8
+ */
9
+ import * as React from "react";
10
+ import { hierarchy as d3hierarchy, tree as d3tree } from "d3-hierarchy";
11
+ import { ArrowLeftRight, ArrowUpDown, ChevronUp, ChevronsDownUp, ChevronsUpDown, Crosshair, Ellipsis, GitBranch, Maximize, Minus, Plus } from "lucide-react";
12
+ import { cn } from "../lib/cn.js";
13
+ import { useLabels } from "../lib/labels.js";
14
+ import { useLocale } from "../lib/locale.js";
15
+ import { matchText } from "../lib/text.js";
16
+ import { useReducedMotion } from "../lib/use-reduced-motion.js";
17
+ import { useControllableState, useLatest } from "../lib/use-controllable-state.js";
18
+ import { Avatar } from "./avatar.js";
19
+ import { IconButton } from "./button.js";
20
+ import { Skeleton } from "./skeleton.js";
21
+ import { toast } from "./toast.js";
22
+ import { TreeView } from "./tree-view.js";
23
+ import { Dialog, DialogBody, DialogContent, DialogHeader } from "./dialog.js";
24
+ import { Command, CommandEmpty, CommandInput, CommandItem, CommandList } from "./command.js";
25
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "./dropdown-menu.js";
26
+ // ---------------------------------------------------------------------------------------------
27
+ // Labels
28
+ // ---------------------------------------------------------------------------------------------
29
+ export const hierarchyChartLabels = {
30
+ canvas: "Chart canvas",
31
+ instructions: "Arrow keys pan the canvas, plus and minus zoom, 0 fits the chart. In the tree, arrow keys move between nodes, Shift+F10 opens node actions.",
32
+ zoomIn: "Zoom in",
33
+ zoomOut: "Zoom out",
34
+ fit: "Fit to view",
35
+ zoomLevel: "Zoom {percent}",
36
+ expandAll: "Expand all",
37
+ collapseAll: "Collapse all",
38
+ vertical: "Top to bottom",
39
+ horizontal: "Left to right",
40
+ nodeMenu: "Actions for {node}",
41
+ expand: "Expand",
42
+ collapse: "Collapse",
43
+ center: "Center in view",
44
+ changeParent: "Change parent…",
45
+ changeParentTitle: "Move {node} under…",
46
+ changeParentDescription: "Pick the new parent. Its whole team moves with it.",
47
+ searchNodes: "Search",
48
+ noMatches: "No matches",
49
+ hiddenCount: "{count, plural, one {# hidden below} other {# hidden below}}",
50
+ reparented: "{node} moved under {parent}.",
51
+ reparentFailed: "Couldn't move {node}",
52
+ cycle: "Can't move a node under its own team",
53
+ retry: "Retry",
54
+ loading: "Loading chart",
55
+ empty: "No nodes to show",
56
+ };
57
+ const PRESETS = { compact: { width: 184, height: 56 }, card: { width: 236, height: 84 } };
58
+ const ROOT = "\u0000root";
59
+ const clamp = (v, a, b) => Math.min(b, Math.max(a, v));
60
+ const MIN_K = 0.15;
61
+ const MAX_K = 2;
62
+ const defaultLabel = (n) => {
63
+ const o = n;
64
+ const v = o.name ?? o.label ?? o.title;
65
+ return typeof v === "string" ? v : String(o.id);
66
+ };
67
+ // ---------------------------------------------------------------------------------------------
68
+ // Layout (pure)
69
+ // ---------------------------------------------------------------------------------------------
70
+ /**
71
+ * Tidy-tree layout of a flat `{ id, parentId }` list. Returns top-left node boxes in content
72
+ * coordinates (origin at 0,0) and the content size. Collapsed nodes hide their subtree.
73
+ */
74
+ export function layoutHierarchy(nodes, opts = {}) {
75
+ const { collapsed, orientation = "vertical", size = PRESETS.card, gap = { x: 28, y: 56 }, dir = "ltr" } = opts;
76
+ const byId = new Map(nodes.map((n) => [n.id, n]));
77
+ const kids = new Map();
78
+ for (const n of nodes) {
79
+ const p = n.parentId !== null && byId.has(n.parentId) ? n.parentId : ROOT;
80
+ const list = kids.get(p);
81
+ if (list)
82
+ list.push(n);
83
+ else
84
+ kids.set(p, [n]);
85
+ }
86
+ if (!kids.get(ROOT)?.length)
87
+ return { nodes: [], width: 0, height: 0 };
88
+ const root = d3hierarchy({ id: ROOT }, (d) => (d.id !== ROOT && collapsed?.has(d.id) ? null : (kids.get(d.id) ?? []).map((c) => ({ id: c.id, data: c }))));
89
+ const vertical = orientation === "vertical";
90
+ const layout = d3tree()
91
+ .nodeSize(vertical ? [size.width + gap.x, size.height + gap.y] : [size.height + gap.x * 0.6, size.width + gap.y])
92
+ .separation((a, b) => (a.parent === b.parent ? 1 : 1.2));
93
+ const laid = layout(root);
94
+ const out = [];
95
+ let minX = Infinity;
96
+ let minY = Infinity;
97
+ let maxX = -Infinity;
98
+ let maxY = -Infinity;
99
+ laid.each((p) => {
100
+ if (p.data.id === ROOT)
101
+ return;
102
+ const depth = p.depth - 1;
103
+ let x;
104
+ let y;
105
+ if (vertical) {
106
+ x = p.x - size.width / 2;
107
+ y = depth * (size.height + gap.y);
108
+ }
109
+ else {
110
+ x = depth * (size.width + gap.y);
111
+ y = p.x - size.height / 2;
112
+ }
113
+ // RTL: the root sits on the inline-start (right) side and siblings run right to left.
114
+ if (dir === "rtl")
115
+ x = -x - size.width;
116
+ const siblings = p.parent?.children ?? [p];
117
+ out.push({
118
+ id: p.data.id,
119
+ data: p.data.data,
120
+ depth,
121
+ x,
122
+ y,
123
+ parentId: p.parent && p.parent.data.id !== ROOT ? p.parent.data.id : null,
124
+ childCount: kids.get(p.data.id)?.length ?? 0,
125
+ posinset: siblings.indexOf(p) + 1,
126
+ setsize: siblings.length,
127
+ });
128
+ minX = Math.min(minX, x);
129
+ minY = Math.min(minY, y);
130
+ maxX = Math.max(maxX, x + size.width);
131
+ maxY = Math.max(maxY, y + size.height);
132
+ });
133
+ for (const n of out) {
134
+ n.x -= minX;
135
+ n.y -= minY;
136
+ }
137
+ return { nodes: out, width: maxX - minX, height: maxY - minY };
138
+ }
139
+ /** Rounded orthogonal edge between a parent box and a child box. */
140
+ function edgePath(p, c, s, vertical, rtl) {
141
+ if (vertical) {
142
+ const px = p.x + s.width / 2;
143
+ const py = p.y + s.height;
144
+ const cx = c.x + s.width / 2;
145
+ const cy = c.y;
146
+ const my = (py + cy) / 2;
147
+ if (Math.abs(cx - px) < 1)
148
+ return `M${px},${py}V${cy}`;
149
+ const r = Math.min(10, Math.abs(cx - px) / 2, (cy - py) / 4);
150
+ const sx = cx > px ? 1 : -1;
151
+ return `M${px},${py}V${my - r}Q${px},${my} ${px + sx * r},${my}H${cx - sx * r}Q${cx},${my} ${cx},${my + r}V${cy}`;
152
+ }
153
+ const px = rtl ? p.x : p.x + s.width;
154
+ const py = p.y + s.height / 2;
155
+ const cx = rtl ? c.x + s.width : c.x;
156
+ const cy = c.y + s.height / 2;
157
+ const mx = (px + cx) / 2;
158
+ if (Math.abs(cy - py) < 1)
159
+ return `M${px},${py}H${cx}`;
160
+ const r = Math.min(10, Math.abs(cy - py) / 2, Math.abs(cx - px) / 4);
161
+ const sy = cy > py ? 1 : -1;
162
+ const sx = cx > px ? 1 : -1;
163
+ return `M${px},${py}H${mx - sx * r}Q${mx},${py} ${mx},${py + sy * r}V${cy - sy * r}Q${mx},${cy} ${mx + sx * r},${cy}H${cx}`;
164
+ }
165
+ // ---------------------------------------------------------------------------------------------
166
+ // HierarchyChart
167
+ // ---------------------------------------------------------------------------------------------
168
+ function HierarchyChartInner(props, ref) {
169
+ const { nodes: nodesProp, renderNode, getLabel = defaultLabel, getDescription, isPlaceholder, orientation: orientationProp, defaultOrientation = "vertical", onOrientationChange, nodeSize = "card", gap: gapProp, collapsed: collapsedProp, defaultCollapsed, onCollapsedChange, selected: selectedProp, defaultSelected = null, onSelectedChange, focusId, highlight, onReparent, canReparent, nodeMenu, view = "chart", controls = true, height = "32rem", loading, empty, labels, className, "aria-label": ariaLabel, } = props;
170
+ const t = useLabels("hierarchyChart", hierarchyChartLabels, labels);
171
+ const { dir, locale, format } = useLocale();
172
+ const reducedMotion = useReducedMotion();
173
+ // Stable by value: inline `nodeSize` / `gap` objects must not re-run the layout every render.
174
+ const sizeRaw = typeof nodeSize === "string" ? PRESETS[nodeSize] : nodeSize;
175
+ const size = React.useMemo(() => ({ width: sizeRaw.width, height: sizeRaw.height }), [sizeRaw.width, sizeRaw.height]);
176
+ const gap = React.useMemo(() => ({ x: gapProp?.x ?? 28, y: gapProp?.y ?? 56 }), [gapProp?.x, gapProp?.y]);
177
+ const instructionsId = React.useId();
178
+ const [orientation, setOrientation] = useControllableState({ value: orientationProp, defaultValue: defaultOrientation, onChange: onOrientationChange, name: "HierarchyChart" });
179
+ const vertical = orientation === "vertical";
180
+ // Optimistic reparenting.
181
+ const [overrides, setOverrides] = React.useState(() => new Map());
182
+ const nodes = React.useMemo(() => (overrides.size ? nodesProp.map((n) => (overrides.has(n.id) ? { ...n, parentId: overrides.get(n.id) } : n)) : nodesProp), [nodesProp, overrides]);
183
+ const byId = React.useMemo(() => new Map(nodes.map((n) => [n.id, n])), [nodes]);
184
+ const childrenOf = React.useMemo(() => {
185
+ const m = new Map();
186
+ for (const n of nodes) {
187
+ if (n.parentId === null || !byId.has(n.parentId))
188
+ continue;
189
+ const list = m.get(n.parentId);
190
+ if (list)
191
+ list.push(n.id);
192
+ else
193
+ m.set(n.parentId, [n.id]);
194
+ }
195
+ return m;
196
+ }, [nodes, byId]);
197
+ const descendants = React.useMemo(() => {
198
+ const memo = new Map();
199
+ const count = (id) => {
200
+ const hit = memo.get(id);
201
+ if (hit !== undefined)
202
+ return hit;
203
+ const c = (childrenOf.get(id) ?? []).reduce((a, k) => a + 1 + count(k), 0);
204
+ memo.set(id, c);
205
+ return c;
206
+ };
207
+ for (const n of nodes)
208
+ count(n.id);
209
+ return memo;
210
+ }, [nodes, childrenOf]);
211
+ const depthOf = React.useCallback((id) => {
212
+ let d = 0;
213
+ let cur = byId.get(id);
214
+ const seen = new Set();
215
+ while (cur && cur.parentId !== null && byId.has(cur.parentId) && !seen.has(cur.id)) {
216
+ seen.add(cur.id);
217
+ d++;
218
+ cur = byId.get(cur.parentId);
219
+ }
220
+ return d;
221
+ }, [byId]);
222
+ const ancestorsOf = React.useCallback((id) => {
223
+ const out = [];
224
+ let cur = byId.get(id);
225
+ while (cur && cur.parentId !== null && byId.has(cur.parentId) && !out.includes(cur.parentId)) {
226
+ out.push(cur.parentId);
227
+ cur = byId.get(cur.parentId);
228
+ }
229
+ return out;
230
+ }, [byId]);
231
+ const [collapsed, setCollapsed] = useControllableState({
232
+ value: collapsedProp,
233
+ defaultValue: () => {
234
+ const dc = defaultCollapsed ?? (nodesProp.length > 500 ? { depth: 2 } : []);
235
+ if (Array.isArray(dc))
236
+ return dc;
237
+ const ids = new Set(nodesProp.map((n) => n.id));
238
+ const parents = new Set(nodesProp.filter((n) => n.parentId !== null && ids.has(n.parentId)).map((n) => n.parentId));
239
+ const map = new Map(nodesProp.map((n) => [n.id, n]));
240
+ const depth = (n) => {
241
+ let d = 0;
242
+ let c = n;
243
+ while (c && c.parentId !== null && map.has(c.parentId) && d < 1000) {
244
+ d++;
245
+ c = map.get(c.parentId);
246
+ }
247
+ return d;
248
+ };
249
+ return nodesProp.filter((n) => parents.has(n.id) && depth(n) >= dc.depth).map((n) => n.id);
250
+ },
251
+ onChange: onCollapsedChange,
252
+ name: "HierarchyChart",
253
+ });
254
+ const matches = React.useMemo(() => {
255
+ const q = highlight?.trim();
256
+ if (!q)
257
+ return new Set();
258
+ return new Set(nodes.filter((n) => matchText(`${getLabel(n)} ${getDescription?.(n) ?? ""}`, q, locale)).map((n) => n.id));
259
+ }, [highlight, nodes, getLabel, getDescription, locale]);
260
+ const collapsedSet = React.useMemo(() => {
261
+ const s = new Set(collapsed);
262
+ for (const id of matches)
263
+ for (const a of ancestorsOf(id))
264
+ s.delete(a);
265
+ return s;
266
+ }, [collapsed, matches, ancestorsOf]);
267
+ const [selected, setSelected] = useControllableState({ value: selectedProp, defaultValue: defaultSelected, onChange: onSelectedChange, name: "HierarchyChart" });
268
+ const layout = React.useMemo(() => layoutHierarchy(nodes, { collapsed: collapsedSet, orientation, size, gap, dir }), [nodes, collapsedSet, orientation, size, gap, dir]);
269
+ const laidById = React.useMemo(() => new Map(layout.nodes.map((n) => [n.id, n])), [layout]);
270
+ // Depth-first order of visible nodes (DOM and keyboard order).
271
+ const order = React.useMemo(() => {
272
+ const kids = new Map();
273
+ for (const n of layout.nodes) {
274
+ const list = kids.get(n.parentId);
275
+ if (list)
276
+ list.push(n);
277
+ else
278
+ kids.set(n.parentId, [n]);
279
+ }
280
+ const out = [];
281
+ const walk = (pid) => {
282
+ for (const n of (kids.get(pid) ?? []).sort((a, b) => a.posinset - b.posinset)) {
283
+ out.push(n);
284
+ walk(n.id);
285
+ }
286
+ };
287
+ walk(null);
288
+ return out;
289
+ }, [layout]);
290
+ // ------------------------------------------------------------------ viewport / transform
291
+ const viewportRef = React.useRef(null);
292
+ const [vp, setVp] = React.useState({ w: 0, h: 0 });
293
+ const [tf, setTf] = React.useState({ x: 24, y: 24, k: 1 });
294
+ const [animate, setAnimate] = React.useState(false);
295
+ const fitted = React.useRef(false);
296
+ /** The person panned, zoomed or toggled: stop auto-fitting. */
297
+ const touched = React.useRef(false);
298
+ const pendingCenter = React.useRef(null);
299
+ React.useEffect(() => {
300
+ const el = viewportRef.current;
301
+ if (!el || typeof ResizeObserver === "undefined")
302
+ return;
303
+ const ro = new ResizeObserver(([entry]) => {
304
+ if (!entry)
305
+ return;
306
+ const r = entry.contentRect;
307
+ setVp((p) => (p.w === r.width && p.h === r.height ? p : { w: r.width, h: r.height }));
308
+ });
309
+ ro.observe(el);
310
+ return () => ro.disconnect();
311
+ }, [view]);
312
+ const apply = React.useCallback((next, anim = false) => {
313
+ setAnimate(anim && !reducedMotion);
314
+ setTf(next);
315
+ }, [reducedMotion]);
316
+ const fitTransform = React.useCallback(() => {
317
+ if (!vp.w || !vp.h || !layout.width)
318
+ return null;
319
+ const pad = 32;
320
+ // The floating controls sit bottom-end: keep the fitted chart clear of them.
321
+ const bottom = controls ? 64 : pad;
322
+ const k = clamp(Math.min((vp.w - pad * 2) / layout.width, (vp.h - pad - bottom) / layout.height, 1), MIN_K, MAX_K);
323
+ const y = (vp.h - bottom + pad - layout.height * k) / 2;
324
+ return { k, x: (vp.w - layout.width * k) / 2, y: vertical ? Math.max(pad, y) : y };
325
+ }, [vp, layout, vertical, controls]);
326
+ const fit = React.useCallback((anim = true) => {
327
+ const f = fitTransform();
328
+ if (f)
329
+ apply(f, anim);
330
+ }, [fitTransform, apply]);
331
+ const centerOn = React.useCallback((id, anim = true, minK = 0.85) => {
332
+ const n = laidById.get(id);
333
+ if (!n || !vp.w)
334
+ return false;
335
+ touched.current = true;
336
+ apply((p) => {
337
+ const k = Math.max(p.k, minK);
338
+ return { k, x: vp.w / 2 - (n.x + size.width / 2) * k, y: vp.h / 2 - (n.y + size.height / 2) * k };
339
+ }, anim);
340
+ return true;
341
+ }, [laidById, vp, size, apply]);
342
+ const ensureVisible = React.useCallback((id) => {
343
+ const n = laidById.get(id);
344
+ if (!n || !vp.w)
345
+ return;
346
+ const m = 24;
347
+ const sx = n.x * tf.k + tf.x;
348
+ const sy = n.y * tf.k + tf.y;
349
+ const sw = size.width * tf.k;
350
+ const sh = size.height * tf.k;
351
+ let dx = 0;
352
+ let dy = 0;
353
+ if (sx < m)
354
+ dx = m - sx;
355
+ else if (sx + sw > vp.w - m)
356
+ dx = vp.w - m - sx - sw;
357
+ if (sy < m)
358
+ dy = m - sy;
359
+ else if (sy + sh > vp.h - m)
360
+ dy = vp.h - m - sy - sh;
361
+ if (dx || dy)
362
+ apply((p) => ({ ...p, x: p.x + dx, y: p.y + dy }), true);
363
+ }, [laidById, vp, tf, size, apply]);
364
+ // Initial view: fit when it stays readable, otherwise start at the root at 60 %.
365
+ const initialView = React.useCallback(() => {
366
+ const f = fitTransform();
367
+ if (!f)
368
+ return;
369
+ if (f.k >= 0.6)
370
+ return apply(f, false);
371
+ const root = layout.nodes.find((n) => n.depth === 0);
372
+ if (!root)
373
+ return apply(f, false);
374
+ const k = 0.6;
375
+ const pad = 32;
376
+ // Centre the rows that fit vertically instead of pinning a short tree to the top edge.
377
+ const bottom = controls ? 64 : pad;
378
+ if (vertical)
379
+ apply({ k, x: vp.w / 2 - (root.x + size.width / 2) * k, y: Math.max(pad, (vp.h - bottom + pad - layout.height * k) / 2) }, false);
380
+ else
381
+ apply({ k, x: dir === "rtl" ? vp.w - pad - (root.x + size.width) * k : pad - root.x * k, y: vp.h / 2 - (root.y + size.height / 2) * k }, false);
382
+ }, [fitTransform, apply, layout, vertical, vp, size, dir, controls]);
383
+ // Re-run the initial view while the person hasn't moved the canvas (the container may resize
384
+ // during hydration); deferred centering after expand.
385
+ React.useLayoutEffect(() => {
386
+ if ((!fitted.current || !touched.current) && vp.w && layout.width) {
387
+ fitted.current = true;
388
+ initialView();
389
+ }
390
+ if (pendingCenter.current && centerOn(pendingCenter.current, true))
391
+ pendingCenter.current = null;
392
+ }, [vp, layout, initialView, centerOn]);
393
+ const zoomBy = React.useCallback((f, at) => {
394
+ touched.current = true;
395
+ apply((p) => {
396
+ const k = clamp(p.k * f, MIN_K, MAX_K);
397
+ const cx = at?.x ?? vp.w / 2;
398
+ const cy = at?.y ?? vp.h / 2;
399
+ return { k, x: cx - (cx - p.x) * (k / p.k), y: cy - (cy - p.y) * (k / p.k) };
400
+ }, !at);
401
+ }, [apply, vp]);
402
+ const focusNodeImpl = React.useCallback((id) => {
403
+ if (!byId.has(id))
404
+ return;
405
+ const anc = ancestorsOf(id);
406
+ const needs = anc.some((a) => collapsedSet.has(a));
407
+ if (needs)
408
+ setCollapsed((prev) => prev.filter((x) => !anc.includes(x)));
409
+ setFocusedId(id);
410
+ if (needs || !centerOn(id))
411
+ pendingCenter.current = id;
412
+ },
413
+ // eslint-disable-next-line react-hooks/exhaustive-deps
414
+ [byId, ancestorsOf, collapsedSet, setCollapsed, centerOn]);
415
+ React.useEffect(() => {
416
+ if (focusId)
417
+ focusNodeImpl(focusId);
418
+ // eslint-disable-next-line react-hooks/exhaustive-deps
419
+ }, [focusId]);
420
+ // Wheel: pan, Ctrl/⌘ + wheel (and trackpad pinch) zooms at the cursor. Non-passive to keep the page still.
421
+ const wheelLatest = useLatest({ zoomBy, apply });
422
+ React.useEffect(() => {
423
+ const el = viewportRef.current;
424
+ if (!el)
425
+ return;
426
+ const onWheel = (e) => {
427
+ e.preventDefault();
428
+ touched.current = true;
429
+ const L = wheelLatest.current;
430
+ if (e.ctrlKey || e.metaKey) {
431
+ const r = el.getBoundingClientRect();
432
+ L.zoomBy(Math.exp(-e.deltaY * 0.0045), { x: e.clientX - r.left, y: e.clientY - r.top });
433
+ }
434
+ else {
435
+ const dx = e.shiftKey ? e.deltaY : e.deltaX;
436
+ const dy = e.shiftKey ? 0 : e.deltaY;
437
+ L.apply((p) => ({ ...p, x: p.x - dx, y: p.y - dy }));
438
+ }
439
+ };
440
+ el.addEventListener("wheel", onWheel, { passive: false });
441
+ return () => el.removeEventListener("wheel", onWheel);
442
+ }, [wheelLatest, view]);
443
+ // ------------------------------------------------------------------ focus, selection, collapse
444
+ const [focusedId, setFocusedId] = React.useState(null);
445
+ const nodeRefs = React.useRef(new Map());
446
+ const tabId = focusedId && laidById.has(focusedId) ? focusedId : (selected && laidById.has(selected) ? selected : (order[0]?.id ?? null));
447
+ const focusNodeEl = (id) => {
448
+ if (!id)
449
+ return;
450
+ setFocusedId(id);
451
+ ensureVisible(id);
452
+ requestAnimationFrame(() => nodeRefs.current.get(id)?.focus({ preventScroll: true }));
453
+ };
454
+ const toggle = React.useCallback((id, open) => {
455
+ touched.current = true;
456
+ setCollapsed((prev) => {
457
+ const isClosed = prev.includes(id);
458
+ const wantOpen = open ?? isClosed;
459
+ return wantOpen ? prev.filter((x) => x !== id) : isClosed ? prev : [...prev, id];
460
+ });
461
+ }, [setCollapsed]);
462
+ const expandAll = React.useCallback(() => setCollapsed([]), [setCollapsed]);
463
+ const collapseAll = React.useCallback(() => {
464
+ const roots = nodes.filter((n) => n.parentId === null || !byId.has(n.parentId)).map((n) => n.id);
465
+ setCollapsed(roots.filter((r) => childrenOf.has(r)));
466
+ }, [nodes, byId, childrenOf, setCollapsed]);
467
+ // ------------------------------------------------------------------ reparent
468
+ const [status, setStatus] = React.useState("");
469
+ const announce = (msg) => {
470
+ setStatus("");
471
+ requestAnimationFrame(() => setStatus(msg));
472
+ };
473
+ const isInSubtree = React.useCallback((root, id) => {
474
+ let cur = byId.get(id);
475
+ const seen = new Set();
476
+ while (cur && !seen.has(cur.id)) {
477
+ if (cur.id === root)
478
+ return true;
479
+ seen.add(cur.id);
480
+ cur = cur.parentId !== null ? byId.get(cur.parentId) : undefined;
481
+ }
482
+ return false;
483
+ }, [byId]);
484
+ const checkReparent = React.useCallback((id, newParentId) => {
485
+ if (id === newParentId || isInSubtree(id, newParentId))
486
+ return t("cycle");
487
+ const oldParentId = byId.get(id)?.parentId ?? null;
488
+ return canReparent ? canReparent({ id, newParentId, oldParentId }) : true;
489
+ }, [isInSubtree, byId, canReparent, t]);
490
+ const reparent = React.useCallback(async (id, newParentId) => {
491
+ const me = byId.get(id);
492
+ if (!me || !onReparent || me.parentId === newParentId)
493
+ return;
494
+ const ok = checkReparent(id, newParentId);
495
+ if (ok !== true) {
496
+ announce(ok);
497
+ return;
498
+ }
499
+ const ev = { id, newParentId, oldParentId: me.parentId };
500
+ const name = getLabel(me);
501
+ const parentName = byId.get(newParentId) ? getLabel(byId.get(newParentId)) : newParentId;
502
+ setCollapsed((prev) => prev.filter((x) => x !== newParentId));
503
+ announce(t("reparented", { node: name, parent: parentName }));
504
+ pendingCenter.current = id;
505
+ const r = onReparent(ev);
506
+ if (r && typeof r.then === "function") {
507
+ setOverrides((m) => new Map(m).set(id, newParentId));
508
+ try {
509
+ await r;
510
+ }
511
+ catch {
512
+ toast.danger(t("reparentFailed", { node: name }), { action: { label: t("retry"), onClick: () => void reparentRef.current(id, newParentId) } });
513
+ }
514
+ finally {
515
+ setOverrides((m) => {
516
+ const next = new Map(m);
517
+ next.delete(id);
518
+ return next;
519
+ });
520
+ }
521
+ }
522
+ },
523
+ // eslint-disable-next-line react-hooks/exhaustive-deps
524
+ [byId, onReparent, checkReparent, getLabel, setCollapsed, t]);
525
+ const reparentRef = React.useRef(reparent);
526
+ reparentRef.current = reparent;
527
+ const [drag, setDrag] = React.useState(null);
528
+ const gesture = React.useRef(null);
529
+ const suppressClick = React.useRef(false);
530
+ const [panning, setPanning] = React.useState(false);
531
+ const onPointerDown = (e) => {
532
+ if (e.button !== 0)
533
+ return;
534
+ const target = e.target;
535
+ if (target.closest("[data-hierarchy-ui]"))
536
+ return;
537
+ const nodeEl = target.closest("[data-node-id]");
538
+ const kind = nodeEl && onReparent ? "node" : "pan";
539
+ gesture.current = { kind, id: nodeEl?.dataset.nodeId, sx: e.clientX, sy: e.clientY, ox: tf.x, oy: tf.y, moved: false, pointerId: e.pointerId };
540
+ suppressClick.current = false;
541
+ };
542
+ const onPointerMove = (e) => {
543
+ const g = gesture.current;
544
+ if (!g || g.pointerId !== e.pointerId)
545
+ return;
546
+ const dx = e.clientX - g.sx;
547
+ const dy = e.clientY - g.sy;
548
+ if (!g.moved && Math.hypot(dx, dy) < 5)
549
+ return;
550
+ if (!g.moved) {
551
+ g.moved = true;
552
+ suppressClick.current = true;
553
+ viewportRef.current?.setPointerCapture?.(e.pointerId);
554
+ if (typeof document !== "undefined")
555
+ document.documentElement.setAttribute("data-dragging", "");
556
+ }
557
+ if (g.kind === "pan") {
558
+ touched.current = true;
559
+ setAnimate(false);
560
+ setPanning(true);
561
+ setTf((p) => ({ ...p, x: g.ox + dx, y: g.oy + dy }));
562
+ return;
563
+ }
564
+ const r = viewportRef.current.getBoundingClientRect();
565
+ const hit = typeof document !== "undefined" && document.elementsFromPoint ? document.elementsFromPoint(e.clientX, e.clientY) : [];
566
+ const over = hit.map((el) => el.closest?.("[data-node-id]")).find((el) => el && el.dataset.nodeId !== g.id && viewportRef.current?.contains(el));
567
+ const targetId = over?.dataset.nodeId ?? null;
568
+ const reason = targetId ? (byId.get(g.id)?.parentId === targetId ? null : checkReparent(g.id, targetId)) : null;
569
+ setDrag({ id: g.id, x: e.clientX - r.left, y: e.clientY - r.top, target: targetId, reason: reason === true ? null : reason });
570
+ };
571
+ const endGesture = (e, cancel = false) => {
572
+ const g = gesture.current;
573
+ if (!g || g.pointerId !== e.pointerId)
574
+ return;
575
+ gesture.current = null;
576
+ setPanning(false);
577
+ if (typeof document !== "undefined")
578
+ document.documentElement.removeAttribute("data-dragging");
579
+ if (viewportRef.current?.hasPointerCapture?.(e.pointerId))
580
+ viewportRef.current.releasePointerCapture(e.pointerId);
581
+ if (g.kind === "node" && drag) {
582
+ const d = drag;
583
+ setDrag(null);
584
+ if (!cancel && d.target && !d.reason)
585
+ void reparent(d.id, d.target);
586
+ else if (d.reason)
587
+ announce(d.reason);
588
+ }
589
+ };
590
+ // ------------------------------------------------------------------ keyboard
591
+ const onViewportKeyDown = (e) => {
592
+ if (e.key === "Escape" && drag) {
593
+ setDrag(null);
594
+ gesture.current = null;
595
+ return;
596
+ }
597
+ const onCanvas = e.target === e.currentTarget;
598
+ if ("+=-_0".includes(e.key) || (onCanvas && e.key.startsWith("Arrow")))
599
+ touched.current = true;
600
+ if (e.key === "+" || e.key === "=") {
601
+ e.preventDefault();
602
+ zoomBy(1.25);
603
+ return;
604
+ }
605
+ if (e.key === "-" || e.key === "_") {
606
+ e.preventDefault();
607
+ zoomBy(0.8);
608
+ return;
609
+ }
610
+ if (e.key === "0") {
611
+ e.preventDefault();
612
+ fit();
613
+ return;
614
+ }
615
+ if (onCanvas && e.key.startsWith("Arrow")) {
616
+ e.preventDefault();
617
+ const step = e.shiftKey ? 160 : 48;
618
+ const dx = e.key === "ArrowLeft" ? step : e.key === "ArrowRight" ? -step : 0;
619
+ const dy = e.key === "ArrowUp" ? step : e.key === "ArrowDown" ? -step : 0;
620
+ apply((p) => ({ ...p, x: p.x + dx, y: p.y + dy }), true);
621
+ }
622
+ };
623
+ const [menuFor, setMenuFor] = React.useState(null);
624
+ const [pickerFor, setPickerFor] = React.useState(null);
625
+ const onNodeKeyDown = (e, n) => {
626
+ if (e.target !== e.currentTarget)
627
+ return;
628
+ const i = order.findIndex((o) => o.id === n.id);
629
+ const hasKids = n.childCount > 0;
630
+ const open = hasKids && !collapsedSet.has(n.id);
631
+ const fwd = dir === "rtl" ? "ArrowLeft" : "ArrowRight";
632
+ const back = dir === "rtl" ? "ArrowRight" : "ArrowLeft";
633
+ if ((e.shiftKey && e.key === "F10") || e.key === "ContextMenu") {
634
+ e.preventDefault();
635
+ setMenuFor(n.id);
636
+ return;
637
+ }
638
+ switch (e.key) {
639
+ case "ArrowDown":
640
+ e.preventDefault();
641
+ focusNodeEl(order[i + 1]?.id);
642
+ return;
643
+ case "ArrowUp":
644
+ e.preventDefault();
645
+ focusNodeEl(order[i - 1]?.id);
646
+ return;
647
+ case "Home":
648
+ e.preventDefault();
649
+ focusNodeEl(order[0]?.id);
650
+ return;
651
+ case "End":
652
+ e.preventDefault();
653
+ focusNodeEl(order[order.length - 1]?.id);
654
+ return;
655
+ case fwd:
656
+ e.preventDefault();
657
+ if (hasKids && !open)
658
+ toggle(n.id, true);
659
+ else if (open)
660
+ focusNodeEl(order[i + 1]?.id);
661
+ return;
662
+ case back:
663
+ e.preventDefault();
664
+ if (open)
665
+ toggle(n.id, false);
666
+ else if (n.parentId)
667
+ focusNodeEl(n.parentId);
668
+ return;
669
+ case "Enter":
670
+ case " ":
671
+ e.preventDefault();
672
+ setSelected(n.id);
673
+ return;
674
+ case "*": {
675
+ e.preventDefault();
676
+ const sibs = order.filter((o) => o.parentId === n.parentId && o.childCount > 0).map((o) => o.id);
677
+ setCollapsed((prev) => prev.filter((x) => !sibs.includes(x)));
678
+ return;
679
+ }
680
+ }
681
+ if (e.key.length === 1 && /\S/.test(e.key) && !"+-=_0".includes(e.key) && !e.ctrlKey && !e.metaKey && !e.altKey) {
682
+ const ch = e.key.toLocaleLowerCase(locale);
683
+ const rest = [...order.slice(i + 1), ...order.slice(0, i + 1)];
684
+ const hit = rest.find((o) => getLabel(o.data).toLocaleLowerCase(locale).startsWith(ch));
685
+ if (hit) {
686
+ e.preventDefault();
687
+ focusNodeEl(hit.id);
688
+ }
689
+ }
690
+ };
691
+ // ------------------------------------------------------------------ export
692
+ const exportSVG = React.useCallback(() => {
693
+ const el = viewportRef.current;
694
+ const cs = el && typeof getComputedStyle !== "undefined" ? getComputedStyle(el) : null;
695
+ const v = (name, fb) => cs?.getPropertyValue(name).trim() || fb;
696
+ const surface = v("--surface-solid", v("--popover-nested", "#ffffff"));
697
+ const line = v("--line", "#d4d4d4");
698
+ const fg = v("--fg", "#111111");
699
+ const muted = v("--fg-muted", "#666666");
700
+ const scene = v("--scene", "#f5f5f5");
701
+ const font = cs?.fontFamily || "system-ui, sans-serif";
702
+ const pad = 24;
703
+ const esc = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
704
+ const w = layout.width + pad * 2;
705
+ const h = layout.height + pad * 2;
706
+ const edges = layout.nodes
707
+ .filter((n) => n.parentId && laidById.has(n.parentId))
708
+ .map((n) => `<path d="${edgePath(laidById.get(n.parentId), n, size, vertical, dir === "rtl")}" fill="none" stroke="${line}" stroke-width="1.5"/>`)
709
+ .join("");
710
+ const boxes = layout.nodes
711
+ .map((n) => {
712
+ const label = esc(getLabel(n.data));
713
+ const desc = getDescription?.(n.data);
714
+ const dashed = isPlaceholder?.(n.data) ? ' stroke-dasharray="4 3"' : "";
715
+ return `<g transform="translate(${n.x},${n.y})"><rect width="${size.width}" height="${size.height}" rx="10" fill="${surface}" stroke="${line}"${dashed}/><text x="14" y="${desc ? size.height / 2 - 4 : size.height / 2 + 5}" font-size="14" font-weight="600" fill="${fg}">${label}</text>${desc ? `<text x="14" y="${size.height / 2 + 14}" font-size="12" fill="${muted}">${esc(desc)}</text>` : ""}</g>`;
716
+ })
717
+ .join("");
718
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}" font-family="${esc(font)}"><rect width="100%" height="100%" fill="${scene}"/><g transform="translate(${pad},${pad})">${edges}${boxes}</g></svg>`;
719
+ }, [layout, laidById, size, vertical, dir, getLabel, getDescription, isPlaceholder]);
720
+ const exportPNG = React.useCallback((scale = 2) => new Promise((resolve, reject) => {
721
+ const svg = exportSVG();
722
+ const url = URL.createObjectURL(new Blob([svg], { type: "image/svg+xml" }));
723
+ const img = new Image();
724
+ img.onload = () => {
725
+ const canvas = document.createElement("canvas");
726
+ canvas.width = img.width * scale;
727
+ canvas.height = img.height * scale;
728
+ const g = canvas.getContext("2d");
729
+ if (!g)
730
+ return reject(new Error("Canvas unavailable"));
731
+ g.scale(scale, scale);
732
+ g.drawImage(img, 0, 0);
733
+ URL.revokeObjectURL(url);
734
+ canvas.toBlob((b) => (b ? resolve(b) : reject(new Error("PNG export failed"))), "image/png");
735
+ };
736
+ img.onerror = () => {
737
+ URL.revokeObjectURL(url);
738
+ reject(new Error("SVG could not be rendered"));
739
+ };
740
+ img.src = url;
741
+ }), [exportSVG]);
742
+ React.useImperativeHandle(ref, () => ({
743
+ fit: () => fit(),
744
+ zoomIn: () => zoomBy(1.25),
745
+ zoomOut: () => zoomBy(0.8),
746
+ focusNode: focusNodeImpl,
747
+ expandAll,
748
+ collapseAll,
749
+ toSVG: exportSVG,
750
+ toPNG: exportPNG,
751
+ }), [fit, zoomBy, focusNodeImpl, expandAll, collapseAll, exportSVG, exportPNG]);
752
+ // ------------------------------------------------------------------ render
753
+ const frameStyle = { height: typeof height === "number" ? `${height}px` : height };
754
+ if (view === "list") {
755
+ return (_jsx("div", { className: cn("vui-hierarchy-list w-full min-w-0 rounded-ui-lg border border-line bg-surface p-1.5", className), children: _jsx(TreeView, { "aria-label": ariaLabel, data: toTreeData(nodes, byId, getLabel, getDescription, descendants), expanded: nodes.filter((n) => childrenOf.has(n.id) && !collapsedSet.has(n.id)).map((n) => n.id), onExpandedChange: (open) => setCollapsed(nodes.filter((n) => childrenOf.has(n.id) && !open.includes(n.id)).map((n) => n.id)), selected: selected ? [selected] : [], onSelectedChange: (ids) => setSelected(ids[0] ?? null), filter: highlight, height: height }) }));
756
+ }
757
+ // Culling: only nodes in (or near) the visible rect, plus the focused / selected / dragged one.
758
+ const culled = vp.w > 0 && layout.nodes.length > 150;
759
+ const margin = 240 / tf.k;
760
+ const rect = { x0: -tf.x / tf.k - margin, y0: -tf.y / tf.k - margin, x1: (vp.w - tf.x) / tf.k + margin, y1: (vp.h - tf.y) / tf.k + margin };
761
+ const inView = (n) => !culled || (n.x + size.width >= rect.x0 && n.x <= rect.x1 && n.y + size.height >= rect.y0 && n.y <= rect.y1);
762
+ const keep = new Set([tabId, selected, drag?.id].filter(Boolean));
763
+ const visible = order.filter((n) => inView(n) || keep.has(n.id));
764
+ const selectedPath = new Set(selected ? [selected, ...ancestorsOf(selected)] : []);
765
+ return (_jsxs("div", { "data-slot": "hierarchy-chart", className: cn("relative w-full min-w-0", className), children: [_jsxs("div", { ref: viewportRef, role: "group", "aria-label": ariaLabel ? `${ariaLabel} · ${t("canvas")}` : t("canvas"), "aria-describedby": instructionsId, "aria-busy": loading || undefined, tabIndex: 0, "data-panning": panning ? "" : undefined, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: (e) => endGesture(e), onPointerCancel: (e) => endGesture(e, true), onKeyDown: onViewportKeyDown, onClickCapture: (e) => {
766
+ if (suppressClick.current) {
767
+ e.stopPropagation();
768
+ e.preventDefault();
769
+ suppressClick.current = false;
770
+ }
771
+ }, className: "vui-hierarchy focus-ring relative overflow-hidden rounded-ui-lg border border-line outline-none select-none", style: frameStyle, children: [_jsx("p", { id: instructionsId, className: "sr-only", children: t("instructions") }), loading ? (_jsx(HierarchySkeleton, { label: t("loading") })) : layout.nodes.length === 0 ? (_jsx("div", { className: "flex h-full items-center justify-center p-6 text-sm text-fg-subtle", children: empty ?? t("empty") })) : (_jsxs("div", { className: "vui-hierarchy-layer absolute top-0", "data-animate": animate ? "" : undefined, onTransitionEnd: () => setAnimate(false),
772
+ // Canvas coordinates are physical (the layout already mirrors for RTL).
773
+ style: { width: layout.width, height: layout.height, left: 0, transform: `translate(${tf.x}px, ${tf.y}px) scale(${tf.k})` }, children: [_jsx("svg", { "aria-hidden": true, className: "pointer-events-none absolute inset-0 overflow-visible", width: layout.width, height: layout.height, children: layout.nodes.map((n) => {
774
+ if (!n.parentId)
775
+ return null;
776
+ const p = laidById.get(n.parentId);
777
+ if (!p || (!inView(n) && !inView(p)))
778
+ return null;
779
+ return _jsx("path", { className: "vui-hierarchy-edge", "data-active": selectedPath.has(n.id) ? "" : undefined, d: edgePath(p, n, size, vertical, dir === "rtl") }, n.id);
780
+ }) }), _jsx("div", { role: "tree", "aria-label": ariaLabel, className: "absolute inset-0", children: visible.map((n) => {
781
+ const isCollapsed = collapsedSet.has(n.id);
782
+ const state = {
783
+ depth: n.depth,
784
+ childCount: n.childCount,
785
+ descendantCount: descendants.get(n.id) ?? 0,
786
+ collapsed: isCollapsed,
787
+ selected: selected === n.id,
788
+ matched: matches.has(n.id),
789
+ orientation,
790
+ };
791
+ return (_jsx(HierarchyNodeShell, { n: n, state: state, size: size, t: t, label: getLabel(n.data), vertical: vertical, rtl: dir === "rtl", tabbable: tabId === n.id, placeholder: !!isPlaceholder?.(n.data), dragSource: drag?.id === n.id, dropTarget: drag?.target === n.id ? (drag.reason ? "invalid" : "valid") : null, countText: format.number(state.descendantCount), nodeRef: (el) => {
792
+ if (el)
793
+ nodeRefs.current.set(n.id, el);
794
+ else
795
+ nodeRefs.current.delete(n.id);
796
+ }, onFocus: () => setFocusedId(n.id), onClick: () => {
797
+ setSelected(n.id);
798
+ setFocusedId(n.id);
799
+ }, onKeyDown: (e) => onNodeKeyDown(e, n), onToggle: () => toggle(n.id), menu: _jsx(NodeMenu, { open: menuFor === n.id, onOpenChange: (o) => setMenuFor(o ? n.id : null), label: getLabel(n.data), t: t, hasKids: n.childCount > 0, collapsed: isCollapsed, onToggle: () => toggle(n.id), onCenter: () => centerOn(n.id), onChangeParent: onReparent ? () => setPickerFor(n.id) : undefined, returnFocus: () => nodeRefs.current.get(n.id)?.focus({ preventScroll: true }), extra: nodeMenu?.(n.data) }), children: renderNode ? renderNode(n.data, state) : _jsx(HierarchyNodeCard, { title: getLabel(n.data), subtitle: getDescription?.(n.data) }) }, n.id));
800
+ }) })] })), drag ? (_jsx("div", { "aria-hidden": true, className: cn("pointer-events-none absolute z-10 max-w-56 -translate-x-1/2 -translate-y-[130%] truncate rounded-ui-sm border px-2 py-1 text-xs font-medium shadow-(--popover-shadow)", drag.reason ? "border-danger bg-popover text-danger" : "border-line bg-popover text-fg"), style: { left: drag.x, top: drag.y }, children: drag.reason ?? getLabel(byId.get(drag.id)) })) : null, controls && !loading && layout.nodes.length > 0 ? (_jsxs("div", { "data-hierarchy-ui": "", className: "surface-popover absolute end-3 bottom-3 flex items-center gap-0.5 rounded-ui p-1", children: [_jsx(IconButton, { label: t("zoomOut"), size: "xs", tooltip: false, onClick: () => zoomBy(0.8), disabled: tf.k <= MIN_K + 0.001, children: _jsx(Minus, {}) }), _jsx("output", { "aria-live": "off", "aria-label": t("zoomLevel", { percent: format.percent(tf.k, { maximumFractionDigits: 0 }) }), className: "tabular w-11 text-center text-xs text-fg-muted", children: format.percent(tf.k, { maximumFractionDigits: 0 }) }), _jsx(IconButton, { label: t("zoomIn"), size: "xs", tooltip: false, onClick: () => zoomBy(1.25), disabled: tf.k >= MAX_K - 0.001, children: _jsx(Plus, {}) }), _jsx("span", { "aria-hidden": true, className: "mx-0.5 h-4 w-px bg-line" }), _jsx(IconButton, { label: t("fit"), size: "xs", tooltip: false, onClick: () => fit(), children: _jsx(Maximize, {}) }), _jsx(IconButton, { label: vertical ? t("horizontal") : t("vertical"), size: "xs", tooltip: false, onClick: () => {
801
+ setOrientation(vertical ? "horizontal" : "vertical");
802
+ fitted.current = false;
803
+ }, children: vertical ? _jsx(ArrowLeftRight, {}) : _jsx(ArrowUpDown, {}) }), _jsx(IconButton, { label: t("expandAll"), size: "xs", tooltip: false, onClick: () => {
804
+ expandAll();
805
+ fitted.current = false;
806
+ }, children: _jsx(ChevronsUpDown, {}) }), _jsx(IconButton, { label: t("collapseAll"), size: "xs", tooltip: false, onClick: () => {
807
+ collapseAll();
808
+ fitted.current = false;
809
+ }, children: _jsx(ChevronsDownUp, {}) })] })) : null] }), _jsx("span", { role: "status", "aria-live": "polite", "aria-atomic": "true", className: "sr-only", "data-slot": "hierarchy-status", children: status }), onReparent ? (_jsx(ParentPicker, { nodeId: pickerFor, onClose: () => {
810
+ const id = pickerFor;
811
+ setPickerFor(null);
812
+ if (id)
813
+ requestAnimationFrame(() => nodeRefs.current.get(id)?.focus({ preventScroll: true }));
814
+ }, nodes: nodes, getLabel: getLabel, getDescription: getDescription, check: checkReparent, currentParent: pickerFor ? (byId.get(pickerFor)?.parentId ?? null) : null, t: t, locale: locale, onPick: (pid) => {
815
+ const id = pickerFor;
816
+ setPickerFor(null);
817
+ if (id)
818
+ void reparent(id, pid);
819
+ } })) : null] }));
820
+ }
821
+ /**
822
+ * ```tsx
823
+ * <HierarchyChart
824
+ * aria-label="Organization"
825
+ * nodes={people}
826
+ * renderNode={(p) => <HierarchyPersonNode name={p.name} title={p.title} src={p.photo} />}
827
+ * />
828
+ * ```
829
+ */
830
+ export const HierarchyChart = React.forwardRef(HierarchyChartInner);
831
+ function toTreeData(nodes, byId, getLabel, getDescription, descendants) {
832
+ const kids = new Map();
833
+ for (const n of nodes) {
834
+ const p = n.parentId !== null && byId.has(n.parentId) ? n.parentId : null;
835
+ const list = kids.get(p);
836
+ if (list)
837
+ list.push(n);
838
+ else
839
+ kids.set(p, [n]);
840
+ }
841
+ const build = (pid) => (kids.get(pid) ?? []).map((n) => {
842
+ const ch = build(n.id);
843
+ const d = descendants.get(n.id) ?? 0;
844
+ return {
845
+ id: n.id,
846
+ label: getLabel(n),
847
+ description: getDescription?.(n),
848
+ badge: d > 0 ? _jsx("span", { className: "tabular text-xs text-fg-subtle", children: d }) : undefined,
849
+ ...(ch.length ? { children: ch } : {}),
850
+ };
851
+ });
852
+ return build(null);
853
+ }
854
+ function HierarchyNodeShell({ n, state, size, t, vertical, rtl, tabbable, placeholder, dragSource, dropTarget, countText, nodeRef, onFocus, onClick, onKeyDown, onToggle, menu, children }) {
855
+ const chipPos = vertical
856
+ ? { left: "50%", bottom: 0, transform: "translate(-50%, 50%)" }
857
+ : rtl
858
+ ? { left: 0, top: "50%", transform: "translate(-50%, -50%)" }
859
+ : { right: 0, top: "50%", transform: "translate(50%, -50%)" };
860
+ return (_jsxs("div", { ref: nodeRef, role: "treeitem", "aria-level": n.depth + 1, "aria-setsize": n.setsize, "aria-posinset": n.posinset, "aria-expanded": n.childCount > 0 ? !state.collapsed : undefined, "aria-selected": state.selected, "aria-keyshortcuts": "Shift+F10", tabIndex: tabbable ? 0 : -1, "data-node-id": n.id, "data-selected": state.selected ? "" : undefined, "data-match": state.matched ? "" : undefined, "data-drag-source": dragSource ? "" : undefined, "data-drop-target": dropTarget === "valid" ? "" : undefined, "data-drop-invalid": dropTarget === "invalid" ? "" : undefined, onFocus: (e) => e.target === e.currentTarget && onFocus(), onClick: onClick, onKeyDown: onKeyDown, className: "vui-hierarchy-node group/node absolute", style: { left: n.x, top: n.y, width: size.width, height: size.height }, children: [_jsxs("div", { "data-slot": "hierarchy-card", className: cn("relative h-full overflow-hidden rounded-ui-lg border bg-surface text-fg shadow-[0_1px_2px_rgb(0_0_0/0.06)] transition-[box-shadow,background-color]", placeholder ? "border-dashed border-field-border-hover bg-surface-2" : "border-surface-border"), children: [children, _jsx("div", { "data-hierarchy-ui": "", className: "absolute end-1 top-1 opacity-0 transition-opacity group-hover/node:opacity-100 group-focus-visible/node:opacity-100 group-data-[selected]/node:opacity-100 pointer-coarse:opacity-100 has-data-[state=open]:opacity-100", children: menu })] }), n.childCount > 0 ? (_jsx("span", { "aria-hidden": true, "data-hierarchy-ui": "", "data-slot": "hierarchy-toggle", title: state.collapsed ? t("expand") : t("collapse"), onClick: (e) => {
861
+ e.stopPropagation();
862
+ onToggle();
863
+ }, className: cn("tabular absolute z-[1] inline-flex h-5 min-w-5 cursor-pointer items-center justify-center gap-0.5 rounded-full border px-1.5 text-[11px] font-medium shadow-sm transition-colors", state.collapsed ? "border-transparent bg-fg text-scene hover:opacity-90" : "border-line bg-surface text-fg-muted hover:text-fg"), style: chipPos, children: state.collapsed ? (_jsxs(_Fragment, { children: [_jsx(Plus, { className: "size-2.5", strokeWidth: 3 }), countText] })) : (_jsx(ChevronUp, { className: cn("size-3", !vertical && (rtl ? "rotate-90" : "-rotate-90")) })) })) : null, state.collapsed && state.descendantCount > 0 ? _jsx("span", { className: "sr-only", children: t("hiddenCount", { count: state.descendantCount }) }) : null] }));
864
+ }
865
+ function NodeMenu({ open, onOpenChange, label, t, hasKids, collapsed, onToggle, onCenter, onChangeParent, returnFocus, extra, }) {
866
+ return (_jsxs(DropdownMenu, { modal: false, open: open, onOpenChange: onOpenChange, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(IconButton, { label: t("nodeMenu", { node: label }), size: "xs", tooltip: false, tabIndex: -1, className: "size-6 bg-surface text-fg-subtle", onClick: (e) => e.stopPropagation(), children: _jsx(Ellipsis, {}) }) }), open ? (_jsxs(DropdownMenuContent, { align: "end", size: "sm", onCloseAutoFocus: (e) => {
867
+ e.preventDefault();
868
+ returnFocus();
869
+ }, children: [hasKids ? (_jsx(DropdownMenuItem, { icon: collapsed ? _jsx(ChevronsUpDown, {}) : _jsx(ChevronsDownUp, {}), onSelect: onToggle, children: collapsed ? t("expand") : t("collapse") })) : null, _jsx(DropdownMenuItem, { icon: _jsx(Crosshair, {}), onSelect: onCenter, children: t("center") }), onChangeParent ? (_jsx(DropdownMenuItem, { icon: _jsx(GitBranch, {}), onSelect: () => requestAnimationFrame(onChangeParent), children: t("changeParent") })) : null, extra ? (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, {}), extra] })) : null] })) : null] }));
870
+ }
871
+ function ParentPicker({ nodeId, onClose, nodes, getLabel, getDescription, check, currentParent, t, locale, onPick, }) {
872
+ const me = nodeId ? nodes.find((n) => n.id === nodeId) : undefined;
873
+ const options = me ? nodes.filter((n) => n.id !== me.id && n.id !== currentParent) : [];
874
+ return (_jsx(Dialog, { open: !!me, onOpenChange: (o) => !o && onClose(), children: _jsxs(DialogContent, { size: "sm", children: [_jsx(DialogHeader, { title: me ? t("changeParentTitle", { node: getLabel(me) }) : "", description: t("changeParentDescription") }), _jsx(DialogBody, { flush: true, children: _jsxs(Command, { label: t("searchNodes"), filter: (value, search) => (matchText(value, search, locale) ? 1 : 0), children: [_jsx(CommandInput, { placeholder: t("searchNodes") }), _jsxs(CommandList, { className: "max-h-72", children: [_jsx(CommandEmpty, { children: t("noMatches") }), options.map((n) => {
875
+ const ok = me ? check(me.id, n.id) : true;
876
+ const desc = getDescription?.(n);
877
+ return (_jsx(CommandItem, { value: `${getLabel(n)} ${desc ?? ""} ${n.id}`, disabled: ok !== true, onSelect: () => onPick(n.id), children: _jsxs("span", { className: "flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate", children: getLabel(n) }), _jsx("span", { className: "truncate text-xs text-fg-subtle", children: ok !== true ? ok : desc })] }) }, n.id));
878
+ })] })] }) })] }) }));
879
+ }
880
+ function HierarchySkeleton({ label }) {
881
+ return (_jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-10", "aria-hidden": false, children: [_jsx("span", { className: "sr-only", children: label }), _jsx(Skeleton, { "aria-hidden": true, className: "h-16 w-52 rounded-ui-lg" }), _jsx("div", { "aria-hidden": true, className: "flex gap-6", children: [0, 1, 2].map((i) => (_jsx(Skeleton, { className: "h-16 w-44 rounded-ui-lg" }, i))) }), _jsx("div", { "aria-hidden": true, className: "flex gap-4", children: [0, 1, 2, 3, 4].map((i) => (_jsx(Skeleton, { className: "h-12 w-32 rounded-ui-lg" }, i))) })] }));
882
+ }
883
+ /** Generic node content: icon · title · subtitle · badge. */
884
+ export function HierarchyNodeCard({ title, subtitle, icon, badge, meta, className, ...props }) {
885
+ return (_jsxs("div", { "data-slot": "hierarchy-node-card", className: cn("flex h-full min-w-0 items-center gap-2.5 px-3 pe-7", className), ...props, children: [icon ? _jsx("span", { className: "inline-flex shrink-0 items-center text-fg-muted [&_svg]:size-4", children: icon }) : null, _jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [_jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [_jsx("span", { className: "truncate text-[13.5px] leading-tight font-semibold tracking-tight", children: title }), badge] }), subtitle ? _jsx("span", { className: "truncate text-xs leading-snug text-fg-muted", children: subtitle }) : null, meta ? _jsx("span", { className: "mt-0.5 truncate text-[11px] text-fg-subtle", children: meta }) : null] })] }));
886
+ }
887
+ /** Person node for org charts: Avatar · name · job title · meta. */
888
+ export function HierarchyPersonNode({ name, title, src, meta, badge, vacant, className, ...props }) {
889
+ return (_jsxs("div", { "data-slot": "hierarchy-person", className: cn("flex h-full min-w-0 items-center gap-3 px-3 pe-7", className), ...props, children: [vacant ? (_jsx("span", { "aria-hidden": true, className: "inline-flex size-10 shrink-0 items-center justify-center rounded-full border border-dashed border-field-border-hover text-fg-subtle", children: _jsx(Plus, { className: "size-4" }) })) : (_jsx(Avatar, { name: name, src: src, size: "lg" })), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [_jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [_jsx("span", { className: cn("truncate text-[13.5px] leading-tight font-semibold tracking-tight", vacant && "text-fg-muted"), children: name }), badge] }), title ? _jsx("span", { className: "truncate text-xs leading-snug text-fg-muted", children: title }) : null, meta ? _jsx("span", { className: "mt-0.5 truncate text-[11px] text-fg-subtle", children: meta }) : null] })] }));
890
+ }