@inf-monkeys-tech/monkeys-design 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -26912,6 +26912,30 @@ function MoreIcon4() {
26912
26912
  }
26913
26913
  );
26914
26914
  }
26915
+ function DisclosureIcon({ expanded }) {
26916
+ return /* @__PURE__ */ jsxRuntime.jsx(
26917
+ "svg",
26918
+ {
26919
+ "aria-hidden": "true",
26920
+ viewBox: "0 0 20 20",
26921
+ className: cn(
26922
+ "h-4 w-4 transition-transform motion-reduce:transition-none",
26923
+ expanded && "rotate-180"
26924
+ ),
26925
+ fill: "none",
26926
+ children: /* @__PURE__ */ jsxRuntime.jsx(
26927
+ "path",
26928
+ {
26929
+ d: "m6 8 4 4 4-4",
26930
+ stroke: "currentColor",
26931
+ strokeWidth: "1.6",
26932
+ strokeLinecap: "round",
26933
+ strokeLinejoin: "round"
26934
+ }
26935
+ )
26936
+ }
26937
+ );
26938
+ }
26915
26939
  function assignRef3(ref, node) {
26916
26940
  if (typeof ref === "function") {
26917
26941
  ref(node);
@@ -27067,6 +27091,94 @@ function resolveNavigationTreeClassNames(classNames) {
27067
27091
  )
27068
27092
  };
27069
27093
  }
