From 4032f6f1b0bd2971b65f125d6ae3b3ab3fae00bc Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 9 Apr 2026 17:04:32 +0700 Subject: [PATCH 01/10] =?UTF-8?q?confirm-dialog:=20=D1=81=D1=82=D0=B8?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F,=20=D1=81=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D1=81=D1=8B,=20=D0=BE=D0=B1=D1=91=D1=80?= =?UTF-8?q?=D1=82=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../confirm-dialog.component.ts | 73 +++++ src/prime-preset/map-tokens.ts | 5 + .../tokens/components/confirm-dialog.ts | 59 ++++ src/prime-preset/tokens/components/dialog.ts | 8 +- .../confirm-dialog/confirm-dialog.stories.ts | 262 ++++++++++++++++++ .../confirm-dialog-default.component.ts | 40 +++ .../confirm-dialog-severities.component.ts | 114 ++++++++ .../confirm-dialog-sizes.component.ts | 68 +++++ 8 files changed, 625 insertions(+), 4 deletions(-) create mode 100644 src/lib/components/confirm-dialog/confirm-dialog.component.ts create mode 100644 src/prime-preset/tokens/components/confirm-dialog.ts create mode 100644 src/stories/components/confirm-dialog/confirm-dialog.stories.ts create mode 100644 src/stories/components/confirm-dialog/examples/confirm-dialog-default.component.ts create mode 100644 src/stories/components/confirm-dialog/examples/confirm-dialog-severities.component.ts create mode 100644 src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts diff --git a/src/lib/components/confirm-dialog/confirm-dialog.component.ts b/src/lib/components/confirm-dialog/confirm-dialog.component.ts new file mode 100644 index 00000000..f0cca136 --- /dev/null +++ b/src/lib/components/confirm-dialog/confirm-dialog.component.ts @@ -0,0 +1,73 @@ +import { Component, Input } from '@angular/core'; +import { ConfirmDialog } from 'primeng/confirmdialog'; +import { Button } from 'primeng/button'; +import { PrimeTemplate } from 'primeng/api'; + +export type ConfirmDialogSize = 'sm' | 'default' | 'lg' | 'xlg'; +export type ConfirmDialogSeverity = 'success' | 'info' | 'warn' | 'help' | 'danger' | 'default'; + +@Component({ + selector: 'confirm-dialog', + host: { style: 'display: contents' }, + standalone: true, + imports: [ConfirmDialog, Button, PrimeTemplate], + template: ` + + +
+
+ + {{ message.header }} +
+ +
+
+

{{ message.message }}

+
+ +
+
+ `, +}) +export class ConfirmDialogComponent { + @Input() key = ''; + @Input() size: ConfirmDialogSize = 'default'; + @Input() severity: ConfirmDialogSeverity = 'default'; + + get computedClass(): string { + const classes: string[] = []; + if (this.size === 'sm') classes.push('p-confirmdialog-sm'); + else if (this.size === 'lg') classes.push('p-confirmdialog-lg'); + else if (this.size === 'xlg') classes.push('p-confirmdialog-xlg'); + + const severityMap: Record = { + success: 'p-confirm-dialog-accept', + info: 'p-confirm-dialog-info', + warn: 'p-confirm-dialog-warn', + help: 'p-confirm-dialog-help', + danger: 'p-confirm-dialog-error', + default: '', + }; + if (severityMap[this.severity]) classes.push(severityMap[this.severity]); + + return classes.join(' '); + } +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 6f2975f5..2b695ba7 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -4,6 +4,7 @@ import type { AuraBaseDesignTokens } from '@primeuix/themes/aura/base'; import tokens from './tokens/tokens.json'; import { buttonCss } from './tokens/components/button'; +import { confirmDialogCss } from './tokens/components/confirm-dialog'; import { dialogCss } from './tokens/components/dialog'; const presetTokens: Preset = { @@ -15,6 +16,10 @@ const presetTokens: Preset = { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), css: buttonCss, }, + confirmdialog: { + ...(tokens.components.confirmdialog as unknown as ComponentsDesignTokens['confirmdialog']), + css: confirmDialogCss, + }, dialog: { ...(tokens.components.dialog as unknown as ComponentsDesignTokens['dialog']), css: dialogCss, diff --git a/src/prime-preset/tokens/components/confirm-dialog.ts b/src/prime-preset/tokens/components/confirm-dialog.ts new file mode 100644 index 00000000..f0aacab7 --- /dev/null +++ b/src/prime-preset/tokens/components/confirm-dialog.ts @@ -0,0 +1,59 @@ +export const confirmDialogCss = ({ dt }: { dt: (token: string) => string }): string => ` + /* Иконка в заголовке */ + .p-confirmdialog .p-dialog-title { + display: flex; + align-items: center; + gap: ${dt('dialog.header.gap')}; + } + + .p-confirmdialog .p-dialog-title .p-icon { + width: ${dt('confirmdialog.icon.size')}; + height: ${dt('confirmdialog.icon.size')}; + font-size: ${dt('confirmdialog.icon.size')}; + flex-shrink: 0; + } + + /* Размеры */ + .p-confirmdialog.p-dialog { + width: ${dt('overlay.width')}; + } + + .p-confirmdialog-sm.p-dialog { + width: ${dt('sizing.80x')}; + } + + .p-confirmdialog-lg.p-dialog { + width: ${dt('sizing.120x')}; + } + + .p-confirmdialog-xlg.p-dialog { + width: ${dt('sizing.128x')}; + } + + /* Цвета иконок по severity */ + .p-confirmdialog[data-pc-severity="success"] .p-dialog-title .p-icon, + .p-confirmdialog.p-confirm-dialog-accept .p-dialog-title .p-icon { + color: ${dt('confirmdialog.extend.extIcon.success')}; + } + + .p-confirmdialog[data-pc-severity="info"] .p-dialog-title .p-icon, + .p-confirmdialog.p-confirm-dialog-info .p-dialog-title .p-icon { + color: ${dt('confirmdialog.extend.extIcon.info')}; + } + + .p-confirmdialog[data-pc-severity="warn"] .p-dialog-title .p-icon, + .p-confirmdialog.p-confirm-dialog-warn .p-dialog-title .p-icon { + color: ${dt('confirmdialog.extend.extIcon.warn')}; + } + + .p-confirmdialog[data-pc-severity="help"] .p-dialog-title .p-icon, + .p-confirmdialog.p-confirm-dialog-help .p-dialog-title .p-icon { + color: ${dt('confirmdialog.extend.extIcon.help')}; + } + + .p-confirmdialog[data-pc-severity="danger"] .p-dialog-title .p-icon, + .p-confirmdialog[data-pc-severity="error"] .p-dialog-title .p-icon, + .p-confirmdialog.p-confirm-dialog-error .p-dialog-title .p-icon { + color: ${dt('confirmdialog.extend.extIcon.danger')}; + } +`; diff --git a/src/prime-preset/tokens/components/dialog.ts b/src/prime-preset/tokens/components/dialog.ts index c157e61e..7426012c 100644 --- a/src/prime-preset/tokens/components/dialog.ts +++ b/src/prime-preset/tokens/components/dialog.ts @@ -36,18 +36,18 @@ export const dialogCss = ({ dt }: { dt: (token: string) => string }): string => } .p-dialog { - width: ${dt('sizing.80x')}; + width: ${dt('overlay.width')}; } .p-dialog.p-component.p-dialog-sm { - width: ${dt('overlay.sm.width')}; + width: ${dt('sizing.80x')}; } .p-dialog.p-component.p-dialog-lg { - width: ${dt('overlay.lg.width')}; + width: ${dt('sizing.120x')}; } .p-dialog.p-component.p-dialog-xlg { - width: ${dt('overlay.xlg.width')}; + width: ${dt('sizing.128x')}; } `; diff --git a/src/stories/components/confirm-dialog/confirm-dialog.stories.ts b/src/stories/components/confirm-dialog/confirm-dialog.stories.ts new file mode 100644 index 00000000..399c7634 --- /dev/null +++ b/src/stories/components/confirm-dialog/confirm-dialog.stories.ts @@ -0,0 +1,262 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { ConfirmDialogComponent } from '../../../lib/components/confirm-dialog/confirm-dialog.component'; +import { ConfirmDialogDefaultComponent } from './examples/confirm-dialog-default.component'; +import { ConfirmDialogSeveritiesComponent } from './examples/confirm-dialog-severities.component'; +import { ConfirmDialogSizesComponent } from './examples/confirm-dialog-sizes.component'; + +const meta: Meta = { + title: 'Components/Overlay/ConfirmDialog', + component: ConfirmDialogComponent, + tags: ['autodocs'], + parameters: { + docs: { + description: { + component: `Компонент для подтверждения действий пользователя. Требует подключения \`ConfirmationService\`. + +\`\`\`typescript +import { ConfirmDialogComponent } from '@cdek-it/angular-ui-kit'; +import { ConfirmationService } from 'primeng/api'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-confirmdialog' }, + }, + argTypes: { + key: { + control: 'text', + description: 'Идентификатор группы для адресной отправки сообщений.', + table: { + category: 'Props', + type: { summary: 'string' }, + }, + }, + size: { + control: 'select', + options: ['sm', 'default', 'lg', 'xlg'], + description: 'Размер диалога', + table: { + category: 'Props', + defaultValue: { summary: 'default' }, + type: { summary: "'sm' | 'default' | 'lg' | 'xlg'" }, + }, + }, + severity: { + control: 'select', + options: ['default', 'success', 'info', 'warn', 'help', 'danger'], + description: 'Цветовая схема иконки в заголовке', + table: { + category: 'Props', + defaultValue: { summary: 'default' }, + type: { summary: "'default' | 'success' | 'info' | 'warn' | 'help' | 'danger'" }, + }, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ─────────────────────────────────────────────────────────────────── + +export const Default: Story = { + name: 'ConfirmDialog', + decorators: [moduleMetadata({ imports: [ConfirmDialogDefaultComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Базовый пример диалога подтверждения.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { Button } from 'primeng/button'; +import { ConfirmationService } from 'primeng/api'; +import { ConfirmDialogComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-confirm-dialog-default', + standalone: true, + imports: [ConfirmDialogComponent, Button], + providers: [ConfirmationService], + template: \` + + + \`, +}) +export class ConfirmDialogDefaultComponent { + constructor(private confirmationService: ConfirmationService) {} + + showConfirm(): void { + this.confirmationService.confirm({ + key: 'cd-default', + message: 'Вы уверены, что хотите продолжить?', + header: 'Подтверждение', + icon: 'ti ti-alert-triangle', + acceptLabel: 'Да', + rejectLabel: 'Нет', + rejectButtonProps: { + severity: 'secondary', + text: true, + }, + accept: () => {}, + reject: () => {}, + }); + } +} + `, + }, + }, + }, +}; + +// ── Severities ──────────────────────────────────────────────────────────────── + +export const Severities: Story = { + name: 'Severities', + decorators: [moduleMetadata({ imports: [ConfirmDialogSeveritiesComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Варианты диалога с различными уровнями важности: success, info, warn, help, danger.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { Button } from 'primeng/button'; +import { ConfirmationService } from 'primeng/api'; +import { ConfirmDialogComponent } from '@cdek-it/angular-ui-kit'; + +const SEVERITIES = [ + { type: 'success', buttonSeverity: 'success', icon: 'ti ti-circle-check', label: 'Успех', header: 'Успех', message: 'Операция выполнена успешно.', acceptLabel: 'OK' }, + { type: 'info', buttonSeverity: 'info', icon: 'ti ti-info-circle', label: 'Информация', header: 'Информация', message: 'Это информационное сообщение.', acceptLabel: 'Понятно' }, + { type: 'warn', buttonSeverity: 'warn', icon: 'ti ti-alert-triangle', label: 'Предупреждение', header: 'Предупреждение', message: 'Внимание! Это действие может иметь последствия.', acceptLabel: 'Продолжить' }, + { type: 'help', buttonSeverity: 'help', icon: 'ti ti-help-circle', label: 'Справка', header: 'Справка', message: 'Нужна помощь с этим действием?', acceptLabel: 'Да' }, + { type: 'danger', buttonSeverity: 'danger', icon: 'ti ti-circle-x', label: 'Удаление', header: 'Подтверждение', message: 'Это действие нельзя отменить. Продолжить?', acceptLabel: 'Удалить' }, +]; + +@Component({ + selector: 'app-confirm-dialog-severities', + standalone: true, + imports: [ConfirmDialogComponent, Button], + providers: [ConfirmationService], + template: \` + + + + + + +
+ @for (severity of severities; track severity.type) { + + } +
+ \`, +}) +export class ConfirmDialogSeveritiesComponent { + severities = SEVERITIES; + constructor(private confirmationService: ConfirmationService) {} + + showConfirm(severity: any): void { + this.confirmationService.confirm({ + key: 'cd-severity-' + severity.type, + message: severity.message, + header: severity.header, + icon: severity.icon, + acceptLabel: severity.acceptLabel, + rejectLabel: 'Нет', + acceptButtonProps: { severity: severity.buttonSeverity }, + rejectButtonProps: { + severity: 'secondary', + text: true, + }, + accept: () => {}, + reject: () => {}, + }); + } +} + `, + }, + }, + }, +}; + +// ── Sizes ───────────────────────────────────────────────────────────────────── + +export const Sizes: Story = { + name: 'Sizes', + decorators: [moduleMetadata({ imports: [ConfirmDialogSizesComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Доступные размеры диалога: sm, base, lg, xlg.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { Button } from 'primeng/button'; +import { ConfirmationService } from 'primeng/api'; +import { ConfirmDialogComponent } from '@cdek-it/angular-ui-kit'; + +const SIZES = [ + { key: 'sm', label: 'Small' }, + { key: 'default', label: 'Base' }, + { key: 'lg', label: 'Large' }, + { key: 'xlg', label: 'Extra Large' }, +]; + +@Component({ + selector: 'app-confirm-dialog-sizes', + standalone: true, + imports: [ConfirmDialogComponent, Button], + providers: [ConfirmationService], + template: \` + + + + + +
+ @for (size of sizes; track size.key) { + + } +
+ \`, +}) +export class ConfirmDialogSizesComponent { + sizes = SIZES; + constructor(private confirmationService: ConfirmationService) {} + + showConfirm(size: any): void { + this.confirmationService.confirm({ + key: 'cd-size-' + size.key, + message: 'Это диалог размера ' + size.label, + header: 'Подтверждение', + icon: 'ti ti-alert-triangle', + acceptLabel: 'Да', + rejectLabel: 'Нет', + rejectButtonProps: { + severity: 'secondary', + text: true, + }, + accept: () => {}, + reject: () => {}, + }); + } +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/confirm-dialog/examples/confirm-dialog-default.component.ts b/src/stories/components/confirm-dialog/examples/confirm-dialog-default.component.ts new file mode 100644 index 00000000..5c812da3 --- /dev/null +++ b/src/stories/components/confirm-dialog/examples/confirm-dialog-default.component.ts @@ -0,0 +1,40 @@ +import { Component } from '@angular/core'; +import { Button } from 'primeng/button'; +import { ConfirmationService } from 'primeng/api'; +import { ConfirmDialogComponent } from '../../../../lib/components/confirm-dialog/confirm-dialog.component'; + +const template = ` +
+ + + +
+`; + +@Component({ + selector: 'app-confirm-dialog-default', + standalone: true, + imports: [ConfirmDialogComponent, Button], + providers: [ConfirmationService], + template, +}) +export class ConfirmDialogDefaultComponent { + constructor(private confirmationService: ConfirmationService) {} + + showConfirm(): void { + this.confirmationService.confirm({ + key: 'cd-default', + message: 'Вы уверены, что хотите продолжить?', + header: 'Подтверждение', + icon: 'ti ti-alert-triangle', + acceptLabel: 'Да', + rejectLabel: 'Нет', + rejectButtonProps: { + severity: 'secondary', + text: true, + }, + accept: () => {}, + reject: () => {}, + }); + } +} diff --git a/src/stories/components/confirm-dialog/examples/confirm-dialog-severities.component.ts b/src/stories/components/confirm-dialog/examples/confirm-dialog-severities.component.ts new file mode 100644 index 00000000..c3cd8542 --- /dev/null +++ b/src/stories/components/confirm-dialog/examples/confirm-dialog-severities.component.ts @@ -0,0 +1,114 @@ +import { Component } from '@angular/core'; +import { Button } from 'primeng/button'; +import { ConfirmationService } from 'primeng/api'; +import { ConfirmDialogComponent } from '../../../../lib/components/confirm-dialog/confirm-dialog.component'; + +interface SeverityItem { + type: 'success' | 'info' | 'warn' | 'help' | 'danger'; + buttonSeverity: 'success' | 'info' | 'warn' | 'help' | 'danger'; + icon: string; + label: string; + header: string; + message: string; + acceptLabel: string; +} + +const SEVERITIES: SeverityItem[] = [ + { + type: 'success', + buttonSeverity: 'success', + icon: 'ti ti-circle-check', + label: 'Успех', + header: 'Успех', + message: 'Операция выполнена успешно.', + acceptLabel: 'OK', + }, + { + type: 'info', + buttonSeverity: 'info', + icon: 'ti ti-info-circle', + label: 'Информация', + header: 'Информация', + message: 'Это информационное сообщение.', + acceptLabel: 'Понятно', + }, + { + type: 'warn', + buttonSeverity: 'warn', + icon: 'ti ti-alert-triangle', + label: 'Предупреждение', + header: 'Предупреждение', + message: 'Внимание! Это действие может иметь последствия.', + acceptLabel: 'Продолжить', + }, + { + type: 'help', + buttonSeverity: 'help', + icon: 'ti ti-help-circle', + label: 'Справка', + header: 'Справка', + message: 'Нужна помощь с этим действием?', + acceptLabel: 'Да', + }, + { + type: 'danger', + buttonSeverity: 'danger', + icon: 'ti ti-circle-x', + label: 'Удаление', + header: 'Подтверждение', + message: 'Это действие нельзя отменить. Продолжить?', + acceptLabel: 'Удалить', + }, +]; + +const template = ` +
+ + + + + + +
+ @for (severity of severities; track severity.type) { + + } +
+
+`; + +@Component({ + selector: 'app-confirm-dialog-severities', + standalone: true, + imports: [ConfirmDialogComponent, Button], + providers: [ConfirmationService], + template, +}) +export class ConfirmDialogSeveritiesComponent { + severities = SEVERITIES; + + constructor(private confirmationService: ConfirmationService) {} + + showConfirm(severity: SeverityItem): void { + this.confirmationService.confirm({ + key: 'cd-severity-' + severity.type, + message: severity.message, + header: severity.header, + icon: severity.icon, + acceptLabel: severity.acceptLabel, + rejectLabel: 'Нет', + acceptButtonProps: { severity: severity.buttonSeverity }, + rejectButtonProps: { + severity: 'secondary', + text: true, + }, + accept: () => {}, + reject: () => {}, + }); + } +} diff --git a/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts b/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts new file mode 100644 index 00000000..a2dcfada --- /dev/null +++ b/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts @@ -0,0 +1,68 @@ +import { Component } from '@angular/core'; +import { Button } from 'primeng/button'; +import { ConfirmationService } from 'primeng/api'; +import { + ConfirmDialogComponent, + ConfirmDialogSize, +} from '../../../../lib/components/confirm-dialog/confirm-dialog.component'; + +interface SizeItem { + key: ConfirmDialogSize; + label: string; +} + +const SIZES: SizeItem[] = [ + { key: 'sm', label: 'Small' }, + { key: 'default', label: 'Base' }, + { key: 'lg', label: 'Large' }, + { key: 'xlg', label: 'Extra Large' }, +]; + +const template = ` +
+ + + + + +
+ @for (size of sizes; track size.key) { + + } +
+
+`; + +@Component({ + selector: 'app-confirm-dialog-sizes', + standalone: true, + imports: [ConfirmDialogComponent, Button], + providers: [ConfirmationService], + template, +}) +export class ConfirmDialogSizesComponent { + sizes = SIZES; + + constructor(private confirmationService: ConfirmationService) {} + + showConfirm(size: SizeItem): void { + this.confirmationService.confirm({ + key: 'cd-size-' + size.key, + message: 'Это диалог размера ' + size.label, + header: 'Подтверждение', + icon: 'ti ti-alert-triangle', + acceptLabel: 'Да', + rejectLabel: 'Нет', + rejectButtonProps: { + severity: 'secondary', + text: true, + }, + accept: () => {}, + reject: () => {}, + }); + } +} From 8020a49381e00613c5b11fd3709eea83be52a111 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 13 Apr 2026 18:28:15 +0700 Subject: [PATCH 02/10] =?UTF-8?q?confirm-dialog:=20=D1=83=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20p-icon=20=D1=81?= =?UTF-8?q?=20=D0=B8=D0=BA=D0=BE=D0=BD=D0=BA=D0=B8=20=D1=81=D0=BE=D0=BE?= =?UTF-8?q?=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/confirm-dialog/confirm-dialog.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/confirm-dialog/confirm-dialog.component.ts b/src/lib/components/confirm-dialog/confirm-dialog.component.ts index f0cca136..4462b86c 100644 --- a/src/lib/components/confirm-dialog/confirm-dialog.component.ts +++ b/src/lib/components/confirm-dialog/confirm-dialog.component.ts @@ -16,7 +16,7 @@ export type ConfirmDialogSeverity = 'success' | 'info' | 'warn' | 'help' | 'dang
- + {{ message.header }}
- - + }

{{ message.message }}

- + @if (footerTemplate) { + + + } @else { + + }
`, @@ -51,6 +64,8 @@ export class ConfirmDialogComponent { @Input() key = ''; @Input() size: ConfirmDialogSize = 'default'; @Input() severity: ConfirmDialogSeverity = 'default'; + @Input() headerTemplate: TemplateRef | null = null; + @Input() footerTemplate: TemplateRef | null = null; get computedClass(): string { const classes: string[] = []; From 0480f7ae4a973039a405432c4a729957987da80d Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 13 Apr 2026 18:32:34 +0700 Subject: [PATCH 04/10] =?UTF-8?q?confirm-dialog:=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20ConfirmDialogService,=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BC=D0=B5=D0=BD=D1=91=D0=BD=20ConfirmationService=20?= =?UTF-8?q?=D0=B2=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../confirm-dialog/confirm-dialog.service.ts | 16 ++++++++ .../confirm-dialog/confirm-dialog.stories.ts | 40 +++++++------------ .../confirm-dialog-default.component.ts | 11 ++--- .../confirm-dialog-severities.component.ts | 11 ++--- .../confirm-dialog-sizes.component.ts | 11 ++--- 5 files changed, 42 insertions(+), 47 deletions(-) create mode 100644 src/lib/components/confirm-dialog/confirm-dialog.service.ts diff --git a/src/lib/components/confirm-dialog/confirm-dialog.service.ts b/src/lib/components/confirm-dialog/confirm-dialog.service.ts new file mode 100644 index 00000000..1031258d --- /dev/null +++ b/src/lib/components/confirm-dialog/confirm-dialog.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; +import { Confirmation, ConfirmationService } from 'primeng/api'; + +export type ConfirmDialogOptions = Pick< + Confirmation, + 'key' | 'message' | 'header' | 'icon' | 'acceptLabel' | 'rejectLabel' | 'accept' | 'reject' | 'acceptButtonProps' +>; + +@Injectable() +export class ConfirmDialogService { + constructor(private readonly confirmationService: ConfirmationService) {} + + confirm(options: ConfirmDialogOptions): void { + this.confirmationService.confirm(options); + } +} diff --git a/src/stories/components/confirm-dialog/confirm-dialog.stories.ts b/src/stories/components/confirm-dialog/confirm-dialog.stories.ts index 399c7634..91f44e05 100644 --- a/src/stories/components/confirm-dialog/confirm-dialog.stories.ts +++ b/src/stories/components/confirm-dialog/confirm-dialog.stories.ts @@ -11,10 +11,10 @@ const meta: Meta = { parameters: { docs: { description: { - component: `Компонент для подтверждения действий пользователя. Требует подключения \`ConfirmationService\`. + component: `Компонент для подтверждения действий пользователя. Требует подключения \`ConfirmationService\` и \`ConfirmDialogService\`. \`\`\`typescript -import { ConfirmDialogComponent } from '@cdek-it/angular-ui-kit'; +import { ConfirmDialogComponent, ConfirmDialogService } from '@cdek-it/angular-ui-kit'; import { ConfirmationService } from 'primeng/api'; \`\`\``, }, @@ -73,33 +73,29 @@ export const Default: Story = { import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { ConfirmationService } from 'primeng/api'; -import { ConfirmDialogComponent } from '@cdek-it/angular-ui-kit'; +import { ConfirmDialogComponent, ConfirmDialogService } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-confirm-dialog-default', standalone: true, imports: [ConfirmDialogComponent, Button], - providers: [ConfirmationService], + providers: [ConfirmationService, ConfirmDialogService], template: \` \`, }) export class ConfirmDialogDefaultComponent { - constructor(private confirmationService: ConfirmationService) {} + constructor(private confirmDialogService: ConfirmDialogService) {} showConfirm(): void { - this.confirmationService.confirm({ + this.confirmDialogService.confirm({ key: 'cd-default', message: 'Вы уверены, что хотите продолжить?', header: 'Подтверждение', icon: 'ti ti-alert-triangle', acceptLabel: 'Да', rejectLabel: 'Нет', - rejectButtonProps: { - severity: 'secondary', - text: true, - }, accept: () => {}, reject: () => {}, }); @@ -128,7 +124,7 @@ export const Severities: Story = { import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { ConfirmationService } from 'primeng/api'; -import { ConfirmDialogComponent } from '@cdek-it/angular-ui-kit'; +import { ConfirmDialogComponent, ConfirmDialogService } from '@cdek-it/angular-ui-kit'; const SEVERITIES = [ { type: 'success', buttonSeverity: 'success', icon: 'ti ti-circle-check', label: 'Успех', header: 'Успех', message: 'Операция выполнена успешно.', acceptLabel: 'OK' }, @@ -142,7 +138,7 @@ const SEVERITIES = [ selector: 'app-confirm-dialog-severities', standalone: true, imports: [ConfirmDialogComponent, Button], - providers: [ConfirmationService], + providers: [ConfirmationService, ConfirmDialogService], template: \` @@ -164,10 +160,10 @@ const SEVERITIES = [ }) export class ConfirmDialogSeveritiesComponent { severities = SEVERITIES; - constructor(private confirmationService: ConfirmationService) {} + constructor(private confirmDialogService: ConfirmDialogService) {} showConfirm(severity: any): void { - this.confirmationService.confirm({ + this.confirmDialogService.confirm({ key: 'cd-severity-' + severity.type, message: severity.message, header: severity.header, @@ -175,10 +171,6 @@ export class ConfirmDialogSeveritiesComponent { acceptLabel: severity.acceptLabel, rejectLabel: 'Нет', acceptButtonProps: { severity: severity.buttonSeverity }, - rejectButtonProps: { - severity: 'secondary', - text: true, - }, accept: () => {}, reject: () => {}, }); @@ -207,7 +199,7 @@ export const Sizes: Story = { import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { ConfirmationService } from 'primeng/api'; -import { ConfirmDialogComponent } from '@cdek-it/angular-ui-kit'; +import { ConfirmDialogComponent, ConfirmDialogService } from '@cdek-it/angular-ui-kit'; const SIZES = [ { key: 'sm', label: 'Small' }, @@ -220,7 +212,7 @@ const SIZES = [ selector: 'app-confirm-dialog-sizes', standalone: true, imports: [ConfirmDialogComponent, Button], - providers: [ConfirmationService], + providers: [ConfirmationService, ConfirmDialogService], template: \` @@ -236,20 +228,16 @@ const SIZES = [ }) export class ConfirmDialogSizesComponent { sizes = SIZES; - constructor(private confirmationService: ConfirmationService) {} + constructor(private confirmDialogService: ConfirmDialogService) {} showConfirm(size: any): void { - this.confirmationService.confirm({ + this.confirmDialogService.confirm({ key: 'cd-size-' + size.key, message: 'Это диалог размера ' + size.label, header: 'Подтверждение', icon: 'ti ti-alert-triangle', acceptLabel: 'Да', rejectLabel: 'Нет', - rejectButtonProps: { - severity: 'secondary', - text: true, - }, accept: () => {}, reject: () => {}, }); diff --git a/src/stories/components/confirm-dialog/examples/confirm-dialog-default.component.ts b/src/stories/components/confirm-dialog/examples/confirm-dialog-default.component.ts index 5c812da3..8b7118c4 100644 --- a/src/stories/components/confirm-dialog/examples/confirm-dialog-default.component.ts +++ b/src/stories/components/confirm-dialog/examples/confirm-dialog-default.component.ts @@ -2,6 +2,7 @@ import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { ConfirmationService } from 'primeng/api'; import { ConfirmDialogComponent } from '../../../../lib/components/confirm-dialog/confirm-dialog.component'; +import { ConfirmDialogService } from '../../../../lib/components/confirm-dialog/confirm-dialog.service'; const template = `
@@ -15,24 +16,20 @@ const template = ` selector: 'app-confirm-dialog-default', standalone: true, imports: [ConfirmDialogComponent, Button], - providers: [ConfirmationService], + providers: [ConfirmationService, ConfirmDialogService], template, }) export class ConfirmDialogDefaultComponent { - constructor(private confirmationService: ConfirmationService) {} + constructor(private confirmDialogService: ConfirmDialogService) {} showConfirm(): void { - this.confirmationService.confirm({ + this.confirmDialogService.confirm({ key: 'cd-default', message: 'Вы уверены, что хотите продолжить?', header: 'Подтверждение', icon: 'ti ti-alert-triangle', acceptLabel: 'Да', rejectLabel: 'Нет', - rejectButtonProps: { - severity: 'secondary', - text: true, - }, accept: () => {}, reject: () => {}, }); diff --git a/src/stories/components/confirm-dialog/examples/confirm-dialog-severities.component.ts b/src/stories/components/confirm-dialog/examples/confirm-dialog-severities.component.ts index c3cd8542..41cdadcc 100644 --- a/src/stories/components/confirm-dialog/examples/confirm-dialog-severities.component.ts +++ b/src/stories/components/confirm-dialog/examples/confirm-dialog-severities.component.ts @@ -2,6 +2,7 @@ import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { ConfirmationService } from 'primeng/api'; import { ConfirmDialogComponent } from '../../../../lib/components/confirm-dialog/confirm-dialog.component'; +import { ConfirmDialogService } from '../../../../lib/components/confirm-dialog/confirm-dialog.service'; interface SeverityItem { type: 'success' | 'info' | 'warn' | 'help' | 'danger'; @@ -86,16 +87,16 @@ const template = ` selector: 'app-confirm-dialog-severities', standalone: true, imports: [ConfirmDialogComponent, Button], - providers: [ConfirmationService], + providers: [ConfirmationService, ConfirmDialogService], template, }) export class ConfirmDialogSeveritiesComponent { severities = SEVERITIES; - constructor(private confirmationService: ConfirmationService) {} + constructor(private confirmDialogService: ConfirmDialogService) {} showConfirm(severity: SeverityItem): void { - this.confirmationService.confirm({ + this.confirmDialogService.confirm({ key: 'cd-severity-' + severity.type, message: severity.message, header: severity.header, @@ -103,10 +104,6 @@ export class ConfirmDialogSeveritiesComponent { acceptLabel: severity.acceptLabel, rejectLabel: 'Нет', acceptButtonProps: { severity: severity.buttonSeverity }, - rejectButtonProps: { - severity: 'secondary', - text: true, - }, accept: () => {}, reject: () => {}, }); diff --git a/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts b/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts index a2dcfada..fbfb90db 100644 --- a/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts +++ b/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts @@ -5,6 +5,7 @@ import { ConfirmDialogComponent, ConfirmDialogSize, } from '../../../../lib/components/confirm-dialog/confirm-dialog.component'; +import { ConfirmDialogService } from '../../../../lib/components/confirm-dialog/confirm-dialog.service'; interface SizeItem { key: ConfirmDialogSize; @@ -41,26 +42,22 @@ const template = ` selector: 'app-confirm-dialog-sizes', standalone: true, imports: [ConfirmDialogComponent, Button], - providers: [ConfirmationService], + providers: [ConfirmationService, ConfirmDialogService], template, }) export class ConfirmDialogSizesComponent { sizes = SIZES; - constructor(private confirmationService: ConfirmationService) {} + constructor(private confirmDialogService: ConfirmDialogService) {} showConfirm(size: SizeItem): void { - this.confirmationService.confirm({ + this.confirmDialogService.confirm({ key: 'cd-size-' + size.key, message: 'Это диалог размера ' + size.label, header: 'Подтверждение', icon: 'ti ti-alert-triangle', acceptLabel: 'Да', rejectLabel: 'Нет', - rejectButtonProps: { - severity: 'secondary', - text: true, - }, accept: () => {}, reject: () => {}, }); From b6684fd9548606493f433d0dccc8e6391294daac Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 13 Apr 2026 18:39:28 +0700 Subject: [PATCH 05/10] =?UTF-8?q?confirm-dialog:=20=D1=84=D0=B8=D0=BA?= =?UTF-8?q?=D1=81=20=D1=86=D0=B2=D0=B5=D1=82=D0=BE=D0=B2=20=D0=B8=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D0=BE=D0=BA=20severity,=20=D1=83=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=20severity=20secondary=20=D1=83=20=D0=BA=D0=BD=D0=BE?= =?UTF-8?q?=D0=BF=D0=BA=D0=B8=20=D0=BE=D1=82=D0=BA=D0=BB=D0=BE=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../confirm-dialog.component.ts | 1 - .../tokens/components/confirm-dialog.ts | 24 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/lib/components/confirm-dialog/confirm-dialog.component.ts b/src/lib/components/confirm-dialog/confirm-dialog.component.ts index e5958374..cdb49939 100644 --- a/src/lib/components/confirm-dialog/confirm-dialog.component.ts +++ b/src/lib/components/confirm-dialog/confirm-dialog.component.ts @@ -45,7 +45,6 @@ export type ConfirmDialogSeverity = 'success' | 'info' | 'warn' | 'help' | 'dang @@ -86,8 +85,8 @@ const template = ` @Component({ selector: 'app-confirm-dialog-severities', standalone: true, - imports: [ConfirmDialogComponent, Button], - providers: [ConfirmationService, ConfirmDialogService], + imports: [ConfirmDialogComponent, ButtonComponent], + providers: [ConfirmDialogService.providers()], template, }) export class ConfirmDialogSeveritiesComponent { diff --git a/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts b/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts index fbfb90db..717cba6d 100644 --- a/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts +++ b/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts @@ -1,6 +1,5 @@ import { Component } from '@angular/core'; -import { Button } from 'primeng/button'; -import { ConfirmationService } from 'primeng/api'; +import { ButtonComponent } from '../../../../lib/components/button/button.component'; import { ConfirmDialogComponent, ConfirmDialogSize, @@ -28,11 +27,11 @@ const template = `
@for (size of sizes; track size.key) { - + (click)="showConfirm(size)" + > }
@@ -41,8 +40,8 @@ const template = ` @Component({ selector: 'app-confirm-dialog-sizes', standalone: true, - imports: [ConfirmDialogComponent, Button], - providers: [ConfirmationService, ConfirmDialogService], + imports: [ConfirmDialogComponent, ButtonComponent], + providers: [ConfirmDialogService.providers()], template, }) export class ConfirmDialogSizesComponent { From cd9f1227de328bfafc79b877eec251eda46ab616 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Fri, 17 Apr 2026 17:02:03 +0700 Subject: [PATCH 08/10] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D1=91=D0=BD=20?= =?UTF-8?q?=D1=84=D0=B0=D0=B9=D0=BB=20claude.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/CLAUDE-v1.6.md | 751 ----------------------------------------- 1 file changed, 751 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"` (статичный шаблон) | -| ` + >
}
diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 437e87f4..d49732b6 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -6,6 +6,9 @@ import tokens from './tokens/tokens.json'; import { avatarCss } from './tokens/components/avatar'; import { buttonCss } from './tokens/components/button'; import { checkboxCss } from './tokens/components/checkbox'; +import { confirmDialogCss } from './tokens/components/confirm-dialog'; +import { dialogCss } from './tokens/components/dialog'; +import { tagCss } from './tokens/components/tag'; import { tooltipCss } from './tokens/components/tooltip'; const presetTokens: Preset = { @@ -25,6 +28,14 @@ const presetTokens: Preset = { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), css: buttonCss, }, + confirmdialog: { + ...(tokens.components.confirmdialog as unknown as ComponentsDesignTokens['confirmdialog']), + css: confirmDialogCss, + }, + dialog: { + ...(tokens.components.dialog as unknown as ComponentsDesignTokens['dialog']), + css: dialogCss, + }, tag: { ...(tokens.components.tag as unknown as ComponentsDesignTokens['tag']), css: tagCss, From 5bf25e52776b1c1f9c73620c75fc5819e34e4a96 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Sat, 30 May 2026 19:00:27 +0700 Subject: [PATCH 10/10] DS-497 --- .../confirm-dialog.component.ts | 32 +-- .../confirm-dialog/confirm-dialog.service.ts | 10 +- .../components/confirm-dialog/ng-package.json | 7 + .../components/confirm-dialog/public_api.ts | 2 + src/lib/providers/prime-preset/map-tokens.ts | 41 ++-- src/prime-preset/map-tokens.ts | 41 ---- .../confirm-dialog/confirm-dialog.stories.ts | 220 +++--------------- .../confirm-dialog-default.component.ts | 57 ++++- .../confirm-dialog-severities.component.ts | 101 +++++++- .../confirm-dialog-sizes.component.ts | 92 ++++++-- 10 files changed, 301 insertions(+), 302 deletions(-) create mode 100644 src/lib/components/confirm-dialog/ng-package.json create mode 100644 src/lib/components/confirm-dialog/public_api.ts delete mode 100644 src/prime-preset/map-tokens.ts diff --git a/src/lib/components/confirm-dialog/confirm-dialog.component.ts b/src/lib/components/confirm-dialog/confirm-dialog.component.ts index 033da08a..5f114bf0 100644 --- a/src/lib/components/confirm-dialog/confirm-dialog.component.ts +++ b/src/lib/components/confirm-dialog/confirm-dialog.component.ts @@ -2,16 +2,16 @@ import { Component, Input, TemplateRef } from '@angular/core'; import { NgTemplateOutlet } from '@angular/common'; import { ConfirmDialog } from 'primeng/confirmdialog'; import { PrimeTemplate } from 'primeng/api'; -import { ButtonComponent } from '../button/button.component'; +import { ExtraButtonComponent } from '../button/button.component'; -export type ConfirmDialogSize = 'sm' | 'default' | 'lg' | 'xlg'; -export type ConfirmDialogSeverity = 'success' | 'info' | 'warn' | 'help' | 'danger' | 'default'; +export type ExtraConfirmDialogSize = 'sm' | 'default' | 'lg' | 'xlg'; +export type ExtraConfirmDialogSeverity = 'success' | 'info' | 'warn' | 'help' | 'danger' | 'default'; @Component({ - selector: 'confirm-dialog', + selector: 'extra-confirm-dialog', host: { style: 'display: contents' }, standalone: true, - imports: [ConfirmDialog, ButtonComponent, PrimeTemplate, NgTemplateOutlet], + imports: [ConfirmDialog, ExtraButtonComponent, PrimeTemplate, NgTemplateOutlet], template: ` @@ -25,14 +25,14 @@ export type ConfirmDialogSeverity = 'success' | 'info' | 'warn' | 'help' | 'dang {{ message.header }}
- + > }
@@ -44,26 +44,26 @@ export type ConfirmDialogSeverity = 'success' | 'info' | 'warn' | 'help' | 'dang } @else { } `, }) -export class ConfirmDialogComponent { +export class ExtraConfirmDialogComponent { @Input() key = ''; - @Input() size: ConfirmDialogSize = 'default'; - @Input() severity: ConfirmDialogSeverity = 'default'; + @Input() size: ExtraConfirmDialogSize = 'default'; + @Input() severity: ExtraConfirmDialogSeverity = 'default'; @Input() headerTemplate: TemplateRef | null = null; @Input() footerTemplate: TemplateRef | null = null; @@ -73,7 +73,7 @@ export class ConfirmDialogComponent { else if (this.size === 'lg') classes.push('p-confirmdialog-lg'); else if (this.size === 'xlg') classes.push('p-confirmdialog-xlg'); - const severityMap: Record = { + const severityMap: Record = { success: 'p-confirm-dialog-accept', info: 'p-confirm-dialog-info', warn: 'p-confirm-dialog-warn', diff --git a/src/lib/components/confirm-dialog/confirm-dialog.service.ts b/src/lib/components/confirm-dialog/confirm-dialog.service.ts index b4245602..e5a99f56 100644 --- a/src/lib/components/confirm-dialog/confirm-dialog.service.ts +++ b/src/lib/components/confirm-dialog/confirm-dialog.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, Provider } from '@angular/core'; import { Confirmation, ConfirmationService } from 'primeng/api'; export type ConfirmDialogOptions = Pick< @@ -6,12 +6,12 @@ export type ConfirmDialogOptions = Pick< 'key' | 'message' | 'header' | 'icon' | 'acceptLabel' | 'rejectLabel' | 'accept' | 'reject' | 'acceptButtonProps' >; +export function provideConfirmDialog(): Provider[] { + return [ConfirmationService, ConfirmDialogService]; +} + @Injectable() export class ConfirmDialogService { - static providers() { - return [ConfirmationService, ConfirmDialogService]; - } - constructor(private readonly confirmationService: ConfirmationService) {} confirm(options: ConfirmDialogOptions): void { diff --git a/src/lib/components/confirm-dialog/ng-package.json b/src/lib/components/confirm-dialog/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/confirm-dialog/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public_api.ts" + } +} + diff --git a/src/lib/components/confirm-dialog/public_api.ts b/src/lib/components/confirm-dialog/public_api.ts new file mode 100644 index 00000000..cdf98805 --- /dev/null +++ b/src/lib/components/confirm-dialog/public_api.ts @@ -0,0 +1,2 @@ +export * from './confirm-dialog.component'; +export * from './confirm-dialog.service'; diff --git a/src/lib/providers/prime-preset/map-tokens.ts b/src/lib/providers/prime-preset/map-tokens.ts index ed585ea3..d5947c45 100644 --- a/src/lib/providers/prime-preset/map-tokens.ts +++ b/src/lib/providers/prime-preset/map-tokens.ts @@ -23,6 +23,7 @@ import { messageCss } from './tokens/components/message'; import { inputotpCss } from './tokens/components/inputotp'; import { carouselCss } from './tokens/components/carousel'; import { galleriaCss } from './tokens/components/galleria'; +import { confirmDialogCss } from './tokens/components/confirm-dialog'; const presetTokens: Preset = { primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'], @@ -31,62 +32,62 @@ const presetTokens: Preset = { ...(tokens.components as unknown as ComponentsDesignTokens), avatar: { ...(tokens.components.avatar as unknown as ComponentsDesignTokens['avatar']), - css: avatarCss, + css: avatarCss }, card: { ...(tokens.components.card as unknown as ComponentsDesignTokens['card']), - css: cardCss, + css: cardCss }, checkbox: { ...(tokens.components.checkbox as unknown as ComponentsDesignTokens['checkbox']), - css: checkboxCss, + css: checkboxCss }, button: { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), - css: buttonCss, + css: buttonCss }, message: { ...(tokens.components.message as unknown as ComponentsDesignTokens['message']), - css: messageCss, + css: messageCss }, progressspinner: { ...(tokens.components.progressspinner as unknown as ComponentsDesignTokens['progressspinner']), - css: progressspinnerCss, + css: progressspinnerCss }, inputotp: { ...(tokens.components.inputotp as unknown as ComponentsDesignTokens['inputotp']), - css: inputotpCss, + css: inputotpCss }, inputtext: { ...(tokens.components.inputtext as unknown as ComponentsDesignTokens['inputtext']), - css: inputtextCss, + css: inputtextCss }, inputmask: { - css: inputmaskCss, + css: inputmaskCss }, inputgroup: { ...(tokens.components.inputgroup as unknown as ComponentsDesignTokens['inputgroup']), - css: inputgroupCss, + css: inputgroupCss }, tag: { ...(tokens.components.tag as unknown as ComponentsDesignTokens['tag']), - css: tagCss, + css: tagCss }, textarea: { ...(tokens.components.textarea as unknown as ComponentsDesignTokens['textarea']), - css: textareaCss, + css: textareaCss }, tooltip: { ...(tokens.components.tooltip as unknown as ComponentsDesignTokens['tooltip']), - css: tooltipCss, + css: tooltipCss }, megamenu: { ...(tokens.components.megamenu as unknown as ComponentsDesignTokens['megamenu']), - css: megamenuCss, + css: megamenuCss }, select: { ...(tokens.components.select as unknown as ComponentsDesignTokens['select']), - css: selectCss, + css: selectCss }, passwordCss: { ...(tokens.components.password as unknown as ComponentsDesignTokens['password']), @@ -94,13 +95,17 @@ const presetTokens: Preset = { }, carousel: { ...(tokens.components.carousel as unknown as ComponentsDesignTokens['carousel']), - css: carouselCss, + css: carouselCss }, galleria: { ...(tokens.components.galleria as unknown as ComponentsDesignTokens['galleria']), - css: galleriaCss, + css: galleriaCss }, - } as ComponentsDesignTokens, + confirmdialog: { + ...(tokens.components.confirmdialog as unknown as ComponentsDesignTokens['confirmdialog']), + css: confirmDialogCss + } + } as ComponentsDesignTokens }; export default presetTokens; diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts deleted file mode 100644 index afbad16c..00000000 --- a/src/prime-preset/map-tokens.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Preset } from '@primeuix/themes/types'; -import type { ComponentsDesignTokens } from '@primeuix/themes/types'; -import type { AuraBaseDesignTokens } from '@primeuix/themes/aura/base'; - -import tokens from './tokens/tokens.json'; -import { buttonCss } from './tokens/components/button'; -import { dataTableCss } from './tokens/components/data-table'; -import { checkboxCss } from './tokens/components/checkbox'; -import { confirmDialogCss } from './tokens/components/confirm-dialog'; -import { dialogCss } from './tokens/components/dialog'; -import { tagCss } from './tokens/components/tag'; -import { tooltipCss } from './tokens/components/tooltip'; - -const presetTokens: Preset = { - primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'], - semantic: tokens.semantic as unknown as AuraBaseDesignTokens['semantic'], - components: { - ...(tokens.components as unknown as ComponentsDesignTokens), - button: { - ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), - css: buttonCss, - }, - confirmdialog: { - ...(tokens.components.confirmdialog as unknown as ComponentsDesignTokens['confirmdialog']), - css: confirmDialogCss, - }, - dialog: { - ...(tokens.components.dialog as unknown as ComponentsDesignTokens['dialog']), - css: dialogCss, - }, - tag: { - ...(tokens.components.tag as unknown as ComponentsDesignTokens['tag']), - css: tagCss, - datatable: { - ...(tokens.components.datatable as unknown as ComponentsDesignTokens['datatable']), - css: dataTableCss, - }, - } as ComponentsDesignTokens, -}; - -export default presetTokens; diff --git a/src/stories/components/confirm-dialog/confirm-dialog.stories.ts b/src/stories/components/confirm-dialog/confirm-dialog.stories.ts index b35988f1..f967afba 100644 --- a/src/stories/components/confirm-dialog/confirm-dialog.stories.ts +++ b/src/stories/components/confirm-dialog/confirm-dialog.stories.ts @@ -1,24 +1,35 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { ConfirmDialogComponent } from '../../../lib/components/confirm-dialog/confirm-dialog.component'; -import { ConfirmDialogDefaultComponent } from './examples/confirm-dialog-default.component'; -import { ConfirmDialogSeveritiesComponent } from './examples/confirm-dialog-severities.component'; -import { ConfirmDialogSizesComponent } from './examples/confirm-dialog-sizes.component'; +import { ExtraConfirmDialogComponent as ConfirmDialogComponent } from '../../../lib/components/confirm-dialog/confirm-dialog.component'; +import { ConfirmDialogDefaultComponent, Default as DefaultStory } from './examples/confirm-dialog-default.component'; +import { ConfirmDialogSeveritiesComponent, Severities } from './examples/confirm-dialog-severities.component'; +import { ConfirmDialogSizesComponent, Sizes as SizesStory } from './examples/confirm-dialog-sizes.component'; +import { provideConfirmDialog } from '../../../lib/components/confirm-dialog/confirm-dialog.service'; const meta: Meta = { title: 'Components/Overlay/ConfirmDialog', component: ConfirmDialogComponent, tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + ConfirmDialogDefaultComponent, + ConfirmDialogSeveritiesComponent, + ConfirmDialogSizesComponent, + ], + providers: [provideConfirmDialog()], + }), + ], parameters: { docs: { description: { component: `Компонент для подтверждения действий пользователя. \`\`\`typescript -import { ConfirmDialogComponent, ConfirmDialogService } from '@cdek-it/angular-ui-kit'; +import { ExtraConfirmDialogComponent, ConfirmDialogService, provideConfirmDialog } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, - designTokens: { prefix: '--p-confirmdialog' }, + designTokens: { prefix: '--p-confirmdialog' } }, argTypes: { key: { @@ -26,8 +37,8 @@ import { ConfirmDialogComponent, ConfirmDialogService } from '@cdek-it/angular-u description: 'Идентификатор группы для адресной отправки сообщений.', table: { category: 'Props', - type: { summary: 'string' }, - }, + type: { summary: 'string' } + } }, size: { control: 'select', @@ -36,8 +47,8 @@ import { ConfirmDialogComponent, ConfirmDialogService } from '@cdek-it/angular-u table: { category: 'Props', defaultValue: { summary: 'default' }, - type: { summary: "'sm' | 'default' | 'lg' | 'xlg'" }, - }, + type: { summary: "'sm' | 'default' | 'lg' | 'xlg'" } + } }, severity: { control: 'select', @@ -46,10 +57,10 @@ import { ConfirmDialogComponent, ConfirmDialogService } from '@cdek-it/angular-u table: { category: 'Props', defaultValue: { summary: 'default' }, - type: { summary: "'default' | 'success' | 'info' | 'warn' | 'help' | 'danger'" }, - }, - }, - }, + type: { summary: "'default' | 'success' | 'info' | 'warn' | 'help' | 'danger'" } + } + } + } }; export default meta; @@ -57,187 +68,12 @@ type Story = StoryObj; // ── Default ─────────────────────────────────────────────────────────────────── -export const Default: Story = { - name: 'ConfirmDialog', - decorators: [moduleMetadata({ imports: [ConfirmDialogDefaultComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Базовый пример диалога подтверждения.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ConfirmDialogComponent, ConfirmDialogService, ButtonComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-confirm-dialog-default', - standalone: true, - imports: [ConfirmDialogComponent, ButtonComponent], - providers: [ConfirmDialogService.providers()], - template: \` - - - \`, -}) -export class ConfirmDialogDefaultComponent { - constructor(private confirmDialogService: ConfirmDialogService) {} - - showConfirm(): void { - this.confirmDialogService.confirm({ - key: 'cd-default', - message: 'Вы уверены, что хотите продолжить?', - header: 'Подтверждение', - icon: 'ti ti-alert-triangle', - acceptLabel: 'Да', - rejectLabel: 'Нет', - accept: () => {}, - reject: () => {}, - }); - } -} - `, - }, - }, - }, -}; +export const ConfirmDialog: Story = DefaultStory; // ── Severities ──────────────────────────────────────────────────────────────── -export const Severities: Story = { - name: 'Severities', - decorators: [moduleMetadata({ imports: [ConfirmDialogSeveritiesComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Варианты диалога с различными уровнями важности: success, info, warn, help, danger.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ConfirmDialogComponent, ConfirmDialogService, ButtonComponent } from '@cdek-it/angular-ui-kit'; - -const SEVERITIES = [ - { type: 'success', buttonSeverity: 'success', icon: 'ti ti-circle-check', label: 'Успех', header: 'Успех', message: 'Операция выполнена успешно.', acceptLabel: 'OK' }, - { type: 'info', buttonSeverity: 'info', icon: 'ti ti-info-circle', label: 'Информация', header: 'Информация', message: 'Это информационное сообщение.', acceptLabel: 'Понятно' }, - { type: 'warn', buttonSeverity: 'warn', icon: 'ti ti-alert-triangle', label: 'Предупреждение', header: 'Предупреждение', message: 'Внимание! Это действие может иметь последствия.', acceptLabel: 'Продолжить' }, - { type: 'help', buttonSeverity: 'help', icon: 'ti ti-help-circle', label: 'Справка', header: 'Справка', message: 'Нужна помощь с этим действием?', acceptLabel: 'Да' }, - { type: 'danger', buttonSeverity: 'danger', icon: 'ti ti-circle-x', label: 'Удаление', header: 'Подтверждение', message: 'Это действие нельзя отменить. Продолжить?', acceptLabel: 'Удалить' }, -]; - -@Component({ - selector: 'app-confirm-dialog-severities', - standalone: true, - imports: [ConfirmDialogComponent, ButtonComponent], - providers: [ConfirmDialogService.providers()], - template: \` - - - - - - -
- @for (severity of severities; track severity.type) { - - } -
- \`, -}) -export class ConfirmDialogSeveritiesComponent { - severities = SEVERITIES; - constructor(private confirmDialogService: ConfirmDialogService) {} - - showConfirm(severity: any): void { - this.confirmDialogService.confirm({ - key: 'cd-severity-' + severity.type, - message: severity.message, - header: severity.header, - icon: severity.icon, - acceptLabel: severity.acceptLabel, - rejectLabel: 'Нет', - acceptButtonProps: { severity: severity.buttonSeverity }, - accept: () => {}, - reject: () => {}, - }); - } -} - `, - }, - }, - }, -}; +export const SeveritiesStory: Story = Severities; // ── Sizes ───────────────────────────────────────────────────────────────────── -export const Sizes: Story = { - name: 'Sizes', - decorators: [moduleMetadata({ imports: [ConfirmDialogSizesComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Доступные размеры диалога: sm, base, lg, xlg.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ConfirmDialogComponent, ConfirmDialogService, ButtonComponent } from '@cdek-it/angular-ui-kit'; - -const SIZES = [ - { key: 'sm', label: 'Small' }, - { key: 'default', label: 'Base' }, - { key: 'lg', label: 'Large' }, - { key: 'xlg', label: 'Extra Large' }, -]; - -@Component({ - selector: 'app-confirm-dialog-sizes', - standalone: true, - imports: [ConfirmDialogComponent, ButtonComponent], - providers: [ConfirmDialogService.providers()], - template: \` - - - - - -
- @for (size of sizes; track size.key) { - - } -
- \`, -}) -export class ConfirmDialogSizesComponent { - sizes = SIZES; - constructor(private confirmDialogService: ConfirmDialogService) {} - - showConfirm(size: any): void { - this.confirmDialogService.confirm({ - key: 'cd-size-' + size.key, - message: 'Это диалог размера ' + size.label, - header: 'Подтверждение', - icon: 'ti ti-alert-triangle', - acceptLabel: 'Да', - rejectLabel: 'Нет', - accept: () => {}, - reject: () => {}, - }); - } -} - `, - }, - }, - }, -}; +export const Sizes: Story = SizesStory; diff --git a/src/stories/components/confirm-dialog/examples/confirm-dialog-default.component.ts b/src/stories/components/confirm-dialog/examples/confirm-dialog-default.component.ts index 8bda09d6..44db24ee 100644 --- a/src/stories/components/confirm-dialog/examples/confirm-dialog-default.component.ts +++ b/src/stories/components/confirm-dialog/examples/confirm-dialog-default.component.ts @@ -1,21 +1,20 @@ import { Component } from '@angular/core'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; -import { ConfirmDialogComponent } from '../../../../lib/components/confirm-dialog/confirm-dialog.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraConfirmDialogComponent } from '../../../../lib/components/confirm-dialog/confirm-dialog.component'; import { ConfirmDialogService } from '../../../../lib/components/confirm-dialog/confirm-dialog.service'; const template = `
- + - +
`; @Component({ selector: 'app-confirm-dialog-default', standalone: true, - imports: [ConfirmDialogComponent, ButtonComponent], - providers: [ConfirmDialogService.providers()], + imports: [ExtraConfirmDialogComponent, ExtraButtonComponent], template, }) export class ConfirmDialogDefaultComponent { @@ -34,3 +33,49 @@ export class ConfirmDialogDefaultComponent { }); } } + +export const Default = { + name: 'ConfirmDialog', + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Базовый пример диалога подтверждения.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { ExtraConfirmDialogComponent, ConfirmDialogService, ExtraButtonComponent, provideConfirmDialog } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-confirm-dialog-default', + standalone: true, + imports: [ExtraConfirmDialogComponent, ExtraButtonComponent], + providers: [provideConfirmDialog()], + template: \` + + + \`, +}) +export class ConfirmDialogDefaultComponent { + constructor(private confirmDialogService: ConfirmDialogService) {} + + showConfirm(): void { + this.confirmDialogService.confirm({ + key: 'cd-default', + message: 'Вы уверены, что хотите продолжить?', + header: 'Подтверждение', + icon: 'ti ti-alert-triangle', + acceptLabel: 'Да', + rejectLabel: 'Нет', + accept: () => {}, + reject: () => {}, + }); + } +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/confirm-dialog/examples/confirm-dialog-severities.component.ts b/src/stories/components/confirm-dialog/examples/confirm-dialog-severities.component.ts index 95144b13..00a0920a 100644 --- a/src/stories/components/confirm-dialog/examples/confirm-dialog-severities.component.ts +++ b/src/stories/components/confirm-dialog/examples/confirm-dialog-severities.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; -import { ConfirmDialogComponent } from '../../../../lib/components/confirm-dialog/confirm-dialog.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraConfirmDialogComponent } from '../../../../lib/components/confirm-dialog/confirm-dialog.component'; import { ConfirmDialogService } from '../../../../lib/components/confirm-dialog/confirm-dialog.service'; interface SeverityItem { @@ -63,20 +63,20 @@ const SEVERITIES: SeverityItem[] = [ const template = `
- - - - - + + + + +
@for (severity of severities; track severity.type) { - + > }
@@ -85,8 +85,7 @@ const template = ` @Component({ selector: 'app-confirm-dialog-severities', standalone: true, - imports: [ConfirmDialogComponent, ButtonComponent], - providers: [ConfirmDialogService.providers()], + imports: [ExtraConfirmDialogComponent, ExtraButtonComponent], template, }) export class ConfirmDialogSeveritiesComponent { @@ -108,3 +107,83 @@ export class ConfirmDialogSeveritiesComponent { }); } } + +export const Severities = { + name: 'Severities', + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Варианты диалога с различными уровнями важности: success, info, warn, help, danger.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { ExtraConfirmDialogComponent, ConfirmDialogService, ExtraButtonComponent, provideConfirmDialog } from '@cdek-it/angular-ui-kit'; + +interface SeverityItem { + type: 'success' | 'info' | 'warn' | 'help' | 'danger'; + buttonSeverity: 'success' | 'info' | 'warn' | 'help' | 'danger'; + icon: string; + label: string; + header: string; + message: string; + acceptLabel: string; +} + +const SEVERITIES: SeverityItem[] = [ + { type: 'success', buttonSeverity: 'success', icon: 'ti ti-circle-check', label: 'Успех', header: 'Успех', message: 'Операция выполнена успешно.', acceptLabel: 'OK' }, + { type: 'info', buttonSeverity: 'info', icon: 'ti ti-info-circle', label: 'Информация', header: 'Информация', message: 'Это информационное сообщение.', acceptLabel: 'Понятно' }, + { type: 'warn', buttonSeverity: 'warn', icon: 'ti ti-alert-triangle', label: 'Предупреждение', header: 'Предупреждение', message: 'Внимание! Это действие может иметь последствия.', acceptLabel: 'Продолжить' }, + { type: 'help', buttonSeverity: 'help', icon: 'ti ti-help-circle', label: 'Справка', header: 'Справка', message: 'Нужна помощь с этим действием?', acceptLabel: 'Да' }, + { type: 'danger', buttonSeverity: 'danger', icon: 'ti ti-circle-x', label: 'Удаление', header: 'Подтверждение', message: 'Это действие нельзя отменить. Продолжить?', acceptLabel: 'Удалить' }, +]; + +@Component({ + selector: 'app-confirm-dialog-severities', + standalone: true, + imports: [ExtraConfirmDialogComponent, ExtraButtonComponent], + providers: [provideConfirmDialog()], + template: \` + + + + + + +
+ @for (severity of severities; track severity.type) { + + } +
+ \`, +}) +export class ConfirmDialogSeveritiesComponent { + severities = SEVERITIES; + constructor(private confirmDialogService: ConfirmDialogService) {} + + showConfirm(severity: SeverityItem): void { + this.confirmDialogService.confirm({ + key: 'cd-severity-' + severity.type, + message: severity.message, + header: severity.header, + icon: severity.icon, + acceptLabel: severity.acceptLabel, + rejectLabel: 'Нет', + acceptButtonProps: { severity: severity.buttonSeverity }, + accept: () => {}, + reject: () => {}, + }); + } +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts b/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts index 717cba6d..5fc3945d 100644 --- a/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts +++ b/src/stories/components/confirm-dialog/examples/confirm-dialog-sizes.component.ts @@ -1,13 +1,13 @@ import { Component } from '@angular/core'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; import { - ConfirmDialogComponent, - ConfirmDialogSize, + ExtraConfirmDialogComponent, + ExtraConfirmDialogSize, } from '../../../../lib/components/confirm-dialog/confirm-dialog.component'; import { ConfirmDialogService } from '../../../../lib/components/confirm-dialog/confirm-dialog.service'; interface SizeItem { - key: ConfirmDialogSize; + key: ExtraConfirmDialogSize; label: string; } @@ -20,18 +20,18 @@ const SIZES: SizeItem[] = [ const template = `
- - - - + + + +
@for (size of sizes; track size.key) { - + > }
@@ -40,8 +40,7 @@ const template = ` @Component({ selector: 'app-confirm-dialog-sizes', standalone: true, - imports: [ConfirmDialogComponent, ButtonComponent], - providers: [ConfirmDialogService.providers()], + imports: [ExtraConfirmDialogComponent, ExtraButtonComponent], template, }) export class ConfirmDialogSizesComponent { @@ -62,3 +61,70 @@ export class ConfirmDialogSizesComponent { }); } } + +export const Sizes = { + name: 'Sizes', + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Доступные размеры диалога: sm, base, lg, xlg.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { ExtraConfirmDialogComponent, ExtraConfirmDialogSize, ConfirmDialogService, ExtraButtonComponent, provideConfirmDialog } from '@cdek-it/angular-ui-kit'; + +interface SizeItem { + key: ExtraConfirmDialogSize; + label: string; +} + +const SIZES: SizeItem[] = [ + { key: 'sm', label: 'Small' }, + { key: 'default', label: 'Base' }, + { key: 'lg', label: 'Large' }, + { key: 'xlg', label: 'Extra Large' }, +]; + +@Component({ + selector: 'app-confirm-dialog-sizes', + standalone: true, + imports: [ExtraConfirmDialogComponent, ExtraButtonComponent], + providers: [provideConfirmDialog()], + template: \` + + + + + +
+ @for (size of sizes; track size.key) { + + } +
+ \`, +}) +export class ConfirmDialogSizesComponent { + sizes = SIZES; + constructor(private confirmDialogService: ConfirmDialogService) {} + + showConfirm(size: SizeItem): void { + this.confirmDialogService.confirm({ + key: 'cd-size-' + size.key, + message: 'Это диалог размера ' + size.label, + header: 'Подтверждение', + icon: 'ti ti-alert-triangle', + acceptLabel: 'Да', + rejectLabel: 'Нет', + accept: () => {}, + reject: () => {}, + }); + } +} + `, + }, + }, + }, +};