diff --git a/src/lib/components/scroll-panel/scroll-panel.component.ts b/src/lib/components/scroll-panel/scroll-panel.component.ts
new file mode 100644
index 0000000..76a35a6
--- /dev/null
+++ b/src/lib/components/scroll-panel/scroll-panel.component.ts
@@ -0,0 +1,22 @@
+import { Component, Input } from '@angular/core';
+import { ScrollPanel } from 'primeng/scrollpanel';
+
+@Component({
+ selector: 'scroll-panel',
+ host: { style: 'display: block' },
+ standalone: true,
+ imports: [ScrollPanel],
+ template: `
+
+
+
+ `,
+})
+export class ScrollPanelComponent {
+ @Input() step = 10;
+ @Input() height = '100px';
+ @Input() width = '100%';
+}
diff --git a/src/prime-preset/tokens/components/scroll-panel.ts b/src/prime-preset/tokens/components/scroll-panel.ts
new file mode 100644
index 0000000..8bbe369
--- /dev/null
+++ b/src/prime-preset/tokens/components/scroll-panel.ts
@@ -0,0 +1,20 @@
+/**
+ * Кастомная CSS-стилизация для компонента p-scrollpanel.
+ * Подключается в map-tokens.ts: `import { scrollPanelCss } from './tokens/components/scroll-panel'`
+ */
+export const scrollPanelCss = ({ dt }: { dt: (token: string) => string }): string => `
+ /* ─── Полоса прокрутки ─── */
+ .p-scrollpanel-bar {
+ background: ${dt('scrollpanel.bar.background')};
+ border-radius: ${dt('scrollpanel.bar.borderRadius')};
+ transition-duration: ${dt('scrollpanel.root.transitionDuration')};
+ }
+
+ .p-scrollpanel-bar:focus-visible {
+ outline-width: ${dt('scrollpanel.bar.focusRing.width')};
+ outline-style: ${dt('scrollpanel.bar.focusRing.style')};
+ outline-color: ${dt('scrollpanel.bar.focusRing.color')};
+ outline-offset: ${dt('scrollpanel.bar.focusRing.offset')};
+ box-shadow: ${dt('scrollpanel.bar.focusRing.shadow')};
+ }
+`;
diff --git a/src/stories/components/scroll-panel/examples/scroll-panel-both.component.ts b/src/stories/components/scroll-panel/examples/scroll-panel-both.component.ts
new file mode 100644
index 0000000..7969b9d
--- /dev/null
+++ b/src/stories/components/scroll-panel/examples/scroll-panel-both.component.ts
@@ -0,0 +1,29 @@
+import { Component } from '@angular/core';
+import { ScrollPanelComponent } from '../../../../lib/components/scroll-panel/scroll-panel.component';
+
+const template = `
+
+
+
+
№ЦД-00123456 · Москва → Новосибирск · 2.5 кг · 3 места · Принят 14 апр 09:15 · Доставлен 15 апр 14:20
+
№ЦД-00123457 · Санкт-Петербург → Казань · 0.8 кг · 1 место · Принят 13 апр 11:00 · Доставлен 15 апр 10:30
+
№ЦД-00123458 · Екатеринбург → Краснодар · 5.2 кг · 2 места · Принят 12 апр 08:45 · В пути
+
№ЦД-00123459 · Нижний Новгород → Омск · 1.1 кг · 1 место · Принят 14 апр 15:00 · Ожидает отправки
+
№ЦД-00123460 · Самара → Ростов-на-Дону · 3.7 кг · 4 места · Принят 11 апр 13:20 · Доставлен 14 апр 09:00
+
№ЦД-00123461 · Уфа → Владивосток · 7.3 кг · 5 мест · Принят 10 апр 10:00 · Задержан на сортировке
+
№ЦД-00123462 · Пермь → Иркутск · 2.0 кг · 2 места · Принят 13 апр 09:30 · В пути
+
№ЦД-00123463 · Воронеж → Красноярск · 4.5 кг · 3 места · Принят 12 апр 16:00 · В пути
+
+
+
+`;
+const styles = '';
+
+@Component({
+ selector: 'app-scroll-panel-both',
+ standalone: true,
+ imports: [ScrollPanelComponent],
+ template,
+ styles,
+})
+export class ScrollPanelBothComponent {}
diff --git a/src/stories/components/scroll-panel/examples/scroll-panel-horizontal.component.ts b/src/stories/components/scroll-panel/examples/scroll-panel-horizontal.component.ts
new file mode 100644
index 0000000..54de4a1
--- /dev/null
+++ b/src/stories/components/scroll-panel/examples/scroll-panel-horizontal.component.ts
@@ -0,0 +1,22 @@
+import { Component } from '@angular/core';
+import { ScrollPanelComponent } from '../../../../lib/components/scroll-panel/scroll-panel.component';
+
+const template = `
+
+
+
+ Заказ №ЦД-00123456 · Москва → Новосибирск · Принят 14 апр 09:15 · Передан перевозчику 14 апр 14:30 · Отправлен из Москвы 14 апр 23:50 · Прибыл в Новосибирск 15 апр 08:00 · Передан курьеру Петрову А.В. 15 апр 12:00 · Доставлен получателю 15 апр 14:20
+
+
+
+`;
+const styles = '';
+
+@Component({
+ selector: 'app-scroll-panel-horizontal',
+ standalone: true,
+ imports: [ScrollPanelComponent],
+ template,
+ styles,
+})
+export class ScrollPanelHorizontalComponent {}
diff --git a/src/stories/components/scroll-panel/scroll-panel.stories.ts b/src/stories/components/scroll-panel/scroll-panel.stories.ts
new file mode 100644
index 0000000..03bfc32
--- /dev/null
+++ b/src/stories/components/scroll-panel/scroll-panel.stories.ts
@@ -0,0 +1,200 @@
+import { Meta, StoryObj, moduleMetadata } from '@storybook/angular';
+import { ScrollPanelComponent } from '../../../lib/components/scroll-panel/scroll-panel.component';
+import { ScrollPanelHorizontalComponent } from './examples/scroll-panel-horizontal.component';
+import { ScrollPanelBothComponent } from './examples/scroll-panel-both.component';
+
+const TRACKING_CONTENT = `
+
+
Заказ №ЦД-00123456 · Москва → Новосибирск
+
14 апр, 09:15 — Принят в сортировочном центре «Москва-Север»
+
14 апр, 14:30 — Передан перевозчику CDEK
+
14 апр, 23:50 — Отправлен из Москвы
+
15 апр, 08:00 — Прибыл в сортировочный центр «Новосибирск»
+
15 апр, 12:00 — Передан курьеру Петрову А.В.
+
15 апр, 14:20 — Попытка доставки (получатель отсутствовал)
+
15 апр, 18:00 — Ожидает получения в ПВЗ на ул. Ленина, 42
+
16 апр, 10:30 — Доставлен получателю
+
+`;
+
+const HORIZONTAL_CONTENT = `
+
+ Заказ №ЦД-00123456 · Москва → Новосибирск · Принят 14 апр 09:15 · Передан перевозчику 14 апр 14:30 · Отправлен из Москвы 14 апр 23:50 · Прибыл в Новосибирск 15 апр 08:00 · Передан курьеру Петрову А.В. 15 апр 12:00 · Доставлен получателю 15 апр 14:20
+
+`;
+
+const BOTH_CONTENT = `
+
+
№ЦД-00123456 · Москва → Новосибирск · 2.5 кг · 3 места · Принят 14 апр 09:15 · Доставлен 15 апр 14:20
+
№ЦД-00123457 · Санкт-Петербург → Казань · 0.8 кг · 1 место · Принят 13 апр 11:00 · Доставлен 15 апр 10:30
+
№ЦД-00123458 · Екатеринбург → Краснодар · 5.2 кг · 2 места · Принят 12 апр 08:45 · В пути
+
№ЦД-00123459 · Нижний Новгород → Омск · 1.1 кг · 1 место · Принят 14 апр 15:00 · Ожидает отправки
+
№ЦД-00123460 · Самара → Ростов-на-Дону · 3.7 кг · 4 места · Принят 11 апр 13:20 · Доставлен 14 апр 09:00
+
№ЦД-00123461 · Уфа → Владивосток · 7.3 кг · 5 мест · Принят 10 апр 10:00 · Задержан на сортировке
+
№ЦД-00123462 · Пермь → Иркутск · 2.0 кг · 2 места · Принят 13 апр 09:30 · В пути
+
№ЦД-00123463 · Воронеж → Красноярск · 4.5 кг · 3 места · Принят 12 апр 16:00 · В пути
+
+`;
+
+const meta: Meta = {
+ title: 'Components/Panel/ScrollPanel',
+ component: ScrollPanelComponent,
+ tags: ['autodocs'],
+ decorators: [
+ moduleMetadata({
+ imports: [
+ ScrollPanelComponent,
+ ScrollPanelHorizontalComponent,
+ ScrollPanelBothComponent,
+ ],
+ }),
+ ],
+ parameters: {
+ docs: {
+ description: {
+ component: `Кроссбраузерная панель с кастомной полосой прокрутки. Заменяет стандартный скроллбар браузера на стилизованный в соответствии с темой.
+
+\`\`\`typescript
+import { ScrollPanelModule } from 'primeng/scrollpanel';
+\`\`\``,
+ },
+ },
+ designTokens: { prefix: '--p-scrollpanel' },
+ },
+ argTypes: {
+ step: {
+ control: 'number',
+ description: 'Шаг прокрутки при нажатии клавиш со стрелками (в пикселях)',
+ table: {
+ category: 'Props',
+ defaultValue: { summary: '10' },
+ type: { summary: 'number' },
+ },
+ },
+ height: {
+ control: 'text',
+ description: 'Высота области прокрутки',
+ table: {
+ category: 'Props',
+ defaultValue: { summary: '100px' },
+ type: { summary: 'string' },
+ },
+ },
+ width: {
+ control: 'text',
+ description: 'Ширина области прокрутки',
+ table: {
+ category: 'Props',
+ defaultValue: { summary: '100%' },
+ type: { summary: 'string' },
+ },
+ },
+ },
+ args: {
+ step: 10,
+ height: '100px',
+ width: '100%',
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+// ── Default ──────────────────────────────────────────────────────────────────
+
+export const Default: Story = {
+ name: 'Default',
+ render: (args) => {
+ const parts: string[] = [];
+
+ if (args.height && args.height !== '100px') parts.push(`height="${args.height}"`);
+ if (args.width && args.width !== '100%') parts.push(`width="${args.width}"`);
+ if (args.step !== 10) parts.push(`[step]="${args.step}"`);
+
+ const attrStr = parts.length ? `\n ${parts.join('\n ')}\n` : '';
+ const template = `${TRACKING_CONTENT}`;
+
+ return { props: args, template };
+ },
+ parameters: {
+ docs: {
+ description: {
+ story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.',
+ },
+ },
+ },
+};
+
+// ── Stories ──────────────────────────────────────────────────────────────────
+
+export const Horizontal: Story = {
+ render: (args) => ({
+ props: args,
+ template: `${HORIZONTAL_CONTENT}`,
+ }),
+ args: { step: 10, height: '80px', width: '100%' },
+ parameters: {
+ docs: {
+ description: { story: 'Горизонтальная прокрутка. Контент без переносов выходит за ширину контейнера.' },
+ source: {
+ language: 'ts',
+ code: `
+import { Component } from '@angular/core';
+import { ScrollPanelComponent } from '@cdek-it/angular-ui-kit';
+
+@Component({
+ selector: 'app-scroll-panel-horizontal',
+ standalone: true,
+ imports: [ScrollPanelComponent],
+ template: \`
+
+
+ Заказ №ЦД-00123456 · Москва → Новосибирск · Принят 14 апр 09:15 · Передан перевозчику 14 апр 14:30 · Отправлен из Москвы 14 апр 23:50 · Прибыл в Новосибирск 15 апр 08:00 · Доставлен получателю 15 апр 14:20
+
+
+ \`,
+})
+export class ScrollPanelHorizontalComponent {}
+ `,
+ },
+ },
+ },
+};
+
+export const Both: Story = {
+ render: (args) => ({
+ props: args,
+ template: `${BOTH_CONTENT}`,
+ }),
+ args: { step: 10, height: '200px', width: '50%' },
+ parameters: {
+ docs: {
+ description: { story: 'Прокрутка в обоих направлениях — таблица отправлений шире и длиннее контейнера.' },
+ source: {
+ language: 'ts',
+ code: `
+import { Component } from '@angular/core';
+import { ScrollPanelComponent } from '@cdek-it/angular-ui-kit';
+
+@Component({
+ selector: 'app-scroll-panel-both',
+ standalone: true,
+ imports: [ScrollPanelComponent],
+ template: \`
+
+
+
№ЦД-00123456 · Москва → Новосибирск · 2.5 кг · 3 места · Принят 14 апр · Доставлен 15 апр
+
№ЦД-00123457 · Санкт-Петербург → Казань · 0.8 кг · 1 место · Принят 13 апр · Доставлен 15 апр
+
№ЦД-00123458 · Екатеринбург → Краснодар · 5.2 кг · 2 места · Принят 12 апр · В пути
+
№ЦД-00123459 · Нижний Новгород → Омск · 1.1 кг · 1 место · Принят 14 апр · Ожидает отправки
+
№ЦД-00123460 · Самара → Ростов-на-Дону · 3.7 кг · 4 места · Принят 11 апр · Доставлен 14 апр
+
+
+ \`,
+})
+export class ScrollPanelBothComponent {}
+ `,
+ },
+ },
+ },
+};