@k3-universe/react-kit 0.0.1 → 0.0.3

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 (222) hide show
  1. package/.storybook/preview.ts +1 -1
  2. package/dist/index.d.ts +63 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +91 -0
  5. package/dist/kit/builder/data-table/components/DataTable.d.ts +4 -1
  6. package/dist/kit/builder/data-table/components/DataTable.d.ts.map +1 -1
  7. package/dist/kit/builder/data-table/index.d.ts +6 -5
  8. package/dist/kit/builder/data-table/index.d.ts.map +1 -1
  9. package/dist/kit/builder/form/components/FormBuilder.d.ts +5 -2
  10. package/dist/kit/builder/form/components/FormBuilder.d.ts.map +1 -1
  11. package/dist/kit/builder/form/components/{FormActions.d.ts → FormBuilderActions.d.ts} +3 -3
  12. package/dist/kit/builder/form/components/FormBuilderActions.d.ts.map +1 -0
  13. package/{storybook-static/kit/builder/form/components/FormField.d.ts → dist/kit/builder/form/components/FormBuilderField.d.ts} +4 -4
  14. package/dist/kit/builder/form/components/FormBuilderField.d.ts.map +1 -0
  15. package/dist/kit/builder/form/components/index.d.ts +2 -3
  16. package/dist/kit/builder/form/components/index.d.ts.map +1 -1
  17. package/dist/kit/builder/form/utils/field-factories.d.ts +1 -0
  18. package/dist/kit/builder/form/utils/field-factories.d.ts.map +1 -1
  19. package/dist/kit/builder/section/SectionBuilder.d.ts.map +1 -1
  20. package/dist/kit/components/autocomplete/types.d.ts +1 -1
  21. package/dist/kit/components/autocomplete/types.d.ts.map +1 -1
  22. package/dist/kit/layouts/admin/components/AdminLayout.d.ts.map +1 -1
  23. package/dist/kit/layouts/admin/hooks/menu.d.ts +1 -0
  24. package/dist/kit/layouts/admin/hooks/menu.d.ts.map +1 -1
  25. package/dist/kit/providers/ThemeProvider.d.ts.map +1 -1
  26. package/dist/kit/themes/base.css +1 -0
  27. package/dist/kit/themes/clean-slate.css +1 -0
  28. package/dist/kit/themes/default.css +1 -0
  29. package/dist/kit/themes/minimal-modern.css +1 -0
  30. package/dist/kit/themes/spotify.css +1 -0
  31. package/package.json +11 -10
  32. package/src/index.ts +88 -0
  33. package/src/kit/builder/data-table/components/DataTable.tsx +63 -23
  34. package/src/kit/builder/data-table/index.ts +6 -5
  35. package/src/kit/builder/form/components/FormBuilder.tsx +37 -10
  36. package/src/kit/builder/form/components/{FormActions.tsx → FormBuilderActions.tsx} +3 -3
  37. package/src/kit/builder/form/components/{FormField.tsx → FormBuilderField.tsx} +131 -9
  38. package/src/kit/builder/form/components/index.ts +2 -3
  39. package/src/kit/builder/form/utils/field-factories.ts +13 -0
  40. package/src/kit/builder/section/SectionBuilder.tsx +67 -10
  41. package/src/kit/components/autocomplete/types.ts +1 -1
  42. package/src/kit/layouts/admin/components/AdminLayout.tsx +1 -2
  43. package/src/kit/layouts/admin/hooks/menu.ts +2 -2
  44. package/src/kit/providers/ThemeProvider.tsx +38 -38
  45. package/src/stories/kit/builder/Form.Basic.stories.tsx +2 -0
  46. package/src/stories/kit/builder/Form.Simple.stories.tsx +4 -0
  47. package/src/stories/kit/layouts/admin/AdminLayout.Basic.stories.tsx +2 -0
  48. package/src/stories/kit/layouts/admin/AdminLayout.Collapsible.stories.tsx +2 -0
  49. package/src/stories/kit/layouts/admin/AdminLayout.Complex.stories.tsx +2 -0
  50. package/src/stories/kit/layouts/admin/AdminLayout.CustomSidebarHeaderComponent.stories.tsx +2 -0
  51. package/src/stories/kit/layouts/admin/AdminLayout.CustomSidebarTitleAndIcon.stories.tsx +2 -0
  52. package/src/stories/kit/layouts/admin/AdminLayout.HeaderSlots.stories.tsx +2 -0
  53. package/storybook-static/assets/{Accordion.stories-N1auke5L.js → Accordion.stories-q6yg6wg1.js} +1 -1
  54. package/storybook-static/assets/{AdminLayout-Cxd0-A_L.js → AdminLayout-B9bV4J_6.js} +1 -1
  55. package/storybook-static/assets/{AdminLayout.Basic.stories-C_I6rWuq.js → AdminLayout.Basic.stories-C-ZxuH-O.js} +1 -1
  56. package/storybook-static/assets/AdminLayout.Collapsible.stories-xcQzkxio.js +4 -0
  57. package/storybook-static/assets/{AdminLayout.Complex.stories-BbY1Ue6d.js → AdminLayout.Complex.stories-DyjkVpvE.js} +1 -1
  58. package/storybook-static/assets/{AdminLayout.CustomSidebarHeaderComponent.stories-LFVi-aIv.js → AdminLayout.CustomSidebarHeaderComponent.stories-BqhzWCIA.js} +1 -1
  59. package/storybook-static/assets/AdminLayout.CustomSidebarTitleAndIcon.stories-aWxyR67T.js +4 -0
  60. package/storybook-static/assets/{AdminLayout.HeaderSlots.stories-BactzgkF.js → AdminLayout.HeaderSlots.stories-dNzhUdDt.js} +1 -1
  61. package/storybook-static/assets/{Alert.stories-_FtuixdR.js → Alert.stories-DXwNfJ3w.js} +1 -1
  62. package/storybook-static/assets/{AlertDialog.stories-6NY3BjwR.js → AlertDialog.stories-I324NsnP.js} +1 -1
  63. package/storybook-static/assets/{AspectRatio.stories-DAT11y02.js → AspectRatio.stories-CghHiX3Z.js} +1 -1
  64. package/storybook-static/assets/{Autocomplete-DngjqsCM.js → Autocomplete-B4gV705L.js} +1 -1
  65. package/storybook-static/assets/{Autocomplete.stories-BCaOrgTR.js → Autocomplete.stories-CyOvjTGN.js} +1 -1
  66. package/storybook-static/assets/{Avatar.stories-DlzxSLJ-.js → Avatar.stories-CEF5FVSR.js} +1 -1
  67. package/storybook-static/assets/{Badge.stories-DKHXsoV5.js → Badge.stories-_-G3GriP.js} +1 -1
  68. package/storybook-static/assets/{Breadcrumb.stories-D8eUHpf7.js → Breadcrumb.stories-DORe9T4b.js} +1 -1
  69. package/storybook-static/assets/{Button.stories-kvPdKxdw.js → Button.stories-3nQ6wsBX.js} +1 -1
  70. package/storybook-static/assets/{Calendar.stories-D-hUtQQI.js → Calendar.stories-Dn__djE1.js} +1 -1
  71. package/storybook-static/assets/{Card.stories-y8Z7NgrQ.js → Card.stories-BJcbdwCI.js} +1 -1
  72. package/storybook-static/assets/{Carousel.stories-CFcHYKgp.js → Carousel.stories-CfqbE7Va.js} +1 -1
  73. package/storybook-static/assets/{Chart.stories-BJwLNKfE.js → Chart.stories-cGgef3tv.js} +1 -1
  74. package/storybook-static/assets/{Checkbox.stories-B22Fbwx1.js → Checkbox.stories-BcaxWzCS.js} +1 -1
  75. package/storybook-static/assets/{Collapsible.stories-BgcRp8Rk.js → Collapsible.stories-CQ95s7Cs.js} +1 -1
  76. package/storybook-static/assets/{Combination-BT_gXe1L.js → Combination-CeVus13L.js} +1 -1
  77. package/storybook-static/assets/{Command.stories-Dp4CtSQR.js → Command.stories-DYflJh8u.js} +1 -1
  78. package/storybook-static/assets/{ContextMenu.stories-DnVnIi-T.js → ContextMenu.stories-CU7ehYrE.js} +1 -1
  79. package/storybook-static/assets/DataTable.Basic.stories-BQNWUKiw.js +6 -0
  80. package/storybook-static/assets/{DataTable.Filters.stories-CO0ipuGm.js → DataTable.Filters.stories-DPCoeYhK.js} +1 -1
  81. package/storybook-static/assets/{DataTable.Pagination.stories-DNwCw64e.js → DataTable.Pagination.stories-8UNqTNgw.js} +1 -1
  82. package/storybook-static/assets/{DataTable.SelectionAndActions.stories-DGgdEbsf.js → DataTable.SelectionAndActions.stories-CDEjgQ6T.js} +1 -1
  83. package/storybook-static/assets/DataTable.Sorting.stories-qG7-X_6r.js +6 -0
  84. package/storybook-static/assets/{Dialog.stories-DQkYN8ht.js → Dialog.stories-Bu6ZJXNH.js} +1 -1
  85. package/storybook-static/assets/{Dialog.stories-DXZINEgo.js → Dialog.stories-DobNZ0Hp.js} +1 -1
  86. package/storybook-static/assets/{Drawer.stories-DMH_vZgi.js → Drawer.stories-BN0idp4u.js} +1 -1
  87. package/storybook-static/assets/{DropdownMenu.stories-Dl8y-N7T.js → DropdownMenu.stories-sfsVDTvm.js} +1 -1
  88. package/storybook-static/assets/{Form.Basic.stories-CJugIYsx.js → Form.Basic.stories-dE4nbgpr.js} +1 -1
  89. package/storybook-static/assets/{Form.Complex.stories-BPogRp6F.js → Form.Complex.stories-BEZufnjb.js} +1 -1
  90. package/storybook-static/assets/{Form.Dynamic.stories-Boway5AK.js → Form.Dynamic.stories-cJTbd6cV.js} +1 -1
  91. package/storybook-static/assets/{Form.Simple.stories-_OXGXXpE.js → Form.Simple.stories-DOPzZKhh.js} +1 -1
  92. package/storybook-static/assets/{Form.stories-BoHyR8ho.js → Form.stories-27doU7JS.js} +1 -1
  93. package/storybook-static/assets/{FormBuilder-BGgeY8ik.js → FormBuilder-C0S7C69Q.js} +1 -1
  94. package/storybook-static/assets/{HoverCard.stories-1HM92M79.js → HoverCard.stories-0lted9Zx.js} +1 -1
  95. package/storybook-static/assets/{Input.stories-sQ4EUlWt.js → Input.stories-CwsIObFs.js} +1 -1
  96. package/storybook-static/assets/{InputOtp.stories-Cpk_EmLx.js → InputOtp.stories-DVc086h4.js} +1 -1
  97. package/storybook-static/assets/{Label.stories-MjABHKSw.js → Label.stories-bJa0rk1A.js} +1 -1
  98. package/storybook-static/assets/{Login.stories-BY4OYGk3.js → Login.stories-C6X6Kj5B.js} +1 -1
  99. package/storybook-static/assets/{Menubar.stories-B_60TWNE.js → Menubar.stories-CuediVp7.js} +1 -1
  100. package/storybook-static/assets/{NavigationMenu.stories-DyuaBvvq.js → NavigationMenu.stories-CKGZYhKk.js} +1 -1
  101. package/storybook-static/assets/{Page.stories-DQKMxrPZ.js → Page.stories-Cf76wtRx.js} +1 -1
  102. package/storybook-static/assets/{Pagination.stories-CBo7UrNd.js → Pagination.stories-D7IdL1_4.js} +1 -1
  103. package/storybook-static/assets/{Popover.stories-D98_JrxN.js → Popover.stories-1VP_zNY8.js} +1 -1
  104. package/storybook-static/assets/{Progress.stories-Dejt5v3z.js → Progress.stories-C35R5YvA.js} +1 -1
  105. package/storybook-static/assets/{RadioGroup.stories-Tz2LW6O6.js → RadioGroup.stories-CjuD3CwD.js} +1 -1
  106. package/storybook-static/assets/{Resizable.stories-DhP2GKN7.js → Resizable.stories-Cs8dvdc5.js} +1 -1
  107. package/storybook-static/assets/{ScrollArea.stories-CF7-8wbM.js → ScrollArea.stories-D6_z-5jm.js} +1 -1
  108. package/storybook-static/assets/{Section.stories-BpurjHIQ.js → Section.stories-Ce5qYITI.js} +1 -1
  109. package/storybook-static/assets/SectionBuilder-Df_lRZkj.js +1 -0
  110. package/storybook-static/assets/{Select.stories-DJrU-mi0.js → Select.stories-w_kbza5k.js} +1 -1
  111. package/storybook-static/assets/{Separator.stories-BYH_o8QM.js → Separator.stories-B5QnaJXb.js} +1 -1
  112. package/storybook-static/assets/{Sheet.stories-BNJ7BIb-.js → Sheet.stories-CORnEGvV.js} +1 -1
  113. package/storybook-static/assets/{Sidebar.stories-BbjcJuOg.js → Sidebar.stories-DVuWTi4j.js} +1 -1
  114. package/storybook-static/assets/{Slider.stories-CWOjKHKD.js → Slider.stories-YoS2vvT2.js} +1 -1
  115. package/storybook-static/assets/{Sonner.stories-CXSZs5yN.js → Sonner.stories-CXW5e_Qg.js} +1 -1
  116. package/storybook-static/assets/{Switch.stories-BUQjobWe.js → Switch.stories-zr6i-aNi.js} +1 -1
  117. package/storybook-static/assets/{Table.stories-DJcV7M9R.js → Table.stories-BuGU4MUM.js} +1 -1
  118. package/storybook-static/assets/{Tabs.stories-ByeVrP18.js → Tabs.stories-jxkJ-AUI.js} +1 -1
  119. package/storybook-static/assets/{Textarea.stories-CKsDPHYc.js → Textarea.stories-CHXVobz6.js} +1 -1
  120. package/storybook-static/assets/{Toggle.stories-DutEzZ8k.js → Toggle.stories-C4uB4Hkq.js} +1 -1
  121. package/storybook-static/assets/{ToggleGroup.stories-C9fzJTh-.js → ToggleGroup.stories-Cr229wf_.js} +1 -1
  122. package/storybook-static/assets/{Tooltip.stories-CngnJbP7.js → Tooltip.stories-DmMYGR3T.js} +1 -1
  123. package/storybook-static/assets/{accordion-bQe9Rep4.js → accordion-BCfsz_gl.js} +1 -1
  124. package/storybook-static/assets/{alert-dialog-CypF_yaW.js → alert-dialog-BYt6Z7Kt.js} +1 -1
  125. package/storybook-static/assets/{avatar-CukM9hXu.js → avatar-CRn1qQsC.js} +1 -1
  126. package/storybook-static/assets/{axe-W8QMjM0E.js → axe-JCJl60WC.js} +1 -1
  127. package/storybook-static/assets/{button-BTWmFXop.js → button-BObfgcV1.js} +1 -1
  128. package/storybook-static/assets/{chart-column-Bzh5arua.js → chart-column-CplFCmg8.js} +1 -1
  129. package/storybook-static/assets/{check-BgWXKGqi.js → check-DyecuwP4.js} +1 -1
  130. package/storybook-static/assets/{checkbox-QlugAqJY.js → checkbox-D5BmNJeL.js} +1 -1
  131. package/storybook-static/assets/{chevron-down-BqLjUn1_.js → chevron-down-Bp7zbUB0.js} +1 -1
  132. package/storybook-static/assets/{chevron-left-BR_0lKnE.js → chevron-left-D1L4J3UW.js} +1 -1
  133. package/storybook-static/assets/{chevron-right-DpCIoMaJ.js → chevron-right-oMYqDJ_f.js} +1 -1
  134. package/storybook-static/assets/{circle-DVJTkDI7.js → circle-CyarsADt.js} +1 -1
  135. package/storybook-static/assets/clean-slate-V4nUw2Bm.css +1 -0
  136. package/storybook-static/assets/{command-BERL33lL.js → command-DCnXmNmT.js} +1 -1
  137. package/storybook-static/assets/{createLucideIcon-1ZwIAs_l.js → createLucideIcon-CLBo0iA0.js} +1 -1
  138. package/storybook-static/assets/default-CuTBjDca.css +1 -0
  139. package/storybook-static/assets/{dialog-DM9YJ1JD.js → dialog-DL0QBIbC.js} +1 -1
  140. package/storybook-static/assets/{dropdown-menu-TfFll7G9.js → dropdown-menu-BwL9gQwG.js} +1 -1
  141. package/storybook-static/assets/{ellipsis-BSY8VuLI.js → ellipsis-DPg968Rc.js} +1 -1
  142. package/storybook-static/assets/{grip-vertical-Buja1rv9.js → grip-vertical-CM0GDwvq.js} +1 -1
  143. package/storybook-static/assets/{iframe-G-6sM9Mt.js → iframe-BWjPIle6.js} +4 -4
  144. package/storybook-static/assets/{index-DqWzLCH-.js → index-04C4iZwC.js} +1 -1
  145. package/storybook-static/assets/{index-B-fXBfyD.js → index-3zykFCgl.js} +1 -1
  146. package/storybook-static/assets/{index-CAwQR9Pv.js → index-7XoYQV2z.js} +1 -1
  147. package/storybook-static/assets/{index-DySHPxMy.js → index-A7UzX-Xw.js} +1 -1
  148. package/storybook-static/assets/index-BN5_W3Yi.js +1 -0
  149. package/storybook-static/assets/{index-1v1lhNFD.js → index-BcAKBHrX.js} +1 -1
  150. package/storybook-static/assets/{index-7yNAGow7.js → index-BfKpUbCE.js} +1 -1
  151. package/storybook-static/assets/index-C5eJ31Z3.js +1 -0
  152. package/storybook-static/assets/{index-CayhpKmv.js → index-C6O7WofA.js} +1 -1
  153. package/storybook-static/assets/{index-BDwnENHR.js → index-C9xvlw_B.js} +1 -1
  154. package/storybook-static/assets/{index-Bq6UNRVc.js → index-CKwUGXmt.js} +1 -1
  155. package/storybook-static/assets/{index-d_S6mtzU.js → index-Cce91yJQ.js} +1 -1
  156. package/storybook-static/assets/{index-CMmbDm5O.js → index-Cw7p-pms.js} +1 -1
  157. package/storybook-static/assets/{index-CLmN5G1a.js → index-DE2OlfDP.js} +1 -1
  158. package/storybook-static/assets/{index-ev1RjzGv.js → index-DMk2qc2_.js} +1 -1
  159. package/storybook-static/assets/index-DWC9SV-P.js +1 -0
  160. package/storybook-static/assets/{index-HghBIZeg.js → index-Dqw7miiX.js} +1 -1
  161. package/storybook-static/assets/{index-ClNNG_ys.js → index-Dr2xmx-F.js} +1 -1
  162. package/storybook-static/assets/{index-lH-AZpAn.js → index-DschQYGl.js} +1 -1
  163. package/storybook-static/assets/{index-SxI7_jxe.js → index-Dsg7S8zu.js} +1 -1
  164. package/storybook-static/assets/{index-DvM9azdj.js → index-Pk2lGsul.js} +1 -1
  165. package/storybook-static/assets/{index-DNAxNqEO.js → index-URSssr5a.js} +1 -1
  166. package/storybook-static/assets/{index-CZaD3imo.js → index-npvyVsxD.js} +1 -1
  167. package/storybook-static/assets/{index-CzJf-yyP.js → index-u70nzfOV.js} +1 -1
  168. package/storybook-static/assets/{label-C5vJTTwH.js → label-CwntpYJ0.js} +1 -1
  169. package/storybook-static/assets/{lodash-Q9aGJGMb.js → lodash-BkmSIg_J.js} +1 -1
  170. package/storybook-static/assets/minimal-modern-d2yFlFJM.css +1 -0
  171. package/storybook-static/assets/{popover-DW1K4QCO.js → popover-ClqrrvjL.js} +1 -1
  172. package/storybook-static/assets/{radio-group-iPL-8jvw.js → radio-group-CvN0LQZp.js} +1 -1
  173. package/storybook-static/assets/{react-18-CK1-M7n3.js → react-18-Bj31y5Nr.js} +1 -1
  174. package/storybook-static/assets/{react-icons.esm-n2MUhK0n.js → react-icons.esm-DNr9VcvP.js} +1 -1
  175. package/storybook-static/assets/{refresh-cw-FYEbhX1i.js → refresh-cw-OZakDsFY.js} +1 -1
  176. package/storybook-static/assets/{schemas-S_Tg7JYp.js → schemas-CaLvKjsI.js} +1 -1
  177. package/storybook-static/assets/{section-factories-CC6eFfbk.js → section-factories-DKfKL-5s.js} +1 -1
  178. package/storybook-static/assets/{select-DbLzULCJ.js → select-gtXRB92c.js} +1 -1
  179. package/storybook-static/assets/{separator-DoUX1TNx.js → separator-CxCWfpZX.js} +1 -1
  180. package/storybook-static/assets/{settings-2-CpOcGlDm.js → settings-2-DSSkfF6W.js} +1 -1
  181. package/storybook-static/assets/{sheet-n5VQ25jh.js → sheet-r0VNiBiN.js} +1 -1
  182. package/storybook-static/assets/{shopping-cart-9kOJ1UDd.js → shopping-cart-CJBClF2m.js} +1 -1
  183. package/storybook-static/assets/{sidebar-CvUiZOJe.js → sidebar-BsMnOE7Y.js} +1 -1
  184. package/storybook-static/assets/spotify-BuPUgQEa.css +1 -0
  185. package/storybook-static/assets/{toggle-B-YKWMF8.js → toggle-D08-8sQA.js} +1 -1
  186. package/storybook-static/assets/{tooltip-CNONbPiI.js → tooltip-CZ1UAE_e.js} +1 -1
  187. package/storybook-static/assets/{trash-2-Bt5LMclM.js → trash-2-D55eseMQ.js} +1 -1
  188. package/storybook-static/assets/{x-DG9mLFAg.js → x-n8sFtlI2.js} +1 -1
  189. package/storybook-static/iframe.html +1 -1
  190. package/storybook-static/index.d.ts +63 -0
  191. package/storybook-static/index.d.ts.map +1 -1
  192. package/storybook-static/kit/builder/form/components/{FormActions.d.ts → FormBuilderActions.d.ts} +3 -3
  193. package/storybook-static/kit/builder/form/components/FormBuilderActions.d.ts.map +1 -0
  194. package/{dist/kit/builder/form/components/FormField.d.ts → storybook-static/kit/builder/form/components/FormBuilderField.d.ts} +4 -4
  195. package/storybook-static/kit/builder/form/components/FormBuilderField.d.ts.map +1 -0
  196. package/storybook-static/kit/builder/form/components/index.d.ts +2 -3
  197. package/storybook-static/kit/builder/form/components/index.d.ts.map +1 -1
  198. package/storybook-static/kit/builder/section/SectionBuilder.d.ts.map +1 -1
  199. package/storybook-static/project.json +1 -1
  200. package/vite.config.ts +76 -52
  201. package/dist/kit/builder/form/components/FormActions.d.ts.map +0 -1
  202. package/dist/kit/builder/form/components/FormField.d.ts.map +0 -1
  203. package/dist/kit/builder/form/components/FormSection.d.ts +0 -15
  204. package/dist/kit/builder/form/components/FormSection.d.ts.map +0 -1
  205. package/src/kit/builder/form/components/FormSection.tsx +0 -88
  206. package/storybook-static/assets/AdminLayout.Collapsible.stories-CsU3DwTo.js +0 -4
  207. package/storybook-static/assets/AdminLayout.CustomSidebarTitleAndIcon.stories-BqP6UVc7.js +0 -4
  208. package/storybook-static/assets/DataTable.Basic.stories-DBF5VYq9.js +0 -6
  209. package/storybook-static/assets/DataTable.Sorting.stories-CWpqloAB.js +0 -6
  210. package/storybook-static/assets/SectionBuilder-Bav4WrnT.js +0 -1
  211. package/storybook-static/assets/clean-slate-BR-XvZPt.css +0 -1
  212. package/storybook-static/assets/default-M24vcGB8.css +0 -1
  213. package/storybook-static/assets/index-DhoByIgc.js +0 -1
  214. package/storybook-static/assets/index-I343IfOC.js +0 -1
  215. package/storybook-static/assets/index-_crRFOM5.js +0 -1
  216. package/storybook-static/assets/minimal-modern-BmvR5wyr.css +0 -1
  217. package/storybook-static/assets/spotify-DpbeJq1r.css +0 -1
  218. package/storybook-static/kit/builder/form/components/FormActions.d.ts.map +0 -1
  219. package/storybook-static/kit/builder/form/components/FormField.d.ts.map +0 -1
  220. package/storybook-static/kit/builder/form/components/FormSection.d.ts +0 -15
  221. package/storybook-static/kit/builder/form/components/FormSection.d.ts.map +0 -1
  222. /package/src/{index.css → kit/themes/base.css} +0 -0
