@riverbankcms/sdk 0.5.2 → 0.6.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 (37) hide show
  1. package/README.md +9 -8
  2. package/dist/cli/index.js +57 -37
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/client/client.js +1 -1
  5. package/dist/client/client.js.map +1 -1
  6. package/dist/client/client.mjs +1 -1
  7. package/dist/client/client.mjs.map +1 -1
  8. package/dist/server/{chunk-L5EA4FXU.mjs → chunk-2HXHFSMI.mjs} +2 -2
  9. package/dist/server/{chunk-6PWMOREA.js → chunk-EOWGKCUZ.js} +2 -2
  10. package/dist/server/{chunk-6PWMOREA.js.map → chunk-EOWGKCUZ.js.map} +1 -1
  11. package/dist/server/{chunk-VSFQRHYZ.js → chunk-PHS2KWJX.js} +4 -4
  12. package/dist/server/{chunk-VSFQRHYZ.js.map → chunk-PHS2KWJX.js.map} +1 -1
  13. package/dist/server/{chunk-KFLZGNPO.mjs → chunk-PMHLZ3FW.mjs} +128 -1
  14. package/dist/server/chunk-PMHLZ3FW.mjs.map +1 -0
  15. package/dist/server/{chunk-XY66HIB4.mjs → chunk-SQMGHEJM.mjs} +2 -2
  16. package/dist/server/{chunk-XY66HIB4.mjs.map → chunk-SQMGHEJM.mjs.map} +1 -1
  17. package/dist/server/{chunk-5STV4MWD.js → chunk-SSS7CCRR.js} +130 -3
  18. package/dist/server/chunk-SSS7CCRR.js.map +1 -0
  19. package/dist/server/components.js +3 -3
  20. package/dist/server/components.mjs +2 -2
  21. package/dist/server/index.js +2 -2
  22. package/dist/server/index.mjs +1 -1
  23. package/dist/server/navigation.d.mts +147 -1
  24. package/dist/server/navigation.d.ts +147 -1
  25. package/dist/server/navigation.js +14 -2
  26. package/dist/server/navigation.js.map +1 -1
  27. package/dist/server/navigation.mjs +15 -3
  28. package/dist/server/rendering/server.js +3 -3
  29. package/dist/server/rendering/server.mjs +2 -2
  30. package/dist/server/rendering.js +3 -3
  31. package/dist/server/rendering.mjs +2 -2
  32. package/dist/server/server.js +2 -2
  33. package/dist/server/server.mjs +1 -1
  34. package/package.json +1 -1
  35. package/dist/server/chunk-5STV4MWD.js.map +0 -1
  36. package/dist/server/chunk-KFLZGNPO.mjs.map +0 -1
  37. /package/dist/server/{chunk-L5EA4FXU.mjs.map → chunk-2HXHFSMI.mjs.map} +0 -0
@@ -1,4 +1,10 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/navigation/index.ts
2
+ function isNavLink(item) {
3
+ return item.kind === "link";
4
+ }
5
+ function isNavDropdown(item) {
6
+ return item.kind === "dropdown";
7
+ }
2
8
  function getPrimaryNavigation(navigation) {
3
9
  if (!navigation || navigation.length === 0) return null;
4
10
  return _nullishCoalesce(_nullishCoalesce(navigation.find((menu) => menu.isPrimary), () => ( navigation[0])), () => ( null));
@@ -21,6 +27,40 @@ function transformToNavItems(menu) {
21
27
  isExternal: isExternalLink(item)
22
28
  })).filter((item) => Boolean(item.href));
23
29
  }
