@psnext/design-system 2.3.0 → 2.4.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 (488) hide show
  1. package/DESIGN.md +466 -4
  2. package/README.md +3 -3
  3. package/SKILL.md +83 -5
  4. package/bin/install-agent-skill.mjs +39 -7
  5. package/dist/Header.cjs +151 -20
  6. package/dist/Header.cjs.map +1 -1
  7. package/dist/Header.js +151 -20
  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/MultiColumn.cjs +354 -0
  14. package/dist/MultiColumn.cjs.map +1 -0
  15. package/dist/MultiColumn.js +335 -0
  16. package/dist/MultiColumn.js.map +1 -0
  17. package/dist/Sidebar.cjs +4 -3
  18. package/dist/Sidebar.cjs.map +1 -1
  19. package/dist/Sidebar.js +4 -3
  20. package/dist/Sidebar.js.map +1 -1
  21. package/dist/index.cjs +5 -1
  22. package/dist/index.d.cts +5 -5
  23. package/dist/index.d.cts.map +1 -1
  24. package/dist/index.d.ts +5 -5
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +3 -2
  27. package/dist/index10.d.cts +6 -6
  28. package/dist/index10.d.ts +6 -6
  29. package/dist/index11.d.cts +3 -3
  30. package/dist/index11.d.cts.map +1 -1
  31. package/dist/index11.d.ts +3 -3
  32. package/dist/index11.d.ts.map +1 -1
  33. package/dist/index12.d.cts +12 -12
  34. package/dist/index12.d.cts.map +1 -1
  35. package/dist/index12.d.ts +13 -13
  36. package/dist/index13.d.cts +6 -6
  37. package/dist/index13.d.cts.map +1 -1
  38. package/dist/index13.d.ts +6 -6
  39. package/dist/index13.d.ts.map +1 -1
  40. package/dist/index14.d.cts +5 -5
  41. package/dist/index14.d.ts +5 -5
  42. package/dist/index15.d.cts +3 -3
  43. package/dist/index15.d.cts.map +1 -1
  44. package/dist/index15.d.ts +3 -3
  45. package/dist/index15.d.ts.map +1 -1
  46. package/dist/index16.d.cts +2 -2
  47. package/dist/index16.d.cts.map +1 -1
  48. package/dist/index16.d.ts +2 -2
  49. package/dist/index16.d.ts.map +1 -1
  50. package/dist/index17.d.cts +4 -4
  51. package/dist/index17.d.cts.map +1 -1
  52. package/dist/index17.d.ts +4 -4
  53. package/dist/index18.d.cts +11 -11
  54. package/dist/index18.d.cts.map +1 -1
  55. package/dist/index18.d.ts +11 -11
  56. package/dist/index18.d.ts.map +1 -1
  57. package/dist/index19.d.cts +10 -10
  58. package/dist/index19.d.cts.map +1 -1
  59. package/dist/index19.d.ts +10 -10
  60. package/dist/index19.d.ts.map +1 -1
  61. package/dist/index2.d.cts +8 -8
  62. package/dist/index2.d.cts.map +1 -1
  63. package/dist/index2.d.ts +9 -9
  64. package/dist/index2.d.ts.map +1 -1
  65. package/dist/index20.d.cts +16 -16
  66. package/dist/index20.d.cts.map +1 -1
  67. package/dist/index20.d.ts +16 -16
  68. package/dist/index20.d.ts.map +1 -1
  69. package/dist/index21.d.cts +4 -4
  70. package/dist/index21.d.cts.map +1 -1
  71. package/dist/index21.d.ts +4 -4
  72. package/dist/index21.d.ts.map +1 -1
  73. package/dist/index22.d.cts +11 -11
  74. package/dist/index22.d.ts +11 -11
  75. package/dist/index23.d.cts +16 -16
  76. package/dist/index23.d.cts.map +1 -1
  77. package/dist/index23.d.ts +16 -16
  78. package/dist/index23.d.ts.map +1 -1
  79. package/dist/index24.d.cts +10 -10
  80. package/dist/index24.d.cts.map +1 -1
  81. package/dist/index24.d.ts +11 -11
  82. package/dist/index24.d.ts.map +1 -1
  83. package/dist/index25.d.cts +2 -2
  84. package/dist/index25.d.ts +2 -2
  85. package/dist/index25.d.ts.map +1 -1
  86. package/dist/index26.d.cts +13 -13
  87. package/dist/index26.d.cts.map +1 -1
  88. package/dist/index26.d.ts +14 -14
  89. package/dist/index26.d.ts.map +1 -1
  90. package/dist/index27.d.cts +7 -7
  91. package/dist/index27.d.cts.map +1 -1
  92. package/dist/index27.d.ts +7 -7
  93. package/dist/index27.d.ts.map +1 -1
  94. package/dist/index28.d.cts +6 -6
  95. package/dist/index28.d.cts.map +1 -1
  96. package/dist/index28.d.ts +5 -5
  97. package/dist/index28.d.ts.map +1 -1
  98. package/dist/index29.d.cts +4 -4
  99. package/dist/index29.d.ts +4 -4
  100. package/dist/index29.d.ts.map +1 -1
  101. package/dist/index3.d.cts +13 -13
  102. package/dist/index3.d.cts.map +1 -1
  103. package/dist/index3.d.ts +13 -13
  104. package/dist/index30.d.cts +41 -12
  105. package/dist/index30.d.cts.map +1 -1
  106. package/dist/index30.d.ts +42 -13
  107. package/dist/index30.d.ts.map +1 -1
  108. package/dist/index31.d.cts +5 -5
  109. package/dist/index31.d.cts.map +1 -1
  110. package/dist/index31.d.ts +6 -6
  111. package/dist/index31.d.ts.map +1 -1
  112. package/dist/index32.d.cts +5 -5
  113. package/dist/index32.d.cts.map +1 -1
  114. package/dist/index32.d.ts +6 -6
  115. package/dist/index33.d.cts +10 -10
  116. package/dist/index33.d.cts.map +1 -1
  117. package/dist/index33.d.ts +11 -11
  118. package/dist/index33.d.ts.map +1 -1
  119. package/dist/index34.d.cts +5 -5
  120. package/dist/index34.d.cts.map +1 -1
  121. package/dist/index34.d.ts +5 -5
  122. package/dist/index34.d.ts.map +1 -1
  123. package/dist/index35.d.cts +16 -16
  124. package/dist/index35.d.cts.map +1 -1
  125. package/dist/index35.d.ts +17 -17
  126. package/dist/index35.d.ts.map +1 -1
  127. package/dist/index36.d.cts +3 -3
  128. package/dist/index36.d.cts.map +1 -1
  129. package/dist/index36.d.ts +3 -3
  130. package/dist/index36.d.ts.map +1 -1
  131. package/dist/index37.d.cts +5 -5
  132. package/dist/index37.d.ts +3 -3
  133. package/dist/index38.d.cts +2 -2
  134. package/dist/index38.d.cts.map +1 -1
  135. package/dist/index38.d.ts +2 -2
  136. package/dist/index39.d.cts +17 -17
  137. package/dist/index39.d.cts.map +1 -1
  138. package/dist/index39.d.ts +17 -17
  139. package/dist/index39.d.ts.map +1 -1
  140. package/dist/index4.d.cts +2 -2
  141. package/dist/index4.d.ts +2 -2
  142. package/dist/index4.d.ts.map +1 -1
  143. package/dist/index40.d.cts +5 -5
  144. package/dist/index40.d.cts.map +1 -1
  145. package/dist/index40.d.ts +6 -6
  146. package/dist/index40.d.ts.map +1 -1
  147. package/dist/index41.d.cts +11 -11
  148. package/dist/index41.d.cts.map +1 -1
  149. package/dist/index41.d.ts +11 -11
  150. package/dist/index41.d.ts.map +1 -1
  151. package/dist/index42.d.cts +8 -8
  152. package/dist/index42.d.cts.map +1 -1
  153. package/dist/index42.d.ts +8 -8
  154. package/dist/index43.d.cts +9 -9
  155. package/dist/index43.d.cts.map +1 -1
  156. package/dist/index43.d.ts +9 -9
  157. package/dist/index43.d.ts.map +1 -1
  158. package/dist/index45.d.cts +8 -8
  159. package/dist/index45.d.cts.map +1 -1
  160. package/dist/index45.d.ts +8 -8
  161. package/dist/index45.d.ts.map +1 -1
  162. package/dist/index46.d.cts +2 -2
  163. package/dist/index46.d.cts.map +1 -1
  164. package/dist/index46.d.ts +2 -2
  165. package/dist/index46.d.ts.map +1 -1
  166. package/dist/index47.d.cts +4 -4
  167. package/dist/index47.d.cts.map +1 -1
  168. package/dist/index47.d.ts +4 -4
  169. package/dist/index47.d.ts.map +1 -1
  170. package/dist/index48.d.cts +4 -4
  171. package/dist/index48.d.cts.map +1 -1
  172. package/dist/index48.d.ts +4 -4
  173. package/dist/index48.d.ts.map +1 -1
  174. package/dist/index49.d.cts +3 -3
  175. package/dist/index49.d.ts +3 -3
  176. package/dist/index5.d.cts +7 -7
  177. package/dist/index5.d.ts +7 -7
  178. package/dist/index50.d.cts +11 -11
  179. package/dist/index50.d.cts.map +1 -1
  180. package/dist/index50.d.ts +11 -11
  181. package/dist/index50.d.ts.map +1 -1
  182. package/dist/index51.d.cts +9 -9
  183. package/dist/index51.d.cts.map +1 -1
  184. package/dist/index51.d.ts +9 -9
  185. package/dist/index51.d.ts.map +1 -1
  186. package/dist/index52.d.cts +5 -5
  187. package/dist/index52.d.ts +5 -5
  188. package/dist/index53.d.cts +27 -27
  189. package/dist/index53.d.cts.map +1 -1
  190. package/dist/index53.d.ts +28 -28
  191. package/dist/index53.d.ts.map +1 -1
  192. package/dist/index54.d.cts +5 -5
  193. package/dist/index54.d.ts +5 -5
  194. package/dist/index54.d.ts.map +1 -1
  195. package/dist/index55.d.cts +2 -2
  196. package/dist/index55.d.cts.map +1 -1
  197. package/dist/index55.d.ts +2 -2
  198. package/dist/index55.d.ts.map +1 -1
  199. package/dist/index56.d.cts +2 -2
  200. package/dist/index56.d.cts.map +1 -1
  201. package/dist/index56.d.ts +2 -2
  202. package/dist/index56.d.ts.map +1 -1
  203. package/dist/index57.d.cts +2 -2
  204. package/dist/index57.d.cts.map +1 -1
  205. package/dist/index57.d.ts +2 -2
  206. package/dist/index57.d.ts.map +1 -1
  207. package/dist/index58.d.cts +4 -4
  208. package/dist/index58.d.cts.map +1 -1
  209. package/dist/index58.d.ts +4 -4
  210. package/dist/index58.d.ts.map +1 -1
  211. package/dist/index59.d.cts +9 -9
  212. package/dist/index59.d.ts +9 -9
  213. package/dist/index59.d.ts.map +1 -1
  214. package/dist/index6.d.cts +5 -5
  215. package/dist/index6.d.cts.map +1 -1
  216. package/dist/index6.d.ts +6 -6
  217. package/dist/index60.d.cts +9 -9
  218. package/dist/index60.d.ts +9 -9
  219. package/dist/index60.d.ts.map +1 -1
  220. package/dist/index61.d.cts +8 -8
  221. package/dist/index61.d.cts.map +1 -1
  222. package/dist/index61.d.ts +7 -7
  223. package/dist/index61.d.ts.map +1 -1
  224. package/dist/index62.d.cts +4 -4
  225. package/dist/index62.d.cts.map +1 -1
  226. package/dist/index62.d.ts +5 -5
  227. package/dist/index63.d.cts +2 -2
  228. package/dist/index63.d.ts +2 -2
  229. package/dist/index64.d.cts +4 -4
  230. package/dist/index64.d.ts +7 -7
  231. package/dist/index64.d.ts.map +1 -1
  232. package/dist/index65.d.cts +3 -3
  233. package/dist/index65.d.ts +4 -4
  234. package/dist/index66.d.cts +4 -4
  235. package/dist/index66.d.ts +5 -5
  236. package/dist/index67.d.cts +83 -11
  237. package/dist/index67.d.cts.map +1 -1
  238. package/dist/index67.d.ts +83 -11
  239. package/dist/index67.d.ts.map +1 -1
  240. package/dist/index68.d.cts +12 -30
  241. package/dist/index68.d.cts.map +1 -1
  242. package/dist/index68.d.ts +12 -30
  243. package/dist/index68.d.ts.map +1 -1
  244. package/dist/index69.d.cts +28 -27
  245. package/dist/index69.d.cts.map +1 -1
  246. package/dist/index69.d.ts +29 -28
  247. package/dist/index69.d.ts.map +1 -1
  248. package/dist/index7.d.cts +8 -8
  249. package/dist/index7.d.cts.map +1 -1
  250. package/dist/index7.d.ts +8 -8
  251. package/dist/index7.d.ts.map +1 -1
  252. package/dist/index70.d.cts +33 -78
  253. package/dist/index70.d.cts.map +1 -1
  254. package/dist/index70.d.ts +33 -78
  255. package/dist/index70.d.ts.map +1 -1
  256. package/dist/index71.d.cts +77 -260
  257. package/dist/index71.d.cts.map +1 -1
  258. package/dist/index71.d.ts +77 -260
  259. package/dist/index71.d.ts.map +1 -1
  260. package/dist/index72.d.cts +278 -0
  261. package/dist/index72.d.cts.map +1 -0
  262. package/dist/index72.d.ts +278 -0
  263. package/dist/index72.d.ts.map +1 -0
  264. package/dist/index8.d.cts +4 -4
  265. package/dist/index8.d.cts.map +1 -1
  266. package/dist/index8.d.ts +5 -5
  267. package/dist/index9.d.cts +2 -2
  268. package/dist/index9.d.cts.map +1 -1
  269. package/dist/index9.d.ts +2 -2
  270. package/dist/index9.d.ts.map +1 -1
  271. package/dist/layouts/Container/index.cjs +2 -1
  272. package/dist/layouts/Container/index.cjs.map +1 -1
  273. package/dist/layouts/Container/index.js +1 -1
  274. package/dist/layouts/MultiColumn/index.cjs +5 -0
  275. package/dist/layouts/MultiColumn/index.d.cts +2 -0
  276. package/dist/layouts/MultiColumn/index.d.ts +2 -0
  277. package/dist/layouts/MultiColumn/index.js +2 -0
  278. package/dist/layouts/PageBackground/index.d.cts +1 -1
  279. package/dist/layouts/PageBackground/index.d.ts +1 -1
  280. package/dist/layouts/Stack/index.cjs +2 -1
  281. package/dist/layouts/Stack/index.cjs.map +1 -1
  282. package/dist/layouts/Stack/index.d.cts +1 -1
  283. package/dist/layouts/Stack/index.d.ts +1 -1
  284. package/dist/layouts/Stack/index.js +1 -1
  285. package/dist/layouts/TwoColumn/index.cjs +2 -1
  286. package/dist/layouts/TwoColumn/index.cjs.map +1 -1
  287. package/dist/layouts/TwoColumn/index.d.cts +1 -1
  288. package/dist/layouts/TwoColumn/index.d.ts +1 -1
  289. package/dist/layouts/TwoColumn/index.js +1 -1
  290. package/dist/layouts/index.cjs +4 -0
  291. package/dist/layouts/index.d.cts +5 -4
  292. package/dist/layouts/index.d.ts +5 -4
  293. package/dist/layouts/index.js +2 -1
  294. package/dist/patterns/DataTable/index.cjs +6 -2
  295. package/dist/patterns/DataTable/index.cjs.map +1 -1
  296. package/dist/patterns/DataTable/index.d.cts +3 -3
  297. package/dist/patterns/DataTable/index.d.cts.map +1 -1
  298. package/dist/patterns/DataTable/index.d.ts +3 -3
  299. package/dist/patterns/DataTable/index.d.ts.map +1 -1
  300. package/dist/patterns/DataTable/index.js +6 -2
  301. package/dist/patterns/DataTable/index.js.map +1 -1
  302. package/dist/patterns/Footer/index.d.cts +7 -7
  303. package/dist/patterns/Footer/index.d.cts.map +1 -1
  304. package/dist/patterns/Footer/index.d.ts +7 -7
  305. package/dist/patterns/Footer/index.d.ts.map +1 -1
  306. package/dist/patterns/Header/index.d.cts +1 -1
  307. package/dist/patterns/Header/index.d.ts +1 -1
  308. package/dist/patterns/MediaObject/index.cjs +1 -1
  309. package/dist/patterns/MediaObject/index.d.cts +11 -11
  310. package/dist/patterns/MediaObject/index.d.ts +12 -12
  311. package/dist/patterns/MediaObject/index.js +1 -1
  312. package/dist/patterns/NavRail/index.cjs +4 -2
  313. package/dist/patterns/NavRail/index.cjs.map +1 -1
  314. package/dist/patterns/NavRail/index.js +4 -2
  315. package/dist/patterns/NavRail/index.js.map +1 -1
  316. package/dist/patterns/SectionCard/index.d.cts +2 -2
  317. package/dist/patterns/SectionCard/index.d.ts +2 -2
  318. package/dist/patterns/SectionHeading/index.d.cts +2 -2
  319. package/dist/patterns/index.d.cts +1 -1
  320. package/dist/patterns/index.d.ts +1 -1
  321. package/dist/primitives/Accordion/index.cjs +6 -2
  322. package/dist/primitives/Accordion/index.cjs.map +1 -1
  323. package/dist/primitives/Accordion/index.js +6 -2
  324. package/dist/primitives/Accordion/index.js.map +1 -1
  325. package/dist/primitives/Alert/index.cjs +2 -1
  326. package/dist/primitives/Alert/index.cjs.map +1 -1
  327. package/dist/primitives/Alert/index.js +1 -1
  328. package/dist/primitives/AlertDialog/index.cjs +1 -1
  329. package/dist/primitives/AlertDialog/index.js +1 -1
  330. package/dist/primitives/AspectRatio/index.cjs +1 -1
  331. package/dist/primitives/AspectRatio/index.js +1 -1
  332. package/dist/primitives/Avatar/index.cjs +1 -1
  333. package/dist/primitives/Avatar/index.js +1 -1
  334. package/dist/primitives/Badge/index.cjs +3 -2
  335. package/dist/primitives/Badge/index.cjs.map +1 -1
  336. package/dist/primitives/Badge/index.js +2 -2
  337. package/dist/primitives/Breadcrumb/index.cjs +7 -3
  338. package/dist/primitives/Breadcrumb/index.cjs.map +1 -1
  339. package/dist/primitives/Breadcrumb/index.js +7 -3
  340. package/dist/primitives/Breadcrumb/index.js.map +1 -1
  341. package/dist/primitives/Button/index.cjs +3 -2
  342. package/dist/primitives/Button/index.cjs.map +1 -1
  343. package/dist/primitives/Button/index.js +2 -2
  344. package/dist/primitives/ButtonGroup/index.cjs +3 -2
  345. package/dist/primitives/ButtonGroup/index.cjs.map +1 -1
  346. package/dist/primitives/ButtonGroup/index.js +2 -2
  347. package/dist/primitives/Calendar/index.cjs +12 -11
  348. package/dist/primitives/Calendar/index.cjs.map +1 -1
  349. package/dist/primitives/Calendar/index.js +12 -11
  350. package/dist/primitives/Calendar/index.js.map +1 -1
  351. package/dist/primitives/Card/index.cjs +2 -1
  352. package/dist/primitives/Card/index.cjs.map +1 -1
  353. package/dist/primitives/Card/index.js +1 -1
  354. package/dist/primitives/Carousel/index.cjs +4 -3
  355. package/dist/primitives/Carousel/index.cjs.map +1 -1
  356. package/dist/primitives/Carousel/index.js +4 -3
  357. package/dist/primitives/Carousel/index.js.map +1 -1
  358. package/dist/primitives/Checkbox/index.cjs +9 -2
  359. package/dist/primitives/Checkbox/index.cjs.map +1 -1
  360. package/dist/primitives/Checkbox/index.js +9 -2
  361. package/dist/primitives/Checkbox/index.js.map +1 -1
  362. package/dist/primitives/CheckboxTree/index.cjs +6 -2
  363. package/dist/primitives/CheckboxTree/index.cjs.map +1 -1
  364. package/dist/primitives/CheckboxTree/index.js +6 -2
  365. package/dist/primitives/CheckboxTree/index.js.map +1 -1
  366. package/dist/primitives/Collapsible/index.cjs +1 -1
  367. package/dist/primitives/Collapsible/index.js +1 -1
  368. package/dist/primitives/Command/index.cjs +6 -2
  369. package/dist/primitives/Command/index.cjs.map +1 -1
  370. package/dist/primitives/Command/index.js +6 -2
  371. package/dist/primitives/Command/index.js.map +1 -1
  372. package/dist/primitives/ContextMenu/index.cjs +14 -4
  373. package/dist/primitives/ContextMenu/index.cjs.map +1 -1
  374. package/dist/primitives/ContextMenu/index.js +14 -4
  375. package/dist/primitives/ContextMenu/index.js.map +1 -1
  376. package/dist/primitives/Credits/index.cjs +8 -3
  377. package/dist/primitives/Credits/index.cjs.map +1 -1
  378. package/dist/primitives/Credits/index.js +7 -3
  379. package/dist/primitives/Credits/index.js.map +1 -1
  380. package/dist/primitives/Dialog/index.cjs +3 -2
  381. package/dist/primitives/Dialog/index.cjs.map +1 -1
  382. package/dist/primitives/Dialog/index.js +3 -2
  383. package/dist/primitives/Dialog/index.js.map +1 -1
  384. package/dist/primitives/DropdownMenu/index.cjs +14 -4
  385. package/dist/primitives/DropdownMenu/index.cjs.map +1 -1
  386. package/dist/primitives/DropdownMenu/index.js +14 -4
  387. package/dist/primitives/DropdownMenu/index.js.map +1 -1
  388. package/dist/primitives/Empty/index.cjs +1 -1
  389. package/dist/primitives/Empty/index.js +1 -1
  390. package/dist/primitives/Field/index.cjs +1 -1
  391. package/dist/primitives/Field/index.js +1 -1
  392. package/dist/primitives/Form/index.cjs +1 -1
  393. package/dist/primitives/Form/index.js +1 -1
  394. package/dist/primitives/Heading/index.cjs +2 -1
  395. package/dist/primitives/Heading/index.cjs.map +1 -1
  396. package/dist/primitives/Heading/index.js +1 -1
  397. package/dist/primitives/HoverCard/index.cjs +1 -1
  398. package/dist/primitives/HoverCard/index.js +1 -1
  399. package/dist/primitives/InfoBanner/index.cjs +6 -3
  400. package/dist/primitives/InfoBanner/index.cjs.map +1 -1
  401. package/dist/primitives/InfoBanner/index.js +5 -3
  402. package/dist/primitives/InfoBanner/index.js.map +1 -1
  403. package/dist/primitives/Input/index.cjs +2 -1
  404. package/dist/primitives/Input/index.cjs.map +1 -1
  405. package/dist/primitives/Input/index.js +1 -1
  406. package/dist/primitives/InputGroup/index.cjs +1 -1
  407. package/dist/primitives/InputGroup/index.js +1 -1
  408. package/dist/primitives/InputOtp/index.cjs +3 -2
  409. package/dist/primitives/InputOtp/index.cjs.map +1 -1
  410. package/dist/primitives/InputOtp/index.js +3 -2
  411. package/dist/primitives/InputOtp/index.js.map +1 -1
  412. package/dist/primitives/Item/index.cjs +2 -2
  413. package/dist/primitives/Item/index.js +2 -2
  414. package/dist/primitives/Label/index.cjs +1 -1
  415. package/dist/primitives/Label/index.js +1 -1
  416. package/dist/primitives/Link/index.cjs +3 -2
  417. package/dist/primitives/Link/index.cjs.map +1 -1
  418. package/dist/primitives/Link/index.js +2 -2
  419. package/dist/primitives/Menubar/index.cjs +14 -4
  420. package/dist/primitives/Menubar/index.cjs.map +1 -1
  421. package/dist/primitives/Menubar/index.js +14 -4
  422. package/dist/primitives/Menubar/index.js.map +1 -1
  423. package/dist/primitives/NativeSelect/index.cjs +6 -3
  424. package/dist/primitives/NativeSelect/index.cjs.map +1 -1
  425. package/dist/primitives/NativeSelect/index.js +5 -3
  426. package/dist/primitives/NativeSelect/index.js.map +1 -1
  427. package/dist/primitives/NavigationMenu/index.cjs +5 -3
  428. package/dist/primitives/NavigationMenu/index.cjs.map +1 -1
  429. package/dist/primitives/NavigationMenu/index.js +5 -3
  430. package/dist/primitives/NavigationMenu/index.js.map +1 -1
  431. package/dist/primitives/Pagination/index.cjs +6 -2
  432. package/dist/primitives/Pagination/index.cjs.map +1 -1
  433. package/dist/primitives/Pagination/index.js +6 -2
  434. package/dist/primitives/Pagination/index.js.map +1 -1
  435. package/dist/primitives/Popover/index.cjs +1 -1
  436. package/dist/primitives/Popover/index.js +1 -1
  437. package/dist/primitives/Progress/index.cjs +1 -1
  438. package/dist/primitives/Progress/index.js +1 -1
  439. package/dist/primitives/RadioGroup/index.cjs +6 -2
  440. package/dist/primitives/RadioGroup/index.cjs.map +1 -1
  441. package/dist/primitives/RadioGroup/index.js +6 -2
  442. package/dist/primitives/RadioGroup/index.js.map +1 -1
  443. package/dist/primitives/Resizable/index.cjs +6 -2
  444. package/dist/primitives/Resizable/index.cjs.map +1 -1
  445. package/dist/primitives/Resizable/index.js +6 -2
  446. package/dist/primitives/Resizable/index.js.map +1 -1
  447. package/dist/primitives/ScrollArea/index.cjs +1 -1
  448. package/dist/primitives/ScrollArea/index.js +1 -1
  449. package/dist/primitives/Select/index.cjs +18 -5
  450. package/dist/primitives/Select/index.cjs.map +1 -1
  451. package/dist/primitives/Select/index.js +18 -5
  452. package/dist/primitives/Select/index.js.map +1 -1
  453. package/dist/primitives/Separator/index.cjs +1 -1
  454. package/dist/primitives/Separator/index.js +1 -1
  455. package/dist/primitives/Sheet/index.cjs +6 -2
  456. package/dist/primitives/Sheet/index.cjs.map +1 -1
  457. package/dist/primitives/Sheet/index.js +6 -2
  458. package/dist/primitives/Sheet/index.js.map +1 -1
  459. package/dist/primitives/Slider/index.cjs +1 -1
  460. package/dist/primitives/Slider/index.js +1 -1
  461. package/dist/primitives/Sonner/index.cjs +22 -6
  462. package/dist/primitives/Sonner/index.cjs.map +1 -1
  463. package/dist/primitives/Sonner/index.js +22 -6
  464. package/dist/primitives/Sonner/index.js.map +1 -1
  465. package/dist/primitives/Spinner/index.cjs +4 -2
  466. package/dist/primitives/Spinner/index.cjs.map +1 -1
  467. package/dist/primitives/Spinner/index.js +4 -2
  468. package/dist/primitives/Spinner/index.js.map +1 -1
  469. package/dist/primitives/Switch/index.cjs +1 -1
  470. package/dist/primitives/Switch/index.js +1 -1
  471. package/dist/primitives/Tabs/index.cjs +2 -2
  472. package/dist/primitives/Tabs/index.js +2 -2
  473. package/dist/primitives/Text/index.cjs +2 -1
  474. package/dist/primitives/Text/index.cjs.map +1 -1
  475. package/dist/primitives/Text/index.js +1 -1
  476. package/dist/primitives/Textarea/index.cjs +2 -1
  477. package/dist/primitives/Textarea/index.cjs.map +1 -1
  478. package/dist/primitives/Textarea/index.js +1 -1
  479. package/dist/primitives/Toggle/index.cjs +3 -2
  480. package/dist/primitives/Toggle/index.cjs.map +1 -1
  481. package/dist/primitives/Toggle/index.js +2 -2
  482. package/dist/primitives/ToggleGroup/index.cjs +1 -1
  483. package/dist/primitives/ToggleGroup/index.js +1 -1
  484. package/dist/primitives/Tooltip/index.cjs +1 -1
  485. package/dist/primitives/Tooltip/index.js +1 -1
  486. package/dist/primitives/index.cjs +1 -1
  487. package/dist/primitives/index.js +1 -1
  488. package/package.json +2 -1
