@alfakit/react 0.1.1 → 0.1.6

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 (219) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/components/actions/action-button.d.ts.map +1 -1
  3. package/dist/components/actions/action-button.js +5 -4
  4. package/dist/components/actions/action-button.js.map +1 -1
  5. package/dist/components/actions/action-modals.d.ts.map +1 -1
  6. package/dist/components/actions/action-modals.js +6 -5
  7. package/dist/components/actions/action-modals.js.map +1 -1
  8. package/dist/components/ai/copilot.d.ts +3 -1
  9. package/dist/components/ai/copilot.d.ts.map +1 -1
  10. package/dist/components/ai/copilot.js +4 -1
  11. package/dist/components/ai/copilot.js.map +1 -1
  12. package/dist/components/cms/live-preview.js +3 -2
  13. package/dist/components/cms/live-preview.js.map +1 -1
  14. package/dist/components/cms/page.js +1 -1
  15. package/dist/components/fields/builder.js +15 -6
  16. package/dist/components/fields/builder.js.map +1 -1
  17. package/dist/components/fields/color-picker.js +1 -0
  18. package/dist/components/fields/color-picker.js.map +1 -1
  19. package/dist/components/fields/file-upload.js +11 -10
  20. package/dist/components/fields/file-upload.js.map +1 -1
  21. package/dist/components/fields/image-editor-dialog.js +4 -2
  22. package/dist/components/fields/image-editor-dialog.js.map +1 -1
  23. package/dist/components/fields/item-actions.js +10 -10
  24. package/dist/components/fields/item-actions.js.map +1 -1
  25. package/dist/components/fields/key-value.d.ts.map +1 -1
  26. package/dist/components/fields/key-value.js +3 -3
  27. package/dist/components/fields/key-value.js.map +1 -1
  28. package/dist/components/fields/modal-table-select.js +6 -5
  29. package/dist/components/fields/modal-table-select.js.map +1 -1
  30. package/dist/components/fields/one-time-code-input.js +1 -1
  31. package/dist/components/fields/one-time-code-input.js.map +1 -1
  32. package/dist/components/fields/repeater-table.js +12 -1
  33. package/dist/components/fields/repeater-table.js.map +1 -1
  34. package/dist/components/fields/repeater.js +2 -2
  35. package/dist/components/fields/repeater.js.map +1 -1
  36. package/dist/components/fields/rich-editor.js +2 -1
  37. package/dist/components/fields/rich-editor.js.map +1 -1
  38. package/dist/components/fields/select.js +3 -3
  39. package/dist/components/fields/select.js.map +1 -1
  40. package/dist/components/file-manager/file-manager.js +1 -1
  41. package/dist/components/file-manager/file-manager.js.map +1 -1
  42. package/dist/components/form/form-block.d.ts.map +1 -1
  43. package/dist/components/form/form-block.js +14 -2
  44. package/dist/components/form/form-block.js.map +1 -1
  45. package/dist/components/form/form-context.js +7 -3
  46. package/dist/components/form/form-context.js.map +1 -1
  47. package/dist/components/kanban/kanban.js +4 -3
  48. package/dist/components/kanban/kanban.js.map +1 -1
  49. package/dist/components/layout/fused-group.js +1 -0
  50. package/dist/components/layout/fused-group.js.map +1 -1
  51. package/dist/components/layout/section.js +2 -2
  52. package/dist/components/layout/section.js.map +1 -1
  53. package/dist/components/layout/tabs.d.ts.map +1 -1
  54. package/dist/components/layout/tabs.js +54 -15
  55. package/dist/components/layout/tabs.js.map +1 -1
  56. package/dist/components/panel/app-sidebar.d.ts +2 -3
  57. package/dist/components/panel/app-sidebar.d.ts.map +1 -1
  58. package/dist/components/panel/app-sidebar.js +1 -24
  59. package/dist/components/panel/app-sidebar.js.map +1 -1
  60. package/dist/components/panel/brand.d.ts +10 -0
  61. package/dist/components/panel/brand.d.ts.map +1 -0
  62. package/dist/components/panel/brand.js +37 -0
  63. package/dist/components/panel/brand.js.map +1 -0
  64. package/dist/components/panel/global-search.js +1 -0
  65. package/dist/components/panel/global-search.js.map +1 -1
  66. package/dist/components/panel/index.d.ts +2 -1
  67. package/dist/components/panel/shortcut-keys.js +1 -0
  68. package/dist/components/panel/shortcut-keys.js.map +1 -1
  69. package/dist/components/panel/tenant-menu.js +2 -2
  70. package/dist/components/panel/tenant-menu.js.map +1 -1
  71. package/dist/components/panel/topbar.js +1 -1
  72. package/dist/components/realtime/live-records-pill.d.ts.map +1 -1
  73. package/dist/components/realtime/live-records-pill.js +6 -3
  74. package/dist/components/realtime/live-records-pill.js.map +1 -1
  75. package/dist/components/table/cells.d.ts +6 -0
  76. package/dist/components/table/cells.d.ts.map +1 -1
  77. package/dist/components/table/cells.js +15 -3
  78. package/dist/components/table/cells.js.map +1 -1
  79. package/dist/components/table/column-manager.js +8 -7
  80. package/dist/components/table/column-manager.js.map +1 -1
  81. package/dist/components/table/content-layout.js +2 -1
  82. package/dist/components/table/content-layout.js.map +1 -1
  83. package/dist/components/table/grouping.js +11 -1
  84. package/dist/components/table/grouping.js.map +1 -1
  85. package/dist/components/table/pagination.js +16 -13
  86. package/dist/components/table/pagination.js.map +1 -1
  87. package/dist/components/table/table-block.js +14 -4
  88. package/dist/components/table/table-block.js.map +1 -1
  89. package/dist/components/ui/dialog.d.ts.map +1 -1
  90. package/dist/components/ui/dialog.js +3 -1
  91. package/dist/components/ui/dialog.js.map +1 -1
  92. package/dist/components/ui/popover.d.ts.map +1 -1
  93. package/dist/components/ui/popover.js +3 -1
  94. package/dist/components/ui/popover.js.map +1 -1
  95. package/dist/components/ui/sheet.d.ts.map +1 -1
  96. package/dist/components/ui/sheet.js +3 -1
  97. package/dist/components/ui/sheet.js.map +1 -1
  98. package/dist/components/ui/tooltip.js +3 -1
  99. package/dist/components/ui/tooltip.js.map +1 -1
  100. package/dist/components.css +347 -0
  101. package/dist/context.d.ts +5 -0
  102. package/dist/context.d.ts.map +1 -1
  103. package/dist/context.js +5 -1
  104. package/dist/context.js.map +1 -1
  105. package/dist/create-alfakit.d.ts.map +1 -1
  106. package/dist/create-alfakit.js +8 -5
  107. package/dist/create-alfakit.js.map +1 -1
  108. package/dist/eject-manifest.json +16 -3
  109. package/dist/index.d.ts +6 -3
  110. package/dist/index.js +24 -21
  111. package/dist/layouts/app-layout.d.ts.map +1 -1
  112. package/dist/layouts/app-layout.js +2 -29
  113. package/dist/layouts/app-layout.js.map +1 -1
  114. package/dist/layouts/auth-layout.js +2 -2
  115. package/dist/layouts/auth-layout.js.map +1 -1
  116. package/dist/layouts/fullscreen-layout.js +1 -1
  117. package/dist/layouts/fullscreen-layout.js.map +1 -1
  118. package/dist/layouts/lazy-layouts.js +15 -0
  119. package/dist/layouts/lazy-layouts.js.map +1 -0
  120. package/dist/layouts/max-widths.js +34 -0
  121. package/dist/layouts/max-widths.js.map +1 -0
  122. package/dist/layouts/panel-layouts.d.ts +10 -0
  123. package/dist/layouts/panel-layouts.d.ts.map +1 -0
  124. package/dist/layouts/panel-layouts.js +20 -0
  125. package/dist/layouts/panel-layouts.js.map +1 -0
  126. package/dist/layouts/top-nav-layout.js +2 -2
  127. package/dist/layouts/top-nav-layout.js.map +1 -1
  128. package/dist/pages/page.d.ts.map +1 -1
  129. package/dist/pages/page.js +12 -7
  130. package/dist/pages/page.js.map +1 -1
  131. package/dist/standalone/alfakit-component.js +11 -6
  132. package/dist/standalone/alfakit-component.js.map +1 -1
  133. package/dist/standalone/alfakit-toaster.d.ts.map +1 -1
  134. package/dist/standalone/alfakit-toaster.js +8 -1
  135. package/dist/standalone/alfakit-toaster.js.map +1 -1
  136. package/dist/standalone.css +54 -0
  137. package/dist/starter-kit/dashboard-widgets.d.ts +33 -0
  138. package/dist/starter-kit/dashboard-widgets.d.ts.map +1 -0
  139. package/dist/starter-kit/dashboard-widgets.js +53 -0
  140. package/dist/starter-kit/dashboard-widgets.js.map +1 -0
  141. package/dist/starter-kit/impersonation-banner.js +34 -0
  142. package/dist/starter-kit/impersonation-banner.js.map +1 -0
  143. package/dist/starter-kit/index.d.ts +3 -2
  144. package/dist/starter-kit/index.js +3 -2
  145. package/dist/starter-kit/starter-kit.d.ts +6 -0
  146. package/dist/starter-kit/starter-kit.d.ts.map +1 -1
  147. package/dist/starter-kit/starter-kit.js +18 -7
  148. package/dist/starter-kit/starter-kit.js.map +1 -1
  149. package/dist/starter-kit/widgets-loaded.js +21 -5
  150. package/dist/starter-kit/widgets-loaded.js.map +1 -1
  151. package/dist/starter-kit/widgets-triggers.js +35 -3
  152. package/dist/starter-kit/widgets-triggers.js.map +1 -1
  153. package/dist/starter-kit/widgets.d.ts +13 -5
  154. package/dist/starter-kit/widgets.d.ts.map +1 -1
  155. package/dist/starter-kit/widgets.js +56 -18
  156. package/dist/starter-kit/widgets.js.map +1 -1
  157. package/dist/styles.css +15 -2
  158. package/dist/themes.css +8 -335
  159. package/package.json +2 -2
  160. package/src/components/actions/action-button.tsx +7 -4
  161. package/src/components/actions/action-modals.tsx +13 -1
  162. package/src/components/ai/copilot.tsx +14 -1
  163. package/src/components/cms/live-preview.tsx +5 -2
  164. package/src/components/fields/builder.tsx +14 -5
  165. package/src/components/fields/color-picker.tsx +1 -0
  166. package/src/components/fields/file-upload.tsx +21 -10
  167. package/src/components/fields/image-editor-dialog.tsx +7 -2
  168. package/src/components/fields/item-actions.tsx +32 -9
  169. package/src/components/fields/key-value.tsx +3 -2
  170. package/src/components/fields/modal-table-select.tsx +8 -3
  171. package/src/components/fields/one-time-code-input.tsx +1 -1
  172. package/src/components/fields/repeater-table.tsx +12 -1
  173. package/src/components/fields/repeater.tsx +2 -3
  174. package/src/components/fields/rich-editor.tsx +3 -0
  175. package/src/components/fields/select.tsx +7 -3
  176. package/src/components/file-manager/file-manager.tsx +1 -1
  177. package/src/components/form/form-block.tsx +26 -1
  178. package/src/components/form/form-context.tsx +3 -6
  179. package/src/components/kanban/kanban.tsx +16 -3
  180. package/src/components/layout/fused-group.tsx +5 -1
  181. package/src/components/layout/section.tsx +2 -2
  182. package/src/components/layout/tabs.tsx +72 -17
  183. package/src/components/panel/app-sidebar.tsx +2 -38
  184. package/src/components/panel/brand.tsx +46 -0
  185. package/src/components/panel/global-search.tsx +1 -1
  186. package/src/components/panel/shortcut-keys.tsx +4 -1
  187. package/src/components/panel/tenant-menu.tsx +2 -2
  188. package/src/components/realtime/live-records-pill.tsx +4 -3
  189. package/src/components/table/cells.tsx +27 -5
  190. package/src/components/table/column-manager.tsx +12 -10
  191. package/src/components/table/content-layout.tsx +5 -1
  192. package/src/components/table/grouping.tsx +15 -1
  193. package/src/components/table/pagination.tsx +16 -9
  194. package/src/components/table/table-block.tsx +25 -12
  195. package/src/components/ui/dialog.tsx +5 -1
  196. package/src/components/ui/popover.tsx +5 -1
  197. package/src/components/ui/sheet.tsx +5 -1
  198. package/src/components/ui/tooltip.tsx +5 -1
  199. package/src/context.tsx +10 -0
  200. package/src/create-alfakit.tsx +11 -2
  201. package/src/index.ts +2 -0
  202. package/src/layouts/app-layout.tsx +4 -28
  203. package/src/layouts/auth-layout.tsx +2 -2
  204. package/src/layouts/fullscreen-layout.tsx +1 -1
  205. package/src/layouts/lazy-layouts.ts +14 -0
  206. package/src/layouts/max-widths.ts +29 -0
  207. package/src/layouts/panel-layouts.ts +17 -0
  208. package/src/layouts/top-nav-layout.tsx +2 -2
  209. package/src/pages/page.tsx +21 -12
  210. package/src/standalone/alfakit-component.tsx +18 -7
  211. package/src/standalone/alfakit-toaster.tsx +21 -2
  212. package/src/starter-kit/dashboard-widgets.tsx +78 -0
  213. package/src/starter-kit/impersonation-banner.tsx +48 -0
  214. package/src/starter-kit/index.ts +2 -0
  215. package/src/starter-kit/starter-kit.tsx +31 -4
  216. package/src/starter-kit/widgets-loaded.tsx +23 -1
  217. package/src/starter-kit/widgets-triggers.tsx +37 -2
  218. package/src/starter-kit/widgets.tsx +95 -20
  219. package/src/styles.css +15 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impersonation-banner.js","names":[],"sources":["../../src/starter-kit/impersonation-banner.tsx"],"sourcesContent":["import type { ImpersonationSchema } from '@alfakit/core'\nimport { useEffect, useState, useSyncExternalStore } from 'react'\nimport { ImpersonationBanner } from '../components/panel/impersonation-banner'\n\n// The header components appear in both header layouts and next to each other: the first\n// one mounted shows the banner, the others render nothing.\nlet owner: symbol | null = null\nconst listeners = new Set<() => void>()\n\nfunction setOwner(next: symbol | null): void {\n owner = next\n listeners.forEach((listener) => listener())\n}\n\nfunction subscribe(listener: () => void): () => void {\n listeners.add(listener)\n\n return () => listeners.delete(listener)\n}\n\n/**\n * The impersonation banner (who you are signed in as, **Leave**) on the host's own pages,\n * rendered by the header components. Loaded only while impersonating; AlfaKit's pages\n * render their own (`AlfakitRoot`).\n */\nexport default function StarterKitImpersonationBanner({\n impersonation,\n}: {\n impersonation: ImpersonationSchema\n}) {\n const [id] = useState(() => Symbol('impersonation-banner'))\n // Claimed once mounted (effects never run on the server), so SSR and hydration skip it.\n const owns = useSyncExternalStore(\n subscribe,\n () => owner === id,\n () => false,\n )\n\n useEffect(() => {\n if (owner === null) setOwner(id)\n\n return () => {\n if (owner === id) setOwner(null)\n }\n }, [id])\n\n return owns ? <ImpersonationBanner impersonation={impersonation} /> : null\n}\n"],"mappings":";;;;AAMA,IAAI,QAAuB;AAC3B,MAAM,4BAAY,IAAI,IAAgB;AAEtC,SAAS,SAAS,MAA2B;CAC3C,QAAQ;CACR,UAAU,SAAS,aAAa,SAAS,CAAC;AAC5C;AAEA,SAAS,UAAU,UAAkC;CACnD,UAAU,IAAI,QAAQ;CAEtB,aAAa,UAAU,OAAO,QAAQ;AACxC;;;;;;AAOA,SAAwB,8BAA8B,EACpD,iBAGC;CACD,MAAM,CAAC,MAAM,eAAe,OAAO,sBAAsB,CAAC;CAE1D,MAAM,OAAO,qBACX,iBACM,UAAU,UACV,KACR;CAEA,gBAAgB;EACd,IAAI,UAAU,MAAM,SAAS,EAAE;EAE/B,aAAa;GACX,IAAI,UAAU,IAAI,SAAS,IAAI;EACjC;CACF,GAAG,CAAC,EAAE,CAAC;CAEP,OAAO,OAAO,oBAAC,qBAAD,EAAoC,cAAgB,CAAA,IAAI;AACxE"}
