From 6ba763dc51a39b666479bcb3deac36aa8758eccf Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 8 Apr 2026 21:57:05 +0700 Subject: [PATCH] =?UTF-8?q?scrollpanel:=20=D1=81=D1=82=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D1=81=D1=8B,=20=D0=BE=D0=B1=D1=91=D1=80=D1=82=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scroll-panel/scroll-panel.component.ts | 22 ++ .../tokens/components/scroll-panel.ts | 20 ++ .../examples/scroll-panel-both.component.ts | 29 +++ .../scroll-panel-horizontal.component.ts | 22 ++ .../scroll-panel/scroll-panel.stories.ts | 200 ++++++++++++++++++ 5 files changed, 293 insertions(+) create mode 100644 src/lib/components/scroll-panel/scroll-panel.component.ts create mode 100644 src/prime-preset/tokens/components/scroll-panel.ts create mode 100644 src/stories/components/scroll-panel/examples/scroll-panel-both.component.ts create mode 100644 src/stories/components/scroll-panel/examples/scroll-panel-horizontal.component.ts create mode 100644 src/stories/components/scroll-panel/scroll-panel.stories.ts 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 {} + `, + }, + }, + }, +};