@alfakit/react 0.1.2 → 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 (171) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/components/actions/action-modals.js +4 -0
  3. package/dist/components/actions/action-modals.js.map +1 -1
  4. package/dist/components/ai/copilot.d.ts +3 -1
  5. package/dist/components/ai/copilot.d.ts.map +1 -1
  6. package/dist/components/ai/copilot.js +4 -1
  7. package/dist/components/ai/copilot.js.map +1 -1
  8. package/dist/components/cms/live-preview.js +3 -2
  9. package/dist/components/cms/live-preview.js.map +1 -1
  10. package/dist/components/cms/page.js +1 -1
  11. package/dist/components/fields/builder.js +15 -6
  12. package/dist/components/fields/builder.js.map +1 -1
  13. package/dist/components/fields/image-editor-dialog.js +4 -2
  14. package/dist/components/fields/image-editor-dialog.js.map +1 -1
  15. package/dist/components/fields/item-actions.js +10 -10
  16. package/dist/components/fields/item-actions.js.map +1 -1
  17. package/dist/components/fields/key-value.d.ts.map +1 -1
  18. package/dist/components/fields/key-value.js +3 -3
  19. package/dist/components/fields/key-value.js.map +1 -1
  20. package/dist/components/fields/modal-table-select.js +6 -5
  21. package/dist/components/fields/modal-table-select.js.map +1 -1
  22. package/dist/components/fields/repeater.js +2 -2
  23. package/dist/components/fields/repeater.js.map +1 -1
  24. package/dist/components/fields/rich-editor.js +2 -1
  25. package/dist/components/fields/rich-editor.js.map +1 -1
  26. package/dist/components/form/form-block.js +1 -1
  27. package/dist/components/form/form-block.js.map +1 -1
  28. package/dist/components/form/form-context.js +2 -2
  29. package/dist/components/form/form-context.js.map +1 -1
  30. package/dist/components/kanban/kanban.js +4 -3
  31. package/dist/components/kanban/kanban.js.map +1 -1
  32. package/dist/components/layout/section.js +2 -2
  33. package/dist/components/layout/section.js.map +1 -1
  34. package/dist/components/panel/app-sidebar.d.ts +2 -3
  35. package/dist/components/panel/app-sidebar.d.ts.map +1 -1
  36. package/dist/components/panel/app-sidebar.js +1 -24
  37. package/dist/components/panel/app-sidebar.js.map +1 -1
  38. package/dist/components/panel/brand.d.ts +10 -0
  39. package/dist/components/panel/brand.d.ts.map +1 -0
  40. package/dist/components/panel/brand.js +37 -0
  41. package/dist/components/panel/brand.js.map +1 -0
  42. package/dist/components/panel/index.d.ts +2 -1
  43. package/dist/components/panel/topbar.js +1 -1
  44. package/dist/components/realtime/live-records-pill.d.ts.map +1 -1
  45. package/dist/components/realtime/live-records-pill.js +6 -3
  46. package/dist/components/realtime/live-records-pill.js.map +1 -1
  47. package/dist/components/table/cells.d.ts +6 -0
  48. package/dist/components/table/cells.d.ts.map +1 -1
  49. package/dist/components/table/cells.js +6 -2
  50. package/dist/components/table/cells.js.map +1 -1
  51. package/dist/components/table/column-manager.js +8 -7
  52. package/dist/components/table/column-manager.js.map +1 -1
  53. package/dist/components/table/content-layout.js +2 -1
  54. package/dist/components/table/content-layout.js.map +1 -1
  55. package/dist/components/table/pagination.js +16 -13
  56. package/dist/components/table/pagination.js.map +1 -1
  57. package/dist/components/table/table-block.js +14 -4
  58. package/dist/components/table/table-block.js.map +1 -1
  59. package/dist/components/ui/dialog.d.ts.map +1 -1
  60. package/dist/components/ui/dialog.js +3 -1
  61. package/dist/components/ui/dialog.js.map +1 -1
  62. package/dist/components/ui/popover.d.ts.map +1 -1
  63. package/dist/components/ui/popover.js +3 -1
  64. package/dist/components/ui/popover.js.map +1 -1
  65. package/dist/components/ui/sheet.d.ts.map +1 -1
  66. package/dist/components/ui/sheet.js +3 -1
  67. package/dist/components/ui/sheet.js.map +1 -1
  68. package/dist/components/ui/tooltip.js +3 -1
  69. package/dist/components/ui/tooltip.js.map +1 -1
  70. package/dist/context.d.ts +5 -0
  71. package/dist/context.d.ts.map +1 -1
  72. package/dist/context.js +5 -1
  73. package/dist/context.js.map +1 -1
  74. package/dist/create-alfakit.d.ts.map +1 -1
  75. package/dist/create-alfakit.js +8 -5
  76. package/dist/create-alfakit.js.map +1 -1
  77. package/dist/eject-manifest.json +16 -3
  78. package/dist/index.d.ts +6 -3
  79. package/dist/index.js +24 -21
  80. package/dist/layouts/app-layout.d.ts.map +1 -1
  81. package/dist/layouts/app-layout.js +2 -29
  82. package/dist/layouts/app-layout.js.map +1 -1
  83. package/dist/layouts/auth-layout.js +2 -2
  84. package/dist/layouts/auth-layout.js.map +1 -1
  85. package/dist/layouts/fullscreen-layout.js +1 -1
  86. package/dist/layouts/fullscreen-layout.js.map +1 -1
  87. package/dist/layouts/lazy-layouts.js +15 -0
  88. package/dist/layouts/lazy-layouts.js.map +1 -0
  89. package/dist/layouts/max-widths.js +34 -0
  90. package/dist/layouts/max-widths.js.map +1 -0
  91. package/dist/layouts/panel-layouts.d.ts +10 -0
  92. package/dist/layouts/panel-layouts.d.ts.map +1 -0
  93. package/dist/layouts/panel-layouts.js +20 -0
  94. package/dist/layouts/panel-layouts.js.map +1 -0
  95. package/dist/layouts/top-nav-layout.js +2 -2
  96. package/dist/layouts/top-nav-layout.js.map +1 -1
  97. package/dist/pages/page.d.ts.map +1 -1
  98. package/dist/pages/page.js +12 -7
  99. package/dist/pages/page.js.map +1 -1
  100. package/dist/standalone/alfakit-component.js +11 -6
  101. package/dist/standalone/alfakit-component.js.map +1 -1
  102. package/dist/standalone.css +7 -0
  103. package/dist/starter-kit/dashboard-widgets.d.ts +33 -0
  104. package/dist/starter-kit/dashboard-widgets.d.ts.map +1 -0
  105. package/dist/starter-kit/dashboard-widgets.js +53 -0
  106. package/dist/starter-kit/dashboard-widgets.js.map +1 -0
  107. package/dist/starter-kit/impersonation-banner.js +34 -0
  108. package/dist/starter-kit/impersonation-banner.js.map +1 -0
  109. package/dist/starter-kit/index.d.ts +3 -2
  110. package/dist/starter-kit/index.js +3 -2
  111. package/dist/starter-kit/starter-kit.d.ts +6 -0
  112. package/dist/starter-kit/starter-kit.d.ts.map +1 -1
  113. package/dist/starter-kit/starter-kit.js +18 -7
  114. package/dist/starter-kit/starter-kit.js.map +1 -1
  115. package/dist/starter-kit/widgets-loaded.js +20 -4
  116. package/dist/starter-kit/widgets-loaded.js.map +1 -1
  117. package/dist/starter-kit/widgets-triggers.js +34 -3
  118. package/dist/starter-kit/widgets-triggers.js.map +1 -1
  119. package/dist/starter-kit/widgets.d.ts +13 -5
  120. package/dist/starter-kit/widgets.d.ts.map +1 -1
  121. package/dist/starter-kit/widgets.js +56 -18
  122. package/dist/starter-kit/widgets.js.map +1 -1
  123. package/dist/styles.css +15 -2
  124. package/dist/themes.css +6 -1
  125. package/package.json +2 -2
  126. package/src/components/actions/action-modals.tsx +10 -0
  127. package/src/components/ai/copilot.tsx +14 -1
  128. package/src/components/cms/live-preview.tsx +5 -2
  129. package/src/components/fields/builder.tsx +14 -5
  130. package/src/components/fields/image-editor-dialog.tsx +7 -2
  131. package/src/components/fields/item-actions.tsx +32 -9
  132. package/src/components/fields/key-value.tsx +3 -2
  133. package/src/components/fields/modal-table-select.tsx +8 -3
  134. package/src/components/fields/repeater.tsx +2 -3
  135. package/src/components/fields/rich-editor.tsx +3 -0
  136. package/src/components/form/form-block.tsx +2 -1
  137. package/src/components/form/form-context.tsx +2 -2
  138. package/src/components/kanban/kanban.tsx +16 -3
  139. package/src/components/layout/section.tsx +2 -2
  140. package/src/components/panel/app-sidebar.tsx +2 -38
  141. package/src/components/panel/brand.tsx +46 -0
  142. package/src/components/realtime/live-records-pill.tsx +4 -3
  143. package/src/components/table/cells.tsx +9 -2
  144. package/src/components/table/column-manager.tsx +12 -10
  145. package/src/components/table/content-layout.tsx +5 -1
  146. package/src/components/table/pagination.tsx +16 -9
  147. package/src/components/table/table-block.tsx +25 -12
  148. package/src/components/ui/dialog.tsx +5 -1
  149. package/src/components/ui/popover.tsx +5 -1
  150. package/src/components/ui/sheet.tsx +5 -1
  151. package/src/components/ui/tooltip.tsx +5 -1
  152. package/src/context.tsx +10 -0
  153. package/src/create-alfakit.tsx +11 -2
  154. package/src/index.ts +2 -0
  155. package/src/layouts/app-layout.tsx +4 -28
  156. package/src/layouts/auth-layout.tsx +2 -2
  157. package/src/layouts/fullscreen-layout.tsx +1 -1
  158. package/src/layouts/lazy-layouts.ts +14 -0
  159. package/src/layouts/max-widths.ts +29 -0
  160. package/src/layouts/panel-layouts.ts +17 -0
  161. package/src/layouts/top-nav-layout.tsx +2 -2
  162. package/src/pages/page.tsx +21 -12
  163. package/src/standalone/alfakit-component.tsx +18 -7
  164. package/src/starter-kit/dashboard-widgets.tsx +78 -0
  165. package/src/starter-kit/impersonation-banner.tsx +48 -0
  166. package/src/starter-kit/index.ts +2 -0
  167. package/src/starter-kit/starter-kit.tsx +31 -4
  168. package/src/starter-kit/widgets-loaded.tsx +22 -0
  169. package/src/starter-kit/widgets-triggers.tsx +36 -1
  170. package/src/starter-kit/widgets.tsx +95 -20
  171. package/src/styles.css +15 -2
