@logickernel/frame 0.7.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -72,17 +72,30 @@ Make sure your `tsconfig.json` has the path alias configured:
72
72
 
73
73
  ### Framework Adapter
74
74
 
75
- The library is framework-agnostic and requires a framework adapter to be provided. For Next.js applications, use the provided adapter:
75
+ The library is framework-agnostic and requires a framework adapter to be provided. For Next.js applications, use the provided adapter hook:
76
76
 
77
77
  ```typescript
78
- import { AppSidebar, createNextJSAdapter } from "@logickernel/frame"
79
- import type { User, Organization } from "@logickernel/frame"
78
+ "use client" // Required: adapter hook must be used in a Client Component
80
79
 
81
- // Create the adapter (do this once, can be reused)
82
- const adapter = createNextJSAdapter()
80
+ import { AppLayout, useNextJSAdapter } from "@logickernel/frame"
81
+ import type { User, SidebarData } from "@logickernel/frame"
82
+
83
+ export default function Layout({ children }: { children: React.ReactNode }) {
84
+ // Create the adapter using the hook (must be called in a Client Component)
85
+ const adapter = useNextJSAdapter()
86
+
87
+ return (
88
+ <AppLayout adapter={adapter} user={user} data={sidebarData}>
89
+ {children}
90
+ </AppLayout>
91
+ )
92
+ }
83
93
  ```
84
94
 
85
- For other frameworks, you'll need to implement the `FrameworkAdapter` interface (see Types section).
95
+ **Important:**
96
+ - The `adapter` prop is now **required** (previously optional)
97
+ - `useNextJSAdapter()` must be called in a **Client Component** (add `"use client"` directive)
98
+ - For other frameworks, you'll need to implement the `FrameworkAdapter` interface (see Types section)
86
99
 
87
100
  ### Props Mode vs API Mode
88
101
 
@@ -96,12 +109,12 @@ The component automatically detects which mode to use:
96
109
  Pass a `data` object containing organizations and navigation items. The `{organizationId}` placeholder in URLs is automatically replaced.
97
110
 
98
111
  ```typescript
99
- import { AppSidebar, createNextJSAdapter } from "@logickernel/frame"
112
+ "use client" // Required: adapter hook must be used in a Client Component
113
+
114
+ import { AppLayout, useNextJSAdapter } from "@logickernel/frame"
100
115
  import { Home, Users, GalleryVerticalEnd } from "lucide-react"
101
116
  import type { SidebarData, User } from "@logickernel/frame"
102
117
 
103
- const adapter = createNextJSAdapter()
104
-
105
118
  const user: User = {
106
119
  name: "John Doe",
107
120
  email: "john@example.com",
@@ -121,11 +134,12 @@ const data: SidebarData = {
121
134
  }
122
135
 
123
136
  export default function Layout({ children }: { children: React.ReactNode }) {
137
+ const adapter = useNextJSAdapter()
138
+
124
139
  return (
125
- <>
126
- <AppSidebar user={user} adapter={adapter} data={data} />
127
- <main>{children}</main>
128
- </>
140
+ <AppLayout adapter={adapter} user={user} data={data}>
141
+ {children}
142
+ </AppLayout>
129
143
  )
130
144
  }
131
145
  ```