@@ -1,4 +1,5 @@
1
+ import { AlfakitWidgets, AlfakitWidgetsProps } from "./dashboard-widgets.js";
1
2
  import { AlfakitNavigation, useAlfakitNavigation } from "./navigation.js";
2
3
  import { AlfakitStarterKitRoot, StarterKitContentLayout, StarterKitLayout, StarterKitPageOptions, createStarterKitPage } from "./starter-kit.js";
3
- import { AlfakitHeaderWidgetProps, AlfakitNotifications, AlfakitSearch, AlfakitTenantSwitcher } from "./widgets.js";
4
- export { type AlfakitHeaderWidgetProps, type AlfakitNavigation, AlfakitNotifications, AlfakitSearch, AlfakitStarterKitRoot, AlfakitTenantSwitcher, StarterKitContentLayout, type StarterKitLayout, type StarterKitPageOptions, createStarterKitPage, useAlfakitNavigation };
4
+ import { AlfakitCopilot, AlfakitHeaderWidgetProps, AlfakitNotifications, AlfakitSearch, AlfakitTenantSwitcher } from "./widgets.js";
5
+ export { AlfakitCopilot, type AlfakitHeaderWidgetProps, type AlfakitNavigation, AlfakitNotifications, AlfakitSearch, AlfakitStarterKitRoot, AlfakitTenantSwitcher, AlfakitWidgets, type AlfakitWidgetsProps, StarterKitContentLayout, type StarterKitLayout, type StarterKitPageOptions, createStarterKitPage, useAlfakitNavigation };
@@ -1,4 +1,5 @@
1
+ import { AlfakitWidgets } from "./dashboard-widgets.js";
1
2
  import { useAlfakitNavigation } from "./navigation.js";
2
3
  import { AlfakitStarterKitRoot, StarterKitContentLayout, createStarterKitPage } from "./starter-kit.js";
3
- import { AlfakitNotifications, AlfakitSearch, AlfakitTenantSwitcher } from "./widgets.js";
4
- export { AlfakitNotifications, AlfakitSearch, AlfakitStarterKitRoot, AlfakitTenantSwitcher, StarterKitContentLayout, createStarterKitPage, useAlfakitNavigation };
4
+ import { AlfakitCopilot, AlfakitNotifications, AlfakitSearch, AlfakitTenantSwitcher } from "./widgets.js";
5
+ export { AlfakitCopilot, AlfakitNotifications, AlfakitSearch, AlfakitStarterKitRoot, AlfakitTenantSwitcher, AlfakitWidgets, StarterKitContentLayout, createStarterKitPage, useAlfakitNavigation };
@@ -15,6 +15,12 @@ export interface StarterKitPageOptions extends Pick<AlfakitOptions<AnyComponent>
15
15
  * `null` renders the pages without a host layout.
16
16
  */
17
17
  layout?: StarterKitLayout | null;
18
+ /**
19
+ * Auto-registered custom components, as for `createAlfakit({ discover })`: pass
20
+ * `import.meta.glob('../../alfakit/{fields,columns,entries,widgets,pages,components,blocks}/**\/*.tsx')`
21
+ * from `resources/js/pages/Alfakit/Page.tsx` and every file there registers under its name.
22
+ */
23
+ discover?: AlfakitOptions<AnyComponent>['discover'];
18
24
  }
