From 73c38466e3efe38fd9595a9306bdcba4fdbf66be Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 15 Apr 2026 20:08:16 +0700 Subject: [PATCH 1/4] =?UTF-8?q?drawer:=20=D1=81=D1=82=D0=B8=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/drawer/drawer.component.ts | 63 ++++++ src/prime-preset/map-tokens.ts | 5 + src/prime-preset/tokens/components/drawer.ts | 83 +++++++ src/prime-preset/tokens/tokens.json | 14 +- .../components/drawer/drawer.stories.ts | 202 ++++++++++++++++++ .../examples/drawer-full-screen.component.ts | 59 +++++ .../examples/drawer-position.component.ts | 99 +++++++++ .../drawer/examples/drawer-sizes.component.ts | 99 +++++++++ .../examples/drawer-with-footer.component.ts | 73 +++++++ .../drawer-without-modal.component.ts | 59 +++++ 10 files changed, 754 insertions(+), 2 deletions(-) create mode 100644 src/lib/components/drawer/drawer.component.ts create mode 100644 src/prime-preset/tokens/components/drawer.ts create mode 100644 src/stories/components/drawer/drawer.stories.ts create mode 100644 src/stories/components/drawer/examples/drawer-full-screen.component.ts create mode 100644 src/stories/components/drawer/examples/drawer-position.component.ts create mode 100644 src/stories/components/drawer/examples/drawer-sizes.component.ts create mode 100644 src/stories/components/drawer/examples/drawer-with-footer.component.ts create mode 100644 src/stories/components/drawer/examples/drawer-without-modal.component.ts diff --git a/src/lib/components/drawer/drawer.component.ts b/src/lib/components/drawer/drawer.component.ts new file mode 100644 index 00000000..32ddce45 --- /dev/null +++ b/src/lib/components/drawer/drawer.component.ts @@ -0,0 +1,63 @@ +import { + Component, + ContentChild, + EventEmitter, + Input, + Output, + TemplateRef, +} from '@angular/core'; +import { Drawer } from 'primeng/drawer'; +import { SharedModule } from 'primeng/api'; +import { NgIf, NgTemplateOutlet } from '@angular/common'; + +@Component({ + selector: 'drawer', + standalone: true, + imports: [Drawer, SharedModule, NgIf, NgTemplateOutlet], + template: ` + + + + + + + `, +}) +export class DrawerComponent { + @Input() visible = false; + @Input() header: string | undefined; + @Input() position: 'left' | 'right' | 'top' | 'bottom' = 'right'; + @Input() size: 'default' | 'sm' | 'lg' | 'xlg' = 'default'; + @Input() modal = true; + @Input() fullScreen = false; + @Input() dismissible = true; + @Input() showCloseIcon = true; + @Input() closeOnEscape = true; + @Input() blockScroll = true; + + @Output() visibleChange = new EventEmitter(); + @Output() onShow = new EventEmitter(); + @Output() onHide = new EventEmitter(); + + @ContentChild('drawerFooter') footerTemplate: TemplateRef | null = + null; + + get sizeClass(): string { + if (this.size === 'default') return ''; + return `p-drawer-${this.size}`; + } +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 0194af83..58e60a51 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -8,6 +8,7 @@ import { buttonCss } from './tokens/components/button'; import { checkboxCss } from './tokens/components/checkbox'; import { progressspinnerCss } from './tokens/components/progressspinner'; import { tagCss } from './tokens/components/tag'; +import { drawerCss } from './tokens/components/drawer'; import { tooltipCss } from './tokens/components/tooltip'; const presetTokens: Preset = { @@ -19,6 +20,10 @@ const presetTokens: Preset = { ...(tokens.components.avatar as unknown as ComponentsDesignTokens['avatar']), css: avatarCss, }, + drawer: { + ...(tokens.components.drawer as unknown as ComponentsDesignTokens['drawer']), + css: drawerCss, + }, checkbox: { ...(tokens.components.checkbox as unknown as ComponentsDesignTokens['checkbox']), css: checkboxCss, diff --git a/src/prime-preset/tokens/components/drawer.ts b/src/prime-preset/tokens/components/drawer.ts new file mode 100644 index 00000000..0f3b2ce8 --- /dev/null +++ b/src/prime-preset/tokens/components/drawer.ts @@ -0,0 +1,83 @@ +const drawerCss = ({ dt }: { dt: (token: string) => string }): string => ` + +/* Скругление углов */ +.p-drawer.p-component { + border-radius: ${dt('drawer.extend.borderRadius')}; +} + +/* Нижняя граница и внутренние отступы заголовка */ +.p-drawer.p-component .p-drawer-header { + border-bottom: 1px solid ${dt('drawer.extend.extHeader.borderColor')}; + padding: ${dt('overlay.modal.padding.300')} ${dt('overlay.modal.padding.300')} ${dt('overlay.modal.padding.100')} ${dt('overlay.modal.padding.300')}; +} + +/* Типографика */ +.p-drawer.p-component .p-drawer-title { + font-weight: ${dt('drawer.title.fontWeight')}; + font-size: ${dt('drawer.title.fontSize')}; +} + +/* Кнопки действий в заголовке - расстояние между элементами */ +.p-drawer.p-component .p-drawer-header-actions { + gap: ${dt('drawer.extend.extHeader.gap')}; +} + +/* Внутренние отступы контента и футера */ +.p-drawer.p-component .p-drawer-content { + padding: ${dt('overlay.modal.padding.300')}; +} + +.p-drawer.p-component .p-drawer-footer { + padding: 0 ${dt('overlay.modal.padding.300')} ${dt('overlay.modal.padding.300')} ${dt('overlay.modal.padding.300')}; +} + +/* Кнопка закрытия — нейтральный outlined стиль вместо secondary */ +.p-drawer.p-component .p-drawer-close-button { + background: transparent; + border: 1px solid ${dt('drawer.root.borderColor')}; + color: ${dt('text.color')}; +} + +.p-drawer.p-component .p-drawer-close-button:hover { + background: ${dt('surface.100')}; + border-color: ${dt('drawer.root.borderColor')}; + color: ${dt('text.color')}; +} + +.p-drawer.p-component .p-drawer-close-button:active { + background: ${dt('surface.200')}; +} + +/* Боковые drawer (слева/справа) - базовые размеры и отступы от краев экрана */ +.p-drawer.p-component.p-drawer-left, +.p-drawer.p-component.p-drawer-right { + margin: ${dt('drawer.extend.padding')}; + width: ${dt('drawer.root.width')}; + height: calc(100% - ${dt('drawer.extend.padding')} * 2); +} + +.p-drawer.p-component.p-drawer-left.p-drawer-sm, +.p-drawer.p-component.p-drawer-right.p-drawer-sm { + width: ${dt('drawer.sm.width')}; +} + +.p-drawer.p-component.p-drawer-left.p-drawer-lg, +.p-drawer.p-component.p-drawer-right.p-drawer-lg { + width: ${dt('drawer.lg.width')}; +} + +.p-drawer.p-component.p-drawer-left.p-drawer-xlg, +.p-drawer.p-component.p-drawer-right.p-drawer-xlg { + width: ${dt('drawer.xlg.width')}; +} + +/* Горизонтальные drawer (сверху/снизу) - базовые размеры и отступы от краев экрана */ +.p-drawer.p-component.p-drawer-top, +.p-drawer.p-component.p-drawer-bottom { + margin: ${dt('drawer.extend.padding')}; + width: calc(100% - ${dt('drawer.extend.padding')} * 2); +} + +`; + +export { drawerCss }; diff --git a/src/prime-preset/tokens/tokens.json b/src/prime-preset/tokens/tokens.json index 19d1ea50..b8ffef1d 100644 --- a/src/prime-preset/tokens/tokens.json +++ b/src/prime-preset/tokens/tokens.json @@ -2805,10 +2805,20 @@ "background": "{overlay.modal.background}", "borderColor": "{overlay.modal.borderColor}", "color": "{overlay.modal.color}", - "shadow": "{overlay.modal.shadow}" + "shadow": "{overlay.modal.shadow}", + "width": "{overlay.width}" + }, + "sm": { + "width": "{overlay.sm.width}" + }, + "lg": { + "width": "{overlay.lg.width}" + }, + "xlg": { + "width": "{overlay.xlg.width}" }, "header": { - "padding": "{overlay.modal.padding.300} {overlay.modal.padding.300} {overlay.modal.padding.100} {overlay.modal.padding.300} " + "padding": "{overlay.modal.padding.300} {overlay.modal.padding.300} {overlay.modal.padding.200} {overlay.modal.padding.300} " }, "title": { "fontSize": "{fonts.fontSize.500}", diff --git a/src/stories/components/drawer/drawer.stories.ts b/src/stories/components/drawer/drawer.stories.ts new file mode 100644 index 00000000..39a4ede3 --- /dev/null +++ b/src/stories/components/drawer/drawer.stories.ts @@ -0,0 +1,202 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { DrawerComponent } from '../../../lib/components/drawer/drawer.component'; +import { ButtonComponent } from '../../../lib/components/button/button.component'; +import { DrawerSizesComponent, Sizes as SizesStory } from './examples/drawer-sizes.component'; +import { DrawerPositionComponent, Position as PositionStory } from './examples/drawer-position.component'; +import { DrawerWithFooterComponent, WithFooter as WithFooterStory } from './examples/drawer-with-footer.component'; +import { DrawerFullScreenComponent, FullScreen as FullScreenStory } from './examples/drawer-full-screen.component'; +import { DrawerWithoutModalComponent, WithoutModal as WithoutModalStory } from './examples/drawer-without-modal.component'; + +type DrawerArgs = DrawerComponent & { visible: boolean }; + +const meta: Meta = { + title: 'Components/Overlay/Drawer', + component: DrawerComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + DrawerComponent, + ButtonComponent, + DrawerSizesComponent, + DrawerPositionComponent, + DrawerWithFooterComponent, + DrawerFullScreenComponent, + DrawerWithoutModalComponent, + ], + }), + ], + parameters: { + docs: { + description: { + component: `Drawer — панель, отображаемая как оверлей у края экрана. + +\`\`\`typescript +import { DrawerComponent } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-drawer' }, + }, + argTypes: { + visible: { + control: 'boolean', + description: 'Видимость drawer (two-way binding)', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + header: { + control: 'text', + description: 'Заголовок drawer', + table: { + category: 'Props', + defaultValue: { summary: 'undefined' }, + type: { summary: 'string' }, + }, + }, + position: { + control: 'select', + options: ['left', 'right', 'top', 'bottom'], + description: 'Позиция drawer', + table: { + category: 'Props', + defaultValue: { summary: 'right' }, + type: { summary: "'left' | 'right' | 'top' | 'bottom'" }, + }, + }, + size: { + control: 'select', + options: ['default', 'sm', 'lg', 'xlg'], + description: 'Размер drawer', + table: { + category: 'Props', + defaultValue: { summary: 'default' }, + type: { summary: "'default' | 'sm' | 'lg' | 'xlg'" }, + }, + }, + modal: { + control: 'boolean', + description: 'Показывать модальный оверлей', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + fullScreen: { + control: 'boolean', + description: 'Полноэкранный режим', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + dismissible: { + control: 'boolean', + description: 'Закрытие по клику на оверлей', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + showCloseIcon: { + control: 'boolean', + description: 'Показывать кнопку закрытия', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + closeOnEscape: { + control: 'boolean', + description: 'Закрытие по Escape', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + blockScroll: { + control: 'boolean', + description: 'Блокировка прокрутки страницы', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ─────────────────────────────────────────────────────────────────── + +export const Default: Story = { + name: 'Default', + render: (args) => ({ + props: { ...args, visible: false }, + template: ` + + +

Drawer content.

+
+ `, + }), + args: { + header: 'Drawer', + position: 'right', + size: 'default', + modal: true, + fullScreen: false, + dismissible: true, + showCloseIcon: true, + closeOnEscape: true, + blockScroll: true, + }, + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + }, + }, +}; + +// ── Sizes ───────────────────────────────────────────────────────────────────── + +export const Sizes: Story = SizesStory; + +// ── Position ────────────────────────────────────────────────────────────────── + +export const Position: Story = PositionStory; + +// ── WithFooter ──────────────────────────────────────────────────────────────── + +export const WithFooter: Story = WithFooterStory; + +// ── FullScreen ──────────────────────────────────────────────────────────────── + +export const FullScreen: Story = FullScreenStory; + +// ── WithoutModal ────────────────────────────────────────────────────────────── + +export const WithoutModal: Story = WithoutModalStory; diff --git a/src/stories/components/drawer/examples/drawer-full-screen.component.ts b/src/stories/components/drawer/examples/drawer-full-screen.component.ts new file mode 100644 index 00000000..2671de84 --- /dev/null +++ b/src/stories/components/drawer/examples/drawer-full-screen.component.ts @@ -0,0 +1,59 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { DrawerComponent } from '../../../../lib/components/drawer/drawer.component'; +import { ButtonComponent } from '../../../../lib/components/button/button.component'; + +const template = ` + + + +

Full screen drawer content.

+
+`; +const styles = ''; + +@Component({ + selector: 'app-drawer-full-screen', + standalone: true, + imports: [DrawerComponent, ButtonComponent], + template, + styles, +}) +export class DrawerFullScreenComponent { + visible = false; +} + +export const FullScreen: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { story: 'Drawer в полноэкранном режиме.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DrawerComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-drawer-full-screen', + standalone: true, + imports: [DrawerComponent, ButtonComponent], + template: \` + + + +

Full screen drawer content.

+
+ \`, +}) +export class DrawerFullScreenComponent { + visible = false; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/drawer/examples/drawer-position.component.ts b/src/stories/components/drawer/examples/drawer-position.component.ts new file mode 100644 index 00000000..88eae30b --- /dev/null +++ b/src/stories/components/drawer/examples/drawer-position.component.ts @@ -0,0 +1,99 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { DrawerComponent } from '../../../../lib/components/drawer/drawer.component'; +import { ButtonComponent } from '../../../../lib/components/button/button.component'; + +const template = ` +
+ + + + +
+ + +

Left drawer content.

+
+ + +

Right drawer content.

+
+ + +

Top drawer content.

+
+ + +

Bottom drawer content.

+
+`; +const styles = ''; + +@Component({ + selector: 'app-drawer-position', + standalone: true, + imports: [DrawerComponent, ButtonComponent], + template, + styles, +}) +export class DrawerPositionComponent { + visibleLeft = false; + visibleRight = false; + visibleTop = false; + visibleBottom = false; +} + +export const Position: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { story: 'Drawer с различными позициями: left, right, top, bottom.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DrawerComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-drawer-position', + standalone: true, + imports: [DrawerComponent, ButtonComponent], + template: \` +
+ + + + +
+ + +

Left drawer content.

+
+ + +

Right drawer content.

+
+ + +

Top drawer content.

+
+ + +

Bottom drawer content.

+
+ \`, +}) +export class DrawerPositionComponent { + visibleLeft = false; + visibleRight = false; + visibleTop = false; + visibleBottom = false; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/drawer/examples/drawer-sizes.component.ts b/src/stories/components/drawer/examples/drawer-sizes.component.ts new file mode 100644 index 00000000..4b637afc --- /dev/null +++ b/src/stories/components/drawer/examples/drawer-sizes.component.ts @@ -0,0 +1,99 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { DrawerComponent } from '../../../../lib/components/drawer/drawer.component'; +import { ButtonComponent } from '../../../../lib/components/button/button.component'; + +const template = ` +
+ + + + +
+ + +

Default size drawer content.

+
+ + +

Small size drawer content.

+
+ + +

Large size drawer content.

+
+ + +

Extra large size drawer content.

+
+`; +const styles = ''; + +@Component({ + selector: 'app-drawer-sizes', + standalone: true, + imports: [DrawerComponent, ButtonComponent], + template, + styles, +}) +export class DrawerSizesComponent { + visibleDefault = false; + visibleSm = false; + visibleLg = false; + visibleXlg = false; +} + +export const Sizes: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { story: 'Drawer в различных размерах: default, sm, lg, xlg.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DrawerComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-drawer-sizes', + standalone: true, + imports: [DrawerComponent, ButtonComponent], + template: \` +
+ + + + +
+ + +

Default size drawer content.

+
+ + +

Small size drawer content.

+
+ + +

Large size drawer content.

+
+ + +

Extra large size drawer content.

+
+ \`, +}) +export class DrawerSizesComponent { + visibleDefault = false; + visibleSm = false; + visibleLg = false; + visibleXlg = false; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/drawer/examples/drawer-with-footer.component.ts b/src/stories/components/drawer/examples/drawer-with-footer.component.ts new file mode 100644 index 00000000..c4adb74c --- /dev/null +++ b/src/stories/components/drawer/examples/drawer-with-footer.component.ts @@ -0,0 +1,73 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { DrawerComponent } from '../../../../lib/components/drawer/drawer.component'; +import { ButtonComponent } from '../../../../lib/components/button/button.component'; + +const template = ` + + + +

Drawer content with footer actions.

+ + +
+ + +
+
+
+`; +const styles = ''; + +@Component({ + selector: 'app-drawer-with-footer', + standalone: true, + imports: [DrawerComponent, ButtonComponent], + template, + styles, +}) +export class DrawerWithFooterComponent { + visible = false; +} + +export const WithFooter: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { story: 'Drawer с футером, содержащим кнопки действий.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DrawerComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-drawer-with-footer', + standalone: true, + imports: [DrawerComponent, ButtonComponent], + template: \` + + + +

Drawer content with footer actions.

+ + +
+ + +
+
+
+ \`, +}) +export class DrawerWithFooterComponent { + visible = false; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/drawer/examples/drawer-without-modal.component.ts b/src/stories/components/drawer/examples/drawer-without-modal.component.ts new file mode 100644 index 00000000..b9f3dbaa --- /dev/null +++ b/src/stories/components/drawer/examples/drawer-without-modal.component.ts @@ -0,0 +1,59 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { DrawerComponent } from '../../../../lib/components/drawer/drawer.component'; +import { ButtonComponent } from '../../../../lib/components/button/button.component'; + +const template = ` + + + +

Drawer without backdrop overlay.

+
+`; +const styles = ''; + +@Component({ + selector: 'app-drawer-without-modal', + standalone: true, + imports: [DrawerComponent, ButtonComponent], + template, + styles, +}) +export class DrawerWithoutModalComponent { + visible = false; +} + +export const WithoutModal: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { story: 'Drawer без модального оверлея.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DrawerComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-drawer-without-modal', + standalone: true, + imports: [DrawerComponent, ButtonComponent], + template: \` + + + +

Drawer without backdrop overlay.

+
+ \`, +}) +export class DrawerWithoutModalComponent { + visible = false; +} + `, + }, + }, + }, +}; From 5e540c14df3d298632ff11df4d0a030ffc2b4082 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 15 Apr 2026 20:17:12 +0700 Subject: [PATCH 2/4] =?UTF-8?q?=D1=81=D1=82=D0=B8=D0=BB=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/CLAUDE-v1.6.md | 751 ------------------ src/lib/components/drawer/drawer.component.ts | 1 + src/prime-preset/tokens/components/drawer.ts | 13 - 3 files changed, 1 insertion(+), 764 deletions(-) delete mode 100644 .claude/CLAUDE-v1.6.md diff --git a/.claude/CLAUDE-v1.6.md b/.claude/CLAUDE-v1.6.md deleted file mode 100644 index 2cf230a4..00000000 --- a/.claude/CLAUDE-v1.6.md +++ /dev/null @@ -1,751 +0,0 @@ -# CLAUDE.md — Angular UI Kit (@cdek-it/angular-ui-kit) - -Инструкции для Claude Code по генерации компонентов, обёрток и сторисов. - ---- - -## Стек и версии - -| Технология | Версия | -|----------------|---------| -| Angular | 20 | -| PrimeNG | 20 | -| Storybook | 10 | -| Tailwind CSS | 3 | -| TypeScript | 5 | - ---- - -## Структура проекта - -``` -src/ -├── lib/ -│ └── components/ -│ └── {name}/ -│ └── {name}.component.ts ← компонент-обёртка -├── stories/ -│ └── components/ -│ └── {name}/ -│ ├── {name}.stories.ts ← сторисы -│ └── examples/ ← примеры для сторисов -├── prime-preset/ -│ └── tokens/ -│ └── components/ -│ └── {name}.ts ← CSS-токены компонента -└── styles.scss ← Tailwind + иконки + шрифты -``` - ---- - -## Паттерн компонента-обёртки - -Каждый компонент — standalone Angular-компонент, оборачивающий PrimeNG. - -### Правила - -1. Файл: `src/lib/components/{name}/{name}.component.ts` -2. `selector` — с приставкой `extra-` + имя компонента строчными буквами (например `selector: 'extra-button'`) -3. Импортировать PrimeNG-компонент и указать его в `imports: []` -4. Для каждого типа Input создавать отдельный `type`-алиас -5. Все `@Input()` отражают **свой** API обёртки, не PrimeNG напрямую -6. Computed-геттеры маппят API обёртки → PrimeNG API -7. Шаблон компонента использует только геттеры, не сырые инпуты - -### Эталон — ButtonComponent - -```typescript -import { Component, Input } from '@angular/core'; -import { Button, ButtonSeverity as PrimeButtonSeverity } from 'primeng/button'; - -// Типы — отдельные алиасы, не inline union -export type ButtonVariant = 'primary' | 'secondary' | 'outlined' | 'text' | 'link'; -export type ButtonSeverity = 'success' | 'warning' | 'danger' | 'info' | null; -export type ButtonSize = 'small' | 'base' | 'large' | 'xlarge'; -export type ButtonIconPos = 'prefix' | 'postfix' | null; -export type BadgeSeverity = 'success' | 'info' | 'warning' | 'danger' | 'secondary' | 'contrast' | null; - -@Component({ - selector: 'extra-button', - standalone: true, - imports: [Button], - template: ` - - ` -}) -export class ButtonComponent { - @Input() label = 'Button'; - @Input() variant: ButtonVariant = 'primary'; - @Input() severity: ButtonSeverity = null; - @Input() size: ButtonSize = 'base'; - @Input() rounded = false; - @Input() iconPos: ButtonIconPos = null; - @Input() iconOnly = false; - @Input() icon = ''; - @Input() disabled = false; - @Input() loading = false; - @Input() badge = ''; - @Input() badgeSeverity: BadgeSeverity = null; - @Input() showBadge = false; - @Input() fluid = false; - @Input() ariaLabel: string | undefined = undefined; - @Input() autofocus = false; - @Input() tabindex: number | undefined = undefined; - @Input() text = false; - - // Геттеры — маппинг в PrimeNG API - get primeSize(): 'small' | 'large' | undefined { - if (this.size === 'small') return 'small'; - if (this.size === 'large') return 'large'; - return undefined; - } - - get primeIconPos(): 'left' | 'right' { - return this.iconPos === 'postfix' ? 'right' : 'left'; - } - - get primeSeverity(): PrimeButtonSeverity | null { - if (this.variant === 'secondary') return 'secondary'; - if (this.severity === 'warning') return 'warn'; - return this.severity; - } - - get primeBadgeSeverity() { - if (this.badgeSeverity === 'warning') return 'warn'; - return this.badgeSeverity; - } -} -``` - ---- - -## Паттерн сторисов - -### Файл: `src/stories/components/{name}/{name}.stories.ts` - -**Все тексты описаний — на русском языке.** - -### Правило: title сториса - -Формат: `Components/{Category}/{ComponentName}` - -Категории соответствуют группировке на [primeng.org](https://primeng.org/): - -| Категория | Компоненты | -|-----------|-----------------------------------------------------------------------------------------------| -| Button | Button, SpeedDial, SplitButton | -| Data | DataTable, DataView, OrderList, OrgChart, Paginator, PickList, Timeline, Tree, TreeTable | -| Form | AutoComplete, Checkbox, ColorPicker, DatePicker, InputMask, InputNumber, InputOtp, InputText, Knob, Listbox, MultiSelect, Password, RadioButton, Rating, Select, SelectButton, Slider, Textarea, ToggleButton, ToggleSwitch, TreeSelect | -| Menu | Breadcrumb, ContextMenu, Dock, Menu, Menubar, MegaMenu, PanelMenu, Steps, TabMenu, TieredMenu | -| Messages | Message, Toast | -| Misc | Avatar, Badge, BlockUI, Chip, Inplace, MeterGroup, ProgressBar, ProgressSpinner, ScrollTop, Skeleton, Tag | -| Overlay | ConfirmDialog, ConfirmPopup, Dialog, Drawer, Popover, Tooltip | -| Panel | Accordion, Card, Divider, Fieldset, Panel, ScrollPanel, Splitter, Stepper, Tabs | -| Media | Carousel, Galleria, Image, ImageCompare | - -```typescript -// ❌ Запрещено -title: 'Prime/Button' -title: 'Components/Button' - -// ✅ Правильно -title: 'Components/Button/Button' -title: 'Components/Panel/Card' -title: 'Components/Panel/Divider' -title: 'Components/Form/InputText' -``` - -### Полный шаблон сториса - -```typescript -import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { XxxComponent } from '../../../lib/components/xxx/xxx.component'; - -// Расширяем тип для Events, которых нет в @Output() -type XxxArgs = XxxComponent & { onClick?: (event: MouseEvent) => void }; - -const meta: Meta = { - title: 'Components/{Category}/Xxx', - component: XxxComponent, - tags: ['autodocs'], - decorators: [ - moduleMetadata({ imports: [XxxComponent] }) - ], - parameters: { - docs: { - description: { - // 1. Одна строка — для чего компонент - // 2. Ссылка на Figma - // 3. Блок импорта - component: `Описание компонента. [Figma Design](https://www.figma.com/design/...). - -\`\`\`typescript -import { XxxModule } from 'primeng/xxx'; -\`\`\``, - }, - }, - }, - argTypes: { - // ── Props ──────────────────────────────────────────────── - propName: { - control: 'text' | 'boolean' | 'select' | 'number', - options: [...], // только для select - description: 'Описание на русском', - table: { - category: 'Props', - defaultValue: { summary: 'значение' }, - type: { summary: "'тип1' | 'тип2'" }, - }, - }, - // ── Badge ──────────────────────────────────────────────── - badge: { - // ... category: 'Badge' - }, - // ── Events ─────────────────────────────────────────────── - onClick: { - control: false, - description: 'Событие клика', - table: { - category: 'Events', - type: { summary: 'EventEmitter' }, - }, - }, - }, - args: { - // Дефолты для полей, которые нужно явно инициализировать - }, -}; - -// commonTemplate — для сторисов-вариаций (НЕ для Default) -const commonTemplate = ` - -`; - -export default meta; -type Story = StoryObj; - -// ── Default ────────────────────────────────────────────────────────────────── -// Динамический render: template генерируется из текущих args. -// Storybook Angular захватывает template как source code → -// при смене controls сниппет обновляется автоматически. - -export const Default: Story = { - name: 'Default', - render: (args) => { - const parts: string[] = []; - - if (args.label) parts.push(`label="${args.label}"`); - if (args.variant) parts.push(`variant="${args.variant}"`); - if (args.severity) parts.push(`severity="${args.severity}"`); - // ... остальные пропсы - if (args.rounded) parts.push(`[rounded]="true"`); - if (args.disabled) parts.push(`[disabled]="true"`); - - const template = parts.length - ? `` - : ``; - - return { props: args, template }; - }, - args: { label: 'Label' }, - parameters: { - docs: { - description: { - story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', - }, - }, - }, -}; - -// ── Сторисы-вариации ───────────────────────────────────────────────────────── -// Каждая сторис — ОДИН вариант компонента. -// Используют commonTemplate + props: args → controls работают. -// source.code — статичный минимальный пример. - -export const Sizes: Story = { - render: (args) => ({ props: args, template: commonTemplate }), - args: { label: 'Button', size: 'large' }, - parameters: { - docs: { - description: { story: 'Описание вариации.' }, - source: { - code: ``, - }, - }, - }, -}; -``` - ---- - -## Паттерн examples/ - -### Назначение - -Папка `src/stories/components/{name}/examples/` содержит **standalone Angular-компоненты** — каждый инкапсулирует один вариант использования компонента. -В блоке **Source** в Storybook показывается полноценный Angular-компонент (TypeScript), который пользователь библиотеки может скопировать к себе как есть. - -Это принципиально отличается от подхода в `{name}.stories.ts`, где `source.code` показывает просто HTML-шаблон. - -### Структура файла - -```typescript -import { Component } from '@angular/core'; -import { StoryObj } from '@storybook/angular'; -import { XxxComponent } from '../../../../lib/components/xxx/xxx.component'; - -// 1. Шаблон выносится в const — чтобы переиспользовать в source.code -const template = ` -
- -
-`; -const styles = ''; - -// 2. Standalone-компонент с реальным шаблоном -@Component({ - selector: 'app-xxx-variant', - standalone: true, - imports: [XxxComponent], - template, - styles, -}) -export class XxxVariantComponent {} - -// 3. StoryObj — рендерит компонент; source.code — код компонента для копирования -export const Variant: StoryObj = { - render: () => ({ - template: ``, - }), - parameters: { - docs: { - description: { story: 'Описание на русском.' }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { XxxComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-xxx-variant', - standalone: true, - imports: [XxxComponent], - template: \` - - \`, -}) -export class XxxVariantComponent {} - `, - }, - }, - }, -}; -``` - -### Правила - -1. Каждый файл — **одна вариация**, один `@Component` + один `StoryObj` -2. Шаблон выносится в `const template` — чтобы использовать в `source.code` -3. `render: () => ({ template: '' })` — **только** для статичных примеров, где controls не нужны (форм-контролы с `ngModel`, группы компонентов). Для простых prop-вариаций controls не будут работать при таком подходе — см. правило ниже. -4. `source.code` содержит полный TypeScript-код компонента с импортами из `@cdek-it/angular-ui-kit` -5. Обёртка `
` — фон preview; **`p-4` не добавлять** -6. Именование файлов: `{name}-{variant}.component.ts` (например `avatar-label.component.ts`) -7. Именование selector компонента: `app-{name}-{variant}` (например `app-avatar-label`) -8. Класс компонента: `{Name}{Variant}Component` (например `AvatarLabelComponent`) - -### Когда создавать examples/ - -`examples/` создаётся **обязательно для каждого компонента** — для всех вариационных сторисов (кроме `Default`). - -`Default` (интерактивный playground) в examples/ **не дублируется** — он живёт только в `{name}.stories.ts`. - -Каждая вариационная сторис (`WithIcon`, `Removable`, `Disabled` и т.д.) имеет соответствующий файл в `examples/`. - ---- - -## Структура сторисов — обязательные разделы - -| Порядок | Сторис | Описание | -|---------|-------------|-----------------------------------------------------------------------| -| 1 | **Default** | Интерактивный playground. Динамический render. Все пропсы в Controls. | -| 2+ | Вариации | По одному варианту: Sizes, Icons, Rounded, Loading, Disabled, и т.д. | - -### Правило: один экземпляр компонента на сторис - -**Каждая сторис показывает ровно один вариант компонента. Все остальные виды компонента настраиваются с помощью пропсов через `args`.** - -В каждой вариационной сторис шаблон содержит **ровно один** экземпляр компонента. -Это правило распространяется как на сторисы в `{name}.stories.ts`, так и на компоненты в `examples/`. -Вариация демонстрируется через `args` (пропсы), а не через дублирование тегов. - -```typescript -// ❌ Запрещено — несколько экземпляров компонента в шаблоне -export const Sizes: Story = { - render: (args) => ({ - props: args, - template: ` - - - - `, - }), -}; - -// ❌ Запрещено — то же нарушение внутри examples/ -@Component({ template: ` - - - -` }) -export class TagSeveritiesComponent {} - -// ✅ Правильно — один экземпляр, вариация задаётся через args -export const Sizes: Story = { - render: (args) => ({ props: args, template: commonTemplate }), - args: { label: 'Button', size: 'large' }, -}; - -export const Severity: Story = { - render: (args) => ({ props: args, template: commonTemplate }), - args: { value: 'Success', severity: 'success' }, -}; -``` - -**Исключение**: составные компоненты (например группа радиокнопок / чекбоксов), где несколько дочерних элементов — это **сам смысл компонента**, а не визуальное перечисление вариантов. - -### Обязательные вариации для большинства компонентов -- `Sizes` — один компонент с нужным `size` в `args` -- `Icons` — один компонент с иконкой в `args` -- `Loading` — один компонент с `loading: true` в `args` -- `Rounded` — один компонент с `rounded: true` в `args` -- `Severity` — один компонент с нужным `severity` в `args` -- `Disabled` — один компонент с `disabled: true` в `args` - -### Правило: controls (пропсы) работают во всех вариационных сторисах - -**Вариационные сторисы ВСЕГДА рендерят через `commonTemplate + args`** — это единственный способ, при котором Storybook передаёт значения controls в компонент. - -`render: () => ({ template: '' })` — статичный рендер, controls **не работают**. Такой подход применим только для форм-контролов с `ngModel` и групп компонентов. - -```typescript -// ❌ Controls не работают — props не передаются в статичный компонент -export const Rounded: Story = { - render: () => ({ - template: ``, - }), -}; - -// ✅ Controls работают — props передаются через args -export const Rounded: Story = { - render: (args) => ({ props: args, template: commonTemplate }), - args: { value: 'Rounded', severity: 'success', rounded: true }, - parameters: { - docs: { - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { TagComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-tag-rounded', - standalone: true, - imports: [TagComponent], - template: \\\` - - \\\`, -}) -export class TagRoundedComponent {} - `, - }, - }, - }, -}; -``` - -**Если для вариации существует example-файл:** example-компонент регистрируется в `moduleMetadata`, но сторис рендерит через `commonTemplate + args`. В `source.code` сторис показывает TypeScript-код из example-файла (дублируется вручную). - ---- - -## Ключевые технические решения - -### Почему Default story использует динамический render - -В Storybook 10 Angular `source.transform` **не реактивен** — вызывается один раз. -Единственный способ обновлять code-сниппет при смене controls: -генерировать `template` строку прямо в `render(args)`. -Storybook Angular использует `template` из render как source code. - -```typescript -// ✅ Правильно — template обновляется при смене controls -render: (args) => { - const template = ``; - return { props: args, template }; -}, - -// ❌ Неправильно — source.transform не реактивен -parameters: { - docs: { source: { transform: (src, ctx) => ... } } -} -``` - -### Почему НЕ используется самозакрывающийся тег - -Angular JIT-компилятор запрещает ``. -` - -``` - -Поиск иконок: https://tabler.io/icons - ---- - -## Стилизация компонентов - -### Порядок слоёв - -``` -Компонент-обёртка → PrimeNG (p-button) → PrimeNG Aura тема -→ Токены (src/prime-preset/tokens/components/{name}.ts) -→ Tailwind CSS -``` - -### Добавление CSS-токенов - -Файл: `src/prime-preset/tokens/components/{name}.ts` - -Структура токенов соответствует PrimeNG Aura preset. -Кастомные расширения — через префикс `--p-{name}-extend-*`. - -### Tailwind в шаблонах сторисов - -```html - -
- -
-``` - ---- - -## Референс Vue UI Kit - -Vue UI Kit (PrimeVue) — источник референса по структуре сторисов и вариациям компонентов: - -- **Репозиторий**: `~/Downloads/vue-ui-kit-3/src/plugins/prime/stories/` -- **Запущен локально**: `http://localhost:6006` - -### Что брать как референс - -| Vue файл | Что переносить в Angular | -|-----------------------------------|--------------------------------------------------| -| `Button/Button.stories.js` | argTypes, stories args, описания | -| `Button/Button.template.js` | Шаблоны вариаций (grid-матрица размеров/severity)| -| `Button/Button.mdx` | Структура документации, порядок сторисов | - -### Как адаптировать Vue → Angular - -| Vue | Angular | -|-----------------------------|----------------------------------------------| -| `v-bind="args"` | `[prop]="prop"` (через `props: args`) | -| `variant="text"` | Остаётся `variant="text"` (статичный шаблон) | -| ` - +

