@invana/ui 0.0.23 → 0.0.24

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.cjs CHANGED
@@ -3115,27 +3115,214 @@ function ChatSessionMessage({
3115
3115
  footer
3116
3116
  ] });
3117
3117
  }
3118
+ var NONE = Object.freeze([]);
3119
+ function same(a, b) {
3120
+ if (a.length !== b.length) return false;
3121
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
3122
+ return true;
3123
+ }
3124
+ function useOverflowItems({
3125
+ count,
3126
+ enabled = true,
3127
+ pinnedIndex,
3128
+ reserve = 32
3129
+ }) {
3130
+ const containerEl = React23__namespace.useRef(null);
3131
+ const itemEls = React23__namespace.useRef([]);
3132
+ const widths = React23__namespace.useRef([]);
3133
+ const itemRefs = React23__namespace.useRef([]);
3134
+ const [hidden, setHidden] = React23__namespace.useState(NONE);
3135
+ const fit = React23__namespace.useCallback(() => {
3136
+ const el = containerEl.current;
3137
+ if (!el || !enabled) {
3138
+ setHidden((prev) => prev === NONE ? prev : NONE);
3139
+ return;
3140
+ }
3141
+ const gap = Number.parseFloat(getComputedStyle(el).columnGap) || 0;
3142
+ for (let i = 0; i < count; i++) {
3143
+ const item = itemEls.current[i];
3144
+ if (item && item.offsetParent !== null) widths.current[i] = item.offsetWidth + gap;
3145
+ }
3146
+ const budget = el.clientWidth;
3147
+ if (budget <= 0) return;
3148
+ let total = 0;
3149
+ for (let i = 0; i < count; i++) total += widths.current[i] ?? 0;
3150
+ if (total <= budget + gap) {
3151
+ setHidden((prev) => prev === NONE ? prev : NONE);
3152
+ return;
3153
+ }
3154
+ const next = [];
3155
+ let used = pinnedIndex != null ? widths.current[pinnedIndex] ?? 0 : 0;
3156
+ for (let i = 0; i < count; i++) {
3157
+ if (i === pinnedIndex) continue;
3158
+ const w = widths.current[i] ?? 0;
3159
+ if (used + w <= budget - reserve) used += w;
3160
+ else next.push(i);
3161
+ }
3162
+ setHidden((prev) => same(prev, next) ? prev : next);
3163
+ }, [count, enabled, pinnedIndex, reserve]);
3164
+ React23__namespace.useLayoutEffect(() => {
3165
+ widths.current = [];
3166
+ itemEls.current.length = count;
3167
+ setHidden((prev) => prev === NONE ? prev : NONE);
3168
+ }, [count]);
3169
+ React23__namespace.useLayoutEffect(() => {
3170
+ fit();
3171
+ if (!enabled || typeof ResizeObserver === "undefined") return;
3172
+ const observer = new ResizeObserver(() => fit());
3173
+ if (containerEl.current) observer.observe(containerEl.current);
3174
+ for (const item of itemEls.current) if (item) observer.observe(item);
3175
+ return () => observer.disconnect();
3176
+ }, [fit, enabled, hidden]);
3177
+ const containerRef = React23__namespace.useCallback((el) => {
3178
+ containerEl.current = el;
3179
+ }, []);
3180
+ const itemRef = React23__namespace.useCallback((index) => {
3181
+ let fn = itemRefs.current[index];
3182
+ if (!fn) {
3183
+ fn = (el) => {
3184
+ itemEls.current[index] = el;
3185
+ };
3186
+ itemRefs.current[index] = fn;
3187
+ }
3188
+ return fn;
3189
+ }, []);
3190
+ const isHidden = React23__namespace.useCallback(
3191
+ (index) => hidden.includes(index),
3192
+ [hidden]
3193
+ );
3194
+ return { containerRef, itemRef, hiddenIndices: hidden, isHidden };
3195
+ }
3196
+ var VARIANT = {
3197
+ /** The capsule: a filled, ringed chip. Toolbars, rails, header actions. */
3198
+ nav: {
3199
+ item: "rounded-control ring-1 ring-transparent",
3200
+ hover: "hover:bg-primary/10 hover:text-primary hover:ring-primary/25",
3201
+ open: "data-[state=open]:bg-primary/15 data-[state=open]:text-primary data-[state=open]:ring-primary/25",
3202
+ active: "bg-primary/15 text-primary ring-primary/25",
3203
+ strip: ""
3204
+ },
3205
+ /** The panel tab: accented fill with a rule under it, merging into the body. */
3206
+ underline: {
3207
+ item: "h-full rounded-none px-3 py-2",
3208
+ hover: "hover:text-foreground",
3209
+ open: "data-[state=open]:text-foreground",
3210
+ active: "bg-primary/10 text-primary border-b-2 border-primary mb-[-1px]",
3211
+ strip: "items-stretch"
3212
+ },
3213
+ /**
3214
+ * The workbook tab: boxed on top / left / right with an *open bottom*, so it
3215
+ * punches through the strip's own rule — the classic folder-tab notch.
3216
+ */
3217
+ folder: {
3218
+ item: "h-full rounded-none px-3 py-2 gap-1.5",
3219
+ hover: "hover:text-foreground",
3220
+ open: "data-[state=open]:text-foreground",
3221
+ active: "mb-[-1px] rounded-t-md border border-b-0 border-primary text-primary",
3222
+ strip: "items-stretch"
3223
+ }
3224
+ };
3225
+ var keyOf = (item) => item.key ?? item.name;
3118
3226
  var NavItems = ({
3119
3227
  items,
3120
3228
  orientation = "horizontal",
3121
3229
  tooltipSide = orientation === "vertical" ? "right" : "bottom",
3122
- iconClassName = orientation === "vertical" ? "w-5 h-5" : "w-4 h-4 flex-shrink-0"
3230
+ iconClassName = orientation === "vertical" ? "w-5 h-5" : "w-4 h-4 flex-shrink-0",
3231
+ variant = "nav",
3232
+ activeKey,
3233
+ onActiveChange,
3234
+ selectionMode = "none",
3235
+ panelId,
3236
+ overflow = false,
3237
+ overflowLabel = "More",
3238
+ className
3123
3239
  }) => {
3124
3240
  const isVertical = orientation === "vertical";
3125
- const [activeItem, setActiveItem] = React23__namespace.default.useState(null);
3126
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: items.map((item) => {
3127
- const isActive = activeItem === item.name;
3128
- const padding = item.label ? "px-3 py-1.5" : "px-2 py-2";
3241
+ const isTabs = selectionMode === "tabs";
3242
+ const V = VARIANT[variant];
3243
+ const [internalActive, setInternalActive] = React23__namespace.default.useState(
3244
+ null
3245
+ );
3246
+ const isControlled = activeKey !== void 0;
3247
+ const currentKey = isControlled ? activeKey : internalActive;
3248
+ const activeIndex = items.findIndex((item) => keyOf(item) === currentKey);
3249
+ const nodes = React23__namespace.default.useRef({});
3250
+ const pendingFocus = React23__namespace.default.useRef(null);
3251
+ React23__namespace.default.useEffect(() => {
3252
+ const key = pendingFocus.current;
3253
+ if (!key) return;
3254
+ const node = nodes.current[key];
3255
+ if (!node) return;
3256
+ pendingFocus.current = null;
3257
+ node.focus();
3258
+ });
3259
+ const { containerRef, itemRef, hiddenIndices, isHidden } = useOverflowItems({
3260
+ count: items.length,
3261
+ enabled: overflow && !isVertical,
3262
+ pinnedIndex: activeIndex >= 0 ? activeIndex : void 0
3263
+ });
3264
+ const select = React23__namespace.default.useCallback(
3265
+ (item) => {
3266
+ if (item.disabled) return;
3267
+ const key = keyOf(item);
3268
+ item.onClick?.();
3269
+ if (!isControlled) {
3270
+ setInternalActive((prev) => isTabs ? key : prev === key ? null : key);
3271
+ }
3272
+ onActiveChange?.(key);
3273
+ },
3274
+ [isControlled, isTabs, onActiveChange]
3275
+ );
3276
+ const step = (from, delta) => {
3277
+ if (items.length === 0) return -1;
3278
+ let i = from < 0 ? delta > 0 ? -1 : 0 : from;
3279
+ for (let n = 0; n < items.length; n++) {
3280
+ i = (i + delta + items.length) % items.length;
3281
+ if (!items[i]?.disabled) return i;
3282
+ }
3283
+ return -1;
3284
+ };
3285
+ const edge = (delta) => {
3286
+ const start = delta > 0 ? -1 : items.length;
3287
+ return step(start, delta);
3288
+ };
3289
+ const handleKeyDown = (event) => {
3290
+ if (!isTabs) return;
3291
+ const next = isVertical ? "ArrowDown" : "ArrowRight";
3292
+ const prev = isVertical ? "ArrowUp" : "ArrowLeft";
3293
+ let target = -1;
3294
+ if (event.key === next) target = step(activeIndex, 1);
3295
+ else if (event.key === prev) target = step(activeIndex, -1);
3296
+ else if (event.key === "Home") target = edge(1);
3297
+ else if (event.key === "End") target = edge(-1);
3298
+ else return;
3299
+ const item = items[target];
3300
+ if (!item) return;
3301
+ event.preventDefault();
3302
+ pendingFocus.current = keyOf(item);
3303
+ select(item);
3304
+ };
3305
+ const renderItem = (item, index) => {
3306
+ const key = keyOf(item);
3307
+ const isActive = key === currentKey;
3129
3308
  const hasMenu = !item.href && Boolean(item.menuItems?.length);
3130
- const isInteractive = Boolean(item.href || item.onClick || hasMenu);
3131
- const itemClass = `relative inline-flex border-0 items-center justify-center gap-2
3132
- whitespace-nowrap rounded-control transition-colors
3133
- ring-1 ring-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring
3134
- ${padding}
3135
- ${isInteractive ? "cursor-pointer hover:bg-primary/10 hover:text-primary hover:ring-primary/25" : ""}
3136
- ${hasMenu ? "data-[state=open]:bg-primary/15 data-[state=open]:text-primary data-[state=open]:ring-primary/25" : ""}
3137
- ${isActive ? `bg-primary/15 text-primary ring-primary/25 ${item.activeClass || ""}` : ""}
3138
- ${item.className || ""}`;
3309
+ const asCaret = hasMenu && item.menuTrigger === "caret";
3310
+ const isInteractive = Boolean(
3311
+ item.href || item.onClick || hasMenu || isTabs
3312
+ );
3313
+ const padding = variant === "nav" ? item.label ? "px-3 py-1.5" : "px-2 py-2" : "";
3314
+ const itemClass = cn(
3315
+ `relative inline-flex border-0 items-center justify-center gap-2
3316
+ whitespace-nowrap transition-colors
3317
+ ring-1 ring-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring`,
3318
+ V.item,
3319
+ padding,
3320
+ isInteractive && !item.disabled && `cursor-pointer ${V.hover}`,
3321
+ hasMenu && !asCaret && V.open,
3322
+ item.disabled && "pointer-events-none opacity-50",
3323
+ isActive && cn(V.active, item.activeClass),
3324
+ item.className
3325
+ );
3139
3326
  const icon = item.icon && /* @__PURE__ */ jsxRuntime.jsx(
3140
3327
  item.icon,
3141
3328
  {
@@ -3143,41 +3330,79 @@ var NavItems = ({
3143
3330
  className: item.iconClassName || iconClassName
3144
3331
  }
3145
3332
  );
3146
- const label = item.label && /* @__PURE__ */ jsxRuntime.jsx("span", { children: item.label });
3333
+ const label = item.label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: item.labelClassName, children: item.label });
3147
3334
  const badge = item.badge != null && /* @__PURE__ */ jsxRuntime.jsx(
3148
3335
  "span",
3149
3336
  {
3150
- className: "pointer-events-none absolute -right-0.5 -top-0.5 inline-flex h-3.5\n min-w-3.5 items-center justify-center rounded-full bg-primary px-1\n text-[9px] font-semibold leading-none text-primary-foreground",
3337
+ className: "pointer-events-none absolute -right-0.5 -top-0.5 inline-flex h-3.5\n min-w-3.5 items-center justify-center rounded-full bg-primary px-1\n text-[9px] font-semibold leading-none text-primary-foreground",
3151
3338
  children: item.badge
3152
3339
  }
3153
3340
  );
3341
+ const tabProps = isTabs ? {
3342
+ role: "tab",
3343
+ "aria-selected": isActive,
3344
+ "aria-controls": panelId?.(key),
3345
+ tabIndex: isActive || activeIndex < 0 && index === 0 ? 0 : -1
3346
+ } : {};
3347
+ const setNode = (el) => {
3348
+ nodes.current[key] = el;
3349
+ itemRef(index)(el);
3350
+ };
3351
+ const caret = asCaret && /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
3352
+ "span",
3353
+ {
3354
+ role: "button",
3355
+ tabIndex: -1,
3356
+ "aria-label": `${item.name} menu`,
3357
+ onClick: (e) => e.stopPropagation(),
3358
+ className: "ml-0.5 grid size-4 shrink-0 cursor-pointer place-items-center\n rounded-control text-muted-foreground hover:bg-accent hover:text-foreground",
3359
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-3" })
3360
+ }
3361
+ ) });
3154
3362
  const inner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3155
3363
  icon,
3156
3364
  label,
3365
+ caret,
3157
3366
  badge
3158
3367
  ] });