19
25
  /**
20
26
  * The content area of an Alfakit page inside the host layout: what `layout:app` renders in
@@ -1 +1 @@
1
- {"version":3,"file":"starter-kit.d.ts","names":[],"sources":["../../src/starter-kit/starter-kit.tsx"],"mappings":";;;;;;YAgCY,mBAAmB;EAC7B,cAAc;EACd,UAAU;;iBAGK,8BAA8B,KAC7C,eAAe;;;;;;EAQf,SAAS;;;;;;;wBAQK,0BAA0B,UAAU,mBAAmB,iCAAc,IAAA;;;;;;wBAgErE,wBACd,SACA;EAEA,UAAU;EACV,WAAW;oBACZ,IAAA;;;;;;;;;;;;;;wBAmDe,qBAAqB,UAAS;;EAYL,OAAA,OAAA,qCAAuB"}
1
+ {"version":3,"file":"starter-kit.d.ts","names":[],"sources":["../../src/starter-kit/starter-kit.tsx"],"mappings":";;;;;;YAqCY,mBAAmB;EAC7B,cAAc;EACd,UAAU;;iBAGK,8BAA8B,KAC7C,eAAe;;;;;;EAQf,SAAS;;;;;;EAMT,WAAW,eAAe;;;;;;;wBAQZ,0BAA0B,UAAU,mBAAmB,iCAAc,IAAA;;;;;;wBAuErE,wBACd,SACA;EAEA,UAAU;EACV,WAAW;oBACZ,IAAA;;;;;;;;;;;;;;wBA4De,qBAAqB,UAAS;;EAYL,OAAA,OAAA,qCAAuB"}
@@ -1,13 +1,16 @@
1
1
  import { AlfakitProvider, useAlfakitProps } from "../context.js";
2
2
  import { cn } from "../lib/utils.js";
3
3
  import { preloadIcons } from "../lib/icons.js";
4
+ import { discoverComponents } from "../lib/discovery.js";
4
5
  import { createDefaultRegistry } from "../registry.js";
5
6
  import { setToasterId, showToast } from "../components/notifications/flash-toasts.js";
6
7
  import { Slot } from "../components/panel/slot.js";
7
- import { MAX_WIDTHS } from "../layouts/app-layout.js";
8
8
  import { AlfakitPage } from "../pages/page.js";
9
+ import { MAX_WIDTHS } from "../layouts/max-widths.js";
10
+ import { AuthLayout } from "../layouts/auth-layout.js";
9
11
  import { AlfakitRoot } from "../create-alfakit.js";
10
- import { ActionRunner, STARTER_KIT_TOASTER_ID, Translator, configureCharts, installStarterKitRuntime, registerRichEditorExtensions, resolveRequestErrorNotification, starterKitBreadcrumbsFromProps, syncStarterKitPage } from "@alfakit/core";
12
+ import { lazyPanelLayouts } from "../layouts/lazy-layouts.js";
13
+ import { ActionRunner, STARTER_KIT_TOASTER_ID, Translator, configureCharts, installStarterKitRuntime, registerRichEditorExtensions, resolveRequestErrorNotification, starterKitBreadcrumbsFromProps, syncStarterKitPage, usesStarterKitHostLayout } from "@alfakit/core";
11
14
  import { usePage } from "@inertiajs/react";
12
15
  import { useEffect, useState } from "react";
13
16
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -33,12 +36,14 @@ function StarterKitContentLayout({ children, maxContentWidth }) {
33
36
  }
34
37
  let browserContext = null;
35
38
  function createStarterKitContext(options) {
36
- const registry = createDefaultRegistry().register("layout:app", StarterKitContentLayout).registerMany(options.components ?? {});
39
+ const discovered = discoverComponents(options.discover);
40
+ const registry = createDefaultRegistry().registerMany(lazyPanelLayouts).register("layout:auth", AuthLayout).register("layout:app", StarterKitContentLayout).registerMany(discovered.components).registerMany(options.components ?? {});
37
41
  const translator = new Translator();
38
42
  return {
39
43
  registry,
40
44
  pages: {
41
45
  "Alfakit/Page": AlfakitPage,
46
+ ...discovered.pages,
42
47
  ...options.pages
43
48
  },
44
49
  translator,
@@ -85,9 +90,15 @@ function AlfakitStarterKitRoot({ options, children }) {
85
90
  }, [context]);
86
91
  return /* @__PURE__ */ jsx(AlfakitProvider, {
87
92
  value: context,
88
- children: /* @__PURE__ */ jsx(AlfakitRoot, {
89
- toasterId: STARTER_KIT_TOASTER_ID,
90
- children
93
+ children: /* @__PURE__ */ jsx("div", {
94
+ "data-slot": "starter-kit-root",
95
+ dir: panel?.localization?.direction ?? "ltr",
96
+ lang: panel?.localization?.tag,
97
+ className: "contents",
98
+ children: /* @__PURE__ */ jsx(AlfakitRoot, {
99
+ toasterId: STARTER_KIT_TOASTER_ID,
100
+ children
101
+ })
91
102
  })
92
103
  });
93
104
  }
@@ -111,7 +122,7 @@ function createStarterKitPage(options = {}) {
111
122
  function AlfakitStarterKitPage() {
112
123
  return /* @__PURE__ */ jsx(AlfakitPage, {});
113
124
  }
114
- AlfakitStarterKitPage.layout = (props) => [...options.layout ? [[options.layout, { breadcrumbs: starterKitBreadcrumbsFromProps(props) }]] : [], [AlfakitStarterKitRoot, { options }]];
125
+ AlfakitStarterKitPage.layout = (props) => [...options.layout && usesStarterKitHostLayout(props) ? [[options.layout, { breadcrumbs: starterKitBreadcrumbsFromProps(props) }]] : [], [AlfakitStarterKitRoot, { options }]];
115
126
  return AlfakitStarterKitPage;
116
127
  }
117
128
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"starter-kit.js","names":[],"sources":["../../src/starter-kit/starter-kit.tsx"],"sourcesContent":["import {\n ActionRunner,\n STARTER_KIT_TOASTER_ID,\n Translator,\n configureCharts,\n installStarterKitRuntime,\n registerRichEditorExtensions,\n resolveRequestErrorNotification,\n starterKitBreadcrumbsFromProps,\n syncStarterKitPage,\n type AlfakitOptions,\n type AlfakitPageProps,\n type StarterKitBreadcrumb,\n} from '@alfakit/core'\nimport { usePage } from '@inertiajs/react'\nimport { useEffect, useState, type ComponentType, type ReactNode } from 'react'\nimport { setToasterId, showToast } from '../components/notifications/flash-toasts'\nimport { Slot } from '../components/panel/slot'\nimport {\n AlfakitProvider,\n useAlfakitProps,\n type AlfakitContextValue,\n type AnyComponent,\n} from '../context'\nimport { AlfakitRoot } from '../create-alfakit'\nimport { MAX_WIDTHS, type AppLayoutProps } from '../layouts/app-layout'\nimport { preloadIcons } from '../lib/icons'\nimport { cn } from '../lib/utils'\nimport { AlfakitPage } from '../pages/page'\nimport { createDefaultRegistry } from '../registry'\n\n/** The host's layout, as the starter kits' `AppLayout` takes its props. */\nexport type StarterKitLayout = ComponentType<{\n breadcrumbs?: StarterKitBreadcrumb[]\n children: ReactNode\n}>\n\nexport interface StarterKitPageOptions extends Pick<\n AlfakitOptions<AnyComponent>,\n 'components' | 'pages' | 'chartFormatters' | 'chartPlugins' | 'richEditorExtensions'\n> {\n /**\n * The host layout Alfakit pages render in, usually the starter kit's `AppLayout`\n * (`@/layouts/app-layout`). It receives the page's breadcrumbs as `{ title, href }`.\n * `null` renders the pages without a host layout.\n */\n layout?: StarterKitLayout | null\n}\n\n/**\n * The content area of an Alfakit page inside the host layout: what `layout:app` renders in\n * starter kit mode instead of Alfakit's sidebar and top bar. Replace it with\n * `createStarterKitPage({ components: { 'layout:app': MyContent } })`.\n */\nexport function StarterKitContentLayout({ children, maxContentWidth }: AppLayoutProps) {\n const props = useAlfakitProps()\n // The host's pages fill the content area, so starter kit pages default to the full width.\n const width = maxContentWidth ?? props.alfakit.maxContentWidth ?? 'full'\n\n return (\n <div\n data-slot=\"content\"\n data-alfakit-embedded=\"\"\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-full',\n )}\n >\n <Slot name=\"content.start\" />\n {children}\n <Slot name=\"content.end\" />\n </div>\n )\n}\n\n// One context for the browser session (it survives navigations between host and Alfakit\n// pages); a server render builds one per request so concurrent renders never share a locale.\nlet browserContext: AlfakitContextValue | null = null\n\nfunction createStarterKitContext(options: StarterKitPageOptions): AlfakitContextValue {\n const registry = createDefaultRegistry()\n .register('layout:app', StarterKitContentLayout)\n .registerMany(options.components ?? {})\n const translator = new Translator()\n\n return {\n registry,\n pages: { 'Alfakit/Page': AlfakitPage, ...options.pages },\n translator,\n actions: new ActionRunner({\n endpoints: { action: '', modal: '' },\n // A failed action request is a toast, never a silent no-op.\n onError: (error) => {\n const notification = resolveRequestErrorNotification(\n error,\n null,\n (key, replacements, fallback) => translator.t(key, replacements, fallback),\n )\n\n if (notification) showToast(notification)\n },\n }),\n }\n}\n\nfunction starterKitContext(options: StarterKitPageOptions): AlfakitContextValue {\n if (typeof window === 'undefined') return createStarterKitContext(options)\n\n browserContext ??= createStarterKitContext(options)\n\n return browserContext\n}\n\n/**\n * The Inertia layout around every Alfakit page in starter kit mode, inside the host layout:\n * Alfakit's context, modals, toasts and the reading direction. It stays mounted while the\n * user moves between Alfakit pages.\n */\nexport function AlfakitStarterKitRoot({\n options,\n children,\n}: {\n options?: StarterKitPageOptions\n children?: ReactNode\n}) {\n const [context] = useState(() => starterKitContext(options ?? {}))\n const props = usePage<AlfakitPageProps>().props\n const panel = props.alfakit\n\n // Endpoints and error notifications follow the open page.\n if (panel) {\n context.actions.setEndpoints({\n action: panel.endpoints.action ?? '',\n modal: panel.endpoints.modal ?? '',\n })\n }\n\n useEffect(() => {\n syncStarterKitPage(props)\n }, [props])\n\n useEffect(() => {\n installStarterKitRuntime(\n (notification) => showToast(notification),\n (key, replacements, fallback) => context.translator.t(key, replacements, fallback),\n )\n setToasterId(STARTER_KIT_TOASTER_ID)\n\n return () => {\n // A host page is open: its errors and toasts are the host's again.\n syncStarterKitPage(null)\n setToasterId(undefined)\n }\n }, [context])\n\n return (\n <AlfakitProvider value={context}>\n <AlfakitRoot toasterId={STARTER_KIT_TOASTER_ID}>{children}</AlfakitRoot>\n </AlfakitProvider>\n )\n}\n\n/**\n * The page component for `Alfakit/Page` in a starter kit app: the host's\n * `resources/js/pages/Alfakit/Page.tsx` (written by `alfakit:install --starter-kit`) exports it,\n * so Inertia's page resolution, the root view's page preload and SSR all find it like any\n * other host page.\n *\n * ```tsx\n * import { createStarterKitPage } from '@alfakit/react'\n * import AppLayout from '@/layouts/app-layout'\n *\n * export default createStarterKitPage({ layout: AppLayout })\n * ```\n */\nexport function createStarterKitPage(options: StarterKitPageOptions = {}) {\n // Panel pages draw named icons: fetch `lucide-react/dynamic` with the page.\n preloadIcons()\n // `'js:name'` chart option callbacks, Chart.js plugins and rich editor extensions.\n configureCharts(options)\n registerRichEditorExtensions(options.richEditorExtensions ?? {})\n\n function AlfakitStarterKitPage() {\n return <AlfakitPage />\n }\n\n // A layout callback: the host layout (with the page's breadcrumbs), then Alfakit's root.\n AlfakitStarterKitPage.layout = (props: Record<string, unknown>) => [\n ...(options.layout\n ? [[options.layout, { breadcrumbs: starterKitBreadcrumbsFromProps(props) }] as const]\n : []),\n [AlfakitStarterKitRoot, { options }] as const,\n ]\n\n return AlfakitStarterKitPage\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAsDA,SAAgB,wBAAwB,EAAE,UAAU,mBAAmC;CACrF,MAAM,QAAQ,gBAAgB;CAE9B,MAAM,QAAQ,mBAAmB,MAAM,QAAQ,mBAAmB;CAElE,OACE,qBAAC,OAAD;EACE,aAAU;EACV,yBAAsB;EACtB,WAAW,GACT,gEACA,WAAW,UAAU,YACvB;EANF,UAAA;GAQE,oBAAC,MAAD,EAAM,MAAK,gBAAiB,CAAA;GAC3B;GACD,oBAAC,MAAD,EAAM,MAAK,cAAe,CAAA;EACvB;;AAET;AAIA,IAAI,iBAA6C;AAEjD,SAAS,wBAAwB,SAAqD;CACpF,MAAM,WAAW,sBAAsB,CAAC,CACrC,SAAS,cAAc,uBAAuB,CAAC,CAC/C,aAAa,QAAQ,cAAc,CAAC,CAAC;CACxC,MAAM,aAAa,IAAI,WAAW;CAElC,OAAO;EACL;EACA,OAAO;GAAE,gBAAgB;GAAa,GAAG,QAAQ;EAAM;EACvD;EACA,SAAS,IAAI,aAAa;GACxB,WAAW;IAAE,QAAQ;IAAI,OAAO;GAAG;GAEnC,UAAU,UAAU;IAClB,MAAM,eAAe,gCACnB,OACA,OACC,KAAK,cAAc,aAAa,WAAW,EAAE,KAAK,cAAc,QAAQ,CAC3E;IAEA,IAAI,cAAc,UAAU,YAAY;GAC1C;EACF,CAAC;CACH;AACF;AAEA,SAAS,kBAAkB,SAAqD;CAC9E,IAAI,OAAO,WAAW,aAAa,OAAO,wBAAwB,OAAO;CAEzE,mBAAmB,wBAAwB,OAAO;CAElD,OAAO;AACT;;;;;;AAOA,SAAgB,sBAAsB,EACpC,SACA,YAIC;CACD,MAAM,CAAC,WAAW,eAAe,kBAAkB,WAAW,CAAC,CAAC,CAAC;CACjE,MAAM,QAAQ,QAA0B,CAAC,CAAC;CAC1C,MAAM,QAAQ,MAAM;CAGpB,IAAI,OACF,QAAQ,QAAQ,aAAa;EAC3B,QAAQ,MAAM,UAAU,UAAU;EAClC,OAAO,MAAM,UAAU,SAAS;CAClC,CAAC;CAGH,gBAAgB;EACd,mBAAmB,KAAK;CAC1B,GAAG,CAAC,KAAK,CAAC;CAEV,gBAAgB;EACd,0BACG,iBAAiB,UAAU,YAAY,IACvC,KAAK,cAAc,aAAa,QAAQ,WAAW,EAAE,KAAK,cAAc,QAAQ,CACnF;EACA,aAAa,sBAAsB;EAEnC,aAAa;GAEX,mBAAmB,IAAI;GACvB,aAAa,KAAA,CAAS;EACxB;CACF,GAAG,CAAC,OAAO,CAAC;CAEZ,OACE,oBAAC,iBAAD;EAAiB,OAAO;EACtB,UAAA,oBAAC,aAAD;GAAa,WAAW;GAAyB;EAAsB,CAAA;CACxD,CAAA;AAErB;;;;;;;;;;;;;;AAeA,SAAgB,qBAAqB,UAAiC,CAAC,GAAG;CAExE,aAAa;CAEb,gBAAgB,OAAO;CACvB,6BAA6B,QAAQ,wBAAwB,CAAC,CAAC;CAE/D,SAAS,wBAAwB;EAC/B,OAAO,oBAAC,aAAD,CAAc,CAAA;CACvB;CAGA,sBAAsB,UAAU,UAAmC,CACjE,GAAI,QAAQ,SACR,CAAC,CAAC,QAAQ,QAAQ,EAAE,aAAa,+BAA+B,KAAK,EAAE,CAAC,CAAU,IAClF,CAAC,GACL,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CACrC;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"starter-kit.js","names":[],"sources":["../../src/starter-kit/starter-kit.tsx"],"sourcesContent":["import {\n ActionRunner,\n STARTER_KIT_TOASTER_ID,\n Translator,\n configureCharts,\n installStarterKitRuntime,\n registerRichEditorExtensions,\n resolveRequestErrorNotification,\n starterKitBreadcrumbsFromProps,\n syncStarterKitPage,\n usesStarterKitHostLayout,\n type AlfakitOptions,\n type AlfakitPageProps,\n type StarterKitBreadcrumb,\n} from '@alfakit/core'\nimport { usePage } from '@inertiajs/react'\nimport { useEffect, useState, type ComponentType, type ReactNode } from 'react'\nimport { setToasterId, showToast } from '../components/notifications/flash-toasts'\nimport { Slot } from '../components/panel/slot'\nimport {\n AlfakitProvider,\n useAlfakitProps,\n type AlfakitContextValue,\n type AnyComponent,\n} from '../context'\nimport { AlfakitRoot } from '../create-alfakit'\nimport type { AppLayoutProps } from '../layouts/app-layout'\nimport { AuthLayout } from '../layouts/auth-layout'\nimport { lazyPanelLayouts } from '../layouts/lazy-layouts'\nimport { MAX_WIDTHS } from '../layouts/max-widths'\nimport { discoverComponents } from '../lib/discovery'\nimport { preloadIcons } from '../lib/icons'\nimport { cn } from '../lib/utils'\nimport { AlfakitPage } from '../pages/page'\nimport { createDefaultRegistry } from '../registry'\n\n/** The host's layout, as the starter kits' `AppLayout` takes its props. */\nexport type StarterKitLayout = ComponentType<{\n breadcrumbs?: StarterKitBreadcrumb[]\n children: ReactNode\n}>\n\nexport interface StarterKitPageOptions extends Pick<\n AlfakitOptions<AnyComponent>,\n 'components' | 'pages' | 'chartFormatters' | 'chartPlugins' | 'richEditorExtensions'\n> {\n /**\n * The host layout Alfakit pages render in, usually the starter kit's `AppLayout`\n * (`@/layouts/app-layout`). It receives the page's breadcrumbs as `{ title, href }`.\n * `null` renders the pages without a host layout.\n */\n layout?: StarterKitLayout | null\n /**\n * Auto-registered custom components, as for `createAlfakit({ discover })`: pass\n * `import.meta.glob('../../alfakit/{fields,columns,entries,widgets,pages,components,blocks}/**\\/*.tsx')`\n * from `resources/js/pages/Alfakit/Page.tsx` and every file there registers under its name.\n */\n discover?: AlfakitOptions<AnyComponent>['discover']\n}\n\n/**\n * The content area of an Alfakit page inside the host layout: what `layout:app` renders in\n * starter kit mode instead of Alfakit's sidebar and top bar. Replace it with\n * `createStarterKitPage({ components: { 'layout:app': MyContent } })`.\n */\nexport function StarterKitContentLayout({ children, maxContentWidth }: AppLayoutProps) {\n const props = useAlfakitProps()\n // The host's pages fill the content area, so starter kit pages default to the full width.\n const width = maxContentWidth ?? props.alfakit.maxContentWidth ?? 'full'\n\n return (\n <div\n data-slot=\"content\"\n data-alfakit-embedded=\"\"\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-full',\n )}\n >\n <Slot name=\"content.start\" />\n {children}\n <Slot name=\"content.end\" />\n </div>\n )\n}\n\n// One context for the browser session (it survives navigations between host and Alfakit\n// pages); a server render builds one per request so concurrent renders never share a locale.\nlet browserContext: AlfakitContextValue | null = null\n\nfunction createStarterKitContext(options: StarterKitPageOptions): AlfakitContextValue {\n // The host's layout replaces the panel's. Auth pages (invitations, tenant registration)\n // keep the panel's card; the fullscreen layout loads on demand.\n // Auto-registered files sit between the built-ins and the explicit `components` / `pages`.\n const discovered = discoverComponents(options.discover)\n const registry = createDefaultRegistry()\n .registerMany(lazyPanelLayouts)\n .register('layout:auth', AuthLayout)\n .register('layout:app', StarterKitContentLayout)\n .registerMany(discovered.components)\n .registerMany(options.components ?? {})\n const translator = new Translator()\n\n return {\n registry,\n pages: { 'Alfakit/Page': AlfakitPage, ...discovered.pages, ...options.pages },\n translator,\n actions: new ActionRunner({\n endpoints: { action: '', modal: '' },\n // A failed action request is a toast, never a silent no-op.\n onError: (error) => {\n const notification = resolveRequestErrorNotification(\n error,\n null,\n (key, replacements, fallback) => translator.t(key, replacements, fallback),\n )\n\n if (notification) showToast(notification)\n },\n }),\n }\n}\n\nfunction starterKitContext(options: StarterKitPageOptions): AlfakitContextValue {\n if (typeof window === 'undefined') return createStarterKitContext(options)\n\n browserContext ??= createStarterKitContext(options)\n\n return browserContext\n}\n\n/**\n * The Inertia layout around every Alfakit page in starter kit mode, inside the host layout:\n * Alfakit's context, modals, toasts and the reading direction. It stays mounted while the\n * user moves between Alfakit pages.\n */\nexport function AlfakitStarterKitRoot({\n options,\n children,\n}: {\n options?: StarterKitPageOptions\n children?: ReactNode\n}) {\n const [context] = useState(() => starterKitContext(options ?? {}))\n const props = usePage<AlfakitPageProps>().props\n const panel = props.alfakit\n\n // Endpoints and error notifications follow the open page.\n if (panel) {\n context.actions.setEndpoints({\n action: panel.endpoints.action ?? '',\n modal: panel.endpoints.modal ?? '',\n })\n }\n\n useEffect(() => {\n syncStarterKitPage(props)\n }, [props])\n\n useEffect(() => {\n installStarterKitRuntime(\n (notification) => showToast(notification),\n (key, replacements, fallback) => context.translator.t(key, replacements, fallback),\n )\n setToasterId(STARTER_KIT_TOASTER_ID)\n\n return () => {\n // A host page is open: its errors and toasts are the host's again.\n syncStarterKitPage(null)\n setToasterId(undefined)\n }\n }, [context])\n\n return (\n <AlfakitProvider value={context}>\n {/* The reading direction and language of Alfakit's content only: the host layout around\n it (sidebar, header) and the app's own pages keep the document's. */}\n <div\n data-slot=\"starter-kit-root\"\n dir={panel?.localization?.direction ?? 'ltr'}\n lang={panel?.localization?.tag}\n className=\"contents\"\n >\n <AlfakitRoot toasterId={STARTER_KIT_TOASTER_ID}>{children}</AlfakitRoot>\n </div>\n </AlfakitProvider>\n )\n}\n\n/**\n * The page component for `Alfakit/Page` in a starter kit app: the host's\n * `resources/js/pages/Alfakit/Page.tsx` (written by `alfakit:install --starter-kit`) exports it,\n * so Inertia's page resolution, the root view's page preload and SSR all find it like any\n * other host page.\n *\n * ```tsx\n * import { createStarterKitPage } from '@alfakit/react'\n * import AppLayout from '@/layouts/app-layout'\n *\n * export default createStarterKitPage({ layout: AppLayout })\n * ```\n */\nexport function createStarterKitPage(options: StarterKitPageOptions = {}) {\n // Panel pages draw named icons: fetch `lucide-react/dynamic` with the page.\n preloadIcons()\n // `'js:name'` chart option callbacks, Chart.js plugins and rich editor extensions.\n configureCharts(options)\n registerRichEditorExtensions(options.richEditorExtensions ?? {})\n\n function AlfakitStarterKitPage() {\n return <AlfakitPage />\n }\n\n // A layout callback: the host layout (with the page's breadcrumbs), then Alfakit's root.\n AlfakitStarterKitPage.layout = (props: Record<string, unknown>) => [\n ...(options.layout && usesStarterKitHostLayout(props)\n ? [[options.layout, { breadcrumbs: starterKitBreadcrumbsFromProps(props) }] as const]\n : []),\n [AlfakitStarterKitRoot, { options }] as const,\n ]\n\n return AlfakitStarterKitPage\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAiEA,SAAgB,wBAAwB,EAAE,UAAU,mBAAmC;CACrF,MAAM,QAAQ,gBAAgB;CAE9B,MAAM,QAAQ,mBAAmB,MAAM,QAAQ,mBAAmB;CAElE,OACE,qBAAC,OAAD;EACE,aAAU;EACV,yBAAsB;EACtB,WAAW,GACT,gEACA,WAAW,UAAU,YACvB;EANF,UAAA;GAQE,oBAAC,MAAD,EAAM,MAAK,gBAAiB,CAAA;GAC3B;GACD,oBAAC,MAAD,EAAM,MAAK,cAAe,CAAA;EACvB;;AAET;AAIA,IAAI,iBAA6C;AAEjD,SAAS,wBAAwB,SAAqD;CAIpF,MAAM,aAAa,mBAAmB,QAAQ,QAAQ;CACtD,MAAM,WAAW,sBAAsB,CAAC,CACrC,aAAa,gBAAgB,CAAC,CAC9B,SAAS,eAAe,UAAU,CAAC,CACnC,SAAS,cAAc,uBAAuB,CAAC,CAC/C,aAAa,WAAW,UAAU,CAAC,CACnC,aAAa,QAAQ,cAAc,CAAC,CAAC;CACxC,MAAM,aAAa,IAAI,WAAW;CAElC,OAAO;EACL;EACA,OAAO;GAAE,gBAAgB;GAAa,GAAG,WAAW;GAAO,GAAG,QAAQ;EAAM;EAC5E;EACA,SAAS,IAAI,aAAa;GACxB,WAAW;IAAE,QAAQ;IAAI,OAAO;GAAG;GAEnC,UAAU,UAAU;IAClB,MAAM,eAAe,gCACnB,OACA,OACC,KAAK,cAAc,aAAa,WAAW,EAAE,KAAK,cAAc,QAAQ,CAC3E;IAEA,IAAI,cAAc,UAAU,YAAY;GAC1C;EACF,CAAC;CACH;AACF;AAEA,SAAS,kBAAkB,SAAqD;CAC9E,IAAI,OAAO,WAAW,aAAa,OAAO,wBAAwB,OAAO;CAEzE,mBAAmB,wBAAwB,OAAO;CAElD,OAAO;AACT;;;;;;AAOA,SAAgB,sBAAsB,EACpC,SACA,YAIC;CACD,MAAM,CAAC,WAAW,eAAe,kBAAkB,WAAW,CAAC,CAAC,CAAC;CACjE,MAAM,QAAQ,QAA0B,CAAC,CAAC;CAC1C,MAAM,QAAQ,MAAM;CAGpB,IAAI,OACF,QAAQ,QAAQ,aAAa;EAC3B,QAAQ,MAAM,UAAU,UAAU;EAClC,OAAO,MAAM,UAAU,SAAS;CAClC,CAAC;CAGH,gBAAgB;EACd,mBAAmB,KAAK;CAC1B,GAAG,CAAC,KAAK,CAAC;CAEV,gBAAgB;EACd,0BACG,iBAAiB,UAAU,YAAY,IACvC,KAAK,cAAc,aAAa,QAAQ,WAAW,EAAE,KAAK,cAAc,QAAQ,CACnF;EACA,aAAa,sBAAsB;EAEnC,aAAa;GAEX,mBAAmB,IAAI;GACvB,aAAa,KAAA,CAAS;EACxB;CACF,GAAG,CAAC,OAAO,CAAC;CAEZ,OACE,oBAAC,iBAAD;EAAiB,OAAO;EAGtB,UAAA,oBAAC,OAAD;GACE,aAAU;GACV,KAAK,OAAO,cAAc,aAAa;GACvC,MAAM,OAAO,cAAc;GAC3B,WAAU;GAEV,UAAA,oBAAC,aAAD;IAAa,WAAW;IAAyB;GAAsB,CAAA;EACpE,CAAA;CACU,CAAA;AAErB;;;;;;;;;;;;;;AAeA,SAAgB,qBAAqB,UAAiC,CAAC,GAAG;CAExE,aAAa;CAEb,gBAAgB,OAAO;CACvB,6BAA6B,QAAQ,wBAAwB,CAAC,CAAC;CAE/D,SAAS,wBAAwB;EAC/B,OAAO,oBAAC,aAAD,CAAc,CAAA;CACvB;CAGA,sBAAsB,UAAU,UAAmC,CACjE,GAAI,QAAQ,UAAU,yBAAyB,KAAK,IAChD,CAAC,CAAC,QAAQ,QAAQ,EAAE,aAAa,+BAA+B,KAAK,EAAE,CAAC,CAAU,IAClF,CAAC,GACL,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CACrC;CAEA,OAAO;AACT"}
@@ -2,14 +2,15 @@ import { AlfakitProvider, StandaloneProvider, useT } from "../context.js";
2
2
  import { Icon } from "../lib/icons.js";
3
3
  import { DropdownMenu as DropdownMenu$1, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "../components/ui/dropdown-menu.js";
4
4
  import { TooltipProvider } from "../components/ui/tooltip.js";
5
+ import { AiCopilot } from "../components/ai/copilot.js";
5
6
  import { TenantName } from "../components/panel/nav-label.js";
6
7
  import { Avatar as Avatar$1, AvatarFallback, AvatarImage } from "../components/ui/avatar.js";
7
8
  import { NotificationsMenu } from "../components/notifications/notifications-menu.js";
9
+ import { RealtimeNotifications } from "../components/notifications/realtime-notifications.js";
8
10
  import { GlobalSearch } from "../components/panel/global-search.js";
9
11
  import { TenantMenu } from "../components/panel/tenant-menu.js";
10
- import { RealtimeNotifications } from "../components/notifications/realtime-notifications.js";
11
- import { NotificationsTrigger, SearchTrigger, TenantSwitcherTrigger } from "./widgets-triggers.js";
12
- import { ActionRunner, ComponentRegistry, Translator, initials, isAlfakitPage, loadStarterKitPanel, loadedStarterKitPanel, openRequestedStarterKitSearch, starterKitWidgetsPage, starterKitWidgetsPanel, tenantNameText } from "@alfakit/core";
12
+ import { CopilotTrigger, NotificationsTrigger, SearchTrigger, TenantSwitcherTrigger } from "./widgets-triggers.js";
13
+ import { ActionRunner, ComponentRegistry, Translator, initials, isAlfakitPage, loadStarterKitPanel, loadedStarterKitPanel, openRequestedStarterKitSearch, starterKitCopilot, starterKitWidgetsPage, starterKitWidgetsPanel, takeRequestedStarterKitCopilot, tenantNameText } from "@alfakit/core";
13
14
  import { router, usePage } from "@inertiajs/react";
14
15
  import { useEffect, useMemo, useState } from "react";
15
16
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -109,6 +110,21 @@ function LoadedTenantSwitcher({ source }) {
109
110
  children: panel.tenancy?.current ? /* @__PURE__ */ jsx(TenantMenu, { variant: "topbar" }) : /* @__PURE__ */ jsx(TenantChooser, { panel })
110
111
  });
111
112
  }
113
+ /** The AI copilot (the panel pages' `topbar.end` slot component). */
114
+ function LoadedCopilot({ source }) {
115
+ const panel = useWidgetsPanel(source);
116
+ const [autoOpen] = useState(() => takeRequestedStarterKitCopilot());
117
+ const component = useMemo(() => panel ? starterKitCopilot(panel) : null, [panel]);
118
+ if (!panel) return /* @__PURE__ */ jsx(CopilotTrigger, { source });
119
+ if (!component) return null;
120
+ return /* @__PURE__ */ jsx(WidgetShell, {
121
+ panel,
122
+ children: /* @__PURE__ */ jsx(AiCopilot, {
123
+ component,
124
+ autoOpen: autoOpen || takeRequestedStarterKitCopilot()
125
+ })
126
+ });
127
+ }
112
128
  /** The user's tenants on a page outside the panel (no current tenant). */
113
129
  function TenantChooser({ panel }) {
114
130
  const t = useT();
@@ -161,12 +177,12 @@ function TenantChooser({ panel }) {
161
177
  children: [/* @__PURE__ */ jsx(Icon, {
162
178
  name: "alfakit::panels.tenant-menu.registration-button",
163
179
  fallback: PlusIcon
164
- }), t("tenancy.register", {}, "New")]
180
+ }), tenancy.registrationLabel ?? t("tenancy.register", {}, "New")]
165
181
  })] })