Drawer content.

-
+ `, }), args: { @@ -200,3 +202,7 @@ export const FullScreen: Story = FullScreenStory; // ── WithoutModal ────────────────────────────────────────────────────────────── export const WithoutModal: Story = WithoutModalStory; + +// ── WithCustomHeader ───────────────────────────────────────────────────────── + +export const WithCustomHeader: Story = WithCustomHeaderStory; diff --git a/src/stories/components/drawer/examples/drawer-full-screen.component.ts b/src/stories/components/drawer/examples/drawer-full-screen.component.ts index 2671de84..544ccb8a 100644 --- a/src/stories/components/drawer/examples/drawer-full-screen.component.ts +++ b/src/stories/components/drawer/examples/drawer-full-screen.component.ts @@ -1,21 +1,21 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { DrawerComponent } from '../../../../lib/components/drawer/drawer.component'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraDrawerComponent } from '../../../../lib/components/drawer/drawer.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; const template = ` - + - +

Full screen drawer content.

-
+ `; const styles = ''; @Component({ selector: 'app-drawer-full-screen', standalone: true, - imports: [DrawerComponent, ButtonComponent], + imports: [ExtraDrawerComponent, ExtraButtonComponent], template, styles, }) @@ -35,18 +35,18 @@ export const FullScreen: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DrawerComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDrawerComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-drawer-full-screen', standalone: true, - imports: [DrawerComponent, ButtonComponent], + imports: [ExtraDrawerComponent, ExtraButtonComponent], template: \` - + - +

Full screen drawer content.

-
+ \`, }) export class DrawerFullScreenComponent { diff --git a/src/stories/components/drawer/examples/drawer-position.component.ts b/src/stories/components/drawer/examples/drawer-position.component.ts index 88eae30b..a927bb69 100644 --- a/src/stories/components/drawer/examples/drawer-position.component.ts +++ b/src/stories/components/drawer/examples/drawer-position.component.ts @@ -1,38 +1,38 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { DrawerComponent } from '../../../../lib/components/drawer/drawer.component'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraDrawerComponent } from '../../../../lib/components/drawer/drawer.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; const template = `
- - - - + + + +
- +