3159
- const control = item.href ? /* @__PURE__ */ jsxRuntime.jsx(
3368
+ const control = asCaret ? /* @__PURE__ */ jsxRuntime.jsx(
3369
+ "div",
3370
+ {
3371
+ ref: setNode,
3372
+ ...tabProps,
3373
+ style: item.style,
3374
+ onClick: () => select(item),
3375
+ className: itemClass,
3376
+ children: inner
3377
+ }
3378
+ ) : item.href ? /* @__PURE__ */ jsxRuntime.jsx(
3160
3379
  "a",
3161
3380
  {
3381
+ ref: setNode,
3162
3382
  href: item.href,
3163
- onClick: () => setActiveItem(item.name),
3383
+ style: item.style,
3384
+ onClick: () => select(item),
3164
3385
  className: itemClass,
3165
3386
  children: inner
3166
3387
  }
3167
- ) : item.onClick || hasMenu ? /* @__PURE__ */ jsxRuntime.jsx(
3388
+ ) : item.onClick || hasMenu || isTabs ? /* @__PURE__ */ jsxRuntime.jsx(
3168
3389
  "button",
3169
3390
  {
3391
+ ref: setNode,
3170
3392
  type: "button",
3393
+ disabled: item.disabled,
3394
+ ...tabProps,
3395
+ style: item.style,
3171
3396
  onClick: () => {
3172
- item.onClick?.();
3173
- if (!hasMenu) setActiveItem(isActive ? null : item.name);
3397
+ if (hasMenu) item.onClick?.();
3398
+ else select(item);
3174
3399
  },
3175
3400
  className: itemClass,
3176
3401
  children: inner
3177
3402
  }
3178
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: itemClass, children: inner });
3403
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { ref: setNode, style: item.style, className: itemClass, children: inner });
3179
3404
  const withTooltip = /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
