@pihanga2/shadcn 0.1.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 (399) hide show
  1. package/README.md +114 -0
  2. package/cards/badge/badge.component.d.ts +14 -0
  3. package/cards/badge/badge.component.js +18 -0
  4. package/cards/badge/badge.component.js.map +1 -0
  5. package/cards/badge/badge.types.d.ts +37 -0
  6. package/cards/badge/badge.types.js +7 -0
  7. package/cards/badge/badge.types.js.map +1 -0
  8. package/cards/badge/index.d.ts +1 -0
  9. package/cards/badge/index.js +12 -0
  10. package/cards/badge/index.js.map +1 -0
  11. package/cards/box/box.component.d.ts +4 -0
  12. package/cards/box/box.component.js +24 -0
  13. package/cards/box/box.component.js.map +1 -0
  14. package/cards/box/box.types.d.ts +71 -0
  15. package/cards/box/box.types.js +7 -0
  16. package/cards/box/box.types.js.map +1 -0
  17. package/cards/box/index.d.ts +1 -0
  18. package/cards/box/index.js +12 -0
  19. package/cards/box/index.js.map +1 -0
  20. package/cards/button/button.component.d.ts +4 -0
  21. package/cards/button/button.component.js +71 -0
  22. package/cards/button/button.component.js.map +1 -0
  23. package/cards/button/button.types.d.ts +106 -0
  24. package/cards/button/button.types.js +7 -0
  25. package/cards/button/button.types.js.map +1 -0
  26. package/cards/button/index.d.ts +1 -0
  27. package/cards/button/index.js +13 -0
  28. package/cards/button/index.js.map +1 -0
  29. package/cards/checkbox/checkbox.component.d.ts +4 -0
  30. package/cards/checkbox/checkbox.component.js +36 -0
  31. package/cards/checkbox/checkbox.component.js.map +1 -0
  32. package/cards/checkbox/checkbox.types.d.ts +37 -0
  33. package/cards/checkbox/checkbox.types.js +7 -0
  34. package/cards/checkbox/checkbox.types.js.map +1 -0
  35. package/cards/checkbox/index.d.ts +1 -0
  36. package/cards/checkbox/index.js +13 -0
  37. package/cards/checkbox/index.js.map +1 -0
  38. package/cards/conditional/conditional.component.d.ts +11 -0
  39. package/cards/conditional/conditional.component.js +15 -0
  40. package/cards/conditional/conditional.component.js.map +1 -0
  41. package/cards/conditional/conditional.types.d.ts +29 -0
  42. package/cards/conditional/conditional.types.js +7 -0
  43. package/cards/conditional/conditional.types.js.map +1 -0
  44. package/cards/conditional/index.d.ts +1 -0
  45. package/cards/conditional/index.js +12 -0
  46. package/cards/conditional/index.js.map +1 -0
  47. package/cards/core-index.d.ts +30 -0
  48. package/cards/core-index.js +61 -0
  49. package/cards/dataTable/dataTable.component.d.ts +4 -0
  50. package/cards/dataTable/dataTable.component.js +209 -0
  51. package/cards/dataTable/dataTable.component.js.map +1 -0
  52. package/cards/dataTable/dataTable.types.d.ts +196 -0
  53. package/cards/dataTable/dataTable.types.js +13 -0
  54. package/cards/dataTable/dataTable.types.js.map +1 -0
  55. package/cards/dataTable/dataTableRowDetail.component.d.ts +26 -0
  56. package/cards/dataTable/dataTableRowDetail.component.js +47 -0
  57. package/cards/dataTable/dataTableRowDetail.component.js.map +1 -0
  58. package/cards/dataTable/index.d.ts +1 -0
  59. package/cards/dataTable/index.js +16 -0
  60. package/cards/dataTable/index.js.map +1 -0
  61. package/cards/dialog/dialog.component.d.ts +4 -0
  62. package/cards/dialog/dialog.component.js +89 -0
  63. package/cards/dialog/dialog.component.js.map +1 -0
  64. package/cards/dialog/dialog.types.d.ts +115 -0
  65. package/cards/dialog/dialog.types.js +11 -0
  66. package/cards/dialog/dialog.types.js.map +1 -0
  67. package/cards/dialog/index.d.ts +1 -0
  68. package/cards/dialog/index.js +13 -0
  69. package/cards/dialog/index.js.map +1 -0
  70. package/cards/dropDownMenu/drop-down.component.d.ts +4 -0
  71. package/cards/dropDownMenu/drop-down.component.js +205 -0
  72. package/cards/dropDownMenu/drop-down.component.js.map +1 -0
  73. package/cards/dropDownMenu/drop-down.types.d.ts +131 -0
  74. package/cards/dropDownMenu/drop-down.types.js +7 -0
  75. package/cards/dropDownMenu/drop-down.types.js.map +1 -0
  76. package/cards/dropDownMenu/dropdown-context.d.ts +7 -0
  77. package/cards/dropDownMenu/dropdown-context.js +7 -0
  78. package/cards/dropDownMenu/dropdown-context.js.map +1 -0
  79. package/cards/dropDownMenu/dropdown-menu.ui.d.ts +42 -0
  80. package/cards/dropDownMenu/dropdown-menu.ui.js +111 -0
  81. package/cards/dropDownMenu/dropdown-menu.ui.js.map +1 -0
  82. package/cards/dropDownMenu/index.d.ts +1 -0
  83. package/cards/dropDownMenu/index.js +13 -0
  84. package/cards/dropDownMenu/index.js.map +1 -0
  85. package/cards/emptyCard.d.ts +7 -0
  86. package/cards/field/field.component.d.ts +4 -0
  87. package/cards/field/field.component.js +38 -0
  88. package/cards/field/field.component.js.map +1 -0
  89. package/cards/field/field.types.d.ts +30 -0
  90. package/cards/field/field.types.js +7 -0
  91. package/cards/field/field.types.js.map +1 -0
  92. package/cards/field/index.d.ts +1 -0
  93. package/cards/field/index.js +12 -0
  94. package/cards/field/index.js.map +1 -0
  95. package/cards/flexGrid/flexGrid.component.d.ts +4 -0
  96. package/cards/flexGrid/flexGrid.component.js +40 -0
  97. package/cards/flexGrid/flexGrid.component.js.map +1 -0
  98. package/cards/flexGrid/flexGrid.types.d.ts +23 -0
  99. package/cards/flexGrid/flexGrid.types.js +7 -0
  100. package/cards/flexGrid/flexGrid.types.js.map +1 -0
  101. package/cards/flexGrid/index.d.ts +1 -0
  102. package/cards/flexGrid/index.js +12 -0
  103. package/cards/flexGrid/index.js.map +1 -0
  104. package/cards/form/form.component.d.ts +4 -0
  105. package/cards/form/form.component.js +64 -0
  106. package/cards/form/form.component.js.map +1 -0
  107. package/cards/form/form.context.d.ts +23 -0
  108. package/cards/form/form.context.js +13 -0
  109. package/cards/form/form.context.js.map +1 -0
  110. package/cards/form/form.types.d.ts +43 -0
  111. package/cards/form/form.types.js +7 -0
  112. package/cards/form/form.types.js.map +1 -0
  113. package/cards/form/index.d.ts +2 -0
  114. package/cards/form/index.js +14 -0
  115. package/cards/form/index.js.map +1 -0
  116. package/cards/framework/framework.component.d.ts +3 -0
  117. package/cards/framework/framework.component.js +21 -0
  118. package/cards/framework/framework.component.js.map +1 -0
  119. package/cards/framework/index.d.ts +2 -0
  120. package/cards/framework/index.js +12 -0
  121. package/cards/framework/index.js.map +1 -0
  122. package/cards/graphin/graphin.component.d.ts +4 -0
  123. package/cards/graphin/graphin.types.d.ts +18 -0
  124. package/cards/graphin/index.d.ts +2 -0
  125. package/cards/graphin/tooltip.component.d.ts +10 -0
  126. package/cards/icons.d.ts +15 -0
  127. package/cards/icons.js +15 -0
  128. package/cards/icons.js.map +1 -0
  129. package/cards/input/index.d.ts +1 -0
  130. package/cards/input/index.js +13 -0
  131. package/cards/input/index.js.map +1 -0
  132. package/cards/input/input.component.d.ts +4 -0
  133. package/cards/input/input.component.js +69 -0
  134. package/cards/input/input.component.js.map +1 -0
  135. package/cards/input/input.types.d.ts +80 -0
  136. package/cards/input/input.types.js +7 -0
  137. package/cards/input/input.types.js.map +1 -0
  138. package/cards/jsonViewer/index.d.ts +1 -0
  139. package/cards/jsonViewer/jsonViewer.component.d.ts +4 -0
  140. package/cards/jsonViewer/jsonViewer.types.d.ts +76 -0
  141. package/cards/list/index.d.ts +1 -0
  142. package/cards/list/index.js +13 -0
  143. package/cards/list/index.js.map +1 -0
  144. package/cards/list/list.component.d.ts +4 -0
  145. package/cards/list/list.component.js +102 -0
  146. package/cards/list/list.component.js.map +1 -0
  147. package/cards/list/list.types.d.ts +65 -0
  148. package/cards/list/list.types.js +7 -0
  149. package/cards/list/list.types.js.map +1 -0
  150. package/cards/loadingOverlay/index.d.ts +1 -0
  151. package/cards/loadingOverlay/index.js +12 -0
  152. package/cards/loadingOverlay/index.js.map +1 -0
  153. package/cards/loadingOverlay/loadingOverlay.component.d.ts +4 -0
  154. package/cards/loadingOverlay/loadingOverlay.component.js +31 -0
  155. package/cards/loadingOverlay/loadingOverlay.component.js.map +1 -0
  156. package/cards/loadingOverlay/loadingOverlay.types.d.ts +13 -0
  157. package/cards/loadingOverlay/loadingOverlay.types.js +7 -0
  158. package/cards/loadingOverlay/loadingOverlay.types.js.map +1 -0
  159. package/cards/loadingSkeleton/index.d.ts +1 -0
  160. package/cards/loadingSkeleton/index.js +12 -0
  161. package/cards/loadingSkeleton/index.js.map +1 -0
  162. package/cards/loadingSkeleton/loading-skeleton.component.d.ts +19 -0
  163. package/cards/loadingSkeleton/loading-skeleton.component.js +33 -0
  164. package/cards/loadingSkeleton/loading-skeleton.component.js.map +1 -0
  165. package/cards/loadingSkeleton/loading-skeleton.types.d.ts +94 -0
  166. package/cards/loadingSkeleton/loading-skeleton.types.js +7 -0
  167. package/cards/loadingSkeleton/loading-skeleton.types.js.map +1 -0
  168. package/cards/markdownViewer/index.d.ts +1 -0
  169. package/cards/markdownViewer/markdownViewer.component.d.ts +4 -0
  170. package/cards/markdownViewer/markdownViewer.types.d.ts +28 -0
  171. package/cards/menu/index.d.ts +1 -0
  172. package/cards/menu/index.js +13 -0
  173. package/cards/menu/index.js.map +1 -0
  174. package/cards/menu/menu.component.d.ts +4 -0
  175. package/cards/menu/menu.component.js +23 -0
  176. package/cards/menu/menu.component.js.map +1 -0
  177. package/cards/menu/menu.types.d.ts +53 -0
  178. package/cards/menu/menu.types.js +7 -0
  179. package/cards/menu/menu.types.js.map +1 -0
  180. package/cards/modeToggle/index.d.ts +1 -0
  181. package/cards/modeToggle/index.js +13 -0
  182. package/cards/modeToggle/index.js.map +1 -0
  183. package/cards/modeToggle/mode-toggle.component.d.ts +4 -0
  184. package/cards/modeToggle/mode-toggle.component.js +32 -0
  185. package/cards/modeToggle/mode-toggle.component.js.map +1 -0
  186. package/cards/modeToggle/mode-toggle.types.d.ts +20 -0
  187. package/cards/modeToggle/mode-toggle.types.js +7 -0
  188. package/cards/modeToggle/mode-toggle.types.js.map +1 -0
  189. package/cards/navbarSearch/index.d.ts +1 -0
  190. package/cards/navbarSearch/index.js +13 -0
  191. package/cards/navbarSearch/index.js.map +1 -0
  192. package/cards/navbarSearch/navbarSearch.component.d.ts +3 -0
  193. package/cards/navbarSearch/navbarSearch.component.js +88 -0
  194. package/cards/navbarSearch/navbarSearch.component.js.map +1 -0
  195. package/cards/navbarSearch/navbarSearch.type.d.ts +32 -0
  196. package/cards/navbarSearch/navbarSearch.type.js +11 -0
  197. package/cards/navbarSearch/navbarSearch.type.js.map +1 -0
  198. package/cards/pageWithNavbar/index.d.ts +2 -0
  199. package/cards/pageWithNavbar/index.js +14 -0
  200. package/cards/pageWithNavbar/index.js.map +1 -0
  201. package/cards/pageWithNavbar/pageWithNavbar.component.d.ts +12 -0
  202. package/cards/pageWithNavbar/pageWithNavbar.component.js +153 -0
  203. package/cards/pageWithNavbar/pageWithNavbar.component.js.map +1 -0
  204. package/cards/pageWithNavbar/pageWithNavbar.type.d.ts +81 -0
  205. package/cards/pageWithNavbar/pageWithNavbar.type.js +7 -0
  206. package/cards/pageWithNavbar/pageWithNavbar.type.js.map +1 -0
  207. package/cards/pasteTarget/index.d.ts +1 -0
  208. package/cards/pasteTarget/index.js +13 -0
  209. package/cards/pasteTarget/index.js.map +1 -0
  210. package/cards/pasteTarget/pasteTarget.component.d.ts +4 -0
  211. package/cards/pasteTarget/pasteTarget.component.js +158 -0
  212. package/cards/pasteTarget/pasteTarget.component.js.map +1 -0
  213. package/cards/pasteTarget/pasteTarget.types.d.ts +46 -0
  214. package/cards/pasteTarget/pasteTarget.types.js +11 -0
  215. package/cards/pasteTarget/pasteTarget.types.js.map +1 -0
  216. package/cards/resizable/index.d.ts +1 -0
  217. package/cards/resizable/resizable.component.d.ts +4 -0
  218. package/cards/resizable/resizable.types.d.ts +49 -0
  219. package/cards/select/index.d.ts +1 -0
  220. package/cards/select/index.js +13 -0
  221. package/cards/select/index.js.map +1 -0
  222. package/cards/select/select.component.d.ts +4 -0
  223. package/cards/select/select.component.js +41 -0
  224. package/cards/select/select.component.js.map +1 -0
  225. package/cards/select/select.types.d.ts +73 -0
  226. package/cards/select/select.types.js +11 -0
  227. package/cards/select/select.types.js.map +1 -0
  228. package/cards/stack/index.d.ts +1 -0
  229. package/cards/stack/index.js +12 -0
  230. package/cards/stack/index.js.map +1 -0
  231. package/cards/stack/stack.component.d.ts +7 -0
  232. package/cards/stack/stack.component.js +83 -0
  233. package/cards/stack/stack.component.js.map +1 -0
  234. package/cards/stack/stack.types.d.ts +47 -0
  235. package/cards/stack/stack.types.js +7 -0
  236. package/cards/stack/stack.types.js.map +1 -0
  237. package/cards/stepper/index.d.ts +1 -0
  238. package/cards/stepper/index.js +13 -0
  239. package/cards/stepper/index.js.map +1 -0
  240. package/cards/stepper/stepper.component.d.ts +4 -0
  241. package/cards/stepper/stepper.component.js +48 -0
  242. package/cards/stepper/stepper.component.js.map +1 -0
  243. package/cards/stepper/stepper.types.d.ts +96 -0
  244. package/cards/stepper/stepper.types.js +7 -0
  245. package/cards/stepper/stepper.types.js.map +1 -0
  246. package/cards/switch/index.d.ts +1 -0
  247. package/cards/switch/index.js +13 -0
  248. package/cards/switch/index.js.map +1 -0
  249. package/cards/switch/switch.component.d.ts +4 -0
  250. package/cards/switch/switch.component.js +34 -0
  251. package/cards/switch/switch.component.js.map +1 -0
  252. package/cards/switch/switch.types.d.ts +39 -0
  253. package/cards/switch/switch.types.js +7 -0
  254. package/cards/switch/switch.types.js.map +1 -0
  255. package/cards/tabs/index.d.ts +1 -0
  256. package/cards/tabs/index.js +13 -0
  257. package/cards/tabs/index.js.map +1 -0
  258. package/cards/tabs/tabs.component.d.ts +4 -0
  259. package/cards/tabs/tabs.component.js +42 -0
  260. package/cards/tabs/tabs.component.js.map +1 -0
  261. package/cards/tabs/tabs.types.d.ts +72 -0
  262. package/cards/tabs/tabs.types.js +7 -0
  263. package/cards/tabs/tabs.types.js.map +1 -0
  264. package/cards/textField/index.d.ts +1 -0
  265. package/cards/textField/index.js +13 -0
  266. package/cards/textField/index.js.map +1 -0
  267. package/cards/textField/textField.component.d.ts +4 -0
  268. package/cards/textField/textField.component.js +29 -0
  269. package/cards/textField/textField.component.js.map +1 -0
  270. package/cards/textField/textField.types.d.ts +36 -0
  271. package/cards/textField/textField.types.js +7 -0
  272. package/cards/textField/textField.types.js.map +1 -0
  273. package/cards/toast/index.d.ts +1 -0
  274. package/cards/toast/index.js +13 -0
  275. package/cards/toast/index.js.map +1 -0
  276. package/cards/toast/toast.component.d.ts +4 -0
  277. package/cards/toast/toast.component.js +76 -0
  278. package/cards/toast/toast.component.js.map +1 -0
  279. package/cards/toast/toast.types.d.ts +100 -0
  280. package/cards/toast/toast.types.js +12 -0
  281. package/cards/toast/toast.types.js.map +1 -0
  282. package/cards/toggleGroup/index.d.ts +1 -0
  283. package/cards/toggleGroup/index.js +13 -0
  284. package/cards/toggleGroup/index.js.map +1 -0
  285. package/cards/toggleGroup/toggleGroup.component.d.ts +4 -0
  286. package/cards/toggleGroup/toggleGroup.component.js +55 -0
  287. package/cards/toggleGroup/toggleGroup.component.js.map +1 -0
  288. package/cards/toggleGroup/toggleGroup.types.d.ts +96 -0
  289. package/cards/toggleGroup/toggleGroup.types.js +7 -0
  290. package/cards/toggleGroup/toggleGroup.types.js.map +1 -0
  291. package/cards/types.d.ts +72 -0
  292. package/cards/types.js +22 -0
  293. package/cards/types.js.map +1 -0
  294. package/cards/typography/index.d.ts +1 -0
  295. package/cards/typography/index.js +12 -0
  296. package/cards/typography/index.js.map +1 -0
  297. package/cards/typography/typography.component.d.ts +4 -0
  298. package/cards/typography/typography.component.js +44 -0
  299. package/cards/typography/typography.component.js.map +1 -0
  300. package/cards/typography/typography.types.d.ts +23 -0
  301. package/cards/typography/typography.types.js +7 -0
  302. package/cards/typography/typography.types.js.map +1 -0
  303. package/components/hooks/use-is-touch-device.d.ts +1 -0
  304. package/components/lib/utils.js +10 -0
  305. package/components/lib/utils.js.map +1 -0
  306. package/components/theme-provider/index.d.ts +4 -0
  307. package/components/theme-provider/index.js +12 -0
  308. package/components/theme-provider/index.js.map +1 -0
  309. package/components/theme-provider/theme-provider.component.d.ts +2 -0
  310. package/components/theme-provider/theme-provider.component.js +31 -0
  311. package/components/theme-provider/theme-provider.component.js.map +1 -0
  312. package/components/theme-provider/theme-provider.types.d.ts +12 -0
  313. package/components/theme-provider/theme-provider.types.js +9 -0
  314. package/components/theme-provider/theme-provider.types.js.map +1 -0
  315. package/components/ui/avatar.js +30 -0
  316. package/components/ui/avatar.js.map +1 -0
  317. package/components/ui/badge.js +26 -0
  318. package/components/ui/badge.js.map +1 -0
  319. package/components/ui/button.js +98 -0
  320. package/components/ui/button.js.map +1 -0
  321. package/components/ui/dialog.js +109 -0
  322. package/components/ui/dialog.js.map +1 -0
  323. package/components/ui/field.js +68 -0
  324. package/components/ui/field.js.map +1 -0
  325. package/components/ui/input.js +16 -0
  326. package/components/ui/input.js.map +1 -0
  327. package/components/ui/label.js +16 -0
  328. package/components/ui/label.js.map +1 -0
  329. package/components/ui/menubar.js +62 -0
  330. package/components/ui/menubar.js.map +1 -0
  331. package/components/ui/select.js +84 -0
  332. package/components/ui/select.js.map +1 -0
  333. package/components/ui/separator.js +5 -0
  334. package/components/ui/sheet.js +49 -0
  335. package/components/ui/sheet.js.map +1 -0
  336. package/components/ui/spinner.js +35 -0
  337. package/components/ui/spinner.js.map +1 -0
  338. package/components/ui/stepper.js +145 -0
  339. package/components/ui/stepper.js.map +1 -0
  340. package/components/ui/switch.js +20 -0
  341. package/components/ui/switch.js.map +1 -0
  342. package/components/ui/table.js +61 -0
  343. package/components/ui/table.js.map +1 -0
  344. package/components/ui/tabs.js +38 -0
  345. package/components/ui/tabs.js.map +1 -0
  346. package/components/ui/toggle-group.js +50 -0
  347. package/components/ui/toggle-group.js.map +1 -0
  348. package/components/ui/toggle.js +27 -0
  349. package/components/ui/toggle.js.map +1 -0
  350. package/components/ui/tooltip.js +38 -0
  351. package/components/ui/tooltip.js.map +1 -0
  352. package/lib/utils.d.ts +2 -0
  353. package/lib/utils.js +10 -0
  354. package/lib/utils.js.map +1 -0
  355. package/mountain-snow.svg +4 -0
  356. package/package.json +203 -0
  357. package/pihanga-shadcn.css +2 -0
  358. package/r/badge.json +35 -0
  359. package/r/box.json +26 -0
  360. package/r/button.json +39 -0
  361. package/r/checkbox.json +31 -0
  362. package/r/conditional.json +30 -0
  363. package/r/dataTable.json +43 -0
  364. package/r/dialog.json +36 -0
  365. package/r/dropDownMenu.json +47 -0
  366. package/r/field.json +35 -0
  367. package/r/flexGrid.json +32 -0
  368. package/r/form.json +37 -0
  369. package/r/framework.json +28 -0
  370. package/r/graphin.json +42 -0
  371. package/r/input.json +35 -0
  372. package/r/jsonViewer.json +40 -0
  373. package/r/list.json +39 -0
  374. package/r/loadingOverlay.json +39 -0
  375. package/r/loadingSkeleton.json +30 -0
  376. package/r/markdownViewer.json +51 -0
  377. package/r/menu.json +34 -0
  378. package/r/modeToggle.json +36 -0
  379. package/r/navbarSearch.json +31 -0
  380. package/r/pageWithNavbar.json +46 -0
  381. package/r/pasteTarget.json +41 -0
  382. package/r/pihanga-base.json +11 -0
  383. package/r/pihanga-cards-icons.json +16 -0
  384. package/r/pihanga-cards-types.json +16 -0
  385. package/r/pihanga-hook-use-is-touch-device.json +15 -0
  386. package/r/pihanga-lib-utils.json +18 -0
  387. package/r/pihanga-theme-provider.json +25 -0
  388. package/r/pihanga-ui-extras.json +68 -0
  389. package/r/registry.json +171 -0
  390. package/r/resizable.json +35 -0
  391. package/r/select.json +35 -0
  392. package/r/stack.json +27 -0
  393. package/r/stepper.json +39 -0
  394. package/r/switch.json +36 -0
  395. package/r/tabs.json +33 -0
  396. package/r/textField.json +32 -0
  397. package/r/toast.json +32 -0
  398. package/r/toggleGroup.json +35 -0
  399. package/r/typography.json +31 -0