Left drawer content.

-
+ - +

Right drawer content.

-
+ - +

Top drawer content.

-
+ - +

Bottom drawer content.

-
+ `; const styles = ''; @Component({ selector: 'app-drawer-position', standalone: true, - imports: [DrawerComponent, ButtonComponent], + imports: [ExtraDrawerComponent, ExtraButtonComponent], template, styles, }) @@ -55,35 +55,35 @@ export const Position: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DrawerComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDrawerComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-drawer-position', standalone: true, - imports: [DrawerComponent, ButtonComponent], + imports: [ExtraDrawerComponent, ExtraButtonComponent], template: \`
- - - - + + + +
- +

Left drawer content.

-
+ - +

Right drawer content.

-
+ - +

Top drawer content.

-
+ - +

Bottom drawer content.

-
+ \`, }) export class DrawerPositionComponent { diff --git a/src/stories/components/drawer/examples/drawer-sizes.component.ts b/src/stories/components/drawer/examples/drawer-sizes.component.ts index 4b637afc..481152da 100644 --- a/src/stories/components/drawer/examples/drawer-sizes.component.ts +++ b/src/stories/components/drawer/examples/drawer-sizes.component.ts @@ -1,38 +1,38 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { DrawerComponent } from '../../../../lib/components/drawer/drawer.component'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraDrawerComponent } from '../../../../lib/components/drawer/drawer.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; const template = `
- - - - + + + +
- +