@@ -17,6 +17,13 @@
17
17
 
18
18
  @custom-variant dark (&:is(.dark *));
19
19
 
20
+ /*
21
+ * Class lists that live in @alfakit/core (stacked-on-mobile tables, filter and column manager
22
+ * widths in `table.ts`, …): scan core's build too. Relative to this file in
23
+ * node_modules/@alfakit/<renderer>/dist, next to node_modules/@alfakit/core.
24
+ */
25
+ @source '../../core/dist';
26
+
20
27
  /*
21
28
  * Grid classes are composed at runtime from schema breakpoints (`columns`, `columnSpan`),
22
29
  * so force Tailwind to generate every variant the renderers can produce.
@@ -0,0 +1,33 @@
1
+ import { AnyComponent } from "../context.js";
2
+ import { ReactNode } from "react";
3
+ //#region src/starter-kit/dashboard-widgets.d.ts
4
+ /** Props of `<AlfakitWidgets>`. */
5
+ export interface AlfakitWidgetsProps {
6
+ /** The `starterKit()` panel whose widgets to show (the first one by default). */
7
+ panel?: string;
8
+ /** Frontend components of custom widgets (`{ RevenueWidget }`), as for `<AlfakitComponent>`. */
9
+ components?: Record<string, AnyComponent>;
10
+ className?: string;
11
+ /** Rendered instead when there are no widgets to show. */
12
+ children?: ReactNode;
13
+ }
14
+ /**
15
+ * The dashboard widgets of a `starterKit()` panel on the host's own dashboard. Reads the
16
+ * `alfakitWidgets` prop (shared on the panel's `starterKitDashboard()` pages only, the
17
+ * starter kit's `/dashboard` by default) and renders the widgets with the host's theme, as
18
+ * `<AlfakitComponent>` renders standalone widgets: lazy widgets, polling and table widget
19
+ * actions go through the panel's endpoints. Its code loads in the browser; the server
20
+ * render and hydration show placeholders. Renders `children` (the kit's placeholder boxes)
21
+ * when there are no widgets to show: other pages, guests, users who may not open the panel.
22
+ *
23
+ * ```tsx
24
+ * import { AlfakitWidgets } from '@alfakit/react'
25
+ *
26
+ * <AlfakitWidgets>
27
+ * <MyEmptyState />
28
+ * </AlfakitWidgets>
29
+ * ```
30
+ */
31
+ export declare function AlfakitWidgets({ panel, components, className, children }: AlfakitWidgetsProps): import("react").JSX.Element;
32
+ //#endregion
33
+ //# sourceMappingURL=dashboard-widgets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-widgets.d.ts","names":[],"sources":["../../src/starter-kit/dashboard-widgets.tsx"],"mappings":";;;;iBAYiB;;EAEf;;EAEA,aAAa,eAAe;EAC5B;;EAEA,WAAW;;;;;;;;;;;;;;;;;;;wBAgDG,iBAAiB,OAAO,YAAY,WAAW,YAAY,sCAAmB,IAAA"}
@@ -0,0 +1,53 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { lazyComponent } from "../lib/lazy.js";
3
+ import { standaloneWidgetCount, starterKitDashboardWidgets } from "@alfakit/core";
4
+ import { usePage } from "@inertiajs/react";
5
+ import { Fragment, jsx } from "react/jsx-runtime";
6
+ //#region src/starter-kit/dashboard-widgets.tsx
7
+ const LoadedWidgets = lazyComponent(() => import("../standalone/alfakit-component.js").then((module) => module.AlfakitComponent), (props) => /* @__PURE__ */ jsx(WidgetsPlaceholder, { ...props }));
8
+ /** Widget-sized boxes until the widgets' code has loaded (also during SSR). */
9
+ function WidgetsPlaceholder({ component, className }) {
10
+ const count = standaloneWidgetCount(component);
11
+ return /* @__PURE__ */ jsx("div", {
12
+ "data-slot": "starter-kit-widgets-placeholder",
13
+ "aria-busy": "true",
14
+ className: cn("grid auto-rows-min gap-4 md:grid-cols-2", className),
15
+ children: Array.from({ length: Math.max(count, 1) }, (_, index) => /* @__PURE__ */ jsx("div", {
16
+ "aria-hidden": "true",
17
+ className: "bg-muted h-28 animate-pulse rounded-xl"
18
+ }, index))
19
+ });
20
+ }
21
+ /**
22
+ * The dashboard widgets of a `starterKit()` panel on the host's own dashboard. Reads the
23
+ * `alfakitWidgets` prop (shared on the panel's `starterKitDashboard()` pages only, the
24
+ * starter kit's `/dashboard` by default) and renders the widgets with the host's theme, as
25
+ * `<AlfakitComponent>` renders standalone widgets: lazy widgets, polling and table widget
26
+ * actions go through the panel's endpoints. Its code loads in the browser; the server
27
+ * render and hydration show placeholders. Renders `children` (the kit's placeholder boxes)
28
+ * when there are no widgets to show: other pages, guests, users who may not open the panel.
29
+ *
30
+ * ```tsx
31
+ * import { AlfakitWidgets } from '@alfakit/react'
32
+ *
33
+ * <AlfakitWidgets>
34
+ * <MyEmptyState />
35
+ * </AlfakitWidgets>
36
+ * ```
37
+ */
38
+ function AlfakitWidgets({ panel, components, className, children }) {
39
+ const component = starterKitDashboardWidgets(usePage().props, panel);
40
+ if (!component) return /* @__PURE__ */ jsx(Fragment, { children });
41
+ return /* @__PURE__ */ jsx("div", {
42
+ "data-slot": "starter-kit-widgets",
43
+ children: /* @__PURE__ */ jsx(LoadedWidgets, {
44
+ component,
45
+ components,
46
+ className
47
+ })
48
+ });
49
+ }
50
+ //#endregion
51
+ export { AlfakitWidgets };
52
+
53
+ //# sourceMappingURL=dashboard-widgets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-widgets.js","names":[],"sources":["../../src/starter-kit/dashboard-widgets.tsx"],"sourcesContent":["import {\n standaloneWidgetCount,\n starterKitDashboardWidgets,\n type StandaloneComponentSchema,\n} from '@alfakit/core'\nimport { usePage } from '@inertiajs/react'\nimport type { ReactNode } from 'react'\nimport type { AnyComponent } from '../context'\nimport { lazyComponent } from '../lib/lazy'\nimport { cn } from '../lib/utils'\n\n/** Props of `<AlfakitWidgets>`. */\nexport interface AlfakitWidgetsProps {\n /** The `starterKit()` panel whose widgets to show (the first one by default). */\n panel?: string\n /** Frontend components of custom widgets (`{ RevenueWidget }`), as for `<AlfakitComponent>`. */\n components?: Record<string, AnyComponent>\n className?: string\n /** Rendered instead when there are no widgets to show. */\n children?: ReactNode\n}\n\ninterface LoadedProps {\n component: StandaloneComponentSchema\n components?: Record<string, AnyComponent>\n className?: string\n}\n\nconst LoadedWidgets = lazyComponent<LoadedProps>(\n () => import('../standalone/alfakit-component').then((module) => module.AlfakitComponent),\n (props) => <WidgetsPlaceholder {...props} />,\n)\n\n/** Widget-sized boxes until the widgets' code has loaded (also during SSR). */\nfunction WidgetsPlaceholder({ component, className }: LoadedProps) {\n const count = standaloneWidgetCount(component)\n\n return (\n <div\n data-slot=\"starter-kit-widgets-placeholder\"\n aria-busy=\"true\"\n className={cn('grid auto-rows-min gap-4 md:grid-cols-2', className)}\n >\n {Array.from({ length: Math.max(count, 1) }, (_, index) => (\n <div key={index} aria-hidden=\"true\" className=\"bg-muted h-28 animate-pulse rounded-xl\" />\n ))}\n </div>\n )\n}\n\n/**\n * The dashboard widgets of a `starterKit()` panel on the host's own dashboard. Reads the\n * `alfakitWidgets` prop (shared on the panel's `starterKitDashboard()` pages only, the\n * starter kit's `/dashboard` by default) and renders the widgets with the host's theme, as\n * `<AlfakitComponent>` renders standalone widgets: lazy widgets, polling and table widget\n * actions go through the panel's endpoints. Its code loads in the browser; the server\n * render and hydration show placeholders. Renders `children` (the kit's placeholder boxes)\n * when there are no widgets to show: other pages, guests, users who may not open the panel.\n *\n * ```tsx\n * import { AlfakitWidgets } from '@alfakit/react'\n *\n * <AlfakitWidgets>\n * <MyEmptyState />\n * </AlfakitWidgets>\n * ```\n */\nexport function AlfakitWidgets({ panel, components, className, children }: AlfakitWidgetsProps) {\n const component = starterKitDashboardWidgets(usePage().props, panel)\n\n if (!component) return <>{children}</>\n\n return (\n <div data-slot=\"starter-kit-widgets\">\n <LoadedWidgets component={component} components={components} className={className} />\n </div>\n )\n}\n"],"mappings":";;;;;;AA4BA,MAAM,gBAAgB,oBACd,OAAO,qCAAkC,CAAC,MAAM,WAAW,OAAO,gBAAgB,IACvF,UAAU,oBAAC,oBAAD,EAAoB,GAAI,MAAQ,CAAA,CAC7C;;AAGA,SAAS,mBAAmB,EAAE,WAAW,aAA0B;CACjE,MAAM,QAAQ,sBAAsB,SAAS;CAE7C,OACE,oBAAC,OAAD;EACE,aAAU;EACV,aAAU;EACV,WAAW,GAAG,2CAA2C,SAAS;EAEjE,UAAA,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,OAAO,CAAC,EAAE,IAAI,GAAG,UAC9C,oBAAC,OAAD;GAAiB,eAAY;GAAO,WAAU;EAA0C,GAA9E,KAA8E,CACzF;CACE,CAAA;AAET;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,eAAe,EAAE,OAAO,YAAY,WAAW,YAAiC;CAC9F,MAAM,YAAY,2BAA2B,QAAQ,CAAC,CAAC,OAAO,KAAK;CAEnE,IAAI,CAAC,WAAW,OAAO,oBAAA,UAAA,EAAG,SAAW,CAAA;CAErC,OACE,oBAAC,OAAD;EAAK,aAAU;EACb,UAAA,oBAAC,eAAD;GAA0B;GAAuB;GAAuB;EAAY,CAAA;CACjF,CAAA;AAET"}
@@ -0,0 +1,34 @@
1
+ import { ImpersonationBanner } from "../components/panel/impersonation-banner.js";
2
+ import { useEffect, useState, useSyncExternalStore } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/starter-kit/impersonation-banner.tsx
5
+ let owner = null;
6
+ const listeners = /* @__PURE__ */ new Set();
7
+ function setOwner(next) {
8
+ owner = next;
9
+ listeners.forEach((listener) => listener());
10
+ }
11
+ function subscribe(listener) {
12
+ listeners.add(listener);
13
+ return () => listeners.delete(listener);
14
+ }
15
+ /**
16
+ * The impersonation banner (who you are signed in as, **Leave**) on the host's own pages,
17
+ * rendered by the header components. Loaded only while impersonating; AlfaKit's pages
18
+ * render their own (`AlfakitRoot`).
19
+ */
20
+ function StarterKitImpersonationBanner({ impersonation }) {
21
+ const [id] = useState(() => Symbol("impersonation-banner"));
22
+ const owns = useSyncExternalStore(subscribe, () => owner === id, () => false);
23
+ useEffect(() => {
24
+ if (owner === null) setOwner(id);
25
+ return () => {
26
+ if (owner === id) setOwner(null);
27
+ };
28
+ }, [id]);
29
+ return owns ? /* @__PURE__ */ jsx(ImpersonationBanner, { impersonation }) : null;
30
+ }
31
+ //#endregion
32
+ export { StarterKitImpersonationBanner as default };
33
+
34
+ //# sourceMappingURL=impersonation-banner.js.map
@@ -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();
@@ -167,6 +183,6 @@ function TenantChooser({ panel }) {
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 {tenancy.registrationLabel ?? 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,QAAQ,qBAAqB,EAAE,oBAAoB,CAAC,GAAG,KAAK,CAC7C;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. */
@@ -85,7 +85,38 @@ function TenantSwitcherTrigger({ source }) {
85
85
  ]
86
86
  });
87
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
+ }
88
119
  //#endregion
89
- export { NotificationsTrigger, SearchTrigger, TenantSwitcherTrigger };
120
+ export { CopilotTrigger, NotificationsTrigger, SearchTrigger, TenantSwitcherTrigger };
90
121
 
91
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 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"],"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,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"}
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"}