3180
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: hasMenu ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { asChild: true, children: control }) : control }),
3405
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: hasMenu && !asCaret ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { asChild: true, children: control }) : control }),
3181
3406
  /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: item.tooltipSide || tooltipSide, children: item.tooltip || item.name })
3182
3407
  ] });
3183
3408
  return /* @__PURE__ */ jsxRuntime.jsxs(React23__namespace.default.Fragment, { children: [
@@ -3188,28 +3413,7 @@ var NavItems = ({
3188
3413
  {
3189
3414
  side: isVertical ? "right" : "bottom",
3190
3415
  align: isVertical ? "start" : "end",
3191
- children: item.menuItems?.map((menuItem) => {
3192
- const MenuIcon = menuItem.icon;
3193
- const gutter = item.menuItems?.some((m) => m.icon);
3194
- return /* @__PURE__ */ jsxRuntime.jsxs(React23__namespace.default.Fragment, { children: [
3195
- menuItem.separatorBefore && /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}),
3196
- /* @__PURE__ */ jsxRuntime.jsxs(
3197
- DropdownMenuItem,
3198
- {
3199
- disabled: menuItem.disabled,
3200
- onSelect: () => menuItem.onSelect?.(),
3201
- className: cn(
3202
- menuItem.destructive && "text-destructive focus:bg-destructive/15 focus:text-destructive hover:bg-destructive/10 hover:text-destructive"
3203
- ),
3204
- children: [
3205
- MenuIcon ? /* @__PURE__ */ jsxRuntime.jsx(MenuIcon, {}) : gutter ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "size-4 shrink-0" }) : null,
3206
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: menuItem.label }),
3207
- menuItem.shortcut && /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuShortcut, { children: menuItem.shortcut })
3208
- ]
3209
- }
3210
- )
3211
- ] }, menuItem.id);
3212
- })
3416
+ children: renderMenuRows(item.menuItems)
3213
3417
  }
