@xui/navigation-menu 2.0.0-alpha.19 → 2.0.0-alpha.21

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.
@@ -15,10 +15,16 @@ import { XuiIcon } from '@xui/icon';
15
15
  * template and lays out the bar.
16
16
  */
17
17
  class XuiNavigationMenuItem {
18
+ /** The item's key, used by the menu to track which panel is open. Must be unique within the menu. */
18
19
  value = input.required(/* @ts-ignore */
19
20
  ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
21
+ /** The label shown in the menu bar. Project content for the panel it opens. */
20
22
  trigger = input('', /* @ts-ignore */
21
23
  ...(ngDevMode ? [{ debugName: "trigger" }] : /* istanbul ignore next */ []));
24
+ /**
25
+ * Turns the item into a plain link rather than a panel trigger. Use it for a top-level entry with nothing beneath
26
+ * it.
27
+ */
22
28
  href = input('', /* @ts-ignore */
23
29
  ...(ngDevMode ? [{ debugName: "href" }] : /* istanbul ignore next */ []));
24
30
  /** The dropdown panel content; absent for a plain link. */
@@ -58,6 +64,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
58
64
  * ```
59
65
  */
60
66
  class XuiNavigationMenu {
67
+ /** Extra classes, merged into the component's own rather than replacing them. */
61
68
  class = input('', /* @ts-ignore */
62
69
  ...(ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []));
63
70
  items = contentChildren(XuiNavigationMenuItem, /* @ts-ignore */
@@ -1 +1 @@
1
- {"version":3,"file":"xui-navigation-menu.mjs","sources":["../../../../../../libs/ui/navigation-menu/xui/src/lib/navigation-menu-item.ts","../../../../../../libs/ui/navigation-menu/xui/src/lib/navigation-menu.ts","../../../../../../libs/ui/navigation-menu/xui/src/index.ts","../../../../../../libs/ui/navigation-menu/xui/src/xui-navigation-menu.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n input,\n TemplateRef,\n ViewEncapsulation\n} from '@angular/core';\n\n/**\n * One entry of an {@link XuiNavigationMenu}. Give it a `trigger` label and a\n * `value`. Project an `<ng-template>` to make it a dropdown panel; give it an\n * `href` (and no template) to make it a plain link.\n *\n * The component renders nothing itself — the parent reads its inputs and panel\n * template and lays out the bar.\n */\n@Component({\n selector: 'xui-navigation-menu-item',\n template: ``,\n host: {\n class: 'hidden'\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None\n})\nexport class XuiNavigationMenuItem {\n readonly value = input.required<string>();\n readonly trigger = input<string>('');\n readonly href = input<string>('');\n\n /** The dropdown panel content; absent for a plain link. */\n readonly content = contentChild(TemplateRef);\n readonly hasPanel = computed(() => this.content() != null);\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChildren,\n input,\n signal,\n ViewEncapsulation\n} from '@angular/core';\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { matExpandMoreRound } from '@ng-icons/material-icons/round';\nimport { xui } from '@xui/core';\nimport { XuiIcon } from '@xui/icon';\nimport type { ClassValue } from 'clsx';\nimport { XuiNavigationMenuItem } from './navigation-menu-item';\n\n/**\n * A horizontal navigation bar where items can open a rich dropdown panel — a\n * \"mega menu\". Panels open on hover or focus and share one viewport beneath the\n * bar; a padded bridge keeps the panel reachable across the gap. Items with an\n * `href` and no template render as plain links.\n *\n * ```html\n * <xui-navigation-menu>\n * <xui-navigation-menu-item value=\"products\" trigger=\"Products\">\n * <ng-template><div class=\"grid grid-cols-2 gap-2 w-[28rem]\">…</div></ng-template>\n * </xui-navigation-menu-item>\n * <xui-navigation-menu-item value=\"pricing\" trigger=\"Pricing\" href=\"/pricing\" />\n * </xui-navigation-menu>\n * ```\n */\n@Component({\n selector: 'xui-navigation-menu',\n imports: [NgTemplateOutlet, NgIcon, XuiIcon],\n template: `\n <nav [class]=\"navClass()\" (mouseleave)=\"active.set(null)\" (focusout)=\"onFocusOut($event)\">\n <ul class=\"flex items-center gap-1\">\n @for (item of items(); track item.value()) {\n <li>\n @if (item.hasPanel()) {\n <button\n type=\"button\"\n [class]=\"triggerClass(active() === item.value())\"\n [attr.aria-expanded]=\"active() === item.value()\"\n (mouseenter)=\"active.set(item.value())\"\n (focus)=\"active.set(item.value())\"\n (click)=\"toggle(item.value())\"\n >\n {{ item.trigger() }}\n <ng-icon\n xui\n name=\"matExpandMoreRound\"\n size=\"sm\"\n class=\"shrink-0 transition-transform duration-200\"\n [class.rotate-180]=\"active() === item.value()\"\n />\n </button>\n } @else {\n <a [attr.href]=\"item.href() || null\" [class]=\"linkClass()\" (mouseenter)=\"active.set(null)\">\n {{ item.trigger() }}\n </a>\n }\n </li>\n }\n </ul>\n\n @if (activeItem(); as item) {\n <div [class]=\"viewportClass()\">\n <div [class]=\"panelClass()\">\n <ng-container [ngTemplateOutlet]=\"item.content()!\" />\n </div>\n </div>\n }\n </nav>\n\n <ng-content />\n `,\n host: {\n '[class]': 'computedClass()'\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n viewProviders: [provideIcons({ matExpandMoreRound })]\n})\nexport class XuiNavigationMenu {\n readonly class = input<ClassValue>('');\n\n protected readonly items = contentChildren(XuiNavigationMenuItem);\n protected readonly active = signal<string | null>(null);\n\n protected readonly activeItem = computed(() => {\n const value = this.active();\n return this.items().find(item => item.value() === value && item.hasPanel()) ?? null;\n });\n\n protected toggle(value: string): void {\n this.active.update(current => (current === value ? null : value));\n }\n\n protected onFocusOut(event: FocusEvent): void {\n const next = event.relatedTarget as Node | null;\n if (!next || !(event.currentTarget as HTMLElement).contains(next)) {\n this.active.set(null);\n }\n }\n\n protected readonly computedClass = computed(() => xui('inline-block', this.class()));\n protected readonly navClass = computed(() =>\n xui('border-border bg-surface relative inline-flex rounded-md border p-1')\n );\n\n // The base layer already draws the focus ring; only the negative offset (the\n // ring must sit inside the bar's border) is stated here.\n protected triggerClass(open: boolean): string {\n return xui(\n 'text-foreground hover:bg-surface-inset flex items-center gap-1 rounded px-3 py-1.5 text-sm font-medium select-none',\n 'focus-visible:-outline-offset-2',\n open && 'bg-surface-inset'\n );\n }\n protected readonly linkClass = computed(() =>\n xui(\n 'text-foreground hover:bg-surface-inset flex items-center rounded px-3 py-1.5 text-sm font-medium',\n 'focus-visible:-outline-offset-2'\n )\n );\n\n // `pt-2` (not margin) keeps the panel's hitbox contiguous with the bar, so the\n // pointer can cross the visual gap without the menu closing — that hover\n // bridge is why this panel stays inline instead of moving to the overlay\n // container. `z-10` is local structural stacking (the navbar scale), not an\n // overlay z-index: it only needs to clear in-flow page content below the bar.\n // eslint-disable-next-line local/no-hand-z-index -- local structural stacking on the navbar scale, documented above\n protected readonly viewportClass = computed(() => xui('absolute top-full start-0 z-10 pt-2'));\n protected readonly panelClass = computed(() =>\n xui('border-border bg-surface-overlay shadow-overlay rounded-lg border p-3')\n );\n}\n","import { XuiNavigationMenu } from './lib/navigation-menu';\nimport { XuiNavigationMenuItem } from './lib/navigation-menu-item';\n\nexport * from './lib/navigation-menu';\nexport * from './lib/navigation-menu-item';\n\nexport const XuiNavigationMenuImports = [XuiNavigationMenu, XuiNavigationMenuItem] as const;\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"xui-navigation-menu.mjs","sources":["../../../../../../libs/ui/navigation-menu/xui/src/lib/navigation-menu-item.ts","../../../../../../libs/ui/navigation-menu/xui/src/lib/navigation-menu.ts","../../../../../../libs/ui/navigation-menu/xui/src/index.ts","../../../../../../libs/ui/navigation-menu/xui/src/xui-navigation-menu.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n input,\n TemplateRef,\n ViewEncapsulation\n} from '@angular/core';\n\n/**\n * One entry of an {@link XuiNavigationMenu}. Give it a `trigger` label and a\n * `value`. Project an `<ng-template>` to make it a dropdown panel; give it an\n * `href` (and no template) to make it a plain link.\n *\n * The component renders nothing itself — the parent reads its inputs and panel\n * template and lays out the bar.\n */\n@Component({\n selector: 'xui-navigation-menu-item',\n template: ``,\n host: {\n class: 'hidden'\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None\n})\nexport class XuiNavigationMenuItem {\n /** The item's key, used by the menu to track which panel is open. Must be unique within the menu. */\n readonly value = input.required<string>();\n /** The label shown in the menu bar. Project content for the panel it opens. */\n readonly trigger = input<string>('');\n /**\n * Turns the item into a plain link rather than a panel trigger. Use it for a top-level entry with nothing beneath\n * it.\n */\n readonly href = input<string>('');\n\n /** The dropdown panel content; absent for a plain link. */\n readonly content = contentChild(TemplateRef);\n readonly hasPanel = computed(() => this.content() != null);\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChildren,\n input,\n signal,\n ViewEncapsulation\n} from '@angular/core';\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { matExpandMoreRound } from '@ng-icons/material-icons/round';\nimport { xui } from '@xui/core';\nimport { XuiIcon } from '@xui/icon';\nimport type { ClassValue } from 'clsx';\nimport { XuiNavigationMenuItem } from './navigation-menu-item';\n\n/**\n * A horizontal navigation bar where items can open a rich dropdown panel — a\n * \"mega menu\". Panels open on hover or focus and share one viewport beneath the\n * bar; a padded bridge keeps the panel reachable across the gap. Items with an\n * `href` and no template render as plain links.\n *\n * ```html\n * <xui-navigation-menu>\n * <xui-navigation-menu-item value=\"products\" trigger=\"Products\">\n * <ng-template><div class=\"grid grid-cols-2 gap-2 w-[28rem]\">…</div></ng-template>\n * </xui-navigation-menu-item>\n * <xui-navigation-menu-item value=\"pricing\" trigger=\"Pricing\" href=\"/pricing\" />\n * </xui-navigation-menu>\n * ```\n */\n@Component({\n selector: 'xui-navigation-menu',\n imports: [NgTemplateOutlet, NgIcon, XuiIcon],\n template: `\n <nav [class]=\"navClass()\" (mouseleave)=\"active.set(null)\" (focusout)=\"onFocusOut($event)\">\n <ul class=\"flex items-center gap-1\">\n @for (item of items(); track item.value()) {\n <li>\n @if (item.hasPanel()) {\n <button\n type=\"button\"\n [class]=\"triggerClass(active() === item.value())\"\n [attr.aria-expanded]=\"active() === item.value()\"\n (mouseenter)=\"active.set(item.value())\"\n (focus)=\"active.set(item.value())\"\n (click)=\"toggle(item.value())\"\n >\n {{ item.trigger() }}\n <ng-icon\n xui\n name=\"matExpandMoreRound\"\n size=\"sm\"\n class=\"shrink-0 transition-transform duration-200\"\n [class.rotate-180]=\"active() === item.value()\"\n />\n </button>\n } @else {\n <a [attr.href]=\"item.href() || null\" [class]=\"linkClass()\" (mouseenter)=\"active.set(null)\">\n {{ item.trigger() }}\n </a>\n }\n </li>\n }\n </ul>\n\n @if (activeItem(); as item) {\n <div [class]=\"viewportClass()\">\n <div [class]=\"panelClass()\">\n <ng-container [ngTemplateOutlet]=\"item.content()!\" />\n </div>\n </div>\n }\n </nav>\n\n <ng-content />\n `,\n host: {\n '[class]': 'computedClass()'\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n viewProviders: [provideIcons({ matExpandMoreRound })]\n})\nexport class XuiNavigationMenu {\n /** Extra classes, merged into the component's own rather than replacing them. */\n readonly class = input<ClassValue>('');\n\n protected readonly items = contentChildren(XuiNavigationMenuItem);\n protected readonly active = signal<string | null>(null);\n\n protected readonly activeItem = computed(() => {\n const value = this.active();\n return this.items().find(item => item.value() === value && item.hasPanel()) ?? null;\n });\n\n protected toggle(value: string): void {\n this.active.update(current => (current === value ? null : value));\n }\n\n protected onFocusOut(event: FocusEvent): void {\n const next = event.relatedTarget as Node | null;\n if (!next || !(event.currentTarget as HTMLElement).contains(next)) {\n this.active.set(null);\n }\n }\n\n protected readonly computedClass = computed(() => xui('inline-block', this.class()));\n protected readonly navClass = computed(() =>\n xui('border-border bg-surface relative inline-flex rounded-md border p-1')\n );\n\n // The base layer already draws the focus ring; only the negative offset (the\n // ring must sit inside the bar's border) is stated here.\n protected triggerClass(open: boolean): string {\n return xui(\n 'text-foreground hover:bg-surface-inset flex items-center gap-1 rounded px-3 py-1.5 text-sm font-medium select-none',\n 'focus-visible:-outline-offset-2',\n open && 'bg-surface-inset'\n );\n }\n protected readonly linkClass = computed(() =>\n xui(\n 'text-foreground hover:bg-surface-inset flex items-center rounded px-3 py-1.5 text-sm font-medium',\n 'focus-visible:-outline-offset-2'\n )\n );\n\n // `pt-2` (not margin) keeps the panel's hitbox contiguous with the bar, so the\n // pointer can cross the visual gap without the menu closing — that hover\n // bridge is why this panel stays inline instead of moving to the overlay\n // container. `z-10` is local structural stacking (the navbar scale), not an\n // overlay z-index: it only needs to clear in-flow page content below the bar.\n // eslint-disable-next-line local/no-hand-z-index -- local structural stacking on the navbar scale, documented above\n protected readonly viewportClass = computed(() => xui('absolute top-full start-0 z-10 pt-2'));\n protected readonly panelClass = computed(() =>\n xui('border-border bg-surface-overlay shadow-overlay rounded-lg border p-3')\n );\n}\n","import { XuiNavigationMenu } from './lib/navigation-menu';\nimport { XuiNavigationMenuItem } from './lib/navigation-menu-item';\n\nexport * from './lib/navigation-menu';\nexport * from './lib/navigation-menu-item';\n\nexport const XuiNavigationMenuImports = [XuiNavigationMenu, XuiNavigationMenuItem] as const;\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xui/navigation-menu",
3
- "version": "2.0.0-alpha.19",
3
+ "version": "2.0.0-alpha.21",
4
4
  "description": "Modern Angular 22 UI Library based on TailwindCSS",
5
5
  "keywords": [
6
6
  "angular",
@@ -40,8 +40,8 @@
40
40
  "@angular/core": "22",
41
41
  "@ng-icons/core": "34",
42
42
  "@ng-icons/material-icons": "34",
43
- "@xui/core": "2.0.0-alpha.19",
44
- "@xui/icon": "2.0.0-alpha.19",
43
+ "@xui/core": "2.0.0-alpha.21",
44
+ "@xui/icon": "2.0.0-alpha.21",
45
45
  "clsx": "^2.1.1"
46
46
  },
47
47
  "publishConfig": {
@@ -11,8 +11,14 @@ import { ClassValue } from 'clsx';
11
11
  * template and lays out the bar.
12
12
  */
13
13
  declare class XuiNavigationMenuItem {
14
+ /** The item's key, used by the menu to track which panel is open. Must be unique within the menu. */
14
15
  readonly value: _angular_core.InputSignal<string>;
16
+ /** The label shown in the menu bar. Project content for the panel it opens. */
15
17
  readonly trigger: _angular_core.InputSignal<string>;
18
+ /**
19
+ * Turns the item into a plain link rather than a panel trigger. Use it for a top-level entry with nothing beneath
20
+ * it.
21
+ */
16
22
  readonly href: _angular_core.InputSignal<string>;
17
23
  /** The dropdown panel content; absent for a plain link. */
18
24
  readonly content: _angular_core.Signal<TemplateRef<any> | undefined>;
@@ -37,6 +43,7 @@ declare class XuiNavigationMenuItem {
37
43
  * ```
38
44
  */
39
45
  declare class XuiNavigationMenu {
46
+ /** Extra classes, merged into the component's own rather than replacing them. */
40
47
  readonly class: _angular_core.InputSignal<ClassValue>;
41
48
  protected readonly items: _angular_core.Signal<readonly XuiNavigationMenuItem[]>;
42
49
  protected readonly active: _angular_core.WritableSignal<string | null>;