166
182
  ]
167
183
  })] });
168
184
  }
169
185
  //#endregion
170
- export { LoadedNotifications, LoadedSearch, LoadedTenantSwitcher };
186
+ export { LoadedCopilot, LoadedNotifications, LoadedSearch, LoadedTenantSwitcher };
171
187
 
172
188
  //# sourceMappingURL=widgets-loaded.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"widgets-loaded.js","names":["DropdownMenu","Avatar"],"sources":["../../src/starter-kit/widgets-loaded.tsx"],"sourcesContent":["import {\n ActionRunner,\n ComponentRegistry,\n Translator,\n initials,\n isAlfakitPage,\n loadStarterKitPanel,\n loadedStarterKitPanel,\n openRequestedStarterKitSearch,\n starterKitWidgetsPage,\n starterKitWidgetsPanel,\n tenantNameText,\n type PanelSchema,\n type StarterKitWidgets,\n} from '@alfakit/core'\nimport { router, usePage } from '@inertiajs/react'\nimport { ChevronsUpDownIcon, PlusIcon } from 'lucide-react'\nimport { Direction } from 'radix-ui'\nimport { useEffect, useMemo, useState, type ReactNode } from 'react'\nimport { NotificationsMenu } from '../components/notifications/notifications-menu'\nimport { RealtimeNotifications } from '../components/notifications/realtime-notifications'\nimport { GlobalSearch } from '../components/panel/global-search'\nimport { TenantName } from '../components/panel/nav-label'\nimport { TenantMenu } from '../components/panel/tenant-menu'\nimport { Avatar, AvatarFallback, AvatarImage } from '../components/ui/avatar'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../components/ui/dropdown-menu'\nimport { TooltipProvider } from '../components/ui/tooltip'\nimport {\n AlfakitProvider,\n StandaloneProvider,\n useT,\n type AlfakitContextValue,\n type AnyComponent,\n} from '../context'\nimport { Icon } from '../lib/icons'\nimport {\n NotificationsTrigger,\n SearchTrigger,\n TenantSwitcherTrigger,\n type WidgetProps,\n} from './widgets-triggers'\n\n/**\n * The loaded header components of starter kit mode: the panel's own search palette,\n * notifications menu and tenant menu, rendered outside Alfakit pages with the panel data\n * from `widgets.endpoint`. This module only loads in the browser.\n */\n\n// One context for the browser session: its own translator (the panel's strings), an empty\n// registry (only `panel:icon` overrides are looked up here) and an idle action runner.\nlet widgetsContext: AlfakitContextValue | null = null\n\nfunction useWidgetsContext(panel: PanelSchema): AlfakitContextValue {\n widgetsContext ??= {\n registry: new ComponentRegistry<AnyComponent>(),\n pages: {},\n translator: new Translator(),\n actions: new ActionRunner({ endpoints: { action: '', modal: '' } }),\n }\n\n widgetsContext.translator.setTranslations(panel.translations ?? {})\n widgetsContext.translator.setLocale(panel.localization?.tag ?? 'en')\n\n return widgetsContext\n}\n\n/** The panel the components render with, once its data has loaded (null until then). */\nfunction useWidgetsPanel(source: StarterKitWidgets): PanelSchema | null {\n const endpoint = source.widgets.endpoint\n const [loaded, setLoaded] = useState(() => loadedStarterKitPanel(endpoint))\n const base = loadedStarterKitPanel(endpoint) ?? loaded\n\n useEffect(() => {\n let active = true\n\n // Another endpoint (a tenant switch) loads its own panel data.\n void loadStarterKitPanel(endpoint).then(\n (panel) => active && setLoaded(panel),\n () => {},\n )\n\n return () => {\n active = false\n }\n }, [endpoint])\n\n const { navigation, widgets } = source\n\n return useMemo(\n () => (base ? starterKitWidgetsPanel(base, { navigation, widgets }) : null),\n [base, navigation, widgets],\n )\n}\n\nfunction WidgetShell({ panel, children }: { panel: PanelSchema; children: ReactNode }) {\n const context = useWidgetsContext(panel)\n const page = useMemo(() => starterKitWidgetsPage(), [])\n\n return (\n <AlfakitProvider value={context}>\n <StandaloneProvider value={{ panel, page }}>\n <Direction.Provider dir={panel.localization?.direction ?? 'ltr'}>\n <TooltipProvider delayDuration={0}>{children}</TooltipProvider>\n </Direction.Provider>\n </StandaloneProvider>\n </AlfakitProvider>\n )\n}\n\n/** The panel's command palette and global search. */\nexport function LoadedSearch({ source }: WidgetProps) {\n const panel = useWidgetsPanel(source)\n\n // A click or the key bindings before the palette loaded open it now (after its own\n // effects registered the shortcut).\n useEffect(() => {\n if (panel) openRequestedStarterKitSearch()\n }, [panel])\n\n if (!panel) return <SearchTrigger source={source} />\n\n return (\n <WidgetShell panel={panel}>\n <GlobalSearch />\n </WidgetShell>\n )\n}\n\n/** The notifications bell, with realtime notifications on the host's own pages. */\nexport function LoadedNotifications({ source }: WidgetProps) {\n const panel = useWidgetsPanel(source)\n // Alfakit pages subscribe to realtime notifications themselves.\n const alfakitPage = isAlfakitPage(usePage().props)\n\n if (!panel) return <NotificationsTrigger source={source} />\n\n return (\n <WidgetShell panel={panel}>\n <NotificationsMenu />\n {!alfakitPage && <RealtimeNotifications />}\n </WidgetShell>\n )\n}\n\n/** The panel's tenant menu inside a tenant, a menu to choose one elsewhere. */\nexport function LoadedTenantSwitcher({ source }: WidgetProps) {\n const panel = useWidgetsPanel(source)\n\n if (!panel) return <TenantSwitcherTrigger source={source} />\n\n return (\n <WidgetShell panel={panel}>\n {panel.tenancy?.current ? <TenantMenu variant=\"topbar\" /> : <TenantChooser panel={panel} />}\n </WidgetShell>\n )\n}\n\n/** The user's tenants on a page outside the panel (no current tenant). */\nfunction TenantChooser({ panel }: { panel: PanelSchema }) {\n const t = useT()\n const tenancy = panel.tenancy\n\n if (!tenancy || (tenancy.tenants.length === 0 && !tenancy.registrationUrl)) return null\n\n const label = t('starter_kit.choose_tenant', {}, 'Choose a tenant')\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n data-slot=\"tenant-menu\"\n className=\"hover:bg-accent data-[state=open]:bg-accent inline-flex h-9 max-w-60 shrink-0 items-center gap-2 rounded-md px-2 text-sm font-medium\"\n >\n <span className=\"sr-only lg:not-sr-only lg:truncate\">{label}</span>\n <Icon\n name=\"alfakit::panels.tenant-menu.toggle-button\"\n fallback={ChevronsUpDownIcon}\n className=\"text-muted-foreground size-4 shrink-0\"\n />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent className=\"min-w-56 rounded-lg\" side=\"bottom\" align=\"end\" sideOffset={4}>\n {tenancy.tenants.length > 0 && (\n <DropdownMenuLabel className=\"text-muted-foreground text-xs\">{label}</DropdownMenuLabel>\n )}\n {tenancy.tenants.map((tenant) => (\n <DropdownMenuItem key={String(tenant.id)} onSelect={() => router.visit(tenant.url)}>\n <Avatar className=\"size-6 rounded-sm\">\n {tenant.avatar && <AvatarImage src={tenant.avatar} alt=\"\" />}\n <AvatarFallback className=\"rounded-sm text-[10px]\">\n {initials(tenantNameText(tenant))}\n </AvatarFallback>\n </Avatar>\n <TenantName tenant={tenant} className=\"flex-1 truncate\" />\n </DropdownMenuItem>\n ))}\n {tenancy.registrationUrl && (\n <>\n {tenancy.tenants.length > 0 && <DropdownMenuSeparator />}\n <DropdownMenuItem onSelect={() => router.visit(tenancy.registrationUrl!)}>\n <Icon name=\"alfakit::panels.tenant-menu.registration-button\" fallback={PlusIcon} />\n {t('tenancy.register', {}, 'New')}\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAyDA,IAAI,iBAA6C;AAEjD,SAAS,kBAAkB,OAAyC;CAClE,mBAAmB;EACjB,UAAU,IAAI,kBAAgC;EAC9C,OAAO,CAAC;EACR,YAAY,IAAI,WAAW;EAC3B,SAAS,IAAI,aAAa,EAAE,WAAW;GAAE,QAAQ;GAAI,OAAO;EAAG,EAAE,CAAC;CACpE;CAEA,eAAe,WAAW,gBAAgB,MAAM,gBAAgB,CAAC,CAAC;CAClE,eAAe,WAAW,UAAU,MAAM,cAAc,OAAO,IAAI;CAEnE,OAAO;AACT;;AAGA,SAAS,gBAAgB,QAA+C;CACtE,MAAM,WAAW,OAAO,QAAQ;CAChC,MAAM,CAAC,QAAQ,aAAa,eAAe,sBAAsB,QAAQ,CAAC;CAC1E,MAAM,OAAO,sBAAsB,QAAQ,KAAK;CAEhD,gBAAgB;EACd,IAAI,SAAS;EAGb,oBAAyB,QAAQ,CAAC,CAAC,MAChC,UAAU,UAAU,UAAU,KAAK,SAC9B,CAAC,CACT;EAEA,aAAa;GACX,SAAS;EACX;CACF,GAAG,CAAC,QAAQ,CAAC;CAEb,MAAM,EAAE,YAAY,YAAY;CAEhC,OAAO,cACE,OAAO,uBAAuB,MAAM;EAAE;EAAY;CAAQ,CAAC,IAAI,MACtE;EAAC;EAAM;EAAY;CAAO,CAC5B;AACF;AAEA,SAAS,YAAY,EAAE,OAAO,YAAyD;CACrF,MAAM,UAAU,kBAAkB,KAAK;CACvC,MAAM,OAAO,cAAc,sBAAsB,GAAG,CAAC,CAAC;CAEtD,OACE,oBAAC,iBAAD;EAAiB,OAAO;EACtB,UAAA,oBAAC,oBAAD;GAAoB,OAAO;IAAE;IAAO;GAAK;GACvC,UAAA,oBAAC,UAAU,UAAX;IAAoB,KAAK,MAAM,cAAc,aAAa;IACxD,UAAA,oBAAC,iBAAD;KAAiB,eAAe;KAAI;IAA0B,CAAA;GAC5C,CAAA;EACF,CAAA;CACL,CAAA;AAErB;;AAGA,SAAgB,aAAa,EAAE,UAAuB;CACpD,MAAM,QAAQ,gBAAgB,MAAM;CAIpC,gBAAgB;EACd,IAAI,OAAO,8BAA8B;CAC3C,GAAG,CAAC,KAAK,CAAC;CAEV,IAAI,CAAC,OAAO,OAAO,oBAAC,eAAD,EAAuB,OAAS,CAAA;CAEnD,OACE,oBAAC,aAAD;EAAoB;EAClB,UAAA,oBAAC,cAAD,CAAe,CAAA;CACJ,CAAA;AAEjB;;AAGA,SAAgB,oBAAoB,EAAE,UAAuB;CAC3D,MAAM,QAAQ,gBAAgB,MAAM;CAEpC,MAAM,cAAc,cAAc,QAAQ,CAAC,CAAC,KAAK;CAEjD,IAAI,CAAC,OAAO,OAAO,oBAAC,sBAAD,EAA8B,OAAS,CAAA;CAE1D,OACE,qBAAC,aAAD;EAAoB;EAApB,UAAA,CACE,oBAAC,mBAAD,CAAoB,CAAA,GACnB,CAAC,eAAe,oBAAC,uBAAD,CAAwB,CAAA,CAC9B;;AAEjB;;AAGA,SAAgB,qBAAqB,EAAE,UAAuB;CAC5D,MAAM,QAAQ,gBAAgB,MAAM;CAEpC,IAAI,CAAC,OAAO,OAAO,oBAAC,uBAAD,EAA+B,OAAS,CAAA;CAE3D,OACE,oBAAC,aAAD;EAAoB;EACjB,UAAA,MAAM,SAAS,UAAU,oBAAC,YAAD,EAAY,SAAQ,SAAU,CAAA,IAAI,oBAAC,eAAD,EAAsB,MAAQ,CAAA;CAC/E,CAAA;AAEjB;;AAGA,SAAS,cAAc,EAAE,SAAiC;CACxD,MAAM,IAAI,KAAK;CACf,MAAM,UAAU,MAAM;CAEtB,IAAI,CAAC,WAAY,QAAQ,QAAQ,WAAW,KAAK,CAAC,QAAQ,iBAAkB,OAAO;CAEnF,MAAM,QAAQ,EAAE,6BAA6B,CAAC,GAAG,iBAAiB;CAElE,OACE,qBAACA,gBAAD,EAAA,UAAA,CACE,oBAAC,qBAAD;EAAqB,SAAA;EACnB,UAAA,qBAAC,UAAD;GACE,MAAK;GACL,aAAU;GACV,WAAU;GAHZ,UAAA,CAKE,oBAAC,QAAD;IAAM,WAAU;IAAsC,UAAA;GAAY,CAAA,GAClE,oBAAC,MAAD;IACE,MAAK;IACL,UAAU;IACV,WAAU;GACX,CAAA,CACK;;CACW,CAAA,GACrB,qBAAC,qBAAD;EAAqB,WAAU;EAAsB,MAAK;EAAS,OAAM;EAAM,YAAY;EAA3F,UAAA;GACG,QAAQ,QAAQ,SAAS,KACxB,oBAAC,mBAAD;IAAmB,WAAU;IAAiC,UAAA;GAAyB,CAAA;GAExF,QAAQ,QAAQ,KAAK,WACpB,qBAAC,kBAAD;IAA0C,gBAAgB,OAAO,MAAM,OAAO,GAAG;IAAjF,UAAA,CACE,qBAACC,UAAD;KAAQ,WAAU;KAAlB,UAAA,CACG,OAAO,UAAU,oBAAC,aAAD;MAAa,KAAK,OAAO;MAAQ,KAAI;KAAI,CAAA,GAC3D,oBAAC,gBAAD;MAAgB,WAAU;MACvB,UAAA,SAAS,eAAe,MAAM,CAAC;KAClB,CAAA,CACV;IACR,CAAA,GAAA,oBAAC,YAAD;KAAoB;KAAQ,WAAU;IAAmB,CAAA,CACzC;GARK,GAAA,OAAO,OAAO,EAAE,CAQrB,CACnB;GACA,QAAQ,mBACP,qBAAA,YAAA,EAAA,UAAA,CACG,QAAQ,QAAQ,SAAS,KAAK,oBAAC,uBAAD,CAAwB,CAAA,GACvD,qBAAC,kBAAD;IAAkB,gBAAgB,OAAO,MAAM,QAAQ,eAAgB;IAAvE,UAAA,CACE,oBAAC,MAAD;KAAM,MAAK;KAAkD,UAAU;IAAW,CAAA,GACjF,EAAE,oBAAoB,CAAC,GAAG,KAAK,CAChB;GAClB,CAAA,CAAA,EAAA,CAAA;EAEe;CACT,CAAA,CAAA,EAAA,CAAA;AAElB"}