Default size drawer content.

-
+ - +

Small size drawer content.

-
+ - +

Large size drawer content.

-
+ - +

Extra large size drawer content.

-
+ `; const styles = ''; @Component({ selector: 'app-drawer-sizes', standalone: true, - imports: [DrawerComponent, ButtonComponent], + imports: [ExtraDrawerComponent, ExtraButtonComponent], template, styles, }) @@ -55,35 +55,35 @@ export const Sizes: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DrawerComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDrawerComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-drawer-sizes', standalone: true, - imports: [DrawerComponent, ButtonComponent], + imports: [ExtraDrawerComponent, ExtraButtonComponent], template: \`
- - - - + + + +
- +

Default size drawer content.

-
+ - +

Small size drawer content.

-
+ - +

Large size drawer content.

-
+ - +

Extra large size drawer content.

-
+ \`, }) export class DrawerSizesComponent { diff --git a/src/stories/components/drawer/examples/drawer-with-custom-header.component.ts b/src/stories/components/drawer/examples/drawer-with-custom-header.component.ts new file mode 100644 index 00000000..3e074525 --- /dev/null +++ b/src/stories/components/drawer/examples/drawer-with-custom-header.component.ts @@ -0,0 +1,73 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { ExtraDrawerComponent } from '../../../../lib/components/drawer/drawer.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; + +const template = ` + + + + +
+ Custom Header + +
+
+ +

