@alfakit/react 0.1.2 → 0.1.7

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 (171) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/components/actions/action-modals.js +4 -0
  3. package/dist/components/actions/action-modals.js.map +1 -1
  4. package/dist/components/ai/copilot.d.ts +3 -1
  5. package/dist/components/ai/copilot.d.ts.map +1 -1
  6. package/dist/components/ai/copilot.js +4 -1
  7. package/dist/components/ai/copilot.js.map +1 -1
  8. package/dist/components/cms/live-preview.js +3 -2
  9. package/dist/components/cms/live-preview.js.map +1 -1
  10. package/dist/components/cms/page.js +1 -1
  11. package/dist/components/fields/builder.js +15 -6
  12. package/dist/components/fields/builder.js.map +1 -1
  13. package/dist/components/fields/image-editor-dialog.js +4 -2
  14. package/dist/components/fields/image-editor-dialog.js.map +1 -1
  15. package/dist/components/fields/item-actions.js +10 -10
  16. package/dist/components/fields/item-actions.js.map +1 -1
  17. package/dist/components/fields/key-value.d.ts.map +1 -1
  18. package/dist/components/fields/key-value.js +3 -3
  19. package/dist/components/fields/key-value.js.map +1 -1
  20. package/dist/components/fields/modal-table-select.js +6 -5
  21. package/dist/components/fields/modal-table-select.js.map +1 -1
  22. package/dist/components/fields/repeater.js +2 -2
  23. package/dist/components/fields/repeater.js.map +1 -1
  24. package/dist/components/fields/rich-editor.js +2 -1
  25. package/dist/components/fields/rich-editor.js.map +1 -1
  26. package/dist/components/form/form-block.js +1 -1
  27. package/dist/components/form/form-block.js.map +1 -1
  28. package/dist/components/form/form-context.js +2 -2
  29. package/dist/components/form/form-context.js.map +1 -1
  30. package/dist/components/kanban/kanban.js +4 -3
  31. package/dist/components/kanban/kanban.js.map +1 -1
  32. package/dist/components/layout/section.js +2 -2
  33. package/dist/components/layout/section.js.map +1 -1
  34. package/dist/components/panel/app-sidebar.d.ts +2 -3
  35. package/dist/components/panel/app-sidebar.d.ts.map +1 -1
  36. package/dist/components/panel/app-sidebar.js +1 -24
  37. package/dist/components/panel/app-sidebar.js.map +1 -1
  38. package/dist/components/panel/brand.d.ts +10 -0
  39. package/dist/components/panel/brand.d.ts.map +1 -0
  40. package/dist/components/panel/brand.js +37 -0
  41. package/dist/components/panel/brand.js.map +1 -0
  42. package/dist/components/panel/index.d.ts +2 -1
  43. package/dist/components/panel/topbar.js +1 -1
  44. package/dist/components/realtime/live-records-pill.d.ts.map +1 -1
  45. package/dist/components/realtime/live-records-pill.js +6 -3
  46. package/dist/components/realtime/live-records-pill.js.map +1 -1
  47. package/dist/components/table/cells.d.ts +6 -0
  48. package/dist/components/table/cells.d.ts.map +1 -1
  49. package/dist/components/table/cells.js +6 -2
  50. package/dist/components/table/cells.js.map +1 -1
  51. package/dist/components/table/column-manager.js +8 -7
  52. package/dist/components/table/column-manager.js.map +1 -1
  53. package/dist/components/table/content-layout.js +2 -1
  54. package/dist/components/table/content-layout.js.map +1 -1
  55. package/dist/components/table/pagination.js +16 -13
  56. package/dist/components/table/pagination.js.map +1 -1
  57. package/dist/components/table/table-block.js +14 -4
  58. package/dist/components/table/table-block.js.map +1 -1
  59. package/dist/components/ui/dialog.d.ts.map +1 -1
  60. package/dist/components/ui/dialog.js +3 -1
  61. package/dist/components/ui/dialog.js.map +1 -1
  62. package/dist/components/ui/popover.d.ts.map +1 -1
  63. package/dist/components/ui/popover.js +3 -1
  64. package/dist/components/ui/popover.js.map +1 -1
  65. package/dist/components/ui/sheet.d.ts.map +1 -1
  66. package/dist/components/ui/sheet.js +3 -1
  67. package/dist/components/ui/sheet.js.map +1 -1
  68. package/dist/components/ui/tooltip.js +3 -1
  69. package/dist/components/ui/tooltip.js.map +1 -1
  70. package/dist/context.d.ts +5 -0
  71. package/dist/context.d.ts.map +1 -1
  72. package/dist/context.js +5 -1
  73. package/dist/context.js.map +1 -1
  74. package/dist/create-alfakit.d.ts.map +1 -1
  75. package/dist/create-alfakit.js +8 -5
  76. package/dist/create-alfakit.js.map +1 -1
  77. package/dist/eject-manifest.json +16 -3
  78. package/dist/index.d.ts +6 -3
  79. package/dist/index.js +24 -21
  80. package/dist/layouts/app-layout.d.ts.map +1 -1
  81. package/dist/layouts/app-layout.js +2 -29
  82. package/dist/layouts/app-layout.js.map +1 -1
  83. package/dist/layouts/auth-layout.js +2 -2
  84. package/dist/layouts/auth-layout.js.map +1 -1
  85. package/dist/layouts/fullscreen-layout.js +1 -1
  86. package/dist/layouts/fullscreen-layout.js.map +1 -1
  87. package/dist/layouts/lazy-layouts.js +15 -0
  88. package/dist/layouts/lazy-layouts.js.map +1 -0
  89. package/dist/layouts/max-widths.js +34 -0
  90. package/dist/layouts/max-widths.js.map +1 -0
  91. package/dist/layouts/panel-layouts.d.ts +10 -0
  92. package/dist/layouts/panel-layouts.d.ts.map +1 -0
  93. package/dist/layouts/panel-layouts.js +20 -0
  94. package/dist/layouts/panel-layouts.js.map +1 -0
  95. package/dist/layouts/top-nav-layout.js +2 -2
  96. package/dist/layouts/top-nav-layout.js.map +1 -1
  97. package/dist/pages/page.d.ts.map +1 -1
  98. package/dist/pages/page.js +12 -7
  99. package/dist/pages/page.js.map +1 -1
  100. package/dist/standalone/alfakit-component.js +11 -6
  101. package/dist/standalone/alfakit-component.js.map +1 -1
  102. package/dist/standalone.css +7 -0
  103. package/dist/starter-kit/dashboard-widgets.d.ts +33 -0
  104. package/dist/starter-kit/dashboard-widgets.d.ts.map +1 -0
  105. package/dist/starter-kit/dashboard-widgets.js +53 -0
  106. package/dist/starter-kit/dashboard-widgets.js.map +1 -0
  107. package/dist/starter-kit/impersonation-banner.js +34 -0
  108. package/dist/starter-kit/impersonation-banner.js.map +1 -0
  109. package/dist/starter-kit/index.d.ts +3 -2
  110. package/dist/starter-kit/index.js +3 -2
  111. package/dist/starter-kit/starter-kit.d.ts +6 -0
  112. package/dist/starter-kit/starter-kit.d.ts.map +1 -1
  113. package/dist/starter-kit/starter-kit.js +18 -7
  114. package/dist/starter-kit/starter-kit.js.map +1 -1
  115. package/dist/starter-kit/widgets-loaded.js +20 -4
  116. package/dist/starter-kit/widgets-loaded.js.map +1 -1
  117. package/dist/starter-kit/widgets-triggers.js +34 -3
  118. package/dist/starter-kit/widgets-triggers.js.map +1 -1
  119. package/dist/starter-kit/widgets.d.ts +13 -5
  120. package/dist/starter-kit/widgets.d.ts.map +1 -1
  121. package/dist/starter-kit/widgets.js +56 -18
  122. package/dist/starter-kit/widgets.js.map +1 -1
  123. package/dist/styles.css +15 -2
  124. package/dist/themes.css +6 -1
  125. package/package.json +2 -2
  126. package/src/components/actions/action-modals.tsx +10 -0
  127. package/src/components/ai/copilot.tsx +14 -1
  128. package/src/components/cms/live-preview.tsx +5 -2
  129. package/src/components/fields/builder.tsx +14 -5
  130. package/src/components/fields/image-editor-dialog.tsx +7 -2
  131. package/src/components/fields/item-actions.tsx +32 -9
  132. package/src/components/fields/key-value.tsx +3 -2
  133. package/src/components/fields/modal-table-select.tsx +8 -3
  134. package/src/components/fields/repeater.tsx +2 -3
  135. package/src/components/fields/rich-editor.tsx +3 -0
  136. package/src/components/form/form-block.tsx +2 -1
  137. package/src/components/form/form-context.tsx +2 -2
  138. package/src/components/kanban/kanban.tsx +16 -3
  139. package/src/components/layout/section.tsx +2 -2
  140. package/src/components/panel/app-sidebar.tsx +2 -38
  141. package/src/components/panel/brand.tsx +46 -0
  142. package/src/components/realtime/live-records-pill.tsx +4 -3
  143. package/src/components/table/cells.tsx +9 -2
  144. package/src/components/table/column-manager.tsx +12 -10
  145. package/src/components/table/content-layout.tsx +5 -1
  146. package/src/components/table/pagination.tsx +16 -9
  147. package/src/components/table/table-block.tsx +25 -12
  148. package/src/components/ui/dialog.tsx +5 -1
  149. package/src/components/ui/popover.tsx +5 -1
  150. package/src/components/ui/sheet.tsx +5 -1
  151. package/src/components/ui/tooltip.tsx +5 -1
  152. package/src/context.tsx +10 -0
  153. package/src/create-alfakit.tsx +11 -2
  154. package/src/index.ts +2 -0
  155. package/src/layouts/app-layout.tsx +4 -28
  156. package/src/layouts/auth-layout.tsx +2 -2
  157. package/src/layouts/fullscreen-layout.tsx +1 -1
  158. package/src/layouts/lazy-layouts.ts +14 -0
  159. package/src/layouts/max-widths.ts +29 -0
  160. package/src/layouts/panel-layouts.ts +17 -0
  161. package/src/layouts/top-nav-layout.tsx +2 -2
  162. package/src/pages/page.tsx +21 -12
  163. package/src/standalone/alfakit-component.tsx +18 -7
  164. package/src/starter-kit/dashboard-widgets.tsx +78 -0
  165. package/src/starter-kit/impersonation-banner.tsx +48 -0
  166. package/src/starter-kit/index.ts +2 -0
  167. package/src/starter-kit/starter-kit.tsx +31 -4
  168. package/src/starter-kit/widgets-loaded.tsx +22 -0
  169. package/src/starter-kit/widgets-triggers.tsx +36 -1
  170. package/src/starter-kit/widgets.tsx +95 -20
  171. package/src/styles.css +15 -2