@@ -4,7 +4,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
4
4
  import { z } from 'zod';
5
5
  import { cn } from '../../../../shadcn/lib/utils';
6
6
  import { Button } from '../../../../shadcn/ui/button';
7
- import { FormField } from './FormField';
7
+ import { FormBuilderField } from './FormBuilderField';
8
8
  import SectionBuilder from '../../section/SectionBuilder';
9
9
  import type { SectionLayout, SectionGridOptions, SectionFlexOptions, SectionNode } from '../../section/types';
10
10
  import { AutocompleteFetcher, AutocompleteOption } from '../../../components/autocomplete/types';
@@ -22,6 +22,7 @@ export interface FormBuilderFieldConfig {
22
22
  | 'select'
23
23
  | 'autocomplete'
24
24
  | 'checkbox'
25
+ | 'switch'
25
26
  | 'radio'
26
27
  | 'date'
27
28
  | 'file'
@@ -70,6 +71,10 @@ export interface FormBuilderFieldConfig {
70
71
  value: any;
71
72
  }; // For conditional field visibility
72
73
  hidden?: boolean; // Declarative hide
74
+ // Label placement control across inputs
75
+ labelPlacement?: 'stacked' | 'inline' | 'hidden';
76
+ // Wrapper container className (applies to the field wrapper, not the input)
77
+ wrapperClassName?: string;
73
78
  }