Drawer content with a custom header template.

+
+`; +const styles = ''; + +@Component({ + selector: 'app-drawer-with-custom-header', + standalone: true, + imports: [ExtraDrawerComponent, ExtraButtonComponent], + template, + styles, +}) +export class DrawerWithCustomHeaderComponent { + visible = false; +} + +export const WithCustomHeader: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { story: 'Drawer с кастомным заголовком через ng-template #drawerHeader.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { ExtraDrawerComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-drawer-with-custom-header', + standalone: true, + imports: [ExtraDrawerComponent, ExtraButtonComponent], + template: \` + + + + +
+ Custom Header + +
+
+ +

Drawer content with a custom header template.

+
+ \`, +}) +export class DrawerWithCustomHeaderComponent { + visible = false; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/drawer/examples/drawer-with-footer.component.ts b/src/stories/components/drawer/examples/drawer-with-footer.component.ts index c4adb74c..dccabc71 100644 --- a/src/stories/components/drawer/examples/drawer-with-footer.component.ts +++ b/src/stories/components/drawer/examples/drawer-with-footer.component.ts @@ -1,28 +1,28 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { DrawerComponent } from '../../../../lib/components/drawer/drawer.component'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraDrawerComponent } from '../../../../lib/components/drawer/drawer.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; const template = ` - + - +

