@naeil/ui 0.7.2 → 0.8.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.
@@ -343,13 +343,15 @@ var NativeLink = React.forwardRef(
343
343
  return /* @__PURE__ */ jsx4("a", __spreadValues({ ref }, props));
344
344
  }
345
345
  );
346
+ var NavigationSheetAction = React.createContext(void 0);
346
347
  function DesktopGroup({
347
348
  item,
348
349
  active,
349
350
  open,
350
351
  anotherGroupOpen,
351
352
  onOpenChange,
352
- children
353
+ children,
354
+ chrome
353
355
  }) {
354
356
  var _a;
355
357
  const hoverOpened = React.useRef(false);
@@ -428,7 +430,7 @@ function DesktopGroup({
428
430
  ),
429
431
  /* @__PURE__ */ jsx4(Popover.Portal, { children: /* @__PURE__ */ jsx4(
430
432
  Popover.Content,
431
- {
433
+ __spreadProps(__spreadValues({}, chrome), {
432
434
  ref: panel,
433
435
  "data-slot": "navigation-popover",
434
436
  className: "ui-navigation-popover ui-popup",
@@ -454,7 +456,7 @@ function DesktopGroup({
454
456
  event.preventDefault();
455
457
  },
456
458
  children: /* @__PURE__ */ jsx4("nav", { "aria-label": item.label, className: "ui-navigation-menu-grid", children })
457
- }
459
+ })
458
460
  ) })
459
461
  ]
460
462
  }
@@ -470,6 +472,8 @@ function Navigation(_a) {
470
472
  toolbar,
471
473
  mobileToolbar,
472
474
  mobileFooter,
475
+ mobileOpen: controlledOpen,
476
+ onMobileOpenChange,
473
477
  containerClassName,
474
478
  onNavigate,
475
479
  className
@@ -482,18 +486,75 @@ function Navigation(_a) {
482
486
  "toolbar",
483
487
  "mobileToolbar",
484
488
  "mobileFooter",
489
+ "mobileOpen",
490
+ "onMobileOpenChange",
485
491
  "containerClassName",
486
492
  "onNavigate",
487
493
  "className"
488
494
  ]);
489
- const [mobileOpen, setMobileOpen] = React.useState(false);
495
+ const [internalOpen, setInternalOpen] = React.useState(false);
496
+ const mobileOpen = controlledOpen != null ? controlledOpen : internalOpen;
497
+ const state = React.useRef({ open: mobileOpen, controlled: controlledOpen !== void 0, onChange: onMobileOpenChange });
498
+ const mounted = React.useRef(false);
499
+ const pendingAction = React.useRef(void 0);
500
+ const cancelAction = React.useCallback(() => {
501
+ var _a2;
502
+ clearTimeout((_a2 = pendingAction.current) == null ? void 0 : _a2.timer);
503
+ pendingAction.current = void 0;
504
+ }, []);
505
+ React.useLayoutEffect(() => {
506
+ const reopening = mobileOpen && !state.current.open;
507
+ state.current = { open: mobileOpen, controlled: controlledOpen !== void 0, onChange: onMobileOpenChange };
508
+ if (reopening) cancelAction();
509
+ });
510
+ React.useLayoutEffect(() => {
511
+ mounted.current = true;
512
+ return () => {
513
+ mounted.current = false;
514
+ cancelAction();
515
+ };
516
+ }, [cancelAction]);
517
+ const setMobileOpen = React.useCallback((next, owner) => {
518
+ var _a2, _b2;
519
+ if (next) cancelAction();
520
+ if (next === state.current.open) return;
521
+ if (pendingAction.current !== owner) cancelAction();
522
+ if (!state.current.controlled) {
523
+ state.current.open = next;
524
+ setInternalOpen(next);
525
+ }
526
+ (_b2 = (_a2 = state.current).onChange) == null ? void 0 : _b2.call(_a2, next);
527
+ }, [cancelAction]);
528
+ const chrome = "data-naeil-chrome" in props ? { "data-naeil-chrome": "", lang: props.lang } : {};
490
529
  const [openGroup, setOpenGroup] = React.useState(null);
491
530
  const trigger = React.useRef(null);
492
531
  const desktop = React.useRef(null);
532
+ const sheetContent = React.useRef(null);
533
+ function settleAction(flow) {
534
+ if (!mounted.current || pendingAction.current !== flow || state.current.open || !flow.menuClosed || !flow.sheetClosed || flow.timer !== void 0) return;
535
+ flow.timer = setTimeout(() => {
536
+ var _a2, _b2;
537
+ flow.timer = void 0;
538
+ if (!mounted.current || pendingAction.current !== flow) return;
539
+ if (state.current.open) {
540
+ cancelAction();
541
+ return;
542
+ }
543
+ if (!flow.menuClosed || !flow.sheetClosed) return;
544
+ const target = [trigger.current, (_b2 = (_a2 = desktop.current) == null ? void 0 : _a2.parentElement) == null ? void 0 : _b2.querySelector(".ui-navigation-toolbar [data-naeil-account-trigger]")].find((element) => (element == null ? void 0 : element.isConnected) && element.getBoundingClientRect().width && element.getBoundingClientRect().height);
545
+ cancelAction();
546
+ if (!target) return;
547
+ target.focus();
548
+ flow.action();
549
+ }, 0);
550
+ }
551
+ const previousHref = React.useRef(currentHref);
493
552
  React.useEffect(() => {
553
+ if (previousHref.current === currentHref) return;
554
+ previousHref.current = currentHref;
494
555
  setMobileOpen(false);
495
556
  setOpenGroup(null);
496
- }, [currentHref]);
557
+ }, [currentHref, setMobileOpen]);
497
558
  React.useEffect(() => {
498
559
  const element = desktop.current;
499
560
  if (!element || typeof ResizeObserver === "undefined") return;
@@ -503,7 +564,7 @@ function Navigation(_a) {
503
564
  });
504
565
  observer.observe(element);
505
566
  return () => observer.disconnect();
506
- }, []);
567
+ }, [setMobileOpen]);
507
568
  const active = (item) => {
508
569
  var _a2;
509
570
  return (_a2 = item.active) != null ? _a2 : !item.external && item.href === currentHref;
@@ -523,8 +584,10 @@ function Navigation(_a) {
523
584
  ),
524
585
  onClick: (event) => {
525
586
  onNavigate == null ? void 0 : onNavigate(event, item);
526
- if (event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey)
527
- close == null ? void 0 : close();
587
+ if (event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey) {
588
+ if (close === "mobile") setMobileOpen(false);
589
+ else if (close === "group") setOpenGroup(null);
590
+ }
528
591
  },
529
592
  children: [
530
593
  item.icon && /* @__PURE__ */ jsx4("span", { className: "ui-navigation-icon", "aria-hidden": "true", children: item.icon }),
@@ -559,6 +622,7 @@ function Navigation(_a) {
559
622
  (item) => "items" in item ? /* @__PURE__ */ jsx4(
560
623
  DesktopGroup,
561
624
  {
625
+ chrome,
562
626
  item,
563
627
  active: item.items.some(active),
564
628
  open: openGroup === item.id,
@@ -567,7 +631,7 @@ function Navigation(_a) {
567
631
  (current) => open ? item.id : current === item.id ? null : current
568
632
  ),
569
633
  children: item.items.map(
570
- (child) => link(child, () => setOpenGroup(null), true)
634
+ (child) => link(child, "group", true)
571
635
  )
572
636
  },
573
637
  item.id
@@ -596,12 +660,26 @@ function Navigation(_a) {
596
660
  ),
597
661
  /* @__PURE__ */ jsxs2(
598
662
  Dialog.Content,
599
- {
663
+ __spreadProps(__spreadValues({}, chrome), {
664
+ ref: (element) => {
665
+ if (element) sheetContent.current = element;
666
+ },
600
667
  "data-slot": "navigation-sheet",
601
668
  className: "ui-navigation-sheet ui-popup",
602
669
  "aria-describedby": void 0,
603
670
  onCloseAutoFocus: (event) => {
604
671
  var _a2, _b2;
672
+ if (controlledOpen !== void 0 && (!mounted.current || state.current.open)) {
673
+ event.preventDefault();
674
+ return;
675
+ }
676
+ const flow = pendingAction.current;
677
+ if (flow && event.target === flow.sheet) {
678
+ event.preventDefault();
679
+ flow.sheetClosed = true;
680
+ settleAction(flow);
681
+ return;
682
+ }
605
683
  if (trigger.current && trigger.current.getBoundingClientRect().width === 0) {
606
684
  event.preventDefault();
607
685
  (_b2 = (_a2 = desktop.current) == null ? void 0 : _a2.querySelector("button, a")) == null ? void 0 : _b2.focus();
@@ -628,16 +706,34 @@ function Navigation(_a) {
628
706
  (item) => "items" in item ? /* @__PURE__ */ jsxs2("section", { "aria-label": item.label, children: [
629
707
  /* @__PURE__ */ jsx4("h3", { className: "ui-navigation-group-label", children: item.label }),
630
708
  item.items.map(
631
- (child) => link(child, () => setMobileOpen(false), true)
709
+ (child) => link(child, "mobile", true)
632
710
  )
633
- ] }, item.id) : link(item, () => setMobileOpen(false))
711
+ ] }, item.id) : link(item, "mobile")
634
712
  )
635
713
  }
636
714
  ),
637
- (mobileToolbar != null ? mobileToolbar : toolbar) && /* @__PURE__ */ jsx4("div", { className: "ui-navigation-mobile-toolbar", children: mobileToolbar != null ? mobileToolbar : toolbar }),
715
+ (mobileToolbar != null ? mobileToolbar : toolbar) && /* @__PURE__ */ jsx4("div", { className: "ui-navigation-mobile-toolbar", children: /* @__PURE__ */ jsx4(NavigationSheetAction.Provider, { value: controlledOpen === void 0 ? void 0 : (action) => {
716
+ if (!mounted.current) return { menuClosed: () => {
717
+ }, cancel: () => {
718
+ } };
719
+ cancelAction();
720
+ const flow = { action, sheet: sheetContent.current, menuClosed: false, sheetClosed: false };
721
+ pendingAction.current = flow;
722
+ return {
723
+ menuClosed: () => {
724
+ if (!mounted.current || pendingAction.current !== flow) return;
725
+ flow.menuClosed = true;
726
+ setMobileOpen(false, flow);
727
+ settleAction(flow);
728
+ },
729
+ cancel: () => {
730
+ if (pendingAction.current === flow) cancelAction();
731
+ }
732
+ };
733
+ }, children: mobileToolbar != null ? mobileToolbar : toolbar }) }),
638
734
  mobileFooter && /* @__PURE__ */ jsx4("div", { className: "ui-navigation-mobile-footer", children: mobileFooter })
639
735
  ]
640
- }
736
+ })
641
737
  )