1
+ {"version":3,"file":"widgets-loaded.js","names":["DropdownMenu","Avatar"],"sources":["../../src/starter-kit/widgets-loaded.tsx"],"sourcesContent":["import {\n ActionRunner,\n ComponentRegistry,\n Translator,\n initials,\n isAlfakitPage,\n loadStarterKitPanel,\n loadedStarterKitPanel,\n openRequestedStarterKitSearch,\n starterKitCopilot,\n starterKitWidgetsPage,\n starterKitWidgetsPanel,\n takeRequestedStarterKitCopilot,\n tenantNameText,\n type PanelSchema,\n type StarterKitWidgets,\n} from '@alfakit/core'\nimport { router, usePage } from '@inertiajs/react'\nimport { ChevronsUpDownIcon, PlusIcon } from 'lucide-react'\nimport { Direction } from 'radix-ui'\nimport { useEffect, useMemo, useState, type ReactNode } from 'react'\nimport { AiCopilot } from '../components/ai/copilot'\nimport { NotificationsMenu } from '../components/notifications/notifications-menu'\nimport { RealtimeNotifications } from '../components/notifications/realtime-notifications'\nimport { GlobalSearch } from '../components/panel/global-search'\nimport { TenantName } from '../components/panel/nav-label'\nimport { TenantMenu } from '../components/panel/tenant-menu'\nimport { Avatar, AvatarFallback, AvatarImage } from '../components/ui/avatar'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../components/ui/dropdown-menu'\nimport { TooltipProvider } from '../components/ui/tooltip'\nimport {\n AlfakitProvider,\n StandaloneProvider,\n useT,\n type AlfakitContextValue,\n type AnyComponent,\n} from '../context'\nimport { Icon } from '../lib/icons'\nimport {\n CopilotTrigger,\n NotificationsTrigger,\n SearchTrigger,\n TenantSwitcherTrigger,\n type WidgetProps,\n} from './widgets-triggers'\n\n/**\n * The loaded header components of starter kit mode: the panel's own search palette,\n * notifications menu and tenant menu, rendered outside Alfakit pages with the panel data\n * from `widgets.endpoint`. This module only loads in the browser.\n */\n\n// One context for the browser session: its own translator (the panel's strings), an empty\n// registry (only `panel:icon` overrides are looked up here) and an idle action runner.\nlet widgetsContext: AlfakitContextValue | null = null\n\nfunction useWidgetsContext(panel: PanelSchema): AlfakitContextValue {\n widgetsContext ??= {\n registry: new ComponentRegistry<AnyComponent>(),\n pages: {},\n translator: new Translator(),\n actions: new ActionRunner({ endpoints: { action: '', modal: '' } }),\n }\n\n widgetsContext.translator.setTranslations(panel.translations ?? {})\n widgetsContext.translator.setLocale(panel.localization?.tag ?? 'en')\n\n return widgetsContext\n}\n\n/** The panel the components render with, once its data has loaded (null until then). */\nfunction useWidgetsPanel(source: StarterKitWidgets): PanelSchema | null {\n const endpoint = source.widgets.endpoint\n const [loaded, setLoaded] = useState(() => loadedStarterKitPanel(endpoint))\n const base = loadedStarterKitPanel(endpoint) ?? loaded\n\n useEffect(() => {\n let active = true\n\n // Another endpoint (a tenant switch) loads its own panel data.\n void loadStarterKitPanel(endpoint).then(\n (panel) => active && setLoaded(panel),\n () => {},\n )\n\n return () => {\n active = false\n }\n }, [endpoint])\n\n const { navigation, widgets } = source\n\n return useMemo(\n () => (base ? starterKitWidgetsPanel(base, { navigation, widgets }) : null),\n [base, navigation, widgets],\n )\n}\n\nfunction WidgetShell({ panel, children }: { panel: PanelSchema; children: ReactNode }) {\n const context = useWidgetsContext(panel)\n const page = useMemo(() => starterKitWidgetsPage(), [])\n\n return (\n <AlfakitProvider value={context}>\n <StandaloneProvider value={{ panel, page }}>\n <Direction.Provider dir={panel.localization?.direction ?? 'ltr'}>\n <TooltipProvider delayDuration={0}>{children}</TooltipProvider>\n </Direction.Provider>\n </StandaloneProvider>\n </AlfakitProvider>\n )\n}\n\n/** The panel's command palette and global search. */\nexport function LoadedSearch({ source }: WidgetProps) {\n const panel = useWidgetsPanel(source)\n\n // A click or the key bindings before the palette loaded open it now (after its own\n // effects registered the shortcut).\n useEffect(() => {\n if (panel) openRequestedStarterKitSearch()\n }, [panel])\n\n if (!panel) return <SearchTrigger source={source} />\n\n return (\n <WidgetShell panel={panel}>\n <GlobalSearch />\n </WidgetShell>\n )\n}\n\n/** The notifications bell, with realtime notifications on the host's own pages. */\nexport function LoadedNotifications({ source }: WidgetProps) {\n const panel = useWidgetsPanel(source)\n // Alfakit pages subscribe to realtime notifications themselves.\n const alfakitPage = isAlfakitPage(usePage().props)\n\n if (!panel) return <NotificationsTrigger source={source} />\n\n return (\n <WidgetShell panel={panel}>\n <NotificationsMenu />\n {!alfakitPage && <RealtimeNotifications />}\n </WidgetShell>\n )\n}\n\n/** The panel's tenant menu inside a tenant, a menu to choose one elsewhere. */\nexport function LoadedTenantSwitcher({ source }: WidgetProps) {\n const panel = useWidgetsPanel(source)\n\n if (!panel) return <TenantSwitcherTrigger source={source} />\n\n return (\n <WidgetShell panel={panel}>\n {panel.tenancy?.current ? <TenantMenu variant=\"topbar\" /> : <TenantChooser panel={panel} />}\n </WidgetShell>\n )\n}\n\n/** The AI copilot (the panel pages' `topbar.end` slot component). */\nexport function LoadedCopilot({ source }: WidgetProps) {\n const panel = useWidgetsPanel(source)\n // A click or the key bindings before the copilot loaded open it at once.\n const [autoOpen] = useState(() => takeRequestedStarterKitCopilot())\n const component = useMemo(() => (panel ? starterKitCopilot(panel) : null), [panel])\n\n if (!panel) return <CopilotTrigger source={source} />\n\n if (!component) return null\n\n return (\n <WidgetShell panel={panel}>\n <AiCopilot component={component} autoOpen={autoOpen || takeRequestedStarterKitCopilot()} />\n </WidgetShell>\n )\n}\n\n/** The user's tenants on a page outside the panel (no current tenant). */\nfunction TenantChooser({ panel }: { panel: PanelSchema }) {\n const t = useT()\n const tenancy = panel.tenancy\n\n if (!tenancy || (tenancy.tenants.length === 0 && !tenancy.registrationUrl)) return null\n\n const label = t('starter_kit.choose_tenant', {}, 'Choose a tenant')\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n data-slot=\"tenant-menu\"\n className=\"hover:bg-accent data-[state=open]:bg-accent inline-flex h-9 max-w-60 shrink-0 items-center gap-2 rounded-md px-2 text-sm font-medium\"\n >\n <span className=\"sr-only lg:not-sr-only lg:truncate\">{label}</span>\n <Icon\n name=\"alfakit::panels.tenant-menu.toggle-button\"\n fallback={ChevronsUpDownIcon}\n className=\"text-muted-foreground size-4 shrink-0\"\n />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent className=\"min-w-56 rounded-lg\" side=\"bottom\" align=\"end\" sideOffset={4}>\n {tenancy.tenants.length > 0 && (\n <DropdownMenuLabel className=\"text-muted-foreground text-xs\">{label}</DropdownMenuLabel>\n )}\n {tenancy.tenants.map((tenant) => (\n <DropdownMenuItem key={String(tenant.id)} onSelect={() => router.visit(tenant.url)}>\n <Avatar className=\"size-6 rounded-sm\">\n {tenant.avatar && <AvatarImage src={tenant.avatar} alt=\"\" />}\n <AvatarFallback className=\"rounded-sm text-[10px]\">\n {initials(tenantNameText(tenant))}\n </AvatarFallback>\n </Avatar>\n <TenantName tenant={tenant} className=\"flex-1 truncate\" />\n </DropdownMenuItem>\n ))}\n {tenancy.registrationUrl && (\n <>\n {tenancy.tenants.length > 0 && <DropdownMenuSeparator />}\n <DropdownMenuItem onSelect={() => router.visit(tenancy.registrationUrl!)}>\n <Icon name=\"alfakit::panels.tenant-menu.registration-button\" fallback={PlusIcon} />\n {tenancy.registrationLabel ?? t('tenancy.register', {}, 'New')}\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { useHydrated } from "../hooks/use-hydrated.js";
2
- import { formatKeyBinding, initials, registerStarterKitSearchShortcut, requestStarterKitSearch, tenantNameText } from "@alfakit/core";
2
+ import { formatKeyBinding, initials, registerStarterKitCopilotShortcut, registerStarterKitSearchShortcut, requestStarterKitCopilot, requestStarterKitSearch, tenantNameText } from "@alfakit/core";
3
3
  import { useEffect } from "react";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
- import { BellIcon, ChevronsUpDownIcon, SearchIcon } from "lucide-react";
5
+ import { BellIcon, ChevronsUpDownIcon, SearchIcon, SparklesIcon } from "lucide-react";
6
6
  //#region src/starter-kit/widgets-triggers.tsx
7
7
  const triggerClasses = "border-input bg-background hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 inline-flex h-8 shrink-0 items-center rounded-md border text-sm shadow-xs outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50";
8
8
  /** The search field until the palette has loaded: the same look, and it remembers a click. */
@@ -35,6 +35,7 @@ function SearchTrigger({ source, onLoad }) {
35
35
  children: placeholder
36
36
  }),
37
37
  hydrated && binding && /* @__PURE__ */ jsx("kbd", {
38
+ dir: "ltr",
38
39
  className: "bg-muted hidden rounded px-1 font-mono text-[10px] sm:inline",
39
40
  children: formatKeyBinding(binding)
40
41
  })
@@ -84,7 +85,38 @@ function TenantSwitcherTrigger({ source }) {
84
85
  ]
85
86
  });
