@opencosmos/ui 1.3.3 → 1.3.5

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.d.mts CHANGED
@@ -2441,8 +2441,10 @@ interface AppSidebarProviderProps {
2441
2441
  children: React__default.ReactNode;
2442
2442
  /** Initial open state used on server and first render @default true */
2443
2443
  defaultOpen?: boolean;
2444
+ /** localStorage key for persisting open state. Use unique keys per page to avoid cross-page state bleed. @default 'appsidebar:state' */
2445
+ storageKey?: string;
2444
2446
  }
2445
- declare function AppSidebarProvider({ children, defaultOpen }: AppSidebarProviderProps): react_jsx_runtime.JSX.Element;
2447
+ declare function AppSidebarProvider({ children, defaultOpen, storageKey }: AppSidebarProviderProps): react_jsx_runtime.JSX.Element;
2446
2448
  declare function AppSidebarInset({ children, className, }: {
2447
2449
  children: React__default.ReactNode;
2448
2450
  className?: string;
@@ -2459,16 +2461,18 @@ interface AppSidebarProps {
2459
2461
  logo?: React__default.ReactNode;
2460
2462
  /** Wordmark shown next to the logo when expanded */
2461
2463
  title?: string;
2462
- /** Navigation items */
2464
+ /** Navigation items rendered at the top (below the header) */
2463
2465
  items?: AppSidebarNavItem[];
2464
- /** Body slot rendered in the scrollable mid-section (e.g. conversation history). Only visible when expanded. */
2466
+ /** Navigation items rendered at the bottom (above the footer) */
2467
+ bottomItems?: AppSidebarNavItem[];
2468
+ /** Body slot — rendered in the flex-1 mid-section (e.g. conversation history). Only visible when expanded. */
2465
2469
  children?: React__default.ReactNode;
2466
2470
  /** Footer slot — auth section, user avatar, sign-in prompt, etc. */
2467
2471
  footer?: React__default.ReactNode;
2468
2472
  /** Additional className for the <aside> */
2469
2473
  className?: string;
2470
2474
  }
2471
- declare function AppSidebar({ logo, title, items, children, footer, className, }: AppSidebarProps): react_jsx_runtime.JSX.Element;
2475
+ declare function AppSidebar({ logo, title, items, bottomItems, children, footer, className, }: AppSidebarProps): react_jsx_runtime.JSX.Element;
2472
2476
 
2473
2477
  interface StackProps extends React__default.HTMLAttributes<HTMLDivElement> {
2474
2478
  /**
package/dist/index.d.ts CHANGED
@@ -2441,8 +2441,10 @@ interface AppSidebarProviderProps {
2441
2441
  children: React__default.ReactNode;
2442
2442
  /** Initial open state used on server and first render @default true */
2443
2443
  defaultOpen?: boolean;
2444
+ /** localStorage key for persisting open state. Use unique keys per page to avoid cross-page state bleed. @default 'appsidebar:state' */
2445
+ storageKey?: string;
2444
2446
  }
2445
- declare function AppSidebarProvider({ children, defaultOpen }: AppSidebarProviderProps): react_jsx_runtime.JSX.Element;
2447
+ declare function AppSidebarProvider({ children, defaultOpen, storageKey }: AppSidebarProviderProps): react_jsx_runtime.JSX.Element;
2446
2448
  declare function AppSidebarInset({ children, className, }: {
2447
2449
  children: React__default.ReactNode;
2448
2450
  className?: string;
@@ -2459,16 +2461,18 @@ interface AppSidebarProps {
2459
2461
  logo?: React__default.ReactNode;
2460
2462
  /** Wordmark shown next to the logo when expanded */
2461
2463
  title?: string;
2462
- /** Navigation items */
2464
+ /** Navigation items rendered at the top (below the header) */
2463
2465
  items?: AppSidebarNavItem[];
2464
- /** Body slot rendered in the scrollable mid-section (e.g. conversation history). Only visible when expanded. */
2466
+ /** Navigation items rendered at the bottom (above the footer) */
2467
+ bottomItems?: AppSidebarNavItem[];
2468
+ /** Body slot — rendered in the flex-1 mid-section (e.g. conversation history). Only visible when expanded. */
2465
2469
  children?: React__default.ReactNode;
2466
2470
  /** Footer slot — auth section, user avatar, sign-in prompt, etc. */
2467
2471
  footer?: React__default.ReactNode;
2468
2472
  /** Additional className for the <aside> */
2469
2473
  className?: string;
2470
2474
  }
2471
- declare function AppSidebar({ logo, title, items, children, footer, className, }: AppSidebarProps): react_jsx_runtime.JSX.Element;
2475
+ declare function AppSidebar({ logo, title, items, bottomItems, children, footer, className, }: AppSidebarProps): react_jsx_runtime.JSX.Element;
2472
2476
 
2473
2477
  interface StackProps extends React__default.HTMLAttributes<HTMLDivElement> {
2474
2478
  /**
package/dist/index.js CHANGED
@@ -11073,13 +11073,13 @@ var DEFAULT_CONTEXT = {
11073
11073
  function useAppSidebar() {
11074
11074
  return (0, import_react19.useContext)(AppSidebarContext) ?? DEFAULT_CONTEXT;
11075
11075
  }
11076
- function AppSidebarProvider({ children, defaultOpen = true }) {
11076
+ function AppSidebarProvider({ children, defaultOpen = true, storageKey = STORAGE_KEY }) {
11077
11077
  const [isOpen, setIsOpen] = (0, import_react19.useState)(defaultOpen);
11078
11078
  (0, import_react19.useEffect)(() => {
11079
- const stored = localStorage.getItem(STORAGE_KEY);
11079
+ const stored = localStorage.getItem(storageKey);
11080
11080
  if (stored !== null) setIsOpen(stored === "true");
11081
- }, []);
11082
- const persist3 = (value) => localStorage.setItem(STORAGE_KEY, String(value));
11081
+ }, [storageKey]);
11082
+ const persist3 = (value) => localStorage.setItem(storageKey, String(value));
11083
11083
  const toggle = () => setIsOpen((prev) => {
11084
11084
  const next = !prev;
11085
11085
  persist3(next);
@@ -11118,6 +11118,7 @@ function AppSidebar({
11118
11118
  logo,
11119
11119
  title,
11120
11120
  items = [],
11121
+ bottomItems = [],
11121
11122
  children,
11122
11123
  footer,
11123
11124
  className
@@ -11232,6 +11233,40 @@ function AppSidebar({
11232
11233
  children
11233
11234
  }
11234
11235
  ),
11236
+ bottomItems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("nav", { className: "px-2 py-2 space-y-1 shrink-0 border-t border-foreground/8", "aria-label": "Bottom navigation", children: bottomItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(
11237
+ "a",
11238
+ {
11239
+ href: item.href,
11240
+ target: item.external ? "_blank" : void 0,
11241
+ rel: item.external ? "noopener noreferrer" : void 0,
11242
+ title: !isOpen ? item.label : void 0,
11243
+ "aria-label": !isOpen ? item.label : void 0,
11244
+ className: cn(
11245
+ "flex items-center rounded-lg transition-colors duration-150",
11246
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus)]",
11247
+ isOpen ? "gap-3 px-3 py-3" : "justify-center w-9 h-9 mx-auto",
11248
+ item.active ? "bg-foreground/8 text-foreground font-medium" : "text-[var(--color-text-secondary)] hover:bg-foreground/5 hover:text-[var(--color-text-primary)]"
11249
+ ),
11250
+ children: [
11251
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "shrink-0 flex items-center justify-center w-4 h-4", children: item.icon }),
11252
+ /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
11253
+ "span",
11254
+ {
11255
+ className: "text-sm whitespace-nowrap",
11256
+ style: {
11257
+ opacity: isOpen ? 1 : 0,
11258
+ width: isOpen ? "auto" : 0,
11259
+ overflow: "hidden",
11260
+ pointerEvents: isOpen ? "auto" : "none",
11261
+ transition: shouldAnimate ? `opacity ${Math.round(duration * 0.55)}ms ease-out` : "none"
11262
+ },
11263
+ children: item.label
11264
+ }
11265
+ )
11266
+ ]
11267
+ },
11268
+ item.label
11269
+ )) }),
11235
11270
  footer && /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
11236
11271
  "div",
11237
11272
  {