@psnext/design-system 2.3.0 → 2.5.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 (671) hide show
  1. package/DESIGN.md +493 -8
  2. package/README.md +3 -3
  3. package/SKILL.md +84 -6
  4. package/bin/install-agent-skill.mjs +39 -7
  5. package/dist/Header.cjs +152 -21
  6. package/dist/Header.cjs.map +1 -1
  7. package/dist/Header.js +152 -21
  8. package/dist/Header.js.map +1 -1
  9. package/dist/Icon.cjs +40 -8
  10. package/dist/Icon.cjs.map +1 -1
  11. package/dist/Icon.js +40 -8
  12. package/dist/Icon.js.map +1 -1
  13. package/dist/Mosaic.cjs +472 -0
  14. package/dist/Mosaic.cjs.map +1 -0
  15. package/dist/Mosaic.js +459 -0
  16. package/dist/Mosaic.js.map +1 -0
  17. package/dist/MultiColumn.cjs +354 -0
  18. package/dist/MultiColumn.cjs.map +1 -0
  19. package/dist/MultiColumn.js +335 -0
  20. package/dist/MultiColumn.js.map +1 -0
  21. package/dist/Sidebar.cjs +4 -3
  22. package/dist/Sidebar.cjs.map +1 -1
  23. package/dist/Sidebar.js +4 -3
  24. package/dist/Sidebar.js.map +1 -1
  25. package/dist/index.cjs +18 -3
  26. package/dist/index.d.cts +5 -5
  27. package/dist/index.d.cts.map +1 -1
  28. package/dist/index.d.ts +5 -5
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +9 -4
  31. package/dist/index10.d.cts +6 -6
  32. package/dist/index10.d.cts.map +1 -1
  33. package/dist/index10.d.ts +6 -6
  34. package/dist/index11.d.cts +3 -3
  35. package/dist/index11.d.cts.map +1 -1
  36. package/dist/index11.d.ts +3 -3
  37. package/dist/index11.d.ts.map +1 -1
  38. package/dist/index12.d.cts +12 -12
  39. package/dist/index12.d.ts +12 -12
  40. package/dist/index13.d.cts +6 -6
  41. package/dist/index13.d.cts.map +1 -1
  42. package/dist/index13.d.ts +6 -6
  43. package/dist/index13.d.ts.map +1 -1
  44. package/dist/index14.d.cts +5 -5
  45. package/dist/index14.d.ts +5 -5
  46. package/dist/index15.d.cts +58 -23
  47. package/dist/index15.d.cts.map +1 -1
  48. package/dist/index15.d.ts +58 -23
  49. package/dist/index15.d.ts.map +1 -1
  50. package/dist/index16.d.cts +23 -32
  51. package/dist/index16.d.cts.map +1 -1
  52. package/dist/index16.d.ts +23 -32
  53. package/dist/index16.d.ts.map +1 -1
  54. package/dist/index17.d.cts +34 -15
  55. package/dist/index17.d.cts.map +1 -1
  56. package/dist/index17.d.ts +34 -15
  57. package/dist/index17.d.ts.map +1 -1
  58. package/dist/index18.d.cts +13 -67
  59. package/dist/index18.d.cts.map +1 -1
  60. package/dist/index18.d.ts +13 -67
  61. package/dist/index18.d.ts.map +1 -1
  62. package/dist/index19.d.cts +55 -48
  63. package/dist/index19.d.cts.map +1 -1
  64. package/dist/index19.d.ts +55 -48
  65. package/dist/index19.d.ts.map +1 -1
  66. package/dist/index2.d.cts +8 -8
  67. package/dist/index2.d.ts +9 -9
  68. package/dist/index20.d.cts +45 -75
  69. package/dist/index20.d.cts.map +1 -1
  70. package/dist/index20.d.ts +45 -75
  71. package/dist/index20.d.ts.map +1 -1
  72. package/dist/index21.d.cts +90 -28
  73. package/dist/index21.d.cts.map +1 -1
  74. package/dist/index21.d.ts +90 -28
  75. package/dist/index21.d.ts.map +1 -1
  76. package/dist/index22.d.cts +28 -56
  77. package/dist/index22.d.cts.map +1 -1
  78. package/dist/index22.d.ts +28 -56
  79. package/dist/index22.d.ts.map +1 -1
  80. package/dist/index23.d.cts +53 -78
  81. package/dist/index23.d.cts.map +1 -1
  82. package/dist/index23.d.ts +53 -78
  83. package/dist/index23.d.ts.map +1 -1
  84. package/dist/index24.d.cts +83 -33
  85. package/dist/index24.d.cts.map +1 -1
  86. package/dist/index24.d.ts +83 -33
  87. package/dist/index24.d.ts.map +1 -1
  88. package/dist/index25.d.cts +43 -11
  89. package/dist/index25.d.cts.map +1 -1
  90. package/dist/index25.d.ts +43 -11
  91. package/dist/index25.d.ts.map +1 -1
  92. package/dist/index26.d.cts +11 -74
  93. package/dist/index26.d.cts.map +1 -1
  94. package/dist/index26.d.ts +11 -74
  95. package/dist/index26.d.ts.map +1 -1
  96. package/dist/index27.d.cts +68 -59
  97. package/dist/index27.d.cts.map +1 -1
  98. package/dist/index27.d.ts +68 -59
  99. package/dist/index27.d.ts.map +1 -1
  100. package/dist/index28.d.cts +47 -30
  101. package/dist/index28.d.cts.map +1 -1
  102. package/dist/index28.d.ts +47 -30
  103. package/dist/index28.d.ts.map +1 -1
  104. package/dist/index29.d.cts +63 -17
  105. package/dist/index29.d.cts.map +1 -1
  106. package/dist/index29.d.ts +63 -17
  107. package/dist/index29.d.ts.map +1 -1
  108. package/dist/index3.d.cts +13 -13
  109. package/dist/index3.d.ts +13 -13
  110. package/dist/index30.d.cts +29 -51
  111. package/dist/index30.d.cts.map +1 -1
  112. package/dist/index30.d.ts +30 -52
  113. package/dist/index30.d.ts.map +1 -1
  114. package/dist/index31.d.cts +19 -34
  115. package/dist/index31.d.cts.map +1 -1
  116. package/dist/index31.d.ts +19 -34
  117. package/dist/index31.d.ts.map +1 -1
  118. package/dist/index32.d.cts +80 -18
  119. package/dist/index32.d.cts.map +1 -1
  120. package/dist/index32.d.ts +79 -17
  121. package/dist/index32.d.ts.map +1 -1
  122. package/dist/index33.d.cts +32 -51
  123. package/dist/index33.d.cts.map +1 -1
  124. package/dist/index33.d.ts +33 -52
  125. package/dist/index33.d.ts.map +1 -1
  126. package/dist/index34.d.cts +19 -36
  127. package/dist/index34.d.cts.map +1 -1
  128. package/dist/index34.d.ts +19 -36
  129. package/dist/index34.d.ts.map +1 -1
  130. package/dist/index35.d.cts +43 -61
  131. package/dist/index35.d.cts.map +1 -1
  132. package/dist/index35.d.ts +44 -62
  133. package/dist/index35.d.ts.map +1 -1
  134. package/dist/index36.d.cts +35 -11
  135. package/dist/index36.d.cts.map +1 -1
  136. package/dist/index36.d.ts +35 -11
  137. package/dist/index36.d.ts.map +1 -1
  138. package/dist/index37.d.cts +68 -20
  139. package/dist/index37.d.cts.map +1 -1
  140. package/dist/index37.d.ts +69 -21
  141. package/dist/index37.d.ts.map +1 -1
  142. package/dist/index38.d.cts +14 -15
  143. package/dist/index38.d.cts.map +1 -1
  144. package/dist/index38.d.ts +14 -15
  145. package/dist/index38.d.ts.map +1 -1
  146. package/dist/index39.d.cts +22 -98
  147. package/dist/index39.d.cts.map +1 -1
  148. package/dist/index39.d.ts +22 -98
  149. package/dist/index39.d.ts.map +1 -1
  150. package/dist/index4.d.cts +2 -2
  151. package/dist/index4.d.cts.map +1 -1
  152. package/dist/index4.d.ts +2 -2
  153. package/dist/index40.d.cts +15 -17
  154. package/dist/index40.d.cts.map +1 -1
  155. package/dist/index40.d.ts +15 -17
  156. package/dist/index40.d.ts.map +1 -1
  157. package/dist/index41.d.cts +84 -35
  158. package/dist/index41.d.cts.map +1 -1
  159. package/dist/index41.d.ts +84 -35
  160. package/dist/index41.d.ts.map +1 -1
  161. package/dist/index42.d.cts +118 -38
  162. package/dist/index42.d.cts.map +1 -1
  163. package/dist/index42.d.ts +118 -38
  164. package/dist/index42.d.ts.map +1 -1
  165. package/dist/index43.d.cts +15 -89
  166. package/dist/index43.d.cts.map +1 -1
  167. package/dist/index43.d.ts +15 -89
  168. package/dist/index43.d.ts.map +1 -1
  169. package/dist/index44.d.cts +56 -1
  170. package/dist/index44.d.cts.map +1 -0
  171. package/dist/index44.d.ts +56 -1
  172. package/dist/index44.d.ts.map +1 -0
  173. package/dist/index45.d.cts +31 -34
  174. package/dist/index45.d.cts.map +1 -1
  175. package/dist/index45.d.ts +31 -34
  176. package/dist/index45.d.ts.map +1 -1
  177. package/dist/index46.d.cts +89 -21
  178. package/dist/index46.d.cts.map +1 -1
  179. package/dist/index46.d.ts +89 -21
  180. package/dist/index46.d.ts.map +1 -1
  181. package/dist/index47.d.cts +1 -41
  182. package/dist/index47.d.ts +1 -41
  183. package/dist/index48.d.cts +122 -20
  184. package/dist/index48.d.cts.map +1 -1
  185. package/dist/index48.d.ts +122 -20
  186. package/dist/index48.d.ts.map +1 -1
  187. package/dist/index49.d.cts +40 -13
  188. package/dist/index49.d.cts.map +1 -1
  189. package/dist/index49.d.ts +40 -13
  190. package/dist/index49.d.ts.map +1 -1
  191. package/dist/index5.d.cts +7 -7
  192. package/dist/index5.d.cts.map +1 -1
  193. package/dist/index5.d.ts +7 -7
  194. package/dist/index50.d.cts +22 -63
  195. package/dist/index50.d.cts.map +1 -1
  196. package/dist/index50.d.ts +22 -63
  197. package/dist/index50.d.ts.map +1 -1
  198. package/dist/index51.d.cts +33 -55
  199. package/dist/index51.d.cts.map +1 -1
  200. package/dist/index51.d.ts +33 -55
  201. package/dist/index51.d.ts.map +1 -1
  202. package/dist/index52.d.cts +18 -24
  203. package/dist/index52.d.cts.map +1 -1
  204. package/dist/index52.d.ts +18 -24
  205. package/dist/index52.d.ts.map +1 -1
  206. package/dist/index53.d.cts +12 -200
  207. package/dist/index53.d.cts.map +1 -1
  208. package/dist/index53.d.ts +12 -200
  209. package/dist/index53.d.ts.map +1 -1
  210. package/dist/index54.d.cts +58 -15
  211. package/dist/index54.d.cts.map +1 -1
  212. package/dist/index54.d.ts +58 -15
  213. package/dist/index54.d.ts.map +1 -1
  214. package/dist/index55.d.cts +93 -23
  215. package/dist/index55.d.cts.map +1 -1
  216. package/dist/index55.d.ts +93 -23
  217. package/dist/index55.d.ts.map +1 -1
  218. package/dist/index56.d.cts +27 -21
  219. package/dist/index56.d.cts.map +1 -1
  220. package/dist/index56.d.ts +27 -21
  221. package/dist/index56.d.ts.map +1 -1
  222. package/dist/index57.d.cts +203 -6
  223. package/dist/index57.d.cts.map +1 -1
  224. package/dist/index57.d.ts +203 -6
  225. package/dist/index57.d.ts.map +1 -1
  226. package/dist/index58.d.cts +17 -41
  227. package/dist/index58.d.cts.map +1 -1
  228. package/dist/index58.d.ts +17 -41
  229. package/dist/index58.d.ts.map +1 -1
  230. package/dist/index59.d.cts +24 -47
  231. package/dist/index59.d.cts.map +1 -1
  232. package/dist/index59.d.ts +24 -47
  233. package/dist/index59.d.ts.map +1 -1
  234. package/dist/index6.d.cts +5 -5
  235. package/dist/index6.d.cts.map +1 -1
  236. package/dist/index6.d.ts +6 -6
  237. package/dist/index60.d.cts +19 -57
  238. package/dist/index60.d.cts.map +1 -1
  239. package/dist/index60.d.ts +19 -57
  240. package/dist/index60.d.ts.map +1 -1
  241. package/dist/index61.d.cts +6 -39
  242. package/dist/index61.d.cts.map +1 -1
  243. package/dist/index61.d.ts +6 -39
  244. package/dist/index61.d.ts.map +1 -1
  245. package/dist/index62.d.cts +44 -18
  246. package/dist/index62.d.cts.map +1 -1
  247. package/dist/index62.d.ts +44 -18
  248. package/dist/index62.d.ts.map +1 -1
  249. package/dist/index63.d.cts +47 -41
  250. package/dist/index63.d.cts.map +1 -1
  251. package/dist/index63.d.ts +47 -41
  252. package/dist/index63.d.ts.map +1 -1
  253. package/dist/index64.d.cts +55 -15
  254. package/dist/index64.d.cts.map +1 -1
  255. package/dist/index64.d.ts +54 -14
  256. package/dist/index64.d.ts.map +1 -1
  257. package/dist/index65.d.cts +36 -39
  258. package/dist/index65.d.cts.map +1 -1
  259. package/dist/index65.d.ts +37 -40
  260. package/dist/index65.d.ts.map +1 -1
  261. package/dist/index66.d.cts +16 -17
  262. package/dist/index66.d.cts.map +1 -1
  263. package/dist/index66.d.ts +17 -18
  264. package/dist/index66.d.ts.map +1 -1
  265. package/dist/index67.d.cts +40 -14
  266. package/dist/index67.d.cts.map +1 -1
  267. package/dist/index67.d.ts +40 -14
  268. package/dist/index67.d.ts.map +1 -1
  269. package/dist/index68.d.cts +16 -30
  270. package/dist/index68.d.cts.map +1 -1
  271. package/dist/index68.d.ts +17 -31
  272. package/dist/index68.d.ts.map +1 -1
  273. package/dist/index69.d.cts +39 -27
  274. package/dist/index69.d.cts.map +1 -1
  275. package/dist/index69.d.ts +40 -28
  276. package/dist/index69.d.ts.map +1 -1
  277. package/dist/index7.d.cts +8 -8
  278. package/dist/index7.d.cts.map +1 -1
  279. package/dist/index7.d.ts +8 -8
  280. package/dist/index7.d.ts.map +1 -1
  281. package/dist/index70.d.cts +22 -78
  282. package/dist/index70.d.cts.map +1 -1
  283. package/dist/index70.d.ts +22 -78
  284. package/dist/index70.d.ts.map +1 -1
  285. package/dist/index71.d.cts +77 -251
  286. package/dist/index71.d.cts.map +1 -1
  287. package/dist/index71.d.ts +77 -251
  288. package/dist/index71.d.ts.map +1 -1
  289. package/dist/index72.d.cts +19 -0
  290. package/dist/index72.d.cts.map +1 -0
  291. package/dist/index72.d.ts +19 -0
  292. package/dist/index72.d.ts.map +1 -0
  293. package/dist/index73.d.cts +37 -0
  294. package/dist/index73.d.cts.map +1 -0
  295. package/dist/index73.d.ts +37 -0
  296. package/dist/index73.d.ts.map +1 -0
  297. package/dist/index74.d.cts +36 -0
  298. package/dist/index74.d.cts.map +1 -0
  299. package/dist/index74.d.ts +36 -0
  300. package/dist/index74.d.ts.map +1 -0
  301. package/dist/index75.d.cts +86 -0
  302. package/dist/index75.d.cts.map +1 -0
  303. package/dist/index75.d.ts +86 -0
  304. package/dist/index75.d.ts.map +1 -0
  305. package/dist/index76.d.cts +278 -0
  306. package/dist/index76.d.cts.map +1 -0
  307. package/dist/index76.d.ts +278 -0
  308. package/dist/index76.d.ts.map +1 -0
  309. package/dist/index8.d.cts +4 -4
  310. package/dist/index8.d.ts +5 -5
  311. package/dist/index9.d.cts +2 -2
  312. package/dist/index9.d.ts +2 -2
  313. package/dist/index9.d.ts.map +1 -1
  314. package/dist/layouts/Container/index.cjs +2 -1
  315. package/dist/layouts/Container/index.cjs.map +1 -1
  316. package/dist/layouts/Container/index.d.cts +1 -1
  317. package/dist/layouts/Container/index.d.ts +1 -1
  318. package/dist/layouts/Container/index.js +1 -1
  319. package/dist/layouts/MultiColumn/index.cjs +5 -0
  320. package/dist/layouts/MultiColumn/index.d.cts +2 -0
  321. package/dist/layouts/MultiColumn/index.d.ts +2 -0
  322. package/dist/layouts/MultiColumn/index.js +2 -0
  323. package/dist/layouts/PageBackground/index.d.cts +1 -1
  324. package/dist/layouts/PageBackground/index.d.ts +1 -1
  325. package/dist/layouts/Stack/index.cjs +2 -1
  326. package/dist/layouts/Stack/index.cjs.map +1 -1
  327. package/dist/layouts/Stack/index.d.cts +1 -1
  328. package/dist/layouts/Stack/index.d.ts +1 -1
  329. package/dist/layouts/Stack/index.js +1 -1
  330. package/dist/layouts/TwoColumn/index.cjs +2 -1
  331. package/dist/layouts/TwoColumn/index.cjs.map +1 -1
  332. package/dist/layouts/TwoColumn/index.d.cts +1 -1
  333. package/dist/layouts/TwoColumn/index.d.ts +1 -1
  334. package/dist/layouts/TwoColumn/index.js +1 -1
  335. package/dist/layouts/index.cjs +4 -0
  336. package/dist/layouts/index.d.cts +6 -5
  337. package/dist/layouts/index.d.ts +6 -5
  338. package/dist/layouts/index.js +2 -1
  339. package/dist/patterns/DataTable/index.cjs +6 -2
  340. package/dist/patterns/DataTable/index.cjs.map +1 -1
  341. package/dist/patterns/DataTable/index.d.cts +3 -3
  342. package/dist/patterns/DataTable/index.d.cts.map +1 -1
  343. package/dist/patterns/DataTable/index.d.ts +3 -3
  344. package/dist/patterns/DataTable/index.d.ts.map +1 -1
  345. package/dist/patterns/DataTable/index.js +6 -2
  346. package/dist/patterns/DataTable/index.js.map +1 -1
  347. package/dist/patterns/Footer/index.d.cts +7 -7
  348. package/dist/patterns/Footer/index.d.cts.map +1 -1
  349. package/dist/patterns/Footer/index.d.ts +7 -7
  350. package/dist/patterns/Footer/index.d.ts.map +1 -1
  351. package/dist/patterns/Header/index.d.cts +1 -1
  352. package/dist/patterns/Header/index.d.ts +1 -1
  353. package/dist/patterns/MediaObject/index.cjs +1 -1
  354. package/dist/patterns/MediaObject/index.d.cts +14 -14
  355. package/dist/patterns/MediaObject/index.d.cts.map +1 -1
  356. package/dist/patterns/MediaObject/index.d.ts +12 -12
  357. package/dist/patterns/MediaObject/index.js +1 -1
  358. package/dist/patterns/NavRail/index.cjs +4 -2
  359. package/dist/patterns/NavRail/index.cjs.map +1 -1
  360. package/dist/patterns/NavRail/index.d.cts +1 -1
  361. package/dist/patterns/NavRail/index.d.ts +1 -1
  362. package/dist/patterns/NavRail/index.js +4 -2
  363. package/dist/patterns/NavRail/index.js.map +1 -1
  364. package/dist/patterns/SectionCard/index.d.cts +2 -2
  365. package/dist/patterns/SectionCard/index.d.cts.map +1 -1
  366. package/dist/patterns/SectionCard/index.d.ts +2 -2
  367. package/dist/patterns/SectionCard/index.d.ts.map +1 -1
  368. package/dist/patterns/SectionHeading/index.d.cts +3 -3
  369. package/dist/patterns/SectionHeading/index.d.cts.map +1 -1
  370. package/dist/patterns/SectionHeading/index.d.ts +3 -3
  371. package/dist/patterns/SectionHeading/index.d.ts.map +1 -1
  372. package/dist/patterns/index.d.cts +2 -2
  373. package/dist/patterns/index.d.ts +2 -2
  374. package/dist/primitives/Accordion/index.cjs +6 -2
  375. package/dist/primitives/Accordion/index.cjs.map +1 -1
  376. package/dist/primitives/Accordion/index.js +6 -2
  377. package/dist/primitives/Accordion/index.js.map +1 -1
  378. package/dist/primitives/Alert/index.cjs +2 -1
  379. package/dist/primitives/Alert/index.cjs.map +1 -1
  380. package/dist/primitives/Alert/index.js +1 -1
  381. package/dist/primitives/AlertDialog/index.cjs +1 -1
  382. package/dist/primitives/AlertDialog/index.js +1 -1
  383. package/dist/primitives/AspectRatio/index.cjs +1 -1
  384. package/dist/primitives/AspectRatio/index.js +1 -1
  385. package/dist/primitives/Avatar/index.cjs +1 -1
  386. package/dist/primitives/Avatar/index.js +1 -1
  387. package/dist/primitives/Badge/index.cjs +3 -2
  388. package/dist/primitives/Badge/index.cjs.map +1 -1
  389. package/dist/primitives/Badge/index.js +2 -2
  390. package/dist/primitives/Breadcrumb/index.cjs +7 -3
  391. package/dist/primitives/Breadcrumb/index.cjs.map +1 -1
  392. package/dist/primitives/Breadcrumb/index.js +7 -3
  393. package/dist/primitives/Breadcrumb/index.js.map +1 -1
  394. package/dist/primitives/Button/index.cjs +3 -2
  395. package/dist/primitives/Button/index.cjs.map +1 -1
  396. package/dist/primitives/Button/index.js +2 -2
  397. package/dist/primitives/ButtonGroup/index.cjs +3 -2
  398. package/dist/primitives/ButtonGroup/index.cjs.map +1 -1
  399. package/dist/primitives/ButtonGroup/index.js +2 -2
  400. package/dist/primitives/Calendar/index.cjs +12 -11
  401. package/dist/primitives/Calendar/index.cjs.map +1 -1
  402. package/dist/primitives/Calendar/index.js +12 -11
  403. package/dist/primitives/Calendar/index.js.map +1 -1
  404. package/dist/primitives/Card/index.cjs +2 -1
  405. package/dist/primitives/Card/index.cjs.map +1 -1
  406. package/dist/primitives/Card/index.js +1 -1
  407. package/dist/primitives/Carousel/index.cjs +4 -3
  408. package/dist/primitives/Carousel/index.cjs.map +1 -1
  409. package/dist/primitives/Carousel/index.js +4 -3
  410. package/dist/primitives/Carousel/index.js.map +1 -1
  411. package/dist/primitives/Checkbox/index.cjs +10 -3
  412. package/dist/primitives/Checkbox/index.cjs.map +1 -1
  413. package/dist/primitives/Checkbox/index.d.cts +1 -1
  414. package/dist/primitives/Checkbox/index.d.ts +1 -1
  415. package/dist/primitives/Checkbox/index.js +10 -3
  416. package/dist/primitives/Checkbox/index.js.map +1 -1
  417. package/dist/primitives/CheckboxTree/index.cjs +6 -2
  418. package/dist/primitives/CheckboxTree/index.cjs.map +1 -1
  419. package/dist/primitives/CheckboxTree/index.d.cts +1 -1
  420. package/dist/primitives/CheckboxTree/index.d.ts +1 -1
  421. package/dist/primitives/CheckboxTree/index.js +6 -2
  422. package/dist/primitives/CheckboxTree/index.js.map +1 -1
  423. package/dist/primitives/CircularProgress/index.cjs +106 -0
  424. package/dist/primitives/CircularProgress/index.cjs.map +1 -0
  425. package/dist/primitives/CircularProgress/index.d.cts +2 -0
  426. package/dist/primitives/CircularProgress/index.d.ts +2 -0
  427. package/dist/primitives/CircularProgress/index.js +105 -0
  428. package/dist/primitives/CircularProgress/index.js.map +1 -0
  429. package/dist/primitives/Collapsible/index.cjs +1 -1
  430. package/dist/primitives/Collapsible/index.d.cts +1 -1
  431. package/dist/primitives/Collapsible/index.d.ts +1 -1
  432. package/dist/primitives/Collapsible/index.js +1 -1
  433. package/dist/primitives/Command/index.cjs +6 -2
  434. package/dist/primitives/Command/index.cjs.map +1 -1
  435. package/dist/primitives/Command/index.d.cts +1 -1
  436. package/dist/primitives/Command/index.d.ts +1 -1
  437. package/dist/primitives/Command/index.js +6 -2
  438. package/dist/primitives/Command/index.js.map +1 -1
  439. package/dist/primitives/ContextMenu/index.cjs +14 -4
  440. package/dist/primitives/ContextMenu/index.cjs.map +1 -1
  441. package/dist/primitives/ContextMenu/index.d.cts +1 -1
  442. package/dist/primitives/ContextMenu/index.d.ts +1 -1
  443. package/dist/primitives/ContextMenu/index.js +14 -4
  444. package/dist/primitives/ContextMenu/index.js.map +1 -1
  445. package/dist/primitives/Credits/index.cjs +8 -3
  446. package/dist/primitives/Credits/index.cjs.map +1 -1
  447. package/dist/primitives/Credits/index.d.cts +1 -1
  448. package/dist/primitives/Credits/index.d.ts +1 -1
  449. package/dist/primitives/Credits/index.js +7 -3
  450. package/dist/primitives/Credits/index.js.map +1 -1
  451. package/dist/primitives/Dialog/index.cjs +3 -2
  452. package/dist/primitives/Dialog/index.cjs.map +1 -1
  453. package/dist/primitives/Dialog/index.d.cts +1 -1
  454. package/dist/primitives/Dialog/index.d.ts +1 -1
  455. package/dist/primitives/Dialog/index.js +3 -2
  456. package/dist/primitives/Dialog/index.js.map +1 -1
  457. package/dist/primitives/Drawer/index.cjs +34 -2
  458. package/dist/primitives/Drawer/index.cjs.map +1 -1
  459. package/dist/primitives/Drawer/index.d.cts +1 -1
  460. package/dist/primitives/Drawer/index.d.ts +1 -1
  461. package/dist/primitives/Drawer/index.js +34 -2
  462. package/dist/primitives/Drawer/index.js.map +1 -1
  463. package/dist/primitives/DropdownMenu/index.cjs +14 -4
  464. package/dist/primitives/DropdownMenu/index.cjs.map +1 -1
  465. package/dist/primitives/DropdownMenu/index.d.cts +1 -1
  466. package/dist/primitives/DropdownMenu/index.d.ts +1 -1
  467. package/dist/primitives/DropdownMenu/index.js +14 -4
  468. package/dist/primitives/DropdownMenu/index.js.map +1 -1
  469. package/dist/primitives/Empty/index.cjs +1 -1
  470. package/dist/primitives/Empty/index.d.cts +1 -1
  471. package/dist/primitives/Empty/index.d.ts +1 -1
  472. package/dist/primitives/Empty/index.js +1 -1
  473. package/dist/primitives/Field/index.cjs +1 -1
  474. package/dist/primitives/Field/index.d.cts +1 -1
  475. package/dist/primitives/Field/index.d.ts +1 -1
  476. package/dist/primitives/Field/index.js +1 -1
  477. package/dist/primitives/FileUpload/index.cjs +354 -0
  478. package/dist/primitives/FileUpload/index.cjs.map +1 -0
  479. package/dist/primitives/FileUpload/index.d.cts +2 -0
  480. package/dist/primitives/FileUpload/index.d.ts +2 -0
  481. package/dist/primitives/FileUpload/index.js +351 -0
  482. package/dist/primitives/FileUpload/index.js.map +1 -0
  483. package/dist/primitives/Form/index.cjs +1 -1
  484. package/dist/primitives/Form/index.d.cts +1 -1
  485. package/dist/primitives/Form/index.d.ts +1 -1
  486. package/dist/primitives/Form/index.js +1 -1
  487. package/dist/primitives/Heading/index.cjs +2 -1
  488. package/dist/primitives/Heading/index.cjs.map +1 -1
  489. package/dist/primitives/Heading/index.d.cts +1 -1
  490. package/dist/primitives/Heading/index.d.ts +1 -1
  491. package/dist/primitives/Heading/index.js +1 -1
  492. package/dist/primitives/HoverCard/index.cjs +1 -1
  493. package/dist/primitives/HoverCard/index.d.cts +1 -1
  494. package/dist/primitives/HoverCard/index.d.ts +1 -1
  495. package/dist/primitives/HoverCard/index.js +1 -1
  496. package/dist/primitives/Icon/index.d.cts +1 -1
  497. package/dist/primitives/Icon/index.d.ts +1 -1
  498. package/dist/primitives/InfoBanner/index.cjs +6 -3
  499. package/dist/primitives/InfoBanner/index.cjs.map +1 -1
  500. package/dist/primitives/InfoBanner/index.d.cts +1 -1
  501. package/dist/primitives/InfoBanner/index.d.ts +1 -1
  502. package/dist/primitives/InfoBanner/index.js +5 -3
  503. package/dist/primitives/InfoBanner/index.js.map +1 -1
  504. package/dist/primitives/Input/index.cjs +2 -1
  505. package/dist/primitives/Input/index.cjs.map +1 -1
  506. package/dist/primitives/Input/index.d.cts +1 -1
  507. package/dist/primitives/Input/index.d.ts +1 -1
  508. package/dist/primitives/Input/index.js +1 -1
  509. package/dist/primitives/InputGroup/index.cjs +1 -1
  510. package/dist/primitives/InputGroup/index.d.cts +1 -1
  511. package/dist/primitives/InputGroup/index.d.ts +1 -1
  512. package/dist/primitives/InputGroup/index.js +1 -1
  513. package/dist/primitives/InputOtp/index.cjs +3 -2
  514. package/dist/primitives/InputOtp/index.cjs.map +1 -1
  515. package/dist/primitives/InputOtp/index.d.cts +1 -1
  516. package/dist/primitives/InputOtp/index.d.ts +1 -1
  517. package/dist/primitives/InputOtp/index.js +3 -2
  518. package/dist/primitives/InputOtp/index.js.map +1 -1
  519. package/dist/primitives/Item/index.cjs +2 -2
  520. package/dist/primitives/Item/index.d.cts +1 -1
  521. package/dist/primitives/Item/index.d.ts +1 -1
  522. package/dist/primitives/Item/index.js +2 -2
  523. package/dist/primitives/Kbd/index.d.cts +1 -1
  524. package/dist/primitives/Kbd/index.d.ts +1 -1
  525. package/dist/primitives/Label/index.cjs +1 -1
  526. package/dist/primitives/Label/index.d.cts +1 -1
  527. package/dist/primitives/Label/index.d.ts +1 -1
  528. package/dist/primitives/Label/index.js +1 -1
  529. package/dist/primitives/Link/index.cjs +3 -2
  530. package/dist/primitives/Link/index.cjs.map +1 -1
  531. package/dist/primitives/Link/index.d.cts +1 -1
  532. package/dist/primitives/Link/index.d.ts +1 -1
  533. package/dist/primitives/Link/index.js +2 -2
  534. package/dist/primitives/Logo/index.d.cts +1 -1
  535. package/dist/primitives/Logo/index.d.ts +1 -1
  536. package/dist/primitives/Menubar/index.cjs +14 -4
  537. package/dist/primitives/Menubar/index.cjs.map +1 -1
  538. package/dist/primitives/Menubar/index.d.cts +1 -1
  539. package/dist/primitives/Menubar/index.d.ts +1 -1
  540. package/dist/primitives/Menubar/index.js +14 -4
  541. package/dist/primitives/Menubar/index.js.map +1 -1
  542. package/dist/primitives/Mosaic/index.cjs +4 -0
  543. package/dist/primitives/Mosaic/index.d.cts +2 -0
  544. package/dist/primitives/Mosaic/index.d.ts +2 -0
  545. package/dist/primitives/Mosaic/index.js +2 -0
  546. package/dist/primitives/NativeSelect/index.cjs +6 -3
  547. package/dist/primitives/NativeSelect/index.cjs.map +1 -1
  548. package/dist/primitives/NativeSelect/index.d.cts +1 -1
  549. package/dist/primitives/NativeSelect/index.d.ts +1 -1
  550. package/dist/primitives/NativeSelect/index.js +5 -3
  551. package/dist/primitives/NativeSelect/index.js.map +1 -1
  552. package/dist/primitives/NavRail/index.d.cts +2 -2
  553. package/dist/primitives/NavRail/index.d.ts +2 -2
  554. package/dist/primitives/NavigationMenu/index.cjs +5 -3
  555. package/dist/primitives/NavigationMenu/index.cjs.map +1 -1
  556. package/dist/primitives/NavigationMenu/index.d.cts +1 -1
  557. package/dist/primitives/NavigationMenu/index.d.ts +1 -1
  558. package/dist/primitives/NavigationMenu/index.js +5 -3
  559. package/dist/primitives/NavigationMenu/index.js.map +1 -1
  560. package/dist/primitives/NotchedCard/index.cjs +390 -0
  561. package/dist/primitives/NotchedCard/index.cjs.map +1 -0
  562. package/dist/primitives/NotchedCard/index.d.cts +2 -0
  563. package/dist/primitives/NotchedCard/index.d.ts +2 -0
  564. package/dist/primitives/NotchedCard/index.js +385 -0
  565. package/dist/primitives/NotchedCard/index.js.map +1 -0
  566. package/dist/primitives/Pagination/index.cjs +6 -2
  567. package/dist/primitives/Pagination/index.cjs.map +1 -1
  568. package/dist/primitives/Pagination/index.d.cts +1 -1
  569. package/dist/primitives/Pagination/index.d.ts +1 -1
  570. package/dist/primitives/Pagination/index.js +6 -2
  571. package/dist/primitives/Pagination/index.js.map +1 -1
  572. package/dist/primitives/Popover/index.cjs +1 -1
  573. package/dist/primitives/Popover/index.d.cts +1 -1
  574. package/dist/primitives/Popover/index.d.ts +1 -1
  575. package/dist/primitives/Popover/index.js +1 -1
  576. package/dist/primitives/Progress/index.cjs +1 -1
  577. package/dist/primitives/Progress/index.d.cts +1 -1
  578. package/dist/primitives/Progress/index.d.ts +1 -1
  579. package/dist/primitives/Progress/index.js +1 -1
  580. package/dist/primitives/RadioGroup/index.cjs +7 -3
  581. package/dist/primitives/RadioGroup/index.cjs.map +1 -1
  582. package/dist/primitives/RadioGroup/index.d.cts +1 -1
  583. package/dist/primitives/RadioGroup/index.d.ts +1 -1
  584. package/dist/primitives/RadioGroup/index.js +7 -3
  585. package/dist/primitives/RadioGroup/index.js.map +1 -1
  586. package/dist/primitives/Resizable/index.cjs +6 -2
  587. package/dist/primitives/Resizable/index.cjs.map +1 -1
  588. package/dist/primitives/Resizable/index.d.cts +1 -1
  589. package/dist/primitives/Resizable/index.d.ts +1 -1
  590. package/dist/primitives/Resizable/index.js +6 -2
  591. package/dist/primitives/Resizable/index.js.map +1 -1
  592. package/dist/primitives/ScrollArea/index.cjs +1 -1
  593. package/dist/primitives/ScrollArea/index.d.cts +1 -1
  594. package/dist/primitives/ScrollArea/index.d.ts +1 -1
  595. package/dist/primitives/ScrollArea/index.js +1 -1
  596. package/dist/primitives/Select/index.cjs +18 -5
  597. package/dist/primitives/Select/index.cjs.map +1 -1
  598. package/dist/primitives/Select/index.d.cts +1 -1
  599. package/dist/primitives/Select/index.d.ts +1 -1
  600. package/dist/primitives/Select/index.js +18 -5
  601. package/dist/primitives/Select/index.js.map +1 -1
  602. package/dist/primitives/Separator/index.cjs +1 -1
  603. package/dist/primitives/Separator/index.js +1 -1
  604. package/dist/primitives/Sheet/index.cjs +40 -4
  605. package/dist/primitives/Sheet/index.cjs.map +1 -1
  606. package/dist/primitives/Sheet/index.d.cts +1 -1
  607. package/dist/primitives/Sheet/index.d.ts +1 -1
  608. package/dist/primitives/Sheet/index.js +40 -4
  609. package/dist/primitives/Sheet/index.js.map +1 -1
  610. package/dist/primitives/Sidebar/index.d.cts +1 -1
  611. package/dist/primitives/Sidebar/index.d.ts +1 -1
  612. package/dist/primitives/Skeleton/index.d.cts +1 -1
  613. package/dist/primitives/Skeleton/index.d.ts +1 -1
  614. package/dist/primitives/Slider/index.cjs +1 -1
  615. package/dist/primitives/Slider/index.d.cts +1 -1
  616. package/dist/primitives/Slider/index.d.ts +1 -1
  617. package/dist/primitives/Slider/index.js +1 -1
  618. package/dist/primitives/Sonner/index.cjs +22 -6
  619. package/dist/primitives/Sonner/index.cjs.map +1 -1
  620. package/dist/primitives/Sonner/index.d.cts +1 -1
  621. package/dist/primitives/Sonner/index.d.ts +1 -1
  622. package/dist/primitives/Sonner/index.js +22 -6
  623. package/dist/primitives/Sonner/index.js.map +1 -1
  624. package/dist/primitives/Spinner/index.cjs +4 -2
  625. package/dist/primitives/Spinner/index.cjs.map +1 -1
  626. package/dist/primitives/Spinner/index.d.cts +1 -1
  627. package/dist/primitives/Spinner/index.d.ts +1 -1
  628. package/dist/primitives/Spinner/index.js +4 -2
  629. package/dist/primitives/Spinner/index.js.map +1 -1
  630. package/dist/primitives/Switch/index.cjs +1 -1
  631. package/dist/primitives/Switch/index.d.cts +1 -1
  632. package/dist/primitives/Switch/index.d.ts +1 -1
  633. package/dist/primitives/Switch/index.js +1 -1
  634. package/dist/primitives/Table/index.d.cts +1 -1
  635. package/dist/primitives/Table/index.d.ts +1 -1
  636. package/dist/primitives/Tabs/index.cjs +2 -2
  637. package/dist/primitives/Tabs/index.d.cts +1 -1
  638. package/dist/primitives/Tabs/index.d.ts +1 -1
  639. package/dist/primitives/Tabs/index.js +2 -2
  640. package/dist/primitives/Text/index.cjs +2 -1
  641. package/dist/primitives/Text/index.cjs.map +1 -1
  642. package/dist/primitives/Text/index.d.cts +1 -1
  643. package/dist/primitives/Text/index.d.ts +1 -1
  644. package/dist/primitives/Text/index.js +1 -1
  645. package/dist/primitives/Textarea/index.cjs +2 -1
  646. package/dist/primitives/Textarea/index.cjs.map +1 -1
  647. package/dist/primitives/Textarea/index.d.cts +1 -1
  648. package/dist/primitives/Textarea/index.d.ts +1 -1
  649. package/dist/primitives/Textarea/index.js +1 -1
  650. package/dist/primitives/ThemeProvider/index.d.cts +1 -1
  651. package/dist/primitives/ThemeProvider/index.d.ts +1 -1
  652. package/dist/primitives/Toggle/index.cjs +3 -2
  653. package/dist/primitives/Toggle/index.cjs.map +1 -1
  654. package/dist/primitives/Toggle/index.d.cts +1 -1
  655. package/dist/primitives/Toggle/index.d.ts +1 -1
  656. package/dist/primitives/Toggle/index.js +2 -2
  657. package/dist/primitives/ToggleGroup/index.cjs +1 -1
  658. package/dist/primitives/ToggleGroup/index.d.cts +1 -1
  659. package/dist/primitives/ToggleGroup/index.d.ts +1 -1
  660. package/dist/primitives/ToggleGroup/index.js +1 -1
  661. package/dist/primitives/Tooltip/index.cjs +1 -1
  662. package/dist/primitives/Tooltip/index.d.cts +1 -1
  663. package/dist/primitives/Tooltip/index.d.ts +1 -1
  664. package/dist/primitives/Tooltip/index.js +1 -1
  665. package/dist/primitives/index.cjs +14 -3
  666. package/dist/primitives/index.d.cts +55 -51
  667. package/dist/primitives/index.d.ts +55 -51
  668. package/dist/primitives/index.js +8 -4
  669. package/package.json +2 -1
  670. package/dist/index47.d.cts.map +0 -1
  671. package/dist/index47.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Header.cjs","names":["PILL","React","cn","Skeleton","ChevronDown","Popover","PopoverTrigger","PopoverContent","Search","Input","ChevronRight","Check","React","React","cn","Logo","Skeleton","useTheme","Button","Moon","Sun","DropdownMenu","DropdownMenuTrigger","Avatar","AvatarFallback","DropdownMenuContent","DropdownMenuLabel","DropdownMenuSeparator","DropdownMenuItem","LogOut","QueryClient","QueryClientProvider","MessageSquareShare","Credits"],"sources":["../src/patterns/Header/project-tree.ts","../src/patterns/Header/ProjectPicker.tsx","../src/patterns/Header/labels.ts","../src/patterns/Header/api.ts","../src/patterns/Header/storage.ts","../src/patterns/Header/header-store.ts","../src/patterns/Header/session.ts","../src/patterns/Header/use-global-header.ts","../src/patterns/Header/Header.tsx"],"sourcesContent":["import type { ProjectNode } from \"./types\";\n\n/** True when a node with the given id exists anywhere in the tree. */\nexport function nodeExistsInTree(tree: ProjectNode[], id: string): boolean {\n return tree.some((node) => node.id === id || nodeExistsInTree(node.children, id));\n}\n\n/** Name of the node with the given id, or undefined. */\nexport function findProjectName(tree: ProjectNode[], id: string): string | undefined {\n for (const node of tree) {\n if (node.id === id) return node.name;\n const found = findProjectName(node.children, id);\n if (found) return found;\n }\n return undefined;\n}\n\n/** First selectable node in the tree (depth-first, skipping context-only ancestors). */\nexport function firstSelectableProject(tree: ProjectNode[]): ProjectNode | undefined {\n for (const node of tree) {\n if (!node.isContextOnly) return node;\n const found = firstSelectableProject(node.children);\n if (found) return found;\n }\n return undefined;\n}\n\n/** Filter the tree to nodes matching `term`, preserving ancestors of matches. */\nexport function filterTree(nodes: ProjectNode[], term: string): ProjectNode[] {\n if (!term) return nodes;\n const lower = term.toLowerCase();\n return nodes.flatMap((node) => {\n if (node.name.toLowerCase().includes(lower)) return [node];\n const children = filterTree(node.children, term);\n return children.length > 0 ? [{ ...node, children }] : [];\n });\n}\n","\"use client\";\n\nimport { Check, ChevronDown, ChevronRight, Search } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { Input } from \"@/primitives/Input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/primitives/Popover\";\nimport { Skeleton } from \"@/primitives/Skeleton\";\nimport { cn } from \"@/utils\";\nimport { filterTree, findProjectName } from \"./project-tree\";\nimport type { ProjectNode } from \"./types\";\n\ninterface ProjectPickerProps {\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n selectedProjectName?: string;\n onSelect: (id: string) => void;\n projectLabel: string;\n projectPlaceholder: string;\n searchPlaceholder: string;\n emptyStateText: string;\n isLoading?: boolean;\n}\n\n// Pill shared by the trigger and the org pill — keeps the header lockup consistent.\nconst PILL =\n \"flex min-h-8 items-center gap-1 rounded-12 border border-primary-border bg-input-bg px-3 py-1 text-xs leading-4\";\n\nexport function ProjectPicker({\n projectsTree,\n selectedProjectId,\n selectedProjectName,\n onSelect,\n projectLabel,\n projectPlaceholder,\n searchPlaceholder,\n emptyStateText,\n isLoading = false,\n}: Readonly<ProjectPickerProps>) {\n const [open, setOpen] = React.useState(false);\n const [searchTerm, setSearchTerm] = React.useState(\"\");\n const [collapsedIds, setCollapsedIds] = React.useState<Set<string>>(new Set());\n\n const toggleCollapse = (id: string) =>\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n\n const handleSelect = (id: string) => {\n onSelect(id);\n setOpen(false);\n };\n\n const selectedName = selectedProjectId\n ? (findProjectName(projectsTree, selectedProjectId) ?? selectedProjectName)\n : undefined;\n\n const filteredTree = filterTree(projectsTree, searchTerm);\n\n if (isLoading) {\n return (\n <div data-slot=\"header-project-picker\" className={cn(PILL, \"min-w-44\")}>\n <span className=\"shrink-0 text-muted-txt\">{projectLabel}:</span>\n <Skeleton className=\"h-3 flex-1\" />\n <ChevronDown className=\"size-4 shrink-0 text-muted-txt opacity-40\" />\n </div>\n );\n }\n\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setSearchTerm(\"\");\n }}\n >\n <PopoverTrigger\n data-slot=\"header-project-picker\"\n className={cn(PILL, \"text-left transition-colors hover:border-focus/60\")}\n >\n <span className=\"shrink-0 text-muted-txt\">{projectLabel}:</span>\n <span className={cn(\"max-w-36 truncate\", selectedName ? \"font-medium\" : \"text-muted-txt\")}>\n {selectedName ?? projectPlaceholder}\n </span>\n <ChevronDown className=\"ml-1 size-4 shrink-0 text-muted-txt\" />\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-64 p-0\" role=\"tree\" aria-label={projectLabel}>\n <div className=\"border-b p-2\">\n <div className=\"relative\">\n <Search className=\"absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-txt\" />\n <Input\n size=\"sm\"\n className=\"pl-8\"\n placeholder={searchPlaceholder}\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n />\n </div>\n </div>\n <div className=\"max-h-64 overflow-y-auto py-1\">\n {filteredTree.length === 0 ? (\n <p className=\"px-1 py-0.5 text-sm text-muted-txt\">{emptyStateText}</p>\n ) : (\n filteredTree.map((node) => (\n <TreeNode\n key={node.id}\n node={node}\n depth={0}\n selectedId={selectedProjectId}\n onSelect={handleSelect}\n collapsedIds={collapsedIds}\n onToggleCollapse={toggleCollapse}\n />\n ))\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\ninterface TreeNodeProps {\n node: ProjectNode;\n depth: number;\n selectedId: string;\n onSelect: (id: string) => void;\n collapsedIds: Set<string>;\n onToggleCollapse: (id: string) => void;\n}\n\nfunction TreeNode({\n node,\n depth,\n selectedId,\n onSelect,\n collapsedIds,\n onToggleCollapse,\n}: Readonly<TreeNodeProps>) {\n const isSelected = !node.isContextOnly && selectedId === node.id;\n const isCollapsed = collapsedIds.has(node.id);\n const hasChildren = node.children.length > 0;\n\n return (\n <div\n role=\"treeitem\"\n aria-selected={node.isContextOnly ? undefined : isSelected}\n aria-expanded={hasChildren ? !isCollapsed : undefined}\n >\n <div\n style={{ paddingLeft: `${0.75 + depth}rem` }}\n className={cn(\n \"flex items-center gap-1 py-2 pr-3 text-sm transition-colors\",\n node.isContextOnly\n ? \"cursor-default text-muted-txt\"\n : \"cursor-pointer hover:bg-ghost-hover-bg\",\n isSelected && \"bg-secondary-bg font-medium\",\n )}\n >\n {hasChildren ? (\n <button\n type=\"button\"\n aria-label={isCollapsed ? `Expand ${node.name}` : `Collapse ${node.name}`}\n onClick={() => onToggleCollapse(node.id)}\n className=\"shrink-0 text-muted-txt hover:text-primary-txt\"\n >\n {isCollapsed ? (\n <ChevronRight className=\"size-3.5\" />\n ) : (\n <ChevronDown className=\"size-3.5\" />\n )}\n </button>\n ) : (\n <span className=\"inline-block w-3.5 shrink-0\" />\n )}\n\n {node.isContextOnly ? (\n <span className=\"flex-1 text-left\">{node.name}</span>\n ) : (\n <button type=\"button\" onClick={() => onSelect(node.id)} className=\"flex-1 text-left\">\n {node.name}\n </button>\n )}\n\n {isSelected && <Check className=\"ml-auto size-3.5 shrink-0 text-primary\" />}\n </div>\n {!isCollapsed && hasChildren && (\n <div role=\"group\">\n {node.children.map((child) => (\n <TreeNode\n key={child.id}\n node={child}\n depth={depth + 1}\n selectedId={selectedId}\n onSelect={onSelect}\n collapsedIds={collapsedIds}\n onToggleCollapse={onToggleCollapse}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n","/** Default UI strings. Spread-override via the Header `labels` prop if needed. */\nexport const DEFAULT_LABELS = {\n orgLabel: \"Org\",\n projectLabel: \"Project\",\n projectPlaceholder: \"Select project...\",\n searchPlaceholder: \"Search project\",\n emptyStateText: \"No projects found\",\n profileMenuLabel: \"Profile menu\",\n logoutLabel: \"Logout\",\n} as const;\n\nexport type Labels = typeof DEFAULT_LABELS;\n","import type { Fetcher, HeaderEndpoints, HeaderProps, ProjectNode } from \"./types\";\n\n// Studio-auth API. Endpoints are built from the host-provided `apiBaseUrl` (full\n// domain) so the same header works across environments/subdomains. All requests\n// send cookies (`credentials: 'include'`); the parent-domain session cookie is\n// readable cross-subdomain.\n\nconst PATHS = {\n token: \"/api/v1/studio-auth/sessions/token\",\n logout: \"/api/v1/studio-auth/sessions/logout\",\n projects: (clientId: string) =>\n `/api/v1/client-projects/getAllProjects?limit=50&page=1&sort=name&sortOrder=ASC&clientId=${encodeURIComponent(clientId)}&metaData=true`,\n credits: \"/save/api/v1/users\",\n};\n\n/** Join a base URL and path without doubling slashes. */\nfunction join(baseUrl: string, path: string): string {\n return `${baseUrl.replace(/\\/$/, \"\")}${path}`;\n}\n\nexport function buildEndpoints(\n apiBaseUrl: string,\n overrides?: HeaderProps[\"endpoints\"],\n): HeaderEndpoints {\n return {\n token: overrides?.token ?? join(apiBaseUrl, PATHS.token),\n logout: overrides?.logout ?? join(apiBaseUrl, PATHS.logout),\n projects:\n overrides?.projects ?? ((clientId: string) => join(apiBaseUrl, PATHS.projects(clientId))),\n credits: overrides?.credits ?? join(apiBaseUrl, PATHS.credits),\n };\n}\n\ntype ApiEnvelope<T> = { response?: { data?: T } };\n\nexport async function fetchToken(endpoints: HeaderEndpoints, fetcher: Fetcher): Promise<string> {\n const res = await fetcher(endpoints.token, { credentials: \"include\" });\n if (!res.ok) throw new Error(`token request failed: ${res.status}`);\n const { accessToken } = (await res.json()) as { accessToken: string };\n return accessToken;\n}\n\nexport async function fetchProjects(\n endpoints: HeaderEndpoints,\n clientId: string,\n accessToken: string,\n fetcher: Fetcher,\n): Promise<{ projectsTree: ProjectNode[]; organizationName: string | undefined }> {\n const res = await fetcher(endpoints.projects(clientId), {\n credentials: \"include\",\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) throw new Error(`projects request failed: ${res.status}`);\n const data = (await res.json()) as ApiEnvelope<{\n projectsTree?: ProjectNode[];\n organization?: { name?: string };\n }>;\n return {\n projectsTree: data.response?.data?.projectsTree ?? [],\n organizationName: data.response?.data?.organization?.name,\n };\n}\n\nexport async function fetchCredits(\n endpoints: HeaderEndpoints,\n accessToken: string,\n fetcher: Fetcher,\n): Promise<number | undefined> {\n const res = await fetcher(endpoints.credits, {\n credentials: \"include\",\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) throw new Error(`credits request failed: ${res.status}`);\n const data = (await res.json()) as { remainingCredits?: number };\n return data.remainingCredits;\n}\n\nexport async function callLogout(endpoints: HeaderEndpoints, fetcher: Fetcher): Promise<void> {\n try {\n await fetcher(endpoints.logout, { method: \"POST\", credentials: \"include\" });\n } finally {\n if (typeof window !== \"undefined\") window.location.href = \"/\";\n }\n}\n","// Persists the user's project selection across reloads (sessionStorage), tagged\n// with the client it belongs to so a stale selection from a different org is\n// discarded on re-login. Explicit selections are additionally remembered in\n// localStorage (`lastSelectedProject`) so new tabs default to the project the\n// user picked last — while each tab keeps its own per-tab selection.\n\nconst PROJECT_KEY = \"ds-header-project\";\nconst LAST_PROJECT_KEY = \"lastSelectedProject\";\n\nexport interface StoredProject {\n id: string;\n name: string;\n clientId?: string;\n}\n\nexport function getStoredProject(): StoredProject | null {\n try {\n const raw = sessionStorage.getItem(PROJECT_KEY);\n return raw ? (JSON.parse(raw) as StoredProject) : null;\n } catch {\n return null;\n }\n}\n\nexport function setStoredProject(project: StoredProject): void {\n try {\n sessionStorage.setItem(PROJECT_KEY, JSON.stringify(project));\n } catch {\n // sessionStorage unavailable — degrade silently\n }\n}\n\nexport function clearStoredProject(): void {\n try {\n sessionStorage.removeItem(PROJECT_KEY);\n } catch {\n // noop\n }\n}\n\n/** The project the user last explicitly selected, in any tab (localStorage). */\nexport function getLastSelectedProject(): StoredProject | null {\n try {\n const raw = localStorage.getItem(LAST_PROJECT_KEY);\n return raw ? (JSON.parse(raw) as StoredProject) : null;\n } catch {\n return null;\n }\n}\n\nexport function setLastSelectedProject(project: StoredProject): void {\n try {\n localStorage.setItem(LAST_PROJECT_KEY, JSON.stringify(project));\n } catch {\n // localStorage unavailable — degrade silently\n }\n}\n","\"use client\";\n\nimport * as React from \"react\";\n\nimport {\n clearStoredProject,\n getStoredProject,\n setLastSelectedProject,\n setStoredProject,\n} from \"./storage\";\n\n// Module-level store for the current project/org selection. Module scope (not\n// React context) so a host app can read and change the selection from anywhere —\n// including components rendered outside the <Header> subtree. The Header is one\n// writer/reader; `useHeaderProject()` gives apps the same access.\n\nexport interface HeaderSelection {\n selectedProjectId: string;\n selectedProjectName: string;\n organizationName: string | undefined;\n /** Remaining credits for the logged-in user (read-only here; set by the Header). */\n credits: number | undefined;\n /** Client/org the current selection + org belong to (for cross-org invalidation). */\n clientId: string | undefined;\n}\n\nfunction initialState(): HeaderSelection {\n const stored = typeof window !== \"undefined\" ? getStoredProject() : null;\n return {\n selectedProjectId: stored?.id ?? \"\",\n selectedProjectName: stored?.name ?? \"\",\n organizationName: undefined,\n credits: undefined,\n clientId: stored?.clientId,\n };\n}\n\nlet state: HeaderSelection = initialState();\n// Stable reference for SSR / first server render.\nconst SERVER_SNAPSHOT: HeaderSelection = Object.freeze({\n selectedProjectId: \"\",\n selectedProjectName: \"\",\n organizationName: undefined,\n credits: undefined,\n clientId: undefined,\n});\n\nconst listeners = new Set<() => void>();\nfunction emit() {\n for (const listener of listeners) listener();\n}\n\nexport const headerStore = {\n subscribe(listener: () => void) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n getSnapshot(): HeaderSelection {\n return state;\n },\n getServerSnapshot(): HeaderSelection {\n return SERVER_SNAPSHOT;\n },\n\n /**\n * Set the selected project. `name` is best-effort; the Header backfills it from\n * the tree. Explicit selections are also remembered in localStorage as the\n * cross-tab default; pass `remember: false` for internal backfill/auto-select\n * writes so they don't overwrite the user's last explicit choice.\n */\n setProject(id: string, name = \"\", clientId?: string, { remember = true } = {}) {\n if (id) {\n const project = { id, name, clientId: clientId ?? state.clientId };\n setStoredProject(project);\n if (remember) setLastSelectedProject(project);\n } else clearStoredProject();\n state = {\n ...state,\n selectedProjectId: id,\n selectedProjectName: name,\n clientId: clientId ?? state.clientId,\n };\n emit();\n },\n\n clearProject() {\n clearStoredProject();\n state = { ...state, selectedProjectId: \"\", selectedProjectName: \"\" };\n emit();\n },\n\n setOrganization(name: string | undefined, clientId?: string) {\n state = { ...state, organizationName: name, clientId: clientId ?? state.clientId };\n emit();\n },\n\n setCredits(credits: number | undefined) {\n if (state.credits === credits) return;\n state = { ...state, credits };\n emit();\n },\n\n /** When the active client changes, drop a selection/org from the previous one. */\n reconcileClient(clientId: string) {\n if (state.clientId === clientId) return;\n if (state.clientId && state.clientId !== clientId) {\n clearStoredProject();\n state = {\n selectedProjectId: \"\",\n selectedProjectName: \"\",\n organizationName: undefined,\n credits: state.credits, // user-level — survives org switches\n clientId,\n };\n } else {\n state = { ...state, clientId };\n }\n emit();\n },\n};\n\n/** Internal: subscribe a component to the selection store. */\nexport function useHeaderStore(): HeaderSelection {\n return React.useSyncExternalStore(\n headerStore.subscribe,\n headerStore.getSnapshot,\n headerStore.getServerSnapshot,\n );\n}\n\nexport interface UseHeaderProjectResult {\n selectedProjectId: string;\n selectedProjectName: string | undefined;\n organizationName: string | undefined;\n /** Set the active project from outside the Header (by id). */\n setProject: (id: string) => void;\n /** Clear this tab's active project (the header re-defaults on next projects load). */\n clearProject: () => void;\n}\n\n/**\n * Read the current project/org and change the project from anywhere in the app —\n * no need to be inside the <Header>. Reflects user selections made in the header\n * and updates the header when changed here.\n */\nexport function useHeaderProject(): UseHeaderProjectResult {\n const snapshot = useHeaderStore();\n return {\n selectedProjectId: snapshot.selectedProjectId,\n selectedProjectName: snapshot.selectedProjectName || undefined,\n organizationName: snapshot.organizationName,\n setProject: React.useCallback((id: string) => headerStore.setProject(id), []),\n clearProject: React.useCallback(() => headerStore.clearProject(), []),\n };\n}\n\n/** Read the logged-in user's remaining credits (read-only; the Header owns it). */\nexport function useHeaderCredits(): number | undefined {\n return useHeaderStore().credits;\n}\n","// Client-side session detection. The auth system writes a JS-readable cookie\n// `{environmentId}-sessionId` (a JWT) on the shared parent domain. We decode it\n// and check its expiry to know whether the user is logged in — no network call.\n\ninterface JwtPayload {\n exp?: number;\n [key: string]: unknown;\n}\n\n/** Read the raw session JWT from the `{environmentId}-sessionId` cookie. */\nexport function getSessionToken(environmentId: string): string | null {\n if (typeof document === \"undefined\") return null;\n const name = `${environmentId}-sessionId`;\n for (const part of document.cookie.split(\";\")) {\n const [key, ...rest] = part.trim().split(\"=\");\n if (key === name) return decodeURIComponent(rest.join(\"=\"));\n }\n return null;\n}\n\n/** Decode a JWT payload without verifying the signature (display/expiry only). */\nexport function decodeJwt(token: string): JwtPayload | null {\n try {\n const payload = token.split(\".\")[1];\n if (!payload) return null;\n const base64 = payload.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const json = atob(base64);\n return JSON.parse(json) as JwtPayload;\n } catch {\n return null;\n }\n}\n\n/** User/session claims carried in the session JWT (the subset the header uses). */\nexport interface SessionClaims {\n email?: string;\n name?: string;\n userId?: string;\n /** Active organisation id (`client_id` claim). */\n clientId?: string;\n exp?: number;\n}\n\n/**\n * Decode the user claims from the session cookie's JWT — no network call.\n * Returns null when the cookie is absent or undecodable.\n */\nexport function getSessionClaims(environmentId: string): SessionClaims | null {\n const token = getSessionToken(environmentId);\n if (!token) return null;\n const payload = decodeJwt(token);\n if (!payload) return null;\n const str = (v: unknown) => (typeof v === \"string\" ? v : undefined);\n return {\n email: str(payload.email),\n name: str(payload.name),\n userId: str(payload.user_id),\n clientId: str(payload.client_id),\n exp: typeof payload.exp === \"number\" ? payload.exp : undefined,\n };\n}\n\n/** True when a valid, unexpired session cookie exists for the environment. */\nexport function isSessionValid(environmentId: string): boolean {\n const token = getSessionToken(environmentId);\n if (!token) return false;\n const payload = decodeJwt(token);\n if (!payload) return false;\n // No exp claim → treat as a non-expiring session.\n if (typeof payload.exp !== \"number\") return true;\n return payload.exp * 1000 > Date.now();\n}\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport * as React from \"react\";\n\nimport { buildEndpoints, callLogout, fetchCredits, fetchProjects, fetchToken } from \"./api\";\nimport { headerStore, useHeaderStore } from \"./header-store\";\nimport { findProjectName, firstSelectableProject, nodeExistsInTree } from \"./project-tree\";\nimport { getSessionClaims, isSessionValid } from \"./session\";\nimport { getLastSelectedProject } from \"./storage\";\nimport type { HeaderProps, ProjectNode } from \"./types\";\n\n/** Window event other modules can dispatch to show/hide the project dropdown. */\nexport const TOGGLE_PROJECT_DROPDOWN_EVENT = \"toggle-project-dropdown\";\nexport interface ToggleProjectDropdownDetail {\n show: boolean;\n}\n\nconst DEFAULT_STALE_TIME = 5 * 60_000;\nconst DEFAULT_GC_TIME = 10 * 60_000;\n\nexport interface GlobalHeaderState {\n /** Whether a valid session cookie exists — when false, hide all user content. */\n isAuthenticated: boolean;\n userEmail: string | undefined;\n organizationName: string | undefined;\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n selectedProjectName: string | undefined;\n isProjectsLoading: boolean;\n isOrgLoading: boolean;\n /** Remaining credits for the user (undefined until loaded / when disabled). */\n credits: number | undefined;\n /** Where the credits pill links to (studio-auth `/user/activity`). */\n creditsHref: string;\n projectDropdownVisible: boolean;\n selectProject: (id: string) => void;\n logout: () => void;\n}\n\ntype UseGlobalHeaderArgs = Pick<\n HeaderProps,\n | \"apiBaseUrl\"\n | \"environmentId\"\n | \"clientId\"\n | \"_dangerouslyInjectAccessToken\"\n | \"showProjectDropdown\"\n | \"showProfile\"\n | \"showOrg\"\n | \"showCredits\"\n | \"endpoints\"\n | \"fetcher\"\n | \"staleTime\"\n | \"gcTime\"\n | \"onProjectChange\"\n>;\n\nexport function useGlobalHeader({\n apiBaseUrl,\n environmentId,\n clientId,\n _dangerouslyInjectAccessToken: injectedToken,\n showProjectDropdown = false,\n showProfile = false,\n showOrg = false,\n showCredits = false,\n endpoints: endpointOverrides,\n fetcher: fetcherProp,\n staleTime = DEFAULT_STALE_TIME,\n gcTime = DEFAULT_GC_TIME,\n onProjectChange,\n}: UseGlobalHeaderArgs): GlobalHeaderState {\n const fetcher = React.useMemo(\n () => fetcherProp ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init)),\n [fetcherProp],\n );\n const endpoints = React.useMemo(\n () => buildEndpoints(apiBaseUrl, endpointOverrides),\n [apiBaseUrl, endpointOverrides],\n );\n\n // Read the session cookie each render (cheap); gates every network call.\n // User identity (email, client id) comes from the JWT claims — no /me call.\n const isAuthenticated = isSessionValid(environmentId);\n const claims = getSessionClaims(environmentId);\n\n // token → projects, enabled only when the previous resolved.\n const tokenQuery = useQuery({\n queryKey: [\"ds-header\", \"token\", endpoints.token],\n queryFn: () => fetchToken(endpoints, fetcher),\n enabled: isAuthenticated && !injectedToken,\n staleTime,\n gcTime,\n });\n const token = injectedToken ?? tokenQuery.data;\n\n const effectiveClientId = clientId ?? claims?.clientId;\n const wantsProjects = showProjectDropdown || showOrg;\n const projectsQuery = useQuery({\n queryKey: [\"ds-header\", \"projects\", effectiveClientId, token],\n queryFn: () => fetchProjects(endpoints, effectiveClientId as string, token as string, fetcher),\n enabled: isAuthenticated && !!token && !!effectiveClientId && wantsProjects,\n staleTime,\n gcTime,\n });\n\n // Credits — only needs the token. Always refetched on mount (staleTime 0) so a\n // page refresh shows the current balance.\n const creditsQuery = useQuery({\n queryKey: [\"ds-header\", \"credits\", endpoints.credits, token],\n queryFn: () => fetchCredits(endpoints, token as string, fetcher),\n enabled: isAuthenticated && !!token && showCredits,\n staleTime: 0,\n gcTime,\n });\n\n const projectsTree = projectsQuery.data?.projectsTree ?? [];\n const userEmail = showProfile ? claims?.email : undefined;\n const creditsHref = React.useMemo(() => {\n try {\n return new URL(\"/user/activity\", apiBaseUrl).toString();\n } catch {\n return \"/user/activity\";\n }\n }, [apiBaseUrl]);\n\n // Selection + org live in a module store so host apps can read/change them\n // from outside the header (see useHeaderProject).\n const selection = useHeaderStore();\n\n // Ref so the auto-select effect sees the latest callback without re-running.\n const onProjectChangeRef = React.useRef(onProjectChange);\n React.useEffect(() => {\n onProjectChangeRef.current = onProjectChange;\n });\n\n // Once the client id resolves, drop a selection/org from a different client.\n React.useEffect(() => {\n if (effectiveClientId) headerStore.reconcileClient(effectiveClientId);\n }, [effectiveClientId]);\n\n // Once projects load: publish the org name and validate/backfill the selection.\n // A tab with no valid selection defaults to the user's last explicitly selected\n // project (localStorage `lastSelectedProject`) when it still exists in the\n // tree, else the first selectable project — no selection prompt.\n React.useEffect(() => {\n if (!projectsQuery.data) return;\n const tree = projectsQuery.data.projectsTree;\n const id = headerStore.getSnapshot().selectedProjectId;\n if (id && nodeExistsInTree(tree, id)) {\n const name = findProjectName(tree, id);\n if (name && name !== headerStore.getSnapshot().selectedProjectName) {\n headerStore.setProject(id, name, effectiveClientId, { remember: false });\n }\n } else {\n const last = getLastSelectedProject();\n const fallback =\n last && nodeExistsInTree(tree, last.id)\n ? { id: last.id, name: findProjectName(tree, last.id) ?? last.name }\n : firstSelectableProject(tree);\n if (fallback) {\n headerStore.setProject(fallback.id, fallback.name, effectiveClientId, {\n remember: false,\n });\n onProjectChangeRef.current?.(fallback.id);\n } else if (id) {\n headerStore.clearProject();\n }\n }\n headerStore.setOrganization(projectsQuery.data.organizationName, effectiveClientId);\n }, [projectsQuery.data, effectiveClientId]);\n\n // Publish credits to the store so host apps can read them via useHeaderCredits.\n React.useEffect(() => {\n if (creditsQuery.data !== undefined) headerStore.setCredits(creditsQuery.data);\n }, [creditsQuery.data]);\n\n const selectProject = (id: string) => {\n const name = findProjectName(projectsTree, id) ?? \"\";\n headerStore.setProject(id, name, effectiveClientId);\n onProjectChange?.(id);\n };\n\n const logout = () => {\n headerStore.clearProject();\n void callLogout(endpoints, fetcher);\n };\n\n // Visibility: declarative from the prop, overridable at runtime via the event.\n const [projectDropdownVisible, setProjectDropdownVisible] = React.useState(showProjectDropdown);\n React.useEffect(() => setProjectDropdownVisible(showProjectDropdown), [showProjectDropdown]);\n React.useEffect(() => {\n const handler = (e: Event) => {\n setProjectDropdownVisible((e as CustomEvent<ToggleProjectDropdownDetail>).detail.show);\n };\n window.addEventListener(TOGGLE_PROJECT_DROPDOWN_EVENT, handler);\n return () => window.removeEventListener(TOGGLE_PROJECT_DROPDOWN_EVENT, handler);\n }, []);\n\n const isProjectsLoading = projectsQuery.isFetching && !projectsQuery.data;\n\n return {\n isAuthenticated,\n userEmail,\n organizationName: selection.organizationName,\n projectsTree,\n selectedProjectId: selection.selectedProjectId,\n selectedProjectName: selection.selectedProjectName || undefined,\n isProjectsLoading,\n isOrgLoading: showOrg && isProjectsLoading,\n credits: selection.credits,\n creditsHref,\n projectDropdownVisible,\n selectProject,\n logout,\n };\n}\n","\"use client\";\n\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { LogOut, MessageSquareShare, Moon, Sun } from \"lucide-react\";\nimport type * as React from \"react\";\n\nimport { Avatar, AvatarFallback } from \"@/primitives/Avatar\";\nimport { Button } from \"@/primitives/Button\";\nimport { Credits } from \"@/primitives/Credits\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/primitives/DropdownMenu\";\nimport { Logo } from \"@/primitives/Logo\";\nimport { Skeleton } from \"@/primitives/Skeleton\";\nimport { type ThemeProduct, useTheme } from \"@/primitives/ThemeProvider\";\nimport { cn } from \"@/utils\";\nimport { ProjectPicker } from \"./ProjectPicker\";\nimport { DEFAULT_LABELS } from \"./labels\";\nimport type { HeaderProps } from \"./types\";\nimport { useGlobalHeader } from \"./use-global-header\";\n\n// Fallback logo destinations when the host doesn't pass `logoHref`.\nconst LOGO_HREF: Record<ThemeProduct, string> = {\n psai: \"https://sapientaiproducts.com/\",\n slingshot: \"https://sapientaiproducts.com/slingshot\",\n sustain: \"https://www.publicissapient.com/\",\n bodhi: \"https://sapientaiproducts.com/bodhi\",\n};\n\nconst PILL =\n \"flex min-h-8 items-center gap-1 rounded-12 border border-primary-border bg-input-bg px-3 py-1 text-xs leading-4\";\n\n// ── Presentational parts (props-driven; Storybook/VR-able) ──────────────────\n\n/** The header bar shell — a sticky glass strip. */\nfunction HeaderBar({ className, ...props }: React.ComponentProps<\"header\">) {\n return (\n <header\n data-slot=\"header\"\n className={cn(\n \"sticky top-1 z-10 mt-1 flex h-15 items-center gap-5 rounded-16 px-3 py-2\",\n \"bg-glass-60-bg backdrop-blur-glass\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** Product logo linking to its home, with a Suspense-safe fallback. */\nfunction HeaderLogo({ brand, href }: { brand: ThemeProduct; href?: string }) {\n return (\n <a href={href ?? LOGO_HREF[brand]} aria-label=\"Go to product home\" data-slot=\"header-logo\">\n <Logo brand={brand} className=\"h-8 w-auto\" />\n </a>\n );\n}\n\n/** Read-only organisation pill. */\nfunction OrgPill({ name, loading }: { name?: string; loading?: boolean }) {\n if (loading && !name) {\n return (\n <div className={cn(PILL, \"ml-3\")} data-slot=\"header-org\">\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <Skeleton className=\"h-4 w-24\" />\n </div>\n );\n }\n if (!name) return null;\n return (\n <div className={cn(PILL, \"ml-3 select-none\")} title={name} data-slot=\"header-org\">\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <span className=\"max-w-36 truncate text-primary-txt\">{name}</span>\n </div>\n );\n}\n\n/** Light/dark toggle — defers to ThemeProvider. */\nfunction ThemeToggle() {\n const { theme, toggleTheme } = useTheme();\n return (\n <Button variant=\"ghost\" size=\"icon\" onClick={toggleTheme} aria-label=\"Toggle theme\">\n {theme === \"light\" ? <Moon className=\"size-4\" /> : <Sun className=\"size-4\" />}\n </Button>\n );\n}\n\n/** Profile menu — avatar trigger with email + logout. */\nfunction ProfileMenu({ email, onLogout }: { email?: string; onLogout: () => void }) {\n const initial = email?.trim().charAt(0).toUpperCase() || \"?\";\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" aria-label={DEFAULT_LABELS.profileMenuLabel}>\n <Avatar className=\"size-7\">\n <AvatarFallback>{initial}</AvatarFallback>\n </Avatar>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" sideOffset={8} className=\"min-w-44\">\n {email && (\n <>\n <DropdownMenuLabel className=\"truncate font-normal text-muted-txt\">\n {email}\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n </>\n )}\n <DropdownMenuItem onSelect={onLogout} variant=\"destructive\">\n <LogOut />\n {DEFAULT_LABELS.logoutLabel}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport { HeaderBar, HeaderLogo, OrgPill, ThemeToggle, ProfileMenu };\n\n// ── Wired Header ─────────────────────────────────────────────────────────────\n\n// Internal singleton client so the header is drop-in (no app setup) while still\n// sharing its cache across mounts/navigation.\nlet sharedClient: QueryClient | undefined;\nfunction getQueryClient(): QueryClient {\n sharedClient ??= new QueryClient({\n defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: false } },\n });\n return sharedClient;\n}\n\n/** Drop-in global header. Must be rendered inside a <ThemeProvider>. */\nexport function Header(props: HeaderProps) {\n return (\n <QueryClientProvider client={getQueryClient()}>\n <HeaderInner {...props} />\n </QueryClientProvider>\n );\n}\n\nfunction HeaderInner({\n logoType,\n logoHref,\n showOrg = false,\n showProjectDropdown = false,\n showProfile = false,\n showThemeSwitcher = false,\n showCredits = false,\n pageTitle,\n feedbackUrl,\n logoAddon,\n actionsStart,\n actionsEnd,\n className,\n ...rest\n}: HeaderProps) {\n const { product } = useTheme();\n const brand = logoType ?? product;\n const state = useGlobalHeader({\n showOrg,\n showProjectDropdown,\n showProfile,\n showCredits,\n ...rest,\n });\n\n // Logged-out users see no user content (project/org/profile/credits).\n const showProjectUi = showProjectDropdown && state.isAuthenticated;\n const showOrgUi = showOrg && state.isAuthenticated;\n const showProfileUi = showProfile && state.isAuthenticated;\n const showCreditsUi = showCredits && state.isAuthenticated && state.credits !== undefined;\n const showActions =\n showThemeSwitcher ||\n showProfileUi ||\n showCreditsUi ||\n !!feedbackUrl ||\n !!actionsStart ||\n !!actionsEnd;\n\n return (\n <HeaderBar className={className}>\n <HeaderLogo brand={brand} href={logoHref} />\n {/* Page title — 20px (gap-5) from the logo. */}\n {pageTitle && (\n <span data-slot=\"header-title\" className=\"ml-5 font-semibold text-primary-txt text-sm\">\n {pageTitle}\n </span>\n )}\n {logoAddon}\n\n {showOrgUi && <OrgPill name={state.organizationName} loading={state.isOrgLoading} />}\n\n {showProjectUi && state.projectDropdownVisible && (\n <div className=\"ml-2\">\n <ProjectPicker\n projectsTree={state.projectsTree}\n selectedProjectId={state.selectedProjectId}\n selectedProjectName={state.selectedProjectName}\n onSelect={state.selectProject}\n projectLabel={DEFAULT_LABELS.projectLabel}\n projectPlaceholder={DEFAULT_LABELS.projectPlaceholder}\n searchPlaceholder={DEFAULT_LABELS.searchPlaceholder}\n emptyStateText={DEFAULT_LABELS.emptyStateText}\n isLoading={state.isProjectsLoading}\n />\n </div>\n )}\n\n {showActions && (\n <div className=\"ml-auto flex items-center gap-2\">\n {actionsStart}\n {feedbackUrl && (\n <Button variant=\"ghost\" size=\"icon\" asChild>\n <a\n href={feedbackUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label=\"Share feedback\"\n >\n <MessageSquareShare className=\"size-4\" />\n </a>\n </Button>\n )}\n {showThemeSwitcher && <ThemeToggle />}\n {showCreditsUi && state.credits !== undefined && (\n <a\n href={state.creditsHref}\n aria-label=\"View credit activity\"\n className=\"rounded-full outline-none focus-visible:ring-3 focus-visible:ring-focus\"\n >\n <Credits value={state.credits} />\n </a>\n )}\n {showProfileUi && <ProfileMenu email={state.userEmail} onLogout={state.logout} />}\n {actionsEnd}\n </div>\n )}\n </HeaderBar>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Header.cjs","names":["PILL","React","cn","Skeleton","Icon","ChevronDown","Popover","PopoverTrigger","PopoverContent","Search","Input","ChevronRight","Check","React","React","cn","Logo","Skeleton","useTheme","Button","Moon","Sun","DropdownMenu","DropdownMenuTrigger","Avatar","AvatarFallback","DropdownMenuContent","DropdownMenuLabel","DropdownMenuSeparator","DropdownMenuItem","LogOut","QueryClient","QueryClientProvider","MessageSquareShare","Credits"],"sources":["../src/patterns/Header/project-tree.ts","../src/patterns/Header/ProjectPicker.tsx","../src/patterns/Header/labels.ts","../src/patterns/Header/api.ts","../src/patterns/Header/storage.ts","../src/patterns/Header/header-store.ts","../src/patterns/Header/session.ts","../src/patterns/Header/use-global-header.ts","../src/patterns/Header/Header.tsx"],"sourcesContent":["import type { ProjectNode } from \"./types\";\n\n/** True when a node with the given id exists anywhere in the tree. */\nexport function nodeExistsInTree(tree: ProjectNode[], id: string): boolean {\n return tree.some((node) => node.id === id || nodeExistsInTree(node.children, id));\n}\n\n/** Name of the node with the given id, or undefined. */\nexport function findProjectName(tree: ProjectNode[], id: string): string | undefined {\n for (const node of tree) {\n if (node.id === id) return node.name;\n const found = findProjectName(node.children, id);\n if (found) return found;\n }\n return undefined;\n}\n\n/** First selectable node in the tree (depth-first, skipping context-only ancestors). */\nexport function firstSelectableProject(tree: ProjectNode[]): ProjectNode | undefined {\n for (const node of tree) {\n if (!node.isContextOnly) return node;\n const found = firstSelectableProject(node.children);\n if (found) return found;\n }\n return undefined;\n}\n\n/** Filter the tree to nodes matching `term`, preserving ancestors of matches. */\nexport function filterTree(nodes: ProjectNode[], term: string): ProjectNode[] {\n if (!term) return nodes;\n const lower = term.toLowerCase();\n return nodes.flatMap((node) => {\n if (node.name.toLowerCase().includes(lower)) return [node];\n const children = filterTree(node.children, term);\n return children.length > 0 ? [{ ...node, children }] : [];\n });\n}\n","\"use client\";\n\nimport { Icon } from \"@/primitives/Icon\";\nimport { Check, ChevronDown, ChevronRight, Search } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { Input } from \"@/primitives/Input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/primitives/Popover\";\nimport { Skeleton } from \"@/primitives/Skeleton\";\nimport { cn } from \"@/utils\";\nimport { filterTree, findProjectName } from \"./project-tree\";\nimport type { ProjectNode } from \"./types\";\n\ninterface ProjectPickerProps {\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n selectedProjectName?: string;\n onSelect: (id: string) => void;\n projectLabel: string;\n projectPlaceholder: string;\n searchPlaceholder: string;\n emptyStateText: string;\n isLoading?: boolean;\n}\n\n// Pill shared by the trigger and the org pill — keeps the header lockup consistent.\nconst PILL =\n \"flex min-h-8 items-center gap-1 rounded-12 border border-primary-border bg-input-bg px-3 py-1 text-xs leading-4\";\n\nexport function ProjectPicker({\n projectsTree,\n selectedProjectId,\n selectedProjectName,\n onSelect,\n projectLabel,\n projectPlaceholder,\n searchPlaceholder,\n emptyStateText,\n isLoading = false,\n}: Readonly<ProjectPickerProps>) {\n const [open, setOpen] = React.useState(false);\n const [searchTerm, setSearchTerm] = React.useState(\"\");\n const [collapsedIds, setCollapsedIds] = React.useState<Set<string>>(new Set());\n\n const toggleCollapse = (id: string) =>\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n\n const handleSelect = (id: string) => {\n onSelect(id);\n setOpen(false);\n };\n\n const selectedName = selectedProjectId\n ? (findProjectName(projectsTree, selectedProjectId) ?? selectedProjectName)\n : undefined;\n\n const filteredTree = filterTree(projectsTree, searchTerm);\n\n if (isLoading) {\n return (\n <div data-slot=\"header-project-picker\" className={cn(PILL, \"min-w-44\")}>\n <span className=\"shrink-0 text-muted-txt\">{projectLabel}:</span>\n <Skeleton className=\"h-3 flex-1\" />\n <Icon as={ChevronDown} className=\"size-4 shrink-0 text-muted-txt opacity-40\" />\n </div>\n );\n }\n\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setSearchTerm(\"\");\n }}\n >\n <PopoverTrigger\n data-slot=\"header-project-picker\"\n className={cn(PILL, \"text-left transition-colors hover:border-focus/60\")}\n >\n <span className=\"shrink-0 text-muted-txt\">{projectLabel}:</span>\n <span className={cn(\"max-w-36 truncate\", selectedName ? \"font-medium\" : \"text-muted-txt\")}>\n {selectedName ?? projectPlaceholder}\n </span>\n <Icon as={ChevronDown} className=\"ml-1 size-4 shrink-0 text-muted-txt\" />\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-64 p-0\" role=\"tree\" aria-label={projectLabel}>\n <div className=\"border-b p-2\">\n <div className=\"relative\">\n <Icon\n as={Search}\n className=\"absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-txt\"\n />\n <Input\n size=\"sm\"\n className=\"pl-8\"\n placeholder={searchPlaceholder}\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n />\n </div>\n </div>\n <div className=\"max-h-64 overflow-y-auto py-1\">\n {filteredTree.length === 0 ? (\n <p className=\"px-1 py-0.5 text-sm text-muted-txt\">{emptyStateText}</p>\n ) : (\n filteredTree.map((node) => (\n <TreeNode\n key={node.id}\n node={node}\n depth={0}\n selectedId={selectedProjectId}\n onSelect={handleSelect}\n collapsedIds={collapsedIds}\n onToggleCollapse={toggleCollapse}\n />\n ))\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\ninterface TreeNodeProps {\n node: ProjectNode;\n depth: number;\n selectedId: string;\n onSelect: (id: string) => void;\n collapsedIds: Set<string>;\n onToggleCollapse: (id: string) => void;\n}\n\nfunction TreeNode({\n node,\n depth,\n selectedId,\n onSelect,\n collapsedIds,\n onToggleCollapse,\n}: Readonly<TreeNodeProps>) {\n const isSelected = !node.isContextOnly && selectedId === node.id;\n const isCollapsed = collapsedIds.has(node.id);\n const hasChildren = node.children.length > 0;\n\n return (\n <div\n role=\"treeitem\"\n aria-selected={node.isContextOnly ? undefined : isSelected}\n aria-expanded={hasChildren ? !isCollapsed : undefined}\n >\n <div\n style={{ paddingLeft: `${0.75 + depth}rem` }}\n className={cn(\n \"flex items-center gap-1 py-2 pr-3 text-sm transition-colors\",\n node.isContextOnly\n ? \"cursor-default text-muted-txt\"\n : \"cursor-pointer hover:bg-ghost-hover-bg\",\n isSelected && \"bg-secondary-bg font-medium\",\n )}\n >\n {hasChildren ? (\n <button\n type=\"button\"\n aria-label={isCollapsed ? `Expand ${node.name}` : `Collapse ${node.name}`}\n onClick={() => onToggleCollapse(node.id)}\n className=\"shrink-0 text-muted-txt hover:text-primary-txt\"\n >\n {isCollapsed ? (\n <Icon as={ChevronRight} className=\"size-3.5\" />\n ) : (\n <Icon as={ChevronDown} className=\"size-3.5\" />\n )}\n </button>\n ) : (\n <span className=\"inline-block w-3.5 shrink-0\" />\n )}\n\n {node.isContextOnly ? (\n <span className=\"flex-1 text-left\">{node.name}</span>\n ) : (\n <button type=\"button\" onClick={() => onSelect(node.id)} className=\"flex-1 text-left\">\n {node.name}\n </button>\n )}\n\n {isSelected && <Icon as={Check} className=\"ml-auto size-3.5 shrink-0 text-primary\" />}\n </div>\n {!isCollapsed && hasChildren && (\n <div role=\"group\">\n {node.children.map((child) => (\n <TreeNode\n key={child.id}\n node={child}\n depth={depth + 1}\n selectedId={selectedId}\n onSelect={onSelect}\n collapsedIds={collapsedIds}\n onToggleCollapse={onToggleCollapse}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n","/** Default UI strings. Spread-override via the Header `labels` prop if needed. */\nexport const DEFAULT_LABELS = {\n orgLabel: \"Org\",\n projectLabel: \"Project\",\n projectPlaceholder: \"Select project...\",\n searchPlaceholder: \"Search project\",\n emptyStateText: \"No projects found\",\n profileMenuLabel: \"Profile menu\",\n logoutLabel: \"Logout\",\n} as const;\n\nexport type Labels = typeof DEFAULT_LABELS;\n","import type { Fetcher, HeaderEndpoints, HeaderProps, ProjectNode } from \"./types\";\n\n// Studio-auth API. Endpoints are built from the host-provided `apiBaseUrl` (full\n// domain) so the same header works across environments/subdomains. All requests\n// send cookies (`credentials: 'include'`); the parent-domain session cookie is\n// readable cross-subdomain.\n\n/** Page size for the paginated projects endpoint. */\nexport const PROJECTS_PAGE_LIMIT = 50;\n/** Hard cap on project pages fetched — guards against a runaway loop. */\nconst PROJECTS_MAX_PAGES = 40;\n\nconst PATHS = {\n token: \"/api/v1/studio-auth/sessions/token\",\n logout: \"/api/v1/studio-auth/sessions/logout\",\n projects: (clientId: string) =>\n `/save/api/v1/client-projects/getAllProjects?limit=${PROJECTS_PAGE_LIMIT}&page=1&sort=name&sortOrder=ASC&clientId=${encodeURIComponent(clientId)}&metaData=true`,\n credits: \"/save/api/v1/users\",\n};\n\n/** Join a base URL and path without doubling slashes. */\nfunction join(baseUrl: string, path: string): string {\n return `${baseUrl.replace(/\\/$/, \"\")}${path}`;\n}\n\nexport function buildEndpoints(\n apiBaseUrl: string,\n overrides?: HeaderProps[\"endpoints\"],\n): HeaderEndpoints {\n return {\n token: overrides?.token ?? join(apiBaseUrl, PATHS.token),\n logout: overrides?.logout ?? join(apiBaseUrl, PATHS.logout),\n projects:\n overrides?.projects ?? ((clientId: string) => join(apiBaseUrl, PATHS.projects(clientId))),\n credits: overrides?.credits ?? join(apiBaseUrl, PATHS.credits),\n };\n}\n\ntype ApiEnvelope<T> = { response?: { data?: T } };\n\nexport async function fetchToken(endpoints: HeaderEndpoints, fetcher: Fetcher): Promise<string> {\n const res = await fetcher(endpoints.token, { credentials: \"include\" });\n if (!res.ok) throw new Error(`token request failed: ${res.status}`);\n const { accessToken } = (await res.json()) as { accessToken: string };\n return accessToken;\n}\n\ntype ProjectsPayload = {\n projectsTree?: ProjectNode[];\n organization?: { name?: string };\n};\n\n/**\n * Return `url` with the `page` query param set to the given page (and `limit`\n * backfilled when absent). Pagination stays owned by the header: host-provided\n * endpoint URLs don't need — and can't break — the paging params. Handles\n * absolute and relative URLs.\n */\nexport function withPageParam(url: string, page: number): string {\n const isAbsolute = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(url);\n try {\n const u = new URL(url, isAbsolute ? undefined : \"http://relative.invalid\");\n u.searchParams.set(\"page\", String(page));\n if (!u.searchParams.has(\"limit\")) u.searchParams.set(\"limit\", String(PROJECTS_PAGE_LIMIT));\n return isAbsolute ? u.toString() : `${u.pathname}${u.search}${u.hash}`;\n } catch {\n return url;\n }\n}\n\n/** The `limit` query param already on a URL, else the default page size. */\nfunction readLimitParam(url: string): number {\n try {\n const limit = Number(new URL(url, \"http://relative.invalid\").searchParams.get(\"limit\"));\n return Number.isInteger(limit) && limit > 0 ? limit : PROJECTS_PAGE_LIMIT;\n } catch {\n return PROJECTS_PAGE_LIMIT;\n }\n}\n\n/** Total node count in a tree page (roots + descendants). */\nfunction countNodes(tree: ProjectNode[]): number {\n return tree.reduce((sum, node) => sum + 1 + countNodes(node.children ?? []), 0);\n}\n\n/**\n * Merge a page's tree into the accumulated tree. Nodes repeated across pages\n * (e.g. a context-only ancestor whose children span a page boundary) are\n * merged by id instead of duplicated.\n */\nfunction mergeTrees(into: ProjectNode[], page: ProjectNode[]): void {\n for (const node of page) {\n const existing = into.find((n) => n.id === node.id);\n if (existing) mergeTrees(existing.children, node.children ?? []);\n else into.push({ ...node, children: [...(node.children ?? [])] });\n }\n}\n\n/**\n * Fetch ALL pages of the paginated projects endpoint and merge them into a\n * single tree, so users with more projects than one page still see everything.\n * The response carries no pagination metadata, so the first page that comes\n * back with fewer than `limit` nodes is treated as the last one.\n */\nexport async function fetchProjects(\n endpoints: HeaderEndpoints,\n clientId: string,\n accessToken: string,\n fetcher: Fetcher,\n): Promise<{ projectsTree: ProjectNode[]; organizationName: string | undefined }> {\n const projectsTree: ProjectNode[] = [];\n let organizationName: string | undefined;\n const baseUrl = endpoints.projects(clientId);\n const pageLimit = readLimitParam(baseUrl);\n\n for (let page = 1; page <= PROJECTS_MAX_PAGES; page++) {\n const res = await fetcher(withPageParam(baseUrl, page), {\n credentials: \"include\",\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) throw new Error(`projects request failed: ${res.status}`);\n const body = (await res.json()) as ApiEnvelope<ProjectsPayload>;\n const pageTree = body.response?.data?.projectsTree ?? [];\n mergeTrees(projectsTree, pageTree);\n organizationName ??= body.response?.data?.organization?.name;\n\n // A short page means there is nothing left.\n if (countNodes(pageTree) < pageLimit) break;\n }\n\n return { projectsTree, organizationName };\n}\n\nexport async function fetchCredits(\n endpoints: HeaderEndpoints,\n accessToken: string,\n fetcher: Fetcher,\n): Promise<number | undefined> {\n const res = await fetcher(endpoints.credits, {\n credentials: \"include\",\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) throw new Error(`credits request failed: ${res.status}`);\n const data = (await res.json()) as { remainingCredits?: number };\n return data.remainingCredits;\n}\n\nexport async function callLogout(endpoints: HeaderEndpoints, fetcher: Fetcher): Promise<void> {\n try {\n await fetcher(endpoints.logout, { method: \"POST\", credentials: \"include\" });\n } finally {\n if (typeof window !== \"undefined\") window.location.href = \"/\";\n }\n}\n","// Persists the user's project selection across reloads (sessionStorage), tagged\n// with the client it belongs to so a stale selection from a different org is\n// discarded on re-login. Explicit selections are additionally remembered in\n// localStorage (`lastSelectedProject`) so new tabs default to the project the\n// user picked last — while each tab keeps its own per-tab selection.\n// The full (all pages, merged) projects result is also cached in sessionStorage\n// so the paginated projects API is hit once per tab session, not on every mount\n// or reload.\n\nimport type { ProjectNode } from \"./types\";\n\nconst PROJECT_KEY = \"ds-header-project\";\nconst LAST_PROJECT_KEY = \"lastSelectedProject\";\nconst PROJECTS_CACHE_KEY = \"ds-header-projects-cache\";\n\nexport interface StoredProject {\n id: string;\n name: string;\n clientId?: string;\n}\n\nexport function getStoredProject(): StoredProject | null {\n try {\n const raw = sessionStorage.getItem(PROJECT_KEY);\n return raw ? (JSON.parse(raw) as StoredProject) : null;\n } catch {\n return null;\n }\n}\n\nexport function setStoredProject(project: StoredProject): void {\n try {\n sessionStorage.setItem(PROJECT_KEY, JSON.stringify(project));\n } catch {\n // sessionStorage unavailable — degrade silently\n }\n}\n\nexport function clearStoredProject(): void {\n try {\n sessionStorage.removeItem(PROJECT_KEY);\n } catch {\n // noop\n }\n}\n\n/** The project the user last explicitly selected, in any tab (localStorage). */\nexport function getLastSelectedProject(): StoredProject | null {\n try {\n const raw = localStorage.getItem(LAST_PROJECT_KEY);\n return raw ? (JSON.parse(raw) as StoredProject) : null;\n } catch {\n return null;\n }\n}\n\nexport function setLastSelectedProject(project: StoredProject): void {\n try {\n localStorage.setItem(LAST_PROJECT_KEY, JSON.stringify(project));\n } catch {\n // localStorage unavailable — degrade silently\n }\n}\n\nexport interface CachedProjects {\n projectsTree: ProjectNode[];\n organizationName: string | undefined;\n}\n\n// Keyed by client id + user id (both from the session JWT) so switching user\n// or organisation misses the cache and refetches instead of serving another\n// identity's projects.\nfunction projectsCacheKey(clientId: string, userId: string): string {\n return `${PROJECTS_CACHE_KEY}:${clientId}:${userId}`;\n}\n\n/** The session-cached projects result for this client + user, or null on miss. */\nexport function getCachedProjects(clientId: string, userId: string): CachedProjects | null {\n try {\n const raw = sessionStorage.getItem(projectsCacheKey(clientId, userId));\n if (!raw) return null;\n const cached = JSON.parse(raw) as Partial<CachedProjects>;\n if (!Array.isArray(cached.projectsTree)) return null;\n return { projectsTree: cached.projectsTree, organizationName: cached.organizationName };\n } catch {\n return null;\n }\n}\n\nexport function setCachedProjects(clientId: string, userId: string, data: CachedProjects): void {\n try {\n sessionStorage.setItem(projectsCacheKey(clientId, userId), JSON.stringify(data));\n } catch {\n // sessionStorage unavailable/full — degrade silently\n }\n}\n\n/** Drop every cached projects entry (all clients/users) — used on logout. */\nexport function clearCachedProjects(): void {\n try {\n for (let i = sessionStorage.length - 1; i >= 0; i--) {\n const key = sessionStorage.key(i);\n if (key?.startsWith(PROJECTS_CACHE_KEY)) sessionStorage.removeItem(key);\n }\n } catch {\n // noop\n }\n}\n","\"use client\";\n\nimport * as React from \"react\";\n\nimport {\n clearStoredProject,\n getStoredProject,\n setLastSelectedProject,\n setStoredProject,\n} from \"./storage\";\n\n// Module-level store for the current project/org selection. Module scope (not\n// React context) so a host app can read and change the selection from anywhere —\n// including components rendered outside the <Header> subtree. The Header is one\n// writer/reader; `useHeaderProject()` gives apps the same access.\n\nexport interface HeaderSelection {\n selectedProjectId: string;\n selectedProjectName: string;\n organizationName: string | undefined;\n /** Remaining credits for the logged-in user (read-only here; set by the Header). */\n credits: number | undefined;\n /** Client/org the current selection + org belong to (for cross-org invalidation). */\n clientId: string | undefined;\n}\n\nfunction initialState(): HeaderSelection {\n const stored = typeof window !== \"undefined\" ? getStoredProject() : null;\n return {\n selectedProjectId: stored?.id ?? \"\",\n selectedProjectName: stored?.name ?? \"\",\n organizationName: undefined,\n credits: undefined,\n clientId: stored?.clientId,\n };\n}\n\nlet state: HeaderSelection = initialState();\n// Stable reference for SSR / first server render.\nconst SERVER_SNAPSHOT: HeaderSelection = Object.freeze({\n selectedProjectId: \"\",\n selectedProjectName: \"\",\n organizationName: undefined,\n credits: undefined,\n clientId: undefined,\n});\n\nconst listeners = new Set<() => void>();\nfunction emit() {\n for (const listener of listeners) listener();\n}\n\nexport const headerStore = {\n subscribe(listener: () => void) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n getSnapshot(): HeaderSelection {\n return state;\n },\n getServerSnapshot(): HeaderSelection {\n return SERVER_SNAPSHOT;\n },\n\n /**\n * Set the selected project. `name` is best-effort; the Header backfills it from\n * the tree. Explicit selections are also remembered in localStorage as the\n * cross-tab default; pass `remember: false` for internal backfill/auto-select\n * writes so they don't overwrite the user's last explicit choice.\n */\n setProject(id: string, name = \"\", clientId?: string, { remember = true } = {}) {\n if (id) {\n const project = { id, name, clientId: clientId ?? state.clientId };\n setStoredProject(project);\n if (remember) setLastSelectedProject(project);\n } else clearStoredProject();\n state = {\n ...state,\n selectedProjectId: id,\n selectedProjectName: name,\n clientId: clientId ?? state.clientId,\n };\n emit();\n },\n\n clearProject() {\n clearStoredProject();\n state = { ...state, selectedProjectId: \"\", selectedProjectName: \"\" };\n emit();\n },\n\n setOrganization(name: string | undefined, clientId?: string) {\n state = { ...state, organizationName: name, clientId: clientId ?? state.clientId };\n emit();\n },\n\n setCredits(credits: number | undefined) {\n if (state.credits === credits) return;\n state = { ...state, credits };\n emit();\n },\n\n /** When the active client changes, drop a selection/org from the previous one. */\n reconcileClient(clientId: string) {\n if (state.clientId === clientId) return;\n if (state.clientId && state.clientId !== clientId) {\n clearStoredProject();\n state = {\n selectedProjectId: \"\",\n selectedProjectName: \"\",\n organizationName: undefined,\n credits: state.credits, // user-level — survives org switches\n clientId,\n };\n } else {\n state = { ...state, clientId };\n }\n emit();\n },\n};\n\n/** Internal: subscribe a component to the selection store. */\nexport function useHeaderStore(): HeaderSelection {\n return React.useSyncExternalStore(\n headerStore.subscribe,\n headerStore.getSnapshot,\n headerStore.getServerSnapshot,\n );\n}\n\nexport interface UseHeaderProjectResult {\n selectedProjectId: string;\n selectedProjectName: string | undefined;\n organizationName: string | undefined;\n /** Set the active project from outside the Header (by id). */\n setProject: (id: string) => void;\n /** Clear this tab's active project (the header re-defaults on next projects load). */\n clearProject: () => void;\n}\n\n/**\n * Read the current project/org and change the project from anywhere in the app —\n * no need to be inside the <Header>. Reflects user selections made in the header\n * and updates the header when changed here.\n */\nexport function useHeaderProject(): UseHeaderProjectResult {\n const snapshot = useHeaderStore();\n return {\n selectedProjectId: snapshot.selectedProjectId,\n selectedProjectName: snapshot.selectedProjectName || undefined,\n organizationName: snapshot.organizationName,\n setProject: React.useCallback((id: string) => headerStore.setProject(id), []),\n clearProject: React.useCallback(() => headerStore.clearProject(), []),\n };\n}\n\n/** Read the logged-in user's remaining credits (read-only; the Header owns it). */\nexport function useHeaderCredits(): number | undefined {\n return useHeaderStore().credits;\n}\n","// Client-side session detection. The auth system writes a JS-readable cookie\n// `{environmentId}-sessionId` (a JWT) on the shared parent domain. We decode it\n// and check its expiry to know whether the user is logged in — no network call.\n\ninterface JwtPayload {\n exp?: number;\n [key: string]: unknown;\n}\n\n/** Read the raw session JWT from the `{environmentId}-sessionId` cookie. */\nexport function getSessionToken(environmentId: string): string | null {\n if (typeof document === \"undefined\") return null;\n const name = `${environmentId}-sessionId`;\n for (const part of document.cookie.split(\";\")) {\n const [key, ...rest] = part.trim().split(\"=\");\n if (key === name) return decodeURIComponent(rest.join(\"=\"));\n }\n return null;\n}\n\n/** Decode a JWT payload without verifying the signature (display/expiry only). */\nexport function decodeJwt(token: string): JwtPayload | null {\n try {\n const payload = token.split(\".\")[1];\n if (!payload) return null;\n const base64 = payload.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const json = atob(base64);\n return JSON.parse(json) as JwtPayload;\n } catch {\n return null;\n }\n}\n\n/** User/session claims carried in the session JWT (the subset the header uses). */\nexport interface SessionClaims {\n email?: string;\n name?: string;\n userId?: string;\n /** Active organisation id (`client_id` claim). */\n clientId?: string;\n exp?: number;\n}\n\n/**\n * Decode the user claims from the session cookie's JWT — no network call.\n * Returns null when the cookie is absent or undecodable.\n */\nexport function getSessionClaims(environmentId: string): SessionClaims | null {\n const token = getSessionToken(environmentId);\n if (!token) return null;\n const payload = decodeJwt(token);\n if (!payload) return null;\n const str = (v: unknown) => (typeof v === \"string\" ? v : undefined);\n return {\n email: str(payload.email),\n name: str(payload.name),\n userId: str(payload.user_id),\n clientId: str(payload.client_id),\n exp: typeof payload.exp === \"number\" ? payload.exp : undefined,\n };\n}\n\n/** True when a valid, unexpired session cookie exists for the environment. */\nexport function isSessionValid(environmentId: string): boolean {\n const token = getSessionToken(environmentId);\n if (!token) return false;\n const payload = decodeJwt(token);\n if (!payload) return false;\n // No exp claim → treat as a non-expiring session.\n if (typeof payload.exp !== \"number\") return true;\n return payload.exp * 1000 > Date.now();\n}\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport * as React from \"react\";\n\nimport { buildEndpoints, callLogout, fetchCredits, fetchProjects, fetchToken } from \"./api\";\nimport { headerStore, useHeaderStore } from \"./header-store\";\nimport { findProjectName, firstSelectableProject, nodeExistsInTree } from \"./project-tree\";\nimport { getSessionClaims, isSessionValid } from \"./session\";\nimport {\n clearCachedProjects,\n getCachedProjects,\n getLastSelectedProject,\n setCachedProjects,\n} from \"./storage\";\nimport type { HeaderProps, ProjectNode } from \"./types\";\n\n/** Window event other modules can dispatch to show/hide the project dropdown. */\nexport const TOGGLE_PROJECT_DROPDOWN_EVENT = \"toggle-project-dropdown\";\nexport interface ToggleProjectDropdownDetail {\n show: boolean;\n}\n\nconst DEFAULT_STALE_TIME = 5 * 60_000;\nconst DEFAULT_GC_TIME = 10 * 60_000;\n\nexport interface GlobalHeaderState {\n /** Whether a valid session cookie exists — when false, hide all user content. */\n isAuthenticated: boolean;\n userEmail: string | undefined;\n organizationName: string | undefined;\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n selectedProjectName: string | undefined;\n isProjectsLoading: boolean;\n isOrgLoading: boolean;\n /** Remaining credits for the user (undefined until loaded / when disabled). */\n credits: number | undefined;\n /** Where the credits pill links to (studio-auth `/user/activity`). */\n creditsHref: string;\n projectDropdownVisible: boolean;\n selectProject: (id: string) => void;\n logout: () => void;\n}\n\ntype UseGlobalHeaderArgs = Pick<\n HeaderProps,\n | \"apiBaseUrl\"\n | \"environmentId\"\n | \"clientId\"\n | \"defaultProjectId\"\n | \"_dangerouslyInjectAccessToken\"\n | \"showProjectDropdown\"\n | \"showProfile\"\n | \"showOrg\"\n | \"showCredits\"\n | \"endpoints\"\n | \"fetcher\"\n | \"staleTime\"\n | \"gcTime\"\n | \"onProjectChange\"\n>;\n\nexport function useGlobalHeader({\n apiBaseUrl,\n environmentId,\n clientId,\n defaultProjectId,\n _dangerouslyInjectAccessToken: injectedToken,\n showProjectDropdown = false,\n showProfile = false,\n showOrg = false,\n showCredits = false,\n endpoints: endpointOverrides,\n fetcher: fetcherProp,\n staleTime = DEFAULT_STALE_TIME,\n gcTime = DEFAULT_GC_TIME,\n onProjectChange,\n}: UseGlobalHeaderArgs): GlobalHeaderState {\n const fetcher = React.useMemo(\n () => fetcherProp ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init)),\n [fetcherProp],\n );\n const endpoints = React.useMemo(\n () => buildEndpoints(apiBaseUrl, endpointOverrides),\n [apiBaseUrl, endpointOverrides],\n );\n\n // Read the session cookie each render (cheap); gates every network call.\n // User identity (email, client id) comes from the JWT claims — no /me call.\n const isAuthenticated = isSessionValid(environmentId);\n const claims = getSessionClaims(environmentId);\n\n // token → projects, enabled only when the previous resolved.\n const tokenQuery = useQuery({\n queryKey: [\"ds-header\", \"token\", endpoints.token],\n queryFn: () => fetchToken(endpoints, fetcher),\n enabled: isAuthenticated && !injectedToken,\n staleTime,\n gcTime,\n });\n const token = injectedToken ?? tokenQuery.data;\n\n const effectiveClientId = clientId ?? claims?.clientId;\n const wantsProjects = showProjectDropdown || showOrg;\n // All pages of the projects API, merged. Served from the sessionStorage\n // cache when present so the API is hit once per tab session — not on every\n // mount, reload, or react-query refetch. The cache is keyed by client id +\n // user id (from the JWT), so a different user or org refetches.\n const userId = claims?.userId ?? \"\";\n const projectsQuery = useQuery({\n queryKey: [\"ds-header\", \"projects\", effectiveClientId, userId, token],\n queryFn: async () => {\n const id = effectiveClientId as string;\n const cached = getCachedProjects(id, userId);\n if (cached) return cached;\n const fresh = await fetchProjects(endpoints, id, token as string, fetcher);\n setCachedProjects(id, userId, fresh);\n return fresh;\n },\n enabled: isAuthenticated && !!token && !!effectiveClientId && wantsProjects,\n staleTime,\n gcTime,\n });\n\n // Credits — only needs the token. Always refetched on mount (staleTime 0) so a\n // page refresh shows the current balance.\n const creditsQuery = useQuery({\n queryKey: [\"ds-header\", \"credits\", endpoints.credits, token],\n queryFn: () => fetchCredits(endpoints, token as string, fetcher),\n enabled: isAuthenticated && !!token && showCredits,\n staleTime: 0,\n gcTime,\n });\n\n const projectsTree = projectsQuery.data?.projectsTree ?? [];\n const userEmail = showProfile ? claims?.email : undefined;\n const creditsHref = React.useMemo(() => {\n try {\n return new URL(\"/user/activity\", apiBaseUrl).toString();\n } catch {\n return \"/user/activity\";\n }\n }, [apiBaseUrl]);\n\n // Selection + org live in a module store so host apps can read/change them\n // from outside the header (see useHeaderProject).\n const selection = useHeaderStore();\n\n // Ref so the auto-select effect sees the latest callback without re-running.\n const onProjectChangeRef = React.useRef(onProjectChange);\n React.useEffect(() => {\n onProjectChangeRef.current = onProjectChange;\n });\n\n // Once the client id resolves, drop a selection/org from a different client.\n React.useEffect(() => {\n if (effectiveClientId) headerStore.reconcileClient(effectiveClientId);\n }, [effectiveClientId]);\n\n // Once projects load: publish the org name and validate/backfill the selection.\n // A tab with no valid selection defaults to the user's last explicitly selected\n // project (localStorage `lastSelectedProject`) when it still exists in the\n // tree, else the host's `defaultProjectId`, else the first selectable\n // project — no selection prompt.\n React.useEffect(() => {\n if (!projectsQuery.data) return;\n const tree = projectsQuery.data.projectsTree;\n const id = headerStore.getSnapshot().selectedProjectId;\n if (id && nodeExistsInTree(tree, id)) {\n const name = findProjectName(tree, id);\n if (name && name !== headerStore.getSnapshot().selectedProjectName) {\n headerStore.setProject(id, name, effectiveClientId, { remember: false });\n }\n } else {\n const last = getLastSelectedProject();\n const fallback =\n last && nodeExistsInTree(tree, last.id)\n ? { id: last.id, name: findProjectName(tree, last.id) ?? last.name }\n : defaultProjectId && nodeExistsInTree(tree, defaultProjectId)\n ? { id: defaultProjectId, name: findProjectName(tree, defaultProjectId) ?? \"\" }\n : firstSelectableProject(tree);\n if (fallback) {\n headerStore.setProject(fallback.id, fallback.name, effectiveClientId, {\n remember: false,\n });\n onProjectChangeRef.current?.(fallback.id);\n } else if (id) {\n headerStore.clearProject();\n }\n }\n headerStore.setOrganization(projectsQuery.data.organizationName, effectiveClientId);\n }, [projectsQuery.data, effectiveClientId, defaultProjectId]);\n\n // Publish credits to the store so host apps can read them via useHeaderCredits.\n React.useEffect(() => {\n if (creditsQuery.data !== undefined) headerStore.setCredits(creditsQuery.data);\n }, [creditsQuery.data]);\n\n const selectProject = (id: string) => {\n const name = findProjectName(projectsTree, id) ?? \"\";\n headerStore.setProject(id, name, effectiveClientId);\n onProjectChange?.(id);\n };\n\n const logout = () => {\n headerStore.clearProject();\n clearCachedProjects();\n void callLogout(endpoints, fetcher);\n };\n\n // Visibility: declarative from the prop, overridable at runtime via the event.\n const [projectDropdownVisible, setProjectDropdownVisible] = React.useState(showProjectDropdown);\n React.useEffect(() => setProjectDropdownVisible(showProjectDropdown), [showProjectDropdown]);\n React.useEffect(() => {\n const handler = (e: Event) => {\n setProjectDropdownVisible((e as CustomEvent<ToggleProjectDropdownDetail>).detail.show);\n };\n window.addEventListener(TOGGLE_PROJECT_DROPDOWN_EVENT, handler);\n return () => window.removeEventListener(TOGGLE_PROJECT_DROPDOWN_EVENT, handler);\n }, []);\n\n const isProjectsLoading = projectsQuery.isFetching && !projectsQuery.data;\n\n return {\n isAuthenticated,\n userEmail,\n organizationName: selection.organizationName,\n projectsTree,\n selectedProjectId: selection.selectedProjectId,\n selectedProjectName: selection.selectedProjectName || undefined,\n isProjectsLoading,\n isOrgLoading: showOrg && isProjectsLoading,\n credits: selection.credits,\n creditsHref,\n projectDropdownVisible,\n selectProject,\n logout,\n };\n}\n","\"use client\";\n\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { LogOut, MessageSquareShare, Moon, Sun } from \"lucide-react\";\nimport type * as React from \"react\";\n\nimport { Avatar, AvatarFallback } from \"@/primitives/Avatar\";\nimport { Button } from \"@/primitives/Button\";\nimport { Credits } from \"@/primitives/Credits\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/primitives/DropdownMenu\";\nimport { Logo } from \"@/primitives/Logo\";\nimport { Skeleton } from \"@/primitives/Skeleton\";\nimport { type ThemeProduct, useTheme } from \"@/primitives/ThemeProvider\";\nimport { cn } from \"@/utils\";\nimport { ProjectPicker } from \"./ProjectPicker\";\nimport { DEFAULT_LABELS } from \"./labels\";\nimport type { HeaderProps } from \"./types\";\nimport { useGlobalHeader } from \"./use-global-header\";\n\n// Fallback logo destinations when the host doesn't pass `logoHref`.\nconst LOGO_HREF: Record<ThemeProduct, string> = {\n psai: \"https://sapientaiproducts.com/\",\n slingshot: \"https://sapientaiproducts.com/slingshot\",\n sustain: \"https://www.publicissapient.com/\",\n bodhi: \"https://sapientaiproducts.com/bodhi\",\n};\n\nconst PILL =\n \"flex min-h-8 items-center gap-1 rounded-12 border border-primary-border bg-input-bg px-3 py-1 text-xs leading-4\";\n\n// ── Presentational parts (props-driven; Storybook/VR-able) ──────────────────\n\n/** The header bar shell — a sticky glass strip. */\nfunction HeaderBar({ className, ...props }: React.ComponentProps<\"header\">) {\n return (\n <header\n data-slot=\"header\"\n className={cn(\n \"sticky top-1 z-10 mt-1 flex h-15 items-center gap-5 rounded-16 px-3 py-2\",\n \"bg-glass-60-bg backdrop-blur-glass\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** Product logo linking to its home, with a Suspense-safe fallback. */\nfunction HeaderLogo({ brand, href }: { brand: ThemeProduct; href?: string }) {\n return (\n <a href={href ?? LOGO_HREF[brand]} aria-label=\"Go to product home\" data-slot=\"header-logo\">\n <Logo brand={brand} className=\"h-8 w-auto\" />\n </a>\n );\n}\n\n/** Read-only organisation pill. */\nfunction OrgPill({ name, loading }: { name?: string; loading?: boolean }) {\n if (loading && !name) {\n return (\n <div className={cn(PILL, \"ml-3\")} data-slot=\"header-org\">\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <Skeleton className=\"h-4 w-24\" />\n </div>\n );\n }\n if (!name) return null;\n return (\n <div className={cn(PILL, \"ml-3 select-none\")} title={name} data-slot=\"header-org\">\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <span className=\"max-w-36 truncate text-primary-txt\">{name}</span>\n </div>\n );\n}\n\n/** Light/dark toggle — defers to ThemeProvider. */\nfunction ThemeToggle() {\n const { theme, toggleTheme } = useTheme();\n return (\n <Button variant=\"ghost\" size=\"icon\" onClick={toggleTheme} aria-label=\"Toggle theme\">\n {theme === \"light\" ? <Moon className=\"size-4\" /> : <Sun className=\"size-4\" />}\n </Button>\n );\n}\n\n/** Profile menu — avatar trigger with email + logout. */\nfunction ProfileMenu({ email, onLogout }: { email?: string; onLogout: () => void }) {\n const initial = email?.trim().charAt(0).toUpperCase() || \"?\";\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" aria-label={DEFAULT_LABELS.profileMenuLabel}>\n <Avatar className=\"size-7\">\n <AvatarFallback>{initial}</AvatarFallback>\n </Avatar>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" sideOffset={8} className=\"min-w-44\">\n {email && (\n <>\n <DropdownMenuLabel className=\"truncate font-normal text-muted-txt\">\n {email}\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n </>\n )}\n <DropdownMenuItem onSelect={onLogout} variant=\"destructive\">\n <LogOut />\n {DEFAULT_LABELS.logoutLabel}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport { HeaderBar, HeaderLogo, OrgPill, ThemeToggle, ProfileMenu };\n\n// ── Wired Header ─────────────────────────────────────────────────────────────\n\n// Internal singleton client so the header is drop-in (no app setup) while still\n// sharing its cache across mounts/navigation.\nlet sharedClient: QueryClient | undefined;\nfunction getQueryClient(): QueryClient {\n sharedClient ??= new QueryClient({\n defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: false } },\n });\n return sharedClient;\n}\n\n/** Drop-in global header. Must be rendered inside a <ThemeProvider>. */\nexport function Header(props: HeaderProps) {\n return (\n <QueryClientProvider client={getQueryClient()}>\n <HeaderInner {...props} />\n </QueryClientProvider>\n );\n}\n\nfunction HeaderInner({\n logoType,\n logoHref,\n showOrg = false,\n showProjectDropdown = false,\n showProfile = false,\n showThemeSwitcher = false,\n showCredits = false,\n pageTitle,\n feedbackUrl,\n logoAddon,\n actionsStart,\n actionsEnd,\n className,\n ...rest\n}: HeaderProps) {\n const { product } = useTheme();\n const brand = logoType ?? product;\n const state = useGlobalHeader({\n showOrg,\n showProjectDropdown,\n showProfile,\n showCredits,\n ...rest,\n });\n\n // Logged-out users see no user content (project/org/profile/credits).\n const showProjectUi = showProjectDropdown && state.isAuthenticated;\n const showOrgUi = showOrg && state.isAuthenticated;\n const showProfileUi = showProfile && state.isAuthenticated;\n const showCreditsUi = showCredits && state.isAuthenticated && state.credits !== undefined;\n const showActions =\n showThemeSwitcher ||\n showProfileUi ||\n showCreditsUi ||\n !!feedbackUrl ||\n !!actionsStart ||\n !!actionsEnd;\n\n return (\n <HeaderBar className={className}>\n <HeaderLogo brand={brand} href={logoHref} />\n {/* Page title — 20px (gap-5) from the logo. */}\n {pageTitle && (\n <span data-slot=\"header-title\" className=\"ml-5 font-semibold text-primary-txt text-sm\">\n {pageTitle}\n </span>\n )}\n {logoAddon}\n\n {showOrgUi && <OrgPill name={state.organizationName} loading={state.isOrgLoading} />}\n\n {showProjectUi && state.projectDropdownVisible && (\n <div className=\"ml-2\">\n <ProjectPicker\n projectsTree={state.projectsTree}\n selectedProjectId={state.selectedProjectId}\n selectedProjectName={state.selectedProjectName}\n onSelect={state.selectProject}\n projectLabel={DEFAULT_LABELS.projectLabel}\n projectPlaceholder={DEFAULT_LABELS.projectPlaceholder}\n searchPlaceholder={DEFAULT_LABELS.searchPlaceholder}\n emptyStateText={DEFAULT_LABELS.emptyStateText}\n isLoading={state.isProjectsLoading}\n />\n </div>\n )}\n\n {showActions && (\n <div className=\"ml-auto flex items-center gap-2\">\n {actionsStart}\n {feedbackUrl && (\n <Button variant=\"ghost\" size=\"icon\" asChild>\n <a\n href={feedbackUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label=\"Share feedback\"\n >\n <MessageSquareShare className=\"size-4\" />\n </a>\n </Button>\n )}\n {showThemeSwitcher && <ThemeToggle />}\n {showCreditsUi && state.credits !== undefined && (\n <a\n href={state.creditsHref}\n aria-label=\"View credit activity\"\n className=\"rounded-full outline-none focus-visible:ring-3 focus-visible:ring-focus\"\n >\n <Credits value={state.credits} />\n </a>\n )}\n {showProfileUi && <ProfileMenu email={state.userEmail} onLogout={state.logout} />}\n {actionsEnd}\n </div>\n )}\n </HeaderBar>\n );\n}\n"],"mappings":"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"}