86
87
  }
88
+ /**
89
+ * The AI copilot's button until its code has loaded: the same look, and it remembers a
90
+ * click or its key bindings (`mod+j`), so the copilot opens once loaded.
91
+ */
92
+ function CopilotTrigger({ source, onLoad }) {
93
+ const copilot = source.widgets.copilot;
94
+ const keys = JSON.stringify(copilot?.keyBindings ?? []);
95
+ const label = copilot?.label ?? "";
96
+ useEffect(() => registerStarterKitCopilotShortcut(JSON.parse(keys), label, () => onLoad?.()), [
97
+ keys,
98
+ label,
99
+ onLoad
100
+ ]);
101
+ return /* @__PURE__ */ jsx("button", {
102
+ type: "button",
103
+ "data-slot": "ai-copilot-trigger",
104
+ "aria-label": label,
105
+ "aria-haspopup": "dialog",
106
+ title: label,
107
+ className: "hover:bg-accent hover:text-accent-foreground inline-flex size-9 items-center justify-center rounded-md",
108
+ onPointerEnter: () => onLoad?.(),
109
+ onClick: () => {
110
+ requestStarterKitCopilot();
111
+ onLoad?.();
112
+ },
113
+ children: /* @__PURE__ */ jsx(SparklesIcon, {
114
+ className: "size-4",
115
+ "aria-hidden": "true"
116
+ })
117
+ });
118
+ }
87
119
  //#endregion
88
- export { NotificationsTrigger, SearchTrigger, TenantSwitcherTrigger };
120
+ export { CopilotTrigger, NotificationsTrigger, SearchTrigger, TenantSwitcherTrigger };
89
121
 
90
122
  //# sourceMappingURL=widgets-triggers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"widgets-triggers.js","names":[],"sources":["../../src/starter-kit/widgets-triggers.tsx"],"sourcesContent":["import {\n formatKeyBinding,\n initials,\n registerStarterKitSearchShortcut,\n requestStarterKitSearch,\n tenantNameText,\n type StarterKitWidgets,\n} from '@alfakit/core'\nimport { BellIcon, ChevronsUpDownIcon, SearchIcon } from 'lucide-react'\nimport { useEffect } from 'react'\nimport { useHydrated } from '../hooks/use-hydrated'\n\n/**\n * What the starter kit header components show until their code and the panel data have\n * loaded: the same look as the loaded triggers, from the shared prop alone.\n */\nexport interface WidgetProps {\n source: StarterKitWidgets\n}\n\nconst triggerClasses =\n 'border-input bg-background hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 inline-flex h-8 shrink-0 items-center rounded-md border text-sm shadow-xs outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50'\n\n/** The search field until the palette has loaded: the same look, and it remembers a click. */\nexport function SearchTrigger({ source, onLoad }: WidgetProps & { onLoad?: () => void }) {\n const hydrated = useHydrated()\n const search = source.widgets.search\n const keys = JSON.stringify(search?.keyBindings ?? ['mod+k'])\n const placeholder = search?.placeholder ?? ''\n // `onLoad` is a stable function (it starts loading the palette's code).\n useEffect(\n () =>\n registerStarterKitSearchShortcut(JSON.parse(keys) as string[], placeholder, () => onLoad?.()),\n [keys, placeholder, onLoad],\n )\n\n const binding = search?.keyBindings[0]\n\n return (\n <button\n type=\"button\"\n className={`${triggerClasses} text-muted-foreground size-8 justify-center gap-2 px-0 font-normal sm:w-56 sm:justify-start sm:px-2.5`}\n onPointerEnter={() => onLoad?.()}\n onClick={() => {\n requestStarterKitSearch()\n onLoad?.()\n }}\n >\n <SearchIcon className=\"size-4\" aria-hidden=\"true\" />\n <span className=\"sr-only sm:not-sr-only sm:flex-1 sm:text-start\">{placeholder}</span>\n {hydrated && binding && (\n <kbd className=\"bg-muted hidden rounded px-1 font-mono text-[10px] sm:inline\">\n {formatKeyBinding(binding)}\n </kbd>\n )}\n </button>\n )\n}\n\n/** The bell and its unread count until the menu has loaded. */\nexport function NotificationsTrigger({ source }: WidgetProps) {\n const notifications = source.widgets.notifications\n const count = notifications?.unreadCount ?? 0\n\n return (\n <button\n type=\"button\"\n data-slot=\"notifications-trigger\"\n aria-label={notifications?.label}\n className=\"hover:bg-accent hover:text-accent-foreground relative inline-flex size-9 items-center justify-center rounded-md\"\n >\n <BellIcon className=\"size-4\" aria-hidden=\"true\" />\n {count > 0 && (\n <span className=\"bg-primary text-primary-foreground absolute -end-0.5 -top-0.5 flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-[10px] font-medium\">\n {count > 99 ? '99+' : count}\n </span>\n )}\n </button>\n )\n}\n\n/** The current tenant (or an empty avatar) until the switcher has loaded: a placeholder. */\nexport function TenantSwitcherTrigger({ source }: WidgetProps) {\n const current = source.widgets.tenancy?.current\n\n return (\n <button\n type=\"button\"\n data-slot=\"tenant-menu\"\n aria-hidden=\"true\"\n tabIndex={-1}\n className=\"hover:bg-accent inline-flex h-9 max-w-60 shrink-0 items-center gap-2 rounded-md px-2 text-sm font-medium\"\n >\n <span className=\"bg-muted flex size-6 items-center justify-center rounded-md text-[10px]\">\n {current ? initials(tenantNameText(current)) : ''}\n </span>\n {current && (\n <span className=\"sr-only min-w-0 truncate lg:not-sr-only\">{tenantNameText(current)}</span>\n )}\n <ChevronsUpDownIcon className=\"text-muted-foreground size-4 shrink-0\" aria-hidden=\"true\" />\n </button>\n )\n}\n"],"mappings":";;;;;;AAoBA,MAAM,iBACJ;;AAGF,SAAgB,cAAc,EAAE,QAAQ,UAAiD;CACvF,MAAM,WAAW,YAAY;CAC7B,MAAM,SAAS,OAAO,QAAQ;CAC9B,MAAM,OAAO,KAAK,UAAU,QAAQ,eAAe,CAAC,OAAO,CAAC;CAC5D,MAAM,cAAc,QAAQ,eAAe;CAE3C,gBAEI,iCAAiC,KAAK,MAAM,IAAI,GAAe,mBAAmB,SAAS,CAAC,GAC9F;EAAC;EAAM;EAAa;CAAM,CAC5B;CAEA,MAAM,UAAU,QAAQ,YAAY;CAEpC,OACE,qBAAC,UAAD;EACE,MAAK;EACL,WAAW,GAAG,eAAe;EAC7B,sBAAsB,SAAS;EAC/B,eAAe;GACb,wBAAwB;GACxB,SAAS;EACX;EAPF,UAAA;GASE,oBAAC,YAAD;IAAY,WAAU;IAAS,eAAY;GAAQ,CAAA;GACnD,oBAAC,QAAD;IAAM,WAAU;IAAkD,UAAA;GAAkB,CAAA;GACnF,YAAY,WACX,oBAAC,OAAD;IAAK,WAAU;IACZ,UAAA,iBAAiB,OAAO;GACtB,CAAA;EAED;;AAEZ;;AAGA,SAAgB,qBAAqB,EAAE,UAAuB;CAC5D,MAAM,gBAAgB,OAAO,QAAQ;CACrC,MAAM,QAAQ,eAAe,eAAe;CAE5C,OACE,qBAAC,UAAD;EACE,MAAK;EACL,aAAU;EACV,cAAY,eAAe;EAC3B,WAAU;EAJZ,UAAA,CAME,oBAAC,UAAD;GAAU,WAAU;GAAS,eAAY;EAAQ,CAAA,GAChD,QAAQ,KACP,oBAAC,QAAD;GAAM,WAAU;GACb,UAAA,QAAQ,KAAK,QAAQ;EAClB,CAAA,CAEF;;AAEZ;;AAGA,SAAgB,sBAAsB,EAAE,UAAuB;CAC7D,MAAM,UAAU,OAAO,QAAQ,SAAS;CAExC,OACE,qBAAC,UAAD;EACE,MAAK;EACL,aAAU;EACV,eAAY;EACZ,UAAU;EACV,WAAU;EALZ,UAAA;GAOE,oBAAC,QAAD;IAAM,WAAU;IACb,UAAA,UAAU,SAAS,eAAe,OAAO,CAAC,IAAI;GAC3C,CAAA;GACL,WACC,oBAAC,QAAD;IAAM,WAAU;IAA2C,UAAA,eAAe,OAAO;GAAQ,CAAA;GAE3F,oBAAC,oBAAD;IAAoB,WAAU;IAAwC,eAAY;GAAQ,CAAA;EACpF;;AAEZ"}
