From 1804ba1869ace9db4760ca44e2720b1978cd919d Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 14 Apr 2026 23:36:09 +0700 Subject: [PATCH 1/2] =?UTF-8?q?=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8F=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2=20=D1=81?= =?UTF-8?q?=D1=82=D0=B8=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B8?= =?UTF-8?q?=20=D1=81=D1=82=D0=BE=D1=80=D0=B8=D1=81=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../panelmenu/panelmenu.component.ts | 22 +++ src/prime-preset/map-tokens.ts | 5 + .../tokens/components/panelmenu.ts | 63 ++++++++ .../examples/panelmenu-basic.component.ts | 93 ++++++++++++ .../examples/panelmenu-custom.component.ts | 134 ++++++++++++++++++ .../examples/panelmenu-multiple.component.ts | 97 +++++++++++++ .../components/panelmenu/panelmenu.stories.ts | 108 ++++++++++++++ 7 files changed, 522 insertions(+) create mode 100644 src/lib/components/panelmenu/panelmenu.component.ts create mode 100644 src/prime-preset/tokens/components/panelmenu.ts create mode 100644 src/stories/components/panelmenu/examples/panelmenu-basic.component.ts create mode 100644 src/stories/components/panelmenu/examples/panelmenu-custom.component.ts create mode 100644 src/stories/components/panelmenu/examples/panelmenu-multiple.component.ts create mode 100644 src/stories/components/panelmenu/panelmenu.stories.ts diff --git a/src/lib/components/panelmenu/panelmenu.component.ts b/src/lib/components/panelmenu/panelmenu.component.ts new file mode 100644 index 0000000..33f4ddb --- /dev/null +++ b/src/lib/components/panelmenu/panelmenu.component.ts @@ -0,0 +1,22 @@ +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { PanelMenu } from 'primeng/panelmenu'; +import { MenuItem } from 'primeng/api'; + +@Component({ + selector: 'panelmenu', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [PanelMenu], + template: ` + + `, +}) +export class PanelMenuComponent { + @Input() model: MenuItem[] = []; + @Input() multiple = false; + @Input() tabindex: number | undefined = undefined; +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index a5dd634..687c020 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -5,6 +5,7 @@ import type { AuraBaseDesignTokens } from '@primeuix/themes/aura/base'; import tokens from './tokens/tokens.json'; import { avatarCss } from './tokens/components/avatar'; import { buttonCss } from './tokens/components/button'; +import { panelmenuCss } from './tokens/components/panelmenu'; import { tooltipCss } from './tokens/components/tooltip'; const presetTokens: Preset = { @@ -20,6 +21,10 @@ const presetTokens: Preset = { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), css: buttonCss, }, + panelmenu: { + ...(tokens.components.panelmenu as unknown as ComponentsDesignTokens['panelmenu']), + css: panelmenuCss, + }, tooltip: { ...(tokens.components.tooltip as unknown as ComponentsDesignTokens['tooltip']), css: tooltipCss, diff --git a/src/prime-preset/tokens/components/panelmenu.ts b/src/prime-preset/tokens/components/panelmenu.ts new file mode 100644 index 0000000..02db6f8 --- /dev/null +++ b/src/prime-preset/tokens/components/panelmenu.ts @@ -0,0 +1,63 @@ +export const panelmenuCss = ({ dt }: { dt: (token: string) => string }): string => ` + .p-panelmenu { + gap: ${dt('panelmenu.extend.extPanel.gap')}; + } + + .p-panelmenu-panel { + padding: ${dt('panelmenu.extend.extPanel.gap')}; + } + + .p-panelmenu-header-content, + .p-panelmenu-item-content { + font-size: ${dt('fonts.fontSize.300')}; + } + + .p-panelmenu-submenu-icon { + font-size: ${dt('panelmenu.extend.iconSize')}; + } + + /* ─── Active & Focused States ─── */ + + .p-panelmenu .p-panelmenu-item.p-focus > .p-panelmenu-item-content, + .p-panelmenu .p-panelmenu-header.p-focus .p-panelmenu-header-content { + background: ${dt('panelmenu.extend.extItem.activeBackground')}; + color: ${dt('panelmenu.extend.extItem.activeColor')}; + } + + .p-panelmenu .p-panelmenu-item.p-focus > .p-panelmenu-item-content :is(.p-panelmenu-item-link, .p-panelmenu-item-label, .p-panelmenu-item-icon, .p-panelmenu-header-icon, .p-panelmenu-submenu-icon), + .p-panelmenu .p-panelmenu-header.p-focus .p-panelmenu-header-content :is(.p-panelmenu-header-link, .p-panelmenu-header-label, .p-panelmenu-submenu-icon, .p-panelmenu-item-icon, .p-panelmenu-header-icon) { + color: ${dt('panelmenu.extend.extItem.activeColor')}; + } + + /* ─── Hover on Active States ─── */ + + .p-panelmenu .p-panelmenu-item.p-focus:not(.p-disabled) > .p-panelmenu-item-content:hover, + .p-panelmenu .p-panelmenu-header.p-focus .p-panelmenu-header-content:hover { + background: ${dt('panelmenu.item.focusBackground')}; + color: ${dt('panelmenu.item.focusColor')}; + } + + .p-panelmenu .p-panelmenu-item.p-focus:not(.p-disabled) > .p-panelmenu-item-content:hover :is(.p-panelmenu-item-link, .p-panelmenu-item-label), + .p-panelmenu .p-panelmenu-header.p-focus .p-panelmenu-header-content:hover :is(.p-panelmenu-header-link, .p-panelmenu-header-label) { + color: ${dt('panelmenu.item.focusColor')}; + } + + .p-panelmenu .p-panelmenu-item.p-focus:not(.p-disabled) > .p-panelmenu-item-content:hover :is(.p-panelmenu-item-icon, .p-panelmenu-submenu-icon), + .p-panelmenu .p-panelmenu-header.p-focus .p-panelmenu-header-content:hover :is(.p-panelmenu-submenu-icon, .p-panelmenu-item-icon) { + color: ${dt('panelmenu.item.icon.focusColor')}; + } + + /* ─── Captions ─── */ + + .p-panelmenu .panelmenu-item-label { + display: flex; + flex-direction: column; + gap: ${dt('panelmenu.extend.extItem.caption.gap')}; + } + + .p-panelmenu .panelmenu-item-caption { + font-size: ${dt('fonts.fontSize.200')}; + line-height: ${dt('fonts.lineHeight.450')}; + color: ${dt('panelmenu.extend.extItem.caption.color')}; + } +`; diff --git a/src/stories/components/panelmenu/examples/panelmenu-basic.component.ts b/src/stories/components/panelmenu/examples/panelmenu-basic.component.ts new file mode 100644 index 0000000..d19cafd --- /dev/null +++ b/src/stories/components/panelmenu/examples/panelmenu-basic.component.ts @@ -0,0 +1,93 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { MenuItem } from 'primeng/api'; +import { PanelMenuComponent } from '../../../../lib/components/panelmenu/panelmenu.component'; + +const template = ` +
+ +
+`; +const styles = ''; + +@Component({ + selector: 'app-panelmenu-basic', + standalone: true, + imports: [PanelMenuComponent], + template, + styles, +}) +export class PanelMenuBasicComponent { + items: MenuItem[] = [ + { + label: 'Отправления', + items: [ + { label: 'Новые' }, + { label: 'В пути' }, + { label: 'Доставленные' }, + { label: 'Возвраты', items: [{ label: 'Ожидают' }, { label: 'Завершённые' }] }, + ], + }, + { label: 'Маршруты' }, + { + label: 'Склады', + items: [ + { label: 'Москва' }, + { label: 'Новосибирск' }, + { label: 'Екатеринбург' }, + ], + }, + { label: 'Настройки', disabled: true }, + ]; +} + +export const Basic: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Базовое аккордеон-меню без иконок.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { MenuItem } from 'primeng/api'; +import { PanelMenuComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-panelmenu-basic', + standalone: true, + imports: [PanelMenuComponent], + template: \` + + \`, +}) +export class PanelMenuBasicComponent { + items: MenuItem[] = [ + { + label: 'Отправления', + items: [ + { label: 'Новые' }, + { label: 'В пути' }, + { label: 'Доставленные' }, + { label: 'Возвраты', items: [{ label: 'Ожидают' }, { label: 'Завершённые' }] }, + ], + }, + { label: 'Маршруты' }, + { + label: 'Склады', + items: [ + { label: 'Москва' }, + { label: 'Новосибирск' }, + { label: 'Екатеринбург' }, + ], + }, + { label: 'Настройки', disabled: true }, + ]; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/panelmenu/examples/panelmenu-custom.component.ts b/src/stories/components/panelmenu/examples/panelmenu-custom.component.ts new file mode 100644 index 0000000..3a1ac66 --- /dev/null +++ b/src/stories/components/panelmenu/examples/panelmenu-custom.component.ts @@ -0,0 +1,134 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { MenuItem } from 'primeng/api'; +import { PanelMenu } from 'primeng/panelmenu'; +import { Badge } from 'primeng/badge'; +import { NgIf, NgClass } from '@angular/common'; + +const template = ` + +`; +const styles = ''; + +@Component({ + selector: 'app-panelmenu-custom', + standalone: true, + imports: [PanelMenu, Badge, NgIf, NgClass], + template, + styles, +}) +export class PanelMenuCustomComponent { + items: MenuItem[] = [ + { + label: 'Дашборд', + icon: 'ti ti-layout-dashboard', + description: 'Главная страница', + items: [ + { label: 'Аналитика', icon: 'ti ti-chart-line', description: 'Аналитика данных' }, + { label: 'Отчёты', icon: 'ti ti-file-analytics', description: 'Сводные отчёты' }, + { label: 'Статистика', icon: 'ti ti-chart-bar', description: 'Показатели доставки' }, + ], + }, + { + label: 'Отправления', + icon: 'ti ti-package', + description: 'Управление заказами', + badge: 'New', + }, + { + label: 'Склады', + icon: 'ti ti-building-warehouse', + description: 'Складское хранение', + items: [ + { label: 'Документы', icon: 'ti ti-file-text', description: 'Накладные и акты' }, + { label: 'Фото', icon: 'ti ti-photo', description: 'Фотофиксация грузов' }, + ], + }, + { + label: 'Настройки', + icon: 'ti ti-settings', + description: 'Параметры системы', + disabled: true, + }, + ]; +} + +export const Custom: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Кастомный шаблон пункта меню с описанием и бейджем.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { MenuItem } from 'primeng/api'; +import { PanelMenu } from 'primeng/panelmenu'; +import { Badge } from 'primeng/badge'; +import { NgIf } from '@angular/common'; + +@Component({ + selector: 'app-panelmenu-custom', + standalone: true, + imports: [PanelMenu, Badge, NgIf], + template: \` + + + + +
+ {{ item.label }} + {{ item['description'] }} +
+ + +
+
+
+ \`, +}) +export class PanelMenuCustomComponent { + items: MenuItem[] = [ + { + label: 'Дашборд', + icon: 'ti ti-layout-dashboard', + description: 'Главная страница', + items: [ + { label: 'Аналитика', icon: 'ti ti-chart-line', description: 'Аналитика данных' }, + { label: 'Отчёты', icon: 'ti ti-file-analytics', description: 'Сводные отчёты' }, + ], + }, + { label: 'Отправления', icon: 'ti ti-package', description: 'Управление заказами', badge: 'New' }, + { + label: 'Склады', + icon: 'ti ti-building-warehouse', + description: 'Складское хранение', + items: [ + { label: 'Документы', icon: 'ti ti-file-text', description: 'Накладные и акты' }, + { label: 'Фото', icon: 'ti ti-photo', description: 'Фотофиксация грузов' }, + ], + }, + { label: 'Настройки', icon: 'ti ti-settings', description: 'Параметры системы', disabled: true }, + ]; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/panelmenu/examples/panelmenu-multiple.component.ts b/src/stories/components/panelmenu/examples/panelmenu-multiple.component.ts new file mode 100644 index 0000000..606aaa4 --- /dev/null +++ b/src/stories/components/panelmenu/examples/panelmenu-multiple.component.ts @@ -0,0 +1,97 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { MenuItem } from 'primeng/api'; +import { PanelMenuComponent } from '../../../../lib/components/panelmenu/panelmenu.component'; + +const template = ` +
+ +
+`; +const styles = ''; + +@Component({ + selector: 'app-panelmenu-multiple', + standalone: true, + imports: [PanelMenuComponent], + template, + styles, +}) +export class PanelMenuMultipleComponent { + items: MenuItem[] = [ + { + label: 'Отправления', + icon: 'ti ti-package', + items: [ + { label: 'Новые', icon: 'ti ti-circle-plus' }, + { label: 'В пути', icon: 'ti ti-truck' }, + { label: 'Доставленные', icon: 'ti ti-circle-check' }, + { + label: 'Возвраты', + icon: 'ti ti-arrow-back', + items: [{ label: 'Ожидают' }, { label: 'Завершённые' }], + }, + ], + }, + { label: 'Маршруты', icon: 'ti ti-route' }, + { + label: 'Склады', + icon: 'ti ti-building-warehouse', + items: [ + { label: 'Москва' }, + { label: 'Новосибирск' }, + { label: 'Екатеринбург' }, + ], + }, + { label: 'Настройки', icon: 'ti ti-settings', disabled: true }, + ]; +} + +export const Multiple: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Несколько панелей могут быть раскрыты одновременно.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { MenuItem } from 'primeng/api'; +import { PanelMenuComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-panelmenu-multiple', + standalone: true, + imports: [PanelMenuComponent], + template: \` + + \`, +}) +export class PanelMenuMultipleComponent { + items: MenuItem[] = [ + { + label: 'Отправления', + icon: 'ti ti-package', + items: [ + { label: 'Новые', icon: 'ti ti-circle-plus' }, + { label: 'В пути', icon: 'ti ti-truck' }, + { label: 'Доставленные', icon: 'ti ti-circle-check' }, + { label: 'Возвраты', icon: 'ti ti-arrow-back', items: [{ label: 'Ожидают' }, { label: 'Завершённые' }] }, + ], + }, + { label: 'Маршруты', icon: 'ti ti-route' }, + { + label: 'Склады', + icon: 'ti ti-building-warehouse', + items: [{ label: 'Москва' }, { label: 'Новосибирск' }, { label: 'Екатеринбург' }], + }, + { label: 'Настройки', icon: 'ti ti-settings', disabled: true }, + ]; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/panelmenu/panelmenu.stories.ts b/src/stories/components/panelmenu/panelmenu.stories.ts new file mode 100644 index 0000000..8a600d6 --- /dev/null +++ b/src/stories/components/panelmenu/panelmenu.stories.ts @@ -0,0 +1,108 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { PanelMenuComponent } from '../../../lib/components/panelmenu/panelmenu.component'; +import { PanelMenuBasicComponent, Basic } from './examples/panelmenu-basic.component'; +import { PanelMenuMultipleComponent, Multiple } from './examples/panelmenu-multiple.component'; +import { PanelMenuCustomComponent, Custom } from './examples/panelmenu-custom.component'; + +const meta: Meta = { + title: 'Components/Menu/PanelMenu', + component: PanelMenuComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + PanelMenuComponent, + PanelMenuBasicComponent, + PanelMenuMultipleComponent, + PanelMenuCustomComponent, + ], + }), + ], + parameters: { + docs: { + description: { + component: `Аккордеон-меню с поддержкой вложенных подменю и раскрытием нескольких панелей. + +\`\`\`typescript +import { PanelMenuComponent } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-panelmenu' }, + }, + argTypes: { + model: { + table: { disable: true }, + }, + multiple: { + control: 'boolean', + description: 'Разрешает одновременное раскрытие нескольких панелей', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + tabindex: { + control: 'number', + description: 'Порядок фокуса при навигации клавиатурой', + table: { + category: 'Props', + defaultValue: { summary: 'undefined' }, + type: { summary: 'number' }, + }, + }, + }, + args: { + multiple: false, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ─────────────────────────────────────────────────────────────────── + +export const Default: Story = { + name: 'Default', + render: (args) => { + const parts: string[] = [`[model]="model"`]; + if (args.multiple) parts.push(`[multiple]="true"`); + if (args.tabindex !== undefined) parts.push(`[tabindex]="${args.tabindex}"`); + + const template = ``; + + return { + props: { + ...args, + model: [ + { + label: 'Отправления', + items: [ + { label: 'Новые' }, + { label: 'В пути' }, + { label: 'Доставленные' }, + ], + }, + { label: 'Маршруты' }, + { + label: 'Склады', + items: [{ label: 'Москва' }, { label: 'Новосибирск' }], + }, + { label: 'Настройки', disabled: true }, + ], + }, + template, + }; + }, + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + }, + }, +}; + +// ── Re-exports from example components ──────────────────────────────────── +export { Basic, Multiple, Custom }; From cb050bc62ba50555c5e13c4a56f721da04742a7b Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 15 Apr 2026 00:10:57 +0700 Subject: [PATCH 2/2] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=81=D1=82?= =?UTF-8?q?=D0=B8=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=B8=D0=B2=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=BF=D1=83=D0=BD?= =?UTF-8?q?=D0=BA=D1=82=D0=B0=20=D0=BC=D0=B5=D0=BD=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../panelmenu/panelmenu.component.ts | 40 ++++++++++++++++++- .../tokens/components/panelmenu.ts | 5 +++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/lib/components/panelmenu/panelmenu.component.ts b/src/lib/components/panelmenu/panelmenu.component.ts index 33f4ddb..efb3516 100644 --- a/src/lib/components/panelmenu/panelmenu.component.ts +++ b/src/lib/components/panelmenu/panelmenu.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { AfterViewChecked, ChangeDetectionStrategy, Component, ElementRef, HostListener, Input } from '@angular/core'; import { PanelMenu } from 'primeng/panelmenu'; import { MenuItem } from 'primeng/api'; @@ -15,8 +15,44 @@ import { MenuItem } from 'primeng/api'; > `, }) -export class PanelMenuComponent { +export class PanelMenuComponent implements AfterViewChecked { @Input() model: MenuItem[] = []; @Input() multiple = false; @Input() tabindex: number | undefined = undefined; + + private activeItemId: string | null = null; + + constructor(private readonly el: ElementRef) {} + + @HostListener('click', ['$event']) + onItemClick(event: MouseEvent): void { + const target = event.target as Element; + + if (target.closest('.p-panelmenu-header')) return; + + const item = target.closest('.p-panelmenu-item'); + if (!item) return; + + this.activeItemId = item.id || null; + this.applyActiveClass(); + } + + ngAfterViewChecked(): void { + if (this.activeItemId) { + this.applyActiveClass(); + } + } + + private applyActiveClass(): void { + const root = this.el.nativeElement; + root.querySelectorAll('.p-panelmenu-item-active') + .forEach(el => el.classList.remove('p-panelmenu-item-active')); + + if (this.activeItemId) { + const active = root.querySelector(`#${CSS.escape(this.activeItemId)}`); + if (active) { + active.classList.add('p-panelmenu-item-active'); + } + } + } } diff --git a/src/prime-preset/tokens/components/panelmenu.ts b/src/prime-preset/tokens/components/panelmenu.ts index 02db6f8..0ef7994 100644 --- a/src/prime-preset/tokens/components/panelmenu.ts +++ b/src/prime-preset/tokens/components/panelmenu.ts @@ -18,12 +18,14 @@ export const panelmenuCss = ({ dt }: { dt: (token: string) => string }): string /* ─── Active & Focused States ─── */ + .p-panelmenu .p-panelmenu-item.p-panelmenu-item-active > .p-panelmenu-item-content, .p-panelmenu .p-panelmenu-item.p-focus > .p-panelmenu-item-content, .p-panelmenu .p-panelmenu-header.p-focus .p-panelmenu-header-content { background: ${dt('panelmenu.extend.extItem.activeBackground')}; color: ${dt('panelmenu.extend.extItem.activeColor')}; } + .p-panelmenu .p-panelmenu-item.p-panelmenu-item-active > .p-panelmenu-item-content :is(.p-panelmenu-item-link, .p-panelmenu-item-label, .p-panelmenu-item-icon, .p-panelmenu-submenu-icon), .p-panelmenu .p-panelmenu-item.p-focus > .p-panelmenu-item-content :is(.p-panelmenu-item-link, .p-panelmenu-item-label, .p-panelmenu-item-icon, .p-panelmenu-header-icon, .p-panelmenu-submenu-icon), .p-panelmenu .p-panelmenu-header.p-focus .p-panelmenu-header-content :is(.p-panelmenu-header-link, .p-panelmenu-header-label, .p-panelmenu-submenu-icon, .p-panelmenu-item-icon, .p-panelmenu-header-icon) { color: ${dt('panelmenu.extend.extItem.activeColor')}; @@ -31,17 +33,20 @@ export const panelmenuCss = ({ dt }: { dt: (token: string) => string }): string /* ─── Hover on Active States ─── */ + .p-panelmenu .p-panelmenu-item.p-panelmenu-item-active:not(.p-disabled) > .p-panelmenu-item-content:hover, .p-panelmenu .p-panelmenu-item.p-focus:not(.p-disabled) > .p-panelmenu-item-content:hover, .p-panelmenu .p-panelmenu-header.p-focus .p-panelmenu-header-content:hover { background: ${dt('panelmenu.item.focusBackground')}; color: ${dt('panelmenu.item.focusColor')}; } + .p-panelmenu .p-panelmenu-item.p-panelmenu-item-active:not(.p-disabled) > .p-panelmenu-item-content:hover :is(.p-panelmenu-item-link, .p-panelmenu-item-label), .p-panelmenu .p-panelmenu-item.p-focus:not(.p-disabled) > .p-panelmenu-item-content:hover :is(.p-panelmenu-item-link, .p-panelmenu-item-label), .p-panelmenu .p-panelmenu-header.p-focus .p-panelmenu-header-content:hover :is(.p-panelmenu-header-link, .p-panelmenu-header-label) { color: ${dt('panelmenu.item.focusColor')}; } + .p-panelmenu .p-panelmenu-item.p-panelmenu-item-active:not(.p-disabled) > .p-panelmenu-item-content:hover :is(.p-panelmenu-item-icon, .p-panelmenu-submenu-icon), .p-panelmenu .p-panelmenu-item.p-focus:not(.p-disabled) > .p-panelmenu-item-content:hover :is(.p-panelmenu-item-icon, .p-panelmenu-submenu-icon), .p-panelmenu .p-panelmenu-header.p-focus .p-panelmenu-header-content:hover :is(.p-panelmenu-submenu-icon, .p-panelmenu-item-icon) { color: ${dt('panelmenu.item.icon.focusColor')};