27094
+ function entryClassName({
27095
+ item,
27096
+ active,
27097
+ collapsed,
27098
+ mobile,
27099
+ embedded = false,
27100
+ appearance,
27101
+ classNames,
27102
+ domClassName
27103
+ }) {
27104
+ return cn(
27105
+ "group/navigation-item relative flex w-full min-w-0 items-center gap-3 rounded-[var(--radius)] border border-transparent text-left text-sm outline-none transition-[background-color,border-color,color,box-shadow] focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none",
27106
+ appearance.itemHeight,
27107
+ appearance.itemPadding,
27108
+ embedded ? "min-h-0 self-stretch border-0 bg-transparent text-inherit hover:bg-transparent hover:text-inherit" : active ? activeVariantClassName(appearance.activeVariant) : "text-muted-foreground hover:border-border/70 hover:bg-muted/60 hover:text-foreground",
27109
+ collapsed && !mobile && "justify-center px-0",
27110
+ item.disabled && "pointer-events-none opacity-50",
27111
+ classNames?.item,
27112
+ active && classNames?.itemActive,
27113
+ mobile && classNames?.mobileItem,
27114
+ domClassName,
27115
+ item.className
27116
+ );
27117
+ }
27118
+ function EntryContent({
27119
+ item,
27120
+ collapsed,
27121
+ mobile,
27122
+ classNames,
27123
+ endIndicator
27124
+ }) {
27125
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
27126
+ hasRenderableNode(item.icon) ? /* @__PURE__ */ jsxRuntime.jsx(
27127
+ "span",
27128
+ {
27129
+ className: cn(
27130
+ "flex size-5 shrink-0 items-center justify-center [&_svg]:size-full",
27131
+ classNames?.itemIcon
27132
+ ),
27133
+ "aria-hidden": "true",
27134
+ children: item.icon
27135
+ }
27136
+ ) : null,
27137
+ mobile || !collapsed ? /* @__PURE__ */ jsxRuntime.jsxs(
27138
+ "span",
27139
+ {
27140
+ className: cn(
27141
+ "flex min-w-0 flex-1 flex-col",
27142
+ classNames?.itemContent
27143
+ ),
27144
+ children: [
27145
+ /* @__PURE__ */ jsxRuntime.jsx(
27146
+ "span",
27147
+ {
27148
+ className: cn(
27149
+ "min-w-0 truncate font-semibold",
27150
+ classNames?.itemLabel
27151
+ ),
27152
+ children: item.label
27153
+ }
27154
+ ),
27155
+ hasRenderableNode(item.description) ? /* @__PURE__ */ jsxRuntime.jsx(
27156
+ "span",
27157
+ {
27158
+ className: cn(
27159
+ "mt-0.5 truncate text-xs font-normal",
27160
+ classNames?.itemDescription
27161
+ ),
27162
+ children: item.description
27163
+ }
27164
+ ) : null
27165
+ ]
27166
+ }
27167
+ ) : null,
27168
+ (mobile || !collapsed) && hasRenderableNode(item.meta) ? /* @__PURE__ */ jsxRuntime.jsx(
27169
+ "span",
27170
+ {
27171
+ className: cn(
27172
+ "shrink-0 text-xs text-muted-foreground",
27173
+ classNames?.itemMeta
27174
+ ),
27175
+ children: item.meta
27176
+ }
27177
+ ) : null,
27178
+ (mobile || !collapsed) && hasRenderableNode(item.endContent) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("shrink-0", classNames?.itemEndContent), children: item.endContent }) : null,
27179
+ (mobile || !collapsed) && hasRenderableNode(endIndicator) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-center justify-center", children: endIndicator }) : null
27180
+ ] });
27181
+ }
27070
27182
  function EntryButton({
27071
27183
  item,
27072
27184
  active,
@@ -27075,7 +27187,11 @@ function EntryButton({
27075
27187
  appearance,
27076
27188
  classNames,
27077
27189
  mobile = false,
27078
- onSelect
27190
+ embedded = false,
27191
+ onSelect,
27192
+ ariaControls,
27193
+ ariaExpanded,
27194
+ endIndicator
27079
27195
  }) {
27080
27196
  const ItemComponent = itemAs ?? (item.href ? "a" : "button");
27081
27197
  const title = getNodeTitle(item.label, item.title);
@@ -27092,90 +27208,90 @@ function EntryButton({
27092
27208
  ...domProps,
27093
27209
  ...item.to ? { to: item.to } : {},
27094
27210
  ...item.href ? { href: item.href } : {},
27095
- ...ItemComponent === "button" ? { type: "button" } : {},
27211
+ ...ItemComponent === "button" ? { type: "button", disabled: item.disabled } : {},
27096
27212
  title,
27097
27213
  "aria-current": active ? "page" : void 0,
27098
27214
  "aria-disabled": item.disabled || void 0,
27215
+ "aria-controls": ariaControls,
27216
+ "aria-expanded": ariaExpanded,
27099
27217
  tabIndex: item.disabled ? -1 : domProps.tabIndex,
27100
27218
  onClick: handleClick
27101
27219
  };
27102
- return /* @__PURE__ */ jsxRuntime.jsxs(
27220
+ return /* @__PURE__ */ jsxRuntime.jsx(
27103
27221
  ItemComponent,
27104
27222
  {
27105
27223
  ...componentProps,
27106
27224
  "data-navigation-sidebar-item-id": item.id,
27107
27225
  "data-active": active ? "true" : "false",
27108
- className: cn(
27109
- "group/navigation-item relative flex w-full min-w-0 items-center gap-3 rounded-[var(--radius)] border border-transparent text-left text-sm outline-none transition-[background-color,border-color,color,box-shadow] focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none",
27110
- appearance.itemHeight,
27111
- appearance.itemPadding,
27112
- active ? activeVariantClassName(appearance.activeVariant) : "text-muted-foreground hover:border-border/70 hover:bg-muted/60 hover:text-foreground",
27113
- collapsed && !mobile && "justify-center px-0",
27114
- item.disabled && "pointer-events-none opacity-50",
27115
- classNames?.item,
27116
- active && classNames?.itemActive,
27117
- mobile && classNames?.mobileItem,
27118
- domProps.className,
27119
- item.className
27120
- ),
27121
- children: [
27122
- hasRenderableNode(item.icon) ? /* @__PURE__ */ jsxRuntime.jsx(
27123
- "span",
27124
- {
27125
- className: cn(
27126
- "flex size-5 shrink-0 items-center justify-center [&_svg]:size-full",
27127
- classNames?.itemIcon
27128
- ),
27129
- "aria-hidden": "true",
27130
- children: item.icon
27131
- }
27132
- ) : null,
27133
- mobile || !collapsed ? /* @__PURE__ */ jsxRuntime.jsxs(
27134
- "span",
27135
- {
27136
- className: cn(
27137
- "flex min-w-0 flex-1 flex-col",
27138
- classNames?.itemContent
27139
- ),
27140
- children: [
27141
- /* @__PURE__ */ jsxRuntime.jsx(
27142
- "span",
27143
- {
27144
- className: cn(
27145
- "min-w-0 truncate font-semibold",
27146
- classNames?.itemLabel
27147
- ),
27148
- children: item.label
27149
- }
27150
- ),
27151
- hasRenderableNode(item.description) ? /* @__PURE__ */ jsxRuntime.jsx(
27152
- "span",
27153
- {
27154
- className: cn(
27155
- "mt-0.5 truncate text-xs font-normal",
27156
- classNames?.itemDescription
27157
- ),
27158
- children: item.description
27159
- }
27160
- ) : null
27161
- ]
27162
- }
27163
- ) : null,
27164
- (mobile || !collapsed) && hasRenderableNode(item.meta) ? /* @__PURE__ */ jsxRuntime.jsx(
27165
- "span",
27166
- {
27167
- className: cn(
27168
- "shrink-0 text-xs text-muted-foreground",
27169
- classNames?.itemMeta
27170
- ),
27171
- children: item.meta
27172
- }
27173
- ) : null,
27174
- (mobile || !collapsed) && hasRenderableNode(item.endContent) ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("shrink-0", classNames?.itemEndContent), children: item.endContent }) : null
27175
- ]
27226
+ "data-expanded": ariaExpanded === void 0 ? void 0 : String(ariaExpanded),
27227
+ className: entryClassName({
27228
+ item,
27229
+ active,
27230
+ collapsed,
27231
+ mobile,
27232
+ embedded,
27233
+ appearance,
27234
+ classNames,
27235
+ domClassName: domProps.className
27236
+ }),
27237
+ children: /* @__PURE__ */ jsxRuntime.jsx(
27238
+ EntryContent,
27239
+ {
27240
+ item,
27241
+ collapsed,
27242
+ mobile,
27243
+ classNames,
27244
+ endIndicator
27245
+ }
27246
+ )
27176
27247
  }
27177
27248
  );
27178
27249
  }
27250
+ function EntryPresentation({
27251
+ item,
27252
+ appearance,
27253
+ classNames
27254
+ }) {
27255
+ const domProps = item.domProps ?? {};
27256
+ return /* @__PURE__ */ jsxRuntime.jsx(
27257
+ "div",
27258
+ {
27259
+ ...domProps,
27260
+ "data-navigation-sidebar-item-id": item.id,
27261
+ "aria-disabled": item.disabled || void 0,
27262
+ title: getNodeTitle(item.label, item.title),
27263
+ className: entryClassName({
27264
+ item,
27265
+ active: false,
27266
+ collapsed: false,
27267
+ mobile: true,
27268
+ embedded: true,
27269
+ appearance,
27270
+ classNames,
27271
+ domClassName: domProps.className
27272
+ }),
27273
+ children: /* @__PURE__ */ jsxRuntime.jsx(
27274
+ EntryContent,
27275
+ {
27276
+ item,
27277
+ collapsed: false,
27278
+ mobile: true,
27279
+ classNames
27280
+ }
27281
+ )
27282
+ }
27283
+ );
27284
+ }
27285
+ function routeRowClassName({
27286
+ active,
27287
+ appearance
27288
+ }) {
27289
+ return cn(
27290
+ "flex w-full min-w-0 items-center gap-0.5 rounded-[var(--radius)] border border-transparent pr-1 text-sm transition-[background-color,border-color,color,box-shadow] motion-reduce:transition-none",
27291
+ appearance.itemHeight,
27292
+ active ? activeVariantClassName(appearance.activeVariant) : "text-muted-foreground hover:border-border/70 hover:bg-muted/60 hover:text-foreground"
27293
+ );
27294
+ }
27179
27295
  function filterCatalogItems(items, activeFilterId) {
27180
27296
  if (!activeFilterId) return items;
27181
27297
  return items.filter(
@@ -27307,7 +27423,9 @@ function ChildEntry({
27307
27423
  active,
27308
27424
  interactive,
27309
27425
  onSelect,
27310
- classNames
27426
+ appearance,
27427
+ classNames,
27428
+ embedded = false
27311
27429
  }) {
27312
27430
  const Component = interactive ? "button" : "div";
27313
27431
  const domProps = child.domProps ?? {};
@@ -27322,8 +27440,11 @@ function ChildEntry({
27322
27440
  title: getNodeTitle(child.label, child.title),
27323
27441
  disabled: interactive ? child.disabled : void 0,
27324
27442
  className: cn(
27325
- "flex min-h-9 w-full min-w-0 items-center gap-2 rounded-md border border-transparent px-2 text-left text-xs font-medium outline-none transition-[background-color,border-color,color] focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none",
27326
- active ? "border-primary/35 bg-primary/10 text-primary" : "text-muted-foreground hover:border-border hover:bg-muted/60 hover:text-foreground",
27443
+ "flex w-full min-w-0 flex-1 items-center gap-3 rounded-[var(--radius)] border border-transparent text-left text-sm font-semibold outline-none transition-[background-color,border-color,color,box-shadow] focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none",
27444
+ appearance.itemHeight,
27445
+ appearance.itemPadding,
27446
+ "pl-11",
27447
+ embedded ? "min-h-0 self-stretch border-0 bg-transparent text-inherit hover:bg-transparent hover:text-inherit" : active ? activeVariantClassName(appearance.activeVariant) : "text-muted-foreground hover:border-border/70 hover:bg-muted/60 hover:text-foreground",
27327
27448
  child.disabled && "pointer-events-none opacity-50",
27328
27449
  classNames?.childItem,
27329
27450
  active && classNames?.childItemActive,
@@ -27335,7 +27456,7 @@ function ChildEntry({
27335
27456
  hasRenderableNode(child.icon) ? /* @__PURE__ */ jsxRuntime.jsx(
27336
27457
  "span",
27337
27458
  {
27338
- className: "flex size-4 shrink-0 items-center justify-center",
27459
+ className: "flex size-5 shrink-0 items-center justify-center [&_svg]:size-full",
27339
27460
  "aria-hidden": "true",
27340
27461
  children: child.icon
27341
27462
  }
@@ -27345,29 +27466,167 @@ function ChildEntry({
27345
27466
  }
27346
27467
  );
27347
27468
  }
27469
+ function RouteActions({
27470
+ itemId,
27471
+ actions,
27472
+ kind,
27473
+ className,
27474
+ mobile = false
27475
+ }) {
27476
+ if (!hasRenderableNode(actions)) return null;
27477
+ return /* @__PURE__ */ jsxRuntime.jsx(
27478
+ "div",
27479
+ {
27480
+ "data-navigation-sidebar-item-actions": kind === "item" ? itemId : void 0,
27481
+ "data-navigation-sidebar-child-actions": kind === "child" ? itemId : void 0,
27482
+ "data-navigation-sidebar-actions-mobile": mobile ? "true" : void 0,
27483
+ className: cn(
27484
+ "ml-auto flex shrink-0 items-center gap-1 [&>button]:border-0 [&>button]:bg-transparent [&>button]:shadow-none [&>button:hover]:bg-muted",
27485
+ className
27486
+ ),
27487
+ children: actions
27488
+ }
27489
+ );
27490
+ }
27491
+ function isDisclosureRouteItem(item) {
27492
+ return item.interaction === "disclosure";
27493
+ }
27494
+ function validateRouteItems(routeItems) {
27495
+ const itemIds = /* @__PURE__ */ new Set();
27496
+ const childIds = /* @__PURE__ */ new Set();
27497
+ const collapsibleItemIds = /* @__PURE__ */ new Set();
27498
+ for (const item of routeItems) {
27499
+ const itemId = item.id;
27500
+ if (itemIds.has(itemId)) {
27501
+ throw new RangeError(
27502
+ `NavigationSidebar route item ids must be unique; received "${itemId}" more than once.`
27503
+ );
27504
+ }
27505
+ itemIds.add(itemId);
27506
+ const disclosure = isDisclosureRouteItem(item);
27507
+ if (disclosure) {
27508
+ if (!item.children.length) {
27509
+ throw new RangeError(
27510
+ `NavigationSidebar disclosure item "${item.id}" must include at least one child.`
27511
+ );
27512
+ }
27513
+ if (item.href !== void 0 || item.to !== void 0 || item.onClick !== void 0) {
27514
+ throw new TypeError(
27515
+ `NavigationSidebar disclosure item "${itemId}" cannot define href, to, or onClick.`
27516
+ );
27517
+ }
27518
+ collapsibleItemIds.add(item.id);
27519
+ } else if (item.childrenPresentation === "collapsible") {
27520
+ if (!item.children?.length) {
27521
+ throw new RangeError(
27522
+ `NavigationSidebar collapsible route item "${item.id}" must include at least one child.`
27523
+ );
27524
+ }
27525
+ collapsibleItemIds.add(item.id);
27526
+ }
27527
+ for (const child of item.children ?? []) {
27528
+ if (childIds.has(child.id)) {
27529
+ throw new RangeError(
27530
+ `NavigationSidebar route child ids must be unique; received "${child.id}" more than once.`
27531
+ );
27532
+ }
27533
+ childIds.add(child.id);
27534
+ }
27535
+ }
27536
+ return collapsibleItemIds;
27537
+ }
27538
+ function RouteChildrenToggle({
27539
+ item,
27540
+ expanded,
27541
+ controls,
27542
+ label,
27543
+ onToggle,
27544
+ classNames
27545
+ }) {
27546
+ const itemLabel = typeof item.label === "string" ? item.label : item.id;
27547
+ return /* @__PURE__ */ jsxRuntime.jsx(
27548
+ "button",
27549
+ {
27550
+ type: "button",
27551
+ disabled: item.disabled,
27552
+ "aria-expanded": expanded,
27553
+ "aria-controls": controls,
27554
+ "aria-label": `${label}: ${itemLabel}`,
27555
+ title: label,
27556
+ "data-navigation-sidebar-disclosure-trigger": item.id,
27557
+ className: cn(
27558
+ "inline-flex h-8 w-7 shrink-0 items-center justify-center rounded-md border-0 bg-transparent text-muted-foreground shadow-none outline-none hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
27559
+ classNames?.childMenuTrigger
27560
+ ),
27561
+ onClick: onToggle,
27562
+ children: /* @__PURE__ */ jsxRuntime.jsx(DisclosureIcon, { expanded })
27563
+ }
27564
+ );
27565
+ }
27348
27566
  function CollapsedChildMenu({
27349
27567
  item,
27350
27568
  activeChildId,
27351
27569
  label,
27352
27570
  onChildSelect,
27353
- classNames
27571
+ classNames,
27572
+ appearance,
27573
+ triggerVariant = "submenu",
27574
+ mobile = false
27354
27575
  }) {
27355
27576
  const enabledChildren = (item.children ?? []).filter(
27356
27577
  (child) => !child.disabled
27357
27578
  );
27358
- if (enabledChildren.length === 0) return null;
27579
+ if (!item.children?.length) return null;
27580
+ if (triggerVariant === "submenu" && (!onChildSelect || enabledChildren.length === 0))
27581
+ return null;
27582
+ const itemLabel = typeof item.label === "string" ? item.label : item.id;
27583
+ const itemTriggerDisabled = Boolean(item.disabled) || !onChildSelect || enabledChildren.length === 0;
27584
+ const domProps = item.domProps ?? {};
27359
27585
  return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu2__namespace.Root, { children: [
27360
- /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu2__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
27586
+ /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu2__namespace.Trigger, { asChild: true, children: triggerVariant === "item" && appearance ? /* @__PURE__ */ jsxRuntime.jsx(
27587
+ "button",
27588
+ {
27589
+ ...domProps,
27590
+ type: "button",
27591
+ disabled: itemTriggerDisabled,
27592
+ "aria-label": `${label}: ${itemLabel}`,
27593
+ title: label,
27594
+ "data-navigation-sidebar-item-id": item.id,
27595
+ "data-navigation-sidebar-disclosure-menu": "true",
27596
+ className: entryClassName({
27597
+ item,
27598
+ active: false,
27599
+ collapsed: !mobile,
27600
+ mobile,
27601
+ appearance,
27602
+ classNames,
27603
+ domClassName: domProps.className
27604
+ }),
27605
+ children: /* @__PURE__ */ jsxRuntime.jsx(
27606
+ EntryContent,
27607
+ {
27608
+ item,
27609
+ collapsed: !mobile,
27610
+ mobile,
27611
+ classNames,
27612
+ endIndicator: mobile ? /* @__PURE__ */ jsxRuntime.jsx(DisclosureIcon, { expanded: false }) : void 0
27613
+ }
27614
+ )
27615
+ }
27616
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
27361
27617
  "button",
27362
27618
  {
27363
27619
  type: "button",
27620
+ disabled: triggerVariant === "disclosure" ? itemTriggerDisabled : void 0,
27621
+ "data-navigation-sidebar-disclosure-trigger": triggerVariant === "disclosure" ? item.id : void 0,
27364
27622
  className: cn(
27365
- "inline-flex h-8 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring",
27623
+ "inline-flex h-8 shrink-0 items-center justify-center rounded-md border-0 bg-transparent text-muted-foreground shadow-none outline-none hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
27624
+ triggerVariant === "disclosure" ? "w-7" : "w-6",
27366
27625
  classNames?.childMenuTrigger
27367
27626
  ),
27368
- "aria-label": `${label}: ${typeof item.label === "string" ? item.label : item.id}`,
27627
+ "aria-label": `${label}: ${itemLabel}`,
27369
27628
  title: label,
27370
- children: /* @__PURE__ */ jsxRuntime.jsx(MoreIcon4, {})
27629
+ children: triggerVariant === "disclosure" ? /* @__PURE__ */ jsxRuntime.jsx(DisclosureIcon, { expanded: false }) : /* @__PURE__ */ jsxRuntime.jsx(MoreIcon4, {})
27371
27630
  }
27372
27631
  ) }),
27373
27632
  /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu2__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -27390,7 +27649,7 @@ function CollapsedChildMenu({
27390
27649
  "flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
27391
27650
  child.id === activeChildId && "bg-accent text-accent-foreground"
27392
27651
  ),
27393
- onSelect: () => onChildSelect(child, item),
27652
+ onSelect: () => onChildSelect?.(child, item),
27394
27653
  children: [
27395
27654
  hasRenderableNode(child.icon) ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: child.icon }) : null,
27396
27655
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: child.label })
@@ -27411,22 +27670,81 @@ function RouteContent({
27411
27670
  routeItems,
27412
27671
  activeItemId,
27413
27672
  activeChildId,
27673
+ expandedItemIds,
27674
+ defaultExpandedItemIds = [],
27414
27675
  itemAs,
27415
27676
  onItemSelect,
27416
27677
  onChildSelect,
27678
+ onExpandedItemIdsChange,
27417
27679
  collapsedChildMenuLabel = "Open submenu",
27680
+ disclosureLabel = "Toggle submenu",
27418
27681
  ariaLabel,
27419
27682
  classNames
27420
27683
  } = props;
27421
- return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": ariaLabel, children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: cn("grid list-none gap-2 p-0", classNames?.list), children: routeItems.map((item) => {
27422
- const active = item.id === activeItemId;
27684
+ const disclosureId = React4.useId();
27685
+ const collapsibleItemIds = React4.useMemo(
27686
+ () => validateRouteItems(routeItems),
27687
+ [routeItems]
27688
+ );
27689
+ const [internalExpandedItemIds, setInternalExpandedItemIds] = React4.useState(
27690
+ () => defaultExpandedItemIds
27691
+ );
27692
+ const isExpandedControlled = expandedItemIds !== void 0;
27693
+ const resolvedExpandedItemIds = expandedItemIds ?? internalExpandedItemIds;
27694
+ const normalizedExpandedItemIds = React4.useMemo(
27695
+ () => resolvedExpandedItemIds.filter(
27696
+ (itemId) => collapsibleItemIds.has(itemId)
27697
+ ),
27698
+ [collapsibleItemIds, resolvedExpandedItemIds]
27699
+ );
27700
+ const expandedItemIdSet = React4.useMemo(
27701
+ () => new Set(normalizedExpandedItemIds),
27702
+ [normalizedExpandedItemIds]
27703
+ );
27704
+ const toggleItemExpanded = React4.useCallback(
27705
+ (item) => {
27706
+ if (item.disabled || !collapsibleItemIds.has(item.id)) return;
27707
+ const nextExpandedItemIds = expandedItemIdSet.has(item.id) ? normalizedExpandedItemIds.filter((itemId) => itemId !== item.id) : [...normalizedExpandedItemIds, item.id];
27708
+ if (!isExpandedControlled) {
27709
+ setInternalExpandedItemIds(nextExpandedItemIds);
27710
+ }
27711
+ onExpandedItemIdsChange?.(nextExpandedItemIds);
27712
+ },
27713
+ [
27714
+ collapsibleItemIds,
27715
+ expandedItemIdSet,
27716
+ isExpandedControlled,
27717
+ normalizedExpandedItemIds,
27718
+ onExpandedItemIdsChange
27719
+ ]
27720
+ );
27721
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": ariaLabel, children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: cn("grid list-none gap-2 p-0", classNames?.list), children: routeItems.map((item, itemIndex) => {
27722
+ const disclosure = isDisclosureRouteItem(item);
27723
+ const active = !disclosure && item.id === activeItemId;
27724
+ const hasChildren = Boolean(item.children?.length);
27725
+ const childrenCollapsible = collapsibleItemIds.has(item.id);
27726
+ const childrenExpanded = !childrenCollapsible || expandedItemIdSet.has(item.id);
27727
+ const showItemActions = !collapsed && hasRenderableNode(item.actions);
27728
+ const compoundItemRow = collapsed && hasChildren && Boolean(onChildSelect) || !collapsed && childrenCollapsible && !disclosure || showItemActions;
27729
+ const childListId = `${disclosureId}-route-children-${itemIndex}`;
27423
27730
  return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "grid min-w-0 gap-1", children: [
27424
- /* @__PURE__ */ jsxRuntime.jsxs(
27731
+ collapsed && disclosure ? /* @__PURE__ */ jsxRuntime.jsx(
27732
+ CollapsedChildMenu,
27733
+ {
27734
+ item,
27735
+ activeChildId,
27736
+ label: collapsedChildMenuLabel,
27737
+ onChildSelect,
27738
+ classNames,
27739
+ appearance,
27740
+ triggerVariant: "item"
27741
+ }
27742
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
27425
27743
  "div",
27426
27744
  {
27427
- className: cn(
27428
- collapsed && Boolean(item.children?.length) && Boolean(onChildSelect) && "flex min-w-0 items-center gap-0.5"
27429
- ),
27745
+ "data-navigation-sidebar-item-row": compoundItemRow ? item.id : void 0,
27746
+ "data-active": compoundItemRow ? String(active) : void 0,
27747
+ className: compoundItemRow ? routeRowClassName({ active, appearance }) : void 0,
27430
27748
  children: [
27431
27749
  /* @__PURE__ */ jsxRuntime.jsx(
27432
27750
  EntryButton,
@@ -27434,12 +27752,25 @@ function RouteContent({
27434
27752
  item,
27435
27753
  active,
27436
27754
  collapsed,
27437
- itemAs,
27755
+ embedded: compoundItemRow,
27756
+ itemAs: disclosure ? "button" : itemAs,
27438
27757
  appearance,
27439
27758
  classNames,
27440
- onSelect: onItemSelect ? () => onItemSelect(item) : void 0
27759
+ onSelect: disclosure ? () => toggleItemExpanded(item) : onItemSelect ? () => onItemSelect(item) : void 0,
27760
+ ariaControls: !collapsed && childrenCollapsible && disclosure ? childListId : void 0,
27761
+ ariaExpanded: !collapsed && childrenCollapsible && disclosure ? childrenExpanded : void 0,
27762
+ endIndicator: !collapsed && disclosure && !showItemActions ? /* @__PURE__ */ jsxRuntime.jsx(DisclosureIcon, { expanded: childrenExpanded }) : void 0
27441
27763
  }
27442
27764
  ),
27765
+ showItemActions ? /* @__PURE__ */ jsxRuntime.jsx(
27766
+ RouteActions,
27767
+ {
27768
+ itemId: item.id,
27769
+ actions: item.actions,
27770
+ kind: "item",
27771
+ className: classNames?.itemActions
27772
+ }
27773
+ ) : null,
27443
27774
  collapsed && onChildSelect ? /* @__PURE__ */ jsxRuntime.jsx(
27444
27775
  CollapsedChildMenu,
27445
27776
  {
@@ -27449,28 +27780,71 @@ function RouteContent({
27449
27780
  onChildSelect,
27450
27781
  classNames
27451
27782
  }
27783
+ ) : null,
27784
+ !collapsed && childrenCollapsible && (!disclosure || showItemActions) ? /* @__PURE__ */ jsxRuntime.jsx(
27785
+ RouteChildrenToggle,
27786
+ {
27787
+ item,
27788
+ expanded: childrenExpanded,
27789
+ controls: childListId,
27790
+ label: disclosureLabel,
27791
+ onToggle: () => toggleItemExpanded(item),
27792
+ classNames
27793
+ }
27452
27794
  ) : null
27453
27795
  ]
27454
27796
  }
27455
27797
  ),
27456
- !collapsed && item.children?.length ? /* @__PURE__ */ jsxRuntime.jsx(
27798
+ !collapsed && hasChildren ? /* @__PURE__ */ jsxRuntime.jsx(
27457
27799
  "ul",
27458
27800
  {
27801
+ id: childListId,
27802
+ hidden: !childrenExpanded,
27803
+ style: childrenExpanded ? void 0 : { display: "none" },
27459
27804
  className: cn(
27460
27805
  "ml-5 grid list-none gap-0.5 border-l border-border/70 py-1 pl-3",
27461
27806
  classNames?.childList
27462
27807
  ),
27463
- children: item.children.map((child) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
27464
- ChildEntry,
27465
- {
27466
- child,
27467
- parent: item,
27468
- active: child.id === activeChildId,
27469
- interactive: Boolean(onChildSelect),
27470
- onSelect: onChildSelect,
27471
- classNames
27472
- }
27473
- ) }, child.id))
27808
+ children: item.children?.map((child) => {
27809
+ const hasChildActions = hasRenderableNode(child.actions);
27810
+ const childActive = child.id === activeChildId;
27811
+ const childEntry = /* @__PURE__ */ jsxRuntime.jsx(
27812
+ ChildEntry,
27813
+ {
27814
+ child,
27815
+ parent: item,
27816
+ active: childActive,
27817
+ interactive: Boolean(onChildSelect),
27818
+ onSelect: onChildSelect,
27819
+ appearance,
27820
+ classNames,
27821
+ embedded: hasChildActions
27822
+ }
27823
+ );
27824
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: hasChildActions ? /* @__PURE__ */ jsxRuntime.jsxs(
27825
+ "div",
27826
+ {
27827
+ "data-navigation-sidebar-child-row": child.id,
27828
+ "data-active": String(childActive),
27829
+ className: routeRowClassName({
27830
+ active: childActive,
27831
+ appearance
27832
+ }),
27833
+ children: [
27834
+ childEntry,
27835
+ /* @__PURE__ */ jsxRuntime.jsx(
27836
+ RouteActions,
27837
+ {
27838
+ itemId: child.id,
27839
+ actions: child.actions,
27840
+ kind: "child",
27841
+ className: classNames?.childActions
27842
+ }
27843
+ )
27844
+ ]
27845
+ }
27846
+ ) : childEntry }, child.id);
27847
+ })
27474
27848
  }
27475
27849
  ) : null
27476
27850
  ] }, item.id);
@@ -27504,23 +27878,116 @@ function MobileNavigation({
27504
27878
  classNames?.mobileNav,
27505
27879
  props.mobile.className
27506
27880
  ),
27507
- children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
27508
- EntryButton,
27509
- {
27510
- item,
27511
- active: props.kind === "catalog" ? item.active ?? item.id === props.activeItemId : item.id === props.activeItemId,
27512
- collapsed: false,
27513
- itemAs: props.itemAs,
27514
- appearance,
27515
- classNames: {
27516
- ...classNames,
27517
- mobileItem: cn(classNames?.mobileItem, props.mobile?.itemClassName)
27881
+ children: items.map((item) => {
27882
+ const mobileClassNames = {
27883
+ ...classNames,
27884
+ mobileItem: cn(
27885
+ classNames?.mobileItem,
27886
+ props.mobile?.itemClassName
27887
+ )
27888
+ };
27889
+ const routeItem = props.kind === "route" ? item : void 0;
27890
+ const showRouteActions = routeItem !== void 0 && hasRenderableNode(routeItem.actions);
27891
+ if (props.kind === "route" && isDisclosureRouteItem(item)) {
27892
+ return showRouteActions ? /* @__PURE__ */ jsxRuntime.jsxs(
27893
+ "div",
27894
+ {
27895
+ "data-navigation-sidebar-item-row": item.id,
27896
+ "data-active": "false",
27897
+ className: cn(
27898
+ routeRowClassName({ active: false, appearance }),
27899
+ "shrink-0"
27900
+ ),
27901
+ children: [
27902
+ /* @__PURE__ */ jsxRuntime.jsx(
27903
+ EntryPresentation,
27904
+ {
27905
+ item,
27906
+ appearance,
27907
+ classNames: mobileClassNames
27908
+ }
27909
+ ),
27910
+ /* @__PURE__ */ jsxRuntime.jsx(
27911
+ RouteActions,
27912
+ {
27913
+ itemId: item.id,
27914
+ actions: item.actions,
27915
+ kind: "item",
27916
+ className: classNames?.itemActions,
27917
+ mobile: true
27918
+ }
27919
+ ),
27920
+ /* @__PURE__ */ jsxRuntime.jsx(
27921
+ CollapsedChildMenu,
27922
+ {
27923
+ item,
27924
+ activeChildId: props.activeChildId,
27925
+ label: props.collapsedChildMenuLabel ?? "Open submenu",
27926
+ onChildSelect: props.onChildSelect,
27927
+ classNames: mobileClassNames,
27928
+ appearance,
27929
+ triggerVariant: "disclosure",
27930
+ mobile: true
27931
+ }
27932
+ )
27933
+ ]
27934
+ },
27935
+ item.id
27936
+ ) : /* @__PURE__ */ jsxRuntime.jsx(React4.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
27937
+ CollapsedChildMenu,
27938
+ {
27939
+ item,
27940
+ activeChildId: props.activeChildId,
27941
+ label: props.collapsedChildMenuLabel ?? "Open submenu",
27942
+ onChildSelect: props.onChildSelect,
27943
+ classNames: mobileClassNames,
27944
+ appearance,
27945
+ triggerVariant: "item",
27946
+ mobile: true
27947
+ }
27948
+ ) }, item.id);
27949
+ }
27950
+ const active = props.kind === "catalog" ? item.active ?? item.id === props.activeItemId : item.id === props.activeItemId;
27951
+ const entryButton = /* @__PURE__ */ jsxRuntime.jsx(
27952
+ EntryButton,
27953
+ {
27954
+ item,
27955
+ active,
27956
+ collapsed: false,
27957
+ embedded: showRouteActions,
27958
+ itemAs: props.itemAs,
27959
+ appearance,
27960
+ classNames: mobileClassNames,
27961
+ mobile: true,
27962
+ onSelect: props.kind === "route" && props.onItemSelect ? () => props.onItemSelect?.(item) : void 0
27963
+ }
27964
+ );
27965
+ return showRouteActions && routeItem ? /* @__PURE__ */ jsxRuntime.jsxs(
27966
+ "div",
27967
+ {
27968
+ "data-navigation-sidebar-item-row": item.id,
27969
+ "data-active": String(active),
27970
+ className: cn(
27971
+ routeRowClassName({ active, appearance }),
27972
+ "shrink-0"
27973
+ ),
27974
+ children: [
27975
+ entryButton,
27976
+ /* @__PURE__ */ jsxRuntime.jsx(
27977
+ RouteActions,
27978
+ {
27979
+ itemId: routeItem.id,
27980
+ actions: routeItem.actions,
27981
+ kind: "item",
27982
+ className: classNames?.itemActions,
27983
+ mobile: true
27984
+ }
27985
+ )
27986
+ ]
27518
27987
  },
27519
- mobile: true,
27520
- onSelect: props.kind === "route" && props.onItemSelect ? () => props.onItemSelect?.(item) : void 0
27521
- },
27522
- item.id
27523
- ))
27988
+ item.id
27989
+ ) : /* @__PURE__ */ jsxRuntime.jsx(React4.Fragment, { children: entryButton }, item.id);
27990
+ })
27524
27991
  }
27525
27992
  );
27526
27993
  }