1
+ {"version":3,"file":"widgets-triggers.js","names":[],"sources":["../../src/starter-kit/widgets-triggers.tsx"],"sourcesContent":["import {\n formatKeyBinding,\n initials,\n registerStarterKitCopilotShortcut,\n registerStarterKitSearchShortcut,\n requestStarterKitCopilot,\n requestStarterKitSearch,\n tenantNameText,\n type StarterKitWidgets,\n} from '@alfakit/core'\nimport { BellIcon, ChevronsUpDownIcon, SearchIcon, SparklesIcon } from 'lucide-react'\nimport { useEffect } from 'react'\nimport { useHydrated } from '../hooks/use-hydrated'\n\n/**\n * What the starter kit header components show until their code and the panel data have\n * loaded: the same look as the loaded triggers, from the shared prop alone.\n */\nexport interface WidgetProps {\n source: StarterKitWidgets\n}\n\nconst triggerClasses =\n 'border-input bg-background hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 inline-flex h-8 shrink-0 items-center rounded-md border text-sm shadow-xs outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50'\n\n/** The search field until the palette has loaded: the same look, and it remembers a click. */\nexport function SearchTrigger({ source, onLoad }: WidgetProps & { onLoad?: () => void }) {\n const hydrated = useHydrated()\n const search = source.widgets.search\n const keys = JSON.stringify(search?.keyBindings ?? ['mod+k'])\n const placeholder = search?.placeholder ?? ''\n // `onLoad` is a stable function (it starts loading the palette's code).\n useEffect(\n () =>\n registerStarterKitSearchShortcut(JSON.parse(keys) as string[], placeholder, () => onLoad?.()),\n [keys, placeholder, onLoad],\n )\n\n const binding = search?.keyBindings[0]\n\n return (\n <button\n type=\"button\"\n className={`${triggerClasses} text-muted-foreground size-8 justify-center gap-2 px-0 font-normal sm:w-56 sm:justify-start sm:px-2.5`}\n onPointerEnter={() => onLoad?.()}\n onClick={() => {\n requestStarterKitSearch()\n onLoad?.()\n }}\n >\n <SearchIcon className=\"size-4\" aria-hidden=\"true\" />\n <span className=\"sr-only sm:not-sr-only sm:flex-1 sm:text-start\">{placeholder}</span>\n {hydrated && binding && (\n <kbd dir=\"ltr\" className=\"bg-muted hidden rounded px-1 font-mono text-[10px] sm:inline\">\n {formatKeyBinding(binding)}\n </kbd>\n )}\n </button>\n )\n}\n\n/** The bell and its unread count until the menu has loaded. */\nexport function NotificationsTrigger({ source }: WidgetProps) {\n const notifications = source.widgets.notifications\n const count = notifications?.unreadCount ?? 0\n\n return (\n <button\n type=\"button\"\n data-slot=\"notifications-trigger\"\n aria-label={notifications?.label}\n className=\"hover:bg-accent hover:text-accent-foreground relative inline-flex size-9 items-center justify-center rounded-md\"\n >\n <BellIcon className=\"size-4\" aria-hidden=\"true\" />\n {count > 0 && (\n <span className=\"bg-primary text-primary-foreground absolute -end-0.5 -top-0.5 flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-[10px] font-medium\">\n {count > 99 ? '99+' : count}\n </span>\n )}\n </button>\n )\n}\n\n/** The current tenant (or an empty avatar) until the switcher has loaded: a placeholder. */\nexport function TenantSwitcherTrigger({ source }: WidgetProps) {\n const current = source.widgets.tenancy?.current\n\n return (\n <button\n type=\"button\"\n data-slot=\"tenant-menu\"\n aria-hidden=\"true\"\n tabIndex={-1}\n className=\"hover:bg-accent inline-flex h-9 max-w-60 shrink-0 items-center gap-2 rounded-md px-2 text-sm font-medium\"\n >\n <span className=\"bg-muted flex size-6 items-center justify-center rounded-md text-[10px]\">\n {current ? initials(tenantNameText(current)) : ''}\n </span>\n {current && (\n <span className=\"sr-only min-w-0 truncate lg:not-sr-only\">{tenantNameText(current)}</span>\n )}\n <ChevronsUpDownIcon className=\"text-muted-foreground size-4 shrink-0\" aria-hidden=\"true\" />\n </button>\n )\n}\n\n/**\n * The AI copilot's button until its code has loaded: the same look, and it remembers a\n * click or its key bindings (`mod+j`), so the copilot opens once loaded.\n */\nexport function CopilotTrigger({ source, onLoad }: WidgetProps & { onLoad?: () => void }) {\n const copilot = source.widgets.copilot\n const keys = JSON.stringify(copilot?.keyBindings ?? [])\n const label = copilot?.label ?? ''\n // `onLoad` is a stable function (it starts loading the copilot's code).\n useEffect(\n () => registerStarterKitCopilotShortcut(JSON.parse(keys) as string[], label, () => onLoad?.()),\n [keys, label, onLoad],\n )\n\n return (\n <button\n type=\"button\"\n data-slot=\"ai-copilot-trigger\"\n aria-label={label}\n aria-haspopup=\"dialog\"\n title={label}\n className=\"hover:bg-accent hover:text-accent-foreground inline-flex size-9 items-center justify-center rounded-md\"\n onPointerEnter={() => onLoad?.()}\n onClick={() => {\n requestStarterKitCopilot()\n onLoad?.()\n }}\n >\n <SparklesIcon className=\"size-4\" aria-hidden=\"true\" />\n </button>\n )\n}\n"],"mappings":";;;;;;AAsBA,MAAM,iBACJ;;AAGF,SAAgB,cAAc,EAAE,QAAQ,UAAiD;CACvF,MAAM,WAAW,YAAY;CAC7B,MAAM,SAAS,OAAO,QAAQ;CAC9B,MAAM,OAAO,KAAK,UAAU,QAAQ,eAAe,CAAC,OAAO,CAAC;CAC5D,MAAM,cAAc,QAAQ,eAAe;CAE3C,gBAEI,iCAAiC,KAAK,MAAM,IAAI,GAAe,mBAAmB,SAAS,CAAC,GAC9F;EAAC;EAAM;EAAa;CAAM,CAC5B;CAEA,MAAM,UAAU,QAAQ,YAAY;CAEpC,OACE,qBAAC,UAAD;EACE,MAAK;EACL,WAAW,GAAG,eAAe;EAC7B,sBAAsB,SAAS;EAC/B,eAAe;GACb,wBAAwB;GACxB,SAAS;EACX;EAPF,UAAA;GASE,oBAAC,YAAD;IAAY,WAAU;IAAS,eAAY;GAAQ,CAAA;GACnD,oBAAC,QAAD;IAAM,WAAU;IAAkD,UAAA;GAAkB,CAAA;GACnF,YAAY,WACX,oBAAC,OAAD;IAAK,KAAI;IAAM,WAAU;IACtB,UAAA,iBAAiB,OAAO;GACtB,CAAA;EAED;;AAEZ;;AAGA,SAAgB,qBAAqB,EAAE,UAAuB;CAC5D,MAAM,gBAAgB,OAAO,QAAQ;CACrC,MAAM,QAAQ,eAAe,eAAe;CAE5C,OACE,qBAAC,UAAD;EACE,MAAK;EACL,aAAU;EACV,cAAY,eAAe;EAC3B,WAAU;EAJZ,UAAA,CAME,oBAAC,UAAD;GAAU,WAAU;GAAS,eAAY;EAAQ,CAAA,GAChD,QAAQ,KACP,oBAAC,QAAD;GAAM,WAAU;GACb,UAAA,QAAQ,KAAK,QAAQ;EAClB,CAAA,CAEF;;AAEZ;;AAGA,SAAgB,sBAAsB,EAAE,UAAuB;CAC7D,MAAM,UAAU,OAAO,QAAQ,SAAS;CAExC,OACE,qBAAC,UAAD;EACE,MAAK;EACL,aAAU;EACV,eAAY;EACZ,UAAU;EACV,WAAU;EALZ,UAAA;GAOE,oBAAC,QAAD;IAAM,WAAU;IACb,UAAA,UAAU,SAAS,eAAe,OAAO,CAAC,IAAI;GAC3C,CAAA;GACL,WACC,oBAAC,QAAD;IAAM,WAAU;IAA2C,UAAA,eAAe,OAAO;GAAQ,CAAA;GAE3F,oBAAC,oBAAD;IAAoB,WAAU;IAAwC,eAAY;GAAQ,CAAA;EACpF;;AAEZ;;;;;AAMA,SAAgB,eAAe,EAAE,QAAQ,UAAiD;CACxF,MAAM,UAAU,OAAO,QAAQ;CAC/B,MAAM,OAAO,KAAK,UAAU,SAAS,eAAe,CAAC,CAAC;CACtD,MAAM,QAAQ,SAAS,SAAS;CAEhC,gBACQ,kCAAkC,KAAK,MAAM,IAAI,GAAe,aAAa,SAAS,CAAC,GAC7F;EAAC;EAAM;EAAO;CAAM,CACtB;CAEA,OACE,oBAAC,UAAD;EACE,MAAK;EACL,aAAU;EACV,cAAY;EACZ,iBAAc;EACd,OAAO;EACP,WAAU;EACV,sBAAsB,SAAS;EAC/B,eAAe;GACb,yBAAyB;GACzB,SAAS;EACX;EAEA,UAAA,oBAAC,cAAD;GAAc,WAAU;GAAS,eAAY;EAAQ,CAAA;CAC/C,CAAA;AAEZ"}
@@ -7,14 +7,15 @@
7
7
  * (in the browser, never during SSR).
8
8
  *
9
9
  * ```tsx
10
- * import { AlfakitNotifications, AlfakitSearch } from '@alfakit/react'
10
+ * import { AlfakitCopilot, AlfakitNotifications, AlfakitSearch } from '@alfakit/react'
11
11
  *
12
12
  * <AlfakitSearch />
13
13
  * <AlfakitNotifications />
14
+ * <AlfakitCopilot />
14
15
  * ```
15
16
  */
16
17
  export interface AlfakitHeaderWidgetProps {
17
- /** The `starterKit()` panel to use (the first one by default). */
18
+ /** The `starterKit()` panel to use (by default the open AlfaKit page's panel, else the first one that has this component). */
18
19
  panel?: string;
19
20
  }
20
21
  /**
@@ -22,17 +23,24 @@ export interface AlfakitHeaderWidgetProps {
22
23
  * panel's key bindings (⌘K / Ctrl+K by default), registered once for the page. Renders
23
24
  * nothing for guests or without global search and a command palette.
24
25
  */
25
- export declare function AlfakitSearch({ panel }?: AlfakitHeaderWidgetProps): import("react").JSX.Element | null;
26
+ export declare function AlfakitSearch({ panel }?: AlfakitHeaderWidgetProps): import("react").JSX.Element;
26
27
  /**
27
28
  * The bell with the user's database notifications (`databaseNotifications()`), polling and
28
29
  * realtime updates as in the panel. Renders nothing for guests or without database
29
30
  * notifications.
30
31
  */
31
- export declare function AlfakitNotifications({ panel }?: AlfakitHeaderWidgetProps): import("react").JSX.Element | null;
32
+ export declare function AlfakitNotifications({ panel }?: AlfakitHeaderWidgetProps): import("react").JSX.Element;
32
33
  /**
33
34
  * The tenant switcher of a tenancy panel: the current tenant inside the panel, or a menu
34
35
  * to choose one on the host's own pages. Renders nothing for guests or other panels.
35
36
  */
36
- export declare function AlfakitTenantSwitcher({ panel }?: AlfakitHeaderWidgetProps): import("react").JSX.Element | null;
37
+ export declare function AlfakitTenantSwitcher({ panel }?: AlfakitHeaderWidgetProps): import("react").JSX.Element;
38
+ /**
39
+ * The AI copilot of alfasix/alfakit-ai (`AiPlugin::copilot()`): its button and chat
40
+ * slide-over, opened with its key bindings (`mod+j`) from any page. Renders nothing for
41
+ * guests, without the plugin's copilot, for users who may not use it and (tenancy panels)
42
+ * outside a tenant.
43
+ */
44
+ export declare function AlfakitCopilot({ panel }?: AlfakitHeaderWidgetProps): import("react").JSX.Element;
37
45
  //#endregion
38
46
  //# sourceMappingURL=widgets.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"widgets.d.ts","names":[],"sources":["../../src/starter-kit/widgets.tsx"],"mappings":";;;;;;;;;;;;;;;iBAwBiB;;EAEf;;;;;;;wBAiCc,gBAAgB,UAAS,2CAA6B,IAAA;;;;;;wBAiBtD,uBAAuB,UAAS,2CAA6B,IAAA;;;;;wBAgB7D,wBAAwB,UAAS,2CAA6B,IAAA"}
1
+ {"version":3,"file":"widgets.d.ts","names":[],"sources":["../../src/starter-kit/widgets.tsx"],"mappings":";;;;;;;;;;;;;;;;iBAgCiB;;EAEf;;;;;;;wBA8Dc,gBAAgB,UAAS,2CAA6B,IAAA;;;;;;wBAsBtD,uBAAuB,UAAS,2CAA6B,IAAA;;;;;wBAqB7D,wBAAwB,UAAS,2CAA6B,IAAA;;;;;;;wBAuB9D,iBAAiB,UAAS,2CAA6B,IAAA"}
@@ -1,8 +1,9 @@
1
1
  import { lazyComponent } from "../lib/lazy.js";
2
- import { NotificationsTrigger, SearchTrigger, TenantSwitcherTrigger } from "./widgets-triggers.js";
3
- import { starterKitWidgets } from "@alfakit/core";
2
+ import { CopilotTrigger, NotificationsTrigger, SearchTrigger, TenantSwitcherTrigger } from "./widgets-triggers.js";
3
+ import { isAlfakitPage, starterKitWidgets } from "@alfakit/core";
4
4
  import { usePage } from "@inertiajs/react";
5
- import { jsx } from "react/jsx-runtime";
5
+ import { Suspense, lazy } from "react";
6
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
7
  //#region src/starter-kit/widgets.tsx
7
8
  const load = () => import("./widgets-loaded.js");
8
9
  const LoadedSearch = lazyComponent(() => load().then((module) => module.LoadedSearch), (props) => /* @__PURE__ */ jsx(SearchTrigger, {
@@ -14,8 +15,26 @@ function preloadSearch() {
14
15
  }
15
16
  const LoadedNotifications = lazyComponent(() => load().then((module) => module.LoadedNotifications), (props) => /* @__PURE__ */ jsx(NotificationsTrigger, { ...props }));
16
17
  const LoadedTenantSwitcher = lazyComponent(() => load().then((module) => module.LoadedTenantSwitcher), (props) => /* @__PURE__ */ jsx(TenantSwitcherTrigger, { ...props }));
17
- function useWidgets(panelId) {
18
- return starterKitWidgets(usePage().props, panelId);
18
+ const LoadedCopilot = lazyComponent(() => load().then((module) => module.LoadedCopilot), (props) => /* @__PURE__ */ jsx(CopilotTrigger, {
19
+ ...props,
20
+ onLoad: preloadCopilot
21
+ }));
22
+ function preloadCopilot() {
23
+ LoadedCopilot.preload();
24
+ }
25
+ const LazyImpersonationBanner = lazy(() => import("./impersonation-banner.js"));
26
+ /** While impersonating, the first header component shows the banner on host pages. */
27
+ function StarterKitImpersonationBanner({ source }) {
28
+ const props = usePage().props;
29
+ const impersonation = source?.widgets.impersonation;
30
+ if (!impersonation || isAlfakitPage(props)) return null;
31
+ return /* @__PURE__ */ jsx(Suspense, {
32
+ fallback: null,
33
+ children: /* @__PURE__ */ jsx(LazyImpersonationBanner, { impersonation })
34
+ });
35
+ }
36
+ function useWidgets(panelId, part) {
37
+ return starterKitWidgets(usePage().props, panelId, part);
19
38
  }
20
39
  /**
21
40
  * AlfaKit's command palette and global search: the search field opens it, and so do the
@@ -23,13 +42,14 @@ function useWidgets(panelId) {
23
42
  * nothing for guests or without global search and a command palette.
24
43
  */
25
44
  function AlfakitSearch({ panel } = {}) {
26
- const source = useWidgets(panel);
27
- if (!source?.widgets.search) return null;
28
- return /* @__PURE__ */ jsx("span", {
45
+ const source = useWidgets(panel, "search");
46
+ const banner = /* @__PURE__ */ jsx(StarterKitImpersonationBanner, { source });
47
+ if (!source?.widgets.search) return banner;
48
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [banner, /* @__PURE__ */ jsx("span", {
29
49
  "data-slot": "starter-kit-search",
30
50
  className: "inline-flex",
31
51
  children: /* @__PURE__ */ jsx(LoadedSearch, { source })
32
- });
52
+ })] });
33
53
  }
34
54
  /**
35
55
  * The bell with the user's database notifications (`databaseNotifications()`), polling and
@@ -37,28 +57,46 @@ function AlfakitSearch({ panel } = {}) {
37
57
  * notifications.
38
58
  */
39
59
  function AlfakitNotifications({ panel } = {}) {
40
- const source = useWidgets(panel);
41
- if (!source?.widgets.notifications) return null;
42
- return /* @__PURE__ */ jsx("span", {
60
+ const source = useWidgets(panel, "notifications");
61
+ const banner = /* @__PURE__ */ jsx(StarterKitImpersonationBanner, { source });
62
+ if (!source?.widgets.notifications) return banner;
63
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [banner, /* @__PURE__ */ jsx("span", {
43
64
  "data-slot": "starter-kit-notifications",
44
65
  className: "inline-flex",
45
66
  children: /* @__PURE__ */ jsx(LoadedNotifications, { source })
46
- });
67
+ })] });
47
68
  }
48
69
  /**
49
70
  * The tenant switcher of a tenancy panel: the current tenant inside the panel, or a menu
50
71
  * to choose one on the host's own pages. Renders nothing for guests or other panels.
51
72
  */
52
73
  function AlfakitTenantSwitcher({ panel } = {}) {
53
- const source = useWidgets(panel);
54
- if (!source?.widgets.tenancy) return null;
55
- return /* @__PURE__ */ jsx("span", {
74
+ const source = useWidgets(panel, "tenancy");
75
+ const banner = /* @__PURE__ */ jsx(StarterKitImpersonationBanner, { source });
76
+ if (!source?.widgets.tenancy) return banner;
77
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [banner, /* @__PURE__ */ jsx("span", {
56
78
  "data-slot": "starter-kit-tenant-switcher",
57
79
  className: "inline-flex",
58
80
  children: /* @__PURE__ */ jsx(LoadedTenantSwitcher, { source })
59
- });
81
+ })] });
82
+ }
83
+ /**
84
+ * The AI copilot of alfasix/alfakit-ai (`AiPlugin::copilot()`): its button and chat
85
+ * slide-over, opened with its key bindings (`mod+j`) from any page. Renders nothing for
86
+ * guests, without the plugin's copilot, for users who may not use it and (tenancy panels)
87
+ * outside a tenant.
88
+ */
89
+ function AlfakitCopilot({ panel } = {}) {
90
+ const source = useWidgets(panel, "copilot");
91
+ const banner = /* @__PURE__ */ jsx(StarterKitImpersonationBanner, { source });
92
+ if (!source?.widgets.copilot) return banner;
93
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [banner, /* @__PURE__ */ jsx("span", {
94
+ "data-slot": "starter-kit-copilot",
95
+ className: "inline-flex",
96
+ children: /* @__PURE__ */ jsx(LoadedCopilot, { source })
97
+ })] });
60
98
  }