Drawer content with footer actions.

- - + +
-
+ `; const styles = ''; @Component({ selector: 'app-drawer-with-footer', standalone: true, - imports: [DrawerComponent, ButtonComponent], + imports: [ExtraDrawerComponent, ExtraButtonComponent], template, styles, }) @@ -42,25 +42,25 @@ export const WithFooter: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DrawerComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDrawerComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-drawer-with-footer', standalone: true, - imports: [DrawerComponent, ButtonComponent], + imports: [ExtraDrawerComponent, ExtraButtonComponent], template: \` - + - +

Drawer content with footer actions.

- - + +
-
+ \`, }) export class DrawerWithFooterComponent { diff --git a/src/stories/components/drawer/examples/drawer-without-modal.component.ts b/src/stories/components/drawer/examples/drawer-without-modal.component.ts index b9f3dbaa..ba27fdf5 100644 --- a/src/stories/components/drawer/examples/drawer-without-modal.component.ts +++ b/src/stories/components/drawer/examples/drawer-without-modal.component.ts @@ -1,21 +1,21 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { DrawerComponent } from '../../../../lib/components/drawer/drawer.component'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraDrawerComponent } from '../../../../lib/components/drawer/drawer.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; const template = ` - + - +

Drawer without backdrop overlay.

-
+ `; const styles = ''; @Component({ selector: 'app-drawer-without-modal', standalone: true, - imports: [DrawerComponent, ButtonComponent], + imports: [ExtraDrawerComponent, ExtraButtonComponent], template, styles, }) @@ -35,18 +35,18 @@ export const WithoutModal: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DrawerComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDrawerComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-drawer-without-modal', standalone: true, - imports: [DrawerComponent, ButtonComponent], + imports: [ExtraDrawerComponent, ExtraButtonComponent], template: \` - + - +

Drawer without backdrop overlay.

-
+ \`, }) export class DrawerWithoutModalComponent {