642
738
  ] })
643
739
  ] })
@@ -894,6 +990,7 @@ export {
894
990
  SelectSeparator,
895
991
  SelectScrollUpButton,
896
992
  SelectScrollDownButton,
993
+ NavigationSheetAction,
897
994
  Navigation,
898
995
  DropdownMenu,
899
996
  DropdownMenuPortal,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  Logo,
4
4
  uiRelease
5
- } from "./chunk-7JBLPGZ4.js";
5
+ } from "./chunk-WA5D7UI2.js";
6
6
  import {
7
7
  Badge,
8
8
  Button,
@@ -13,12 +13,13 @@ import {
13
13
  DropdownMenuSeparator,
14
14
  DropdownMenuTrigger,
15
15
  Navigation,
16
+ NavigationSheetAction,
16
17
  Select,
17
18
  SelectContent,
18
19
  SelectItem,
19
20
  SelectTrigger,
20
21
  SelectValue
21
- } from "./chunk-QQQQZEPV.js";
22
+ } from "./chunk-KPE4KKYM.js";
22
23
  import {
23
24
  __objRest,
24
25
  __spreadProps,
@@ -177,6 +178,7 @@ var headerContent = {
177
178
 
178
179
  // src/components/naeil-header-account.tsx
179
180
  import { UserRound } from "lucide-react";
181
+ import { useContext, useRef } from "react";
180
182
  import { jsx, jsxs } from "react/jsx-runtime";
181
183
  var labels = {
182
184
  en: { menu: "Account menu", account: "Account", login: "Log in", logout: "Log out", busy: "Logging out\u2026" },
@@ -186,10 +188,18 @@ var labels = {
186
188
  var NativeLink = (props) => /* @__PURE__ */ jsx("a", __spreadValues({}, props));
187
189
  function NaeilHeaderAccountControl({ locale, account, Link = NativeLink }) {
188
190
  const text = labels[locale];
191
+ const handoff = useContext(NavigationSheetAction);
192
+ const pendingAction = useRef(void 0);
189
193
  if (account.status === "signed-out") {
190
194
  return /* @__PURE__ */ jsx(Link, { href: account.loginHref, className: "ui-navigation-link ui-focus naeil-header-login", "data-naeil-account-state": "signed-out", children: text.login });
191
195
  }
192
- return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
196
+ return /* @__PURE__ */ jsxs(DropdownMenu, { onOpenChange: (open) => {
197
+ var _a;
198
+ if (open) {
199
+ (_a = pendingAction.current) == null ? void 0 : _a.cancel();
200
+ pendingAction.current = void 0;
201
+ }
202
+ }, children: [
193
203
  /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
194
204
  "button",
195
205
  {
@@ -202,24 +212,46 @@ function NaeilHeaderAccountControl({ locale, account, Link = NativeLink }) {
202
212
  children: /* @__PURE__ */ jsx("span", { className: "naeil-header-account-avatar", "aria-hidden": "true", children: /* @__PURE__ */ jsx(UserRound, {}) })
203
213
  }
204
214
  ) }),
205
- /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-56 max-w-[calc(100vw-2rem)]", "data-naeil-account-menu": true, children: [
206
- /* @__PURE__ */ jsxs(DropdownMenuLabel, { className: "flex min-w-0 flex-col font-normal", children: [
207
- /* @__PURE__ */ jsx("span", { className: "truncate text-base font-medium", children: account.displayName || text.account }),
208
- account.email && /* @__PURE__ */ jsx("span", { className: "truncate text-sm text-muted-foreground", children: account.email })
209
- ] }),
210
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
211
- /* @__PURE__ */ jsx(
212
- DropdownMenuItem,
213
- {
214
- className: "min-h-11",
215
- disabled: account.busy,
216
- onSelect: () => {
217
- if (!account.busy) account.onLogout();
218
- },
219
- children: account.busy ? text.busy : text.logout
220
- }
221
- )
222
- ] })
215
+ /* @__PURE__ */ jsxs(
216
+ DropdownMenuContent,
217
+ {
218
+ align: "end",
219
+ className: "w-56 max-w-[calc(100vw-2rem)]",
220
+ "data-naeil-account-menu": true,
221
+ "data-naeil-chrome": "",
222
+ lang: locale,
223
+ onCloseAutoFocus: (event) => {
224
+ const flow = pendingAction.current;
225
+ if (!flow || event.target !== flow.menu) return;
226
+ event.preventDefault();
227
+ flow.menu = null;
228
+ flow.menuClosed();
229
+ },
230
+ children: [
231
+ /* @__PURE__ */ jsxs(DropdownMenuLabel, { className: "flex min-w-0 flex-col font-normal", children: [
232
+ /* @__PURE__ */ jsx("span", { className: "truncate text-base font-medium", children: account.displayName || text.account }),
233
+ account.email && /* @__PURE__ */ jsx("span", { className: "truncate text-sm text-muted-foreground", children: account.email })
234
+ ] }),
235
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
236
+ /* @__PURE__ */ jsx(
237
+ DropdownMenuItem,
238
+ {
239
+ className: "min-h-11",
240
+ disabled: account.busy,
241
+ onSelect: (event) => {
242
+ if (account.busy) return;
243
+ if (handoff) {
244
+ const menu = event.target.closest("[data-naeil-account-menu]");
245
+ if (!(menu == null ? void 0 : menu.isConnected)) return;
246
+ pendingAction.current = __spreadProps(__spreadValues({}, handoff(account.onLogout)), { menu });
247
+ } else account.onLogout();
248
+ },
249
+ children: account.busy ? text.busy : text.logout
250
+ }
251
+ )
252
+ ]
253
+ }
254
+ )
223
255
  ] });
