@veiag/payload-enhanced-sidebar 0.2.0 → 0.3.0-beta.0

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 (39) hide show
  1. package/README.md +62 -5
  2. package/dist/components/EnhancedSidebar/NavContent/index.d.ts +3 -0
  3. package/dist/components/EnhancedSidebar/NavContent/index.js +34 -0
  4. package/dist/components/EnhancedSidebar/NavContent/index.js.map +1 -0
  5. package/dist/components/EnhancedSidebar/NavItem/index.d.ts +0 -2
  6. package/dist/components/EnhancedSidebar/NavItem/index.js +3 -1
  7. package/dist/components/EnhancedSidebar/NavItem/index.js.map +1 -1
  8. package/dist/components/EnhancedSidebar/SidebarContent.d.ts +6 -4
  9. package/dist/components/EnhancedSidebar/SidebarContent.js +31 -140
  10. package/dist/components/EnhancedSidebar/SidebarContent.js.map +1 -1
  11. package/dist/components/EnhancedSidebar/TabsBar/TabItem.d.ts +2 -0
  12. package/dist/components/EnhancedSidebar/TabsBar/TabItem.js +4 -4
  13. package/dist/components/EnhancedSidebar/TabsBar/TabItem.js.map +1 -1
  14. package/dist/components/EnhancedSidebar/TabsBar/index.d.ts +2 -0
  15. package/dist/components/EnhancedSidebar/TabsBar/index.js +4 -2
  16. package/dist/components/EnhancedSidebar/TabsBar/index.js.map +1 -1
  17. package/dist/components/EnhancedSidebar/context.d.ts +6 -0
  18. package/dist/components/EnhancedSidebar/context.js +9 -0
  19. package/dist/components/EnhancedSidebar/context.js.map +1 -0
  20. package/dist/components/EnhancedSidebar/hooks/useNavItemState.d.ts +23 -0
  21. package/dist/components/EnhancedSidebar/hooks/useNavItemState.js +32 -0
  22. package/dist/components/EnhancedSidebar/hooks/useNavItemState.js.map +1 -0
  23. package/dist/components/EnhancedSidebar/hooks/useTabState.d.ts +13 -0
  24. package/dist/components/EnhancedSidebar/hooks/useTabState.js +19 -0
  25. package/dist/components/EnhancedSidebar/hooks/useTabState.js.map +1 -0
  26. package/dist/components/EnhancedSidebar/index.js +286 -9
  27. package/dist/components/EnhancedSidebar/index.js.map +1 -1
  28. package/dist/index.d.ts +4 -1
  29. package/dist/index.js +33 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/types.d.ts +243 -14
  32. package/dist/types.js.map +1 -1
  33. package/dist/utils/index.d.ts +8 -1
  34. package/dist/utils/index.js +14 -0
  35. package/dist/utils/index.js.map +1 -1
  36. package/package.json +2 -1
  37. package/dist/components/EnhancedSidebar/index.client.d.ts +0 -8
  38. package/dist/components/EnhancedSidebar/index.client.js +0 -87
  39. package/dist/components/EnhancedSidebar/index.client.js.map +0 -1
@@ -0,0 +1,6 @@
1
+ export type EnhancedSidebarContextValue = {
2
+ activeTabId: string;
3
+ onTabChange: (tabId: string) => void;
4
+ };
5
+ export declare const EnhancedSidebarContext: import("react").Context<EnhancedSidebarContextValue>;
6
+ export declare const useEnhancedSidebar: () => EnhancedSidebarContextValue;
@@ -0,0 +1,9 @@
1
+ 'use client';
2
+ import { createContext, useContext } from 'react';
3
+ export const EnhancedSidebarContext = createContext({
4
+ activeTabId: '',
5
+ onTabChange: ()=>{}
6
+ });
7
+ export const useEnhancedSidebar = ()=>useContext(EnhancedSidebarContext);
8
+
9
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/EnhancedSidebar/context.ts"],"sourcesContent":["'use client'\n\nimport { createContext, useContext } from 'react'\n\nexport type EnhancedSidebarContextValue = {\n activeTabId: string\n onTabChange: (tabId: string) => void\n}\n\nexport const EnhancedSidebarContext = createContext<EnhancedSidebarContextValue>({\n activeTabId: '',\n onTabChange: () => {},\n})\n\nexport const useEnhancedSidebar = () => useContext(EnhancedSidebarContext)\n"],"names":["createContext","useContext","EnhancedSidebarContext","activeTabId","onTabChange","useEnhancedSidebar"],"mappings":"AAAA;AAEA,SAASA,aAAa,EAAEC,UAAU,QAAQ,QAAO;AAOjD,OAAO,MAAMC,yBAAyBF,cAA2C;IAC/EG,aAAa;IACbC,aAAa,KAAO;AACtB,GAAE;AAEF,OAAO,MAAMC,qBAAqB,IAAMJ,WAAWC,wBAAuB"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Hook to get the active state of a nav item based on the current pathname.
3
+ * Use this in your custom NavItem component registered via `customComponents.NavItem`.
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * 'use client'
8
+ * import { useNavItemState } from '@veiag/payload-enhanced-sidebar'
9
+ *
10
+ * export const MyNavItem = ({ href, label }) => {
11
+ * const { isActive, isCurrentPage } = useNavItemState(href)
12
+ * return (
13
+ * <a href={href} style={{ fontWeight: isActive ? 'bold' : 'normal' }}>
14
+ * {label}
15
+ * </a>
16
+ * )
17
+ * }
18
+ * ```
19
+ */
20
+ export declare const useNavItemState: (href: string) => {
21
+ isActive: boolean;
22
+ isCurrentPage: boolean;
23
+ };
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+ import { usePathname } from 'next/navigation';
3
+ /**
4
+ * Hook to get the active state of a nav item based on the current pathname.
5
+ * Use this in your custom NavItem component registered via `customComponents.NavItem`.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * 'use client'
10
+ * import { useNavItemState } from '@veiag/payload-enhanced-sidebar'
11
+ *
12
+ * export const MyNavItem = ({ href, label }) => {
13
+ * const { isActive, isCurrentPage } = useNavItemState(href)
14
+ * return (
15
+ * <a href={href} style={{ fontWeight: isActive ? 'bold' : 'normal' }}>
16
+ * {label}
17
+ * </a>
18
+ * )
19
+ * }
20
+ * ```
21
+ */ export const useNavItemState = (href)=>{
22
+ const pathname = usePathname();
23
+ return {
24
+ isActive: pathname.startsWith(href) && [
25
+ '/',
26
+ undefined
27
+ ].includes(pathname[href.length]),
28
+ isCurrentPage: pathname === href
29
+ };
30
+ };
31
+
32
+ //# sourceMappingURL=useNavItemState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/EnhancedSidebar/hooks/useNavItemState.ts"],"sourcesContent":["'use client'\n\nimport { usePathname } from 'next/navigation'\n\n/**\n * Hook to get the active state of a nav item based on the current pathname.\n * Use this in your custom NavItem component registered via `customComponents.NavItem`.\n *\n * @example\n * ```tsx\n * 'use client'\n * import { useNavItemState } from '@veiag/payload-enhanced-sidebar'\n *\n * export const MyNavItem = ({ href, label }) => {\n * const { isActive, isCurrentPage } = useNavItemState(href)\n * return (\n * <a href={href} style={{ fontWeight: isActive ? 'bold' : 'normal' }}>\n * {label}\n * </a>\n * )\n * }\n * ```\n */\nexport const useNavItemState = (href: string): { isActive: boolean; isCurrentPage: boolean } => {\n const pathname = usePathname()\n return {\n isActive: pathname.startsWith(href) && ['/', undefined].includes(pathname[href.length]),\n isCurrentPage: pathname === href,\n }\n}\n"],"names":["usePathname","useNavItemState","href","pathname","isActive","startsWith","undefined","includes","length","isCurrentPage"],"mappings":"AAAA;AAEA,SAASA,WAAW,QAAQ,kBAAiB;AAE7C;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,MAAMC,kBAAkB,CAACC;IAC9B,MAAMC,WAAWH;IACjB,OAAO;QACLI,UAAUD,SAASE,UAAU,CAACH,SAAS;YAAC;YAAKI;SAAU,CAACC,QAAQ,CAACJ,QAAQ,CAACD,KAAKM,MAAM,CAAC;QACtFC,eAAeN,aAAaD;IAC9B;AACF,EAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Returns whether a sidebar tab is currently active.
3
+ * Use this inside a custom `NavContent` component to show/hide tab content.
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * const { isActive } = useTabState('my-tab-id')
8
+ * return <div style={{ display: isActive ? undefined : 'none' }}>{children}</div>
9
+ * ```
10
+ */
11
+ export declare const useTabState: (id: string) => {
12
+ isActive: boolean;
13
+ };
@@ -0,0 +1,19 @@
1
+ 'use client';
2
+ import { useEnhancedSidebar } from '../context';
3
+ /**
4
+ * Returns whether a sidebar tab is currently active.
5
+ * Use this inside a custom `NavContent` component to show/hide tab content.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * const { isActive } = useTabState('my-tab-id')
10
+ * return <div style={{ display: isActive ? undefined : 'none' }}>{children}</div>
11
+ * ```
12
+ */ export const useTabState = (id)=>{
13
+ const { activeTabId } = useEnhancedSidebar();
14
+ return {
15
+ isActive: activeTabId === id
16
+ };
17
+ };
18
+
19
+ //# sourceMappingURL=useTabState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/EnhancedSidebar/hooks/useTabState.ts"],"sourcesContent":["'use client'\n\nimport { useEnhancedSidebar } from '../context'\n\n/**\n * Returns whether a sidebar tab is currently active.\n * Use this inside a custom `NavContent` component to show/hide tab content.\n *\n * @example\n * ```tsx\n * const { isActive } = useTabState('my-tab-id')\n * return <div style={{ display: isActive ? undefined : 'none' }}>{children}</div>\n * ```\n */\nexport const useTabState = (id: string): { isActive: boolean } => {\n const { activeTabId } = useEnhancedSidebar()\n return { isActive: activeTabId === id }\n}\n"],"names":["useEnhancedSidebar","useTabState","id","activeTabId","isActive"],"mappings":"AAAA;AAEA,SAASA,kBAAkB,QAAQ,aAAY;AAE/C;;;;;;;;;CASC,GACD,OAAO,MAAMC,cAAc,CAACC;IAC1B,MAAM,EAAEC,WAAW,EAAE,GAAGH;IACxB,OAAO;QAAEI,UAAUD,gBAAgBD;IAAG;AACxC,EAAC"}
@@ -1,14 +1,105 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { getTranslation } from '@payloadcms/translations';
2
3
  import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent';