package/dist/Header.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { t as cn } from "./cn.js";
2
+ import { t as Icon } from "./Icon.js";
2
3
  import { Button } from "./primitives/Button/index.js";
3
4
  import { Avatar, AvatarFallback } from "./primitives/Avatar/index.js";
4
5
  import { Credits } from "./primitives/Credits/index.js";
@@ -9,8 +10,8 @@ import { Popover, PopoverContent, PopoverTrigger } from "./primitives/Popover/in
9
10
  import { Skeleton } from "./primitives/Skeleton/index.js";
10
11
  import { useTheme } from "./primitives/ThemeProvider/index.js";
11
12
  import * as React from "react";
12
- import { Check, ChevronDown, ChevronRight, LogOut, MessageSquareShare, Moon, Search, Sun } from "lucide-react";
13
13
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
14
+ import { Check, ChevronDown, ChevronRight, LogOut, MessageSquareShare, Moon, Search, Sun } from "lucide-react";
14
15
  import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
15
16
  //#region src/patterns/Header/project-tree.ts
16
17
  /** True when a node with the given id exists anywhere in the tree. */
@@ -74,7 +75,10 @@ function ProjectPicker({ projectsTree, selectedProjectId, selectedProjectName, o
74
75
  children: [projectLabel, ":"]
75
76
  }),