3214
3418
  )
3215
3419
  ] }) : withTooltip,
@@ -3221,22 +3425,132 @@ var NavItems = ({
3221
3425
  }
3222
3426
  )
3223
3427
  ] }, item.key || item.name);
3224
- }) });
3428
+ };
3429
+ const rendered = items.map(
3430
+ (item, index) => isHidden(index) ? null : renderItem(item, index)
3431
+ );
3432
+ const overflowTrigger = hiddenIndices.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
3433
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
3434
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
3435
+ "button",
3436
+ {
3437
+ type: "button",
3438
+ "aria-label": overflowLabel,
3439
+ className: cn(
3440
+ `relative inline-flex shrink-0 items-center justify-center border-0
3441
+ transition-colors ring-1 ring-transparent focus-visible:outline-none
3442
+ focus-visible:ring-2 focus-visible:ring-ring cursor-pointer`,
3443
+ V.item,
3444
+ variant === "nav" && "px-2 py-2",
3445
+ V.hover,
3446
+ V.open
3447
+ ),
3448
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: iconClassName })
3449
+ }
3450
+ ) }) }),
3451
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: tooltipSide, children: overflowLabel })
3452
+ ] }),
3453
+ /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuContent, { align: "end", children: hiddenIndices.map((index) => {
3454
+ const item = items[index];
3455
+ if (!item) return null;
3456
+ const Icon = item.icon;
3457
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3458
+ DropdownMenuItem,
3459
+ {
3460
+ disabled: item.disabled,
3461
+ onSelect: () => select(item),
3462
+ children: [
3463
+ Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, {}) : /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "size-4 shrink-0" }),
3464
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: item.label ?? item.name })
3465
+ ]
3466
+ },
3467
+ keyOf(item)
3468
+ );
3469
+ }) })
3470
+ ] });
3471
+ if (!isTabs && !overflow) {
3472
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 0, children: rendered });
3473
+ }
3474
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxRuntime.jsxs(
3475
+ "div",
3476
+ {
3477
+ ref: containerRef,
3478
+ role: isTabs ? "tablist" : void 0,
3479
+ "aria-orientation": isTabs ? orientation : void 0,
3480
+ onKeyDown: handleKeyDown,
3481
+ className: cn(
3482
+ "flex min-w-0",
3483
+ isVertical ? "flex-col items-center gap-1" : "items-center gap-1",
3484
+ V.strip,
3485
+ className
3486
+ ),
3487
+ children: [
3488
+ rendered,
3489
+ overflowTrigger
3490
+ ]
3491
+ }
3492
+ ) });
3225
3493
  };