@@ -135,31 +149,24 @@ export default function Layout({ children }: { children: React.ReactNode }) {
135
149
  **Important:** Always import sidebar components (`SidebarProvider`, `SidebarTrigger`, `SidebarInset`, etc.) from `@logickernel/frame`, not from your local `@/components/ui/sidebar`. This ensures all components share the same React Context.
136
150
 
137
151
  ```typescript
152
+ "use client" // Required: adapter hook must be used in a Client Component
153
+
138
154
  import {
139
- AppSidebar,
140
- SidebarProvider,
141
- SidebarTrigger,
142
- SidebarInset,
143
- createNextJSAdapter,
155
+ AppLayout,
156
+ useNextJSAdapter,
144
157
  } from "@logickernel/frame"
145
158
  import type { User, SidebarData } from "@logickernel/frame"
146
159
 
147
- const adapter = createNextJSAdapter()
148
160
  const user: User = { name: "John Doe", email: "john@example.com", image: null }
149
161
  const data: SidebarData = { /* ... */ }
150
162
 
151
163
  export default function Layout({ children }: { children: React.ReactNode }) {
164
+ const adapter = useNextJSAdapter()
165
+
152
166
  return (
153
- <SidebarProvider>
154
- <AppSidebar user={user} adapter={adapter} data={data} />
155
- <SidebarInset>
156
- <header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
157
- <SidebarTrigger />
158
- <h1>My App</h1>
159
- </header>
160
- <main className="flex flex-1 flex-col gap-4 p-4">{children}</main>
161
- </SidebarInset>
162
- </SidebarProvider>
167
+ <AppLayout adapter={adapter} user={user} data={data}>
168
+ {children}
169
+ </AppLayout>
163
170
  )
164
171
  }
165
172
  ```
@@ -177,11 +184,12 @@ export default function Layout({ children }: { children: React.ReactNode }) {
177
184
  Omit `data` — the component fetches organizations and navigation from the API.
178
185
 
179
186
  ```typescript
180
- import { AppSidebar, createNextJSAdapter } from "@logickernel/frame"
187
+ "use client" // Required: adapter hook must be used in a Client Component
181
188
 
182
- const adapter = createNextJSAdapter()
189
+ import { AppLayout, useNextJSAdapter } from "@logickernel/frame"
183
190
 
184
191
  export default function Layout({ children }: { children: React.ReactNode }) {
192
+ const adapter = useNextJSAdapter()
185
193
  return (
186
194
  <>
187
195
  <AppSidebar
@@ -479,9 +487,7 @@ For cross-origin requests, use the full API URL:
479
487
  ```typescript
480
488
  <AppSidebar
481
489
  user={user}
482
- organizations={organizations}
483
490
  organizationId={orgId}
484
- useApiNavigation={true}
485
491
  apiBaseUrl="https://kernel.example.com/api"
486
492
  />
487
493
  ```
package/dist/index.d.mts CHANGED
@@ -88,8 +88,8 @@ interface FrameworkAdapter {
88
88
  */
89
89
  interface AppSidebarProps$1 {
90
90
  user: User;
91
- /** Optional adapter - if not provided, Next.js defaults will be used */
92
- adapter?: FrameworkAdapter;
91
+ /** Framework adapter - required for framework-agnostic operation */
92
+ adapter: FrameworkAdapter;
93
93
  /** Sidebar data containing organizations and navigation items (props mode) */
94
94
  data?: SidebarData;
95
95
  /** Current organization ID (optional, can be extracted from pathname) */
@@ -103,20 +103,14 @@ interface AppSidebarProps$1 {
103
103
  interface AppLayoutProps {
104
104
  /** User data for sidebar */
105
105
  user: User;
106
- /** Optional adapter - if not provided, Next.js defaults will be used */
107
- adapter?: FrameworkAdapter;
106
+ /** Framework adapter - required for framework-agnostic operation */
107
+ adapter: FrameworkAdapter;
108
108
  /** Sidebar data containing organizations and navigation items (props mode) */
109
109
  data?: SidebarData;
110
110
  /** Current organization ID (optional, can be extracted from pathname) */
111
111
  organizationId?: string;
112
112
  /** Custom API base URL (API mode only, defaults to "/api" which constructs "/api/navigation/{organizationId}") */
113
113
  apiBaseUrl?: string;
114
- /** Enable API mode - library will fetch navigation from API */
115
- useApiNavigation?: boolean;
116
- /** Custom header content (breadcrumbs, actions, etc.) */
117
- headerContent?: ReactNode;
118
- /** Show/hide default header (default: true) */
119
- showHeader?: boolean;
120
114
  /** Children to render in the main content area */
121
115
  children: ReactNode;
122
116
  }
@@ -151,8 +145,8 @@ declare const SidebarInset: React$1.ForwardRefExoticComponent<Omit<React$1.Detai
151
145
  */
152
146
  interface AppSidebarProps extends React$1.ComponentProps<typeof Sidebar> {
153
147
  user: User;
154
- /** Optional adapter - if not provided, Next.js defaults will be used */
155
- adapter?: FrameworkAdapter;
148
+ /** Framework adapter - required for framework-agnostic operation */
149
+ adapter: FrameworkAdapter;
156
150
  /** Sidebar data containing organizations and navigation items (props mode) */
157
151
  data?: SidebarData;
158
152
  /** Current organization ID (optional, can be extracted from pathname) */
@@ -160,7 +154,7 @@ interface AppSidebarProps extends React$1.ComponentProps<typeof Sidebar> {
160
154
  /** Custom API base URL (API mode only, defaults to "/api") */
161
155
  apiBaseUrl?: string;
162
156
  }
163
- declare function AppSidebar({ user, adapter: externalAdapter, data, organizationId, apiBaseUrl, ...props }: AppSidebarProps): react_jsx_runtime.JSX.Element;
157
+ declare function AppSidebar({ user, adapter, data, organizationId, apiBaseUrl, ...props }: AppSidebarProps): react_jsx_runtime.JSX.Element;
164
158
 
165
159
  /**
166
160
  * High-level layout component that handles the entire sidebar + content layout structure.
@@ -168,18 +162,45 @@ declare function AppSidebar({ user, adapter: externalAdapter, data, organization
168
162
  * This component wraps AppSidebar and SidebarInset in SidebarProvider and provides
169
163
  * a default header with sidebar trigger. It handles all layout concerns internally.
170
164
  *
165
+ * Navigation mode is determined automatically:
166
+ * - If `data` prop is provided, uses props mode
167
+ * - If `data` is not provided, automatically uses API mode (fetches from API)
168
+ *
171
169
  * @example
172
170
  * ```tsx
173
- * <AppLayout
174
- * user={user}
175
- * useApiNavigation={true}
176
- * headerContent={<Breadcrumb>...</Breadcrumb>}
177
- * >
178
- * {children}
179
- * </AppLayout>
171
+ * // In Next.js
172
+ * import { useNextJSAdapter } from "@logickernel/frame"
173
+ *
174
+ * function Layout({ children }) {
175
+ * const adapter = useNextJSAdapter()
176
+ * return (
177
+ * <AppLayout adapter={adapter} user={user} data={sidebarData}>
178
+ * {children}
179
+ * </AppLayout>
180
+ * )
181
+ * }
182
+ *
183
+ * // In React Router
184
+ * import { useLocation, useNavigate } from "react-router-dom"
185
+ *
186
+ * function Layout({ children }) {
187
+ * const location = useLocation()
188
+ * const navigate = useNavigate()
189
+ * const adapter = useMemo(() => ({
190
+ * usePathname: () => location.pathname,
191
+ * useRouter: () => ({ push: navigate }),
192
+ * Link: ({ href, children }) => <Link to={href}>{children}</Link>,
193
+ * }), [location.pathname, navigate])
194
+ *
195
+ * return (
196
+ * <AppLayout adapter={adapter} user={user} data={sidebarData}>
197
+ * {children}
198
+ * </AppLayout>
199
+ * )
200
+ * }
180
201
  * ```
181
202
  */
182
- declare function AppLayout({ user, adapter, data, organizationId, apiBaseUrl, useApiNavigation, headerContent, showHeader, children, }: AppLayoutProps): react_jsx_runtime.JSX.Element;
203
+ declare function AppLayout({ user, adapter, data, organizationId, apiBaseUrl, children, }: AppLayoutProps): react_jsx_runtime.JSX.Element;
183
204
 
184
205
  interface NavMainProps {
185
206
  items: NavigationItem[];
@@ -233,16 +254,24 @@ declare function useNavigation({ organizationId, apiBaseUrl, enabled, }?: UseNav
233
254
  declare function getIconComponent(icon?: string | LucideIcon): LucideIcon | undefined;
234
255
 
235
256
  /**
236
- * Next.js adapter for @logickernel/frame
237
- * Provides Next.js-specific implementations of FrameworkAdapter
238
- */
239
-
240
- /**
241
- * Creates a Next.js adapter for the framework
257
+ * Creates a Next.js adapter hook for the framework
242
258
  * Use this when using @logickernel/frame in a Next.js application
243
259
  *
244
260
  * Note: This requires Next.js and next-auth to be installed
261
+ * This hook MUST be called in a Client Component ("use client")
262
+ *
263
+ * @example
264
+ * ```tsx
265
+ * "use client"
266
+ *
267
+ * import { AppLayout, useNextJSAdapter } from "@logickernel/frame"
268
+ *
269
+ * function MyLayout({ children }) {
270
+ * const adapter = useNextJSAdapter()
271
+ * return <AppLayout adapter={adapter} user={user}>{children}</AppLayout>
272
+ * }
273
+ * ```
245
274
  */
246
- declare function createNextJSAdapter(): FrameworkAdapter;
275
+ declare function useNextJSAdapter(): FrameworkAdapter;
247
276
 
248
- export { AppLayout, type AppLayoutProps, AppSidebar, type AppSidebarProps$1 as AppSidebarProps, type FrameworkAdapter, type LinkProps, NavMain, NavUser, type NavigationConfig, type NavigationItem, type Organization, type Router, type SidebarData, SidebarInset, SidebarProvider, SidebarTrigger, TeamSwitcher, type User, createNextJSAdapter, getIconComponent, useNavigation, useSidebar };
277
+ export { AppLayout, type AppLayoutProps, AppSidebar, type AppSidebarProps$1 as AppSidebarProps, type FrameworkAdapter, type LinkProps, NavMain, NavUser, type NavigationConfig, type NavigationItem, type Organization, type Router, type SidebarData, SidebarInset, SidebarProvider, SidebarTrigger, TeamSwitcher, type User, getIconComponent, useNavigation, useNextJSAdapter, useSidebar };
package/dist/index.d.ts CHANGED
@@ -88,8 +88,8 @@ interface FrameworkAdapter {
88
88
  */
89
89
  interface AppSidebarProps$1 {
90
90
  user: User;
91
- /** Optional adapter - if not provided, Next.js defaults will be used */
92
- adapter?: FrameworkAdapter;
91
+ /** Framework adapter - required for framework-agnostic operation */
92
+ adapter: FrameworkAdapter;
93
93
  /** Sidebar data containing organizations and navigation items (props mode) */
94
94
  data?: SidebarData;
95
95
  /** Current organization ID (optional, can be extracted from pathname) */
@@ -103,20 +103,14 @@ interface AppSidebarProps$1 {
103
103
  interface AppLayoutProps {
104
104
  /** User data for sidebar */
105
105
  user: User;
106
- /** Optional adapter - if not provided, Next.js defaults will be used */
107
- adapter?: FrameworkAdapter;
106
+ /** Framework adapter - required for framework-agnostic operation */
107
+ adapter: FrameworkAdapter;
108
108
  /** Sidebar data containing organizations and navigation items (props mode) */
109
109
  data?: SidebarData;
110
110
  /** Current organization ID (optional, can be extracted from pathname) */
111
111
  organizationId?: string;
112
112
  /** Custom API base URL (API mode only, defaults to "/api" which constructs "/api/navigation/{organizationId}") */
113
113
  apiBaseUrl?: string;
114
- /** Enable API mode - library will fetch navigation from API */
115
- useApiNavigation?: boolean;
116
- /** Custom header content (breadcrumbs, actions, etc.) */
117
- headerContent?: ReactNode;
118
- /** Show/hide default header (default: true) */
119
- showHeader?: boolean;
120
114
  /** Children to render in the main content area */
121
115
  children: ReactNode;
122
116
  }
@@ -151,8 +145,8 @@ declare const SidebarInset: React$1.ForwardRefExoticComponent<Omit<React$1.Detai
151
145
  */
152
146
  interface AppSidebarProps extends React$1.ComponentProps<typeof Sidebar> {
153
147
  user: User;
154
- /** Optional adapter - if not provided, Next.js defaults will be used */
155
- adapter?: FrameworkAdapter;
148
+ /** Framework adapter - required for framework-agnostic operation */
149
+ adapter: FrameworkAdapter;
156
150
  /** Sidebar data containing organizations and navigation items (props mode) */
157
151
  data?: SidebarData;
158
152
  /** Current organization ID (optional, can be extracted from pathname) */
@@ -160,7 +154,7 @@ interface AppSidebarProps extends React$1.ComponentProps<typeof Sidebar> {
160
154
  /** Custom API base URL (API mode only, defaults to "/api") */
161
155
  apiBaseUrl?: string;
162
156
  }
163
- declare function AppSidebar({ user, adapter: externalAdapter, data, organizationId, apiBaseUrl, ...props }: AppSidebarProps): react_jsx_runtime.JSX.Element;
157
+ declare function AppSidebar({ user, adapter, data, organizationId, apiBaseUrl, ...props }: AppSidebarProps): react_jsx_runtime.JSX.Element;
164
158
 
165
159
  /**
166
160
  * High-level layout component that handles the entire sidebar + content layout structure.
@@ -168,18 +162,45 @@ declare function AppSidebar({ user, adapter: externalAdapter, data, organization
168
162
  * This component wraps AppSidebar and SidebarInset in SidebarProvider and provides
169
163
  * a default header with sidebar trigger. It handles all layout concerns internally.
170
164
  *
165
+ * Navigation mode is determined automatically:
166
+ * - If `data` prop is provided, uses props mode
167
+ * - If `data` is not provided, automatically uses API mode (fetches from API)
168
+ *
171
169
  * @example
172
170
  * ```tsx
173
- * <AppLayout
174
- * user={user}
175
- * useApiNavigation={true}
176
- * headerContent={<Breadcrumb>...</Breadcrumb>}
177
- * >
178
- * {children}
179
- * </AppLayout>
171
+ * // In Next.js
172
+ * import { useNextJSAdapter } from "@logickernel/frame"
173
+ *
174
+ * function Layout({ children }) {
175
+ * const adapter = useNextJSAdapter()
176
+ * return (
177
+ * <AppLayout adapter={adapter} user={user} data={sidebarData}>
178
+ * {children}
179
+ * </AppLayout>
180
+ * )
181
+ * }
182
+ *
183
+ * // In React Router
184
+ * import { useLocation, useNavigate } from "react-router-dom"
185
+ *
186
+ * function Layout({ children }) {
187
+ * const location = useLocation()
188
+ * const navigate = useNavigate()
189
+ * const adapter = useMemo(() => ({
190
+ * usePathname: () => location.pathname,
191
+ * useRouter: () => ({ push: navigate }),
192
+ * Link: ({ href, children }) => <Link to={href}>{children}</Link>,
193
+ * }), [location.pathname, navigate])
194
+ *
195
+ * return (
196
+ * <AppLayout adapter={adapter} user={user} data={sidebarData}>
197
+ * {children}
198
+ * </AppLayout>
199
+ * )
200
+ * }
180
201
  * ```
181
202
  */
182
- declare function AppLayout({ user, adapter, data, organizationId, apiBaseUrl, useApiNavigation, headerContent, showHeader, children, }: AppLayoutProps): react_jsx_runtime.JSX.Element;
203
+ declare function AppLayout({ user, adapter, data, organizationId, apiBaseUrl, children, }: AppLayoutProps): react_jsx_runtime.JSX.Element;
183
204
 
184
205
  interface NavMainProps {
185
206
  items: NavigationItem[];
@@ -233,16 +254,24 @@ declare function useNavigation({ organizationId, apiBaseUrl, enabled, }?: UseNav
233
254
  declare function getIconComponent(icon?: string | LucideIcon): LucideIcon | undefined;
234
255
 
235
256
  /**
236
- * Next.js adapter for @logickernel/frame
237
- * Provides Next.js-specific implementations of FrameworkAdapter
238
- */
239
-
240
- /**
241
- * Creates a Next.js adapter for the framework
257
+ * Creates a Next.js adapter hook for the framework
242
258
  * Use this when using @logickernel/frame in a Next.js application
243
259
  *
244
260
  * Note: This requires Next.js and next-auth to be installed
261
+ * This hook MUST be called in a Client Component ("use client")
262
+ *
263
+ * @example
264
+ * ```tsx
265
+ * "use client"
266
+ *
267
+ * import { AppLayout, useNextJSAdapter } from "@logickernel/frame"
268
+ *
269
+ * function MyLayout({ children }) {
270
+ * const adapter = useNextJSAdapter()
271
+ * return <AppLayout adapter={adapter} user={user}>{children}</AppLayout>
272
+ * }
273
+ * ```
245
274
  */
246
- declare function createNextJSAdapter(): FrameworkAdapter;
275
+ declare function useNextJSAdapter(): FrameworkAdapter;
247
276
 
248
- export { AppLayout, type AppLayoutProps, AppSidebar, type AppSidebarProps$1 as AppSidebarProps, type FrameworkAdapter, type LinkProps, NavMain, NavUser, type NavigationConfig, type NavigationItem, type Organization, type Router, type SidebarData, SidebarInset, SidebarProvider, SidebarTrigger, TeamSwitcher, type User, createNextJSAdapter, getIconComponent, useNavigation, useSidebar };
277
+ export { AppLayout, type AppLayoutProps, AppSidebar, type AppSidebarProps$1 as AppSidebarProps, type FrameworkAdapter, type LinkProps, NavMain, NavUser, type NavigationConfig, type NavigationItem, type Organization, type Router, type SidebarData, SidebarInset, SidebarProvider, SidebarTrigger, TeamSwitcher, type User, getIconComponent, useNavigation, useNextJSAdapter, useSidebar };