@@ -1 +1 @@
1
- {"version":3,"file":"app-layout.js","names":[],"sources":["../../src/layouts/app-layout.tsx"],"sourcesContent":["import {\n hasMobilePreset,\n hasTopbar,\n sidebarDefaultOpen,\n sidebarWidthStyle,\n type BreadcrumbSchema,\n type Width,\n} from '@alfakit/core'\nimport { createElement, type CSSProperties, type ReactNode } from 'react'\nimport { AppSidebar } from '../components/panel/app-sidebar'\nimport { BottomNav } from '../components/panel/bottom-nav'\nimport { TopbarLocaleSwitcher } from '../components/panel/locale-switcher'\nimport { Slot } from '../components/panel/slot'\nimport { Topbar } from '../components/panel/topbar'\nimport { SidebarInset, SidebarProvider, SidebarTrigger } from '../components/ui/sidebar'\nimport { useAlfakitProps, useRegistry } from '../context'\nimport { cn } from '../lib/utils'\nimport { TopNavLayout } from './top-nav-layout'\n\nexport const MAX_WIDTHS: Record<string, string> = {\n '3xs': 'max-w-3xs',\n '2xs': 'max-w-2xs',\n xs: 'max-w-xs',\n sm: 'max-w-sm',\n md: 'max-w-md',\n lg: 'max-w-lg',\n xl: 'max-w-xl',\n '2xl': 'max-w-2xl',\n '3xl': 'max-w-3xl',\n '4xl': 'max-w-4xl',\n '5xl': 'max-w-5xl',\n '6xl': 'max-w-6xl',\n '7xl': 'max-w-7xl',\n none: 'max-w-none',\n min: 'max-w-min',\n max: 'max-w-max',\n fit: 'max-w-fit',\n prose: 'max-w-prose',\n container: 'container',\n 'screen-sm': 'max-w-(--breakpoint-sm)',\n 'screen-md': 'max-w-(--breakpoint-md)',\n 'screen-lg': 'max-w-(--breakpoint-lg)',\n 'screen-xl': 'max-w-(--breakpoint-xl)',\n 'screen-2xl': 'max-w-(--breakpoint-2xl)',\n full: 'max-w-full',\n screen: 'max-w-screen',\n}\n\nexport interface AppLayoutProps {\n children: ReactNode\n breadcrumbs?: BreadcrumbSchema[]\n maxContentWidth?: Width | string\n}\n\n/** Sidebar + topbar shell used by every authenticated page. */\n/**\n * Stands in for the top bar on phones when the panel has `topbar(false)`: the sidebar\n * toggle has to stay reachable.\n */\nexport function MobileTopbar() {\n return (\n <header\n data-slot=\"topbar\"\n data-variant=\"mobile\"\n className=\"bg-background/80 sticky top-0 z-20 flex h-12 shrink-0 items-center gap-2 border-b px-4 backdrop-blur md:hidden\"\n >\n <SidebarTrigger className=\"-ms-1\" />\n <div className=\"ms-auto flex items-center gap-1\">\n <TopbarLocaleSwitcher />\n </div>\n </header>\n )\n}\n\nexport function AppLayout({ children, breadcrumbs, maxContentWidth }: AppLayoutProps) {\n const props = useAlfakitProps()\n const registry = useRegistry()\n const layout = props.alfakit.theme?.design?.layout ?? 'sidebar'\n // Replace the sidebar or top bar everywhere with createAlfakit({ components: { 'panel:sidebar': … } }).\n const Sidebar = registry.resolve('panel:sidebar') ?? AppSidebar\n const Bar = registry.resolve('panel:topbar') ?? Topbar\n // The mobile preset's bottom bar (`Panel::mobile()`), hidden from `md` up.\n const Bottom = registry.resolve('panel:bottom-nav') ?? BottomNav\n const width = maxContentWidth ?? props.alfakit.maxContentWidth ?? '7xl'\n\n if (layout === 'topbar') {\n return (\n <TopNavLayout breadcrumbs={breadcrumbs} maxContentWidth={maxContentWidth}>\n {children}\n </TopNavLayout>\n )\n }\n\n return (\n // The rail layout starts as icons only until the user expands it.\n <SidebarProvider\n defaultOpen={sidebarDefaultOpen(props.alfakitSidebarOpen, layout)}\n style={sidebarWidthStyle(props.alfakit) as CSSProperties | undefined}\n >\n <Slot name=\"body.start\" />\n <Slot name=\"layout.start\" />\n {createElement(Sidebar)}\n <SidebarInset>\n <Slot name=\"topbar.before\" />\n {/* `topbar(false)`: no top bar, except a slim one with the sidebar toggle on phones. */}\n {hasTopbar(props.alfakit) ? createElement(Bar, { breadcrumbs }) : <MobileTopbar />}\n <Slot name=\"topbar.after\" />\n <Slot name=\"content.before\" />\n <div\n data-slot=\"content\"\n className={cn(\n 'mx-auto flex w-full min-w-0 flex-1 flex-col gap-6 p-4 md:p-6',\n MAX_WIDTHS[width] ?? 'max-w-7xl',\n )}\n >\n <Slot name=\"content.start\" />\n {children}\n <Slot name=\"content.end\" />\n </div>\n <Slot name=\"content.after\" />\n <Slot name=\"footer\" />\n </SidebarInset>\n {hasMobilePreset(props.alfakit) && createElement(Bottom)}\n <Slot name=\"layout.end\" />\n <Slot name=\"body.end\" />\n </SidebarProvider>\n )\n}\n"],"mappings":";;;;;;;;;;;;;AAmBA,MAAa,aAAqC;CAChD,OAAO;CACP,OAAO;CACP,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;CACP,MAAM;CACN,KAAK;CACL,KAAK;CACL,KAAK;CACL,OAAO;CACP,WAAW;CACX,aAAa;CACb,aAAa;CACb,aAAa;CACb,aAAa;CACb,cAAc;CACd,MAAM;CACN,QAAQ;AACV;;;;;;AAaA,SAAgB,eAAe;CAC7B,OACE,qBAAC,UAAD;EACE,aAAU;EACV,gBAAa;EACb,WAAU;EAHZ,UAAA,CAKE,oBAAC,gBAAD,EAAgB,WAAU,QAAS,CAAA,GACnC,oBAAC,OAAD;GAAK,WAAU;GACb,UAAA,oBAAC,sBAAD,CAAuB,CAAA;EACpB,CAAA,CACC;;AAEZ;AAEA,SAAgB,UAAU,EAAE,UAAU,aAAa,mBAAmC;CACpF,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,WAAW,YAAY;CAC7B,MAAM,SAAS,MAAM,QAAQ,OAAO,QAAQ,UAAU;CAEtD,MAAM,UAAU,SAAS,QAAQ,eAAe,KAAK;CACrD,MAAM,MAAM,SAAS,QAAQ,cAAc,KAAK;CAEhD,MAAM,SAAS,SAAS,QAAQ,kBAAkB,KAAK;CACvD,MAAM,QAAQ,mBAAmB,MAAM,QAAQ,mBAAmB;CAElE,IAAI,WAAW,UACb,OACE,oBAAC,cAAD;EAA2B;EAA8B;EACtD;CACW,CAAA;CAIlB,OAEE,qBAAC,iBAAD;EACE,aAAa,mBAAmB,MAAM,oBAAoB,MAAM;EAChE,OAAO,kBAAkB,MAAM,OAAO;EAFxC,UAAA;GAIE,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;GACzB,oBAAC,MAAD,EAAM,MAAK,eAAgB,CAAA;GAC1B,cAAc,OAAO;GACtB,qBAAC,cAAD,EAAA,UAAA;IACE,oBAAC,MAAD,EAAM,MAAK,gBAAiB,CAAA;IAE3B,UAAU,MAAM,OAAO,IAAI,cAAc,KAAK,EAAE,YAAY,CAAC,IAAI,oBAAC,cAAD,CAAe,CAAA;IACjF,oBAAC,MAAD,EAAM,MAAK,eAAgB,CAAA;IAC3B,oBAAC,MAAD,EAAM,MAAK,iBAAkB,CAAA;IAC7B,qBAAC,OAAD;KACE,aAAU;KACV,WAAW,GACT,gEACA,WAAW,UAAU,WACvB;KALF,UAAA;MAOE,oBAAC,MAAD,EAAM,MAAK,gBAAiB,CAAA;MAC3B;MACD,oBAAC,MAAD,EAAM,MAAK,cAAe,CAAA;KACvB;;IACL,oBAAC,MAAD,EAAM,MAAK,gBAAiB,CAAA;IAC5B,oBAAC,MAAD,EAAM,MAAK,SAAU,CAAA;GACT,EAAA,CAAA;GACb,gBAAgB,MAAM,OAAO,KAAK,cAAc,MAAM;GACvD,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;GACzB,oBAAC,MAAD,EAAM,MAAK,WAAY,CAAA;EACR;;AAErB"}
1
+ {"version":3,"file":"app-layout.js","names":[],"sources":["../../src/layouts/app-layout.tsx"],"sourcesContent":["import {\n hasMobilePreset,\n hasTopbar,\n sidebarDefaultOpen,\n sidebarWidthStyle,\n type BreadcrumbSchema,\n type Width,\n} from '@alfakit/core'\nimport { createElement, type CSSProperties, type ReactNode } from 'react'\nimport { AppSidebar } from '../components/panel/app-sidebar'\nimport { BottomNav } from '../components/panel/bottom-nav'\nimport { TopbarLocaleSwitcher } from '../components/panel/locale-switcher'\nimport { Slot } from '../components/panel/slot'\nimport { Topbar } from '../components/panel/topbar'\nimport { SidebarInset, SidebarProvider, SidebarTrigger } from '../components/ui/sidebar'\nimport { useAlfakitProps, useRegistry } from '../context'\nimport { cn } from '../lib/utils'\nimport { MAX_WIDTHS } from './max-widths'\nimport { TopNavLayout } from './top-nav-layout'\n\n// Re-exported for code that imported it from here; the map lives in `./max-widths` so the\n// starter kit's content layout doesn't pull the panel chrome in.\nexport { MAX_WIDTHS } from './max-widths'\n\nexport interface AppLayoutProps {\n children: ReactNode\n breadcrumbs?: BreadcrumbSchema[]\n maxContentWidth?: Width | string\n}\n\n/** Sidebar + topbar shell used by every authenticated page. */\n/**\n * Stands in for the top bar on phones when the panel has `topbar(false)`: the sidebar\n * toggle has to stay reachable.\n */\nexport function MobileTopbar() {\n return (\n <header\n data-slot=\"topbar\"\n data-variant=\"mobile\"\n className=\"bg-background/80 sticky top-0 z-20 flex h-12 shrink-0 items-center gap-2 border-b px-4 backdrop-blur md:hidden\"\n >\n <SidebarTrigger className=\"-ms-1\" />\n <div className=\"ms-auto flex items-center gap-1\">\n <TopbarLocaleSwitcher />\n </div>\n </header>\n )\n}\n\nexport function AppLayout({ children, breadcrumbs, maxContentWidth }: AppLayoutProps) {\n const props = useAlfakitProps()\n const registry = useRegistry()\n const layout = props.alfakit.theme?.design?.layout ?? 'sidebar'\n // Replace the sidebar or top bar everywhere with createAlfakit({ components: { 'panel:sidebar': … } }).\n const Sidebar = registry.resolve('panel:sidebar') ?? AppSidebar\n const Bar = registry.resolve('panel:topbar') ?? Topbar\n // The mobile preset's bottom bar (`Panel::mobile()`), hidden from `md` up.\n const Bottom = registry.resolve('panel:bottom-nav') ?? BottomNav\n const width = maxContentWidth ?? props.alfakit.maxContentWidth ?? '7xl'\n\n if (layout === 'topbar') {\n return (\n <TopNavLayout breadcrumbs={breadcrumbs} maxContentWidth={maxContentWidth}>\n {children}\n </TopNavLayout>\n )\n }\n\n return (\n // The rail layout starts as icons only until the user expands it.\n <SidebarProvider\n defaultOpen={sidebarDefaultOpen(props.alfakitSidebarOpen, layout)}\n style={sidebarWidthStyle(props.alfakit) as CSSProperties | undefined}\n >\n <Slot name=\"body.start\" />\n <Slot name=\"layout.start\" />\n {createElement(Sidebar)}\n <SidebarInset>\n <Slot name=\"topbar.before\" />\n {/* `topbar(false)`: no top bar, except a slim one with the sidebar toggle on phones. */}\n {hasTopbar(props.alfakit) ? createElement(Bar, { breadcrumbs }) : <MobileTopbar />}\n <Slot name=\"topbar.after\" />\n <Slot name=\"content.before\" />\n <div\n data-slot=\"content\"\n className={cn(\n 'mx-auto flex w-full min-w-0 flex-1 flex-col gap-6 p-4 md:p-6',\n MAX_WIDTHS[width] ?? 'max-w-7xl',\n )}\n >\n <Slot name=\"content.start\" />\n {children}\n <Slot name=\"content.end\" />\n </div>\n <Slot name=\"content.after\" />\n <Slot name=\"footer\" />\n </SidebarInset>\n {hasMobilePreset(props.alfakit) && createElement(Bottom)}\n <Slot name=\"layout.end\" />\n <Slot name=\"body.end\" />\n </SidebarProvider>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,eAAe;CAC7B,OACE,qBAAC,UAAD;EACE,aAAU;EACV,gBAAa;EACb,WAAU;EAHZ,UAAA,CAKE,oBAAC,gBAAD,EAAgB,WAAU,QAAS,CAAA,GACnC,oBAAC,OAAD;GAAK,WAAU;GACb,UAAA,oBAAC,sBAAD,CAAuB,CAAA;EACpB,CAAA,CACC;;AAEZ;AAEA,SAAgB,UAAU,EAAE,UAAU,aAAa,mBAAmC;CACpF,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,WAAW,YAAY;CAC7B,MAAM,SAAS,MAAM,QAAQ,OAAO,QAAQ,UAAU;CAEtD,MAAM,UAAU,SAAS,QAAQ,eAAe,KAAK;CACrD,MAAM,MAAM,SAAS,QAAQ,cAAc,KAAK;CAEhD,MAAM,SAAS,SAAS,QAAQ,kBAAkB,KAAK;CACvD,MAAM,QAAQ,mBAAmB,MAAM,QAAQ,mBAAmB;CAElE,IAAI,WAAW,UACb,OACE,oBAAC,cAAD;EAA2B;EAA8B;EACtD;CACW,CAAA;CAIlB,OAEE,qBAAC,iBAAD;EACE,aAAa,mBAAmB,MAAM,oBAAoB,MAAM;EAChE,OAAO,kBAAkB,MAAM,OAAO;EAFxC,UAAA;GAIE,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;GACzB,oBAAC,MAAD,EAAM,MAAK,eAAgB,CAAA;GAC1B,cAAc,OAAO;GACtB,qBAAC,cAAD,EAAA,UAAA;IACE,oBAAC,MAAD,EAAM,MAAK,gBAAiB,CAAA;IAE3B,UAAU,MAAM,OAAO,IAAI,cAAc,KAAK,EAAE,YAAY,CAAC,IAAI,oBAAC,cAAD,CAAe,CAAA;IACjF,oBAAC,MAAD,EAAM,MAAK,eAAgB,CAAA;IAC3B,oBAAC,MAAD,EAAM,MAAK,iBAAkB,CAAA;IAC7B,qBAAC,OAAD;KACE,aAAU;KACV,WAAW,GACT,gEACA,WAAW,UAAU,WACvB;KALF,UAAA;MAOE,oBAAC,MAAD,EAAM,MAAK,gBAAiB,CAAA;MAC3B;MACD,oBAAC,MAAD,EAAM,MAAK,cAAe,CAAA;KACvB;;IACL,oBAAC,MAAD,EAAM,MAAK,gBAAiB,CAAA;IAC5B,oBAAC,MAAD,EAAM,MAAK,SAAU,CAAA;GACT,EAAA,CAAA;GACb,gBAAgB,MAAM,OAAO,KAAK,cAAc,MAAM;GACvD,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;GACzB,oBAAC,MAAD,EAAM,MAAK,WAAY,CAAA;EACR;;AAErB"}
@@ -2,10 +2,10 @@ import { usePanel } from "../context.js";
2
2
  import { cn } from "../lib/utils.js";
3
3
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../components/ui/card.js";
4
4
  import { Slot } from "../components/panel/slot.js";
5
+ import { Brand } from "../components/panel/brand.js";
5
6
  import { LocaleSwitcher } from "../components/panel/locale-switcher.js";
6
- import { Brand } from "../components/panel/app-sidebar.js";
7
7
  import { ThemeToggle } from "../components/panel/theme-toggle.js";
8
- import { MAX_WIDTHS } from "./app-layout.js";
8
+ import { MAX_WIDTHS } from "./max-widths.js";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
10
  //#region src/layouts/auth-layout.tsx
11
11
  /** Centered card used by login, registration, password reset and simple profile pages. */
@@ -1 +1 @@
1
- {"version":3,"file":"auth-layout.js","names":[],"sources":["../../src/layouts/auth-layout.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport { Brand } from '../components/panel/app-sidebar'\nimport { LocaleSwitcher } from '../components/panel/locale-switcher'\nimport { Slot } from '../components/panel/slot'\nimport { ThemeToggle } from '../components/panel/theme-toggle'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../components/ui/card'\nimport { usePanel } from '../context'\nimport { cn } from '../lib/utils'\nimport { MAX_WIDTHS } from './app-layout'\n\nexport interface AuthLayoutProps {\n children: ReactNode\n heading?: string\n subheading?: string\n}\n\n/** Centered card used by login, registration, password reset and simple profile pages. */\nexport function AuthLayout({ children, heading, subheading }: AuthLayoutProps) {\n // `simplePageMaxContentWidth()` on the panel; `md` by default.\n const width = usePanel()?.simplePageMaxContentWidth ?? 'md'\n\n return (\n <div className=\"bg-muted/40 flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10\">\n <Slot name=\"simple.layout.start\" />\n <div className=\"absolute end-4 top-4 flex items-center gap-1\">\n <LocaleSwitcher />\n <ThemeToggle />\n </div>\n <div className={cn('flex w-full flex-col gap-6', MAX_WIDTHS[width] ?? 'max-w-md')}>\n <div className=\"flex justify-center\">\n <Brand />\n </div>\n <Slot name=\"auth.before\" />\n <Card>\n <Slot name=\"simple.page.start\" />\n {(heading || subheading) && (\n <CardHeader className=\"text-center\">\n {heading && (\n <CardTitle role=\"heading\" aria-level={1} className=\"text-xl\">\n {heading}\n </CardTitle>\n )}\n {subheading && <CardDescription>{subheading}</CardDescription>}\n </CardHeader>\n )}\n <CardContent>\n {/* The server sends each form's slots on its own page only (Slot::pageTypes()). */}\n <Slot name=\"auth.login.form.before\" />\n <Slot name=\"auth.register.form.before\" />\n <Slot name=\"auth.password-reset.request.form.before\" />\n <Slot name=\"auth.password-reset.reset.form.before\" />\n {children}\n <Slot name=\"auth.login.form.after\" />\n <Slot name=\"auth.register.form.after\" />\n <Slot name=\"auth.password-reset.request.form.after\" />\n <Slot name=\"auth.password-reset.reset.form.after\" />\n </CardContent>\n <Slot name=\"simple.page.end\" />\n </Card>\n <Slot name=\"auth.after\" />\n <Slot name=\"footer\" />\n </div>\n <Slot name=\"simple.layout.end\" />\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;AAiBA,SAAgB,WAAW,EAAE,UAAU,SAAS,cAA+B;CAE7E,MAAM,QAAQ,SAAS,CAAC,EAAE,6BAA6B;CAEvD,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,oBAAC,MAAD,EAAM,MAAK,sBAAuB,CAAA;GAClC,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,gBAAD,CAAiB,CAAA,GACjB,oBAAC,aAAD,CAAc,CAAA,CACX;;GACL,qBAAC,OAAD;IAAK,WAAW,GAAG,8BAA8B,WAAW,UAAU,UAAU;IAAhF,UAAA;KACE,oBAAC,OAAD;MAAK,WAAU;MACb,UAAA,oBAAC,OAAD,CAAQ,CAAA;KACL,CAAA;KACL,oBAAC,MAAD,EAAM,MAAK,cAAe,CAAA;KAC1B,qBAAC,MAAD,EAAA,UAAA;MACE,oBAAC,MAAD,EAAM,MAAK,oBAAqB,CAAA;OAC9B,WAAW,eACX,qBAAC,YAAD;OAAY,WAAU;OAAtB,UAAA,CACG,WACC,oBAAC,WAAD;QAAW,MAAK;QAAU,cAAY;QAAG,WAAU;QAChD,UAAA;OACQ,CAAA,GAEZ,cAAc,oBAAC,iBAAD,EAAA,UAAkB,WAA4B,CAAA,CACnD;;MAEd,qBAAC,aAAD,EAAA,UAAA;OAEE,oBAAC,MAAD,EAAM,MAAK,yBAA0B,CAAA;OACrC,oBAAC,MAAD,EAAM,MAAK,4BAA6B,CAAA;OACxC,oBAAC,MAAD,EAAM,MAAK,0CAA2C,CAAA;OACtD,oBAAC,MAAD,EAAM,MAAK,wCAAyC,CAAA;OACnD;OACD,oBAAC,MAAD,EAAM,MAAK,wBAAyB,CAAA;OACpC,oBAAC,MAAD,EAAM,MAAK,2BAA4B,CAAA;OACvC,oBAAC,MAAD,EAAM,MAAK,yCAA0C,CAAA;OACrD,oBAAC,MAAD,EAAM,MAAK,uCAAwC,CAAA;MACxC,EAAA,CAAA;MACb,oBAAC,MAAD,EAAM,MAAK,kBAAmB,CAAA;KAC1B,EAAA,CAAA;KACN,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;KACzB,oBAAC,MAAD,EAAM,MAAK,SAAU,CAAA;IAClB;;GACL,oBAAC,MAAD,EAAM,MAAK,oBAAqB,CAAA;EAC7B;;AAET"}
1
+ {"version":3,"file":"auth-layout.js","names":[],"sources":["../../src/layouts/auth-layout.tsx"],"sourcesContent":["import type { ReactNode } from 'react'\nimport { Brand } from '../components/panel/brand'\nimport { LocaleSwitcher } from '../components/panel/locale-switcher'\nimport { Slot } from '../components/panel/slot'\nimport { ThemeToggle } from '../components/panel/theme-toggle'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../components/ui/card'\nimport { usePanel } from '../context'\nimport { cn } from '../lib/utils'\nimport { MAX_WIDTHS } from './max-widths'\n\nexport interface AuthLayoutProps {\n children: ReactNode\n heading?: string\n subheading?: string\n}\n\n/** Centered card used by login, registration, password reset and simple profile pages. */\nexport function AuthLayout({ children, heading, subheading }: AuthLayoutProps) {\n // `simplePageMaxContentWidth()` on the panel; `md` by default.\n const width = usePanel()?.simplePageMaxContentWidth ?? 'md'\n\n return (\n <div className=\"bg-muted/40 flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10\">\n <Slot name=\"simple.layout.start\" />\n <div className=\"absolute end-4 top-4 flex items-center gap-1\">\n <LocaleSwitcher />\n <ThemeToggle />\n </div>\n <div className={cn('flex w-full flex-col gap-6', MAX_WIDTHS[width] ?? 'max-w-md')}>\n <div className=\"flex justify-center\">\n <Brand />\n </div>\n <Slot name=\"auth.before\" />\n <Card>\n <Slot name=\"simple.page.start\" />\n {(heading || subheading) && (\n <CardHeader className=\"text-center\">\n {heading && (\n <CardTitle role=\"heading\" aria-level={1} className=\"text-xl\">\n {heading}\n </CardTitle>\n )}\n {subheading && <CardDescription>{subheading}</CardDescription>}\n </CardHeader>\n )}\n <CardContent>\n {/* The server sends each form's slots on its own page only (Slot::pageTypes()). */}\n <Slot name=\"auth.login.form.before\" />\n <Slot name=\"auth.register.form.before\" />\n <Slot name=\"auth.password-reset.request.form.before\" />\n <Slot name=\"auth.password-reset.reset.form.before\" />\n {children}\n <Slot name=\"auth.login.form.after\" />\n <Slot name=\"auth.register.form.after\" />\n <Slot name=\"auth.password-reset.request.form.after\" />\n <Slot name=\"auth.password-reset.reset.form.after\" />\n </CardContent>\n <Slot name=\"simple.page.end\" />\n </Card>\n <Slot name=\"auth.after\" />\n <Slot name=\"footer\" />\n </div>\n <Slot name=\"simple.layout.end\" />\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;AAiBA,SAAgB,WAAW,EAAE,UAAU,SAAS,cAA+B;CAE7E,MAAM,QAAQ,SAAS,CAAC,EAAE,6BAA6B;CAEvD,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,oBAAC,MAAD,EAAM,MAAK,sBAAuB,CAAA;GAClC,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,gBAAD,CAAiB,CAAA,GACjB,oBAAC,aAAD,CAAc,CAAA,CACX;;GACL,qBAAC,OAAD;IAAK,WAAW,GAAG,8BAA8B,WAAW,UAAU,UAAU;IAAhF,UAAA;KACE,oBAAC,OAAD;MAAK,WAAU;MACb,UAAA,oBAAC,OAAD,CAAQ,CAAA;KACL,CAAA;KACL,oBAAC,MAAD,EAAM,MAAK,cAAe,CAAA;KAC1B,qBAAC,MAAD,EAAA,UAAA;MACE,oBAAC,MAAD,EAAM,MAAK,oBAAqB,CAAA;OAC9B,WAAW,eACX,qBAAC,YAAD;OAAY,WAAU;OAAtB,UAAA,CACG,WACC,oBAAC,WAAD;QAAW,MAAK;QAAU,cAAY;QAAG,WAAU;QAChD,UAAA;OACQ,CAAA,GAEZ,cAAc,oBAAC,iBAAD,EAAA,UAAkB,WAA4B,CAAA,CACnD;;MAEd,qBAAC,aAAD,EAAA,UAAA;OAEE,oBAAC,MAAD,EAAM,MAAK,yBAA0B,CAAA;OACrC,oBAAC,MAAD,EAAM,MAAK,4BAA6B,CAAA;OACxC,oBAAC,MAAD,EAAM,MAAK,0CAA2C,CAAA;OACtD,oBAAC,MAAD,EAAM,MAAK,wCAAyC,CAAA;OACnD;OACD,oBAAC,MAAD,EAAM,MAAK,wBAAyB,CAAA;OACpC,oBAAC,MAAD,EAAM,MAAK,2BAA4B,CAAA;OACvC,oBAAC,MAAD,EAAM,MAAK,yCAA0C,CAAA;OACrD,oBAAC,MAAD,EAAM,MAAK,uCAAwC,CAAA;MACxC,EAAA,CAAA;MACb,oBAAC,MAAD,EAAM,MAAK,kBAAmB,CAAA;KAC1B,EAAA,CAAA;KACN,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;KACzB,oBAAC,MAAD,EAAM,MAAK,SAAU,CAAA;IAClB;;GACL,oBAAC,MAAD,EAAM,MAAK,oBAAqB,CAAA;EAC7B;;AAET"}
@@ -4,9 +4,9 @@ import { Button } from "../components/ui/button.js";
4
4
  import { Slot } from "../components/panel/slot.js";
5
5
  import { NotificationsMenu } from "../components/notifications/notifications-menu.js";
6
6
  import { Separator } from "../components/ui/separator.js";
7
+ import { Brand } from "../components/panel/brand.js";
7
8
  import { TopbarLocaleSwitcher } from "../components/panel/locale-switcher.js";
8
9
  import { UserMenu } from "../components/panel/user-menu.js";
9
- import { Brand } from "../components/panel/app-sidebar.js";
10
10
  import { DebugPanelSlot } from "../components/panel/debug-panel-slot.js";
11
11
  import { ThemeToggle } from "../components/panel/theme-toggle.js";
12
12
  import { Link } from "@inertiajs/react";
@@ -1 +1 @@
1
- {"version":3,"file":"fullscreen-layout.js","names":[],"sources":["../../src/layouts/fullscreen-layout.tsx"],"sourcesContent":["import type { PageSchema } from '@alfakit/core'\nimport { Link } from '@inertiajs/react'\nimport { LogOutIcon } from 'lucide-react'\nimport type { ReactNode } from 'react'\nimport { NotificationsMenu } from '../components/notifications/notifications-menu'\nimport { Brand } from '../components/panel/app-sidebar'\nimport { DebugPanelSlot } from '../components/panel/debug-panel-slot'\nimport { TopbarLocaleSwitcher } from '../components/panel/locale-switcher'\nimport { Slot } from '../components/panel/slot'\nimport { ThemeToggle } from '../components/panel/theme-toggle'\nimport { UserMenu } from '../components/panel/user-menu'\nimport { Button } from '../components/ui/button'\nimport { Separator } from '../components/ui/separator'\nimport { useT } from '../context'\nimport { Icon } from '../lib/icons'\n\nexport interface FullscreenLayoutProps {\n children: ReactNode\n page?: PageSchema\n}\n\n/**\n * `$layout = 'fullscreen'`: the whole viewport for an app screen (point of sale, kiosk,\n * board). No sidebar or topbar; an optional slim header keeps the brand, the page title,\n * notifications, the user menu and a way back to the panel. Toasts, modals and the debug\n * panel work as on every other page. Replace it with `components: { 'layout:fullscreen': … }`.\n */\nexport function FullscreenLayout({ children, page }: FullscreenLayoutProps) {\n const t = useT()\n const header = page?.fullscreen?.header !== false\n const exitUrl = page?.fullscreen?.exitUrl\n\n return (\n <div data-layout=\"fullscreen\" className=\"bg-background flex h-svh min-h-0 flex-col\">\n <Slot name=\"body.start\" />\n <Slot name=\"layout.start\" />\n {header ? (\n <header\n data-slot=\"topbar\"\n data-variant=\"fullscreen\"\n className=\"bg-background flex h-12 shrink-0 items-center gap-3 border-b px-3 md:px-4\"\n >\n <Slot name=\"topbar.logo.before\" />\n <Brand className=\"hidden shrink-0 sm:flex\" />\n <Slot name=\"topbar.logo.after\" />\n <Separator orientation=\"vertical\" className=\"hidden h-4 sm:block\" />\n <h1 className=\"min-w-0 truncate text-sm font-semibold\">{page?.heading ?? page?.title}</h1>\n <Slot name=\"topbar.start\" />\n <div className=\"ms-auto flex shrink-0 items-center gap-1\">\n <Slot name=\"topbar.end\" />\n <NotificationsMenu />\n <TopbarLocaleSwitcher />\n <ThemeToggle />\n <DebugPanelSlot />\n <UserMenu variant=\"topbar\" />\n {exitUrl && (\n <Button variant=\"ghost\" size=\"sm\" asChild>\n <Link href={exitUrl} data-slot=\"fullscreen-exit\">\n <Icon\n name=\"alfakit::panels.widgets.account.logout-button\"\n fallback={LogOutIcon}\n className=\"rtl:rotate-180\"\n aria-hidden=\"true\"\n />\n <span className=\"hidden sm:inline\">{t('exit_fullscreen', {}, 'Exit')}</span>\n <span className=\"sr-only sm:hidden\">{t('exit_fullscreen', {}, 'Exit')}</span>\n </Link>\n </Button>\n )}\n </div>\n </header>\n ) : (\n <div className=\"fixed end-3 bottom-3 z-40\">\n <DebugPanelSlot />\n </div>\n )}\n <main data-slot=\"content\" className=\"flex min-h-0 w-full min-w-0 flex-1 flex-col\">\n <Slot name=\"content.start\" />\n {children}\n <Slot name=\"content.end\" />\n </main>\n <Slot name=\"layout.end\" />\n <Slot name=\"body.end\" />\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,iBAAiB,EAAE,UAAU,QAA+B;CAC1E,MAAM,IAAI,KAAK;CACf,MAAM,SAAS,MAAM,YAAY,WAAW;CAC5C,MAAM,UAAU,MAAM,YAAY;CAElC,OACE,qBAAC,OAAD;EAAK,eAAY;EAAa,WAAU;EAAxC,UAAA;GACE,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;GACzB,oBAAC,MAAD,EAAM,MAAK,eAAgB,CAAA;GAC1B,SACC,qBAAC,UAAD;IACE,aAAU;IACV,gBAAa;IACb,WAAU;IAHZ,UAAA;KAKE,oBAAC,MAAD,EAAM,MAAK,qBAAsB,CAAA;KACjC,oBAAC,OAAD,EAAO,WAAU,0BAA2B,CAAA;KAC5C,oBAAC,MAAD,EAAM,MAAK,oBAAqB,CAAA;KAChC,oBAAC,WAAD;MAAW,aAAY;MAAW,WAAU;KAAuB,CAAA;KACnE,oBAAC,MAAD;MAAI,WAAU;MAA0C,UAAA,MAAM,WAAW,MAAM;KAAU,CAAA;KACzF,oBAAC,MAAD,EAAM,MAAK,eAAgB,CAAA;KAC3B,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACE,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;OACzB,oBAAC,mBAAD,CAAoB,CAAA;OACpB,oBAAC,sBAAD,CAAuB,CAAA;OACvB,oBAAC,aAAD,CAAc,CAAA;OACd,oBAAC,gBAAD,CAAiB,CAAA;OACjB,oBAAC,UAAD,EAAU,SAAQ,SAAU,CAAA;OAC3B,WACC,oBAAC,QAAD;QAAQ,SAAQ;QAAQ,MAAK;QAAK,SAAA;QAChC,UAAA,qBAAC,MAAD;SAAM,MAAM;SAAS,aAAU;SAA/B,UAAA;UACE,oBAAC,MAAD;WACE,MAAK;WACL,UAAU;WACV,WAAU;WACV,eAAY;UACb,CAAA;UACD,oBAAC,QAAD;WAAM,WAAU;WAAoB,UAAA,EAAE,mBAAmB,CAAC,GAAG,MAAM;UAAQ,CAAA;UAC3E,oBAAC,QAAD;WAAM,WAAU;WAAqB,UAAA,EAAE,mBAAmB,CAAC,GAAG,MAAM;UAAQ,CAAA;SACxE;;OACA,CAAA;MAEP;;IACC;GAER,CAAA,IAAA,oBAAC,OAAD;IAAK,WAAU;IACb,UAAA,oBAAC,gBAAD,CAAiB,CAAA;GACd,CAAA;GAEP,qBAAC,QAAD;IAAM,aAAU;IAAU,WAAU;IAApC,UAAA;KACE,oBAAC,MAAD,EAAM,MAAK,gBAAiB,CAAA;KAC3B;KACD,oBAAC,MAAD,EAAM,MAAK,cAAe,CAAA;IACtB;;GACN,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;GACzB,oBAAC,MAAD,EAAM,MAAK,WAAY,CAAA;EACpB;;AAET"}
1
+ {"version":3,"file":"fullscreen-layout.js","names":[],"sources":["../../src/layouts/fullscreen-layout.tsx"],"sourcesContent":["import type { PageSchema } from '@alfakit/core'\nimport { Link } from '@inertiajs/react'\nimport { LogOutIcon } from 'lucide-react'\nimport type { ReactNode } from 'react'\nimport { NotificationsMenu } from '../components/notifications/notifications-menu'\nimport { Brand } from '../components/panel/brand'\nimport { DebugPanelSlot } from '../components/panel/debug-panel-slot'\nimport { TopbarLocaleSwitcher } from '../components/panel/locale-switcher'\nimport { Slot } from '../components/panel/slot'\nimport { ThemeToggle } from '../components/panel/theme-toggle'\nimport { UserMenu } from '../components/panel/user-menu'\nimport { Button } from '../components/ui/button'\nimport { Separator } from '../components/ui/separator'\nimport { useT } from '../context'\nimport { Icon } from '../lib/icons'\n\nexport interface FullscreenLayoutProps {\n children: ReactNode\n page?: PageSchema\n}\n\n/**\n * `$layout = 'fullscreen'`: the whole viewport for an app screen (point of sale, kiosk,\n * board). No sidebar or topbar; an optional slim header keeps the brand, the page title,\n * notifications, the user menu and a way back to the panel. Toasts, modals and the debug\n * panel work as on every other page. Replace it with `components: { 'layout:fullscreen': … }`.\n */\nexport function FullscreenLayout({ children, page }: FullscreenLayoutProps) {\n const t = useT()\n const header = page?.fullscreen?.header !== false\n const exitUrl = page?.fullscreen?.exitUrl\n\n return (\n <div data-layout=\"fullscreen\" className=\"bg-background flex h-svh min-h-0 flex-col\">\n <Slot name=\"body.start\" />\n <Slot name=\"layout.start\" />\n {header ? (\n <header\n data-slot=\"topbar\"\n data-variant=\"fullscreen\"\n className=\"bg-background flex h-12 shrink-0 items-center gap-3 border-b px-3 md:px-4\"\n >\n <Slot name=\"topbar.logo.before\" />\n <Brand className=\"hidden shrink-0 sm:flex\" />\n <Slot name=\"topbar.logo.after\" />\n <Separator orientation=\"vertical\" className=\"hidden h-4 sm:block\" />\n <h1 className=\"min-w-0 truncate text-sm font-semibold\">{page?.heading ?? page?.title}</h1>\n <Slot name=\"topbar.start\" />\n <div className=\"ms-auto flex shrink-0 items-center gap-1\">\n <Slot name=\"topbar.end\" />\n <NotificationsMenu />\n <TopbarLocaleSwitcher />\n <ThemeToggle />\n <DebugPanelSlot />\n <UserMenu variant=\"topbar\" />\n {exitUrl && (\n <Button variant=\"ghost\" size=\"sm\" asChild>\n <Link href={exitUrl} data-slot=\"fullscreen-exit\">\n <Icon\n name=\"alfakit::panels.widgets.account.logout-button\"\n fallback={LogOutIcon}\n className=\"rtl:rotate-180\"\n aria-hidden=\"true\"\n />\n <span className=\"hidden sm:inline\">{t('exit_fullscreen', {}, 'Exit')}</span>\n <span className=\"sr-only sm:hidden\">{t('exit_fullscreen', {}, 'Exit')}</span>\n </Link>\n </Button>\n )}\n </div>\n </header>\n ) : (\n <div className=\"fixed end-3 bottom-3 z-40\">\n <DebugPanelSlot />\n </div>\n )}\n <main data-slot=\"content\" className=\"flex min-h-0 w-full min-w-0 flex-1 flex-col\">\n <Slot name=\"content.start\" />\n {children}\n <Slot name=\"content.end\" />\n </main>\n <Slot name=\"layout.end\" />\n <Slot name=\"body.end\" />\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,iBAAiB,EAAE,UAAU,QAA+B;CAC1E,MAAM,IAAI,KAAK;CACf,MAAM,SAAS,MAAM,YAAY,WAAW;CAC5C,MAAM,UAAU,MAAM,YAAY;CAElC,OACE,qBAAC,OAAD;EAAK,eAAY;EAAa,WAAU;EAAxC,UAAA;GACE,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;GACzB,oBAAC,MAAD,EAAM,MAAK,eAAgB,CAAA;GAC1B,SACC,qBAAC,UAAD;IACE,aAAU;IACV,gBAAa;IACb,WAAU;IAHZ,UAAA;KAKE,oBAAC,MAAD,EAAM,MAAK,qBAAsB,CAAA;KACjC,oBAAC,OAAD,EAAO,WAAU,0BAA2B,CAAA;KAC5C,oBAAC,MAAD,EAAM,MAAK,oBAAqB,CAAA;KAChC,oBAAC,WAAD;MAAW,aAAY;MAAW,WAAU;KAAuB,CAAA;KACnE,oBAAC,MAAD;MAAI,WAAU;MAA0C,UAAA,MAAM,WAAW,MAAM;KAAU,CAAA;KACzF,oBAAC,MAAD,EAAM,MAAK,eAAgB,CAAA;KAC3B,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACE,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;OACzB,oBAAC,mBAAD,CAAoB,CAAA;OACpB,oBAAC,sBAAD,CAAuB,CAAA;OACvB,oBAAC,aAAD,CAAc,CAAA;OACd,oBAAC,gBAAD,CAAiB,CAAA;OACjB,oBAAC,UAAD,EAAU,SAAQ,SAAU,CAAA;OAC3B,WACC,oBAAC,QAAD;QAAQ,SAAQ;QAAQ,MAAK;QAAK,SAAA;QAChC,UAAA,qBAAC,MAAD;SAAM,MAAM;SAAS,aAAU;SAA/B,UAAA;UACE,oBAAC,MAAD;WACE,MAAK;WACL,UAAU;WACV,WAAU;WACV,eAAY;UACb,CAAA;UACD,oBAAC,QAAD;WAAM,WAAU;WAAoB,UAAA,EAAE,mBAAmB,CAAC,GAAG,MAAM;UAAQ,CAAA;UAC3E,oBAAC,QAAD;WAAM,WAAU;WAAqB,UAAA,EAAE,mBAAmB,CAAC,GAAG,MAAM;UAAQ,CAAA;SACxE;;OACA,CAAA;MAEP;;IACC;GAER,CAAA,IAAA,oBAAC,OAAD;IAAK,WAAU;IACb,UAAA,oBAAC,gBAAD,CAAiB,CAAA;GACd,CAAA;GAEP,qBAAC,QAAD;IAAM,aAAU;IAAU,WAAU;IAApC,UAAA;KACE,oBAAC,MAAD,EAAM,MAAK,gBAAiB,CAAA;KAC3B;KACD,oBAAC,MAAD,EAAM,MAAK,cAAe,CAAA;IACtB;;GACN,oBAAC,MAAD,EAAM,MAAK,aAAc,CAAA;GACzB,oBAAC,MAAD,EAAM,MAAK,WAAY,CAAA;EACpB;;AAET"}
@@ -0,0 +1,15 @@
1
+ import { discoveredComponent } from "../lib/discovery.js";
2
+ import { lazyComponents } from "@alfakit/core";
3
+ //#region src/layouts/lazy-layouts.ts
4
+ /**
5
+ * The fullscreen layout (`$layout = 'fullscreen'`), loaded on demand by starter kit pages:
6
+ * they render in the host's layout, so the page chunk never imports the panel's header,
7
+ * menus and notifications for a layout few pages use. Only the starter kit registers it;
8
+ * `createAlfakit()` registers the layouts themselves up front (`panelLayouts`), so a panel's
9
+ * bundle has no extra lazy entry points.
10
+ */
11
+ const lazyPanelLayouts = lazyComponents({ "layout:fullscreen": () => import("./fullscreen-layout.js").then((m) => m.FullscreenLayout) }).map(discoveredComponent).components;
12
+ //#endregion
13
+ export { lazyPanelLayouts };
14
+
15
+ //# sourceMappingURL=lazy-layouts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy-layouts.js","names":[],"sources":["../../src/layouts/lazy-layouts.ts"],"sourcesContent":["import { lazyComponents } from '@alfakit/core'\nimport type { AnyComponent } from '../context'\nimport { discoveredComponent } from '../lib/discovery'\n\n/**\n * The fullscreen layout (`$layout = 'fullscreen'`), loaded on demand by starter kit pages:\n * they render in the host's layout, so the page chunk never imports the panel's header,\n * menus and notifications for a layout few pages use. Only the starter kit registers it;\n * `createAlfakit()` registers the layouts themselves up front (`panelLayouts`), so a panel's\n * bundle has no extra lazy entry points.\n */\nexport const lazyPanelLayouts: Record<string, AnyComponent> = lazyComponents<AnyComponent>({\n 'layout:fullscreen': () => import('./fullscreen-layout').then((m) => m.FullscreenLayout),\n}).map(discoveredComponent).components\n"],"mappings":";;;;;;;;;;AAWA,MAAa,mBAAiD,eAA6B,EACzF,2BAA2B,OAAO,yBAAsB,CAAC,MAAM,MAAM,EAAE,gBAAgB,EACzF,CAAC,CAAC,CAAC,IAAI,mBAAmB,CAAC,CAAC"}
@@ -0,0 +1,34 @@
1
+ //#region src/layouts/max-widths.ts
2
+ /** Tailwind classes for the `maxContentWidth` setting of the panel and its pages. */
3
+ const MAX_WIDTHS = {
4
+ "3xs": "max-w-3xs",
5
+ "2xs": "max-w-2xs",
6
+ xs: "max-w-xs",
7
+ sm: "max-w-sm",
8
+ md: "max-w-md",
9
+ lg: "max-w-lg",
10
+ xl: "max-w-xl",
11
+ "2xl": "max-w-2xl",
12
+ "3xl": "max-w-3xl",
13
+ "4xl": "max-w-4xl",
14
+ "5xl": "max-w-5xl",
15
+ "6xl": "max-w-6xl",
16
+ "7xl": "max-w-7xl",
17
+ none: "max-w-none",
18
+ min: "max-w-min",
19
+ max: "max-w-max",
20
+ fit: "max-w-fit",
21
+ prose: "max-w-prose",
22
+ container: "container",
23
+ "screen-sm": "max-w-(--breakpoint-sm)",
24
+ "screen-md": "max-w-(--breakpoint-md)",
25
+ "screen-lg": "max-w-(--breakpoint-lg)",
26
+ "screen-xl": "max-w-(--breakpoint-xl)",
27
+ "screen-2xl": "max-w-(--breakpoint-2xl)",
28
+ full: "max-w-full",
29
+ screen: "max-w-screen"
30
+ };
31
+ //#endregion
32
+ export { MAX_WIDTHS };
33
+
34
+ //# sourceMappingURL=max-widths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"max-widths.js","names":[],"sources":["../../src/layouts/max-widths.ts"],"sourcesContent":["/** Tailwind classes for the `maxContentWidth` setting of the panel and its pages. */\nexport const MAX_WIDTHS: Record<string, string> = {\n '3xs': 'max-w-3xs',\n '2xs': 'max-w-2xs',\n xs: 'max-w-xs',\n sm: 'max-w-sm',\n md: 'max-w-md',\n lg: 'max-w-lg',\n xl: 'max-w-xl',\n '2xl': 'max-w-2xl',\n '3xl': 'max-w-3xl',\n '4xl': 'max-w-4xl',\n '5xl': 'max-w-5xl',\n '6xl': 'max-w-6xl',\n '7xl': 'max-w-7xl',\n none: 'max-w-none',\n min: 'max-w-min',\n max: 'max-w-max',\n fit: 'max-w-fit',\n prose: 'max-w-prose',\n container: 'container',\n 'screen-sm': 'max-w-(--breakpoint-sm)',\n 'screen-md': 'max-w-(--breakpoint-md)',\n 'screen-lg': 'max-w-(--breakpoint-lg)',\n 'screen-xl': 'max-w-(--breakpoint-xl)',\n 'screen-2xl': 'max-w-(--breakpoint-2xl)',\n full: 'max-w-full',\n screen: 'max-w-screen',\n}\n"],"mappings":";;AACA,MAAa,aAAqC;CAChD,OAAO;CACP,OAAO;CACP,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;CACP,MAAM;CACN,KAAK;CACL,KAAK;CACL,KAAK;CACL,OAAO;CACP,WAAW;CACX,aAAa;CACb,aAAa;CACb,aAAa;CACb,aAAa;CACb,cAAc;CACd,MAAM;CACN,QAAQ;AACV"}
@@ -0,0 +1,10 @@
1
+ import { AnyComponent } from "../context.js";
2
+ //#region src/layouts/panel-layouts.d.ts
3
+ /**
4
+ * The panel's own layouts (sidebar or top navigation, auth card, blank, fullscreen), which
5
+ * `createAlfakit()` registers up front. Starter kit pages render in the host's layout and
6
+ * never import these: `PageShell` loads one on demand if such a page asks for it.
7
+ */
8
+ export declare const panelLayouts: Record<string, AnyComponent>;
9
+ //#endregion
10
+ //# sourceMappingURL=panel-layouts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel-layouts.d.ts","names":[],"sources":["../../src/layouts/panel-layouts.ts"],"mappings":";;;;;;;qBAWa,cAAc,eAAe"}
@@ -0,0 +1,20 @@
1
+ import { BlankLayout } from "./blank-layout.js";
2
+ import { AppLayout } from "./app-layout.js";
3
+ import { AuthLayout } from "./auth-layout.js";
4
+ import { FullscreenLayout } from "./fullscreen-layout.js";
5
+ //#region src/layouts/panel-layouts.ts
6
+ /**
7
+ * The panel's own layouts (sidebar or top navigation, auth card, blank, fullscreen), which
8
+ * `createAlfakit()` registers up front. Starter kit pages render in the host's layout and
9
+ * never import these: `PageShell` loads one on demand if such a page asks for it.
10
+ */
11
+ const panelLayouts = {
12
+ "layout:app": AppLayout,
13
+ "layout:auth": AuthLayout,
14
+ "layout:blank": BlankLayout,
15
+ "layout:fullscreen": FullscreenLayout
16
+ };
17
+ //#endregion
18
+ export { panelLayouts };
19
+
20
+ //# sourceMappingURL=panel-layouts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panel-layouts.js","names":[],"sources":["../../src/layouts/panel-layouts.ts"],"sourcesContent":["import type { AnyComponent } from '../context'\nimport { AppLayout } from './app-layout'\nimport { AuthLayout } from './auth-layout'\nimport { BlankLayout } from './blank-layout'\nimport { FullscreenLayout } from './fullscreen-layout'\n\n/**\n * The panel's own layouts (sidebar or top navigation, auth card, blank, fullscreen), which\n * `createAlfakit()` registers up front. Starter kit pages render in the host's layout and\n * never import these: `PageShell` loads one on demand if such a page asks for it.\n */\nexport const panelLayouts: Record<string, AnyComponent> = {\n 'layout:app': AppLayout,\n 'layout:auth': AuthLayout,\n 'layout:blank': BlankLayout,\n 'layout:fullscreen': FullscreenLayout,\n}\n"],"mappings":";;;;;;;;;;AAWA,MAAa,eAA6C;CACxD,cAAc;CACd,eAAe;CACf,gBAAgB;CAChB,qBAAqB;AACvB"}
@@ -9,16 +9,16 @@ import { NavLabel } from "../components/panel/nav-label.js";
9
9
  import { NewTabHint } from "../lib/new-tab-hint.js";
10
10
  import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "../components/ui/sheet.js";
11
11
  import { NotificationsMenu } from "../components/notifications/notifications-menu.js";
12
+ import { Brand } from "../components/panel/brand.js";
12
13
  import { GlobalSearch } from "../components/panel/global-search.js";
13
14
  import { TenantMenu } from "../components/panel/tenant-menu.js";
14
15
  import { TopbarLocaleSwitcher } from "../components/panel/locale-switcher.js";
15
16
  import { UserMenu } from "../components/panel/user-menu.js";
16
- import { Brand } from "../components/panel/app-sidebar.js";
17
17
  import { BottomNav } from "../components/panel/bottom-nav.js";
18
18
  import { DebugPanelSlot } from "../components/panel/debug-panel-slot.js";
19
19
  import { ThemeToggle } from "../components/panel/theme-toggle.js";
20
20
  import { Breadcrumbs } from "../components/panel/topbar.js";
21
- import { MAX_WIDTHS } from "./app-layout.js";
21
+ import { MAX_WIDTHS } from "./max-widths.js";
22
22
  import { PREFETCH_CACHE_FOR, hasMobilePreset } from "@alfakit/core";
23
23
  import { Link } from "@inertiajs/react";
24
24
  import { createElement, useState } from "react";
@@ -1 +1 @@
1
- {"version":3,"file":"top-nav-layout.js","names":[],"sources":["../../src/layouts/top-nav-layout.tsx"],"sourcesContent":["import {\n PREFETCH_CACHE_FOR,\n hasMobilePreset,\n type BreadcrumbSchema,\n type NavigationGroupSchema,\n type NavigationItemSchema,\n type Width,\n} from '@alfakit/core'\nimport { Link } from '@inertiajs/react'\nimport { ChevronDownIcon, MenuIcon } from 'lucide-react'\nimport { createElement, useState, type ReactNode } from 'react'\nimport { NotificationsMenu } from '../components/notifications/notifications-menu'\nimport { Brand } from '../components/panel/app-sidebar'\nimport { BottomNav } from '../components/panel/bottom-nav'\nimport { DebugPanelSlot } from '../components/panel/debug-panel-slot'\nimport { GlobalSearch } from '../components/panel/global-search'\nimport { TopbarLocaleSwitcher } from '../components/panel/locale-switcher'\nimport { NavLabel } from '../components/panel/nav-label'\nimport { Slot } from '../components/panel/slot'\nimport { TenantMenu } from '../components/panel/tenant-menu'\nimport { ThemeToggle } from '../components/panel/theme-toggle'\nimport { Breadcrumbs } from '../components/panel/topbar'\nimport { UserMenu } from '../components/panel/user-menu'\nimport { Button } from '../components/ui/button'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '../components/ui/dropdown-menu'\nimport { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '../components/ui/sheet'\nimport { useDirection, usePanel, useRegistry, useT } from '../context'\nimport { extraProps } from '../lib/attributes'\nimport { Icon } from '../lib/icons'\nimport { NewTabHint } from '../lib/new-tab-hint'\nimport { cn } from '../lib/utils'\nimport { MAX_WIDTHS } from './app-layout'\n\nexport interface TopNavLayoutProps {\n children: ReactNode\n breadcrumbs?: BreadcrumbSchema[]\n maxContentWidth?: Width | string\n}\n\nconst isActive = (item: NavigationItemSchema): boolean =>\n Boolean(item.active || item.children?.some(isActive))\n\nfunction TopNavLink({ item }: { item: NavigationItemSchema }) {\n const className =\n 'text-muted-foreground hover:text-foreground hover:bg-accent data-[active=true]:bg-accent data-[active=true]:text-foreground inline-flex h-9 shrink-0 items-center gap-2 rounded-md px-3 text-sm font-medium transition-colors [&_svg]:size-4'\n\n if (item.children && item.children.length > 0) {\n return (\n <TopNavMenu\n label={<NavLabel item={item} />}\n icon={item.icon}\n items={item.children}\n active={isActive(item)}\n attributes={item.extraAttributes}\n />\n )\n }\n\n return item.openInNewTab ? (\n <a\n // `NavigationItem::extraAttributes()`; `class` is merged with the link's own.\n {...extraProps(item.extraAttributes, className)}\n href={item.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n data-slot=\"topnav-link\"\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NewTabHint />\n </a>\n ) : (\n <Link\n {...extraProps(item.extraAttributes, className)}\n href={item.url ?? '#'}\n prefetch\n cacheFor={PREFETCH_CACHE_FOR}\n data-slot=\"topnav-link\"\n data-active={item.active ? 'true' : undefined}\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n </Link>\n )\n}\n\nfunction TopNavMenu({\n label,\n icon,\n items,\n active,\n attributes,\n}: {\n label: ReactNode\n icon?: string\n items: NavigationItemSchema[]\n active: boolean\n attributes?: NavigationItemSchema['extraAttributes']\n}) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger\n {...extraProps(\n attributes,\n 'text-muted-foreground hover:text-foreground hover:bg-accent data-[active=true]:bg-accent data-[active=true]:text-foreground data-[state=open]:text-foreground inline-flex h-9 shrink-0 items-center gap-1.5 rounded-md px-3 text-sm font-medium transition-colors outline-none [&_svg]:size-4',\n )}\n data-slot=\"topnav-link\"\n data-active={active ? 'true' : undefined}\n >\n {icon && <Icon name={icon} />}\n {label}\n <ChevronDownIcon className=\"opacity-60\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"min-w-48\">\n {items.map((item) => (\n <DropdownMenuItem key={item.label} asChild>\n <Link\n {...extraProps(item.extraAttributes, cn('w-full', item.active && 'font-medium'))}\n href={item.url ?? '#'}\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n </Link>\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\nfunction TopNavGroup({ group }: { group: NavigationGroupSchema }) {\n // `NavigationGroup::extraTopbarAttributes()` wrap the group; `class` is merged.\n if (group.extraTopbarAttributes) {\n return (\n <div\n data-slot=\"topnav-group\"\n {...extraProps(group.extraTopbarAttributes, 'flex shrink-0 items-center gap-1')}\n >\n <TopNavGroup group={{ ...group, extraTopbarAttributes: undefined }} />\n </div>\n )\n }\n\n if (!group.label) {\n return (\n <>\n {group.items.map((item) => (\n <TopNavLink key={item.label} item={item} />\n ))}\n </>\n )\n }\n\n return (\n <TopNavMenu\n label={group.label}\n icon={group.icon}\n items={group.items}\n active={group.items.some(isActive)}\n />\n )\n}\n\n/** Vertical navigation for the mobile drawer. */\nfunction MobileNav({ onNavigate }: { onNavigate: () => void }) {\n const panel = usePanel()\n\n return (\n <nav className=\"flex flex-col gap-4 overflow-y-auto p-4 text-sm\">\n {panel.navigation.map((group, index) => (\n <div key={group.label ?? index} className=\"flex flex-col gap-1\">\n {group.label && (\n <p className=\"text-muted-foreground px-2 text-xs font-medium\">{group.label}</p>\n )}\n {group.items\n .flatMap((item) => [item, ...(item.children ?? [])])\n .map((item) => (\n <Link\n key={item.label}\n href={item.url ?? '#'}\n onClick={onNavigate}\n data-active={item.active ? 'true' : undefined}\n className=\"hover:bg-accent data-[active=true]:bg-accent flex items-center gap-2 rounded-md px-2 py-2 font-medium [&_svg]:size-4\"\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n </Link>\n ))}\n </div>\n ))}\n </nav>\n )\n}\n\n/**\n * Navigation across the top instead of a sidebar (`layout: 'topbar'`). Ungrouped items are\n * links; labelled groups and items with children open as dropdowns.\n */\nexport function TopNavLayout({ children, breadcrumbs, maxContentWidth }: TopNavLayoutProps) {\n const panel = usePanel()\n const t = useT()\n const direction = useDirection()\n const registry = useRegistry()\n const [open, setOpen] = useState(false)\n const width = MAX_WIDTHS[maxContentWidth ?? panel.maxContentWidth ?? '7xl'] ?? 'max-w-7xl'\n const Bottom = registry.resolve('panel:bottom-nav') ?? BottomNav\n\n return (\n <div data-slot=\"topnav-layout\" className=\"bg-background flex min-h-svh flex-col\">\n <Slot name=\"body.start\" />\n <Slot name=\"layout.start\" />\n <Slot name=\"topbar.before\" />\n <header\n data-slot=\"topbar\"\n className=\"bg-background/90 supports-[backdrop-filter]:bg-background/70 sticky top-0 z-30 border-b backdrop-blur\"\n >\n <div className={cn('mx-auto flex h-14 w-full items-center gap-3 px-4 md:px-6', width)}>\n <Sheet open={open} onOpenChange={setOpen}>\n <SheetTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"md:hidden\"\n aria-label={t('toggle_sidebar', {}, 'Toggle sidebar')}\n >\n <Icon name=\"alfakit::panels.topbar.open-sidebar-button\" fallback={MenuIcon} />\n </Button>\n </SheetTrigger>\n <SheetContent side={direction === 'rtl' ? 'right' : 'left'} className=\"w-72 p-0\">\n <SheetHeader className=\"border-b\">\n <SheetTitle asChild>\n <div>\n <Brand />\n </div>\n </SheetTitle>\n </SheetHeader>\n <MobileNav onNavigate={() => setOpen(false)} />\n </SheetContent>\n </Sheet>\n <Slot name=\"topbar.logo.before\" />\n <Brand className=\"me-2 shrink-0\" />\n <Slot name=\"topbar.logo.after\" />\n {panel.tenancy?.current && <Slot name=\"tenant-menu.before\" />}\n <TenantMenu variant=\"topbar\" />\n {panel.tenancy?.current && <Slot name=\"tenant-menu.after\" />}\n <nav\n data-slot=\"topnav\"\n aria-label={t('navigation', {}, 'Navigation')}\n className=\"hidden min-w-0 flex-1 items-center gap-1 self-stretch overflow-x-auto md:flex\"\n >\n {panel.navigation.map((group, index) => (\n <TopNavGroup key={group.label ?? `group-${index}`} group={group} />\n ))}\n </nav>\n <Slot name=\"topbar.start\" />\n <div className=\"ms-auto flex shrink-0 items-center gap-1\">\n <Slot name=\"topbar.end\" />\n <GlobalSearch />\n <NotificationsMenu />\n <TopbarLocaleSwitcher />\n <ThemeToggle />\n <DebugPanelSlot />\n <UserMenu variant=\"topbar\" />\n </div>\n </div>\n </header>\n <Slot name=\"topbar.after\" />\n <Slot name=\"content.before\" />\n <main\n data-slot=\"content\"\n className={cn('mx-auto flex w-full min-w-0 flex-1 flex-col gap-6 p-4 md:p-6', width)}\n >\n {panel.breadcrumbs && breadcrumbs && breadcrumbs.length > 0 && (\n <Breadcrumbs items={breadcrumbs} />\n )}\n <Slot name=\"content.start\" />\n {children}\n <Slot name=\"content.end\" />\n </main>\n <Slot name=\"content.after\" />\n <Slot name=\"footer\" />\n {hasMobilePreset(panel) && createElement(Bottom)}\n <Slot name=\"layout.end\" />\n <Slot name=\"body.end\" />\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"top-nav-layout.js","names":[],"sources":["../../src/layouts/top-nav-layout.tsx"],"sourcesContent":["import {\n PREFETCH_CACHE_FOR,\n hasMobilePreset,\n type BreadcrumbSchema,\n type NavigationGroupSchema,\n type NavigationItemSchema,\n type Width,\n} from '@alfakit/core'\nimport { Link } from '@inertiajs/react'\nimport { ChevronDownIcon, MenuIcon } from 'lucide-react'\nimport { createElement, useState, type ReactNode } from 'react'\nimport { NotificationsMenu } from '../components/notifications/notifications-menu'\nimport { BottomNav } from '../components/panel/bottom-nav'\nimport { Brand } from '../components/panel/brand'\nimport { DebugPanelSlot } from '../components/panel/debug-panel-slot'\nimport { GlobalSearch } from '../components/panel/global-search'\nimport { TopbarLocaleSwitcher } from '../components/panel/locale-switcher'\nimport { NavLabel } from '../components/panel/nav-label'\nimport { Slot } from '../components/panel/slot'\nimport { TenantMenu } from '../components/panel/tenant-menu'\nimport { ThemeToggle } from '../components/panel/theme-toggle'\nimport { Breadcrumbs } from '../components/panel/topbar'\nimport { UserMenu } from '../components/panel/user-menu'\nimport { Button } from '../components/ui/button'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '../components/ui/dropdown-menu'\nimport { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '../components/ui/sheet'\nimport { useDirection, usePanel, useRegistry, useT } from '../context'\nimport { extraProps } from '../lib/attributes'\nimport { Icon } from '../lib/icons'\nimport { NewTabHint } from '../lib/new-tab-hint'\nimport { cn } from '../lib/utils'\nimport { MAX_WIDTHS } from './max-widths'\n\nexport interface TopNavLayoutProps {\n children: ReactNode\n breadcrumbs?: BreadcrumbSchema[]\n maxContentWidth?: Width | string\n}\n\nconst isActive = (item: NavigationItemSchema): boolean =>\n Boolean(item.active || item.children?.some(isActive))\n\nfunction TopNavLink({ item }: { item: NavigationItemSchema }) {\n const className =\n 'text-muted-foreground hover:text-foreground hover:bg-accent data-[active=true]:bg-accent data-[active=true]:text-foreground inline-flex h-9 shrink-0 items-center gap-2 rounded-md px-3 text-sm font-medium transition-colors [&_svg]:size-4'\n\n if (item.children && item.children.length > 0) {\n return (\n <TopNavMenu\n label={<NavLabel item={item} />}\n icon={item.icon}\n items={item.children}\n active={isActive(item)}\n attributes={item.extraAttributes}\n />\n )\n }\n\n return item.openInNewTab ? (\n <a\n // `NavigationItem::extraAttributes()`; `class` is merged with the link's own.\n {...extraProps(item.extraAttributes, className)}\n href={item.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n data-slot=\"topnav-link\"\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n <NewTabHint />\n </a>\n ) : (\n <Link\n {...extraProps(item.extraAttributes, className)}\n href={item.url ?? '#'}\n prefetch\n cacheFor={PREFETCH_CACHE_FOR}\n data-slot=\"topnav-link\"\n data-active={item.active ? 'true' : undefined}\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n </Link>\n )\n}\n\nfunction TopNavMenu({\n label,\n icon,\n items,\n active,\n attributes,\n}: {\n label: ReactNode\n icon?: string\n items: NavigationItemSchema[]\n active: boolean\n attributes?: NavigationItemSchema['extraAttributes']\n}) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger\n {...extraProps(\n attributes,\n 'text-muted-foreground hover:text-foreground hover:bg-accent data-[active=true]:bg-accent data-[active=true]:text-foreground data-[state=open]:text-foreground inline-flex h-9 shrink-0 items-center gap-1.5 rounded-md px-3 text-sm font-medium transition-colors outline-none [&_svg]:size-4',\n )}\n data-slot=\"topnav-link\"\n data-active={active ? 'true' : undefined}\n >\n {icon && <Icon name={icon} />}\n {label}\n <ChevronDownIcon className=\"opacity-60\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"min-w-48\">\n {items.map((item) => (\n <DropdownMenuItem key={item.label} asChild>\n <Link\n {...extraProps(item.extraAttributes, cn('w-full', item.active && 'font-medium'))}\n href={item.url ?? '#'}\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n </Link>\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\nfunction TopNavGroup({ group }: { group: NavigationGroupSchema }) {\n // `NavigationGroup::extraTopbarAttributes()` wrap the group; `class` is merged.\n if (group.extraTopbarAttributes) {\n return (\n <div\n data-slot=\"topnav-group\"\n {...extraProps(group.extraTopbarAttributes, 'flex shrink-0 items-center gap-1')}\n >\n <TopNavGroup group={{ ...group, extraTopbarAttributes: undefined }} />\n </div>\n )\n }\n\n if (!group.label) {\n return (\n <>\n {group.items.map((item) => (\n <TopNavLink key={item.label} item={item} />\n ))}\n </>\n )\n }\n\n return (\n <TopNavMenu\n label={group.label}\n icon={group.icon}\n items={group.items}\n active={group.items.some(isActive)}\n />\n )\n}\n\n/** Vertical navigation for the mobile drawer. */\nfunction MobileNav({ onNavigate }: { onNavigate: () => void }) {\n const panel = usePanel()\n\n return (\n <nav className=\"flex flex-col gap-4 overflow-y-auto p-4 text-sm\">\n {panel.navigation.map((group, index) => (\n <div key={group.label ?? index} className=\"flex flex-col gap-1\">\n {group.label && (\n <p className=\"text-muted-foreground px-2 text-xs font-medium\">{group.label}</p>\n )}\n {group.items\n .flatMap((item) => [item, ...(item.children ?? [])])\n .map((item) => (\n <Link\n key={item.label}\n href={item.url ?? '#'}\n onClick={onNavigate}\n data-active={item.active ? 'true' : undefined}\n className=\"hover:bg-accent data-[active=true]:bg-accent flex items-center gap-2 rounded-md px-2 py-2 font-medium [&_svg]:size-4\"\n >\n {item.icon && <Icon name={item.icon} />}\n <NavLabel item={item} />\n </Link>\n ))}\n </div>\n ))}\n </nav>\n )\n}\n\n/**\n * Navigation across the top instead of a sidebar (`layout: 'topbar'`). Ungrouped items are\n * links; labelled groups and items with children open as dropdowns.\n */\nexport function TopNavLayout({ children, breadcrumbs, maxContentWidth }: TopNavLayoutProps) {\n const panel = usePanel()\n const t = useT()\n const direction = useDirection()\n const registry = useRegistry()\n const [open, setOpen] = useState(false)\n const width = MAX_WIDTHS[maxContentWidth ?? panel.maxContentWidth ?? '7xl'] ?? 'max-w-7xl'\n const Bottom = registry.resolve('panel:bottom-nav') ?? BottomNav\n\n return (\n <div data-slot=\"topnav-layout\" className=\"bg-background flex min-h-svh flex-col\">\n <Slot name=\"body.start\" />\n <Slot name=\"layout.start\" />\n <Slot name=\"topbar.before\" />\n <header\n data-slot=\"topbar\"\n className=\"bg-background/90 supports-[backdrop-filter]:bg-background/70 sticky top-0 z-30 border-b backdrop-blur\"\n >\n <div className={cn('mx-auto flex h-14 w-full items-center gap-3 px-4 md:px-6', width)}>\n <Sheet open={open} onOpenChange={setOpen}>\n <SheetTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"md:hidden\"\n aria-label={t('toggle_sidebar', {}, 'Toggle sidebar')}\n >\n <Icon name=\"alfakit::panels.topbar.open-sidebar-button\" fallback={MenuIcon} />\n </Button>\n </SheetTrigger>\n <SheetContent side={direction === 'rtl' ? 'right' : 'left'} className=\"w-72 p-0\">\n <SheetHeader className=\"border-b\">\n <SheetTitle asChild>\n <div>\n <Brand />\n </div>\n </SheetTitle>\n </SheetHeader>\n <MobileNav onNavigate={() => setOpen(false)} />\n </SheetContent>\n </Sheet>\n <Slot name=\"topbar.logo.before\" />\n <Brand className=\"me-2 shrink-0\" />\n <Slot name=\"topbar.logo.after\" />\n {panel.tenancy?.current && <Slot name=\"tenant-menu.before\" />}\n <TenantMenu variant=\"topbar\" />\n {panel.tenancy?.current && <Slot name=\"tenant-menu.after\" />}\n <nav\n data-slot=\"topnav\"\n aria-label={t('navigation', {}, 'Navigation')}\n className=\"hidden min-w-0 flex-1 items-center gap-1 self-stretch overflow-x-auto md:flex\"\n >\n {panel.navigation.map((group, index) => (\n <TopNavGroup key={group.label ?? `group-${index}`} group={group} />\n ))}\n </nav>\n <Slot name=\"topbar.start\" />\n <div className=\"ms-auto flex shrink-0 items-center gap-1\">\n <Slot name=\"topbar.end\" />\n <GlobalSearch />\n <NotificationsMenu />\n <TopbarLocaleSwitcher />\n <ThemeToggle />\n <DebugPanelSlot />\n <UserMenu variant=\"topbar\" />\n </div>\n </div>\n </header>\n <Slot name=\"topbar.after\" />\n <Slot name=\"content.before\" />\n <main\n data-slot=\"content\"\n className={cn('mx-auto flex w-full min-w-0 flex-1 flex-col gap-6 p-4 md:p-6', width)}\n >\n {panel.breadcrumbs && breadcrumbs && breadcrumbs.length > 0 && (\n <Breadcrumbs items={breadcrumbs} />\n )}\n <Slot name=\"content.start\" />\n {children}\n <Slot name=\"content.end\" />\n </main>\n <Slot name=\"content.after\" />\n <Slot name=\"footer\" />\n {hasMobilePreset(panel) && createElement(Bottom)}\n <Slot name=\"layout.end\" />\n <Slot name=\"body.end\" />\n </div>\n )\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"page.d.ts","names":[],"sources":["../../src/pages/page.tsx"],"mappings":";;;;;;;wBA8DgB,+BAAW,IAAA;wBA8EX,YAAY,MAAM;EAAc,MAAM;EAAY,UAAU;oBAAW,2CAAA;wBA+CvE,aAAa;EAAU,MAAM;oBAAY,IAAA;wBA4DzC,cAAc;EAAU,MAAM;oBAAY,IAAA;wBAU1C,uBAAuB;EAAW,OAAO;oBAAc,IAAA"}
1
+ {"version":3,"file":"page.d.ts","names":[],"sources":["../../src/pages/page.tsx"],"mappings":";;;;;;;wBAkEgB,+BAAW,IAAA;wBAuFX,YAAY,MAAM;EAAc,MAAM;EAAY,UAAU;oBAAW,2CAAA;wBA2CvE,aAAa;EAAU,MAAM;oBAAY,IAAA;wBA4DzC,cAAc;EAAU,MAAM;oBAAY,IAAA;wBAU1C,uBAAuB;EAAW,OAAO;oBAAc,IAAA"}
@@ -17,10 +17,7 @@ import { RecordPresence } from "../components/realtime/record-presence.js";
17
17
  import { ListTabs, ListTabsPanel } from "../components/table/list-tabs.js";
18
18
  import { DataTable } from "../components/table/table-block.js";
19
19
  import { WidgetGrid } from "../components/widgets/widgets-block.js";
20
- import { AppLayout } from "../layouts/app-layout.js";
21
- import { AuthLayout } from "../layouts/auth-layout.js";
22
20
  import { BlankLayout } from "../layouts/blank-layout.js";
23
- import { FullscreenLayout } from "../layouts/fullscreen-layout.js";
24
21
  import { RELATION_QUERY_KEY, applyBodyAttributes, hasRelationManagerTabs, isLazyPlaceholder, openDefaultAction, relationManagerTabs, relationTabFromQuery, relationTabSlug, resolveLazyComponents } from "@alfakit/core";
25
22
  import { Head, Link, usePage } from "@inertiajs/react";
26
23
  import { Fragment, createElement, useEffect, useId, useMemo, useRef, useState } from "react";
@@ -86,17 +83,25 @@ function useBodyAttributes(attributes) {
86
83
  const key = attributes ? JSON.stringify(attributes) : "";
87
84
  useEffect(() => applyBodyAttributes(key ? JSON.parse(key) : void 0), [key]);
88
85
  }
86
+ /**
87
+ * The registered layout: `createAlfakit()` registers the panel's (`panelLayouts`), the starter
88
+ * kit its content layout. Without one the page renders bare: importing the panel layouts here
89
+ * would put the sidebar and top bar in every starter kit page.
90
+ */
91
+ function layout(registry, key) {
92
+ return registry.resolve(key) ?? BlankLayout;
93
+ }
89
94
  function PageShell({ page, children }) {
90
95
  const { registry } = useAlfakit();
91
96
  useBodyAttributes(page.extraBodyAttributes);
92
- if (page.layout === "auth") return createElement(registry.resolve("layout:auth") ?? AuthLayout, {
97
+ if (page.layout === "auth") return createElement(layout(registry, "layout:auth"), {
93
98
  heading: page.heading ?? page.title,
94
99
  subheading: page.subheading,
95
100
  page
96
101
  }, children);
97
- if (page.layout === "blank") return createElement(registry.resolve("layout:blank") ?? BlankLayout, { page }, children);
98
- if (page.layout === "fullscreen") return createElement(registry.resolve("layout:fullscreen") ?? FullscreenLayout, { page }, children);
99
- return createElement(registry.resolve("layout:app") ?? AppLayout, {
102
+ if (page.layout === "blank") return createElement(layout(registry, "layout:blank"), { page }, children);
103
+ if (page.layout === "fullscreen") return createElement(layout(registry, "layout:fullscreen"), { page }, children);
104
+ return createElement(layout(registry, "layout:app"), {
100
105
  breadcrumbs: page.breadcrumbs,
101
106
  maxContentWidth: page.maxContentWidth,
102
107
  page
@@ -1 +1 @@
1
- {"version":3,"file":"page.js","names":["FormBlock"],"sources":["../../src/pages/page.tsx"],"sourcesContent":["import type {\n ContentBlock,\n FormBlock as FormBlockSchema,\n InfolistBlock,\n LinksBlock,\n PageSchema,\n RelationManagersBlock,\n SchemaBlock,\n TableBlock as TableBlockSchema,\n WidgetsBlock as WidgetsBlockSchema,\n} from '@alfakit/core'\nimport {\n applyBodyAttributes,\n hasRelationManagerTabs,\n isLazyPlaceholder,\n openDefaultAction,\n RELATION_QUERY_KEY,\n relationManagerTabs,\n relationTabFromQuery,\n relationTabSlug,\n resolveLazyComponents,\n type DefaultActionOpener,\n} from '@alfakit/core'\nimport { Head, Link, usePage } from '@inertiajs/react'\nimport {\n createElement,\n Fragment,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react'\nimport { PageActionProvider } from '../components/actions/action-context'\nimport { ActionList } from '../components/actions/action-list'\nimport { FormBlock } from '../components/form/form-block'\nimport { KeyboardShortcuts } from '../components/panel/keyboard-shortcuts'\nimport { LazyPlaceholder } from '../components/panel/lazy-placeholder'\nimport { Slot } from '../components/panel/slot'\nimport { SubNavigationLayout } from '../components/panel/sub-navigation'\nimport { ConflictBanner } from '../components/realtime/conflict-banner'\nimport { RecordPresence } from '../components/realtime/record-presence'\nimport { SchemaRenderer } from '../components/schema/schema-renderer'\nimport { ListTabs, ListTabsPanel } from '../components/table/list-tabs'\nimport { DataTable } from '../components/table/table-block'\nimport { Badge } from '../components/ui/badge'\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '../components/ui/tabs'\nimport { WidgetGrid } from '../components/widgets/widgets-block'\nimport { useActionRunner, useAlfakit, useAlfakitProps, usePanel, useT } from '../context'\nimport { AppLayout } from '../layouts/app-layout'\nimport { AuthLayout } from '../layouts/auth-layout'\nimport { BlankLayout } from '../layouts/blank-layout'\nimport { FullscreenLayout } from '../layouts/fullscreen-layout'\nimport { badgeColorClasses, colorClass } from '../lib/colors'\nimport { Icon } from '../lib/icons'\nimport { cn } from '../lib/utils'\n\n/**\n * `Alfakit/Page`: renders any schema-driven page. Custom pages (`Page::$component`) are\n * resolved from the `pages` map passed to `createAlfakit()`.\n */\nexport function AlfakitPage() {\n const props = useAlfakitProps()\n const panel = usePanel()\n const t = useT()\n const { pages } = useAlfakit()\n // Lazy widgets and relation managers arrive in a deferred prop after the first response.\n const page = useMemo(\n () => (props.page ? resolveLazyComponents(props.page, props.alfakitLazy) : undefined),\n [props.page, props.alfakitLazy],\n )\n\n useDefaultAction(page)\n\n if (!page) {\n return null\n }\n\n // Starter kit mode: the host's `title` callback adds the application name.\n const title = panel.starterKit ? page.title : `${page.title} - ${panel.brandName}`\n\n if (page.view) {\n const Custom = pages[page.view.component]\n\n if (!Custom) {\n return (\n <div className=\"text-destructive p-6\">\n {t(\n 'page_not_registered',\n { component: page.view.component },\n `Page component ${page.view.component} is not registered in createAlfakit({ pages }).`,\n )}\n </div>\n )\n }\n\n return (\n <PageActionProvider value={{ token: page.token, component: 'page' }}>\n <Head title={title} />\n <PageShell page={page}>\n <Custom {...page.view.props} page={page} />\n </PageShell>\n </PageActionProvider>\n )\n }\n\n return (\n <PageActionProvider value={{ token: page.token, component: 'page' }}>\n <Head title={title} />\n <PageShell page={page}>\n <PageContent page={page} />\n </PageShell>\n </PageActionProvider>\n )\n}\n\n/**\n * Opens the page's default action (`$defaultAction`, `?tableAction=`) once the page has\n * hydrated, and once per page: re-renders after the action ran don't open it again.\n */\nexport function useDefaultAction(page: PageSchema | undefined) {\n const runner = useActionRunner()\n const opener = useRef<DefaultActionOpener>({ opened: null })\n\n useEffect(() => {\n openDefaultAction(page, opener.current, (action, context) => runner.trigger(action, context))\n }, [page, runner])\n}\n\n/** Sets the page's `$extraBodyAttributes` on `<body>` while it is open. */\nexport function useBodyAttributes(attributes: Record<string, string> | undefined) {\n const key = attributes ? JSON.stringify(attributes) : ''\n\n useEffect(\n () => applyBodyAttributes(key ? (JSON.parse(key) as Record<string, string>) : undefined),\n [key],\n )\n}\n\nexport function PageShell({ page, children }: { page: PageSchema; children: ReactNode }) {\n const { registry } = useAlfakit()\n\n useBodyAttributes(page.extraBodyAttributes)\n\n // Each layout can be replaced: createAlfakit({ components: { 'layout:app': MyLayout } }).\n if (page.layout === 'auth') {\n return createElement(\n registry.resolve('layout:auth') ?? AuthLayout,\n { heading: page.heading ?? page.title, subheading: page.subheading, page },\n children,\n )\n }\n\n if (page.layout === 'blank') {\n return createElement(registry.resolve('layout:blank') ?? BlankLayout, { page }, children)\n }\n\n if (page.layout === 'fullscreen') {\n return createElement(\n registry.resolve('layout:fullscreen') ?? FullscreenLayout,\n { page },\n children,\n )\n }\n\n return createElement(\n registry.resolve('layout:app') ?? AppLayout,\n { breadcrumbs: page.breadcrumbs, maxContentWidth: page.maxContentWidth, page },\n <>\n {/* `?` overlay, `/`, `g d` and panel command shortcuts (`keyboardShortcuts()`). */}\n <KeyboardShortcuts />\n <Slot name=\"page.start\" />\n <PageHeader page={page} />\n {/* Edit pages: somebody else saved the record (`detectConflicts()`, `Panel::realtime()`). */}\n {page.conflicts &&\n createElement(registry.resolve('page:conflict-banner') ?? ConflictBanner, { page })}\n {page.subNavigation ? (\n <SubNavigationLayout navigation={page.subNavigation}>{children}</SubNavigationLayout>\n ) : (\n children\n )}\n <Slot name=\"page.end\" />\n </>,\n )\n}\n\nexport function PageHeader({ page }: { page: PageSchema }) {\n const { registry } = useAlfakit()\n const actions = page.headerActions ?? []\n // `$headerActionsAlignment`: the default (end) sits beside the heading; the others\n // stack the actions under it.\n const alignment = page.headerActionsAlignment\n\n return (\n <>\n <Slot name=\"page.header.before\" />\n <header\n data-slot=\"page-header\"\n data-actions-alignment={alignment}\n className={cn(\n 'flex flex-col gap-4',\n !alignment && 'sm:flex-row sm:items-start sm:justify-between',\n )}\n >\n <div className=\"min-w-0\">\n <Slot name=\"page.heading.before\" />\n <h1 className=\"text-2xl font-semibold tracking-tight\">{page.heading ?? page.title}</h1>\n {page.subheading && (\n <p className=\"text-muted-foreground mt-1 text-sm\">{page.subheading}</p>\n )}\n <Slot name=\"page.heading.after\" />\n </div>\n <div\n className={cn(\n 'flex shrink-0 flex-wrap items-center gap-2',\n alignment === 'start'\n ? 'justify-start'\n : alignment === 'center'\n ? 'justify-center'\n : alignment === 'between' || alignment === 'justify'\n ? 'justify-between'\n : 'justify-end',\n )}\n >\n {/* Record pages with `Panel::realtime()`: who else is on the record. */}\n {page.presence &&\n createElement(registry.resolve('page:presence') ?? RecordPresence, {\n presence: page.presence,\n })}\n <Slot name=\"page.actions.before\" />\n {actions.length > 0 && (\n <ActionList\n actions={actions}\n context={{ token: page.token, component: 'page' }}\n align=\"end\"\n className=\"max-w-full shrink-0\"\n />\n )}\n <Slot name=\"page.actions.after\" />\n </div>\n </header>\n <Slot name=\"page.header.after\" />\n </>\n )\n}\n\nexport function PageContent({ page }: { page: PageSchema }) {\n return (\n <div className=\"flex flex-col gap-6\">\n {page.content.map((block) => (\n <ContentBlockRenderer key={block.key} block={block} />\n ))}\n </div>\n )\n}\n\nexport function ContentBlockRenderer({ block }: { block: ContentBlock }) {\n const { registry } = useAlfakit()\n // Links list tabs to the table they control.\n const tabsIdBase = `alfakit-list-tabs-${useId().replace(/[^A-Za-z0-9_-]/g, '')}`\n\n switch (block.type) {\n case 'Form':\n return <FormBlock block={block as FormBlockSchema} />\n case 'Infolist':\n return (\n <div data-slot=\"infolist\" className=\"contents\">\n <SchemaRenderer\n components={(block as InfolistBlock).components}\n columns={{ default: 1, lg: 2 }}\n />\n </div>\n )\n case 'Schema':\n return (\n <SchemaRenderer components={(block as SchemaBlock).components} columns={{ default: 1 }} />\n )\n case 'Table': {\n const table = block as TableBlockSchema\n const content = table.tabs?.length ? (\n <div className=\"flex flex-col gap-4\">\n <ListTabs\n tabs={table.tabs}\n activeTab={table.activeTab}\n tabsQueryKey={table.tabsQueryKey}\n label={table.pluralModelLabel}\n idBase={tabsIdBase}\n />\n <ListTabsPanel idBase={tabsIdBase} activeTab={table.activeTab}>\n <DataTable table={table} component={table.component} />\n </ListTabsPanel>\n </div>\n ) : (\n <DataTable table={table} component={table.component} />\n )\n\n if (block.key !== 'table') {\n return content\n }\n\n // The page's main table: the server sends these slots on List / ManageRelatedRecords pages only.\n return (\n <>\n <Slot name=\"resource.list-records.table.before\" />\n <Slot name=\"resource.manage-related-records.table.before\" />\n {content}\n <Slot name=\"resource.manage-related-records.table.after\" />\n <Slot name=\"resource.list-records.table.after\" />\n </>\n )\n }\n case 'RelationManagers':\n return <RelationManagers block={block as RelationManagersBlock} />\n case 'Widgets':\n return block.key === 'headerWidgets' ? (\n <>\n <Slot name=\"page.header-widgets.before\" />\n <WidgetGrid block={block as WidgetsBlockSchema} />\n <Slot name=\"page.header-widgets.after\" />\n </>\n ) : block.key === 'footerWidgets' ? (\n <>\n <Slot name=\"page.footer-widgets.before\" />\n <WidgetGrid block={block as WidgetsBlockSchema} />\n <Slot name=\"page.footer-widgets.after\" />\n </>\n ) : (\n <WidgetGrid block={block as WidgetsBlockSchema} />\n )\n case 'Links':\n return (\n <div className=\"flex flex-col items-center gap-1 text-center text-sm\">\n {(block as LinksBlock).links.map((link) => (\n <Link\n key={link.url}\n href={link.url}\n className=\"text-primary underline-offset-4 hover:underline\"\n >\n {link.label}\n </Link>\n ))}\n </div>\n )\n default: {\n const Custom = registry.resolve(block.type)\n\n return Custom ? createElement(Custom, { block }) : null\n }\n }\n}\n\nfunction RelationManagers({ block }: { block: RelationManagersBlock }) {\n const tabs = useMemo(() => relationManagerTabs(block), [block])\n // `?relation=`: a key in `getRelations()` or a position. The page URL (not\n // `window.location`) so the server renders the same tab as the browser.\n const url = usePage().url\n const [active, setActive] = useState(\n () =>\n relationTabFromQuery(\n tabs,\n new URL(url, 'http://localhost').searchParams.get(RELATION_QUERY_KEY),\n )?.key ??\n tabs[0]?.key ??\n '',\n )\n\n const changeTab = (key: string) => {\n setActive(key)\n\n if (typeof window === 'undefined') return\n\n const next = new URL(window.location.href)\n const slug = relationTabSlug(tabs, key)\n\n if (slug === null) next.searchParams.delete(RELATION_QUERY_KEY)\n else next.searchParams.set(RELATION_QUERY_KEY, slug)\n\n window.history.replaceState(window.history.state, '', next)\n }\n\n if (block.managers.length === 0) {\n return null\n }\n\n if (!hasRelationManagerTabs(block)) {\n const manager = block.managers[0]!\n\n return (\n <section className=\"flex flex-col gap-3\">\n <Slot name=\"resource.relation-manager.before\" scope={manager.key} />\n {isLazyPlaceholder(manager) ? (\n <LazyPlaceholder variant=\"table\" />\n ) : (\n <DataTable\n table={{ ...manager.table, heading: manager.table.heading ?? manager.title }}\n component={manager.component}\n />\n )}\n <Slot name=\"resource.relation-manager.after\" scope={manager.key} />\n </section>\n )\n }\n\n return (\n <Tabs value={active} onValueChange={changeTab}>\n <TabsList>\n <Slot name=\"resource.tabs.start\" />\n {tabs.map((tab) => (\n <TabsTrigger key={tab.key} value={tab.key}>\n {tab.icon && <Icon name={tab.icon} />}\n {tab.title}\n {tab.badge !== undefined && tab.badge !== null && tab.badge !== '' && (\n <Badge\n variant=\"secondary\"\n title={tab.badgeTooltip}\n className={cn(\n 'ms-1 px-1.5 py-0',\n tab.badgeColor && colorClass(badgeColorClasses, tab.badgeColor, 'gray'),\n )}\n >\n {tab.badge}\n {tab.badgeTooltip && <span className=\"sr-only\">{` (${tab.badgeTooltip})`}</span>}\n </Badge>\n )}\n </TabsTrigger>\n ))}\n <Slot name=\"resource.tabs.end\" />\n </TabsList>\n {tabs.map((tab) => (\n <TabsContent\n key={tab.key}\n value={tab.key}\n className=\"flex flex-col gap-6 pt-2 data-[state=inactive]:hidden\"\n data-slot={tab.group ? 'relation-group' : tab.content ? 'relation-content' : undefined}\n // The form keeps its unsaved state while another tab is open.\n forceMount={tab.content ? true : undefined}\n >\n {/* The page's form / infolist (`hasCombinedRelationManagerTabsWithContent()`). */}\n {tab.content && <ContentBlockRenderer block={tab.content as ContentBlock} />}\n {tab.managers.map((manager) => (\n <Fragment key={manager.key}>\n <Slot name=\"resource.relation-manager.before\" scope={manager.key} />\n {isLazyPlaceholder(manager) ? (\n <LazyPlaceholder variant=\"table\" />\n ) : (\n <DataTable\n // Inside a group each table keeps its own heading; a lone manager's is the tab.\n table={{\n ...manager.table,\n heading: tab.group ? (manager.table.heading ?? manager.title) : undefined,\n }}\n component={manager.component}\n />\n )}\n <Slot name=\"resource.relation-manager.after\" scope={manager.key} />\n </Fragment>\n ))}\n </TabsContent>\n ))}\n </Tabs>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"page.js","names":["FormBlock"],"sources":["../../src/pages/page.tsx"],"sourcesContent":["import type {\n ContentBlock,\n FormBlock as FormBlockSchema,\n InfolistBlock,\n LinksBlock,\n PageSchema,\n RelationManagersBlock,\n SchemaBlock,\n TableBlock as TableBlockSchema,\n WidgetsBlock as WidgetsBlockSchema,\n} from '@alfakit/core'\nimport {\n applyBodyAttributes,\n hasRelationManagerTabs,\n isLazyPlaceholder,\n openDefaultAction,\n RELATION_QUERY_KEY,\n relationManagerTabs,\n relationTabFromQuery,\n relationTabSlug,\n resolveLazyComponents,\n type DefaultActionOpener,\n} from '@alfakit/core'\nimport { Head, Link, usePage } from '@inertiajs/react'\nimport {\n createElement,\n Fragment,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react'\nimport { PageActionProvider } from '../components/actions/action-context'\nimport { ActionList } from '../components/actions/action-list'\nimport { FormBlock } from '../components/form/form-block'\nimport { KeyboardShortcuts } from '../components/panel/keyboard-shortcuts'\nimport { LazyPlaceholder } from '../components/panel/lazy-placeholder'\nimport { Slot } from '../components/panel/slot'\nimport { SubNavigationLayout } from '../components/panel/sub-navigation'\nimport { ConflictBanner } from '../components/realtime/conflict-banner'\nimport { RecordPresence } from '../components/realtime/record-presence'\nimport { SchemaRenderer } from '../components/schema/schema-renderer'\nimport { ListTabs, ListTabsPanel } from '../components/table/list-tabs'\nimport { DataTable } from '../components/table/table-block'\nimport { Badge } from '../components/ui/badge'\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '../components/ui/tabs'\nimport { WidgetGrid } from '../components/widgets/widgets-block'\nimport {\n useActionRunner,\n useAlfakit,\n useAlfakitProps,\n usePanel,\n useT,\n type AnyComponent,\n} from '../context'\nimport { BlankLayout } from '../layouts/blank-layout'\nimport { badgeColorClasses, colorClass } from '../lib/colors'\nimport { Icon } from '../lib/icons'\nimport { cn } from '../lib/utils'\n\n/**\n * `Alfakit/Page`: renders any schema-driven page. Custom pages (`Page::$component`) are\n * resolved from the `pages` map passed to `createAlfakit()`.\n */\nexport function AlfakitPage() {\n const props = useAlfakitProps()\n const panel = usePanel()\n const t = useT()\n const { pages } = useAlfakit()\n // Lazy widgets and relation managers arrive in a deferred prop after the first response.\n const page = useMemo(\n () => (props.page ? resolveLazyComponents(props.page, props.alfakitLazy) : undefined),\n [props.page, props.alfakitLazy],\n )\n\n useDefaultAction(page)\n\n if (!page) {\n return null\n }\n\n // Starter kit mode: the host's `title` callback adds the application name.\n const title = panel.starterKit ? page.title : `${page.title} - ${panel.brandName}`\n\n if (page.view) {\n const Custom = pages[page.view.component]\n\n if (!Custom) {\n return (\n <div className=\"text-destructive p-6\">\n {t(\n 'page_not_registered',\n { component: page.view.component },\n `Page component ${page.view.component} is not registered in createAlfakit({ pages }).`,\n )}\n </div>\n )\n }\n\n return (\n <PageActionProvider value={{ token: page.token, component: 'page' }}>\n <Head title={title} />\n <PageShell page={page}>\n <Custom {...page.view.props} page={page} />\n </PageShell>\n </PageActionProvider>\n )\n }\n\n return (\n <PageActionProvider value={{ token: page.token, component: 'page' }}>\n <Head title={title} />\n <PageShell page={page}>\n <PageContent page={page} />\n </PageShell>\n </PageActionProvider>\n )\n}\n\n/**\n * Opens the page's default action (`$defaultAction`, `?tableAction=`) once the page has\n * hydrated, and once per page: re-renders after the action ran don't open it again.\n */\nexport function useDefaultAction(page: PageSchema | undefined) {\n const runner = useActionRunner()\n const opener = useRef<DefaultActionOpener>({ opened: null })\n\n useEffect(() => {\n openDefaultAction(page, opener.current, (action, context) => runner.trigger(action, context))\n }, [page, runner])\n}\n\n/** Sets the page's `$extraBodyAttributes` on `<body>` while it is open. */\nexport function useBodyAttributes(attributes: Record<string, string> | undefined) {\n const key = attributes ? JSON.stringify(attributes) : ''\n\n useEffect(\n () => applyBodyAttributes(key ? (JSON.parse(key) as Record<string, string>) : undefined),\n [key],\n )\n}\n\n/**\n * The registered layout: `createAlfakit()` registers the panel's (`panelLayouts`), the starter\n * kit its content layout. Without one the page renders bare: importing the panel layouts here\n * would put the sidebar and top bar in every starter kit page.\n */\nfunction layout(registry: { resolve(key: string): AnyComponent | undefined }, key: string) {\n return registry.resolve(key) ?? BlankLayout\n}\n\nexport function PageShell({ page, children }: { page: PageSchema; children: ReactNode }) {\n const { registry } = useAlfakit()\n\n useBodyAttributes(page.extraBodyAttributes)\n\n // Each layout can be replaced: createAlfakit({ components: { 'layout:app': MyLayout } }).\n if (page.layout === 'auth') {\n return createElement(\n layout(registry, 'layout:auth'),\n { heading: page.heading ?? page.title, subheading: page.subheading, page },\n children,\n )\n }\n\n if (page.layout === 'blank') {\n return createElement(layout(registry, 'layout:blank'), { page }, children)\n }\n\n if (page.layout === 'fullscreen') {\n return createElement(layout(registry, 'layout:fullscreen'), { page }, children)\n }\n\n return createElement(\n layout(registry, 'layout:app'),\n { breadcrumbs: page.breadcrumbs, maxContentWidth: page.maxContentWidth, page },\n <>\n {/* `?` overlay, `/`, `g d` and panel command shortcuts (`keyboardShortcuts()`). */}\n <KeyboardShortcuts />\n <Slot name=\"page.start\" />\n <PageHeader page={page} />\n {/* Edit pages: somebody else saved the record (`detectConflicts()`, `Panel::realtime()`). */}\n {page.conflicts &&\n createElement(registry.resolve('page:conflict-banner') ?? ConflictBanner, { page })}\n {page.subNavigation ? (\n <SubNavigationLayout navigation={page.subNavigation}>{children}</SubNavigationLayout>\n ) : (\n children\n )}\n <Slot name=\"page.end\" />\n </>,\n )\n}\n\nexport function PageHeader({ page }: { page: PageSchema }) {\n const { registry } = useAlfakit()\n const actions = page.headerActions ?? []\n // `$headerActionsAlignment`: the default (end) sits beside the heading; the others\n // stack the actions under it.\n const alignment = page.headerActionsAlignment\n\n return (\n <>\n <Slot name=\"page.header.before\" />\n <header\n data-slot=\"page-header\"\n data-actions-alignment={alignment}\n className={cn(\n 'flex flex-col gap-4',\n !alignment && 'sm:flex-row sm:items-start sm:justify-between',\n )}\n >\n <div className=\"min-w-0\">\n <Slot name=\"page.heading.before\" />\n <h1 className=\"text-2xl font-semibold tracking-tight\">{page.heading ?? page.title}</h1>\n {page.subheading && (\n <p className=\"text-muted-foreground mt-1 text-sm\">{page.subheading}</p>\n )}\n <Slot name=\"page.heading.after\" />\n </div>\n <div\n className={cn(\n 'flex shrink-0 flex-wrap items-center gap-2',\n alignment === 'start'\n ? 'justify-start'\n : alignment === 'center'\n ? 'justify-center'\n : alignment === 'between' || alignment === 'justify'\n ? 'justify-between'\n : 'justify-end',\n )}\n >\n {/* Record pages with `Panel::realtime()`: who else is on the record. */}\n {page.presence &&\n createElement(registry.resolve('page:presence') ?? RecordPresence, {\n presence: page.presence,\n })}\n <Slot name=\"page.actions.before\" />\n {actions.length > 0 && (\n <ActionList\n actions={actions}\n context={{ token: page.token, component: 'page' }}\n align=\"end\"\n className=\"max-w-full shrink-0\"\n />\n )}\n <Slot name=\"page.actions.after\" />\n </div>\n </header>\n <Slot name=\"page.header.after\" />\n </>\n )\n}\n\nexport function PageContent({ page }: { page: PageSchema }) {\n return (\n <div className=\"flex flex-col gap-6\">\n {page.content.map((block) => (\n <ContentBlockRenderer key={block.key} block={block} />\n ))}\n </div>\n )\n}\n\nexport function ContentBlockRenderer({ block }: { block: ContentBlock }) {\n const { registry } = useAlfakit()\n // Links list tabs to the table they control.\n const tabsIdBase = `alfakit-list-tabs-${useId().replace(/[^A-Za-z0-9_-]/g, '')}`\n\n switch (block.type) {\n case 'Form':\n return <FormBlock block={block as FormBlockSchema} />\n case 'Infolist':\n return (\n <div data-slot=\"infolist\" className=\"contents\">\n <SchemaRenderer\n components={(block as InfolistBlock).components}\n columns={{ default: 1, lg: 2 }}\n />\n </div>\n )\n case 'Schema':\n return (\n <SchemaRenderer components={(block as SchemaBlock).components} columns={{ default: 1 }} />\n )\n case 'Table': {\n const table = block as TableBlockSchema\n const content = table.tabs?.length ? (\n <div className=\"flex flex-col gap-4\">\n <ListTabs\n tabs={table.tabs}\n activeTab={table.activeTab}\n tabsQueryKey={table.tabsQueryKey}\n label={table.pluralModelLabel}\n idBase={tabsIdBase}\n />\n <ListTabsPanel idBase={tabsIdBase} activeTab={table.activeTab}>\n <DataTable table={table} component={table.component} />\n </ListTabsPanel>\n </div>\n ) : (\n <DataTable table={table} component={table.component} />\n )\n\n if (block.key !== 'table') {\n return content\n }\n\n // The page's main table: the server sends these slots on List / ManageRelatedRecords pages only.\n return (\n <>\n <Slot name=\"resource.list-records.table.before\" />\n <Slot name=\"resource.manage-related-records.table.before\" />\n {content}\n <Slot name=\"resource.manage-related-records.table.after\" />\n <Slot name=\"resource.list-records.table.after\" />\n </>\n )\n }\n case 'RelationManagers':\n return <RelationManagers block={block as RelationManagersBlock} />\n case 'Widgets':\n return block.key === 'headerWidgets' ? (\n <>\n <Slot name=\"page.header-widgets.before\" />\n <WidgetGrid block={block as WidgetsBlockSchema} />\n <Slot name=\"page.header-widgets.after\" />\n </>\n ) : block.key === 'footerWidgets' ? (\n <>\n <Slot name=\"page.footer-widgets.before\" />\n <WidgetGrid block={block as WidgetsBlockSchema} />\n <Slot name=\"page.footer-widgets.after\" />\n </>\n ) : (\n <WidgetGrid block={block as WidgetsBlockSchema} />\n )\n case 'Links':\n return (\n <div className=\"flex flex-col items-center gap-1 text-center text-sm\">\n {(block as LinksBlock).links.map((link) => (\n <Link\n key={link.url}\n href={link.url}\n className=\"text-primary underline-offset-4 hover:underline\"\n >\n {link.label}\n </Link>\n ))}\n </div>\n )\n default: {\n const Custom = registry.resolve(block.type)\n\n return Custom ? createElement(Custom, { block }) : null\n }\n }\n}\n\nfunction RelationManagers({ block }: { block: RelationManagersBlock }) {\n const tabs = useMemo(() => relationManagerTabs(block), [block])\n // `?relation=`: a key in `getRelations()` or a position. The page URL (not\n // `window.location`) so the server renders the same tab as the browser.\n const url = usePage().url\n const [active, setActive] = useState(\n () =>\n relationTabFromQuery(\n tabs,\n new URL(url, 'http://localhost').searchParams.get(RELATION_QUERY_KEY),\n )?.key ??\n tabs[0]?.key ??\n '',\n )\n\n const changeTab = (key: string) => {\n setActive(key)\n\n if (typeof window === 'undefined') return\n\n const next = new URL(window.location.href)\n const slug = relationTabSlug(tabs, key)\n\n if (slug === null) next.searchParams.delete(RELATION_QUERY_KEY)\n else next.searchParams.set(RELATION_QUERY_KEY, slug)\n\n window.history.replaceState(window.history.state, '', next)\n }\n\n if (block.managers.length === 0) {\n return null\n }\n\n if (!hasRelationManagerTabs(block)) {\n const manager = block.managers[0]!\n\n return (\n <section className=\"flex flex-col gap-3\">\n <Slot name=\"resource.relation-manager.before\" scope={manager.key} />\n {isLazyPlaceholder(manager) ? (\n <LazyPlaceholder variant=\"table\" />\n ) : (\n <DataTable\n table={{ ...manager.table, heading: manager.table.heading ?? manager.title }}\n component={manager.component}\n />\n )}\n <Slot name=\"resource.relation-manager.after\" scope={manager.key} />\n </section>\n )\n }\n\n return (\n <Tabs value={active} onValueChange={changeTab}>\n <TabsList>\n <Slot name=\"resource.tabs.start\" />\n {tabs.map((tab) => (\n <TabsTrigger key={tab.key} value={tab.key}>\n {tab.icon && <Icon name={tab.icon} />}\n {tab.title}\n {tab.badge !== undefined && tab.badge !== null && tab.badge !== '' && (\n <Badge\n variant=\"secondary\"\n title={tab.badgeTooltip}\n className={cn(\n 'ms-1 px-1.5 py-0',\n tab.badgeColor && colorClass(badgeColorClasses, tab.badgeColor, 'gray'),\n )}\n >\n {tab.badge}\n {tab.badgeTooltip && <span className=\"sr-only\">{` (${tab.badgeTooltip})`}</span>}\n </Badge>\n )}\n </TabsTrigger>\n ))}\n <Slot name=\"resource.tabs.end\" />\n </TabsList>\n {tabs.map((tab) => (\n <TabsContent\n key={tab.key}\n value={tab.key}\n className=\"flex flex-col gap-6 pt-2 data-[state=inactive]:hidden\"\n data-slot={tab.group ? 'relation-group' : tab.content ? 'relation-content' : undefined}\n // The form keeps its unsaved state while another tab is open.\n forceMount={tab.content ? true : undefined}\n >\n {/* The page's form / infolist (`hasCombinedRelationManagerTabsWithContent()`). */}\n {tab.content && <ContentBlockRenderer block={tab.content as ContentBlock} />}\n {tab.managers.map((manager) => (\n <Fragment key={manager.key}>\n <Slot name=\"resource.relation-manager.before\" scope={manager.key} />\n {isLazyPlaceholder(manager) ? (\n <LazyPlaceholder variant=\"table\" />\n ) : (\n <DataTable\n // Inside a group each table keeps its own heading; a lone manager's is the tab.\n table={{\n ...manager.table,\n heading: tab.group ? (manager.table.heading ?? manager.title) : undefined,\n }}\n component={manager.component}\n />\n )}\n <Slot name=\"resource.relation-manager.after\" scope={manager.key} />\n </Fragment>\n ))}\n </TabsContent>\n ))}\n </Tabs>\n )\n}\n"],"mappings":"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"}
@@ -32,15 +32,20 @@ function AlfakitComponent({ component, components, className, header, footer, ch
32
32
  state.setComponent(component);
33
33
  const context = useMemo(() => {
34
34
  const poll = (target, interval) => state.poll(target, interval);
35
+ const refresh = (targets) => state.refresh(targets);
35
36
  if (parent) return {
36
37
  ...parent,
37
38
  registry: createStandaloneRegistry(components, parent.registry),
38
- poll
39
+ poll,
40
+ refresh
41
+ };
42
+ return {
43
+ ...createStandaloneContext({
44
+ action: component.endpoints.action,
45
+ modal: component.endpoints.modal
46
+ }, components, poll),
47
+ refresh
39
48
  };
40
- return createStandaloneContext({
41
- action: component.endpoints.action,
42
- modal: component.endpoints.modal
43
- }, components, poll);
44
49
  }, [
45
50
  parent,
46
51
  state,
@@ -63,7 +68,7 @@ function AlfakitComponent({ component, components, className, header, footer, ch
63
68
  const propName = findStandalonePropName(props, component);
64
69
  useEffect(() => registerStandaloneProp(propName ?? null), [propName]);
65
70
  useEffect(() => {
66
- state.loadLazy();
71
+ state.loadLazy(component);
67
72
  }, [state, component.token]);
68
73
  const [ownsToaster, setOwnsToaster] = useState(false);
69
74
  useEffect(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"alfakit-component.js","names":[],"sources":["../../src/standalone/alfakit-component.tsx"],"sourcesContent":["import {\n StandaloneComponentState,\n findStandalonePropName,\n registerStandaloneProp,\n standalonePanelSchema,\n type ContentBlock,\n type StandaloneComponentSchema,\n} from '@alfakit/core'\nimport { usePage } from '@inertiajs/react'\nimport { Direction } from 'radix-ui'\nimport { useEffect, useMemo, useState, type ReactNode } from 'react'\nimport { PageActionProvider } from '../components/actions/action-context'\nimport { ActionList } from '../components/actions/action-list'\nimport { ActionModals } from '../components/actions/action-modals'\nimport { TooltipProvider } from '../components/ui/tooltip'\nimport {\n AlfakitProvider,\n StandaloneProvider,\n useOptionalAlfakit,\n type AlfakitContextValue,\n type AnyComponent,\n} from '../context'\nimport { cn } from '../lib/utils'\nimport { ContentBlockRenderer } from '../pages/page'\nimport { AlfakitToaster } from './alfakit-toaster'\nimport {\n claimToaster,\n createStandaloneContext,\n createStandaloneRegistry,\n ensureStandaloneRuntime,\n hasToaster,\n} from './runtime'\n\nexport interface AlfakitComponentProps {\n /** The payload: `ContactForm::make()` passed as an Inertia prop. */\n component: StandaloneComponentSchema\n /** Renderer overrides for this instance (`{ TextInput: MyInput }`), on top of `configureAlfakit()`. */\n components?: Record<string, AnyComponent>\n className?: string\n /** Rendered above the content blocks (after the heading and actions). */\n header?: ReactNode\n /** Rendered below the content blocks. */\n footer?: ReactNode\n /** Render each content block yourself (e.g. to lay a form and a table side by side). */\n children?: (blocks: ContentBlock[], render: (block: ContentBlock) => ReactNode) => ReactNode\n}\n\n/**\n * Renders an Alfakit component outside a panel: a form, table, infolist, widgets or any mix\n * (`AlfaSix\\Alfakit\\Standalone\\*`) in any Inertia page of the application. Needs no\n * `createAlfakit()` and no panel layout: it provides its own translator, registry, action\n * runner and modals, and inherits the application's shadcn tokens.\n *\n * ```tsx\n * <AlfakitComponent component={orders} className=\"max-w-4xl\" />\n * ```\n */\nexport function AlfakitComponent({\n component,\n components,\n className,\n header,\n footer,\n children,\n}: AlfakitComponentProps) {\n const parent = useOptionalAlfakit()\n const props = useOptionalPageProps()\n const [, setVersion] = useState(0)\n // The registry overrides are an object literal in JSX: compare them by their keys.\n const overrideKeys = Object.keys(components ?? {}).join(',')\n\n // Lazy and polled schemas of this component, merged into the page it renders.\n const state = useMemo(\n () => new StandaloneComponentState(component, () => setVersion((value) => value + 1)),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n )\n state.setComponent(component)\n\n const context = useMemo<AlfakitContextValue>(() => {\n const poll = (target: string, interval: string | number | null | undefined) =>\n state.poll(target, interval)\n\n if (parent) {\n return { ...parent, registry: createStandaloneRegistry(components, parent.registry), poll }\n }\n\n return createStandaloneContext(\n { action: component.endpoints.action, modal: component.endpoints.modal },\n components,\n poll,\n )\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [parent, state, overrideKeys])\n\n // Endpoints follow the latest payload (they change per locale or path).\n context.actions.setEndpoints({\n action: component.endpoints.action,\n modal: component.endpoints.modal,\n })\n\n // Inside `createAlfakit()` the panel feeds the shared translator; on a page without the\n // `alfakit` prop (the rest of the app) the component's own translations apply.\n const ownsTranslator = !parent || !props?.alfakit\n\n if (ownsTranslator) {\n context.translator.setTranslations(component.translations ?? {})\n context.translator.setLocale(component.localization?.tag ?? 'en')\n }\n\n const panel = useMemo(() => standalonePanelSchema(component), [component])\n const page = state.page\n const direction = component.localization?.direction ?? 'ltr'\n\n useEffect(() => {\n ensureStandaloneRuntime()\n }, [])\n\n // Partial reloads (sorting, paging, inline edits) request this component's own prop.\n const propName = findStandalonePropName(props, component)\n\n useEffect(() => registerStandaloneProp(propName ?? null), [propName])\n\n useEffect(() => {\n void state.loadLazy()\n }, [state, component.token])\n\n // Toasts: use the layout's <AlfakitToaster /> when there is one, else the first component\n // on the page renders one (checked after every component's effects ran).\n const [ownsToaster, setOwnsToaster] = useState(false)\n\n useEffect(() => {\n if (parent) return\n\n let release: (() => void) | null = null\n let cancelled = false\n\n queueMicrotask(() => {\n if (cancelled || hasToaster()) return\n\n release = claimToaster()\n setOwnsToaster(true)\n })\n\n return () => {\n cancelled = true\n release?.()\n }\n }, [parent])\n\n const render = (block: ContentBlock) => <ContentBlockRenderer key={block.key} block={block} />\n const actionContext = useMemo(\n () => ({ token: component.token, component: 'page' }),\n [component.token],\n )\n\n const body = (\n <PageActionProvider value={actionContext}>\n <div\n data-slot=\"standalone\"\n data-alfakit-component={component.class}\n dir={direction}\n className={cn('flex flex-col gap-6', className)}\n >\n {(page.heading || page.headerActions?.length) && (\n <header\n data-slot=\"page-header\"\n className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\"\n >\n <div className=\"min-w-0\">\n {page.heading && (\n <h2 className=\"text-xl font-semibold tracking-tight\">{page.heading}</h2>\n )}\n {page.subheading && (\n <p className=\"text-muted-foreground mt-1 text-sm\">{page.subheading}</p>\n )}\n </div>\n {page.headerActions && page.headerActions.length > 0 && (\n <ActionList\n actions={page.headerActions}\n context={actionContext}\n align=\"end\"\n className=\"max-w-full shrink-0\"\n />\n )}\n </header>\n )}\n {header}\n {children ? children(page.content, render) : page.content.map(render)}\n {footer}\n </div>\n <ActionModals />\n {ownsToaster && <AlfakitToaster claimed />}\n </PageActionProvider>\n )\n\n return (\n <AlfakitProvider value={context}>\n <StandaloneProvider value={{ panel, page }}>\n {parent ? (\n body\n ) : (\n <Direction.Provider dir={direction}>\n <TooltipProvider delayDuration={0}>{body}</TooltipProvider>\n </Direction.Provider>\n )}\n </StandaloneProvider>\n </AlfakitProvider>\n )\n}\n\n/**\n * The host page's Inertia props, or undefined when rendered outside an Inertia app (a\n * component test, Storybook, a plain server render): partial reloads then reload every prop.\n */\nfunction useOptionalPageProps(): Record<string, unknown> | undefined {\n try {\n return usePage().props as Record<string, unknown>\n } catch {\n return undefined\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"alfakit-component.js","names":[],"sources":["../../src/standalone/alfakit-component.tsx"],"sourcesContent":["import {\n StandaloneComponentState,\n findStandalonePropName,\n registerStandaloneProp,\n standalonePanelSchema,\n type ContentBlock,\n type StandaloneComponentSchema,\n} from '@alfakit/core'\nimport { usePage } from '@inertiajs/react'\nimport { Direction } from 'radix-ui'\nimport { useEffect, useMemo, useState, type ReactNode } from 'react'\nimport { PageActionProvider } from '../components/actions/action-context'\nimport { ActionList } from '../components/actions/action-list'\nimport { ActionModals } from '../components/actions/action-modals'\nimport { TooltipProvider } from '../components/ui/tooltip'\nimport {\n AlfakitProvider,\n StandaloneProvider,\n useOptionalAlfakit,\n type AlfakitContextValue,\n type AnyComponent,\n} from '../context'\nimport { cn } from '../lib/utils'\nimport { ContentBlockRenderer } from '../pages/page'\nimport { AlfakitToaster } from './alfakit-toaster'\nimport {\n claimToaster,\n createStandaloneContext,\n createStandaloneRegistry,\n ensureStandaloneRuntime,\n hasToaster,\n} from './runtime'\n\nexport interface AlfakitComponentProps {\n /** The payload: `ContactForm::make()` passed as an Inertia prop. */\n component: StandaloneComponentSchema\n /** Renderer overrides for this instance (`{ TextInput: MyInput }`), on top of `configureAlfakit()`. */\n components?: Record<string, AnyComponent>\n className?: string\n /** Rendered above the content blocks (after the heading and actions). */\n header?: ReactNode\n /** Rendered below the content blocks. */\n footer?: ReactNode\n /** Render each content block yourself (e.g. to lay a form and a table side by side). */\n children?: (blocks: ContentBlock[], render: (block: ContentBlock) => ReactNode) => ReactNode\n}\n\n/**\n * Renders an Alfakit component outside a panel: a form, table, infolist, widgets or any mix\n * (`AlfaSix\\Alfakit\\Standalone\\*`) in any Inertia page of the application. Needs no\n * `createAlfakit()` and no panel layout: it provides its own translator, registry, action\n * runner and modals, and inherits the application's shadcn tokens.\n *\n * ```tsx\n * <AlfakitComponent component={orders} className=\"max-w-4xl\" />\n * ```\n */\nexport function AlfakitComponent({\n component,\n components,\n className,\n header,\n footer,\n children,\n}: AlfakitComponentProps) {\n const parent = useOptionalAlfakit()\n const props = useOptionalPageProps()\n const [, setVersion] = useState(0)\n // The registry overrides are an object literal in JSX: compare them by their keys.\n const overrideKeys = Object.keys(components ?? {}).join(',')\n\n // Lazy and polled schemas of this component, merged into the page it renders.\n const state = useMemo(\n () => new StandaloneComponentState(component, () => setVersion((value) => value + 1)),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n )\n state.setComponent(component)\n\n const context = useMemo<AlfakitContextValue>(() => {\n const poll = (target: string, interval: string | number | null | undefined) =>\n state.poll(target, interval)\n const refresh = (targets: string[]) => state.refresh(targets)\n\n if (parent) {\n return {\n ...parent,\n registry: createStandaloneRegistry(components, parent.registry),\n poll,\n refresh,\n }\n }\n\n return {\n ...createStandaloneContext(\n { action: component.endpoints.action, modal: component.endpoints.modal },\n components,\n poll,\n ),\n refresh,\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [parent, state, overrideKeys])\n\n // Endpoints follow the latest payload (they change per locale or path).\n context.actions.setEndpoints({\n action: component.endpoints.action,\n modal: component.endpoints.modal,\n })\n\n // Inside `createAlfakit()` the panel feeds the shared translator; on a page without the\n // `alfakit` prop (the rest of the app) the component's own translations apply.\n const ownsTranslator = !parent || !props?.alfakit\n\n if (ownsTranslator) {\n context.translator.setTranslations(component.translations ?? {})\n context.translator.setLocale(component.localization?.tag ?? 'en')\n }\n\n const panel = useMemo(() => standalonePanelSchema(component), [component])\n const page = state.page\n const direction = component.localization?.direction ?? 'ltr'\n\n useEffect(() => {\n ensureStandaloneRuntime()\n }, [])\n\n // Partial reloads (sorting, paging, inline edits) request this component's own prop.\n const propName = findStandalonePropName(props, component)\n\n useEffect(() => registerStandaloneProp(propName ?? null), [propName])\n\n useEffect(() => {\n void state.loadLazy(component)\n // The token identifies a new payload.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [state, component.token])\n\n // Toasts: use the layout's <AlfakitToaster /> when there is one, else the first component\n // on the page renders one (checked after every component's effects ran).\n const [ownsToaster, setOwnsToaster] = useState(false)\n\n useEffect(() => {\n if (parent) return\n\n let release: (() => void) | null = null\n let cancelled = false\n\n queueMicrotask(() => {\n if (cancelled || hasToaster()) return\n\n release = claimToaster()\n setOwnsToaster(true)\n })\n\n return () => {\n cancelled = true\n release?.()\n }\n }, [parent])\n\n const render = (block: ContentBlock) => <ContentBlockRenderer key={block.key} block={block} />\n const actionContext = useMemo(\n () => ({ token: component.token, component: 'page' }),\n [component.token],\n )\n\n const body = (\n <PageActionProvider value={actionContext}>\n <div\n data-slot=\"standalone\"\n data-alfakit-component={component.class}\n dir={direction}\n className={cn('flex flex-col gap-6', className)}\n >\n {(page.heading || page.headerActions?.length) && (\n <header\n data-slot=\"page-header\"\n className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\"\n >\n <div className=\"min-w-0\">\n {page.heading && (\n <h2 className=\"text-xl font-semibold tracking-tight\">{page.heading}</h2>\n )}\n {page.subheading && (\n <p className=\"text-muted-foreground mt-1 text-sm\">{page.subheading}</p>\n )}\n </div>\n {page.headerActions && page.headerActions.length > 0 && (\n <ActionList\n actions={page.headerActions}\n context={actionContext}\n align=\"end\"\n className=\"max-w-full shrink-0\"\n />\n )}\n </header>\n )}\n {header}\n {children ? children(page.content, render) : page.content.map(render)}\n {footer}\n </div>\n <ActionModals />\n {ownsToaster && <AlfakitToaster claimed />}\n </PageActionProvider>\n )\n\n return (\n <AlfakitProvider value={context}>\n <StandaloneProvider value={{ panel, page }}>\n {parent ? (\n body\n ) : (\n <Direction.Provider dir={direction}>\n <TooltipProvider delayDuration={0}>{body}</TooltipProvider>\n </Direction.Provider>\n )}\n </StandaloneProvider>\n </AlfakitProvider>\n )\n}\n\n/**\n * The host page's Inertia props, or undefined when rendered outside an Inertia app (a\n * component test, Storybook, a plain server render): partial reloads then reload every prop.\n */\nfunction useOptionalPageProps(): Record<string, unknown> | undefined {\n try {\n return usePage().props as Record<string, unknown>\n } catch {\n return undefined\n }\n}\n"],"mappings":"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"}