package/SKILL.md CHANGED
@@ -12,18 +12,44 @@ component catalog, full token inventory, theming model — is in
12
12
 
13
13
  ## Decision order
14
14
 
15
+ Work down this ladder in order — each step is only allowed after the one above it
16
+ demonstrably can't produce the design:
17
+
15
18
  1. **Pattern first**: does a pattern (`patterns/Header`, `DataTable`, `Footer`,
16
19
  `SectionCard`, `SectionHeading`, `MediaObject`) or layout (`Container`, `Stack`,
17
- `TwoColumn`, `PageBackground`) already solve it? Use it.
20
+ `TwoColumn`, `MultiColumn`, `PageBackground`) already solve it? Use it.
18
21
  2. **Primitive second**: compose from `primitives/*` (64 of them — check the catalog
19
22
  in DESIGN.md §6 before writing anything custom).
20
- 3. **Custom last**: build with token utilities only; never raw colors, never a
21
- parallel component that shadows an existing one.
23
+ 3. **Stock rendering**: render the chosen component with its variants/props as
24
+ designed. Pick the variant from its "Choosing a variant" table in DESIGN.md
25
+ (intent + light/dark look + tell) — don't guess from the variant name.
26
+ 4. **Layout tweaks only**: `className` may place and size the component in its
27
+ context — margin, width, flex/grid placement, alignment. It must never repaint
28
+ it (no `bg-*`/`text-*` color/`border-*` color/`hover:*` on a variant).
29
+ 5. **Exception — last resort, and marked**: only when 1–4 can't get there:
30
+ - **Component missing from the DS** → build custom from token utilities only
31
+ (tokens, px-named radii, `ring-focus`; never raw colors, never `dark:`,
32
+ never a parallel component that shadows an existing one).
33
+ - **Component exists but no variant fits** → do NOT re-skin it (see the
34
+ anti-pattern below); add or request a variant. If you must ship now, mark
35
+ the deviation at the call site so it stays auditable:
36
+ `// DS-EXCEPTION: <why> — <what the DS should provide instead>`
37
+
38
+ Every `DS-EXCEPTION` is a design-system backlog item — sweep them with
39
+ `grep -rn "DS-EXCEPTION"` and either upstream the need into a real
40
+ variant/component or remove the deviation. Exceptions feed the DS; they must
41
+ never silently erode it.
22
42
 
