@codbex/harmonia 1.11.0 → 1.12.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.
@@ -6770,13 +6770,13 @@ function list_default(Alpine) {
6770
6770
  // src/components/menu.js
6771
6771
  function menu_default(Alpine) {
6772
6772
  Alpine.directive("h-menu-trigger", (el, { modifiers }) => {
6773
- el._menu_trigger = {
6773
+ el._h_menu_trigger = {
6774
6774
  isDropdown: modifiers.includes("dropdown"),
6775
6775
  setOpen(open) {
6776
6776
  el.setAttribute("aria-expanded", open);
6777
6777
  }
6778
6778
  };
6779
- if (el._menu_trigger.isDropdown) {
6779
+ if (el._h_menu_trigger.isDropdown) {
6780
6780
  el.setAttribute("aria-haspopup", "true");
6781
6781
  el.setAttribute("aria-expanded", "false");
6782
6782
  if (!el.hasAttribute("id")) {
@@ -6818,10 +6818,10 @@ function menu_default(Alpine) {
6818
6818
  const menuTrigger = (() => {
6819
6819
  if (isSubmenu) return;
6820
6820
  let sibling = el.previousElementSibling;
6821
- while (sibling && !Object.prototype.hasOwnProperty.call(sibling, "_menu_trigger")) {
6821
+ while (sibling && !Object.prototype.hasOwnProperty.call(sibling, "_h_menu_trigger")) {
6822
6822
  sibling = sibling.previousElementSibling;
6823
6823
  }
6824
- if (!Object.prototype.hasOwnProperty.call(sibling, "_menu_trigger")) {
6824
+ if (!Object.prototype.hasOwnProperty.call(sibling, "_h_menu_trigger")) {
6825
6825
  throw new Error(`${original} menu must be placed after a menu trigger element`);
6826
6826
  }
6827
6827
  return sibling;
@@ -6843,16 +6843,22 @@ function menu_default(Alpine) {
6843
6843
  }
6844
6844
  setAriaAttrubutes(menuSubItem);
6845
6845
  } else if (menuTrigger) {
6846
- setAriaAttrubutes(menuTrigger._menu_trigger.isDropdown ? menuTrigger : void 0);
6846
+ if (menuTrigger._h_menu_trigger.isDropdown) {
6847
+ if (!el.hasAttribute("id")) {
6848
+ el.setAttribute("id", `m${uuid_default()}`);
6849
+ }
6850
+ menuTrigger.setAttribute("aria-controls", el.getAttribute("id"));
6851
+ setAriaAttrubutes(menuTrigger);
6852
+ } else setAriaAttrubutes();
6847
6853
  } else {
6848
6854
  setAriaAttrubutes();
6849
6855
  }
6850
6856
  function listenForTrigger(listen) {
6851
6857
  if (listen) {
6852
- if (menuTrigger._menu_trigger.isDropdown) menuTrigger.addEventListener("click", openDropdown);
6858
+ if (menuTrigger._h_menu_trigger.isDropdown) menuTrigger.addEventListener("click", openDropdown);
6853
6859
  else menuTrigger.addEventListener("contextmenu", onContextmenu);
6854
6860
  } else {
6855
- if (menuTrigger._menu_trigger.isDropdown) menuTrigger.removeEventListener("click", openDropdown);
6861
+ if (menuTrigger._h_menu_trigger.isDropdown) menuTrigger.removeEventListener("click", openDropdown);
6856
6862
  else menuTrigger.removeEventListener("contextmenu", onContextmenu);
6857
6863
  }
6858
6864
  }
@@ -6881,8 +6887,8 @@ function menu_default(Alpine) {
6881
6887
  } else {
6882
6888
  listenForTrigger(true);
6883
6889
  if (focusTrigger) menuTrigger.focus();
6884
- if (menuTrigger._menu_trigger.isDropdown) {
6885
- menuTrigger._menu_trigger.setOpen(false);
6890
+ if (menuTrigger._h_menu_trigger.isDropdown) {
6891
+ menuTrigger._h_menu_trigger.setOpen(false);
6886
6892
  }
6887
6893
  }
6888
6894
  }
@@ -6997,7 +7003,7 @@ function menu_default(Alpine) {
6997
7003
  let getPlacement = function() {
6998
7004
  if (isSubmenu) {
6999
7005
  return "right-start";
7000
- } else if (menuTrigger._menu_trigger.isDropdown) {
7006
+ } else if (menuTrigger._h_menu_trigger.isDropdown) {
7001
7007
  return el.getAttribute("data-align") || "bottom-start";
7002
7008
  }
7003
7009
  return "right-start";
@@ -7042,7 +7048,7 @@ function menu_default(Alpine) {
7042
7048
  el.classList.remove("hidden");
7043
7049
  el.pauseKeyEvents = false;
7044
7050
  let firstOpen = true;
7045
- if (!isSubmenu && menuTrigger._menu_trigger.isDropdown) {
7051
+ if (!isSubmenu && menuTrigger._h_menu_trigger.isDropdown) {
7046
7052
  autoUpdateCleanup = autoUpdate(parent, el, updatePosition);
7047
7053
  } else {
7048
7054
  updatePosition();
@@ -7050,8 +7056,8 @@ function menu_default(Alpine) {
7050
7056
  }
7051
7057
  }
7052
7058
  function openDropdown() {
7053
- if (menuTrigger._menu_trigger.isDropdown) {
7054
- menuTrigger._menu_trigger.setOpen(true);
7059
+ if (menuTrigger._h_menu_trigger.isDropdown) {
7060
+ menuTrigger._h_menu_trigger.setOpen(true);
7055
7061
  }
7056
7062
  open(menuTrigger);
7057
7063
  }
@@ -7077,6 +7083,10 @@ function menu_default(Alpine) {
7077
7083
  menuSubItem._menu_sub.open = open;
7078
7084
  menuSubItem._menu_sub.close = close;
7079
7085
  } else {
7086
+ if (menuTrigger._h_menu_trigger.navItem) {
7087
+ menuTrigger._h_menu_trigger.openMenu = openDropdown;
7088
+ menuTrigger._h_menu_trigger.closeMenu = close;
7089
+ }
7080
7090
  listenForTrigger(true);
7081
7091
  }
7082
7092
  function onTransitionEnd(event) {
@@ -7445,6 +7455,154 @@ function menu_default(Alpine) {
7445
7455
  });
7446
7456
  }
7447
7457
 
7458
+ // src/components/navigation-menu.js
7459
+ var navItemTriggerClasses = [
7460
+ "inline-flex",
7461
+ "h-9",
7462
+ "w-max",
7463
+ "items-center",
7464
+ "justify-center",
7465
+ "rounded-control",
7466
+ "px-3",
7467
+ "py-2",
7468
+ "text-sm",
7469
+ "font-medium",
7470
+ "whitespace-nowrap",
7471
+ "gap-1.5",
7472
+ "transition-colors",
7473
+ "duration-100",
7474
+ "motion-reduce:transition-none",
7475
+ "hover:bg-secondary-hover",
7476
+ "hover:text-secondary-foreground",
7477
+ "focus:bg-secondary-hover",
7478
+ "focus:text-secondary-foreground",
7479
+ "outline-ring/50",
7480
+ "focus-visible:outline-[calc(var(--spacing)*0.75)]",
7481
+ "focus-visible:outline",
7482
+ "cursor-pointer",
7483
+ "shrink-0",
7484
+ "[&_svg]:shrink-0",
7485
+ "[&_svg:not([class*='size-'])]:size-4",
7486
+ "has-[>svg]:px-2.5"
7487
+ ];
7488
+ function navigation_menu_default(Alpine) {
7489
+ Alpine.directive("h-nav", (el, { original }) => {
7490
+ if (el.tagName !== "NAV") {
7491
+ throw new Error(`${original} must be a nav element`);
7492
+ }
7493
+ if (!el.hasAttribute("aria-label")) {
7494
+ throw new Error(`${original} must have an "aria-label" attribute`);
7495
+ }
7496
+ el.classList.add("relative", "z-10", "flex", "items-center");
7497
+ el.setAttribute("data-slot", "nav");
7498
+ });
7499
+ Alpine.directive("h-nav-list", (el, { original }, { Alpine: Alpine2 }) => {
7500
+ if (el.tagName !== "UL") {
7501
+ throw new Error(`${original} must be a ul element`);
7502
+ }
7503
+ const nav = Alpine2.findClosest(el.parentElement, (parent) => parent.getAttribute("data-slot") === "nav");
7504
+ if (!nav) {
7505
+ throw new Error(`${original} must be inside a ${Alpine2.prefixed("h-nav")} element`);
7506
+ }
7507
+ el.classList.add("flex", "flex-1", "list-none", "items-center", "gap-1");
7508
+ el.setAttribute("data-slot", "nav-list");
7509
+ });
7510
+ Alpine.directive("h-nav-item", (el, { original }) => {
7511
+ if (el.tagName !== "LI") {
7512
+ throw new Error(`${original} must be a li element`);
7513
+ }
7514
+ if (el.parentElement?.getAttribute("data-slot") !== "nav-list") {
7515
+ throw new Error(`${original} must be a direct child of a x-h-nav-list element`);
7516
+ }
7517
+ el.classList.add("relative");
7518
+ el.setAttribute("data-slot", "nav-item");
7519
+ });
7520
+ Alpine.directive("h-nav-trigger", (el, { original }, { cleanup, Alpine: Alpine2 }) => {
7521
+ if (el.tagName !== "BUTTON") {
7522
+ throw new Error(`${original} must be a button element`);
7523
+ }
7524
+ const navItem = Alpine2.findClosest(el.parentElement, (parent) => parent.getAttribute("data-slot") === "nav-item");
7525
+ if (!navItem) {
7526
+ throw new Error(`${original} must be inside a ${Alpine2.prefixed("h-nav-item")} element`);
7527
+ }
7528
+ if (!el.hasAttribute("id")) {
7529
+ el.setAttribute("id", `nnt${uuid_default()}`);
7530
+ }
7531
+ const chevron = createSvg({
7532
+ icon: ChevronDown,
7533
+ classes: "size-4 shrink-0 transition-transform duration-200 motion-reduce:transition-none [[data-state=open]_&]:rotate-180",
7534
+ attrs: { "aria-hidden": "true", role: "presentation" }
7535
+ });
7536
+ el._h_menu_trigger = {
7537
+ isDropdown: true,
7538
+ navItem: true,
7539
+ openMenu: void 0,
7540
+ closeMenu: void 0,
7541
+ setOpen(open) {
7542
+ el.setAttribute("aria-expanded", String(open));
7543
+ el.setAttribute("data-state", open ? "open" : "closed");
7544
+ }
7545
+ };
7546
+ el.setAttribute("aria-haspopup", "menu");
7547
+ el.setAttribute("aria-expanded", "false");
7548
+ el.setAttribute("data-state", "closed");
7549
+ el.classList.add("bg-transparent", "data-[state=open]:bg-secondary-hover", "disabled:opacity-50", "disabled:pointer-events-none", ...navItemTriggerClasses);
7550
+ el.appendChild(chevron);
7551
+ el.setAttribute("data-slot", "nav-trigger");
7552
+ const nav = Alpine2.findClosest(el.parentElement, (p) => p.getAttribute("data-slot") === "nav");
7553
+ let cancelHoverCleanup = null;
7554
+ if (nav?.hasAttribute("data-open-on-hover")) {
7555
+ let scheduleClose = function() {
7556
+ closeTimer = setTimeout(() => {
7557
+ el._h_menu_trigger.closeMenu?.();
7558
+ closeTimer = null;
7559
+ }, 100);
7560
+ }, cancelClose = function() {
7561
+ if (closeTimer) {
7562
+ clearTimeout(closeTimer);
7563
+ closeTimer = null;
7564
+ }
7565
+ }, onNavItemEnter = function() {
7566
+ cancelClose();
7567
+ el._h_menu_trigger.openMenu?.();
7568
+ };
7569
+ el.classList.remove("cursor-pointer");
7570
+ let closeTimer = null;
7571
+ navItem.addEventListener("mouseenter", onNavItemEnter);
7572
+ navItem.addEventListener("mouseleave", scheduleClose);
7573
+ cancelHoverCleanup = () => {
7574
+ cancelClose();
7575
+ navItem.removeEventListener("mouseenter", onNavItemEnter);
7576
+ navItem.removeEventListener("mouseleave", scheduleClose);
7577
+ };
7578
+ }
7579
+ cleanup(() => {
7580
+ if (cancelHoverCleanup) cancelHoverCleanup();
7581
+ if (chevron.parentElement === el) el.removeChild(chevron);
7582
+ });
7583
+ });
7584
+ Alpine.directive("h-nav-link", (el, { original }, { cleanup }) => {
7585
+ if (el.tagName !== "A" && el.tagName !== "BUTTON") {
7586
+ throw new Error(`${original} must be an anchor or button element`);
7587
+ } else if (el.tagName === "BUTTON") {
7588
+ el.setAttribute("type", "button");
7589
+ }
7590
+ el.classList.add(...navItemTriggerClasses, "no-underline", "text-inherit", "data-[active]:bg-secondary-hover", "data-[active]:font-semibold");
7591
+ function syncActive() {
7592
+ if (el.hasAttribute("data-active")) {
7593
+ el.setAttribute("aria-current", "page");
7594
+ } else {
7595
+ el.removeAttribute("aria-current");
7596
+ }
7597
+ }
7598
+ syncActive();
7599
+ const observer = new MutationObserver(syncActive);
7600
+ observer.observe(el, { attributes: true, attributeFilter: ["data-active"] });
7601
+ el.setAttribute("data-slot", "nav-link");
7602
+ cleanup(() => observer.disconnect());
7603
+ });
7604
+ }
7605
+
7448
7606
  // src/utils/breakpoint-listener.js
7449
7607
  function getBreakpointListener(handler, breakpoint = 768, frame = false) {
7450
7608
  let bps = Number.isFinite(breakpoint) ? `${breakpoint}px` : breakpoint;
@@ -9342,8 +9500,13 @@ function split_default(Alpine) {
9342
9500
  if (!storageKey) return;
9343
9501
  if (saveTimer) clearTimeout(saveTimer);
9344
9502
  saveTimer = setTimeout(() => {
9503
+ const usable = usableSize();
9504
+ if (usable <= 0) {
9505
+ saveTimer = null;
9506
+ return;
9507
+ }
9345
9508
  const visible = panels.filter((p) => !p.hidden);
9346
- const sizes = visible.map((p) => p.size / usableSize());
9509
+ const sizes = visible.map((p) => p.size / usable);
9347
9510
  localStorage.setItem(storageKey, JSON.stringify(sizes));
9348
9511
  saveTimer = null;
9349
9512
  }, SAVE_DELAY);
@@ -9378,26 +9541,44 @@ function split_default(Alpine) {
9378
9541
  const total = usableSize();
9379
9542
  if (!initialized) {
9380
9543
  initialized = true;
9381
- const visible2 = panels.filter((p) => !p.hidden);
9382
- const stored = loadSizes();
9383
- if (stored && stored.length === visible2.length) {
9384
- visible2.forEach((p, i) => {
9385
- p.size = stored[i] * usableSize();
9386
- p.explicit = true;
9387
- });
9388
- } else {
9389
- const explicitTotal = visible2.filter((p) => p.explicit).reduce((sum, p) => sum + p.declaredSize, 0);
9390
- const autoPanels = visible2.filter((p) => !p.explicit);
9391
- const remaining = total - explicitTotal;
9392
- const share = autoPanels.length ? remaining / autoPanels.length : 0;
9393
- visible2.forEach((p) => {
9394
- if (p.explicit) {
9395
- p.size = p.declaredSize;
9544
+ const anyRestore = visible.some((p) => p.restoreFraction != null);
9545
+ if (anyRestore) {
9546
+ const restoreFractionSum = visible.reduce((sum, p) => sum + (p.restoreFraction ?? 0), 0);
9547
+ const remainingSpace = total * (1 - restoreFractionSum);
9548
+ const nonRestorePanels = visible.filter((p) => p.restoreFraction == null);
9549
+ const nonRestoreDeclaredTotal = nonRestorePanels.reduce((s, p) => s + (p.declaredSize ?? 0), 0);
9550
+ visible.forEach((p) => {
9551
+ if (p.restoreFraction != null) {
9552
+ p.size = p.restoreFraction * total;
9553
+ p.explicit = true;
9554
+ p.restoreFraction = null;
9555
+ } else if (nonRestoreDeclaredTotal > 0) {
9556
+ p.size = (p.declaredSize ?? 0) / nonRestoreDeclaredTotal * remainingSpace;
9396
9557
  } else {
9397
- p.size = share;
9558
+ p.size = nonRestorePanels.length > 0 ? remainingSpace / nonRestorePanels.length : 0;
9398
9559
  }
9399
- p.size = Math.min(Math.max(p.size ?? share, p.min), p.max);
9400
9560
  });
9561
+ } else {
9562
+ const stored = loadSizes();
9563
+ if (stored && stored.length === visible.length) {
9564
+ visible.forEach((p, i) => {
9565
+ p.size = stored[i] * usableSize();
9566
+ p.explicit = true;
9567
+ });
9568
+ } else {
9569
+ const explicitTotal = visible.filter((p) => p.explicit).reduce((sum, p) => sum + p.declaredSize, 0);
9570
+ const autoPanels = visible.filter((p) => !p.explicit);
9571
+ const remaining = total - explicitTotal;
9572
+ const share = autoPanels.length ? remaining / autoPanels.length : 0;
9573
+ visible.forEach((p) => {
9574
+ if (p.explicit) {
9575
+ p.size = p.declaredSize;
9576
+ } else {
9577
+ p.size = share;
9578
+ }
9579
+ p.size = Math.min(Math.max(p.size ?? share, p.min), p.max);
9580
+ });
9581
+ }
9401
9582
  }
9402
9583
  }
9403
9584
  visible.forEach((p) => {
@@ -9410,6 +9591,10 @@ function split_default(Alpine) {
9410
9591
  let delta = total - currentTotal;
9411
9592
  if (Math.abs(delta) < DELTA_ABS) {
9412
9593
  visible.forEach((p) => p.apply());
9594
+ if (total > 0)
9595
+ visible.forEach((p) => {
9596
+ p.savedFraction = p.size / total;
9597
+ });
9413
9598
  return;
9414
9599
  }
9415
9600
  let flexible = visible.filter((p) => {
@@ -9443,6 +9628,10 @@ function split_default(Alpine) {
9443
9628
  if (Math.abs(consumed) < DELTA_ABS) break;
9444
9629
  }
9445
9630
  visible.forEach((p) => p.apply());
9631
+ if (total > 0)
9632
+ visible.forEach((p) => {
9633
+ p.savedFraction = p.size / total;
9634
+ });
9446
9635
  };
9447
9636
  let layoutFrame = null;
9448
9637
  const queueLayout = () => {
@@ -9477,7 +9666,6 @@ function split_default(Alpine) {
9477
9666
  queueLayout();
9478
9667
  },
9479
9668
  panelHidden() {
9480
- initialized = false;
9481
9669
  refreshGutters();
9482
9670
  queueLayout();
9483
9671
  },
@@ -9488,6 +9676,9 @@ function split_default(Alpine) {
9488
9676
  panelChange() {
9489
9677
  queueLayout();
9490
9678
  },
9679
+ resetInit() {
9680
+ initialized = false;
9681
+ },
9491
9682
  normalize,
9492
9683
  saveSizes
9493
9684
  };
@@ -9651,6 +9842,9 @@ function split_default(Alpine) {
9651
9842
  max: split._h_split.normalize(el.getAttribute("data-max")) ?? Infinity,
9652
9843
  collapsed: false,
9653
9844
  prevSize: null,
9845
+ prevHiddenFraction: null,
9846
+ savedFraction: null,
9847
+ restoreFraction: null,
9654
9848
  apply() {
9655
9849
  el.style.flexBasis = `${this.size.toFixed(2)}px`;
9656
9850
  if (split._h_split.state.isBorder) {
@@ -9755,7 +9949,7 @@ function split_default(Alpine) {
9755
9949
  gutter.addEventListener("pointerdown", drag);
9756
9950
  const collapse = () => {
9757
9951
  if (panel.collapsed) return;
9758
- panel.prevSize = panel.size;
9952
+ panel.prevSize = panel.size > (panel.min ?? 0) ? panel.size : panel.declaredSize;
9759
9953
  panel.size = panel.min ?? 0;
9760
9954
  panel.collapsed = true;
9761
9955
  panel.explicit = true;
@@ -9779,19 +9973,32 @@ function split_default(Alpine) {
9779
9973
  panel.explicit = true;
9780
9974
  split._h_split.panelChange();
9781
9975
  };
9976
+ const setState = () => {
9977
+ if (panel.hidden) {
9978
+ el.classList.add("hidden");
9979
+ } else {
9980
+ el.classList.remove("hidden");
9981
+ }
9982
+ split._h_split.panelHidden();
9983
+ };
9984
+ setState();
9782
9985
  const observer = new MutationObserver((mutations) => {
9783
9986
  mutations.forEach((mutation) => {
9784
9987
  if (mutation.attributeName === "data-gutterless") {
9785
9988
  gutterless = el.getAttribute("data-gutterless") === "true";
9786
9989
  split._h_split.gutterHidden();
9787
9990
  } else if (mutation.attributeName === "data-hidden") {
9788
- panel.hidden = el.getAttribute("data-hidden") === "true";
9789
- if (panel.hidden) {
9790
- el.classList.add("hidden");
9791
- } else {
9792
- el.classList.remove("hidden");
9991
+ const newHidden = el.getAttribute("data-hidden") === "true";
9992
+ if (!panel.hidden && newHidden) {
9993
+ panel.prevHiddenFraction = panel.savedFraction;
9994
+ } else if (panel.hidden && !newHidden) {
9995
+ if (panel.prevHiddenFraction != null) {
9996
+ panel.restoreFraction = panel.prevHiddenFraction;
9997
+ }
9998
+ split._h_split.resetInit();
9793
9999
  }
9794
- split._h_split.panelHidden();
10000
+ panel.hidden = newHidden;
10001
+ setState();
9795
10002
  } else if (mutation.attributeName === "data-locked") {
9796
10003
  panel.setLocked();
9797
10004
  } else {
@@ -11579,7 +11786,7 @@ function tree_default(Alpine) {
11579
11786
  }
11580
11787
 
11581
11788
  // package.json
11582
- var version = "1.11.0";
11789
+ var version = "1.12.0";
11583
11790
 
11584
11791
  // src/utils/theme.js
11585
11792
  var colorSchemeKey = "codbex.harmonia.colorMode";
@@ -11789,6 +11996,7 @@ var registerComponents = (registerPlugin) => {
11789
11996
  registerPlugin(label_default);
11790
11997
  registerPlugin(list_default);
11791
11998
  registerPlugin(menu_default);
11999
+ registerPlugin(navigation_menu_default);
11792
12000
  registerPlugin(notifications_default);
11793
12001
  registerPlugin(pagination_default);
11794
12002
  registerPlugin(popover_default);
@@ -11839,6 +12047,7 @@ export {
11839
12047
  label_default as Label,
11840
12048
  list_default as List,
11841
12049
  menu_default as Menu,
12050
+ navigation_menu_default as NavigationMenu,
11842
12051
  notifications_default as Notifications,
11843
12052
  pagination_default as Pagination,
11844
12053
  popover_default as Popover,