@k3-universe/react-kit 0.0.1 → 0.0.2
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.
- package/.storybook/preview.ts +1 -1
- package/dist/index.d.ts +63 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +91 -0
- package/dist/kit/builder/data-table/components/DataTable.d.ts +4 -1
- package/dist/kit/builder/data-table/components/DataTable.d.ts.map +1 -1
- package/dist/kit/builder/data-table/index.d.ts +6 -5
- package/dist/kit/builder/data-table/index.d.ts.map +1 -1
- package/dist/kit/builder/form/components/FormBuilder.d.ts +4 -1
- package/dist/kit/builder/form/components/FormBuilder.d.ts.map +1 -1
- package/dist/kit/builder/form/components/{FormActions.d.ts → FormBuilderActions.d.ts} +3 -3
- package/dist/kit/builder/form/components/FormBuilderActions.d.ts.map +1 -0
- package/{storybook-static/kit/builder/form/components/FormField.d.ts → dist/kit/builder/form/components/FormBuilderField.d.ts} +4 -4
- package/dist/kit/builder/form/components/FormBuilderField.d.ts.map +1 -0
- package/dist/kit/builder/form/components/index.d.ts +2 -3
- package/dist/kit/builder/form/components/index.d.ts.map +1 -1
- package/dist/kit/builder/section/SectionBuilder.d.ts.map +1 -1
- package/dist/kit/components/autocomplete/types.d.ts +1 -1
- package/dist/kit/components/autocomplete/types.d.ts.map +1 -1
- package/dist/kit/layouts/admin/components/AdminLayout.d.ts.map +1 -1
- package/dist/kit/layouts/admin/hooks/menu.d.ts +1 -0
- package/dist/kit/layouts/admin/hooks/menu.d.ts.map +1 -1
- package/dist/kit/providers/ThemeProvider.d.ts.map +1 -1
- package/dist/kit/themes/base.css +1 -0
- package/dist/kit/themes/clean-slate.css +1 -0
- package/dist/kit/themes/default.css +1 -0
- package/dist/kit/themes/minimal-modern.css +1 -0
- package/dist/kit/themes/spotify.css +1 -0
- package/package.json +11 -10
- package/src/index.ts +88 -0
- package/src/kit/builder/data-table/components/DataTable.tsx +63 -23
- package/src/kit/builder/data-table/index.ts +6 -5
- package/src/kit/builder/form/components/FormBuilder.tsx +34 -10
- package/src/kit/builder/form/components/{FormActions.tsx → FormBuilderActions.tsx} +3 -3
- package/src/kit/builder/form/components/{FormField.tsx → FormBuilderField.tsx} +79 -8
- package/src/kit/builder/form/components/index.ts +2 -3
- package/src/kit/builder/section/SectionBuilder.tsx +67 -10
- package/src/kit/components/autocomplete/types.ts +1 -1
- package/src/kit/layouts/admin/components/AdminLayout.tsx +1 -2
- package/src/kit/layouts/admin/hooks/menu.ts +2 -2
- package/src/kit/providers/ThemeProvider.tsx +38 -38
- package/src/stories/kit/layouts/admin/AdminLayout.Basic.stories.tsx +2 -0
- package/src/stories/kit/layouts/admin/AdminLayout.Collapsible.stories.tsx +2 -0
- package/src/stories/kit/layouts/admin/AdminLayout.Complex.stories.tsx +2 -0
- package/src/stories/kit/layouts/admin/AdminLayout.CustomSidebarHeaderComponent.stories.tsx +2 -0
- package/src/stories/kit/layouts/admin/AdminLayout.CustomSidebarTitleAndIcon.stories.tsx +2 -0
- package/src/stories/kit/layouts/admin/AdminLayout.HeaderSlots.stories.tsx +2 -0
- package/storybook-static/assets/{Accordion.stories-N1auke5L.js → Accordion.stories-q6yg6wg1.js} +1 -1
- package/storybook-static/assets/{AdminLayout-Cxd0-A_L.js → AdminLayout-B9bV4J_6.js} +1 -1
- package/storybook-static/assets/{AdminLayout.Basic.stories-C_I6rWuq.js → AdminLayout.Basic.stories-C-ZxuH-O.js} +1 -1
- package/storybook-static/assets/AdminLayout.Collapsible.stories-xcQzkxio.js +4 -0
- package/storybook-static/assets/{AdminLayout.Complex.stories-BbY1Ue6d.js → AdminLayout.Complex.stories-DyjkVpvE.js} +1 -1
- package/storybook-static/assets/{AdminLayout.CustomSidebarHeaderComponent.stories-LFVi-aIv.js → AdminLayout.CustomSidebarHeaderComponent.stories-BqhzWCIA.js} +1 -1
- package/storybook-static/assets/AdminLayout.CustomSidebarTitleAndIcon.stories-aWxyR67T.js +4 -0
- package/storybook-static/assets/{AdminLayout.HeaderSlots.stories-BactzgkF.js → AdminLayout.HeaderSlots.stories-dNzhUdDt.js} +1 -1
- package/storybook-static/assets/{Alert.stories-_FtuixdR.js → Alert.stories-DXwNfJ3w.js} +1 -1
- package/storybook-static/assets/{AlertDialog.stories-6NY3BjwR.js → AlertDialog.stories-I324NsnP.js} +1 -1
- package/storybook-static/assets/{AspectRatio.stories-DAT11y02.js → AspectRatio.stories-CghHiX3Z.js} +1 -1
- package/storybook-static/assets/{Autocomplete-DngjqsCM.js → Autocomplete-B4gV705L.js} +1 -1
- package/storybook-static/assets/{Autocomplete.stories-BCaOrgTR.js → Autocomplete.stories-CyOvjTGN.js} +1 -1
- package/storybook-static/assets/{Avatar.stories-DlzxSLJ-.js → Avatar.stories-CEF5FVSR.js} +1 -1
- package/storybook-static/assets/{Badge.stories-DKHXsoV5.js → Badge.stories-_-G3GriP.js} +1 -1
- package/storybook-static/assets/{Breadcrumb.stories-D8eUHpf7.js → Breadcrumb.stories-DORe9T4b.js} +1 -1
- package/storybook-static/assets/{Button.stories-kvPdKxdw.js → Button.stories-3nQ6wsBX.js} +1 -1
- package/storybook-static/assets/{Calendar.stories-D-hUtQQI.js → Calendar.stories-Dn__djE1.js} +1 -1
- package/storybook-static/assets/{Card.stories-y8Z7NgrQ.js → Card.stories-BJcbdwCI.js} +1 -1
- package/storybook-static/assets/{Carousel.stories-CFcHYKgp.js → Carousel.stories-CfqbE7Va.js} +1 -1
- package/storybook-static/assets/{Chart.stories-BJwLNKfE.js → Chart.stories-cGgef3tv.js} +1 -1
- package/storybook-static/assets/{Checkbox.stories-B22Fbwx1.js → Checkbox.stories-BcaxWzCS.js} +1 -1
- package/storybook-static/assets/{Collapsible.stories-BgcRp8Rk.js → Collapsible.stories-CQ95s7Cs.js} +1 -1
- package/storybook-static/assets/{Combination-BT_gXe1L.js → Combination-CeVus13L.js} +1 -1
- package/storybook-static/assets/{Command.stories-Dp4CtSQR.js → Command.stories-DYflJh8u.js} +1 -1
- package/storybook-static/assets/{ContextMenu.stories-DnVnIi-T.js → ContextMenu.stories-CU7ehYrE.js} +1 -1
- package/storybook-static/assets/DataTable.Basic.stories-BQNWUKiw.js +6 -0
- package/storybook-static/assets/{DataTable.Filters.stories-CO0ipuGm.js → DataTable.Filters.stories-DPCoeYhK.js} +1 -1
- package/storybook-static/assets/{DataTable.Pagination.stories-DNwCw64e.js → DataTable.Pagination.stories-8UNqTNgw.js} +1 -1
- package/storybook-static/assets/{DataTable.SelectionAndActions.stories-DGgdEbsf.js → DataTable.SelectionAndActions.stories-CDEjgQ6T.js} +1 -1
- package/storybook-static/assets/DataTable.Sorting.stories-qG7-X_6r.js +6 -0
- package/storybook-static/assets/{Dialog.stories-DQkYN8ht.js → Dialog.stories-Bu6ZJXNH.js} +1 -1
- package/storybook-static/assets/{Dialog.stories-DXZINEgo.js → Dialog.stories-DobNZ0Hp.js} +1 -1
- package/storybook-static/assets/{Drawer.stories-DMH_vZgi.js → Drawer.stories-BN0idp4u.js} +1 -1
- package/storybook-static/assets/{DropdownMenu.stories-Dl8y-N7T.js → DropdownMenu.stories-sfsVDTvm.js} +1 -1
- package/storybook-static/assets/{Form.Basic.stories-CJugIYsx.js → Form.Basic.stories-dE4nbgpr.js} +1 -1
- package/storybook-static/assets/{Form.Complex.stories-BPogRp6F.js → Form.Complex.stories-BEZufnjb.js} +1 -1
- package/storybook-static/assets/{Form.Dynamic.stories-Boway5AK.js → Form.Dynamic.stories-cJTbd6cV.js} +1 -1
- package/storybook-static/assets/{Form.Simple.stories-_OXGXXpE.js → Form.Simple.stories-DOPzZKhh.js} +1 -1
- package/storybook-static/assets/{Form.stories-BoHyR8ho.js → Form.stories-27doU7JS.js} +1 -1
- package/storybook-static/assets/{FormBuilder-BGgeY8ik.js → FormBuilder-C0S7C69Q.js} +1 -1
- package/storybook-static/assets/{HoverCard.stories-1HM92M79.js → HoverCard.stories-0lted9Zx.js} +1 -1
- package/storybook-static/assets/{Input.stories-sQ4EUlWt.js → Input.stories-CwsIObFs.js} +1 -1
- package/storybook-static/assets/{InputOtp.stories-Cpk_EmLx.js → InputOtp.stories-DVc086h4.js} +1 -1
- package/storybook-static/assets/{Label.stories-MjABHKSw.js → Label.stories-bJa0rk1A.js} +1 -1
- package/storybook-static/assets/{Login.stories-BY4OYGk3.js → Login.stories-C6X6Kj5B.js} +1 -1
- package/storybook-static/assets/{Menubar.stories-B_60TWNE.js → Menubar.stories-CuediVp7.js} +1 -1
- package/storybook-static/assets/{NavigationMenu.stories-DyuaBvvq.js → NavigationMenu.stories-CKGZYhKk.js} +1 -1
- package/storybook-static/assets/{Page.stories-DQKMxrPZ.js → Page.stories-Cf76wtRx.js} +1 -1
- package/storybook-static/assets/{Pagination.stories-CBo7UrNd.js → Pagination.stories-D7IdL1_4.js} +1 -1
- package/storybook-static/assets/{Popover.stories-D98_JrxN.js → Popover.stories-1VP_zNY8.js} +1 -1
- package/storybook-static/assets/{Progress.stories-Dejt5v3z.js → Progress.stories-C35R5YvA.js} +1 -1
- package/storybook-static/assets/{RadioGroup.stories-Tz2LW6O6.js → RadioGroup.stories-CjuD3CwD.js} +1 -1
- package/storybook-static/assets/{Resizable.stories-DhP2GKN7.js → Resizable.stories-Cs8dvdc5.js} +1 -1
- package/storybook-static/assets/{ScrollArea.stories-CF7-8wbM.js → ScrollArea.stories-D6_z-5jm.js} +1 -1
- package/storybook-static/assets/{Section.stories-BpurjHIQ.js → Section.stories-Ce5qYITI.js} +1 -1
- package/storybook-static/assets/SectionBuilder-Df_lRZkj.js +1 -0
- package/storybook-static/assets/{Select.stories-DJrU-mi0.js → Select.stories-w_kbza5k.js} +1 -1
- package/storybook-static/assets/{Separator.stories-BYH_o8QM.js → Separator.stories-B5QnaJXb.js} +1 -1
- package/storybook-static/assets/{Sheet.stories-BNJ7BIb-.js → Sheet.stories-CORnEGvV.js} +1 -1
- package/storybook-static/assets/{Sidebar.stories-BbjcJuOg.js → Sidebar.stories-DVuWTi4j.js} +1 -1
- package/storybook-static/assets/{Slider.stories-CWOjKHKD.js → Slider.stories-YoS2vvT2.js} +1 -1
- package/storybook-static/assets/{Sonner.stories-CXSZs5yN.js → Sonner.stories-CXW5e_Qg.js} +1 -1
- package/storybook-static/assets/{Switch.stories-BUQjobWe.js → Switch.stories-zr6i-aNi.js} +1 -1
- package/storybook-static/assets/{Table.stories-DJcV7M9R.js → Table.stories-BuGU4MUM.js} +1 -1
- package/storybook-static/assets/{Tabs.stories-ByeVrP18.js → Tabs.stories-jxkJ-AUI.js} +1 -1
- package/storybook-static/assets/{Textarea.stories-CKsDPHYc.js → Textarea.stories-CHXVobz6.js} +1 -1
- package/storybook-static/assets/{Toggle.stories-DutEzZ8k.js → Toggle.stories-C4uB4Hkq.js} +1 -1
- package/storybook-static/assets/{ToggleGroup.stories-C9fzJTh-.js → ToggleGroup.stories-Cr229wf_.js} +1 -1
- package/storybook-static/assets/{Tooltip.stories-CngnJbP7.js → Tooltip.stories-DmMYGR3T.js} +1 -1
- package/storybook-static/assets/{accordion-bQe9Rep4.js → accordion-BCfsz_gl.js} +1 -1
- package/storybook-static/assets/{alert-dialog-CypF_yaW.js → alert-dialog-BYt6Z7Kt.js} +1 -1
- package/storybook-static/assets/{avatar-CukM9hXu.js → avatar-CRn1qQsC.js} +1 -1
- package/storybook-static/assets/{axe-W8QMjM0E.js → axe-JCJl60WC.js} +1 -1
- package/storybook-static/assets/{button-BTWmFXop.js → button-BObfgcV1.js} +1 -1
- package/storybook-static/assets/{chart-column-Bzh5arua.js → chart-column-CplFCmg8.js} +1 -1
- package/storybook-static/assets/{check-BgWXKGqi.js → check-DyecuwP4.js} +1 -1
- package/storybook-static/assets/{checkbox-QlugAqJY.js → checkbox-D5BmNJeL.js} +1 -1
- package/storybook-static/assets/{chevron-down-BqLjUn1_.js → chevron-down-Bp7zbUB0.js} +1 -1
- package/storybook-static/assets/{chevron-left-BR_0lKnE.js → chevron-left-D1L4J3UW.js} +1 -1
- package/storybook-static/assets/{chevron-right-DpCIoMaJ.js → chevron-right-oMYqDJ_f.js} +1 -1
- package/storybook-static/assets/{circle-DVJTkDI7.js → circle-CyarsADt.js} +1 -1
- package/storybook-static/assets/clean-slate-V4nUw2Bm.css +1 -0
- package/storybook-static/assets/{command-BERL33lL.js → command-DCnXmNmT.js} +1 -1
- package/storybook-static/assets/{createLucideIcon-1ZwIAs_l.js → createLucideIcon-CLBo0iA0.js} +1 -1
- package/storybook-static/assets/default-CuTBjDca.css +1 -0
- package/storybook-static/assets/{dialog-DM9YJ1JD.js → dialog-DL0QBIbC.js} +1 -1
- package/storybook-static/assets/{dropdown-menu-TfFll7G9.js → dropdown-menu-BwL9gQwG.js} +1 -1
- package/storybook-static/assets/{ellipsis-BSY8VuLI.js → ellipsis-DPg968Rc.js} +1 -1
- package/storybook-static/assets/{grip-vertical-Buja1rv9.js → grip-vertical-CM0GDwvq.js} +1 -1
- package/storybook-static/assets/{iframe-G-6sM9Mt.js → iframe-BWjPIle6.js} +4 -4
- package/storybook-static/assets/{index-DqWzLCH-.js → index-04C4iZwC.js} +1 -1
- package/storybook-static/assets/{index-B-fXBfyD.js → index-3zykFCgl.js} +1 -1
- package/storybook-static/assets/{index-CAwQR9Pv.js → index-7XoYQV2z.js} +1 -1
- package/storybook-static/assets/{index-DySHPxMy.js → index-A7UzX-Xw.js} +1 -1
- package/storybook-static/assets/index-BN5_W3Yi.js +1 -0
- package/storybook-static/assets/{index-1v1lhNFD.js → index-BcAKBHrX.js} +1 -1
- package/storybook-static/assets/{index-7yNAGow7.js → index-BfKpUbCE.js} +1 -1
- package/storybook-static/assets/index-C5eJ31Z3.js +1 -0
- package/storybook-static/assets/{index-CayhpKmv.js → index-C6O7WofA.js} +1 -1
- package/storybook-static/assets/{index-BDwnENHR.js → index-C9xvlw_B.js} +1 -1
- package/storybook-static/assets/{index-Bq6UNRVc.js → index-CKwUGXmt.js} +1 -1
- package/storybook-static/assets/{index-d_S6mtzU.js → index-Cce91yJQ.js} +1 -1
- package/storybook-static/assets/{index-CMmbDm5O.js → index-Cw7p-pms.js} +1 -1
- package/storybook-static/assets/{index-CLmN5G1a.js → index-DE2OlfDP.js} +1 -1
- package/storybook-static/assets/{index-ev1RjzGv.js → index-DMk2qc2_.js} +1 -1
- package/storybook-static/assets/index-DWC9SV-P.js +1 -0
- package/storybook-static/assets/{index-HghBIZeg.js → index-Dqw7miiX.js} +1 -1
- package/storybook-static/assets/{index-ClNNG_ys.js → index-Dr2xmx-F.js} +1 -1
- package/storybook-static/assets/{index-lH-AZpAn.js → index-DschQYGl.js} +1 -1
- package/storybook-static/assets/{index-SxI7_jxe.js → index-Dsg7S8zu.js} +1 -1
- package/storybook-static/assets/{index-DvM9azdj.js → index-Pk2lGsul.js} +1 -1
- package/storybook-static/assets/{index-DNAxNqEO.js → index-URSssr5a.js} +1 -1
- package/storybook-static/assets/{index-CZaD3imo.js → index-npvyVsxD.js} +1 -1
- package/storybook-static/assets/{index-CzJf-yyP.js → index-u70nzfOV.js} +1 -1
- package/storybook-static/assets/{label-C5vJTTwH.js → label-CwntpYJ0.js} +1 -1
- package/storybook-static/assets/{lodash-Q9aGJGMb.js → lodash-BkmSIg_J.js} +1 -1
- package/storybook-static/assets/minimal-modern-d2yFlFJM.css +1 -0
- package/storybook-static/assets/{popover-DW1K4QCO.js → popover-ClqrrvjL.js} +1 -1
- package/storybook-static/assets/{radio-group-iPL-8jvw.js → radio-group-CvN0LQZp.js} +1 -1
- package/storybook-static/assets/{react-18-CK1-M7n3.js → react-18-Bj31y5Nr.js} +1 -1
- package/storybook-static/assets/{react-icons.esm-n2MUhK0n.js → react-icons.esm-DNr9VcvP.js} +1 -1
- package/storybook-static/assets/{refresh-cw-FYEbhX1i.js → refresh-cw-OZakDsFY.js} +1 -1
- package/storybook-static/assets/{schemas-S_Tg7JYp.js → schemas-CaLvKjsI.js} +1 -1
- package/storybook-static/assets/{section-factories-CC6eFfbk.js → section-factories-DKfKL-5s.js} +1 -1
- package/storybook-static/assets/{select-DbLzULCJ.js → select-gtXRB92c.js} +1 -1
- package/storybook-static/assets/{separator-DoUX1TNx.js → separator-CxCWfpZX.js} +1 -1
- package/storybook-static/assets/{settings-2-CpOcGlDm.js → settings-2-DSSkfF6W.js} +1 -1
- package/storybook-static/assets/{sheet-n5VQ25jh.js → sheet-r0VNiBiN.js} +1 -1
- package/storybook-static/assets/{shopping-cart-9kOJ1UDd.js → shopping-cart-CJBClF2m.js} +1 -1
- package/storybook-static/assets/{sidebar-CvUiZOJe.js → sidebar-BsMnOE7Y.js} +1 -1
- package/storybook-static/assets/spotify-BuPUgQEa.css +1 -0
- package/storybook-static/assets/{toggle-B-YKWMF8.js → toggle-D08-8sQA.js} +1 -1
- package/storybook-static/assets/{tooltip-CNONbPiI.js → tooltip-CZ1UAE_e.js} +1 -1
- package/storybook-static/assets/{trash-2-Bt5LMclM.js → trash-2-D55eseMQ.js} +1 -1
- package/storybook-static/assets/{x-DG9mLFAg.js → x-n8sFtlI2.js} +1 -1
- package/storybook-static/iframe.html +1 -1
- package/storybook-static/index.d.ts +63 -0
- package/storybook-static/index.d.ts.map +1 -1
- package/storybook-static/kit/builder/form/components/{FormActions.d.ts → FormBuilderActions.d.ts} +3 -3
- package/storybook-static/kit/builder/form/components/FormBuilderActions.d.ts.map +1 -0
- package/{dist/kit/builder/form/components/FormField.d.ts → storybook-static/kit/builder/form/components/FormBuilderField.d.ts} +4 -4
- package/storybook-static/kit/builder/form/components/FormBuilderField.d.ts.map +1 -0
- package/storybook-static/kit/builder/form/components/index.d.ts +2 -3
- package/storybook-static/kit/builder/form/components/index.d.ts.map +1 -1
- package/storybook-static/kit/builder/section/SectionBuilder.d.ts.map +1 -1
- package/storybook-static/project.json +1 -1
- package/vite.config.ts +76 -52
- package/dist/kit/builder/form/components/FormActions.d.ts.map +0 -1
- package/dist/kit/builder/form/components/FormField.d.ts.map +0 -1
- package/dist/kit/builder/form/components/FormSection.d.ts +0 -15
- package/dist/kit/builder/form/components/FormSection.d.ts.map +0 -1
- package/src/kit/builder/form/components/FormSection.tsx +0 -88
- package/storybook-static/assets/AdminLayout.Collapsible.stories-CsU3DwTo.js +0 -4
- package/storybook-static/assets/AdminLayout.CustomSidebarTitleAndIcon.stories-BqP6UVc7.js +0 -4
- package/storybook-static/assets/DataTable.Basic.stories-DBF5VYq9.js +0 -6
- package/storybook-static/assets/DataTable.Sorting.stories-CWpqloAB.js +0 -6
- package/storybook-static/assets/SectionBuilder-Bav4WrnT.js +0 -1
- package/storybook-static/assets/clean-slate-BR-XvZPt.css +0 -1
- package/storybook-static/assets/default-M24vcGB8.css +0 -1
- package/storybook-static/assets/index-DhoByIgc.js +0 -1
- package/storybook-static/assets/index-I343IfOC.js +0 -1
- package/storybook-static/assets/index-_crRFOM5.js +0 -1
- package/storybook-static/assets/minimal-modern-BmvR5wyr.css +0 -1
- package/storybook-static/assets/spotify-DpbeJq1r.css +0 -1
- package/storybook-static/kit/builder/form/components/FormActions.d.ts.map +0 -1
- package/storybook-static/kit/builder/form/components/FormField.d.ts.map +0 -1
- package/storybook-static/kit/builder/form/components/FormSection.d.ts +0 -15
- package/storybook-static/kit/builder/form/components/FormSection.d.ts.map +0 -1
- /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 {
|
|
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';
|
|
@@ -70,6 +70,10 @@ export interface FormBuilderFieldConfig {
|
|
|
70
70
|
value: any;
|
|
71
71
|
}; // For conditional field visibility
|
|
72
72
|
hidden?: boolean; // Declarative hide
|
|
73
|
+
// Label placement control across inputs
|
|
74
|
+
labelPlacement?: 'stacked' | 'inline' | 'hidden';
|
|
75
|
+
// Wrapper container className (applies to the field wrapper, not the input)
|
|
76
|
+
wrapperClassName?: string;
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
export interface FormBuilderSectionConfig {
|
|
@@ -108,6 +112,8 @@ export interface FormBuilderProps {
|
|
|
108
112
|
actionsClassName?: string;
|
|
109
113
|
showActions?: boolean;
|
|
110
114
|
customActions?: React.ReactNode;
|
|
115
|
+
// UI: show a separator line above action buttons
|
|
116
|
+
showActionsSeparator?: boolean;
|
|
111
117
|
}
|
|
112
118
|
|
|
113
119
|
export function FormBuilder({
|
|
@@ -127,6 +133,7 @@ export function FormBuilder({
|
|
|
127
133
|
actionsClassName,
|
|
128
134
|
showActions = true,
|
|
129
135
|
customActions,
|
|
136
|
+
showActionsSeparator = true,
|
|
130
137
|
}: FormBuilderProps) {
|
|
131
138
|
// Generate schema from field configs if not provided
|
|
132
139
|
const generatedSchema = useMemo(() => {
|
|
@@ -309,18 +316,27 @@ export function FormBuilder({
|
|
|
309
316
|
|
|
310
317
|
const { control, handleSubmit, reset, setValue, getValues, watch } = form;
|
|
311
318
|
|
|
312
|
-
//
|
|
313
|
-
const
|
|
319
|
+
// Determine if any field dependencies are declared
|
|
320
|
+
const hasDependencies = useMemo(() => {
|
|
321
|
+
return sections.some((section) =>
|
|
322
|
+
section.fields?.some((f) => Array.isArray(f.dependencies) && f.dependencies.length > 0),
|
|
323
|
+
);
|
|
324
|
+
}, [sections]);
|
|
325
|
+
|
|
326
|
+
// Only watch values when there are dependencies to respond to
|
|
327
|
+
// This prevents unnecessary re-renders that can cause focus loss
|
|
328
|
+
const emptyWatchedValues = useMemo(() => ({} as Record<string, any>), []);
|
|
329
|
+
const watchedValues = hasDependencies ? watch() : emptyWatchedValues;
|
|
314
330
|
|
|
315
331
|
// Handle field dependencies
|
|
316
332
|
const handleFieldDependencies = useCallback(
|
|
317
333
|
(field: FormBuilderFieldConfig) => {
|
|
318
|
-
if (!field.dependencies) return {};
|
|
334
|
+
if (!hasDependencies || !field.dependencies) return {};
|
|
319
335
|
|
|
320
336
|
const result: { disabled?: boolean; hidden?: boolean } = {};
|
|
321
337
|
|
|
322
338
|
field.dependencies.forEach((dep) => {
|
|
323
|
-
const dependentValue = watchedValues[dep.field];
|
|
339
|
+
const dependentValue = (watchedValues as Record<string, any>)[dep.field];
|
|
324
340
|
const conditionMet = dep.condition(dependentValue);
|
|
325
341
|
|
|
326
342
|
switch (dep.action) {
|
|
@@ -350,7 +366,7 @@ export function FormBuilder({
|
|
|
350
366
|
|
|
351
367
|
return result;
|
|
352
368
|
},
|
|
353
|
-
[watchedValues, setValue, getValues],
|
|
369
|
+
[hasDependencies, watchedValues, setValue, getValues],
|
|
354
370
|
);
|
|
355
371
|
|
|
356
372
|
// Handle field change with custom onChange
|
|
@@ -387,7 +403,7 @@ export function FormBuilder({
|
|
|
387
403
|
id: section.id ?? `section-${sectionIndex}`,
|
|
388
404
|
title: section.title,
|
|
389
405
|
subtitle: section.description,
|
|
390
|
-
variant: section.variant ?? '
|
|
406
|
+
variant: section.variant ?? 'plain',
|
|
391
407
|
className: section.className,
|
|
392
408
|
layout: section.layout ?? 'grid',
|
|
393
409
|
grid: section.grid ?? { cols: 1, mdCols: 2, gap: 'gap-4' },
|
|
@@ -403,9 +419,10 @@ export function FormBuilder({
|
|
|
403
419
|
return {
|
|
404
420
|
key: field.name,
|
|
405
421
|
span: { base: 1, md: spanMd },
|
|
422
|
+
className: field.wrapperClassName,
|
|
406
423
|
hidden: field.hidden,
|
|
407
424
|
content: (
|
|
408
|
-
<
|
|
425
|
+
<FormBuilderField
|
|
409
426
|
key={field.name}
|
|
410
427
|
field={{ ...field, disabled: field.disabled || fieldState.disabled }}
|
|
411
428
|
control={control}
|
|
@@ -430,7 +447,14 @@ export function FormBuilder({
|
|
|
430
447
|
<SectionBuilder sections={sectionNodes} />
|
|
431
448
|
|
|
432
449
|
{showActions && (
|
|
433
|
-
<div
|
|
450
|
+
<div
|
|
451
|
+
className={cn(
|
|
452
|
+
'flex flex-col sm:flex-row gap-3',
|
|
453
|
+
showActionsSeparator && 'pt-6',
|
|
454
|
+
showActionsSeparator && 'border-t',
|
|
455
|
+
actionsClassName,
|
|
456
|
+
)}
|
|
457
|
+
>
|
|
434
458
|
<Button type="submit" disabled={isSubmitting} className="sm:order-last">
|
|
435
459
|
{isSubmitting ? 'Submitting...' : submitLabel}
|
|
436
460
|
</Button>
|
|
@@ -442,7 +466,7 @@ export function FormBuilder({
|
|
|
442
466
|
)}
|
|
443
467
|
|
|
444
468
|
{onReset && (
|
|
445
|
-
<Button type="button" variant="
|
|
469
|
+
<Button type="button" variant="outline" onClick={handleReset} disabled={isSubmitting}>
|
|
446
470
|
{resetLabel}
|
|
447
471
|
</Button>
|
|
448
472
|
)}
|
|
@@ -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
|
|
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
|
|
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
|
-
}:
|
|
37
|
+
}: FormBuilderActionsProps) {
|
|
38
38
|
return (
|
|
39
39
|
<div className={cn('flex items-center justify-end space-x-4', className)}>
|
|
40
40
|
{customActions}
|
|
@@ -14,7 +14,7 @@ import { FormBuilderFieldConfig } from './FormBuilder';
|
|
|
14
14
|
import { Autocomplete } from '../../../components/autocomplete/Autocomplete';
|
|
15
15
|
import type { AutocompleteOption } from '../../../components/autocomplete/types';
|
|
16
16
|
|
|
17
|
-
export interface
|
|
17
|
+
export interface FormBuilderFieldProps {
|
|
18
18
|
field: FormBuilderFieldConfig;
|
|
19
19
|
control: Control<any>;
|
|
20
20
|
onChange?: (value: any) => void;
|
|
@@ -22,7 +22,7 @@ export interface FormFieldProps {
|
|
|
22
22
|
parentPath?: string;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export function
|
|
25
|
+
export function FormBuilderField({ field, control, onChange, onFieldChange, parentPath }: FormBuilderFieldProps) {
|
|
26
26
|
const fieldPath = parentPath ? `${parentPath}.${field.name}` : field.name;
|
|
27
27
|
const NULL_SENTINEL = '__NULL__';
|
|
28
28
|
|
|
@@ -130,7 +130,39 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
|
|
|
130
130
|
);
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
case 'checkbox':
|
|
133
|
+
case 'checkbox': {
|
|
134
|
+
const placement = field.labelPlacement ?? 'inline';
|
|
135
|
+
if (placement === 'stacked') {
|
|
136
|
+
const labelId = `${fieldPath}-label`;
|
|
137
|
+
return (
|
|
138
|
+
<div className="space-y-2">
|
|
139
|
+
<Label id={labelId} className="text-sm font-medium">
|
|
140
|
+
{field.label}
|
|
141
|
+
{field.required && <span className="text-destructive ml-1">*</span>}
|
|
142
|
+
</Label>
|
|
143
|
+
<Checkbox
|
|
144
|
+
aria-labelledby={labelId}
|
|
145
|
+
id={fieldPath}
|
|
146
|
+
checked={controllerField.value || false}
|
|
147
|
+
onCheckedChange={handleChange}
|
|
148
|
+
disabled={field.disabled}
|
|
149
|
+
className={cn(error && 'border-destructive', field.className)}
|
|
150
|
+
/>
|
|
151
|
+
</div>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
if (placement === 'hidden') {
|
|
155
|
+
return (
|
|
156
|
+
<Checkbox
|
|
157
|
+
id={fieldPath}
|
|
158
|
+
checked={controllerField.value || false}
|
|
159
|
+
onCheckedChange={handleChange}
|
|
160
|
+
disabled={field.disabled}
|
|
161
|
+
className={cn(error && 'border-destructive', field.className)}
|
|
162
|
+
/>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
// inline (default)
|
|
134
166
|
return (
|
|
135
167
|
<div className="flex items-center space-x-2">
|
|
136
168
|
<Checkbox
|
|
@@ -142,9 +174,11 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
|
|
|
142
174
|
/>
|
|
143
175
|
<Label htmlFor={fieldPath} className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
|
|
144
176
|
{field.label}
|
|
177
|
+
{field.required && <span className="text-destructive ml-1">*</span>}
|
|
145
178
|
</Label>
|
|
146
179
|
</div>
|
|
147
180
|
);
|
|
181
|
+
}
|
|
148
182
|
|
|
149
183
|
case 'radio': {
|
|
150
184
|
const toUiValue = (val: unknown) => (val === null || val === undefined ? NULL_SENTINEL : String(val));
|
|
@@ -213,7 +247,7 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
|
|
|
213
247
|
<CardContent className="space-y-4">
|
|
214
248
|
<div className="grid gap-4 md:grid-cols-2">
|
|
215
249
|
{field.fields.map(subField => (
|
|
216
|
-
<
|
|
250
|
+
<FormBuilderField
|
|
217
251
|
key={subField.name}
|
|
218
252
|
field={subField}
|
|
219
253
|
control={control}
|
|
@@ -306,7 +340,7 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
|
|
|
306
340
|
<CardContent>
|
|
307
341
|
{field.fields && field.fields.length === 1 ? (
|
|
308
342
|
// Single field array
|
|
309
|
-
<
|
|
343
|
+
<FormBuilderField
|
|
310
344
|
field={{
|
|
311
345
|
...field.fields[0],
|
|
312
346
|
name: field.fields[0].name,
|
|
@@ -320,7 +354,7 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
|
|
|
320
354
|
// Object array
|
|
321
355
|
<div className="grid gap-4 md:grid-cols-2">
|
|
322
356
|
{field.fields.map(subField => (
|
|
323
|
-
<
|
|
357
|
+
<FormBuilderField
|
|
324
358
|
key={subField.name}
|
|
325
359
|
field={subField}
|
|
326
360
|
control={control}
|
|
@@ -360,7 +394,7 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
|
|
|
360
394
|
return renderArrayField();
|
|
361
395
|
}
|
|
362
396
|
|
|
363
|
-
// For checkbox,
|
|
397
|
+
// For checkbox, label may be inline/stacked/hidden handled inside renderBasicField
|
|
364
398
|
if (field.type === 'checkbox') {
|
|
365
399
|
return (
|
|
366
400
|
<div className={cn('space-y-2', field.gridCols && `md:col-span-${field.gridCols}`)}>
|
|
@@ -375,6 +409,43 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
|
|
|
375
409
|
);
|
|
376
410
|
}
|
|
377
411
|
|
|
412
|
+
// Non-checkbox fields: support labelPlacement
|
|
413
|
+
const placement = field.labelPlacement ?? 'stacked';
|
|
414
|
+
if (placement === 'hidden') {
|
|
415
|
+
return (
|
|
416
|
+
<div className={cn('space-y-2', field.gridCols && `md:col-span-${field.gridCols}`)}>
|
|
417
|
+
{renderBasicField()}
|
|
418
|
+
{field.description && (
|
|
419
|
+
<p className="text-sm text-muted-foreground">{field.description}</p>
|
|
420
|
+
)}
|
|
421
|
+
{error && (
|
|
422
|
+
<p className="text-sm text-destructive">{error.message}</p>
|
|
423
|
+
)}
|
|
424
|
+
</div>
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (placement === 'inline') {
|
|
429
|
+
return (
|
|
430
|
+
<div className={cn('space-y-1', field.gridCols && `md:col-span-${field.gridCols}`)}>
|
|
431
|
+
<div className="flex items-center gap-2">
|
|
432
|
+
<Label htmlFor={fieldPath} className="text-sm font-medium">
|
|
433
|
+
{field.label}
|
|
434
|
+
{field.required && <span className="text-destructive ml-1">*</span>}
|
|
435
|
+
</Label>
|
|
436
|
+
{renderBasicField()}
|
|
437
|
+
</div>
|
|
438
|
+
{field.description && (
|
|
439
|
+
<p className="text-sm text-muted-foreground">{field.description}</p>
|
|
440
|
+
)}
|
|
441
|
+
{error && (
|
|
442
|
+
<p className="text-sm text-destructive">{error.message}</p>
|
|
443
|
+
)}
|
|
444
|
+
</div>
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// stacked (default)
|
|
378
449
|
return (
|
|
379
450
|
<div className={cn('space-y-2', field.gridCols && `md:col-span-${field.gridCols}`)}>
|
|
380
451
|
<Label htmlFor={fieldPath} className="text-sm font-medium">
|
|
@@ -392,4 +463,4 @@ export function FormField({ field, control, onChange, onFieldChange, parentPath
|
|
|
392
463
|
);
|
|
393
464
|
}
|
|
394
465
|
|
|
395
|
-
export default
|
|
466
|
+
export default FormBuilderField;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { memo } from 'react';
|
|
2
2
|
import { cn } from '../../../shadcn/lib/utils';
|
|
3
|
-
import {
|
|
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
|
-
<
|
|
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
|
-
</
|
|
258
|
+
</SectionContainer>
|
|
202
259
|
);
|
|
203
260
|
}
|
|
204
261
|
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
Circle,
|
|
23
23
|
} from 'lucide-react';
|
|
24
24
|
|
|
25
|
-
import {
|
|
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
|
|
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
|
-
|
|
30
|
-
|
|
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
|
-
|
|
34
|
-
|
|
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
|
-
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
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: (
|
|
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 (
|
|
@@ -4,6 +4,7 @@ import AdminLayout from '../../../../kit/layouts/admin/components/AdminLayout';
|
|
|
4
4
|
import { ThemeProvider } from '../../../../kit/providers/ThemeProvider';
|
|
5
5
|
import { useAdminSidebarMenuRegistration } from '../../../../kit/layouts/admin/hooks/menu';
|
|
6
6
|
import {
|
|
7
|
+
Outlet,
|
|
7
8
|
RouterProvider,
|
|
8
9
|
createRootRoute,
|
|
9
10
|
createRoute,
|
|
@@ -43,6 +44,7 @@ function App(props: AdminLayoutStoryProps) {
|
|
|
43
44
|
<ThemeProvider>
|
|
44
45
|
<AdminLayout {...props}>
|
|
45
46
|
<RegisterMenus />
|
|
47
|
+
<Outlet />
|
|
46
48
|
</AdminLayout>
|
|
47
49
|
</ThemeProvider>
|
|
48
50
|
),
|
|
@@ -4,6 +4,7 @@ import AdminLayout from '../../../../kit/layouts/admin/components/AdminLayout';
|
|
|
4
4
|
import { ThemeProvider } from '../../../../kit/providers/ThemeProvider';
|
|
5
5
|
import { useAdminSidebarMenuRegistration } from '../../../../kit/layouts/admin/hooks/menu';
|
|
6
6
|
import {
|
|
7
|
+
Outlet,
|
|
7
8
|
RouterProvider,
|
|
8
9
|
createRootRoute,
|
|
9
10
|
createRoute,
|
|
@@ -41,6 +42,7 @@ function App(props: AdminLayoutStoryProps) {
|
|
|
41
42
|
<ThemeProvider>
|
|
42
43
|
<AdminLayout {...props}>
|
|
43
44
|
<RegisterMenus />
|
|
45
|
+
<Outlet />
|
|
44
46
|
</AdminLayout>
|
|
45
47
|
</ThemeProvider>
|
|
46
48
|
),
|
|
@@ -4,6 +4,7 @@ import AdminLayout from '../../../../kit/layouts/admin/components/AdminLayout';
|
|
|
4
4
|
import { ThemeProvider } from '../../../../kit/providers/ThemeProvider';
|
|
5
5
|
import { useAdminSidebarMenuRegistration } from '../../../../kit/layouts/admin/hooks/menu';
|
|
6
6
|
import {
|
|
7
|
+
Outlet,
|
|
7
8
|
RouterProvider,
|
|
8
9
|
createRootRoute,
|
|
9
10
|
createRoute,
|
|
@@ -102,6 +103,7 @@ function App(props: AdminLayoutStoryProps) {
|
|
|
102
103
|
<ThemeProvider>
|
|
103
104
|
<AdminLayout {...props}>
|
|
104
105
|
<RegisterComplexMenus />
|
|
106
|
+
<Outlet />
|
|
105
107
|
</AdminLayout>
|
|
106
108
|
</ThemeProvider>
|
|
107
109
|
),
|
|
@@ -4,6 +4,7 @@ import AdminLayout from '../../../../kit/layouts/admin/components/AdminLayout';
|
|
|
4
4
|
import { ThemeProvider } from '../../../../kit/providers/ThemeProvider';
|
|
5
5
|
import { useAdminSidebarMenuRegistration } from '../../../../kit/layouts/admin/hooks/menu';
|
|
6
6
|
import {
|
|
7
|
+
Outlet,
|
|
7
8
|
RouterProvider,
|
|
8
9
|
createRootRoute,
|
|
9
10
|
createRoute,
|
|
@@ -37,6 +38,7 @@ function App(props: AdminLayoutStoryProps) {
|
|
|
37
38
|
<ThemeProvider>
|
|
38
39
|
<AdminLayout {...props}>
|
|
39
40
|
<RegisterMenus />
|
|
41
|
+
<Outlet />
|
|
40
42
|
</AdminLayout>
|
|
41
43
|
</ThemeProvider>
|
|
42
44
|
),
|
|
@@ -4,6 +4,7 @@ import AdminLayout from '../../../../kit/layouts/admin/components/AdminLayout';
|
|
|
4
4
|
import { ThemeProvider } from '../../../../kit/providers/ThemeProvider';
|
|
5
5
|
import { useAdminSidebarMenuRegistration } from '../../../../kit/layouts/admin/hooks/menu';
|
|
6
6
|
import {
|
|
7
|
+
Outlet,
|
|
7
8
|
RouterProvider,
|
|
8
9
|
createRootRoute,
|
|
9
10
|
createRoute,
|
|
@@ -37,6 +38,7 @@ function App(props: AdminLayoutStoryProps) {
|
|
|
37
38
|
<ThemeProvider>
|
|
38
39
|
<AdminLayout {...props}>
|
|
39
40
|
<RegisterMenus />
|
|
41
|
+
<Outlet />
|
|
40
42
|
</AdminLayout>
|
|
41
43
|
</ThemeProvider>
|
|
42
44
|
),
|
|
@@ -4,6 +4,7 @@ import AdminLayout from '../../../../kit/layouts/admin/components/AdminLayout';
|
|
|
4
4
|
import { ThemeProvider } from '../../../../kit/providers/ThemeProvider';
|
|
5
5
|
import { useAdminSidebarMenuRegistration } from '../../../../kit/layouts/admin/hooks/menu';
|
|
6
6
|
import {
|
|
7
|
+
Outlet,
|
|
7
8
|
RouterProvider,
|
|
8
9
|
createRootRoute,
|
|
9
10
|
createRoute,
|
|
@@ -37,6 +38,7 @@ function App(props: AdminLayoutStoryProps) {
|
|
|
37
38
|
<ThemeProvider>
|
|
38
39
|
<AdminLayout {...props}>
|
|
39
40
|
<RegisterMenus />
|
|
41
|
+
<Outlet />
|
|
40
42
|
</AdminLayout>
|
|
41
43
|
</ThemeProvider>
|
|
42
44
|
),
|