76
77
  /* @__PURE__ */ jsx(Skeleton, { className: "h-3 flex-1" }),
77
- /* @__PURE__ */ jsx(ChevronDown, { className: "size-4 shrink-0 text-muted-txt opacity-40" })
78
+ /* @__PURE__ */ jsx(Icon, {
79
+ as: ChevronDown,
80
+ className: "size-4 shrink-0 text-muted-txt opacity-40"
81
+ })
78
82
  ]
79
83
  });
80
84
  return /* @__PURE__ */ jsxs(Popover, {
@@ -95,7 +99,10 @@ function ProjectPicker({ projectsTree, selectedProjectId, selectedProjectName, o
95
99
  className: cn("max-w-36 truncate", selectedName ? "font-medium" : "text-muted-txt"),
96
100
  children: selectedName ?? projectPlaceholder
97
101
  }),
98
- /* @__PURE__ */ jsx(ChevronDown, { className: "ml-1 size-4 shrink-0 text-muted-txt" })
102
+ /* @__PURE__ */ jsx(Icon, {
103
+ as: ChevronDown,
104
+ className: "ml-1 size-4 shrink-0 text-muted-txt"
105
+ })
99
106
  ]
100
107
  }), /* @__PURE__ */ jsxs(PopoverContent, {
101
108
  align: "start",
@@ -106,7 +113,10 @@ function ProjectPicker({ projectsTree, selectedProjectId, selectedProjectName, o
106
113
  className: "border-b p-2",
107
114
  children: /* @__PURE__ */ jsxs("div", {
108
115
  className: "relative",
109
- children: [/* @__PURE__ */ jsx(Search, { className: "absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-txt" }), /* @__PURE__ */ jsx(Input, {
116
+ children: [/* @__PURE__ */ jsx(Icon, {
117
+ as: Search,
118
+ className: "absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-txt"
119
+ }), /* @__PURE__ */ jsx(Input, {
110
120
  size: "sm",
111
121
  className: "pl-8",
112
122
  placeholder: searchPlaceholder,
@@ -148,7 +158,13 @@ function TreeNode({ node, depth, selectedId, onSelect, collapsedIds, onToggleCol
148
158
  "aria-label": isCollapsed ? `Expand ${node.name}` : `Collapse ${node.name}`,
149
159
  onClick: () => onToggleCollapse(node.id),
150
160
  className: "shrink-0 text-muted-txt hover:text-primary-txt",
151
- children: isCollapsed ? /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5" })
161
+ children: isCollapsed ? /* @__PURE__ */ jsx(Icon, {
162
+ as: ChevronRight,
163
+ className: "size-3.5"
164
+ }) : /* @__PURE__ */ jsx(Icon, {
165
+ as: ChevronDown,
166
+ className: "size-3.5"
167
+ })
152
168
  }) : /* @__PURE__ */ jsx("span", { className: "inline-block w-3.5 shrink-0" }),
153
169
  node.isContextOnly ? /* @__PURE__ */ jsx("span", {
154
170
  className: "flex-1 text-left",
@@ -159,7 +175,10 @@ function TreeNode({ node, depth, selectedId, onSelect, collapsedIds, onToggleCol
159
175
  className: "flex-1 text-left",
160
176
  children: node.name
161
177
  }),
162
- isSelected && /* @__PURE__ */ jsx(Check, { className: "ml-auto size-3.5 shrink-0 text-primary" })
178
+ isSelected && /* @__PURE__ */ jsx(Icon, {
179
+ as: Check,
180
+ className: "ml-auto size-3.5 shrink-0 text-primary"
181
+ })
163
182
  ]
164
183
  }), !isCollapsed && hasChildren && /* @__PURE__ */ jsx("div", {
165
184
  role: "group",
@@ -186,12 +205,12 @@ const DEFAULT_LABELS = {
186
205
  profileMenuLabel: "Profile menu",
187
206
  logoutLabel: "Logout"
188
207
  };
189
- //#endregion
190
- //#region src/patterns/Header/api.ts
208
+ /** Hard cap on project pages fetched — guards against a runaway loop. */
209
+ const PROJECTS_MAX_PAGES = 40;
191
210
  const PATHS = {
192
211
  token: "/api/v1/studio-auth/sessions/token",
193
212
  logout: "/api/v1/studio-auth/sessions/logout",
194
- projects: (clientId) => `/api/v1/client-projects/getAllProjects?limit=50&page=1&sort=name&sortOrder=ASC&clientId=${encodeURIComponent(clientId)}&metaData=true`,
213
+ projects: (clientId) => `/save/api/v1/client-projects/getAllProjects?limit=50&page=1&sort=name&sortOrder=ASC&clientId=${encodeURIComponent(clientId)}&metaData=true`,
195
214
  credits: "/save/api/v1/users"
196
215
  };
197
216
  /** Join a base URL and path without doubling slashes. */
@@ -212,16 +231,77 @@ async function fetchToken(endpoints, fetcher) {
212
231
  const { accessToken } = await res.json();
213
232
  return accessToken;
214
233
  }
234
+ /**
235
+ * Return `url` with the `page` query param set to the given page (and `limit`
236
+ * backfilled when absent). Pagination stays owned by the header: host-provided
237
+ * endpoint URLs don't need — and can't break — the paging params. Handles
238
+ * absolute and relative URLs.
239
+ */
240
+ function withPageParam(url, page) {
241
+ const isAbsolute = /^[a-z][a-z0-9+.-]*:\/\//i.test(url);
242
+ try {
243
+ const u = new URL(url, isAbsolute ? void 0 : "http://relative.invalid");
244
+ u.searchParams.set("page", String(page));
245
+ if (!u.searchParams.has("limit")) u.searchParams.set("limit", String(50));
246
+ return isAbsolute ? u.toString() : `${u.pathname}${u.search}${u.hash}`;
247
+ } catch {
248
+ return url;
249
+ }
250
+ }
251
+ /** The `limit` query param already on a URL, else the default page size. */
252
+ function readLimitParam(url) {
253
+ try {
254
+ const limit = Number(new URL(url, "http://relative.invalid").searchParams.get("limit"));
255
+ return Number.isInteger(limit) && limit > 0 ? limit : 50;
256
+ } catch {
257
+ return 50;
258
+ }
259
+ }
260
+ /** Total node count in a tree page (roots + descendants). */
261
+ function countNodes(tree) {
262
+ return tree.reduce((sum, node) => sum + 1 + countNodes(node.children ?? []), 0);
263
+ }
264
+ /**
265
+ * Merge a page's tree into the accumulated tree. Nodes repeated across pages
266
+ * (e.g. a context-only ancestor whose children span a page boundary) are
267
+ * merged by id instead of duplicated.
268
+ */
269
+ function mergeTrees(into, page) {
270
+ for (const node of page) {
271
+ const existing = into.find((n) => n.id === node.id);
272
+ if (existing) mergeTrees(existing.children, node.children ?? []);
273
+ else into.push({
274
+ ...node,
275
+ children: [...node.children ?? []]
276
+ });
277
+ }
278
+ }
279
+ /**
280
+ * Fetch ALL pages of the paginated projects endpoint and merge them into a
281
+ * single tree, so users with more projects than one page still see everything.
282
+ * The response carries no pagination metadata, so the first page that comes
283
+ * back with fewer than `limit` nodes is treated as the last one.
284
+ */
215
285
  async function fetchProjects(endpoints, clientId, accessToken, fetcher) {
216
- const res = await fetcher(endpoints.projects(clientId), {
217
- credentials: "include",
218
- headers: { Authorization: `Bearer ${accessToken}` }
219
- });
220
- if (!res.ok) throw new Error(`projects request failed: ${res.status}`);
221
- const data = await res.json();
286
+ const projectsTree = [];
287
+ let organizationName;
288
+ const baseUrl = endpoints.projects(clientId);
289
+ const pageLimit = readLimitParam(baseUrl);
290
+ for (let page = 1; page <= PROJECTS_MAX_PAGES; page++) {
291
+ const res = await fetcher(withPageParam(baseUrl, page), {
292
+ credentials: "include",
293
+ headers: { Authorization: `Bearer ${accessToken}` }
294
+ });
295
+ if (!res.ok) throw new Error(`projects request failed: ${res.status}`);
296
+ const body = await res.json();
297
+ const pageTree = body.response?.data?.projectsTree ?? [];
298
+ mergeTrees(projectsTree, pageTree);
299
+ organizationName ??= body.response?.data?.organization?.name;
300
+ if (countNodes(pageTree) < pageLimit) break;
301
+ }
222
302
  return {
223
- projectsTree: data.response?.data?.projectsTree ?? [],
224
- organizationName: data.response?.data?.organization?.name
303
+ projectsTree,
304
+ organizationName
225
305
  };
226
306
  }
227
307
  async function fetchCredits(endpoints, accessToken, fetcher) {
@@ -246,6 +326,7 @@ async function callLogout(endpoints, fetcher) {
246
326
  //#region src/patterns/Header/storage.ts
247
327
  const PROJECT_KEY = "ds-header-project";
248
328
  const LAST_PROJECT_KEY = "lastSelectedProject";
329
+ const PROJECTS_CACHE_KEY = "ds-header-projects-cache";
249
330
  function getStoredProject() {
250
331
  try {
251
332
  const raw = sessionStorage.getItem(PROJECT_KEY);
@@ -278,6 +359,38 @@ function setLastSelectedProject(project) {
278
359
  localStorage.setItem(LAST_PROJECT_KEY, JSON.stringify(project));
279
360
  } catch {}
280
361
  }
362
+ function projectsCacheKey(clientId, userId) {
363
+ return `${PROJECTS_CACHE_KEY}:${clientId}:${userId}`;
364
+ }
365
+ /** The session-cached projects result for this client + user, or null on miss. */
366
+ function getCachedProjects(clientId, userId) {
367
+ try {
368
+ const raw = sessionStorage.getItem(projectsCacheKey(clientId, userId));
369
+ if (!raw) return null;
370
+ const cached = JSON.parse(raw);
371
+ if (!Array.isArray(cached.projectsTree)) return null;
372
+ return {
373
+ projectsTree: cached.projectsTree,
374
+ organizationName: cached.organizationName
375
+ };
376
+ } catch {
377
+ return null;
378
+ }
379
+ }
380
+ function setCachedProjects(clientId, userId, data) {
381
+ try {
382
+ sessionStorage.setItem(projectsCacheKey(clientId, userId), JSON.stringify(data));
383
+ } catch {}
384
+ }
385
+ /** Drop every cached projects entry (all clients/users) — used on logout. */
386
+ function clearCachedProjects() {
387
+ try {
388
+ for (let i = sessionStorage.length - 1; i >= 0; i--) {
389
+ const key = sessionStorage.key(i);
390
+ if (key?.startsWith(PROJECTS_CACHE_KEY)) sessionStorage.removeItem(key);
391
+ }
392
+ } catch {}
393
+ }
281
394
  //#endregion
282
395
  //#region src/patterns/Header/header-store.ts
283
396
  function initialState() {
@@ -461,7 +574,7 @@ function isSessionValid(environmentId) {
461
574
  const TOGGLE_PROJECT_DROPDOWN_EVENT = "toggle-project-dropdown";
462
575
  const DEFAULT_STALE_TIME = 5 * 6e4;
463
576
  const DEFAULT_GC_TIME = 10 * 6e4;
464
- function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInjectAccessToken: injectedToken, showProjectDropdown = false, showProfile = false, showOrg = false, showCredits = false, endpoints: endpointOverrides, fetcher: fetcherProp, staleTime = DEFAULT_STALE_TIME, gcTime = DEFAULT_GC_TIME, onProjectChange }) {
577
+ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, defaultProjectId, _dangerouslyInjectAccessToken: injectedToken, showProjectDropdown = false, showProfile = false, showOrg = false, showCredits = false, endpoints: endpointOverrides, fetcher: fetcherProp, staleTime = DEFAULT_STALE_TIME, gcTime = DEFAULT_GC_TIME, onProjectChange }) {
465
578
  const fetcher = React.useMemo(() => fetcherProp ?? ((input, init) => fetch(input, init)), [fetcherProp]);
466
579
  const endpoints = React.useMemo(() => buildEndpoints(apiBaseUrl, endpointOverrides), [apiBaseUrl, endpointOverrides]);
467
580
  const isAuthenticated = isSessionValid(environmentId);
@@ -479,15 +592,25 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
479
592
  });
480
593
  const token = injectedToken ?? tokenQuery.data;
481
594
  const effectiveClientId = clientId ?? claims?.clientId;
595
+ const wantsProjects = showProjectDropdown || showOrg;
596
+ const userId = claims?.userId ?? "";
482
597
  const projectsQuery = useQuery({
483
598
  queryKey: [
484
599
  "ds-header",
485
600
  "projects",
486
601
  effectiveClientId,
602
+ userId,
487
603
  token
488
604
  ],
489
- queryFn: () => fetchProjects(endpoints, effectiveClientId, token, fetcher),
490
- enabled: isAuthenticated && !!token && !!effectiveClientId && (showProjectDropdown || showOrg),
605
+ queryFn: async () => {
606
+ const id = effectiveClientId;
607
+ const cached = getCachedProjects(id, userId);
608
+ if (cached) return cached;
609
+ const fresh = await fetchProjects(endpoints, id, token, fetcher);
610
+ setCachedProjects(id, userId, fresh);
611
+ return fresh;
612
+ },
613
+ enabled: isAuthenticated && !!token && !!effectiveClientId && wantsProjects,
491
614
  staleTime,
492
615
  gcTime
493
616
  });
@@ -532,6 +655,9 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
532
655
  const fallback = last && nodeExistsInTree(tree, last.id) ? {
533
656
  id: last.id,
534
657
  name: findProjectName(tree, last.id) ?? last.name
658
+ } : defaultProjectId && nodeExistsInTree(tree, defaultProjectId) ? {
659
+ id: defaultProjectId,
660
+ name: findProjectName(tree, defaultProjectId) ?? ""
535
661
  } : firstSelectableProject(tree);
536
662
  if (fallback) {
537
663
  headerStore.setProject(fallback.id, fallback.name, effectiveClientId, { remember: false });
@@ -539,7 +665,11 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
539
665
  } else if (id) headerStore.clearProject();
540
666
  }
541
667
  headerStore.setOrganization(projectsQuery.data.organizationName, effectiveClientId);
542
- }, [projectsQuery.data, effectiveClientId]);
668
+ }, [
669
+ projectsQuery.data,
670
+ effectiveClientId,
671
+ defaultProjectId
672
+ ]);
543
673
  React.useEffect(() => {
544
674
  if (creditsQuery.data !== void 0) headerStore.setCredits(creditsQuery.data);
545
675
  }, [creditsQuery.data]);
@@ -550,6 +680,7 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
550
680
  };
551
681
  const logout = () => {
552
682
  headerStore.clearProject();
683
+ clearCachedProjects();
553
684
  callLogout(endpoints, fetcher);
554
685
  };
555
686
  const [projectDropdownVisible, setProjectDropdownVisible] = React.useState(showProjectDropdown);