4
+ import { NavGroup } from '@payloadcms/ui';
3
5
  import { EntityType, groupNavItems } from '@payloadcms/ui/shared';
4
6
  import { cookies } from 'next/headers';
5
- import React from 'react';
7
+ import { formatAdminURL } from 'payload/shared';
8
+ import React, { Fragment } from 'react';
6
9
  const COOKIE_KEY = 'payload-enhanced-sidebar-active-tab';
10
+ import { extractLocalizedValue, resolveSidebarComponent } from '../../utils';
7
11
  import { getNavPrefs } from './getNavPrefs';
12
+ import { Icon } from './Icon';
13
+ import { NavItem } from './NavItem';
8
14
  import { SidebarContent } from './SidebarContent';
9
15
  import './index.scss';
16
+ /**
17
+ * Computes filtered and merged groups for a specific tab (server-side).
18
+ */ const computeGroupsForTab = (tab, groups, currentLang)=>{
19
+ const { collections: tabCollections, customItems, globals: tabGlobals } = tab;
20
+ const showAll = !tabCollections && !tabGlobals;
21
+ const allowedSlugs = new Set([
22
+ ...tabCollections ?? [],
23
+ ...tabGlobals ?? []
24
+ ]);
25
+ let result = [];
26
+ if (showAll) {
27
+ result = groups.map((g)=>({
28
+ ...g,
29
+ entities: [
30
+ ...g.entities
31
+ ]
32
+ }));
33
+ } else if (allowedSlugs.size > 0) {
34
+ result = groups.map((group)=>({
35
+ ...group,
36
+ entities: group.entities.filter((entity)=>allowedSlugs.has(entity.slug))
37
+ })).filter((group)=>group.entities.length > 0);
38
+ }
39
+ if (customItems && customItems.length > 0) {
40
+ const topAdditions = [];
41
+ const topUngrouped = [];
42
+ const bottomUngrouped = [];
43
+ const toEntity = (item)=>({
44
+ slug: item.slug,
45
+ type: 'custom',
46
+ href: item.href,
47
+ isExternal: item.isExternal,
48
+ label: item.label
49
+ });
50
+ for (const item of customItems){
51
+ if (item.group) {
52
+ const itemGroupLabel = extractLocalizedValue(item.group, currentLang);
53
+ const existingGroup = result.find((g)=>{
54
+ const groupLabel = extractLocalizedValue(g.label, currentLang);
55
+ return groupLabel === itemGroupLabel;
56
+ });
57
+ if (existingGroup) {
58
+ // Merged into existing collection group — position has no effect here
59
+ existingGroup.entities.push(toEntity(item));
60
+ } else {
61
+ // New custom group — position controls top vs bottom
62
+ const newGroup = {
63
+ entities: [
64
+ toEntity(item)
65
+ ],
66
+ label: item.group
67
+ };
68
+ if (item.position === 'top') {
69
+ topAdditions.push(newGroup);
70
+ } else {
71
+ result.push(newGroup);
72
+ }
73
+ }
74
+ } else {
75
+ if (item.position === 'top') {
76
+ topUngrouped.push(item);
77
+ } else {
78
+ bottomUngrouped.push(item);
79
+ }
80
+ }
81
+ }
82
+ if (topUngrouped.length > 0) {
83
+ topAdditions.unshift({
84
+ entities: topUngrouped.map(toEntity),
85
+ label: ''
86
+ });
87
+ }
88
+ if (bottomUngrouped.length > 0) {
89
+ result.push({
90
+ entities: bottomUngrouped.map(toEntity),
91
+ label: ''
92
+ });
93
+ }
94
+ result = [
95
+ ...topAdditions,
96
+ ...result
97
+ ];
98
+ }
99
+ return result;
100
+ };
10
101
  export const EnhancedSidebar = async (props)=>{
11
- const { i18n, locale, params, payload, permissions, req, searchParams, sidebarConfig, user, visibleEntities } = props;
102
+ const { i18n, locale, params, payload, permissions, req, searchParams, sidebarConfig, user, visibleEntities, documentSubViewType, viewType } = props;
12
103
  if (!payload?.config) {
13
104
  return null;
14
105
  }
@@ -33,23 +124,29 @@ export const EnhancedSidebar = async (props)=>{
33
124
  searchParams,
34
125
  user
35
126
  };
127
+ const clientProps = {
128
+ documentSubViewType,
129
+ viewType
130
+ };
36
131
  const beforeNavLinksRendered = RenderServerComponent({
37
132
  Component: beforeNavLinks,
38
133
  importMap: payload.importMap,
39
- serverProps
134
+ serverProps,
135
+ clientProps
40
136
  });
41
137
  const afterNavLinksRendered = RenderServerComponent({
42
138
  Component: afterNavLinks,
43
139
  importMap: payload.importMap,
44
- serverProps
140
+ serverProps,
141
+ clientProps
45
142
  });
46
143
  const renderedSettingsMenu = settingsMenu && Array.isArray(settingsMenu) ? settingsMenu.map((item, index)=>RenderServerComponent({
47
144
  Component: item,
48
145
  importMap: payload.importMap,
49
146
  key: `settings-menu-item-${index}`,
50
- serverProps
147
+ serverProps,
148
+ clientProps
51
149
  })) : [];
52
- // Default config if not provided
53
150
  const config = sidebarConfig ?? {
54
151
  tabs: [
55
152
  {
@@ -66,14 +163,194 @@ export const EnhancedSidebar = async (props)=>{
66
163
  const tabs = config.tabs?.filter((t)=>t.type === 'tab') ?? [];
67
164
  const defaultTabId = tabs[0]?.id ?? 'default';
68
165
  const initialActiveTabId = storedTabId && tabs.some((t)=>t.id === storedTabId) ? storedTabId : defaultTabId;
166
+ const adminRoute = payload.config.routes.admin;
167
+ const currentLang = i18n.language;
168
+ /**
169
+ * Renders a single entity as a NavItem (default or custom).
170
+ */ const renderEntity = (entity, key)=>{
171
+ const { slug, type } = entity;
172
+ let href;
173
+ let id;
174
+ if (type === 'collection') {
175
+ href = formatAdminURL({
176
+ adminRoute,
177
+ path: `/collections/${slug}`
178
+ });
179
+ id = `nav-${slug}`;
180
+ } else if (type === 'global') {
181
+ href = formatAdminURL({
182
+ adminRoute,
183
+ path: `/globals/${slug}`
184
+ });
185
+ id = `nav-global-${slug}`;
186
+ } else if (type === 'custom' && entity.href) {
187
+ id = `nav-custom-${slug}`;
188
+ href = entity.isExternal ? entity.href : formatAdminURL({
189
+ adminRoute,
190
+ path: entity.href
191
+ });
192
+ } else {
193
+ return null;
194
+ }
195
+ const badgeConfig = config.badges?.[slug];
196
+ if (config.customComponents?.NavItem) {
197
+ const label = getTranslation(entity.label, i18n);
198
+ const { path, clientProps: extraProps } = resolveSidebarComponent(config.customComponents.NavItem);
199
+ return RenderServerComponent({
200
+ Component: path,
201
+ importMap: payload.importMap,
202
+ key,
203
+ clientProps: {
204
+ entity,
205
+ href,
206
+ id,
207
+ badgeConfig,
208
+ label,
209
+ ...extraProps
210
+ }
211
+ });
212
+ }
213
+ return /*#__PURE__*/ _jsx(NavItem, {
214
+ badgeConfig: badgeConfig,
215
+ entity: entity,
216
+ href: href,
217
+ id: id
218
+ }, key);
219
+ };
220
+ /**
221
+ * Renders a group with its entities (default NavGroup or custom).
222
+ */ const renderGroup = (group, key)=>{
223
+ const { entities, label } = group;
224
+ const isUngrouped = !label || typeof label === 'string' && label === '';
225
+ const translatedLabel = getTranslation(label || '', i18n);
226
+ const items = entities.map((entity, i)=>renderEntity(entity, `${key}-${i}`));
227
+ if (isUngrouped) {
228
+ return /*#__PURE__*/ _jsx(Fragment, {
229
+ children: items
230
+ }, key);
231
+ }
232
+ if (config.customComponents?.NavGroup) {
233
+ const { path, clientProps: extraProps } = resolveSidebarComponent(config.customComponents.NavGroup);
234
+ return RenderServerComponent({
235
+ Component: path,
236
+ importMap: payload.importMap,
237
+ key,
238
+ clientProps: {
239
+ label: translatedLabel,
240
+ isOpen: navPreferences?.groups?.[translatedLabel]?.open,
241
+ children: items,
242
+ ...extraProps
243
+ }
244
+ });
245
+ }
246
+ return /*#__PURE__*/ _jsx(NavGroup, {
247
+ isOpen: navPreferences?.groups?.[translatedLabel]?.open,
248
+ label: translatedLabel,
249
+ children: items
250
+ }, key);
251
+ };
252
+ // Pre-render content for every tab on the server
253
+ const tabsContent = {};
254
+ for (const tab of tabs){
255
+ const tabGroups = computeGroupsForTab(tab, groups, currentLang);
256
+ tabsContent[tab.id] = /*#__PURE__*/ _jsx(Fragment, {
257
+ children: tabGroups.map((group, i)=>renderGroup(group, `${tab.id}-${i}`))
258
+ });
259
+ }
260
+ // For the no-tabs fallback
261
+ const allContent = tabs.length === 0 ? /*#__PURE__*/ _jsx(Fragment, {
262
+ children: groups.map((group, i)=>renderGroup(group, `all-${i}`))
263
+ }) : undefined;
264
+ // Build server-side icon and tab button rendering
265
+ const allTabItems = config.tabs ?? [];
266
+ const hasCustomTabButton = !!config.customComponents?.TabButton;
267
+ const hasAnyIconComponent = allTabItems.some((t)=>t.iconComponent);
268
+ // tabIcons: per-id icon node (only built when no custom TabButton, just iconComponent overrides)
269
+ const tabIcons = {};
270
+ // renderedTabItems: fully custom tab button nodes (built when customComponents.TabButton is set)
271
+ const renderedTabItems = [];
272
+ if (hasCustomTabButton || hasAnyIconComponent) {
273
+ for (const item of allTabItems){
274
+ const label = getTranslation(item.label, i18n);
275
+ // Resolve icon: custom iconComponent > default Lucide
276
+ let iconNode;
277
+ if (item.iconComponent) {
278
+ const { path: iconPath, clientProps: iconExtraProps } = resolveSidebarComponent(item.iconComponent);
279
+ iconNode = RenderServerComponent({
280
+ Component: iconPath,
281
+ importMap: payload.importMap,
282
+ clientProps: {
283
+ id: item.id,
284
+ label,
285
+ type: item.type,
286
+ ...iconExtraProps
287
+ }
288
+ });
289
+ } else {
290
+ iconNode = /*#__PURE__*/ _jsx(Icon, {
291
+ name: item.icon,
292
+ size: 20
293
+ });
294
+ }
295
+ if (hasCustomTabButton) {
296
+ // Compute href for links
297
+ let href;
298
+ if (item.type === 'link') {
299
+ href = item.isExternal ? item.href : formatAdminURL({
300
+ adminRoute,
301
+ path: item.href
302
+ });
303
+ }
304
+ const { path: tabBtnPath, clientProps: tabBtnExtraProps } = resolveSidebarComponent(config.customComponents.TabButton);
305
+ renderedTabItems.push(RenderServerComponent({
306
+ Component: tabBtnPath,
307
+ importMap: payload.importMap,
308
+ key: item.id,
309
+ clientProps: {
310
+ badge: item.badge,
311
+ href,
312
+ icon: iconNode,
313
+ id: item.id,
314
+ isExternal: item.type === 'link' ? item.isExternal : undefined,
315
+ label,
316
+ type: item.type,
317
+ ...tabBtnExtraProps
318
+ }
319
+ }));
320
+ } else if (item.iconComponent) {
321
+ tabIcons[item.id] = iconNode;
322
+ }
323
+ }
324
+ }
325
+ const customNavContent = config.customComponents?.NavContent ? (()=>{
326
+ const { path, clientProps: extraProps } = resolveSidebarComponent(config.customComponents.NavContent);
327
+ return RenderServerComponent({
328
+ Component: path,
329
+ importMap: payload.importMap,
330
+ key: 'enhanced-sidebar-nav-content',
331
+ clientProps: {
332
+ afterNavLinks: afterNavLinksRendered,
333
+ allContent,
334
+ beforeNavLinks: beforeNavLinksRendered,
335
+ tabs: tabs.map((t)=>({
336
+ id: t.id
337
+ })),
338
+ tabsContent,
339
+ ...extraProps
340
+ }
341
+ });
342
+ })() : undefined;
69
343
  return /*#__PURE__*/ _jsx(SidebarContent, {
70
344
  afterNavLinks: afterNavLinksRendered,
345
+ allContent: allContent,
71
346
  beforeNavLinks: beforeNavLinksRendered,
72
- groups: groups,
347
+ customNavContent: customNavContent,
73
348
  initialActiveTabId: initialActiveTabId,
74
- navPreferences: navPreferences,
349
+ renderedTabItems: renderedTabItems.length > 0 ? renderedTabItems : undefined,
75
350
  settingsMenu: renderedSettingsMenu,
76
- sidebarConfig: config
351
+ sidebarConfig: config,
352
+ tabIcons: Object.keys(tabIcons).length > 0 ? tabIcons : undefined,
353
+ tabsContent: tabsContent
77
354
  });
78
355
  };
79
356
  export default EnhancedSidebar;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/EnhancedSidebar/index.tsx"],"sourcesContent":["import type { EntityToGroup } from '@payloadcms/ui/shared'\nimport type { PayloadRequest, ServerProps } from 'payload'\n\nimport { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'\nimport { EntityType, groupNavItems } from '@payloadcms/ui/shared'\nimport { cookies } from 'next/headers'\nimport React from 'react'\n\nconst COOKIE_KEY = 'payload-enhanced-sidebar-active-tab'\n\nimport type { EnhancedSidebarConfig, ExtendedGroup } from '../../types'\n\nimport { getNavPrefs } from './getNavPrefs'\nimport { SidebarContent } from './SidebarContent'\nimport './index.scss'\n\nexport type EnhancedSidebarProps = {\n req?: PayloadRequest\n sidebarConfig?: EnhancedSidebarConfig\n} & ServerProps\n\nexport const EnhancedSidebar: React.FC<EnhancedSidebarProps> = async (props) => {\n const {\n i18n,\n locale,\n params,\n payload,\n permissions,\n req,\n searchParams,\n sidebarConfig,\n user,\n visibleEntities,\n } = props\n\n if (!payload?.config) {\n return null\n }\n\n const {\n admin: {\n components: { afterNavLinks, beforeNavLinks, settingsMenu },\n },\n collections,\n globals,\n } = payload.config\n\n const groups = groupNavItems(\n [\n ...collections\n .filter(({ slug }) => visibleEntities?.collections.includes(slug))\n .map(\n (collection) =>\n ({\n type: EntityType.collection,\n entity: collection,\n }) satisfies EntityToGroup,\n ),\n ...globals\n .filter(({ slug }) => visibleEntities?.globals.includes(slug))\n .map(\n (global) =>\n ({\n type: EntityType.global,\n entity: global,\n }) satisfies EntityToGroup,\n ),\n ],\n permissions || {},\n i18n,\n ) as unknown as ExtendedGroup[]\n\n const navPreferences = await getNavPrefs(req)\n\n const serverProps = {\n i18n,\n locale,\n params,\n payload,\n permissions,\n searchParams,\n user,\n }\n\n const beforeNavLinksRendered = RenderServerComponent({\n Component: beforeNavLinks,\n importMap: payload.importMap,\n serverProps,\n })\n\n const afterNavLinksRendered = RenderServerComponent({\n Component: afterNavLinks,\n importMap: payload.importMap,\n serverProps,\n })\n\n const renderedSettingsMenu =\n settingsMenu && Array.isArray(settingsMenu)\n ? settingsMenu.map((item, index) =>\n RenderServerComponent({\n Component: item,\n importMap: payload.importMap,\n key: `settings-menu-item-${index}`,\n serverProps,\n }),\n )\n : []\n\n // Default config if not provided\n const config: EnhancedSidebarConfig = sidebarConfig ?? {\n tabs: [\n {\n id: 'default',\n type: 'tab',\n icon: 'LayoutGrid',\n label: 'Collections',\n },\n ],\n }\n\n // Read active tab from cookie\n const cookieStore = await cookies()\n const storedTabId = cookieStore.get(COOKIE_KEY)?.value\n const tabs = config.tabs?.filter((t) => t.type === 'tab') ?? []\n const defaultTabId = tabs[0]?.id ?? 'default'\n const initialActiveTabId =\n storedTabId && tabs.some((t) => t.id === storedTabId) ? storedTabId : defaultTabId\n\n return (\n <SidebarContent\n afterNavLinks={afterNavLinksRendered}\n beforeNavLinks={beforeNavLinksRendered}\n groups={groups}\n initialActiveTabId={initialActiveTabId}\n navPreferences={navPreferences}\n settingsMenu={renderedSettingsMenu}\n sidebarConfig={config}\n />\n )\n}\n\nexport default EnhancedSidebar\n"],"names":["RenderServerComponent","EntityType","groupNavItems","cookies","React","COOKIE_KEY","getNavPrefs","SidebarContent","EnhancedSidebar","props","i18n","locale","params","payload","permissions","req","searchParams","sidebarConfig","user","visibleEntities","config","admin","components","afterNavLinks","beforeNavLinks","settingsMenu","collections","globals","groups","filter","slug","includes","map","collection","type","entity","global","navPreferences","serverProps","beforeNavLinksRendered","Component","importMap","afterNavLinksRendered","renderedSettingsMenu","Array","isArray","item","index","key","tabs","id","icon","label","cookieStore","storedTabId","get","value","t","defaultTabId","initialActiveTabId","some"],"mappings":";AAGA,SAASA,qBAAqB,QAAQ,gDAA+C;AACrF,SAASC,UAAU,EAAEC,aAAa,QAAQ,wBAAuB;AACjE,SAASC,OAAO,QAAQ,eAAc;AACtC,OAAOC,WAAW,QAAO;AAEzB,MAAMC,aAAa;AAInB,SAASC,WAAW,QAAQ,gBAAe;AAC3C,SAASC,cAAc,QAAQ,mBAAkB;AACjD,OAAO,eAAc;AAOrB,OAAO,MAAMC,kBAAkD,OAAOC;IACpE,MAAM,EACJC,IAAI,EACJC,MAAM,EACNC,MAAM,EACNC,OAAO,EACPC,WAAW,EACXC,GAAG,EACHC,YAAY,EACZC,aAAa,EACbC,IAAI,EACJC,eAAe,EAChB,GAAGV;IAEJ,IAAI,CAACI,SAASO,QAAQ;QACpB,OAAO;IACT;IAEA,MAAM,EACJC,OAAO,EACLC,YAAY,EAAEC,aAAa,EAAEC,cAAc,EAAEC,YAAY,EAAE,EAC5D,EACDC,WAAW,EACXC,OAAO,EACR,GAAGd,QAAQO,MAAM;IAElB,MAAMQ,SAAS1B,cACb;WACKwB,YACAG,MAAM,CAAC,CAAC,EAAEC,IAAI,EAAE,GAAKX,iBAAiBO,YAAYK,SAASD,OAC3DE,GAAG,CACF,CAACC,aACE,CAAA;gBACCC,MAAMjC,WAAWgC,UAAU;gBAC3BE,QAAQF;YACV,CAAA;WAEHN,QACAE,MAAM,CAAC,CAAC,EAAEC,IAAI,EAAE,GAAKX,iBAAiBQ,QAAQI,SAASD,OACvDE,GAAG,CACF,CAACI,SACE,CAAA;gBACCF,MAAMjC,WAAWmC,MAAM;gBACvBD,QAAQC;YACV,CAAA;KAEP,EACDtB,eAAe,CAAC,GAChBJ;IAGF,MAAM2B,iBAAiB,MAAM/B,YAAYS;IAEzC,MAAMuB,cAAc;QAClB5B;QACAC;QACAC;QACAC;QACAC;QACAE;QACAE;IACF;IAEA,MAAMqB,yBAAyBvC,sBAAsB;QACnDwC,WAAWhB;QACXiB,WAAW5B,QAAQ4B,SAAS;QAC5BH;IACF;IAEA,MAAMI,wBAAwB1C,sBAAsB;QAClDwC,WAAWjB;QACXkB,WAAW5B,QAAQ4B,SAAS;QAC5BH;IACF;IAEA,MAAMK,uBACJlB,gBAAgBmB,MAAMC,OAAO,CAACpB,gBAC1BA,aAAaO,GAAG,CAAC,CAACc,MAAMC,QACtB/C,sBAAsB;YACpBwC,WAAWM;YACXL,WAAW5B,QAAQ4B,SAAS;YAC5BO,KAAK,CAAC,mBAAmB,EAAED,OAAO;YAClCT;QACF,MAEF,EAAE;IAER,iCAAiC;IACjC,MAAMlB,SAAgCH,iBAAiB;QACrDgC,MAAM;YACJ;gBACEC,IAAI;gBACJhB,MAAM;gBACNiB,MAAM;gBACNC,OAAO;YACT;SACD;IACH;IAEA,8BAA8B;IAC9B,MAAMC,cAAc,MAAMlD;IAC1B,MAAMmD,cAAcD,YAAYE,GAAG,CAAClD,aAAamD;IACjD,MAAMP,OAAO7B,OAAO6B,IAAI,EAAEpB,OAAO,CAAC4B,IAAMA,EAAEvB,IAAI,KAAK,UAAU,EAAE;IAC/D,MAAMwB,eAAeT,IAAI,CAAC,EAAE,EAAEC,MAAM;IACpC,MAAMS,qBACJL,eAAeL,KAAKW,IAAI,CAAC,CAACH,IAAMA,EAAEP,EAAE,KAAKI,eAAeA,cAAcI;IAExE,qBACE,KAACnD;QACCgB,eAAemB;QACflB,gBAAgBe;QAChBX,QAAQA;QACR+B,oBAAoBA;QACpBtB,gBAAgBA;QAChBZ,cAAckB;QACd1B,eAAeG;;AAGrB,EAAC;AAED,eAAeZ,gBAAe"}
1
+ {"version":3,"sources":["../../../src/components/EnhancedSidebar/index.tsx"],"sourcesContent":["import type { EntityToGroup } from '@payloadcms/ui/shared'\nimport type { PayloadRequest, ServerProps } from 'payload'\n\nimport { getTranslation } from '@payloadcms/translations'\nimport { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'\nimport { NavGroup } from '@payloadcms/ui'\nimport { EntityType, groupNavItems } from '@payloadcms/ui/shared'\nimport { cookies } from 'next/headers'\nimport { formatAdminURL } from 'payload/shared'\nimport React, { Fragment } from 'react'\n\nconst COOKIE_KEY = 'payload-enhanced-sidebar-active-tab'\n\nimport type {\n EnhancedSidebarConfig,\n ExtendedEntity,\n ExtendedGroup,\n SidebarTab,\n SidebarTabContent as SidebarTabContentType,\n SidebarTabItem,\n} from '../../types'\n\nimport { extractLocalizedValue, resolveSidebarComponent } from '../../utils'\nimport { getNavPrefs } from './getNavPrefs'\nimport { Icon } from './Icon'\nimport { NavItem } from './NavItem'\nimport { SidebarContent } from './SidebarContent'\nimport './index.scss'\n\nexport type EnhancedSidebarProps = {\n req?: PayloadRequest\n sidebarConfig?: EnhancedSidebarConfig\n} & ServerProps\n\n/**\n * Computes filtered and merged groups for a specific tab (server-side).\n */\nconst computeGroupsForTab = (\n tab: SidebarTabContentType,\n groups: ExtendedGroup[],\n currentLang: string,\n): ExtendedGroup[] => {\n const { collections: tabCollections, customItems, globals: tabGlobals } = tab\n\n const showAll = !tabCollections && !tabGlobals\n const allowedSlugs = new Set([...(tabCollections ?? []), ...(tabGlobals ?? [])])\n\n let result: ExtendedGroup[] = []\n\n if (showAll) {\n result = groups.map((g) => ({ ...g, entities: [...g.entities] }))\n } else if (allowedSlugs.size > 0) {\n result = groups\n .map((group) => ({\n ...group,\n entities: group.entities.filter((entity) => allowedSlugs.has(entity.slug)),\n }))\n .filter((group) => group.entities.length > 0)\n }\n\n if (customItems && customItems.length > 0) {\n const topAdditions: ExtendedGroup[] = []\n const topUngrouped: SidebarTabItem[] = []\n const bottomUngrouped: SidebarTabItem[] = []\n\n const toEntity = (item: SidebarTabItem): ExtendedEntity =>\n ({\n slug: item.slug,\n type: 'custom',\n href: item.href,\n isExternal: item.isExternal,\n label: item.label,\n }) as ExtendedEntity\n\n for (const item of customItems) {\n if (item.group) {\n const itemGroupLabel = extractLocalizedValue(item.group, currentLang)\n const existingGroup = result.find((g) => {\n const groupLabel = extractLocalizedValue(g.label, currentLang)\n return groupLabel === itemGroupLabel\n })\n\n if (existingGroup) {\n // Merged into existing collection group — position has no effect here\n existingGroup.entities.push(toEntity(item))\n } else {\n // New custom group — position controls top vs bottom\n const newGroup: ExtendedGroup = { entities: [toEntity(item)], label: item.group }\n if (item.position === 'top') {\n topAdditions.push(newGroup)\n } else {\n result.push(newGroup)\n }\n }\n } else {\n if (item.position === 'top') {\n topUngrouped.push(item)\n } else {\n bottomUngrouped.push(item)\n }\n }\n }\n\n if (topUngrouped.length > 0) {\n topAdditions.unshift({ entities: topUngrouped.map(toEntity), label: '' })\n }\n\n if (bottomUngrouped.length > 0) {\n result.push({ entities: bottomUngrouped.map(toEntity), label: '' })\n }\n\n result = [...topAdditions, ...result]\n }\n\n return result\n}\n\nexport const EnhancedSidebar: React.FC<EnhancedSidebarProps> = async (props) => {\n const {\n i18n,\n locale,\n params,\n payload,\n permissions,\n req,\n searchParams,\n sidebarConfig,\n user,\n visibleEntities,\n documentSubViewType,\n viewType,\n } = props\n\n if (!payload?.config) {\n return null\n }\n\n const {\n admin: {\n components: { afterNavLinks, beforeNavLinks, settingsMenu },\n },\n collections,\n globals,\n } = payload.config\n\n const groups = groupNavItems(\n [\n ...collections\n .filter(({ slug }) => visibleEntities?.collections.includes(slug))\n .map(\n (collection) =>\n ({\n type: EntityType.collection,\n entity: collection,\n }) satisfies EntityToGroup,\n ),\n ...globals\n .filter(({ slug }) => visibleEntities?.globals.includes(slug))\n .map(\n (global) =>\n ({\n type: EntityType.global,\n entity: global,\n }) satisfies EntityToGroup,\n ),\n ],\n permissions || {},\n i18n,\n ) as unknown as ExtendedGroup[]\n\n const navPreferences = await getNavPrefs(req)\n\n const serverProps = {\n i18n,\n locale,\n params,\n payload,\n permissions,\n searchParams,\n user,\n }\n\n const clientProps = {\n documentSubViewType,\n viewType,\n }\n\n const beforeNavLinksRendered = RenderServerComponent({\n Component: beforeNavLinks,\n importMap: payload.importMap,\n serverProps,\n clientProps,\n })\n\n const afterNavLinksRendered = RenderServerComponent({\n Component: afterNavLinks,\n importMap: payload.importMap,\n serverProps,\n clientProps,\n })\n\n const renderedSettingsMenu =\n settingsMenu && Array.isArray(settingsMenu)\n ? settingsMenu.map((item, index) =>\n RenderServerComponent({\n Component: item,\n importMap: payload.importMap,\n key: `settings-menu-item-${index}`,\n serverProps,\n clientProps,\n }),\n )\n : []\n\n const config: EnhancedSidebarConfig = sidebarConfig ?? {\n tabs: [\n {\n id: 'default',\n type: 'tab',\n icon: 'LayoutGrid',\n label: 'Collections',\n },\n ],\n }\n\n // Read active tab from cookie\n const cookieStore = await cookies()\n const storedTabId = cookieStore.get(COOKIE_KEY)?.value\n const tabs = config.tabs?.filter((t) => t.type === 'tab') ?? []\n const defaultTabId = tabs[0]?.id ?? 'default'\n const initialActiveTabId =\n storedTabId && tabs.some((t) => t.id === storedTabId) ? storedTabId : defaultTabId\n\n const adminRoute = payload.config.routes.admin\n const currentLang = i18n.language\n\n /**\n * Renders a single entity as a NavItem (default or custom).\n */\n const renderEntity = (entity: ExtendedEntity, key: string): React.ReactNode => {\n const { slug, type } = entity\n let href: string\n let id: string\n\n if (type === 'collection') {\n href = formatAdminURL({ adminRoute, path: `/collections/${slug}` })\n id = `nav-${slug}`\n } else if (type === 'global') {\n href = formatAdminURL({ adminRoute, path: `/globals/${slug}` })\n id = `nav-global-${slug}`\n } else if (type === 'custom' && entity.href) {\n id = `nav-custom-${slug}`\n href = entity.isExternal ? entity.href : formatAdminURL({ adminRoute, path: entity.href })\n } else {\n return null\n }\n\n const badgeConfig = config.badges?.[slug]\n\n if (config.customComponents?.NavItem) {\n const label = getTranslation(entity.label, i18n)\n const { path, clientProps: extraProps } = resolveSidebarComponent(config.customComponents.NavItem)\n return RenderServerComponent({\n Component: path,\n importMap: payload.importMap,\n key,\n clientProps: { entity, href, id, badgeConfig, label, ...extraProps },\n })\n }\n\n return <NavItem key={key} badgeConfig={badgeConfig} entity={entity} href={href} id={id} />\n }\n\n /**\n * Renders a group with its entities (default NavGroup or custom).\n */\n const renderGroup = (group: ExtendedGroup, key: string): React.ReactNode => {\n const { entities, label } = group\n const isUngrouped = !label || (typeof label === 'string' && label === '')\n const translatedLabel = getTranslation(label || '', i18n)\n\n const items = entities.map((entity, i) => renderEntity(entity, `${key}-${i}`))\n\n if (isUngrouped) {\n return <Fragment key={key}>{items}</Fragment>\n }\n\n if (config.customComponents?.NavGroup) {\n const { path, clientProps: extraProps } = resolveSidebarComponent(config.customComponents.NavGroup)\n return RenderServerComponent({\n Component: path,\n importMap: payload.importMap,\n key,\n clientProps: {\n label: translatedLabel,\n isOpen: navPreferences?.groups?.[translatedLabel]?.open,\n children: items,\n ...extraProps,\n },\n })\n }\n\n return (\n <NavGroup\n isOpen={navPreferences?.groups?.[translatedLabel]?.open}\n key={key}\n label={translatedLabel}\n >\n {items}\n </NavGroup>\n )\n }\n\n // Pre-render content for every tab on the server\n const tabsContent: Record<string, React.ReactNode> = {}\n for (const tab of tabs) {\n const tabGroups = computeGroupsForTab(tab, groups, currentLang)\n tabsContent[tab.id] = (\n <Fragment>{tabGroups.map((group, i) => renderGroup(group, `${tab.id}-${i}`))}</Fragment>\n )\n }\n\n // For the no-tabs fallback\n const allContent =\n tabs.length === 0 ? (\n <Fragment>{groups.map((group, i) => renderGroup(group, `all-${i}`))}</Fragment>\n ) : undefined\n\n // Build server-side icon and tab button rendering\n const allTabItems = config.tabs ?? []\n const hasCustomTabButton = !!config.customComponents?.TabButton\n const hasAnyIconComponent = allTabItems.some((t) => t.iconComponent)\n\n // tabIcons: per-id icon node (only built when no custom TabButton, just iconComponent overrides)\n const tabIcons: Record<string, React.ReactNode> = {}\n // renderedTabItems: fully custom tab button nodes (built when customComponents.TabButton is set)\n const renderedTabItems: React.ReactNode[] = []\n\n if (hasCustomTabButton || hasAnyIconComponent) {\n for (const item of allTabItems) {\n const label = getTranslation(item.label, i18n)\n\n // Resolve icon: custom iconComponent > default Lucide\n let iconNode: React.ReactNode\n if (item.iconComponent) {\n const { path: iconPath, clientProps: iconExtraProps } = resolveSidebarComponent(item.iconComponent)\n iconNode = RenderServerComponent({\n Component: iconPath,\n importMap: payload.importMap,\n clientProps: { id: item.id, label, type: item.type, ...iconExtraProps },\n })\n } else {\n iconNode = <Icon name={item.icon!} size={20} />\n }\n\n if (hasCustomTabButton) {\n // Compute href for links\n let href: string | undefined\n if (item.type === 'link') {\n href = item.isExternal\n ? item.href\n : formatAdminURL({ adminRoute, path: item.href })\n }\n\n const { path: tabBtnPath, clientProps: tabBtnExtraProps } = resolveSidebarComponent(config.customComponents!.TabButton!)\n renderedTabItems.push(\n RenderServerComponent({\n Component: tabBtnPath,\n importMap: payload.importMap,\n key: item.id,\n clientProps: {\n badge: item.badge,\n href,\n icon: iconNode,\n id: item.id,\n isExternal: item.type === 'link' ? item.isExternal : undefined,\n label,\n type: item.type,\n ...tabBtnExtraProps,\n },\n }),\n )\n } else if (item.iconComponent) {\n tabIcons[item.id] = iconNode\n }\n }\n }\n\n const customNavContent = config.customComponents?.NavContent\n ? (() => {\n const { path, clientProps: extraProps } = resolveSidebarComponent(config.customComponents!.NavContent!)\n return RenderServerComponent({\n Component: path,\n importMap: payload.importMap,\n key: 'enhanced-sidebar-nav-content',\n clientProps: {\n afterNavLinks: afterNavLinksRendered,\n allContent,\n beforeNavLinks: beforeNavLinksRendered,\n tabs: tabs.map((t) => ({ id: t.id })),\n tabsContent,\n ...extraProps,\n },\n })\n })()\n : undefined\n\n return (\n <SidebarContent\n afterNavLinks={afterNavLinksRendered}\n allContent={allContent}\n beforeNavLinks={beforeNavLinksRendered}\n customNavContent={customNavContent}\n initialActiveTabId={initialActiveTabId}\n renderedTabItems={renderedTabItems.length > 0 ? renderedTabItems : undefined}\n settingsMenu={renderedSettingsMenu}\n sidebarConfig={config}\n tabIcons={Object.keys(tabIcons).length > 0 ? tabIcons : undefined}\n tabsContent={tabsContent}\n />\n )\n}\n\nexport default EnhancedSidebar\n"],"names":["getTranslation","RenderServerComponent","NavGroup","EntityType","groupNavItems","cookies","formatAdminURL","React","Fragment","COOKIE_KEY","extractLocalizedValue","resolveSidebarComponent","getNavPrefs","Icon","NavItem","SidebarContent","computeGroupsForTab","tab","groups","currentLang","collections","tabCollections","customItems","globals","tabGlobals","showAll","allowedSlugs","Set","result","map","g","entities","size","group","filter","entity","has","slug","length","topAdditions","topUngrouped","bottomUngrouped","toEntity","item","type","href","isExternal","label","itemGroupLabel","existingGroup","find","groupLabel","push","newGroup","position","unshift","EnhancedSidebar","props","i18n","locale","params","payload","permissions","req","searchParams","sidebarConfig","user","visibleEntities","documentSubViewType","viewType","config","admin","components","afterNavLinks","beforeNavLinks","settingsMenu","includes","collection","global","navPreferences","serverProps","clientProps","beforeNavLinksRendered","Component","importMap","afterNavLinksRendered","renderedSettingsMenu","Array","isArray","index","key","tabs","id","icon","cookieStore","storedTabId","get","value","t","defaultTabId","initialActiveTabId","some","adminRoute","routes","language","renderEntity","path","badgeConfig","badges","customComponents","extraProps","renderGroup","isUngrouped","translatedLabel","items","i","isOpen","open","children","tabsContent","tabGroups","allContent","undefined","allTabItems","hasCustomTabButton","TabButton","hasAnyIconComponent","iconComponent","tabIcons","renderedTabItems","iconNode","iconPath","iconExtraProps","name","tabBtnPath","tabBtnExtraProps","badge","customNavContent","NavContent","Object","keys"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,4 +2,7 @@ import { type Config } from 'payload';
2
2
  import type { EnhancedSidebarConfig } from './types';
3
3
  export declare const payloadEnhancedSidebar: (pluginOptions?: EnhancedSidebarConfig) => (config: Config) => Config;
4
4
  export { BadgeProvider, useBadgeContext, useBadgeValue, } from './components/EnhancedSidebar/BadgeProvider';
5
- export type { BadgeColor, BadgeConfig, BadgeConfigApi, BadgeConfigCollectionCount, BadgeConfigProvider, BadgeValues, EnhancedSidebarConfig, } from './types';
5
+ export { useEnhancedSidebar } from './components/EnhancedSidebar/context';
6
+ export { useNavItemState } from './components/EnhancedSidebar/hooks/useNavItemState';
7
+ export { useTabState } from './components/EnhancedSidebar/hooks/useTabState';
8
+ export type { BadgeColor, BadgeConfig, BadgeConfigApi, BadgeConfigCollectionCount, BadgeConfigProvider, BadgeValues, CustomNavContentProps, CustomNavGroupProps, CustomNavItemProps, CustomTabButtonProps, CustomTabIconProps, EnhancedSidebarConfig, SidebarComponent, } from './types';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { deepMerge } from 'payload';
2
2
  import { sidebarTranslations } from './translations';
3
+ import { resolveSidebarComponent } from './utils';
3
4
  /**
4
5
  * Default configuration for the enhanced sidebar
5
6
  */ const defaultConfig = {
@@ -30,7 +31,6 @@ export const payloadEnhancedSidebar = (pluginOptions = {})=>(config)=>{
30
31
  if (pluginOptions.disabled) {
31
32
  return config;
32
33
  }
33
- // Merge user config with defaults
34
34
  const sidebarConfig = {
35
35
  ...defaultConfig,
36
36
  ...pluginOptions,
@@ -50,6 +50,35 @@ export const payloadEnhancedSidebar = (pluginOptions = {})=>(config)=>{
50
50
  }
51
51
  };
52
52
  }
53
+ // Register custom components and per-tab icons in the import map
54
+ if (!config.admin.dependencies) {
55
+ config.admin.dependencies = {};
56
+ }
57
+ const customComponentSlots = [
58
+ 'NavContent',
59
+ 'NavGroup',
60
+ 'NavItem',
61
+ 'TabButton'
62
+ ];
63
+ for (const slot of customComponentSlots){
64
+ const component = pluginOptions.customComponents?.[slot];
65
+ if (component) {
66
+ const { path } = resolveSidebarComponent(component);
67
+ config.admin.dependencies[`enhanced-sidebar-${slot.toLowerCase()}`] = {
68
+ type: 'component',
69
+ path
70
+ };
71
+ }
72
+ }
73
+ for (const tab of sidebarConfig.tabs ?? []){
74
+ if (tab.iconComponent) {
75
+ const { path } = resolveSidebarComponent(tab.iconComponent);
76
+ config.admin.dependencies[`enhanced-sidebar-icon-${tab.id}`] = {
77
+ type: 'component',
78
+ path
79
+ };
80
+ }
81
+ }
53
82
  // Check if we have any badges to fetch (api or collection-count)
54
83
  const hasBadgesToFetch = sidebarConfig.badges || sidebarConfig.tabs?.some((tab)=>tab.badge && tab.badge.type !== 'provider');
55
84
  // Add InternalBadgeProvider if we have badges to fetch
@@ -76,5 +105,8 @@ export const payloadEnhancedSidebar = (pluginOptions = {})=>(config)=>{
76
105
  return config;
77
106
  };
78
107
  export { BadgeProvider, useBadgeContext, useBadgeValue } from './components/EnhancedSidebar/BadgeProvider';
108
+ export { useEnhancedSidebar } from './components/EnhancedSidebar/context';
109
+ export { useNavItemState } from './components/EnhancedSidebar/hooks/useNavItemState';
110
+ export { useTabState } from './components/EnhancedSidebar/hooks/useTabState';
79
111
 
80
112
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { type Config, deepMerge } from 'payload'\n\nimport type { EnhancedSidebarConfig } from './types'\n\nimport { sidebarTranslations } from './translations'\n\n/**\n * Default configuration for the enhanced sidebar\n */\nconst defaultConfig: EnhancedSidebarConfig = {\n showLogout: true,\n tabs: [\n {\n id: 'dashboard',\n type: 'link',\n href: '/',\n icon: 'House',\n label: { en: 'Dashboard', uk: 'Головна' },\n },\n {\n id: 'default',\n type: 'tab',\n icon: 'LayoutGrid',\n label: { en: 'Collections', uk: 'Колекції' },\n },\n ],\n}\n\nexport const payloadEnhancedSidebar =\n (pluginOptions: EnhancedSidebarConfig = {}) =>\n (config: Config): Config => {\n if (pluginOptions.disabled) {\n return config\n }\n\n // Merge user config with defaults\n const sidebarConfig: EnhancedSidebarConfig = {\n ...defaultConfig,\n ...pluginOptions,\n tabs: pluginOptions.tabs ?? defaultConfig.tabs,\n }\n\n if (!config.admin) {\n config.admin = {}\n }\n\n if (!config.admin.components) {\n config.admin.components = {}\n }\n\n if (!config.admin.components.Nav) {\n config.admin.components.Nav = {\n path: '@veiag/payload-enhanced-sidebar/rsc#EnhancedSidebar',\n serverProps: {\n sidebarConfig,\n },\n }\n }\n\n // Check if we have any badges to fetch (api or collection-count)\n const hasBadgesToFetch =\n sidebarConfig.badges ||\n sidebarConfig.tabs?.some((tab) => tab.badge && tab.badge.type !== 'provider')\n\n // Add InternalBadgeProvider if we have badges to fetch\n if (hasBadgesToFetch) {\n if (!config.admin.components.providers) {\n config.admin.components.providers = []\n }\n\n // Add our internal provider at the beginning (so user providers can override)\n config.admin.components.providers.unshift({\n clientProps: {\n sidebarConfig,\n },\n path: '@veiag/payload-enhanced-sidebar/client#InternalBadgeProvider',\n })\n }\n\n // Adding translations\n if (!config.i18n) {\n config.i18n = {}\n }\n if (!config.i18n.translations) {\n config.i18n.translations = {}\n }\n\n config.i18n.translations = deepMerge(config.i18n.translations, sidebarTranslations)\n\n return config\n }\n\nexport {\n BadgeProvider,\n useBadgeContext,\n useBadgeValue,\n} from './components/EnhancedSidebar/BadgeProvider'\n\nexport type {\n BadgeColor,\n BadgeConfig,\n BadgeConfigApi,\n BadgeConfigCollectionCount,\n BadgeConfigProvider,\n BadgeValues,\n EnhancedSidebarConfig,\n} from './types'\n"],"names":["deepMerge","sidebarTranslations","defaultConfig","showLogout","tabs","id","type","href","icon","label","en","uk","payloadEnhancedSidebar","pluginOptions","config","disabled","sidebarConfig","admin","components","Nav","path","serverProps","hasBadgesToFetch","badges","some","tab","badge","providers","unshift","clientProps","i18n","translations","BadgeProvider","useBadgeContext","useBadgeValue"],"mappings":"AAAA,SAAsBA,SAAS,QAAQ,UAAS;AAIhD,SAASC,mBAAmB,QAAQ,iBAAgB;AAEpD;;CAEC,GACD,MAAMC,gBAAuC;IAC3CC,YAAY;IACZC,MAAM;QACJ;YACEC,IAAI;YACJC,MAAM;YACNC,MAAM;YACNC,MAAM;YACNC,OAAO;gBAAEC,IAAI;gBAAaC,IAAI;YAAU;QAC1C;QACA;YACEN,IAAI;YACJC,MAAM;YACNE,MAAM;YACNC,OAAO;gBAAEC,IAAI;gBAAeC,IAAI;YAAW;QAC7C;KACD;AACH;AAEA,OAAO,MAAMC,yBACX,CAACC,gBAAuC,CAAC,CAAC,GAC1C,CAACC;QACC,IAAID,cAAcE,QAAQ,EAAE;YAC1B,OAAOD;QACT;QAEA,kCAAkC;QAClC,MAAME,gBAAuC;YAC3C,GAAGd,aAAa;YAChB,GAAGW,aAAa;YAChBT,MAAMS,cAAcT,IAAI,IAAIF,cAAcE,IAAI;QAChD;QAEA,IAAI,CAACU,OAAOG,KAAK,EAAE;YACjBH,OAAOG,KAAK,GAAG,CAAC;QAClB;QAEA,IAAI,CAACH,OAAOG,KAAK,CAACC,UAAU,EAAE;YAC5BJ,OAAOG,KAAK,CAACC,UAAU,GAAG,CAAC;QAC7B;QAEA,IAAI,CAACJ,OAAOG,KAAK,CAACC,UAAU,CAACC,GAAG,EAAE;YAChCL,OAAOG,KAAK,CAACC,UAAU,CAACC,GAAG,GAAG;gBAC5BC,MAAM;gBACNC,aAAa;oBACXL;gBACF;YACF;QACF;QAEA,iEAAiE;QACjE,MAAMM,mBACJN,cAAcO,MAAM,IACpBP,cAAcZ,IAAI,EAAEoB,KAAK,CAACC,MAAQA,IAAIC,KAAK,IAAID,IAAIC,KAAK,CAACpB,IAAI,KAAK;QAEpE,uDAAuD;QACvD,IAAIgB,kBAAkB;YACpB,IAAI,CAACR,OAAOG,KAAK,CAACC,UAAU,CAACS,SAAS,EAAE;gBACtCb,OAAOG,KAAK,CAACC,UAAU,CAACS,SAAS,GAAG,EAAE;YACxC;YAEA,8EAA8E;YAC9Eb,OAAOG,KAAK,CAACC,UAAU,CAACS,SAAS,CAACC,OAAO,CAAC;gBACxCC,aAAa;oBACXb;gBACF;gBACAI,MAAM;YACR;QACF;QAEA,sBAAsB;QACtB,IAAI,CAACN,OAAOgB,IAAI,EAAE;YAChBhB,OAAOgB,IAAI,GAAG,CAAC;QACjB;QACA,IAAI,CAAChB,OAAOgB,IAAI,CAACC,YAAY,EAAE;YAC7BjB,OAAOgB,IAAI,CAACC,YAAY,GAAG,CAAC;QAC9B;QAEAjB,OAAOgB,IAAI,CAACC,YAAY,GAAG/B,UAAUc,OAAOgB,IAAI,CAACC,YAAY,EAAE9B;QAE/D,OAAOa;IACT,EAAC;AAEH,SACEkB,aAAa,EACbC,eAAe,EACfC,aAAa,QACR,6CAA4C"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { type Config, deepMerge } from 'payload'\n\nimport type { EnhancedSidebarConfig } from './types'\n\nimport { sidebarTranslations } from './translations'\nimport { resolveSidebarComponent } from './utils'\n\n/**\n * Default configuration for the enhanced sidebar\n */\nconst defaultConfig: EnhancedSidebarConfig = {\n showLogout: true,\n tabs: [\n {\n id: 'dashboard',\n type: 'link',\n href: '/',\n icon: 'House',\n label: { en: 'Dashboard', uk: 'Головна' },\n },\n {\n id: 'default',\n type: 'tab',\n icon: 'LayoutGrid',\n label: { en: 'Collections', uk: 'Колекції' },\n },\n ],\n}\n\nexport const payloadEnhancedSidebar =\n (pluginOptions: EnhancedSidebarConfig = {}) =>\n (config: Config): Config => {\n if (pluginOptions.disabled) {\n return config\n }\n\n const sidebarConfig: EnhancedSidebarConfig = {\n ...defaultConfig,\n ...pluginOptions,\n tabs: pluginOptions.tabs ?? defaultConfig.tabs,\n }\n\n if (!config.admin) {\n config.admin = {}\n }\n\n if (!config.admin.components) {\n config.admin.components = {}\n }\n\n if (!config.admin.components.Nav) {\n config.admin.components.Nav = {\n path: '@veiag/payload-enhanced-sidebar/rsc#EnhancedSidebar',\n serverProps: {\n sidebarConfig,\n },\n }\n }\n\n // Register custom components and per-tab icons in the import map\n if (!config.admin.dependencies) {\n config.admin.dependencies = {}\n }\n\n const customComponentSlots = ['NavContent', 'NavGroup', 'NavItem', 'TabButton'] as const\n for (const slot of customComponentSlots) {\n const component = pluginOptions.customComponents?.[slot]\n if (component) {\n const { path } = resolveSidebarComponent(component)\n config.admin.dependencies[`enhanced-sidebar-${slot.toLowerCase()}`] = {\n type: 'component',\n path,\n }\n }\n }\n\n for (const tab of sidebarConfig.tabs ?? []) {\n if (tab.iconComponent) {\n const { path } = resolveSidebarComponent(tab.iconComponent)\n config.admin.dependencies[`enhanced-sidebar-icon-${tab.id}`] = {\n type: 'component',\n path,\n }\n }\n }\n\n // Check if we have any badges to fetch (api or collection-count)\n const hasBadgesToFetch =\n sidebarConfig.badges ||\n sidebarConfig.tabs?.some((tab) => tab.badge && tab.badge.type !== 'provider')\n\n // Add InternalBadgeProvider if we have badges to fetch\n if (hasBadgesToFetch) {\n if (!config.admin.components.providers) {\n config.admin.components.providers = []\n }\n\n // Add our internal provider at the beginning (so user providers can override)\n config.admin.components.providers.unshift({\n clientProps: {\n sidebarConfig,\n },\n path: '@veiag/payload-enhanced-sidebar/client#InternalBadgeProvider',\n })\n }\n\n // Adding translations\n if (!config.i18n) {\n config.i18n = {}\n }\n if (!config.i18n.translations) {\n config.i18n.translations = {}\n }\n\n config.i18n.translations = deepMerge(config.i18n.translations, sidebarTranslations)\n\n return config\n }\n\nexport {\n BadgeProvider,\n useBadgeContext,\n useBadgeValue,\n} from './components/EnhancedSidebar/BadgeProvider'\n\nexport { useEnhancedSidebar } from './components/EnhancedSidebar/context'\nexport { useNavItemState } from './components/EnhancedSidebar/hooks/useNavItemState'\nexport { useTabState } from './components/EnhancedSidebar/hooks/useTabState'\n\nexport type {\n BadgeColor,\n BadgeConfig,\n BadgeConfigApi,\n BadgeConfigCollectionCount,\n BadgeConfigProvider,\n BadgeValues,\n CustomNavContentProps,\n CustomNavGroupProps,\n CustomNavItemProps,\n CustomTabButtonProps,\n CustomTabIconProps,\n EnhancedSidebarConfig,\n SidebarComponent,\n} from './types'\n"],"names":["deepMerge","sidebarTranslations","resolveSidebarComponent","defaultConfig","showLogout","tabs","id","type","href","icon","label","en","uk","payloadEnhancedSidebar","pluginOptions","config","disabled","sidebarConfig","admin","components","Nav","path","serverProps","dependencies","customComponentSlots","slot","component","customComponents","toLowerCase","tab","iconComponent","hasBadgesToFetch","badges","some","badge","providers","unshift","clientProps","i18n","translations","BadgeProvider","useBadgeContext","useBadgeValue","useEnhancedSidebar","useNavItemState","useTabState"],"mappings":"AAAA,SAAsBA,SAAS,QAAQ,UAAS;AAIhD,SAASC,mBAAmB,QAAQ,iBAAgB;AACpD,SAASC,uBAAuB,QAAQ,UAAS;AAEjD;;CAEC,GACD,MAAMC,gBAAuC;IAC3CC,YAAY;IACZC,MAAM;QACJ;YACEC,IAAI;YACJC,MAAM;YACNC,MAAM;YACNC,MAAM;YACNC,OAAO;gBAAEC,IAAI;gBAAaC,IAAI;YAAU;QAC1C;QACA;YACEN,IAAI;YACJC,MAAM;YACNE,MAAM;YACNC,OAAO;gBAAEC,IAAI;gBAAeC,IAAI;YAAW;QAC7C;KACD;AACH;AAEA,OAAO,MAAMC,yBACX,CAACC,gBAAuC,CAAC,CAAC,GAC1C,CAACC;QACC,IAAID,cAAcE,QAAQ,EAAE;YAC1B,OAAOD;QACT;QAEA,MAAME,gBAAuC;YAC3C,GAAGd,aAAa;YAChB,GAAGW,aAAa;YAChBT,MAAMS,cAAcT,IAAI,IAAIF,cAAcE,IAAI;QAChD;QAEA,IAAI,CAACU,OAAOG,KAAK,EAAE;YACjBH,OAAOG,KAAK,GAAG,CAAC;QAClB;QAEA,IAAI,CAACH,OAAOG,KAAK,CAACC,UAAU,EAAE;YAC5BJ,OAAOG,KAAK,CAACC,UAAU,GAAG,CAAC;QAC7B;QAEA,IAAI,CAACJ,OAAOG,KAAK,CAACC,UAAU,CAACC,GAAG,EAAE;YAChCL,OAAOG,KAAK,CAACC,UAAU,CAACC,GAAG,GAAG;gBAC5BC,MAAM;gBACNC,aAAa;oBACXL;gBACF;YACF;QACF;QAEA,iEAAiE;QACjE,IAAI,CAACF,OAAOG,KAAK,CAACK,YAAY,EAAE;YAC9BR,OAAOG,KAAK,CAACK,YAAY,GAAG,CAAC;QAC/B;QAEA,MAAMC,uBAAuB;YAAC;YAAc;YAAY;YAAW;SAAY;QAC/E,KAAK,MAAMC,QAAQD,qBAAsB;YACvC,MAAME,YAAYZ,cAAca,gBAAgB,EAAE,CAACF,KAAK;YACxD,IAAIC,WAAW;gBACb,MAAM,EAAEL,IAAI,EAAE,GAAGnB,wBAAwBwB;gBACzCX,OAAOG,KAAK,CAACK,YAAY,CAAC,CAAC,iBAAiB,EAAEE,KAAKG,WAAW,IAAI,CAAC,GAAG;oBACpErB,MAAM;oBACNc;gBACF;YACF;QACF;QAEA,KAAK,MAAMQ,OAAOZ,cAAcZ,IAAI,IAAI,EAAE,CAAE;YAC1C,IAAIwB,IAAIC,aAAa,EAAE;gBACrB,MAAM,EAAET,IAAI,EAAE,GAAGnB,wBAAwB2B,IAAIC,aAAa;gBAC1Df,OAAOG,KAAK,CAACK,YAAY,CAAC,CAAC,sBAAsB,EAAEM,IAAIvB,EAAE,EAAE,CAAC,GAAG;oBAC7DC,MAAM;oBACNc;gBACF;YACF;QACF;QAEA,iEAAiE;QACjE,MAAMU,mBACJd,cAAce,MAAM,IACpBf,cAAcZ,IAAI,EAAE4B,KAAK,CAACJ,MAAQA,IAAIK,KAAK,IAAIL,IAAIK,KAAK,CAAC3B,IAAI,KAAK;QAEpE,uDAAuD;QACvD,IAAIwB,kBAAkB;YACpB,IAAI,CAAChB,OAAOG,KAAK,CAACC,UAAU,CAACgB,SAAS,EAAE;gBACtCpB,OAAOG,KAAK,CAACC,UAAU,CAACgB,SAAS,GAAG,EAAE;YACxC;YAEA,8EAA8E;YAC9EpB,OAAOG,KAAK,CAACC,UAAU,CAACgB,SAAS,CAACC,OAAO,CAAC;gBACxCC,aAAa;oBACXpB;gBACF;gBACAI,MAAM;YACR;QACF;QAEA,sBAAsB;QACtB,IAAI,CAACN,OAAOuB,IAAI,EAAE;YAChBvB,OAAOuB,IAAI,GAAG,CAAC;QACjB;QACA,IAAI,CAACvB,OAAOuB,IAAI,CAACC,YAAY,EAAE;YAC7BxB,OAAOuB,IAAI,CAACC,YAAY,GAAG,CAAC;QAC9B;QAEAxB,OAAOuB,IAAI,CAACC,YAAY,GAAGvC,UAAUe,OAAOuB,IAAI,CAACC,YAAY,EAAEtC;QAE/D,OAAOc;IACT,EAAC;AAEH,SACEyB,aAAa,EACbC,eAAe,EACfC,aAAa,QACR,6CAA4C;AAEnD,SAASC,kBAAkB,QAAQ,uCAAsC;AACzE,SAASC,eAAe,QAAQ,qDAAoD;AACpF,SAASC,WAAW,QAAQ,iDAAgD"}