23
43
  Import per subpath: `@psnext/design-system/primitives/Button`. The DS bundles Radix,
24
44
  cva, lucide-react, recharts, sonner, react-hook-form, zod — import primitives from the
25
- DS, not from those libraries directly (exception: `toast()` from `"sonner"`, and
26
- `lucide-react` icons which are the standard icon set).
45
+ DS, not from those libraries directly (exception: `toast()` from `"sonner"`).
46
+
47
+ **Icons**: prefer the DS `Icon` — `<Icon icon="search" />` (typed lucide name, lazy /
48
+ code-split) for content icons, or `<Icon as={Search} />` (sync, bare `<svg>`) with a
49
+ lucide **or a custom** icon component, e.g. inside a component's icon slot. `Icon`
50
+ inherits the surrounding text color by default, so it's correct on a Button; pass
51
+ `color` or a `text-*` class to override. Raw `lucide-react` icons still work as icon-slot
52
+ children (`<Button><Search /></Button>`) — those slots style a direct-child `[&>svg]`.
27
53
 
28
54
  ## Class-writing rules (do / don't)
29
55
 
@@ -38,10 +64,41 @@ DS, not from those libraries directly (exception: `toast()` from `"sonner"`, and
38
64
  | `text-danger-txt` for errors | `text-destructive`, `text-red-500` | severity family is info/success/warning/danger |
39
65
  | `cn(...)` from the DS for merged classes | template-string concat | cn's tailwind-merge knows the numeric radius scale |
40
66
  | suffix matches property: `bg-*-bg`, `text-*-txt` | `text-primary-bg` | token suffix encodes the valid context |
67
+ | pick the variant that already looks right | re-skin a variant with paint classes | variants bundle hover/active/focus states — overrides break them (see below) |
41
68
 
42
69
  Figma → code: px ÷ 4 = spacing step (16px → `p-4`); radius px maps 1:1 (`rounded-12`);
43
70
  heading levels map to `<Heading size={n}>`.
44
71
 
72
+ ## Never re-skin a variant (anti-pattern)
73
+
74
+ A component variant is a **package deal**: rest + hover + active + focus + disabled
75
+ states, tuned together. Overriding its paint with `className` only changes the rest
76
+ state — the interaction states still belong to the original variant, and the result
77
+ is visibly broken.
78
+
79
+ Real failure seen in the wild:
80
+
81
+ ```tsx
82
+ // ✗ WRONG — outline button "made primary" with a bg override
83
+ <Button variant="outline" className="bg-primary-invert-bg text-primary-invert-txt">
84
+ // Looks primary at rest. On hover, outline's own hover:bg-outline-hover-bg fires
85
+ // and the fill flickers to a translucent gray — broken hover, broken contrast.
86
+
87
+ // ✓ RIGHT — that look already exists as a variant
88
+ <Button variant="default">
89
+ ```
90
+
91
+ Rules:
92
+
93
+ - **`className` on a DS component is for layout only** — margin, width, flex/grid
94
+ placement, alignment. Never for paint: `bg-*`, `text-*` color, `border-*` color,
95
+ `hover:*`, `rounded-*` that fight the variant.
96
+ - **If the look you want isn't a variant, that's a DS gap** — don't patch it at the
97
+ call site. Add/request a variant (cva) so the states are designed together.
98
+ - This applies to **every** cva-styled component (Button, Badge, Tabs, Card, Alert, …),
99
+ not just Button. If you catch yourself writing a paint class on one, stop and check
100
+ the component's variant table in DESIGN.md first.
101
+
45
102
  ## Recipes
46
103
 
47
104
  **Page scaffold**
@@ -85,6 +142,27 @@ tokens inside flip; do not hand-pick dark colors.
85
142
  with `cn`); don't wrap in extra divs to fight specificity.