74
79
 
75
80
  export interface FormBuilderSectionConfig {
@@ -108,6 +113,8 @@ export interface FormBuilderProps {
108
113
  actionsClassName?: string;
109
114
  showActions?: boolean;
110
115
  customActions?: React.ReactNode;
116
+ // UI: show a separator line above action buttons
117
+ showActionsSeparator?: boolean;
111
118
  }
112
119
 
113
120
  export function FormBuilder({
@@ -127,6 +134,7 @@ export function FormBuilder({
127
134
  actionsClassName,
128
135
  showActions = true,
129
136
  customActions,
137
+ showActionsSeparator = true,
130
138
  }: FormBuilderProps) {
131
139
  // Generate schema from field configs if not provided
132
140
  const generatedSchema = useMemo(() => {
@@ -154,6 +162,7 @@ export function FormBuilder({
154
162
  baseSchema = z.union([z.string(), z.number()]).nullable();
155
163
  break;
156
164
  case 'checkbox':
165
+ case 'switch':
157
166
  baseSchema = z.boolean();
158
167
  break;
159
168
  case 'date':
@@ -196,6 +205,7 @@ export function FormBuilder({
196
205
  fieldSchema = z.union([z.string(), z.number(), z.object()]).nullable();
197
206
  break;
198
207
  case 'checkbox':
208
+ case 'switch':
199
209
  fieldSchema = z.boolean();
200
210
  break;
201
211
  case 'date':
@@ -309,18 +319,27 @@ export function FormBuilder({
309
319
 
310
320
  const { control, handleSubmit, reset, setValue, getValues, watch } = form;
311
321
 
312
- // Watch all form values for dependencies
313
- const watchedValues = watch();
322
+ // Determine if any field dependencies are declared
323
+ const hasDependencies = useMemo(() => {
324
+ return sections.some((section) =>
325
+ section.fields?.some((f) => Array.isArray(f.dependencies) && f.dependencies.length > 0),
326
+ );
327
+ }, [sections]);
328
+
329
+ // Only watch values when there are dependencies to respond to
330
+ // This prevents unnecessary re-renders that can cause focus loss
331
+ const emptyWatchedValues = useMemo(() => ({} as Record<string, any>), []);
332
+ const watchedValues = hasDependencies ? watch() : emptyWatchedValues;
314
333
 
315
334
  // Handle field dependencies
316
335
  const handleFieldDependencies = useCallback(
317
336
  (field: FormBuilderFieldConfig) => {
318
- if (!field.dependencies) return {};
337
+ if (!hasDependencies || !field.dependencies) return {};
319
338
 
320
339
  const result: { disabled?: boolean; hidden?: boolean } = {};
321
340
 
322
341
  field.dependencies.forEach((dep) => {
323
- const dependentValue = watchedValues[dep.field];
342
+ const dependentValue = (watchedValues as Record<string, any>)[dep.field];
324
343
  const conditionMet = dep.condition(dependentValue);
325
344
 
326
345
  switch (dep.action) {
@@ -350,7 +369,7 @@ export function FormBuilder({
350
369
 
351
370
  return result;
352
371
  },
353
- [watchedValues, setValue, getValues],
372
+ [hasDependencies, watchedValues, setValue, getValues],
354
373
  );
355
374
 
356
375
  // Handle field change with custom onChange
@@ -387,7 +406,7 @@ export function FormBuilder({
387
406
  id: section.id ?? `section-${sectionIndex}`,
388
407
  title: section.title,
389
408
  subtitle: section.description,
390
- variant: section.variant ?? 'card',
409
+ variant: section.variant ?? 'plain',
391
410
  className: section.className,
392
411
  layout: section.layout ?? 'grid',
393
412
  grid: section.grid ?? { cols: 1, mdCols: 2, gap: 'gap-4' },
@@ -403,9 +422,10 @@ export function FormBuilder({
403
422
  return {
404
423
  key: field.name,
405
424
  span: { base: 1, md: spanMd },
425
+ className: field.wrapperClassName,
406
426
  hidden: field.hidden,
407
427
  content: (
408
- <FormField
428
+ <FormBuilderField
409
429
  key={field.name}
410
430
  field={{ ...field, disabled: field.disabled || fieldState.disabled }}
411
431
  control={control}
@@ -430,7 +450,14 @@ export function FormBuilder({
430
450
  <SectionBuilder sections={sectionNodes} />
431
451
 
432
452
  {showActions && (
433
- <div className={cn('flex flex-col sm:flex-row gap-3 pt-6 border-t', actionsClassName)}>
453
+ <div
454
+ className={cn(
455
+ 'flex flex-col sm:flex-row gap-3',
456
+ showActionsSeparator && 'pt-6',
457
+ showActionsSeparator && 'border-t',
458
+ actionsClassName,
459
+ )}
460
+ >
434
461
  <Button type="submit" disabled={isSubmitting} className="sm:order-last">
435
462
  {isSubmitting ? 'Submitting...' : submitLabel}
436
463
  </Button>
@@ -442,7 +469,7 @@ export function FormBuilder({
442
469
  )}
443
470
 
444
471
  {onReset && (
445
- <Button type="button" variant="ghost" onClick={handleReset} disabled={isSubmitting}>
472
+ <Button type="button" variant="outline" onClick={handleReset} disabled={isSubmitting}>
446
473
  {resetLabel}
447
474
  </Button>
448
475
  )}
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { Button } from '../../../../shadcn/ui/button';
3
3
  import { cn } from '../../../../shadcn/lib/utils';
4
4
 
5
- export interface FormActionsProps {
5
+ export interface FormBuilderActionsProps {
6
6
  onSubmit?: () => void;
7
7
  onCancel?: () => void;
8
8
  onReset?: () => void;
@@ -19,7 +19,7 @@ export interface FormActionsProps {
19
19
  resetButtonProps?: React.ComponentProps<typeof Button>;
20
20
  }
21
21
 
22
- export function FormActions({
22
+ export function FormBuilderActions({
23
23
  onSubmit,
24
24
  onCancel,
25
25
  onReset,
@@ -34,7 +34,7 @@ export function FormActions({
34
34
  submitButtonProps,
35
35
  cancelButtonProps,
36
36
  resetButtonProps,
37
- }: FormActionsProps) {
37
+ }: FormBuilderActionsProps) {
38
38
  return (
39
39
  <div className={cn('flex items-center justify-end space-x-4', className)}>
40
40
  {customActions}
@@ -6,6 +6,7 @@ import { Input } from '../../../../shadcn/ui/input';
6
6
  import { Textarea } from '../../../../shadcn/ui/textarea';
7
7
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../../shadcn/ui/select';
8
8
  import { Checkbox } from '../../../../shadcn/ui/checkbox';
9
+ import { Switch } from '../../../../shadcn/ui/switch';
9
10
  import { RadioGroup, RadioGroupItem } from '../../../../shadcn/ui/radio-group';
10
11
  import { Label } from '../../../../shadcn/ui/label';
11
12
  import { Card, CardContent, CardHeader, CardTitle } from '../../../../shadcn/ui/card';
@@ -14,7 +15,7 @@ import { FormBuilderFieldConfig } from './FormBuilder';
14
15
  import { Autocomplete } from '../../../components/autocomplete/Autocomplete';
15
16
  import type { AutocompleteOption } from '../../../components/autocomplete/types';
16
17
 
17
- export interface FormFieldProps {
18
+ export interface FormBuilderFieldProps {
18
19
  field: FormBuilderFieldConfig;
19
20
  control: Control<any>;
20
21
  onChange?: (value: any) => void;
@@ -22,7 +23,7 @@ export interface FormFieldProps {
22
23
  parentPath?: string;
23
24
  }
24
25
 
25
- export function FormField({ field, control, onChange, onFieldChange, parentPath }: FormFieldProps) {
26
+ export function FormBuilderField({ field, control, onChange, onFieldChange, parentPath }: FormBuilderFieldProps) {
26
27
  const fieldPath = parentPath ? `${parentPath}.${field.name}` : field.name;
27
28
  const NULL_SENTINEL = '__NULL__';
28
29
 
@@ -130,7 +131,39 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
130
131
  );
131
132
  }
132
133
 
133
- case 'checkbox':
134
+ case 'checkbox': {
135
+ const placement = field.labelPlacement ?? 'inline';
136
+ if (placement === 'stacked') {
137
+ const labelId = `${fieldPath}-label`;
138
+ return (
139
+ <div className="space-y-2">
140
+ <Label id={labelId} className="text-sm font-medium">
141
+ {field.label}
142
+ {field.required && <span className="text-destructive ml-1">*</span>}
143
+ </Label>
144
+ <Checkbox
145
+ aria-labelledby={labelId}
146
+ id={fieldPath}
147
+ checked={controllerField.value || false}
148
+ onCheckedChange={handleChange}
149
+ disabled={field.disabled}
150
+ className={cn(error && 'border-destructive', field.className)}
151
+ />
152
+ </div>
153
+ );
154
+ }
155
+ if (placement === 'hidden') {
156
+ return (
157
+ <Checkbox
158
+ id={fieldPath}
159
+ checked={controllerField.value || false}
160
+ onCheckedChange={handleChange}
161
+ disabled={field.disabled}
162
+ className={cn(error && 'border-destructive', field.className)}
163
+ />
164
+ );
165
+ }
166
+ // inline (default)
134
167
  return (
135
168
  <div className="flex items-center space-x-2">
136
169
  <Checkbox
@@ -142,9 +175,61 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
142
175
  />
143
176
  <Label htmlFor={fieldPath} className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
144
177
  {field.label}
178
+ {field.required && <span className="text-destructive ml-1">*</span>}
145
179
  </Label>
146
180
  </div>
147
181
  );
182
+ }
183
+
184
+ case 'switch': {
185
+ const placement = field.labelPlacement ?? 'inline';
186
+ if (placement === 'stacked') {
187
+ const labelId = `${fieldPath}-label`;
188
+ return (
189
+ <div className="space-y-2">
190
+ <Label id={labelId} className="text-sm font-medium">
191
+ {field.label}
192
+ {field.required && <span className="text-destructive ml-1">*</span>}
193
+ </Label>
194
+ <Switch
195
+ aria-labelledby={labelId}
196
+ id={fieldPath}
197
+ checked={controllerField.value || false}
198
+ onCheckedChange={handleChange}
199
+ disabled={field.disabled}
200
+ className={cn(error && 'border-destructive', field.className)}
201
+ />
202
+ </div>
203
+ );
204
+ }
205
+ if (placement === 'hidden') {
206
+ return (
207
+ <Switch
208
+ id={fieldPath}
209
+ checked={controllerField.value || false}
210
+ onCheckedChange={handleChange}
211
+ disabled={field.disabled}
212
+ className={cn(error && 'border-destructive', field.className)}
213
+ />
214
+ );
215
+ }
216
+ // inline (default)
217
+ return (
218
+ <div className="flex items-center space-x-2">
219
+ <Switch
220
+ id={fieldPath}
221
+ checked={controllerField.value || false}
222
+ onCheckedChange={handleChange}
223
+ disabled={field.disabled}
224
+ className={cn(error && 'border-destructive', field.className)}
225
+ />
226
+ <Label htmlFor={fieldPath} className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
227
+ {field.label}
228
+ {field.required && <span className="text-destructive ml-1">*</span>}
229
+ </Label>
230
+ </div>
231
+ );
232
+ }
148
233
 
149
234
  case 'radio': {
150
235
  const toUiValue = (val: unknown) => (val === null || val === undefined ? NULL_SENTINEL : String(val));
@@ -213,7 +298,7 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
213
298
  <CardContent className="space-y-4">
214
299
  <div className="grid gap-4 md:grid-cols-2">
215
300
  {field.fields.map(subField => (
216
- <FormField
301
+ <FormBuilderField
217
302
  key={subField.name}
218
303
  field={subField}
219
304
  control={control}
@@ -306,7 +391,7 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
306
391
  <CardContent>
307
392
  {field.fields && field.fields.length === 1 ? (
308
393
  // Single field array
309
- <FormField
394
+ <FormBuilderField
310
395
  field={{
311
396
  ...field.fields[0],
312
397
  name: field.fields[0].name,
@@ -320,7 +405,7 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
320
405
  // Object array
321
406
  <div className="grid gap-4 md:grid-cols-2">
322
407
  {field.fields.map(subField => (
323
- <FormField
408
+ <FormBuilderField
324
409
  key={subField.name}
325
410
  field={subField}
326
411
  control={control}
@@ -360,8 +445,24 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
360
445
  return renderArrayField();
361
446
  }
362
447
 
363
- // For checkbox, we don't need the label wrapper since it's handled internally
364
- if (field.type === 'checkbox') {
448
+ // For checkbox/switch, label may be inline/stacked/hidden handled inside renderBasicField
449
+ if (field.type === 'checkbox' || field.type === 'switch') {
450
+ return (
451
+ <div className={cn('space-y-2', field.gridCols && `md:col-span-${field.gridCols}`)}>
452
+ {renderBasicField()}
453
+ {field.description && (
454
+ <p className="text-sm text-muted-foreground">{field.description}</p>
455
+ )}
456
+ {error && (
457
+ <p className="text-sm text-destructive">{error.message}</p>
458
+ )}
459
+ </div>
460
+ );
461
+ }
462
+
463
+ // Non-checkbox fields: support labelPlacement
464
+ const placement = field.labelPlacement ?? 'stacked';
465
+ if (placement === 'hidden') {
365
466
  return (
366
467
  <div className={cn('space-y-2', field.gridCols && `md:col-span-${field.gridCols}`)}>
367
468
  {renderBasicField()}
@@ -375,6 +476,27 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
375
476
  );
376
477
  }
377
478
 
479
+ if (placement === 'inline') {
480
+ return (
481
+ <div className={cn('space-y-1', field.gridCols && `md:col-span-${field.gridCols}`)}>
482
+ <div className="flex items-center gap-2">
483
+ <Label htmlFor={fieldPath} className="text-sm font-medium">
484
+ {field.label}
485
+ {field.required && <span className="text-destructive ml-1">*</span>}
486
+ </Label>
487
+ {renderBasicField()}
488
+ </div>
489
+ {field.description && (
490
+ <p className="text-sm text-muted-foreground">{field.description}</p>
491
+ )}
492
+ {error && (
493
+ <p className="text-sm text-destructive">{error.message}</p>
494
+ )}
495
+ </div>
496
+ );
497
+ }
498
+
499
+ // stacked (default)
378
500
  return (
379
501
  <div className={cn('space-y-2', field.gridCols && `md:col-span-${field.gridCols}`)}>
380
502
  <Label htmlFor={fieldPath} className="text-sm font-medium">
@@ -392,4 +514,4 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
392
514
  );
393
515
  }
394
516
 
395
- export default FormField;
517
+ export default FormBuilderField;
@@ -1,4 +1,3 @@
1
- export * from './FormActions';
1
+ export * from './FormBuilderActions';
2
2
  export * from './FormBuilder';
3
- export * from './FormField';
4
- export * from './FormSection';
3
+ export * from './FormBuilderField';
@@ -93,6 +93,19 @@ export const createField = {
93
93
  ...options,
94
94
  }),
95
95
 
96
+ switch: (
97
+ name: string,
98
+ label: string,
99
+ options: Partial<FormBuilderFieldConfig> = {},
100
+ ): FormBuilderFieldConfig => ({
101
+ name,
102
+ label,
103
+ type: 'switch',
104
+ required: false,
105
+ defaultValue: false,
106
+ ...options,
107
+ }),
108
+
96
109
  radio: (
97
110
  name: string,
98
111
  label: string,
@@ -1,6 +1,7 @@
1
1
  import { memo } from 'react';
2
2
  import { cn } from '../../../shadcn/lib/utils';
3
- import { FormSection } from '../form/components/FormSection';
3
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../../../shadcn/ui/card';
4
+ import { Separator } from '../../../shadcn/ui/separator';
4
5
  import type { SectionBuilderProps, SectionLeaf, SectionNode } from './types';
5
6
 
6
7
  // Tailwind-safe literal class maps (1-12)
@@ -176,15 +177,71 @@ function SectionNodeRenderer({ node, renderLeaf }: { node: SectionNode; renderLe
176
177
  const layout = node.layout ?? 'grid';
177
178
  const containerClass = layout === 'grid' ? gridClasses(node.grid) : flexClasses(node.flex);
178
179
 
180
+ // Local presentational container replacing FormBuilderSection
181
+ const SectionContainer = ({ children }: { children: React.ReactNode }) => {
182
+ const title = node.title;
183
+ const description = node.subtitle;
184
+ const variant = node.variant ?? 'card';
185
+ const className = node.className;
186
+ const headerClassName = node.headerClassName;
187
+ const contentClassName = node.contentClassName;
188
+
189
+ const renderHeader = () => {
190
+ if (!title && !description) return null;
191
+ return (
192
+ <div className={cn('space-y-1', headerClassName)}>
193
+ {title && <h3 className="text-lg font-medium leading-none">{title}</h3>}
194
+ {description && <p className="text-sm text-muted-foreground">{description}</p>}
195
+ </div>
196
+ );
197
+ };
198
+
199
+ const renderContent = () => (
200
+ <div className={cn('space-y-4', contentClassName)}>
201
+ {children}
202
+ </div>
203
+ );
204
+
205
+ switch (variant) {
206
+ case 'card':
207
+ return (
208
+ <Card className={className}>
209
+ {(title || description) && (
210
+ <CardHeader>
211
+ {title && <CardTitle>{title}</CardTitle>}
212
+ {description && <CardDescription>{description}</CardDescription>}
213
+ </CardHeader>
214
+ )}
215
+ <CardContent>
216
+ {renderContent()}
217
+ </CardContent>
218
+ </Card>
219
+ );
220
+ case 'separator':
221
+ return (
222
+ <div className={cn('space-y-6', className)}>
223
+ {(title || description) && (
224
+ <>
225
+ {renderHeader()}
226
+ <Separator />
227
+ </>
228
+ )}
229
+ {renderContent()}
230
+ </div>
231
+ );
232
+ case 'plain':
233
+ default:
234
+ return (
235
+ <div className={cn('space-y-6', className)}>
236
+ {renderHeader()}
237
+ {renderContent()}
238
+ </div>
239
+ );
240
+ }
241
+ };
242
+
179
243
  return (
180
- <FormSection
181
- title={node.title}
182
- description={node.subtitle}
183
- variant={node.variant ?? 'card'}
184
- className={node.className}
185
- headerClassName={node.headerClassName}
186
- contentClassName={node.contentClassName}
187
- >
244
+ <SectionContainer>
188
245
  <div className={containerClass}>
189
246
  {(node.children ?? []).map((child) => {
190
247
  if (isLeaf(child)) {
@@ -198,7 +255,7 @@ function SectionNodeRenderer({ node, renderLeaf }: { node: SectionNode; renderLe
198
255
  );
199
256
  })}
200
257
  </div>
201
- </FormSection>
258
+ </SectionContainer>
202
259
  );
203
260
  }
204
261
 
@@ -6,7 +6,7 @@ export type AutocompleteOption = {
6
6
  export type AutocompleteFetchParams = {
7
7
  search: string
8
8
  cursor?: string | number | null
9
- page?: number
9
+ page: number
10
10
  pageSize: number
11
11
  }
12
12
 
@@ -22,7 +22,7 @@ import {
22
22
  Circle,
23
23
  } from 'lucide-react';
24
24
 
25
- import { Outlet, useLocation, Link } from '@tanstack/react-router';
25
+ import { useLocation, Link } from '@tanstack/react-router';
26
26
  import { Fragment, useState, useCallback } from 'react';
27
27
  import ThemeToggle from './ThemeToggle';
28
28
  import { useAdminSidebarMenu } from '../hooks/menu';
@@ -214,7 +214,6 @@ function AdminLayoutContent({
214
214
  </header>
215
215
  <main className="flex flex-1 flex-col gap-4 p-4">
216
216
  {children}
217
- <Outlet />
218
217
  </main>
219
218
  </SidebarInset>
220
219
  </div>
@@ -21,6 +21,6 @@ export function useAdminSidebarMenu() {
21
21
  }
22
22
 
23
23
  export function useAdminSidebarMenuRegistration() {
24
- const { registerGroup, registerItem, clear } = useAdminSidebarMenu();
25
- return { registerGroup, registerItem, clear };
24
+ const { setGroups, registerGroup, registerItem, clear } = useAdminSidebarMenu();
25
+ return { setGroups, registerGroup, registerItem, clear };
26
26
  }
@@ -1,11 +1,15 @@
1
- import { createContext, use, useEffect, useState } from 'react';
1
+ import { createContext, use, useEffect } from 'react';
2
+ import {
3
+ ThemeProvider as NextThemesProvider,
4
+ useTheme as useNextThemes,
5
+ } from 'next-themes';
2
6
 
3
7
  type Theme = 'dark' | 'light' | 'system';
4
8
 
5
9
  type ThemeProviderProps = {
6
10
  children: React.ReactNode;
7
- defaultTheme?: Theme;
8
- storageKey?: string;
11
+ defaultTheme?: Theme; // maps to next-themes defaultTheme
12
+ storageKey?: string; // maps to next-themes storageKey
9
13
  };
10
14
 
11
15
  type ThemeProviderState = {
@@ -26,51 +30,47 @@ export function ThemeProvider({
26
30
  storageKey = 'vite-ui-theme',
27
31
  ...props
28
32
  }: ThemeProviderProps) {
29
- const [theme, setTheme] = useState<Theme>(
30
- () => (localStorage.getItem(storageKey) as Theme) || defaultTheme,
33
+ return (
34
+ <NextThemesProvider
35
+ attribute="class"
36
+ defaultTheme={defaultTheme}
37
+ storageKey={storageKey}
38
+ enableSystem
39
+ disableTransitionOnChange
40
+ >
41
+ <ThemeBridge {...props}>{children}</ThemeBridge>
42
+ </NextThemesProvider>
31
43
  );
44
+ }
32
45
 
33
- // On first mount, if there is no saved preference or it's 'system' and
34
- // the app provides a concrete default (e.g., 'light'), apply it.
35
- useEffect(() => {
36
- const stored = localStorage.getItem(storageKey) as Theme | null;
37
- if ((!stored || stored === 'system') && defaultTheme !== 'system') {
38
- localStorage.setItem(storageKey, defaultTheme);
39
- setTheme(defaultTheme);
40
- }
41
- }, []);
46
+ function ThemeBridge({ children, ...props }: { children: React.ReactNode }) {
47
+ const { theme, resolvedTheme, setTheme } = useNextThemes();
42
48
 
49
+ // Mirror resolved theme to data-theme and color-scheme for CSS/Tailwind consumers
43
50
  useEffect(() => {
44
- const root = window.document.documentElement;
45
- const body = window.document.body;
46
- const app = window.document.getElementById('app');
47
- root.classList.remove('light', 'dark');
48
- body.classList.remove('light', 'dark');
49
- app?.classList.remove('light', 'dark');
51
+ if (typeof document === 'undefined') return;
52
+ const root = document.documentElement;
53
+ const body = document.body;
54
+ const app = document.getElementById('app');
55
+ const resolved = (resolvedTheme as 'light' | 'dark') ?? 'light';
50
56
 
51
- const resolved = (() => {
52
- if (theme === 'system') {
53
- return window.matchMedia('(prefers-color-scheme: dark)').matches
54
- ? 'dark'
55
- : 'light';
56
- }
57
- return theme;
58
- })();
57
+ // data-theme + color-scheme for CSS variables and form controls
58
+ root.setAttribute('data-theme', resolved);
59
+ root.style.colorScheme = resolved;
59
60
 
61
+ // Ensure class-based dark mode works across html, body, and #app
62
+ const opposite = resolved === 'dark' ? 'light' : 'dark';
63
+ root.classList.remove(opposite);
64
+ body.classList.remove(opposite);
65
+ app?.classList.remove(opposite);
60
66
  root.classList.add(resolved);
61
67
  body.classList.add(resolved);
62
68
  app?.classList.add(resolved);
63
- root.style.colorScheme = resolved;
64
- // Important for Tailwind v4 @theme dark support
65
- root.setAttribute('data-theme', resolved);
66
- }, [theme]);
69
+ }, [resolvedTheme]);
67
70
 
68
- const value = {
69
- theme,
70
- setTheme: (theme: Theme) => {
71
- localStorage.setItem(storageKey, theme);
72
- setTheme(theme);
73
- },
71
+ const value: ThemeProviderState = {
72
+ theme: (theme as Theme) ?? 'system',
73
+ setTheme: (t: Theme) => setTheme(t),
74
74
  };
75
75
 
76
76
  return (
@@ -29,6 +29,8 @@ export const BasicUsage: Story = {
29
29
  { name: 'lastName', label: 'Last name', type: 'text', required: true },
30
30
  { name: 'email', label: 'Email', type: 'email', required: true },
31
31
  { name: 'newsletter', label: 'Subscribe to newsletter', type: 'checkbox', defaultValue: false, gridCols: 2 },
32
+ { name: 'darkMode', label: 'Enable dark mode', type: 'switch', defaultValue: false, gridCols: 2 },
33
+ { name: 'darkModeStacked', label: 'Enable dark mode (stacked)', type: 'switch', defaultValue: true, labelPlacement: 'stacked', gridCols: 2 },
32
34
  ],
33
35
  },
34
36
  ],
@@ -59,6 +59,10 @@ export const SimpleExample: Story = {
59
59
  defaultValue: false,
60
60
  gridCols: 2,
61
61
  }),
62
+ createField.switch('contactPermission', 'Allow contact by phone', {
63
+ defaultValue: false,
64
+ gridCols: 2,
65
+ }),
62
66
  ]),
63
67
  ];
64
68