224
256
  }
225
257
 
@@ -254,7 +286,7 @@ function NaeilHeaderLocaleControl({ locale, onLocaleChange }) {
254
286
  children: /* @__PURE__ */ jsx2(SelectValue, { children: locale.toUpperCase() })
255
287
  }
256
288
  ),
257
- /* @__PURE__ */ jsx2(SelectContent, { align: "end", children: headerLocales.map((value) => /* @__PURE__ */ jsx2(SelectItem, { value, className: "min-h-11", lang: value, children: headerLocaleNames[value] }, value)) })
289
+ /* @__PURE__ */ jsx2(SelectContent, { align: "end", "data-naeil-chrome": "", "data-naeil-locale-menu": "", lang: locale, children: headerLocales.map((value) => /* @__PURE__ */ jsx2(SelectItem, { value, className: "min-h-11", lang: value, children: headerLocaleNames[value] }, value)) })
258
290
  ] });
259
291
  }
260
292
  var NativeLink2 = (props) => /* @__PURE__ */ jsx2("a", __spreadValues({}, props));
@@ -264,6 +296,9 @@ function NaeilHeader(_a) {
264
296
  resolveHref = (path) => `https://naeil.dev/${locale}${path === "/" ? "" : path}`,
265
297
  brandHref,
266
298
  brandSlot,
299
+ brandSuffix,
300
+ statusSlot,
301
+ appNavigation,
267
302
  brandLinkProps,
268
303
  brandLinkComponent,
269
304
  onLocaleChange,
@@ -288,6 +323,9 @@ function NaeilHeader(_a) {
288
323
  "resolveHref",
289
324
  "brandHref",
290
325
  "brandSlot",
326
+ "brandSuffix",
327
+ "statusSlot",
328
+ "appNavigation",
291
329
  "brandLinkProps",
292
330
  "brandLinkComponent",
293
331
  "onLocaleChange",
@@ -330,41 +368,61 @@ function NaeilHeader(_a) {
330
368
  const brandDestination = brandHref != null ? brandHref : resolveHref("/");
331
369
  const BrandLink = brandLinkComponent != null ? brandLinkComponent : Link;
332
370
  const _a2 = brandLinkProps != null ? brandLinkProps : {}, { onClick: onBrandClick } = _a2, brandProps = __objRest(_a2, ["onClick"]);
333
- const toolbar = /* @__PURE__ */ jsx2("div", { "data-app-toolbar": true, className: "naeil-header-controls", children: toolbarSlot !== void 0 ? toolbarSlot : /* @__PURE__ */ jsxs2(Fragment, { children: [
334
- /* @__PURE__ */ jsx2(NaeilHeaderThemeControl, { locale }),
335
- onLocaleChange && /* @__PURE__ */ jsx2(NaeilHeaderLocaleControl, { locale, onLocaleChange }),
336
- authSlot && /* @__PURE__ */ jsxs2(Fragment, { children: [
337
- /* @__PURE__ */ jsx2("div", { "aria-hidden": "true", className: "naeil-header-separator" }),
338
- authSlot
339
- ] })
340
- ] }) });
371
+ const toolbar = /* @__PURE__ */ jsx2(
372
+ "div",
373
+ {
374
+ "data-app-toolbar": true,
375
+ className: "naeil-header-controls",
376
+ "data-naeil-chrome": toolbarSlot === void 0 ? "" : void 0,
377
+ lang: toolbarSlot === void 0 ? locale : void 0,
378
+ children: toolbarSlot !== void 0 ? toolbarSlot : /* @__PURE__ */ jsxs2(Fragment, { children: [
379
+ /* @__PURE__ */ jsx2(NaeilHeaderThemeControl, { locale }),
380
+ onLocaleChange && /* @__PURE__ */ jsx2(NaeilHeaderLocaleControl, { locale, onLocaleChange }),
381
+ authSlot && /* @__PURE__ */ jsxs2(Fragment, { children: [
382
+ /* @__PURE__ */ jsx2("div", { "aria-hidden": "true", className: "naeil-header-separator" }),
383
+ authSlot
384
+ ] })
385
+ ] })
386
+ }
387
+ );
388
+ const logo = /* @__PURE__ */ jsx2(Logo, { variant: "horizontal", size: 28, className: "block", label: null });
389
+ const brand = /* @__PURE__ */ jsx2(
390
+ BrandLink,
391
+ __spreadProps(__spreadValues({
392
+ href: brandDestination,
393
+ "data-app-brand": true,
394
+ "aria-label": brandSlot == null ? ".naeil" : void 0
395
+ }, brandProps), {
396
+ onClick: (event) => {
397
+ onBrandClick == null ? void 0 : onBrandClick(event);
398
+ onNavigate == null ? void 0 : onNavigate(event, { id: "brand", href: brandDestination, label: ".naeil" });
399
+ },
400
+ children: brandSlot != null ? brandSlot : brandSuffix ? /* @__PURE__ */ jsxs2(Fragment, { children: [
401
+ logo,
402
+ /* @__PURE__ */ jsx2("span", { className: "naeil-header-brand-suffix", children: brandSuffix })
403
+ ] }) : logo
404
+ })
405
+ );
341
406
  return /* @__PURE__ */ jsx2(
342
407
  Navigation,
343
408
  __spreadProps(__spreadValues({}, props), {
344
409
  "data-global-header": true,
345
410
  "data-naeil-header": true,
411
+ "data-naeil-chrome": "",
412
+ lang: locale,
346
413
  "data-naeil-ui-version": uiRelease.version,
347
414
  "data-naeil-ui-contract": uiRelease.contractVersion,
348
415
  Link,
349
416
  currentHref,
350
417
  onNavigate,
351
- brand: /* @__PURE__ */ jsx2(
352
- BrandLink,
353
- __spreadProps(__spreadValues({
354
- href: brandDestination,
355
- "data-app-brand": true,
356
- "aria-label": brandSlot == null ? ".naeil" : void 0
357
- }, brandProps), {
358
- onClick: (event) => {
359
- onBrandClick == null ? void 0 : onBrandClick(event);
360
- onNavigate == null ? void 0 : onNavigate(event, { id: "brand", href: brandDestination, label: ".naeil" });
361
- },
362
- children: brandSlot != null ? brandSlot : /* @__PURE__ */ jsx2(Logo, { variant: "horizontal", size: 28, className: "block", label: null })
363
- })
364
- ),
418
+ brand: statusSlot != null ? /* @__PURE__ */ jsxs2("div", { className: "naeil-header-brand-row", children: [
419
+ brand,
420
+ statusSlot
421
+ ] }) : brand,
365
422
  items: [
366
423
  ...showProjects ? [{ id: "projects", label: (_b2 = translations == null ? void 0 : translations.projects) != null ? _b2 : content.nav.projects, items: projectLinks, columns: projectLinks.length > 1 ? 2 : 1 }] : [],
367
424
  ...showBlog ? [{ id: "blog", label: (_c = translations == null ? void 0 : translations.blog) != null ? _c : content.nav.blog, href: resolveHref("/blog"), external: projectsExternal }] : [],
425
+ ...appNavigation != null ? appNavigation : [],
368
426
  ...(subNav != null ? subNav : []).map((item) => __spreadProps(__spreadValues({}, item), { id: item.href }))
369
427
  ],
370
428
  labels: labels2 != null ? labels2 : { navigation: content.nav.navigation, menu: content.nav.menu, close: content.nav.closeMenu },
@@ -1165,7 +1165,7 @@ function Logo(_a) {
1165
1165
  }
1166
1166
 
1167
1167
  // src/lib/ui-release.ts
1168
- var uiRelease = { version: "0.7.2", contractVersion: "1" };
1168
+ var uiRelease = { version: "0.8.0", contractVersion: "1" };
1169
1169
 
1170
1170
  export {
1171
1171
  Logo,
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { N as NavigationLink, a as NavigationProps } from '../navigation-CgPeL9tF.js';
3
- import { S as SiteFooterProps } from '../site-footer-vXDa_6yr.js';
2
+ import { N as NavigationLink, a as NavigationProps } from '../navigation-D8N1tMTu.js';
3
+ import { S as SiteFooterProps } from '../site-footer-s113FZgC.js';
4
4
  import { ThemeProvider as ThemeProvider$1 } from 'next-themes';
5
5
  import * as React$1 from 'react';
6
6
  import { SVGProps } from 'react';
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  NaeilHeader,
4
4
  headerLocales
5
- } from "../chunk-MGCCKOGU.js";
5
+ } from "../chunk-ULZPJI5X.js";
6
6
  import {
7
7
  Logo
8
- } from "../chunk-7JBLPGZ4.js";
8
+ } from "../chunk-WA5D7UI2.js";
9
9
  import {
10
10
  SiteFooter
11
11
  } from "../chunk-HSTDPY56.js";
@@ -15,7 +15,7 @@ import {
15
15
  DropdownMenuContent,
16
16
  DropdownMenuItem,
17
17
  DropdownMenuTrigger
18
- } from "../chunk-QQQQZEPV.js";
18
+ } from "../chunk-KPE4KKYM.js";
19
19
  import {
20
20
  __objRest,
21
21
  __spreadProps,
@@ -1,8 +1,8 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { S as SiteFooterProps } from '../site-footer-vXDa_6yr.js';
2
+ import { S as SiteFooterProps } from '../site-footer-s113FZgC.js';
3
3
  import { N as NaeilHeaderLocale } from '../naeil-header-content-BvISJ4RV.js';
4
4
  import 'react';
5
- import '../navigation-CgPeL9tF.js';
5
+ import '../navigation-D8N1tMTu.js';
6
6
 
7
7
  type NaeilFooterLocale = NaeilHeaderLocale;
8
8
  interface NaeilFooterProps extends Omit<SiteFooterProps, "brand" | "description" | "groups"> {
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  Logo,
5
5
  uiRelease
6
- } from "../chunk-7JBLPGZ4.js";
6
+ } from "../chunk-WA5D7UI2.js";
7
7
  import {
8
8
  SiteFooter
9
9
  } from "../chunk-HSTDPY56.js";
@@ -44,6 +44,8 @@ function NaeilFooter(_a) {
44
44
  Link,
45
45
  onNavigate,
46
46
  "data-naeil-footer": true,
47
+ "data-naeil-chrome": "",
48
+ lang: locale,
47
49
  "data-naeil-ui-version": uiRelease.version,
48
50
  "data-naeil-ui-contract": uiRelease.contractVersion,
49
51
  brand: /* @__PURE__ */ jsx(
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { b as NavigationLinkComponent, a as NavigationProps, c as NavigationLinkProps, N as NavigationLink } from '../navigation-CgPeL9tF.js';
3
+ import { b as NavigationLinkComponent, a as NavigationProps, c as NavigationItem, d as NavigationLinkProps, N as NavigationLink } from '../navigation-D8N1tMTu.js';
4
4
  import { N as NaeilHeaderLocale } from '../naeil-header-content-BvISJ4RV.js';
5
5
 
6
6
  type NaeilHeaderAccount = {
@@ -29,6 +29,12 @@ interface NaeilHeaderProps extends Omit<NavigationProps, "brand" | "items" | "to
29
29
  resolveHref?: (path: string) => string;
30
30
  brandHref?: string;
31
31
  brandSlot?: ReactNode;
32
+ /** Ignored when brandSlot replaces the complete brand content. */
33
+ brandSuffix?: string;
34
+ /** After the brand link, outside it; rendered once at every width. */
35
+ statusSlot?: ReactNode;
36
+ /** Product menu data, after catalog/blog and before flat subNav links. */
37
+ appNavigation?: NavigationItem[];
32
38
  brandLinkProps?: Omit<NavigationLinkProps, "href" | "children">;
33
39
  /** Omit when the application does not support changing its UI language. */
34
40
  onLocaleChange?: (locale: NaeilHeaderLocale) => void;
@@ -67,6 +73,6 @@ declare function NaeilHeaderLocaleControl({ locale, onLocaleChange }: {
67
73
  onLocaleChange: (locale: NaeilHeaderLocale) => void;
68
74
  }): react_jsx_runtime.JSX.Element;
69
75
  /** One complete, opt-in branded composition shared by naeil.dev and applications. */
70
- declare function NaeilHeader({ locale, resolveHref, brandHref, brandSlot, brandLinkProps, brandLinkComponent, onLocaleChange, authSlot, toolbarSlot, projects, projectsExternal, translations, showProjects, showBlog, subNav, currentProjectKey, currentProjectHref, labels, Link, currentHref, onNavigate, className, containerClassName, ...props }: NaeilHeaderProps): react_jsx_runtime.JSX.Element;
76
+ declare function NaeilHeader({ locale, resolveHref, brandHref, brandSlot, brandSuffix, statusSlot, appNavigation, brandLinkProps, brandLinkComponent, onLocaleChange, authSlot, toolbarSlot, projects, projectsExternal, translations, showProjects, showBlog, subNav, currentProjectKey, currentProjectHref, labels, Link, currentHref, onNavigate, className, containerClassName, ...props }: NaeilHeaderProps): react_jsx_runtime.JSX.Element;
71
77
 
72
78
  export { NaeilHeader, type NaeilHeaderAccount, NaeilHeaderAccountControl, type NaeilHeaderAccountControlProps, NaeilHeaderLocale, NaeilHeaderLocaleControl, type NaeilHeaderProps, NaeilHeaderThemeControl };
@@ -5,9 +5,9 @@ import {
5
5
  NaeilHeaderAccountControl,
6
6
  NaeilHeaderLocaleControl,
7
7
  NaeilHeaderThemeControl
8
- } from "../chunk-MGCCKOGU.js";
9
- import "../chunk-7JBLPGZ4.js";
10
- import "../chunk-QQQQZEPV.js";
8
+ } from "../chunk-ULZPJI5X.js";
9
+ import "../chunk-WA5D7UI2.js";
10
+ import "../chunk-KPE4KKYM.js";
11
11
  import "../chunk-JBTDRVZ7.js";
12
12
  export {
13
13
  NaeilHeader,
@@ -4,8 +4,8 @@ import { Avatar as Avatar$1, Dialog as Dialog$1, DropdownMenu as DropdownMenu$1,
4
4
  import * as class_variance_authority_types from 'class-variance-authority/types';
5
5
  import { VariantProps } from 'class-variance-authority';
6
6
  import { ToasterProps } from 'sonner';
7
- export { d as Navigation, e as NavigationGroup, f as NavigationItem, N as NavigationLink, b as NavigationLinkComponent, c as NavigationLinkProps, a as NavigationProps } from '../../navigation-CgPeL9tF.js';
8
- export { a as SiteFooter, S as SiteFooterProps } from '../../site-footer-vXDa_6yr.js';
7
+ export { e as Navigation, f as NavigationGroup, c as NavigationItem, N as NavigationLink, b as NavigationLinkComponent, d as NavigationLinkProps, a as NavigationProps } from '../../navigation-D8N1tMTu.js';
8
+ export { a as SiteFooter, S as SiteFooterProps } from '../../site-footer-s113FZgC.js';
9
9
 
10
10
  declare function Avatar({ className, size, ...props }: React.ComponentProps<typeof Avatar$1.Root> & {
11
11
  size?: "default" | "sm" | "lg";
@@ -33,7 +33,7 @@ import {
33
33
  SelectValue,
34
34
  badgeVariants,
35
35
  buttonVariants
36
- } from "../../chunk-QQQQZEPV.js";
36
+ } from "../../chunk-KPE4KKYM.js";
37
37
  import {
38
38
  __objRest,
39
39
  __spreadProps,
@@ -1 +1 @@
1
- export declare const uiRelease: Readonly<{version: "0.7.2"; contractVersion: "1"}>;
1
+ export declare const uiRelease: Readonly<{version: "0.8.0"; contractVersion: "1"}>;
@@ -1 +1 @@
1
- export const uiRelease = Object.freeze({"version":"0.7.2","contractVersion":"1"});
1
+ export const uiRelease = Object.freeze({"version":"0.8.0","contractVersion":"1"});
@@ -38,11 +38,13 @@ interface NavigationProps extends Omit<React.ComponentPropsWithoutRef<"header">,
38
38
  toolbar?: React.ReactNode;
39
39
  mobileToolbar?: React.ReactNode;
40
40
  mobileFooter?: React.ReactNode;
41
+ mobileOpen?: boolean;
42
+ onMobileOpenChange?: (open: boolean) => void;
41
43
  /** Use the same product-owned frame class on header, footer and main. */
42
44
  containerClassName?: string;
43
45
  /** Preserve modified clicks; applications may preventDefault for client routing/guards. */
44
46
  onNavigate?: (event: React.MouseEvent<HTMLAnchorElement>, item: NavigationLink) => void;
45
47
  }
46
- declare function Navigation({ brand, items, labels, Link, currentHref, toolbar, mobileToolbar, mobileFooter, containerClassName, onNavigate, className, ...props }: NavigationProps): react_jsx_runtime.JSX.Element;
48
+ declare function Navigation({ brand, items, labels, Link, currentHref, toolbar, mobileToolbar, mobileFooter, mobileOpen: controlledOpen, onMobileOpenChange, containerClassName, onNavigate, className, ...props }: NavigationProps): react_jsx_runtime.JSX.Element;
47
49
 
48
- export { type NavigationLink as N, type NavigationProps as a, type NavigationLinkComponent as b, type NavigationLinkProps as c, Navigation as d, type NavigationGroup as e, type NavigationItem as f };
50
+ export { type NavigationLink as N, type NavigationProps as a, type NavigationLinkComponent as b, type NavigationItem as c, type NavigationLinkProps as d, Navigation as e, type NavigationGroup as f };
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
- import { N as NavigationLink, b as NavigationLinkComponent, a as NavigationProps } from './navigation-CgPeL9tF.js';
3
+ import { N as NavigationLink, b as NavigationLinkComponent, a as NavigationProps } from './navigation-D8N1tMTu.js';
4
4
 
5
5
  interface SiteFooterProps extends React.ComponentPropsWithoutRef<"footer"> {
6
6
  brand?: React.ReactNode;
@@ -63,6 +63,8 @@ function NaeilFooter(_a) {
63
63
  Link,
64
64
  onNavigate,
65
65
  "data-naeil-footer": true,
66
+ "data-naeil-chrome": "",
67
+ lang: locale,
66
68
  "data-naeil-ui-version": uiRelease.version,
67
69
  "data-naeil-ui-contract": uiRelease.contractVersion,
68
70
  brand: /* @__PURE__ */ jsx(