86
143
  - **`!important` on library-styled elements** (e.g. toast classNames) will override
87
144
  richColors/severity styling — scope with `data-[type=…]` variants instead.
145
+ - **App-defined `@layer base` wiping the tokens**: an app that declares its own
146
+ base-layer `:root`/`body` rules (or a reset) can silently override the DS token
147
+ variables — every component then renders colorless while classes look correct.
148
+ Don't redefine base-layer custom properties; put app-level overrides *after* the
149
+ DS styles import, outside `@layer base`.
150
+
151
+ **If the DS token variables are missing entirely** (components render but
152
+ `--primary-bg` etc. aren't on `:root`), walk this tree in order:
153
+
154
+ 1. Devtools → inspect `<html>` → computed styles → search `--primary-bg`.
155
+ Present? The tokens are fine — suspect a wrong class name or missing `@source`.
156
+ 2. Absent → check the Tailwind entry CSS: `@import "tailwindcss"` then
157
+ `@import "@psnext/design-system/styles"`, and **all `@import`s before any other
158
+ statement** (including `@source` — a misplaced import can abort the rest).
159
+ 3. Confirm Tailwind is **v4** and this file is actually compiled by
160
+ `@tailwindcss/vite` / `@tailwindcss/postcss` (not served as plain CSS).
161
+ 4. Check nothing *later* redefines the vars: app `@layer base` blocks, resets, or
162
+ `:root` rules after the import (see the pitfall above — this has happened).
163
+ 5. Isolation test: `@import "@psnext/design-system/dist/styles/tokens/mode-light.css"`.
164
+ If vars appear now, the `/styles` subpath isn't resolving in your bundler —
165
+ report that, don't ship the workaround.
88
166
  - **Logo**: never recolor; wordmark ink follows mode automatically; no ThemeProvider
89
167
  needed.
90
168
 
@@ -2,14 +2,14 @@
2
2
  // Install the design-system agent docs (SKILL.md + DESIGN.md) into a consumer
3
3
  // project as an Agent Skill, so coding agents load them for UI work.
4
4
  //
5
- // npx @psnext/design-system → .agents/skills/design-system/
5
+ // npx @psnext/design-system → .agent/skills/design-system/
6
6
  // npx @psnext/design-system <dir> → <dir>/ (explicit destination)
7
7
  //
8
8
  // The two docs are copied verbatim from the installed package; SKILL.md links to
9
9
  // DESIGN.md as a sibling, so they must land in the same folder (this does that).
10
10
 
11
- import { copyFileSync, existsSync, mkdirSync } from "node:fs";
12
- import { dirname, join, resolve } from "node:path";
11
+ import { copyFileSync, existsSync, mkdirSync, statSync } from "node:fs";
12
+ import { dirname, join, resolve, sep } from "node:path";
13
13
  import { fileURLToPath } from "node:url";
14
14
 
15
15
  const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
@@ -20,7 +20,7 @@ if (args.includes("--help") || args.includes("-h")) {
20
20
  console.log(`Install @psnext/design-system agent docs as an Agent Skill.
21
21
 
22
22
  Usage:
23
- npx @psnext/design-system Copy SKILL.md + DESIGN.md into .agents/skills/design-system/
23
+ npx @psnext/design-system Copy SKILL.md + DESIGN.md into .agent/skills/design-system/
24
24
  npx @psnext/design-system <dir> Copy into an explicit destination folder
25
25
  npx @psnext/design-system --help Show this help
26
26
 
@@ -32,7 +32,7 @@ The agent then loads the skill when writing or reviewing UI in this project.`);
32
32
  const positional = args.find((a) => !a.startsWith("-"));
33
33
  const dest = positional
34
34
  ? resolve(process.cwd(), positional)
35
- : resolve(process.cwd(), ".agents/skills/design-system");
35
+ : resolve(process.cwd(), ".agent/skills/design-system");
36
36
 
37
37
  for (const doc of DOCS) {
38
38
  const src = join(PKG_ROOT, doc);
@@ -42,13 +42,45 @@ for (const doc of DOCS) {
42
42
  }
43
43
  }
44
44
 
45
- mkdirSync(dest, { recursive: true });
45
+ // Whether the skill was already installed here (a re-run just refreshes the two
46
+ // docs in place) — checked before we create anything.
47
+ const isRefresh = DOCS.every((doc) => existsSync(join(dest, doc)));
48
+
49
+ // Validate/create the destination one level at a time (for the default that's
50
+ // .agent → skills → design-system): reuse a folder that already exists, create
51
+ // the ones that don't, and bail with a clear message if a segment is occupied
52
+ // by a file — otherwise mkdir would fail cryptically. Only walk segments under
53
+ // the cwd; anything outside falls through to the recursive mkdir below.
54
+ const chain = [];
55
+ for (let cur = dest; cur.startsWith(process.cwd() + sep); cur = dirname(cur)) {
56
+ chain.unshift(cur);
57
+ }
58
+ for (const dir of chain) {
59
+ if (existsSync(dir)) {
60
+ if (!statSync(dir).isDirectory()) {
61
+ console.error(`✗ ${dir} already exists but is not a directory — move it aside and re-run.`);
62
+ process.exit(1);
63
+ }
64
+ continue; // reuse the existing folder
65
+ }
66
+ mkdirSync(dir); // parent already ensured by the outer→inner order
67
+ }
68
+
69
+ try {
70
+ mkdirSync(dest, { recursive: true }); // covers a destination outside the cwd
71
+ } catch (err) {
72
+ console.error(`✗ Could not create ${dest}: ${err.message}`);
73
+ process.exit(1);
74
+ }
75
+
46
76
  for (const doc of DOCS) {
47
77
  copyFileSync(join(PKG_ROOT, doc), join(dest, doc));
48
78
  }
49
79
 
50
80
  const rel = dest.startsWith(process.cwd()) ? `.${dest.slice(process.cwd().length)}` : dest;
51
- console.log(`✓ Installed @psnext/design-system agent skill → ${rel}/`);
81
+ console.log(
82
+ `✓ ${isRefresh ? "Refreshed" : "Installed"} @psnext/design-system agent skill → ${rel}/`,
83
+ );
52
84
  console.log(" • SKILL.md — workflow playbook (the Agent Skill entry point)");
53
85
  console.log(" • DESIGN.md — full token + component reference");
54
86
  console.log("\nRe-run this after upgrading the package to refresh the docs.");
package/dist/Header.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  const require_chunk = require("./chunk.cjs");
2
2
  const require_cn = require("./cn.cjs");
3
+ const require_Icon = require("./Icon.cjs");
3
4
  const require_primitives_Button_index = require("./primitives/Button/index.cjs");
4
5
  const require_primitives_Avatar_index = require("./primitives/Avatar/index.cjs");
5
6
  const require_primitives_Credits_index = require("./primitives/Credits/index.cjs");
@@ -12,8 +13,8 @@ const require_primitives_ThemeProvider_index = require("./primitives/ThemeProvid
12
13
  let react = require("react");
13
14
  let react$1 = require_chunk.__toESM(react, 1);
14
15
  react = require_chunk.__toESM(react);
15
- let lucide_react = require("lucide-react");
16
16
  let react_jsx_runtime = require("react/jsx-runtime");
17
+ let lucide_react = require("lucide-react");
17
18
  let _tanstack_react_query = require("@tanstack/react-query");
18
19
  //#region src/patterns/Header/project-tree.ts
19
20
  /** True when a node with the given id exists anywhere in the tree. */
@@ -77,7 +78,10 @@ function ProjectPicker({ projectsTree, selectedProjectId, selectedProjectName, o
77
78
  children: [projectLabel, ":"]
78
79
  }),
79
80
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_primitives_Skeleton_index.Skeleton, { className: "h-3 flex-1" }),
80
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronDown, { className: "size-4 shrink-0 text-muted-txt opacity-40" })
81
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Icon.Icon, {
82
+ as: lucide_react.ChevronDown,
83
+ className: "size-4 shrink-0 text-muted-txt opacity-40"
84
+ })
81
85
  ]
