diff --git a/src/lib/components/megamenu/megamenu.component.ts b/src/lib/components/megamenu/megamenu.component.ts
new file mode 100644
index 0000000..9da0845
--- /dev/null
+++ b/src/lib/components/megamenu/megamenu.component.ts
@@ -0,0 +1,77 @@
+import { Component, Input, TemplateRef } from '@angular/core';
+import { NgTemplateOutlet } from '@angular/common';
+import { MegaMenu } from 'primeng/megamenu';
+import { MegaMenuItem, PrimeTemplate } from 'primeng/api';
+import { Badge } from 'primeng/badge';
+
+export type MegaMenuOrientation = 'horizontal' | 'vertical';
+
+export interface MegaMenuModel extends MegaMenuItem {
+ description?: string;
+ badge?: string;
+}
+
+@Component({
+ selector: 'megamenu',
+ host: { style: 'display: contents' },
+ standalone: true,
+ imports: [MegaMenu, PrimeTemplate, NgTemplateOutlet, Badge],
+ template: `
+
+
+ @if (itemTemplate) {
+
+
+ } @else {
+
+ }
+
+
+ `,
+})
+export class MegaMenuComponent {
+ @Input() model: MegaMenuModel[] = [];
+ @Input() orientation: MegaMenuOrientation = 'horizontal';
+ @Input() breakpoint: string = '960px';
+ @Input() scrollHeight: string = '';
+ @Input() disabled: boolean = false;
+ @Input() ariaLabel: string | undefined = undefined;
+ @Input() ariaLabelledBy: string | undefined = undefined;
+ @Input() tabindex: number = 0;
+ @Input() itemTemplate: TemplateRef | null = null;
+}
diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts
index a5dd634..bbad52d 100644
--- a/src/prime-preset/map-tokens.ts
+++ b/src/prime-preset/map-tokens.ts
@@ -6,6 +6,7 @@ import tokens from './tokens/tokens.json';
import { avatarCss } from './tokens/components/avatar';
import { buttonCss } from './tokens/components/button';
import { tooltipCss } from './tokens/components/tooltip';
+import { megamenuCss } from './tokens/components/megamenu';
const presetTokens: Preset = {
primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'],
@@ -24,6 +25,10 @@ const presetTokens: Preset = {
...(tokens.components.tooltip as unknown as ComponentsDesignTokens['tooltip']),
css: tooltipCss,
},
+ megamenu: {
+ ...(tokens.components.megamenu as unknown as ComponentsDesignTokens['megamenu']),
+ css: megamenuCss,
+ },
} as ComponentsDesignTokens,
};
diff --git a/src/prime-preset/tokens/components/megamenu.ts b/src/prime-preset/tokens/components/megamenu.ts
new file mode 100644
index 0000000..542864b
--- /dev/null
+++ b/src/prime-preset/tokens/components/megamenu.ts
@@ -0,0 +1,42 @@
+export const megamenuCss = ({ dt }: { dt: (token: string) => string }): string => `
+/* ─── Размер иконок ─── */
+.p-megamenu-submenu-icon,
+.p-megamenu-item-icon {
+ font-size: ${dt('megamenu.extend.iconSize')};
+}
+
+/* ─── Типографика пунктов меню ─── */
+.p-megamenu-item-label {
+ font-size: ${dt('fonts.fontSize.300')};
+ font-weight: ${dt('fonts.fontWeight.regular')};
+}
+
+/* ─── Caption (описание) для кастомных пунктов ─── */
+.p-megamenu .megamenu-item-label {
+ display: flex;
+ flex-direction: column;
+ gap: ${dt('megamenu.extend.extItem.caption.gap')};
+}
+
+.p-megamenu .megamenu-item-caption {
+ font-size: ${dt('fonts.fontSize.200')};
+ color: ${dt('megamenu.extend.extItem.caption.color')};
+}
+
+/* ─── Иконка мобильной кнопки ─── */
+.p-megamenu-mobile-button-icon {
+ font-size: ${dt('megamenu.extend.iconSize')};
+}
+
+/* ─── Размер ширины панели по контенту и позиционирование для активных пунктов горизонтального вида от начала пункта меню ─── */
+.p-megamenu-root-list > .p-megamenu-item-active > .p-megamenu-overlay,
+.p-megamenu-vertical .p-megamenu-root-list > .p-megamenu-item-active > .p-megamenu-overlay {
+ min-width: fit-content;
+ left: unset;
+}
+
+/* ─── Позиционирование оверлея от пункта для вертикального вида ─── */
+.p-megamenu.p-megamenu-vertical .p-megamenu-root-list > .p-megamenu-item-active > .p-megamenu-overlay {
+ left: 100%;
+}
+`;
diff --git a/src/prime-preset/tokens/tokens.json b/src/prime-preset/tokens/tokens.json
index 19d1ea5..c7c7178 100644
--- a/src/prime-preset/tokens/tokens.json
+++ b/src/prime-preset/tokens/tokens.json
@@ -630,7 +630,7 @@
},
"submenuLabel": {
"padding": "{spacing.2x} {spacing.3x}",
- "fontWeight": "{fonts.fontWeight.demibold}"
+ "fontWeight": "{fonts.fontWeight.regular}"
},
"submenuIcon": {
"size": "{fonts.fontSize.500}"
@@ -3292,6 +3292,7 @@
"gap": "{navigation.list.gap}"
},
"submenuLabel": {
+ "fontWeight": "{navigation.submenuLabel.fontWeight}",
"padding": "{navigation.submenuLabel.padding}",
"background": "{navigation.submenuLabel.background}",
"color": "{navigation.submenuLabel.color}"
diff --git a/src/stories/components/megamenu/examples/megamenu-custom.component.ts b/src/stories/components/megamenu/examples/megamenu-custom.component.ts
new file mode 100644
index 0000000..7568a9f
--- /dev/null
+++ b/src/stories/components/megamenu/examples/megamenu-custom.component.ts
@@ -0,0 +1,81 @@
+import { Component } from '@angular/core';
+import { MegaMenuComponent, MegaMenuModel } from '../../../../lib/components/megamenu/megamenu.component';
+
+const template = ``;
+
+@Component({
+ selector: 'app-megamenu-custom',
+ standalone: true,
+ imports: [MegaMenuComponent],
+ template,
+})
+export class MegaMenuCustomComponent {
+ items: MegaMenuModel[] = [
+ {
+ label: 'Products',
+ icon: 'ti ti-box',
+ items: [
+ [
+ {
+ label: 'Components',
+ items: [
+ {
+ label: 'Form',
+ description: 'Input, Select, Checkbox',
+ icon: 'ti ti-forms',
+ badge: 'New',
+ } as any,
+ {
+ label: 'Button',
+ description: 'Actions and triggers',
+ icon: 'ti ti-hand-click',
+ } as any,
+ ],
+ },
+ ],
+ [
+ {
+ label: 'Charts',
+ items: [
+ {
+ label: 'Bar Chart',
+ description: 'Categorical comparison',
+ icon: 'ti ti-chart-bar',
+ } as any,
+ {
+ label: 'Line Chart',
+ description: 'Trends over time',
+ icon: 'ti ti-chart-line',
+ badge: 'Beta',
+ } as any,
+ ],
+ },
+ ],
+ ],
+ },
+ {
+ label: 'Solutions',
+ icon: 'ti ti-bulb',
+ items: [
+ [
+ {
+ label: 'Business',
+ items: [
+ {
+ label: 'Analytics',
+ description: 'Reports and dashboards',
+ icon: 'ti ti-chart-dots',
+ } as any,
+ {
+ label: 'CRM',
+ description: 'Customer management',
+ icon: 'ti ti-users',
+ badge: 'Pro',
+ } as any,
+ ],
+ },
+ ],
+ ],
+ },
+ ];
+}
diff --git a/src/stories/components/megamenu/examples/megamenu-horizontal.component.ts b/src/stories/components/megamenu/examples/megamenu-horizontal.component.ts
new file mode 100644
index 0000000..ce40470
--- /dev/null
+++ b/src/stories/components/megamenu/examples/megamenu-horizontal.component.ts
@@ -0,0 +1,60 @@
+import { Component } from '@angular/core';
+import { MegaMenuComponent, MegaMenuModel } from '../../../../lib/components/megamenu/megamenu.component';
+
+const template = ``;
+
+@Component({
+ selector: 'app-megamenu-horizontal',
+ standalone: true,
+ imports: [MegaMenuComponent],
+ template,
+})
+export class MegaMenuHorizontalComponent {
+ items: MegaMenuModel[] = [
+ {
+ label: 'Products',
+ icon: 'ti ti-box',
+ items: [
+ [
+ {
+ label: 'UI Components',
+ items: [
+ { label: 'Form', icon: 'ti ti-forms' },
+ { label: 'Button', icon: 'ti ti-hand-click' },
+ { label: 'Table', icon: 'ti ti-table' },
+ ],
+ },
+ ],
+ [
+ {
+ label: 'Charts',
+ items: [
+ { label: 'Bar Chart', icon: 'ti ti-chart-bar' },
+ { label: 'Line Chart', icon: 'ti ti-chart-line' },
+ ],
+ },
+ ],
+ ],
+ },
+ {
+ label: 'Solutions',
+ icon: 'ti ti-bulb',
+ items: [
+ [
+ {
+ label: 'Business',
+ items: [
+ { label: 'Analytics', icon: 'ti ti-chart-dots' },
+ { label: 'CRM', icon: 'ti ti-users' },
+ ],
+ },
+ ],
+ ],
+ },
+ {
+ label: 'Contact',
+ icon: 'ti ti-mail',
+ disabled: true,
+ },
+ ];
+}
diff --git a/src/stories/components/megamenu/examples/megamenu-vertical.component.ts b/src/stories/components/megamenu/examples/megamenu-vertical.component.ts
new file mode 100644
index 0000000..6797839
--- /dev/null
+++ b/src/stories/components/megamenu/examples/megamenu-vertical.component.ts
@@ -0,0 +1,60 @@
+import { Component } from '@angular/core';
+import { MegaMenuComponent, MegaMenuModel } from '../../../../lib/components/megamenu/megamenu.component';
+
+const template = ``;
+
+@Component({
+ selector: 'app-megamenu-vertical',
+ standalone: true,
+ imports: [MegaMenuComponent],
+ template,
+})
+export class MegaMenuVerticalComponent {
+ items: MegaMenuModel[] = [
+ {
+ label: 'Products',
+ icon: 'ti ti-box',
+ items: [
+ [
+ {
+ label: 'UI Components',
+ items: [
+ { label: 'Form', icon: 'ti ti-forms' },
+ { label: 'Button', icon: 'ti ti-hand-click' },
+ { label: 'Table', icon: 'ti ti-table' },
+ ],
+ },
+ ],
+ [
+ {
+ label: 'Charts',
+ items: [
+ { label: 'Bar Chart', icon: 'ti ti-chart-bar' },
+ { label: 'Line Chart', icon: 'ti ti-chart-line' },
+ ],
+ },
+ ],
+ ],
+ },
+ {
+ label: 'Solutions',
+ icon: 'ti ti-bulb',
+ items: [
+ [
+ {
+ label: 'Business',
+ items: [
+ { label: 'Analytics', icon: 'ti ti-chart-dots' },
+ { label: 'CRM', icon: 'ti ti-users' },
+ ],
+ },
+ ],
+ ],
+ },
+ {
+ label: 'Contact',
+ icon: 'ti ti-mail',
+ disabled: true,
+ },
+ ];
+}
diff --git a/src/stories/components/megamenu/megamenu.stories.ts b/src/stories/components/megamenu/megamenu.stories.ts
new file mode 100644
index 0000000..b2a0123
--- /dev/null
+++ b/src/stories/components/megamenu/megamenu.stories.ts
@@ -0,0 +1,262 @@
+import { Meta, StoryObj, moduleMetadata } from '@storybook/angular';
+import { MegaMenuComponent, MegaMenuModel } from '../../../lib/components/megamenu/megamenu.component';
+
+const meta: Meta = {
+ title: 'Components/Menu/MegaMenu',
+ component: MegaMenuComponent,
+ tags: ['autodocs'],
+ decorators: [
+ moduleMetadata({
+ imports: [MegaMenuComponent],
+ }),
+ ],
+ parameters: {
+ docs: {
+ description: {
+ component: `Расширенное меню с поддержкой многоколоночных подменю. Поддерживает горизонтальную и вертикальную ориентацию.
+
+\`\`\`typescript
+import { MegaMenuComponent } from '@cdek-it/angular-ui-kit';
+\`\`\``,
+ },
+ story: {
+ height: '300px',
+ },
+ },
+ designTokens: { prefix: '--p-megamenu' },
+ },
+ argTypes: {
+ model: {
+ control: false,
+ description: 'Массив пунктов меню.',
+ table: {
+ category: 'Props',
+ type: { summary: 'MegaMenuModel[]' },
+ },
+ },
+ orientation: {
+ control: 'select',
+ options: ['horizontal', 'vertical'],
+ description: 'Ориентация меню.',
+ table: {
+ category: 'Props',
+ defaultValue: { summary: 'horizontal' },
+ type: { summary: "'horizontal' | 'vertical'" },
+ },
+ },
+ disabled: {
+ control: 'boolean',
+ description: 'Отключает взаимодействие с меню.',
+ table: {
+ category: 'Props',
+ defaultValue: { summary: 'false' },
+ type: { summary: 'boolean' },
+ },
+ },
+ },
+ args: {
+ orientation: 'horizontal',
+ disabled: false,
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+const baseItems: MegaMenuModel[] = [
+ {
+ label: 'Products',
+ icon: 'ti ti-box',
+ items: [
+ [
+ {
+ label: 'UI Components',
+ items: [
+ { label: 'Form', icon: 'ti ti-forms' },
+ { label: 'Button', icon: 'ti ti-hand-click' },
+ { label: 'Table', icon: 'ti ti-table' },
+ ],
+ },
+ ],
+ [
+ {
+ label: 'Charts',
+ items: [
+ { label: 'Bar Chart', icon: 'ti ti-chart-bar' },
+ { label: 'Line Chart', icon: 'ti ti-chart-line' },
+ ],
+ },
+ ],
+ ],
+ },
+ {
+ label: 'Solutions',
+ icon: 'ti ti-bulb',
+ items: [
+ [
+ {
+ label: 'Business',
+ items: [
+ { label: 'Analytics', icon: 'ti ti-chart-dots' },
+ { label: 'CRM', icon: 'ti ti-users' },
+ ],
+ },
+ ],
+ ],
+ },
+ {
+ label: 'Contact',
+ icon: 'ti ti-mail',
+ disabled: true,
+ },
+];
+
+const commonTemplate = `
+
+`;
+
+// ── Default ──────────────────────────────────────────────────────────────────
+export const Default: Story = {
+ name: 'Default',
+ render: (args) => {
+ const parts: string[] = ['[model]="model"'];
+
+ if (args.orientation && args.orientation !== 'horizontal') parts.push(`orientation="${args.orientation}"`);
+ if (args.disabled) parts.push(`[disabled]="true"`);
+
+ const template = ``;
+ return { props: { ...args, model: baseItems }, template };
+ },
+ parameters: {
+ docs: {
+ description: {
+ story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.',
+ },
+ },
+ },
+};
+
+// ── Horizontal ──────────────────────────────────────────────────────────────
+export const Horizontal: Story = {
+ render: (args) => ({
+ props: { ...args, model: baseItems },
+ template: commonTemplate,
+ }),
+ args: { orientation: 'horizontal' },
+ parameters: {
+ docs: {
+ description: { story: 'Горизонтальная ориентация (по умолчанию).' },
+ source: {
+ code: ``,
+ },
+ },
+ },
+};
+
+// ── Vertical ────────────────────────────────────────────────────────────────
+export const Vertical: Story = {
+ render: (args) => ({
+ props: { ...args, model: baseItems },
+ template: commonTemplate,
+ }),
+ args: { orientation: 'vertical' },
+ parameters: {
+ docs: {
+ description: { story: 'Вертикальная ориентация.' },
+ source: {
+ code: ``,
+ },
+ },
+ },
+};
+
+// ── Custom ──────────────────────────────────────────────────────────────────
+const customItems: MegaMenuModel[] = [
+ {
+ label: 'Products',
+ icon: 'ti ti-box',
+ items: [
+ [
+ {
+ label: 'Components',
+ items: [
+ {
+ label: 'Form',
+ description: 'Input, Select, Checkbox',
+ icon: 'ti ti-forms',
+ badge: 'New',
+ } as any,
+ {
+ label: 'Button',
+ description: 'Actions and triggers',
+ icon: 'ti ti-hand-click',
+ } as any,
+ ],
+ },
+ ],
+ [
+ {
+ label: 'Charts',
+ items: [
+ {
+ label: 'Bar Chart',
+ description: 'Categorical comparison',
+ icon: 'ti ti-chart-bar',
+ } as any,
+ {
+ label: 'Line Chart',
+ description: 'Trends over time',
+ icon: 'ti ti-chart-line',
+ badge: 'Beta',
+ } as any,
+ ],
+ },
+ ],
+ ],
+ },
+ {
+ label: 'Solutions',
+ icon: 'ti ti-bulb',
+ items: [
+ [
+ {
+ label: 'Business',
+ items: [
+ {
+ label: 'Analytics',
+ description: 'Reports and dashboards',
+ icon: 'ti ti-chart-dots',
+ } as any,
+ {
+ label: 'CRM',
+ description: 'Customer management',
+ icon: 'ti ti-users',
+ badge: 'Pro',
+ } as any,
+ ],
+ },
+ ],
+ ],
+ },
+];
+
+export const Custom: Story = {
+ render: (args) => ({
+ props: { ...args, model: customItems },
+ template: commonTemplate,
+ }),
+ parameters: {
+ docs: {
+ description: {
+ story: 'Пункты меню с описанием (description) и бейджами.',
+ },
+ source: {
+ code: ``,
+ },
+ },
+ },
+};