61
99
  //#endregion
62
- export { AlfakitNotifications, AlfakitSearch, AlfakitTenantSwitcher };
100
+ export { AlfakitCopilot, AlfakitNotifications, AlfakitSearch, AlfakitTenantSwitcher };
63
101
 
64
102
  //# sourceMappingURL=widgets.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"widgets.js","names":[],"sources":["../../src/starter-kit/widgets.tsx"],"sourcesContent":["import { starterKitWidgets, type StarterKitWidgets } from '@alfakit/core'\nimport { usePage } from '@inertiajs/react'\nimport { lazyComponent } from '../lib/lazy'\nimport {\n NotificationsTrigger,\n SearchTrigger,\n TenantSwitcherTrigger,\n type WidgetProps,\n} from './widgets-triggers'\n\n/**\n * Drop-in header components of starter kit mode (`Panel::starterKit()`): AlfaKit's search,\n * notifications bell and tenant switcher in the host's own header, on every page of the\n * application. They read the shared `alfakitNavigation` prop, render a lightweight trigger\n * straight away, and load their code and the panel data the first time they render\n * (in the browser, never during SSR).\n *\n * ```tsx\n * import { AlfakitNotifications, AlfakitSearch } from '@alfakit/react'\n *\n * <AlfakitSearch />\n * <AlfakitNotifications />\n * ```\n */\nexport interface AlfakitHeaderWidgetProps {\n /** The `starterKit()` panel to use (the first one by default). */\n panel?: string\n}\n\nconst load = () => import('./widgets-loaded')\n\nconst LoadedSearch = lazyComponent<WidgetProps>(\n () => load().then((module) => module.LoadedSearch),\n (props) => <SearchTrigger {...props} onLoad={preloadSearch} />,\n)\n\nfunction preloadSearch() {\n void LoadedSearch.preload()\n}\n\nconst LoadedNotifications = lazyComponent<WidgetProps>(\n () => load().then((module) => module.LoadedNotifications),\n (props) => <NotificationsTrigger {...props} />,\n)\n\nconst LoadedTenantSwitcher = lazyComponent<WidgetProps>(\n () => load().then((module) => module.LoadedTenantSwitcher),\n (props) => <TenantSwitcherTrigger {...props} />,\n)\n\nfunction useWidgets(panelId: string | undefined): StarterKitWidgets | null {\n return starterKitWidgets(usePage().props, panelId)\n}\n\n/**\n * AlfaKit's command palette and global search: the search field opens it, and so do the\n * panel's key bindings (⌘K / Ctrl+K by default), registered once for the page. Renders\n * nothing for guests or without global search and a command palette.\n */\nexport function AlfakitSearch({ panel }: AlfakitHeaderWidgetProps = {}) {\n const source = useWidgets(panel)\n\n if (!source?.widgets.search) return null\n\n return (\n <span data-slot=\"starter-kit-search\" className=\"inline-flex\">\n <LoadedSearch source={source} />\n </span>\n )\n}\n\n/**\n * The bell with the user's database notifications (`databaseNotifications()`), polling and\n * realtime updates as in the panel. Renders nothing for guests or without database\n * notifications.\n */\nexport function AlfakitNotifications({ panel }: AlfakitHeaderWidgetProps = {}) {\n const source = useWidgets(panel)\n\n if (!source?.widgets.notifications) return null\n\n return (\n <span data-slot=\"starter-kit-notifications\" className=\"inline-flex\">\n <LoadedNotifications source={source} />\n </span>\n )\n}\n\n/**\n * The tenant switcher of a tenancy panel: the current tenant inside the panel, or a menu\n * to choose one on the host's own pages. Renders nothing for guests or other panels.\n */\nexport function AlfakitTenantSwitcher({ panel }: AlfakitHeaderWidgetProps = {}) {\n const source = useWidgets(panel)\n\n if (!source?.widgets.tenancy) return null\n\n return (\n <span data-slot=\"starter-kit-tenant-switcher\" className=\"inline-flex\">\n <LoadedTenantSwitcher source={source} />\n </span>\n )\n}\n"],"mappings":";;;;;;AA6BA,MAAM,aAAa,OAAO;AAE1B,MAAM,eAAe,oBACb,KAAK,CAAC,CAAC,MAAM,WAAW,OAAO,YAAY,IAChD,UAAU,oBAAC,eAAD;CAAe,GAAI;CAAO,QAAQ;AAAgB,CAAA,CAC/D;AAEA,SAAS,gBAAgB;CACvB,aAAkB,QAAQ;AAC5B;AAEA,MAAM,sBAAsB,oBACpB,KAAK,CAAC,CAAC,MAAM,WAAW,OAAO,mBAAmB,IACvD,UAAU,oBAAC,sBAAD,EAAsB,GAAI,MAAQ,CAAA,CAC/C;AAEA,MAAM,uBAAuB,oBACrB,KAAK,CAAC,CAAC,MAAM,WAAW,OAAO,oBAAoB,IACxD,UAAU,oBAAC,uBAAD,EAAuB,GAAI,MAAQ,CAAA,CAChD;AAEA,SAAS,WAAW,SAAuD;CACzE,OAAO,kBAAkB,QAAQ,CAAC,CAAC,OAAO,OAAO;AACnD;;;;;;AAOA,SAAgB,cAAc,EAAE,UAAoC,CAAC,GAAG;CACtE,MAAM,SAAS,WAAW,KAAK;CAE/B,IAAI,CAAC,QAAQ,QAAQ,QAAQ,OAAO;CAEpC,OACE,oBAAC,QAAD;EAAM,aAAU;EAAqB,WAAU;EAC7C,UAAA,oBAAC,cAAD,EAAsB,OAAS,CAAA;CAC3B,CAAA;AAEV;;;;;;AAOA,SAAgB,qBAAqB,EAAE,UAAoC,CAAC,GAAG;CAC7E,MAAM,SAAS,WAAW,KAAK;CAE/B,IAAI,CAAC,QAAQ,QAAQ,eAAe,OAAO;CAE3C,OACE,oBAAC,QAAD;EAAM,aAAU;EAA4B,WAAU;EACpD,UAAA,oBAAC,qBAAD,EAA6B,OAAS,CAAA;CAClC,CAAA;AAEV;;;;;AAMA,SAAgB,sBAAsB,EAAE,UAAoC,CAAC,GAAG;CAC9E,MAAM,SAAS,WAAW,KAAK;CAE/B,IAAI,CAAC,QAAQ,QAAQ,SAAS,OAAO;CAErC,OACE,oBAAC,QAAD;EAAM,aAAU;EAA8B,WAAU;EACtD,UAAA,oBAAC,sBAAD,EAA8B,OAAS,CAAA;CACnC,CAAA;AAEV"}
1
+ {"version":3,"file":"widgets.js","names":[],"sources":["../../src/starter-kit/widgets.tsx"],"sourcesContent":["import {\n isAlfakitPage,\n starterKitWidgets,\n type StarterKitWidgets,\n type StarterKitWidgetsSchema,\n} from '@alfakit/core'\nimport { usePage } from '@inertiajs/react'\nimport { lazy, Suspense } from 'react'\nimport { lazyComponent } from '../lib/lazy'\nimport {\n CopilotTrigger,\n NotificationsTrigger,\n SearchTrigger,\n TenantSwitcherTrigger,\n type WidgetProps,\n} from './widgets-triggers'\n\n/**\n * Drop-in header components of starter kit mode (`Panel::starterKit()`): AlfaKit's search,\n * notifications bell and tenant switcher in the host's own header, on every page of the\n * application. They read the shared `alfakitNavigation` prop, render a lightweight trigger\n * straight away, and load their code and the panel data the first time they render\n * (in the browser, never during SSR).\n *\n * ```tsx\n * import { AlfakitCopilot, AlfakitNotifications, AlfakitSearch } from '@alfakit/react'\n *\n * <AlfakitSearch />\n * <AlfakitNotifications />\n * <AlfakitCopilot />\n * ```\n */\nexport interface AlfakitHeaderWidgetProps {\n /** The `starterKit()` panel to use (by default the open AlfaKit page's panel, else the first one that has this component). */\n panel?: string\n}\n\nconst load = () => import('./widgets-loaded')\n\nconst LoadedSearch = lazyComponent<WidgetProps>(\n () => load().then((module) => module.LoadedSearch),\n (props) => <SearchTrigger {...props} onLoad={preloadSearch} />,\n)\n\nfunction preloadSearch() {\n void LoadedSearch.preload()\n}\n\nconst LoadedNotifications = lazyComponent<WidgetProps>(\n () => load().then((module) => module.LoadedNotifications),\n (props) => <NotificationsTrigger {...props} />,\n)\n\nconst LoadedTenantSwitcher = lazyComponent<WidgetProps>(\n () => load().then((module) => module.LoadedTenantSwitcher),\n (props) => <TenantSwitcherTrigger {...props} />,\n)\n\nconst LoadedCopilot = lazyComponent<WidgetProps>(\n () => load().then((module) => module.LoadedCopilot),\n (props) => <CopilotTrigger {...props} onLoad={preloadCopilot} />,\n)\n\nfunction preloadCopilot() {\n void LoadedCopilot.preload()\n}\n\n// Only needed while impersonating: its code loads then (and never on AlfaKit pages).\nconst LazyImpersonationBanner = lazy(() => import('./impersonation-banner'))\n\n/** While impersonating, the first header component shows the banner on host pages. */\nfunction StarterKitImpersonationBanner({ source }: { source: StarterKitWidgets | null }) {\n const props = usePage().props\n const impersonation = source?.widgets.impersonation\n\n if (!impersonation || isAlfakitPage(props)) return null\n\n return (\n <Suspense fallback={null}>\n <LazyImpersonationBanner impersonation={impersonation} />\n </Suspense>\n )\n}\n\nfunction useWidgets(\n panelId: string | undefined,\n part: keyof StarterKitWidgetsSchema,\n): StarterKitWidgets | null {\n return starterKitWidgets(usePage().props, panelId, part)\n}\n\n/**\n * AlfaKit's command palette and global search: the search field opens it, and so do the\n * panel's key bindings (⌘K / Ctrl+K by default), registered once for the page. Renders\n * nothing for guests or without global search and a command palette.\n */\nexport function AlfakitSearch({ panel }: AlfakitHeaderWidgetProps = {}) {\n const source = useWidgets(panel, 'search')\n\n const banner = <StarterKitImpersonationBanner source={source} />\n\n if (!source?.widgets.search) return banner\n\n return (\n <>\n {banner}\n <span data-slot=\"starter-kit-search\" className=\"inline-flex\">\n <LoadedSearch source={source} />\n </span>\n </>\n )\n}\n\n/**\n * The bell with the user's database notifications (`databaseNotifications()`), polling and\n * realtime updates as in the panel. Renders nothing for guests or without database\n * notifications.\n */\nexport function AlfakitNotifications({ panel }: AlfakitHeaderWidgetProps = {}) {\n const source = useWidgets(panel, 'notifications')\n\n const banner = <StarterKitImpersonationBanner source={source} />\n\n if (!source?.widgets.notifications) return banner\n\n return (\n <>\n {banner}\n <span data-slot=\"starter-kit-notifications\" className=\"inline-flex\">\n <LoadedNotifications source={source} />\n </span>\n </>\n )\n}\n\n/**\n * The tenant switcher of a tenancy panel: the current tenant inside the panel, or a menu\n * to choose one on the host's own pages. Renders nothing for guests or other panels.\n */\nexport function AlfakitTenantSwitcher({ panel }: AlfakitHeaderWidgetProps = {}) {\n const source = useWidgets(panel, 'tenancy')\n\n const banner = <StarterKitImpersonationBanner source={source} />\n\n if (!source?.widgets.tenancy) return banner\n\n return (\n <>\n {banner}\n <span data-slot=\"starter-kit-tenant-switcher\" className=\"inline-flex\">\n <LoadedTenantSwitcher source={source} />\n </span>\n </>\n )\n}\n\n/**\n * The AI copilot of alfasix/alfakit-ai (`AiPlugin::copilot()`): its button and chat\n * slide-over, opened with its key bindings (`mod+j`) from any page. Renders nothing for\n * guests, without the plugin's copilot, for users who may not use it and (tenancy panels)\n * outside a tenant.\n */\nexport function AlfakitCopilot({ panel }: AlfakitHeaderWidgetProps = {}) {\n const source = useWidgets(panel, 'copilot')\n\n const banner = <StarterKitImpersonationBanner source={source} />\n\n if (!source?.widgets.copilot) return banner\n\n return (\n <>\n {banner}\n <span data-slot=\"starter-kit-copilot\" className=\"inline-flex\">\n <LoadedCopilot source={source} />\n </span>\n </>\n )\n}\n"],"mappings":"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"}
package/dist/styles.css CHANGED
@@ -11,8 +11,21 @@
11
11
  /* Built-in themes (alfakit, minimal, soft, corporate, filament); neutral is below. */
12
12
  @import './themes.css';
13
13
 
14
+ /*
15
+ * Toast styles, as in the Vue renderer. Sonner also injects them at runtime, which a
16
+ * nonce-based Content Security Policy blocks; from the stylesheet they always apply.
17
+ */
18
+ @import 'sonner/dist/styles.css';
19
+
14
20
  @custom-variant dark (&:is(.dark *));
15
21
 
22
+ /*
23
+ * Class lists that live in @alfakit/core (stacked-on-mobile tables, filter and column manager
24
+ * widths in `table.ts`, …): scan core's build too. Relative to this file in
25
+ * node_modules/@alfakit/<renderer>/dist, next to node_modules/@alfakit/core.
26
+ */
27
+ @source '../../core/dist';
28
+
16
29
  /*
17
30
  * Grid classes are composed at runtime from schema breakpoints (`columns`, `columnSpan`),
18
31
  * so force Tailwind to generate every variant the renderers can produce.
@@ -116,10 +129,10 @@
116
129
  --secondary: oklch(0.97 0 0);
117
130
  --secondary-foreground: oklch(0.205 0 0);
118
131
  --muted: oklch(0.97 0 0);
119
- --muted-foreground: oklch(0.556 0 0);
132
+ --muted-foreground: oklch(0.54 0 0);
120
133
  --accent: oklch(0.97 0 0);
121
134
  --accent-foreground: oklch(0.205 0 0);
122
- --destructive: var(--alfakit-danger, oklch(0.55 0.245 27.325));
135
+ --destructive: var(--alfakit-danger, oklch(0.5 0.245 27.325));
123
136
  --destructive-foreground: var(--alfakit-danger-foreground, oklch(0.985 0 0));
124
137
  --border: oklch(0.922 0 0);
125
138
  --input: oklch(0.64 0 0);