82
86
  });
83
87
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_primitives_Popover_index.Popover, {
@@ -98,7 +102,10 @@ function ProjectPicker({ projectsTree, selectedProjectId, selectedProjectName, o
98
102
  className: require_cn.cn("max-w-36 truncate", selectedName ? "font-medium" : "text-muted-txt"),
99
103
  children: selectedName ?? projectPlaceholder
100
104
  }),
101
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronDown, { className: "ml-1 size-4 shrink-0 text-muted-txt" })
105
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Icon.Icon, {
106
+ as: lucide_react.ChevronDown,
107
+ className: "ml-1 size-4 shrink-0 text-muted-txt"
108
+ })
102
109
  ]
103
110
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_primitives_Popover_index.PopoverContent, {
104
111
  align: "start",
@@ -109,7 +116,10 @@ function ProjectPicker({ projectsTree, selectedProjectId, selectedProjectName, o
109
116
  className: "border-b p-2",
110
117
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
111
118
  className: "relative",
112
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Search, { className: "absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-txt" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_primitives_Input_index.Input, {
119
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Icon.Icon, {
120
+ as: lucide_react.Search,
121
+ className: "absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-txt"
122
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_primitives_Input_index.Input, {
113
123
  size: "sm",
114
124
  className: "pl-8",
115
125
  placeholder: searchPlaceholder,
@@ -151,7 +161,13 @@ function TreeNode({ node, depth, selectedId, onSelect, collapsedIds, onToggleCol
151
161
  "aria-label": isCollapsed ? `Expand ${node.name}` : `Collapse ${node.name}`,
152
162
  onClick: () => onToggleCollapse(node.id),
153
163
  className: "shrink-0 text-muted-txt hover:text-primary-txt",
154
- children: isCollapsed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, { className: "size-3.5" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronDown, { className: "size-3.5" })
164
+ children: isCollapsed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Icon.Icon, {
165
+ as: lucide_react.ChevronRight,
166
+ className: "size-3.5"
167
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Icon.Icon, {
168
+ as: lucide_react.ChevronDown,
169
+ className: "size-3.5"
170
+ })
155
171
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "inline-block w-3.5 shrink-0" }),
156
172
  node.isContextOnly ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
157
173
  className: "flex-1 text-left",
@@ -162,7 +178,10 @@ function TreeNode({ node, depth, selectedId, onSelect, collapsedIds, onToggleCol
162
178
  className: "flex-1 text-left",
163
179
  children: node.name
164
180
  }),
165
- isSelected && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Check, { className: "ml-auto size-3.5 shrink-0 text-primary" })
181
+ isSelected && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Icon.Icon, {
182
+ as: lucide_react.Check,
183
+ className: "ml-auto size-3.5 shrink-0 text-primary"
184
+ })
166
185
  ]
167
186
  }), !isCollapsed && hasChildren && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
168
187
  role: "group",
@@ -189,8 +208,8 @@ const DEFAULT_LABELS = {
189
208
  profileMenuLabel: "Profile menu",
190
209
  logoutLabel: "Logout"
191
210
  };
192
- //#endregion
193
- //#region src/patterns/Header/api.ts
211
+ /** Hard cap on project pages fetched — guards against a runaway loop. */
212
+ const PROJECTS_MAX_PAGES = 40;
194
213
  const PATHS = {
195
214
  token: "/api/v1/studio-auth/sessions/token",
196
215
  logout: "/api/v1/studio-auth/sessions/logout",
@@ -215,16 +234,77 @@ async function fetchToken(endpoints, fetcher) {
215
234
  const { accessToken } = await res.json();
216
235
  return accessToken;
217
236
  }
237
+ /**
238
+ * Return `url` with the `page` query param set to the given page (and `limit`
239
+ * backfilled when absent). Pagination stays owned by the header: host-provided
240
+ * endpoint URLs don't need — and can't break — the paging params. Handles
241
+ * absolute and relative URLs.
242
+ */
243
+ function withPageParam(url, page) {
244
+ const isAbsolute = /^[a-z][a-z0-9+.-]*:\/\//i.test(url);
245
+ try {
246
+ const u = new URL(url, isAbsolute ? void 0 : "http://relative.invalid");
247
+ u.searchParams.set("page", String(page));
248
+ if (!u.searchParams.has("limit")) u.searchParams.set("limit", String(50));
249
+ return isAbsolute ? u.toString() : `${u.pathname}${u.search}${u.hash}`;
250
+ } catch {
251
+ return url;
252
+ }
253
+ }
254
+ /** The `limit` query param already on a URL, else the default page size. */
255
+ function readLimitParam(url) {
256
+ try {
257
+ const limit = Number(new URL(url, "http://relative.invalid").searchParams.get("limit"));
258
+ return Number.isInteger(limit) && limit > 0 ? limit : 50;
259
+ } catch {
260
+ return 50;
261
+ }
262
+ }
263
+ /** Total node count in a tree page (roots + descendants). */
264
+ function countNodes(tree) {
265
+ return tree.reduce((sum, node) => sum + 1 + countNodes(node.children ?? []), 0);
266
+ }
267
+ /**
268
+ * Merge a page's tree into the accumulated tree. Nodes repeated across pages
269
+ * (e.g. a context-only ancestor whose children span a page boundary) are
270
+ * merged by id instead of duplicated.
271
+ */
272
+ function mergeTrees(into, page) {
273
+ for (const node of page) {
274
+ const existing = into.find((n) => n.id === node.id);
275
+ if (existing) mergeTrees(existing.children, node.children ?? []);
276
+ else into.push({
277
+ ...node,
278
+ children: [...node.children ?? []]
279
+ });
280
+ }
281
+ }
282
+ /**
283
+ * Fetch ALL pages of the paginated projects endpoint and merge them into a
284
+ * single tree, so users with more projects than one page still see everything.
285
+ * The response carries no pagination metadata, so the first page that comes
286
+ * back with fewer than `limit` nodes is treated as the last one.
287
+ */
218
288
  async function fetchProjects(endpoints, clientId, accessToken, fetcher) {
219
- const res = await fetcher(endpoints.projects(clientId), {
220
- credentials: "include",
221
- headers: { Authorization: `Bearer ${accessToken}` }
222
- });
223
- if (!res.ok) throw new Error(`projects request failed: ${res.status}`);
224
- const data = await res.json();
289
+ const projectsTree = [];
290
+ let organizationName;
291
+ const baseUrl = endpoints.projects(clientId);
292
+ const pageLimit = readLimitParam(baseUrl);
293
+ for (let page = 1; page <= PROJECTS_MAX_PAGES; page++) {
294
+ const res = await fetcher(withPageParam(baseUrl, page), {
295
+ credentials: "include",
296
+ headers: { Authorization: `Bearer ${accessToken}` }
297
+ });
298
+ if (!res.ok) throw new Error(`projects request failed: ${res.status}`);
299
+ const body = await res.json();
300
+ const pageTree = body.response?.data?.projectsTree ?? [];
301
+ mergeTrees(projectsTree, pageTree);
302
+ organizationName ??= body.response?.data?.organization?.name;
303
+ if (countNodes(pageTree) < pageLimit) break;
304
+ }
225
305
  return {
226
- projectsTree: data.response?.data?.projectsTree ?? [],
227
- organizationName: data.response?.data?.organization?.name
306
+ projectsTree,
307
+ organizationName
228
308
  };
229
309
  }
230
310
  async function fetchCredits(endpoints, accessToken, fetcher) {
@@ -249,6 +329,7 @@ async function callLogout(endpoints, fetcher) {
249
329
  //#region src/patterns/Header/storage.ts
250
330
  const PROJECT_KEY = "ds-header-project";
251
331
  const LAST_PROJECT_KEY = "lastSelectedProject";
332
+ const PROJECTS_CACHE_KEY = "ds-header-projects-cache";
252
333
  function getStoredProject() {
253
334
  try {
254
335
  const raw = sessionStorage.getItem(PROJECT_KEY);
@@ -281,6 +362,38 @@ function setLastSelectedProject(project) {
281
362
  localStorage.setItem(LAST_PROJECT_KEY, JSON.stringify(project));
282
363
  } catch {}
283
364
  }
365
+ function projectsCacheKey(clientId, userId) {
366
+ return `${PROJECTS_CACHE_KEY}:${clientId}:${userId}`;
367
+ }
368
+ /** The session-cached projects result for this client + user, or null on miss. */
369
+ function getCachedProjects(clientId, userId) {
370
+ try {
371
+ const raw = sessionStorage.getItem(projectsCacheKey(clientId, userId));
372
+ if (!raw) return null;
373
+ const cached = JSON.parse(raw);
374
+ if (!Array.isArray(cached.projectsTree)) return null;
375
+ return {
376
+ projectsTree: cached.projectsTree,
377
+ organizationName: cached.organizationName
378
+ };
379
+ } catch {
380
+ return null;
381
+ }
382
+ }
383
+ function setCachedProjects(clientId, userId, data) {
384
+ try {
385
+ sessionStorage.setItem(projectsCacheKey(clientId, userId), JSON.stringify(data));
386
+ } catch {}
387
+ }
388
+ /** Drop every cached projects entry (all clients/users) — used on logout. */
389
+ function clearCachedProjects() {
390
+ try {
391
+ for (let i = sessionStorage.length - 1; i >= 0; i--) {
392
+ const key = sessionStorage.key(i);
393
+ if (key?.startsWith(PROJECTS_CACHE_KEY)) sessionStorage.removeItem(key);
394
+ }
395
+ } catch {}
396
+ }
284
397
  //#endregion
285
398
  //#region src/patterns/Header/header-store.ts
286
399
  function initialState() {
@@ -464,7 +577,7 @@ function isSessionValid(environmentId) {
464
577
  const TOGGLE_PROJECT_DROPDOWN_EVENT = "toggle-project-dropdown";
465
578
  const DEFAULT_STALE_TIME = 5 * 6e4;
466
579
  const DEFAULT_GC_TIME = 10 * 6e4;
467
- 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 }) {
580
+ 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 }) {
468
581
  const fetcher = react$1.useMemo(() => fetcherProp ?? ((input, init) => fetch(input, init)), [fetcherProp]);
469
582
  const endpoints = react$1.useMemo(() => buildEndpoints(apiBaseUrl, endpointOverrides), [apiBaseUrl, endpointOverrides]);
470
583
  const isAuthenticated = isSessionValid(environmentId);
@@ -482,15 +595,25 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
482
595
  });
483
596
  const token = injectedToken ?? tokenQuery.data;
484
597
  const effectiveClientId = clientId ?? claims?.clientId;
598
+ const wantsProjects = showProjectDropdown || showOrg;
599
+ const userId = claims?.userId ?? "";
485
600
  const projectsQuery = (0, _tanstack_react_query.useQuery)({
486
601
  queryKey: [
487
602
  "ds-header",
488
603
  "projects",
489
604
  effectiveClientId,
605
+ userId,
490
606
  token
491
607
  ],
492
- queryFn: () => fetchProjects(endpoints, effectiveClientId, token, fetcher),
493
- enabled: isAuthenticated && !!token && !!effectiveClientId && (showProjectDropdown || showOrg),
608
+ queryFn: async () => {
609
+ const id = effectiveClientId;
610
+ const cached = getCachedProjects(id, userId);
611
+ if (cached) return cached;
612
+ const fresh = await fetchProjects(endpoints, id, token, fetcher);
613
+ setCachedProjects(id, userId, fresh);
614
+ return fresh;
615
+ },
616
+ enabled: isAuthenticated && !!token && !!effectiveClientId && wantsProjects,
494
617
  staleTime,
495
618
  gcTime
496
619
  });
@@ -535,6 +658,9 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
535
658
  const fallback = last && nodeExistsInTree(tree, last.id) ? {
536
659
  id: last.id,
537
660
  name: findProjectName(tree, last.id) ?? last.name
661
+ } : defaultProjectId && nodeExistsInTree(tree, defaultProjectId) ? {
662
+ id: defaultProjectId,
663
+ name: findProjectName(tree, defaultProjectId) ?? ""
538
664
  } : firstSelectableProject(tree);
539
665
  if (fallback) {
540
666
  headerStore.setProject(fallback.id, fallback.name, effectiveClientId, { remember: false });
@@ -542,7 +668,11 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
542
668
  } else if (id) headerStore.clearProject();
543
669
  }
544
670
  headerStore.setOrganization(projectsQuery.data.organizationName, effectiveClientId);
545
- }, [projectsQuery.data, effectiveClientId]);
671
+ }, [
672
+ projectsQuery.data,
673
+ effectiveClientId,
674
+ defaultProjectId
675
+ ]);
546
676
  react$1.useEffect(() => {
547
677
  if (creditsQuery.data !== void 0) headerStore.setCredits(creditsQuery.data);
548
678
  }, [creditsQuery.data]);
@@ -553,6 +683,7 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
553
683
  };
554
684
  const logout = () => {
555
685
  headerStore.clearProject();
686
+ clearCachedProjects();
556
687
  callLogout(endpoints, fetcher);
557
688
  };
558
689
  const [projectDropdownVisible, setProjectDropdownVisible] = react$1.useState(showProjectDropdown);