package/package.json ADDED
@@ -0,0 +1,203 @@
1
+ {
2
+ "name": "@pihanga2/shadcn",
3
+ "version": "0.1.0",
4
+ "description": "Pihanga core card components built on shadcn/ui and Radix UI — the npm distribution of pihanga-shadcn.",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./cards/core-index.js",
9
+ "types": "./cards/core-index.d.ts"
10
+ },
11
+ "./cards/badge": {
12
+ "import": "./cards/badge/index.js",
13
+ "types": "./cards/badge/index.d.ts"
14
+ },
15
+ "./cards/box": {
16
+ "import": "./cards/box/index.js",
17
+ "types": "./cards/box/index.d.ts"
18
+ },
19
+ "./cards/button": {
20
+ "import": "./cards/button/index.js",
21
+ "types": "./cards/button/index.d.ts"
22
+ },
23
+ "./cards/checkbox": {
24
+ "import": "./cards/checkbox/index.js",
25
+ "types": "./cards/checkbox/index.d.ts"
26
+ },
27
+ "./cards/conditional": {
28
+ "import": "./cards/conditional/index.js",
29
+ "types": "./cards/conditional/index.d.ts"
30
+ },
31
+ "./cards/dataTable": {
32
+ "import": "./cards/dataTable/index.js",
33
+ "types": "./cards/dataTable/index.d.ts"
34
+ },
35
+ "./cards/dialog": {
36
+ "import": "./cards/dialog/index.js",
37
+ "types": "./cards/dialog/index.d.ts"
38
+ },
39
+ "./cards/dropDownMenu": {
40
+ "import": "./cards/dropDownMenu/index.js",
41
+ "types": "./cards/dropDownMenu/index.d.ts"
42
+ },
43
+ "./cards/field": {
44
+ "import": "./cards/field/index.js",
45
+ "types": "./cards/field/index.d.ts"
46
+ },
47
+ "./cards/flexGrid": {
48
+ "import": "./cards/flexGrid/index.js",
49
+ "types": "./cards/flexGrid/index.d.ts"
50
+ },
51
+ "./cards/form": {
52
+ "import": "./cards/form/index.js",
53
+ "types": "./cards/form/index.d.ts"
54
+ },
55
+ "./cards/framework": {
56
+ "import": "./cards/framework/index.js",
57
+ "types": "./cards/framework/index.d.ts"
58
+ },
59
+ "./cards/input": {
60
+ "import": "./cards/input/index.js",
61
+ "types": "./cards/input/index.d.ts"
62
+ },
63
+ "./cards/list": {
64
+ "import": "./cards/list/index.js",
65
+ "types": "./cards/list/index.d.ts"
66
+ },
67
+ "./cards/loadingOverlay": {
68
+ "import": "./cards/loadingOverlay/index.js",
69
+ "types": "./cards/loadingOverlay/index.d.ts"
70
+ },
71
+ "./cards/loadingSkeleton": {
72
+ "import": "./cards/loadingSkeleton/index.js",
73
+ "types": "./cards/loadingSkeleton/index.d.ts"
74
+ },
75
+ "./cards/menu": {
76
+ "import": "./cards/menu/index.js",
77
+ "types": "./cards/menu/index.d.ts"
78
+ },
79
+ "./cards/modeToggle": {
80
+ "import": "./cards/modeToggle/index.js",
81
+ "types": "./cards/modeToggle/index.d.ts"
82
+ },
83
+ "./cards/navbarSearch": {
84
+ "import": "./cards/navbarSearch/index.js",
85
+ "types": "./cards/navbarSearch/index.d.ts"
86
+ },
87
+ "./cards/pageWithNavbar": {
88
+ "import": "./cards/pageWithNavbar/index.js",
89
+ "types": "./cards/pageWithNavbar/index.d.ts"
90
+ },
91
+ "./cards/pasteTarget": {
92
+ "import": "./cards/pasteTarget/index.js",
93
+ "types": "./cards/pasteTarget/index.d.ts"
94
+ },
95
+ "./cards/select": {
96
+ "import": "./cards/select/index.js",
97
+ "types": "./cards/select/index.d.ts"
98
+ },
99
+ "./cards/stack": {
100
+ "import": "./cards/stack/index.js",
101
+ "types": "./cards/stack/index.d.ts"
102
+ },
103
+ "./cards/stepper": {
104
+ "import": "./cards/stepper/index.js",
105
+ "types": "./cards/stepper/index.d.ts"
106
+ },
107
+ "./cards/switch": {
108
+ "import": "./cards/switch/index.js",
109
+ "types": "./cards/switch/index.d.ts"
110
+ },
111
+ "./cards/tabs": {
112
+ "import": "./cards/tabs/index.js",
113
+ "types": "./cards/tabs/index.d.ts"
114
+ },
115
+ "./cards/textField": {
116
+ "import": "./cards/textField/index.js",
117
+ "types": "./cards/textField/index.d.ts"
118
+ },
119
+ "./cards/toast": {
120
+ "import": "./cards/toast/index.js",
121
+ "types": "./cards/toast/index.d.ts"
122
+ },
123
+ "./cards/toggleGroup": {
124
+ "import": "./cards/toggleGroup/index.js",
125
+ "types": "./cards/toggleGroup/index.d.ts"
126
+ },
127
+ "./cards/typography": {
128
+ "import": "./cards/typography/index.js",
129
+ "types": "./cards/typography/index.d.ts"
130
+ }
131
+ },
132
+ "main": "./cards/core-index.js",
133
+ "types": "./cards/core-index.d.ts",
134
+ "sideEffects": [
135
+ "./cards/badge/index.js",
136
+ "./cards/box/index.js",
137
+ "./cards/button/index.js",
138
+ "./cards/checkbox/index.js",
139
+ "./cards/conditional/index.js",
140
+ "./cards/dataTable/index.js",
141
+ "./cards/dialog/index.js",
142
+ "./cards/dropDownMenu/index.js",
143
+ "./cards/field/index.js",
144
+ "./cards/flexGrid/index.js",
145
+ "./cards/form/index.js",
146
+ "./cards/framework/index.js",
147
+ "./cards/input/index.js",
148
+ "./cards/list/index.js",
149
+ "./cards/loadingOverlay/index.js",
150
+ "./cards/loadingSkeleton/index.js",
151
+ "./cards/menu/index.js",
152
+ "./cards/modeToggle/index.js",
153
+ "./cards/navbarSearch/index.js",
154
+ "./cards/pageWithNavbar/index.js",
155
+ "./cards/pasteTarget/index.js",
156
+ "./cards/select/index.js",
157
+ "./cards/stack/index.js",
158
+ "./cards/stepper/index.js",
159
+ "./cards/switch/index.js",
160
+ "./cards/tabs/index.js",
161
+ "./cards/textField/index.js",
162
+ "./cards/toast/index.js",
163
+ "./cards/toggleGroup/index.js",
164
+ "./cards/typography/index.js"
165
+ ],
166
+ "license": "MIT",
167
+ "homepage": "https://ivcap-works.github.io/pihanga-shadcn",
168
+ "repository": {
169
+ "type": "git",
170
+ "url": "https://github.com/ivcap-works/pihanga-shadcn.git"
171
+ },
172
+ "keywords": [
173
+ "pihanga",
174
+ "shadcn",
175
+ "radix-ui",
176
+ "react",
177
+ "ui",
178
+ "components",
179
+ "cards"
180
+ ],
181
+ "peerDependencies": {
182
+ "react": "^19.1.0",
183
+ "react-dom": "^19.1.0",
184
+ "@pihanga2/core": "*",
185
+ "@pihanga2/cards": "^0.3.15"
186
+ },
187
+ "dependencies": {
188
+ "@radix-ui/react-dialog": "^1.1.15",
189
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
190
+ "@radix-ui/react-menubar": "^1.1.16",
191
+ "@radix-ui/react-select": "^2.2.6",
192
+ "@radix-ui/react-slot": "^1.2.4",
193
+ "@radix-ui/react-switch": "^1.1.2",
194
+ "@radix-ui/react-tabs": "^1.1.13",
195
+ "@radix-ui/react-tooltip": "^1.2.8",
196
+ "class-variance-authority": "^0.7.1",
197
+ "clsx": "^2.1.1",
198
+ "lucide-react": "^0.513.0",
199
+ "radix-ui": "^1.4.3",
200
+ "sonner": "^2.0.7",
201
+ "tailwind-merge": "^3.3.0"
202
+ }
203
+ }
@@ -0,0 +1,2 @@
1
+ .overlay-wrapper{flex-direction:column;width:100%;min-width:0;display:flex;position:relative}.overlay-wrapper.is-loading.fill-parent{min-height:12rem}.overlay-content{flex-direction:column;flex-grow:1;width:100%;min-width:0;display:flex;position:relative;overflow-y:hidden}.overlay-wrapper.fill-parent .overlay-content{min-height:inherit}.loading-overlay{opacity:0;pointer-events:none;z-index:2;background:oklch(100% 0 0/.7);justify-content:center;align-items:center;transition:opacity .15s;display:flex;position:absolute;inset:0}.overlay-wrapper.viewport-centered .loading-overlay{z-index:50;position:fixed;inset:0}.dark .loading-overlay{background:oklch(14.5% 0 0/.5)}.overlay-wrapper.is-loading .loading-overlay{opacity:1;pointer-events:auto}.loading-overlay__content{color:var(--muted-foreground);align-items:center;gap:.5rem;font-size:.875rem;display:flex}@layer theme{@theme default{--font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; --color-red-50: oklch(97.1% .013 17.38); --color-red-100: oklch(93.6% .032 17.717); --color-red-200: oklch(88.5% .062 18.334); --color-red-300: oklch(80.8% .114 19.571); --color-red-400: oklch(70.4% .191 22.216); --color-red-500: oklch(63.7% .237 25.331); --color-red-600: oklch(57.7% .245 27.325); --color-red-700: oklch(50.5% .213 27.518); --color-red-800: oklch(44.4% .177 26.899); --color-red-900: oklch(39.6% .141 25.723); --color-red-950: oklch(25.8% .092 26.042); --color-orange-50: oklch(98% .016 73.684); --color-orange-100: oklch(95.4% .038 75.164); --color-orange-200: oklch(90.1% .076 70.697); --color-orange-300: oklch(83.7% .128 66.29); --color-orange-400: oklch(75% .183 55.934); --color-orange-500: oklch(70.5% .213 47.604); --color-orange-600: oklch(64.6% .222 41.116); --color-orange-700: oklch(55.3% .195 38.402); --color-orange-800: oklch(47% .157 37.304); --color-orange-900: oklch(40.8% .123 38.172); --color-orange-950: oklch(26.6% .079 36.259); --color-amber-50: oklch(98.7% .022 95.277); --color-amber-100: oklch(96.2% .059 95.617); --color-amber-200: oklch(92.4% .12 95.746); --color-amber-300: oklch(87.9% .169 91.605); --color-amber-400: oklch(82.8% .189 84.429); --color-amber-500: oklch(76.9% .188 70.08); --color-amber-600: oklch(66.6% .179 58.318); --color-amber-700: oklch(55.5% .163 48.998); --color-amber-800: oklch(47.3% .137 46.201); --color-amber-900: oklch(41.4% .112 45.904); --color-amber-950: oklch(27.9% .077 45.635); --color-yellow-50: oklch(98.7% .026 102.212); --color-yellow-100: oklch(97.3% .071 103.193); --color-yellow-200: oklch(94.5% .129 101.54); --color-yellow-300: oklch(90.5% .182 98.111); --color-yellow-400: oklch(85.2% .199 91.936); --color-yellow-500: oklch(79.5% .184 86.047); --color-yellow-600: oklch(68.1% .162 75.834); --color-yellow-700: oklch(55.4% .135 66.442); --color-yellow-800: oklch(47.6% .114 61.907); --color-yellow-900: oklch(42.1% .095 57.708); --color-yellow-950: oklch(28.6% .066 53.813); --color-lime-50: oklch(98.6% .031 120.757); --color-lime-100: oklch(96.7% .067 122.328); --color-lime-200: oklch(93.8% .127 124.321); --color-lime-300: oklch(89.7% .196 126.665); --color-lime-400: oklch(84.1% .238 128.85); --color-lime-500: oklch(76.8% .233 130.85); --color-lime-600: oklch(64.8% .2 131.684); --color-lime-700: oklch(53.2% .157 131.589); --color-lime-800: oklch(45.3% .124 130.933); --color-lime-900: oklch(40.5% .101 131.063); --color-lime-950: oklch(27.4% .072 132.109); --color-green-50: oklch(98.2% .018 155.826); --color-green-100: oklch(96.2% .044 156.743); --color-green-200: oklch(92.5% .084 155.995); --color-green-300: oklch(87.1% .15 154.449); --color-green-400: oklch(79.2% .209 151.711); --color-green-500: oklch(72.3% .219 149.579); --color-green-600: oklch(62.7% .194 149.214); --color-green-700: oklch(52.7% .154 150.069); --color-green-800: oklch(44.8% .119 151.328); --color-green-900: oklch(39.3% .095 152.535); --color-green-950: oklch(26.6% .065 152.934); --color-emerald-50: oklch(97.9% .021 166.113); --color-emerald-100: oklch(95% .052 163.051); --color-emerald-200: oklch(90.5% .093 164.15); --color-emerald-300: oklch(84.5% .143 164.978); --color-emerald-400: oklch(76.5% .177 163.223); --color-emerald-500: oklch(69.6% .17 162.48); --color-emerald-600: oklch(59.6% .145 163.225); --color-emerald-700: oklch(50.8% .118 165.612); --color-emerald-800: oklch(43.2% .095 166.913); --color-emerald-900: oklch(37.8% .077 168.94); --color-emerald-950: oklch(26.2% .051 172.552); --color-teal-50: oklch(98.4% .014 180.72); --color-teal-100: oklch(95.3% .051 180.801); --color-teal-200: oklch(91% .096 180.426); --color-teal-300: oklch(85.5% .138 181.071); --color-teal-400: oklch(77.7% .152 181.912); --color-teal-500: oklch(70.4% .14 182.503); --color-teal-600: oklch(60% .118 184.704); --color-teal-700: oklch(51.1% .096 186.391); --color-teal-800: oklch(43.7% .078 188.216); --color-teal-900: oklch(38.6% .063 188.416); --color-teal-950: oklch(27.7% .046 192.524); --color-cyan-50: oklch(98.4% .019 200.873); --color-cyan-100: oklch(95.6% .045 203.388); --color-cyan-200: oklch(91.7% .08 205.041); --color-cyan-300: oklch(86.5% .127 207.078); --color-cyan-400: oklch(78.9% .154 211.53); --color-cyan-500: oklch(71.5% .143 215.221); --color-cyan-600: oklch(60.9% .126 221.723); --color-cyan-700: oklch(52% .105 223.128); --color-cyan-800: oklch(45% .085 224.283); --color-cyan-900: oklch(39.8% .07 227.392); --color-cyan-950: oklch(30.2% .056 229.695); --color-sky-50: oklch(97.7% .013 236.62); --color-sky-100: oklch(95.1% .026 236.824); --color-sky-200: oklch(90.1% .058 230.902); --color-sky-300: oklch(82.8% .111 230.318); --color-sky-400: oklch(74.6% .16 232.661); --color-sky-500: oklch(68.5% .169 237.323); --color-sky-600: oklch(58.8% .158 241.966); --color-sky-700: oklch(50% .134 242.749); --color-sky-800: oklch(44.3% .11 240.79); --color-sky-900: oklch(39.1% .09 240.876); --color-sky-950: oklch(29.3% .066 243.157); --color-blue-50: oklch(97% .014 254.604); --color-blue-100: oklch(93.2% .032 255.585); --color-blue-200: oklch(88.2% .059 254.128); --color-blue-300: oklch(80.9% .105 251.813); --color-blue-400: oklch(70.7% .165 254.624); --color-blue-500: oklch(62.3% .214 259.815); --color-blue-600: oklch(54.6% .245 262.881); --color-blue-700: oklch(48.8% .243 264.376); --color-blue-800: oklch(42.4% .199 265.638); --color-blue-900: oklch(37.9% .146 265.522); --color-blue-950: oklch(28.2% .091 267.935); --color-indigo-50: oklch(96.2% .018 272.314); --color-indigo-100: oklch(93% .034 272.788); --color-indigo-200: oklch(87% .065 274.039); --color-indigo-300: oklch(78.5% .115 274.713); --color-indigo-400: oklch(67.3% .182 276.935); --color-indigo-500: oklch(58.5% .233 277.117); --color-indigo-600: oklch(51.1% .262 276.966); --color-indigo-700: oklch(45.7% .24 277.023); --color-indigo-800: oklch(39.8% .195 277.366); --color-indigo-900: oklch(35.9% .144 278.697); --color-indigo-950: oklch(25.7% .09 281.288); --color-violet-50: oklch(96.9% .016 293.756); --color-violet-100: oklch(94.3% .029 294.588); --color-violet-200: oklch(89.4% .057 293.283); --color-violet-300: oklch(81.1% .111 293.571); --color-violet-400: oklch(70.2% .183 293.541); --color-violet-500: oklch(60.6% .25 292.717); --color-violet-600: oklch(54.1% .281 293.009); --color-violet-700: oklch(49.1% .27 292.581); --color-violet-800: oklch(43.2% .232 292.759); --color-violet-900: oklch(38% .189 293.745); --color-violet-950: oklch(28.3% .141 291.089); --color-purple-50: oklch(97.7% .014 308.299); --color-purple-100: oklch(94.6% .033 307.174); --color-purple-200: oklch(90.2% .063 306.703); --color-purple-300: oklch(82.7% .119 306.383); --color-purple-400: oklch(71.4% .203 305.504); --color-purple-500: oklch(62.7% .265 303.9); --color-purple-600: oklch(55.8% .288 302.321); --color-purple-700: oklch(49.6% .265 301.924); --color-purple-800: oklch(43.8% .218 303.724); --color-purple-900: oklch(38.1% .176 304.987); --color-purple-950: oklch(29.1% .149 302.717); --color-fuchsia-50: oklch(97.7% .017 320.058); --color-fuchsia-100: oklch(95.2% .037 318.852); --color-fuchsia-200: oklch(90.3% .076 319.62); --color-fuchsia-300: oklch(83.3% .145 321.434); --color-fuchsia-400: oklch(74% .238 322.16); --color-fuchsia-500: oklch(66.7% .295 322.15); --color-fuchsia-600: oklch(59.1% .293 322.896); --color-fuchsia-700: oklch(51.8% .253 323.949); --color-fuchsia-800: oklch(45.2% .211 324.591); --color-fuchsia-900: oklch(40.1% .17 325.612); --color-fuchsia-950: oklch(29.3% .136 325.661); --color-pink-50: oklch(97.1% .014 343.198); --color-pink-100: oklch(94.8% .028 342.258); --color-pink-200: oklch(89.9% .061 343.231); --color-pink-300: oklch(82.3% .12 346.018); --color-pink-400: oklch(71.8% .202 349.761); --color-pink-500: oklch(65.6% .241 354.308); --color-pink-600: oklch(59.2% .249 .584); --color-pink-700: oklch(52.5% .223 3.958); --color-pink-800: oklch(45.9% .187 3.815); --color-pink-900: oklch(40.8% .153 2.432); --color-pink-950: oklch(28.4% .109 3.907); --color-rose-50: oklch(96.9% .015 12.422); --color-rose-100: oklch(94.1% .03 12.58); --color-rose-200: oklch(89.2% .058 10.001); --color-rose-300: oklch(81% .117 11.638); --color-rose-400: oklch(71.2% .194 13.428); --color-rose-500: oklch(64.5% .246 16.439); --color-rose-600: oklch(58.6% .253 17.585); --color-rose-700: oklch(51.4% .222 16.935); --color-rose-800: oklch(45.5% .188 13.697); --color-rose-900: oklch(41% .159 10.272); --color-rose-950: oklch(27.1% .105 12.094); --color-slate-50: oklch(98.4% .003 247.858); --color-slate-100: oklch(96.8% .007 247.896); --color-slate-200: oklch(92.9% .013 255.508); --color-slate-300: oklch(86.9% .022 252.894); --color-slate-400: oklch(70.4% .04 256.788); --color-slate-500: oklch(55.4% .046 257.417); --color-slate-600: oklch(44.6% .043 257.281); --color-slate-700: oklch(37.2% .044 257.287); --color-slate-800: oklch(27.9% .041 260.031); --color-slate-900: oklch(20.8% .042 265.755); --color-slate-950: oklch(12.9% .042 264.695); --color-gray-50: oklch(98.5% .002 247.839); --color-gray-100: oklch(96.7% .003 264.542); --color-gray-200: oklch(92.8% .006 264.531); --color-gray-300: oklch(87.2% .01 258.338); --color-gray-400: oklch(70.7% .022 261.325); --color-gray-500: oklch(55.1% .027 264.364); --color-gray-600: oklch(44.6% .03 256.802); --color-gray-700: oklch(37.3% .034 259.733); --color-gray-800: oklch(27.8% .033 256.848); --color-gray-900: oklch(21% .034 264.665); --color-gray-950: oklch(13% .028 261.692); --color-zinc-50: oklch(98.5% 0 0); --color-zinc-100: oklch(96.7% .001 286.375); --color-zinc-200: oklch(92% .004 286.32); --color-zinc-300: oklch(87.1% .006 286.286); --color-zinc-400: oklch(70.5% .015 286.067); --color-zinc-500: oklch(55.2% .016 285.938); --color-zinc-600: oklch(44.2% .017 285.786); --color-zinc-700: oklch(37% .013 285.805); --color-zinc-800: oklch(27.4% .006 286.033); --color-zinc-900: oklch(21% .006 285.885); --color-zinc-950: oklch(14.1% .005 285.823); --color-neutral-50: oklch(98.5% 0 0); --color-neutral-100: oklch(97% 0 0); --color-neutral-200: oklch(92.2% 0 0); --color-neutral-300: oklch(87% 0 0); --color-neutral-400: oklch(70.8% 0 0); --color-neutral-500: oklch(55.6% 0 0); --color-neutral-600: oklch(43.9% 0 0); --color-neutral-700: oklch(37.1% 0 0); --color-neutral-800: oklch(26.9% 0 0); --color-neutral-900: oklch(20.5% 0 0); --color-neutral-950: oklch(14.5% 0 0); --color-stone-50: oklch(98.5% .001 106.423); --color-stone-100: oklch(97% .001 106.424); --color-stone-200: oklch(92.3% .003 48.717); --color-stone-300: oklch(86.9% .005 56.366); --color-stone-400: oklch(70.9% .01 56.259); --color-stone-500: oklch(55.3% .013 58.071); --color-stone-600: oklch(44.4% .011 73.639); --color-stone-700: oklch(37.4% .01 67.558); --color-stone-800: oklch(26.8% .007 34.298); --color-stone-900: oklch(21.6% .006 56.043); --color-stone-950: oklch(14.7% .004 49.25); --color-mauve-50: oklch(98.5% 0 0); --color-mauve-100: oklch(96% .003 325.6); --color-mauve-200: oklch(92.2% .005 325.62); --color-mauve-300: oklch(86.5% .012 325.68); --color-mauve-400: oklch(71.1% .019 323.02); --color-mauve-500: oklch(54.2% .034 322.5); --color-mauve-600: oklch(43.5% .029 321.78); --color-mauve-700: oklch(36.4% .029 323.89); --color-mauve-800: oklch(26.3% .024 320.12); --color-mauve-900: oklch(21.2% .019 322.12); --color-mauve-950: oklch(14.5% .008 326); --color-olive-50: oklch(98.8% .003 106.5); --color-olive-100: oklch(96.6% .005 106.5); --color-olive-200: oklch(93% .007 106.5); --color-olive-300: oklch(88% .011 106.6); --color-olive-400: oklch(73.7% .021 106.9); --color-olive-500: oklch(58% .031 107.3); --color-olive-600: oklch(46.6% .025 107.3); --color-olive-700: oklch(39.4% .023 107.4); --color-olive-800: oklch(28.6% .016 107.4); --color-olive-900: oklch(22.8% .013 107.4); --color-olive-950: oklch(15.3% .006 107.1); --color-mist-50: oklch(98.7% .002 197.1); --color-mist-100: oklch(96.3% .002 197.1); --color-mist-200: oklch(92.5% .005 214.3); --color-mist-300: oklch(87.2% .007 219.6); --color-mist-400: oklch(72.3% .014 214.4); --color-mist-500: oklch(56% .021 213.5); --color-mist-600: oklch(45% .017 213.2); --color-mist-700: oklch(37.8% .015 216); --color-mist-800: oklch(27.5% .011 216.9); --color-mist-900: oklch(21.8% .008 223.9); --color-mist-950: oklch(14.8% .004 228.8); --color-taupe-50: oklch(98.6% .002 67.8); --color-taupe-100: oklch(96% .002 17.2); --color-taupe-200: oklch(92.2% .005 34.3); --color-taupe-300: oklch(86.8% .007 39.5); --color-taupe-400: oklch(71.4% .014 41.2); --color-taupe-500: oklch(54.7% .021 43.1); --color-taupe-600: oklch(43.8% .017 39.3); --color-taupe-700: oklch(36.7% .016 35.7); --color-taupe-800: oklch(26.8% .011 36.5); --color-taupe-900: oklch(21.4% .009 43.1); --color-taupe-950: oklch(14.7% .004 49.3); --color-black: #000; --color-white: #fff; --spacing: .25rem; --breakpoint-sm: 40rem; --breakpoint-md: 48rem; --breakpoint-lg: 64rem; --breakpoint-xl: 80rem; --breakpoint-2xl: 96rem; --container-3xs: 16rem; --container-2xs: 18rem; --container-xs: 20rem; --container-sm: 24rem; --container-md: 28rem; --container-lg: 32rem; --container-xl: 36rem; --container-2xl: 42rem; --container-3xl: 48rem; --container-4xl: 56rem; --container-5xl: 64rem; --container-6xl: 72rem; --container-7xl: 80rem; --text-xs: .75rem; --text-xs--line-height: calc(1 / .75); --text-sm: .875rem; --text-sm--line-height: calc(1.25 / .875); --text-base: 1rem; --text-base--line-height: calc(1.5 / 1); --text-lg: 1.125rem; --text-lg--line-height: calc(1.75 / 1.125); --text-xl: 1.25rem; --text-xl--line-height: calc(1.75 / 1.25); --text-2xl: 1.5rem; --text-2xl--line-height: calc(2 / 1.5); --text-3xl: 1.875rem; --text-3xl--line-height: calc(2.25 / 1.875); --text-4xl: 2.25rem; --text-4xl--line-height: calc(2.5 / 2.25); --text-5xl: 3rem; --text-5xl--line-height: 1; --text-6xl: 3.75rem; --text-6xl--line-height: 1; --text-7xl: 4.5rem; --text-7xl--line-height: 1; --text-8xl: 6rem; --text-8xl--line-height: 1; --text-9xl: 8rem; --text-9xl--line-height: 1; --font-weight-thin: 100; --font-weight-extralight: 200; --font-weight-light: 300; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; --font-weight-extrabold: 800; --font-weight-black: 900; --tracking-tighter: -.05em; --tracking-tight: -.025em; --tracking-normal: 0em; --tracking-wide: .025em; --tracking-wider: .05em; --tracking-widest: .1em; --leading-tight: 1.25; --leading-snug: 1.375; --leading-normal: 1.5; --leading-relaxed: 1.625; --leading-loose: 2; --radius-xs: .125rem; --radius-sm: .25rem; --radius-md: .375rem; --radius-lg: .5rem; --radius-xl: .75rem; --radius-2xl: 1rem; --radius-3xl: 1.5rem; --radius-4xl: 2rem; --shadow-2xs: 0 1px #0000000d; --shadow-xs: 0 1px 2px 0 #0000000d; --shadow-sm: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; --shadow-md: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; --shadow-lg: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; --shadow-xl: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; --shadow-2xl: 0 25px 50px -12px #00000040; --inset-shadow-2xs: inset 0 1px #0000000d; --inset-shadow-xs: inset 0 1px 1px #0000000d; --inset-shadow-sm: inset 0 2px 4px #0000000d; --drop-shadow-xs: 0 1px 1px #0000000d; --drop-shadow-sm: 0 1px 2px #00000026; --drop-shadow-md: 0 3px 3px #0000001f; --drop-shadow-lg: 0 4px 4px #00000026; --drop-shadow-xl: 0 9px 7px #0000001a; --drop-shadow-2xl: 0 25px 25px #00000026; --text-shadow-2xs: 0px 1px 0px #00000026; --text-shadow-xs: 0px 1px 1px #0003; --text-shadow-sm: 0px 1px 0px #00000013, 0px 1px 1px #00000013, 0px 2px 2px #00000013; --text-shadow-md: 0px 1px 1px #0000001a, 0px 1px 2px #0000001a, 0px 2px 4px #0000001a; --text-shadow-lg: 0px 1px 2px #0000001a, 0px 3px 2px #0000001a, 0px 4px 8px #0000001a; --ease-in: cubic-bezier(.4, 0, 1, 1); --ease-out: cubic-bezier(0, 0, .2, 1); --ease-in-out: cubic-bezier(.4, 0, .2, 1); --animate-spin: spin 1s linear infinite; --animate-ping: ping 1s cubic-bezier(0, 0, .2, 1) infinite; --animate-pulse: pulse 2s cubic-bezier(.4, 0, .6, 1) infinite; --animate-bounce: bounce 1s infinite; @keyframes spin { to { transform: rotate(360deg); } } @keyframes ping { 75%, 100% { transform: scale(2); opacity: 0; } } @keyframes pulse { 50% { opacity: .5; } } @keyframes bounce { 0%, 100% { transform: translateY(-25%); animation-timing-function: cubic-bezier(.8, 0, 1, 1); } 50% { transform: none; animation-timing-function: cubic-bezier(0, 0, .2, 1); } } --blur-xs: 4px; --blur-sm: 8px; --blur-md: 12px; --blur-lg: 16px; --blur-xl: 24px; --blur-2xl: 40px; --blur-3xl: 64px; --perspective-dramatic: 100px; --perspective-near: 300px; --perspective-normal: 500px; --perspective-midrange: 800px; --perspective-distant: 1200px; --aspect-video: 16 / 9; --default-transition-duration: .15s; --default-transition-timing-function: cubic-bezier(.4, 0, .2, 1); --default-font-family: --theme(--font-sans, initial); --default-font-feature-settings: --theme(--font-sans--font-feature-settings, initial); --default-font-variation-settings: --theme(--font-sans--font-variation-settings, initial); --default-mono-font-family: --theme(--font-mono, initial); --default-mono-font-feature-settings: --theme(--font-mono--font-feature-settings, initial); --default-mono-font-variation-settings: --theme(--font-mono--font-variation-settings, initial);}@theme default inline reference{--blur: 8px; --shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; --shadow-inner: inset 0 2px 4px 0 #0000000d; --drop-shadow: 0 1px 2px #0000001a, 0 1px 1px #0000000f; --radius: .25rem; --max-width-prose: 65ch;}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:--theme(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:--theme(--default-font-feature-settings, normal);font-variation-settings:--theme(--default-font-variation-settings, normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:--theme(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:--theme(--default-mono-font-feature-settings, normal);font-variation-settings:--theme(--default-mono-font-variation-settings, normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{@tailwind utilities;}@apply flex w-full justify-center;@apply w-full min-h-screen h-screen;.page{grid-template:"header"4rem"main"1fr"footer"/100%;display:grid}@apply flex items-center gap-4 border-b bg-(--background) px-4 md:px-6;.header{grid-area:header}@apply inline-flex items-center gap-2;@apply h-6 w-6 shrink-0;@apply text-lg font-semibold text-(--foreground);@apply hidden md:flex flex-row items-center gap-5 lg:gap-6;@apply text-(--muted-foreground) transition-colors hover:text-(--foreground) px-0;@apply grid gap-6 text-lg font-medium p-4;@apply text-(--muted-foreground) hover:text-(--foreground) justify-start px-0 text-lg;@apply ml-auto flex items-center gap-2 lg:gap-4;@apply bg-(--background) p-4 py-2 md:p-8 md:py-4;.main{grid-area:main;min-height:0;overflow-y:auto}@apply bg-(--background) text-(--muted-foreground) px-4 py-2 md:px-8 md:py-4;.footer{grid-area:footer}.pihanga-paste-target{border:2px dashed #999}.pihanga-paste-target .paste-target-msg-title{font-size:1.2em}.pihanga-paste-target textarea:focus{outline:none}.pihanga-paste-target-focused{border-width:3px;border-color:#007bff}.pihanga-paste-target-focused .paste-target-focus-reminder{display:none}.pi-stepper{--pi-stepper-indicator-size-sm:1.5rem;--pi-stepper-indicator-size-md:2rem;--pi-stepper-indicator-size-lg:2.5rem;--pi-stepper-indicator-size:var(--pi-stepper-indicator-size-md);--pi-stepper-connector-thickness:2px;--pi-stepper-connector-min-height:1.5rem;--pi-stepper-label-max-width:6rem}.pi-stepper--sm{--pi-stepper-indicator-size:var(--pi-stepper-indicator-size-sm)}.pi-stepper--md{--pi-stepper-indicator-size:var(--pi-stepper-indicator-size-md)}.pi-stepper--lg{--pi-stepper-indicator-size:var(--pi-stepper-indicator-size-lg)}.pi-stepper__indicator{transition:background-color .2s,border-color .2s,color .2s,outline-color .2s}.pi-stepper__indicator--clickable{cursor:pointer}.pi-stepper__indicator--clickable:hover{opacity:.8}.pi-stepper__indicator--static{cursor:default}.pi-stepper__connector{transition:background-color .3s}.pi-stepper__connector--vertical{min-height:var(--pi-stepper-connector-min-height)}.pi-stepper__label-title{transition:color .2s}
2
+ /*$vite$:1*/
package/r/badge.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "badge",
4
+ "type": "registry:component",
5
+ "description": "Pihanga badge card component",
6
+ "dependencies": [
7
+ "@radix-ui/react-slot@^1.2.4",
8
+ "class-variance-authority@^0.7.1"
9
+ ],
10
+ "registryDependencies": [
11
+ "https://ivcap-works.github.io/pihanga-shadcn/r/pihanga-base.json",
12
+ "badge",
13
+ "https://ivcap-works.github.io/pihanga-shadcn/r/pihanga-lib-utils.json"
14
+ ],
15
+ "files": [
16
+ {
17
+ "path": "cards/badge/badge.component.tsx",
18
+ "content": "import * as React from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {Badge} from \"@/components/ui/badge\";\nimport {cn} from \"@/lib/utils\";\nimport type {BadgeCardProps} from \"./badge.types\";\n\n/**\n * `shad/badge` card component.\n *\n * Renders a shadcn `<Badge>` element with a `label` and an optional `variant`.\n * The variant vocabulary is intentionally identical to the `BadgeColumn.variants`\n * map used by the `shad/data-table` card, so both can be driven from the same\n * source-of-truth value:\n *\n * \"default\" | \"secondary\" | \"destructive\" | \"outline\"\n */\nexport const BadgeComponent = (\n props: PiCardProps<BadgeCardProps>,\n): React.ReactNode => {\n const {label, variant = \"secondary\", className, cardName} = props;\n\n return (\n <Badge\n variant={variant}\n className={cn(className)}\n data-pihanga={cardName}\n >\n {label}\n </Badge>\n );\n};\n",
19
+ "type": "registry:component",
20
+ "target": "src/cards/badge/badge.component.tsx"
21
+ },
22
+ {
23
+ "path": "cards/badge/badge.types.ts",
24
+ "content": "import {createCardDeclaration} from \"@pihanga2/core\";\n\nexport const BADGE_CARD = \"shad/badge\";\n\n/**\n * Badge visual style variants — mirrors the shadcn `Badge` `variant` prop and\n * the `variants` map used in the dataTable `BadgeColumn` type, so the same\n * string values work in both contexts.\n *\n * | Value | Appearance |\n * |-----------------|------------------------------------------|\n * | `\"default\"` | Primary colour, filled |\n * | `\"secondary\"` | Muted/secondary colour, filled (default) |\n * | `\"destructive\"` | Red / error colour, filled |\n * | `\"outline\"` | Transparent background, border only |\n */\nexport type BadgeVariant = \"default\" | \"secondary\" | \"destructive\" | \"outline\";\n\nexport type BadgeCardProps = {\n /** Text content rendered inside the badge */\n label: string;\n\n /**\n * Visual style variant. Matches the shadcn Badge variants and the\n * `BadgeColumn.variants` map in `dataTable.types.ts`.\n * @default \"secondary\"\n */\n variant?: BadgeVariant;\n\n /** Additional Tailwind classes applied to the `<Badge>` element */\n className?: string;\n};\n\n/**\n * Factory function for declaring a `shad/badge` card instance.\n *\n * ```ts\n * import {registerCard} from \"@pihanga2/core\";\n * import {ShadBadge} from \"@/cards/badge\";\n *\n * registerCard(\"myApp/status\", ShadBadge({label: \"Active\", variant: \"default\"}));\n * ```\n */\nexport const ShadBadge = createCardDeclaration<BadgeCardProps>(BADGE_CARD);\n",
25
+ "type": "registry:component",
26
+ "target": "src/cards/badge/badge.types.ts"
27
+ },
28
+ {
29
+ "path": "cards/badge/index.ts",
30
+ "content": "import {registerCardComponent} from \"@pihanga2/core\";\n\nimport {BadgeComponent} from \"./badge.component\";\nimport {BADGE_CARD} from \"./badge.types\";\n\nexport * from \"./badge.types\";\n\nregisterCardComponent({\n name: BADGE_CARD,\n component: BadgeComponent,\n});\n",
31
+ "type": "registry:component",
32
+ "target": "src/cards/badge/index.ts"
33
+ }
34
+ ]
35
+ }
package/r/box.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "box",
4
+ "type": "registry:component",
5
+ "description": "Pihanga box card component",
6
+ "dependencies": [
7
+ "@pihanga2/cards@^0.3.15"
8
+ ],
9
+ "registryDependencies": [
10
+ "https://ivcap-works.github.io/pihanga-shadcn/r/pihanga-base.json"
11
+ ],
12
+ "files": [
13
+ {
14
+ "path": "cards/box/box.component.tsx",
15
+ "content": "import * as React from \"react\";\n\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport type {BoxProps} from \"@pihanga2/cards\";\n\nexport const BoxComponent = (props: PiCardProps<BoxProps>): React.ReactNode => {\n const {content, className, style, cardName} = props;\n\n let sy: Record<string, string | number> = {};\n if (props.height) sy.height = `${props.height}px`;\n if (props.width) sy.height = `${props.width}px`;\n\n if (props.marginTop) sy[\"margin-top\"] = `${props.marginTop}px`;\n if (props.marginBottom) sy[\"margin-bottom\"] = `${props.marginBottom}px`;\n if (props.marginLeft) sy[\"margin-ledt\"] = `${props.marginLeft}px`;\n if (props.marginRight) sy[\"margin-right\"] = `${props.marginRight}px`;\n\n if (props.paddingTop) sy[\"padding-top\"] = `${props.paddingTop}px`;\n if (props.paddingBottom) sy[\"padding-bottom\"] = `${props.paddingBottom}px`;\n if (props.paddingLeft) sy[\"padding-ledt\"] = `${props.paddingLeft}px`;\n if (props.paddingRight) sy[\"padding-right\"] = `${props.paddingRight}px`;\n\n sy = {\n ...(style?.shad as Record<string, string | number> | undefined),\n };\n\n function renderContent() {\n if (!content) return null;\n return content.map((cn, i) => (\n <Card cardName={cn} parentCard={cardName} key={i} />\n ));\n }\n\n return (\n <div className={className} style={sy} data-pihanga={cardName}>\n {renderContent()}\n {props.children}\n </div>\n );\n};\n",
16
+ "type": "registry:component",
17
+ "target": "src/cards/box/box.component.tsx"
18
+ },
19
+ {
20
+ "path": "cards/box/index.ts",
21
+ "content": "import {createCardDeclaration, registerCardComponent} from \"@pihanga2/core\";\n\nimport {BoxComponent} from \"./box.component\";\nimport type {BoxProps} from \"@pihanga2/cards\";\n\nexport const BOX_CARD = \"shad/box\";\nexport const Box = createCardDeclaration<BoxProps>(BOX_CARD);\n\nregisterCardComponent({\n name: BOX_CARD,\n component: BoxComponent,\n});\n",
22
+ "type": "registry:component",
23
+ "target": "src/cards/box/index.ts"
24
+ }
25
+ ]
26
+ }
package/r/button.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "button",
4
+ "type": "registry:component",
5
+ "description": "Pihanga button card component",
6
+ "dependencies": [
7
+ "@radix-ui/react-tooltip@^1.2.8",
8
+ "class-variance-authority@^0.7.1",
9
+ "lucide-react@^0.513.0",
10
+ "radix-ui@^1.4.3"
11
+ ],
12
+ "registryDependencies": [
13
+ "https://ivcap-works.github.io/pihanga-shadcn/r/pihanga-base.json",
14
+ "https://ivcap-works.github.io/pihanga-shadcn/r/pihanga-ui-extras.json",
15
+ "tooltip",
16
+ "https://ivcap-works.github.io/pihanga-shadcn/r/pihanga-cards-icons.json",
17
+ "https://ivcap-works.github.io/pihanga-shadcn/r/dropDownMenu.json"
18
+ ],
19
+ "files": [
20
+ {
21
+ "path": "cards/button/button.component.tsx",
22
+ "content": "import React from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\n\nimport {Button, LinkButton} from \"@/components/ui/button\";\nimport {Tooltip, TooltipContent, TooltipTrigger} from \"@/components/ui/tooltip\";\nimport {getIcon} from \"@/cards/icons\";\nimport {useDropdownOpen} from \"@/cards/dropDownMenu/dropdown-context\";\n\nimport type {PiButtonEvents, PiButtonProps} from \"./button.types\";\n\nfunction resolveIconByName(name?: string): React.ReactNode {\n if (!name) return null;\n return getIcon(name);\n}\n\nexport const ButtonComponent = (\n props: PiCardProps<PiButtonProps, PiButtonEvents>,\n): React.ReactNode => {\n const {\n opts,\n ariaLabel,\n label,\n iconLabel,\n contentCard: content,\n href,\n target,\n tooltip,\n tooltipCard,\n tooltipMode,\n tooltipPlacement,\n className,\n id,\n onClicked,\n cardName,\n _cls,\n active,\n focused,\n disabled,\n loading,\n isPending,\n } = props;\n\n // Check if this button is inside an open dropdown menu\n const isInsideOpenDropdown = useDropdownOpen();\n\n const beforeIcon = resolveIconByName(opts?.beforeIcon);\n const afterIcon = resolveIconByName(opts?.afterIcon);\n\n // Determine base content: iconLabel takes precedence, then contentCard, then label\n const baseContent = iconLabel ? (\n resolveIconByName(iconLabel)\n ) : content ? (\n <Card cardName={content} parentCard={cardName} />\n ) : (\n label\n );\n\n // Render icons as children following shadcn/ui pattern\n const children = (\n <>\n {beforeIcon}\n {baseContent}\n {afterIcon}\n </>\n );\n\n const common = {\n active,\n focused,\n isMenu: opts?.isMenu,\n truncate: opts?.truncate,\n variant: opts?.variant,\n size: opts?.size,\n\n disabled,\n loading,\n isPending,\n loadingClassName: opts?.loadingClassName,\n\n className: `${_cls(\"root\")} ${className || \"\"}`.trim(),\n };\n\n const handleClick = () => {\n onClicked({id});\n };\n\n const renderButton = () => {\n if (href) {\n return (\n <LinkButton\n {...common}\n href={href}\n target={target}\n data-pihanga={cardName}\n label={ariaLabel ?? label}\n onClick={handleClick}\n >\n {children}\n </LinkButton>\n );\n }\n\n return (\n <Button\n {...common}\n data-pihanga={cardName}\n label={ariaLabel ?? label}\n onClick={handleClick}\n >\n {children}\n </Button>\n );\n };\n\n if (!tooltip && !tooltipCard) return renderButton();\n\n // Determine tooltip open state based on mode.\n // If the button is inside an open dropdown, force the tooltip closed\n // to avoid UI conflicts (dropdown menu should take precedence).\n const tooltipOpen = isInsideOpenDropdown\n ? false\n : tooltipMode === \"open\"\n ? true\n : tooltipMode === \"closed\"\n ? false\n : undefined; // 'auto' or undefined = uncontrolled\n\n // Render tooltip content: use tooltipCard if provided, otherwise use tooltip string\n const tooltipContent = tooltipCard ? (\n <Card cardName={tooltipCard} parentCard={cardName} />\n ) : (\n <p data-pihanga={`${cardName}-tooltip`}>{tooltip}</p>\n );\n\n return (\n <Tooltip open={tooltipOpen}>\n <TooltipTrigger asChild>{renderButton()}</TooltipTrigger>\n <TooltipContent side={tooltipPlacement}>{tooltipContent}</TooltipContent>\n </Tooltip>\n );\n};\n",
23
+ "type": "registry:component",
24
+ "target": "src/cards/button/button.component.tsx"
25
+ },
26
+ {
27
+ "path": "cards/button/button.types.ts",
28
+ "content": "import {\n createCardDeclaration,\n createOnAction,\n PiCardRef,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const PI_BUTTON_CARD = \"pi/button\";\n\nexport const Button = createCardDeclaration<PiButtonProps, PiButtonEvents>(\n PI_BUTTON_CARD,\n);\n\nexport const PI_BUTTON_ACTION = registerActions(PI_BUTTON_CARD, [\"clicked\"]);\n\nexport const onPiButtonClicked = createOnAction<PiButtonClickedEvent>(\n PI_BUTTON_ACTION.CLICKED,\n);\n\n/**\n * Declarative \"opts\" subset based on `src/registry/ui/button.tsx`.\n *\n * Notes:\n * - Any icon is referenced by name and resolved via `src/pihanga/icons.ts`.\n * - `children` are provided via `label` (simple) or `content` (card ref).\n */\nexport type PiButtonOpts = {\n /**\n * Visual style variant of the button.\n * Determines the button's appearance (colors, borders, etc.).\n */\n variant?:\n | \"default\"\n | \"destructive\"\n | \"outline\"\n | \"secondary\"\n | \"ghost\"\n | \"ghost2\"\n | \"ghost3\"\n | \"ghostActive\"\n | \"brand\"\n | \"nav\"\n | \"navAction\"\n | \"menuAction\"\n | \"blockAction\"\n | \"blockActionSecondary\"\n | \"primaryOutline\"\n | \"radio\"\n | \"none\";\n\n /**\n * Size of the button.\n * Controls padding, font size, and overall dimensions.\n */\n size?:\n | \"default\"\n | \"xs\"\n | \"md\"\n | \"lg\"\n | \"icon\"\n | \"iconSm\"\n | \"navAction\"\n | \"menuAction\"\n | \"blockAction\"\n | \"none\";\n\n /** Truncate button content with ellipsis if it overflows. */\n truncate?: boolean;\n\n /** If true, button is rendered as a menu trigger button. */\n isMenu?: boolean;\n\n /** Custom CSS class to apply to the loading spinner/indicator. */\n loadingClassName?: string;\n\n /** Icon to display before the button content. Set 'size' to 'icon' if ONLY show icon */\n beforeIcon?: string;\n\n /** Icon to display after the button content */\n afterIcon?: string;\n};\n\nexport type PiButtonProps = {\n id?: string; // optional 'id' to be added to events\n\n /**\n * Optional explicit aria-label.\n *\n * Useful for icon-only / letter-only buttons where the visible content\n * shouldn't be used as the accessible name.\n */\n ariaLabel?: string;\n\n /**\n * Declarative options; maps closely to `@/components/ui/button`.\n */\n opts?: PiButtonOpts;\n\n /** Simple label; used as children and aria-label fallback. */\n label?: string;\n\n /**\n * Icon name to use as the main button content (instead of text label).\n * Resolved via `src/pihanga/icons.ts`.\n * Takes precedence over `label` and `contentCard`.\n */\n iconLabel?: string;\n\n /**\n * If set, renders this card as the content instead of `label`.\n * (Useful for rich content.)\n */\n contentCard?: PiCardRef;\n\n /** When provided, button will render as an anchor. */\n href?: string;\n target?: string;\n\n tooltip?: string;\n\n /**\n * If set, renders this card as the tooltip content instead of `tooltip`.\n * (Useful for rich tooltip content.)\n */\n tooltipCard?: PiCardRef;\n\n /**\n * Controls tooltip visibility mode.\n * - 'auto' (default): Normal hover behavior\n * - 'open': Force tooltip to be visible\n * - 'closed': Force tooltip to be hidden\n */\n tooltipMode?: \"auto\" | \"open\" | \"closed\";\n\n /**\n * Controls tooltip placement/position.\n * - 'top': Tooltip appears above the button (default)\n * - 'right': Tooltip appears to the right of the button\n * - 'bottom': Tooltip appears below the button\n * - 'left': Tooltip appears to the left of the button\n */\n tooltipPlacement?: \"top\" | \"right\" | \"bottom\" | \"left\";\n\n /** Indicates whether the button is in an active/selected state. */\n active?: boolean;\n\n /** Indicates whether the button has focus state styling applied. */\n focused?: boolean;\n\n /** If true, disables the button and prevents interaction. */\n disabled?: boolean;\n\n /** If true, shows loading state and typically disables interaction. */\n loading?: boolean;\n\n /** If true, indicates an async operation is pending (similar to loading but distinct). */\n isPending?: boolean;\n\n className?: string;\n};\n\nexport type PiButtonClickedEvent = {\n id?: string;\n};\n\nexport type PiButtonEvents = {\n onClicked: PiButtonClickedEvent;\n};\n",
29
+ "type": "registry:component",
30
+ "target": "src/cards/button/button.types.ts"
31
+ },
32
+ {
33
+ "path": "cards/button/index.ts",
34
+ "content": "import {actionTypesToEvents, registerCardComponent} from \"@pihanga2/core\";\n\nimport {ButtonComponent} from \"./button.component\";\nimport {PI_BUTTON_ACTION, PI_BUTTON_CARD} from \"./button.types\";\n\nexport * from \"./button.types\";\n\n// Optional convenience alias (mirrors older pattern like SdDropDownMenu)\n// export const SdButton = createCardDeclaration<PiButtonProps, PiButtonEvents>(\n// PI_BUTTON_CARD,\n// );\n\nregisterCardComponent({\n name: PI_BUTTON_CARD,\n component: ButtonComponent,\n events: actionTypesToEvents(PI_BUTTON_ACTION),\n});\n",
35
+ "type": "registry:component",
36
+ "target": "src/cards/button/index.ts"
37
+ }
38
+ ]
39
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "checkbox",
4
+ "type": "registry:component",
5
+ "description": "Pihanga checkbox card component",
6
+ "dependencies": [],
7
+ "registryDependencies": [
8
+ "https://ivcap-works.github.io/pihanga-shadcn/r/pihanga-base.json",
9
+ "https://ivcap-works.github.io/pihanga-shadcn/r/form.json"
10
+ ],
11
+ "files": [
12
+ {
13
+ "path": "cards/checkbox/checkbox.component.tsx",
14
+ "content": "import React from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {useFormContext} from \"@/cards/form/form.context\";\nimport type {PiCheckboxEvents, PiCheckboxProps} from \"./checkbox.types\";\n\nexport const CheckboxComponent = (\n props: PiCardProps<PiCheckboxProps, PiCheckboxEvents>,\n): React.ReactNode => {\n const {\n name,\n checked: propChecked = false,\n disabled,\n label,\n cardName,\n onChanged,\n } = props;\n\n // `id` and `invalid` may be injected by a parent pi/field card via\n // Pihanga's extra-prop forwarding. They are not in the official type so\n // we read them through an escape hatch.\n const injectedId = (props as {id?: string}).id;\n const invalid = Boolean((props as {invalid?: boolean}).invalid);\n\n // Detect if we are inside a pi/form card via React context.\n const form = useFormContext();\n const useFormData = form.isInForm && Boolean(name);\n\n const checked = useFormData\n ? Boolean(form.formData[name!] ?? false)\n : propChecked;\n\n function handleChange(e: React.ChangeEvent<HTMLInputElement>) {\n const newChecked = e.target.checked;\n if (useFormData) {\n form.handleChange(name!, newChecked);\n } else {\n onChanged({name, checked: newChecked});\n }\n }\n\n // Use the id injected by pi/field; fall back to a local id when standalone.\n const selfId = `${cardName}-${name ?? \"checkbox\"}`;\n const fieldId = injectedId ?? selfId;\n\n return (\n <div data-pihanga={cardName} className=\"flex items-center gap-2\">\n <input\n id={fieldId}\n type=\"checkbox\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n aria-invalid={invalid || undefined}\n className=\"h-4 w-4 rounded border-input accent-primary disabled:cursor-not-allowed disabled:opacity-50\"\n />\n {label && (\n <label\n htmlFor={fieldId}\n className=\"text-sm leading-none cursor-pointer select-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n >\n {label}\n </label>\n )}\n </div>\n );\n};\n",
15
+ "type": "registry:component",
16
+ "target": "src/cards/checkbox/checkbox.component.tsx"
17
+ },
18
+ {
19
+ "path": "cards/checkbox/checkbox.types.ts",
20
+ "content": "import {\n createCardDeclaration,\n createOnAction,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const PI_CHECKBOX_CARD = \"pi/checkbox\";\n\nexport const Checkbox = createCardDeclaration<\n PiCheckboxProps,\n PiCheckboxEvents\n>(PI_CHECKBOX_CARD);\n\nexport const PI_CHECKBOX_ACTION = registerActions(PI_CHECKBOX_CARD, [\n \"changed\",\n]);\n\nexport const onPiCheckboxChanged = createOnAction<PiCheckboxChangedEvent>(\n PI_CHECKBOX_ACTION.CHANGED,\n);\n\nexport type PiCheckboxProps = {\n /**\n * Field name used to bind to FormContext when inside a pi/form card.\n * When provided the component reads its checked state from form data and\n * writes back via form.handleChange.\n */\n name?: string;\n\n /**\n * Controlled checked state used in standalone mode (outside a Form).\n * Ignored when `name` is set and the component is inside a pi/form.\n */\n checked?: boolean;\n\n /** When true, the checkbox is disabled and non-interactive. */\n disabled?: boolean;\n\n /**\n * Optional label text rendered next to the checkbox.\n * The label is automatically associated with the input via `htmlFor`.\n */\n label?: string;\n};\n\nexport type PiCheckboxChangedEvent = {\n /** Field name, mirrors the `name` prop if provided. */\n name?: string;\n /** New checked state after the change. */\n checked: boolean;\n};\n\nexport type PiCheckboxEvents = {\n onChanged: PiCheckboxChangedEvent;\n};\n",
21
+ "type": "registry:component",
22
+ "target": "src/cards/checkbox/checkbox.types.ts"
23
+ },
24
+ {
25
+ "path": "cards/checkbox/index.ts",
26
+ "content": "import {actionTypesToEvents, registerCardComponent} from \"@pihanga2/core\";\n\nimport {CheckboxComponent} from \"./checkbox.component\";\nimport {PI_CHECKBOX_ACTION, PI_CHECKBOX_CARD} from \"./checkbox.types\";\n\nexport * from \"./checkbox.types\";\n\nregisterCardComponent({\n name: PI_CHECKBOX_CARD,\n component: CheckboxComponent,\n events: actionTypesToEvents(PI_CHECKBOX_ACTION),\n});\n",
27
+ "type": "registry:component",
28
+ "target": "src/cards/checkbox/index.ts"
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "conditional",
4
+ "type": "registry:component",
5
+ "description": "Pihanga conditional card component",
6
+ "dependencies": [],
7
+ "registryDependencies": [
8
+ "https://ivcap-works.github.io/pihanga-shadcn/r/pihanga-base.json"
9
+ ],
10
+ "files": [
11
+ {
12
+ "path": "cards/conditional/conditional.component.tsx",
13
+ "content": "import * as React from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport type {ConditionalProps} from \"./conditional.types\";\n\n/**\n * ConditionalComponent\n *\n * Transparent pass-through: renders the `content` card when `show` is `true`,\n * returns `null` otherwise. No extra DOM wrapper is added — the mounted\n * card's own root element is the only node in the tree.\n */\nexport const ConditionalComponent = (\n props: PiCardProps<ConditionalProps>,\n): React.ReactNode => {\n const {cardName, show, content} = props;\n if (!show) return null;\n return <Card cardName={content} parentCard={cardName} />;\n};\n",
14
+ "type": "registry:component",
15
+ "target": "src/cards/conditional/conditional.component.tsx"
16
+ },
17
+ {
18
+ "path": "cards/conditional/conditional.types.ts",
19
+ "content": "import {createCardDeclaration} from \"@pihanga2/core\";\nimport type {PiCardRef} from \"@pihanga2/core\";\n\n// ── Card id ───────────────────────────────────────────────────────────────────\n\nexport const CONDITIONAL_CARD = \"shad/conditional\";\n\n// ── Card declaration factory ──────────────────────────────────────────────────\n\nexport const Conditional =\n createCardDeclaration<ConditionalProps>(CONDITIONAL_CARD);\n\n// ── Props ─────────────────────────────────────────────────────────────────────\n\n/**\n * Props for the `shad/conditional` card.\n *\n * Renders `content` only when `show` is `true`; renders nothing otherwise.\n * This is a transparent pass-through — no extra DOM wrapper is added.\n *\n * In a real app, drive `show` from a `memo()` selector so the card\n * reactively mounts/unmounts as state changes:\n *\n * ```ts\n * import {memo, registerCard} from \"@pihanga2/core\";\n * import {Conditional} from \"@/cards/conditional\";\n *\n * registerCard(\"myApp/hint\", Conditional({\n * show: memo((s: AppState) => s.items.length === 0 && !s.isLoading),\n * content: \"myApp/emptyStateHint\",\n * }));\n * ```\n */\nexport type ConditionalProps = {\n /** Render `content` only when this is `true`. Drive with `memo()` for\n * reactive mount/unmount behaviour. */\n show: boolean;\n\n /** The card to render when `show` is `true`. */\n content: PiCardRef;\n};\n",
20
+ "type": "registry:component",
21
+ "target": "src/cards/conditional/conditional.types.ts"
22
+ },
23
+ {
24
+ "path": "cards/conditional/index.ts",
25
+ "content": "import {registerCardComponent} from \"@pihanga2/core\";\nimport {ConditionalComponent} from \"./conditional.component\";\nimport {CONDITIONAL_CARD} from \"./conditional.types\";\n\nexport * from \"./conditional.types\";\n\n// No events — this card is purely structural.\nregisterCardComponent({\n name: CONDITIONAL_CARD,\n component: ConditionalComponent,\n});\n",
26
+ "type": "registry:component",
27
+ "target": "src/cards/conditional/index.ts"
28
+ }
29
+ ]
30
+ }
@@ -0,0 +1,43 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
3
+ "name": "dataTable",
4
+ "type": "registry:component",
5
+ "description": "Pihanga dataTable card component",
6
+ "dependencies": [
7
+ "@radix-ui/react-slot@^1.2.4",
8
+ "class-variance-authority@^0.7.1",
9
+ "lucide-react@^0.513.0"
10
+ ],
11
+ "registryDependencies": [
12
+ "https://ivcap-works.github.io/pihanga-shadcn/r/pihanga-base.json",
13
+ "https://ivcap-works.github.io/pihanga-shadcn/r/pihanga-lib-utils.json",
14
+ "badge",
15
+ "table"
16
+ ],
17
+ "files": [
18
+ {
19
+ "path": "cards/dataTable/dataTable.component.tsx",
20
+ "content": "import React, {useMemo, useState} from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport {\n Check,\n ChevronDown,\n ChevronRight,\n ChevronUp,\n ChevronsUpDown,\n X,\n} from \"lucide-react\";\nimport {cn} from \"@/lib/utils\";\nimport {Badge} from \"@/components/ui/badge\";\nimport {\n Table,\n TableBody,\n TableCaption,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/components/ui/table\";\nimport type {\n DataTableColumn,\n DataTableEvents,\n DataTableProps,\n DataTableRow as DataTableRowType,\n} from \"./dataTable.types\";\n\n// ---------------------------------------------------------------------------\n// Cell renderer\n// ---------------------------------------------------------------------------\n\nfunction renderCell(\n column: DataTableColumn,\n value: unknown,\n parentCard: string,\n): React.ReactNode {\n if (value == null) return null;\n\n switch (column.type) {\n case \"number\": {\n const num = typeof value === \"number\" ? value : Number(value);\n return isNaN(num)\n ? String(value)\n : column.format\n ? column.format(num)\n : String(num);\n }\n\n case \"date\": {\n if (column.format) {\n return column.format(value as Date | string);\n }\n const d = value instanceof Date ? value : new Date(String(value));\n return isNaN(d.getTime()) ? String(value) : d.toLocaleDateString();\n }\n\n case \"badge\": {\n const strVal = String(value);\n const variant = column.variants?.[strVal] ?? \"secondary\";\n return <Badge variant={variant}>{strVal}</Badge>;\n }\n\n case \"boolean\": {\n return value ? (\n <Check className=\"size-4 text-green-600\" aria-label=\"true\" />\n ) : (\n <X className=\"size-4 text-muted-foreground\" aria-label=\"false\" />\n );\n }\n\n case \"card\": {\n // Cell value is expected to be a PiCardRef (string)\n return <Card cardName={String(value)} parentCard={parentCard} />;\n }\n\n default:\n // \"text\" or omitted type\n return String(value);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Sort icon\n// ---------------------------------------------------------------------------\n\nfunction SortIcon({\n columnKey,\n activeKey,\n ascending,\n}: {\n columnKey: string;\n activeKey: string | undefined;\n ascending: boolean;\n}): React.ReactNode {\n if (columnKey !== activeKey) {\n return <ChevronsUpDown className=\"ml-1 inline size-3.5 opacity-40\" />;\n }\n return ascending ? (\n <ChevronUp className=\"ml-1 inline size-3.5\" />\n ) : (\n <ChevronDown className=\"ml-1 inline size-3.5\" />\n );\n}\n\n// ---------------------------------------------------------------------------\n// Pagination controls\n// ---------------------------------------------------------------------------\n\nfunction PaginationBar({\n page,\n totalPages,\n onPrev,\n onNext,\n}: {\n page: number;\n totalPages: number;\n onPrev: () => void;\n onNext: () => void;\n}): React.ReactNode {\n return (\n <div className=\"flex items-center justify-end gap-2 mt-2 px-2\">\n <span className=\"text-sm text-muted-foreground\">\n Page {page + 1} of {totalPages}\n </span>\n <button\n type=\"button\"\n className={cn(\n \"rounded border px-2 py-1 text-sm transition-colors\",\n \"hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40\",\n )}\n disabled={page === 0}\n onClick={onPrev}\n >\n Previous\n </button>\n <button\n type=\"button\"\n className={cn(\n \"rounded border px-2 py-1 text-sm transition-colors\",\n \"hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40\",\n )}\n disabled={page >= totalPages - 1}\n onClick={onNext}\n >\n Next\n </button>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Helper: derive a human-readable title from a camelCase key\n// ---------------------------------------------------------------------------\n\nfunction keyToTitle(key: string): string {\n return key\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (s) => s.toUpperCase())\n .trim();\n}\n\n// ---------------------------------------------------------------------------\n// Main data-table component\n// ---------------------------------------------------------------------------\n\nexport const DataTableComponent = (\n props: PiCardProps<DataTableProps, DataTableEvents>,\n): React.ReactNode => {\n const {\n columns,\n rows,\n caption,\n sortKey: sortKeyProp,\n sortAscending: sortAscendingProp,\n pageSize,\n currentPage: currentPageProp,\n stickyHeader = false,\n striped = false,\n hoverable = true,\n compact = false,\n emptyCard,\n emptyText = \"No data\",\n className,\n cardName,\n onRowClicked,\n onSortChanged,\n onShowDetail,\n onHideDetail,\n onPageChanged,\n } = props;\n\n // ── Expanded-rows state ──────────────────────────────────────────────────\n const [expandedRows, setExpandedRows] = useState<Set<string | number>>(\n new Set(),\n );\n\n // ── Sort state (uncontrolled; props override when present) ───────────────\n const [localSortKey, setLocalSortKey] = useState<string | undefined>(\n sortKeyProp,\n );\n const [localSortAsc, setLocalSortAsc] = useState<boolean>(\n sortAscendingProp ?? true,\n );\n const activeSortKey = sortKeyProp !== undefined ? sortKeyProp : localSortKey;\n const activeSortAsc =\n sortAscendingProp !== undefined ? sortAscendingProp : localSortAsc;\n\n // ── Pagination state (uncontrolled; props override when present) ─────────\n const [localPage, setLocalPage] = useState<number>(currentPageProp ?? 0);\n const activePage =\n currentPageProp !== undefined ? currentPageProp : localPage;\n\n // ── Derived flags ────────────────────────────────────────────────────────\n const hasDetailRows = rows.some((row) => row.detailCard != null);\n // Total column count used for detail-row colSpan\n const colCount = columns.length + (hasDetailRows ? 1 : 0);\n\n // ── Sorted rows ──────────────────────────────────────────────────────────\n const sortedRows = useMemo(() => {\n if (!activeSortKey) return rows;\n return [...rows].sort((a, b) => {\n const av = (a.data as Record<string, unknown>)[activeSortKey];\n const bv = (b.data as Record<string, unknown>)[activeSortKey];\n if (av == null && bv == null) return 0;\n if (av == null) return 1;\n if (bv == null) return -1;\n const cmp = av < bv ? -1 : av > bv ? 1 : 0;\n return activeSortAsc ? cmp : -cmp;\n });\n }, [rows, activeSortKey, activeSortAsc]);\n\n // ── Paginated slice ──────────────────────────────────────────────────────\n const paginatedRows = useMemo(() => {\n if (!pageSize) return sortedRows;\n const start = activePage * pageSize;\n return sortedRows.slice(start, start + pageSize);\n }, [sortedRows, pageSize, activePage]);\n\n const totalPages = pageSize ? Math.ceil(sortedRows.length / pageSize) : 1;\n\n // ── Handlers ─────────────────────────────────────────────────────────────\n const handleSortClick = (key: string) => {\n const newAsc = activeSortKey === key ? !activeSortAsc : true;\n setLocalSortKey(key);\n setLocalSortAsc(newAsc);\n onSortChanged({key, ascending: newAsc});\n };\n\n const handleToggleDetail = (row: DataTableRowType, e: React.MouseEvent) => {\n e.stopPropagation();\n setExpandedRows((prev) => {\n const next = new Set(prev);\n if (next.has(row.id)) {\n next.delete(row.id);\n onHideDetail({rowId: row.id, row});\n } else {\n next.add(row.id);\n onShowDetail({rowId: row.id, row});\n }\n return next;\n });\n };\n\n const handleRowClick = (row: DataTableRowType) => {\n onRowClicked({rowId: row.id, row});\n };\n\n const handlePageChange = (page: number) => {\n setLocalPage(page);\n if (pageSize) {\n onPageChanged({page, pageSize});\n }\n };\n\n // ── Cell padding ─────────────────────────────────────────────────────────\n const cellPad = compact ? \"py-1 px-2\" : \"py-2 px-3\";\n\n // ── Render ────────────────────────────────────────────────────────────────\n return (\n <div className={cn(\"w-full\", className)} data-pihanga={cardName}>\n <Table>\n {caption && <TableCaption>{caption}</TableCaption>}\n\n {/* ── Header ─────────────────────────────────────────────────────── */}\n <TableHeader\n className={\n stickyHeader ? \"sticky top-0 z-10 bg-background\" : undefined\n }\n >\n <TableRow>\n {/* Expand-toggle placeholder header cell */}\n {hasDetailRows && (\n <TableHead className=\"w-10 px-2\" aria-label=\"Row details\" />\n )}\n\n {columns.map((col) => (\n <TableHead\n key={col.key}\n style={col.width ? {width: col.width} : undefined}\n className={cn(\n cellPad,\n col.align === \"center\" && \"text-center\",\n col.align === \"right\" && \"text-right\",\n col.sortable && \"cursor-pointer select-none\",\n col.headerClassName,\n )}\n onClick={\n col.sortable ? () => handleSortClick(col.key) : undefined\n }\n >\n <span className=\"inline-flex items-center\">\n {col.title ?? keyToTitle(col.key)}\n {col.sortable && (\n <SortIcon\n columnKey={col.key}\n activeKey={activeSortKey}\n ascending={activeSortAsc}\n />\n )}\n </span>\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n\n {/* ── Body ───────────────────────────────────────────────────────── */}\n <TableBody>\n {paginatedRows.length === 0 ? (\n /* Empty state */\n <TableRow>\n <TableCell\n colSpan={colCount}\n className=\"py-8 text-center text-muted-foreground\"\n >\n {emptyCard ? (\n <Card cardName={emptyCard} parentCard={cardName} />\n ) : (\n emptyText\n )}\n </TableCell>\n </TableRow>\n ) : (\n paginatedRows.map((row, rowIdx) => {\n const isExpanded = expandedRows.has(row.id);\n const isStriped = striped && rowIdx % 2 === 1;\n\n return (\n <React.Fragment key={row.id}>\n {/* ── Data row ─────────────────────────────────────────── */}\n <TableRow\n className={cn(\n isStriped && \"bg-muted/30\",\n hoverable && \"cursor-pointer\",\n )}\n data-expanded={isExpanded || undefined}\n onClick={() => handleRowClick(row)}\n >\n {/* Expand / collapse toggle */}\n {hasDetailRows && (\n <TableCell className=\"w-10 px-2\">\n {row.detailCard && (\n <button\n type=\"button\"\n aria-label={\n isExpanded ? \"Collapse detail\" : \"Expand detail\"\n }\n aria-expanded={isExpanded}\n className={cn(\n \"flex items-center justify-center rounded p-0.5 transition-colors\",\n \"hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n )}\n onClick={(e) => handleToggleDetail(row, e)}\n >\n {isExpanded ? (\n <ChevronDown className=\"size-4\" />\n ) : (\n <ChevronRight className=\"size-4\" />\n )}\n </button>\n )}\n </TableCell>\n )}\n\n {/* Data cells */}\n {columns.map((col) => {\n const value = (row.data as Record<string, unknown>)[\n col.key\n ];\n return (\n <TableCell\n key={col.key}\n className={cn(\n cellPad,\n col.align === \"center\" && \"text-center\",\n col.align === \"right\" && \"text-right\",\n col.cellClassName,\n )}\n >\n {renderCell(col, value, cardName)}\n </TableCell>\n );\n })}\n </TableRow>\n\n {/* ── Detail row (full-width, shown when expanded) ──────── */}\n {isExpanded && row.detailCard && (\n <TableRow\n // Suppress the default hover/click styles on the detail row\n className=\"hover:bg-transparent\"\n onClick={(e) => e.stopPropagation()}\n >\n <TableCell colSpan={colCount} className=\"border-b p-0\">\n <div className=\"bg-muted/20 px-4 py-3\">\n {/*\n * cardKey creates a unique virtual card instance per row\n * (e.g. \"myDetailTemplate@detail-42\").\n * The `row` prop is forwarded as ctxtProps so the detail\n * card's state-mapper functions can access it via\n * `ctx.ctxtProps.row` — no need to pre-register one card\n * per row.\n */}\n <Card\n cardName={row.detailCard}\n cardKey={`detail-${row.id}`}\n row={row}\n parentCard={cardName}\n key={`${cardName}-${row.id}-detail`}\n />\n </div>\n </TableCell>\n </TableRow>\n )}\n </React.Fragment>\n );\n })\n )}\n </TableBody>\n </Table>\n\n {/* ── Pagination controls ──────────────────────────────────────────── */}\n {pageSize && totalPages > 1 && (\n <PaginationBar\n page={activePage}\n totalPages={totalPages}\n onPrev={() => handlePageChange(activePage - 1)}\n onNext={() => handlePageChange(activePage + 1)}\n />\n )}\n </div>\n );\n};\n",
21
+ "type": "registry:component",
22
+ "target": "src/cards/dataTable/dataTable.component.tsx"
23
+ },
24
+ {
25
+ "path": "cards/dataTable/dataTable.types.ts",
26
+ "content": "import {\n PiCardRef,\n createCardDeclaration,\n createOnAction,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const DATA_TABLE_CARD = \"shad/data-table\";\n\nexport const DataTable = createCardDeclaration<DataTableProps, DataTableEvents>(\n DATA_TABLE_CARD,\n);\n\nexport const DATA_TABLE_ACTION = registerActions(DATA_TABLE_CARD, [\n \"row_clicked\",\n \"sort_changed\",\n \"show_detail\",\n \"hide_detail\",\n \"page_changed\",\n]);\n\nexport const onDataTableRowClicked = createOnAction<DataTableRowClickedEvent>(\n DATA_TABLE_ACTION.ROW_CLICKED,\n);\nexport const onDataTableSortChanged = createOnAction<DataTableSortChangedEvent>(\n DATA_TABLE_ACTION.SORT_CHANGED,\n);\nexport const onDataTableShowDetail = createOnAction<DataTableDetailEvent>(\n DATA_TABLE_ACTION.SHOW_DETAIL,\n);\nexport const onDataTableHideDetail = createOnAction<DataTableDetailEvent>(\n DATA_TABLE_ACTION.HIDE_DETAIL,\n);\nexport const onDataTablePageChanged = createOnAction<DataTablePageChangedEvent>(\n DATA_TABLE_ACTION.PAGE_CHANGED,\n);\n\n// ---------------------------------------------------------------------------\n// Column type definitions\n// ---------------------------------------------------------------------------\n\n/** Shared base for all column definitions */\nexport type DataTableColumnBase = {\n /** Key into the row's `data` object used to retrieve the cell value */\n key: string;\n /**\n * Column header label.\n * Defaults to the `key` with camelCase expanded to \"Title Case\".\n */\n title?: string;\n /** Column width as a CSS value (e.g. \"120px\", \"10%\", \"1fr\") */\n width?: string | number;\n /** Horizontal alignment of cell content. Defaults to \"left\". */\n align?: \"left\" | \"center\" | \"right\";\n /** Whether the column header is clickable for sorting */\n sortable?: boolean;\n /** Extra CSS class applied to the `<th>` header cell */\n headerClassName?: string;\n /** Extra CSS class applied to every `<td>` data cell in this column */\n cellClassName?: string;\n};\n\n/** Plain text column — cell value rendered as a string */\nexport type TextColumn = DataTableColumnBase & {\n type?: \"text\";\n};\n\n/** Numeric column with optional custom formatter */\nexport type NumberColumn = DataTableColumnBase & {\n type: \"number\";\n /** Custom number formatter; defaults to `String(value)` */\n format?: (n: number) => string;\n};\n\n/** Badge/chip column — cell value is rendered inside a `<Badge>` */\nexport type BadgeColumn = DataTableColumnBase & {\n type: \"badge\";\n /**\n * Map from cell value (as a string) to a shadcn Badge variant.\n * Falls back to \"secondary\" for unrecognised values.\n */\n variants?: Record<\n string,\n \"default\" | \"secondary\" | \"destructive\" | \"outline\"\n >;\n};\n\n/** Date column with optional custom formatter */\nexport type DateColumn = DataTableColumnBase & {\n type: \"date\";\n /** Custom date formatter; defaults to `toLocaleDateString()` */\n format?: (d: Date | string) => string;\n};\n\n/** Boolean column — renders a check-mark or cross icon */\nexport type BooleanColumn = DataTableColumnBase & {\n type: \"boolean\";\n};\n\n/**\n * Card column — cell value must be a `PiCardRef` (string).\n * The referenced card is rendered inline via Pihanga's `<Card />`.\n * This enables full reuse of any registered Pihanga card as cell content.\n */\nexport type CardColumn = DataTableColumnBase & {\n type: \"card\";\n};\n\nexport type DataTableColumn =\n | TextColumn\n | NumberColumn\n | BadgeColumn\n | DateColumn\n | BooleanColumn\n | CardColumn;\n\n// ---------------------------------------------------------------------------\n// Row\n// ---------------------------------------------------------------------------\n\nexport type DataTableRow<T = Record<string, unknown>> = {\n /** Unique row identifier used as the React key and in events */\n id: string | number;\n /**\n * Row payload — values are keyed by the column's `key` field.\n * For \"card\" columns the value should be a `PiCardRef` string.\n */\n data: T;\n /**\n * When set, the row shows an expand/collapse toggle button.\n * The referenced card is rendered full-width below the row on expand.\n * Use `onShowDetail` / `onHideDetail` events to track expanded state in\n * your redux store and update `detailCard` per row as needed.\n */\n detailCard?: PiCardRef;\n};\n\n// ---------------------------------------------------------------------------\n// Props\n// ---------------------------------------------------------------------------\n\nexport type DataTableProps<T = Record<string, unknown>> = {\n /** Column definitions — order determines display order */\n columns: DataTableColumn[];\n /** Row data */\n rows: DataTableRow<T>[];\n /** Optional visible `<caption>` rendered below the table */\n caption?: string;\n\n // --- Sorting ---\n /**\n * Key of the currently sorted column.\n * When provided the sort state is controlled; otherwise managed internally.\n */\n sortKey?: string;\n /**\n * Sort direction.\n * When provided together with `sortKey` the sort state is controlled.\n */\n sortAscending?: boolean;\n\n // --- Pagination ---\n /** Maximum number of rows per page. Omit to disable pagination. */\n pageSize?: number;\n /** Current page index (0-based). Treated as controlled when provided. */\n currentPage?: number;\n /**\n * Total row count, used for server-side pagination display.\n * Leave unset for client-side pagination derived from `rows.length`.\n */\n totalRows?: number;\n\n // --- Display ---\n /** Keep the header visible while the body scrolls */\n stickyHeader?: boolean;\n /** Alternate row background colour (zebra striping) */\n striped?: boolean;\n /** Highlight rows on hover (default: true) */\n hoverable?: boolean;\n /** Use compact row padding */\n compact?: boolean;\n\n // --- Empty state ---\n /** Card rendered when `rows` is empty */\n emptyCard?: PiCardRef;\n /** Fallback text when `rows` is empty and `emptyCard` is not set */\n emptyText?: string;\n\n className?: string;\n};\n\n// ---------------------------------------------------------------------------\n// Events\n// ---------------------------------------------------------------------------\n\nexport type DataTableRowClickedEvent = {\n rowId: string | number;\n row: DataTableRow;\n};\n\nexport type DataTableSortChangedEvent = {\n /** The column key that was clicked */\n key: string;\n /** `true` = ascending, `false` = descending */\n ascending: boolean;\n};\n\nexport type DataTableDetailEvent = {\n rowId: string | number;\n row: DataTableRow;\n};\n\nexport type DataTablePageChangedEvent = {\n /** New page index (0-based) */\n page: number;\n pageSize: number;\n};\n\nexport type DataTableEvents = {\n onRowClicked: DataTableRowClickedEvent;\n onSortChanged: DataTableSortChangedEvent;\n onShowDetail: DataTableDetailEvent;\n onHideDetail: DataTableDetailEvent;\n onPageChanged: DataTablePageChangedEvent;\n};\n\n// ---------------------------------------------------------------------------\n// DataTableRowDetail — generic single-template detail panel\n// ---------------------------------------------------------------------------\n\n/** Configuration for a single field shown in the detail panel. */\nexport type DataTableRowDetailField = {\n /** Key to look up in `row.data` */\n key: string;\n /** Optional human-readable label prefix (e.g. \"Director\") */\n label?: string;\n /** Render style: \"title\" → h4 bold, \"muted\" → muted foreground, \"text\" (default) → plain */\n type?: \"title\" | \"text\" | \"muted\";\n /** Additional Tailwind class names forwarded to the element */\n className?: string;\n};\n\nexport type DataTableRowDetailProps = {\n /**\n * The row to display. Set this via a state mapper so a single template\n * card works for all rows:\n * ```ts\n * DataTableRowDetail({\n * row: (_, ctx) => ctx.ctxtProps?.row,\n * fields: [{ key: \"title\", type: \"title\" }, ...],\n * })\n * ```\n */\n row?: DataTableRow<Record<string, unknown>>;\n /**\n * Fields to render in order.\n * When omitted, every key in `row.data` is rendered as a plain key:value pair.\n */\n fields?: DataTableRowDetailField[];\n};\n\nexport const DATA_TABLE_ROW_DETAIL_CARD = \"shad/data-table-row-detail\";\nexport const DataTableRowDetail =\n createCardDeclaration<DataTableRowDetailProps>(DATA_TABLE_ROW_DETAIL_CARD);\n",
27
+ "type": "registry:component",
28
+ "target": "src/cards/dataTable/dataTable.types.ts"
29
+ },
30
+ {
31
+ "path": "cards/dataTable/dataTableRowDetail.component.tsx",
32
+ "content": "import React from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {cn} from \"@/lib/utils\";\nimport type {\n DataTableRowDetailField,\n DataTableRowDetailProps,\n} from \"./dataTable.types\";\n\n/**\n * DataTableRowDetail — generic detail-panel card for use with DataTable.\n *\n * Register it ONCE as a template, then reference it in every row via\n * `detailCard`. The DataTable passes the row via `cardKey` + `row` context\n * props so a state mapper on the `row` field delivers the correct data:\n *\n * ```ts\n * registerCard(\n * \"app/myTable/rowDetail\",\n * DataTableRowDetail({\n * // State mapper — ctx.ctxtProps.row is injected by the DataTable\n * row: (_, ctx) => ctx.ctxtProps?.row,\n * fields: [\n * { key: \"title\", type: \"title\" },\n * { key: \"director\", label: \"Director\" },\n * { key: \"plot\", type: \"muted\" },\n * ],\n * }),\n * );\n * ```\n */\nexport const DataTableRowDetailComponent = (\n props: PiCardProps<DataTableRowDetailProps>,\n): React.ReactNode => {\n const {row, fields, cardName} = props;\n\n if (!row?.data) {\n return null;\n }\n\n const data = row.data as Record<string, unknown>;\n\n /** If no `fields` config, auto-render all keys as plain text */\n if (!fields || fields.length === 0) {\n return (\n <div className=\"flex flex-col gap-1 text-sm\" data-pihanga={cardName}>\n {Object.entries(data).map(([key, value]) => (\n <div key={key}>\n <span className=\"font-medium text-muted-foreground\">{key}: </span>\n <span>{String(value ?? \"\")}</span>\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col gap-1\" data-pihanga={cardName}>\n {fields.map((field: DataTableRowDetailField) => {\n const value = data[field.key];\n const display = value == null ? \"\" : String(value);\n\n switch (field.type) {\n case \"title\":\n return (\n <h4 key={field.key} className=\"text-base font-semibold\">\n {display}\n </h4>\n );\n\n case \"muted\":\n return (\n <p key={field.key} className=\"text-sm text-muted-foreground\">\n {field.label ? (\n <>\n <span className=\"font-medium\">{field.label}: </span>\n {display}\n </>\n ) : (\n display\n )}\n </p>\n );\n\n default:\n // \"text\" or any unknown type\n return (\n <p key={field.key} className={cn(\"text-sm\", field.className)}>\n {field.label ? (\n <>\n <span className=\"font-medium\">{field.label}: </span>\n {display}\n </>\n ) : (\n display\n )}\n </p>\n );\n }\n })}\n </div>\n );\n};\n",
33
+ "type": "registry:component",
34
+ "target": "src/cards/dataTable/dataTableRowDetail.component.tsx"
35
+ },
36
+ {
37
+ "path": "cards/dataTable/index.ts",
38
+ "content": "import {actionTypesToEvents, registerCardComponent} from \"@pihanga2/core\";\n\nimport {DataTableComponent} from \"./dataTable.component\";\nimport {DataTableRowDetailComponent} from \"./dataTableRowDetail.component\";\nimport {\n DATA_TABLE_ACTION,\n DATA_TABLE_CARD,\n DATA_TABLE_ROW_DETAIL_CARD,\n} from \"./dataTable.types\";\n\nexport * from \"./dataTable.types\";\n\nregisterCardComponent({\n name: DATA_TABLE_CARD,\n component: DataTableComponent,\n events: actionTypesToEvents(DATA_TABLE_ACTION),\n});\n\nregisterCardComponent({\n name: DATA_TABLE_ROW_DETAIL_CARD,\n component: DataTableRowDetailComponent,\n});\n",
39
+ "type": "registry:component",
40
+ "target": "src/cards/dataTable/index.ts"
41
+ }
42
+ ]
43
+ }