3226
- var NavBase = ({ className = "", orientation, sections }) => {
3494
+ function renderMenuRows(menuItems) {
3495
+ const gutter = menuItems?.some((m) => m.icon);
3496
+ return menuItems?.map((menuItem) => {
3497
+ const MenuIcon = menuItem.icon;
3498
+ return /* @__PURE__ */ jsxRuntime.jsxs(React23__namespace.default.Fragment, { children: [
3499
+ menuItem.separatorBefore && /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}),
3500
+ /* @__PURE__ */ jsxRuntime.jsxs(
3501
+ DropdownMenuItem,
3502
+ {
3503
+ disabled: menuItem.disabled,
3504
+ onSelect: () => menuItem.onSelect?.(),
3505
+ className: cn(
3506
+ menuItem.destructive && "text-destructive focus:bg-destructive/15 focus:text-destructive hover:bg-destructive/10 hover:text-destructive"
3507
+ ),
3508
+ children: [
3509
+ MenuIcon ? /* @__PURE__ */ jsxRuntime.jsx(MenuIcon, {}) : gutter ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "size-4 shrink-0" }) : null,
3510
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: menuItem.label }),
3511
+ menuItem.shortcut && /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuShortcut, { children: menuItem.shortcut })
3512
+ ]
3513
+ }
3514
+ )
3515
+ ] }, menuItem.id);
3516
+ });
3517
+ }
3518
+ var NavBase = ({
3519
+ className = "",
3520
+ orientation,
3521
+ sections
3522
+ }) => {
3227
3523
  const isVertical = orientation === "vertical";
3228
3524
  const containerClass = isVertical ? `flex flex-col items-center h-full ${className}` : `flex items-center w-full ${className}`;
3229
3525
  const sectionWrapperClass = isVertical ? "flex flex-col items-center gap-1" : "flex items-center gap-1 ";
3230
3526
  return /* @__PURE__ */ jsxRuntime.jsxs("nav", { className: containerClass, children: [
3231
- sections.start?.content && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${sectionWrapperClass} ${sections.start.className || ""}`, children: sections.start.content }),
3232
- sections.center?.content ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-1 ${isVertical ? "" : "flex justify-center items-center gap-1"} ${sections.center.className || ""}`, children: sections.center.content }) : (
3527
+ sections.start?.content && /* @__PURE__ */ jsxRuntime.jsx(
3528
+ "div",
3529
+ {
3530
+ className: `${sectionWrapperClass} ${sections.start.className || ""}`,
3531
+ children: sections.start.content
3532
+ }
3533
+ ),
3534
+ sections.center?.content ? /* @__PURE__ */ jsxRuntime.jsx(
3535
+ "div",
3536
+ {
3537
+ className: `flex-1 ${isVertical ? "" : "flex justify-center items-center gap-1"} ${sections.center.className || ""}`,
3538
+ children: sections.center.content
3539
+ }
3540
+ ) : (
3233
3541
  // Empty spacer to push end section to the bottom/right
3234
3542
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" })
3235
3543
  ),
3236
- sections.end?.content && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${sectionWrapperClass} ${isVertical ? "" : "ml-auto"} ${sections.end.className || ""}`, children: sections.end.content })
3544
+ sections.end?.content && /* @__PURE__ */ jsxRuntime.jsx(
3545
+ "div",
3546
+ {
3547
+ className: `${sectionWrapperClass} ${isVertical ? "" : "ml-auto"} ${sections.end.className || ""}`,
3548
+ children: sections.end.content
3549
+ }
3550
+ )
3237
3551
  ] });
3238
3552
  };
3239
- var NavHorizontalItems = ({ items }) => /* @__PURE__ */ jsxRuntime.jsx(NavItems, { items, orientation: "horizontal" });
3553
+ var NavHorizontalItems = (props) => /* @__PURE__ */ jsxRuntime.jsx(NavItems, { ...props, orientation: "horizontal" });
3240
3554
  var NavHorizontal = ({
3241
3555
  left,
3242
3556
  leftNavItems,
@@ -4270,7 +4584,7 @@ var MetricGrid = React23__namespace.forwardRef(
4270
4584
  )
4271
4585
  );
4272
4586
  MetricGrid.displayName = "MetricGrid";
4273
- var NavVerticalItems = ({ items }) => /* @__PURE__ */ jsxRuntime.jsx(NavItems, { items, orientation: "vertical" });
4587
+ var NavVerticalItems = (props) => /* @__PURE__ */ jsxRuntime.jsx(NavItems, { ...props, orientation: "vertical" });
4274
4588
  var NavVertical = ({
4275
4589
  className = "",
4276
4590
  top,
@@ -4975,6 +5289,9 @@ function TabbedPanel({
4975
5289
  activeTab,
4976
5290
  onTabChange,
4977
5291
  headerActions,
5292
+ overflow = false,
5293
+ overflowLabel = "More panels",
5294
+ keepMounted = false,
4978
5295
  className,
4979
5296
  headerClassName,
4980
5297
  bodyClassName,
@@ -4989,34 +5306,64 @@ function TabbedPanel({
4989
5306
  }
4990
5307
  onTabChange?.(value);
4991
5308
  };
4992
- return /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxRuntime.jsx(Tabs, { value: currentTab, onValueChange: handleTabChange, className: "h-full", children: /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: cn("h-full border rounded-none", className), children: [
4993
- /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: `flex flex-row items-center justify-between py-0 border-b h-[30px] px-0 space-y-0 ${headerClassName || ""}`, children: [
4994
- /* @__PURE__ */ jsxRuntime.jsx(TabsList, { className: "h-full bg-transparent p-0 gap-0 rounded-none", children: tabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsxs(
4995
- TabsTrigger,
5309
+ const uid = React23__namespace.default.useId();
5310
+ const panelId = (value) => `${uid}-panel-${value}`;
5311
+ const items = React23__namespace.default.useMemo(
5312
+ () => tabs.map((tab) => ({
5313
+ key: tab.value,
5314
+ name: tab.name ?? (typeof tab.label === "string" ? tab.label : tab.value),
5315
+ label: tab.label,
5316
+ icon: tab.icon,
5317
+ disabled: tab.disabled
5318
+ })),
5319
+ [tabs]
5320
+ );
5321
+ return /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: cn("flex h-full min-h-0 flex-col border rounded-none", className), children: [
5322
+ /* @__PURE__ */ jsxRuntime.jsxs(
5323
+ "div",
5324
+ {
5325
+ className: cn(
5326
+ "flex h-[30px] shrink-0 flex-row items-stretch border-b",
5327
+ headerClassName
5328
+ ),
5329
+ children: [
5330
+ /* @__PURE__ */ jsxRuntime.jsx(
5331
+ NavItems,
5332
+ {
5333
+ items,
5334
+ variant: "underline",
5335
+ selectionMode: "tabs",
5336
+ activeKey: currentTab,
5337
+ onActiveChange: handleTabChange,
5338
+ panelId,
5339
+ overflow,
5340
+ overflowLabel,
5341
+ className: "min-w-0 flex-1 gap-0",
5342
+ iconClassName: "h-3.5 w-3.5 shrink-0"
5343
+ }
5344
+ ),
5345
+ headerActions && headerActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex h-full shrink-0 items-center gap-1 pr-1", children: /* @__PURE__ */ jsxRuntime.jsx(NavHorizontalItems, { items: headerActions }) })
5346
+ ]
5347
+ }
5348
+ ),
5349
+ tabs.map((tab) => {
5350
+ const active = tab.value === currentTab;
5351
+ if (!keepMounted && !active) return null;
5352
+ return /* @__PURE__ */ jsxRuntime.jsx(
5353
+ "div",
4996
5354
  {
4997
- value: tab.value,
4998
- disabled: tab.disabled,
4999
- className: "h-full text-muted-foreground hover:text-foreground data-[state=active]:bg-primary/10 data-[state=active]:text-primary data-[state=active]:border-b-2 data-[state=active]:border-primary data-[state=active]:mb-[-1px] rounded-none px-3 py-2",
5000
- children: [
5001
- tab.icon && /* @__PURE__ */ jsxRuntime.jsx(tab.icon, { className: "h-3.5 w-3.5 mr-1.5" }),
5002
- tab.label
5003
- ]
5355
+ id: panelId(tab.value),
5356
+ role: "tabpanel",
5357
+ "aria-label": tab.name ?? (typeof tab.label === "string" ? tab.label : tab.value),
5358
+ hidden: !active,
5359
+ className: cn("m-0 min-h-0 flex-1 overflow-y-auto", bodyClassName),
5360
+ children: tab.content
5004
5361
  },
5005
5362
  tab.value
5006
- )) }),
5007
- headerActions && headerActions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex h-full shrink-0 items-center gap-1 pr-1", children: /* @__PURE__ */ jsxRuntime.jsx(NavHorizontalItems, { items: headerActions }) })
5008
- ] }),
5009
- tabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(
5010
- TabsContent,
5011
- {
5012
- value: tab.value,
5013
- className: `h-[calc(100%-30px)] m-0 ${bodyClassName || ""}`,
5014
- children: /* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "overflow-y-auto h-full p-0", children: tab.content })
5015
- },
5016
- tab.value
5017
- )),
5018
- footerContent && /* @__PURE__ */ jsxRuntime.jsx(CardFooter, { className: footerClassName, children: footerContent })
5019
- ] }) }) }) });
5363
+ );
5364
+ }),
5365
+ footerContent && /* @__PURE__ */ jsxRuntime.jsx(CardFooter, { className: cn("shrink-0", footerClassName), children: footerContent })
5366
+ ] }) }) });
5020
5367
  }
5021
5368
  var TemplatePicker = React23__namespace.forwardRef(({ heading, options, value, onSelect, footnote, className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
5022
5369
  "div",
@@ -5128,27 +5475,93 @@ var TerminalLine = React23__namespace.forwardRef(
5128
5475
  )
5129
5476
  );
5130
5477
  TerminalLine.displayName = "TerminalLine";
5131
- var TimelineList = React23__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("ol", { ref, className: cn("flex flex-col", className), ...props, children }));
5478
+ var TimelineVariantContext = React23__namespace.createContext("columns");
5479
+ var RAIL_MARKER_OFFSET = "h-[0.692rem]";
5480
+ var RAIL_FOOTER_TAIL = "h-[1.067rem]";
5481
+ var TimelineList = React23__namespace.forwardRef(({ className, variant = "columns", children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(TimelineVariantContext.Provider, { value: variant, children: /* @__PURE__ */ jsxRuntime.jsx("ol", { ref, className: cn("flex flex-col", className), ...props, children }) }));
5132
5482
  TimelineList.displayName = "TimelineList";
5133
- var TimelineEntry = React23__namespace.forwardRef(({ when, title, marker, className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
5134
- "li",
5135
- {
5136
- ref,
5137
- className: cn("flex gap-2 border-b border-border py-1.5 last:border-b-0", className),
5138
- ...props,
5139
- children: [
5140
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex w-[72px] shrink-0 items-baseline gap-1.5 text-meta text-muted-foreground", children: [
5141
- marker ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "translate-y-1", children: marker }) : null,
5142
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: when })
5143
- ] }),
5144
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
5145
- title != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: title }) : null,
5146
- children
5147
- ] })
5148
- ]
5483
+ function RailGutter({ marker }) {
5484
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex w-2.5 shrink-0 flex-col items-center", children: [
5485
+ /* @__PURE__ */ jsxRuntime.jsx(
5486
+ "span",
5487
+ {
5488
+ "aria-hidden": true,
5489
+ className: cn(
5490
+ "w-px shrink-0 bg-border group-first/entry:bg-transparent",
5491
+ RAIL_MARKER_OFFSET
5492
+ )
5493
+ }
5494
+ ),
5495
+ marker,
5496
+ /* @__PURE__ */ jsxRuntime.jsx(
5497
+ "span",
5498
+ {
5499
+ "aria-hidden": true,
5500
+ className: "w-px flex-1 bg-border group-last/entry:bg-transparent"
5501
+ }
5502
+ )
5503
+ ] });
5504
+ }
5505
+ var TimelineEntry = React23__namespace.forwardRef(({ when, title, marker, className, children, ...props }, ref) => {
5506
+ const variant = React23__namespace.useContext(TimelineVariantContext);
5507
+ if (variant === "rail") {
5508
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5509
+ "li",
5510
+ {
5511
+ ref,
5512
+ className: cn("group/entry flex gap-2.5", className),
5513
+ ...props,
5514
+ children: [
5515
+ /* @__PURE__ */ jsxRuntime.jsx(RailGutter, { marker }),
5516
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 pb-4 group-last/entry:pb-0", children: [
5517
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-meta text-muted-foreground", children: when }),
5518
+ title != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: title }) : null,
5519
+ children
5520
+ ] })
5521
+ ]
5522
+ }
5523
+ );
5149
5524
  }
5150
- ));
5525
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5526
+ "li",
5527
+ {
5528
+ ref,
5529
+ className: cn("flex gap-2 border-b border-border py-1.5 last:border-b-0", className),
5530
+ ...props,
5531
+ children: [
5532
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex w-[72px] shrink-0 items-baseline gap-1.5 text-meta text-muted-foreground", children: [
5533
+ marker ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "translate-y-1", children: marker }) : null,
5534
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: when })
5535
+ ] }),
5536
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
5537
+ title != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: title }) : null,
5538
+ children
5539
+ ] })
5540
+ ]
5541
+ }
5542
+ );
5543
+ });
5151
5544
  TimelineEntry.displayName = "TimelineEntry";
5545
+ var TimelineFooter = React23__namespace.forwardRef(({ className, children, ...props }, ref) => {
5546
+ const variant = React23__namespace.useContext(TimelineVariantContext);
5547
+ if (variant === "rail") {
5548
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5549
+ "li",
5550
+ {
5551
+ ref,
5552
+ role: "presentation",
5553
+ className: cn("flex gap-2.5", className),
5554
+ ...props,
5555
+ children: [
5556
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex w-2.5 shrink-0 justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: cn("w-px bg-border", RAIL_FOOTER_TAIL) }) }),
5557
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1 pt-1.5", children })
5558
+ ]
5559
+ }
5560
+ );
5561
+ }
5562
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { ref, role: "presentation", className: cn("pt-1.5", className), ...props, children });
5563
+ });
5564
+ TimelineFooter.displayName = "TimelineFooter";
5152
5565
  var Toolbar = () => {
5153
5566
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-5 items-center space-x-2", children: [
5154
5567
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -5984,6 +6397,7 @@ exports.TemplatePicker = TemplatePicker;
5984
6397
  exports.Terminal = Terminal;
5985
6398
  exports.TerminalLine = TerminalLine;
5986
6399
  exports.TimelineEntry = TimelineEntry;
6400
+ exports.TimelineFooter = TimelineFooter;
5987
6401
  exports.TimelineList = TimelineList;
5988
6402
  exports.Toaster = Toaster;
5989
6403
  exports.Toggle = Toggle;
@@ -6023,6 +6437,7 @@ exports.cn = cn;
6023
6437
  exports.navigationMenuTriggerStyle = navigationMenuTriggerStyle;
6024
6438
  exports.statusDotVariants = statusDotVariants;
6025
6439
  exports.toggleVariants = toggleVariants;
6440
+ exports.useOverflowItems = useOverflowItems;
6026
6441
  exports.useSidebar = useSidebar;
6027
6442
  exports.useTour = useTour;
6028
6443
  //# sourceMappingURL=index.cjs.map