30
+ function transformToNestedNavItems(menu) {
31
+ if (!_optionalChain([menu, 'optionalAccess', _2 => _2.items]) || menu.items.length === 0) return [];
32
+ const toNavLink = (item) => {
33
+ const href = extractHref(item);
34
+ if (!href) return null;
35
+ return {
36
+ kind: "link",
37
+ id: item.id,
38
+ label: item.label,
39
+ href,
40
+ isExternal: isExternalLink(item)
41
+ };
42
+ };
43
+ const { items } = buildNestedStructure(
44
+ menu.items,
45
+ {
46
+ toLink: toNavLink,
47
+ createDropdown: (id, label, children) => ({
48
+ kind: "dropdown",
49
+ id,
50
+ label,
51
+ children
52
+ }),
53
+ extractCta: false
54
+ }
55
+ );
56
+ return items;
57
+ }
58
+ function getNestedPrimaryNavItems(navigation) {
59
+ return transformToNestedNavItems(getPrimaryNavigation(navigation));
60
+ }
61
+ function getNestedNavItemsBySlug(navigation, slug) {
62
+ return transformToNestedNavItems(getNavigationBySlug(navigation, slug));
63
+ }
24
64
  function buildMenuViewModel(navigation) {
25
65
  const menu = getPrimaryNavigation(navigation);
26
66
  if (!menu) {
@@ -76,6 +116,56 @@ function isExternalLink(item) {
76
116
  if (!link || typeof link !== "object" || !("kind" in link)) return false;
77
117
  return link.kind === "external";
78
118
  }
119
+ function buildChildrenByParentId(items) {
120
+ const childrenByParentId = /* @__PURE__ */ new Map();
121
+ const itemsById = /* @__PURE__ */ new Map();
122
+ for (const item of items) {
123
+ itemsById.set(item.id, item);
124
+ }
125
+ for (const item of items) {
126
+ if (item.parentId) {
127
+ const parent = itemsById.get(item.parentId);
128
+ if (_optionalChain([parent, 'optionalAccess', _3 => _3.parentId]) && typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
129
+ console.warn(
130
+ `[SDK Navigation] Deeply nested item detected: "${item.label}" (id: ${item.id}). Only 1 level of nesting is supported. This item will be ignored.`
131
+ );
132
+ continue;
133
+ }
134
+ const siblings = _nullishCoalesce(childrenByParentId.get(item.parentId), () => ( []));
135
+ siblings.push(item);
136
+ childrenByParentId.set(item.parentId, siblings);
137
+ }
138
+ }
139
+ return childrenByParentId;
140
+ }
141
+ function buildNestedStructure(items, options) {
142
+ const childrenByParentId = buildChildrenByParentId(items);
143
+ const rootItems = items.filter((item) => !item.parentId).sort((a, b) => (_nullishCoalesce(a.orderIndex, () => ( 0))) - (_nullishCoalesce(b.orderIndex, () => ( 0))));
144
+ const result = [];
145
+ let ctaItem = null;
146
+ for (const item of rootItems) {
147
+ if (options.extractCta && !ctaItem && Boolean(item.isCta) && item.urlType !== "dropdown") {
148
+ const link = options.toLink(item);
149
+ if (link) {
150
+ ctaItem = link;
151
+ continue;
152
+ }
153
+ }
154
+ if (item.urlType === "dropdown") {
155
+ const childRecords = _nullishCoalesce(childrenByParentId.get(item.id), () => ( []));
156
+ const children = childRecords.sort((a, b) => (_nullishCoalesce(a.orderIndex, () => ( 0))) - (_nullishCoalesce(b.orderIndex, () => ( 0)))).map(options.toLink).filter((child) => child !== null);
157
+ if (children.length > 0) {
158
+ result.push(options.createDropdown(item.id, item.label, children));
159
+ }
160
+ } else {
161
+ const link = options.toLink(item);
162
+ if (link) {
163
+ result.push(link);
164
+ }
165
+ }
166
+ }
167
+ return { items: result, ctaItem };
168
+ }
79
169
  function convertToLinkValue(item) {
80
170
  const payload = item.url;
81
171
  if (!payload) return null;
@@ -125,7 +215,7 @@ function buildSimpleMenu(navigation, routes) {
125
215
  id: item.id,
126
216
  label: item.label,
127
217
  href,
128
- isExternal: _optionalChain([link, 'optionalAccess', _2 => _2.kind]) === "external"
218
+ isExternal: _optionalChain([link, 'optionalAccess', _4 => _4.kind]) === "external"
129
219
  };
130
220
  if (!ctaItem && Boolean(item.isCta)) {
131
221
  ctaItem = navLink;
@@ -135,6 +225,37 @@ function buildSimpleMenu(navigation, routes) {
135
225
  }
136
226
  return { items, ctaItem };
137
227
  }
228
+ function buildSimpleNestedMenu(navigation, routes) {
229
+ const menu = getPrimaryNavigation(navigation);
230
+ if (!menu) {
231
+ return { items: [], ctaItem: null };
232
+ }
233
+ const toSimpleLink = (item) => {
234
+ const link = item.url;
235
+ const href = resolveHref(link, routes);
236
+ if (!href) return null;
237
+ return {
238
+ kind: "link",
239
+ id: item.id,
240
+ label: item.label,
241
+ href,
242
+ isExternal: _optionalChain([link, 'optionalAccess', _5 => _5.kind]) === "external"
243
+ };
244
+ };
245
+ return buildNestedStructure(
246
+ menu.items,
247
+ {
248
+ toLink: toSimpleLink,
249
+ createDropdown: (id, label, children) => ({
250
+ kind: "dropdown",
251
+ id,
252
+ label,
253
+ children
254
+ }),
255
+ extractCta: true
256
+ }
257
+ );
258
+ }
138
259
  function resolveHref(link, routes) {
139
260
  if (!link) return null;
140
261
  if (link.kind === "external" || link.kind === "url") {
@@ -185,5 +306,11 @@ var selectPrimaryMenu = getPrimaryNavigation;
185
306
 
186
307
 
187
308
 
188
- exports.getPrimaryNavigation = getPrimaryNavigation; exports.getNavigationBySlug = getNavigationBySlug; exports.getPrimaryNavItems = getPrimaryNavItems; exports.getNavItemsBySlug = getNavItemsBySlug; exports.transformToNavItems = transformToNavItems; exports.buildMenuViewModel = buildMenuViewModel; exports.buildLogoViewModel = buildLogoViewModel; exports.buildSimpleMenu = buildSimpleMenu; exports.buildSimpleLogo = buildSimpleLogo; exports.transformNavItems = transformNavItems; exports.selectPrimaryMenu = selectPrimaryMenu;
189
- //# sourceMappingURL=chunk-5STV4MWD.js.map
309
+
310
+
311
+
312
+
313
+
314
+
315
+ exports.isNavLink = isNavLink; exports.isNavDropdown = isNavDropdown; exports.getPrimaryNavigation = getPrimaryNavigation; exports.getNavigationBySlug = getNavigationBySlug; exports.getPrimaryNavItems = getPrimaryNavItems; exports.getNavItemsBySlug = getNavItemsBySlug; exports.transformToNavItems = transformToNavItems; exports.transformToNestedNavItems = transformToNestedNavItems; exports.getNestedPrimaryNavItems = getNestedPrimaryNavItems; exports.getNestedNavItemsBySlug = getNestedNavItemsBySlug; exports.buildMenuViewModel = buildMenuViewModel; exports.buildLogoViewModel = buildLogoViewModel; exports.buildSimpleMenu = buildSimpleMenu; exports.buildSimpleNestedMenu = buildSimpleNestedMenu; exports.buildSimpleLogo = buildSimpleLogo; exports.transformNavItems = transformNavItems; exports.selectPrimaryMenu = selectPrimaryMenu;
316
+ //# sourceMappingURL=chunk-SSS7CCRR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/chunk-SSS7CCRR.js","../../src/navigation/index.ts"],"names":[],"mappings":"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","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/chunk-SSS7CCRR.js","sourcesContent":[null,"/**\n * Navigation helper utilities for SDK sites.\n *\n * Provides helpers to transform CMS navigation data into render-ready structures.\n * Supports both simple NavItem arrays and full MenuViewModels for block rendering.\n *\n * @example Simple usage\n * ```ts\n * import { getPrimaryNavItems } from '@riverbankcms/sdk/navigation';\n *\n * const headerNav = getPrimaryNavItems(siteData.navigation);\n * // [{ href: '/', label: 'Home', isExternal: false }, ...]\n * ```\n *\n * @example Block rendering usage\n * ```ts\n * import { buildMenuViewModel, buildLogoViewModel } from '@riverbankcms/sdk/navigation';\n *\n * const menu = buildMenuViewModel(siteData.navigation);\n * const logo = buildLogoViewModel(siteData.layout.logo, siteData.site.title);\n *\n * renderBlock(siteHeaderManifest, layout.header, {\n * viewModelOverrides: { menu, content: { logo } },\n * });\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { NavigationMenuWithItems, NavigationItemRecord, LinkPayload } from '@riverbankcms/api';\nimport type { RouteMap } from '@riverbankcms/blocks';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types for block rendering\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Link value types matching @riverbankcms/blocks\n */\nexport type InternalLinkValue = {\n kind: 'internal';\n routeId: string;\n entityId: string;\n entityType: 'page' | 'content';\n href: string;\n title: string;\n typeLabel: string;\n contentTypeKey?: string | null;\n contentTypeName?: string | null;\n updatedAt?: string | null;\n};\n\nexport type ExternalLinkValue = {\n kind: 'external';\n href: string;\n};\n\nexport type CustomLinkValue = {\n kind: 'url';\n href: string;\n};\n\nexport type LinkValue = InternalLinkValue | ExternalLinkValue | CustomLinkValue;\n\n/**\n * Menu link view model for block rendering\n */\nexport type MenuLinkViewModel = {\n id: string;\n label: string;\n link: LinkValue | null;\n target: string | null;\n rel: string | null;\n active?: boolean;\n};\n\n/**\n * CTA link view model (extends MenuLinkViewModel with variant)\n */\nexport type MenuCtaViewModel = MenuLinkViewModel & {\n variant: string;\n};\n\n/**\n * Complete menu view model for header/footer blocks\n */\nexport type MenuViewModel = {\n items: MenuLinkViewModel[];\n ctaItem: MenuCtaViewModel | null;\n};\n\n/**\n * Logo source data from site layout\n */\nexport type LogoSource = {\n url: string | null;\n alt: string | null;\n assetId?: string | null;\n width?: number | null;\n height?: number | null;\n storagePath?: string | null;\n storageBucket?: string | null;\n} | null;\n\n/**\n * Logo view model for block rendering\n */\nexport type LogoViewModel = {\n type: 'image';\n src: string;\n alt: string;\n assetId?: string;\n width?: number | null;\n height?: number | null;\n storagePath?: string;\n storageBucket?: string;\n} | null;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Simple NavItem type for basic usage\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * A simplified navigation item structure for component rendering.\n */\nexport type NavItem = {\n /** The URL to navigate to */\n href: string;\n /** Display text for the navigation link */\n label: string;\n /** Whether link should open in new tab (external links) */\n isExternal: boolean;\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Nested Navigation Types (with dropdown support)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * A navigation link item with a direct URL.\n * Use `kind` discriminator for type-safe narrowing.\n *\n * @example\n * ```ts\n * if (item.kind === 'link') {\n * console.log(item.href); // TypeScript knows href exists\n * }\n * ```\n */\nexport type NavLink = {\n /** Discriminator for type narrowing */\n kind: 'link';\n /** Unique identifier from CMS */\n id: string;\n /** Display text for the navigation link */\n label: string;\n /** The URL to navigate to */\n href: string;\n /** Whether link should open in new tab (external links) */\n isExternal: boolean;\n};\n\n/**\n * A dropdown container holding child navigation items.\n * Clicking reveals children instead of navigating.\n * Max 1 level of nesting (children are always NavLink, not NavDropdown).\n */\nexport type NavDropdown = {\n /** Discriminator for type narrowing */\n kind: 'dropdown';\n /** Unique identifier from CMS */\n id: string;\n /** Display text for the dropdown trigger */\n label: string;\n /** Child navigation links */\n children: NavLink[];\n};\n\n/**\n * Unified navigation item supporting both links and dropdowns.\n * Use `kind` property for type-safe discrimination.\n *\n * @example\n * ```ts\n * const items = getNestedPrimaryNavItems(navigation);\n * items.forEach(item => {\n * if (item.kind === 'link') {\n * console.log(item.href);\n * } else {\n * console.log(item.children.length);\n * }\n * });\n * ```\n */\nexport type NestedNavItem = NavLink | NavDropdown;\n\n/**\n * Type guard to check if a navigation item is a link.\n */\nexport function isNavLink(item: NestedNavItem): item is NavLink {\n return item.kind === 'link';\n}\n\n/**\n * Type guard to check if a navigation item is a dropdown.\n */\nexport function isNavDropdown(item: NestedNavItem): item is NavDropdown {\n return item.kind === 'dropdown';\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Simple types for block rendering\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Simple nav link with pre-resolved href for block rendering.\n */\nexport type SimpleNavLink = {\n id: string;\n label: string;\n href: string;\n isExternal: boolean;\n};\n\n/**\n * Simple menu view model with pre-resolved hrefs.\n * Use this instead of MenuViewModel for cleaner data flow.\n */\nexport type SimpleMenuViewModel = {\n items: SimpleNavLink[];\n ctaItem: SimpleNavLink | null;\n};\n\n/**\n * Simple nested nav link with pre-resolved href.\n */\nexport type SimpleNestedNavLink = {\n kind: 'link';\n id: string;\n label: string;\n href: string;\n isExternal: boolean;\n};\n\n/**\n * Simple nested dropdown with pre-resolved children.\n */\nexport type SimpleNestedNavDropdown = {\n kind: 'dropdown';\n id: string;\n label: string;\n children: SimpleNestedNavLink[];\n};\n\n/**\n * Unified simple nested navigation item.\n */\nexport type SimpleNestedNavItem = SimpleNestedNavLink | SimpleNestedNavDropdown;\n\n/**\n * Simple menu view model with nested navigation support.\n */\nexport type SimpleNestedMenuViewModel = {\n items: SimpleNestedNavItem[];\n ctaItem: SimpleNestedNavLink | null;\n};\n\n/**\n * Simple logo data for block rendering.\n */\nexport type SimpleLogo = {\n type: 'image';\n src: string;\n alt: string;\n width?: number;\n height?: number;\n} | null;\n\n// RouteMap type is imported from @riverbankcms/blocks for consistency\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Menu selection helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Get the primary navigation menu object.\n * Returns menu marked as isPrimary, or first menu if none marked.\n *\n * @example\n * ```ts\n * const menu = getPrimaryNavigation(siteData.navigation);\n * console.log(menu?.title); // \"Main Navigation\"\n * ```\n */\nexport function getPrimaryNavigation(\n navigation: NavigationMenuWithItems[],\n): NavigationMenuWithItems | null {\n if (!navigation || navigation.length === 0) return null;\n // navigation.length > 0 is guaranteed above, so [0] exists\n return navigation.find((menu) => menu.isPrimary) ?? navigation[0] ?? null;\n}\n\n/**\n * Get a navigation menu by name/slug.\n *\n * @example\n * ```ts\n * const footerMenu = getNavigationBySlug(siteData.navigation, 'footer');\n * ```\n */\nexport function getNavigationBySlug(\n navigation: NavigationMenuWithItems[],\n slug: string,\n): NavigationMenuWithItems | null {\n if (!navigation || navigation.length === 0) return null;\n return navigation.find((menu) => menu.name === slug) ?? null;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Simple NavItem[] transformations\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Get nav items from the primary menu (marked isPrimary, or first menu).\n * Returns empty array if no navigation configured.\n *\n * @example\n * ```ts\n * const headerNav = getPrimaryNavItems(siteData.navigation);\n * // [{ href: '/', label: 'Home', isExternal: false }, ...]\n * ```\n */\nexport function getPrimaryNavItems(navigation: NavigationMenuWithItems[]): NavItem[] {\n return transformToNavItems(getPrimaryNavigation(navigation));\n}\n\n/**\n * Get nav items from a specific menu by slug.\n * Useful for footer nav, secondary nav, etc.\n * Returns empty array if menu not found.\n *\n * @example\n * ```ts\n * const footerNav = getNavItemsBySlug(siteData.navigation, 'footer');\n * ```\n */\nexport function getNavItemsBySlug(navigation: NavigationMenuWithItems[], slug: string): NavItem[] {\n return transformToNavItems(getNavigationBySlug(navigation, slug));\n}\n\n/**\n * Transform a menu into simple NavItem array.\n */\nexport function transformToNavItems(menu: NavigationMenuWithItems | null): NavItem[] {\n if (!menu?.items || menu.items.length === 0) return [];\n\n return menu.items\n .filter((item) => !item.parentId && item.urlType !== 'dropdown')\n .sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0))\n .map((item) => ({\n label: item.label,\n href: extractHref(item),\n isExternal: isExternalLink(item),\n }))\n .filter((item): item is NavItem => Boolean(item.href));\n}\n\n/**\n * Transform a menu into nested NestedNavItem array.\n * Builds tree structure from flat items, supporting dropdowns with children.\n *\n * @example\n * ```ts\n * const nav = transformToNestedNavItems(menu);\n * // [\n * // { kind: 'link', href: '/', label: 'Home', ... },\n * // { kind: 'dropdown', label: 'Services', children: [...] },\n * // ]\n * ```\n */\nexport function transformToNestedNavItems(\n menu: NavigationMenuWithItems | null\n): NestedNavItem[] {\n if (!menu?.items || menu.items.length === 0) return [];\n\n const toNavLink = (item: NavigationItemRecord): NavLink | null => {\n const href = extractHref(item);\n if (!href) return null;\n return {\n kind: 'link',\n id: item.id,\n label: item.label,\n href,\n isExternal: isExternalLink(item),\n };\n };\n\n const { items } = buildNestedStructure<NavLink, NavDropdown, NavLink>(\n menu.items,\n {\n toLink: toNavLink,\n createDropdown: (id, label, children) => ({\n kind: 'dropdown',\n id,\n label,\n children,\n }),\n extractCta: false,\n }\n );\n\n return items;\n}\n\n/**\n * Get nested nav items from the primary menu.\n * Supports dropdowns with children for complex navigation structures.\n *\n * @example\n * ```ts\n * const nav = getNestedPrimaryNavItems(siteData.navigation);\n * nav.forEach(item => {\n * if (item.kind === 'dropdown') {\n * console.log(`${item.label} has ${item.children.length} children`);\n * }\n * });\n * ```\n */\nexport function getNestedPrimaryNavItems(\n navigation: NavigationMenuWithItems[]\n): NestedNavItem[] {\n return transformToNestedNavItems(getPrimaryNavigation(navigation));\n}\n\n/**\n * Get nested nav items from a specific menu by slug.\n *\n * @example\n * ```ts\n * const footerNav = getNestedNavItemsBySlug(siteData.navigation, 'footer');\n * ```\n */\nexport function getNestedNavItemsBySlug(\n navigation: NavigationMenuWithItems[],\n slug: string\n): NestedNavItem[] {\n return transformToNestedNavItems(getNavigationBySlug(navigation, slug));\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Full MenuViewModel for block rendering\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Build a MenuViewModel from navigation data for block rendering.\n * Extracts CTA item separately and preserves full link data.\n *\n * @example\n * ```ts\n * const menuViewModel = buildMenuViewModel(siteData.navigation);\n *\n * renderBlock(siteHeaderManifest, layout.header, {\n * viewModelOverrides: { menu: menuViewModel },\n * });\n * ```\n */\nexport function buildMenuViewModel(navigation: NavigationMenuWithItems[]): MenuViewModel {\n const menu = getPrimaryNavigation(navigation);\n\n if (!menu) {\n return { items: [], ctaItem: null };\n }\n\n const flatItems = menu.items\n .filter((item) => !item.parentId && item.urlType !== 'dropdown')\n .sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0));\n\n const items: MenuLinkViewModel[] = [];\n let ctaItem: MenuCtaViewModel | null = null;\n\n for (const item of flatItems) {\n const viewItem: MenuLinkViewModel = {\n id: item.id,\n label: item.label,\n link: convertToLinkValue(item),\n target: null,\n rel: null,\n active: false,\n };\n\n // Extract first CTA item separately\n if (!ctaItem && Boolean(item.isCta)) {\n ctaItem = { ...viewItem, variant: 'primary' };\n continue;\n }\n\n items.push(viewItem);\n }\n\n return { items, ctaItem };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Logo view model helper\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Build a LogoViewModel from site layout data.\n *\n * @param logo - Logo source from siteData.layout.logo\n * @param fallbackTitle - Site title to use as alt text fallback\n *\n * @example\n * ```ts\n * const logoViewModel = buildLogoViewModel(siteData.layout.logo, siteData.site.title);\n *\n * renderBlock(siteHeaderManifest, layout.header, {\n * viewModelOverrides: { content: { logo: logoViewModel } },\n * });\n * ```\n */\nexport function buildLogoViewModel(\n logo: LogoSource,\n fallbackTitle: string | null | undefined,\n): LogoViewModel {\n if (!logo) {\n return null;\n }\n\n // Logo must have storagePath (for direct Supabase URL) or explicit url\n if (!logo.url && !logo.storagePath) {\n return null;\n }\n\n const alt = logo.alt && logo.alt.trim().length > 0 ? logo.alt : fallbackTitle ?? 'Site logo';\n\n return {\n type: 'image',\n src: logo.url ?? '', // Empty when using storagePath - MediaNode builds direct URL\n alt,\n assetId: logo.assetId ?? undefined,\n width: logo.width ?? undefined,\n height: logo.height ?? undefined,\n storagePath: logo.storagePath ?? undefined,\n storageBucket: logo.storageBucket ?? undefined,\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Extracts the href from a navigation item's url field.\n */\nfunction extractHref(item: NavigationItemRecord): string {\n const link = item.url as LinkPayload | null | undefined;\n if (!link || typeof link !== 'object' || !('href' in link)) return '';\n return link.href;\n}\n\n/**\n * Determines if a navigation item's link is external.\n */\nfunction isExternalLink(item: NavigationItemRecord): boolean {\n const link = item.url as LinkPayload | null | undefined;\n if (!link || typeof link !== 'object' || !('kind' in link)) return false;\n return link.kind === 'external';\n}\n\n/**\n * Build a map of children items by parent ID.\n * Also warns about deeply nested items (grandchildren) which CMS shouldn't allow.\n * @internal\n */\nfunction buildChildrenByParentId(\n items: NavigationItemRecord[]\n): Map<string, NavigationItemRecord[]> {\n const childrenByParentId = new Map<string, NavigationItemRecord[]>();\n const itemsById = new Map<string, NavigationItemRecord>();\n\n // First pass: index items by ID\n for (const item of items) {\n itemsById.set(item.id, item);\n }\n\n // Second pass: build children map and warn about deep nesting\n for (const item of items) {\n if (item.parentId) {\n // Check if parent is itself a child (deep nesting)\n const parent = itemsById.get(item.parentId);\n if (parent?.parentId && typeof process !== 'undefined' && process.env.NODE_ENV !== 'production') {\n console.warn(\n `[SDK Navigation] Deeply nested item detected: \"${item.label}\" (id: ${item.id}). ` +\n `Only 1 level of nesting is supported. This item will be ignored.`\n );\n continue; // Skip deeply nested items\n }\n\n const siblings = childrenByParentId.get(item.parentId) ?? [];\n siblings.push(item);\n childrenByParentId.set(item.parentId, siblings);\n }\n }\n\n return childrenByParentId;\n}\n\n/**\n * Generic nested structure builder.\n * Extracts shared logic between transformToNestedNavItems and buildSimpleNestedMenu.\n * @internal\n */\nfunction buildNestedStructure<TLink, TDropdown, TCta extends TLink>(\n items: NavigationItemRecord[],\n options: {\n /** Convert a navigation item record to a link type */\n toLink: (item: NavigationItemRecord) => TLink | null;\n /** Create a dropdown from id, label, and children */\n createDropdown: (id: string, label: string, children: TLink[]) => TDropdown;\n /** Extract CTA from items (return null to skip CTA extraction) */\n extractCta?: boolean;\n }\n): { items: (TLink | TDropdown)[]; ctaItem: TCta | null } {\n const childrenByParentId = buildChildrenByParentId(items);\n\n // Process root items (no parentId) sorted by orderIndex\n const rootItems = items\n .filter((item) => !item.parentId)\n .sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0));\n\n const result: (TLink | TDropdown)[] = [];\n let ctaItem: TCta | null = null;\n\n for (const item of rootItems) {\n // Handle CTA extraction (CTAs are always links, not dropdowns)\n if (options.extractCta && !ctaItem && Boolean(item.isCta) && item.urlType !== 'dropdown') {\n const link = options.toLink(item);\n if (link) {\n ctaItem = link as TCta;\n continue;\n }\n }\n\n if (item.urlType === 'dropdown') {\n // It's a dropdown - gather its children\n const childRecords = childrenByParentId.get(item.id) ?? [];\n const children = childRecords\n .sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0))\n .map(options.toLink)\n .filter((child): child is TLink => child !== null);\n\n // Only include dropdown if it has children\n if (children.length > 0) {\n result.push(options.createDropdown(item.id, item.label, children));\n }\n } else {\n // It's a regular link\n const link = options.toLink(item);\n if (link) {\n result.push(link);\n }\n }\n }\n\n return { items: result, ctaItem };\n}\n\n/**\n * Convert navigation item to LinkValue for block rendering.\n */\nfunction convertToLinkValue(item: NavigationItemRecord): LinkValue | null {\n const payload = item.url as Record<string, unknown> | null;\n if (!payload) return null;\n\n const kind = typeof payload.kind === 'string' ? payload.kind : null;\n\n if (kind === 'external' || kind === 'url') {\n const href = typeof payload.href === 'string' ? payload.href : null;\n return href ? { kind, href } as ExternalLinkValue | CustomLinkValue : null;\n }\n\n if (kind === 'internal') {\n const routeId = typeof payload.routeId === 'string' ? payload.routeId : null;\n const entityId = typeof payload.entityId === 'string' ? payload.entityId : null;\n const entityType = payload.entityType === 'page' || payload.entityType === 'content'\n ? payload.entityType\n : null;\n const href = typeof payload.href === 'string' ? payload.href : null;\n const title = typeof payload.title === 'string' ? payload.title : null;\n const typeLabel = typeof payload.typeLabel === 'string' ? payload.typeLabel : null;\n\n if (!routeId || !entityId || !entityType || !href || !title || !typeLabel) {\n return null;\n }\n\n return {\n kind: 'internal',\n routeId,\n entityId,\n entityType,\n href,\n title,\n typeLabel,\n contentTypeKey: typeof payload.contentTypeKey === 'string' ? payload.contentTypeKey : null,\n contentTypeName: typeof payload.contentTypeName === 'string' ? payload.contentTypeName : null,\n updatedAt: typeof payload.updatedAt === 'string' ? payload.updatedAt : null,\n };\n }\n\n return null;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Simple pre-resolved menu/logo helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Build a SimpleMenuViewModel from navigation data with pre-resolved hrefs.\n * Use this instead of buildMenuViewModel for cleaner data flow.\n *\n * @param navigation - Navigation menus from site data\n * @param routes - Route map for resolving internal links\n *\n * @example\n * ```ts\n * const menu = buildSimpleMenu(siteData.navigation, siteData.routes);\n * // { items: [{ id, label, href: '/', isExternal: false }], cta: null }\n * ```\n */\nexport function buildSimpleMenu(\n navigation: NavigationMenuWithItems[],\n routes: RouteMap,\n): SimpleMenuViewModel {\n const menu = getPrimaryNavigation(navigation);\n\n if (!menu) {\n return { items: [], ctaItem: null };\n }\n\n const flatItems = menu.items\n .filter((item) => !item.parentId && item.urlType !== 'dropdown')\n .sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0));\n\n const items: SimpleNavLink[] = [];\n let ctaItem: SimpleNavLink | null = null;\n\n for (const item of flatItems) {\n const link = item.url as LinkPayload | null;\n const href = resolveHref(link, routes);\n\n if (!href) continue;\n\n const navLink: SimpleNavLink = {\n id: item.id,\n label: item.label,\n href,\n isExternal: link?.kind === 'external',\n };\n\n // Extract first CTA item separately\n if (!ctaItem && Boolean(item.isCta)) {\n ctaItem = navLink;\n continue;\n }\n\n items.push(navLink);\n }\n\n return { items, ctaItem };\n}\n\n/**\n * Build a SimpleNestedMenuViewModel with pre-resolved hrefs.\n * Supports dropdown containers with nested children.\n *\n * @example\n * ```ts\n * const menu = buildSimpleNestedMenu(siteData.navigation, siteData.routes);\n * menu.items.forEach(item => {\n * if (item.kind === 'dropdown') {\n * console.log(item.children);\n * }\n * });\n * ```\n */\nexport function buildSimpleNestedMenu(\n navigation: NavigationMenuWithItems[],\n routes: RouteMap,\n): SimpleNestedMenuViewModel {\n const menu = getPrimaryNavigation(navigation);\n\n if (!menu) {\n return { items: [], ctaItem: null };\n }\n\n const toSimpleLink = (item: NavigationItemRecord): SimpleNestedNavLink | null => {\n const link = item.url as LinkPayload | null;\n const href = resolveHref(link, routes);\n if (!href) return null;\n\n return {\n kind: 'link',\n id: item.id,\n label: item.label,\n href,\n isExternal: link?.kind === 'external',\n };\n };\n\n return buildNestedStructure<SimpleNestedNavLink, SimpleNestedNavDropdown, SimpleNestedNavLink>(\n menu.items,\n {\n toLink: toSimpleLink,\n createDropdown: (id, label, children) => ({\n kind: 'dropdown',\n id,\n label,\n children,\n }),\n extractCta: true,\n }\n );\n}\n\n/**\n * Resolve href from a link payload using route map.\n * @internal\n */\nfunction resolveHref(link: LinkPayload | null, routes: RouteMap): string | null {\n if (!link) return null;\n\n // External or custom URL links - use href directly\n if (link.kind === 'external' || link.kind === 'url') {\n return link.href || null;\n }\n\n // Internal link - resolve from route map\n if (link.kind === 'internal' && link.routeId) {\n const route = routes[link.routeId];\n if (route) {\n if (typeof route === 'string') {\n return route;\n }\n // Try path first, then href, then draftPath\n return route.path ?? route.href ?? route.draftPath ?? link.href ?? null;\n }\n // Fall back to link.href if route not found\n return link.href ?? null;\n }\n\n return null;\n}\n\n/**\n * Build a SimpleLogo from site layout data.\n *\n * @param logo - Logo data from site layout\n * @param fallbackAlt - Fallback alt text (usually site title)\n *\n * @example\n * ```ts\n * const logo = buildSimpleLogo(siteData.layout.logo, siteData.site.title);\n * // { src: 'https://...', alt: 'Site Name', width: 200, height: 50 }\n * ```\n */\nexport function buildSimpleLogo(\n logo: { url?: string | null; alt?: string | null; width?: number | null; height?: number | null } | null,\n fallbackAlt: string | null | undefined,\n): SimpleLogo {\n if (!logo || !logo.url) {\n return null;\n }\n\n const alt = logo.alt && logo.alt.trim().length > 0 ? logo.alt : (fallbackAlt ?? 'Site logo');\n\n const result: NonNullable<SimpleLogo> = {\n type: 'image',\n src: logo.url,\n alt,\n };\n\n if (logo.width != null) {\n result.width = logo.width;\n }\n if (logo.height != null) {\n result.height = logo.height;\n }\n\n return result;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Deprecated aliases (for backwards compatibility during migration)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * @deprecated Use `transformToNavItems` instead.\n * This alias is maintained for backwards compatibility only.\n */\nexport const transformNavItems = transformToNavItems;\n\n/**\n * @deprecated Use `getPrimaryNavigation` instead.\n * This alias is maintained for backwards compatibility only.\n */\nexport const selectPrimaryMenu = getPrimaryNavigation;\n\n// Re-export types for convenience\nexport type { NavigationMenuWithItems, NavigationItemRecord, LinkPayload } from '@riverbankcms/api';\n"]}
@@ -1,8 +1,8 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
3
 
4
- var _chunkVSFQRHYZjs = require('./chunk-VSFQRHYZ.js');
5
- require('./chunk-5STV4MWD.js');
4
+ var _chunkPHS2KWJXjs = require('./chunk-PHS2KWJX.js');
5
+ require('./chunk-SSS7CCRR.js');
6
6
 
7
7
 
8
8
 
@@ -22,5 +22,5 @@ require('./chunk-DGUM43GV.js');
22
22
 
23
23
 
24
24
 
25
- exports.Layout = _chunkVSFQRHYZjs.Layout; exports.Page = _chunkVSFQRHYZjs.Page; exports.PageRenderer = _chunk7UPVCT3Kjs.PageRenderer; exports.RichText = _chunk7UPVCT3Kjs.RichText; exports.SectionBackground = _chunk7UPVCT3Kjs.SectionBackground; exports.buildThemeRuntime = _chunk7UPVCT3Kjs.buildThemeRuntime; exports.resolveBackground = _chunk7UPVCT3Kjs.resolveBackground; exports.resolveImageUrl = _chunk7UPVCT3Kjs.resolveImageUrl;
25
+ exports.Layout = _chunkPHS2KWJXjs.Layout; exports.Page = _chunkPHS2KWJXjs.Page; exports.PageRenderer = _chunk7UPVCT3Kjs.PageRenderer; exports.RichText = _chunk7UPVCT3Kjs.RichText; exports.SectionBackground = _chunk7UPVCT3Kjs.SectionBackground; exports.buildThemeRuntime = _chunk7UPVCT3Kjs.buildThemeRuntime; exports.resolveBackground = _chunk7UPVCT3Kjs.resolveBackground; exports.resolveImageUrl = _chunk7UPVCT3Kjs.resolveImageUrl;
26
26
  //# sourceMappingURL=components.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  Layout,
3
3
  Page
4
- } from "./chunk-L5EA4FXU.mjs";
5
- import "./chunk-KFLZGNPO.mjs";
4
+ } from "./chunk-2HXHFSMI.mjs";
5
+ import "./chunk-PMHLZ3FW.mjs";
6
6
  import {
7
7
  PageRenderer,
8
8
  RichText,
@@ -5,7 +5,7 @@ var _chunkGERCMTPQjs = require('./chunk-GERCMTPQ.js');
5
5
 
6
6
 
7
7
 
8
- var _chunk6PWMOREAjs = require('./chunk-6PWMOREA.js');
8
+ var _chunkEOWGKCUZjs = require('./chunk-EOWGKCUZ.js');
9
9
  require('./chunk-DGUM43GV.js');
10
10
 
11
11
  // ../api/src/aiPlayground.ts
@@ -101,5 +101,5 @@ var MultiPageUpdateResponse = _zod.z.object({
101
101
 
102
102
 
103
103
 
104
- exports.API_ENDPOINTS = _chunk6PWMOREAjs.API_ENDPOINTS; exports.SYSTEM_BLOCK_KINDS = _chunkGERCMTPQjs.SYSTEM_BLOCK_KINDS; exports.buildEndpointURL = _chunk6PWMOREAjs.buildEndpointURL; exports.createRiverbankClient = _chunk6PWMOREAjs.createRiverbankClient;
104
+ exports.API_ENDPOINTS = _chunkEOWGKCUZjs.API_ENDPOINTS; exports.SYSTEM_BLOCK_KINDS = _chunkGERCMTPQjs.SYSTEM_BLOCK_KINDS; exports.buildEndpointURL = _chunkEOWGKCUZjs.buildEndpointURL; exports.createRiverbankClient = _chunkEOWGKCUZjs.createRiverbankClient;
105
105
  //# sourceMappingURL=index.js.map
@@ -5,7 +5,7 @@ import {
5
5
  API_ENDPOINTS,
6
6
  buildEndpointURL,
7
7
  createRiverbankClient
8
- } from "./chunk-XY66HIB4.mjs";
8
+ } from "./chunk-SQMGHEJM.mjs";
9
9
  import "./chunk-BJTO5JO5.mjs";
10
10
 
11
11
  // ../api/src/aiPlayground.ts
@@ -121,6 +121,69 @@ type NavItem = {
121
121
  /** Whether link should open in new tab (external links) */
122
122
  isExternal: boolean;
123
123
  };
124
+ /**
125
+ * A navigation link item with a direct URL.
126
+ * Use `kind` discriminator for type-safe narrowing.
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * if (item.kind === 'link') {
131
+ * console.log(item.href); // TypeScript knows href exists
132
+ * }
133
+ * ```
134
+ */
135
+ type NavLink = {
136
+ /** Discriminator for type narrowing */
137
+ kind: 'link';
138
+ /** Unique identifier from CMS */
139
+ id: string;
140
+ /** Display text for the navigation link */
141
+ label: string;
142
+ /** The URL to navigate to */
143
+ href: string;
144
+ /** Whether link should open in new tab (external links) */
145
+ isExternal: boolean;
146
+ };
147
+ /**
148
+ * A dropdown container holding child navigation items.
149
+ * Clicking reveals children instead of navigating.
150
+ * Max 1 level of nesting (children are always NavLink, not NavDropdown).
151
+ */
152
+ type NavDropdown = {
153
+ /** Discriminator for type narrowing */
154
+ kind: 'dropdown';
155
+ /** Unique identifier from CMS */
156
+ id: string;
157
+ /** Display text for the dropdown trigger */
158
+ label: string;
159
+ /** Child navigation links */
160
+ children: NavLink[];
161
+ };
162
+ /**
163
+ * Unified navigation item supporting both links and dropdowns.
164
+ * Use `kind` property for type-safe discrimination.
165
+ *
166
+ * @example
167
+ * ```ts
168
+ * const items = getNestedPrimaryNavItems(navigation);
169
+ * items.forEach(item => {
170
+ * if (item.kind === 'link') {
171
+ * console.log(item.href);
172
+ * } else {
173
+ * console.log(item.children.length);
174
+ * }
175
+ * });
176
+ * ```
177
+ */
178
+ type NestedNavItem = NavLink | NavDropdown;
179
+ /**
180
+ * Type guard to check if a navigation item is a link.
181
+ */
182
+ declare function isNavLink(item: NestedNavItem): item is NavLink;
183
+ /**
184
+ * Type guard to check if a navigation item is a dropdown.
185
+ */
186
+ declare function isNavDropdown(item: NestedNavItem): item is NavDropdown;
124
187
  /**
125
188
  * Simple nav link with pre-resolved href for block rendering.
126
189
  */
@@ -138,6 +201,36 @@ type SimpleMenuViewModel = {
138
201
  items: SimpleNavLink[];
139
202
  ctaItem: SimpleNavLink | null;
140
203
  };
204
+ /**
205
+ * Simple nested nav link with pre-resolved href.
206
+ */
207
+ type SimpleNestedNavLink = {
208
+ kind: 'link';
209
+ id: string;
210
+ label: string;
211
+ href: string;
212
+ isExternal: boolean;
213
+ };
214
+ /**
215
+ * Simple nested dropdown with pre-resolved children.
216
+ */
217
+ type SimpleNestedNavDropdown = {
218
+ kind: 'dropdown';
219
+ id: string;
220
+ label: string;
221
+ children: SimpleNestedNavLink[];
222
+ };
223
+ /**
224
+ * Unified simple nested navigation item.
225
+ */
226
+ type SimpleNestedNavItem = SimpleNestedNavLink | SimpleNestedNavDropdown;
227
+ /**
228
+ * Simple menu view model with nested navigation support.
229
+ */
230
+ type SimpleNestedMenuViewModel = {
231
+ items: SimpleNestedNavItem[];
232
+ ctaItem: SimpleNestedNavLink | null;
233
+ };
141
234
  /**
142
235
  * Simple logo data for block rendering.
143
236
  */
@@ -194,6 +287,44 @@ declare function getNavItemsBySlug(navigation: NavigationMenuWithItems[], slug:
194
287
  * Transform a menu into simple NavItem array.
195
288
  */
196
289
  declare function transformToNavItems(menu: NavigationMenuWithItems | null): NavItem[];
290
+ /**
291
+ * Transform a menu into nested NestedNavItem array.
292
+ * Builds tree structure from flat items, supporting dropdowns with children.
293
+ *
294
+ * @example
295
+ * ```ts
296
+ * const nav = transformToNestedNavItems(menu);
297
+ * // [
298
+ * // { kind: 'link', href: '/', label: 'Home', ... },
299
+ * // { kind: 'dropdown', label: 'Services', children: [...] },
300
+ * // ]
301
+ * ```
302
+ */
303
+ declare function transformToNestedNavItems(menu: NavigationMenuWithItems | null): NestedNavItem[];
304
+ /**
305
+ * Get nested nav items from the primary menu.
306
+ * Supports dropdowns with children for complex navigation structures.
307
+ *
308
+ * @example
309
+ * ```ts
310
+ * const nav = getNestedPrimaryNavItems(siteData.navigation);
311
+ * nav.forEach(item => {
312
+ * if (item.kind === 'dropdown') {
313
+ * console.log(`${item.label} has ${item.children.length} children`);
314
+ * }
315
+ * });
316
+ * ```
317
+ */
318
+ declare function getNestedPrimaryNavItems(navigation: NavigationMenuWithItems[]): NestedNavItem[];
319
+ /**
320
+ * Get nested nav items from a specific menu by slug.
321
+ *
322
+ * @example
323
+ * ```ts
324
+ * const footerNav = getNestedNavItemsBySlug(siteData.navigation, 'footer');
325
+ * ```
326
+ */
327
+ declare function getNestedNavItemsBySlug(navigation: NavigationMenuWithItems[], slug: string): NestedNavItem[];
197
328
  /**
198
329
  * Build a MenuViewModel from navigation data for block rendering.
199
330
  * Extracts CTA item separately and preserves full link data.
@@ -238,6 +369,21 @@ declare function buildLogoViewModel(logo: LogoSource, fallbackTitle: string | nu
238
369
  * ```
239
370
  */
240
371
  declare function buildSimpleMenu(navigation: NavigationMenuWithItems[], routes: RouteMap): SimpleMenuViewModel;
372
+ /**
373
+ * Build a SimpleNestedMenuViewModel with pre-resolved hrefs.
374
+ * Supports dropdown containers with nested children.
375
+ *
376
+ * @example
377
+ * ```ts
378
+ * const menu = buildSimpleNestedMenu(siteData.navigation, siteData.routes);
379
+ * menu.items.forEach(item => {
380
+ * if (item.kind === 'dropdown') {
381
+ * console.log(item.children);
382
+ * }
383
+ * });
384
+ * ```
385
+ */
386
+ declare function buildSimpleNestedMenu(navigation: NavigationMenuWithItems[], routes: RouteMap): SimpleNestedMenuViewModel;
241
387
  /**
242
388
  * Build a SimpleLogo from site layout data.
243
389
  *
@@ -267,4 +413,4 @@ declare const transformNavItems: typeof transformToNavItems;
267
413
  */
268
414
  declare const selectPrimaryMenu: typeof getPrimaryNavigation;
269
415
 
270
- export { type CustomLinkValue, type ExternalLinkValue, type InternalLinkValue, type LinkValue, type LogoSource, type LogoViewModel, type MenuCtaViewModel, type MenuLinkViewModel, type MenuViewModel, type NavItem, NavigationMenuWithItems, type SimpleLogo, type SimpleMenuViewModel, type SimpleNavLink, buildLogoViewModel, buildMenuViewModel, buildSimpleLogo, buildSimpleMenu, getNavItemsBySlug, getNavigationBySlug, getPrimaryNavItems, getPrimaryNavigation, selectPrimaryMenu, transformNavItems, transformToNavItems };
416
+ export { type CustomLinkValue, type ExternalLinkValue, type InternalLinkValue, type LinkValue, type LogoSource, type LogoViewModel, type MenuCtaViewModel, type MenuLinkViewModel, type MenuViewModel, type NavDropdown, type NavItem, type NavLink, NavigationMenuWithItems, type NestedNavItem, type SimpleLogo, type SimpleMenuViewModel, type SimpleNavLink, type SimpleNestedMenuViewModel, type SimpleNestedNavDropdown, type SimpleNestedNavItem, type SimpleNestedNavLink, buildLogoViewModel, buildMenuViewModel, buildSimpleLogo, buildSimpleMenu, buildSimpleNestedMenu, getNavItemsBySlug, getNavigationBySlug, getNestedNavItemsBySlug, getNestedPrimaryNavItems, getPrimaryNavItems, getPrimaryNavigation, isNavDropdown, isNavLink, selectPrimaryMenu, transformNavItems, transformToNavItems, transformToNestedNavItems };