@misael703/ui 1.17.0 → 1.18.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.
@@ -36,23 +36,18 @@ var NavItemNode = React.memo(function NavItemNode2({
36
36
  item.children && item.children.length > 0 && /* @__PURE__ */ jsx("ul", { className: "appshell__navchildren", children: item.children.map((c) => /* @__PURE__ */ jsx(NavItemNode2, { item: c, depth: depth + 1, linkAs, onCloseMobile }, c.id)) })
37
37
  ] });
38
38
  });
39
- function AppShell({
40
- brand,
41
- brandCollapsed,
42
- sections,
43
- topbar,
44
- footer,
45
- user,
46
- defaultCollapsed = false,
47
- collapsed: ctrlCollapsed,
48
- onCollapsedChange,
49
- children,
50
- className,
51
- theme = "default",
52
- linkAs,
53
- headerLayout = "side",
54
- header
55
- }) {
39
+ function AppShell(props) {
40
+ const {
41
+ sections,
42
+ footer,
43
+ defaultCollapsed = false,
44
+ collapsed: ctrlCollapsed,
45
+ onCollapsedChange,
46
+ children,
47
+ className,
48
+ theme = "default",
49
+ linkAs
50
+ } = props;
56
51
  const [internalCollapsed, setInternalCollapsed] = React.useState(defaultCollapsed);
57
52
  const [mobileOpen, setMobileOpen] = React.useState(false);
58
53
  const t = useLocale();
@@ -62,8 +57,10 @@ function AppShell({
62
57
  onCollapsedChange?.(v);
63
58
  };
64
59
  const closeMobile = React.useCallback(() => setMobileOpen(false), []);
65
- if (headerLayout === "top") {
66
- return /* @__PURE__ */ jsxs("div", { className: cx("appshell", `appshell--${theme}`, "appshell--header-top", collapsed && "is-collapsed", className), children: [
60
+ if (props.headerLayout === "top") {
61
+ const { header } = props;
62
+ const headerTheme = props.headerTheme ?? theme;
63
+ return /* @__PURE__ */ jsxs("div", { className: cx("appshell", `appshell--${theme}`, "appshell--header-top", `appshell--header-${headerTheme}`, collapsed && "is-collapsed", className), children: [
67
64
  /* @__PURE__ */ jsxs("header", { className: "appshell__header", role: "banner", children: [
68
65
  /* @__PURE__ */ jsx("div", { className: "appshell__header-left", children: header?.left }),
69
66
  /* @__PURE__ */ jsx("div", { className: "appshell__header-center", children: header?.center }),
@@ -81,6 +78,7 @@ function AppShell({
81
78
  ] })
82
79
  ] });
83
80
  }
81
+ const { brand, brandCollapsed, topbar, user } = props;
84
82
  return /* @__PURE__ */ jsxs("div", { className: cx("appshell", `appshell--${theme}`, collapsed && "is-collapsed", mobileOpen && "is-mobile-open", className), children: [
85
83
  /* @__PURE__ */ jsxs("aside", { className: "appshell__sidebar", "aria-label": t["appshell.mainNav"], children: [
86
84
  /* @__PURE__ */ jsx("div", { className: "appshell__brand", children: collapsed ? brandCollapsed ?? brand : brand }),
@@ -144,5 +142,5 @@ function PageHeader({ title, description, breadcrumbs, actions, meta, className
144
142
  }
145
143
 
146
144
  export { AppShell, PageHeader };
147
- //# sourceMappingURL=chunk-Y6AYAE4O.mjs.map
148
- //# sourceMappingURL=chunk-Y6AYAE4O.mjs.map
145
+ //# sourceMappingURL=chunk-E462CF6P.mjs.map
146
+ //# sourceMappingURL=chunk-E462CF6P.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/AppShell.tsx"],"names":["NavItemNode"],"mappings":"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","file":"chunk-E462CF6P.mjs","sourcesContent":["'use client';\nimport * as React from 'react';\nimport { cx } from '../utils/cx';\nimport { ChevronLeft, ChevronRight, MenuIcon } from './Icons';\nimport { useLocale } from '../locale/LocaleProvider';\n\n// ---------- AppShell (Sidebar + Topbar + Content) -----------------------\n// Designed to drop into a Next.js app/layout.tsx as a Client Component shell.\n\nexport interface NavItem {\n id: string;\n label: React.ReactNode;\n icon?: React.ReactNode;\n href?: string;\n active?: boolean;\n badge?: React.ReactNode;\n onSelect?: () => void;\n children?: NavItem[];\n}\n\nexport interface NavSection {\n id?: string;\n label?: React.ReactNode;\n items: NavItem[];\n}\n\nexport type AppShellTheme = 'default' | 'brand';\n\nexport type AppShellHeaderLayout = 'side' | 'top';\n\nexport interface AppShellHeader {\n /** Left slot — typically a menu/hamburger trigger or back action. */\n left?: React.ReactNode;\n /** Center slot — typically the brand (Logo). Lands at the true viewport centre. */\n center?: React.ReactNode;\n /** Right slot — notifications, user avatar, utilities. */\n right?: React.ReactNode;\n}\n\n/**\n * Props shared by both layouts. The layout-specific props live in\n * `AppShellSideProps` / `AppShellTopProps`; `AppShellProps` is the\n * discriminated union of the two, keyed on `headerLayout`.\n */\nexport interface AppShellBaseProps {\n sections: NavSection[];\n footer?: React.ReactNode;\n defaultCollapsed?: boolean;\n collapsed?: boolean;\n onCollapsedChange?: (c: boolean) => void;\n children: React.ReactNode;\n className?: string;\n /**\n * Color theme (applies to both layouts):\n * - `default` (light): claro, mejor para apps data-heavy de uso prolongado.\n * - `brand`: superficie azul de marca con texto blanco. Mayor brand recall.\n * En `side` tiñe el sidebar; en `top` tiñe header + sidebar (un solo knob).\n */\n theme?: AppShellTheme;\n /** Render-prop for navigation links so the host app can use Next.js Link, etc. */\n linkAs?: (item: NavItem, content: React.ReactNode, className: string) => React.ReactNode;\n}\n\n/**\n * Sidebar layout (default, `headerLayout=\"side\"` or omitted). The brand\n * block + collapse rail live in the sidebar; the topbar sits over the\n * content with a mobile hamburger. `header` is **not** valid here — that\n * slot belongs to the `top` layout.\n */\nexport interface AppShellSideProps extends AppShellBaseProps {\n headerLayout?: 'side';\n /** Brand node in the sidebar header (expanded state). */\n brand?: React.ReactNode;\n /** Brand node shown when the rail is collapsed. Falls back to `brand`. */\n brandCollapsed?: React.ReactNode;\n /** Content of the topbar over the page (search, etc.). */\n topbar?: React.ReactNode;\n /** User slot at the right of the topbar (avatar/menu). */\n user?: React.ReactNode;\n /** Not valid in the `side` layout — the header slots belong to `top`. */\n header?: never;\n}\n\n/**\n * Top-header layout (`headerLayout=\"top\"`, v1.15.0). Full-width header\n * above the body with three slots (`header.{left,center,right}`); the\n * centre slot lands at the **true viewport centre** (1fr·auto·1fr grid).\n * The sidebar has no brand block and `collapsed` hides it entirely (no\n * 72px rail); the header is **invariant** to the collapse. `theme=\"brand\"`\n * tints both bands. The `side`-only props are **not** valid here — put your\n * chrome in `header`.\n */\nexport interface AppShellTopProps extends AppShellBaseProps {\n headerLayout: 'top';\n /** Slots for the full-width header. Brand usually goes in `center`. */\n header?: AppShellHeader;\n /**\n * Theme of the **header band only**, independent of the sidebar (`theme`).\n * Defaults to `theme`, so `theme=\"brand\"` still tints both bands (no\n * change for existing consumers). Set `theme=\"default\" headerTheme=\"brand\"`\n * for a branded top bar over a neutral, legible sidebar — common in\n * data-heavy admin apps.\n */\n headerTheme?: AppShellTheme;\n /** Not valid in `top` — use `header.center` for the brand. */\n brand?: never;\n /** Not valid in `top` — the sidebar collapses entirely. */\n brandCollapsed?: never;\n /** Not valid in `top` — use the `header` slots. */\n topbar?: never;\n /** Not valid in `top` — use `header.right`. */\n user?: never;\n}\n\n/**\n * Discriminated union keyed on `headerLayout`. TypeScript enforces that\n * `header` is only accepted with `headerLayout=\"top\"` and that\n * `brand`/`brandCollapsed`/`topbar`/`user` are only accepted with the\n * (default) `side` layout — passing the wrong prop for the layout is a\n * compile error instead of being silently ignored at runtime.\n */\nexport type AppShellProps = AppShellSideProps | AppShellTopProps;\n\n// Recursive nav item, memoized so a single item's parent re-render doesn't\n// churn through every other item in the tree. Stability of `linkAs` and\n// `onCloseMobile` is the parent's responsibility (we stabilize\n// `onCloseMobile` via useCallback below; consumers should memoize `linkAs`\n// if they care about avoiding renders, but for typical Next.js Link usage\n// the inline arrow is rarely a hot path).\ninterface NavItemNodeProps {\n item: NavItem;\n depth: number;\n linkAs?: AppShellBaseProps['linkAs'];\n onCloseMobile: () => void;\n}\n\nconst NavItemNode = React.memo(function NavItemNode({\n item, depth, linkAs, onCloseMobile,\n}: NavItemNodeProps) {\n const klass = cx('appshell__navitem', item.active && 'is-active', `appshell__navitem--depth-${depth}`);\n const inner = (\n <>\n {item.icon && <span className=\"appshell__navicon\" aria-hidden=\"true\">{item.icon}</span>}\n <span className=\"appshell__navlabel\">{item.label}</span>\n {item.badge && <span className=\"appshell__navbadge\">{item.badge}</span>}\n </>\n );\n const node = item.href && linkAs\n ? linkAs(item, inner, klass)\n : (\n <a\n href={item.href ?? '#'}\n className={klass}\n aria-current={item.active ? 'page' : undefined}\n onClick={(e) => {\n if (!item.href) e.preventDefault();\n item.onSelect?.();\n onCloseMobile();\n }}\n >\n {inner}\n </a>\n );\n return (\n <li>\n {node}\n {item.children && item.children.length > 0 && (\n <ul className=\"appshell__navchildren\">\n {item.children.map((c) => (\n <NavItemNode key={c.id} item={c} depth={depth + 1} linkAs={linkAs} onCloseMobile={onCloseMobile} />\n ))}\n </ul>\n )}\n </li>\n );\n});\n\nexport function AppShell(props: AppShellProps) {\n const {\n sections, footer, defaultCollapsed = false,\n collapsed: ctrlCollapsed, onCollapsedChange,\n children, className, theme = 'default', linkAs,\n } = props;\n const [internalCollapsed, setInternalCollapsed] = React.useState(defaultCollapsed);\n const [mobileOpen, setMobileOpen] = React.useState(false);\n const t = useLocale();\n const collapsed = ctrlCollapsed ?? internalCollapsed;\n const setCollapsed = (v: boolean) => {\n if (ctrlCollapsed === undefined) setInternalCollapsed(v);\n onCollapsedChange?.(v);\n };\n const closeMobile = React.useCallback(() => setMobileOpen(false), []);\n\n // Top-header variant: full-width header above the body. Topbar is\n // invariant to `collapsed` (only the inner body's columns animate); brand\n // lives in `header.center` at the true viewport centre. Default\n // `headerLayout=\"side\"` falls through to the legacy JSX below\n // (byte-identical for existing consumers). The `props.headerLayout`\n // check narrows the discriminated union, so `header` (top) and\n // `brand`/`topbar`/`user` (side) are each only in scope in their branch.\n if (props.headerLayout === 'top') {\n const { header } = props;\n // Header band themes independently of the sidebar; defaults to `theme`\n // so `theme=\"brand\"` keeps tinting both bands (back-compat).\n const headerTheme = props.headerTheme ?? theme;\n return (\n <div className={cx('appshell', `appshell--${theme}`, 'appshell--header-top', `appshell--header-${headerTheme}`, collapsed && 'is-collapsed', className)}>\n <header className=\"appshell__header\" role=\"banner\">\n <div className=\"appshell__header-left\">{header?.left}</div>\n <div className=\"appshell__header-center\">{header?.center}</div>\n <div className=\"appshell__header-right\">{header?.right}</div>\n </header>\n <div className=\"appshell__body\">\n <aside className=\"appshell__sidebar\" aria-label={t['appshell.mainNav']}>\n <nav className=\"appshell__nav\">\n {sections.map((s, i) => (\n <div key={s.id ?? i} className=\"appshell__navsection\">\n {s.label && <div className=\"appshell__navlabel-section\">{s.label}</div>}\n <ul>{s.items.map((it) => (\n <NavItemNode key={it.id} item={it} depth={0} linkAs={linkAs} onCloseMobile={closeMobile} />\n ))}</ul>\n </div>\n ))}\n </nav>\n {footer != null && <div className=\"appshell__sidebar-foot\">{footer}</div>}\n </aside>\n <main className=\"appshell__content\" role=\"main\">{children}</main>\n </div>\n </div>\n );\n }\n\n const { brand, brandCollapsed, topbar, user } = props;\n return (\n <div className={cx('appshell', `appshell--${theme}`, collapsed && 'is-collapsed', mobileOpen && 'is-mobile-open', className)}>\n <aside className=\"appshell__sidebar\" aria-label={t['appshell.mainNav']}>\n <div className=\"appshell__brand\">\n {collapsed ? (brandCollapsed ?? brand) : brand}\n </div>\n <nav className=\"appshell__nav\">\n {sections.map((s, i) => (\n <div key={s.id ?? i} className=\"appshell__navsection\">\n {s.label && <div className=\"appshell__navlabel-section\">{s.label}</div>}\n <ul>{s.items.map((it) => (\n <NavItemNode key={it.id} item={it} depth={0} linkAs={linkAs} onCloseMobile={closeMobile} />\n ))}</ul>\n </div>\n ))}\n </nav>\n <div className=\"appshell__sidebar-foot\">\n {footer}\n <button\n type=\"button\"\n className=\"appshell__collapse\"\n onClick={() => setCollapsed(!collapsed)}\n aria-expanded={!collapsed}\n aria-label={collapsed ? t['appshell.expandMenu'] : t['appshell.collapseMenu']}\n title={collapsed ? t['appshell.expand'] : t['appshell.collapse']}\n >\n {collapsed ? <ChevronRight size={14} /> : <ChevronLeft size={14} />}\n </button>\n </div>\n </aside>\n\n <div className=\"appshell__main\">\n <header className=\"appshell__topbar\">\n <button\n type=\"button\"\n className=\"appshell__hamburger\"\n aria-label={t['appshell.openMenu']}\n aria-expanded={mobileOpen}\n onClick={() => setMobileOpen((o) => !o)}\n ><MenuIcon size={20} /></button>\n <div className=\"appshell__topbar-content\">{topbar}</div>\n {user && <div className=\"appshell__topbar-user\">{user}</div>}\n </header>\n <main className=\"appshell__content\" role=\"main\">{children}</main>\n </div>\n\n {mobileOpen && (\n <div className=\"appshell__scrim\" onClick={() => setMobileOpen(false)} aria-hidden=\"true\" />\n )}\n </div>\n );\n}\n\n// ---------- PageHeader --------------------------------------------------\nexport interface PageHeaderProps {\n title: React.ReactNode;\n description?: React.ReactNode;\n breadcrumbs?: Array<{ label: React.ReactNode; href?: string }>;\n actions?: React.ReactNode;\n meta?: React.ReactNode;\n className?: string;\n}\n\nexport function PageHeader({ title, description, breadcrumbs, actions, meta, className }: PageHeaderProps) {\n const t = useLocale();\n return (\n <div className={cx('page-header', className)}>\n {breadcrumbs && breadcrumbs.length > 0 && (\n <nav className=\"page-header__crumbs\" aria-label={t['appshell.breadcrumb']}>\n <ol>\n {breadcrumbs.map((c, i) => (\n <li key={i}>\n {c.href ? <a href={c.href}>{c.label}</a> : <span aria-current=\"page\">{c.label}</span>}\n {i < breadcrumbs.length - 1 && <span className=\"page-header__crumb-sep\" aria-hidden=\"true\">/</span>}\n </li>\n ))}\n </ol>\n </nav>\n )}\n <div className=\"page-header__row\">\n <div className=\"page-header__title-wrap\">\n <h1 className=\"page-header__title\">{title}</h1>\n {description && <p className=\"page-header__desc\">{description}</p>}\n </div>\n {actions && <div className=\"page-header__actions\">{actions}</div>}\n </div>\n {meta && <div className=\"page-header__meta\">{meta}</div>}\n </div>\n );\n}\n"]}
@@ -58,23 +58,18 @@ var NavItemNode = React__namespace.memo(function NavItemNode2({
58
58
  item.children && item.children.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "appshell__navchildren", children: item.children.map((c) => /* @__PURE__ */ jsxRuntime.jsx(NavItemNode2, { item: c, depth: depth + 1, linkAs, onCloseMobile }, c.id)) })
59
59
  ] });
60
60
  });
61
- function AppShell({
62
- brand,
63
- brandCollapsed,
64
- sections,
65
- topbar,
66
- footer,
67
- user,
68
- defaultCollapsed = false,
69
- collapsed: ctrlCollapsed,
70
- onCollapsedChange,
71
- children,
72
- className,
73
- theme = "default",
74
- linkAs,
75
- headerLayout = "side",
76
- header
77
- }) {
61
+ function AppShell(props) {
62
+ const {
63
+ sections,
64
+ footer,
65
+ defaultCollapsed = false,
66
+ collapsed: ctrlCollapsed,
67
+ onCollapsedChange,
68
+ children,
69
+ className,
70
+ theme = "default",
71
+ linkAs
72
+ } = props;
78
73
  const [internalCollapsed, setInternalCollapsed] = React__namespace.useState(defaultCollapsed);
79
74
  const [mobileOpen, setMobileOpen] = React__namespace.useState(false);
80
75
  const t = chunk4VMQLSHV_js.useLocale();
@@ -84,8 +79,10 @@ function AppShell({
84
79
  onCollapsedChange?.(v);
85
80
  };
86
81
  const closeMobile = React__namespace.useCallback(() => setMobileOpen(false), []);
87
- if (headerLayout === "top") {
88
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkPASF6T4H_js.cx("appshell", `appshell--${theme}`, "appshell--header-top", collapsed && "is-collapsed", className), children: [
82
+ if (props.headerLayout === "top") {
83
+ const { header } = props;
84
+ const headerTheme = props.headerTheme ?? theme;
85
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkPASF6T4H_js.cx("appshell", `appshell--${theme}`, "appshell--header-top", `appshell--header-${headerTheme}`, collapsed && "is-collapsed", className), children: [
89
86
  /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "appshell__header", role: "banner", children: [
90
87
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "appshell__header-left", children: header?.left }),
91
88
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "appshell__header-center", children: header?.center }),
@@ -103,6 +100,7 @@ function AppShell({
103
100
  ] })
104
101
  ] });
105
102
  }
103
+ const { brand, brandCollapsed, topbar, user } = props;
106
104
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkPASF6T4H_js.cx("appshell", `appshell--${theme}`, collapsed && "is-collapsed", mobileOpen && "is-mobile-open", className), children: [
107
105
  /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "appshell__sidebar", "aria-label": t["appshell.mainNav"], children: [
108
106
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "appshell__brand", children: collapsed ? brandCollapsed ?? brand : brand }),
@@ -167,5 +165,5 @@ function PageHeader({ title, description, breadcrumbs, actions, meta, className
167
165
 
168
166
  exports.AppShell = AppShell;
169
167
  exports.PageHeader = PageHeader;
170
- //# sourceMappingURL=chunk-7LCZ6ABE.js.map
171
- //# sourceMappingURL=chunk-7LCZ6ABE.js.map
168
+ //# sourceMappingURL=chunk-SZWROXKE.js.map
169
+ //# sourceMappingURL=chunk-SZWROXKE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/AppShell.tsx"],"names":["React","NavItemNode","cx","jsxs","Fragment","jsx","useLocale","ChevronRight","ChevronLeft","MenuIcon"],"mappings":"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","file":"chunk-SZWROXKE.js","sourcesContent":["'use client';\nimport * as React from 'react';\nimport { cx } from '../utils/cx';\nimport { ChevronLeft, ChevronRight, MenuIcon } from './Icons';\nimport { useLocale } from '../locale/LocaleProvider';\n\n// ---------- AppShell (Sidebar + Topbar + Content) -----------------------\n// Designed to drop into a Next.js app/layout.tsx as a Client Component shell.\n\nexport interface NavItem {\n id: string;\n label: React.ReactNode;\n icon?: React.ReactNode;\n href?: string;\n active?: boolean;\n badge?: React.ReactNode;\n onSelect?: () => void;\n children?: NavItem[];\n}\n\nexport interface NavSection {\n id?: string;\n label?: React.ReactNode;\n items: NavItem[];\n}\n\nexport type AppShellTheme = 'default' | 'brand';\n\nexport type AppShellHeaderLayout = 'side' | 'top';\n\nexport interface AppShellHeader {\n /** Left slot — typically a menu/hamburger trigger or back action. */\n left?: React.ReactNode;\n /** Center slot — typically the brand (Logo). Lands at the true viewport centre. */\n center?: React.ReactNode;\n /** Right slot — notifications, user avatar, utilities. */\n right?: React.ReactNode;\n}\n\n/**\n * Props shared by both layouts. The layout-specific props live in\n * `AppShellSideProps` / `AppShellTopProps`; `AppShellProps` is the\n * discriminated union of the two, keyed on `headerLayout`.\n */\nexport interface AppShellBaseProps {\n sections: NavSection[];\n footer?: React.ReactNode;\n defaultCollapsed?: boolean;\n collapsed?: boolean;\n onCollapsedChange?: (c: boolean) => void;\n children: React.ReactNode;\n className?: string;\n /**\n * Color theme (applies to both layouts):\n * - `default` (light): claro, mejor para apps data-heavy de uso prolongado.\n * - `brand`: superficie azul de marca con texto blanco. Mayor brand recall.\n * En `side` tiñe el sidebar; en `top` tiñe header + sidebar (un solo knob).\n */\n theme?: AppShellTheme;\n /** Render-prop for navigation links so the host app can use Next.js Link, etc. */\n linkAs?: (item: NavItem, content: React.ReactNode, className: string) => React.ReactNode;\n}\n\n/**\n * Sidebar layout (default, `headerLayout=\"side\"` or omitted). The brand\n * block + collapse rail live in the sidebar; the topbar sits over the\n * content with a mobile hamburger. `header` is **not** valid here — that\n * slot belongs to the `top` layout.\n */\nexport interface AppShellSideProps extends AppShellBaseProps {\n headerLayout?: 'side';\n /** Brand node in the sidebar header (expanded state). */\n brand?: React.ReactNode;\n /** Brand node shown when the rail is collapsed. Falls back to `brand`. */\n brandCollapsed?: React.ReactNode;\n /** Content of the topbar over the page (search, etc.). */\n topbar?: React.ReactNode;\n /** User slot at the right of the topbar (avatar/menu). */\n user?: React.ReactNode;\n /** Not valid in the `side` layout — the header slots belong to `top`. */\n header?: never;\n}\n\n/**\n * Top-header layout (`headerLayout=\"top\"`, v1.15.0). Full-width header\n * above the body with three slots (`header.{left,center,right}`); the\n * centre slot lands at the **true viewport centre** (1fr·auto·1fr grid).\n * The sidebar has no brand block and `collapsed` hides it entirely (no\n * 72px rail); the header is **invariant** to the collapse. `theme=\"brand\"`\n * tints both bands. The `side`-only props are **not** valid here — put your\n * chrome in `header`.\n */\nexport interface AppShellTopProps extends AppShellBaseProps {\n headerLayout: 'top';\n /** Slots for the full-width header. Brand usually goes in `center`. */\n header?: AppShellHeader;\n /**\n * Theme of the **header band only**, independent of the sidebar (`theme`).\n * Defaults to `theme`, so `theme=\"brand\"` still tints both bands (no\n * change for existing consumers). Set `theme=\"default\" headerTheme=\"brand\"`\n * for a branded top bar over a neutral, legible sidebar — common in\n * data-heavy admin apps.\n */\n headerTheme?: AppShellTheme;\n /** Not valid in `top` — use `header.center` for the brand. */\n brand?: never;\n /** Not valid in `top` — the sidebar collapses entirely. */\n brandCollapsed?: never;\n /** Not valid in `top` — use the `header` slots. */\n topbar?: never;\n /** Not valid in `top` — use `header.right`. */\n user?: never;\n}\n\n/**\n * Discriminated union keyed on `headerLayout`. TypeScript enforces that\n * `header` is only accepted with `headerLayout=\"top\"` and that\n * `brand`/`brandCollapsed`/`topbar`/`user` are only accepted with the\n * (default) `side` layout — passing the wrong prop for the layout is a\n * compile error instead of being silently ignored at runtime.\n */\nexport type AppShellProps = AppShellSideProps | AppShellTopProps;\n\n// Recursive nav item, memoized so a single item's parent re-render doesn't\n// churn through every other item in the tree. Stability of `linkAs` and\n// `onCloseMobile` is the parent's responsibility (we stabilize\n// `onCloseMobile` via useCallback below; consumers should memoize `linkAs`\n// if they care about avoiding renders, but for typical Next.js Link usage\n// the inline arrow is rarely a hot path).\ninterface NavItemNodeProps {\n item: NavItem;\n depth: number;\n linkAs?: AppShellBaseProps['linkAs'];\n onCloseMobile: () => void;\n}\n\nconst NavItemNode = React.memo(function NavItemNode({\n item, depth, linkAs, onCloseMobile,\n}: NavItemNodeProps) {\n const klass = cx('appshell__navitem', item.active && 'is-active', `appshell__navitem--depth-${depth}`);\n const inner = (\n <>\n {item.icon && <span className=\"appshell__navicon\" aria-hidden=\"true\">{item.icon}</span>}\n <span className=\"appshell__navlabel\">{item.label}</span>\n {item.badge && <span className=\"appshell__navbadge\">{item.badge}</span>}\n </>\n );\n const node = item.href && linkAs\n ? linkAs(item, inner, klass)\n : (\n <a\n href={item.href ?? '#'}\n className={klass}\n aria-current={item.active ? 'page' : undefined}\n onClick={(e) => {\n if (!item.href) e.preventDefault();\n item.onSelect?.();\n onCloseMobile();\n }}\n >\n {inner}\n </a>\n );\n return (\n <li>\n {node}\n {item.children && item.children.length > 0 && (\n <ul className=\"appshell__navchildren\">\n {item.children.map((c) => (\n <NavItemNode key={c.id} item={c} depth={depth + 1} linkAs={linkAs} onCloseMobile={onCloseMobile} />\n ))}\n </ul>\n )}\n </li>\n );\n});\n\nexport function AppShell(props: AppShellProps) {\n const {\n sections, footer, defaultCollapsed = false,\n collapsed: ctrlCollapsed, onCollapsedChange,\n children, className, theme = 'default', linkAs,\n } = props;\n const [internalCollapsed, setInternalCollapsed] = React.useState(defaultCollapsed);\n const [mobileOpen, setMobileOpen] = React.useState(false);\n const t = useLocale();\n const collapsed = ctrlCollapsed ?? internalCollapsed;\n const setCollapsed = (v: boolean) => {\n if (ctrlCollapsed === undefined) setInternalCollapsed(v);\n onCollapsedChange?.(v);\n };\n const closeMobile = React.useCallback(() => setMobileOpen(false), []);\n\n // Top-header variant: full-width header above the body. Topbar is\n // invariant to `collapsed` (only the inner body's columns animate); brand\n // lives in `header.center` at the true viewport centre. Default\n // `headerLayout=\"side\"` falls through to the legacy JSX below\n // (byte-identical for existing consumers). The `props.headerLayout`\n // check narrows the discriminated union, so `header` (top) and\n // `brand`/`topbar`/`user` (side) are each only in scope in their branch.\n if (props.headerLayout === 'top') {\n const { header } = props;\n // Header band themes independently of the sidebar; defaults to `theme`\n // so `theme=\"brand\"` keeps tinting both bands (back-compat).\n const headerTheme = props.headerTheme ?? theme;\n return (\n <div className={cx('appshell', `appshell--${theme}`, 'appshell--header-top', `appshell--header-${headerTheme}`, collapsed && 'is-collapsed', className)}>\n <header className=\"appshell__header\" role=\"banner\">\n <div className=\"appshell__header-left\">{header?.left}</div>\n <div className=\"appshell__header-center\">{header?.center}</div>\n <div className=\"appshell__header-right\">{header?.right}</div>\n </header>\n <div className=\"appshell__body\">\n <aside className=\"appshell__sidebar\" aria-label={t['appshell.mainNav']}>\n <nav className=\"appshell__nav\">\n {sections.map((s, i) => (\n <div key={s.id ?? i} className=\"appshell__navsection\">\n {s.label && <div className=\"appshell__navlabel-section\">{s.label}</div>}\n <ul>{s.items.map((it) => (\n <NavItemNode key={it.id} item={it} depth={0} linkAs={linkAs} onCloseMobile={closeMobile} />\n ))}</ul>\n </div>\n ))}\n </nav>\n {footer != null && <div className=\"appshell__sidebar-foot\">{footer}</div>}\n </aside>\n <main className=\"appshell__content\" role=\"main\">{children}</main>\n </div>\n </div>\n );\n }\n\n const { brand, brandCollapsed, topbar, user } = props;\n return (\n <div className={cx('appshell', `appshell--${theme}`, collapsed && 'is-collapsed', mobileOpen && 'is-mobile-open', className)}>\n <aside className=\"appshell__sidebar\" aria-label={t['appshell.mainNav']}>\n <div className=\"appshell__brand\">\n {collapsed ? (brandCollapsed ?? brand) : brand}\n </div>\n <nav className=\"appshell__nav\">\n {sections.map((s, i) => (\n <div key={s.id ?? i} className=\"appshell__navsection\">\n {s.label && <div className=\"appshell__navlabel-section\">{s.label}</div>}\n <ul>{s.items.map((it) => (\n <NavItemNode key={it.id} item={it} depth={0} linkAs={linkAs} onCloseMobile={closeMobile} />\n ))}</ul>\n </div>\n ))}\n </nav>\n <div className=\"appshell__sidebar-foot\">\n {footer}\n <button\n type=\"button\"\n className=\"appshell__collapse\"\n onClick={() => setCollapsed(!collapsed)}\n aria-expanded={!collapsed}\n aria-label={collapsed ? t['appshell.expandMenu'] : t['appshell.collapseMenu']}\n title={collapsed ? t['appshell.expand'] : t['appshell.collapse']}\n >\n {collapsed ? <ChevronRight size={14} /> : <ChevronLeft size={14} />}\n </button>\n </div>\n </aside>\n\n <div className=\"appshell__main\">\n <header className=\"appshell__topbar\">\n <button\n type=\"button\"\n className=\"appshell__hamburger\"\n aria-label={t['appshell.openMenu']}\n aria-expanded={mobileOpen}\n onClick={() => setMobileOpen((o) => !o)}\n ><MenuIcon size={20} /></button>\n <div className=\"appshell__topbar-content\">{topbar}</div>\n {user && <div className=\"appshell__topbar-user\">{user}</div>}\n </header>\n <main className=\"appshell__content\" role=\"main\">{children}</main>\n </div>\n\n {mobileOpen && (\n <div className=\"appshell__scrim\" onClick={() => setMobileOpen(false)} aria-hidden=\"true\" />\n )}\n </div>\n );\n}\n\n// ---------- PageHeader --------------------------------------------------\nexport interface PageHeaderProps {\n title: React.ReactNode;\n description?: React.ReactNode;\n breadcrumbs?: Array<{ label: React.ReactNode; href?: string }>;\n actions?: React.ReactNode;\n meta?: React.ReactNode;\n className?: string;\n}\n\nexport function PageHeader({ title, description, breadcrumbs, actions, meta, className }: PageHeaderProps) {\n const t = useLocale();\n return (\n <div className={cx('page-header', className)}>\n {breadcrumbs && breadcrumbs.length > 0 && (\n <nav className=\"page-header__crumbs\" aria-label={t['appshell.breadcrumb']}>\n <ol>\n {breadcrumbs.map((c, i) => (\n <li key={i}>\n {c.href ? <a href={c.href}>{c.label}</a> : <span aria-current=\"page\">{c.label}</span>}\n {i < breadcrumbs.length - 1 && <span className=\"page-header__crumb-sep\" aria-hidden=\"true\">/</span>}\n </li>\n ))}\n </ol>\n </nav>\n )}\n <div className=\"page-header__row\">\n <div className=\"page-header__title-wrap\">\n <h1 className=\"page-header__title\">{title}</h1>\n {description && <p className=\"page-header__desc\">{description}</p>}\n </div>\n {actions && <div className=\"page-header__actions\">{actions}</div>}\n </div>\n {meta && <div className=\"page-header__meta\">{meta}</div>}\n </div>\n );\n}\n"]}
@@ -26,42 +26,87 @@ interface AppShellHeader {
26
26
  /** Right slot — notifications, user avatar, utilities. */
27
27
  right?: React.ReactNode;
28
28
  }
29
- interface AppShellProps {
30
- brand?: React.ReactNode;
31
- brandCollapsed?: React.ReactNode;
29
+ /**
30
+ * Props shared by both layouts. The layout-specific props live in
31
+ * `AppShellSideProps` / `AppShellTopProps`; `AppShellProps` is the
32
+ * discriminated union of the two, keyed on `headerLayout`.
33
+ */
34
+ interface AppShellBaseProps {
32
35
  sections: NavSection[];
33
- topbar?: React.ReactNode;
34
36
  footer?: React.ReactNode;
35
- user?: React.ReactNode;
36
37
  defaultCollapsed?: boolean;
37
38
  collapsed?: boolean;
38
39
  onCollapsedChange?: (c: boolean) => void;
39
40
  children: React.ReactNode;
40
41
  className?: string;
41
42
  /**
42
- * Sidebar color theme:
43
+ * Color theme (applies to both layouts):
43
44
  * - `default` (light): claro, mejor para apps data-heavy de uso prolongado.
44
- * - `brand`: sidebar azul de marca con texto blanco. Mayor brand recall.
45
+ * - `brand`: superficie azul de marca con texto blanco. Mayor brand recall.
46
+ * En `side` tiñe el sidebar; en `top` tiñe header + sidebar (un solo knob).
45
47
  */
46
48
  theme?: AppShellTheme;
47
49
  /** Render-prop for navigation links so the host app can use Next.js Link, etc. */
48
50
  linkAs?: (item: NavItem, content: React.ReactNode, className: string) => React.ReactNode;
51
+ }
52
+ /**
53
+ * Sidebar layout (default, `headerLayout="side"` or omitted). The brand
54
+ * block + collapse rail live in the sidebar; the topbar sits over the
55
+ * content with a mobile hamburger. `header` is **not** valid here — that
56
+ * slot belongs to the `top` layout.
57
+ */
58
+ interface AppShellSideProps extends AppShellBaseProps {
59
+ headerLayout?: 'side';
60
+ /** Brand node in the sidebar header (expanded state). */
61
+ brand?: React.ReactNode;
62
+ /** Brand node shown when the rail is collapsed. Falls back to `brand`. */
63
+ brandCollapsed?: React.ReactNode;
64
+ /** Content of the topbar over the page (search, etc.). */
65
+ topbar?: React.ReactNode;
66
+ /** User slot at the right of the topbar (avatar/menu). */
67
+ user?: React.ReactNode;
68
+ /** Not valid in the `side` layout — the header slots belong to `top`. */
69
+ header?: never;
70
+ }
71
+ /**
72
+ * Top-header layout (`headerLayout="top"`, v1.15.0). Full-width header
73
+ * above the body with three slots (`header.{left,center,right}`); the
74
+ * centre slot lands at the **true viewport centre** (1fr·auto·1fr grid).
75
+ * The sidebar has no brand block and `collapsed` hides it entirely (no
76
+ * 72px rail); the header is **invariant** to the collapse. `theme="brand"`
77
+ * tints both bands. The `side`-only props are **not** valid here — put your
78
+ * chrome in `header`.
79
+ */
80
+ interface AppShellTopProps extends AppShellBaseProps {
81
+ headerLayout: 'top';
82
+ /** Slots for the full-width header. Brand usually goes in `center`. */
83
+ header?: AppShellHeader;
49
84
  /**
50
- * Where the chrome lives. Default `'side'` is the legacy layout. `'top'`
51
- * renders a full-width header above the body with three slots
52
- * (`header.left/center/right`); the centre slot lands at the **true
53
- * viewport centre** (1fr·auto·1fr column grid). The sidebar has no brand
54
- * block (brand goes in `header.center`) and `collapsed` hides the
55
- * sidebar entirely — no 72px rail. The topbar is **invariant** to the
56
- * collapse (only the sidebar changes width). `theme="brand"` tints both
57
- * header and sidebar with the same brand colour (single knob). `brand`,
58
- * `brandCollapsed` and `topbar` are ignored when `'top'`.
85
+ * Theme of the **header band only**, independent of the sidebar (`theme`).
86
+ * Defaults to `theme`, so `theme="brand"` still tints both bands (no
87
+ * change for existing consumers). Set `theme="default" headerTheme="brand"`
88
+ * for a branded top bar over a neutral, legible sidebar common in
89
+ * data-heavy admin apps.
59
90
  */
60
- headerLayout?: AppShellHeaderLayout;
61
- /** Slots for the top-layout header (only used when `headerLayout="top"`). */
62
- header?: AppShellHeader;
91
+ headerTheme?: AppShellTheme;
92
+ /** Not valid in `top` — use `header.center` for the brand. */
93
+ brand?: never;
94
+ /** Not valid in `top` — the sidebar collapses entirely. */
95
+ brandCollapsed?: never;
96
+ /** Not valid in `top` — use the `header` slots. */
97
+ topbar?: never;
98
+ /** Not valid in `top` — use `header.right`. */
99
+ user?: never;
63
100
  }
64
- declare function AppShell({ brand, brandCollapsed, sections, topbar, footer, user, defaultCollapsed, collapsed: ctrlCollapsed, onCollapsedChange, children, className, theme, linkAs, headerLayout, header, }: AppShellProps): react_jsx_runtime.JSX.Element;
101
+ /**
102
+ * Discriminated union keyed on `headerLayout`. TypeScript enforces that
103
+ * `header` is only accepted with `headerLayout="top"` and that
104
+ * `brand`/`brandCollapsed`/`topbar`/`user` are only accepted with the
105
+ * (default) `side` layout — passing the wrong prop for the layout is a
106
+ * compile error instead of being silently ignored at runtime.
107
+ */
108
+ type AppShellProps = AppShellSideProps | AppShellTopProps;
109
+ declare function AppShell(props: AppShellProps): react_jsx_runtime.JSX.Element;
65
110
  interface PageHeaderProps {
66
111
  title: React.ReactNode;
67
112
  description?: React.ReactNode;
@@ -75,4 +120,4 @@ interface PageHeaderProps {
75
120
  }
76
121
  declare function PageHeader({ title, description, breadcrumbs, actions, meta, className }: PageHeaderProps): react_jsx_runtime.JSX.Element;
77
122
 
78
- export { AppShell, type AppShellHeader, type AppShellHeaderLayout, type AppShellProps, type AppShellTheme, type NavItem, type NavSection, PageHeader, type PageHeaderProps };
123
+ export { AppShell, type AppShellBaseProps, type AppShellHeader, type AppShellHeaderLayout, type AppShellProps, type AppShellSideProps, type AppShellTheme, type AppShellTopProps, type NavItem, type NavSection, PageHeader, type PageHeaderProps };
@@ -26,42 +26,87 @@ interface AppShellHeader {
26
26
  /** Right slot — notifications, user avatar, utilities. */
27
27
  right?: React.ReactNode;
28
28
  }
29
- interface AppShellProps {
30
- brand?: React.ReactNode;
31
- brandCollapsed?: React.ReactNode;
29
+ /**
30
+ * Props shared by both layouts. The layout-specific props live in
31
+ * `AppShellSideProps` / `AppShellTopProps`; `AppShellProps` is the
32
+ * discriminated union of the two, keyed on `headerLayout`.
33
+ */
34
+ interface AppShellBaseProps {
32
35
  sections: NavSection[];
33
- topbar?: React.ReactNode;
34
36
  footer?: React.ReactNode;
35
- user?: React.ReactNode;
36
37
  defaultCollapsed?: boolean;
37
38
  collapsed?: boolean;
38
39
  onCollapsedChange?: (c: boolean) => void;
39
40
  children: React.ReactNode;
40
41
  className?: string;
41
42
  /**
42
- * Sidebar color theme:
43
+ * Color theme (applies to both layouts):
43
44
  * - `default` (light): claro, mejor para apps data-heavy de uso prolongado.
44
- * - `brand`: sidebar azul de marca con texto blanco. Mayor brand recall.
45
+ * - `brand`: superficie azul de marca con texto blanco. Mayor brand recall.
46
+ * En `side` tiñe el sidebar; en `top` tiñe header + sidebar (un solo knob).
45
47
  */
46
48
  theme?: AppShellTheme;
47
49
  /** Render-prop for navigation links so the host app can use Next.js Link, etc. */
48
50
  linkAs?: (item: NavItem, content: React.ReactNode, className: string) => React.ReactNode;
51
+ }
52
+ /**
53
+ * Sidebar layout (default, `headerLayout="side"` or omitted). The brand
54
+ * block + collapse rail live in the sidebar; the topbar sits over the
55
+ * content with a mobile hamburger. `header` is **not** valid here — that
56
+ * slot belongs to the `top` layout.
57
+ */
58
+ interface AppShellSideProps extends AppShellBaseProps {
59
+ headerLayout?: 'side';
60
+ /** Brand node in the sidebar header (expanded state). */
61
+ brand?: React.ReactNode;
62
+ /** Brand node shown when the rail is collapsed. Falls back to `brand`. */
63
+ brandCollapsed?: React.ReactNode;
64
+ /** Content of the topbar over the page (search, etc.). */
65
+ topbar?: React.ReactNode;
66
+ /** User slot at the right of the topbar (avatar/menu). */
67
+ user?: React.ReactNode;
68
+ /** Not valid in the `side` layout — the header slots belong to `top`. */
69
+ header?: never;
70
+ }
71
+ /**
72
+ * Top-header layout (`headerLayout="top"`, v1.15.0). Full-width header
73
+ * above the body with three slots (`header.{left,center,right}`); the
74
+ * centre slot lands at the **true viewport centre** (1fr·auto·1fr grid).
75
+ * The sidebar has no brand block and `collapsed` hides it entirely (no
76
+ * 72px rail); the header is **invariant** to the collapse. `theme="brand"`
77
+ * tints both bands. The `side`-only props are **not** valid here — put your
78
+ * chrome in `header`.
79
+ */
80
+ interface AppShellTopProps extends AppShellBaseProps {
81
+ headerLayout: 'top';
82
+ /** Slots for the full-width header. Brand usually goes in `center`. */
83
+ header?: AppShellHeader;
49
84
  /**
50
- * Where the chrome lives. Default `'side'` is the legacy layout. `'top'`
51
- * renders a full-width header above the body with three slots
52
- * (`header.left/center/right`); the centre slot lands at the **true
53
- * viewport centre** (1fr·auto·1fr column grid). The sidebar has no brand
54
- * block (brand goes in `header.center`) and `collapsed` hides the
55
- * sidebar entirely — no 72px rail. The topbar is **invariant** to the
56
- * collapse (only the sidebar changes width). `theme="brand"` tints both
57
- * header and sidebar with the same brand colour (single knob). `brand`,
58
- * `brandCollapsed` and `topbar` are ignored when `'top'`.
85
+ * Theme of the **header band only**, independent of the sidebar (`theme`).
86
+ * Defaults to `theme`, so `theme="brand"` still tints both bands (no
87
+ * change for existing consumers). Set `theme="default" headerTheme="brand"`
88
+ * for a branded top bar over a neutral, legible sidebar common in
89
+ * data-heavy admin apps.
59
90
  */
60
- headerLayout?: AppShellHeaderLayout;
61
- /** Slots for the top-layout header (only used when `headerLayout="top"`). */
62
- header?: AppShellHeader;
91
+ headerTheme?: AppShellTheme;
92
+ /** Not valid in `top` — use `header.center` for the brand. */
93
+ brand?: never;
94
+ /** Not valid in `top` — the sidebar collapses entirely. */
95
+ brandCollapsed?: never;
96
+ /** Not valid in `top` — use the `header` slots. */
97
+ topbar?: never;
98
+ /** Not valid in `top` — use `header.right`. */
99
+ user?: never;
63
100
  }
64
- declare function AppShell({ brand, brandCollapsed, sections, topbar, footer, user, defaultCollapsed, collapsed: ctrlCollapsed, onCollapsedChange, children, className, theme, linkAs, headerLayout, header, }: AppShellProps): react_jsx_runtime.JSX.Element;
101
+ /**
102
+ * Discriminated union keyed on `headerLayout`. TypeScript enforces that
103
+ * `header` is only accepted with `headerLayout="top"` and that
104
+ * `brand`/`brandCollapsed`/`topbar`/`user` are only accepted with the
105
+ * (default) `side` layout — passing the wrong prop for the layout is a
106
+ * compile error instead of being silently ignored at runtime.
107
+ */
108
+ type AppShellProps = AppShellSideProps | AppShellTopProps;
109
+ declare function AppShell(props: AppShellProps): react_jsx_runtime.JSX.Element;
65
110
  interface PageHeaderProps {
66
111
  title: React.ReactNode;
67
112
  description?: React.ReactNode;
@@ -75,4 +120,4 @@ interface PageHeaderProps {
75
120
  }
76
121
  declare function PageHeader({ title, description, breadcrumbs, actions, meta, className }: PageHeaderProps): react_jsx_runtime.JSX.Element;
77
122
 
78
- export { AppShell, type AppShellHeader, type AppShellHeaderLayout, type AppShellProps, type AppShellTheme, type NavItem, type NavSection, PageHeader, type PageHeaderProps };
123
+ export { AppShell, type AppShellBaseProps, type AppShellHeader, type AppShellHeaderLayout, type AppShellProps, type AppShellSideProps, type AppShellTheme, type AppShellTopProps, type NavItem, type NavSection, PageHeader, type PageHeaderProps };
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunk7LCZ6ABE_js = require('../chunk-7LCZ6ABE.js');
4
+ var chunkSZWROXKE_js = require('../chunk-SZWROXKE.js');
5
5
  require('../chunk-4VMQLSHV.js');
6
6
  require('../chunk-RQOTH7I7.js');
7
7
  require('../chunk-PASF6T4H.js');
@@ -10,11 +10,11 @@ require('../chunk-PASF6T4H.js');
10
10
 
11
11
  Object.defineProperty(exports, "AppShell", {
12
12
  enumerable: true,
13
- get: function () { return chunk7LCZ6ABE_js.AppShell; }
13
+ get: function () { return chunkSZWROXKE_js.AppShell; }
14
14
  });
15
15
  Object.defineProperty(exports, "PageHeader", {
16
16
  enumerable: true,
17
- get: function () { return chunk7LCZ6ABE_js.PageHeader; }
17
+ get: function () { return chunkSZWROXKE_js.PageHeader; }
18
18
  });
19
19
  //# sourceMappingURL=AppShell.js.map
20
20
  //# sourceMappingURL=AppShell.js.map
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- export { AppShell, PageHeader } from '../chunk-Y6AYAE4O.mjs';
2
+ export { AppShell, PageHeader } from '../chunk-E462CF6P.mjs';
3
3
  import '../chunk-PQV7HHCJ.mjs';
4
4
  import '../chunk-CIBJKJV3.mjs';
5
5
  import '../chunk-IEPCH3JB.mjs';
package/dist/index.d.mts CHANGED
@@ -15,7 +15,7 @@ export { Accordion, AccordionItem, AccordionProps, BreadcrumbItem, Breadcrumbs,
15
15
  export { CheckboxGroup, CheckboxGroupProps, MoneyInput, MoneyInputProps, OptionItem, PhoneInput, PhoneInputProps, Progress, ProgressCircle, ProgressCircleProps, ProgressProps, RadioGroup, RadioGroupProps, Slider, SliderProps, TagInput, TagInputProps, TimePicker, TimePickerProps } from './components/InputsExtra.mjs';
16
16
  export { Avatar, AvatarGroup, AvatarGroupProps, AvatarProps, Menu, MenuItemProps, MenuProps, Stat, StatProps } from './components/Display2.mjs';
17
17
  export { CommandItem, CommandPalette, CommandPaletteProps, DateRange, DateRangePicker, DateRangePickerProps, MultiCombobox, MultiComboboxOption, MultiComboboxProps, UseCommandPaletteOptions, useCommandPalette } from './components/AdvancedPickers.mjs';
18
- export { AppShell, AppShellHeader, AppShellHeaderLayout, AppShellProps, AppShellTheme, NavItem, NavSection, PageHeader, PageHeaderProps } from './components/AppShell.mjs';
18
+ export { AppShell, AppShellBaseProps, AppShellHeader, AppShellHeaderLayout, AppShellProps, AppShellSideProps, AppShellTheme, AppShellTopProps, NavItem, NavSection, PageHeader, PageHeaderProps } from './components/AppShell.mjs';
19
19
  export { AreaChart, AreaChartProps, BarChart, BarChartProps, BaseChartProps, DonutChart, DonutChartProps, LineChart, LineChartProps, RechartsLike, Sparkline, SparklineProps } from './components/Charts.mjs';
20
20
  export { AlertCircle, AlertTriangle, AlignCenter, AlignLeft, AlignRight, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Bell, Bold, Building, CalendarIcon, Check, CheckCircle, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Clock, Copy, CreditCard, Download, Edit, ExternalLink, Eye, EyeOff, FileText, Filter, Folder, Globe, Heart, Home, IconProps, Info, Italic, Link, Loader, Lock, LogOut, Mail, MapPin, MenuIcon, Minus, Moon, MoreHorizontal, MoreVertical, Package, Phone, Plus, RefreshCw, Search, Settings, ShoppingCart, Star, Sun, Tag, Tool, Trash, Truck, Underline, Unlock, Upload, User, Users, Wrench, X } from './components/Icons.mjs';
21
21
  export { Logo, LogoBg, LogoFormat, LogoProps, LogoVariant } from './components/Logo.mjs';
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@ export { Accordion, AccordionItem, AccordionProps, BreadcrumbItem, Breadcrumbs,
15
15
  export { CheckboxGroup, CheckboxGroupProps, MoneyInput, MoneyInputProps, OptionItem, PhoneInput, PhoneInputProps, Progress, ProgressCircle, ProgressCircleProps, ProgressProps, RadioGroup, RadioGroupProps, Slider, SliderProps, TagInput, TagInputProps, TimePicker, TimePickerProps } from './components/InputsExtra.js';
16
16
  export { Avatar, AvatarGroup, AvatarGroupProps, AvatarProps, Menu, MenuItemProps, MenuProps, Stat, StatProps } from './components/Display2.js';
17
17
  export { CommandItem, CommandPalette, CommandPaletteProps, DateRange, DateRangePicker, DateRangePickerProps, MultiCombobox, MultiComboboxOption, MultiComboboxProps, UseCommandPaletteOptions, useCommandPalette } from './components/AdvancedPickers.js';
18
- export { AppShell, AppShellHeader, AppShellHeaderLayout, AppShellProps, AppShellTheme, NavItem, NavSection, PageHeader, PageHeaderProps } from './components/AppShell.js';
18
+ export { AppShell, AppShellBaseProps, AppShellHeader, AppShellHeaderLayout, AppShellProps, AppShellSideProps, AppShellTheme, AppShellTopProps, NavItem, NavSection, PageHeader, PageHeaderProps } from './components/AppShell.js';
19
19
  export { AreaChart, AreaChartProps, BarChart, BarChartProps, BaseChartProps, DonutChart, DonutChartProps, LineChart, LineChartProps, RechartsLike, Sparkline, SparklineProps } from './components/Charts.js';
20
20
  export { AlertCircle, AlertTriangle, AlignCenter, AlignLeft, AlignRight, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Bell, Bold, Building, CalendarIcon, Check, CheckCircle, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Clock, Copy, CreditCard, Download, Edit, ExternalLink, Eye, EyeOff, FileText, Filter, Folder, Globe, Heart, Home, IconProps, Info, Italic, Link, Loader, Lock, LogOut, Mail, MapPin, MenuIcon, Minus, Moon, MoreHorizontal, MoreVertical, Package, Phone, Plus, RefreshCw, Search, Settings, ShoppingCart, Star, Sun, Tag, Tool, Trash, Truck, Underline, Unlock, Upload, User, Users, Wrench, X } from './components/Icons.js';
21
21
  export { Logo, LogoBg, LogoFormat, LogoProps, LogoVariant } from './components/Logo.js';
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
+ require('./chunk-4REALDR3.js');
4
5
  require('./chunk-427NHGTX.js');
5
6
  require('./chunk-2LTV7VB5.js');
6
- require('./chunk-4REALDR3.js');
7
7
  var chunkJT2SFHBH_js = require('./chunk-JT2SFHBH.js');
8
8
  var chunkDGBVPXGW_js = require('./chunk-DGBVPXGW.js');
9
9
  var chunkVDBGWTIG_js = require('./chunk-VDBGWTIG.js');
@@ -41,7 +41,7 @@ var chunkXMLBKK7X_js = require('./chunk-XMLBKK7X.js');
41
41
  var chunk7I5LFBQR_js = require('./chunk-7I5LFBQR.js');
42
42
  var chunkWAGWB35Q_js = require('./chunk-WAGWB35Q.js');
43
43
  var chunk3PXYCXDW_js = require('./chunk-3PXYCXDW.js');
44
- var chunk7LCZ6ABE_js = require('./chunk-7LCZ6ABE.js');
44
+ var chunkSZWROXKE_js = require('./chunk-SZWROXKE.js');
45
45
  var chunk4VMQLSHV_js = require('./chunk-4VMQLSHV.js');
46
46
  var chunkAJ22SXI2_js = require('./chunk-AJ22SXI2.js');
47
47
  var chunkEUB4PHPI_js = require('./chunk-EUB4PHPI.js');
@@ -667,11 +667,11 @@ Object.defineProperty(exports, "resetBrand", {
667
667
  });
668
668
  Object.defineProperty(exports, "AppShell", {
669
669
  enumerable: true,
670
- get: function () { return chunk7LCZ6ABE_js.AppShell; }
670
+ get: function () { return chunkSZWROXKE_js.AppShell; }
671
671
  });
672
672
  Object.defineProperty(exports, "PageHeader", {
673
673
  enumerable: true,
674
- get: function () { return chunk7LCZ6ABE_js.PageHeader; }
674
+ get: function () { return chunkSZWROXKE_js.PageHeader; }
675
675
  });
676
676
  Object.defineProperty(exports, "LocaleProvider", {
677
677
  enumerable: true,
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use client';
2
+ import './chunk-CHVTPN3K.mjs';
2
3
  import './chunk-BVQRDAR7.mjs';
3
4
  import './chunk-XTHC46M2.mjs';
4
- import './chunk-CHVTPN3K.mjs';
5
5
  export { PermissionMatrix } from './chunk-LVLJ75ND.mjs';
6
6
  export { Combobox, DatePicker, FileUpload, MonthPicker, YearPicker } from './chunk-YNU45Y5T.mjs';
7
7
  export { Popover } from './chunk-FA6526ME.mjs';
@@ -39,7 +39,7 @@ export { useDismiss } from './chunk-6P2TKRTL.mjs';
39
39
  export { usePopoverPosition } from './chunk-PRML6VEF.mjs';
40
40
  export { Portal } from './chunk-FKBQYQQD.mjs';
41
41
  export { BRAND_DEFAULTS, configureBrand, getBrand, resetBrand } from './chunk-5GEWIK4T.mjs';
42
- export { AppShell, PageHeader } from './chunk-Y6AYAE4O.mjs';
42
+ export { AppShell, PageHeader } from './chunk-E462CF6P.mjs';
43
43
  export { LocaleProvider, esMessages, useLocale } from './chunk-PQV7HHCJ.mjs';
44
44
  export { Button, ButtonGroup } from './chunk-NAL457NQ.mjs';
45
45
  export { AspectRatio, ScrollArea, Separator, Slot, Slottable } from './chunk-IEPKSPBX.mjs';