From b7f35fd2fc5737983c6952f12b5d7dd062601ba4 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Fri, 23 Jan 2026 14:50:56 +0700 Subject: [PATCH 001/258] add components tokens --- src/prime-preset/map-tokens.ts | 4 +++- src/prime-preset/tokens/components/button.json | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 src/prime-preset/tokens/components/button.json diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 4957dfd4..62ebcb4e 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -11,10 +11,12 @@ import sizingSm from './tokens/sizing-sm.json'; import sizingLg from './tokens/sizing-lg.json'; import sizingXlg from './tokens/sizing-xlg.json'; +import button from './tokens/components/button.json'; + const presetTokens: Preset = { primitive, semantic, - components + components: { ...components, ...button } }; if (presetTokens?.semantic) { diff --git a/src/prime-preset/tokens/components/button.json b/src/prime-preset/tokens/components/button.json new file mode 100644 index 00000000..347c037d --- /dev/null +++ b/src/prime-preset/tokens/components/button.json @@ -0,0 +1,5 @@ +{ + "button": { + "css": "" + } +} From 2e5947fc7d3298a0b90fafef1887da6f21ccd1b1 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Fri, 20 Mar 2026 11:51:32 +0700 Subject: [PATCH 002/258] example of button component --- src/components/button/button.component.html | 3 ++ src/components/button/button.component.scss | 0 .../button/button.component.spec.ts | 23 ++++++++++++++ src/components/button/button.component.ts | 30 +++++++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 src/components/button/button.component.html create mode 100644 src/components/button/button.component.scss create mode 100644 src/components/button/button.component.spec.ts create mode 100644 src/components/button/button.component.ts diff --git a/src/components/button/button.component.html b/src/components/button/button.component.html new file mode 100644 index 00000000..4a13bbdc --- /dev/null +++ b/src/components/button/button.component.html @@ -0,0 +1,3 @@ + + + diff --git a/src/components/button/button.component.scss b/src/components/button/button.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/components/button/button.component.spec.ts b/src/components/button/button.component.spec.ts new file mode 100644 index 00000000..d4ad18ea --- /dev/null +++ b/src/components/button/button.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ButtonComponent } from './button.component'; + +describe('ButtonComponent', () => { + let component: ButtonComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ButtonComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/components/button/button.component.ts b/src/components/button/button.component.ts new file mode 100644 index 00000000..8909500c --- /dev/null +++ b/src/components/button/button.component.ts @@ -0,0 +1,30 @@ +import { Component, Input } from '@angular/core'; +import { Button } from 'primeng/button'; + +/** + * как использовать + * ``` + * + *
content
// это то, на что заменится внутри компонента + *
+ *``` + */ + +@Component({ + selector: 'app-button', + standalone: true, + imports: [Button], + templateUrl: './button.component.html', + styleUrl: './button.component.scss' +}) +export class ButtonComponent { + @Input() size!: 'small' | undefined | 'large' | 'xlarge'; + + @Input() text: boolean = false; + + private innerSize: 'small' | undefined | 'large'; + + constructor() { + this.innerSize = this.size === 'xlarge' ? undefined : this.size; + } +} From 97d2422417ddecd6e5d09607c82886934e820c23 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 23 Mar 2026 17:35:55 +0700 Subject: [PATCH 003/258] style: add space before closing brace in `ButtonSizesComponent` --- .../console-2026-03-20T05-59-04-766Z.log | 1 + documentation.json | 1854 ++++++++ .../tt-fellows/TT_Fellows_DemiBold.woff2 | Bin 0 -> 48592 bytes .../fonts/tt-fellows/TT_Fellows_Regular.woff2 | Bin 0 -> 47760 bytes .../button/button-extra.component.ts | 58 + src/components/button/button.component.html | 2 +- src/components/button/button.component.ts | 6 +- src/prime-preset/map-tokens.ts | 44 +- .../tokens/components-default.json | 3362 --------------- src/prime-preset/tokens/components.ts | 3716 +++++++++++++++++ .../tokens/components/button.json | 5 - src/prime-preset/tokens/components/button.ts | 157 + .../tokens/primitive-default.json | 377 -- src/prime-preset/tokens/primitive.ts | 480 +++ src/prime-preset/tokens/semantic-default.json | 112 - src/prime-preset/tokens/semantic.ts | 838 ++++ src/prime-preset/tokens/sizing-base.json | 30 - src/prime-preset/tokens/sizing-lg.json | 30 - src/prime-preset/tokens/sizing-sm.json | 30 - src/prime-preset/tokens/sizing-xlg.json | 30 - src/prime-preset/tokens/theme-dark.json | 212 - src/prime-preset/tokens/theme-light.json | 212 - .../components/button/button.stories.ts | 414 +- .../button/examples/button-extra.component.ts | 87 + src/styles.scss | 18 + 25 files changed, 7596 insertions(+), 4479 deletions(-) create mode 100644 .playwright-mcp/console-2026-03-20T05-59-04-766Z.log create mode 100644 documentation.json create mode 100644 src/assets/fonts/tt-fellows/TT_Fellows_DemiBold.woff2 create mode 100644 src/assets/fonts/tt-fellows/TT_Fellows_Regular.woff2 create mode 100644 src/components/button/button-extra.component.ts delete mode 100644 src/prime-preset/tokens/components-default.json create mode 100644 src/prime-preset/tokens/components.ts delete mode 100644 src/prime-preset/tokens/components/button.json create mode 100644 src/prime-preset/tokens/components/button.ts delete mode 100644 src/prime-preset/tokens/primitive-default.json create mode 100644 src/prime-preset/tokens/primitive.ts delete mode 100644 src/prime-preset/tokens/semantic-default.json create mode 100644 src/prime-preset/tokens/semantic.ts delete mode 100644 src/prime-preset/tokens/sizing-base.json delete mode 100644 src/prime-preset/tokens/sizing-lg.json delete mode 100644 src/prime-preset/tokens/sizing-sm.json delete mode 100644 src/prime-preset/tokens/sizing-xlg.json delete mode 100644 src/prime-preset/tokens/theme-dark.json delete mode 100644 src/prime-preset/tokens/theme-light.json create mode 100644 src/stories/components/button/examples/button-extra.component.ts diff --git a/.playwright-mcp/console-2026-03-20T05-59-04-766Z.log b/.playwright-mcp/console-2026-03-20T05-59-04-766Z.log new file mode 100644 index 00000000..567be132 --- /dev/null +++ b/.playwright-mcp/console-2026-03-20T05-59-04-766Z.log @@ -0,0 +1 @@ +[ 388ms] [ERROR] Failed to load resource: the server responded with a status of 404 () @ https://raw.githubusercontent.com/cdek-it/vue-ui-kit/storybook-update/src/assets/style/vars/_colors.scss:0 diff --git a/documentation.json b/documentation.json new file mode 100644 index 00000000..d00b737f --- /dev/null +++ b/documentation.json @@ -0,0 +1,1854 @@ +{ + "pipes": [], + "interfaces": [], + "injectables": [], + "guards": [], + "interceptors": [], + "classes": [], + "directives": [], + "components": [ + { + "name": "ButtonBadgeComponent", + "id": "component-ButtonBadgeComponent-c9b005f02f6e55b548ed6d44acdd87fbdf45b61e3a7f18d9d961e78d431b006c05ee81e31efae1ae4ec339fb6b7695b596dedf691d78ee81e927ce08eee82673", + "file": "src/stories/components/button/examples/button-badge.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-button-badge", + "styleUrls": [], + "styles": [], + "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n
\n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "ButtonModule", + "type": "module" + }, + { + "name": "OverlayBadgeModule", + "type": "module" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\nimport { OverlayBadgeModule } from 'primeng/overlaybadge';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-badge',\n standalone: true,\n imports: [ButtonModule, OverlayBadgeModule],\n template\n})\nexport class ButtonBadgeComponent {}\n\nexport const Badge: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с уведомлением или числовым индикатором (OverlayBadge).'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, + { + "name": "ButtonBaseComponent", + "id": "component-ButtonBaseComponent-81242ea4c12e4bd3710ef0ab4cd6263ecce5f5d559192ef040bf30fd20b9ff129d272455cd71793f536ca24f9722d12c4da599572fdc45d6162bc6ffd2e3fa0c", + "file": "src/stories/components/button/examples/button-base.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-button-base", + "styleUrls": [], + "styles": [], + "template": "`
\n \n \n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [ + { + "name": "badge", + "defaultValue": "''", + "deprecated": false, + "deprecationMessage": "", + "line": 41, + "type": "string", + "decorators": [] + }, + { + "name": "disabled", + "defaultValue": "false", + "deprecated": false, + "deprecationMessage": "", + "line": 34, + "type": "boolean", + "decorators": [] + }, + { + "name": "icon", + "defaultValue": "''", + "deprecated": false, + "deprecationMessage": "", + "line": 39, + "type": "string", + "decorators": [] + }, + { + "name": "iconPos", + "defaultValue": "'left'", + "deprecated": false, + "deprecationMessage": "", + "line": 40, + "type": "ButtonIconPosition", + "decorators": [] + }, + { + "name": "label", + "defaultValue": "''", + "deprecated": false, + "deprecationMessage": "", + "line": 33, + "type": "string", + "decorators": [] + }, + { + "name": "loading", + "defaultValue": "false", + "deprecated": false, + "deprecationMessage": "", + "line": 35, + "type": "boolean", + "decorators": [] + }, + { + "name": "rounded", + "defaultValue": "false", + "deprecated": false, + "deprecationMessage": "", + "line": 37, + "type": "boolean", + "decorators": [] + }, + { + "name": "severity", + "defaultValue": "null", + "deprecated": false, + "deprecationMessage": "", + "line": 42, + "type": "Extract", + "decorators": [] + }, + { + "name": "size", + "deprecated": false, + "deprecationMessage": "", + "line": 36, + "type": "\"small\" | \"large\" | \"xlarge\" | undefined", + "decorators": [] + }, + { + "name": "variant", + "defaultValue": "null", + "deprecated": false, + "deprecationMessage": "", + "line": 38, + "type": "\"outlined\" | \"text\" | \"link\" | null", + "decorators": [] + } + ], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "Button" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component, Input } from '@angular/core';\nimport { Button, ButtonIconPosition } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n \n \n
\n`;\n\n@Component({\n selector: 'app-button-base',\n standalone: true,\n imports: [Button],\n template\n})\nexport class ButtonBaseComponent {\n @Input() label = '';\n @Input() disabled = false;\n @Input() loading = false;\n @Input() size: 'small' | 'large' | 'xlarge' | undefined;\n @Input() rounded = false;\n @Input() variant: 'outlined' | 'text' | 'link' | null = null;\n @Input() icon: string = '';\n @Input() iconPos: ButtonIconPosition = 'left';\n @Input() badge: string = '';\n @Input() severity: Extract = null;\n}\n\nexport const Default: StoryObj = {\n render: (args) => ({\n props: args,\n template: `\n\n`\n }),\n args: {\n label: 'Button',\n disabled: false,\n loading: false,\n size: null,\n rounded: false,\n variant: null,\n icon: '',\n iconPos: 'left',\n badge: '',\n severity: null\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n },\n size: {\n control: 'select',\n options: [null, 'small', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n variant: {\n control: 'select',\n options: [null, 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n iconPos: {\n control: 'select',\n options: ['left', 'right', 'top', 'bottom'],\n description: 'Позиция иконки относительно текста'\n },\n badge: {\n control: 'text',\n description: 'Текст для отображения в виде бейджа на кнопке'\n },\n severity: {\n control: 'select',\n options: [null, 'secondary', 'contrast', 'success', 'info', 'warn', 'help', 'danger'],\n description: 'Семантический вариант кнопки'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, + { + "name": "ButtonDisabledComponent", + "id": "component-ButtonDisabledComponent-68a58df505e94299e8d28d3d882464c07106fc021b1ff9a5b2aa900da697878649bb93a7d3022da8d410db37dd98bee18061262bcf1e065b11b8420b496f2216", + "file": "src/stories/components/button/examples/button-disabled.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-button-disabled", + "styleUrls": [], + "styles": [], + "template": "`
\n
\n \n success\n info\n warn\n danger\n\n default\n \n \n \n \n\n outlined\n \n \n \n \n\n text\n \n \n \n \n
\n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "ButtonModule", + "type": "module" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n \n success\n info\n warn\n danger\n\n default\n \n \n \n \n\n outlined\n \n \n \n \n\n text\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-disabled',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonDisabledComponent {}\n\nexport const Disabled: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Состояние кнопки, при котором взаимодействие с ней заблокировано.'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, + { + "name": "ButtonIconComponent", + "id": "component-ButtonIconComponent-593709211f63b4521fe1da011a69eb0b10325b97b3079d710c392a135c70c4087d1dbaeedf8335be9925cfea65651eb17bbe1c054f5064dfef72ada6437d537c", + "file": "src/stories/components/button/examples/button-icon.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-button-icon", + "styleUrls": [], + "styles": [], + "template": "`
\n
\n \n icon prefix\n icon postfix\n rounded\n\n xlarge\n \n \n \n\n large\n \n \n \n\n base\n \n \n \n\n small\n \n \n \n
\n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "ButtonModule", + "type": "module" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n \n icon prefix\n icon postfix\n rounded\n\n xlarge\n \n \n \n\n large\n \n \n \n\n base\n \n \n \n\n small\n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-icon',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonIconComponent {}\n\nexport const Icons: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки могут содержать иконки слева, справа или быть скруглёнными.'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, + { + "name": "ButtonIconOnlyComponent", + "id": "component-ButtonIconOnlyComponent-fd1de76754aa7f8fc48d81d4ca05e7f173032e18879c1ce3a3be46c2f6f02bae7b92f40d2a17085bd004bca0f6cf63fb32ff2fdbcc57868797294c2e1f878fb1", + "file": "src/stories/components/button/examples/button-icon-only.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-button-icon-only", + "styleUrls": [], + "styles": [], + "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "ButtonModule", + "type": "module" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-icon-only',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonIconOnlyComponent {}\n\nexport const IconOnly: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'В случаях, когда текст не требуется, можно использовать только иконку.'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, + { + "name": "ButtonLinkComponent", + "id": "component-ButtonLinkComponent-007a470d2943d83647e22b07ab1a166adb2bcf5277a70764dbf493bd57f58eab655647073590a738e950f3a47daabe97c64a32cbfd51889f3aa4bbfac5339690", + "file": "src/stories/components/button/examples/button-link.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-button-link", + "styleUrls": [], + "styles": [], + "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "ButtonModule", + "type": "module" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-link',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonLinkComponent {}\n\nexport const Link: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка, стилизованная под ссылку.'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, + { + "name": "ButtonLoadingComponent", + "id": "component-ButtonLoadingComponent-38ebe46e8e8f5c9b416d26a65e30fdd9fe7157c394ba9d632f9f8a228a63111342eeedfc9f723724dcd8cc7e6a745b43d412fede99d2c8721a1c2652cec7362c", + "file": "src/stories/components/button/examples/button-loading.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-button-loading", + "styleUrls": [], + "styles": [], + "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "ButtonModule", + "type": "module" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-loading',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonLoadingComponent {}\n\nexport const Loading: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с индикатором загрузки. Полезно для асинхронных действий.'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, + { + "name": "ButtonOutlinedComponent", + "id": "component-ButtonOutlinedComponent-a13faff82fc977a14c4c2617748ac67685eeb29cc4d41568bbdb138ee506668f41237e08b7300bfed3ed505f22b2c92024bf893b714db9e69c0d3e51c71e55eb", + "file": "src/stories/components/button/examples/button-outlined.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-button-outlined", + "styleUrls": [], + "styles": [], + "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "ButtonModule", + "type": "module" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-outlined',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonOutlinedComponent {}\n\nexport const Outlined: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с контуром без заливки.'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, + { + "name": "ButtonRoundedComponent", + "id": "component-ButtonRoundedComponent-6bb6041fd5f04e03709f54d657c1deb7a399760fcfa23e48faf81626afbdf66a023798e961b7a9dd6eb2290dfab0d66b85b0693e4153758f0e107194f6f529ba", + "file": "src/stories/components/button/examples/button-rounded.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-button-rounded", + "styleUrls": [], + "styles": [], + "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "ButtonModule", + "type": "module" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-rounded',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonRoundedComponent {}\n\nexport const Rounded: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Полностью скруглённая форма кнопки.'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, + { + "name": "ButtonSeverityComponent", + "id": "component-ButtonSeverityComponent-4224631554907621005b0d851894c01123bd61db2006116292e39193a72529526c066b8a3a0b11fe7a6af30c49f9baf6543c07a8f1fe9fbace37ad0348cf2a9d", + "file": "src/stories/components/button/examples/button-severity.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-button-severity", + "styleUrls": [], + "styles": [], + "template": "`
\n
\n \n success\n info\n warn\n danger\n\n small\n \n \n \n \n\n base\n \n \n \n \n\n large\n \n \n \n \n\n xlarge\n \n \n \n \n
\n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "ButtonModule", + "type": "module" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n \n success\n info\n warn\n danger\n\n small\n \n \n \n \n\n base\n \n \n \n \n\n large\n \n \n \n \n\n xlarge\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-severity',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonSeverityComponent {}\n\nexport const Severity: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Цветовые схемы для различных контекстов: success, info, warn, danger.'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, + { + "name": "ButtonSizesComponent", + "id": "component-ButtonSizesComponent-661dba1070924aed1cf4ef49813a1f6a6d907cda1dbe15073344241af94004420dbf3f7107d8d4cf54381532ef87576f0bd782219a05c55c872ac9615e66b4f4", + "file": "src/stories/components/button/examples/button-sizes.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-button-sizes", + "styleUrls": [], + "styles": [], + "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "ButtonModule", + "type": "module" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-sizes',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonSizesComponent { }\n\nexport const Sizes: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Все доступные размеры: small, base, large, xlg.'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, + { + "name": "ButtonTextComponent", + "id": "component-ButtonTextComponent-b8472d5ec2f9a7a21c0437842a5b23baa7e24c4a845f0fc5b52a8f2f5775c2686be8685b6806f4825b21f6aaf458393f6fcfd3de779933a6154fdb45c6c2df0d", + "file": "src/stories/components/button/examples/button-text.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-button-text", + "styleUrls": [], + "styles": [], + "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "ButtonModule", + "type": "module" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonTextComponent {}\n\nexport const Text: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка без заливки и границ, часто используется в тулбарах или списках.'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, + { + "name": "ExtraButtonComponent", + "id": "component-ExtraButtonComponent-7358754f1ac1c9e3e3f8be731885ba5cdacf6a1995653ef9d32fe869f8caa4a60c9e6bb1bb9b7da84303aba0a6f8c83d9f60d8b6d22267cc9d61e13d4cd9ed87", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "extra-button", + "styleUrls": [], + "styles": [], + "template": "`
\n \n
\n`", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [ + { + "name": "disabled", + "defaultValue": "false", + "deprecated": false, + "deprecationMessage": "", + "line": 44, + "type": "boolean", + "decorators": [] + }, + { + "name": "icon", + "defaultValue": "''", + "deprecated": false, + "deprecationMessage": "", + "line": 43, + "type": "string", + "decorators": [] + }, + { + "name": "iconOnly", + "defaultValue": "false", + "deprecated": false, + "deprecationMessage": "", + "line": 42, + "type": "boolean", + "decorators": [] + }, + { + "name": "iconPos", + "defaultValue": "null", + "deprecated": false, + "deprecationMessage": "", + "line": 41, + "type": "ExtraButtonIconPos", + "decorators": [] + }, + { + "name": "label", + "defaultValue": "'Button'", + "deprecated": false, + "deprecationMessage": "", + "line": 36, + "type": "string", + "decorators": [] + }, + { + "name": "loading", + "defaultValue": "false", + "deprecated": false, + "deprecationMessage": "", + "line": 45, + "type": "boolean", + "decorators": [] + }, + { + "name": "rounded", + "defaultValue": "false", + "deprecated": false, + "deprecationMessage": "", + "line": 40, + "type": "boolean", + "decorators": [] + }, + { + "name": "severity", + "defaultValue": "null", + "deprecated": false, + "deprecationMessage": "", + "line": 38, + "type": "ExtraButtonSeverity", + "decorators": [] + }, + { + "name": "size", + "defaultValue": "'base'", + "deprecated": false, + "deprecationMessage": "", + "line": 39, + "type": "ExtraButtonSize", + "decorators": [] + }, + { + "name": "variant", + "defaultValue": "'primary'", + "deprecated": false, + "deprecationMessage": "", + "line": 37, + "type": "ExtraButtonVariant", + "decorators": [] + } + ], + "outputsClass": [], + "propertiesClass": [], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": true, + "imports": [ + { + "name": "Button" + } + ], + "description": "", + "rawdescription": "\n", + "type": "component", + "sourceCode": "import { Component, Input } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\ntype ExtraButtonVariant = 'primary' | 'secondary' | 'outlined' | 'text' | 'link';\ntype ExtraButtonSeverity = 'success' | 'warning' | 'danger' | 'info' | null;\ntype ExtraButtonSize = 'small' | 'base' | 'large' | 'xlarge';\ntype ExtraButtonIconPos = 'prefix' | 'postfix' | null;\n\nconst template = `\n
\n \n
\n`;\n\n@Component({\n selector: 'extra-button',\n standalone: true,\n imports: [Button],\n template\n})\nexport class ExtraButtonComponent {\n @Input() label = 'Button';\n @Input() variant: ExtraButtonVariant = 'primary';\n @Input() severity: ExtraButtonSeverity = null;\n @Input() size: ExtraButtonSize = 'base';\n @Input() rounded = false;\n @Input() iconPos: ExtraButtonIconPos = null;\n @Input() iconOnly = false;\n @Input() icon = '';\n @Input() disabled = false;\n @Input() loading = false;\n\n get primeSize(): 'small' | 'large' | undefined {\n if (this.size === 'small') return 'small';\n if (this.size === 'large') return 'large';\n return undefined;\n }\n\n get primeIconPos(): 'left' | 'right' {\n return this.iconPos === 'postfix' ? 'right' : 'left';\n }\n\n get primeSeverity(): string | null {\n if (this.variant === 'secondary') return 'secondary';\n if (this.severity === 'warning') return 'warn';\n return this.severity;\n }\n}\n\nexport const Extra: StoryObj = {\n render: (args) => ({\n props: args,\n template: `\n`\n }),\n args: {\n label: 'Button',\n variant: 'primary',\n severity: null,\n size: 'base',\n rounded: false,\n iconPos: null,\n iconOnly: false,\n icon: '',\n disabled: false,\n loading: false\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'warning', 'danger', 'info'],\n description: 'Цветовая схема кнопки'\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки (prefix — слева, postfix — справа)'\n },\n iconOnly: {\n control: 'boolean',\n description: 'Режим кнопки только с иконкой'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Интерактивный пример с пропсами, соответствующими Figma-компоненту Button.'\n }\n }\n }\n};\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [], + "accessors": { + "primeSize": { + "name": "primeSize", + "getSignature": { + "name": "primeSize", + "type": "unknown", + "returnType": "\"small\" | \"large\" | undefined", + "line": 47 + } + }, + "primeIconPos": { + "name": "primeIconPos", + "getSignature": { + "name": "primeIconPos", + "type": "unknown", + "returnType": "\"left\" | \"right\"", + "line": 53 + } + }, + "primeSeverity": { + "name": "primeSeverity", + "getSignature": { + "name": "primeSeverity", + "type": "unknown", + "returnType": "string | null", + "line": 57 + } + } + } + } + ], + "modules": [], + "miscellaneous": { + "variables": [ + { + "name": "Badge", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-badge.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с уведомлением или числовым индикатором (OverlayBadge).'\n }\n }\n }\n}" + }, + { + "name": "Default", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-base.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n\n`\n }),\n args: {\n label: 'Button',\n disabled: false,\n loading: false,\n size: null,\n rounded: false,\n variant: null,\n icon: '',\n iconPos: 'left',\n badge: '',\n severity: null\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n },\n size: {\n control: 'select',\n options: [null, 'small', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n variant: {\n control: 'select',\n options: [null, 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n iconPos: {\n control: 'select',\n options: ['left', 'right', 'top', 'bottom'],\n description: 'Позиция иконки относительно текста'\n },\n badge: {\n control: 'text',\n description: 'Текст для отображения в виде бейджа на кнопке'\n },\n severity: {\n control: 'select',\n options: [null, 'secondary', 'contrast', 'success', 'info', 'warn', 'help', 'danger'],\n description: 'Семантический вариант кнопки'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.'\n }\n }\n }\n}" + }, + { + "name": "Disabled", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-disabled.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Состояние кнопки, при котором взаимодействие с ней заблокировано.'\n }\n }\n }\n}" + }, + { + "name": "Extra", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n`\n }),\n args: {\n label: 'Button',\n variant: 'primary',\n severity: null,\n size: 'base',\n rounded: false,\n iconPos: null,\n iconOnly: false,\n icon: '',\n disabled: false,\n loading: false\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'warning', 'danger', 'info'],\n description: 'Цветовая схема кнопки'\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки (prefix — слева, postfix — справа)'\n },\n iconOnly: {\n control: 'boolean',\n description: 'Режим кнопки только с иконкой'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Интерактивный пример с пропсами, соответствующими Figma-компоненту Button.'\n }\n }\n }\n}" + }, + { + "name": "IconOnly", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-icon-only.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'В случаях, когда текст не требуется, можно использовать только иконку.'\n }\n }\n }\n}" + }, + { + "name": "Icons", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-icon.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки могут содержать иконки слева, справа или быть скруглёнными.'\n }\n }\n }\n}" + }, + { + "name": "Link", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-link.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка, стилизованная под ссылку.'\n }\n }\n }\n}" + }, + { + "name": "Loading", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-loading.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с индикатором загрузки. Полезно для асинхронных действий.'\n }\n }\n }\n}" + }, + { + "name": "meta", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Meta", + "defaultValue": "{\n title: 'PrimeNG/Button',\n decorators: [\n moduleMetadata({\n imports: [\n CommonModule,\n ButtonModule,\n BadgeModule,\n OverlayBadgeModule,\n ExtraButtonComponent,\n ButtonBaseComponent,\n ButtonSizesComponent,\n ButtonRoundedComponent,\n ButtonTextComponent,\n ButtonLinkComponent,\n ButtonIconComponent,\n ButtonIconOnlyComponent,\n ButtonDisabledComponent,\n ButtonLoadingComponent,\n ButtonBadgeComponent,\n ButtonSeverityComponent\n ]\n })\n ],\n parameters: {\n docs: {\n description: {\n component: 'Кнопка — базовый интерактивный элемент. [PrimeNG Button](https://primeng.org/button), [Figma Design](https://www.figma.com/design/HOLKdvQJ8jCLeX17s9d0Yf/UI-Kit--DS--v2.0?node-id=160-5223)'\n }\n }\n }\n}" + }, + { + "name": "Outlined", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-outlined.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с контуром без заливки.'\n }\n }\n }\n}" + }, + { + "name": "Rounded", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-rounded.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Полностью скруглённая форма кнопки.'\n }\n }\n }\n}" + }, + { + "name": "Severity", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-severity.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Цветовые схемы для различных контекстов: success, info, warn, danger.'\n }\n }\n }\n}" + }, + { + "name": "Sizes", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-sizes.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Все доступные размеры: small, base, large, xlg.'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-badge.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n
\n
\n`" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-base.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n \n \n
\n`" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-disabled.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n \n success\n info\n warn\n danger\n\n default\n \n \n \n \n\n outlined\n \n \n \n \n\n text\n \n \n \n \n
\n
\n`" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n \n
\n`" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-icon-only.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-icon.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n \n icon prefix\n icon postfix\n rounded\n\n xlarge\n \n \n \n\n large\n \n \n \n\n base\n \n \n \n\n small\n \n \n \n
\n
\n`" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-link.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-loading.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-outlined.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-rounded.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-severity.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n \n success\n info\n warn\n danger\n\n small\n \n \n \n \n\n base\n \n \n \n \n\n large\n \n \n \n \n\n xlarge\n \n \n \n \n
\n
\n`" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-sizes.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-text.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + }, + { + "name": "Text", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-text.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка без заливки и границ, часто используется в тулбарах или списках.'\n }\n }\n }\n}" + } + ], + "functions": [], + "typealiases": [ + { + "name": "ExtraButtonIconPos", + "ctype": "miscellaneous", + "subtype": "typealias", + "rawtype": "\"prefix\" | \"postfix\" | null", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "kind": 193 + }, + { + "name": "ExtraButtonSeverity", + "ctype": "miscellaneous", + "subtype": "typealias", + "rawtype": "\"success\" | \"warning\" | \"danger\" | \"info\" | null", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "kind": 193 + }, + { + "name": "ExtraButtonSize", + "ctype": "miscellaneous", + "subtype": "typealias", + "rawtype": "\"small\" | \"base\" | \"large\" | \"xlarge\"", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "kind": 193 + }, + { + "name": "ExtraButtonVariant", + "ctype": "miscellaneous", + "subtype": "typealias", + "rawtype": "\"primary\" | \"secondary\" | \"outlined\" | \"text\" | \"link\"", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "kind": 193 + } + ], + "enumerations": [], + "groupedVariables": { + "src/stories/components/button/examples/button-badge.component.ts": [ + { + "name": "Badge", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-badge.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с уведомлением или числовым индикатором (OverlayBadge).'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-badge.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n
\n
\n`" + } + ], + "src/stories/components/button/examples/button-base.component.ts": [ + { + "name": "Default", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-base.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n\n`\n }),\n args: {\n label: 'Button',\n disabled: false,\n loading: false,\n size: null,\n rounded: false,\n variant: null,\n icon: '',\n iconPos: 'left',\n badge: '',\n severity: null\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n },\n size: {\n control: 'select',\n options: [null, 'small', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n variant: {\n control: 'select',\n options: [null, 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n iconPos: {\n control: 'select',\n options: ['left', 'right', 'top', 'bottom'],\n description: 'Позиция иконки относительно текста'\n },\n badge: {\n control: 'text',\n description: 'Текст для отображения в виде бейджа на кнопке'\n },\n severity: {\n control: 'select',\n options: [null, 'secondary', 'contrast', 'success', 'info', 'warn', 'help', 'danger'],\n description: 'Семантический вариант кнопки'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-base.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n \n \n
\n`" + } + ], + "src/stories/components/button/examples/button-disabled.component.ts": [ + { + "name": "Disabled", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-disabled.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Состояние кнопки, при котором взаимодействие с ней заблокировано.'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-disabled.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n \n success\n info\n warn\n danger\n\n default\n \n \n \n \n\n outlined\n \n \n \n \n\n text\n \n \n \n \n
\n
\n`" + } + ], + "src/stories/components/button/examples/button-extra.component.ts": [ + { + "name": "Extra", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n`\n }),\n args: {\n label: 'Button',\n variant: 'primary',\n severity: null,\n size: 'base',\n rounded: false,\n iconPos: null,\n iconOnly: false,\n icon: '',\n disabled: false,\n loading: false\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'warning', 'danger', 'info'],\n description: 'Цветовая схема кнопки'\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки (prefix — слева, postfix — справа)'\n },\n iconOnly: {\n control: 'boolean',\n description: 'Режим кнопки только с иконкой'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Интерактивный пример с пропсами, соответствующими Figma-компоненту Button.'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n \n
\n`" + } + ], + "src/stories/components/button/examples/button-icon-only.component.ts": [ + { + "name": "IconOnly", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-icon-only.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'В случаях, когда текст не требуется, можно использовать только иконку.'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-icon-only.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + } + ], + "src/stories/components/button/examples/button-icon.component.ts": [ + { + "name": "Icons", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-icon.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки могут содержать иконки слева, справа или быть скруглёнными.'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-icon.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n \n icon prefix\n icon postfix\n rounded\n\n xlarge\n \n \n \n\n large\n \n \n \n\n base\n \n \n \n\n small\n \n \n \n
\n
\n`" + } + ], + "src/stories/components/button/examples/button-link.component.ts": [ + { + "name": "Link", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-link.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка, стилизованная под ссылку.'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-link.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + } + ], + "src/stories/components/button/examples/button-loading.component.ts": [ + { + "name": "Loading", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-loading.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с индикатором загрузки. Полезно для асинхронных действий.'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-loading.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + } + ], + "src/stories/components/button/button.stories.ts": [ + { + "name": "meta", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Meta", + "defaultValue": "{\n title: 'PrimeNG/Button',\n decorators: [\n moduleMetadata({\n imports: [\n CommonModule,\n ButtonModule,\n BadgeModule,\n OverlayBadgeModule,\n ExtraButtonComponent,\n ButtonBaseComponent,\n ButtonSizesComponent,\n ButtonRoundedComponent,\n ButtonTextComponent,\n ButtonLinkComponent,\n ButtonIconComponent,\n ButtonIconOnlyComponent,\n ButtonDisabledComponent,\n ButtonLoadingComponent,\n ButtonBadgeComponent,\n ButtonSeverityComponent\n ]\n })\n ],\n parameters: {\n docs: {\n description: {\n component: 'Кнопка — базовый интерактивный элемент. [PrimeNG Button](https://primeng.org/button), [Figma Design](https://www.figma.com/design/HOLKdvQJ8jCLeX17s9d0Yf/UI-Kit--DS--v2.0?node-id=160-5223)'\n }\n }\n }\n}" + } + ], + "src/stories/components/button/examples/button-outlined.component.ts": [ + { + "name": "Outlined", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-outlined.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с контуром без заливки.'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-outlined.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + } + ], + "src/stories/components/button/examples/button-rounded.component.ts": [ + { + "name": "Rounded", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-rounded.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Полностью скруглённая форма кнопки.'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-rounded.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + } + ], + "src/stories/components/button/examples/button-severity.component.ts": [ + { + "name": "Severity", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-severity.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Цветовые схемы для различных контекстов: success, info, warn, danger.'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-severity.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n \n success\n info\n warn\n danger\n\n small\n \n \n \n \n\n base\n \n \n \n \n\n large\n \n \n \n \n\n xlarge\n \n \n \n \n
\n
\n`" + } + ], + "src/stories/components/button/examples/button-sizes.component.ts": [ + { + "name": "Sizes", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-sizes.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Все доступные размеры: small, base, large, xlg.'\n }\n }\n }\n}" + }, + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-sizes.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + } + ], + "src/stories/components/button/examples/button-text.component.ts": [ + { + "name": "template", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-text.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + }, + { + "name": "Text", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-text.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка без заливки и границ, часто используется в тулбарах или списках.'\n }\n }\n }\n}" + } + ] + }, + "groupedFunctions": {}, + "groupedEnumerations": {}, + "groupedTypeAliases": { + "src/stories/components/button/examples/button-extra.component.ts": [ + { + "name": "ExtraButtonIconPos", + "ctype": "miscellaneous", + "subtype": "typealias", + "rawtype": "\"prefix\" | \"postfix\" | null", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "kind": 193 + }, + { + "name": "ExtraButtonSeverity", + "ctype": "miscellaneous", + "subtype": "typealias", + "rawtype": "\"success\" | \"warning\" | \"danger\" | \"info\" | null", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "kind": 193 + }, + { + "name": "ExtraButtonSize", + "ctype": "miscellaneous", + "subtype": "typealias", + "rawtype": "\"small\" | \"base\" | \"large\" | \"xlarge\"", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "kind": 193 + }, + { + "name": "ExtraButtonVariant", + "ctype": "miscellaneous", + "subtype": "typealias", + "rawtype": "\"primary\" | \"secondary\" | \"outlined\" | \"text\" | \"link\"", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "kind": 193 + } + ] + } + }, + "routes": { + "name": "", + "kind": "module", + "children": [] + }, + "coverage": { + "count": 0, + "status": "low", + "files": [ + { + "filePath": "src/stories/components/button/button.stories.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "meta", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-badge.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonBadgeComponent", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-badge.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Badge", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-badge.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-base.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonBaseComponent", + "coveragePercent": 0, + "coverageCount": "0/11", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-base.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Default", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-base.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-disabled.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonDisabledComponent", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-disabled.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Disabled", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-disabled.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-extra.component.ts", + "type": "component", + "linktype": "component", + "name": "ExtraButtonComponent", + "coveragePercent": 0, + "coverageCount": "0/11", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-extra.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Extra", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-extra.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-extra.component.ts", + "type": "type alias", + "linktype": "miscellaneous", + "linksubtype": "typealias", + "name": "ExtraButtonIconPos", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-extra.component.ts", + "type": "type alias", + "linktype": "miscellaneous", + "linksubtype": "typealias", + "name": "ExtraButtonSeverity", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-extra.component.ts", + "type": "type alias", + "linktype": "miscellaneous", + "linksubtype": "typealias", + "name": "ExtraButtonSize", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-extra.component.ts", + "type": "type alias", + "linktype": "miscellaneous", + "linksubtype": "typealias", + "name": "ExtraButtonVariant", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-icon-only.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonIconOnlyComponent", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-icon-only.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "IconOnly", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-icon-only.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-icon.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonIconComponent", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-icon.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Icons", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-icon.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-link.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonLinkComponent", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-link.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Link", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-link.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-loading.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonLoadingComponent", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-loading.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Loading", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-loading.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-outlined.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonOutlinedComponent", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-outlined.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Outlined", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-outlined.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-rounded.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonRoundedComponent", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-rounded.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Rounded", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-rounded.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-severity.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonSeverityComponent", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-severity.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Severity", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-severity.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-sizes.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonSizesComponent", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-sizes.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Sizes", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-sizes.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-text.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonTextComponent", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-text.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "template", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-text.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Text", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + } + ] + } +} \ No newline at end of file diff --git a/src/assets/fonts/tt-fellows/TT_Fellows_DemiBold.woff2 b/src/assets/fonts/tt-fellows/TT_Fellows_DemiBold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..ec6701528ffd4226e1d3a1492f231ea123c295d2 GIT binary patch literal 48592 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 literal 0 HcmV?d00001 diff --git a/src/assets/fonts/tt-fellows/TT_Fellows_Regular.woff2 b/src/assets/fonts/tt-fellows/TT_Fellows_Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..c4c67360f20d5bc4bd0575eda8355207add62d61 GIT binary patch literal 47760 zcmZ6yW2`Vd6D_)J+qP}nwr$(CZQHhO+xD|<@B4l?_s2PRlBSbM+RSR&WV&X?U0#d{ z01)6m=}G`V{BHt6JNZwi1^~p&{GavzFIYh~*g@$GI0sr_1^}^c5Wz5z`M`)UP{A(< z!IeaSY(ONyISkNoSO6ddpxOH1gJLj&TH1{liFI5iH(X$UPNYMq&a7LUTd$NMa6fmG z?g^Z)*$k*nr(+vfQf7X>?tKJyUm}##oc8-*On8OCQ`1P3?`5;dY_c+$jS|o zn(P|fZSRn>wxpU1A!QC`e#g$0D`u<&kx3d|37LMi?yJf{CMDEly~KKL!ZEgvImRi9 zTFru^zM*FHdR`Nj@vg)0w!aE07mvQU8|8~t2D?@o4OT|iBJC^;idXbf6+8_a!1r!r3!)^H6LK2<%l z)K2Dkv~5vP{KDs1e^3CGS$Izqq=c1X5M*KX~!5>|3&ipeS6)nvdZ_{efmupeq0Q#S=c;OAgru;&&=|!anA)*N=#WUDz7)VKTZcfA_VAZCh_>HmXhh+WU1W z-`@?h*ag(wwJ}|-jO;Xo2C)P1ah_l7_E)?aRb)Z&-_S&pT8<-M0N`)`RS}EDV@Qi3 z?KPs=d~Nfye`xC!9TqF4Xn~q4G+ObD@{A%s3-u-NIy|)0zhIx6Uidn1Wt{ix)P}|W z9le=Bc~J5wk*dJCT(#le#?zC!CACTF^6WSgyu%qd81LM}6AJuel}%1xLi7Wpl$^Vq zEhl<2UwQ7-Jg~MptJ+zM#B9HlLdT&e;dG@w7{RkxOg7O00LnK0gZsJwrd)JjmVjulv0*-NVs8pVE7rrFH&j?xUA{O(N58 zTDMLrc_Wv6B$cG^WsyuONhkTAo>bqSPA0izLcck^_uAIp8&U=Ac#emt0{l0v?AvB9 zNx+?dNRkO6a9lF|tjlBrl-g`(v&9;{fgkNy`=Hlkk9>zDQQ*gI%KmMoJr z8$Jv4w@Ymz{a#)|g(6L$nGfZk0Ms3sVG_7<739EMC||*?^~JaU?BdLNZ@@pa+e?2( z7a7}djUtJOD>)>h0pPGGdhiKE&Cr7bPfk54nM87jR+NdOsFzZ&ocq>R3OlDgiP;09 zup8pr4QZ%|fpm~DSB1b)Q$KCS7CC|QKo4HI@gr3m4g^J^v@B_5TK-US5<6kv%TH<} zJGDNX^Xl>;?!0LiZ~+xSJT0z3V033sh7myGeGB zP8ScXvF_MB^z5*!V%0@jNO~9;Ay;fZx}glXz{-E#Kvnb`c*S zo`y{C;PsE``giXKjnZ2r2L+=EiXs5~v-)99scqgb;Lv^h-x6KaFfRZJ97WIyb8Pqy zZ#x>v-td4jOj0laaL*0!`*~rP`7!j;Ci3i!l=|=WWFD@80EP#K0kVw{}znNBWae{qm#=$Sw;2#j+NWx7RpBmd zVw7~u^n<{fh&Yu1uC?&@lehCLEY&}XAqUeFbfkYuTauP^no*~V=qf6e&_e2_#Kehs zp{l9=6_3wFHI8~_-!QWfJfBW>-ZhQRL-RTP<6$nW}7&J<^ z|Mr=ieczJ#I&q^JJ1mdFEJ&t|bfk1OqE|2`f9P2+Yt6C_i!CVTk;s5+u?e}c|)F_Hq+IlU^=L}Lbj0m6o*;?J$ISH;KqQVM#rImFTeQHUp z)r>hGr?4aU!))=MG_Zjr7nRk-a2et~hp~+|#Zd-sGq{dk_gX8n{&l5LZao6@)oV7R zjZ;XG%Uv^I|O!*}uI*JNGAd$GhOHTpZ88(^u?gsd^ldN)7 z7}t4ys)dBCSZ$6thDA>}i2d;12KTSaLLb;@!X-{3Koo+GDf0c=<$UYS9$+ea(Yon4 zoh|H}P)LACEOFLQhE_|Sv+R=40Y*t-H10iD^y$aGj4H4cyGTNMdm_-m4u8N9Bgc+V zysz%jXz~Wpdp*sxQq2#vl3-)KVs%)U(gfEB4yqAar}rGC)_baZ^S#kFel?KqiT3~? z(u3d!jLon(DoLy9J?dKDeNN*pn`BUKi|2WWOz(Rf;{i>3MTJ681&!E4tw=5!G_!5< zq=(hz3WL#g`}Y!U|M~_D5)lR!^SR#fH`8UdeB&|i8v%%RPylc^;^m0OAWg#S1q!7s zm8v!Vc?=TK+K+%FCoLENAhER12DDaZr&dmVn2)uSIz&&_Cp8A@u&HwJLNt^Ty$u|p zi=#gfGo6lB!UxZ+pnvR|zAv57X(NX>n+`sWpN(&w z*G?_oUxOz1hp_ItsJ{70e~SCEN0~4ulu8#A|NjXQWrL2FsIsdumj6Gts?oi#`1C(0x>x-R@ zGd1cv2nwZvA)L-VK>!AMVGtVGM&JM}Jo~NhIyjA_b`=y!xL6L1r<6)T#*UBqiC+|@J&Hy#+6__H z3l@W!+D=zrt$V=Iiu@Imsz~a&(1AwqNU}kZBK#!x$f6*Y1@vAU>t2%1*iP-7IlNtv;S6 zDGUsiRzk+U%+r&a#OCWJY-P>y#s@7Q1>z(t&~fRim=*Ck^?QjCe*mu;uQZ{*3j-x^ zi@{OFFRWHL;7Eu<;~uyE9C_sXiNr)|F%ePxSgT%Fba5_v8stg&-6yI*v?N6cV7e9< zV|&W?wJY`Wx$*UiQDsR|>Vpz+%q{?H?y;v~EoWoi?q+U&5AfEhgx4wK>67YUnr5hs z=r>Sf3dGo|Oqr(eR4D}9ETdd?2NWINX#MRZje1Wcyw7nvnruSITRMqe>H6M8BDH)U zP$=s%huLgqyTM|TDYaUyX8U2ktajVY%I)h)^Q%u9I$T>{UGOtQkP(OClAkfu0*rPl zEdd1yPh8FHwmcG8hQ=c*MNLs_I{O`8%Q+OmPzY0O_i>%~tv7{AHBO!YNg|~RRxV+h zgu2;kg=)E8u$XLCtHr9?jjpn^wzzsde8lIE!_m^g$h!{2Ay+T=@?Ms!S6*N-VGEcZ z)1CSbe+}f0lxNya3p9%O7Os1wf}G~rsozYe=26wzK}JpzbNXXf&oT4+Sp7SB07&8i zCn2THW;*!{2;Bb(sy_C4zl?UazZg<>^R74Q{zhDrbNYHHH;^`5hOiWHsP*GA- zR8>}2svWJZEdO0xnaY%{nw{^|r1#~R{___93^NRHY1Vvau>nZ4xp$yUHtq`B1)(oE zx4>rrfJw^AC8S19g7htK48hO6uvH-ka6lvxrAnq&%3Fm1u!?PSMV1>MPqHyM9T+4g zAR?Uh6>4-eOCpg>vT+(S!@KjnUnI|0Wp-YXTHh%xD=ampAchVyY8tg1K#I*`v0ki_ z^`<3#ynlrKp%y?vK~l@4imnmQ^#FTv>LA9sq!8!+UC*0<3z8$_gZmD#|M{If#dlu+ zUihMAKIbc)^HI^;_k2Zu?wQu59MNOcYN;0 z#ldl$-+zqv|2g+BX4|kxo^9K((ze~-Ff7*{+qzW*fIvV&$FSo$@Q{X4<8*+C_=lp6 z8;FV9h+$wfsb0X)vtI;@+x47NFdsljJa+CmY-#Jf$(zY42o1U3GIA5kCauv32ZI9( zIKwbukAEEs#|I;E<{ntQhBhOwMcISw&$UQ9p)17pH|d*i8nEr^2f?2A+ax1Rm>3+0 znm_^+EMmAZ)d}kfX1uG>u@RDkiha(=|jSfSjT`=bXD%02vTOAXUNZH*GkqV6d9TT8IqLH}n49OVe zm=FQA6)K7NQTHzs^D%{31AF08BgHb?^8E1lk~5HQpt*;iV6TLhniSvl5xmsc6#dTu zo7PI}{eO;b#tWk&-!T1c~!0?yCHk zGY!^HCiGx9LYjvpxHA0#5dalqnHQk%lpFc@z?*0h_MIcu(2TqFQo1(NR}qH#y~Mo zAj(iT6pC>s@1aUr�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%0AL!1b9~eH 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 + ` +}) +export class ExtraButtonComponent { + @Input() label = 'Button'; + @Input() variant: ExtraButtonVariant = 'primary'; + @Input() severity: ExtraButtonSeverity = null; + @Input() size: ExtraButtonSize = 'base'; + @Input() rounded = false; + @Input() iconPos: ExtraButtonIconPos = null; + @Input() iconOnly = false; + @Input() icon = ''; + @Input() disabled = false; + @Input() loading = false; + + 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(): string | null { + if (this.variant === 'secondary') return 'secondary'; + if (this.severity === 'warning') return 'warn'; + return this.severity; + } +} diff --git a/src/components/button/button.component.html b/src/components/button/button.component.html index 4a13bbdc..b6a3c33f 100644 --- a/src/components/button/button.component.html +++ b/src/components/button/button.component.html @@ -1,3 +1,3 @@ - + diff --git a/src/components/button/button.component.ts b/src/components/button/button.component.ts index 8909500c..c5454f2f 100644 --- a/src/components/button/button.component.ts +++ b/src/components/button/button.component.ts @@ -22,9 +22,7 @@ export class ButtonComponent { @Input() text: boolean = false; - private innerSize: 'small' | undefined | 'large'; - - constructor() { - this.innerSize = this.size === 'xlarge' ? undefined : this.size; + get innerSize(): 'small' | undefined | 'large' { + return (this.size === 'xlarge' || !this.size) ? undefined : (this.size as 'small' | 'large'); } } diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 62ebcb4e..5cb63458 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -1,45 +1,15 @@ import { Preset } from '@primeuix/themes/types'; +import type { ComponentsDesignTokens } from '@primeuix/themes/types'; import type { AuraBaseDesignTokens } from '@primeuix/themes/aura/base'; -import primitive from './tokens/primitive-default.json'; -import semantic from './tokens/semantic-default.json'; -import components from './tokens/components-default.json'; -import themeLight from './tokens/theme-light.json'; -import themeDark from './tokens/theme-dark.json'; -import sizingBase from './tokens/sizing-base.json'; -import sizingSm from './tokens/sizing-sm.json'; -import sizingLg from './tokens/sizing-lg.json'; -import sizingXlg from './tokens/sizing-xlg.json'; - -import button from './tokens/components/button.json'; +import primitive from './tokens/primitive'; +import semantic from './tokens/semantic'; +import components from './tokens/components'; const presetTokens: Preset = { - primitive, - semantic, - components: { ...components, ...button } + primitive: primitive as AuraBaseDesignTokens['primitive'], + semantic: semantic as unknown as AuraBaseDesignTokens['semantic'], + components: components as ComponentsDesignTokens }; -if (presetTokens?.semantic) { - presetTokens.semantic.colorScheme = { - light: themeLight, - dark: themeDark - }; -} - -presetTokens.semantic = { ...presetTokens.semantic, ...sizingBase }; - -const semanticLink: Record = presetTokens.semantic; - -function applySizing(semantic: Record, sizing: Record, sizeKey: 'sm' | 'lg' | 'xlg') { - Object.keys(sizing).forEach((key) => { - if (semantic[key]) { - semantic[key][sizeKey] = sizing[key]?.root ?? sizing[key]; - } - }); -} - -applySizing(semanticLink, sizingSm, 'sm'); -applySizing(semanticLink, sizingLg, 'lg'); -applySizing(semanticLink, sizingXlg, 'xlg'); - export default presetTokens; diff --git a/src/prime-preset/tokens/components-default.json b/src/prime-preset/tokens/components-default.json deleted file mode 100644 index 5d8c8cee..00000000 --- a/src/prime-preset/tokens/components-default.json +++ /dev/null @@ -1,3362 +0,0 @@ -{ - "accordion": { - "header": { - "color": "{text.color}", - "hoverColor": "{text.hoverColor}", - "activeColor": "{text.color}", - "activeHoverColor": "{text.hoverColor}", - "borderColor": "{transparent}", - "padding": "1rem 0 1rem 0", - "fontWeight": "{fonts.fontWeight.bold}", - "borderRadius": "0", - "borderWidth": "0 0 0 0", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "inset {focus.ring.shadow}" - }, - "toggleIcon": { - "color": "{text.color}", - "hoverColor": "{text.hoverColor}", - "activeColor": "{text.color}", - "activeHoverColor": "{text.hoverColor}" - }, - "last": { - "bottomBorderRadius": "{content.borderRadius}", - "activeBottomBorderRadius": "0" - }, - "first": { - "borderWidth": "0", - "topBorderRadius": "{content.borderRadius}" - } - }, - "root": { - "transitionDuration": "{formField.transitionDuration}" - }, - "panel": { - "borderWidth": "0.0625rem", - "borderColor": "{formField.borderColor}" - }, - "colorScheme": { - "light": { - "header": { - "background": "{transparent}", - "hoverBackground": "{transparent}", - "activeBackground": "{transparent}", - "activeHoverBackground": "{transparent}" - } - } - }, - "content": { - "borderWidth": "1px 0 0 0", - "borderColor": "{transparent}", - "background": "{transparent}", - "color": "{text.color}", - "padding": "0 0 1rem 1.75rem" - } - }, - "autocomplete": { - "colorScheme": { - "light": { - "chip": { - "focusBackground": "{chip.colorScheme.light.root.background}", - "focusColor": "{chip.colorScheme.light.root.color}" - }, - "dropdown": { - "background": "{formField.background}", - "hoverBackground": "{formField.background}", - "activeBackground": "{formField.background}", - "color": "{formField.color}", - "hoverColor": "{formField.color}", - "activeColor": "{formField.color}" - } - } - }, - "extend": { - "extOption": { - "gap": "0.4375rem" - }, - "extOptionGroup": { - "gap": "0.4375rem" - } - }, - "root": { - "background": "{formField.background}", - "disabledBackground": "{formField.disabledBackground}", - "filledBackground": "{formField.filledBackground}", - "filledHoverBackground": "{formField.filledHoverBackground}", - "filledFocusBackground": "{formField.filledFocusBackground}", - "borderColor": "{formField.borderColor}", - "hoverBorderColor": "{formField.hoverBorderSecondaryColor}", - "focusBorderColor": "{formField.focusBorderSecondaryColor}", - "invalidBorderColor": "{formField.invalidBorderColor}", - "color": "{formField.color}", - "disabledColor": "{formField.disabledColor}", - "placeholderColor": "{formField.placeholderColor}", - "invalidPlaceholderColor": "{formField.invalidPlaceholderColor}", - "shadow": "{formField.shadow}", - "paddingX": "{formField.paddingX}", - "paddingY": "{formField.paddingY}", - "borderRadius": "{formField.borderRadius}", - "transitionDuration": "{formField.transitionDuration}" - }, - "overlay": { - "background": "{overlay.select.background}", - "borderColor": "{overlay.select.borderColor}", - "borderRadius": "{overlay.select.borderRadius}", - "color": "{overlay.select.color}", - "shadow": "{overlay.select.shadow}" - }, - "list": { - "padding": "{list.padding}", - "gap": "{list.gap}" - }, - "option": { - "focusBackground": "{list.option.focusBackground}", - "selectedBackground": "{list.option.selectedBackground}", - "selectedFocusBackground": "{list.option.selectedFocusBackground}", - "color": "{list.option.color}", - "focusColor": "{list.option.focusColor}", - "selectedColor": "{list.option.selectedColor}", - "selectedFocusColor": "{list.option.selectedFocusColor}", - "padding": "{list.option.padding}", - "borderRadius": "{list.option.borderRadius}" - }, - "optionGroup": { - "background": "{list.optionGroup.background}", - "color": "{list.optionGroup.color}", - "fontWeight": "{fonts.fontWeight.demibold}", - "padding": "{list.optionGroup.padding}" - }, - "dropdown": { - "width": "100%", - "borderColor": "{formField.borderColor}", - "hoverBorderColor": "{formField.hoverBorderSecondaryColor}", - "activeBorderColor": "{formField.focusBorderSecondaryColor}", - "borderRadius": "{formField.borderRadius}", - "focusRing": { - "width": "{focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{formField.focusRing.color}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.focusRing.shadow}" - }, - "sm": { - "width": "1.75rem" - }, - "lg": { - "width": "2.625rem" - } - }, - "chip": { - "borderRadius": "{chip.root.borderRadius}" - }, - "emptyMessage": { - "padding": "{list.option.padding}" - } - }, - "avatar": { - "extend": { - "borderColor": "{formField.borderColor}" - }, - "root": { - "width": "1.75rem", - "height": "1.75rem", - "fontSize": "{fonts.fontSize.base}", - "color": "{text.extend.colorPrimaryStatic}", - "background": "{primary.color}", - "borderRadius": "{borderRadius.md}" - }, - "icon": { - "size": "0.875rem" - }, - "group": { - "borderColor": "{content.background}", - "offset": "-0.75rem" - }, - "lg": { - "width": "2.1875rem", - "height": "2.1875rem", - "fontSize": "{fonts.fontSize.base}", - "icon": { - "size": "0.875rem" - }, - "group": { - "offset": "-1rem" - } - }, - "xl": { - "width": "3.0625rem", - "height": "3.0625rem", - "icon": { - "size": "1.3125rem" - }, - "group": { - "offset": "-1.5rem" - }, - "fontSize": "{fonts.fontSize.base}" - } - }, - "badge": { - "colorScheme": { - "light": { - "primary": { - "color": "{text.extend.colorPrimaryStatic}", - "background": "{primary.color}" - }, - "secondary": { - "color": "{text.extend.colorInverted}", - "background": "{surface.900}" - }, - "success": { - "color": "{success.900}", - "background": "{success.300}" - }, - "info": { - "color": "{info.900}", - "background": "{info.300}" - }, - "warn": { - "color": "{warn.900}", - "background": "{warn.300}" - }, - "danger": { - "color": "{error.900}", - "background": "{error.300}" - } - } - }, - "extend": { - "extDot": { - "success": { - "background": "{colors.solid.green.400}" - }, - "info": { - "background": "{info.400}" - }, - "warn": { - "background": "{warn.400}" - }, - "danger": { - "background": "{error.400}" - }, - "lg": { - "size": "0.65625rem" - }, - "xlg": { - "size": "0.875rem" - } - } - }, - "root": { - "borderRadius": "{borderRadius.xl}", - "padding": "0.46875rem", - "fontSize": "{fonts.fontSize.xs}", - "fontWeight": "{fonts.fontWeight.regular}", - "minWidth": "1.3125rem", - "height": "1.3125rem" - }, - "dot": { - "size": "0.4375rem" - }, - "sm": { - "fontSize": "{fonts.fontSize.xs}", - "minWidth": "0", - "height": "0" - }, - "lg": { - "fontSize": "{fonts.fontSize.xs}", - "minWidth": "1.53125rem", - "height": "1.53125rem" - }, - "xl": { - "fontSize": "{fonts.fontSize.xs}", - "minWidth": "1.75rem", - "height": "1.75rem" - } - }, - "breadcrumb": { - "extend": { - "hoverBackground": "{surface.100}" - }, - "root": { - "padding": "0.21875rem", - "background": "{transparent}", - "gap": "0", - "transitionDuration": "{formField.transitionDuration}" - }, - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - }, - "item": { - "color": "{text.color}", - "hoverColor": "{text.hoverColor}", - "borderRadius": "{borderRadius.xs}", - "gap": "{navigation.item.gap}", - "icon": { - "color": "{text.color}", - "hoverColor": "{text.hoverColor}" - } - }, - "separator": { - "color": "{text.color}" - } - }, - "button": { - "extend": { - "disabledBackground": "{formField.disabledBackground}", - "extOutlined": { - "danger": { - "focusBackground": "{transparent}" - }, - "warn": { - "focusBackground": "{transparent}" - }, - "info": { - "focusBackground": "{transparent}" - }, - "help": { - "focusBackground": "{transparent}" - }, - "success": { - "focusBackground": "{transparent}" - } - }, - "disabledColor": "{formField.disabledColor}", - "extText": { - "danger": { - "focusBackground": "{transparent}" - }, - "warn": { - "focusBackground": "{transparent}" - }, - "info": { - "focusBackground": "{transparent}" - }, - "help": { - "focusBackground": "{transparent}" - }, - "success": { - "focusBackground": "{transparent}" - } - }, - "extLink": { - "background": "{transparent}", - "colorHover": "{text.hoverColor}", - "paddingX": "0", - "paddingY": "0.21875rem", - "sm": { - "iconOnlyWidth": "0.875rem" - }, - "base": { - "iconOnlyWidth": "1.34375rem" - }, - "lg": { - "iconOnlyWidth": "1.53125rem" - }, - "xlg": { - "iconOnlyWidth": "1.75rem" - } - }, - "extSm": { - "borderRadius": "{borderRadius.md}", - "gap": "0.4375rem" - }, - "extLg": { - "borderRadius": "{borderRadius.lg}", - "gap": "0.65625rem" - }, - "extXlg": { - "borderRadius": "{borderRadius.lg}", - "gap": "0.65625rem", - "iconOnlyWidth": "3.5625rem", - "paddingX": "1.3125rem", - "paddingY": "1.09375rem" - }, - "borderWidth": "0.0625rem" - }, - "colorScheme": { - "light": { - "root": { - "primary": { - "background": "{primary.color}", - "hoverBackground": "{primary.hoverColor}", - "activeBackground": "{primary.color}", - "borderColor": "{transparent}", - "hoverBorderColor": "{transparent}", - "activeBorderColor": "{transparent}", - "color": "{text.extend.colorPrimaryStatic}", - "hoverColor": "{text.extend.colorPrimaryStatic}", - "activeColor": "{text.extend.colorPrimaryStatic}", - "focusRing": { - "color": "{primary.200}", - "shadow": "{focusRing.shadow}" - } - }, - "secondary": { - "background": "{surface.900}", - "hoverBackground": "{surface.800}", - "activeBackground": "{surface.900}", - "borderColor": "{transparent}", - "hoverBorderColor": "{transparent}", - "activeBorderColor": "{transparent}", - "color": "{text.extend.colorInverted}", - "hoverColor": "{text.extend.colorInverted}", - "activeColor": "{text.extend.colorInverted}", - "focusRing": { - "color": "{primary.200}", - "shadow": "{focusRing.shadow}" - } - }, - "contrast": { - "background": "{surface.200}", - "hoverBackground": "{surface.300}", - "activeBackground": "{surface.200}", - "borderColor": "{transparent}", - "hoverBorderColor": "{transparent}", - "activeBorderColor": "{transparent}", - "color": "{text.color}", - "hoverColor": "{text.color}", - "activeColor": "{text.color}", - "focusRing": { - "color": "{primary.200}", - "shadow": "{focusRing.shadow}" - } - }, - "info": { - "background": "{info.300}", - "hoverBackground": "{info.400}", - "activeBackground": "{info.300}", - "borderColor": "{transparent}", - "hoverBorderColor": "{transparent}", - "activeBorderColor": "{transparent}", - "color": "{info.900}", - "hoverColor": "{info.950}", - "activeColor": "{info.900}" - }, - "success": { - "background": "{success.300}", - "hoverBackground": "{success.400}", - "activeBackground": "{success.300}", - "borderColor": "{transparent}", - "hoverBorderColor": "{transparent}", - "activeBorderColor": "{transparent}", - "color": "{success.900}", - "hoverColor": "{success.950}", - "activeColor": "{success.900}" - }, - "warn": { - "background": "{warn.300}", - "hoverBackground": "{warn.400}", - "activeBackground": "{warn.300}", - "borderColor": "{transparent}", - "hoverBorderColor": "{transparent}", - "activeBorderColor": "{transparent}", - "color": "{warn.900}", - "hoverColor": "{warn.950}", - "activeColor": "{warn.900}" - }, - "help": { - "background": "{help.300}", - "hoverBackground": "{help.400}", - "activeBackground": "{help.300}", - "borderColor": "{transparent}", - "hoverBorderColor": "{transparent}", - "activeBorderColor": "{transparent}", - "color": "{help.900}", - "hoverColor": "{help.950}", - "activeColor": "{help.900}" - }, - "danger": { - "background": "{error.300}", - "hoverBackground": "{error.400}", - "activeBackground": "{error.300}", - "borderColor": "{transparent}", - "hoverBorderColor": "{transparent}", - "activeBorderColor": "{transparent}", - "color": "{error.900}", - "hoverColor": "{error.950}", - "activeColor": "{error.900}" - } - }, - "outlined": { - "primary": { - "hoverBackground": "{primary.50}", - "activeBackground": "{primary.100}", - "borderColor": "{primary.200}", - "color": "{colors.solid.green.500}" - }, - "success": { - "hoverBackground": "{success.100}", - "activeBackground": "{transparent}", - "borderColor": "{success.600}", - "color": "{success.600}" - }, - "info": { - "hoverBackground": "{info.100}", - "activeBackground": "{transparent}", - "borderColor": "{info.600}", - "color": "{info.600}" - }, - "warn": { - "hoverBackground": "{warn.100}", - "activeBackground": "{transparent}", - "borderColor": "{warn.600}", - "color": "{warn.600}" - }, - "help": { - "hoverBackground": "{help.100}", - "activeBackground": "{transparent}", - "borderColor": "{help.600}", - "color": "{help.600}" - }, - "danger": { - "hoverBackground": "{error.100}", - "activeBackground": "{transparent}", - "borderColor": "{error.600}", - "color": "{error.600}" - } - }, - "text": { - "primary": { - "hoverBackground": "{surface.100}", - "activeBackground": "{transparent}", - "color": "{text.color}" - }, - "success": { - "hoverBackground": "{success.100}", - "activeBackground": "{transparent}", - "color": "{success.600}" - }, - "info": { - "hoverBackground": "{info.100}", - "activeBackground": "{transparent}", - "color": "{info.600}" - }, - "warn": { - "hoverBackground": "{warn.100}", - "activeBackground": "{transparent}", - "color": "{warn.600}" - }, - "help": { - "hoverBackground": "{help.100}", - "activeBackground": "{transparent}", - "color": "{help.600}" - }, - "danger": { - "hoverBackground": "{error.100}", - "activeBackground": "{transparent}", - "color": "{error.600}" - } - }, - "link": { - "color": "{text.color}", - "hoverColor": "{text.hoverColor}", - "activeColor": "{text.color}" - } - } - }, - "root": { - "borderRadius": "{borderRadius.md}", - "roundedBorderRadius": "1.75rem", - "gap": "0.4375rem", - "paddingX": "0.875rem", - "paddingY": "0.4375rem", - "iconOnlyWidth": "2.1875rem", - "raisedShadow": "0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12)", - "badgeSize": "1rem", - "transitionDuration": "{formField.transitionDuration}", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "offset": "{focusRing.offset}" - }, - "sm": { - "fontSize": "{fonts.fontSize.sm}", - "iconOnlyWidth": "1.75rem", - "paddingX": "0.65625rem", - "paddingY": "0.4375rem" - }, - "lg": { - "fontSize": "{fonts.fontSize.xl}", - "iconOnlyWidth": "3.125rem", - "paddingX": "1.3125rem", - "paddingY": "0.875rem" - }, - "label": { - "fontWeight": "{fonts.fontWeight.demibold}" - } - } - }, - "card": { - "extend": { - "borderColor": "{content.borderColor}" - }, - "root": { - "background": "{content.background}", - "borderRadius": "{borderRadius.lg}", - "color": "{content.color}", - "shadow": "0 .125rem .25rem rgba(0,0,0,.075)" - }, - "body": { - "padding": "0.875rem", - "gap": "0.875rem" - }, - "caption": { - "gap": "0.21875rem" - }, - "title": { - "fontSize": "{fonts.fontSize.lg}", - "fontWeight": "{fonts.fontWeight.demibold}" - }, - "subtitle": { - "color": "{text.mutedColor}" - } - }, - "carousel": { - "colorScheme": { - "light": { - "indicator": { - "background": "{surface.300}", - "hoverBackground": "{surface.400}", - "activeBackground": "{surface.900}" - } - } - }, - "root": { - "transitionDuration": "{transitionDuration}" - }, - "content": { - "gap": "0.4375rem" - }, - "indicatorList": { - "padding": "0.875rem", - "gap": "0.4375rem" - }, - "indicator": { - "width": "0.4375rem", - "height": "0.4375rem", - "borderRadius": "{borderRadius.xl}", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{rating.focusRing.shadow}" - } - } - }, - "checkbox": { - "root": { - "borderRadius": "{borderRadius.sm}", - "extend": { - "borderWidth": "0.0625rem" - }, - "width": "1.3125rem", - "height": "1.3125rem", - "background": "{formField.background}", - "checkedBackground": "{surface.900}", - "checkedHoverBackground": "{surface.800}", - "disabledBackground": "{formField.disabledBackground}", - "filledBackground": "{formField.filledBackground}", - "borderColor": "{formField.borderColor}", - "hoverBorderColor": "{formField.hoverBorderPrimaryColor}", - "focusBorderColor": "{formField.focusBorderPrimaryColor}", - "checkedBorderColor": "{surface.900}", - "checkedHoverBorderColor": "{surface.800}", - "checkedFocusBorderColor": "{primary.color}", - "checkedDisabledBorderColor": "{formField.borderColor}", - "invalidBorderColor": "{formField.invalidBorderColor}", - "shadow": "{formField.shadow}", - "focusRing": { - "focusRing": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - }, - "sm": { - "width": "0.875rem", - "height": "0.875rem" - }, - "lg": { - "width": "1.09375rem", - "height": "1.09375rem" - }, - "transitionDuration": "{formField.transitionDuration}" - }, - "icon": { - "size": "0.875rem", - "color": "{formField.color}", - "checkedColor": "{primary.contrastColor}", - "checkedHoverColor": "{primary.contrastColor}", - "disabledColor": "{formField.disabledColor}", - "sm": { - "size": "0.65625rem" - }, - "lg": { - "size": "1.09375rem" - } - } - }, - "chip": { - "extend": { - "borderColor": "{transparent}" - }, - "root": { - "borderRadius": "{borderRadius.sm}", - "paddingX": "0.4375rem", - "paddingY": "0.21875rem", - "gap": "0.4375rem", - "transitionDuration": "{formField.transitionDuration}" - }, - "colorScheme": { - "light": { - "root": { - "background": "{surface.200}", - "color": "{text.color}" - }, - "icon": { - "color": "{text.color}" - }, - "removeIcon": { - "color": "{text.color}" - } - } - }, - "image": { - "width": "0", - "height": "0" - }, - "icon": { - "size": "0.875rem" - }, - "removeIcon": { - "size": "0.875rem", - "focusRing": { - "width": "{formField.focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{primary.200}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.focusRing.shadow}" - } - } - }, - "confirmdialog": { - "extend": { - "extIcon": { - "success": "{success.500}", - "info": "{info.500}", - "help": "{help.500}", - "warn": "{warn.500}", - "danger": "{error.500}" - } - }, - "icon": { - "size": "1.3125rem", - "color": "{overlay.modal.color}" - }, - "content": { - "gap": "0" - } - }, - "confirmpopup": { - "root": { - "background": "{overlay.popover.background}", - "color": "{overlay.popover.color}", - "shadow": "{overlay.popover.shadow}", - "gutter": "10px", - "arrowOffset": "1.25rem" - }, - "content": { - "padding": "{overlay.popover.padding}", - "gap": "1rem" - }, - "icon": { - "size": "1.5rem", - "color": "{overlay.popover.color}" - }, - "footer": { - "gap": "0.5rem", - "padding": "0 {overlay.popover.padding} {overlay.popover.padding} {overlay.popover.padding}" - } - }, - "contextmenu": { - "root": { - "background": "{content.background}", - "color": "{content.color}", - "shadow": "{overlay.navigation.shadow}" - }, - "list": { - "padding": "{navigation.list.padding}", - "gap": "{navigation.list.gap}" - }, - "item": { - "padding": "{navigation.item.padding}", - "gap": "{navigation.item.gap}" - }, - "submenu": { - "mobileIndent": "1.25rem" - } - }, - "datatable": { - "colorScheme": { - "light": { - "root": { - "color": "{text.color}", - "borderColor": "{content.borderColor}" - }, - "header": { - "background": "{surface.50}", - "color": "{text.color}" - }, - "headerCell": { - "background": "{surface.50}", - "hoverBackground": "{surface.100}", - "color": "{text.color}" - }, - "footer": { - "background": "{surface.100}", - "color": "{text.color}" - }, - "footerCell": { - "background": "{content.hoverBackground}", - "color": "{text.color}" - }, - "row": { - "stripedBackground": "{content.hoverBackground}" - }, - "bodyCell": { - "selectedBorderColor": "{content.borderColor}" - } - } - }, - "extended": { - "extHeaderCell": { - "selectedHoverBackground": "{surface.800}" - }, - "extRow": { - "selectedHoverBackground": "{surface.800}", - "stripedHoverBackground": "{surface.100}" - } - }, - "root": { - "transitionDuration": "{transitionDuration}" - }, - "header": { - "borderColor": "{content.borderColor}", - "borderWidth": "1px 0 1px 0", - "padding": "0.875rem", - "sm": { - "padding": "0.4375rem" - }, - "lg": { - "padding": "1.09375rem" - } - }, - "headerCell": { - "selectedBackground": "{highlight.background}", - "borderColor": "{content.borderColor}", - "hoverColor": "{text.hoverColor}", - "selectedColor": "{highlight.color}", - "gap": "0.4375rem", - "padding": "0.875rem", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "inset {focus.ring.shadow}" - }, - "sm": { - "padding": "0.4375rem" - }, - "lg": { - "padding": "1.09375rem" - } - }, - "columnTitle": { - "fontWeight": "{fonts.fontWeight.bold}" - }, - "row": { - "background": "{content.background}", - "hoverBackground": "{content.hoverBackground}", - "selectedBackground": "{highlight.background}", - "color": "{content.color}", - "hoverColor": "{content.hoverColor}", - "selectedColor": "{highlight.color}", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "inset {focus.ring.shadow}" - } - }, - "bodyCell": { - "borderColor": "{content.borderColor}", - "padding": "0.875rem", - "sm": { - "padding": "0.4375rem" - }, - "lg": { - "padding": "1.09375rem" - } - }, - "footerCell": { - "borderColor": "{content.borderColor}", - "padding": "0.875rem", - "sm": { - "padding": "0.4375rem" - }, - "lg": { - "padding": "1.09375rem" - } - }, - "columnFooter": { - "fontWeight": "{fonts.fontWeight.bold}" - }, - "dropPoint": { - "color": "{highlight.background}" - }, - "footer": { - "borderColor": "{content.borderColor}", - "borderWidth": "0 0 1px 0", - "padding": "1rem", - "sm": { - "padding": "0.5rem" - }, - "lg": { - "padding": "1.25rem" - } - }, - "columnResizer": { - "width": "0.4375rem" - }, - "resizeIndicator": { - "width": "1px", - "color": "{highlight.background}" - }, - "sortIcon": { - "color": "{text.color}", - "hoverColor": "{text.hoverColor}", - "size": "0.875rem" - }, - "loadingIcon": { - "size": "1.75rem" - }, - "rowToggleButton": { - "hoverBackground": "{content.hoverBackground}", - "selectedHoverBackground": "{content.hoverBackground}", - "color": "{text.color}", - "hoverColor": "{text.color}", - "selectedHoverColor": "{text.color}", - "size": "1.75rem", - "borderRadius": "{content.borderRadius}", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - }, - "filter": { - "inlineGap": "0.4375rem", - "rule": { - "borderColor": "{content.borderColor}" - }, - "constraintList": { - "padding": "{list.padding}", - "gap": "{list.gap}" - }, - "constraint": { - "focusBackground": "{list.option.focusBackground}", - "selectedBackground": "{list.option.selectedBackground}", - "selectedFocusBackground": "{list.option.selectedFocusBackground}", - "color": "{list.option.color}", - "focusColor": "{list.option.focusColor}", - "selectedColor": "{list.option.selectedColor}", - "selectedFocusColor": "{list.option.selectedFocusColor}", - "padding": "{list.option.padding}", - "borderRadius": "{list.option.borderRadius}", - "separator": { - "borderColor": "{content.borderColor}" - } - }, - "overlaySelect": { - "background": "{overlay.select.background}", - "color": "{overlay.select.color}", - "borderColor": "{overlay.select.borderColor}", - "borderRadius": "{overlay.select.borderRadius}", - "shadow": "{overlay.select.shadow}" - }, - "overlayPopover": { - "background": "{overlay.popover.background}", - "color": "{overlay.popover.color}", - "borderColor": "{overlay.select.borderColor}", - "borderRadius": "{overlay.select.borderRadius}", - "shadow": "{overlay.popover.shadow}", - "padding": "{overlay.popover.padding}", - "gap": "{list.gap}" - } - }, - "paginatorTop": { - "borderColor": "{formField.borderColor}", - "borderWidth": "0 0 1px 0" - }, - "paginatorBottom": { - "borderWidth": "0 0 1px 0", - "borderColor": "{content.borderColor}" - } - }, - "dataview": { - "root": { - "borderWidth": "1px", - "borderRadius": "4px", - "padding": "0", - "borderColor": "#ffffff" - }, - "header": { - "borderWidth": "0 0 1px 0", - "padding": "0.875rem 1.125rem", - "borderRadius": "5px 5px 0 0", - "color": "{text.color}" - }, - "content": { - "background": "{content.background}", - "color": "{content.color}", - "borderColor": "#ffffff", - "borderWidth": "0", - "padding": "0", - "borderRadius": "5px" - }, - "footer": { - "background": "{content.background}", - "color": "{content.color}", - "borderWidth": "1px 0 0 0", - "padding": "0.875rem 1.125rem", - "borderRadius": "0 0 5px 5px" - }, - "paginatorTop": { - "borderWidth": "0 0 1px 0" - }, - "paginatorBottom": { - "borderWidth": "1px 0 0 0" - } - }, - "datepicker": { - "colorScheme": { - "light": { - "dropdown": { - "background": "{content.background}", - "hoverBackground": "{navigation.item.focusBackground}", - "activeBackground": "{navigation.item.activeBackground}", - "color": "{navigation.item.color}", - "hoverColor": "{navigation.item.focusColor}", - "activeColor": "{navigation.item.activeColor}" - }, - "today": { - "background": "{content.background}", - "color": "{text.color}" - } - } - }, - "extend": { - "extDate": { - "selectedHoverBackground": "{primary.600}" - }, - "extToday": { - "borderColor": "{content.borderColor}", - "hoverBackground": "{content.hoverBackground}" - }, - "extTimePicker": { - "minWidth": "2.5rem", - "color": "{content.color}" - }, - "extTitle": { - "width": "13.125rem" - } - }, - "panel": { - "background": "{content.background}", - "borderColor": "{content.borderColor}", - "color": "{content.color}", - "borderRadius": "{content.borderRadius}", - "shadow": "{overlay.popover.shadow}", - "padding": "{overlay.popover.padding}" - }, - "header": { - "background": "{content.background}", - "borderColor": "{content.borderColor}", - "color": "{content.color}", - "padding": "0 0 0.5rem 0" - }, - "title": { - "gap": "0.4375rem", - "fontWeight": "{fonts.fontWeight.bold}" - }, - "selectMonth": { - "hoverBackground": "{content.hoverBackground}", - "color": "{content.color}", - "hoverColor": "{content.hoverColor}", - "borderRadius": "{content.borderRadius}", - "padding": "0.375rem 0.625rem" - }, - "dropdown": { - "width": "2.5rem", - "borderColor": "{formField.borderColor}", - "hoverBorderColor": "{formField.borderColor}", - "activeBorderColor": "{formField.borderColor}", - "borderRadius": "{formField.borderRadius}", - "focusRing": { - "width": "{formField.focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{formField.focusRing.color}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.shadow}" - }, - "sm": { - "width": "0" - }, - "lg": { - "width": "0" - } - }, - "inputIcon": { - "color": "{formField.iconColor}" - }, - "group": { - "borderColor": "{content.borderColor}", - "gap": "{overlay.popover.padding}" - }, - "selectYear": { - "hoverBackground": "{content.hoverBackground}", - "color": "{content.color}", - "hoverColor": "{content.hoverColor}", - "borderRadius": "{content.borderRadius}", - "padding": "0.375rem 0.625rem" - }, - "dayView": { - "margin": "0 0 0 0" - }, - "weekDay": { - "padding": "0.21875rem", - "fontWeight": "{fonts.fontWeight.bold}", - "color": "{content.color}" - }, - "date": { - "hoverBackground": "{content.hoverBackground}", - "selectedBackground": "{primary.500}", - "rangeSelectedBackground": "{highlight.background}", - "color": "{content.color}", - "hoverColor": "{content.color}", - "selectedColor": "{text.extend.colorPrimaryStatic}", - "rangeSelectedColor": "{text.extend.colorSecondaryStatic}", - "width": "1.75rem", - "height": "1.75rem", - "borderRadius": "0.328125rem", - "padding": "0.21875rem", - "focusRing": { - "width": "{formField.focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{formField.focusRing.color}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.shadow}" - } - }, - "monthView": { - "margin": "0 0 0 0" - }, - "month": { - "padding": "0", - "borderRadius": "0" - }, - "yearView": { - "margin": "0 0 0 0" - }, - "year": { - "padding": "0", - "borderRadius": "0" - }, - "buttonbar": { - "padding": "0 0 0 0", - "borderColor": "{content.borderColor}" - }, - "timePicker": { - "padding": "1.5rem 0.75rem 0.75rem 0.75rem", - "borderColor": "{content.borderColor}", - "gap": "0.4375rem", - "buttonGap": "0.21875rem" - }, - "root": { - "transitionDuration": "{transitionDuration}" - } - }, - "dialog": { - "root": { - "background": "{overlay.modal.background}", - "borderColor": "{overlay.modal.borderColor}", - "color": "{overlay.modal.color}", - "borderRadius": "{overlay.modal.borderRadius}", - "shadow": "{overlay.popover.shadow}" - }, - "header": { - "padding": "{overlay.modal.padding} {overlay.modal.padding} 1rem {overlay.modal.padding}", - "gap": "0" - }, - "title": { - "fontSize": "{fonts.fontSize.xl}", - "fontWeight": "{fonts.fontWeight.demibold}" - }, - "content": { - "padding": "1.3125rem" - }, - "footer": { - "padding": "0 {overlay.modal.padding} {overlay.modal.padding} {overlay.modal.padding}", - "gap": "0.4375rem" - } - }, - "divider": { - "root": { - "borderColor": "{content.borderColor}" - }, - "content": { - "background": "{content.background}", - "color": "{text.mutedColor}" - }, - "horizontal": { - "margin": "1rem 0", - "padding": "0 1rem", - "content": { - "padding": "0 0.5rem" - } - }, - "vertical": { - "margin": "0 1rem", - "padding": "1rem 0", - "content": { - "padding": "0.5rem 0" - } - } - }, - "drawer": { - "extend": { - "borderRadius": "{overlay.popover.borderRadius}", - "extHeader": { - "gap": "0.4375rem", - "borderColor": "{drawer.root.borderColor}" - }, - "width": "{sizingDrawer.width}" - }, - "root": { - "background": "{overlay.modal.background}", - "borderColor": "{overlay.modal.borderColor}", - "color": "{overlay.modal.color}", - "shadow": "{overlay.modal.shadow}" - }, - "header": { - "padding": "{overlay.modal.padding} {overlay.modal.padding} 14 {overlay.modal.padding} " - }, - "title": { - "fontSize": "{fonts.fontSize.xl}", - "fontWeight": "{fonts.fontWeight.demibold}" - }, - "content": { - "padding": "{overlay.modal.padding}" - }, - "footer": { - "padding": "0 {overlay.modal.padding} {overlay.modal.padding} {overlay.modal.padding} " - } - }, - "fileupload": { - "colorScheme": { - "light": { - "header": { - "background": "{surface.0}", - "color": "{text.color}" - } - } - }, - "extend": { - "extDragNdrop": { - "background": "{surface.0}", - "padding": "0.875rem", - "borderRadius": "{formField.borderRadius}", - "gap": "0.4375rem", - "info": { - "gap": "0.21875rem" - } - }, - "extContent": { - "borderRadius": "{borderRadius.md}", - "highlightBorderDefault": "{formField.borderColor}" - } - }, - "root": { - "background": "{content.background}", - "borderColor": "{content.borderColor}", - "color": "{content.color}", - "borderRadius": "{content.borderRadius}", - "transitionDuration": "{transitionDuration}" - }, - "header": { - "borderColor": "{content.borderColor}", - "borderWidth": "0", - "padding": "0", - "borderRadius": "0", - "gap": "0.4375rem" - }, - "content": { - "highlightBorderColor": "{surface.900}", - "padding": "0", - "gap": "0.4375rem" - }, - "file": { - "padding": "0.4375rem", - "gap": "0.4375rem", - "borderColor": "{formField.borderColor}", - "info": { - "gap": "0.21875rem" - } - }, - "fileList": { - "gap": "0.4375rem" - }, - "progressbar": { - "height": "0.4375rem" - }, - "basic": { - "gap": "0.5rem" - } - }, - "floatlabel": { - "extend": { - "height": "3.5rem", - "iconSize": "{iconSizeLarge}" - }, - "root": { - "color": "{formField.floatLabelColor}", - "focusColor": "{formField.floatLabelFocusColor}", - "activeColor": "{formField.floatLabelActiveColor}", - "invalidColor": "{formField.floatLabelInvalidColor}", - "transitionDuration": "{formField.transitionDuration}", - "positionX": "{formField.paddingX}", - "positionY": "{formField.paddingY}", - "fontWeight": "{fonts.fontWeight.regular}", - "active": { - "fontSize": "{fonts.fontSize.sm}", - "fontWeight": "{fonts.fontWeight.regular}" - } - }, - "over": { - "active": { - "top": "0.5rem" - } - }, - "inside": { - "input": { - "paddingTop": "1.640625rem", - "paddingBottom": "{formField.paddingY}" - }, - "active": { - "top": "{formField.paddingY}" - } - }, - "on": { - "borderRadius": "0", - "active": { - "padding": "0 0.125rem", - "background": "#ffffff" - } - } - }, - "galleria": { - "colorScheme": { - "light": { - "thumbnailContent": { - "background": "{surface.100}" - }, - "thumbnailNavButton": { - "hoverBackground": "{colors.alpha.white.20}", - "color": "{text.color}", - "hoverColor": "{text.hoverColor}" - }, - "indicatorButton": { - "background": "{surface.300}", - "hoverBackground": "{surface.400}" - } - } - }, - "root": { - "borderWidth": "1px", - "borderColor": "{content.borderColor}", - "borderRadius": "{content.borderRadius}", - "transitionDuration": "{transitionDuration}" - }, - "navButton": { - "background": "{transparent}", - "hoverBackground": "{colors.alpha.white.20}", - "color": "{text.extend.colorInverted}", - "hoverColor": "{text.extend.colorInverted}", - "size": "3.5rem", - "gutter": "0.4375rem", - "prev": { - "borderRadius": "{navigation.item.borderRadius}" - }, - "next": { - "borderRadius": "{navigation.item.borderRadius}" - }, - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - }, - "navIcon": { - "size": "1.75rem" - }, - "thumbnailsContent": { - "padding": "0.21875rem" - }, - "thumbnailNavButton": { - "size": "1.75rem", - "borderRadius": "{content.borderRadius}", - "gutter": "0.4375rem", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - }, - "thumbnailNavButtonIcon": { - "size": "0.875rem" - }, - "caption": { - "background": "{colors.alpha.white.50}", - "color": "{text.color}", - "padding": "0.4375rem" - }, - "indicatorList": { - "gap": "0.4375rem", - "padding": "0.875rem" - }, - "indicatorButton": { - "width": "0.4375rem", - "height": "0.4375rem", - "activeBackground": "{surface.900}", - "borderRadius": "{content.borderRadius}", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - }, - "insetIndicatorList": { - "background": "{colors.alpha.black.50}" - }, - "insetIndicatorButton": { - "background": "{colors.alpha.white.10}", - "hoverBackground": "{colors.alpha.white.20}", - "activeBackground": "{colors.alpha.white.50}" - }, - "closeButton": { - "size": "3.5rem", - "gutter": "0.4375rem", - "background": "{colors.alpha.white.10}", - "hoverBackground": "{colors.alpha.white.20}", - "color": "{text.extend.colorInverted}", - "hoverColor": "{text.extend.colorInverted}", - "borderRadius": "{borderRadius.lg}", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - }, - "closeButtonIcon": { - "size": "1.75rem" - } - }, - "message": { - "colorScheme": { - "light": { - "success": { - "background": "{success.50}", - "borderColor": "{success.500}", - "color": "{text.color}", - "shadow": "none", - "outlined": { - "color": "{text.color}", - "borderColor": "{success.500}" - }, - "closeButton": { - "hoverBackground": "{success.200}", - "focusRing": { - "color": "{focusRing.color}", - "shadow": "none" - } - }, - "simple": { - "color": "{text.color}" - } - }, - "outlined": { - "root": { - "borderWidth": "0" - }, - "closeButton": { - "hoverBackground": "#ffffff", - "focusRing": { - "color": "{focusRing.color}", - "shadow": "none" - } - }, - "outlined": { - "color": "#ffffff", - "borderColor": "#ffffff" - }, - "simple": { - "color": "#ffffff" - } - }, - "simple": { - "content": { - "padding": "0" - } - }, - "warn": { - "background": "{warn.50}", - "borderColor": "{warn.500}", - "color": "{text.color}", - "shadow": "none", - "outlined": { - "color": "{text.color}", - "borderColor": "{warn.500}" - }, - "closeButton": { - "hoverBackground": "{warn.200}", - "focusRing": { - "color": "{focusRing.color}", - "shadow": "none" - } - }, - "simple": { - "color": "{text.color}" - } - }, - "error": { - "background": "{error.50}", - "borderColor": "{error.500}", - "color": "{text.color}", - "shadow": "none", - "outlined": { - "color": "{text.color}", - "borderColor": "{error.500}" - }, - "closeButton": { - "hoverBackground": "{error.200}", - "focusRing": { - "color": "{focusRing.color}", - "shadow": "none" - } - }, - "simple": { - "color": "{text.color}" - } - }, - "secondary": { - "borderColor": "#ffffff", - "shadow": "none", - "closeButton": { - "hoverBackground": "#ffffff", - "focusRing": { - "color": "{focusRing.color}", - "shadow": "none" - } - }, - "simple": { - "color": "#ffffff" - }, - "outlined": { - "color": "#ffffff", - "borderColor": "#ffffff" - } - }, - "contrast": { - "borderColor": "#ffffff", - "shadow": "none", - "closeButton": { - "hoverBackground": "#ffffff", - "focusRing": { - "color": "{focusRing.color}", - "shadow": "none" - } - }, - "simple": { - "color": "#ffffff" - }, - "outlined": { - "color": "#ffffff", - "borderColor": "#ffffff" - } - }, - "info": { - "background": "{info.50}", - "borderColor": "{info.500}", - "color": "{text.color}", - "shadow": "none", - "outlined": { - "color": "{text.color}", - "borderColor": "{info.500}" - }, - "closeButton": { - "hoverBackground": "{info.200}", - "focusRing": { - "color": "{focusRing.color}", - "shadow": "none" - } - }, - "simple": { - "color": "{text.color}" - } - } - } - }, - "extend": { - "width": "{sizingMessage.width}", - "extText": { - "gap": "0.21875rem" - }, - "extInfo": { - "color": "{info.500}", - "closeButton": { - "color": "{info.500}", - "borderColor": "{info.500}" - }, - "caption": { - "color": "{text.color}" - } - }, - "extAccentLine": { - "width": "0.21875rem" - }, - "extCloseButton": { - "width": "0.0625rem" - }, - "extSuccess": { - "color": "{success.500}", - "closeButton": { - "color": "{success.500}", - "borderColor": "{success.500}" - }, - "caption": { - "color": "{text.color}" - } - }, - "extWarn": { - "color": "{warn.500}", - "closeButton": { - "color": "{warn.500}", - "borderColor": "{warn.500}" - }, - "caption": { - "color": "{text.color}" - } - }, - "extError": { - "color": "{error.500}", - "closeButton": { - "color": "{error.500}", - "borderColor": "{error.500}" - }, - "caption": { - "color": "{text.color}" - } - } - }, - "root": { - "borderRadius": "{content.borderRadius}", - "borderWidth": "0.0625rem", - "transitionDuration": "{transitionDuration}" - }, - "content": { - "padding": "0.875rem", - "gap": "0.875rem", - "sm": { - "padding": "0.875rem" - }, - "lg": { - "padding": "0.875rem" - } - }, - "text": { - "fontSize": "{fonts.fontSize.base}", - "fontWeight": "{fonts.fontWeight.bold}", - "sm": { - "fontSize": "{fonts.fontSize.base}" - }, - "lg": { - "fontSize": "{fonts.fontSize.base}" - } - }, - "icon": { - "size": "1.96875rem", - "sm": { - "size": "1.96875rem" - }, - "lg": { - "size": "1.96875rem" - } - }, - "closeButton": { - "width": "1.75rem", - "height": "1.75rem", - "borderRadius": "0.65625rem", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "offset": "{focusRing.offset}" - } - }, - "closeIcon": { - "size": "0.875rem", - "sm": { - "size": "0.875rem" - }, - "lg": { - "size": "0.875rem" - } - } - }, - "inputgroup": { - "colorScheme": { - "light": { - "addon": { - "background": "{transparent}", - "borderColor": "{formField.borderColor}", - "color": "{text.mutedColor}" - } - } - }, - "addon": { - "borderRadius": "{formField.borderRadius}", - "padding": "0.65625rem", - "minWidth": "2.1875rem" - } - }, - "inputnumber": { - "colorScheme": { - "light": { - "button": { - "background": "{transparent}", - "hoverBackground": "{content.hoverBackground}", - "activeBackground": "{transparent}", - "borderColor": "{formField.borderColor}", - "hoverBorderColor": "{formField.borderColor}", - "activeBorderColor": "{formField.borderColor}", - "color": "{text.color}", - "hoverColor": "{text.hoverColor}", - "activeColor": "{text.color}" - } - } - }, - "extend": { - "extButton": { - "height": "2.1875rem" - } - }, - "transitionDuration": { - "transitionDuration": "{formField.transitionDuration}" - }, - "button": { - "width": "2.1875rem", - "borderRadius": "{formField.borderRadius}", - "verticalPadding": "{formField.paddingY}" - } - }, - "inputotp": { - "extend": { - "height": "2.1875rem" - }, - "root": { - "gap": "0.4375rem" - }, - "input": { - "width": "2.1875rem" - }, - "sm": { - "width": "0" - }, - "lg": { - "width": "0" - } - }, - "inputtext": { - "extend": { - "readonlyBackground": "{formField.readonlyBackground}", - "iconSize": "{iconSizeMedium}", - "extXlg": { - "fontSize": "{sizingInputtext.root.fontSize}", - "paddingX": "{sizingInputtext.root.paddingX}", - "paddingY": "{sizingInputtext.root.paddingY}" - } - }, - "root": { - "background": "{formField.background}", - "disabledBackground": "{formField.disabledBackground}", - "filledBackground": "{formField.filledBackground}", - "filledHoverBackground": "{formField.filledHoverBackground}", - "filledFocusBackground": "{formField.filledFocusBackground}", - "borderColor": "{formField.borderColor}", - "hoverBorderColor": "{formField.hoverBorderSecondaryColor}", - "focusBorderColor": "{formField.focusBorderSecondaryColor}", - "invalidBorderColor": "{formField.invalidBorderColor}", - "color": "{text.color}", - "disabledColor": "{formField.disabledColor}", - "placeholderColor": "{formField.placeholderColor}", - "invalidPlaceholderColor": "{formField.invalidPlaceholderColor}", - "shadow": "{formField.shadow}", - "paddingX": "{sizingInputtext.root.paddingX}", - "paddingY": "{sizingInputtext.root.paddingY}", - "borderRadius": "{formField.borderRadius}", - "transitionDuration": "{formField.transitionDuration}", - "sm": { - "fontSize": "{sizingInputtext.root.fontSize}", - "paddingX": "{sizingInputtext.root.paddingX}", - "paddingY": "{sizingInputtext.root.paddingY}" - }, - "lg": { - "fontSize": "{sizingInputtext.root.fontSize}", - "paddingX": "{sizingInputtext.root.paddingX}", - "paddingY": "{sizingInputtext.root.paddingY}" - }, - "focusRing": { - "width": "{formField.focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{formField.focusRing.color}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.shadow}" - } - } - }, - "listbox": { - "colorScheme": { - "light": { - "option": { - "stripedBackground": "{surface.50}" - } - } - }, - "extend": { - "extOption": { - "label": { - "gap": "0.21875rem" - }, - "caption": { - "color": "{text.mutedColor}", - "stripedColor": "{text.mutedColor}" - } - } - }, - "root": { - "background": "{formField.background}", - "disabledBackground": "{formField.disabledBackground}", - "borderColor": "{formField.borderColor}", - "invalidBorderColor": "{formField.invalidBorderColor}", - "color": "{formField.color}", - "disabledColor": "{formField.disabledColor}", - "shadow": "{formField.shadow}", - "borderRadius": "{formField.borderRadius}", - "transitionDuration": "{formField.transitionDuration}" - }, - "list": { - "padding": "{list.padding}", - "gap": "{list.gap}", - "header": { - "padding": "{list.header.padding}" - } - }, - "option": { - "focusBackground": "{list.option.focusBackground}", - "selectedBackground": "{list.option.selectedBackground}", - "selectedFocusBackground": "{list.option.selectedFocusBackground}", - "color": "{list.option.color}", - "focusColor": "{list.option.focusColor}", - "selectedColor": "{list.option.selectedColor}", - "selectedFocusColor": "{list.option.selectedFocusColor}", - "padding": "{list.option.padding}", - "borderRadius": "{list.option.borderRadius}" - }, - "optionGroup": { - "background": "{list.optionGroup.background}", - "color": "{list.optionGroup.color}", - "fontWeight": "{fonts.fontWeight.demibold}", - "padding": "{list.option.padding}" - }, - "checkmark": { - "color": "{list.option.color}", - "gutterStart": "-0.5rem", - "gutterEnd": "0.5rem" - }, - "emptyMessage": { - "padding": "{list.option.padding}" - } - }, - "megamenu": { - "colorScheme": { - "light": { - "root": { - "background": "{transparent}" - } - } - }, - "extend": { - "extItem": { - "caption": { - "color": "{text.mutedColor}", - "gap": "0.21875rem" - } - } - }, - "root": { - "borderColor": "{transparent}", - "borderRadius": "{content.borderRadius}", - "color": "{content.color}", - "gap": "0.21875rem", - "transitionDuration": "{transitionDuration}", - "verticalOrientation": { - "padding": "{navigation.list.padding}", - "gap": "{navigation.list.gap}" - }, - "horizontalOrientation": { - "padding": "{navigation.list.padding}", - "gap": "{navigation.list.gap}" - } - }, - "baseItem": { - "borderRadius": "{content.borderRadius}", - "padding": "{navigation.item.padding}" - }, - "item": { - "focusBackground": "{navigation.item.focusBackground}", - "activeBackground": "{navigation.item.activeBackground}", - "color": "{navigation.item.color}", - "focusColor": "{navigation.item.focusColor}", - "activeColor": "{navigation.item.activeColor}", - "padding": "{navigation.item.padding}", - "borderRadius": "{navigation.item.borderRadius}", - "gap": "{navigation.item.gap}", - "icon": { - "color": "{navigation.item.icon.color}", - "focusColor": "{navigation.item.icon.focusColor}", - "activeColor": "{navigation.item.icon.activeColor}" - } - }, - "overlay": { - "padding": "0.21875rem", - "background": "{content.background}", - "borderColor": "{content.borderColor}", - "borderRadius": "{content.borderRadius}", - "color": "{content.color}", - "shadow": "{overlay.navigation.shadow}", - "gap": "0" - }, - "submenu": { - "padding": "{navigation.list.padding}", - "gap": "{navigation.list.gap}" - }, - "submenuLabel": { - "padding": "{navigation.submenuLabel.padding}", - "background": "{navigation.submenuLabel.background}", - "color": "{navigation.submenuLabel.color}", - "Number": "{fonts.fontWeight.demibold}" - }, - "submenuIcon": { - "size": "{navigation.submenuIcon.size}", - "color": "{navigation.submenuIcon.color}", - "focusColor": "{navigation.submenuIcon.focusColor}", - "activeColor": "{navigation.submenuIcon.activeColor}" - }, - "separator": { - "borderColor": "{content.borderColor}" - }, - "mobileButton": { - "borderRadius": "{navigation.item.borderRadius}", - "size": "1.75rem", - "color": "{text.color}", - "hoverColor": "{text.hoverColor}", - "hoverBackground": "{content.hoverBackground}", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - } - }, - "menu": { - "extend": { - "paddingX": "0.21875rem", - "paddingY": "0.21875rem", - "extItem": { - "caption": { - "color": "{text.mutedColor}", - "gap": "0.21875rem" - } - } - }, - "root": { - "background": "{content.background}", - "borderColor": "{content.borderColor}", - "color": "{content.color}", - "borderRadius": "{content.borderRadius}", - "shadow": "{overlay.navigation.shadow}", - "transitionDuration": "{transitionDuration}" - }, - "list": { - "padding": "{navigation.list.padding}", - "gap": "{navigation.list.gap}" - }, - "item": { - "focusBackground": "{navigation.item.focusBackground}", - "color": "{navigation.item.color}", - "focusColor": "{navigation.item.focusColor}", - "padding": "{navigation.item.padding}", - "borderRadius": "{navigation.item.borderRadius}", - "gap": "{navigation.item.gap}", - "icon": { - "color": "{navigation.item.icon.color}", - "focusColor": "{navigation.item.icon.focusColor}" - } - }, - "submenuLabel": { - "padding": "{navigation.submenuLabel.padding}", - "fontWeight": "{fonts.fontWeight.demibold}", - "background": "{navigation.submenuLabel.background}", - "color": "{navigation.submenuLabel.color}" - }, - "separator": { - "borderColor": "{content.borderColor}" - } - }, - "menubar": { - "extend": { - "extItem": { - "caption": { - "color": "{text.mutedColor}", - "gap": "0.21875rem" - } - }, - "extSubmenuLabel": { - "padding": "{navigation.submenuLabel.padding}", - "fontWeight": "{fonts.fontWeight.demibold}", - "background": "{navigation.submenuLabel.background}", - "color": "{navigation.submenuLabel.color}" - } - }, - "colorScheme": { - "light": { - "root": { - "background": "{transparent}" - } - } - }, - "root": { - "borderColor": "{transparent}", - "borderRadius": "{navigation.item.borderRadius}", - "color": "{content.color}", - "gap": "0.21875rem", - "padding": "{navigation.list.padding}", - "transitionDuration": "{transitionDuration}" - }, - "baseItem": { - "borderRadius": "{navigation.item.borderRadius}", - "padding": "0.5rem 0.75rem" - }, - "item": { - "focusBackground": "{navigation.item.focusBackground}", - "activeBackground": "{navigation.item.activeBackground}", - "color": "{navigation.item.color}", - "focusColor": "{navigation.item.focusColor}", - "activeColor": "{navigation.item.activeColor}", - "padding": "{navigation.item.padding}", - "borderRadius": "{navigation.item.borderRadius}", - "gap": "{navigation.item.gap}", - "icon": { - "color": "{navigation.item.icon.color}", - "focusColor": "{navigation.item.icon.focusColor}", - "activeColor": "{navigation.item.icon.activeColor}" - } - }, - "submenu": { - "padding": "{navigation.list.padding}", - "gap": "{navigation.list.gap}", - "background": "{content.background}", - "borderColor": "{content.borderColor}", - "borderRadius": "{content.borderRadius}", - "shadow": "{overlay.navigation.shadow}", - "mobileIndent": "0.65625rem", - "icon": { - "size": "{navigation.submenuIcon.size}", - "color": "{navigation.submenuIcon.color}", - "focusColor": "{navigation.submenuIcon.focusColor}", - "activeColor": "{navigation.submenuIcon.activeColor}" - } - }, - "separator": { - "borderColor": "{content.borderColor}" - }, - "mobileButton": { - "borderRadius": "{navigation.item.borderRadius}", - "size": "1.75rem", - "color": "{text.color}", - "hoverColor": "{text.hoverColor}", - "hoverBackground": "{content.hoverBackground}", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - } - }, - "metergroup": { - "extend": { - "extLabel": { - "color": "{text.mutedColor}" - } - }, - "root": { - "borderRadius": "{content.borderRadius}", - "gap": "0.65625rem" - }, - "meters": { - "size": "0.4375rem", - "background": "{content.borderColor}" - }, - "label": { - "gap": "0.4375rem" - }, - "labelMarker": { - "size": "0.4375rem" - }, - "labelIcon": { - "size": "0.875rem" - }, - "labelList": { - "verticalGap": "0.4375rem", - "horizontalGap": "0.65625rem" - } - }, - "multiselect": { - "extend": { - "paddingX": "0.3125rem", - "paddingY": "0.3125rem" - }, - "root": { - "background": "{formField.background}", - "disabledBackground": "{formField.disabledBackground}", - "filledBackground": "{formField.filledBackground}", - "filledHoverBackground": "{formField.filledHoverBackground}", - "filledFocusBackground": "{formField.filledFocusBackground}", - "borderColor": "{formField.borderColor}", - "hoverBorderColor": "{formField.hoverBorderSecondaryColor}", - "focusBorderColor": "{formField.focusBorderSecondaryColor}", - "invalidBorderColor": "{formField.invalidBorderColor}", - "color": "{formField.color}", - "disabledColor": "{formField.disabledColor}", - "placeholderColor": "{formField.placeholderColor}", - "invalidPlaceholderColor": "{formField.invalidPlaceholderColor}", - "shadow": "{formField.shadow}", - "paddingX": "{formField.paddingX}", - "paddingY": "{formField.paddingY}", - "borderRadius": "{formField.borderRadius}", - "transitionDuration": "{formField.transitionDuration}", - "sm": { - "fontSize": "{formField.sm.fontSize}", - "paddingX": "{formField.sm.paddingY}", - "paddingY": "{formField.sm.paddingY}" - }, - "lg": { - "fontSize": "{formField.lg.fontSize}", - "paddingX": "{formField.lg.paddingX}", - "paddingY": "{formField.lg.paddingY}" - }, - "focusRing": { - "width": "{formField.focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{formField.focusRing.color}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.shadow}" - } - }, - "dropdown": { - "width": "0.75rem", - "color": "{formField.iconColor}" - }, - "overlay": { - "background": "{datatable.filter.overlaySelect.background}", - "borderColor": "{overlay.select.borderColor}", - "borderRadius": "{datatable.filter.overlaySelect.borderRadius}", - "color": "{datatable.filter.overlaySelect.color}", - "shadow": "{overlay.select.shadow}" - }, - "readonlyBackground": "{formField.readonlyBackground}", - "list": { - "padding": "{list.padding}", - "header": { - "padding": "{list.header.padding}" - }, - "gap": "{list.gap}" - }, - "option": { - "focusBackground": "{list.option.focusBackground}", - "selectedBackground": "{list.option.selectedBackground}", - "selectedFocusBackground": "{list.option.selectedFocusBackground}", - "color": "{list.option.color}", - "focusColor": "{list.option.focusColor}", - "selectedColor": "{list.option.selectedColor}", - "selectedFocusColor": "{list.option.selectedFocusColor}", - "padding": "{list.option.padding}", - "borderRadius": "{list.option.borderRadius}", - "gap": "0.4375rem" - }, - "optionGroup": { - "background": "{list.optionGroup.background}", - "color": "{list.optionGroup.color}", - "fontWeight": "{fonts.fontWeight.demibold}", - "padding": "{list.optionGroup.padding}" - }, - "clearIcon": { - "color": "{formField.iconColor}" - }, - "chip": { - "borderRadius": "{borderRadius.sm}" - }, - "emptyMessage": { - "padding": "{list.option.padding}" - } - }, - "paginator": { - "root": { - "padding": "0 0.5rem", - "gap": "0.4375rem", - "borderRadius": "{content.borderRadius}", - "background": "{transparent}", - "color": "{content.color}", - "transitionDuration": "{transitionDuration}" - }, - "currentPageReport": { - "color": "{text.mutedColor}" - }, - "navButton": { - "background": "{transparent}", - "hoverBackground": "{content.hoverBackground}", - "selectedBackground": "{highlight.background}", - "color": "{text.color}", - "hoverColor": "{text.hoverColor}", - "selectedColor": "{text.extend.colorInverted}", - "width": "2.1875rem", - "height": "2.1875rem", - "borderRadius": "{content.borderRadius}", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "focus": "{focusRing.shadow}" - } - }, - "jumpToPageInput": { - "maxWidth": "4.375rem" - } - }, - "panelmenu": { - "extend": { - "extPanel": { - "gap": "0.21875rem" - }, - "extItem": { - "activeBackground": "{navigation.item.activeBackground}", - "activeColor": "{navigation.item.activeColor}", - "caption": { - "color": "{text.mutedColor}", - "gap": "0.21875rem" - } - } - }, - "root": { - "gap": "0.21875rem", - "transitionDuration": "{transitionDuration}" - }, - "panel": { - "background": "{transparent}", - "borderColor": "{transparent}", - "borderWidth": "0.0625rem", - "color": "{content.color}", - "padding": "0.21875rem", - "borderRadius": "{content.borderRadius}", - "first": { - "borderWidth": "1px 1px 0 1px", - "topBorderRadius": "{content.borderRadius}" - }, - "last": { - "borderWidth": "0 1px 1px 1px", - "topBorderRadius": "{content.borderRadius}" - } - }, - "item": { - "focusBackground": "{navigation.item.focusBackground}", - "color": "{navigation.item.color}", - "focusColor": "{navigation.item.focusColor}", - "gap": "0.4375rem", - "padding": "{navigation.item.padding}", - "borderRadius": "{navigation.item.borderRadius}", - "icon": { - "color": "{navigation.item.icon.color}", - "focusColor": "{navigation.item.icon.focusColor}" - } - }, - "submenu": { - "indent": "0.65625rem" - }, - "separator": { - "borderColor": "{content.borderColor}" - }, - "submenuIcon": { - "color": "{navigation.submenuIcon.color}", - "focusColor": "{navigation.submenuIcon.focusColor}" - } - }, - "password": { - "colorScheme": { - "light": { - "strength": { - "weakBackground": "{error.500}", - "mediumBackground": "{warn.500}", - "strongBackground": "{success.600}" - } - } - }, - "meter": { - "background": "{content.borderColor}", - "borderRadius": "{content.borderRadius}", - "height": "0.4375rem" - }, - "icon": { - "color": "{text.color}" - }, - "overlay": { - "background": "{overlay.popover.background}", - "borderColor": "{overlay.popover.borderColor}", - "borderRadius": "{overlay.popover.borderRadius}", - "color": "{overlay.popover.color}", - "padding": "{overlay.popover.padding}", - "shadow": "{overlay.popover.shadow}" - }, - "content": { - "gap": "0.4375rem" - } - }, - "popover": { - "root": { - "background": "{overlay.popover.background}", - "borderColor": "{datatable.filter.overlayPopover.borderColor}", - "color": "{overlay.popover.color}", - "borderRadius": "{overlay.popover.borderRadius}", - "shadow": "{overlay.popover.shadow}", - "gutter": "0.21875rem", - "arrowOffset": "1.25rem" - }, - "content": { - "padding": "{overlay.popover.padding}" - } - }, - "progressbar": { - "label": { - "color": "{text.extend.colorPrimaryStatic}", - "fontSize": "{fonts.fontSize.xs}", - "fontWeight": "{fonts.fontWeight.regular}" - }, - "root": { - "background": "{content.borderColor}", - "borderRadius": "{content.borderRadius}", - "height": "0.875rem" - }, - "value": { - "background": "{primary.color}" - } - }, - "progressspinner": { - "colorScheme": { - "light": { - "root": { - "colorOne": "{success.500}", - "colorTwo": "{info.500}", - "colorThree": "{error.500}", - "colorFour": "{warn.500}" - } - } - } - }, - "radiobutton": { - "root": { - "width": "1.3125rem", - "height": "1.3125rem", - "background": "{formField.background}", - "checkedBackground": "{surface.900}", - "checkedHoverBackground": "{surface.800}", - "disabledBackground": "{formField.disabledBackground}", - "filledBackground": "{formField.filledBackground}", - "borderColor": "{formField.borderColor}", - "hoverBorderColor": "{formField.hoverBorderPrimaryColor}", - "focusBorderColor": "{formField.borderColor}", - "checkedBorderColor": "{surface.900}", - "checkedHoverBorderColor": "{formField.hoverBorderPrimaryColor}", - "checkedFocusBorderColor": "{formField.focusBorderPrimaryColor}", - "checkedDisabledBorderColor": "{formField.borderColor}", - "invalidBorderColor": "{formField.invalidBorderColor}", - "shadow": "{formField.shadow}", - "transitionDuration": "{formField.transitionDuration}" - }, - "focusRing": { - "width": "0.21875rem", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{formField.focusRing.shadow}" - }, - "sm": { - "width": "0.875rem", - "height": "0.875rem" - }, - "lg": { - "width": "1.09375rem", - "height": "1.09375rem" - }, - "icon": { - "size": "0.75rem", - "checkedColor": "{text.extend.colorInverted}", - "checkedHoverColor": "{text.extend.colorInverted}", - "disabledColor": "{text.mutedColor}", - "sm": { - "size": "0" - }, - "lg": { - "size": "0" - } - } - }, - "rating": { - "root": { - "gap": "0.4375rem", - "transitionDuration": "{formField.transitionDuration}" - }, - "focusRing": { - "width": "{formField.focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{formField.focusRing.color}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.shadow}" - }, - "icon": { - "size": "1.3125rem", - "color": "{surface.500}", - "hoverColor": "{warn.500}", - "activeColor": "{warn.500}" - } - }, - "ripple": { - "colorScheme": { - "light": { - "root": { - "background": "rgba(255, 255, 255, 0.0100)" - } - } - } - }, - "scrollpanel": { - "colorScheme": { - "light": { - "bar": { - "background": "{surface.300}" - } - } - }, - "root": { - "transitionDuration": "{transitionDuration}" - }, - "bar": { - "size": "0.4375rem", - "borderRadius": "{borderRadius.sm}", - "focusRing": { - "width": "0", - "style": "{focusRing.style}", - "color": "#ffffff", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - } - }, - "select": { - "extend": { - "extOption": { - "background": "{list.option.background}", - "gap": "0.4375rem" - }, - "extOptionGroup": { - "gap": "0.4375rem" - }, - "readonlyBackground": "{formField.readonlyBackground}" - }, - "root": { - "background": "{formField.background}", - "disabledBackground": "{formField.disabledBackground}", - "filledBackground": "{formField.filledBackground}", - "filledHoverBackground": "{formField.filledHoverBackground}", - "filledFocusBackground": "{formField.filledFocusBackground}", - "borderColor": "{formField.borderColor}", - "hoverBorderColor": "{formField.hoverBorderSecondaryColor}", - "focusBorderColor": "{formField.focusBorderSecondaryColor}", - "invalidBorderColor": "{formField.invalidBorderColor}", - "color": "{text.color}", - "disabledColor": "{formField.disabledColor}", - "placeholderColor": "{formField.placeholderColor}", - "invalidPlaceholderColor": "{formField.invalidPlaceholderColor}", - "shadow": "{formField.shadow}", - "paddingX": "{sizingSelect.root.paddingX}", - "paddingY": "{sizingSelect.root.paddingY}", - "borderRadius": "{formField.borderRadius}", - "transitionDuration": "{formField.transitionDuration}", - "sm": { - "fontSize": "{sizingSelect.root.fontSize}", - "paddingX": "{sizingSelect.root.paddingX}", - "paddingY": "{sizingSelect.root.paddingY}" - }, - "lg": { - "fontSize": "{sizingSelect.root.fontSize}", - "paddingX": "{sizingSelect.root.paddingX}", - "paddingY": "{sizingSelect.root.paddingY}" - }, - "focusRing": { - "width": "{formField.focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{formField.focusRing.color}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.shadow}" - } - }, - "dropdown": { - "width": "2.5rem", - "color": "{formField.iconColor}" - }, - "overlay": { - "background": "{overlay.select.background}", - "borderColor": "{overlay.select.borderColor}", - "borderRadius": "{overlay.select.borderRadius}", - "color": "{overlay.select.color}", - "shadow": "{overlay.select.shadow}" - }, - "list": { - "padding": "{list.padding}", - "gap": "{list.gap}", - "header": { - "padding": "{list.header.padding}" - } - }, - "option": { - "focusBackground": "{list.option.focusBackground}", - "selectedBackground": "{list.option.selectedBackground}", - "selectedFocusBackground": "{list.option.selectedFocusBackground}", - "color": "{list.option.color}", - "focusColor": "{list.option.focusColor}", - "selectedColor": "{list.option.selectedColor}", - "selectedFocusColor": "{list.option.selectedFocusColor}", - "padding": "{list.option.padding}", - "borderRadius": "{list.option.borderRadius}" - }, - "optionGroup": { - "background": "{list.optionGroup.background}", - "color": "{list.optionGroup.color}", - "fontWeight": "{fonts.fontWeight.demibold}", - "padding": "{list.option.padding}" - }, - "clearIcon": { - "color": "{formField.iconColor}" - }, - "checkmark": { - "color": "{list.option.color}", - "gutterStart": "-0.5rem", - "gutterEnd": "0.5rem" - }, - "emptyMessage": { - "padding": "{list.option.padding}" - } - }, - "selectbutton": { - "colorScheme": { - "light": { - "root": { - "invalidBorderColor": "{formField.invalidBorderColor}" - } - } - }, - "extend": { - "background": "{surface.200}" - }, - "root": { - "borderRadius": "{borderRadius.rounded}" - } - }, - "skeleton": { - "colorScheme": { - "light": { - "root": { - "background": "{surface.200}", - "animationBackground": "{surface.100}" - } - } - }, - "root": { - "borderRadius": "{content.borderRadius}" - } - }, - "slider": { - "colorScheme": { - "light": { - "handle": { - "content": { - "background": "{surface.0}" - } - } - } - }, - "root": { - "transitionDuration": "{formField.transitionDuration}" - }, - "track": { - "background": "{content.borderColor}", - "borderRadius": "{content.borderRadius}", - "size": "0.21875rem" - }, - "range": { - "background": "{surface.900}" - }, - "handle": { - "width": "1.09375rem", - "height": "1.09375rem", - "borderRadius": "{borderRadius.xl}", - "background": "{surface.900}", - "hoverBackground": "{surface.900}", - "focusRing": { - "width": "{formField.focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{formField.focusRing.color}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.shadow}" - }, - "content": { - "borderRadius": "{borderRadius.xl}", - "hoverBackground": "{surface.900}", - "width": "0.65625rem", - "height": "0.65625rem", - "shadow": "none" - } - } - }, - "splitter": { - "colorScheme": { - "light": { - "handle": { - "background": "{surface.900}" - } - } - }, - "gutter": { - "background": "{surface.100}" - }, - "root": { - "background": "{content.background}", - "borderColor": "{content.borderColor}", - "color": "{content.color}", - "transitionDuration": "{transitionDuration}" - }, - "handle": { - "size": "0.21875rem", - "borderRadius": "{content.borderRadius}", - "focusRing": { - "width": "{formField.focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{formField.focusRing.color}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.shadow}" - } - } - }, - "stepper": { - "extend": { - "extCaption": { - "gap": "0.21875rem" - }, - "extStepNumber": { - "invalidBackground": "{error.400}", - "invalidColor": "{error.900}", - "invalidBorderColor": "{error.400}" - } - }, - "root": { - "transitionDuration": "{transitionDuration}" - }, - "separator": { - "background": "{content.borderColor}", - "activeBackground": "{formField.focusBorderPrimaryColor}", - "margin": "0 0 0 1.625rem", - "size": "0.0625rem" - }, - "step": { - "padding": "0.4375rem", - "gap": "0.4375rem" - }, - "stepHeader": { - "padding": "0", - "borderRadius": "0", - "gap": "0.4375rem", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - }, - "stepTitle": { - "color": "{text.color}", - "activeColor": "{text.color}", - "fontWeight": "{fonts.fontWeight.regular}" - }, - "stepNumber": { - "background": "{content.background}", - "activeBackground": "{primary.color}", - "borderColor": "{content.borderColor}", - "activeBorderColor": "{primary.color}", - "color": "{text.color}", - "activeColor": "{text.extend.colorPrimaryStatic}", - "size": "1.3125rem", - "fontSize": "{fonts.fontSize.base}", - "fontWeight": "{fonts.fontWeight.bold}", - "borderRadius": "{content.borderRadius}", - "shadow": "none" - }, - "steppanels": { - "padding": "0.875rem" - }, - "steppanel": { - "background": "{content.background}", - "color": "{content.color}", - "padding": "0", - "indent": "0" - } - }, - "steps": { - "itemLink": { - "gap": "0.5rem" - }, - "itemLabel": { - "fontWeight": "{fonts.fontWeight.regular}" - }, - "itemNumber": { - "background": "{content.background}", - "size": "2.25rem", - "fontSize": "{fonts.fontSize.base}", - "fontWeight": "{fonts.fontWeight.bold}", - "borderRadius": "50%", - "shadow": "none" - } - }, - "tabs": { - "colorScheme": { - "light": { - "navButton": { - "shadow": "0px 0px 10px 50px rgba(255, 255, 255, 0.6)" - }, - "tab": { - "background": "{transparent}", - "hoverBackground": "{transparent}", - "activeBackground": "{transparent}" - } - } - }, - "root": { - "transitionDuration": "{transitionDuration}" - }, - "tablist": { - "borderWidth": "0 0 2px 0", - "background": "{transparent}", - "borderColor": "{content.borderColor}" - }, - "tab": { - "borderWidth": "0", - "borderColor": "{content.borderColor}", - "hoverBorderColor": "{content.borderColor}", - "activeBorderColor": "{formField.focusBorderPrimaryColor}", - "color": "{text.mutedColor}", - "hoverColor": "{text.color}", - "activeColor": "{text.color}", - "padding": "0.875rem", - "fontWeight": "{fonts.fontWeight.demibold}", - "margin": "0 0 -1px 0", - "gap": "0.4375rem", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - }, - "tabpanel": { - "background": "{transparent}", - "color": "{text.color}", - "padding": "0.875rem", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - }, - "navButton": { - "background": "{content.background}", - "color": "{content.color}", - "hoverColor": "{content.hoverColor}", - "width": "1.3125rem", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - }, - "activeBar": { - "height": "0.125rem", - "bottom": "-1", - "background": "{content.color}" - } - }, - "toast": { - "colorScheme": { - "light": { - "info": { - "background": "{info.50}", - "borderColor": "{info.500}", - "color": "{text.color}", - "detailColor": "{text.color}", - "shadow": "{overlay.popover.shadow}", - "closeButton": { - "hoverBackground": "{info.200}", - "focusRing": { - "color": "{focusRing.color}", - "shadow": "none" - } - } - }, - "success": { - "background": "{success.50}", - "borderColor": "{success.500}", - "color": "{text.color}", - "detailColor": "{text.color}", - "shadow": "{overlay.popover.shadow}", - "closeButton": { - "hoverBackground": "{success.200}", - "focusRing": { - "color": "{focusRing.color}", - "shadow": "none" - } - } - }, - "warn": { - "background": "{warn.50}", - "borderColor": "{warn.500}", - "color": "{text.color}", - "detailColor": "{text.color}", - "shadow": "{overlay.popover.shadow}", - "closeButton": { - "hoverBackground": "{warn.200}", - "focusRing": { - "color": "{focusRing.color}", - "shadow": "none" - } - } - }, - "error": { - "background": "{error.50}", - "borderColor": "{error.500}", - "color": "{text.color}", - "detailColor": "{text.color}", - "shadow": "{overlay.popover.shadow}", - "closeButton": { - "hoverBackground": "{error.200}", - "focusRing": { - "color": "{focusRing.color}", - "shadow": "none" - } - } - }, - "secondary": { - "shadow": "{overlay.popover.shadow}" - }, - "contrast": { - "shadow": "{overlay.popover.shadow}" - } - } - }, - "extend": { - "extInfo": { - "color": "{info.500}", - "closeButton": { - "color": "{info.500}", - "borderColor": "{info.500}" - }, - "caption": { - "color": "{text.color}" - } - }, - "extAccentLine": { - "width": "0.21875rem" - }, - "extCloseButton": { - "width": "0.0625rem" - }, - "extSuccess": { - "color": "{success.500}", - "closeButton": { - "color": "{success.500}", - "borderColor": "{success.500}" - }, - "caption": { - "color": "{text.color}" - } - }, - "extWarn": { - "color": "{warn.500}", - "closeButton": { - "color": "{warn.500}", - "borderColor": "{warn.500}" - }, - "caption": { - "color": "{text.color}" - } - }, - "extError": { - "color": "{error.500}", - "closeButton": { - "color": "{error.500}", - "borderColor": "{error.500}" - }, - "caption": { - "color": "{text.color}" - } - } - }, - "root": { - "width": "{sizingToast.width}", - "borderWidth": "0.0625rem", - "borderRadius": "{content.borderRadius}", - "transitionDuration": "{transitionDuration}" - }, - "icon": { - "size": "1.96875rem" - }, - "content": { - "padding": "0.875rem", - "gap": "0.875rem" - }, - "text": { - "gap": "0.21875rem" - }, - "summary": { - "fontWeight": "{fonts.fontWeight.bold}", - "fontSize": "{fonts.fontSize.base}" - }, - "detail": { - "fontWeight": "{fonts.fontWeight.regular}", - "fontSize": "{fonts.fontSize.sm}" - }, - "closeButton": { - "width": "1.75rem", - "height": "1.75rem", - "borderRadius": "{borderRadius.md}", - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "offset": "{focusRing.offset}" - } - }, - "closeIcon": { - "size": "0.875rem" - } - }, - "tag": { - "colorScheme": { - "light": { - "primary": { - "background": "{primary.500}", - "color": "{text.color}" - }, - "secondary": { - "background": "{surface.200}", - "color": "{text.color}" - }, - "success": { - "background": "{success.400}", - "color": "{success.900}" - }, - "info": { - "background": "{info.300}", - "color": "{info.900}" - }, - "warn": { - "background": "{warn.300}", - "color": "{warn.900}" - }, - "danger": { - "background": "{error.300}", - "color": "{error.900}" - } - } - }, - "root": { - "fontSize": "{fonts.fontSize.xs}", - "fontWeight": "{fonts.fontWeight.regular}", - "padding": "0.285rem 0.5rem", - "gap": "0.21875rem", - "borderRadius": "{borderRadius.sm}", - "roundedBorderRadius": "{borderRadius.xl}" - }, - "icon": { - "size": "0.765625rem" - } - }, - "textarea": { - "extend": { - "readonlyBackground": "{formField.readonlyBackground}" - }, - "root": { - "background": "{formField.background}", - "disabledBackground": "{formField.disabledBackground}", - "filledBackground": "{formField.filledBackground}", - "filledHoverBackground": "{formField.filledHoverBackground}", - "filledFocusBackground": "{formField.filledFocusBackground}", - "borderColor": "{formField.borderColor}", - "hoverBorderColor": "{formField.hoverBorderSecondaryColor}", - "focusBorderColor": "{formField.focusBorderSecondaryColor}", - "invalidBorderColor": "{formField.invalidBorderColor}", - "color": "{formField.color}", - "disabledColor": "{formField.disabledColor}", - "placeholderColor": "{formField.placeholderColor}", - "invalidPlaceholderColor": "{formField.invalidPlaceholderColor}", - "shadow": "{formField.shadow}", - "paddingX": "{formField.paddingX}", - "paddingY": "{formField.paddingY}", - "borderRadius": "{formField.borderRadius}", - "transitionDuration": "{formField.transitionDuration}", - "focusRing": { - "width": "{formField.focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{formField.focusRing.color}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.shadow}" - } - }, - "sm": { - "fontSize": "{fonts.fontSize.base}", - "paddingX": "{formField.sm.paddingX}", - "paddingY": "{formField.sm.paddingY}" - }, - "lg": { - "fontSize": "{fonts.fontSize.base}", - "paddingX": "{formField.lg.paddingX}", - "paddingY": "{formField.lg.paddingY}" - } - }, - "tieredmenu": { - "extend": { - "extSubmenu": { - "borderColor": "{content.borderColor}", - "background": "{content.background}" - }, - "extItem": { - "caption": { - "gap": "0.21875rem", - "color": "{text.mutedColor}" - } - } - }, - "root": { - "background": "{transparent}", - "borderColor": "{transparent}", - "color": "{content.color}", - "borderRadius": "{content.borderRadius}", - "shadow": "{overlay.navigation.shadow}", - "transitionDuration": "{transitionDuration}" - }, - "list": { - "padding": "{navigation.list.padding}", - "gap": "{navigation.list.gap}" - }, - "item": { - "focusBackground": "{navigation.item.focusBackground}", - "activeBackground": "{navigation.item.activeBackground}", - "color": "{navigation.item.color}", - "focusColor": "{navigation.item.focusColor}", - "activeColor": "{navigation.item.activeColor}", - "padding": "{navigation.item.padding}", - "borderRadius": "{navigation.item.borderRadius}", - "gap": "{navigation.item.gap}", - "icon": { - "color": "{navigation.item.icon.color}", - "focusColor": "{navigation.item.icon.focusColor}", - "activeColor": "{navigation.item.icon.activeColor}" - } - }, - "submenu": { - "mobileIndent": "0.65625rem" - }, - "separator": { - "borderColor": "{content.borderColor}" - } - }, - "timeline": { - "event": { - "minHeight": "2.65625rem" - }, - "vertical": { - "eventContent": { - "padding": "0 1rem" - } - }, - "horizontal": { - "eventContent": { - "padding": "1rem 0" - } - }, - "eventMarker": { - "size": "0.875rem", - "borderRadius": "{content.borderRadius}", - "borderWidth": "0.21875rem", - "background": "{content.background}", - "borderColor": "{primary.color}", - "content": { - "borderRadius": "{content.borderRadius}", - "size": "0.65625rem", - "background": "{transparent}", - "insetShadow": "none" - } - }, - "eventConnector": { - "color": "{content.borderColor}", - "size": "0.0625rem" - } - }, - "togglebutton": { - "colorScheme": { - "light": { - "root": { - "background": "{surface.200}" - } - } - }, - "extend": { - "gap": "0.65625rem", - "extXlg": { - "padding": "1.25rem 1.5rem", - "iconOnlyWidth": "3.5625rem" - }, - "iconOnlyWidth": "2.1875rem", - "extSm": { - "iconOnlyWidth": "1.875rem" - }, - "hoverBorderColor": "{surface.300}", - "checkedHoverColor": "{text.extend.colorInverted}", - "checkedHoverBackground": "{surface.800}", - "checkedHoverBorderColor": "{surface.800}", - "extLg": { - "iconOnlyWidth": "3.125rem" - } - }, - "root": { - "padding": "0.5rem 1rem", - "borderRadius": "{borderRadius.rounded}", - "gap": "0.4375rem", - "fontWeight": "{fonts.fontWeight.demibold}", - "hoverBackground": "{surface.300}", - "borderColor": "{surface.200}", - "color": "{text.color}", - "hoverColor": "{text.color}", - "checkedBackground": "{surface.900}", - "checkedColor": "{text.extend.colorInverted}", - "checkedBorderColor": "{surface.900}", - "disabledBackground": "{formField.disabledBackground}", - "disabledBorderColor": "{formField.disabledBackground}", - "disabledColor": "{formField.disabledColor}", - "invalidBorderColor": "{formField.invalidBorderColor}", - "focusRing": { - "width": "{formField.focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{formField.focusRing.color}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.shadow}" - }, - "sm": { - "fontSize": "{formField.sm.fontSize}", - "padding": "0.75rem 0.25rem" - }, - "lg": { - "fontSize": "{formField.sm.fontSize}", - "padding": "1rem 1.5rem" - }, - "transitionDuration": "{formField.transitionDuration}" - }, - "icon": { - "color": "{text.color}", - "hoverColor": "{text.color}", - "checkedColor": "{text.extend.colorInverted}", - "disabledColor": "{formField.disabledColor}" - }, - "content": { - "checkedBackground": "{transparent}", - "checkedShadow": "none", - "padding": "0", - "borderRadius": "0", - "sm": { - "padding": "0" - }, - "lg": { - "padding": "0" - } - } - }, - "toggleswitch": { - "colorScheme": { - "light": { - "root": { - "background": "{surface.400}", - "hoverBackground": "{surface.500}", - "disabledBackground": "{formField.disabledBackground}", - "checkedBackground": "{surface.900}", - "checkedHoverBackground": "{surface.500}" - }, - "handle": { - "background": "{formField.backgroundHandler}", - "hoverBackground": "{formField.backgroundHandler}", - "disabledBackground": "{formField.disabledColor}", - "checkedBackground": "{surface.0}", - "checkedHoverBackground": "{surface.0}", - "color": "{text.color}", - "hoverColor": "{text.color}", - "checkedColor": "{text.color}", - "checkedHoverColor": "{text.color}" - } - } - }, - "root": { - "width": "2.1875rem", - "height": "1.3125rem", - "borderRadius": "{borderRadius.xl}", - "gap": "0.125rem", - "borderWidth": "0", - "shadow": "none", - "focusRing": { - "width": "{formField.focusRing.width}", - "style": "{formField.focusRing.style}", - "color": "{primary.200}", - "offset": "{formField.focusRing.offset}", - "shadow": "{formField.shadow}" - }, - "borderColor": "{transparent}", - "hoverBorderColor": "{transparent}", - "checkedBorderColor": "{transparent}", - "checkedHoverBorderColor": "{transparent}", - "invalidBorderColor": "{formField.invalidBorderColor}", - "transitionDuration": "{formField.transitionDuration}", - "slideDuration": "0.2s" - }, - "handle": { - "borderRadius": "6.25rem", - "size": "1.09375rem" - } - }, - "tooltip": { - "colorScheme": { - "light": { - "root": { - "background": "{surface.900}", - "color": "{text.extend.colorInverted}" - } - } - }, - "root": { - "maxWidth": "14.875rem", - "gutter": "0.21875rem", - "shadow": "{overlay.popover.shadow}", - "padding": "0.5rem 1rem", - "borderRadius": "{overlay.popover.borderRadius}" - } - }, - "tree": { - "root": { - "background": "{content.background}", - "color": "{content.color}", - "padding": "1rem", - "gap": "2px", - "indent": "1rem" - }, - "node": { - "padding": "0.375rem 0.625rem", - "color": "{text.color}", - "selectedColor": "{text.extend.colorInverted}", - "gap": "0.25rem" - }, - "nodeIcon": { - "selectedColor": "{text.extend.colorInverted}" - }, - "nodeToggleButton": { - "borderRadius": "50%", - "size": "1.75rem", - "selectedHoverBackground": "{surface.900}" - }, - "loadingIcon": { - "size": "2rem" - }, - "filter": { - "margin": "0 0 0.5rem 0" - } - }, - "overlaybadge": { - "root": { - "outline": { - "width": "0", - "color": "{transparent}" - } - } - } -} diff --git a/src/prime-preset/tokens/components.ts b/src/prime-preset/tokens/components.ts new file mode 100644 index 00000000..865adf1d --- /dev/null +++ b/src/prime-preset/tokens/components.ts @@ -0,0 +1,3716 @@ +import { buttonCss } from './components/button'; + +export default { + accordion: { + extend: { + extHeader: { + iconSize: '{controls.iconOnly.300}', + gap: '{controls.gap.100}', + }, + }, + colorScheme: { + light: { + header: { + background: '{transparent}', + hoverBackground: '{transparent}', + activeBackground: '{transparent}', + activeHoverBackground: '{transparent}', + }, + }, + }, + header: { + color: '{text.color}', + hoverColor: '{text.hoverColor}', + activeColor: '{text.color}', + activeHoverColor: '{text.hoverColor}', + borderColor: '{transparent}', + padding: '{navigation.padding.300} 0 {navigation.padding.300} 0', + fontWeight: '{fonts.fontWeight.bold}', + borderRadius: '{borderRadius.none}', + borderWidth: '{borderWidth.none}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: 'inset {focus.ring.shadow}', + }, + toggleIcon: { + color: '{text.color}', + hoverColor: '{text.hoverColor}', + activeColor: '{text.color}', + activeHoverColor: '{text.hoverColor}', + }, + last: { + bottomBorderRadius: '{borderRadius.none}', + activeBottomBorderRadius: '{borderRadius.none}', + }, + first: { + borderWidth: '{borderWidth.none}', + topBorderRadius: '{borderRadius.none}', + }, + }, + root: { + transitionDuration: '{controls.transitionDuration}', + }, + panel: { + borderWidth: + '{borderWidth.none} {borderWidth.none} {navigation.width.200} {borderWidth.none}', + borderColor: '{form.borderColor}', + }, + content: { + borderWidth: + '{content.borderWidth} {borderWidth.none} {borderWidth.none} {borderWidth.none}', + borderColor: '{transparent}', + background: '{transparent}', + color: '{text.color}', + padding: + '0 {content.padding.400} {content.padding.300} {content.padding.400}', + }, + }, + autocomplete: { + extend: { + extOption: { + gap: '{form.gap.200}', + }, + extOptionGroup: { + gap: '{form.gap.200}', + }, + }, + colorScheme: { + light: { + chip: { + focusBackground: '{chip.colorScheme.light.root.background}', + focusColor: '{chip.colorScheme.light.root.color}', + }, + dropdown: { + background: '{form.background}', + hoverBackground: '{form.background}', + activeBackground: '{form.background}', + color: '{form.color}', + hoverColor: '{form.color}', + activeColor: '{form.color}', + }, + }, + }, + root: { + background: '{form.background}', + disabledBackground: '{form.disabledBackground}', + filledBackground: '{form.filledBackground}', + filledHoverBackground: '{form.filledHoverBackground}', + filledFocusBackground: '{form.filledFocusBackground}', + borderColor: '{form.borderColor}', + hoverBorderColor: '{form.hoverBorderSecondaryColor}', + focusBorderColor: '{form.focusBorderSecondaryColor}', + invalidBorderColor: '{form.invalidBorderColor}', + color: '{form.color}', + disabledColor: '{form.disabledColor}', + placeholderColor: '{form.placeholderColor}', + invalidPlaceholderColor: '{form.invalidPlaceholderColor}', + shadow: '0', + paddingX: '{form.padding.300}', + paddingY: '{form.padding.300}', + borderRadius: '{form.borderRadius.200}', + transitionDuration: '{form.transitionDuration}', + focusRing: { + width: '{focusRing.width}', + style: '{form.focusRing.style}', + color: '{form.focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '0', + }, + }, + overlay: { + background: '{overlay.select.background}', + borderColor: '{overlay.select.borderColor}', + borderRadius: '{overlay.select.borderRadius}', + color: '{overlay.select.color}', + shadow: '{form.shadow}', + }, + list: { + padding: '{list.padding}', + gap: '{list.gap.100}', + }, + option: { + focusBackground: '{list.option.focusBackground}', + selectedBackground: '{list.option.selectedBackground}', + selectedFocusBackground: '{list.option.selectedFocusBackground}', + color: '{list.option.color}', + focusColor: '{list.option.focusColor}', + selectedColor: '{list.option.selectedColor}', + selectedFocusColor: '{list.option.selectedFocusColor}', + padding: '{list.option.padding}', + borderRadius: '{list.option.borderRadius}', + }, + optionGroup: { + background: '{list.optionGroup.background}', + color: '{list.optionGroup.color}', + fontWeight: '{fonts.fontWeight.demibold}', + padding: '{list.optionGroup.padding}', + }, + dropdown: { + width: '{form.width.full}', + borderColor: '{form.borderColor}', + hoverBorderColor: '{form.hoverBorderSecondaryColor}', + activeBorderColor: '{form.focusBorderSecondaryColor}', + borderRadius: '{form.borderRadius.200}', + focusRing: { + width: '{focusRing.width}', + style: '{form.focusRing.style}', + color: '{form.focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '0', + }, + sm: { + width: '{form.width.200}', + }, + lg: { + width: '{form.width.400}', + }, + }, + chip: { + borderRadius: '{chip.root.borderRadius}', + }, + emptyMessage: { + padding: '{list.option.padding}', + }, + }, + avatar: { + extend: { + borderColor: '{form.borderColor}', + circle: { + borderRadius: '{media.borderRadius.max}', + }, + }, + root: { + width: '{media.size.300}', + height: '{media.size.300}', + fontSize: '{fonts.fontSize.200}', + color: '{text.extend.colorPrimaryStatic}', + background: '{primary.color}', + borderRadius: '{media.borderRadius.200}', + }, + icon: { + size: '{media.icon.size.100}', + }, + group: { + borderColor: '{content.background}', + offset: '{media.padding.300}', + }, + lg: { + width: '{media.size.400}', + height: '{media.size.400}', + fontSize: '{fonts.fontSize.300}', + icon: { + size: '{media.icon.size.100}', + }, + group: { + offset: '{media.padding.300}', + }, + }, + xl: { + width: '{media.size.500}', + height: '{media.size.500}', + icon: { + size: '{media.icon.size.200}', + }, + group: { + offset: '{media.padding.600}', + }, + fontSize: '{fonts.fontSize.500}', + }, + }, + badge: { + extend: { + extDot: { + success: { + background: '{colors.solid.green.400}', + }, + info: { + background: '{info.400}', + }, + warn: { + background: '{warn.400}', + }, + danger: { + background: '{error.400}', + }, + lg: { + size: '{feedback.width.400}', + }, + xlg: { + size: '{feedback.width.500}', + }, + }, + ext: { + padding: '0rem', + }, + }, + colorScheme: { + light: { + primary: { + color: '{text.extend.colorPrimaryStatic}', + background: '{primary.color}', + }, + secondary: { + color: '{text.extend.colorInverted}', + background: '{surface.900}', + }, + success: { + color: '{success.900}', + background: '{success.300}', + }, + info: { + color: '{info.900}', + background: '{info.300}', + }, + warn: { + color: '{warn.900}', + background: '{warn.300}', + }, + danger: { + color: '{error.900}', + background: '{error.300}', + }, + }, + }, + root: { + borderRadius: '{feedback.width.300}', + padding: '{feedback.padding.100}', + fontSize: '{fonts.fontSize.100}', + fontWeight: '{fonts.fontWeight.regular}', + minWidth: '{feedback.width.600}', + height: '{feedback.height.500}', + }, + dot: { + size: '{feedback.width.300}', + }, + sm: { + fontSize: '{fonts.fontSize.100}', + minWidth: '0rem', + height: '0rem', + }, + lg: { + fontSize: '{fonts.fontSize.100}', + minWidth: '{feedback.width.650}', + height: '{feedback.height.600}', + }, + xl: { + fontSize: '{fonts.fontSize.100}', + minWidth: '{feedback.width.700}', + height: '{feedback.height.650}', + }, + }, + breadcrumb: { + extend: { + hoverBackground: '{surface.100}', + iconSize: '{navigation.size.300}', + extItem: { + padding: '{navigation.padding.100}', + }, + }, + root: { + padding: '0rem', + background: '{transparent}', + gap: '0rem', + transitionDuration: '{form.transitionDuration}', + }, + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + item: { + color: '{text.color}', + hoverColor: '{text.hoverColor}', + borderRadius: '{navigation.borderRadius}', + gap: '{navigation.item.gap}', + icon: { + color: '{text.color}', + hoverColor: '{text.hoverColor}', + }, + }, + separator: { + color: '{text.color}', + }, + }, + button: { + extend: { + disabledBackground: '{form.disabledBackground}', + extOutlined: { + danger: { + focusBackground: '{transparent}', + }, + warn: { + focusBackground: '{transparent}', + }, + info: { + focusBackground: '{transparent}', + }, + help: { + focusBackground: '{transparent}', + }, + success: { + focusBackground: '{transparent}', + }, + }, + disabledColor: '{form.disabledColor}', + extText: { + danger: { + focusBackground: '{transparent}', + }, + warn: { + focusBackground: '{transparent}', + }, + info: { + focusBackground: '{transparent}', + }, + help: { + focusBackground: '{transparent}', + }, + success: { + focusBackground: '{transparent}', + }, + }, + extLink: { + background: '{transparent}', + colorHover: '{text.hoverColor}', + paddingX: '0rem', + paddingY: '{controls.padding.100}', + sm: { + iconOnlyWidth: '{controls.iconOnly.200}', + }, + base: { + iconOnlyWidth: '{controls.iconOnly.400}', + }, + lg: { + iconOnlyWidth: '{controls.iconOnly.500}', + }, + xlg: { + iconOnlyWidth: '{controls.iconOnly.600}', + }, + }, + extSm: { + borderRadius: '{controls.borderRadius.100}', + gap: '{controls.gap.100}', + }, + extLg: { + borderRadius: '{controls.borderRadius.200}', + gap: '{controls.gap.200}', + height: '{controls.iconOnly.850}', + }, + extXlg: { + borderRadius: '{controls.borderRadius.200}', + gap: '{controls.gap.200}', + iconOnlyWidth: '{controls.iconOnly.900}', + paddingX: '{controls.padding.600}', + paddingY: '{controls.padding.500}', + height: '{controls.iconOnly.900}', + }, + borderWidth: '{controls.width.100}', + iconSize: { + sm: '{controls.iconOnly.200}', + md: '{controls.iconOnly.300}', + lg: '{controls.iconOnly.400}', + }, + }, + colorScheme: { + light: { + root: { + primary: { + background: '{primary.color}', + hoverBackground: '{primary.hoverColor}', + activeBackground: '{primary.activeColor}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{text.extend.colorPrimaryStatic}', + hoverColor: '{text.extend.colorPrimaryStatic}', + activeColor: '{text.extend.colorPrimaryStatic}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + secondary: { + background: '{surface.900}', + hoverBackground: '{surface.800}', + activeBackground: '{surface.700}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{text.extend.colorInverted}', + hoverColor: '{text.extend.colorInverted}', + activeColor: '{text.extend.colorInverted}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + contrast: { + background: '{surface.200}', + hoverBackground: '{surface.300}', + activeBackground: '{surface.400}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{text.color}', + hoverColor: '{text.color}', + activeColor: '{text.color}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + info: { + background: '{info.300}', + hoverBackground: '{info.400}', + activeBackground: '{info.500}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{info.900}', + hoverColor: '{info.950}', + activeColor: '{info.900}', + }, + success: { + background: '{success.300}', + hoverBackground: '{success.400}', + activeBackground: '{success.500}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{success.900}', + hoverColor: '{success.950}', + activeColor: '{success.900}', + }, + warn: { + background: '{warn.300}', + hoverBackground: '{warn.400}', + activeBackground: '{warn.500}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{warn.900}', + hoverColor: '{warn.950}', + activeColor: '{warn.900}', + }, + help: { + background: '{help.300}', + hoverBackground: '{help.400}', + activeBackground: '{help.500}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{help.900}', + hoverColor: '{help.950}', + activeColor: '{help.900}', + }, + danger: { + background: '{error.300}', + hoverBackground: '{error.400}', + activeBackground: '{error.500}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{error.900}', + hoverColor: '{error.950}', + activeColor: '{error.900}', + }, + }, + outlined: { + primary: { + hoverBackground: '{primary.hoverBackground}', + activeBackground: '{primary.activeBackground}', + borderColor: '{primary.borderColor}', + color: '{primary.color}', + }, + success: { + hoverBackground: '{success.100}', + activeBackground: '{success.200}', + borderColor: '{success.600}', + color: '{success.600}', + }, + info: { + hoverBackground: '{info.100}', + activeBackground: '{info.200}', + borderColor: '{info.600}', + color: '{info.600}', + }, + warn: { + hoverBackground: '{warn.100}', + activeBackground: '{warn.200}', + borderColor: '{warn.600}', + color: '{warn.600}', + }, + help: { + hoverBackground: '{help.100}', + activeBackground: '{help.200}', + borderColor: '{help.600}', + color: '{help.600}', + }, + danger: { + hoverBackground: '{error.100}', + activeBackground: '{error.200}', + borderColor: '{error.600}', + color: '{error.600}', + }, + }, + text: { + primary: { + hoverBackground: '{surface.100}', + activeBackground: '{surface.200}', + color: '{text.color}', + }, + success: { + hoverBackground: '{success.100}', + activeBackground: '{success.200}', + color: '{success.600}', + }, + info: { + hoverBackground: '{info.100}', + activeBackground: '{info.200}', + color: '{info.600}', + }, + warn: { + hoverBackground: '{warn.100}', + activeBackground: '{warn.200}', + color: '{warn.600}', + }, + help: { + hoverBackground: '{help.100}', + activeBackground: '{help.200}', + color: '{help.600}', + }, + danger: { + hoverBackground: '{error.100}', + activeBackground: '{error.200}', + color: '{error.600}', + }, + }, + link: { + color: '{text.color}', + hoverColor: '{text.hoverColor}', + activeColor: '{text.mutedColor}', + }, + }, + dark: { + root: { + primary: { + background: '{primary.color}', + hoverBackground: '{primary.hoverColor}', + activeBackground: '{primary.activeColor}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{text.extend.colorPrimaryStatic}', + hoverColor: '{text.extend.colorPrimaryStatic}', + activeColor: '{text.extend.colorPrimaryStatic}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + secondary: { + background: '{surface.200}', + hoverBackground: '{surface.300}', + activeBackground: '{surface.400}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{surface.950}', + hoverColor: '{surface.950}', + activeColor: '{surface.950}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + contrast: { + background: '{surface.950}', + hoverBackground: '{surface.900}', + activeBackground: '{surface.800}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{surface.0}', + hoverColor: '{surface.0}', + activeColor: '{surface.0}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + info: { + background: '{info.500}', + hoverBackground: '{info.400}', + activeBackground: '{info.300}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{text.extend.colorPrimaryStatic}', + hoverColor: '{text.extend.colorPrimaryStatic}', + activeColor: '{text.extend.colorPrimaryStatic}', + }, + success: { + background: '{success.500}', + hoverBackground: '{success.400}', + activeBackground: '{success.300}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{text.extend.colorPrimaryStatic}', + hoverColor: '{text.extend.colorPrimaryStatic}', + activeColor: '{text.extend.colorPrimaryStatic}', + }, + warn: { + background: '{warn.500}', + hoverBackground: '{warn.400}', + activeBackground: '{warn.300}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{text.extend.colorPrimaryStatic}', + hoverColor: '{text.extend.colorPrimaryStatic}', + activeColor: '{text.extend.colorPrimaryStatic}', + }, + help: { + background: '{help.500}', + hoverBackground: '{help.400}', + activeBackground: '{help.300}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{text.extend.colorPrimaryStatic}', + hoverColor: '{text.extend.colorPrimaryStatic}', + activeColor: '{text.extend.colorPrimaryStatic}', + }, + danger: { + background: '{error.500}', + hoverBackground: '{error.400}', + activeBackground: '{error.300}', + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + activeBorderColor: '{transparent}', + color: '{text.extend.colorPrimaryStatic}', + hoverColor: '{text.extend.colorPrimaryStatic}', + activeColor: '{text.extend.colorPrimaryStatic}', + }, + }, + outlined: { + primary: { + hoverBackground: '{primary.hoverBackground}', + activeBackground: '{primary.activeBackground}', + borderColor: '{primary.borderColor}', + color: '{primary.color}', + }, + success: { + hoverBackground: '{success.950}', + activeBackground: '{success.900}', + borderColor: '{success.500}', + color: '{success.500}', + }, + info: { + hoverBackground: '{info.950}', + activeBackground: '{info.900}', + borderColor: '{info.500}', + color: '{info.500}', + }, + warn: { + hoverBackground: '{warn.950}', + activeBackground: '{warn.900}', + borderColor: '{warn.500}', + color: '{warn.500}', + }, + help: { + hoverBackground: '{help.950}', + activeBackground: '{help.900}', + borderColor: '{help.500}', + color: '{help.500}', + }, + danger: { + hoverBackground: '{error.950}', + activeBackground: '{error.900}', + borderColor: '{error.500}', + color: '{error.500}', + }, + }, + text: { + primary: { + hoverBackground: '{surface.800}', + activeBackground: '{surface.700}', + color: '{text.color}', + }, + success: { + hoverBackground: '{success.950}', + activeBackground: '{success.900}', + color: '{success.500}', + }, + info: { + hoverBackground: '{info.950}', + activeBackground: '{info.900}', + color: '{info.500}', + }, + warn: { + hoverBackground: '{warn.950}', + activeBackground: '{warn.900}', + color: '{warn.500}', + }, + help: { + hoverBackground: '{help.950}', + activeBackground: '{help.900}', + color: '{help.500}', + }, + danger: { + hoverBackground: '{error.950}', + activeBackground: '{error.900}', + color: '{error.500}', + }, + }, + link: { + color: '{text.color}', + hoverColor: '{text.hoverColor}', + activeColor: '{text.mutedColor}', + }, + }, + }, + root: { + borderRadius: '{controls.borderRadius.100}', + roundedBorderRadius: '{controls.borderRadius.max}', + gap: '{controls.gap.100}', + fontSize: '{fonts.fontSize.200}', + paddingX: '{controls.padding.400}', + paddingY: '{controls.padding.200}', + iconOnlyWidth: '{controls.iconOnly.700}', + raisedShadow: 'none', + badgeSize: '{feedback.width.500}', + transitionDuration: '{controls.transitionDuration}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + offset: '{focusRing.offset}', + }, + sm: { + fontSize: '{fonts.fontSize.200}', + iconOnlyWidth: '{controls.iconOnly.600}', + paddingX: '{controls.padding.300}', + paddingY: '{controls.padding.200}', + }, + lg: { + fontSize: '{fonts.fontSize.500}', + iconOnlyWidth: '{controls.iconOnly.850}', + paddingX: '{controls.padding.600}', + paddingY: '{controls.padding.400}', + }, + label: { + fontWeight: '{fonts.fontWeight.demibold}', + }, + }, + css: buttonCss, + }, + card: { + extend: { + borderColor: '{content.borderColor}', + borderWidth: '{content.borderWidth}', + }, + root: { + background: '{content.background}', + borderRadius: '{content.gap.400}', + color: '{content.color}', + }, + body: { + padding: '{content.padding.300}', + gap: '{content.gap.400}', + }, + caption: { + gap: '{content.gap.100}', + }, + title: { + fontSize: '{fonts.fontSize.400}', + fontWeight: '{fonts.fontWeight.demibold}', + }, + subtitle: { + color: '{text.mutedColor}', + }, + }, + carousel: { + colorScheme: { + light: { + indicator: { + background: '{surface.300}', + hoverBackground: '{surface.400}', + activeBackground: '{surface.900}', + }, + }, + }, + root: { + transitionDuration: '{media.transitionDuration}', + }, + content: { + gap: '{media.gap.200}', + }, + indicatorList: { + padding: '{media.padding.400}', + gap: '{media.gap.200}', + }, + indicator: { + width: '{controls.iconOnly.100}', + height: '{controls.iconOnly.100}', + borderRadius: '{media.borderRadius.400}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + }, + checkbox: { + root: { + borderRadius: '{form.borderRadius.100}', + extend: { + borderWidth: '{form.borderWidth}', + }, + width: '{form.size.400}', + height: '{form.size.400}', + background: '{form.background}', + checkedBackground: '{surface.900}', + checkedHoverBackground: '{surface.800}', + disabledBackground: '{form.disabledBackground}', + filledBackground: '{form.filledBackground}', + borderColor: '{form.borderColor}', + hoverBorderColor: '{form.hoverBorderPrimaryColor}', + focusBorderColor: '{form.focusBorderPrimaryColor}', + checkedBorderColor: '{surface.900}', + checkedHoverBorderColor: '{surface.800}', + checkedFocusBorderColor: '{primary.color}', + checkedDisabledBorderColor: '{form.borderColor}', + invalidBorderColor: '{form.invalidBorderColor}', + shadow: '0', + focusRing: { + focusRing: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + sm: { + width: '{form.size.200}', + height: '{form.size.200}', + }, + lg: { + width: '{form.size.350}', + height: '{form.size.350}', + }, + transitionDuration: '{form.transitionDuration}', + }, + icon: { + size: '{form.icon.300}', + color: '{form.color}', + checkedColor: '{primary.contrastColor}', + checkedHoverColor: '{primary.contrastColor}', + disabledColor: '{form.disabledColor}', + sm: { + size: '{form.icon.200}', + }, + lg: { + size: '{form.icon.400}', + }, + }, + }, + chip: { + extend: { + borderColor: '{transparent}', + borderWidth: '{controls.width.100}', + }, + root: { + borderRadius: '{media.borderRadius.100}', + paddingX: '{media.padding.200}', + paddingY: '{media.padding.100}', + gap: '{media.gap.200}', + transitionDuration: '{media.transitionDuration}', + }, + colorScheme: { + light: { + root: { + background: '{surface.200}', + color: '{text.color}', + }, + icon: { + color: '{text.color}', + }, + removeIcon: { + color: '{text.color}', + }, + }, + }, + image: { + width: '0rem', + height: '0rem', + }, + icon: { + size: '{media.icon.size.100}', + }, + removeIcon: { + size: '{media.icon.size.100}', + focusRing: { + width: '{form.focusRing.width}', + style: '{form.focusRing.style}', + color: '{focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + }, + confirmdialog: { + extend: { + extIcon: { + success: '{success.500}', + info: '{info.500}', + help: '{help.500}', + warn: '{warn.500}', + danger: '{error.500}', + }, + }, + icon: { + size: '{overlay.icon.size.200}', + color: '{overlay.modal.color}', + }, + content: { + gap: '0rem', + }, + }, + confirmpopup: { + root: { + background: '{overlay.popover.background}', + color: '{overlay.popover.color}', + shadow: '{overlay.popover.shadow}', + gutter: '{overlay.gap.300}', + arrowOffset: '{overlay.modal.padding.200}', + }, + content: { + padding: '{overlay.popover.padding.100}', + gap: '{overlay.gap.400}', + }, + icon: { + size: '{overlay.icon.size.200}', + color: '{overlay.popover.color}', + }, + footer: { + gap: '{overlay.gap.200}', + padding: + '0 {overlay.popover.padding} {overlay.popover.padding} {overlay.popover.padding}', + }, + }, + contextmenu: { + root: { + background: '{content.background}', + color: '{content.color}', + shadow: '{navigation.shadow}', + }, + list: { + padding: '{navigation.list.padding.md} 0', + gap: '{navigation.list.gap}', + }, + item: { + padding: '{navigation.item.padding}', + gap: '{navigation.item.gap}', + }, + submenu: { + mobileIndent: '{navigation.submenu.padding}', + }, + }, + datatable: { + colorScheme: { + light: { + root: { + color: '{text.color}', + borderColor: '{content.borderColor}', + }, + header: { + background: '{surface.50}', + color: '{text.color}', + }, + headerCell: { + background: '{surface.50}', + hoverBackground: '{surface.100}', + color: '{text.color}', + }, + footer: { + background: '{surface.100}', + color: '{text.color}', + }, + footerCell: { + background: '{content.hoverBackground}', + color: '{text.color}', + }, + row: { + stripedBackground: '{content.hoverBackground}', + }, + bodyCell: { + selectedBorderColor: '{content.borderColor}', + }, + }, + }, + extended: { + extHeaderCell: { + selectedHoverBackground: '{surface.800}', + }, + extRow: { + selectedHoverBackground: '{surface.800}', + stripedHoverBackground: '{surface.100}', + }, + }, + root: { + transitionDuration: '{data.transitionDuration}', + }, + header: { + borderColor: '{content.borderColor}', + borderWidth: '{data.width.100} 0 {data.width.100} 0', + padding: '{data.padding.400}', + sm: { + padding: '{data.padding.200}', + }, + lg: { + padding: '{data.padding.500}', + }, + }, + headerCell: { + selectedBackground: '{highlight.background}', + borderColor: '{content.borderColor}', + hoverColor: '{text.extend.colorInverted}', + selectedColor: '{highlight.color}', + gap: '{data.gap.200}', + padding: '{data.padding.400}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: 'inset {focus.ring.shadow}', + }, + sm: { + padding: '{data.padding.200}', + }, + lg: { + padding: '{data.padding.500}', + }, + }, + columnTitle: { + fontWeight: '{fonts.fontWeight.bold}', + }, + row: { + background: '{content.background}', + hoverBackground: '{content.hoverBackground}', + selectedBackground: '{highlight.background}', + color: '{content.color}', + hoverColor: '{content.hoverColor}', + selectedColor: '{highlight.color}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: 'inset {focus.ring.shadow}', + }, + }, + bodyCell: { + borderColor: '{content.borderColor}', + padding: '{data.padding.400}', + sm: { + padding: '{data.padding.200}', + }, + lg: { + padding: '{data.padding.500}', + }, + }, + footerCell: { + borderColor: '{content.borderColor}', + padding: '{data.padding.400}', + sm: { + padding: '{data.padding.200}', + }, + lg: { + padding: '{data.padding.500}', + }, + }, + columnFooter: { + fontWeight: '{fonts.fontWeight.bold}', + }, + dropPoint: { + color: '{highlight.background}', + }, + footer: { + borderColor: '{content.borderColor}', + borderWidth: '0 0 {data.width.100} 0', + padding: '{data.padding.400}', + sm: { + padding: '{data.padding.200}', + }, + lg: { + padding: '{data.padding.500}', + }, + }, + columnResizer: { + width: '{data.width.300}', + }, + resizeIndicator: { + width: '{data.width.100}', + color: '{highlight.background}', + }, + sortIcon: { + color: '{text.color}', + hoverColor: '{text.hoverColor}', + size: '{data.icon.size.100}', + }, + loadingIcon: { + size: '{data.icon.size.500}', + }, + rowToggleButton: { + hoverBackground: '{content.hoverBackground}', + selectedHoverBackground: '{content.hoverBackground}', + color: '{text.color}', + hoverColor: '{text.color}', + selectedHoverColor: '{text.color}', + size: '{data.icon.size.500}', + borderRadius: '{content.borderRadius}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + filter: { + inlineGap: '{data.gap.200}', + rule: { + borderColor: '{content.borderColor}', + }, + constraintList: { + padding: '{list.padding}', + gap: '{list.gap.100}', + }, + constraint: { + focusBackground: '{list.option.focusBackground}', + selectedBackground: '{list.option.selectedBackground}', + selectedFocusBackground: '{list.option.selectedFocusBackground}', + color: '{list.option.color}', + focusColor: '{list.option.focusColor}', + selectedColor: '{list.option.selectedColor}', + selectedFocusColor: '{list.option.selectedFocusColor}', + padding: '{list.option.padding}', + borderRadius: '{list.option.borderRadius}', + separator: { + borderColor: '{content.borderColor}', + }, + }, + overlaySelect: { + background: '{overlay.select.background}', + color: '{overlay.select.color}', + borderColor: '{overlay.select.borderColor}', + borderRadius: '{overlay.select.borderRadius}', + shadow: '{overlay.select.shadow}', + }, + overlayPopover: { + background: '{overlay.popover.background}', + color: '{overlay.popover.color}', + borderColor: '{overlay.select.borderColor}', + borderRadius: '{overlay.select.borderRadius}', + shadow: '{overlay.popover.shadow}', + padding: '{overlay.popover.padding.100}', + gap: '{list.gap.100}', + }, + }, + paginatorTop: { + borderColor: '{form.borderColor}', + borderWidth: '0 0 {data.width.100} 0', + }, + paginatorBottom: { + borderWidth: '0 0 {data.width.100} 0', + borderColor: '{content.borderColor}', + }, + }, + dataview: { + root: { + borderWidth: '{data.width.100}', + borderRadius: '{data.borderRadius}', + padding: '0rem', + borderColor: '{content.borderColor}', + }, + header: { + borderWidth: '0 0 {data.width.100} 0', + padding: '{data.padding.200} {data.padding.300}', + borderRadius: '0 0 0 0', + color: '{text.color}', + }, + content: { + background: '{content.background}', + color: '{content.color}', + borderColor: '{content.borderColor}', + borderWidth: '0rem', + padding: '0rem', + borderRadius: '0', + }, + footer: { + background: '{surface.100}', + color: '{text.color}', + borderWidth: '{data.width.100} 0 0 0', + padding: '{data.padding.200} {data.padding.300}', + borderRadius: '0 0 0 0', + }, + paginatorTop: { + borderWidth: '0 0 {data.width.100} 0', + }, + paginatorBottom: { + borderWidth: '{data.width.100} 0 0 0', + }, + }, + datepicker: { + extend: { + extDate: { + selectedHoverBackground: '{surface.800}', + }, + extToday: { + hoverBackground: '{content.hoverBackground}', + borderColor: '{content.activeBorderColor}', + }, + extTitle: { + width: '{form.width.500}', + }, + extTimePicker: { + minWidth: '{form.width.400}', + color: '{content.color}', + }, + }, + colorScheme: { + light: { + dropdown: { + background: '{content.background}', + hoverBackground: '{navigation.item.focusBackground}', + activeBackground: '{navigation.item.activeBackground}', + color: '{navigation.item.color}', + hoverColor: '{navigation.item.focusColor}', + activeColor: '{navigation.item.activeColor}', + }, + today: { + background: '{transparent}', + color: '{text.extend.colorPrimaryStatic}', + }, + }, + }, + panel: { + background: '{content.background}', + borderColor: '{content.borderColor}', + color: '{content.color}', + borderRadius: '{content.borderRadius}', + shadow: '{overlay.popover.shadow}', + padding: '0rem', + }, + header: { + background: '{content.background}', + borderColor: '{content.borderColor}', + color: '{content.color}', + padding: '{overlay.popover.padding.100}', + }, + title: { + gap: '{form.gap.200}', + fontWeight: '{fonts.fontWeight.bold}', + }, + selectMonth: { + hoverBackground: '{content.hoverBackground}', + color: '{content.color}', + hoverColor: '{content.hoverColor}', + borderRadius: '{content.borderRadius}', + padding: '{form.padding.200}', + }, + inputIcon: { + color: '{form.floatLabelColor}', + }, + dropdown: { + width: '{form.width.300}', + borderColor: '{form.borderColor}', + hoverBorderColor: '{form.borderColor}', + activeBorderColor: '{form.borderColor}', + borderRadius: '{form.borderRadius.200}', + focusRing: { + width: '{form.focusRing.width}', + style: '{form.focusRing.style}', + color: '{form.focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + sm: { + width: '0rem', + }, + lg: { + width: '0rem', + }, + }, + group: { + borderColor: '{content.borderColor}', + gap: '{overlay.popover.padding.100}', + }, + selectYear: { + hoverBackground: '{content.hoverBackground}', + color: '{content.color}', + hoverColor: '{content.hoverColor}', + borderRadius: '{content.borderRadius}', + padding: '{overlay.select.padding}', + }, + dayView: { + margin: '{overlay.popover.padding.100}', + }, + weekDay: { + padding: '{form.padding.100}', + fontWeight: '{fonts.fontWeight.bold}', + color: '{content.color}', + }, + date: { + hoverBackground: '{content.hoverBackground}', + selectedBackground: '{highlight.background}', + rangeSelectedBackground: '{list.option.focusBackground}', + color: '{content.color}', + hoverColor: '{content.color}', + selectedColor: '{text.extend.colorInverted}', + rangeSelectedColor: '{text.color}', + width: '{form.size.500}', + height: '{form.size.500}', + borderRadius: '{form.borderRadius.100}', + padding: '{form.padding.100}', + focusRing: { + width: '{form.focusRing.width}', + style: '{form.focusRing.style}', + color: '{form.focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + monthView: { + margin: '0 0 0 0', + }, + month: { + padding: '0', + borderRadius: '0rem', + }, + yearView: { + margin: '0 0 0 0', + }, + year: { + padding: '0', + borderRadius: '0rem', + }, + buttonbar: { + padding: '{overlay.popover.padding.100}', + borderColor: '{content.borderColor}', + }, + timePicker: { + padding: '{form.padding.300}', + borderColor: '{content.borderColor}', + gap: '{form.gap.200}', + buttonGap: '{form.gap.100}', + }, + root: { + transitionDuration: '{form.transitionDuration}', + }, + }, + dialog: { + extend: { + borderWidth: '{overlay.borderWidth}', + backdrop: '{overlay.modal.backdrop}', + }, + root: { + background: '{overlay.modal.background}', + borderColor: '{overlay.modal.borderColor}', + color: '{overlay.modal.color}', + borderRadius: '{overlay.modal.borderRadius}', + shadow: '{overlay.popover.shadow}', + }, + header: { + padding: + '{overlay.modal.padding.300} {overlay.modal.padding.300} 1rem {overlay.modal.padding.300}', + gap: '{overlay.gap.200}', + }, + title: { + fontSize: '{fonts.fontSize.500}', + fontWeight: '{fonts.fontWeight.demibold}', + }, + content: { + padding: '{content.padding.400}', + }, + footer: { + padding: + '0 {overlay.modal.padding.md} {overlay.modal.padding.md} {overlay.modal.padding.md}', + gap: '{content.gap.200}', + }, + }, + divider: { + colorScheme: { + light: { + content: { + background: '{content.background}', + color: '{text.mutedColor}', + }, + borderColor: '{content.borderColor}', + }, + }, + extend: { + content: { + gap: '{content.gap.200}', + }, + iconSize: '{media.icon.size.100}', + }, + horizontal: { + margin: '{content.padding.300} 0', + padding: '0 {content.padding.300}', + content: { + padding: '0 {content.padding.200}', + }, + }, + vertical: { + margin: '0 {content.padding.300}', + padding: '{content.padding.300} 0', + content: { + padding: '{content.padding.200} 0', + }, + }, + }, + drawer: { + extend: { + borderRadius: '{overlay.popover.borderRadius}', + borderWidth: '{overlay.borderWidth}', + width: '{overlay.width}', + extHeader: { + gap: '{overlay.gap.200}', + borderColor: '{drawer.root.borderColor}', + }, + padding: '{overlay.drawer.padding}', + scale: '0.125rem', + backdrop: '{overlay.modal.backdrop}', + }, + root: { + background: '{overlay.modal.background}', + borderColor: '{overlay.modal.borderColor}', + color: '{overlay.modal.color}', + shadow: '{overlay.modal.shadow}', + }, + header: { + padding: + '{overlay.modal.padding.300} {overlay.modal.padding.300} {overlay.modal.padding.100} {overlay.modal.padding.300} ', + }, + title: { + fontSize: '{fonts.fontSize.500}', + fontWeight: '{fonts.fontWeight.demibold}', + }, + content: { + padding: '{overlay.modal.padding.300}', + }, + footer: { + padding: + '0 {overlay.modal.padding.300} {overlay.modal.padding.300} {overlay.modal.padding.300} ', + }, + }, + fileupload: { + extend: { + extDragNdrop: { + background: '{surface.0}', + borderRadius: '{form.borderRadius.200}', + iconSize: '{form.size.500}', + padding: '{form.padding.400}', + info: { + gap: '{form.gap.100}', + }, + }, + extFile: { + iconSize: '{form.size.350}', + }, + extContent: { + borderRadius: '{content.borderRadius}', + highlightBorderDefault: '{form.borderColor}', + }, + }, + colorScheme: { + light: { + header: { + background: '{surface.0}', + color: '{text.color}', + }, + }, + }, + root: { + background: '{content.background}', + borderColor: '{content.borderColor}', + color: '{content.color}', + borderRadius: '{content.borderRadius}', + transitionDuration: '{form.transitionDuration}', + }, + header: { + borderColor: '{content.borderColor}', + borderWidth: '0rem', + padding: '0rem', + borderRadius: '0rem', + gap: '{content.gap.200}', + }, + content: { + highlightBorderColor: '{surface.900}', + padding: '0rem', + gap: '{content.gap.200}', + }, + file: { + padding: '{content.padding.200}', + gap: '{content.gap.200}', + borderColor: '{form.borderColor}', + info: { + gap: '{content.gap.100}', + }, + }, + fileList: { + gap: '{content.gap.200}', + }, + progressbar: { + height: '{feedback.height.100}', + }, + basic: { + gap: '{content.gap.200}', + }, + }, + floatlabel: { + extend: { + height: '{form.size.800}', + iconSize: '{form.icon.400}', + }, + root: { + color: '{form.floatLabelColor}', + focusColor: '{form.floatLabelFocusColor}', + activeColor: '{form.floatLabelActiveColor}', + invalidColor: '{form.floatLabelInvalidColor}', + transitionDuration: '{form.transitionDuration}', + positionX: '{form.padding.300}', + positionY: '{form.padding.300}', + fontWeight: '{fonts.fontWeight.regular}', + active: { + fontSize: '{fonts.fontSize.100}', + fontWeight: '{fonts.fontWeight.regular}', + }, + }, + over: { + active: { + top: '{form.padding.400}', + }, + }, + inside: { + input: { + paddingTop: '{form.padding.700}', + paddingBottom: '{form.padding.300}', + }, + active: { + top: '{form.padding.300}', + }, + }, + on: { + borderRadius: '0rem', + active: { + padding: '0 {form.padding.100}', + background: '{form.background}', + }, + }, + }, + galleria: { + extend: { + backdrop: '{overlay.modal.backdrop}', + }, + colorScheme: { + light: { + thumbnailContent: { + background: '{surface.100}', + }, + thumbnailNavButton: { + hoverBackground: '{colors.alpha.white.200}', + color: '{text.color}', + hoverColor: '{text.hoverColor}', + }, + indicatorButton: { + background: '{surface.300}', + hoverBackground: '{surface.400}', + }, + }, + }, + root: { + borderWidth: '{content.borderWidth}', + borderColor: '{content.borderColor}', + borderRadius: '{content.borderRadius}', + transitionDuration: '{media.transitionDuration}', + }, + navButton: { + background: '{transparent}', + hoverBackground: '{colors.alpha.white.200}', + color: '{text.extend.colorInverted}', + hoverColor: '{text.extend.colorInverted}', + size: '{media.size.600}', + gutter: '{media.gap.200}', + prev: { + borderRadius: '{navigation.item.borderRadius}', + }, + next: { + borderRadius: '{navigation.item.borderRadius}', + }, + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + navIcon: { + size: '{media.icon.size.300}', + }, + thumbnailsContent: { + padding: '{media.padding.100}', + }, + thumbnailNavButton: { + size: '{media.size.300}', + borderRadius: '{content.borderRadius}', + gutter: '{media.gap.200}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + thumbnailNavButtonIcon: { + size: '{media.icon.size.100}', + }, + caption: { + background: '{colors.alpha.white.500}', + color: '{text.color}', + padding: '{media.gap.200}', + }, + indicatorList: { + gap: '{media.gap.200}', + padding: '{media.padding.400}', + }, + indicatorButton: { + width: '{media.size.200}', + height: '{media.size.200}', + activeBackground: '{surface.900}', + borderRadius: '{content.borderRadius}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + insetIndicatorList: { + background: '{colors.alpha.black.500}', + }, + insetIndicatorButton: { + background: '{colors.alpha.white.100}', + hoverBackground: '{colors.alpha.white.200}', + activeBackground: '{colors.alpha.white.500}', + }, + closeButton: { + size: '{media.size.600}', + gutter: '{media.gap.200}', + background: '{colors.alpha.white.100}', + hoverBackground: '{colors.alpha.white.200}', + color: '{text.extend.colorInverted}', + hoverColor: '{text.extend.colorInverted}', + borderRadius: '{controls.borderRadius.200}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + closeButtonIcon: { + size: '{media.icon.size.300}', + }, + }, + inputgroup: { + extend: { + borderWidth: '{form.borderWidth}', + iconSize: '{form.icon.300}', + }, + colorScheme: { + light: { + addon: { + background: '{form.background}', + borderColor: '{form.borderColor}', + color: '{text.mutedColor}', + }, + }, + }, + addon: { + borderRadius: '{form.borderRadius.200}', + padding: '{form.padding.300}', + minWidth: '{form.width.300}', + }, + }, + inputnumber: { + extend: { + borderWidth: '{form.borderWidth}', + extButton: { + height: '{form.size.600}', + iconSize: '{form.icon.300}', + }, + }, + colorScheme: { + light: { + button: { + background: '{content.background}', + hoverBackground: '{content.hoverBackground}', + activeBackground: '{transparent}', + borderColor: '{form.borderColor}', + hoverBorderColor: '{form.borderColor}', + activeBorderColor: '{form.borderColor}', + color: '{text.color}', + hoverColor: '{text.hoverColor}', + activeColor: '{text.color}', + }, + }, + }, + transitionDuration: { + transitionDuration: '{form.transitionDuration}', + }, + button: { + width: '{form.width.300}', + borderRadius: '{form.borderRadius.200}', + verticalPadding: '{form.padding.300}', + }, + }, + inputotp: { + extend: { + height: '{form.size.600}', + borderWidth: '{form.borderWidth}', + }, + root: { + gap: '{form.gap.200}', + }, + input: { + width: '{form.width.400}', + }, + sm: { + width: '0rem', + }, + lg: { + width: '0rem', + }, + }, + inputtext: { + extend: { + readonlyBackground: '{form.readonlyBackground}', + iconSize: '{form.icon.300}', + borderWidth: '{form.borderWidth}', + extXlg: { + fontSize: '{form.fontSize}', + paddingX: '{form.paddingX}', + paddingY: '{form.paddingY}', + }, + }, + root: { + background: '{form.background}', + disabledBackground: '{form.disabledBackground}', + filledBackground: '{form.filledBackground}', + filledHoverBackground: '{form.filledHoverBackground}', + filledFocusBackground: '{form.filledFocusBackground}', + borderColor: '{form.borderColor}', + hoverBorderColor: '{form.hoverBorderSecondaryColor}', + focusBorderColor: '{form.focusBorderSecondaryColor}', + invalidBorderColor: '{form.invalidBorderColor}', + color: '{text.color}', + disabledColor: '{form.disabledColor}', + placeholderColor: '{form.placeholderColor}', + invalidPlaceholderColor: '{form.invalidPlaceholderColor}', + shadow: '0', + paddingX: '{form.paddingX}', + paddingY: '{form.paddingY}', + borderRadius: '{form.borderRadius.200}', + transitionDuration: '{form.transitionDuration}', + sm: { + fontSize: '{form.fontSize}', + paddingX: '{form.paddingX}', + paddingY: '{form.paddingY}', + }, + lg: { + fontSize: '{form.fontSize}', + paddingX: '{form.paddingX}', + paddingY: '{form.paddingY}', + }, + focusRing: { + width: '{form.focusRing.width}', + style: '{form.focusRing.style}', + color: '{form.focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '0', + }, + }, + }, + listbox: { + extend: { + extOption: { + label: { + gap: '{list.gap.100}', + }, + caption: { + color: '{text.mutedColor}', + stripedColor: '{text.mutedColor}', + }, + gap: '{list.gap.200}', + }, + }, + colorScheme: { + light: { + option: { + stripedBackground: '{surface.50}', + }, + }, + }, + root: { + background: '{form.background}', + disabledBackground: '{form.disabledBackground}', + borderColor: '{form.borderColor}', + invalidBorderColor: '{form.invalidBorderColor}', + color: '{form.color}', + disabledColor: '{form.disabledColor}', + shadow: '0', + borderRadius: '{form.borderRadius.200}', + transitionDuration: '{form.transitionDuration}', + }, + list: { + padding: '{list.padding}', + gap: '{list.gap.100}', + header: { + padding: '{list.header.padding}', + }, + }, + option: { + focusBackground: '{list.option.focusBackground}', + selectedBackground: '{list.option.selectedBackground}', + selectedFocusBackground: '{list.option.selectedFocusBackground}', + color: '{list.option.color}', + focusColor: '{list.option.focusColor}', + selectedColor: '{list.option.selectedColor}', + selectedFocusColor: '{list.option.selectedFocusColor}', + padding: '{list.option.padding}', + borderRadius: '{list.option.borderRadius}', + }, + optionGroup: { + background: '{list.optionGroup.background}', + color: '{list.optionGroup.color}', + fontWeight: '{fonts.fontWeight.demibold}', + padding: '{list.option.padding}', + }, + checkmark: { + color: '{list.option.color}', + gutterStart: '-{list.gap.200}', + gutterEnd: '{list.gap.200}', + }, + emptyMessage: { + padding: '{list.option.padding}', + }, + }, + megamenu: { + extend: { + extItem: { + caption: { + color: '{text.mutedColor}', + gap: '{content.gap.100}', + }, + }, + iconSize: '{navigation.submenuIcon.size}', + }, + colorScheme: { + light: { + root: { + background: '{transparent}', + }, + }, + }, + root: { + borderColor: '{transparent}', + borderRadius: '{content.borderRadius}', + color: '{content.color}', + gap: '{content.gap.100}', + transitionDuration: '{form.transitionDuration}', + verticalOrientation: { + padding: '{navigation.list.padding.100}', + gap: '{navigation.list.gap}', + }, + horizontalOrientation: { + padding: '{navigation.list.padding.100}', + gap: '{navigation.list.gap}', + }, + }, + baseItem: { + borderRadius: '{content.borderRadius}', + padding: '{navigation.item.padding}', + }, + item: { + focusBackground: '{navigation.item.focusBackground}', + activeBackground: '{navigation.item.activeBackground}', + color: '{navigation.item.color}', + focusColor: '{navigation.item.focusColor}', + activeColor: '{navigation.item.activeColor}', + padding: '{navigation.item.padding}', + borderRadius: '{navigation.item.borderRadius}', + gap: '{navigation.item.gap}', + icon: { + color: '{navigation.item.icon.color}', + focusColor: '{navigation.item.icon.focusColor}', + activeColor: '{navigation.item.icon.activeColor}', + }, + }, + overlay: { + padding: '{content.padding.100}', + background: '{content.background}', + borderColor: '{content.borderColor}', + borderRadius: '{content.borderRadius}', + color: '{content.color}', + shadow: '{navigation.shadow}', + gap: '0rem', + }, + submenu: { + padding: '{navigation.list.padding.100}', + gap: '{navigation.list.gap}', + }, + submenuLabel: { + padding: '{navigation.submenuLabel.padding}', + background: '{navigation.submenuLabel.background}', + color: '{navigation.submenuLabel.color}', + }, + submenuIcon: { + size: '{navigation.submenuIcon.size}', + color: '{navigation.submenuIcon.color}', + focusColor: '{navigation.submenuIcon.focusColor}', + activeColor: '{navigation.submenuIcon.activeColor}', + }, + separator: { + borderColor: '{content.borderColor}', + }, + mobileButton: { + borderRadius: '{navigation.item.borderRadius}', + size: '{controls.iconOnly.600}', + color: '{text.color}', + hoverColor: '{text.hoverColor}', + hoverBackground: '{content.hoverBackground}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + }, + menu: { + extend: { + paddingX: '0.25rem', + iconSize: '{navigation.submenuIcon.size}', + paddingY: '0.25rem', + extItem: { + caption: { + gap: '{content.gap.100}', + }, + activeBackground: '{navigation.item.activeBackground}', + activeColor: '{navigation.item.activeColor}', + }, + }, + colorScheme: { + light: { + extend: { + extItem: { + caption: { + color: '{text.mutedColor}', + }, + icon: { + activeColor: '{navigation.item.icon.activeColor}', + }, + }, + }, + root: { + background: '{content.background}', + borderColor: '{content.borderColor}', + color: '{content.color}', + }, + item: { + focusBackground: '{navigation.item.focusBackground}', + color: '{navigation.item.color}', + focusColor: '{navigation.item.focusColor}', + icon: { + color: '{navigation.item.icon.color}', + focusColor: '{navigation.item.icon.focusColor}', + }, + }, + }, + }, + root: { + borderRadius: '{content.borderRadius}', + shadow: '{navigation.shadow}', + transitionDuration: '{form.transitionDuration}', + }, + list: { + padding: '{navigation.list.padding.100}', + gap: '{navigation.list.gap}', + }, + submenuLabel: { + padding: '{navigation.submenuLabel.padding}', + fontWeight: '{fonts.fontWeight.demibold}', + background: '{navigation.submenuLabel.background}', + color: '{navigation.submenuLabel.color}', + }, + separator: { + borderColor: '{content.borderColor}', + }, + item: { + padding: '{navigation.item.padding}', + borderRadius: '{navigation.item.borderRadius}', + gap: '{navigation.item.gap}', + }, + }, + menubar: { + extend: { + iconSize: '{navigation.submenuIcon.size}', + extItem: { + caption: { + color: '{text.mutedColor}', + gap: '{content.padding.100}', + }, + }, + extSubmenuLabel: { + padding: '{navigation.submenuLabel.padding}', + fontWeight: '{fonts.fontWeight.demibold}', + background: '{navigation.submenuLabel.background}', + color: '{navigation.submenuLabel.color}', + }, + }, + colorScheme: { + light: { + root: { + background: '{transparent}', + }, + }, + }, + root: { + borderColor: '{transparent}', + borderRadius: '{navigation.item.borderRadius}', + color: '{content.color}', + gap: '{content.padding.100}', + padding: '{navigation.list.padding.100}', + transitionDuration: '{form.transitionDuration}', + }, + baseItem: { + borderRadius: '{navigation.item.borderRadius}', + padding: '{navigation.item.padding}', + }, + item: { + focusBackground: '{navigation.item.focusBackground}', + activeBackground: '{navigation.item.activeBackground}', + color: '{navigation.item.color}', + focusColor: '{navigation.item.focusColor}', + activeColor: '{navigation.item.activeColor}', + padding: '{navigation.item.padding}', + borderRadius: '{navigation.item.borderRadius}', + gap: '{navigation.item.gap}', + icon: { + color: '{navigation.item.icon.color}', + focusColor: '{navigation.item.icon.focusColor}', + activeColor: '{navigation.item.icon.activeColor}', + }, + }, + submenu: { + padding: '{navigation.list.padding.100}', + gap: '{navigation.list.gap}', + background: '{content.background}', + borderColor: '{content.borderColor}', + borderRadius: '{content.borderRadius}', + shadow: '{navigation.shadow}', + mobileIndent: '{navigation.padding.200}', + icon: { + size: '{navigation.submenuIcon.size}', + color: '{navigation.submenuIcon.color}', + focusColor: '{navigation.submenuIcon.focusColor}', + activeColor: '{navigation.submenuIcon.activeColor}', + }, + }, + separator: { + borderColor: '{content.borderColor}', + }, + mobileButton: { + borderRadius: '{navigation.item.borderRadius}', + size: '{controls.iconOnly.600}', + color: '{text.color}', + hoverColor: '{text.hoverColor}', + hoverBackground: '{content.hoverBackground}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + }, + message: { + extend: { + width: '{messages.width}', + extText: { + gap: '{feedback.gap.100}', + }, + extInfo: { + color: '{info.500}', + closeButton: { + color: '{info.500}', + borderColor: '{info.500}', + }, + caption: { + color: '{text.color}', + }, + }, + extAccentLine: { + width: '{feedback.width.200}', + }, + extCloseButton: { + width: '{feedback.width.100}', + }, + extSuccess: { + color: '{success.500}', + closeButton: { + color: '{success.500}', + borderColor: '{success.500}', + }, + caption: { + color: '{text.color}', + }, + }, + extWarn: { + color: '{warn.500}', + closeButton: { + color: '{warn.500}', + borderColor: '{warn.500}', + }, + caption: { + color: '{text.color}', + }, + }, + extError: { + color: '{error.500}', + closeButton: { + color: '{error.500}', + borderColor: '{error.500}', + }, + caption: { + color: '{text.color}', + }, + }, + }, + colorScheme: { + light: { + success: { + background: '{success.50}', + borderColor: '{success.500}', + color: '{text.color}', + shadow: 'none', + outlined: { + color: '{text.color}', + borderColor: '{success.500}', + }, + closeButton: { + hoverBackground: '{success.200}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + simple: { + color: '{text.color}', + }, + }, + outlined: { + root: { + borderWidth: '0rem', + }, + closeButton: { + hoverBackground: '{transparent}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + outlined: { + color: '{transparent}', + borderColor: '{transparent}', + }, + simple: { + color: '{transparent}', + }, + }, + simple: { + content: { + padding: '0rem', + }, + }, + warn: { + background: '{warn.50}', + borderColor: '{warn.500}', + color: '{text.color}', + shadow: 'none', + outlined: { + color: '{text.color}', + borderColor: '{warn.500}', + }, + closeButton: { + hoverBackground: '{warn.200}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + simple: { + color: '{text.color}', + }, + }, + error: { + background: '{error.50}', + borderColor: '{error.500}', + color: '{text.color}', + shadow: 'none', + outlined: { + color: '{text.color}', + borderColor: '{error.500}', + }, + closeButton: { + hoverBackground: '{error.200}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + simple: { + color: '{text.color}', + }, + }, + secondary: { + borderColor: '{transparent}', + shadow: 'none', + closeButton: { + hoverBackground: '{transparent}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + simple: { + color: '{transparent}', + }, + outlined: { + color: '{transparent}', + borderColor: '{transparent}', + }, + }, + contrast: { + borderColor: '{transparent}', + shadow: 'none', + closeButton: { + hoverBackground: '{transparent}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + simple: { + color: '{transparent}', + }, + outlined: { + color: '{transparent}', + borderColor: '{transparent}', + }, + }, + info: { + background: '{info.50}', + borderColor: '{info.500}', + color: '{text.color}', + shadow: 'none', + closeButton: { + hoverBackground: '{info.200}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + outlined: { + color: '{text.color}', + borderColor: '{info.500}', + }, + simple: { + color: '{text.color}', + }, + }, + }, + }, + root: { + borderRadius: '{content.borderRadius}', + borderWidth: '{feedback.width.100}', + transitionDuration: '{feedback.transitionDuration}', + }, + content: { + padding: '{feedback.padding.200}', + gap: '{feedback.gap.400}', + sm: { + padding: '{feedback.padding.200}', + }, + lg: { + padding: '{feedback.padding.200}', + }, + }, + text: { + fontSize: '{fonts.fontSize.300}', + fontWeight: '{fonts.fontWeight.bold}', + sm: { + fontSize: '{fonts.fontSize.300}', + }, + lg: { + fontSize: '{fonts.fontSize.300}', + }, + }, + icon: { + size: '{feedback.icon.size.500}', + sm: { + size: '{feedback.icon.size.500}', + }, + lg: { + size: '{feedback.icon.size.500}', + }, + }, + closeButton: { + width: '{controls.iconOnly.600}', + height: '{controls.iconOnly.600}', + borderRadius: '{controls.borderRadius.100}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + offset: '{focusRing.offset}', + }, + }, + closeIcon: { + size: '{feedback.icon.size.200}', + sm: { + size: '{feedback.icon.size.200}', + }, + lg: { + size: '{feedback.icon.size.200}', + }, + }, + }, + metergroup: { + extend: { + extLabel: { + color: '{text.mutedColor}', + }, + }, + root: { + borderRadius: '{content.borderRadius}', + gap: '{feedback.gap.300}', + }, + meters: { + size: '{feedback.height.100}', + background: '{content.borderColor}', + }, + label: { + gap: '{feedback.gap.100}', + }, + labelMarker: { + size: '{feedback.icon.size.100}', + }, + labelIcon: { + size: '{feedback.icon.size.200}', + }, + labelList: { + verticalGap: '{feedback.gap.200}', + horizontalGap: '{feedback.gap.300}', + }, + }, + multiselect: { + colorScheme: { + overlay: { + background: '{overlay.select.background}', + borderColor: '{overlay.select.borderColor}', + color: '{overlay.select.color}', + }, + option: { + focusBackground: '{list.option.focusBackground}', + selectedBackground: '{list.option.selectedBackground}', + selectedFocusBackground: '{list.option.selectedFocusBackground}', + color: '{list.option.color}', + focusColor: '{list.option.focusColor}', + selectedColor: '{list.option.selectedColor}', + selectedFocusColor: '{list.option.selectedFocusColor}', + }, + root: { + background: '{form.background}', + disabledBackground: '{form.disabledBackground}', + filledBackground: '{form.filledBackground}', + filledHoverBackground: '{form.filledHoverBackground}', + filledFocusBackground: '{form.filledFocusBackground}', + borderColor: '{form.borderColor}', + hoverBorderColor: '{form.hoverBorderSecondaryColor}', + focusBorderColor: '{form.focusBorderSecondaryColor}', + invalidBorderColor: '{form.invalidBorderColor}', + color: '{form.color}', + disabledColor: '{form.disabledColor}', + placeholderColor: '{form.placeholderColor}', + invalidPlaceholderColor: '{form.invalidPlaceholderColor}', + focusRing: { + color: '{form.focusRing.color}', + }, + }, + dropdown: { + color: '{form.floatLabelColor}', + }, + optionGroup: { + background: '{list.optionGroup.background}', + color: '{list.optionGroup.color}', + }, + clearIcon: { + color: '{form.floatLabelColor}', + }, + }, + extend: { + paddingX: '0.3571rem', + paddingY: '0.3571rem', + borderWidth: '{form.borderWidth}', + iconSize: '{form.icon.300}', + width: '{form.width}', + readonlyBackground: '{form.readonlyBackground}', + }, + root: { + shadow: '0', + paddingX: '{form.paddingX}', + paddingY: '{form.paddingY}', + borderRadius: '{form.borderRadius.200}', + transitionDuration: '{form.transitionDuration}', + sm: { + fontSize: '{fonts.fontSize.300}', + paddingX: '{form.padding.200}', + paddingY: '{form.padding.200}', + }, + lg: { + fontSize: '{fonts.fontSize.300}', + paddingX: '{form.padding.400}', + paddingY: '{form.padding.400}', + }, + focusRing: { + width: '{form.focusRing.width}', + style: '{form.focusRing.style}', + offset: '{form.focusRing.offset}', + shadow: '0', + }, + }, + dropdown: { + width: '{form.width.300}', + }, + overlay: { + borderRadius: '{overlay.select.borderRadius}', + shadow: '{overlay.select.shadow}', + }, + list: { + padding: '{list.padding}', + header: { + padding: '{list.header.padding}', + }, + gap: '{list.gap.100}', + }, + chip: { + borderRadius: '{form.borderRadius.100}', + }, + option: { + padding: '{list.option.padding}', + borderRadius: '{list.option.borderRadius}', + gap: '{list.gap.200}', + }, + optionGroup: { + fontWeight: '{fonts.fontWeight.demibold}', + padding: '{list.optionGroup.padding}', + }, + emptyMessage: { + padding: '{list.option.padding}', + }, + }, + paginator: { + root: { + padding: '0 {data.padding.200}', + gap: '{data.gap.200}', + borderRadius: '{content.borderRadius}', + background: '{transparent}', + color: '{content.color}', + transitionDuration: '{data.transitionDuration}', + }, + currentPageReport: { + color: '{text.mutedColor}', + }, + navButton: { + background: '{transparent}', + hoverBackground: '{content.hoverBackground}', + selectedBackground: '{highlight.background}', + color: '{text.color}', + hoverColor: '{text.hoverColor}', + selectedColor: '{text.extend.colorInverted}', + width: '{data.icon.size.700}', + height: '{data.icon.size.700}', + borderRadius: '{content.borderRadius}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + focus: '{focusRing.shadow}', + }, + }, + jumpToPageInput: { + maxWidth: '{data.width.400}', + }, + }, + panelmenu: { + extend: { + extPanel: { + gap: '{content.gap.100}', + }, + iconSize: '{navigation.submenuIcon.size}', + extItem: { + activeBackground: '{navigation.item.activeBackground}', + activeColor: '{navigation.item.activeColor}', + caption: { + color: '{text.mutedColor}', + gap: '{content.gap.100}', + }, + }, + }, + root: { + gap: '{content.gap.100}', + transitionDuration: '{form.transitionDuration}', + }, + panel: { + background: '{transparent}', + borderColor: '{transparent}', + borderWidth: '{navigation.width.100}', + color: '{content.color}', + padding: '{content.padding.100}', + borderRadius: '{content.borderRadius}', + first: { + borderWidth: + '{navigation.width.100} {navigation.width.100} 0 {navigation.width.100}', + topBorderRadius: '{content.borderRadius}', + }, + last: { + borderWidth: + '0 {navigation.width.100} {navigation.width.100} {navigation.width.100}', + topBorderRadius: '{content.borderRadius}', + }, + }, + item: { + focusBackground: '{navigation.item.focusBackground}', + color: '{navigation.item.color}', + focusColor: '{navigation.item.focusColor}', + gap: '{navigation.item.gap}', + padding: '{navigation.item.padding}', + borderRadius: '{navigation.item.borderRadius}', + icon: { + color: '{navigation.item.icon.color}', + focusColor: '{navigation.item.icon.focusColor}', + }, + }, + submenu: { + indent: '{navigation.padding.400}', + }, + separator: { + borderColor: '{content.borderColor}', + }, + submenuIcon: { + color: '{navigation.submenuIcon.color}', + focusColor: '{navigation.submenuIcon.focusColor}', + }, + }, + password: { + extend: { + borderWidth: '{form.borderWidth}', + }, + colorScheme: { + light: { + strength: { + weakBackground: '{error.500}', + mediumBackground: '{warn.500}', + strongBackground: '{success.600}', + }, + icon: { + color: '{form.placeholderColor}', + }, + }, + }, + meter: { + background: '{content.borderColor}', + borderRadius: '{content.borderRadius}', + height: '{feedback.height.100}', + }, + overlay: { + background: '{overlay.popover.background}', + borderColor: '{overlay.popover.borderColor}', + borderRadius: '{overlay.popover.borderRadius}', + color: '{overlay.popover.color}', + padding: '{overlay.popover.padding.100}', + shadow: '{overlay.popover.shadow}', + }, + content: { + gap: '{content.gap.200}', + }, + }, + popover: { + extend: { + borderWidth: '{overlay.borderWidth}', + arrow: { + width: '{overlay.popover.width.200}', + height: '{overlay.popover.width.100}', + }, + }, + root: { + background: '{overlay.popover.background}', + borderColor: '{overlay.popover.borderColor}', + color: '{overlay.popover.color}', + borderRadius: '{overlay.popover.borderRadius}', + shadow: '{overlay.popover.shadow}', + gutter: '{overlay.gap.100}', + arrowOffset: '{overlay.popover.padding.200}', + }, + content: { + padding: '{overlay.popover.padding.100}', + }, + }, + progressbar: { + label: { + color: '{text.extend.colorPrimaryStatic}', + fontSize: '{fonts.fontSize.100}', + fontWeight: '{fonts.fontWeight.regular}', + }, + root: { + background: '{content.borderColor}', + borderRadius: '{content.borderRadius}', + height: '{feedback.height.300}', + }, + value: { + background: '{primary.color}', + }, + }, + progressspinner: { + extend: { + small: '{feedback.width.500}', + medium: '{feedback.width.700}', + large: '{feedback.width.800}', + xlarge: '{feedback.width.900}', + }, + colorScheme: { + light: { + root: { + colorOne: '{success.500}', + colorTwo: '{info.500}', + colorThree: '{error.500}', + colorFour: '{warn.500}', + }, + }, + }, + root: { + borderWidth: '{feedback.width.200}', + }, + }, + radiobutton: { + root: { + width: '{form.size.400}', + height: '{form.size.400}', + background: '{form.background}', + checkedBackground: '{surface.900}', + checkedHoverBackground: '{surface.800}', + disabledBackground: '{form.disabledBackground}', + filledBackground: '{form.filledBackground}', + borderColor: '{form.borderColor}', + hoverBorderColor: '{form.hoverBorderPrimaryColor}', + focusBorderColor: '{form.borderColor}', + checkedBorderColor: '{surface.900}', + checkedHoverBorderColor: '{form.hoverBorderPrimaryColor}', + checkedFocusBorderColor: '{form.focusBorderPrimaryColor}', + checkedDisabledBorderColor: '{form.borderColor}', + invalidBorderColor: '{form.invalidBorderColor}', + shadow: '0', + transitionDuration: '{form.transitionDuration}', + }, + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + sm: { + width: '{form.size.300}', + height: '{form.size.300}', + }, + lg: { + width: '{form.size.350}', + height: '{form.size.350}', + }, + icon: { + size: '{form.icon.200}', + checkedColor: '{text.extend.colorInverted}', + checkedHoverColor: '{text.extend.colorInverted}', + disabledColor: '{text.mutedColor}', + sm: { + size: '{form.icon.100}', + }, + lg: { + size: '{form.icon.300}', + }, + }, + }, + rating: { + root: { + gap: '{form.gap.200}', + transitionDuration: '{form.transitionDuration}', + }, + focusRing: { + width: '{form.focusRing.width}', + style: '{form.focusRing.style}', + color: '{form.focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + icon: { + size: '{form.icon.500}', + color: '{surface.500}', + hoverColor: '{warn.500}', + activeColor: '{warn.500}', + }, + }, + ripple: { + colorScheme: { + light: { + root: { + background: 'rgba(255, 255, 255, 0.0100)', + }, + }, + }, + }, + scrollpanel: { + colorScheme: { + light: { + bar: { + background: '{surface.300}', + }, + }, + }, + root: { + transitionDuration: '{media.transitionDuration}', + }, + bar: { + size: '{media.size.200}', + borderRadius: '{media.borderRadius.100}', + focusRing: { + width: '0rem', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + }, + select: { + extend: { + extOption: { + background: '{list.option.background}', + gap: '{list.gap.200}', + }, + extOptionGroup: { + gap: '{list.gap.200}', + }, + readonlyBackground: '{form.readonlyBackground}', + borderWidth: '{form.borderWidth}', + iconSize: '{form.icon.300}', + }, + root: { + background: '{form.background}', + disabledBackground: '{form.disabledBackground}', + filledBackground: '{form.filledBackground}', + filledHoverBackground: '{form.filledHoverBackground}', + filledFocusBackground: '{form.filledFocusBackground}', + borderColor: '{form.borderColor}', + hoverBorderColor: '{form.hoverBorderSecondaryColor}', + focusBorderColor: '{form.focusBorderSecondaryColor}', + invalidBorderColor: '{form.invalidBorderColor}', + color: '{text.color}', + disabledColor: '{form.disabledColor}', + placeholderColor: '{form.placeholderColor}', + invalidPlaceholderColor: '{form.invalidPlaceholderColor}', + shadow: '0', + paddingX: '{form.paddingX}', + paddingY: '{form.paddingY}', + borderRadius: '{form.borderRadius.200}', + transitionDuration: '{form.transitionDuration}', + sm: { + fontSize: '{form.fontSize}', + paddingX: '{form.paddingX}', + paddingY: '{form.paddingY}', + }, + lg: { + fontSize: '{form.fontSize}', + paddingX: '{form.paddingX}', + paddingY: '{form.paddingY}', + }, + focusRing: { + width: '{form.focusRing.width}', + style: '{form.focusRing.style}', + color: '{form.focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '0', + }, + }, + dropdown: { + width: '{form.width.300}', + color: '{form.iconColor}', + }, + overlay: { + background: '{overlay.select.background}', + borderColor: '{overlay.select.borderColor}', + borderRadius: '{overlay.select.borderRadius}', + color: '{overlay.select.color}', + shadow: '{overlay.select.shadow}', + }, + list: { + padding: '{list.padding}', + gap: '{list.gap.100}', + header: { + padding: '{list.header.padding}', + }, + }, + option: { + focusBackground: '{list.option.focusBackground}', + selectedBackground: '{list.option.selectedBackground}', + selectedFocusBackground: '{list.option.selectedFocusBackground}', + color: '{list.option.color}', + focusColor: '{list.option.focusColor}', + selectedColor: '{list.option.selectedColor}', + selectedFocusColor: '{list.option.selectedFocusColor}', + padding: '{list.option.padding}', + borderRadius: '{list.option.borderRadius}', + }, + optionGroup: { + background: '{list.optionGroup.background}', + color: '{list.optionGroup.color}', + fontWeight: '{fonts.fontWeight.demibold}', + padding: '{list.option.padding}', + }, + clearIcon: { + color: '{form.iconColor}', + }, + checkmark: { + color: '{list.option.color}', + gutterStart: '-{form.padding.200}', + gutterEnd: '{form.padding.200}', + }, + emptyMessage: { + padding: '{list.option.padding}', + }, + }, + selectbutton: { + extend: { + gap: '{form.gap.100}', + paddingX: '{controls.padding.100}', + paddingY: '{controls.padding.100}', + checkedBackground: '{form.background}', + iconSize: { + sm: '{controls.iconOnly.200}', + md: '{controls.iconOnly.300}', + lg: '{controls.iconOnly.400}', + xlg: '{controls.iconOnly.500}', + }, + checkedBorderColor: '{form.background}', + checkedColor: '{form.color}', + ext: { + borderRadius: '{borderRadius.200}', + }, + }, + colorScheme: { + light: { + root: { + invalidBorderColor: '{form.invalidBorderColor}', + }, + extend: { + background: '{surface.200}', + }, + }, + }, + root: { + borderRadius: '{form.borderRadius.200}', + }, + }, + skeleton: { + extend: { + minWidth: '{feedback.width.700}', + height: '{feedback.height.650}', + }, + colorScheme: { + light: { + root: { + background: '{surface.200}', + animationBackground: '{surface.100}', + }, + }, + }, + root: { + borderRadius: '{content.borderRadius}', + }, + }, + slider: { + colorScheme: { + handle: { + content: { + background: '{surface.0}', + }, + }, + }, + root: { + transitionDuration: '{form.transitionDuration}', + }, + track: { + background: '{content.borderColor}', + borderRadius: '{content.borderRadius}', + size: '{form.size.150}', + }, + range: { + background: '{surface.900}', + }, + handle: { + width: '{form.size.350}', + height: '{form.size.350}', + borderRadius: '{form.borderRadius.300}', + background: '{surface.900}', + hoverBackground: '{surface.900}', + focusRing: { + width: '{form.focusRing.width}', + style: '{form.focusRing.style}', + color: '{form.focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + content: { + borderRadius: '{form.borderRadius.300}', + hoverBackground: '{surface.900}', + width: '{form.size.250}', + height: '{form.size.250}', + shadow: 'none', + }, + }, + }, + splitter: { + colorScheme: { + light: { + handle: { + background: '{surface.900}', + }, + }, + }, + gutter: { + background: '{surface.100}', + }, + root: { + background: '{content.background}', + borderColor: '{content.borderColor}', + color: '{content.color}', + transitionDuration: '{controls.transitionDuration}', + }, + handle: { + size: '{form.size.150}', + borderRadius: '{content.borderRadius}', + focusRing: { + width: '{form.focusRing.width}', + style: '{form.focusRing.style}', + color: '{form.focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + }, + stepper: { + extend: { + extCaption: { + gap: '{feedback.gap.100}', + }, + extStepNumber: { + invalidBackground: '{error.400}', + invalidColor: '{error.900}', + invalidBorderColor: '{error.400}', + borderWidth: '{feedback.width.100}', + iconSize: '{feedback.icon.size.300}', + }, + }, + root: { + transitionDuration: '{feedback.transitionDuration}', + }, + separator: { + background: '{content.borderColor}', + activeBackground: '{form.focusBorderPrimaryColor}', + margin: '0 0 0 1.625rem', + size: '{form.size.100}', + }, + step: { + padding: '{feedback.padding.100}', + gap: '{feedback.gap.200}', + }, + stepHeader: { + padding: '0rem', + borderRadius: '0rem', + gap: '{feedback.gap.200}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + stepTitle: { + color: '{text.color}', + activeColor: '{text.color}', + fontWeight: '{fonts.fontWeight.regular}', + }, + stepNumber: { + background: '{content.background}', + activeBackground: '{primary.color}', + borderColor: '{content.borderColor}', + activeBorderColor: '{primary.color}', + color: '{text.color}', + activeColor: '{text.extend.colorPrimaryStatic}', + size: '{form.size.400}', + fontSize: '{fonts.fontSize.300}', + fontWeight: '{fonts.fontWeight.bold}', + borderRadius: '{form.borderRadius.300}', + shadow: 'none', + }, + steppanels: { + padding: '{feedback.padding.200}', + }, + steppanel: { + background: '{content.background}', + color: '{content.color}', + padding: '0rem', + indent: '0rem', + }, + }, + steps: { + itemLink: { + gap: '{form.gap.200}', + }, + itemLabel: { + fontWeight: '{fonts.fontWeight.regular}', + }, + itemNumber: { + background: '{content.background}', + size: '{form.size.500}', + fontSize: '{fonts.fontSize.300}', + fontWeight: '{fonts.fontWeight.bold}', + borderRadius: '{form.borderRadius.300}', + shadow: 'none', + }, + }, + tabs: { + colorScheme: { + light: { + navButton: { + shadow: 'none', + }, + tab: { + background: '{transparent}', + hoverBackground: '{transparent}', + activeBackground: '{transparent}', + }, + }, + }, + root: { + transitionDuration: '{data.transitionDuration}', + }, + tablist: { + borderWidth: '0 0 {data.width.100} 0', + background: '{transparent}', + borderColor: '{content.borderColor}', + }, + tab: { + borderWidth: '0', + borderColor: '{content.borderColor}', + hoverBorderColor: '{content.borderColor}', + activeBorderColor: '{content.activeBorderColor}', + color: '{text.mutedColor}', + hoverColor: '{text.color}', + activeColor: '{text.color}', + padding: '{content.padding.300}', + fontWeight: '{fonts.fontWeight.demibold}', + margin: '0', + gap: '{content.gap.200}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + tabpanel: { + background: '{transparent}', + color: '{text.color}', + padding: '{spacing.4x}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + navButton: { + background: '{content.background}', + color: '{content.color}', + hoverColor: '{content.hoverColor}', + width: '{controls.iconOnly.400}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + }, + activeBar: { + height: '0.18rem', + bottom: '-0.18rem', + background: '{content.color}', + }, + }, + toast: { + extend: { + extInfo: { + color: '{info.500}', + closeButton: { + color: '{info.500}', + borderColor: '{info.500}', + }, + caption: { + color: '{text.color}', + }, + }, + extAccentLine: { + width: '{feedback.width.200}', + }, + extCloseButton: { + width: '{feedback.width.100}', + }, + extSuccess: { + color: '{success.500}', + closeButton: { + color: '{success.500}', + borderColor: '{success.500}', + }, + caption: { + color: '{text.color}', + }, + }, + extWarn: { + color: '{warn.500}', + closeButton: { + color: '{warn.500}', + borderColor: '{warn.500}', + }, + caption: { + color: '{text.color}', + }, + }, + extError: { + color: '{error.500}', + closeButton: { + color: '{error.500}', + borderColor: '{error.500}', + }, + caption: { + color: '{text.color}', + }, + }, + }, + colorScheme: { + light: { + info: { + background: '{info.50}', + borderColor: '{info.500}', + color: '{text.color}', + detailColor: '{text.color}', + shadow: '{overlay.popover.shadow}', + closeButton: { + hoverBackground: '{info.200}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + }, + success: { + background: '{success.50}', + borderColor: '{success.500}', + color: '{text.color}', + detailColor: '{text.color}', + shadow: '{overlay.popover.shadow}', + closeButton: { + hoverBackground: '{success.200}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + }, + warn: { + background: '{warn.50}', + borderColor: '{warn.500}', + color: '{text.color}', + detailColor: '{text.color}', + shadow: '{overlay.popover.shadow}', + closeButton: { + hoverBackground: '{warn.200}', + focusRing: { + color: '{focusRing.color}', + shadow: 'none', + }, + }, + }, + error: { + background: '{error.50}', + borderColor: '{error.500}', + color: '{text.color}', + detailColor: '{text.color}', + shadow: '{overlay.popover.shadow}', + closeButton: { + hoverBackground: '{error.200}', + focusRing: { + color: '{focusRing.color}', + shadow: '{focusRing.shadow}', + }, + }, + }, + secondary: { + shadow: '{overlay.popover.shadow}', + }, + contrast: { + shadow: '{overlay.popover.shadow}', + }, + }, + }, + root: { + width: '{messages.width}', + borderWidth: '{feedback.width.100}', + borderRadius: '{content.borderRadius}', + transitionDuration: '{feedback.transitionDuration}', + }, + icon: { + size: '{feedback.icon.size.500}', + }, + content: { + padding: '{feedback.padding.200}', + gap: '{feedback.gap.400}', + }, + text: { + gap: '{feedback.gap.100}', + }, + summary: { + fontWeight: '{fonts.fontWeight.bold}', + fontSize: '{fonts.fontSize.300}', + }, + detail: { + fontWeight: '{fonts.fontWeight.regular}', + fontSize: '{fonts.fontSize.200}', + }, + closeButton: { + width: '{feedback.icon.size.400}', + height: '{feedback.icon.size.400}', + borderRadius: '{controls.borderRadius.100}', + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + offset: '{focusRing.offset}', + }, + }, + closeIcon: { + size: '{feedback.icon.size.200}', + }, + }, + tag: { + colorScheme: { + light: { + primary: { + background: '{primary.selectedBackground}', + color: '{text.color}', + }, + secondary: { + background: '{surface.200}', + color: '{text.color}', + }, + success: { + background: '{success.400}', + color: '{success.900}', + }, + info: { + background: '{info.300}', + color: '{info.900}', + }, + warn: { + background: '{warn.300}', + color: '{warn.900}', + }, + danger: { + background: '{error.300}', + color: '{error.900}', + }, + }, + }, + root: { + fontSize: '{fonts.fontSize.100}', + fontWeight: '{fonts.fontWeight.regular}', + padding: '{media.padding.100} {media.padding.200}', + gap: '{media.gap.100}', + borderRadius: '{media.size.200}', + roundedBorderRadius: '{media.borderRadius.400}', + }, + icon: { + size: '{media.icon.size.100}', + }, + }, + textarea: { + extend: { + readonlyBackground: '{form.readonlyBackground}', + borderWidth: '{form.borderWidth}', + iconSize: '{form.icon.300}', + minHeight: '{form.size.900}', + }, + root: { + background: '{form.background}', + disabledBackground: '{form.disabledBackground}', + filledBackground: '{form.filledBackground}', + filledHoverBackground: '{form.filledHoverBackground}', + filledFocusBackground: '{form.filledFocusBackground}', + borderColor: '{form.borderColor}', + hoverBorderColor: '{form.hoverBorderSecondaryColor}', + focusBorderColor: '{form.focusBorderSecondaryColor}', + invalidBorderColor: '{form.invalidBorderColor}', + color: '{form.color}', + disabledColor: '{form.disabledColor}', + placeholderColor: '{form.placeholderColor}', + invalidPlaceholderColor: '{form.invalidPlaceholderColor}', + shadow: '0', + paddingX: '{form.paddingX}', + paddingY: '{form.paddingY}', + borderRadius: '{form.borderRadius.200}', + transitionDuration: '{form.transitionDuration}', + focusRing: { + width: '{form.focusRing.width}', + style: '{form.focusRing.style}', + color: '{form.focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '0', + }, + }, + sm: { + fontSize: '{fonts.fontSize.300}', + paddingX: '{form.padding.200}', + paddingY: '{form.padding.200}', + }, + lg: { + fontSize: '{fonts.fontSize.300}', + paddingX: '{form.padding.400}', + paddingY: '{form.padding.400}', + }, + }, + tieredmenu: { + extend: { + extSubmenu: { + borderColor: '{content.borderColor}', + background: '{content.background}', + }, + iconSize: '{navigation.submenuIcon.size}', + extItem: { + caption: { + gap: '{content.gap.100}', + color: '{text.mutedColor}', + }, + }, + }, + root: { + background: '{content.background}', + borderColor: '{transparent}', + color: '{content.color}', + borderRadius: '{content.borderRadius}', + shadow: '{navigation.shadow}', + transitionDuration: '{feedback.transitionDuration}', + }, + list: { + padding: '{navigation.list.padding.100}', + gap: '{navigation.list.gap}', + }, + item: { + focusBackground: '{navigation.item.focusBackground}', + activeBackground: '{navigation.item.activeBackground}', + color: '{navigation.item.color}', + focusColor: '{navigation.item.focusColor}', + activeColor: '{navigation.item.activeColor}', + padding: '{navigation.item.padding}', + borderRadius: '{navigation.item.borderRadius}', + gap: '{navigation.item.gap}', + icon: { + color: '{navigation.item.icon.color}', + focusColor: '{navigation.item.icon.focusColor}', + activeColor: '{navigation.item.icon.activeColor}', + }, + }, + submenu: { + mobileIndent: '{overlay.popover.padding.100}', + }, + separator: { + borderColor: '{content.borderColor}', + }, + }, + timeline: { + extend: { + extEvent: { + gap: '{feedback.gap.100}', + }, + }, + event: { + minHeight: '{feedback.height.900}', + }, + vertical: { + eventContent: { + padding: '0 {feedback.padding.500}', + }, + }, + horizontal: { + eventContent: { + padding: '{feedback.padding.500} 0', + }, + }, + eventMarker: { + size: '{feedback.width.500}', + borderRadius: '{content.borderRadius}', + borderWidth: '{feedback.width.200}', + background: '{content.background}', + borderColor: '{primary.color}', + content: { + borderRadius: '{content.borderRadius}', + size: '{feedback.width.400}', + background: '{transparent}', + insetShadow: 'none', + }, + }, + eventConnector: { + color: '{content.borderColor}', + size: '{feedback.width.100}', + }, + }, + togglebutton: { + extend: { + ext: { + gap: '{form.gap.300}', + }, + iconSize: { + sm: '{controls.iconOnly.200}', + md: '{controls.iconOnly.300}', + lg: '{controls.iconOnly.400}', + }, + iconOnlyWidth: '{form.size.600}', + hoverBorderColor: '{surface.300}', + checkedHoverColor: '{text.extend.colorInverted}', + checkedHoverBackground: '{surface.800}', + checkedHoverBorderColor: '{surface.800}', + extXlg: { + padding: '{form.padding.500} {form.padding.500}', + iconOnlyWidth: '4.0714rem', + }, + extSm: { + iconOnlyWidth: '2.1429rem', + }, + extLg: { + iconOnlyWidth: '3.5714rem', + }, + }, + colorScheme: { + light: { + root: { + background: '{surface.200}', + hoverBackground: '{surface.300}', + borderColor: '{surface.200}', + color: '{text.color}', + hoverColor: '{text.color}', + checkedBackground: '{surface.900}', + checkedColor: '{text.extend.colorInverted}', + checkedBorderColor: '{surface.900}', + disabledBackground: '{form.disabledBackground}', + disabledBorderColor: '{form.disabledBackground}', + disabledColor: '{form.disabledColor}', + invalidBorderColor: '{form.invalidBorderColor}', + }, + icon: { + color: '{text.color}', + hoverColor: '{text.color}', + checkedColor: '{text.extend.colorInverted}', + disabledColor: '{form.disabledColor}', + }, + content: { + checkedBackground: '{transparent}', + }, + }, + }, + root: { + padding: '{form.padding.200} {form.padding.400}', + borderRadius: '{form.borderRadius.300}', + gap: '{form.gap.200}', + fontWeight: '{fonts.fontWeight.demibold}', + focusRing: { + width: '{form.focusRing.width}', + style: '{form.focusRing.style}', + color: '{form.focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '{focusRing.shadow}', + }, + sm: { + fontSize: '{fonts.fontSize.200}', + padding: '{form.padding.100} {form.padding.300}', + }, + lg: { + fontSize: '{fonts.fontSize.500}', + padding: '{form.padding.400} {form.padding.600}', + }, + transitionDuration: '{form.transitionDuration}', + }, + content: { + checkedShadow: 'none', + padding: '0rem', + borderRadius: '0rem', + sm: { + padding: '0rem', + }, + lg: { + padding: '0rem', + }, + }, + }, + toggleswitch: { + colorScheme: { + light: { + root: { + background: '{surface.400}', + hoverBackground: '{surface.500}', + disabledBackground: '{form.disabledBackground}', + checkedBackground: '{surface.900}', + checkedHoverBackground: '{surface.800}', + }, + handle: { + background: '{form.backgroundHandler}', + hoverBackground: '{form.backgroundHandler}', + disabledBackground: '{form.disabledColor}', + checkedBackground: '{surface.0}', + checkedHoverBackground: '{surface.0}', + color: '{text.color}', + hoverColor: '{text.color}', + checkedColor: '{text.color}', + checkedHoverColor: '{text.color}', + }, + }, + }, + root: { + width: '{form.size.600}', + height: '{form.size.400}', + borderRadius: '{form.borderRadius.300}', + gap: '{form.gap.100}', + borderWidth: '{form.borderWidth}', + shadow: 'none', + focusRing: { + width: '{form.focusRing.width}', + style: '{form.focusRing.style}', + color: '{form.focusRing.color}', + offset: '{form.focusRing.offset}', + shadow: '0', + }, + borderColor: '{transparent}', + hoverBorderColor: '{transparent}', + checkedBorderColor: '{transparent}', + checkedHoverBorderColor: '{transparent}', + invalidBorderColor: '{form.invalidBorderColor}', + transitionDuration: '{form.transitionDuration}', + slideDuration: '{form.transitionDuration}', + }, + handle: { + borderRadius: '{form.borderRadius.300}', + size: '{form.size.300}', + }, + }, + tooltip: { + colorScheme: { + light: { + root: { + background: '{surface.900}', + color: '{text.extend.colorInverted}', + }, + }, + }, + root: { + maxWidth: '{overlay.width}', + gutter: '{feedback.gap.100}', + shadow: '{overlay.popover.shadow}', + padding: '{feedback.padding.100} {feedback.padding.200} ', + borderRadius: '{overlay.popover.borderRadius}', + }, + }, + tree: { + root: { + background: '{content.background}', + color: '{content.color}', + padding: '{data.padding.400}', + gap: '{data.gap.100}', + indent: '{data.padding.400}', + }, + node: { + padding: '{data.padding.200} {data.padding.300}', + color: '{text.color}', + selectedColor: '{text.extend.colorInverted}', + gap: '{data.gap.100}', + }, + nodeIcon: { + selectedColor: '{text.extend.colorInverted}', + }, + nodeToggleButton: { + borderRadius: '{data.borderRadius}', + size: '{data.icon.size.400}', + selectedHoverBackground: '{surface.900}', + }, + loadingIcon: { + size: '{data.icon.size.100}', + }, + filter: { + margin: '0 0 {data.padding.200} 0', + }, + }, + overlaybadge: { + root: { + outline: { + width: '0rem', + color: '{transparent}', + }, + }, + }, +}; diff --git a/src/prime-preset/tokens/components/button.json b/src/prime-preset/tokens/components/button.json deleted file mode 100644 index 347c037d..00000000 --- a/src/prime-preset/tokens/components/button.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "button": { - "css": "" - } -} diff --git a/src/prime-preset/tokens/components/button.ts b/src/prime-preset/tokens/components/button.ts new file mode 100644 index 00000000..2a5c586c --- /dev/null +++ b/src/prime-preset/tokens/components/button.ts @@ -0,0 +1,157 @@ +/** + * Кастомная CSS-стилизация для компонента p-button. + * Публикует extend-токены как CSS-переменные и применяет глобальные стили. + * Подключается в components.ts: `import { buttonCss } from './components/button'` + */ +export const buttonCss = ({ dt }: { dt: (token: string) => string }): string => ` + /* ─── Button extend: публикуем кастомные переменные в :root ─── */ + :root { + --p-button-extend-disabled-background: ${dt('button.extend.disabledBackground')}; + --p-button-extend-disabled-color: ${dt('button.extend.disabledColor')}; + --p-button-extend-border-width: ${dt('button.extend.borderWidth')}; + --p-button-extend-icon-size-sm: ${dt('button.extend.iconSize.sm')}; + --p-button-extend-icon-size-md: ${dt('button.extend.iconSize.md')}; + --p-button-extend-icon-size-lg: ${dt('button.extend.iconSize.lg')}; + --p-button-extend-ext-link-padding-x: ${dt('button.extend.extLink.paddingX')}; + --p-button-extend-ext-link-padding-y: ${dt('button.extend.extLink.paddingY')}; + --p-button-extend-ext-link-color-hover: ${dt('button.extend.extLink.colorHover')}; + --p-button-extend-ext-link-sm-icon-only-width: ${dt('button.extend.extLink.sm.iconOnlyWidth')}; + --p-button-extend-ext-link-base-icon-only-width: ${dt('button.extend.extLink.base.iconOnlyWidth')}; + --p-button-extend-ext-link-lg-icon-only-width: ${dt('button.extend.extLink.lg.iconOnlyWidth')}; + --p-button-extend-ext-link-xlg-icon-only-width: ${dt('button.extend.extLink.xlg.iconOnlyWidth')}; + --p-button-extend-ext-sm-border-radius: ${dt('button.extend.extSm.borderRadius')}; + --p-button-extend-ext-sm-gap: ${dt('button.extend.extSm.gap')}; + --p-button-extend-ext-lg-border-radius: ${dt('button.extend.extLg.borderRadius')}; + --p-button-extend-ext-lg-gap: ${dt('button.extend.extLg.gap')}; + --p-button-extend-ext-lg-height: ${dt('button.extend.extLg.height')}; + --p-button-extend-ext-xlg-border-radius: ${dt('button.extend.extXlg.borderRadius')}; + --p-button-extend-ext-xlg-gap: ${dt('button.extend.extXlg.gap')}; + --p-button-extend-ext-xlg-icon-only-width: ${dt('button.extend.extXlg.iconOnlyWidth')}; + --p-button-extend-ext-xlg-padding-x: ${dt('button.extend.extXlg.paddingX')}; + --p-button-extend-ext-xlg-padding-y: ${dt('button.extend.extXlg.paddingY')}; + --p-button-extend-ext-xlg-height: ${dt('button.extend.extXlg.height')}; + } + + /* ─── Шрифт для текста кнопки ─── */ + .p-button.p-component .p-button-label { + font-family: var(--p-fonts-font-family-heading, 'TT Fellows', sans-serif); + } + + /* ─── Размеры иконок ─── */ + .p-button .p-button-icon { + font-size: var(--p-button-extend-icon-size-md); + } + .p-button.p-button-sm .p-button-icon { + font-size: var(--p-button-extend-icon-size-sm); + } + .p-button.p-button-lg .p-button-icon { + font-size: var(--p-button-extend-icon-size-lg); + } + .p-button-xlg.p-button .p-button-icon, + .p-button-link.p-button-xlg .p-button-icon { + font-size: var(--p-button-extend-icon-size-lg); + } + + /* ─── Disabled / loading ─── */ + .p-button:is(.p-disabled, :disabled, .p-button-loading) { + mix-blend-mode: inherit; + opacity: var(--p-opacity-1000); + color: var(--p-button-extend-disabled-color); + background: var(--p-button-extend-disabled-background); + border-color: var(--p-button-extend-disabled-background); + } + .p-button.p-button-outlined:is(.p-disabled, :disabled, .p-button-loading) { + color: var(--p-button-extend-disabled-color); + background: transparent; + border-color: transparent; + } + .p-button.p-button-text:is(.p-disabled, :disabled, .p-button-loading) { + color: var(--p-button-extend-disabled-color); + background: transparent; + border-color: transparent; + } + .p-button.p-button-link:is(.p-disabled, :disabled, .p-button-loading) { + color: var(--p-button-extend-disabled-color); + background: transparent; + border-color: transparent; + } + + /* ─── Link кнопки ─── */ + .p-button-link.p-button:is(.p-button, .p-button-xlg) { + padding: var(--p-button-extend-ext-link-padding-y) var(--p-button-extend-ext-link-padding-x); + } + .p-button-link.p-button { + width: min-content; + } + .p-button-link.p-button.p-button-xlg { + font-size: var(--p-fonts-font-size-600); + } + .p-button.p-button-link:not(:disabled):hover { + color: var(--p-button-extend-ext-link-color-hover); + } + .p-button.p-button-link:not(:disabled):hover .p-button-label { + text-decoration: none; + } + + /* ─── Icon-only link кнопки ─── */ + .p-button-link.p-button-icon-only { + width: var(--p-button-extend-ext-link-base-icon-only-width); + height: var(--p-button-extend-ext-link-base-icon-only-width); + } + .p-button-link.p-button-icon-only.p-button-sm { + width: var(--p-button-extend-ext-link-sm-icon-only-width); + height: var(--p-button-extend-ext-link-sm-icon-only-width); + } + .p-button-link.p-button-icon-only.p-button-lg { + width: var(--p-button-extend-ext-link-lg-icon-only-width); + height: var(--p-button-extend-ext-link-lg-icon-only-width); + } + + /* ─── Line-height ─── */ + .p-button-sm { + line-height: var(--p-fonts-line-height-250); + } + .p-button:is(.p-button-lg, .p-button-xlg) { + line-height: var(--p-fonts-line-height-550); + } + + /* ─── Border-radius для lg / xlg ─── */ + .p-button:is(.p-button-lg, .p-button-xlg):not(.p-button-rounded) { + border-radius: var(--p-button-extend-ext-lg-border-radius); + } + .p-button-xlg.p-button:not(.p-button-rounded) { + border-radius: var(--p-button-extend-ext-xlg-border-radius); + } + + /* ─── Padding / font-size / height для lg ─── */ + .p-button-lg.p-button:not(.p-button-icon-only):not(.p-button-link) { + padding: var(--p-button-lg-padding-y) var(--p-button-lg-padding-x); + font-size: var(--p-button-lg-font-size); + height: var(--p-controls-icon-only-850); + } + + /* ─── Padding / font-size / height для xlg ─── */ + .p-button-xlg.p-button:not(.p-button-icon-only):not(.p-button-link) { + padding: var(--p-button-extend-ext-xlg-padding-y) var(--p-button-extend-ext-xlg-padding-x); + font-size: var(--p-fonts-font-size-500); + height: var(--p-controls-icon-only-900); + } + + /* ─── Icon-only размеры ─── */ + .p-button-icon-only { + width: var(--p-button-icon-only-width); + height: var(--p-button-icon-only-width); + } + .p-button-sm.p-button-icon-only { + width: var(--p-button-sm-icon-only-width); + height: var(--p-button-sm-icon-only-width); + } + .p-button-lg.p-button-icon-only { + width: var(--p-button-lg-icon-only-width); + height: var(--p-button-lg-icon-only-width); + } + .p-button-xlg.p-button-icon-only { + width: var(--p-button-extend-ext-xlg-icon-only-width); + height: var(--p-button-extend-ext-xlg-icon-only-width); + } +`; diff --git a/src/prime-preset/tokens/primitive-default.json b/src/prime-preset/tokens/primitive-default.json deleted file mode 100644 index 6dc1c0fe..00000000 --- a/src/prime-preset/tokens/primitive-default.json +++ /dev/null @@ -1,377 +0,0 @@ -{ - "colors": { - "alpha": { - "white": { - "10": "rgba(255, 255, 255, 0.1000)", - "20": "rgba(255, 255, 255, 0.2000)", - "30": "rgba(255, 255, 255, 0.3000)", - "40": "rgba(255, 255, 255, 0.4000)", - "50": "rgba(255, 255, 255, 0.5000)", - "60": "rgba(255, 255, 255, 0.6000)", - "70": "rgba(255, 255, 255, 0.7000)", - "80": "rgba(255, 255, 255, 0.8000)", - "90": "rgba(255, 255, 255, 0.9000)", - "100": "#ffffff" - }, - "black": { - "10": "rgba(0, 0, 0, 0.1000)", - "20": "rgba(0, 0, 0, 0.2000)", - "30": "rgba(0, 0, 0, 0.3000)", - "40": "rgba(0, 0, 0, 0.4000)", - "50": "rgba(0, 0, 0, 0.5000)", - "60": "rgba(0, 0, 0, 0.6000)", - "70": "rgba(0, 0, 0, 0.7000)", - "80": "rgba(0, 0, 0, 0.8000)", - "90": "rgba(0, 0, 0, 0.9000)", - "100": "#000000" - } - }, - "solid": { - "purple": { - "50": "#faf5ff", - "100": "#f3e8ff", - "200": "#e9d5ff", - "300": "#d8b4fe", - "400": "#c084fc", - "500": "#a855f7", - "600": "#9333ea", - "700": "#7e22ce", - "800": "#6b21a8", - "900": "#581c87", - "950": "#3b0764" - }, - "fuchsia": { - "50": "#fdf4ff", - "100": "#fae8ff", - "200": "#f5d0fe", - "300": "#f0abfc", - "400": "#e879f9", - "500": "#d946ef", - "600": "#c026d3", - "700": "#a21caf", - "800": "#86198f", - "900": "#701a75", - "950": "#4a044e" - }, - "pink": { - "50": "#fdf2f8", - "100": "#fce7f3", - "200": "#fbcfe8", - "300": "#f9a8d4", - "400": "#f472b6", - "500": "#ec4899", - "600": "#db2777", - "700": "#be185d", - "800": "#9d174d", - "900": "#831843", - "950": "#500724" - }, - "rose": { - "50": "#fff1f2", - "100": "#ffe4e6", - "200": "#fecdd3", - "300": "#fda4af", - "400": "#fb7185", - "500": "#f43f5e", - "600": "#e11d48", - "700": "#be123c", - "800": "#9f1239", - "900": "#881337", - "950": "#4c0519" - }, - "teal": { - "50": "#f0fdfa", - "100": "#ccfbf1", - "200": "#99f6e4", - "300": "#5eead4", - "400": "#2dd4bf", - "500": "#14b8a6", - "600": "#0d9488", - "700": "#0f766e", - "800": "#115e59", - "900": "#134e4a", - "950": "#042f2e" - }, - "cyan": { - "50": "#ecfeff", - "100": "#cffafe", - "200": "#a5f3fc", - "300": "#67e8f9", - "400": "#22d3ee", - "500": "#06b6d4", - "600": "#0891b2", - "700": "#0e7490", - "800": "#155e75", - "900": "#164e63", - "950": "#083344" - }, - "sky": { - "50": "#f0f9ff", - "100": "#e0f2fe", - "200": "#bae6fd", - "300": "#7dd3fc", - "400": "#38bdf8", - "500": "#0ea5e9", - "600": "#0284c7", - "700": "#0369a1", - "800": "#075985", - "900": "#0c4a6e", - "950": "#082f49" - }, - "blue": { - "50": "#fafdff", - "100": "#f0f9ff", - "200": "#d4ecfe", - "300": "#aad7fb", - "400": "#77baf4", - "500": "#4496e8", - "600": "#1e76cd", - "700": "#18538d", - "800": "#123a61", - "900": "#0e2a45", - "950": "#0c243b" - }, - "indigo": { - "50": "#eef2ff", - "100": "#e0e7ff", - "200": "#c7d2fe", - "300": "#a5b4fc", - "400": "#818cf8", - "500": "#6366f1", - "600": "#4f46e5", - "700": "#4338ca", - "800": "#3730a3", - "900": "#312e81", - "950": "#1e1b4b" - }, - "violet": { - "50": "#fcfaff", - "100": "#f6f0ff", - "200": "#e5d4fe", - "300": "#cbaafb", - "400": "#b284f5", - "500": "#a265ec", - "600": "#9457ea", - "700": "#48188d", - "800": "#321261", - "900": "#240e45", - "950": "#1f0c3b" - }, - "emerald": { - "50": "#ecfdf5", - "100": "#d1fae5", - "200": "#a7f3d0", - "300": "#6ee7b7", - "400": "#34d399", - "500": "#10b981", - "600": "#059669", - "700": "#047857", - "800": "#065f46", - "900": "#064e3b", - "950": "#022c22" - }, - "green": { - "50": "#fafffb", - "100": "#f0fff3", - "200": "#d4fedc", - "300": "#aafbb7", - "400": "#77f48a", - "500": "#44e858", - "600": "#1dc831", - "700": "#168322", - "800": "#12611b", - "900": "#0e4514", - "950": "#0c3b11" - }, - "lime": { - "50": "#f7fee7", - "100": "#ecfccb", - "200": "#d9f99d", - "300": "#bef264", - "400": "#a3e635", - "500": "#84cc16", - "600": "#65a30d", - "700": "#4d7c0f", - "800": "#3f6212", - "900": "#365314", - "950": "#1a2e05" - }, - "red": { - "50": "#fffafa", - "100": "#fff0f0", - "200": "#fed4d4", - "300": "#fbacaa", - "400": "#f47f77", - "500": "#e85244", - "600": "#db3424", - "700": "#8d2218", - "800": "#611912", - "900": "#45120e", - "950": "#3b100c" - }, - "orange": { - "50": "#fffbfa", - "100": "#fff3f0", - "200": "#ffddd5", - "300": "#ffbca9", - "400": "#ff9273", - "500": "#fe6434", - "600": "#d53f0b", - "700": "#a83107", - "800": "#752506", - "900": "#561c05", - "950": "#4b1905" - }, - "amber": { - "50": "#fffbeb", - "100": "#fef3c7", - "200": "#fde68a", - "300": "#fcd34d", - "400": "#fbbf24", - "500": "#f59e0b", - "600": "#d97706", - "700": "#b45309", - "800": "#92400e", - "900": "#78350f", - "950": "#451a03" - }, - "yellow": { - "50": "#fffdfa", - "100": "#fff9f0", - "200": "#ffeed4", - "300": "#fddeaa", - "400": "#facb75", - "500": "#f5b83d", - "600": "#dc9710", - "700": "#9d6d0e", - "800": "#6d4c0b", - "900": "#4f3709", - "950": "#453008" - }, - "slate": { - "50": "#f8fafc", - "100": "#f1f5f9", - "200": "#e2e8f0", - "300": "#cbd5e1", - "400": "#94a3b8", - "500": "#64748b", - "600": "#475569", - "700": "#334155", - "800": "#1e293b", - "900": "#0f172a", - "950": "#020617" - }, - "gray": { - "50": "#f9fafb", - "100": "#f3f4f6", - "200": "#e5e7eb", - "300": "#d1d5db", - "400": "#9ca3af", - "500": "#6b7280", - "600": "#4b5563", - "700": "#374151", - "800": "#1f2937", - "900": "#111827", - "950": "#030712" - }, - "zinc": { - "50": "#fafafa", - "100": "#f0f0f1", - "200": "#e2e2e4", - "300": "#cecfd2", - "400": "#a2a5a9", - "500": "#85888e", - "600": "#6d7076", - "700": "#56595f", - "800": "#404348", - "900": "#2b2e33", - "950": "#181a1f" - }, - "neutral": { - "50": "#fafafa", - "100": "#f5f5f5", - "200": "#e5e5e5", - "300": "#d4d4d4", - "400": "#a3a3a3", - "500": "#737373", - "600": "#525252", - "700": "#404040", - "800": "#262626", - "900": "#171717", - "950": "#0a0a0a" - }, - "stone": { - "50": "#fafaf9", - "100": "#f5f5f4", - "200": "#e7e5e4", - "300": "#d6d3d1", - "400": "#a8a29e", - "500": "#78716c", - "600": "#57534e", - "700": "#44403c", - "800": "#292524", - "900": "#1c1917", - "950": "#0c0a09" - } - } - }, - "borderRadius": { - "none": "0", - "xs": "0.21875rem", - "sm": "0.4375rem", - "md": "0.65625rem", - "lg": "0.875rem", - "xl": "1.3125rem", - "rounded": "62.4375rem" - }, - "fonts": { - "fontFamily": { - "heading": "TT Fellows", - "base": "PT Sans" - }, - "fontWeight": { - "regular": "25rem", - "medium": "31.25rem", - "demibold": "37.5rem", - "bold": "43.75rem" - }, - "fontSize": { - "xs": "0.65625rem", - "sm": "0.765625rem", - "base": "0.875rem", - "lg": "0.984375rem", - "xl": "1.09375rem", - "2xl": "1.3125rem", - "3xl": "1.640625rem", - "4xl": "1.96875rem", - "5xl": "2.625rem", - "6xl": "3.28125rem", - "7xl": "3.9375rem", - "8xl": "5.25rem" - }, - "lineHeight": { - "10": "0.6875rem", - "15": "0.75rem", - "20": "0.8125rem", - "25": "0.875rem", - "30": "0.9375rem", - "35": "1rem", - "40": "1.125rem", - "45": "1.25rem", - "50": "1.3125rem", - "55": "1.375rem", - "60": "1.5rem", - "65": "1.625rem", - "70": "2rem", - "75": "2.0625rem", - "80": "2.4375rem", - "85": "2.9375rem", - "auto": "auto" - } - }, - "opacity": { - "0": "0", - "50": "0.03125rem", - "100": "0.0625rem" - } -} diff --git a/src/prime-preset/tokens/primitive.ts b/src/prime-preset/tokens/primitive.ts new file mode 100644 index 00000000..da002b66 --- /dev/null +++ b/src/prime-preset/tokens/primitive.ts @@ -0,0 +1,480 @@ +export default { + colors: { + alpha: { + white: { + '100': 'rgba(255, 255, 255, 0.1000)', + '200': 'rgba(255, 255, 255, 0.2000)', + '300': 'rgba(255, 255, 255, 0.3000)', + '400': 'rgba(255, 255, 255, 0.4000)', + '500': 'rgba(255, 255, 255, 0.5000)', + '600': 'rgba(255, 255, 255, 0.6000)', + '700': 'rgba(255, 255, 255, 0.7000)', + '800': 'rgba(255, 255, 255, 0.8000)', + '900': 'rgba(255, 255, 255, 0.9000)', + '1000': '#ffffff', + }, + black: { + '100': 'rgba(0, 0, 0, 0.1000)', + '200': 'rgba(0, 0, 0, 0.2000)', + '300': 'rgba(0, 0, 0, 0.3000)', + '400': 'rgba(0, 0, 0, 0.4000)', + '500': 'rgba(0, 0, 0, 0.5000)', + '600': 'rgba(0, 0, 0, 0.6000)', + '700': 'rgba(0, 0, 0, 0.7000)', + '800': 'rgba(0, 0, 0, 0.8000)', + '900': 'rgba(0, 0, 0, 0.9000)', + '1000': '#000000', + }, + }, + solid: { + purple: { + '50': '#faf5ff', + '100': '#f3e8ff', + '200': '#e9d5ff', + '300': '#d8b4fe', + '400': '#c084fc', + '500': '#a855f7', + '600': '#9333ea', + '700': '#7e22ce', + '800': '#6b21a8', + '900': '#581c87', + '950': '#3b0764', + }, + fuchsia: { + '50': '#fdf4ff', + '100': '#fae8ff', + '200': '#f5d0fe', + '300': '#f0abfc', + '400': '#e879f9', + '500': '#d946ef', + '600': '#c026d3', + '700': '#a21caf', + '800': '#86198f', + '900': '#701a75', + '950': '#4a044e', + }, + pink: { + '50': '#fdf2f8', + '100': '#fce7f3', + '200': '#fbcfe8', + '300': '#f9a8d4', + '400': '#f472b6', + '500': '#ec4899', + '600': '#db2777', + '700': '#be185d', + '800': '#9d174d', + '900': '#831843', + '950': '#500724', + }, + rose: { + '50': '#fff1f2', + '100': '#ffe4e6', + '200': '#fecdd3', + '300': '#fda4af', + '400': '#fb7185', + '500': '#f43f5e', + '600': '#e11d48', + '700': '#be123c', + '800': '#9f1239', + '900': '#881337', + '950': '#4c0519', + }, + teal: { + '50': '#f0fdfa', + '100': '#ccfbf1', + '200': '#99f6e4', + '300': '#5eead4', + '400': '#2dd4bf', + '500': '#14b8a6', + '600': '#0d9488', + '700': '#0f766e', + '800': '#115e59', + '900': '#134e4a', + '950': '#042f2e', + }, + cyan: { + '50': '#ecfeff', + '100': '#cffafe', + '200': '#a5f3fc', + '300': '#67e8f9', + '400': '#22d3ee', + '500': '#06b6d4', + '600': '#0891b2', + '700': '#0e7490', + '800': '#155e75', + '900': '#164e63', + '950': '#013138', + }, + sky: { + '50': '#f0f9ff', + '100': '#e0f2fe', + '200': '#bae6fd', + '300': '#7dd3fc', + '400': '#38bdf8', + '500': '#0ea5e9', + '600': '#0284c7', + '700': '#0369a1', + '800': '#075985', + '900': '#0c4a6e', + '950': '#082f49', + }, + blue: { + '50': '#fafdff', + '100': '#f0f9ff', + '200': '#d4ecfe', + '300': '#aad7fb', + '400': '#77baf4', + '500': '#4496e8', + '600': '#1e76cd', + '700': '#18538d', + '800': '#123a61', + '900': '#0e2a45', + '950': '#0c243b', + }, + indigo: { + '50': '#eef2ff', + '100': '#e0e7ff', + '200': '#c7d2fe', + '300': '#a5b4fc', + '400': '#818cf8', + '500': '#6366f1', + '600': '#4f46e5', + '700': '#4338ca', + '800': '#3730a3', + '900': '#312e81', + '950': '#1e1b4b', + }, + violet: { + '50': '#fcfaff', + '100': '#f6f0ff', + '200': '#e5d4fe', + '300': '#cbaafb', + '400': '#b284f5', + '500': '#a265ec', + '600': '#9457ea', + '700': '#48188d', + '800': '#321261', + '900': '#240e45', + '950': '#1f0c3b', + }, + emerald: { + '50': '#ecfdf5', + '100': '#d1fae5', + '200': '#a7f3d0', + '300': '#6ee7b7', + '400': '#34d399', + '500': '#10b981', + '600': '#059669', + '700': '#047857', + '800': '#065f46', + '900': '#064e3b', + '950': '#022c22', + }, + green: { + '50': '#fafffb', + '100': '#f0fff3', + '200': '#d4fedc', + '300': '#aafbb7', + '400': '#77f48a', + '500': '#44e858', + '600': '#1dc831', + '700': '#168322', + '800': '#12611b', + '900': '#0e4514', + '950': '#0c3b11', + }, + lime: { + '50': '#f7fee7', + '100': '#ecfccb', + '200': '#d9f99d', + '300': '#bef264', + '400': '#a3e635', + '500': '#84cc16', + '600': '#65a30d', + '700': '#4d7c0f', + '800': '#3f6212', + '900': '#365314', + '950': '#1a2e05', + }, + red: { + '50': '#fffafa', + '100': '#fff0f0', + '200': '#fed4d4', + '300': '#fbacaa', + '400': '#f47f77', + '500': '#e85244', + '600': '#db3424', + '700': '#8d2218', + '800': '#611912', + '900': '#45120e', + '950': '#3b100c', + }, + orange: { + '50': '#fffbfa', + '100': '#fff3f0', + '200': '#ffddd5', + '300': '#ffbca9', + '400': '#ff9273', + '500': '#fe6434', + '600': '#d53f0b', + '700': '#a83107', + '800': '#752506', + '900': '#561c05', + '950': '#4b1905', + }, + amber: { + '50': '#fffbeb', + '100': '#fef3c7', + '200': '#fde68a', + '300': '#fcd34d', + '400': '#fbbf24', + '500': '#f59e0b', + '600': '#d97706', + '700': '#b45309', + '800': '#92400e', + '900': '#78350f', + '950': '#451a03', + }, + yellow: { + '50': '#fffdfa', + '100': '#fff9f0', + '200': '#ffeed4', + '300': '#fddeaa', + '400': '#facb75', + '500': '#f5b83d', + '600': '#dc9710', + '700': '#9d6d0e', + '800': '#6d4c0b', + '900': '#4f3709', + '950': '#453008', + }, + slate: { + '50': '#f8fafc', + '100': '#f1f5f9', + '200': '#e2e8f0', + '300': '#cbd5e1', + '400': '#94a3b8', + '500': '#64748b', + '600': '#475569', + '700': '#334155', + '800': '#1e293b', + '900': '#0f172a', + '950': '#020617', + }, + gray: { + '50': '#f9fafb', + '100': '#f3f4f6', + '200': '#e5e7eb', + '300': '#d1d5db', + '400': '#9ca3af', + '500': '#6b7280', + '600': '#4b5563', + '700': '#374151', + '800': '#1f2937', + '900': '#111827', + '950': '#030712', + }, + zinc: { + '50': '#fafafa', + '100': '#f0f0f1', + '200': '#e2e2e4', + '300': '#cecfd2', + '400': '#a2a5a9', + '500': '#85888e', + '600': '#6d7076', + '700': '#56595f', + '800': '#404348', + '900': '#2b2e33', + '950': '#181a1f', + }, + neutral: { + '50': '#fafafa', + '100': '#f5f5f5', + '200': '#e5e5e5', + '300': '#d4d4d4', + '400': '#a3a3a3', + '500': '#737373', + '600': '#525252', + '700': '#404040', + '800': '#262626', + '900': '#171717', + '950': '#0a0a0a', + }, + stone: { + '50': '#fafaf9', + '100': '#f5f5f4', + '200': '#e7e5e4', + '300': '#d6d3d1', + '400': '#a8a29e', + '500': '#78716c', + '600': '#57534e', + '700': '#44403c', + '800': '#292524', + '900': '#1c1917', + '950': '#0c0a09', + }, + }, + }, + borderRadius: { + '100': '0.25rem', + '200': '0.5rem', + '300': '0.75rem', + '400': '1rem', + '500': '1.5rem', + none: '0rem', + max: '71.3571rem', + }, + borderWidth: { + '100': '0.0714rem', + '200': '0.1429rem', + '300': '0.25rem', + none: '0rem', + }, + fonts: { + fontFamily: { + heading: 'TT Fellows', + base: 'PT Sans', + }, + fontWeight: { + regular: '400', + medium: '500', + demibold: '600', + bold: '700', + }, + fontSize: { + '100': '0.75rem', + '200': '0.875rem', + '300': '1rem', + '400': '1.125rem', + '500': '1.25rem', + '600': '1.5rem', + '650': '1.875rem', + '700': '2.25rem', + '750': '3rem', + '800': '3.75rem', + '900': '4.5rem', + '1000': '6rem', + }, + lineHeight: { + '100': '0.7857rem', + '150': '0.8571rem', + '200': '0.9286rem', + '250': '1rem', + '300': '1.0714rem', + '350': '1.1429rem', + '400': '1.2857rem', + '450': '1.4286rem', + '500': '1.5rem', + '550': '1.5714rem', + '600': '1.7143rem', + '700': '1.8571rem', + '800': '2.2857rem', + '850': '2.3571rem', + '900': '2.7857rem', + '1000': '3.3571rem', + auto: 'auto', + }, + }, + spacing: { + none: '0rem', + '1x': '0.25rem', + '2x': '0.5rem', + '3x': '0.75rem', + '4x': '1rem', + '5x': '1.25rem', + '6x': '1.5rem', + '7x': '1.75rem', + '8x': '2rem', + '9x': '2.25rem', + '10x': '2.5rem', + '11x': '2.75rem', + '12x': '3rem', + '14x': '3.5rem', + '16x': '4rem', + '20x': '5rem', + '24x': '6rem', + '28x': '7rem', + '32x': '8rem', + '36x': '9rem', + '40x': '10rem', + }, + sizing: { + none: '0rem', + min: '0.0714rem', + '1x': '0.25rem', + '2x': '0.5rem', + '3x': '0.75rem', + '4x': '1rem', + '5x': '1.25rem', + '6x': '1.5rem', + '7x': '1.75rem', + '8x': '2rem', + '9x': '2.25rem', + '10x': '2.5rem', + '11x': '2.75rem', + '12x': '3rem', + '14x': '3.5rem', + '16x': '4rem', + '20x': '5rem', + '24x': '6rem', + '28x': '7rem', + '32x': '8rem', + '36x': '9rem', + '40x': '10rem', + '44x': '11rem', + '48x': '12rem', + '52x': '13rem', + '56x': '14rem', + '60x': '15rem', + '64x': '16rem', + '68x': '17rem', + '72x': '18rem', + '76x': '19rem', + '80x': '20rem', + '84x': '21rem', + '88x': '22rem', + '92x': '23rem', + '96x': '24rem', + '100x': '25rem', + '104x': '26rem', + '108x': '27rem', + '112x': '28rem', + '116x': '29rem', + '120x': '30rem', + '124x': '34rem', + '128x': '45rem', + '132x': '50rem', + '136x': '54rem', + '140x': '58rem', + '144x': '60rem', + max: '100%', + }, + shadows: { + '100': '0 0 0.1rem {colors.alpha.black.200}', + '200': '0 0 0.25rem {colors.alpha.black.200}', + '300': '0 0.1rem 0.25rem {colors.alpha.black.200}', + '400': '0 0.25rem 0.5rem {colors.alpha.black.200}', + '500': '0 0.5rem 1rem 0 {colors.alpha.black.200}', + none: 'none', + }, + transition: { + easing: { + linear: 'linear', + in: 'cubic-bezier(0.55, 0.06, 0.7, 0.2)', + out: 'cubic-bezier(0.2, 0.6, 0.4, 1)', + inOut: 'cubic-bezier(0.65, 0.05, 0.35, 1)', + }, + duration: { + '100': '140ms', + '200': '180ms', + '300': '240ms', + '400': '320ms', + '500': '400ms', + }, + }, + opacity: { + '250': '0.25', + '500': '0.5', + '1000': '1', + }, +}; diff --git a/src/prime-preset/tokens/semantic-default.json b/src/prime-preset/tokens/semantic-default.json deleted file mode 100644 index 2167ac22..00000000 --- a/src/prime-preset/tokens/semantic-default.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "list": { - "padding": "0.21875rem", - "gap": "0.21875rem", - "header": { - "padding": "1rem 1rem 0 1rem" - }, - "option": { - "padding": "0.5rem 0.75rem", - "borderRadius": "0.4375rem" - }, - "optionGroup": { - "padding": "0.5rem 0.75rem", - "fontWeight": "{fonts.fontWeight.demibold}" - } - }, - "focusRing": { - "width": "0.21875rem", - "style": "none", - "color": "#ffffff", - "offset": "0", - "shadow": "0 0 0 0.25rem {primary.200}" - }, - "primary": { - "50": "{colors.solid.green.50}", - "100": "{colors.solid.green.100}", - "200": "{colors.solid.green.200}", - "300": "{colors.solid.green.300}", - "400": "{colors.solid.green.400}", - "500": "{colors.solid.green.500}", - "600": "{colors.solid.green.600}", - "700": "{colors.solid.green.700}", - "800": "{colors.solid.green.800}", - "900": "{colors.solid.green.900}", - "950": "{colors.solid.green.950}" - }, - "formField": { - "paddingX": "0.65625rem", - "paddingY": "0.65625rem", - "borderRadius": "{borderRadius.md}", - "transitionDuration": "{transitionDuration}", - "sm": { - "fontSize": "{fonts.fontSize.base}", - "paddingX": "0.0390625rem", - "paddingY": "0.03125rem" - }, - "lg": { - "fontSize": "{fonts.fontSize.base}", - "paddingX": "0.0546875rem", - "paddingY": "0.046875rem" - }, - "focusRing": { - "width": "{focusRing.width}", - "style": "{focusRing.style}", - "color": "{focusRing.color}", - "offset": "{focusRing.offset}", - "shadow": "{focusRing.shadow}" - } - }, - "content": { - "borderRadius": "{borderRadius.md}" - }, - "mask": { - "transitionDuration": "{transitionDuration}" - }, - "navigation": { - "list": { - "padding": "0.21875rem", - "gap": "0.21875rem" - }, - "item": { - "padding": "0.625rem 1rem", - "borderRadius": "{borderRadius.sm}", - "gap": "0.4375rem" - }, - "submenuLabel": { - "padding": "0.625rem 1rem", - "fontWeight": "{fonts.fontWeight.demibold}" - }, - "submenuIcon": { - "size": "1.09375rem" - } - }, - "overlay": { - "select": { - "borderRadius": "{borderRadius.md}", - "shadow": "0 3.5px 7px 0 rgba(0, 0, 0, 0.2)" - }, - "popover": { - "borderRadius": "{borderRadius.sm}", - "padding": "0.65625rem", - "shadow": "0 1px 3px rgba(0, 0, 0, 0.1)" - }, - "modal": { - "borderRadius": "{borderRadius.xl}", - "padding": "1.3125rem", - "shadow": "0 1px 3px rgba(0, 0, 0, 0.3)" - }, - "navigation": { - "shadow": "0 2px 12px 0 rgba(0, 0, 0, 0.1)" - } - }, - "transitionDuration": "0.2s", - "iconSizeMedium": "0.875rem", - "iconSizeLarge": "1.09375rem", - "anchorGutter": "0.125rem", - "opacity": { - "default": "{opacity.100}", - "muted": "{opacity.50}", - "disabled": "{opacity.0}" - } -} \ No newline at end of file diff --git a/src/prime-preset/tokens/semantic.ts b/src/prime-preset/tokens/semantic.ts new file mode 100644 index 00000000..31365dcf --- /dev/null +++ b/src/prime-preset/tokens/semantic.ts @@ -0,0 +1,838 @@ +export default { + list: { + padding: '{spacing.1x}', + gap: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + }, + header: { + padding: '{spacing.4x} {spacing.4x} 0 {spacing.4x}', + }, + option: { + padding: '{spacing.2x} {spacing.3x}', + borderRadius: '{borderRadius.200}', + }, + optionGroup: { + padding: '{spacing.2x} {spacing.3x}', + fontWeight: '{fonts.fontWeight.demibold}', + }, + }, + focusRing: { + width: '{borderWidth.300}', + style: 'none', + color: '{focusRing.extend.success}', + offset: '0rem', + }, + form: { + padding: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + '300': '{spacing.3x}', + '400': '{spacing.4x}', + '500': '{spacing.5x}', + '600': '{spacing.6x}', + '700': '{spacing.7x}', + }, + borderRadius: { + '100': '{borderRadius.200}', + '200': '{borderRadius.300}', + '300': '{borderRadius.max}', + }, + borderWidth: '{borderWidth.100}', + icon: { + '100': '{sizing.2x}', + '200': '{sizing.3x}', + '300': '{sizing.4x}', + '400': '{sizing.5x}', + '500': '{sizing.6x}', + }, + transitionDuration: '{transition.duration.200}', + size: { + '100': '{sizing.min}', + '150': '{sizing.1x}', + '200': '{sizing.2x}', + '250': '{sizing.3x}', + '300': '{sizing.4x}', + '350': '{sizing.5x}', + '400': '{sizing.6x}', + '500': '{sizing.8x}', + '600': '{sizing.10x}', + '700': '{sizing.12x}', + '800': '{sizing.16x}', + '900': '{sizing.20x}', + }, + width: '{sizing.68x}', + gap: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + '300': '{spacing.3x}', + '400': '{spacing.4x}', + }, + focusRing: { + width: '{focusRing.width}', + style: '{focusRing.style}', + color: '{focusRing.color}', + offset: '{focusRing.offset}', + }, + sm: { + width: '{sizing.60x}', + fontSize: '{fonts.fontSize.300}', + paddingX: '{spacing.3x}', + paddingY: '{spacing.3x}', + }, + fontSize: '{fonts.fontSize.300}', + paddingX: '{spacing.4x}', + paddingY: '{spacing.4x}', + lg: { + width: '{sizing.76x}', + fontSize: '{fonts.fontSize.300}', + paddingX: '{spacing.5x}', + paddingY: '{spacing.5x}', + }, + xlg: { + width: '{sizing.84x}', + fontSize: '{fonts.fontSize.300}', + paddingX: '{spacing.6x}', + paddingY: '{spacing.6x}', + }, + }, + content: { + borderRadius: '{borderRadius.300}', + padding: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + '300': '{spacing.4x}', + '400': '{spacing.6x}', + '500': '{spacing.7x}', + }, + borderWidth: '{sizing.min}', + gap: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + '300': '{spacing.3x}', + '400': '{spacing.4x}', + }, + }, + navigation: { + width: { + '100': '{borderWidth.100}', + '200': '{borderWidth.300}', + }, + borderRadius: '{borderRadius.100}', + padding: { + '100': '{spacing.1x}', + '200': '{spacing.3x}', + '300': '{spacing.4x}', + '400': '{spacing.6x}', + }, + size: { + '100': '{sizing.1x}', + '200': '{sizing.2x}', + '300': '{sizing.5x}', + '400': '{sizing.8x}', + '500': '{sizing.16x}', + }, + submenu: { + padding: '{spacing.5x}', + }, + list: { + padding: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + }, + gap: '{spacing.1x}', + }, + item: { + padding: '{spacing.2x} {spacing.3x}', + borderRadius: '{borderRadius.200}', + gap: '{spacing.2x}', + }, + submenuLabel: { + padding: '{spacing.2x} {spacing.3x}', + fontWeight: '{fonts.fontWeight.demibold}', + }, + submenuIcon: { + size: '{fonts.fontSize.500}', + }, + }, + overlay: { + mask: { + transitionDuration: '{transition.duration.200}', + }, + select: { + borderRadius: '{borderRadius.300}', + padding: '{spacing.1x}', + }, + borderWidth: '{borderWidth.100}', + icon: { + size: { + '100': '{sizing.4x}', + '200': '{sizing.6x}', + '300': '{sizing.7x}', + '400': '{sizing.8x}', + '500': '{sizing.9x}', + }, + }, + popover: { + borderRadius: '{borderRadius.200}', + width: { + '100': '{sizing.2x}', + '200': '{sizing.3x}', + }, + padding: { + '100': '{spacing.3x}', + '200': '{spacing.5x}', + }, + }, + modal: { + borderRadius: '{borderRadius.500}', + padding: { + '100': '{spacing.4x}', + '200': '{spacing.5x}', + '300': '{spacing.6x}', + }, + }, + gap: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + '300': '{spacing.3x}', + '400': '{spacing.4x}', + }, + width: '{sizing.100x}', + drawer: { + padding: '{spacing.2x}', + }, + sm: { + width: '{sizing.80x}', + }, + lg: { + width: '{sizing.120x}', + }, + xlg: { + width: '{sizing.128x}', + }, + }, + feedback: { + transitionDuration: '{transition.duration.200}', + width: { + '100': '{sizing.min}', + '200': '{sizing.1x}', + '300': '{sizing.2x}', + '400': '{sizing.3x}', + '500': '{sizing.4x}', + '550': '{sizing.5x}', + '600': '{sizing.6x}', + '650': '{sizing.7x}', + '700': '{sizing.8x}', + '800': '{sizing.12x}', + '900': '{sizing.16x}', + }, + icon: { + size: { + '100': '{sizing.2x}', + '200': '{sizing.4x}', + '300': '{sizing.6x}', + '350': '{sizing.7x}', + '400': '{sizing.8x}', + '500': '{sizing.9x}', + }, + }, + padding: { + '100': '{spacing.2x}', + '200': '{spacing.4x}', + }, + height: { + '100': '{sizing.2x}', + '200': '{sizing.3x}', + '300': '{sizing.4x}', + '400': '{sizing.5x}', + '500': '{sizing.6x}', + '600': '{sizing.7x}', + '650': '{sizing.8x}', + '700': '{sizing.9x}', + '750': '{sizing.10x}', + '800': '{sizing.11x}', + '850': '{sizing.12x}', + '900': '{sizing.16x}', + }, + gap: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + '300': '{spacing.3x}', + '400': '{spacing.4x}', + }, + }, + data: { + padding: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + '300': '{spacing.3x}', + '400': '{spacing.4x}', + '500': '{spacing.5x}', + }, + icon: { + size: { + '100': '{sizing.4x}', + '200': '{sizing.5x}', + '300': '{sizing.6x}', + '400': '{sizing.7x}', + '500': '{sizing.8x}', + '600': '{sizing.9x}', + '700': '{sizing.10x}', + }, + }, + transitionDuration: '{transition.duration.200}', + borderWidth: '{borderWidth.none}', + borderRadius: '{borderRadius.100}', + gap: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + '300': '{spacing.3x}', + }, + width: { + '100': '{sizing.min}', + '200': '{sizing.1x}', + '300': '{sizing.2x}', + '400': '{sizing.20x}', + }, + }, + media: { + size: { + '100': '{sizing.1x}', + '200': '{sizing.2x}', + '300': '{sizing.8x}', + '400': '{sizing.10x}', + '500': '{sizing.14x}', + '600': '{sizing.16x}', + }, + borderRadius: { + '100': '{borderRadius.200}', + '200': '{borderRadius.300}', + '300': '{borderRadius.400}', + '400': '{borderRadius.500}', + max: '{borderRadius.max}', + }, + icon: { + size: { + '100': '{sizing.4x}', + '200': '{sizing.6x}', + '300': '{sizing.8x}', + }, + }, + transitionDuration: '{transition.duration.200}', + padding: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + '300': '{spacing.3x}', + '400': '{spacing.4x}', + '500': '{spacing.5x}', + '600': '{spacing.6x}', + }, + gap: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + }, + }, + controls: { + iconOnly: { + '100': '{sizing.2x}', + '200': '{sizing.4x}', + '300': '{sizing.5x}', + '400': '{sizing.6x}', + '500': '{sizing.7x}', + '600': '{sizing.8x}', + '700': '{sizing.10x}', + '800': '{sizing.11x}', + '850': '{sizing.14x}', + '900': '{sizing.16x}', + }, + borderRadius: { + '100': '{borderRadius.300}', + '200': '{borderRadius.400}', + max: '{borderRadius.max}', + }, + transitionDuration: '{transition.duration.200}', + padding: { + '100': '{spacing.1x}', + '200': '{spacing.2x}', + '300': '{spacing.3x}', + '400': '{spacing.4x}', + '500': '{spacing.5x}', + '600': '{spacing.6x}', + }, + gap: { + '100': '{spacing.2x}', + '200': '{spacing.3x}', + '300': '{spacing.4x}', + }, + width: { + '100': '{sizing.min}', + }, + }, + colorScheme: { + light: { + success: { + '50': '{colors.solid.green.50}', + '100': '{colors.solid.green.100}', + '200': '{colors.solid.green.200}', + '300': '{colors.solid.green.300}', + '400': '{colors.solid.green.400}', + '500': '{colors.solid.green.500}', + '600': '{colors.solid.green.600}', + '700': '{colors.solid.green.700}', + '800': '{colors.solid.green.800}', + '900': '{colors.solid.green.900}', + '950': '{colors.solid.green.950}', + }, + info: { + '50': '{colors.solid.blue.50}', + '100': '{colors.solid.blue.100}', + '200': '{colors.solid.blue.200}', + '300': '{colors.solid.blue.300}', + '400': '{colors.solid.blue.400}', + '500': '{colors.solid.blue.500}', + '600': '{colors.solid.blue.600}', + '700': '{colors.solid.blue.700}', + '800': '{colors.solid.blue.800}', + '900': '{colors.solid.blue.900}', + '950': '{colors.solid.blue.950}', + }, + warn: { + '50': '{colors.solid.yellow.50}', + '100': '{colors.solid.yellow.100}', + '200': '{colors.solid.yellow.200}', + '300': '{colors.solid.yellow.300}', + '400': '{colors.solid.yellow.400}', + '500': '{colors.solid.yellow.500}', + '600': '{colors.solid.yellow.600}', + '700': '{colors.solid.yellow.700}', + '800': '{colors.solid.yellow.800}', + '900': '{colors.solid.yellow.900}', + '950': '{colors.solid.yellow.950}', + }, + transparent: 'rgba(255, 255, 255, 0.0001)', + help: { + '50': '{colors.solid.purple.50}', + '100': '{colors.solid.purple.100}', + '200': '{colors.solid.purple.200}', + '300': '{colors.solid.purple.300}', + '400': '{colors.solid.purple.400}', + '500': '{colors.solid.purple.500}', + '600': '{colors.solid.purple.600}', + '700': '{colors.solid.purple.700}', + '800': '{colors.solid.purple.800}', + '900': '{colors.solid.purple.900}', + '950': '{colors.solid.purple.950}', + }, + error: { + '50': '{colors.solid.red.50}', + '100': '{colors.solid.red.100}', + '200': '{colors.solid.red.200}', + '300': '{colors.solid.red.300}', + '400': '{colors.solid.red.400}', + '500': '{colors.solid.red.500}', + '600': '{colors.solid.red.600}', + '700': '{colors.solid.red.700}', + '800': '{colors.solid.red.800}', + '900': '{colors.solid.red.900}', + '950': '{colors.solid.red.950}', + }, + surface: { + '0': '{colors.alpha.white.1000}', + '50': '{colors.solid.zinc.50}', + '100': '{colors.solid.zinc.100}', + '200': '{colors.solid.zinc.200}', + '300': '{colors.solid.zinc.300}', + '400': '{colors.solid.zinc.400}', + '500': '{colors.solid.zinc.500}', + '600': '{colors.solid.zinc.600}', + '700': '{colors.solid.zinc.700}', + '800': '{colors.solid.zinc.800}', + '900': '{colors.solid.zinc.900}', + '950': '{colors.solid.zinc.950}', + }, + primary: { + color: '{colors.solid.green.500}', + contrastColor: '{colors.alpha.white.1000}', + hoverColor: '{colors.solid.green.600}', + activeColor: '{colors.solid.green.700}', + hoverBackground: '{colors.solid.green.50}', + activeBackground: '{colors.solid.green.100}', + borderColor: '{colors.solid.green.200}', + selectedBackground: '{colors.solid.green.500}', + selectedHoverBackground: '{colors.solid.green.600}', + }, + highlight: { + background: '{colors.solid.zinc.900}', + focusBackground: '{colors.solid.zinc.800}', + color: '{colors.alpha.white.1000}', + focusColor: '{colors.alpha.white.1000}', + }, + focusRing: { + shadow: '{shadows.200}', + extend: { + invalid: '{colors.solid.red.200}', + success: '{colors.solid.green.200}', + warning: '{colors.solid.yellow.200}', + info: '{colors.solid.blue.200}', + }, + }, + mask: { + background: '{colors.alpha.black.400}', + color: '{surface.200}', + }, + form: { + background: '{colors.alpha.white.1000}', + disabledBackground: '{colors.solid.zinc.200}', + readonlyBackground: '{colors.solid.zinc.100}', + filledBackground: '{colors.alpha.white.1000}', + filledHoverBackground: '{colors.alpha.white.1000}', + filledFocusBackground: '{colors.alpha.white.1000}', + borderColor: '{colors.solid.zinc.300}', + hoverBorderPrimaryColor: '{colors.solid.zinc.900}', + focusBorderPrimaryColor: '{colors.solid.zinc.900}', + hoverBorderSecondaryColor: '{colors.solid.green.600}', + focusBorderSecondaryColor: '{colors.solid.green.600}', + invalidBorderColor: '{colors.solid.red.400}', + color: '{colors.solid.zinc.950}', + disabledColor: '{colors.solid.zinc.500}', + placeholderColor: '{colors.solid.zinc.500}', + invalidPlaceholderColor: '{colors.solid.red.600}', + floatLabelColor: '{colors.solid.zinc.500}', + floatLabelFocusColor: '{colors.solid.zinc.500}', + floatLabelActiveColor: '{colors.solid.zinc.500}', + floatLabelInvalidColor: '{form.invalidPlaceholderColor}', + iconColor: '{colors.solid.zinc.950}', + backgroundHandler: '{colors.alpha.white.1000}', + shadow: '{shadows.200}', + }, + text: { + color: '{colors.solid.zinc.900}', + extend: { + colorPrimaryStatic: '{colors.solid.zinc.900}', + colorSecondaryStatic: '{colors.alpha.white.1000}', + colorInverted: '{colors.alpha.white.1000}', + }, + hoverColor: '{colors.solid.zinc.700}', + primaryColor: '{colors.solid.green.600}', + hoverPrimaryColor: '{colors.solid.green.700}', + secondaryColor: '{colors.solid.zinc.600}', + hoverSecondaryColor: '{colors.solid.zinc.400}', + mutedColor: '{colors.solid.zinc.500}', + hoverMutedColor: '{colors.solid.zinc.300}', + disabledColor: '{colors.solid.zinc.300}', + infoColor: '{colors.solid.blue.600}', + successColor: '{colors.solid.green.700}', + dangerColor: '{colors.solid.red.600}', + warningColor: '{colors.solid.yellow.600}', + helpColor: '{colors.solid.purple.600}', + }, + content: { + background: '{colors.alpha.white.1000}', + hoverBackground: '{colors.solid.zinc.100}', + borderColor: '{colors.solid.zinc.200}', + activeBorderColor: '{colors.solid.zinc.800}', + color: '{text.color}', + hoverColor: '{text.hoverColor}', + shadow: '{shadows.400}', + }, + list: { + option: { + background: '{colors.alpha.white.1000}', + focusBackground: '{colors.solid.zinc.100}', + selectedBackground: '{colors.solid.zinc.900}', + selectedFocusBackground: '{colors.solid.zinc.700}', + color: '{text.color}', + focusColor: '{text.color}', + selectedColor: '{text.extend.colorInverted}', + selectedFocusColor: '{text.extend.colorInverted}', + icon: { + color: '{text.color}', + focusColor: '{text.color}', + }, + }, + optionGroup: { + background: '{colors.alpha.white.1000}', + color: '{text.mutedColor}', + }, + }, + overlay: { + select: { + background: '{colors.alpha.white.1000}', + borderColor: '{colors.solid.zinc.200}', + color: '{text.color}', + shadow: '0 0.25rem 0.5rem {colors.alpha.black.200}', + }, + popover: { + background: '{colors.alpha.white.1000}', + borderColor: '{form.borderColor}', + color: '{text.color}', + shadow: '{shadows.400}', + }, + modal: { + background: '{colors.alpha.white.1000}', + backdrop: '{colors.alpha.black.300}', + borderColor: '{colors.solid.zinc.200}', + color: '{text.color}', + shadow: '{shadows.200}', + }, + }, + navigation: { + submenuLabel: { + background: 'rgba(255, 255, 255, 0.0000)', + color: '{text.mutedColor}', + }, + submenuIcon: { + color: '{colors.solid.zinc.900}', + focusColor: '{colors.solid.zinc.900}', + activeColor: '{colors.alpha.white.1000}', + }, + item: { + focusBackground: '{colors.solid.zinc.100}', + activeBackground: '{colors.solid.zinc.900}', + color: '{colors.solid.zinc.900}', + focusColor: '{colors.solid.zinc.900}', + icon: { + color: '{colors.solid.zinc.900}', + focusColor: '{colors.solid.zinc.900}', + activeColor: '{colors.alpha.white.1000}', + }, + activeColor: '{colors.alpha.white.1000}', + }, + shadow: '{shadows.400}', + }, + }, + dark: { + success: { + '50': '{colors.solid.green.950}', + '100': '{colors.solid.green.900}', + '200': '{colors.solid.green.800}', + '300': '{colors.solid.green.700}', + '400': '{colors.solid.green.600}', + '500': '{colors.solid.green.500}', + '600': '{colors.solid.green.400}', + '700': '{colors.solid.green.300}', + '800': '{colors.solid.green.200}', + '900': '{colors.solid.green.100}', + '950': '{colors.solid.green.50}', + }, + info: { + '50': '{colors.solid.blue.950}', + '100': '{colors.solid.blue.900}', + '200': '{colors.solid.blue.800}', + '300': '{colors.solid.blue.700}', + '400': '{colors.solid.blue.600}', + '500': '{colors.solid.blue.500}', + '600': '{colors.solid.blue.400}', + '700': '{colors.solid.blue.300}', + '800': '{colors.solid.blue.200}', + '900': '{colors.solid.blue.100}', + '950': '{colors.solid.blue.50}', + }, + warn: { + '50': '{colors.solid.yellow.950}', + '100': '{colors.solid.yellow.900}', + '200': '{colors.solid.yellow.800}', + '300': '{colors.solid.yellow.700}', + '400': '{colors.solid.yellow.600}', + '500': '{colors.solid.yellow.500}', + '600': '{colors.solid.yellow.400}', + '700': '{colors.solid.yellow.300}', + '800': '{colors.solid.yellow.200}', + '900': '{colors.solid.yellow.100}', + '950': '{colors.solid.yellow.50}', + }, + transparent: 'rgba(0, 0, 0, 0.0001)', + help: { + '50': '{colors.solid.purple.950}', + '100': '{colors.solid.purple.900}', + '200': '{colors.solid.purple.800}', + '300': '{colors.solid.purple.700}', + '400': '{colors.solid.purple.600}', + '500': '{colors.solid.purple.500}', + '600': '{colors.solid.purple.400}', + '700': '{colors.solid.purple.300}', + '800': '{colors.solid.purple.200}', + '900': '{colors.solid.purple.100}', + '950': '{colors.solid.purple.50}', + }, + error: { + '50': '{colors.solid.red.950}', + '100': '{colors.solid.red.900}', + '200': '{colors.solid.red.800}', + '300': '{colors.solid.red.700}', + '400': '{colors.solid.red.600}', + '500': '{colors.solid.red.500}', + '600': '{colors.solid.red.400}', + '700': '{colors.solid.red.300}', + '800': '{colors.solid.red.200}', + '900': '{colors.solid.red.100}', + '950': '{colors.solid.red.50}', + }, + surface: { + '0': '{colors.alpha.black.1000}', + '50': '{colors.solid.zinc.950}', + '100': '{colors.solid.zinc.900}', + '200': '{colors.solid.zinc.800}', + '300': '{colors.solid.zinc.700}', + '400': '{colors.solid.zinc.600}', + '500': '{colors.solid.zinc.500}', + '600': '{colors.solid.zinc.400}', + '700': '{colors.solid.zinc.300}', + '800': '{colors.solid.zinc.200}', + '900': '{colors.solid.zinc.100}', + '950': '{colors.solid.zinc.50}', + }, + primary: { + color: '{colors.solid.green.500}', + contrastColor: '{colors.solid.zinc.900}', + hoverColor: '{colors.solid.green.400}', + activeColor: '{colors.solid.green.300}', + hoverBackground: '{colors.solid.green.950}', + activeBackground: '{colors.solid.green.900}', + borderColor: '{colors.solid.green.800}', + selectedBackground: '{colors.solid.green.500}', + selectedHoverBackground: '{colors.solid.green.600}', + }, + highlight: { + background: '{colors.solid.zinc.100}', + focusBackground: '{colors.solid.zinc.200}', + color: '{colors.solid.zinc.900}', + focusColor: '{colors.solid.zinc.900}', + }, + focusRing: { + shadow: '{shadows.200}', + extend: { + invalid: '{colors.solid.red.800}', + success: '{colors.solid.green.800}', + warning: '{colors.solid.yellow.800}', + info: '{colors.solid.blue.800}', + }, + }, + mask: { + background: '{colors.alpha.black.600}', + color: '{surface.800}', + }, + form: { + background: '{colors.solid.zinc.950}', + disabledBackground: '{colors.solid.zinc.800}', + readonlyBackground: '{colors.solid.zinc.900}', + filledBackground: '{colors.solid.zinc.950}', + filledHoverBackground: '{colors.solid.zinc.950}', + filledFocusBackground: '{colors.solid.zinc.950}', + borderColor: '{colors.solid.zinc.700}', + hoverBorderPrimaryColor: '{colors.solid.zinc.100}', + focusBorderPrimaryColor: '{colors.solid.zinc.100}', + hoverBorderSecondaryColor: '{colors.solid.green.400}', + focusBorderSecondaryColor: '{colors.solid.green.400}', + invalidBorderColor: '{colors.solid.red.600}', + color: '{colors.alpha.white.1000}', + disabledColor: '{colors.solid.zinc.500}', + placeholderColor: '{colors.solid.zinc.500}', + invalidPlaceholderColor: '{colors.solid.red.400}', + floatLabelColor: '{colors.solid.zinc.500}', + floatLabelFocusColor: '{colors.solid.zinc.500}', + floatLabelActiveColor: '{colors.solid.zinc.500}', + floatLabelInvalidColor: '{form.invalidPlaceholderColor}', + iconColor: '{colors.alpha.white.1000}', + backgroundHandler: '{colors.alpha.white.1000}', + shadow: '{shadows.200}', + }, + text: { + color: '{colors.alpha.white.1000}', + extend: { + colorPrimaryStatic: '{colors.solid.zinc.900}', + colorSecondaryStatic: '{colors.alpha.white.1000}', + colorInverted: '{colors.solid.zinc.900}', + }, + hoverColor: '{colors.solid.zinc.300}', + primaryColor: '{colors.solid.green.400}', + hoverPrimaryColor: '{colors.solid.green.300}', + secondaryColor: '{colors.solid.zinc.400}', + hoverSecondaryColor: '{colors.solid.zinc.600}', + mutedColor: '{colors.solid.zinc.500}', + hoverMutedColor: '{colors.solid.zinc.700}', + disabledColor: '{colors.solid.zinc.700}', + infoColor: '{colors.solid.blue.400}', + successColor: '{colors.solid.green.400}', + dangerColor: '{colors.solid.red.400}', + warningColor: '{colors.solid.yellow.400}', + helpColor: '{colors.solid.purple.400}', + }, + content: { + background: '{colors.solid.zinc.900}', + hoverBackground: '{colors.solid.zinc.800}', + borderColor: '{colors.solid.zinc.800}', + activeBorderColor: '{colors.solid.zinc.200}', + color: '{text.color}', + hoverColor: '{text.hoverColor}', + shadow: '{shadows.400}', + }, + list: { + option: { + background: '{colors.solid.zinc.900}', + focusBackground: '{colors.solid.zinc.800}', + selectedBackground: '{colors.solid.zinc.100}', + selectedFocusBackground: '{colors.solid.zinc.300}', + color: '{text.color}', + focusColor: '{text.color}', + selectedColor: '{text.extend.colorInverted}', + selectedFocusColor: '{text.extend.colorInverted}', + icon: { + color: '{text.color}', + focusColor: '{text.color}', + }, + }, + optionGroup: { + background: '{colors.solid.zinc.900}', + color: '{text.mutedColor}', + }, + }, + overlay: { + select: { + background: '{colors.solid.zinc.900}', + borderColor: '{colors.solid.zinc.800}', + color: '{text.color}', + shadow: '{shadows.400}', + }, + popover: { + background: '{colors.solid.zinc.900}', + borderColor: '{form.borderColor}', + color: '{text.color}', + shadow: '{shadows.400}', + }, + modal: { + background: '{colors.solid.zinc.900}', + backdrop: '{colors.alpha.black.300}', + borderColor: '{colors.solid.zinc.800}', + color: '{text.color}', + shadow: '{shadows.200}', + }, + }, + navigation: { + submenuLabel: { + background: 'rgba(255, 255, 255, 0.0000)', + color: '{text.mutedColor}', + }, + submenuIcon: { + color: '{colors.solid.zinc.100}', + focusColor: '{colors.solid.zinc.100}', + activeColor: '{colors.solid.zinc.900}', + }, + item: { + focusBackground: '{colors.solid.zinc.900}', + activeBackground: '{colors.solid.zinc.100}', + color: '{colors.alpha.white.1000}', + focusColor: '{colors.alpha.white.1000}', + icon: { + color: '{colors.alpha.white.1000}', + focusColor: '{colors.alpha.white.1000}', + activeColor: '{colors.solid.zinc.900}', + }, + activeColor: '{colors.solid.zinc.900}', + }, + shadow: '{shadows.400}', + }, + }, + }, +}; diff --git a/src/prime-preset/tokens/sizing-base.json b/src/prime-preset/tokens/sizing-base.json deleted file mode 100644 index cb9c0f35..00000000 --- a/src/prime-preset/tokens/sizing-base.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "sizingInputtext": { - "root": { - "fontSize": "0.875rem", - "paddingX": "0.875rem", - "paddingY": "0.875rem" - } - }, - "sizingSelect": { - "root": { - "fontSize": "0.875rem", - "paddingX": "0.875rem", - "paddingY": "0.875rem" - } - }, - "sizingDialog": { - "extra": { - "minWidth": "21.875rem" - } - }, - "sizingMessage": { - "width": "21.875rem" - }, - "sizingToast": { - "width": "21.875rem" - }, - "sizingDrawer": { - "width": "21.875rem" - } -} \ No newline at end of file diff --git a/src/prime-preset/tokens/sizing-lg.json b/src/prime-preset/tokens/sizing-lg.json deleted file mode 100644 index 9e2f0d67..00000000 --- a/src/prime-preset/tokens/sizing-lg.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "sizingInputtext": { - "root": { - "fontSize": "0.875rem", - "paddingX": "1.09375rem", - "paddingY": "1.09375rem" - } - }, - "sizingSelect": { - "root": { - "fontSize": "0.875rem", - "paddingX": "1.09375rem", - "paddingY": "1.09375rem" - } - }, - "sizingDialog": { - "extra": { - "minWidth": "26.25rem" - } - }, - "sizingMessage": { - "width": "26.25rem" - }, - "sizingToast": { - "width": "26.25rem" - }, - "sizingDrawer": { - "width": "26.25rem" - } -} \ No newline at end of file diff --git a/src/prime-preset/tokens/sizing-sm.json b/src/prime-preset/tokens/sizing-sm.json deleted file mode 100644 index 8118b77d..00000000 --- a/src/prime-preset/tokens/sizing-sm.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "sizingInputtext": { - "root": { - "fontSize": "0.875rem", - "paddingX": "0.65625rem", - "paddingY": "0.65625rem" - } - }, - "sizingSelect": { - "root": { - "fontSize": "0.875rem", - "paddingX": "0.65625rem", - "paddingY": "0.65625rem" - } - }, - "sizingDialog": { - "extra": { - "minWidth": "17.5rem" - } - }, - "sizingMessage": { - "width": "17.5rem" - }, - "sizingToast": { - "width": "17.5rem" - }, - "sizingDrawer": { - "width": "17.5rem" - } -} \ No newline at end of file diff --git a/src/prime-preset/tokens/sizing-xlg.json b/src/prime-preset/tokens/sizing-xlg.json deleted file mode 100644 index 8dc35163..00000000 --- a/src/prime-preset/tokens/sizing-xlg.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "sizingInputtext": { - "root": { - "fontSize": "0.875rem", - "paddingX": "1.3125rem", - "paddingY": "1.3125rem" - } - }, - "sizingSelect": { - "root": { - "fontSize": "0.875rem", - "paddingX": "1.3125rem", - "paddingY": "1.3125rem" - } - }, - "sizingDialog": { - "extra": { - "minWidth": "39.375rem" - } - }, - "sizingMessage": { - "width": "39.375rem" - }, - "sizingToast": { - "width": "39.375rem" - }, - "sizingDrawer": { - "width": "39.375rem" - } -} \ No newline at end of file diff --git a/src/prime-preset/tokens/theme-dark.json b/src/prime-preset/tokens/theme-dark.json deleted file mode 100644 index 9e1b7947..00000000 --- a/src/prime-preset/tokens/theme-dark.json +++ /dev/null @@ -1,212 +0,0 @@ -{ - "success": { - "50": "{colors.solid.green.950}", - "100": "{colors.solid.green.900}", - "200": "{colors.solid.green.800}", - "300": "{colors.solid.green.700}", - "400": "{colors.solid.green.600}", - "500": "{colors.solid.green.500}", - "600": "{colors.solid.green.400}", - "700": "{colors.solid.green.300}", - "800": "{colors.solid.green.200}", - "900": "{colors.solid.green.100}", - "950": "{colors.solid.green.50}" - }, - "info": { - "50": "{colors.solid.blue.950}", - "100": "{colors.solid.blue.900}", - "200": "{colors.solid.blue.800}", - "300": "{colors.solid.blue.700}", - "400": "{colors.solid.blue.600}", - "500": "{colors.solid.blue.500}", - "600": "{colors.solid.blue.400}", - "700": "{colors.solid.blue.300}", - "800": "{colors.solid.blue.200}", - "900": "{colors.solid.blue.100}", - "950": "{colors.solid.blue.50}" - }, - "warn": { - "50": "{colors.solid.yellow.950}", - "100": "{colors.solid.yellow.900}", - "200": "{colors.solid.yellow.800}", - "300": "{colors.solid.yellow.700}", - "400": "{colors.solid.yellow.600}", - "500": "{colors.solid.yellow.500}", - "600": "{colors.solid.yellow.400}", - "700": "{colors.solid.yellow.300}", - "800": "{colors.solid.yellow.200}", - "900": "{colors.solid.yellow.100}", - "950": "{colors.solid.yellow.50}" - }, - "transparent": "rgba(0, 0, 0, 0.0001)", - "help": { - "50": "{colors.solid.purple.950}", - "100": "{colors.solid.purple.900}", - "200": "{colors.solid.purple.800}", - "300": "{colors.solid.purple.700}", - "400": "{colors.solid.purple.600}", - "500": "{colors.solid.purple.500}", - "600": "{colors.solid.purple.400}", - "700": "{colors.solid.purple.300}", - "800": "{colors.solid.purple.200}", - "900": "{colors.solid.purple.100}", - "950": "{colors.solid.purple.50}" - }, - "error": { - "50": "{colors.solid.red.950}", - "100": "{colors.solid.red.900}", - "200": "{colors.solid.red.800}", - "300": "{colors.solid.red.700}", - "400": "{colors.solid.red.600}", - "500": "{colors.solid.red.500}", - "600": "{colors.solid.red.400}", - "700": "{colors.solid.red.300}", - "800": "{colors.solid.red.200}", - "900": "{colors.solid.red.100}", - "950": "{colors.solid.red.50}" - }, - "surface": { - "0": "{colors.alpha.black.100}", - "50": "{colors.solid.zinc.950}", - "100": "{colors.solid.zinc.900}", - "200": "{colors.solid.zinc.800}", - "300": "{colors.solid.zinc.700}", - "400": "{colors.solid.zinc.600}", - "500": "{colors.solid.zinc.500}", - "600": "{colors.solid.zinc.400}", - "700": "{colors.solid.zinc.300}", - "800": "{colors.solid.zinc.200}", - "900": "{colors.solid.zinc.100}", - "950": "{colors.solid.zinc.50}" - }, - "primary": { - "color": "{primary.500}", - "contrastColor": "{colors.solid.zinc.900}", - "hoverColor": "{primary.400}", - "activeColor": "{primary.300}" - }, - "highlight": { - "background": "{colors.solid.zinc.100}", - "focusBackground": "{colors.solid.zinc.200}", - "color": "{colors.solid.zinc.900}", - "focusColor": "{colors.solid.zinc.900}" - }, - "focusRing": { - "shadow": "0 0 0 0.2rem {primary.800}", - "extend": { - "invalid": "{colors.solid.red.800}", - "success": "{colors.solid.green.800}", - "warning": "{colors.solid.yellow.800}", - "info": "{colors.solid.blue.800}" - } - }, - "mask": { - "background": "{colors.alpha.black.60}", - "color": "{surface.800}" - }, - "formField": { - "background": "{colors.solid.zinc.950}", - "disabledBackground": "{colors.solid.zinc.800}", - "readonlyBackground": "{colors.solid.zinc.900}", - "filledBackground": "{colors.solid.zinc.950}", - "filledHoverBackground": "{colors.solid.zinc.950}", - "filledFocusBackground": "{colors.solid.zinc.950}", - "borderColor": "{colors.solid.zinc.700}", - "hoverBorderPrimaryColor": "{colors.solid.zinc.100}", - "focusBorderPrimaryColor": "{colors.solid.zinc.100}", - "hoverBorderSecondaryColor": "{colors.solid.green.400}", - "focusBorderSecondaryColor": "{colors.solid.green.400}", - "invalidBorderColor": "{colors.solid.red.600}", - "color": "{colors.alpha.white.100}", - "disabledColor": "{colors.solid.zinc.500}", - "placeholderColor": "{colors.solid.zinc.500}", - "invalidPlaceholderColor": "{colors.solid.red.400}", - "floatLabelColor": "{colors.solid.zinc.500}", - "floatLabelFocusColor": "{colors.solid.zinc.500}", - "floatLabelActiveColor": "{colors.solid.zinc.500}", - "floatLabelInvalidColor": "{formField.invalidPlaceholderColor}", - "iconColor": "{colors.alpha.white.100}", - "shadow": "rgba(255, 255, 255, 0.0000)", - "backgroundHandler": "{colors.alpha.white.100}" - }, - "text": { - "color": "{colors.alpha.white.100}", - "extend": { - "colorPrimaryStatic": "{colors.solid.zinc.900}", - "colorSecondaryStatic": "{colors.alpha.white.100}", - "colorInverted": "{colors.solid.zinc.900}" - }, - "hoverColor": "{colors.solid.zinc.300}", - "mutedColor": "{colors.solid.zinc.500}", - "hoverMutedColor": "{colors.solid.zinc.700}" - }, - "content": { - "background": "{colors.solid.zinc.900}", - "hoverBackground": "{colors.solid.zinc.800}", - "borderColor": "{colors.solid.zinc.800}", - "color": "{text.color}", - "hoverColor": "{text.hoverColor}" - }, - "overlay": { - "select": { - "background": "{colors.solid.zinc.900}", - "borderColor": "{colors.solid.zinc.800}", - "color": "{text.color}" - }, - "popover": { - "background": "{colors.solid.zinc.900}", - "borderColor": "{formField.borderColor}", - "color": "{text.color}", - "shadow": "rgba(24, 26, 31, 0.2000)" - }, - "modal": { - "background": "{colors.solid.zinc.900}", - "borderColor": "{colors.solid.zinc.800}", - "color": "{text.color}" - } - }, - "list": { - "option": { - "background": "{colors.solid.zinc.900}", - "focusBackground": "{colors.solid.zinc.800}", - "selectedBackground": "{colors.solid.zinc.100}", - "selectedFocusBackground": "{colors.solid.zinc.300}", - "color": "{text.color}", - "focusColor": "{text.color}", - "selectedColor": "{text.extend.colorInverted}", - "selectedFocusColor": "{text.extend.colorInverted}", - "icon": { - "color": "{text.color}", - "focusColor": "{text.color}" - } - }, - "surface": "#ffffff", - "optionGroup": { - "background": "{colors.solid.zinc.900}", - "color": "{text.mutedColor}" - } - }, - "navigation": { - "submenuLabel": { - "background": "rgba(255, 255, 255, 0.0000)", - "color": "{text.mutedColor}" - }, - "submenuIcon": { - "color": "{colors.solid.zinc.100}", - "focusColor": "{colors.solid.zinc.100}", - "activeColor": "{colors.solid.zinc.900}" - }, - "item": { - "focusBackground": "{colors.solid.zinc.900}", - "activeBackground": "{colors.solid.zinc.100}", - "color": "{colors.alpha.white.100}", - "focusColor": "{colors.alpha.white.100}", - "activeColor": "{colors.solid.zinc.900}", - "icon": { - "color": "{colors.alpha.white.100}", - "focusColor": "{colors.alpha.white.100}", - "activeColor": "{colors.solid.zinc.900}" - } - } - } -} \ No newline at end of file diff --git a/src/prime-preset/tokens/theme-light.json b/src/prime-preset/tokens/theme-light.json deleted file mode 100644 index d06ada7f..00000000 --- a/src/prime-preset/tokens/theme-light.json +++ /dev/null @@ -1,212 +0,0 @@ -{ - "success": { - "50": "{colors.solid.green.50}", - "100": "{colors.solid.green.100}", - "200": "{colors.solid.green.200}", - "300": "{colors.solid.green.300}", - "400": "{colors.solid.green.400}", - "500": "{colors.solid.green.500}", - "600": "{colors.solid.green.600}", - "700": "{colors.solid.green.700}", - "800": "{colors.solid.green.800}", - "900": "{colors.solid.green.900}", - "950": "{colors.solid.green.950}" - }, - "info": { - "50": "{colors.solid.blue.50}", - "100": "{colors.solid.blue.100}", - "200": "{colors.solid.blue.200}", - "300": "{colors.solid.blue.300}", - "400": "{colors.solid.blue.400}", - "500": "{colors.solid.blue.500}", - "600": "{colors.solid.blue.600}", - "700": "{colors.solid.blue.700}", - "800": "{colors.solid.blue.800}", - "900": "{colors.solid.blue.900}", - "950": "{colors.solid.blue.950}" - }, - "warn": { - "50": "{colors.solid.yellow.50}", - "100": "{colors.solid.yellow.100}", - "200": "{colors.solid.yellow.200}", - "300": "{colors.solid.yellow.300}", - "400": "{colors.solid.yellow.400}", - "500": "{colors.solid.yellow.500}", - "600": "{colors.solid.yellow.600}", - "700": "{colors.solid.yellow.700}", - "800": "{colors.solid.yellow.800}", - "900": "{colors.solid.yellow.900}", - "950": "{colors.solid.yellow.950}" - }, - "transparent": "rgba(255, 255, 255, 0.0001)", - "help": { - "50": "{colors.solid.purple.50}", - "100": "{colors.solid.purple.100}", - "200": "{colors.solid.purple.200}", - "300": "{colors.solid.purple.300}", - "400": "{colors.solid.purple.400}", - "500": "{colors.solid.purple.500}", - "600": "{colors.solid.purple.600}", - "700": "{colors.solid.purple.700}", - "800": "{colors.solid.purple.800}", - "900": "{colors.solid.purple.900}", - "950": "{colors.solid.purple.950}" - }, - "error": { - "50": "{colors.solid.red.50}", - "100": "{colors.solid.red.100}", - "200": "{colors.solid.red.200}", - "300": "{colors.solid.red.300}", - "400": "{colors.solid.red.400}", - "500": "{colors.solid.red.500}", - "600": "{colors.solid.red.600}", - "700": "{colors.solid.red.700}", - "800": "{colors.solid.red.800}", - "900": "{colors.solid.red.900}", - "950": "{colors.solid.red.950}" - }, - "surface": { - "0": "{colors.alpha.white.100}", - "50": "{colors.solid.zinc.50}", - "100": "{colors.solid.zinc.100}", - "200": "{colors.solid.zinc.200}", - "300": "{colors.solid.zinc.300}", - "400": "{colors.solid.zinc.400}", - "500": "{colors.solid.zinc.500}", - "600": "{colors.solid.zinc.600}", - "700": "{colors.solid.zinc.700}", - "800": "{colors.solid.zinc.800}", - "900": "{colors.solid.zinc.900}", - "950": "{colors.solid.zinc.950}" - }, - "primary": { - "color": "{primary.500}", - "contrastColor": "{surface.0}", - "hoverColor": "{primary.600}", - "activeColor": "{primary.700}" - }, - "highlight": { - "background": "{colors.solid.zinc.900}", - "focusBackground": "{colors.solid.zinc.800}", - "color": "{colors.alpha.white.100}", - "focusColor": "{colors.alpha.white.100}" - }, - "focusRing": { - "shadow": "0 0 0 0.2rem {primary.200}", - "extend": { - "invalid": "{colors.solid.red.200}", - "success": "{colors.solid.green.200}", - "warning": "{colors.solid.yellow.200}", - "info": "{colors.solid.blue.200}" - } - }, - "mask": { - "background": "{colors.alpha.black.40}", - "color": "{surface.200}" - }, - "formField": { - "background": "{colors.alpha.white.100}", - "disabledBackground": "{colors.solid.zinc.200}", - "readonlyBackground": "{colors.solid.zinc.100}", - "filledBackground": "{colors.alpha.white.100}", - "filledHoverBackground": "{colors.alpha.white.100}", - "filledFocusBackground": "{colors.alpha.white.100}", - "borderColor": "{colors.solid.zinc.300}", - "hoverBorderPrimaryColor": "{colors.solid.zinc.900}", - "focusBorderPrimaryColor": "{colors.solid.zinc.900}", - "hoverBorderSecondaryColor": "{colors.solid.green.600}", - "focusBorderSecondaryColor": "{colors.solid.green.600}", - "invalidBorderColor": "{colors.solid.red.400}", - "color": "{colors.solid.zinc.950}", - "disabledColor": "{colors.solid.zinc.500}", - "placeholderColor": "{colors.solid.zinc.500}", - "invalidPlaceholderColor": "{colors.solid.red.600}", - "floatLabelColor": "{colors.solid.zinc.500}", - "floatLabelFocusColor": "{colors.solid.zinc.500}", - "floatLabelActiveColor": "{colors.solid.zinc.500}", - "floatLabelInvalidColor": "{formField.invalidPlaceholderColor}", - "iconColor": "{colors.solid.zinc.950}", - "shadow": "rgba(0, 0, 0, 0.0000)", - "backgroundHandler": "{colors.alpha.white.100}" - }, - "text": { - "color": "{colors.solid.zinc.900}", - "extend": { - "colorPrimaryStatic": "{colors.solid.zinc.900}", - "colorSecondaryStatic": "{colors.alpha.white.100}", - "colorInverted": "{colors.alpha.white.100}" - }, - "hoverColor": "{colors.solid.zinc.700}", - "mutedColor": "{colors.solid.zinc.500}", - "hoverMutedColor": "{colors.solid.zinc.300}" - }, - "content": { - "background": "{colors.alpha.white.100}", - "hoverBackground": "{colors.solid.zinc.100}", - "borderColor": "{colors.solid.zinc.200}", - "color": "{text.color}", - "hoverColor": "{text.hoverColor}" - }, - "overlay": { - "select": { - "background": "{colors.alpha.white.100}", - "borderColor": "{colors.solid.zinc.200}", - "color": "{text.color}" - }, - "popover": { - "background": "{colors.alpha.white.100}", - "borderColor": "{formField.borderColor}", - "color": "{text.color}", - "shadow": "rgba(24, 26, 31, 0.2000)" - }, - "modal": { - "background": "{colors.alpha.white.100}", - "borderColor": "{colors.solid.zinc.200}", - "color": "{text.color}" - } - }, - "list": { - "option": { - "background": "{colors.alpha.white.100}", - "focusBackground": "{colors.solid.zinc.100}", - "selectedBackground": "{colors.solid.zinc.900}", - "selectedFocusBackground": "{colors.solid.zinc.700}", - "color": "{text.color}", - "focusColor": "{text.color}", - "selectedColor": "{text.extend.colorInverted}", - "selectedFocusColor": "{text.extend.colorInverted}", - "icon": { - "color": "{text.color}", - "focusColor": "{text.color}" - } - }, - "surface": "#ffffff", - "optionGroup": { - "background": "{colors.alpha.white.100}", - "color": "{text.mutedColor}" - } - }, - "navigation": { - "submenuLabel": { - "background": "rgba(255, 255, 255, 0.0000)", - "color": "{text.mutedColor}" - }, - "submenuIcon": { - "color": "{colors.solid.zinc.900}", - "focusColor": "{colors.solid.zinc.900}", - "activeColor": "{colors.alpha.white.100}" - }, - "item": { - "focusBackground": "{colors.solid.zinc.100}", - "activeBackground": "{colors.solid.zinc.900}", - "color": "{colors.solid.zinc.900}", - "focusColor": "{colors.solid.zinc.900}", - "activeColor": "{colors.alpha.white.100}", - "icon": { - "color": "{colors.solid.zinc.900}", - "focusColor": "{colors.solid.zinc.900}", - "activeColor": "{colors.alpha.white.100}" - } - } - } -} \ No newline at end of file diff --git a/src/stories/components/button/button.stories.ts b/src/stories/components/button/button.stories.ts index 80c11661..7df3d34a 100644 --- a/src/stories/components/button/button.stories.ts +++ b/src/stories/components/button/button.stories.ts @@ -1,48 +1,388 @@ -import { Meta, moduleMetadata } from '@storybook/angular'; - -import { ButtonModule } from 'primeng/button'; - -import { ButtonBaseComponent, Base } from './examples/button-base.component'; -import { ButtonSizesComponent, Sizes } from './examples/button-sizes.component'; -import { ButtonRoundedComponent, Rounded } from './examples/button-rounded.component'; -import { ButtonOutlinedComponent, Outlined } from './examples/button-outlined.component'; -import { ButtonTextComponent, Text } from './examples/button-text.component'; -import { ButtonIconComponent, Icon } from './examples/button-icon.component'; -import { ButtonDisabledComponent, Disabled } from './examples/button-disabled.component'; -import { ButtonLoadingComponent, Loading } from './examples/button-loading.component'; -import { ButtonBadgeComponent, Badge } from './examples/button-badge.component'; -import { ButtonSeverityComponent, Severity } from './examples/button-severity.component'; -import { CommonModule } from '@angular/common'; - -const meta: Meta = { - title: 'PrimeNG/Button', +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { ExtraButtonComponent } from '../../../components/button/button-extra.component'; + +const gridTemplate = (inner: string) => ` +
+ small + base + large + xlarge + ${inner} +
+`; + +const meta: Meta = { + title: 'Prime/Button', + component: ExtraButtonComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ - imports: [ - CommonModule, - ButtonModule, - ButtonBaseComponent, - ButtonSizesComponent, - ButtonRoundedComponent, - ButtonOutlinedComponent, - ButtonTextComponent, - ButtonIconComponent, - ButtonDisabledComponent, - ButtonLoadingComponent, - ButtonBadgeComponent, - ButtonSeverityComponent - ] + imports: [ExtraButtonComponent] }) ], parameters: { docs: { description: { - component: 'Компонент кнопки с различными стилями, состояниями и иконками' - } - } - } + component: + 'Кнопка — базовый интерактивный элемент. [Figma Design](https://www.figma.com/design/HOLKdvQJ8jCLeX17s9d0Yf/UI-Kit--DS--v2.0?node-id=160-5223)', + }, + }, + }, + argTypes: { + label: { + control: 'text', + description: 'Текст кнопки', + table: { + category: 'Props', + defaultValue: { summary: 'Button' }, + type: { summary: 'string' }, + }, + }, + variant: { + control: 'select', + options: ['primary', 'secondary', 'outlined', 'text', 'link'], + description: 'Вариант отображения кнопки', + table: { + category: 'Props', + defaultValue: { summary: 'primary' }, + type: { summary: "'primary' | 'secondary' | 'outlined' | 'text' | 'link'" }, + }, + }, + severity: { + control: 'select', + options: [null, 'success', 'info', 'warning', 'danger'], + description: 'Семантический вариант кнопки', + table: { + category: 'Props', + defaultValue: { summary: 'null' }, + type: { summary: "'success' | 'info' | 'warning' | 'danger' | null" }, + }, + }, + size: { + control: 'select', + options: ['small', 'base', 'large', 'xlarge'], + description: 'Размер кнопки', + table: { + category: 'Props', + defaultValue: { summary: 'base' }, + type: { summary: "'small' | 'base' | 'large' | 'xlarge'" }, + }, + }, + icon: { + control: 'text', + description: 'CSS-класс иконки (например: ti ti-check)', + table: { + category: 'Props', + defaultValue: { summary: '' }, + type: { summary: 'string' }, + }, + }, + iconPos: { + control: 'select', + options: [null, 'prefix', 'postfix'], + description: 'Позиция иконки относительно текста', + table: { + category: 'Props', + defaultValue: { summary: 'null' }, + type: { summary: "'prefix' | 'postfix' | null" }, + }, + }, + iconOnly: { + control: 'boolean', + description: 'Только иконка, без текста', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + rounded: { + control: 'boolean', + description: 'Скруглённая форма кнопки', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + disabled: { + control: 'boolean', + description: 'Отключённое состояние', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + loading: { + control: 'boolean', + description: 'Состояние загрузки с индикатором', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + }, }; + export default meta; +type Story = StoryObj; + +// ── Default ────────────────────────────────────────────────────────────────── + +export const ButtonDefault: Story = { + name: 'Button', + args: { + label: 'Button', + }, + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + source: { + code: ``, + }, + }, + }, +}; + +// ── Stories ────────────────────────────────────────────────────────────────── + +export const Sizes: Story = { + render: (args) => ({ + props: args, + template: gridTemplate(` + + + + + `), + }), + args: { label: 'Button' }, + parameters: { + docs: { + description: { story: 'Все доступные размеры: small, base, large, xlarge.' }, + source: { + code: ` + + + +`, + }, + }, + }, +}; + +export const Icons: Story = { + render: (args) => ({ + props: args, + template: gridTemplate(` + + + + + `), + }), + args: { label: 'Button', icon: 'ti ti-check' }, + parameters: { + docs: { + description: { story: 'Кнопки с иконками (префикс по умолчанию).' }, + source: { + code: ``, + }, + }, + }, +}; + +export const IconOnly: Story = { + render: (args) => ({ + props: args, + template: gridTemplate(` + + + + + `), + }), + args: { icon: 'ti ti-check' }, + parameters: { + docs: { + description: { story: 'Кнопки без текста, только с иконкой.' }, + source: { + code: ``, + }, + }, + }, +}; + +export const Loading: Story = { + render: (args) => ({ + props: args, + template: gridTemplate(` + + + + + `), + }), + args: { label: 'Button' }, + parameters: { + docs: { + description: { story: 'Состояние загрузки с индикатором.' }, + source: { + code: ``, + }, + }, + }, +}; -export { Base, Disabled, Loading, Sizes, Rounded, Outlined, Text, Icon, Badge, Severity }; +export const Rounded: Story = { + render: (args) => ({ + props: args, + template: gridTemplate(` + + + + + `), + }), + args: { label: 'Button' }, + parameters: { + docs: { + description: { story: 'Скруглённая форма кнопок.' }, + source: { + code: ``, + }, + }, + }, +}; + +export const Text: Story = { + render: (args) => ({ + props: args, + template: gridTemplate(` + + + + + `), + }), + args: { label: 'Button' }, + parameters: { + docs: { + description: { story: 'Текстовый вариант кнопки (без заливки и границ).' }, + source: { + code: ``, + }, + }, + }, +}; + +export const Link: Story = { + render: (args) => ({ + props: args, + template: gridTemplate(` + + + + + `), + }), + args: { label: 'Link Button' }, + parameters: { + docs: { + description: { story: 'Кнопка в виде ссылки.' }, + source: { + code: ``, + }, + }, + }, +}; + +export const Severity: Story = { + render: () => ({ + template: ` +
+ + success + info + warning + danger + + small + + + + + + base + + + + + + large + + + + + + xlarge + + + + +
+ `, + }), + parameters: { + docs: { + description: { story: 'Цветовые схемы для различных контекстов: success, info, warning, danger.' }, + source: { + code: ``, + }, + }, + }, +}; + +export const Disabled: Story = { + render: () => ({ + template: ` +
+ + success + info + warning + danger + + default + + + + + + outlined + + + + + + text + + + + +
+ `, + }), + parameters: { + docs: { + description: { story: 'Состояние кнопки, при котором взаимодействие заблокировано.' }, + source: { + code: ``, + }, + }, + }, +}; diff --git a/src/stories/components/button/examples/button-extra.component.ts b/src/stories/components/button/examples/button-extra.component.ts new file mode 100644 index 00000000..46814e3e --- /dev/null +++ b/src/stories/components/button/examples/button-extra.component.ts @@ -0,0 +1,87 @@ +import { StoryObj } from '@storybook/angular'; + +export { ExtraButtonComponent } from '../../../../../components/button/button-extra.component'; + +export const Extra: StoryObj = { + render: (args) => ({ + props: args, + template: ` +` + }), + args: { + label: 'Button', + variant: 'primary', + severity: null, + size: 'base', + rounded: false, + iconPos: null, + iconOnly: false, + icon: '', + disabled: false, + loading: false + }, + argTypes: { + label: { + control: 'text', + description: 'Текст кнопки' + }, + variant: { + control: 'select', + options: ['primary', 'secondary', 'outlined', 'text', 'link'], + description: 'Вариант отображения кнопки' + }, + severity: { + control: 'select', + options: [null, 'success', 'warning', 'danger', 'info'], + description: 'Цветовая схема кнопки' + }, + size: { + control: 'select', + options: ['small', 'base', 'large', 'xlarge'], + description: 'Размер кнопки' + }, + rounded: { + control: 'boolean', + description: 'Скруглённая форма кнопки' + }, + iconPos: { + control: 'select', + options: [null, 'prefix', 'postfix'], + description: 'Позиция иконки (prefix — слева, postfix — справа)' + }, + iconOnly: { + control: 'boolean', + description: 'Режим кнопки только с иконкой' + }, + icon: { + control: 'text', + description: 'CSS-класс иконки (например: ti ti-check)' + }, + disabled: { + control: 'boolean', + description: 'Отключённое состояние' + }, + loading: { + control: 'boolean', + description: 'Состояние загрузки с индикатором' + } + }, + parameters: { + docs: { + description: { + story: 'Интерактивный пример с пропсами, соответствующими Figma-компоненту Button.' + } + } + } +}; diff --git a/src/styles.scss b/src/styles.scss index e6cb491c..fae03824 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -3,3 +3,21 @@ @tailwind utilities; @import '@tabler/icons-webfont/dist/tabler-icons.min.css'; + +@font-face { + font-family: 'TT Fellows'; + src: url('./assets/fonts/tt-fellows/TT_Fellows_Regular.woff2') format('woff2'); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: 'TT Fellows'; + src: url('./assets/fonts/tt-fellows/TT_Fellows_DemiBold.woff2') format('woff2'); + font-weight: 600; + font-style: normal; +} + +html { + font-size: 14px; +} From 630c16397faf18ac6b8236d94b282e9816cf5c5b Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 26 Mar 2026 21:10:47 +0700 Subject: [PATCH 004/258] =?UTF-8?q?button:=20=D0=BF=D1=80=D0=BE=D0=BF?= =?UTF-8?q?=D1=81=20badge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- angular.json | 3 + documentation.json | 1300 +++++++++-------- .../button/button-extra.component.ts | 8 +- src/components/button/button.component.scss | 15 + .../components/button/button.stories.ts | 222 ++- .../button/examples/button-extra.component.ts | 90 +- 6 files changed, 890 insertions(+), 748 deletions(-) diff --git a/angular.json b/angular.json index 0cbea1d6..15527515 100644 --- a/angular.json +++ b/angular.json @@ -117,5 +117,8 @@ } } } + }, + "cli": { + "analytics": false } } \ No newline at end of file diff --git a/documentation.json b/documentation.json index d00b737f..a5b9d486 100644 --- a/documentation.json +++ b/documentation.json @@ -9,7 +9,7 @@ "components": [ { "name": "ButtonBadgeComponent", - "id": "component-ButtonBadgeComponent-c9b005f02f6e55b548ed6d44acdd87fbdf45b61e3a7f18d9d961e78d431b006c05ee81e31efae1ae4ec339fb6b7695b596dedf691d78ee81e927ce08eee82673", + "id": "component-ButtonBadgeComponent-fab33f9afdb48c6fae49d289621dfd7234c7920f7d3f703dac62f523dd0852ba668326634ecf1aaddf69f2b1afbd505312415662d1865b6b360fbd9dec82dafc", "file": "src/stories/components/button/examples/button-badge.component.ts", "encapsulation": [], "entryComponents": [], @@ -18,8 +18,10 @@ "providers": [], "selector": "app-button-badge", "styleUrls": [], - "styles": [], - "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n
\n
\n`", + "styles": [ + "" + ], + "template": "`
\n
\n \n\n \n\n \n\n \n
\n
\n`", "templateUrl": [], "viewProviders": [], "hostDirectives": [], @@ -34,26 +36,21 @@ "standalone": true, "imports": [ { - "name": "ButtonModule", - "type": "module" - }, - { - "name": "OverlayBadgeModule", - "type": "module" + "name": "Button" } ], "description": "", "rawdescription": "\n", "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\nimport { OverlayBadgeModule } from 'primeng/overlaybadge';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-badge',\n standalone: true,\n imports: [ButtonModule, OverlayBadgeModule],\n template\n})\nexport class ButtonBadgeComponent {}\n\nexport const Badge: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с уведомлением или числовым индикатором (OverlayBadge).'\n }\n }\n }\n};\n", + "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n
\n \n\n \n\n \n\n \n
\n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-badge',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonBadgeComponent {}\n\nexport const Badge: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Badge кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonBadgeComponent {}\n `\n }\n }\n }\n};\n", "assetsDirs": [], "styleUrlsData": "", - "stylesData": "", + "stylesData": "\n", "extends": [] }, { "name": "ButtonBaseComponent", - "id": "component-ButtonBaseComponent-81242ea4c12e4bd3710ef0ab4cd6263ecce5f5d559192ef040bf30fd20b9ff129d272455cd71793f536ca24f9722d12c4da599572fdc45d6162bc6ffd2e3fa0c", + "id": "component-ButtonBaseComponent-c8c405f4a3866155397528b8d67e747d1937ffdd827b6ac823a7f62bf82334820d309b144e65e531862b26ce7b6b3b20f332282f3e7200aa9077211d9f26a9f5", "file": "src/stories/components/button/examples/button-base.component.ts", "encapsulation": [], "entryComponents": [], @@ -62,8 +59,10 @@ "providers": [], "selector": "app-button-base", "styleUrls": [], - "styles": [], - "template": "`
\n \n \n
\n`", + "styles": [ + "" + ], + "template": "`
\n \n \n
\n`", "templateUrl": [], "viewProviders": [], "hostDirectives": [], @@ -73,7 +72,7 @@ "defaultValue": "''", "deprecated": false, "deprecationMessage": "", - "line": 41, + "line": 42, "type": "string", "decorators": [] }, @@ -91,7 +90,7 @@ "defaultValue": "''", "deprecated": false, "deprecationMessage": "", - "line": 39, + "line": 40, "type": "string", "decorators": [] }, @@ -100,7 +99,7 @@ "defaultValue": "'left'", "deprecated": false, "deprecationMessage": "", - "line": 40, + "line": 41, "type": "ButtonIconPosition", "decorators": [] }, @@ -122,6 +121,15 @@ "type": "boolean", "decorators": [] }, + { + "name": "outlined", + "defaultValue": "false", + "deprecated": false, + "deprecationMessage": "", + "line": 38, + "type": "boolean", + "decorators": [] + }, { "name": "rounded", "defaultValue": "false", @@ -136,7 +144,7 @@ "defaultValue": "null", "deprecated": false, "deprecationMessage": "", - "line": 42, + "line": 43, "type": "Extract", "decorators": [] }, @@ -145,16 +153,16 @@ "deprecated": false, "deprecationMessage": "", "line": 36, - "type": "\"small\" | \"large\" | \"xlarge\" | undefined", + "type": "\"small\" | \"large\" | undefined", "decorators": [] }, { - "name": "variant", - "defaultValue": "null", + "name": "text", + "defaultValue": "false", "deprecated": false, "deprecationMessage": "", - "line": 38, - "type": "\"outlined\" | \"text\" | \"link\" | null", + "line": 39, + "type": "boolean", "decorators": [] } ], @@ -174,15 +182,15 @@ "description": "", "rawdescription": "\n", "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { Button, ButtonIconPosition } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n \n \n
\n`;\n\n@Component({\n selector: 'app-button-base',\n standalone: true,\n imports: [Button],\n template\n})\nexport class ButtonBaseComponent {\n @Input() label = '';\n @Input() disabled = false;\n @Input() loading = false;\n @Input() size: 'small' | 'large' | 'xlarge' | undefined;\n @Input() rounded = false;\n @Input() variant: 'outlined' | 'text' | 'link' | null = null;\n @Input() icon: string = '';\n @Input() iconPos: ButtonIconPosition = 'left';\n @Input() badge: string = '';\n @Input() severity: Extract = null;\n}\n\nexport const Default: StoryObj = {\n render: (args) => ({\n props: args,\n template: `\n\n`\n }),\n args: {\n label: 'Button',\n disabled: false,\n loading: false,\n size: null,\n rounded: false,\n variant: null,\n icon: '',\n iconPos: 'left',\n badge: '',\n severity: null\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n },\n size: {\n control: 'select',\n options: [null, 'small', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n variant: {\n control: 'select',\n options: [null, 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n iconPos: {\n control: 'select',\n options: ['left', 'right', 'top', 'bottom'],\n description: 'Позиция иконки относительно текста'\n },\n badge: {\n control: 'text',\n description: 'Текст для отображения в виде бейджа на кнопке'\n },\n severity: {\n control: 'select',\n options: [null, 'secondary', 'contrast', 'success', 'info', 'warn', 'help', 'danger'],\n description: 'Семантический вариант кнопки'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.'\n }\n }\n }\n};\n", + "sourceCode": "import { Component, Input } from '@angular/core';\nimport { Button, ButtonIconPosition } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n \n \n
\n`;\nconst styles = ``;\n\n@Component({\n selector: 'app-button-base',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonBaseComponent {\n @Input() label = '';\n @Input() disabled = false;\n @Input() loading = false;\n @Input() size: 'small' | 'large' | undefined;\n @Input() rounded = false;\n @Input() outlined = false;\n @Input() text = false;\n @Input() icon: string = '';\n @Input() iconPos: ButtonIconPosition = 'left';\n @Input() badge: string = '';\n @Input() severity: Extract = null;\n}\n\nexport const Base: StoryObj = {\n render: (args) => ({\n props: args,\n template: `\n\n`\n }),\n args: {\n label: 'Base button',\n disabled: false,\n loading: false,\n size: null,\n rounded: false,\n outlined: false,\n text: false,\n icon: '',\n iconPos: null,\n badge: '',\n severity: null\n },\n argTypes: {\n label: {\n description: 'Текст кнопки.'\n },\n disabled: {\n description: 'При наличии указывает, что компонент должен быть отключен.'\n },\n loading: {\n description: 'Находится ли кнопка в состоянии загрузки.'\n },\n // TODO Добавить xlarge после фикса в либе.\n size: {\n description: 'Определяет размер кнопки.',\n control: { type: 'select' },\n options: [null, 'small', 'large'],\n table: {\n type: { summary: `'small' | 'large' | null` } // <-- тип в документации\n }\n },\n rounded: {\n description: 'При наличии делает кнопку с закругленными краями.'\n },\n outlined: {\n description: 'При наличии делает кнопку с контуром без фона.'\n },\n text: {\n description: 'При наличии делает кнопку текстовой без фона и границ.'\n },\n icon: {\n description: 'Имя иконки для отображения в кнопке.'\n },\n iconPos: {\n description: 'Позиция иконки относительно текста.',\n control: { type: 'select' },\n options: [null, 'left', 'right'],\n table: {\n type: { summary: `'left' | 'right' | null` }\n }\n },\n badge: {\n description: 'Текст для отображения в виде бейджа на кнопке.'\n },\n severity: {\n description: 'Определяет цветовую схему кнопки.',\n control: { type: 'select' },\n options: [null, 'success', 'info', 'warn', 'primary', 'help', 'danger'],\n table: {\n type: {\n summary: `'success' | 'info' | 'warn' | 'primary' | 'help' | 'danger' | null`\n }\n }\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Стандартная кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-base',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonBaseComponent {\n @Input() label = '';\n @Input() disabled = false;\n @Input() loading = false;\n @Input() size: 'small' | 'large' | null = null;\n @Input() rounded = false;\n}\n `\n }\n }\n }\n};\n", "assetsDirs": [], "styleUrlsData": "", - "stylesData": "", + "stylesData": "\n", "extends": [] }, { "name": "ButtonDisabledComponent", - "id": "component-ButtonDisabledComponent-68a58df505e94299e8d28d3d882464c07106fc021b1ff9a5b2aa900da697878649bb93a7d3022da8d410db37dd98bee18061262bcf1e065b11b8420b496f2216", + "id": "component-ButtonDisabledComponent-08149394bbd9dbd2d50d65e9a92b7cbac68e072764309fc410968d2ef7c91352a365dc0e14dd6193f13ab6eaa25606e8f505fc0a1c17097427aa69d168736ab8", "file": "src/stories/components/button/examples/button-disabled.component.ts", "encapsulation": [], "entryComponents": [], @@ -191,8 +199,10 @@ "providers": [], "selector": "app-button-disabled", "styleUrls": [], - "styles": [], - "template": "`
\n
\n \n success\n info\n warn\n danger\n\n default\n \n \n \n \n\n outlined\n \n \n \n \n\n text\n \n \n \n \n
\n
\n`", + "styles": [ + "" + ], + "template": "`
\n
\n \n
\n
\n`", "templateUrl": [], "viewProviders": [], "hostDirectives": [], @@ -207,22 +217,21 @@ "standalone": true, "imports": [ { - "name": "ButtonModule", - "type": "module" + "name": "Button" } ], "description": "", "rawdescription": "\n", "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n \n success\n info\n warn\n danger\n\n default\n \n \n \n \n\n outlined\n \n \n \n \n\n text\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-disabled',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonDisabledComponent {}\n\nexport const Disabled: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Состояние кнопки, при котором взаимодействие с ней заблокировано.'\n }\n }\n }\n};\n", + "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n
\n \n
\n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-disabled',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonDisabledComponent {}\n\nexport const Disabled: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Disabled кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-disabled',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonDisabledComponent {}\n `\n }\n }\n }\n};\n", "assetsDirs": [], "styleUrlsData": "", - "stylesData": "", + "stylesData": "\n", "extends": [] }, { "name": "ButtonIconComponent", - "id": "component-ButtonIconComponent-593709211f63b4521fe1da011a69eb0b10325b97b3079d710c392a135c70c4087d1dbaeedf8335be9925cfea65651eb17bbe1c054f5064dfef72ada6437d537c", + "id": "component-ButtonIconComponent-553ddfe0086eec00020f592a5e46510ee6019a96420a18f0fc74e8ac183c5cd0e7ec864d369e6d9f3b378c09c5553bd2f92f8a6c407390fe601668ef0e6909ca", "file": "src/stories/components/button/examples/button-icon.component.ts", "encapsulation": [], "entryComponents": [], @@ -231,88 +240,10 @@ "providers": [], "selector": "app-button-icon", "styleUrls": [], - "styles": [], - "template": "`
\n
\n \n icon prefix\n icon postfix\n rounded\n\n xlarge\n \n \n \n\n large\n \n \n \n\n base\n \n \n \n\n small\n \n \n \n
\n
\n`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "ButtonModule", - "type": "module" - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n \n icon prefix\n icon postfix\n rounded\n\n xlarge\n \n \n \n\n large\n \n \n \n\n base\n \n \n \n\n small\n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-icon',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonIconComponent {}\n\nexport const Icons: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки могут содержать иконки слева, справа или быть скруглёнными.'\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "extends": [] - }, - { - "name": "ButtonIconOnlyComponent", - "id": "component-ButtonIconOnlyComponent-fd1de76754aa7f8fc48d81d4ca05e7f173032e18879c1ce3a3be46c2f6f02bae7b92f40d2a17085bd004bca0f6cf63fb32ff2fdbcc57868797294c2e1f878fb1", - "file": "src/stories/components/button/examples/button-icon-only.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-icon-only", - "styleUrls": [], - "styles": [], - "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "ButtonModule", - "type": "module" - } + "styles": [ + "" ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-icon-only',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonIconOnlyComponent {}\n\nexport const IconOnly: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'В случаях, когда текст не требуется, можно использовать только иконку.'\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "extends": [] - }, - { - "name": "ButtonLinkComponent", - "id": "component-ButtonLinkComponent-007a470d2943d83647e22b07ab1a166adb2bcf5277a70764dbf493bd57f58eab655647073590a738e950f3a47daabe97c64a32cbfd51889f3aa4bbfac5339690", - "file": "src/stories/components/button/examples/button-link.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-link", - "styleUrls": [], - "styles": [], - "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", + "template": "`
\n
\n \n \n \n
\n
\n`", "templateUrl": [], "viewProviders": [], "hostDirectives": [], @@ -327,22 +258,21 @@ "standalone": true, "imports": [ { - "name": "ButtonModule", - "type": "module" + "name": "Button" } ], "description": "", "rawdescription": "\n", "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-link',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonLinkComponent {}\n\nexport const Link: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка, стилизованная под ссылку.'\n }\n }\n }\n};\n", + "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n
\n \n \n \n
\n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-icon',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonIconComponent {}\n\nexport const Icon: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки с иконками'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-icon',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonIconComponent {}\n `\n }\n }\n }\n};\n", "assetsDirs": [], "styleUrlsData": "", - "stylesData": "", + "stylesData": "\n", "extends": [] }, { "name": "ButtonLoadingComponent", - "id": "component-ButtonLoadingComponent-38ebe46e8e8f5c9b416d26a65e30fdd9fe7157c394ba9d632f9f8a228a63111342eeedfc9f723724dcd8cc7e6a745b43d412fede99d2c8721a1c2652cec7362c", + "id": "component-ButtonLoadingComponent-747831019d46f2ad5ee976a755845a807fe3d6fce93323c22753c42a300535885ea9570f93c580b2377de7ec8a16386caea5d52b5d8c5d87cf9ba97198870ace", "file": "src/stories/components/button/examples/button-loading.component.ts", "encapsulation": [], "entryComponents": [], @@ -351,8 +281,10 @@ "providers": [], "selector": "app-button-loading", "styleUrls": [], - "styles": [], - "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", + "styles": [ + "" + ], + "template": "`
\n
\n \n
\n
\n`", "templateUrl": [], "viewProviders": [], "hostDirectives": [], @@ -367,22 +299,21 @@ "standalone": true, "imports": [ { - "name": "ButtonModule", - "type": "module" + "name": "Button" } ], "description": "", "rawdescription": "\n", "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-loading',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonLoadingComponent {}\n\nexport const Loading: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с индикатором загрузки. Полезно для асинхронных действий.'\n }\n }\n }\n};\n", + "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n
\n \n
\n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-loading',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonLoadingComponent {}\n\nexport const Loading: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка в состоянии загрузки'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-loading',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonLoadingComponent {}\n `\n }\n }\n }\n};\n", "assetsDirs": [], "styleUrlsData": "", - "stylesData": "", + "stylesData": "\n", "extends": [] }, { "name": "ButtonOutlinedComponent", - "id": "component-ButtonOutlinedComponent-a13faff82fc977a14c4c2617748ac67685eeb29cc4d41568bbdb138ee506668f41237e08b7300bfed3ed505f22b2c92024bf893b714db9e69c0d3e51c71e55eb", + "id": "component-ButtonOutlinedComponent-2f780c950280808a263be91edeaa56e63eedc39495be6eca8bb7dcea5d56a09aea77d6cecdb9341715d1e1f7c582df95b46fd1321497a1536e21b716244a4a5a", "file": "src/stories/components/button/examples/button-outlined.component.ts", "encapsulation": [], "entryComponents": [], @@ -391,8 +322,10 @@ "providers": [], "selector": "app-button-outlined", "styleUrls": [], - "styles": [], - "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", + "styles": [ + "" + ], + "template": "`
\n \n \n
`", "templateUrl": [], "viewProviders": [], "hostDirectives": [], @@ -407,22 +340,21 @@ "standalone": true, "imports": [ { - "name": "ButtonModule", - "type": "module" + "name": "Button" } ], "description": "", "rawdescription": "\n", "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-outlined',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonOutlinedComponent {}\n\nexport const Outlined: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с контуром без заливки.'\n }\n }\n }\n};\n", + "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n \n \n
`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-outlined',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonOutlinedComponent {}\n\nexport const Outlined: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Outlined кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-outlined',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonOutlinedComponent {}\n `\n }\n }\n }\n};\n", "assetsDirs": [], "styleUrlsData": "", - "stylesData": "", + "stylesData": "\n", "extends": [] }, { "name": "ButtonRoundedComponent", - "id": "component-ButtonRoundedComponent-6bb6041fd5f04e03709f54d657c1deb7a399760fcfa23e48faf81626afbdf66a023798e961b7a9dd6eb2290dfab0d66b85b0693e4153758f0e107194f6f529ba", + "id": "component-ButtonRoundedComponent-75651107f6304e710142aef6f4f68ec0f1069847af847d954b7de576ea710779cec3f802adc8586bc9683100e14432e4c15d5d58fa2f7204d7e2e2d034db308a", "file": "src/stories/components/button/examples/button-rounded.component.ts", "encapsulation": [], "entryComponents": [], @@ -431,8 +363,10 @@ "providers": [], "selector": "app-button-rounded", "styleUrls": [], - "styles": [], - "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", + "styles": [ + "" + ], + "template": "`
\n
\n \n
\n
\n`", "templateUrl": [], "viewProviders": [], "hostDirectives": [], @@ -447,22 +381,21 @@ "standalone": true, "imports": [ { - "name": "ButtonModule", - "type": "module" + "name": "Button" } ], "description": "", "rawdescription": "\n", "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-rounded',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonRoundedComponent {}\n\nexport const Rounded: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Полностью скруглённая форма кнопки.'\n }\n }\n }\n};\n", + "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n
\n \n
\n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-rounded',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonRoundedComponent {}\n\nexport const Rounded: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Скругленная кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-rounded',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonRoundedComponent {}\n `\n }\n }\n }\n};\n", "assetsDirs": [], "styleUrlsData": "", - "stylesData": "", + "stylesData": "\n", "extends": [] }, { "name": "ButtonSeverityComponent", - "id": "component-ButtonSeverityComponent-4224631554907621005b0d851894c01123bd61db2006116292e39193a72529526c066b8a3a0b11fe7a6af30c49f9baf6543c07a8f1fe9fbace37ad0348cf2a9d", + "id": "component-ButtonSeverityComponent-bceea86d34a4ff6c3637b6c4b0dfe628631cbeeacb8537089aaeb500fef8c51fbad4689c06a2de3d51f4f3510bc7520fd634f48cb91995dc93e187ab3099c6e5", "file": "src/stories/components/button/examples/button-severity.component.ts", "encapsulation": [], "entryComponents": [], @@ -471,8 +404,10 @@ "providers": [], "selector": "app-button-severity", "styleUrls": [], - "styles": [], - "template": "`
\n
\n \n success\n info\n warn\n danger\n\n small\n \n \n \n \n\n base\n \n \n \n \n\n large\n \n \n \n \n\n xlarge\n \n \n \n \n
\n
\n`", + "styles": [ + "" + ], + "template": "`
\n
\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n
\n
\n`", "templateUrl": [], "viewProviders": [], "hostDirectives": [], @@ -487,22 +422,21 @@ "standalone": true, "imports": [ { - "name": "ButtonModule", - "type": "module" + "name": "Button" } ], "description": "", "rawdescription": "\n", "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n \n success\n info\n warn\n danger\n\n small\n \n \n \n \n\n base\n \n \n \n \n\n large\n \n \n \n \n\n xlarge\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-severity',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonSeverityComponent {}\n\nexport const Severity: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Цветовые схемы для различных контекстов: success, info, warn, danger.'\n }\n }\n }\n};\n", + "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n
\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n
\n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-severity',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonSeverityComponent {}\n\nexport const Severity: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки с разным Severity'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-severity',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonSeverityComponent {}\n `\n }\n }\n }\n};\n", "assetsDirs": [], "styleUrlsData": "", - "stylesData": "", + "stylesData": "\n", "extends": [] }, { "name": "ButtonSizesComponent", - "id": "component-ButtonSizesComponent-661dba1070924aed1cf4ef49813a1f6a6d907cda1dbe15073344241af94004420dbf3f7107d8d4cf54381532ef87576f0bd782219a05c55c872ac9615e66b4f4", + "id": "component-ButtonSizesComponent-cd17928f6a96e0c2d4319065effc31fa54d37723ef053a6ee42aaac52a553f33c495e79ccd49b3caa116ad0a761224fecf5b2f4bec5e1683dd8aa5f78cc53746", "file": "src/stories/components/button/examples/button-sizes.component.ts", "encapsulation": [], "entryComponents": [], @@ -511,8 +445,10 @@ "providers": [], "selector": "app-button-sizes", "styleUrls": [], - "styles": [], - "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", + "styles": [ + "" + ], + "template": "`
\n
\n \n \n \n \n
\n
\n`", "templateUrl": [], "viewProviders": [], "hostDirectives": [], @@ -527,22 +463,21 @@ "standalone": true, "imports": [ { - "name": "ButtonModule", - "type": "module" + "name": "Button" } ], "description": "", "rawdescription": "\n", "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-sizes',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonSizesComponent { }\n\nexport const Sizes: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Все доступные размеры: small, base, large, xlg.'\n }\n }\n }\n};\n", + "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { Button } from 'primeng/button';\n\nconst template = `\n
\n
\n \n \n \n \n
\n
\n`;\n\nconst styles = '';\n\n@Component({\n selector: 'app-button-sizes',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonSizesComponent {}\n\nexport const Sizes: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки разных размеров'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-sizes',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonSizesComponent {}\n `\n }\n }\n }\n};\n", "assetsDirs": [], "styleUrlsData": "", - "stylesData": "", + "stylesData": "\n", "extends": [] }, { "name": "ButtonTextComponent", - "id": "component-ButtonTextComponent-b8472d5ec2f9a7a21c0437842a5b23baa7e24c4a845f0fc5b52a8f2f5775c2686be8685b6806f4825b21f6aaf458393f6fcfd3de779933a6154fdb45c6c2df0d", + "id": "component-ButtonTextComponent-9ec9afa71413a44df8de13324a927aa6ce9c0992a9a509345a5081da321472dde3882151e6e56589f4e751c0c6091d49fb74c41e9cc549be31a6e283b2f0d5c1", "file": "src/stories/components/button/examples/button-text.component.ts", "encapsulation": [], "entryComponents": [], @@ -551,143 +486,14 @@ "providers": [], "selector": "app-button-text", "styleUrls": [], - "styles": [], - "template": "`
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "ButtonModule", - "type": "module" - } + "styles": [ + "" ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { ButtonModule } from 'primeng/button';\n\nconst template = `\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`;\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [ButtonModule],\n template\n})\nexport class ButtonTextComponent {}\n\nexport const Text: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка без заливки и границ, часто используется в тулбарах или списках.'\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "", - "extends": [] - }, - { - "name": "ExtraButtonComponent", - "id": "component-ExtraButtonComponent-7358754f1ac1c9e3e3f8be731885ba5cdacf6a1995653ef9d32fe869f8caa4a60c9e6bb1bb9b7da84303aba0a6f8c83d9f60d8b6d22267cc9d61e13d4cd9ed87", - "file": "src/stories/components/button/examples/button-extra.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "extra-button", - "styleUrls": [], - "styles": [], - "template": "`
\n \n
\n`", + "template": "`
\n \n
\n`", "templateUrl": [], "viewProviders": [], "hostDirectives": [], - "inputsClass": [ - { - "name": "disabled", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 44, - "type": "boolean", - "decorators": [] - }, - { - "name": "icon", - "defaultValue": "''", - "deprecated": false, - "deprecationMessage": "", - "line": 43, - "type": "string", - "decorators": [] - }, - { - "name": "iconOnly", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 42, - "type": "boolean", - "decorators": [] - }, - { - "name": "iconPos", - "defaultValue": "null", - "deprecated": false, - "deprecationMessage": "", - "line": 41, - "type": "ExtraButtonIconPos", - "decorators": [] - }, - { - "name": "label", - "defaultValue": "'Button'", - "deprecated": false, - "deprecationMessage": "", - "line": 36, - "type": "string", - "decorators": [] - }, - { - "name": "loading", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 45, - "type": "boolean", - "decorators": [] - }, - { - "name": "rounded", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 40, - "type": "boolean", - "decorators": [] - }, - { - "name": "severity", - "defaultValue": "null", - "deprecated": false, - "deprecationMessage": "", - "line": 38, - "type": "ExtraButtonSeverity", - "decorators": [] - }, - { - "name": "size", - "defaultValue": "'base'", - "deprecated": false, - "deprecationMessage": "", - "line": 39, - "type": "ExtraButtonSize", - "decorators": [] - }, - { - "name": "variant", - "defaultValue": "'primary'", - "deprecated": false, - "deprecationMessage": "", - "line": 37, - "type": "ExtraButtonVariant", - "decorators": [] - } - ], + "inputsClass": [], "outputsClass": [], "propertiesClass": [], "methodsClass": [], @@ -704,40 +510,11 @@ "description": "", "rawdescription": "\n", "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\ntype ExtraButtonVariant = 'primary' | 'secondary' | 'outlined' | 'text' | 'link';\ntype ExtraButtonSeverity = 'success' | 'warning' | 'danger' | 'info' | null;\ntype ExtraButtonSize = 'small' | 'base' | 'large' | 'xlarge';\ntype ExtraButtonIconPos = 'prefix' | 'postfix' | null;\n\nconst template = `\n
\n \n
\n`;\n\n@Component({\n selector: 'extra-button',\n standalone: true,\n imports: [Button],\n template\n})\nexport class ExtraButtonComponent {\n @Input() label = 'Button';\n @Input() variant: ExtraButtonVariant = 'primary';\n @Input() severity: ExtraButtonSeverity = null;\n @Input() size: ExtraButtonSize = 'base';\n @Input() rounded = false;\n @Input() iconPos: ExtraButtonIconPos = null;\n @Input() iconOnly = false;\n @Input() icon = '';\n @Input() disabled = false;\n @Input() loading = false;\n\n get primeSize(): 'small' | 'large' | undefined {\n if (this.size === 'small') return 'small';\n if (this.size === 'large') return 'large';\n return undefined;\n }\n\n get primeIconPos(): 'left' | 'right' {\n return this.iconPos === 'postfix' ? 'right' : 'left';\n }\n\n get primeSeverity(): string | null {\n if (this.variant === 'secondary') return 'secondary';\n if (this.severity === 'warning') return 'warn';\n return this.severity;\n }\n}\n\nexport const Extra: StoryObj = {\n render: (args) => ({\n props: args,\n template: `\n
`\n }),\n args: {\n label: 'Button',\n variant: 'primary',\n severity: null,\n size: 'base',\n rounded: false,\n iconPos: null,\n iconOnly: false,\n icon: '',\n disabled: false,\n loading: false\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'warning', 'danger', 'info'],\n description: 'Цветовая схема кнопки'\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки (prefix — слева, postfix — справа)'\n },\n iconOnly: {\n control: 'boolean',\n description: 'Режим кнопки только с иконкой'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Интерактивный пример с пропсами, соответствующими Figma-компоненту Button.'\n }\n }\n }\n};\n", + "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n \n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonTextComponent {}\n\nexport const Text: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Text кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonTextComponent {}\n `\n }\n }\n }\n};\n", "assetsDirs": [], "styleUrlsData": "", - "stylesData": "", - "extends": [], - "accessors": { - "primeSize": { - "name": "primeSize", - "getSignature": { - "name": "primeSize", - "type": "unknown", - "returnType": "\"small\" | \"large\" | undefined", - "line": 47 - } - }, - "primeIconPos": { - "name": "primeIconPos", - "getSignature": { - "name": "primeIconPos", - "type": "unknown", - "returnType": "\"left\" | \"right\"", - "line": 53 - } - }, - "primeSeverity": { - "name": "primeSeverity", - "getSignature": { - "name": "primeSeverity", - "type": "unknown", - "returnType": "string | null", - "line": 57 - } - } - } + "stylesData": "\n", + "extends": [] } ], "modules": [], @@ -751,17 +528,37 @@ "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с уведомлением или числовым индикатором (OverlayBadge).'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Badge кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonBadgeComponent {}\n `\n }\n }\n }\n}" }, { - "name": "Default", + "name": "Base", "ctype": "miscellaneous", "subtype": "variable", "file": "src/stories/components/button/examples/button-base.component.ts", "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n\n`\n }),\n args: {\n label: 'Button',\n disabled: false,\n loading: false,\n size: null,\n rounded: false,\n variant: null,\n icon: '',\n iconPos: 'left',\n badge: '',\n severity: null\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n },\n size: {\n control: 'select',\n options: [null, 'small', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n variant: {\n control: 'select',\n options: [null, 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n iconPos: {\n control: 'select',\n options: ['left', 'right', 'top', 'bottom'],\n description: 'Позиция иконки относительно текста'\n },\n badge: {\n control: 'text',\n description: 'Текст для отображения в виде бейджа на кнопке'\n },\n severity: {\n control: 'select',\n options: [null, 'secondary', 'contrast', 'success', 'info', 'warn', 'help', 'danger'],\n description: 'Семантический вариант кнопки'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.'\n }\n }\n }\n}" + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n\n`\n }),\n args: {\n label: 'Base button',\n disabled: false,\n loading: false,\n size: null,\n rounded: false,\n outlined: false,\n text: false,\n icon: '',\n iconPos: null,\n badge: '',\n severity: null\n },\n argTypes: {\n label: {\n description: 'Текст кнопки.'\n },\n disabled: {\n description: 'При наличии указывает, что компонент должен быть отключен.'\n },\n loading: {\n description: 'Находится ли кнопка в состоянии загрузки.'\n },\n // TODO Добавить xlarge после фикса в либе.\n size: {\n description: 'Определяет размер кнопки.',\n control: { type: 'select' },\n options: [null, 'small', 'large'],\n table: {\n type: { summary: `'small' | 'large' | null` } // <-- тип в документации\n }\n },\n rounded: {\n description: 'При наличии делает кнопку с закругленными краями.'\n },\n outlined: {\n description: 'При наличии делает кнопку с контуром без фона.'\n },\n text: {\n description: 'При наличии делает кнопку текстовой без фона и границ.'\n },\n icon: {\n description: 'Имя иконки для отображения в кнопке.'\n },\n iconPos: {\n description: 'Позиция иконки относительно текста.',\n control: { type: 'select' },\n options: [null, 'left', 'right'],\n table: {\n type: { summary: `'left' | 'right' | null` }\n }\n },\n badge: {\n description: 'Текст для отображения в виде бейджа на кнопке.'\n },\n severity: {\n description: 'Определяет цветовую схему кнопки.',\n control: { type: 'select' },\n options: [null, 'success', 'info', 'warn', 'primary', 'help', 'danger'],\n table: {\n type: {\n summary: `'success' | 'info' | 'warn' | 'primary' | 'help' | 'danger' | null`\n }\n }\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Стандартная кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-base',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonBaseComponent {\n @Input() label = '';\n @Input() disabled = false;\n @Input() loading = false;\n @Input() size: 'small' | 'large' | null = null;\n @Input() rounded = false;\n}\n `\n }\n }\n }\n}" + }, + { + "name": "ButtonDefault", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Story", + "defaultValue": "{\n name: 'Button',\n args: {\n label: 'Button',\n },\n parameters: {\n docs: {\n description: {\n story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.',\n },\n source: {\n code: ``,\n },\n },\n },\n}" + }, + { + "name": "Disabled", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Story", + "defaultValue": "{\n render: () => ({\n template: `\n
\n \n success\n info\n warning\n danger\n\n default\n \n \n \n \n\n outlined\n \n \n \n \n\n text\n \n \n \n \n
\n `,\n }),\n parameters: {\n docs: {\n description: { story: 'Состояние кнопки, при котором взаимодействие заблокировано.' },\n source: {\n code: ``,\n },\n },\n },\n}" }, { "name": "Disabled", @@ -771,7 +568,7 @@ "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Состояние кнопки, при котором взаимодействие с ней заблокировано.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Disabled кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-disabled',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonDisabledComponent {}\n `\n }\n }\n }\n}" }, { "name": "Extra", @@ -784,84 +581,144 @@ "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n`\n }),\n args: {\n label: 'Button',\n variant: 'primary',\n severity: null,\n size: 'base',\n rounded: false,\n iconPos: null,\n iconOnly: false,\n icon: '',\n disabled: false,\n loading: false\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'warning', 'danger', 'info'],\n description: 'Цветовая схема кнопки'\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки (prefix — слева, postfix — справа)'\n },\n iconOnly: {\n control: 'boolean',\n description: 'Режим кнопки только с иконкой'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Интерактивный пример с пропсами, соответствующими Figma-компоненту Button.'\n }\n }\n }\n}" }, { - "name": "IconOnly", + "name": "gridTemplate", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon-only.component.ts", + "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'В случаях, когда текст не требуется, можно использовать только иконку.'\n }\n }\n }\n}" + "type": "unknown", + "defaultValue": "(inner: string) => `\n
\n small\n base\n large\n xlarge\n ${inner}\n
\n`" }, { - "name": "Icons", + "name": "Icon", "ctype": "miscellaneous", "subtype": "variable", "file": "src/stories/components/button/examples/button-icon.component.ts", "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки могут содержать иконки слева, справа или быть скруглёнными.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки с иконками'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-icon',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonIconComponent {}\n `\n }\n }\n }\n}" }, { - "name": "Link", + "name": "IconOnly", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-link.component.ts", + "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка, стилизованная под ссылку.'\n }\n }\n }\n}" + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { icon: 'ti ti-check' },\n parameters: {\n docs: {\n description: { story: 'Кнопки без текста, только с иконкой.' },\n source: {\n code: ``,\n },\n },\n },\n}" }, { - "name": "Loading", + "name": "Icons", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-loading.component.ts", + "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с индикатором загрузки. Полезно для асинхронных действий.'\n }\n }\n }\n}" + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button', icon: 'ti ti-check' },\n parameters: {\n docs: {\n description: { story: 'Кнопки с иконками (префикс по умолчанию).' },\n source: {\n code: ``,\n },\n },\n },\n}" }, { - "name": "meta", + "name": "Link", "ctype": "miscellaneous", "subtype": "variable", "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", - "type": "Meta", - "defaultValue": "{\n title: 'PrimeNG/Button',\n decorators: [\n moduleMetadata({\n imports: [\n CommonModule,\n ButtonModule,\n BadgeModule,\n OverlayBadgeModule,\n ExtraButtonComponent,\n ButtonBaseComponent,\n ButtonSizesComponent,\n ButtonRoundedComponent,\n ButtonTextComponent,\n ButtonLinkComponent,\n ButtonIconComponent,\n ButtonIconOnlyComponent,\n ButtonDisabledComponent,\n ButtonLoadingComponent,\n ButtonBadgeComponent,\n ButtonSeverityComponent\n ]\n })\n ],\n parameters: {\n docs: {\n description: {\n component: 'Кнопка — базовый интерактивный элемент. [PrimeNG Button](https://primeng.org/button), [Figma Design](https://www.figma.com/design/HOLKdvQJ8jCLeX17s9d0Yf/UI-Kit--DS--v2.0?node-id=160-5223)'\n }\n }\n }\n}" + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Link Button' },\n parameters: {\n docs: {\n description: { story: 'Кнопка в виде ссылки.' },\n source: {\n code: ``,\n },\n },\n },\n}" }, { - "name": "Outlined", + "name": "Loading", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-outlined.component.ts", + "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с контуром без заливки.'\n }\n }\n }\n}" + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Состояние загрузки с индикатором.' },\n source: {\n code: ``,\n },\n },\n },\n}" }, { - "name": "Rounded", + "name": "Loading", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-rounded.component.ts", + "file": "src/stories/components/button/examples/button-loading.component.ts", "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Полностью скруглённая форма кнопки.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка в состоянии загрузки'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-loading',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonLoadingComponent {}\n `\n }\n }\n }\n}" }, { - "name": "Severity", + "name": "meta", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Meta", + "defaultValue": "{\n title: 'Prime/Button',\n component: ExtraButtonComponent,\n tags: ['autodocs'],\n decorators: [\n moduleMetadata({\n imports: [ExtraButtonComponent]\n })\n ],\n parameters: {\n docs: {\n description: {\n component:\n 'Кнопка — базовый интерактивный элемент. [Figma Design](https://www.figma.com/design/HOLKdvQJ8jCLeX17s9d0Yf/UI-Kit--DS--v2.0?node-id=160-5223)',\n },\n },\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'Button' },\n type: { summary: 'string' },\n },\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'primary' },\n type: { summary: \"'primary' | 'secondary' | 'outlined' | 'text' | 'link'\" },\n },\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'info', 'warning', 'danger'],\n description: 'Семантический вариант кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'null' },\n type: { summary: \"'success' | 'info' | 'warning' | 'danger' | null\" },\n },\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'base' },\n type: { summary: \"'small' | 'base' | 'large' | 'xlarge'\" },\n },\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)',\n table: {\n category: 'Props',\n defaultValue: { summary: '' },\n type: { summary: 'string' },\n },\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки относительно текста',\n table: {\n category: 'Props',\n defaultValue: { summary: 'null' },\n type: { summary: \"'prefix' | 'postfix' | null\" },\n },\n },\n iconOnly: {\n control: 'boolean',\n description: 'Только иконка, без текста',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n },\n}" + }, + { + "name": "Outlined", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-outlined.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Outlined кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-outlined',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonOutlinedComponent {}\n `\n }\n }\n }\n}" + }, + { + "name": "Rounded", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Скруглённая форма кнопок.' },\n source: {\n code: ``,\n },\n },\n },\n}" + }, + { + "name": "Rounded", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-rounded.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Скругленная кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-rounded',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonRoundedComponent {}\n `\n }\n }\n }\n}" + }, + { + "name": "Severity", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Story", + "defaultValue": "{\n render: () => ({\n template: `\n
\n \n success\n info\n warning\n danger\n\n small\n \n \n \n \n\n base\n \n \n \n \n\n large\n \n \n \n \n\n xlarge\n \n \n \n \n
\n `,\n }),\n parameters: {\n docs: {\n description: { story: 'Цветовые схемы для различных контекстов: success, info, warning, danger.' },\n source: {\n code: ``,\n },\n },\n },\n}" + }, + { + "name": "Severity", "ctype": "miscellaneous", "subtype": "variable", "file": "src/stories/components/button/examples/button-severity.component.ts", "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Цветовые схемы для различных контекстов: success, info, warn, danger.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки с разным Severity'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-severity',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonSeverityComponent {}\n `\n }\n }\n }\n}" + }, + { + "name": "Sizes", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Все доступные размеры: small, base, large, xlarge.' },\n source: {\n code: `\n\n\n\n`,\n },\n },\n },\n}" }, { "name": "Sizes", @@ -871,77 +728,147 @@ "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Все доступные размеры: small, base, large, xlg.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки разных размеров'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-sizes',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonSizesComponent {}\n `\n }\n }\n }\n}" }, { - "name": "template", + "name": "styles", "ctype": "miscellaneous", "subtype": "variable", "file": "src/stories/components/button/examples/button-badge.component.ts", "deprecated": false, "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n
\n
\n`" + "type": "string", + "defaultValue": "''" }, { - "name": "template", + "name": "styles", "ctype": "miscellaneous", "subtype": "variable", "file": "src/stories/components/button/examples/button-base.component.ts", "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n \n \n
\n`" + "defaultValue": "``" }, { - "name": "template", + "name": "styles", "ctype": "miscellaneous", "subtype": "variable", "file": "src/stories/components/button/examples/button-disabled.component.ts", "deprecated": false, "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n success\n info\n warn\n danger\n\n default\n \n \n \n \n\n outlined\n \n \n \n \n\n text\n \n \n \n \n
\n
\n`" + "type": "string", + "defaultValue": "''" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-icon.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-loading.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-outlined.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-rounded.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-severity.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-sizes.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-text.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" }, { "name": "template", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-extra.component.ts", + "file": "src/stories/components/button/examples/button-badge.component.ts", "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n \n
\n`" + "defaultValue": "`\n
\n
\n \n\n \n\n \n\n \n
\n
\n`" }, { "name": "template", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon-only.component.ts", + "file": "src/stories/components/button/examples/button-base.component.ts", "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n \n \n
\n`" }, { "name": "template", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon.component.ts", + "file": "src/stories/components/button/examples/button-disabled.component.ts", "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n \n icon prefix\n icon postfix\n rounded\n\n xlarge\n \n \n \n\n large\n \n \n \n\n base\n \n \n \n\n small\n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n
\n \n
\n
\n`" }, { "name": "template", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-link.component.ts", + "file": "src/stories/components/button/examples/button-icon.component.ts", "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n
\n \n \n \n
\n
\n`" }, { "name": "template", @@ -951,7 +878,7 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n
\n \n
\n
\n`" }, { "name": "template", @@ -961,7 +888,7 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n \n \n
`" }, { "name": "template", @@ -971,7 +898,7 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n
\n \n
\n
\n`" }, { "name": "template", @@ -981,7 +908,7 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n \n success\n info\n warn\n danger\n\n small\n \n \n \n \n\n base\n \n \n \n \n\n large\n \n \n \n \n\n xlarge\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n
\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n
\n
\n`" }, { "name": "template", @@ -991,7 +918,7 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n
\n \n \n \n \n
\n
\n`" }, { "name": "template", @@ -1001,7 +928,17 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n \n
\n`" + }, + { + "name": "Text", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Текстовый вариант кнопки (без заливки и границ).' },\n source: {\n code: ``,\n },\n },\n },\n}" }, { "name": "Text", @@ -1011,54 +948,21 @@ "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка без заливки и границ, часто используется в тулбарах или списках.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Text кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonTextComponent {}\n `\n }\n }\n }\n}" } ], "functions": [], "typealiases": [ { - "name": "ExtraButtonIconPos", + "name": "Story", "ctype": "miscellaneous", "subtype": "typealias", - "rawtype": "\"prefix\" | \"postfix\" | null", - "file": "src/stories/components/button/examples/button-extra.component.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 193 - }, - { - "name": "ExtraButtonSeverity", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"success\" | \"warning\" | \"danger\" | \"info\" | null", - "file": "src/stories/components/button/examples/button-extra.component.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 193 - }, - { - "name": "ExtraButtonSize", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"small\" | \"base\" | \"large\" | \"xlarge\"", - "file": "src/stories/components/button/examples/button-extra.component.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 193 - }, - { - "name": "ExtraButtonVariant", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"primary\" | \"secondary\" | \"outlined\" | \"text\" | \"link\"", - "file": "src/stories/components/button/examples/button-extra.component.ts", + "rawtype": "StoryObj", + "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", "description": "", - "kind": 193 + "kind": 184 } ], "enumerations": [], @@ -1072,7 +976,17 @@ "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с уведомлением или числовым индикатором (OverlayBadge).'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Badge кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonBadgeComponent {}\n `\n }\n }\n }\n}" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-badge.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" }, { "name": "template", @@ -1082,19 +996,29 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n\n \n \n \n\n \n \n \n\n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n
\n \n\n \n\n \n\n \n
\n
\n`" } ], "src/stories/components/button/examples/button-base.component.ts": [ { - "name": "Default", + "name": "Base", "ctype": "miscellaneous", "subtype": "variable", "file": "src/stories/components/button/examples/button-base.component.ts", "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n\n`\n }),\n args: {\n label: 'Button',\n disabled: false,\n loading: false,\n size: null,\n rounded: false,\n variant: null,\n icon: '',\n iconPos: 'left',\n badge: '',\n severity: null\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n },\n size: {\n control: 'select',\n options: [null, 'small', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n variant: {\n control: 'select',\n options: [null, 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n iconPos: {\n control: 'select',\n options: ['left', 'right', 'top', 'bottom'],\n description: 'Позиция иконки относительно текста'\n },\n badge: {\n control: 'text',\n description: 'Текст для отображения в виде бейджа на кнопке'\n },\n severity: {\n control: 'select',\n options: [null, 'secondary', 'contrast', 'success', 'info', 'warn', 'help', 'danger'],\n description: 'Семантический вариант кнопки'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.'\n }\n }\n }\n}" + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n\n`\n }),\n args: {\n label: 'Base button',\n disabled: false,\n loading: false,\n size: null,\n rounded: false,\n outlined: false,\n text: false,\n icon: '',\n iconPos: null,\n badge: '',\n severity: null\n },\n argTypes: {\n label: {\n description: 'Текст кнопки.'\n },\n disabled: {\n description: 'При наличии указывает, что компонент должен быть отключен.'\n },\n loading: {\n description: 'Находится ли кнопка в состоянии загрузки.'\n },\n // TODO Добавить xlarge после фикса в либе.\n size: {\n description: 'Определяет размер кнопки.',\n control: { type: 'select' },\n options: [null, 'small', 'large'],\n table: {\n type: { summary: `'small' | 'large' | null` } // <-- тип в документации\n }\n },\n rounded: {\n description: 'При наличии делает кнопку с закругленными краями.'\n },\n outlined: {\n description: 'При наличии делает кнопку с контуром без фона.'\n },\n text: {\n description: 'При наличии делает кнопку текстовой без фона и границ.'\n },\n icon: {\n description: 'Имя иконки для отображения в кнопке.'\n },\n iconPos: {\n description: 'Позиция иконки относительно текста.',\n control: { type: 'select' },\n options: [null, 'left', 'right'],\n table: {\n type: { summary: `'left' | 'right' | null` }\n }\n },\n badge: {\n description: 'Текст для отображения в виде бейджа на кнопке.'\n },\n severity: {\n description: 'Определяет цветовую схему кнопки.',\n control: { type: 'select' },\n options: [null, 'success', 'info', 'warn', 'primary', 'help', 'danger'],\n table: {\n type: {\n summary: `'success' | 'info' | 'warn' | 'primary' | 'help' | 'danger' | null`\n }\n }\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Стандартная кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-base',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonBaseComponent {\n @Input() label = '';\n @Input() disabled = false;\n @Input() loading = false;\n @Input() size: 'small' | 'large' | null = null;\n @Input() rounded = false;\n}\n `\n }\n }\n }\n}" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-base.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "defaultValue": "``" }, { "name": "template", @@ -1104,117 +1028,205 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n \n \n
\n`" + "defaultValue": "`\n
\n \n \n
\n`" } ], - "src/stories/components/button/examples/button-disabled.component.ts": [ + "src/stories/components/button/button.stories.ts": [ + { + "name": "ButtonDefault", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Story", + "defaultValue": "{\n name: 'Button',\n args: {\n label: 'Button',\n },\n parameters: {\n docs: {\n description: {\n story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.',\n },\n source: {\n code: ``,\n },\n },\n },\n}" + }, { "name": "Disabled", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-disabled.component.ts", + "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Состояние кнопки, при котором взаимодействие с ней заблокировано.'\n }\n }\n }\n}" + "type": "Story", + "defaultValue": "{\n render: () => ({\n template: `\n
\n \n success\n info\n warning\n danger\n\n default\n \n \n \n \n\n outlined\n \n \n \n \n\n text\n \n \n \n \n
\n `,\n }),\n parameters: {\n docs: {\n description: { story: 'Состояние кнопки, при котором взаимодействие заблокировано.' },\n source: {\n code: ``,\n },\n },\n },\n}" }, { - "name": "template", + "name": "gridTemplate", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-disabled.component.ts", + "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n \n success\n info\n warn\n danger\n\n default\n \n \n \n \n\n outlined\n \n \n \n \n\n text\n \n \n \n \n
\n
\n`" - } - ], - "src/stories/components/button/examples/button-extra.component.ts": [ + "defaultValue": "(inner: string) => `\n
\n small\n base\n large\n xlarge\n ${inner}\n
\n`" + }, { - "name": "Extra", + "name": "IconOnly", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-extra.component.ts", + "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n
`\n }),\n args: {\n label: 'Button',\n variant: 'primary',\n severity: null,\n size: 'base',\n rounded: false,\n iconPos: null,\n iconOnly: false,\n icon: '',\n disabled: false,\n loading: false\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'warning', 'danger', 'info'],\n description: 'Цветовая схема кнопки'\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки (prefix — слева, postfix — справа)'\n },\n iconOnly: {\n control: 'boolean',\n description: 'Режим кнопки только с иконкой'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Интерактивный пример с пропсами, соответствующими Figma-компоненту Button.'\n }\n }\n }\n}" + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { icon: 'ti ti-check' },\n parameters: {\n docs: {\n description: { story: 'Кнопки без текста, только с иконкой.' },\n source: {\n code: ``,\n },\n },\n },\n}" }, { - "name": "template", + "name": "Icons", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-extra.component.ts", + "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n \n
\n`" - } - ], - "src/stories/components/button/examples/button-icon-only.component.ts": [ + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button', icon: 'ti ti-check' },\n parameters: {\n docs: {\n description: { story: 'Кнопки с иконками (префикс по умолчанию).' },\n source: {\n code: ``,\n },\n },\n },\n}" + }, { - "name": "IconOnly", + "name": "Link", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon-only.component.ts", + "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'В случаях, когда текст не требуется, можно использовать только иконку.'\n }\n }\n }\n}" + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Link Button' },\n parameters: {\n docs: {\n description: { story: 'Кнопка в виде ссылки.' },\n source: {\n code: ``,\n },\n },\n },\n}" }, { - "name": "template", + "name": "Loading", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon-only.component.ts", + "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Состояние загрузки с индикатором.' },\n source: {\n code: ``,\n },\n },\n },\n}" + }, + { + "name": "meta", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Meta", + "defaultValue": "{\n title: 'Prime/Button',\n component: ExtraButtonComponent,\n tags: ['autodocs'],\n decorators: [\n moduleMetadata({\n imports: [ExtraButtonComponent]\n })\n ],\n parameters: {\n docs: {\n description: {\n component:\n 'Кнопка — базовый интерактивный элемент. [Figma Design](https://www.figma.com/design/HOLKdvQJ8jCLeX17s9d0Yf/UI-Kit--DS--v2.0?node-id=160-5223)',\n },\n },\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'Button' },\n type: { summary: 'string' },\n },\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'primary' },\n type: { summary: \"'primary' | 'secondary' | 'outlined' | 'text' | 'link'\" },\n },\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'info', 'warning', 'danger'],\n description: 'Семантический вариант кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'null' },\n type: { summary: \"'success' | 'info' | 'warning' | 'danger' | null\" },\n },\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'base' },\n type: { summary: \"'small' | 'base' | 'large' | 'xlarge'\" },\n },\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)',\n table: {\n category: 'Props',\n defaultValue: { summary: '' },\n type: { summary: 'string' },\n },\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки относительно текста',\n table: {\n category: 'Props',\n defaultValue: { summary: 'null' },\n type: { summary: \"'prefix' | 'postfix' | null\" },\n },\n },\n iconOnly: {\n control: 'boolean',\n description: 'Только иконка, без текста',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n },\n}" + }, + { + "name": "Rounded", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Скруглённая форма кнопок.' },\n source: {\n code: ``,\n },\n },\n },\n}" + }, + { + "name": "Severity", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Story", + "defaultValue": "{\n render: () => ({\n template: `\n
\n \n success\n info\n warning\n danger\n\n small\n \n \n \n \n\n base\n \n \n \n \n\n large\n \n \n \n \n\n xlarge\n \n \n \n \n
\n `,\n }),\n parameters: {\n docs: {\n description: { story: 'Цветовые схемы для различных контекстов: success, info, warning, danger.' },\n source: {\n code: ``,\n },\n },\n },\n}" + }, + { + "name": "Sizes", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Все доступные размеры: small, base, large, xlarge.' },\n source: {\n code: `\n\n\n\n`,\n },\n },\n },\n}" + }, + { + "name": "Text", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/button.stories.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "Story", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Текстовый вариант кнопки (без заливки и границ).' },\n source: {\n code: ``,\n },\n },\n },\n}" } ], - "src/stories/components/button/examples/button-icon.component.ts": [ + "src/stories/components/button/examples/button-disabled.component.ts": [ { - "name": "Icons", + "name": "Disabled", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon.component.ts", + "file": "src/stories/components/button/examples/button-disabled.component.ts", "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки могут содержать иконки слева, справа или быть скруглёнными.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Disabled кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-disabled',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonDisabledComponent {}\n `\n }\n }\n }\n}" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-disabled.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" }, { "name": "template", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon.component.ts", + "file": "src/stories/components/button/examples/button-disabled.component.ts", "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n \n icon prefix\n icon postfix\n rounded\n\n xlarge\n \n \n \n\n large\n \n \n \n\n base\n \n \n \n\n small\n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n
\n \n
\n
\n`" } ], - "src/stories/components/button/examples/button-link.component.ts": [ + "src/stories/components/button/examples/button-extra.component.ts": [ { - "name": "Link", + "name": "Extra", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-extra.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n
`\n }),\n args: {\n label: 'Button',\n variant: 'primary',\n severity: null,\n size: 'base',\n rounded: false,\n iconPos: null,\n iconOnly: false,\n icon: '',\n disabled: false,\n loading: false\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'warning', 'danger', 'info'],\n description: 'Цветовая схема кнопки'\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки (prefix — слева, postfix — справа)'\n },\n iconOnly: {\n control: 'boolean',\n description: 'Режим кнопки только с иконкой'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Интерактивный пример с пропсами, соответствующими Figma-компоненту Button.'\n }\n }\n }\n}" + } + ], + "src/stories/components/button/examples/button-icon.component.ts": [ + { + "name": "Icon", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-link.component.ts", + "file": "src/stories/components/button/examples/button-icon.component.ts", "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка, стилизованная под ссылку.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки с иконками'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-icon',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonIconComponent {}\n `\n }\n }\n }\n}" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-icon.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" }, { "name": "template", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/examples/button-link.component.ts", + "file": "src/stories/components/button/examples/button-icon.component.ts", "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n
\n \n \n \n
\n
\n`" } ], "src/stories/components/button/examples/button-loading.component.ts": [ @@ -1226,29 +1238,27 @@ "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с индикатором загрузки. Полезно для асинхронных действий.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка в состоянии загрузки'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-loading',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonLoadingComponent {}\n `\n }\n }\n }\n}" }, { - "name": "template", + "name": "styles", "ctype": "miscellaneous", "subtype": "variable", "file": "src/stories/components/button/examples/button-loading.component.ts", "deprecated": false, "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" - } - ], - "src/stories/components/button/button.stories.ts": [ + "type": "string", + "defaultValue": "''" + }, { - "name": "meta", + "name": "template", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", + "file": "src/stories/components/button/examples/button-loading.component.ts", "deprecated": false, "deprecationMessage": "", - "type": "Meta", - "defaultValue": "{\n title: 'PrimeNG/Button',\n decorators: [\n moduleMetadata({\n imports: [\n CommonModule,\n ButtonModule,\n BadgeModule,\n OverlayBadgeModule,\n ExtraButtonComponent,\n ButtonBaseComponent,\n ButtonSizesComponent,\n ButtonRoundedComponent,\n ButtonTextComponent,\n ButtonLinkComponent,\n ButtonIconComponent,\n ButtonIconOnlyComponent,\n ButtonDisabledComponent,\n ButtonLoadingComponent,\n ButtonBadgeComponent,\n ButtonSeverityComponent\n ]\n })\n ],\n parameters: {\n docs: {\n description: {\n component: 'Кнопка — базовый интерактивный элемент. [PrimeNG Button](https://primeng.org/button), [Figma Design](https://www.figma.com/design/HOLKdvQJ8jCLeX17s9d0Yf/UI-Kit--DS--v2.0?node-id=160-5223)'\n }\n }\n }\n}" + "type": "unknown", + "defaultValue": "`\n
\n
\n \n
\n
\n`" } ], "src/stories/components/button/examples/button-outlined.component.ts": [ @@ -1260,7 +1270,17 @@ "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка с контуром без заливки.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Outlined кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-outlined',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonOutlinedComponent {}\n `\n }\n }\n }\n}" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-outlined.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" }, { "name": "template", @@ -1270,7 +1290,7 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n \n \n
`" } ], "src/stories/components/button/examples/button-rounded.component.ts": [ @@ -1282,7 +1302,17 @@ "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Полностью скруглённая форма кнопки.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Скругленная кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-rounded',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonRoundedComponent {}\n `\n }\n }\n }\n}" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-rounded.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" }, { "name": "template", @@ -1292,19 +1322,29 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n
\n \n
\n
\n`" } ], "src/stories/components/button/examples/button-severity.component.ts": [ { - "name": "Severity", + "name": "Severity", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-severity.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "StoryObj", + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки с разным Severity'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-severity',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonSeverityComponent {}\n `\n }\n }\n }\n}" + }, + { + "name": "styles", "ctype": "miscellaneous", "subtype": "variable", "file": "src/stories/components/button/examples/button-severity.component.ts", "deprecated": false, "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Цветовые схемы для различных контекстов: success, info, warn, danger.'\n }\n }\n }\n}" + "type": "string", + "defaultValue": "''" }, { "name": "template", @@ -1314,7 +1354,7 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n \n success\n info\n warn\n danger\n\n small\n \n \n \n \n\n base\n \n \n \n \n\n large\n \n \n \n \n\n xlarge\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n
\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n
\n
\n`" } ], "src/stories/components/button/examples/button-sizes.component.ts": [ @@ -1326,7 +1366,17 @@ "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Все доступные размеры: small, base, large, xlg.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки разных размеров'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-sizes',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonSizesComponent {}\n `\n }\n }\n }\n}" + }, + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-sizes.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" }, { "name": "template", @@ -1336,10 +1386,20 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n
\n \n \n \n \n
\n
\n`" } ], "src/stories/components/button/examples/button-text.component.ts": [ + { + "name": "styles", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/stories/components/button/examples/button-text.component.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "defaultValue": "''" + }, { "name": "template", "ctype": "miscellaneous", @@ -1348,7 +1408,7 @@ "deprecated": false, "deprecationMessage": "", "type": "unknown", - "defaultValue": "`\n
\n
\n size=\"small\"\n size=\"base\"\n size=\"large\"\n class=\"p-button-xlg\"\n\n \n \n \n \n
\n
\n`" + "defaultValue": "`\n
\n \n
\n`" }, { "name": "Text", @@ -1358,57 +1418,24 @@ "deprecated": false, "deprecationMessage": "", "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка без заливки и границ, часто используется в тулбарах или списках.'\n }\n }\n }\n}" + "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Text кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonTextComponent {}\n `\n }\n }\n }\n}" } ] }, "groupedFunctions": {}, "groupedEnumerations": {}, "groupedTypeAliases": { - "src/stories/components/button/examples/button-extra.component.ts": [ - { - "name": "ExtraButtonIconPos", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"prefix\" | \"postfix\" | null", - "file": "src/stories/components/button/examples/button-extra.component.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 193 - }, - { - "name": "ExtraButtonSeverity", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"success\" | \"warning\" | \"danger\" | \"info\" | null", - "file": "src/stories/components/button/examples/button-extra.component.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 193 - }, - { - "name": "ExtraButtonSize", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "\"small\" | \"base\" | \"large\" | \"xlarge\"", - "file": "src/stories/components/button/examples/button-extra.component.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 193 - }, + "src/stories/components/button/button.stories.ts": [ { - "name": "ExtraButtonVariant", + "name": "Story", "ctype": "miscellaneous", "subtype": "typealias", - "rawtype": "\"primary\" | \"secondary\" | \"outlined\" | \"text\" | \"link\"", - "file": "src/stories/components/button/examples/button-extra.component.ts", + "rawtype": "StoryObj", + "file": "src/stories/components/button/button.stories.ts", "deprecated": false, "deprecationMessage": "", "description": "", - "kind": 193 + "kind": 184 } ] } @@ -1427,188 +1454,201 @@ "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", - "name": "meta", + "name": "ButtonDefault", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-badge.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonBadgeComponent", + "filePath": "src/stories/components/button/button.stories.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Disabled", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-badge.component.ts", + "filePath": "src/stories/components/button/button.stories.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", - "name": "Badge", + "name": "gridTemplate", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-badge.component.ts", + "filePath": "src/stories/components/button/button.stories.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", - "name": "template", + "name": "IconOnly", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-base.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonBaseComponent", - "coveragePercent": 0, - "coverageCount": "0/11", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-base.component.ts", + "filePath": "src/stories/components/button/button.stories.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", - "name": "Default", + "name": "Icons", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-base.component.ts", + "filePath": "src/stories/components/button/button.stories.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", - "name": "template", + "name": "Link", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-disabled.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonDisabledComponent", + "filePath": "src/stories/components/button/button.stories.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Loading", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-disabled.component.ts", + "filePath": "src/stories/components/button/button.stories.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", - "name": "Disabled", + "name": "meta", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-disabled.component.ts", + "filePath": "src/stories/components/button/button.stories.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", - "name": "template", + "name": "Rounded", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-extra.component.ts", - "type": "component", - "linktype": "component", - "name": "ExtraButtonComponent", + "filePath": "src/stories/components/button/button.stories.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Severity", "coveragePercent": 0, - "coverageCount": "0/11", + "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-extra.component.ts", + "filePath": "src/stories/components/button/button.stories.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", - "name": "Extra", + "name": "Sizes", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-extra.component.ts", + "filePath": "src/stories/components/button/button.stories.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", - "name": "template", + "name": "Text", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-extra.component.ts", + "filePath": "src/stories/components/button/button.stories.ts", "type": "type alias", "linktype": "miscellaneous", "linksubtype": "typealias", - "name": "ExtraButtonIconPos", + "name": "Story", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-extra.component.ts", - "type": "type alias", + "filePath": "src/stories/components/button/examples/button-badge.component.ts", + "type": "component", + "linktype": "component", + "name": "ButtonBadgeComponent", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-badge.component.ts", + "type": "variable", "linktype": "miscellaneous", - "linksubtype": "typealias", - "name": "ExtraButtonSeverity", + "linksubtype": "variable", + "name": "Badge", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-extra.component.ts", - "type": "type alias", + "filePath": "src/stories/components/button/examples/button-badge.component.ts", + "type": "variable", "linktype": "miscellaneous", - "linksubtype": "typealias", - "name": "ExtraButtonSize", + "linksubtype": "variable", + "name": "styles", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-extra.component.ts", - "type": "type alias", + "filePath": "src/stories/components/button/examples/button-badge.component.ts", + "type": "variable", "linktype": "miscellaneous", - "linksubtype": "typealias", - "name": "ExtraButtonVariant", + "linksubtype": "variable", + "name": "template", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-icon-only.component.ts", + "filePath": "src/stories/components/button/examples/button-base.component.ts", "type": "component", "linktype": "component", - "name": "ButtonIconOnlyComponent", + "name": "ButtonBaseComponent", + "coveragePercent": 0, + "coverageCount": "0/12", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-base.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Base", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-icon-only.component.ts", + "filePath": "src/stories/components/button/examples/button-base.component.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", - "name": "IconOnly", + "name": "styles", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-icon-only.component.ts", + "filePath": "src/stories/components/button/examples/button-base.component.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", @@ -1618,26 +1658,36 @@ "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-icon.component.ts", + "filePath": "src/stories/components/button/examples/button-disabled.component.ts", "type": "component", "linktype": "component", - "name": "ButtonIconComponent", + "name": "ButtonDisabledComponent", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-icon.component.ts", + "filePath": "src/stories/components/button/examples/button-disabled.component.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", - "name": "Icons", + "name": "Disabled", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-icon.component.ts", + "filePath": "src/stories/components/button/examples/button-disabled.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "styles", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-disabled.component.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", @@ -1647,26 +1697,46 @@ "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-link.component.ts", + "filePath": "src/stories/components/button/examples/button-extra.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "Extra", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-icon.component.ts", "type": "component", "linktype": "component", - "name": "ButtonLinkComponent", + "name": "ButtonIconComponent", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-link.component.ts", + "filePath": "src/stories/components/button/examples/button-icon.component.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", - "name": "Link", + "name": "Icon", "coveragePercent": 0, "coverageCount": "0/1", "status": "low" }, { - "filePath": "src/stories/components/button/examples/button-link.component.ts", + "filePath": "src/stories/components/button/examples/button-icon.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "styles", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, + { + "filePath": "src/stories/components/button/examples/button-icon.component.ts", "type": "variable", "linktype": "miscellaneous", "linksubtype": "variable", @@ -1694,6 +1764,16 @@ "coverageCount": "0/1", "status": "low" }, + { + "filePath": "src/stories/components/button/examples/button-loading.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "styles", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, { "filePath": "src/stories/components/button/examples/button-loading.component.ts", "type": "variable", @@ -1723,6 +1803,16 @@ "coverageCount": "0/1", "status": "low" }, + { + "filePath": "src/stories/components/button/examples/button-outlined.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "styles", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, { "filePath": "src/stories/components/button/examples/button-outlined.component.ts", "type": "variable", @@ -1752,6 +1842,16 @@ "coverageCount": "0/1", "status": "low" }, + { + "filePath": "src/stories/components/button/examples/button-rounded.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "styles", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, { "filePath": "src/stories/components/button/examples/button-rounded.component.ts", "type": "variable", @@ -1781,6 +1881,16 @@ "coverageCount": "0/1", "status": "low" }, + { + "filePath": "src/stories/components/button/examples/button-severity.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "styles", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, { "filePath": "src/stories/components/button/examples/button-severity.component.ts", "type": "variable", @@ -1810,6 +1920,16 @@ "coverageCount": "0/1", "status": "low" }, + { + "filePath": "src/stories/components/button/examples/button-sizes.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "styles", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, { "filePath": "src/stories/components/button/examples/button-sizes.component.ts", "type": "variable", @@ -1829,6 +1949,16 @@ "coverageCount": "0/1", "status": "low" }, + { + "filePath": "src/stories/components/button/examples/button-text.component.ts", + "type": "variable", + "linktype": "miscellaneous", + "linksubtype": "variable", + "name": "styles", + "coveragePercent": 0, + "coverageCount": "0/1", + "status": "low" + }, { "filePath": "src/stories/components/button/examples/button-text.component.ts", "type": "variable", diff --git a/src/components/button/button-extra.component.ts b/src/components/button/button-extra.component.ts index 483ba4fd..28ca386b 100644 --- a/src/components/button/button-extra.component.ts +++ b/src/components/button/button-extra.component.ts @@ -1,5 +1,6 @@ import { Component, Input } from '@angular/core'; import { Button } from 'primeng/button'; +import { Badge } from 'primeng/badge'; export type ExtraButtonVariant = 'primary' | 'secondary' | 'outlined' | 'text' | 'link'; export type ExtraButtonSeverity = 'success' | 'warning' | 'danger' | 'info' | null; @@ -9,7 +10,7 @@ export type ExtraButtonIconPos = 'prefix' | 'postfix' | null; @Component({ selector: 'extra-button', standalone: true, - imports: [Button], + imports: [Button, Badge], styleUrl: './button.component.scss', template: ` ` }) @@ -39,6 +42,9 @@ export class ExtraButtonComponent { @Input() icon = ''; @Input() disabled = false; @Input() loading = false; + @Input() badge = ''; + @Input() badgeSeverity: 'success' | 'info' | 'warning' | 'danger' | 'secondary' | 'contrast' | null = null; + @Input() showBadge = false; get primeSize(): 'small' | 'large' | undefined { if (this.size === 'small') return 'small'; diff --git a/src/components/button/button.component.scss b/src/components/button/button.component.scss index e69de29b..0716a2ca 100644 --- a/src/components/button/button.component.scss +++ b/src/components/button/button.component.scss @@ -0,0 +1,15 @@ +:host ::ng-deep { + .p-button { + position: relative; + overflow: visible; + + .p-badge { + position: absolute; + inset-block-start: 0; + inset-inline-end: 0; + transform: translate(50%, -50%); + transform-origin: 100% 0; + margin: 0; + } + } +} diff --git a/src/stories/components/button/button.stories.ts b/src/stories/components/button/button.stories.ts index 7df3d34a..b049f38a 100644 --- a/src/stories/components/button/button.stories.ts +++ b/src/stories/components/button/button.stories.ts @@ -1,15 +1,6 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { ExtraButtonComponent } from '../../../components/button/button-extra.component'; -const gridTemplate = (inner: string) => ` -
- small - base - large - xlarge - ${inner} -
-`; const meta: Meta = { title: 'Prime/Button', @@ -123,16 +114,71 @@ const meta: Meta = { type: { summary: 'boolean' }, }, }, + badge: { + control: 'text', + description: 'Значение бейджа', + table: { + category: 'Props', + defaultValue: { summary: '' }, + type: { summary: 'string' }, + }, + }, + badgeSeverity: { + control: 'select', + options: [null, 'success', 'info', 'warning', 'danger', 'secondary', 'contrast'], + description: 'Цветовая схема бейджа', + table: { + category: 'Props', + defaultValue: { summary: 'null' }, + type: { summary: "'success' | 'info' | 'warning' | 'danger' | 'secondary' | 'contrast' | null" }, + }, + }, + showBadge: { + control: 'boolean', + description: 'Показывать ли бейдж', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + }, + args: { + showBadge: false, + badge: '', + badgeSeverity: null, }, }; +const commonTemplate = ` + +`; + export default meta; type Story = StoryObj; // ── Default ────────────────────────────────────────────────────────────────── -export const ButtonDefault: Story = { - name: 'Button', +export const Default: Story = { + name: 'Default', + render: (args) => ({ + props: args, + template: commonTemplate, + }), args: { label: 'Button', }, @@ -153,14 +199,9 @@ export const ButtonDefault: Story = { export const Sizes: Story = { render: (args) => ({ props: args, - template: gridTemplate(` - - - - - `), + template: commonTemplate, }), - args: { label: 'Button' }, + args: { label: 'Button', size: 'large' }, parameters: { docs: { description: { story: 'Все доступные размеры: small, base, large, xlarge.' }, @@ -178,12 +219,7 @@ export const Sizes: Story = { export const Icons: Story = { render: (args) => ({ props: args, - template: gridTemplate(` - - - - - `), + template: commonTemplate, }), args: { label: 'Button', icon: 'ti ti-check' }, parameters: { @@ -199,14 +235,9 @@ export const Icons: Story = { export const IconOnly: Story = { render: (args) => ({ props: args, - template: gridTemplate(` - - - - - `), + template: commonTemplate, }), - args: { icon: 'ti ti-check' }, + args: { icon: 'ti ti-check', iconOnly: true }, parameters: { docs: { description: { story: 'Кнопки без текста, только с иконкой.' }, @@ -220,14 +251,9 @@ export const IconOnly: Story = { export const Loading: Story = { render: (args) => ({ props: args, - template: gridTemplate(` - - - - - `), + template: commonTemplate, }), - args: { label: 'Button' }, + args: { label: 'Button', loading: true }, parameters: { docs: { description: { story: 'Состояние загрузки с индикатором.' }, @@ -241,14 +267,9 @@ export const Loading: Story = { export const Rounded: Story = { render: (args) => ({ props: args, - template: gridTemplate(` - - - - - `), + template: commonTemplate, }), - args: { label: 'Button' }, + args: { label: 'Button', rounded: true }, parameters: { docs: { description: { story: 'Скруглённая форма кнопок.' }, @@ -262,14 +283,9 @@ export const Rounded: Story = { export const Text: Story = { render: (args) => ({ props: args, - template: gridTemplate(` - - - - - `), + template: commonTemplate, }), - args: { label: 'Button' }, + args: { label: 'Button', variant: 'text' }, parameters: { docs: { description: { story: 'Текстовый вариант кнопки (без заливки и границ).' }, @@ -283,14 +299,9 @@ export const Text: Story = { export const Link: Story = { render: (args) => ({ props: args, - template: gridTemplate(` - - - - - `), + template: commonTemplate, }), - args: { label: 'Link Button' }, + args: { label: 'Link Button', variant: 'link' }, parameters: { docs: { description: { story: 'Кнопка в виде ссылки.' }, @@ -302,41 +313,11 @@ export const Link: Story = { }; export const Severity: Story = { - render: () => ({ - template: ` -
- - success - info - warning - danger - - small - - - - - - base - - - - - - large - - - - - - xlarge - - - - -
- `, + render: (args) => ({ + props: args, + template: commonTemplate, }), + args: { label: 'Button', severity: 'success' }, parameters: { docs: { description: { story: 'Цветовые схемы для различных контекстов: success, info, warning, danger.' }, @@ -348,35 +329,11 @@ export const Severity: Story = { }; export const Disabled: Story = { - render: () => ({ - template: ` -
- - success - info - warning - danger - - default - - - - - - outlined - - - - - - text - - - - -
- `, + render: (args) => ({ + props: args, + template: commonTemplate, }), + args: { label: 'Button', disabled: true }, parameters: { docs: { description: { story: 'Состояние кнопки, при котором взаимодействие заблокировано.' }, @@ -386,3 +343,26 @@ export const Disabled: Story = { }, }, }; + +export const Badge: Story = { + render: (args) => ({ + props: args, + template: commonTemplate, + }), + args: { + label: 'Emails', + badge: '8', + severity: 'success', + badgeSeverity: 'danger', + showBadge: true, + }, + parameters: { + docs: { + description: { story: 'Примеры использования бейджей на кнопках с позиционированием в углу.' }, + source: { + code: ``, + }, + }, + }, +}; + diff --git a/src/stories/components/button/examples/button-extra.component.ts b/src/stories/components/button/examples/button-extra.component.ts index 46814e3e..e2fa0b78 100644 --- a/src/stories/components/button/examples/button-extra.component.ts +++ b/src/stories/components/button/examples/button-extra.component.ts @@ -1,6 +1,6 @@ import { StoryObj } from '@storybook/angular'; -export { ExtraButtonComponent } from '../../../../../components/button/button-extra.component'; +export { ExtraButtonComponent } from '../../../../components/button/button-extra.component'; export const Extra: StoryObj = { render: (args) => ({ @@ -17,65 +17,44 @@ export const Extra: StoryObj = { [icon]="icon" [disabled]="disabled" [loading]="loading" + [badge]="badge" + [badgeSeverity]="badgeSeverity" + [showBadge]="showBadge" >` }), args: { label: 'Button', - variant: 'primary', - severity: null, - size: 'base', - rounded: false, - iconPos: null, - iconOnly: false, - icon: '', - disabled: false, - loading: false + showBadge: false }, argTypes: { - label: { - control: 'text', - description: 'Текст кнопки' - }, + label: { control: 'text' }, variant: { control: 'select', - options: ['primary', 'secondary', 'outlined', 'text', 'link'], - description: 'Вариант отображения кнопки' + options: ['primary', 'secondary', 'outlined', 'text', 'link'] }, severity: { control: 'select', - options: [null, 'success', 'warning', 'danger', 'info'], - description: 'Цветовая схема кнопки' + options: [null, 'success', 'warning', 'danger', 'info'] }, size: { control: 'select', - options: ['small', 'base', 'large', 'xlarge'], - description: 'Размер кнопки' - }, - rounded: { - control: 'boolean', - description: 'Скруглённая форма кнопки' + options: ['small', 'base', 'large', 'xlarge'] }, + rounded: { control: 'boolean' }, iconPos: { control: 'select', - options: [null, 'prefix', 'postfix'], - description: 'Позиция иконки (prefix — слева, postfix — справа)' - }, - iconOnly: { - control: 'boolean', - description: 'Режим кнопки только с иконкой' - }, - icon: { - control: 'text', - description: 'CSS-класс иконки (например: ti ti-check)' + options: [null, 'prefix', 'postfix'] }, - disabled: { - control: 'boolean', - description: 'Отключённое состояние' + iconOnly: { control: 'boolean' }, + icon: { control: 'text' }, + disabled: { control: 'boolean' }, + loading: { control: 'boolean' }, + badge: { control: 'text' }, + badgeSeverity: { + control: 'select', + options: [null, 'success', 'warning', 'danger', 'info', 'secondary', 'contrast'] }, - loading: { - control: 'boolean', - description: 'Состояние загрузки с индикатором' - } + showBadge: { control: 'boolean' } }, parameters: { docs: { @@ -85,3 +64,32 @@ export const Extra: StoryObj = { } } }; + +export const Badge: StoryObj = { + render: (args) => ({ + props: args, + template: ` +` + }), + args: { + label: 'Emails', + badge: '8', + badgeSeverity: 'danger', + showBadge: true, + severity: 'success' + }, + parameters: { + docs: { + description: { + story: 'Пример кнопки с бейджем для отображения уведомлений или счётчиков.' + } + } + } +}; + From c70bdb2f274798a42129868ce32261bb1b455149 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 26 Mar 2026 21:31:43 +0700 Subject: [PATCH 005/258] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=BF=D1=81=D1=8B=20?= =?UTF-8?q?fluid,=20ariaLabel,=20autofocus,=20tabindex?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../button/button-extra.component.ts | 11 +++- .../components/button/button.stories.ts | 53 +++++++++++++++++++ .../button/examples/button-extra.component.ts | 18 ++++++- 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/components/button/button-extra.component.ts b/src/components/button/button-extra.component.ts index 28ca386b..ef68005d 100644 --- a/src/components/button/button-extra.component.ts +++ b/src/components/button/button-extra.component.ts @@ -21,13 +21,17 @@ export type ExtraButtonIconPos = 'prefix' | 'postfix' | null; [styleClass]="size === 'xlarge' ? 'p-button-xlg' : ''" [rounded]="rounded" [outlined]="variant === 'outlined'" - [text]="variant === 'text'" + [text]="variant === 'text' || text" [link]="variant === 'link'" [icon]="icon" [iconPos]="primeIconPos" [severity]="primeSeverity" [badge]="showBadge ? (badge || ' ') : null" [badgeSeverity]="badgeSeverity" + [fluid]="fluid" + [ariaLabel]="ariaLabel" + [autofocus]="autofocus" + [tabindex]="tabindex" >
` }) @@ -45,6 +49,11 @@ export class ExtraButtonComponent { @Input() badge = ''; @Input() badgeSeverity: 'success' | 'info' | 'warning' | 'danger' | 'secondary' | 'contrast' | null = null; @Input() showBadge = false; + @Input() fluid = false; + @Input() ariaLabel: string | undefined = undefined; + @Input() autofocus = false; + @Input() tabindex: number | undefined = undefined; + @Input() text = false; get primeSize(): 'small' | 'large' | undefined { if (this.size === 'small') return 'small'; diff --git a/src/stories/components/button/button.stories.ts b/src/stories/components/button/button.stories.ts index b049f38a..e84c0cc6 100644 --- a/src/stories/components/button/button.stories.ts +++ b/src/stories/components/button/button.stories.ts @@ -142,11 +142,59 @@ const meta: Meta = { type: { summary: 'boolean' }, }, }, + fluid: { + control: 'boolean', + description: 'Растягивать ли кнопку на всю ширину контейнера', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + ariaLabel: { + control: 'text', + description: 'Метка для экранных дикторов', + table: { + category: 'Props', + defaultValue: { summary: 'undefined' }, + type: { summary: 'string' }, + }, + }, + autofocus: { + control: 'boolean', + description: 'Автофокус при загрузке', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + tabindex: { + control: 'number', + description: 'Порядок фокуса', + table: { + category: 'Props', + defaultValue: { summary: 'undefined' }, + type: { summary: 'number' }, + }, + }, + text: { + control: 'boolean', + description: 'Текстовый вариант кнопки', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, }, args: { showBadge: false, badge: '', badgeSeverity: null, + fluid: false, + autofocus: false, + text: false, }, }; @@ -165,6 +213,11 @@ const commonTemplate = ` [badge]="badge" [badgeSeverity]="badgeSeverity" [showBadge]="showBadge" + [fluid]="fluid" + [ariaLabel]="ariaLabel" + [autofocus]="autofocus" + [tabindex]="tabindex" + [text]="text" > `; diff --git a/src/stories/components/button/examples/button-extra.component.ts b/src/stories/components/button/examples/button-extra.component.ts index e2fa0b78..dfacded3 100644 --- a/src/stories/components/button/examples/button-extra.component.ts +++ b/src/stories/components/button/examples/button-extra.component.ts @@ -20,11 +20,19 @@ export const Extra: StoryObj = { [badge]="badge" [badgeSeverity]="badgeSeverity" [showBadge]="showBadge" + [fluid]="fluid" + [ariaLabel]="ariaLabel" + [autofocus]="autofocus" + [tabindex]="tabindex" + [text]="text" >` }), args: { label: 'Button', - showBadge: false + showBadge: false, + fluid: false, + autofocus: false, + text: false }, argTypes: { label: { control: 'text' }, @@ -54,9 +62,15 @@ export const Extra: StoryObj = { control: 'select', options: [null, 'success', 'warning', 'danger', 'info', 'secondary', 'contrast'] }, - showBadge: { control: 'boolean' } + showBadge: { control: 'boolean' }, + fluid: { control: 'boolean' }, + ariaLabel: { control: 'text' }, + autofocus: { control: 'boolean' }, + tabindex: { control: 'number' }, + text: { control: 'boolean' } }, parameters: { + docs: { description: { story: 'Интерактивный пример с пропсами, соответствующими Figma-компоненту Button.' From 1e7db4f1cf9753f3402d12df6b516be145ae6ef5 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 26 Mar 2026 21:33:03 +0700 Subject: [PATCH 006/258] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BB=D0=BE=D0=B3=D0=BE=D0=B2=20=D0=BE=D1=82=20?= =?UTF-8?q?mcp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .playwright-mcp/console-2026-03-20T05-59-04-766Z.log | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .playwright-mcp/console-2026-03-20T05-59-04-766Z.log diff --git a/.playwright-mcp/console-2026-03-20T05-59-04-766Z.log b/.playwright-mcp/console-2026-03-20T05-59-04-766Z.log deleted file mode 100644 index 567be132..00000000 --- a/.playwright-mcp/console-2026-03-20T05-59-04-766Z.log +++ /dev/null @@ -1 +0,0 @@ -[ 388ms] [ERROR] Failed to load resource: the server responded with a status of 404 () @ https://raw.githubusercontent.com/cdek-it/vue-ui-kit/storybook-update/src/assets/style/vars/_colors.scss:0 From 18e19a7175b5311086db0b8ee96b90fb7f5e819c Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 26 Mar 2026 21:49:35 +0700 Subject: [PATCH 007/258] =?UTF-8?q?=D0=B8=D0=B3=D0=BD=D0=BE=D1=80=20=D1=84?= =?UTF-8?q?=D0=B0=D0=B9=D0=BB=D0=B0=20documentation.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 6 +- documentation.json | 1984 -------------------------------------------- 2 files changed, 3 insertions(+), 1987 deletions(-) delete mode 100644 documentation.json diff --git a/.gitignore b/.gitignore index 9276a2cc..808f9bdc 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,6 @@ api-generator/typedoc.json # файлы в этим папках компилятся и должны создаваться при сборке src/assets/components/themes -./storybook-static -./debug-storybook.log -./documentation.json +/storybook-static +/debug-storybook.log +/documentation.json diff --git a/documentation.json b/documentation.json deleted file mode 100644 index a5b9d486..00000000 --- a/documentation.json +++ /dev/null @@ -1,1984 +0,0 @@ -{ - "pipes": [], - "interfaces": [], - "injectables": [], - "guards": [], - "interceptors": [], - "classes": [], - "directives": [], - "components": [ - { - "name": "ButtonBadgeComponent", - "id": "component-ButtonBadgeComponent-fab33f9afdb48c6fae49d289621dfd7234c7920f7d3f703dac62f523dd0852ba668326634ecf1aaddf69f2b1afbd505312415662d1865b6b360fbd9dec82dafc", - "file": "src/stories/components/button/examples/button-badge.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-badge", - "styleUrls": [], - "styles": [ - "" - ], - "template": "`
\n
\n \n\n \n\n \n\n \n
\n
\n`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "Button" - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n
\n \n\n \n\n \n\n \n
\n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-badge',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonBadgeComponent {}\n\nexport const Badge: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Badge кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonBadgeComponent {}\n `\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n", - "extends": [] - }, - { - "name": "ButtonBaseComponent", - "id": "component-ButtonBaseComponent-c8c405f4a3866155397528b8d67e747d1937ffdd827b6ac823a7f62bf82334820d309b144e65e531862b26ce7b6b3b20f332282f3e7200aa9077211d9f26a9f5", - "file": "src/stories/components/button/examples/button-base.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-base", - "styleUrls": [], - "styles": [ - "" - ], - "template": "`
\n \n \n
\n`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [ - { - "name": "badge", - "defaultValue": "''", - "deprecated": false, - "deprecationMessage": "", - "line": 42, - "type": "string", - "decorators": [] - }, - { - "name": "disabled", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 34, - "type": "boolean", - "decorators": [] - }, - { - "name": "icon", - "defaultValue": "''", - "deprecated": false, - "deprecationMessage": "", - "line": 40, - "type": "string", - "decorators": [] - }, - { - "name": "iconPos", - "defaultValue": "'left'", - "deprecated": false, - "deprecationMessage": "", - "line": 41, - "type": "ButtonIconPosition", - "decorators": [] - }, - { - "name": "label", - "defaultValue": "''", - "deprecated": false, - "deprecationMessage": "", - "line": 33, - "type": "string", - "decorators": [] - }, - { - "name": "loading", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 35, - "type": "boolean", - "decorators": [] - }, - { - "name": "outlined", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 38, - "type": "boolean", - "decorators": [] - }, - { - "name": "rounded", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 37, - "type": "boolean", - "decorators": [] - }, - { - "name": "severity", - "defaultValue": "null", - "deprecated": false, - "deprecationMessage": "", - "line": 43, - "type": "Extract", - "decorators": [] - }, - { - "name": "size", - "deprecated": false, - "deprecationMessage": "", - "line": 36, - "type": "\"small\" | \"large\" | undefined", - "decorators": [] - }, - { - "name": "text", - "defaultValue": "false", - "deprecated": false, - "deprecationMessage": "", - "line": 39, - "type": "boolean", - "decorators": [] - } - ], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "Button" - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component, Input } from '@angular/core';\nimport { Button, ButtonIconPosition } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n \n \n
\n`;\nconst styles = ``;\n\n@Component({\n selector: 'app-button-base',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonBaseComponent {\n @Input() label = '';\n @Input() disabled = false;\n @Input() loading = false;\n @Input() size: 'small' | 'large' | undefined;\n @Input() rounded = false;\n @Input() outlined = false;\n @Input() text = false;\n @Input() icon: string = '';\n @Input() iconPos: ButtonIconPosition = 'left';\n @Input() badge: string = '';\n @Input() severity: Extract = null;\n}\n\nexport const Base: StoryObj = {\n render: (args) => ({\n props: args,\n template: `\n\n`\n }),\n args: {\n label: 'Base button',\n disabled: false,\n loading: false,\n size: null,\n rounded: false,\n outlined: false,\n text: false,\n icon: '',\n iconPos: null,\n badge: '',\n severity: null\n },\n argTypes: {\n label: {\n description: 'Текст кнопки.'\n },\n disabled: {\n description: 'При наличии указывает, что компонент должен быть отключен.'\n },\n loading: {\n description: 'Находится ли кнопка в состоянии загрузки.'\n },\n // TODO Добавить xlarge после фикса в либе.\n size: {\n description: 'Определяет размер кнопки.',\n control: { type: 'select' },\n options: [null, 'small', 'large'],\n table: {\n type: { summary: `'small' | 'large' | null` } // <-- тип в документации\n }\n },\n rounded: {\n description: 'При наличии делает кнопку с закругленными краями.'\n },\n outlined: {\n description: 'При наличии делает кнопку с контуром без фона.'\n },\n text: {\n description: 'При наличии делает кнопку текстовой без фона и границ.'\n },\n icon: {\n description: 'Имя иконки для отображения в кнопке.'\n },\n iconPos: {\n description: 'Позиция иконки относительно текста.',\n control: { type: 'select' },\n options: [null, 'left', 'right'],\n table: {\n type: { summary: `'left' | 'right' | null` }\n }\n },\n badge: {\n description: 'Текст для отображения в виде бейджа на кнопке.'\n },\n severity: {\n description: 'Определяет цветовую схему кнопки.',\n control: { type: 'select' },\n options: [null, 'success', 'info', 'warn', 'primary', 'help', 'danger'],\n table: {\n type: {\n summary: `'success' | 'info' | 'warn' | 'primary' | 'help' | 'danger' | null`\n }\n }\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Стандартная кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-base',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonBaseComponent {\n @Input() label = '';\n @Input() disabled = false;\n @Input() loading = false;\n @Input() size: 'small' | 'large' | null = null;\n @Input() rounded = false;\n}\n `\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n", - "extends": [] - }, - { - "name": "ButtonDisabledComponent", - "id": "component-ButtonDisabledComponent-08149394bbd9dbd2d50d65e9a92b7cbac68e072764309fc410968d2ef7c91352a365dc0e14dd6193f13ab6eaa25606e8f505fc0a1c17097427aa69d168736ab8", - "file": "src/stories/components/button/examples/button-disabled.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-disabled", - "styleUrls": [], - "styles": [ - "" - ], - "template": "`
\n
\n \n
\n
\n`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "Button" - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n
\n \n
\n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-disabled',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonDisabledComponent {}\n\nexport const Disabled: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Disabled кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-disabled',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonDisabledComponent {}\n `\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n", - "extends": [] - }, - { - "name": "ButtonIconComponent", - "id": "component-ButtonIconComponent-553ddfe0086eec00020f592a5e46510ee6019a96420a18f0fc74e8ac183c5cd0e7ec864d369e6d9f3b378c09c5553bd2f92f8a6c407390fe601668ef0e6909ca", - "file": "src/stories/components/button/examples/button-icon.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-icon", - "styleUrls": [], - "styles": [ - "" - ], - "template": "`
\n
\n \n \n \n
\n
\n`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "Button" - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n
\n \n \n \n
\n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-icon',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonIconComponent {}\n\nexport const Icon: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки с иконками'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-icon',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonIconComponent {}\n `\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n", - "extends": [] - }, - { - "name": "ButtonLoadingComponent", - "id": "component-ButtonLoadingComponent-747831019d46f2ad5ee976a755845a807fe3d6fce93323c22753c42a300535885ea9570f93c580b2377de7ec8a16386caea5d52b5d8c5d87cf9ba97198870ace", - "file": "src/stories/components/button/examples/button-loading.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-loading", - "styleUrls": [], - "styles": [ - "" - ], - "template": "`
\n
\n \n
\n
\n`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "Button" - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n
\n \n
\n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-loading',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonLoadingComponent {}\n\nexport const Loading: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка в состоянии загрузки'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-loading',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonLoadingComponent {}\n `\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n", - "extends": [] - }, - { - "name": "ButtonOutlinedComponent", - "id": "component-ButtonOutlinedComponent-2f780c950280808a263be91edeaa56e63eedc39495be6eca8bb7dcea5d56a09aea77d6cecdb9341715d1e1f7c582df95b46fd1321497a1536e21b716244a4a5a", - "file": "src/stories/components/button/examples/button-outlined.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-outlined", - "styleUrls": [], - "styles": [ - "" - ], - "template": "`
\n \n \n
`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "Button" - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n \n \n
`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-outlined',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonOutlinedComponent {}\n\nexport const Outlined: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Outlined кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-outlined',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonOutlinedComponent {}\n `\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n", - "extends": [] - }, - { - "name": "ButtonRoundedComponent", - "id": "component-ButtonRoundedComponent-75651107f6304e710142aef6f4f68ec0f1069847af847d954b7de576ea710779cec3f802adc8586bc9683100e14432e4c15d5d58fa2f7204d7e2e2d034db308a", - "file": "src/stories/components/button/examples/button-rounded.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-rounded", - "styleUrls": [], - "styles": [ - "" - ], - "template": "`
\n
\n \n
\n
\n`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "Button" - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n
\n \n
\n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-rounded',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonRoundedComponent {}\n\nexport const Rounded: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Скругленная кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-rounded',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonRoundedComponent {}\n `\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n", - "extends": [] - }, - { - "name": "ButtonSeverityComponent", - "id": "component-ButtonSeverityComponent-bceea86d34a4ff6c3637b6c4b0dfe628631cbeeacb8537089aaeb500fef8c51fbad4689c06a2de3d51f4f3510bc7520fd634f48cb91995dc93e187ab3099c6e5", - "file": "src/stories/components/button/examples/button-severity.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-severity", - "styleUrls": [], - "styles": [ - "" - ], - "template": "`
\n
\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n
\n
\n`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "Button" - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n
\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n
\n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-severity',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonSeverityComponent {}\n\nexport const Severity: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки с разным Severity'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-severity',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonSeverityComponent {}\n `\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n", - "extends": [] - }, - { - "name": "ButtonSizesComponent", - "id": "component-ButtonSizesComponent-cd17928f6a96e0c2d4319065effc31fa54d37723ef053a6ee42aaac52a553f33c495e79ccd49b3caa116ad0a761224fecf5b2f4bec5e1683dd8aa5f78cc53746", - "file": "src/stories/components/button/examples/button-sizes.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-sizes", - "styleUrls": [], - "styles": [ - "" - ], - "template": "`
\n
\n \n \n \n \n
\n
\n`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "Button" - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { StoryObj } from '@storybook/angular';\nimport { Button } from 'primeng/button';\n\nconst template = `\n
\n
\n \n \n \n \n
\n
\n`;\n\nconst styles = '';\n\n@Component({\n selector: 'app-button-sizes',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonSizesComponent {}\n\nexport const Sizes: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки разных размеров'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-sizes',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonSizesComponent {}\n `\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n", - "extends": [] - }, - { - "name": "ButtonTextComponent", - "id": "component-ButtonTextComponent-9ec9afa71413a44df8de13324a927aa6ce9c0992a9a509345a5081da321472dde3882151e6e56589f4e751c0c6091d49fb74c41e9cc549be31a6e283b2f0d5c1", - "file": "src/stories/components/button/examples/button-text.component.ts", - "encapsulation": [], - "entryComponents": [], - "inputs": [], - "outputs": [], - "providers": [], - "selector": "app-button-text", - "styleUrls": [], - "styles": [ - "" - ], - "template": "`
\n \n
\n`", - "templateUrl": [], - "viewProviders": [], - "hostDirectives": [], - "inputsClass": [], - "outputsClass": [], - "propertiesClass": [], - "methodsClass": [], - "deprecated": false, - "deprecationMessage": "", - "hostBindings": [], - "hostListeners": [], - "standalone": true, - "imports": [ - { - "name": "Button" - } - ], - "description": "", - "rawdescription": "\n", - "type": "component", - "sourceCode": "import { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\nimport { StoryObj } from '@storybook/angular';\n\nconst template = `\n
\n \n
\n`;\nconst styles = '';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [Button],\n template,\n styles\n})\nexport class ButtonTextComponent {}\n\nexport const Text: StoryObj = {\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Text кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonTextComponent {}\n `\n }\n }\n }\n};\n", - "assetsDirs": [], - "styleUrlsData": "", - "stylesData": "\n", - "extends": [] - } - ], - "modules": [], - "miscellaneous": { - "variables": [ - { - "name": "Badge", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-badge.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Badge кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonBadgeComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "Base", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-base.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n\n`\n }),\n args: {\n label: 'Base button',\n disabled: false,\n loading: false,\n size: null,\n rounded: false,\n outlined: false,\n text: false,\n icon: '',\n iconPos: null,\n badge: '',\n severity: null\n },\n argTypes: {\n label: {\n description: 'Текст кнопки.'\n },\n disabled: {\n description: 'При наличии указывает, что компонент должен быть отключен.'\n },\n loading: {\n description: 'Находится ли кнопка в состоянии загрузки.'\n },\n // TODO Добавить xlarge после фикса в либе.\n size: {\n description: 'Определяет размер кнопки.',\n control: { type: 'select' },\n options: [null, 'small', 'large'],\n table: {\n type: { summary: `'small' | 'large' | null` } // <-- тип в документации\n }\n },\n rounded: {\n description: 'При наличии делает кнопку с закругленными краями.'\n },\n outlined: {\n description: 'При наличии делает кнопку с контуром без фона.'\n },\n text: {\n description: 'При наличии делает кнопку текстовой без фона и границ.'\n },\n icon: {\n description: 'Имя иконки для отображения в кнопке.'\n },\n iconPos: {\n description: 'Позиция иконки относительно текста.',\n control: { type: 'select' },\n options: [null, 'left', 'right'],\n table: {\n type: { summary: `'left' | 'right' | null` }\n }\n },\n badge: {\n description: 'Текст для отображения в виде бейджа на кнопке.'\n },\n severity: {\n description: 'Определяет цветовую схему кнопки.',\n control: { type: 'select' },\n options: [null, 'success', 'info', 'warn', 'primary', 'help', 'danger'],\n table: {\n type: {\n summary: `'success' | 'info' | 'warn' | 'primary' | 'help' | 'danger' | null`\n }\n }\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Стандартная кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-base',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonBaseComponent {\n @Input() label = '';\n @Input() disabled = false;\n @Input() loading = false;\n @Input() size: 'small' | 'large' | null = null;\n @Input() rounded = false;\n}\n `\n }\n }\n }\n}" - }, - { - "name": "ButtonDefault", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n name: 'Button',\n args: {\n label: 'Button',\n },\n parameters: {\n docs: {\n description: {\n story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.',\n },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Disabled", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: () => ({\n template: `\n
\n \n success\n info\n warning\n danger\n\n default\n \n \n \n \n\n outlined\n \n \n \n \n\n text\n \n \n \n \n
\n `,\n }),\n parameters: {\n docs: {\n description: { story: 'Состояние кнопки, при котором взаимодействие заблокировано.' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Disabled", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-disabled.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Disabled кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-disabled',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonDisabledComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "Extra", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-extra.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n`\n }),\n args: {\n label: 'Button',\n variant: 'primary',\n severity: null,\n size: 'base',\n rounded: false,\n iconPos: null,\n iconOnly: false,\n icon: '',\n disabled: false,\n loading: false\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'warning', 'danger', 'info'],\n description: 'Цветовая схема кнопки'\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки (prefix — слева, postfix — справа)'\n },\n iconOnly: {\n control: 'boolean',\n description: 'Режим кнопки только с иконкой'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Интерактивный пример с пропсами, соответствующими Figma-компоненту Button.'\n }\n }\n }\n}" - }, - { - "name": "gridTemplate", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "(inner: string) => `\n
\n small\n base\n large\n xlarge\n ${inner}\n
\n`" - }, - { - "name": "Icon", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки с иконками'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-icon',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonIconComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "IconOnly", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { icon: 'ti ti-check' },\n parameters: {\n docs: {\n description: { story: 'Кнопки без текста, только с иконкой.' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Icons", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button', icon: 'ti ti-check' },\n parameters: {\n docs: {\n description: { story: 'Кнопки с иконками (префикс по умолчанию).' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Link", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Link Button' },\n parameters: {\n docs: {\n description: { story: 'Кнопка в виде ссылки.' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Loading", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Состояние загрузки с индикатором.' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Loading", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-loading.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка в состоянии загрузки'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-loading',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonLoadingComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "meta", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Meta", - "defaultValue": "{\n title: 'Prime/Button',\n component: ExtraButtonComponent,\n tags: ['autodocs'],\n decorators: [\n moduleMetadata({\n imports: [ExtraButtonComponent]\n })\n ],\n parameters: {\n docs: {\n description: {\n component:\n 'Кнопка — базовый интерактивный элемент. [Figma Design](https://www.figma.com/design/HOLKdvQJ8jCLeX17s9d0Yf/UI-Kit--DS--v2.0?node-id=160-5223)',\n },\n },\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'Button' },\n type: { summary: 'string' },\n },\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'primary' },\n type: { summary: \"'primary' | 'secondary' | 'outlined' | 'text' | 'link'\" },\n },\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'info', 'warning', 'danger'],\n description: 'Семантический вариант кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'null' },\n type: { summary: \"'success' | 'info' | 'warning' | 'danger' | null\" },\n },\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'base' },\n type: { summary: \"'small' | 'base' | 'large' | 'xlarge'\" },\n },\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)',\n table: {\n category: 'Props',\n defaultValue: { summary: '' },\n type: { summary: 'string' },\n },\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки относительно текста',\n table: {\n category: 'Props',\n defaultValue: { summary: 'null' },\n type: { summary: \"'prefix' | 'postfix' | null\" },\n },\n },\n iconOnly: {\n control: 'boolean',\n description: 'Только иконка, без текста',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n },\n}" - }, - { - "name": "Outlined", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-outlined.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Outlined кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-outlined',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonOutlinedComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "Rounded", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Скруглённая форма кнопок.' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Rounded", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-rounded.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Скругленная кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-rounded',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonRoundedComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "Severity", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: () => ({\n template: `\n
\n \n success\n info\n warning\n danger\n\n small\n \n \n \n \n\n base\n \n \n \n \n\n large\n \n \n \n \n\n xlarge\n \n \n \n \n
\n `,\n }),\n parameters: {\n docs: {\n description: { story: 'Цветовые схемы для различных контекстов: success, info, warning, danger.' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Severity", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-severity.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки с разным Severity'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-severity',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonSeverityComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "Sizes", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Все доступные размеры: small, base, large, xlarge.' },\n source: {\n code: `\n\n\n\n`,\n },\n },\n },\n}" - }, - { - "name": "Sizes", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-sizes.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки разных размеров'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-sizes',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonSizesComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-badge.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-base.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "``" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-disabled.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-loading.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-outlined.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-rounded.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-severity.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-sizes.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-text.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-badge.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n\n \n\n \n\n \n
\n
\n`" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-base.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n \n \n
\n`" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-disabled.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n
\n
\n`" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n \n \n
\n
\n`" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-loading.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n
\n
\n`" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-outlined.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n \n \n
`" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-rounded.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n
\n
\n`" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-severity.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n
\n
\n`" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-sizes.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n \n \n \n
\n
\n`" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-text.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n \n
\n`" - }, - { - "name": "Text", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Текстовый вариант кнопки (без заливки и границ).' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Text", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-text.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Text кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonTextComponent {}\n `\n }\n }\n }\n}" - } - ], - "functions": [], - "typealiases": [ - { - "name": "Story", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "StoryObj", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 184 - } - ], - "enumerations": [], - "groupedVariables": { - "src/stories/components/button/examples/button-badge.component.ts": [ - { - "name": "Badge", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-badge.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Badge кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonBadgeComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-badge.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-badge.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n\n \n\n \n\n \n
\n
\n`" - } - ], - "src/stories/components/button/examples/button-base.component.ts": [ - { - "name": "Base", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-base.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n\n`\n }),\n args: {\n label: 'Base button',\n disabled: false,\n loading: false,\n size: null,\n rounded: false,\n outlined: false,\n text: false,\n icon: '',\n iconPos: null,\n badge: '',\n severity: null\n },\n argTypes: {\n label: {\n description: 'Текст кнопки.'\n },\n disabled: {\n description: 'При наличии указывает, что компонент должен быть отключен.'\n },\n loading: {\n description: 'Находится ли кнопка в состоянии загрузки.'\n },\n // TODO Добавить xlarge после фикса в либе.\n size: {\n description: 'Определяет размер кнопки.',\n control: { type: 'select' },\n options: [null, 'small', 'large'],\n table: {\n type: { summary: `'small' | 'large' | null` } // <-- тип в документации\n }\n },\n rounded: {\n description: 'При наличии делает кнопку с закругленными краями.'\n },\n outlined: {\n description: 'При наличии делает кнопку с контуром без фона.'\n },\n text: {\n description: 'При наличии делает кнопку текстовой без фона и границ.'\n },\n icon: {\n description: 'Имя иконки для отображения в кнопке.'\n },\n iconPos: {\n description: 'Позиция иконки относительно текста.',\n control: { type: 'select' },\n options: [null, 'left', 'right'],\n table: {\n type: { summary: `'left' | 'right' | null` }\n }\n },\n badge: {\n description: 'Текст для отображения в виде бейджа на кнопке.'\n },\n severity: {\n description: 'Определяет цветовую схему кнопки.',\n control: { type: 'select' },\n options: [null, 'success', 'info', 'warn', 'primary', 'help', 'danger'],\n table: {\n type: {\n summary: `'success' | 'info' | 'warn' | 'primary' | 'help' | 'danger' | null`\n }\n }\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Стандартная кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-base',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonBaseComponent {\n @Input() label = '';\n @Input() disabled = false;\n @Input() loading = false;\n @Input() size: 'small' | 'large' | null = null;\n @Input() rounded = false;\n}\n `\n }\n }\n }\n}" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-base.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "``" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-base.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n \n \n
\n`" - } - ], - "src/stories/components/button/button.stories.ts": [ - { - "name": "ButtonDefault", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n name: 'Button',\n args: {\n label: 'Button',\n },\n parameters: {\n docs: {\n description: {\n story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.',\n },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Disabled", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: () => ({\n template: `\n
\n \n success\n info\n warning\n danger\n\n default\n \n \n \n \n\n outlined\n \n \n \n \n\n text\n \n \n \n \n
\n `,\n }),\n parameters: {\n docs: {\n description: { story: 'Состояние кнопки, при котором взаимодействие заблокировано.' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "gridTemplate", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "(inner: string) => `\n
\n small\n base\n large\n xlarge\n ${inner}\n
\n`" - }, - { - "name": "IconOnly", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { icon: 'ti ti-check' },\n parameters: {\n docs: {\n description: { story: 'Кнопки без текста, только с иконкой.' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Icons", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button', icon: 'ti ti-check' },\n parameters: {\n docs: {\n description: { story: 'Кнопки с иконками (префикс по умолчанию).' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Link", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Link Button' },\n parameters: {\n docs: {\n description: { story: 'Кнопка в виде ссылки.' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Loading", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Состояние загрузки с индикатором.' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "meta", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Meta", - "defaultValue": "{\n title: 'Prime/Button',\n component: ExtraButtonComponent,\n tags: ['autodocs'],\n decorators: [\n moduleMetadata({\n imports: [ExtraButtonComponent]\n })\n ],\n parameters: {\n docs: {\n description: {\n component:\n 'Кнопка — базовый интерактивный элемент. [Figma Design](https://www.figma.com/design/HOLKdvQJ8jCLeX17s9d0Yf/UI-Kit--DS--v2.0?node-id=160-5223)',\n },\n },\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'Button' },\n type: { summary: 'string' },\n },\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'primary' },\n type: { summary: \"'primary' | 'secondary' | 'outlined' | 'text' | 'link'\" },\n },\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'info', 'warning', 'danger'],\n description: 'Семантический вариант кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'null' },\n type: { summary: \"'success' | 'info' | 'warning' | 'danger' | null\" },\n },\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'base' },\n type: { summary: \"'small' | 'base' | 'large' | 'xlarge'\" },\n },\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)',\n table: {\n category: 'Props',\n defaultValue: { summary: '' },\n type: { summary: 'string' },\n },\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки относительно текста',\n table: {\n category: 'Props',\n defaultValue: { summary: 'null' },\n type: { summary: \"'prefix' | 'postfix' | null\" },\n },\n },\n iconOnly: {\n control: 'boolean',\n description: 'Только иконка, без текста',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором',\n table: {\n category: 'Props',\n defaultValue: { summary: 'false' },\n type: { summary: 'boolean' },\n },\n },\n },\n}" - }, - { - "name": "Rounded", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Скруглённая форма кнопок.' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Severity", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: () => ({\n template: `\n
\n \n success\n info\n warning\n danger\n\n small\n \n \n \n \n\n base\n \n \n \n \n\n large\n \n \n \n \n\n xlarge\n \n \n \n \n
\n `,\n }),\n parameters: {\n docs: {\n description: { story: 'Цветовые схемы для различных контекстов: success, info, warning, danger.' },\n source: {\n code: ``,\n },\n },\n },\n}" - }, - { - "name": "Sizes", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Все доступные размеры: small, base, large, xlarge.' },\n source: {\n code: `\n\n\n\n`,\n },\n },\n },\n}" - }, - { - "name": "Text", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "Story", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: gridTemplate(`\n \n \n \n \n `),\n }),\n args: { label: 'Button' },\n parameters: {\n docs: {\n description: { story: 'Текстовый вариант кнопки (без заливки и границ).' },\n source: {\n code: ``,\n },\n },\n },\n}" - } - ], - "src/stories/components/button/examples/button-disabled.component.ts": [ - { - "name": "Disabled", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-disabled.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Disabled кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-disabled',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonDisabledComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-disabled.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-disabled.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n
\n
\n`" - } - ], - "src/stories/components/button/examples/button-extra.component.ts": [ - { - "name": "Extra", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-extra.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: (args) => ({\n props: args,\n template: `\n
`\n }),\n args: {\n label: 'Button',\n variant: 'primary',\n severity: null,\n size: 'base',\n rounded: false,\n iconPos: null,\n iconOnly: false,\n icon: '',\n disabled: false,\n loading: false\n },\n argTypes: {\n label: {\n control: 'text',\n description: 'Текст кнопки'\n },\n variant: {\n control: 'select',\n options: ['primary', 'secondary', 'outlined', 'text', 'link'],\n description: 'Вариант отображения кнопки'\n },\n severity: {\n control: 'select',\n options: [null, 'success', 'warning', 'danger', 'info'],\n description: 'Цветовая схема кнопки'\n },\n size: {\n control: 'select',\n options: ['small', 'base', 'large', 'xlarge'],\n description: 'Размер кнопки'\n },\n rounded: {\n control: 'boolean',\n description: 'Скруглённая форма кнопки'\n },\n iconPos: {\n control: 'select',\n options: [null, 'prefix', 'postfix'],\n description: 'Позиция иконки (prefix — слева, postfix — справа)'\n },\n iconOnly: {\n control: 'boolean',\n description: 'Режим кнопки только с иконкой'\n },\n icon: {\n control: 'text',\n description: 'CSS-класс иконки (например: ti ti-check)'\n },\n disabled: {\n control: 'boolean',\n description: 'Отключённое состояние'\n },\n loading: {\n control: 'boolean',\n description: 'Состояние загрузки с индикатором'\n }\n },\n parameters: {\n docs: {\n description: {\n story: 'Интерактивный пример с пропсами, соответствующими Figma-компоненту Button.'\n }\n }\n }\n}" - } - ], - "src/stories/components/button/examples/button-icon.component.ts": [ - { - "name": "Icon", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки с иконками'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-icon',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonIconComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-icon.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n \n \n
\n
\n`" - } - ], - "src/stories/components/button/examples/button-loading.component.ts": [ - { - "name": "Loading", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-loading.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопка в состоянии загрузки'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-loading',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonLoadingComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-loading.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-loading.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n
\n
\n`" - } - ], - "src/stories/components/button/examples/button-outlined.component.ts": [ - { - "name": "Outlined", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-outlined.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Outlined кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-outlined',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonOutlinedComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-outlined.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-outlined.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n \n \n
`" - } - ], - "src/stories/components/button/examples/button-rounded.component.ts": [ - { - "name": "Rounded", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-rounded.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Скругленная кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-rounded',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonRoundedComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-rounded.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-rounded.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n
\n
\n`" - } - ], - "src/stories/components/button/examples/button-severity.component.ts": [ - { - "name": "Severity", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-severity.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки с разным Severity'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-severity',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonSeverityComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-severity.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-severity.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n\n
\n \n \n \n \n \n \n
\n
\n
\n`" - } - ], - "src/stories/components/button/examples/button-sizes.component.ts": [ - { - "name": "Sizes", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-sizes.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Кнопки разных размеров'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-sizes',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonSizesComponent {}\n `\n }\n }\n }\n}" - }, - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-sizes.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-sizes.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n
\n \n \n \n \n
\n
\n`" - } - ], - "src/stories/components/button/examples/button-text.component.ts": [ - { - "name": "styles", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-text.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "defaultValue": "''" - }, - { - "name": "template", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-text.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "unknown", - "defaultValue": "`\n
\n \n
\n`" - }, - { - "name": "Text", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/stories/components/button/examples/button-text.component.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "StoryObj", - "defaultValue": "{\n render: () => ({\n template: ``\n }),\n parameters: {\n docs: {\n description: {\n story: 'Text кнопка'\n },\n source: {\n language: 'ts',\n code: `\nimport { Component } from '@angular/core';\nimport { Button } from 'primeng/button';\n\n@Component({\n selector: 'app-button-text',\n standalone: true,\n imports: [\n Button\n ],\n template: ${template},\n styles: ${styles}\n})\nexport class ButtonTextComponent {}\n `\n }\n }\n }\n}" - } - ] - }, - "groupedFunctions": {}, - "groupedEnumerations": {}, - "groupedTypeAliases": { - "src/stories/components/button/button.stories.ts": [ - { - "name": "Story", - "ctype": "miscellaneous", - "subtype": "typealias", - "rawtype": "StoryObj", - "file": "src/stories/components/button/button.stories.ts", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "kind": 184 - } - ] - } - }, - "routes": { - "name": "", - "kind": "module", - "children": [] - }, - "coverage": { - "count": 0, - "status": "low", - "files": [ - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "ButtonDefault", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Disabled", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "gridTemplate", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "IconOnly", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Icons", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Link", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Loading", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "meta", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Rounded", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Severity", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Sizes", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Text", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/button.stories.ts", - "type": "type alias", - "linktype": "miscellaneous", - "linksubtype": "typealias", - "name": "Story", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-badge.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonBadgeComponent", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-badge.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Badge", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-badge.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "styles", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-badge.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-base.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonBaseComponent", - "coveragePercent": 0, - "coverageCount": "0/12", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-base.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Base", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-base.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "styles", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-base.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-disabled.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonDisabledComponent", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-disabled.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Disabled", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-disabled.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "styles", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-disabled.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-extra.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Extra", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-icon.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonIconComponent", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-icon.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Icon", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-icon.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "styles", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-icon.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-loading.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonLoadingComponent", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-loading.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Loading", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-loading.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "styles", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-loading.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-outlined.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonOutlinedComponent", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-outlined.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Outlined", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-outlined.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "styles", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-outlined.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-rounded.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonRoundedComponent", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-rounded.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Rounded", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-rounded.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "styles", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-rounded.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-severity.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonSeverityComponent", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-severity.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Severity", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-severity.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "styles", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-severity.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-sizes.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonSizesComponent", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-sizes.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Sizes", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-sizes.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "styles", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-sizes.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-text.component.ts", - "type": "component", - "linktype": "component", - "name": "ButtonTextComponent", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-text.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "styles", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-text.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "template", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - }, - { - "filePath": "src/stories/components/button/examples/button-text.component.ts", - "type": "variable", - "linktype": "miscellaneous", - "linksubtype": "variable", - "name": "Text", - "coveragePercent": 0, - "coverageCount": "0/1", - "status": "low" - } - ] - } -} \ No newline at end of file From cc6f074e7aa362582e1209ba361b8511467599cd Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Thu, 2 Apr 2026 23:19:53 +0700 Subject: [PATCH 008/258] cr fixes --- src/components/button/button.component.html | 3 -- src/components/button/button.component.scss | 15 ------- .../button/button.component.spec.ts | 23 ---------- src/components/button/button.component.ts | 28 ------------- .../components/button/button.component.ts} | 41 ++++++++++-------- src/prime-preset/tokens/components/button.ts | 15 +++++++ .../components/button/button.stories.ts | 42 +++++++++---------- .../button/examples/button-extra.component.ts | 2 +- 8 files changed, 60 insertions(+), 109 deletions(-) delete mode 100644 src/components/button/button.component.html delete mode 100644 src/components/button/button.component.scss delete mode 100644 src/components/button/button.component.spec.ts delete mode 100644 src/components/button/button.component.ts rename src/{components/button/button-extra.component.ts => lib/components/button/button.component.ts} (56%) diff --git a/src/components/button/button.component.html b/src/components/button/button.component.html deleted file mode 100644 index b6a3c33f..00000000 --- a/src/components/button/button.component.html +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/components/button/button.component.scss b/src/components/button/button.component.scss deleted file mode 100644 index 0716a2ca..00000000 --- a/src/components/button/button.component.scss +++ /dev/null @@ -1,15 +0,0 @@ -:host ::ng-deep { - .p-button { - position: relative; - overflow: visible; - - .p-badge { - position: absolute; - inset-block-start: 0; - inset-inline-end: 0; - transform: translate(50%, -50%); - transform-origin: 100% 0; - margin: 0; - } - } -} diff --git a/src/components/button/button.component.spec.ts b/src/components/button/button.component.spec.ts deleted file mode 100644 index d4ad18ea..00000000 --- a/src/components/button/button.component.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ButtonComponent } from './button.component'; - -describe('ButtonComponent', () => { - let component: ButtonComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ButtonComponent] - }) - .compileComponents(); - - fixture = TestBed.createComponent(ButtonComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/components/button/button.component.ts b/src/components/button/button.component.ts deleted file mode 100644 index c5454f2f..00000000 --- a/src/components/button/button.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { Button } from 'primeng/button'; - -/** - * как использовать - * ``` - * - *
content
// это то, на что заменится внутри компонента - *
- *``` - */ - -@Component({ - selector: 'app-button', - standalone: true, - imports: [Button], - templateUrl: './button.component.html', - styleUrl: './button.component.scss' -}) -export class ButtonComponent { - @Input() size!: 'small' | undefined | 'large' | 'xlarge'; - - @Input() text: boolean = false; - - get innerSize(): 'small' | undefined | 'large' { - return (this.size === 'xlarge' || !this.size) ? undefined : (this.size as 'small' | 'large'); - } -} diff --git a/src/components/button/button-extra.component.ts b/src/lib/components/button/button.component.ts similarity index 56% rename from src/components/button/button-extra.component.ts rename to src/lib/components/button/button.component.ts index ef68005d..ab726609 100644 --- a/src/components/button/button-extra.component.ts +++ b/src/lib/components/button/button.component.ts @@ -1,17 +1,17 @@ import { Component, Input } from '@angular/core'; -import { Button } from 'primeng/button'; -import { Badge } from 'primeng/badge'; +import { Button, ButtonSeverity as PrimeButtonSeverity } from 'primeng/button'; -export type ExtraButtonVariant = 'primary' | 'secondary' | 'outlined' | 'text' | 'link'; -export type ExtraButtonSeverity = 'success' | 'warning' | 'danger' | 'info' | null; -export type ExtraButtonSize = 'small' | 'base' | 'large' | 'xlarge'; -export type ExtraButtonIconPos = 'prefix' | 'postfix' | null; +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; +type PrimeBadgeSeverity = Extract; @Component({ - selector: 'extra-button', + selector: 'button', standalone: true, - imports: [Button, Badge], - styleUrl: './button.component.scss', + imports: [Button], template: ` ` }) -export class ExtraButtonComponent { +export class ButtonComponent { @Input() label = 'Button'; - @Input() variant: ExtraButtonVariant = 'primary'; - @Input() severity: ExtraButtonSeverity = null; - @Input() size: ExtraButtonSize = 'base'; + @Input() variant: ButtonVariant = 'primary'; + @Input() severity: ButtonSeverity = null; + @Input() size: ButtonSize = 'base'; @Input() rounded = false; - @Input() iconPos: ExtraButtonIconPos = null; + @Input() iconPos: ButtonIconPos = null; @Input() iconOnly = false; @Input() icon = ''; @Input() disabled = false; @Input() loading = false; @Input() badge = ''; - @Input() badgeSeverity: 'success' | 'info' | 'warning' | 'danger' | 'secondary' | 'contrast' | null = null; + @Input() badgeSeverity: BadgeSeverity = null; @Input() showBadge = false; @Input() fluid = false; @Input() ariaLabel: string | undefined = undefined; @@ -65,9 +65,14 @@ export class ExtraButtonComponent { return this.iconPos === 'postfix' ? 'right' : 'left'; } - get primeSeverity(): string | null { + get primeSeverity(): PrimeButtonSeverity | null { if (this.variant === 'secondary') return 'secondary'; if (this.severity === 'warning') return 'warn'; return this.severity; } + + get primeBadgeSeverity(): PrimeBadgeSeverity { + if (this.badgeSeverity === 'warning') return 'warn'; + return this.badgeSeverity; + } } diff --git a/src/prime-preset/tokens/components/button.ts b/src/prime-preset/tokens/components/button.ts index 2a5c586c..70c844d6 100644 --- a/src/prime-preset/tokens/components/button.ts +++ b/src/prime-preset/tokens/components/button.ts @@ -37,6 +37,21 @@ export const buttonCss = ({ dt }: { dt: (token: string) => string }): string => font-family: var(--p-fonts-font-family-heading, 'TT Fellows', sans-serif); } + /* ─── Button badge ─── */ + .p-button, .p-ripple.p-button { + position: relative; + overflow: visible; + } + + .p-button .p-badge { + position: absolute; + inset-block-start: 0; + inset-inline-end: 0; + transform: translate(50%, -50%); + transform-origin: 100% 0; + margin: 0; + } + /* ─── Размеры иконок ─── */ .p-button .p-button-icon { font-size: var(--p-button-extend-icon-size-md); diff --git a/src/stories/components/button/button.stories.ts b/src/stories/components/button/button.stories.ts index e84c0cc6..7617ada6 100644 --- a/src/stories/components/button/button.stories.ts +++ b/src/stories/components/button/button.stories.ts @@ -1,14 +1,14 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { ExtraButtonComponent } from '../../../components/button/button-extra.component'; +import { ButtonComponent } from '../../../lib/components/button/button.component'; -const meta: Meta = { +const meta: Meta = { title: 'Prime/Button', - component: ExtraButtonComponent, + component: ButtonComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ - imports: [ExtraButtonComponent] + imports: [ButtonComponent] }) ], parameters: { @@ -199,7 +199,7 @@ const meta: Meta = { }; const commonTemplate = ` - +> `; export default meta; -type Story = StoryObj; +type Story = StoryObj; // ── Default ────────────────────────────────────────────────────────────────── @@ -241,7 +241,7 @@ export const Default: Story = { story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', }, source: { - code: ``, + code: `` + : ``; + + return { props: args, template }; + }, args: { label: 'Button', }, @@ -240,9 +270,6 @@ export const Default: Story = { description: { story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', }, - source: { - code: ``; + 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"` (статичный шаблон) | +| ``; - 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"` (статичный шаблон) | -| ` +`; + +// ── Default ────────────────────────────────────────────────────────────────── +export const Default: Story = { + name: 'Default', + render: (args) => { + const parts: string[] = []; + + if (args.tooltip) parts.push(`tooltip="${args.tooltip}"`); + if (args.position && args.position !== 'right') parts.push(`position="${args.position}"`); + if (args.event && args.event !== 'hover') parts.push(`event="${args.event}"`); + if (args.showDelay) parts.push(`[showDelay]="${args.showDelay}"`); + if (args.hideDelay) parts.push(`[hideDelay]="${args.hideDelay}"`); + if (args.disabled) parts.push(`[disabled]="true"`); + if (args.label) parts.push(`label="${args.label}"`); + + const template = ` + +`; + return { props: args, template }; + }, + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + }, + }, +}; + +// ── Вариации ───────────────────────────────────────────────────────────────── + +export const Positions: Story = { + render: (args) => ({ props: args, template: commonTemplate }), + args: { + tooltip: 'Подсказка сверху', + position: 'top', + label: 'Сверху' + }, + parameters: { + docs: { + description: { story: 'Различные варианты позиционирования (измените через Controls).' }, + source: { + code: `` + } + } + } +}; + +export const Delay: Story = { + render: (args) => ({ props: args, template: commonTemplate }), + args: { + tooltip: 'Подсказка с задержкой 1с', + showDelay: 1000, + label: 'Задержка появления (1с)' + }, + parameters: { + docs: { + description: { story: 'Подсказка может появляться или скрываться с задержкой в миллисекундах.' }, + source: { + code: `` + } + } + } +}; + +export const EventFocus: Story = { + name: 'Event', + render: (args) => ({ + props: args, + template: ` + +` + }), + args: { + tooltip: 'Введите ваше имя', + event: 'focus', + label: 'Кликни для фокуса', + isFocused: false + }, + parameters: { + docs: { + description: { story: 'Подсказка может реагировать на фокус элемента вместо наведения.' }, + source: { + code: `` + } + } + } +}; From 5dea3c104e3d1fcb96f0e3c2af41c3322e6e6fae Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 7 Apr 2026 23:43:36 +0700 Subject: [PATCH 031/258] =?UTF-8?q?progressspinner:=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 --- .../progressspinner.component.ts | 35 ++++++ src/prime-preset/map-tokens.ts | 5 + .../tokens/components/progressspinner.ts | 35 ++++++ .../progressspinner-monochrome.component.ts | 51 ++++++++ .../progressspinner-sizes.component.ts | 51 ++++++++ .../progressspinner.stories.ts | 118 ++++++++++++++++++ 6 files changed, 295 insertions(+) create mode 100644 src/lib/components/progressspinner/progressspinner.component.ts create mode 100644 src/prime-preset/tokens/components/progressspinner.ts create mode 100644 src/stories/components/progressspinner/examples/progressspinner-monochrome.component.ts create mode 100644 src/stories/components/progressspinner/examples/progressspinner-sizes.component.ts create mode 100644 src/stories/components/progressspinner/progressspinner.stories.ts diff --git a/src/lib/components/progressspinner/progressspinner.component.ts b/src/lib/components/progressspinner/progressspinner.component.ts new file mode 100644 index 00000000..d4647781 --- /dev/null +++ b/src/lib/components/progressspinner/progressspinner.component.ts @@ -0,0 +1,35 @@ +import { Component, Input } from '@angular/core'; +import { ProgressSpinnerModule } from 'primeng/progressspinner'; // We use Module since PrimeNG 17/18 might export it this way. Wait, earlier we saw ProgressSpinner is standalone? Actually ProgressSpinner in v18 is standalone, but importing it as ProgressSpinner works. +// Let's import the component directly. Wait, index.d.ts exports { ProgressSpinner, ProgressSpinnerModule }. Either is fine. Let's use ProgressSpinner. +import { ProgressSpinner } from 'primeng/progressspinner'; + +export type ProgressSpinnerSize = 'small' | 'medium' | 'large' | 'xlarge'; + +@Component({ + selector: 'progressspinner', + standalone: true, + imports: [ProgressSpinner], + template: ` + + ` +}) +export class ProgressSpinnerComponent { + @Input() size: ProgressSpinnerSize = 'medium'; + @Input() multicolor = true; + @Input() strokeWidth = '2'; + @Input() fill = 'none'; + @Input() animationDuration = '2s'; + @Input() ariaLabel: string | undefined = undefined; + + get primeStyleClass(): string { + const sizeClass = `p-progressspinner-${this.size}`; + const colorClass = this.multicolor ? '' : 'p-progressspinner-monochrome'; + return `${sizeClass} ${colorClass}`.trim(); + } +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 39627587..1d2c0588 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 { progressspinnerCss } from './tokens/components/progressspinner'; const presetTokens: Preset = { primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'], @@ -14,6 +15,10 @@ const presetTokens: Preset = { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), css: buttonCss, }, + progressspinner: { + ...(tokens.components.progressspinner as unknown as ComponentsDesignTokens['progressspinner']), + css: progressspinnerCss, + }, } as ComponentsDesignTokens, }; diff --git a/src/prime-preset/tokens/components/progressspinner.ts b/src/prime-preset/tokens/components/progressspinner.ts new file mode 100644 index 00000000..d901e3e1 --- /dev/null +++ b/src/prime-preset/tokens/components/progressspinner.ts @@ -0,0 +1,35 @@ +export const progressspinnerCss = ({ dt }: { dt: (token: string) => string }): string => ` +.p-progressspinner-circle { + stroke-width: ${dt('progressspinner.root.borderWidth')}; +} + +/* multicolor false */ +.p-progressspinner.p-progressspinner-monochrome .p-progressspinner-circle { + stroke: ${dt('primary.color')}; + animation: p-progressspinner-dash 1.5s ease-in-out infinite; +} + +.p-progressspinner.p-progressspinner-small, +.p-progressspinner.p-progressspinner-small .p-progressspinner-circle { + width: ${dt('progressspinner.extend.small')}; + height: ${dt('progressspinner.extend.small')}; +} + +.p-progressspinner.p-progressspinner-medium, +.p-progressspinner.p-progressspinner-medium .p-progressspinner-circle { + width: ${dt('progressspinner.extend.medium')}; + height: ${dt('progressspinner.extend.medium')}; +} + +.p-progressspinner.p-progressspinner-large, +.p-progressspinner.p-progressspinner-large .p-progressspinner-circle { + width: ${dt('progressspinner.extend.large')}; + height: ${dt('progressspinner.extend.large')}; +} + +.p-progressspinner.p-progressspinner-xlarge, +.p-progressspinner.p-progressspinner-xlarge .p-progressspinner-circle { + width: ${dt('progressspinner.extend.xlarge')}; + height: ${dt('progressspinner.extend.xlarge')}; +} +`; diff --git a/src/stories/components/progressspinner/examples/progressspinner-monochrome.component.ts b/src/stories/components/progressspinner/examples/progressspinner-monochrome.component.ts new file mode 100644 index 00000000..8e2f58f5 --- /dev/null +++ b/src/stories/components/progressspinner/examples/progressspinner-monochrome.component.ts @@ -0,0 +1,51 @@ +import { Component, Input } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { ProgressSpinnerComponent } from '../../../../lib/components/progressspinner/progressspinner.component'; + +const template = ` + +`; + +@Component({ + selector: 'progressspinner-monochrome', + standalone: true, + imports: [ProgressSpinnerComponent], + template +}) +export class ProgressSpinnerMonochromeComponent { + @Input() size: any = 'medium'; + @Input() multicolor = false; +} + +export const Monochrome: StoryObj = { + render: (args) => ({ + props: args, + template: `` + }), + args: { + size: 'medium', + multicolor: false + }, + parameters: { + docs: { + description: { + story: 'Одноцветный вариант спиннера (monochrome).' + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { ProgressSpinnerComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'progressspinner-monochrome', + standalone: true, + imports: [ProgressSpinnerComponent], + template: \`\` +}) +export class ProgressSpinnerMonochromeComponent {} + ` + } + } + } +}; diff --git a/src/stories/components/progressspinner/examples/progressspinner-sizes.component.ts b/src/stories/components/progressspinner/examples/progressspinner-sizes.component.ts new file mode 100644 index 00000000..397cc189 --- /dev/null +++ b/src/stories/components/progressspinner/examples/progressspinner-sizes.component.ts @@ -0,0 +1,51 @@ +import { Component, Input } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { ProgressSpinnerComponent, ProgressSpinnerSize } from '../../../../lib/components/progressspinner/progressspinner.component'; + +const template = ` + +`; + +@Component({ + selector: 'progressspinner-sizes', + standalone: true, + imports: [ProgressSpinnerComponent], + template +}) +export class ProgressSpinnerSizesComponent { + @Input() size: ProgressSpinnerSize = 'xlarge'; + @Input() multicolor = true; +} + +export const Sizes: StoryObj = { + render: (args) => ({ + props: args, + template: `` + }), + args: { + size: 'xlarge', + multicolor: true + }, + parameters: { + docs: { + description: { + story: 'Изменение размера спиннера. Используйте Controls для выбора других вариантов.' + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { ProgressSpinnerComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'progressspinner-sizes', + standalone: true, + imports: [ProgressSpinnerComponent], + template: \`\` +}) +export class ProgressSpinnerSizesComponent {} + ` + } + } + } +}; diff --git a/src/stories/components/progressspinner/progressspinner.stories.ts b/src/stories/components/progressspinner/progressspinner.stories.ts new file mode 100644 index 00000000..0676ec2b --- /dev/null +++ b/src/stories/components/progressspinner/progressspinner.stories.ts @@ -0,0 +1,118 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { ProgressSpinnerComponent } from '../../../lib/components/progressspinner/progressspinner.component'; +import { Sizes, ProgressSpinnerSizesComponent } from './examples/progressspinner-sizes.component'; +import { Monochrome, ProgressSpinnerMonochromeComponent } from './examples/progressspinner-monochrome.component'; + +type ProgressSpinnerArgs = ProgressSpinnerComponent; + +const meta: Meta = { + title: 'Prime/Misc/ProgressSpinner', + component: ProgressSpinnerComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ imports: [ProgressSpinnerComponent, ProgressSpinnerSizesComponent, ProgressSpinnerMonochromeComponent] }) + ], + parameters: { + docs: { + description: { + component: `Используется для отображения индикатора процесса/состояния загрузки неопределенного времени. + +\`\`\`typescript +import { ProgressSpinnerComponent } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-progressspinner' }, + }, + argTypes: { + size: { + control: 'select', + options: ['small', 'medium', 'large', 'xlarge'], + description: 'Размер спиннера (задает вычисленные CSS-классы).', + table: { + category: 'Props', + defaultValue: { summary: 'medium' }, + type: { summary: "'small' | 'medium' | 'large' | 'xlarge'" }, + }, + }, + multicolor: { + control: 'boolean', + description: 'Включить многоцветную анимацию.', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + strokeWidth: { + table: { disable: true }, + }, + fill: { + table: { disable: true }, + }, + animationDuration: { + control: 'text', + description: 'Длительность одной итерации анимации вращения.', + table: { + category: 'Props', + defaultValue: { summary: '2s' }, + type: { summary: 'string' }, + }, + }, + ariaLabel: { + table: { disable: true }, + }, + }, + args: { + size: 'medium', + multicolor: true, + strokeWidth: '2', + fill: 'none', + animationDuration: '2s', + }, +}; + +export default meta; +type Story = StoryObj; + +const commonTemplate = ` + +`; + +// ── Default ────────────────────────────────────────────────────────────────── +export const Default: Story = { + name: 'Default', + render: (args) => { + const parts: string[] = []; + + if (args.size && args.size !== 'medium') parts.push(`size="${args.size}"`); + if (!args.multicolor) parts.push(`[multicolor]="false"`); + if (args.strokeWidth && args.strokeWidth !== '2') parts.push(`strokeWidth="${args.strokeWidth}"`); + if (args.fill && args.fill !== 'none') parts.push(`fill="${args.fill}"`); + if (args.animationDuration && args.animationDuration !== '2s') parts.push(`animationDuration="${args.animationDuration}"`); + + const properties = parts.length > 0 ? ' ' + parts.join('\n ') : ''; + + const template = ` + +`; + return { props: args, template }; + }, + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для изменения размера, цвета и толщины линии.', + }, + }, + }, +}; + +// ── Вариации ───────────────────────────────────────────────────────────────── + +export { Sizes, Monochrome }; From ab3018121fd6417043ceb11ea86940ec68f8c342 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 8 Apr 2026 15:34:26 +0700 Subject: [PATCH 032/258] =?UTF-8?q?card:=20=D1=81=D1=82=D0=B8=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F,=20=D1=81=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B8=D1=81=D1=8B,=20=D0=BE=D0=B1=D1=91=D1=80=D1=82=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/card/card.component.ts | 65 ++++ src/prime-preset/map-tokens.ts | 5 + src/prime-preset/tokens/components/card.ts | 31 ++ src/stories/components/card/card.stories.ts | 280 ++++++++++++++++++ .../card/examples/card-overlay.component.ts | 74 +++++ .../examples/card-without-footer.component.ts | 67 +++++ .../examples/card-without-header.component.ts | 64 ++++ .../card-without-subtitle.component.ts | 74 +++++ 8 files changed, 660 insertions(+) create mode 100644 src/lib/components/card/card.component.ts create mode 100644 src/prime-preset/tokens/components/card.ts create mode 100644 src/stories/components/card/card.stories.ts create mode 100644 src/stories/components/card/examples/card-overlay.component.ts create mode 100644 src/stories/components/card/examples/card-without-footer.component.ts create mode 100644 src/stories/components/card/examples/card-without-header.component.ts create mode 100644 src/stories/components/card/examples/card-without-subtitle.component.ts diff --git a/src/lib/components/card/card.component.ts b/src/lib/components/card/card.component.ts new file mode 100644 index 00000000..1192ce8c --- /dev/null +++ b/src/lib/components/card/card.component.ts @@ -0,0 +1,65 @@ +import { + AfterContentInit, + ChangeDetectorRef, + Component, + ContentChildren, + Input, + QueryList, +} from '@angular/core'; +import { NgTemplateOutlet } from '@angular/common'; +import { Card } from 'primeng/card'; +import { PrimeTemplate, SharedModule } from 'primeng/api'; + +@Component({ + selector: 'card', + host: { style: 'display: block' }, + standalone: true, + imports: [Card, SharedModule, NgTemplateOutlet], + template: ` + + @if (headerTpl) { + + + + } + @if (contentTpl) { + + + + } + @if (footerTpl) { + + + + } + + `, +}) +export class CardComponent implements AfterContentInit { + @Input() title = ''; + @Input() subtitle = ''; + @Input() overlay = false; + + @ContentChildren(PrimeTemplate) templates!: QueryList; + + headerTpl?: PrimeTemplate; + contentTpl?: PrimeTemplate; + footerTpl?: PrimeTemplate; + + constructor(private cdr: ChangeDetectorRef) {} + + ngAfterContentInit(): void { + this.templates.forEach(tpl => { + switch (tpl.getType()) { + case 'header': this.headerTpl = tpl; break; + case 'content': this.contentTpl = tpl; break; + case 'footer': this.footerTpl = tpl; break; + } + }); + this.cdr.detectChanges(); + } +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 39627587..612185c0 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 { cardCss } from './tokens/components/card'; const presetTokens: Preset = { primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'], @@ -14,6 +15,10 @@ const presetTokens: Preset = { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), css: buttonCss, }, + card: { + ...(tokens.components.card as unknown as ComponentsDesignTokens['card']), + css: cardCss, + }, } as ComponentsDesignTokens, }; diff --git a/src/prime-preset/tokens/components/card.ts b/src/prime-preset/tokens/components/card.ts new file mode 100644 index 00000000..57f5707f --- /dev/null +++ b/src/prime-preset/tokens/components/card.ts @@ -0,0 +1,31 @@ +/** + * Кастомная CSS-стилизация для компонента p-card. + * Публикует extend-токены как CSS-переменные и применяет глобальные стили. + * Подключается в map-tokens.ts: `import { cardCss } from './tokens/components/card'` + */ +export const cardCss = ({ dt }: { dt: (token: string) => string }): string => ` + /* ─── Card extend: публикуем кастомные переменные в :root ─── */ + :root { + --p-card-extend-border-color: ${dt('card.extend.borderColor')}; + --p-card-extend-border-width: ${dt('card.extend.borderWidth')}; + } + + /* ─── Card base styles ─── */ + .p-card.p-component { + border: var(--p-card-extend-border-width) solid var(--p-card-extend-border-color); + overflow: hidden; + box-shadow: none; + } + + /* ─── Overlay variant ─── */ + .p-card.p-component.shadow-md { + box-shadow: ${dt('overlay.popover.shadow')}; + } + + /* ─── Subtitle typography ─── */ + .p-card-subtitle { + font-family: ${dt('fonts.fontFamily.heading')}; + font-size: ${dt('fonts.fontSize.200')}; + font-weight: ${dt('fonts.fontWeight.regular')}; + } +`; diff --git a/src/stories/components/card/card.stories.ts b/src/stories/components/card/card.stories.ts new file mode 100644 index 00000000..16223bb4 --- /dev/null +++ b/src/stories/components/card/card.stories.ts @@ -0,0 +1,280 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { SharedModule } from 'primeng/api'; +import { CardComponent } from '../../../lib/components/card/card.component'; +import { ButtonComponent } from '../../../lib/components/button/button.component'; +import { CardOverlayComponent } from './examples/card-overlay.component'; +import { CardWithoutHeaderComponent } from './examples/card-without-header.component'; +import { CardWithoutFooterComponent } from './examples/card-without-footer.component'; +import { CardWithoutSubtitleComponent } from './examples/card-without-subtitle.component'; + +type CardArgs = CardComponent; + +const meta: Meta = { + title: 'Components/Card', + component: CardComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + CardComponent, + ButtonComponent, + SharedModule, + CardOverlayComponent, + CardWithoutHeaderComponent, + CardWithoutFooterComponent, + CardWithoutSubtitleComponent, + ] + }) + ], + parameters: { + docs: { + description: { + component: `Гибкий контейнер для группировки контента с заголовком, подзаголовком, основным содержимым и действиями. + +\`\`\`typescript +import { CardModule } from 'primeng/card'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-card' }, + }, + argTypes: { + title: { + control: 'text', + description: 'Заголовок карточки', + table: { + category: 'Props', + defaultValue: { summary: '' }, + type: { summary: 'string' }, + }, + }, + subtitle: { + control: 'text', + description: 'Подзаголовок карточки', + table: { + category: 'Props', + defaultValue: { summary: '' }, + type: { summary: 'string' }, + }, + }, + overlay: { + control: 'boolean', + description: 'Тень вокруг карточки (shadow-md)', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ────────────────────────────────────────────────────────────────── + +export const Default: Story = { + name: 'Default', + render: (args) => { + const parts: string[] = []; + + if (args.title) parts.push(`title="${args.title}"`); + if (args.subtitle) parts.push(`subtitle="${args.subtitle}"`); + if (args.overlay) parts.push(`[overlay]="true"`); + + const attrs = parts.length ? `\n ${parts.join('\n ')}` : ''; + const template = `
+ + +
+ +
+
+ +

Контент карточки. Гибкая область для любого содержимого.

+
+ + + + +
`; + + return { props: args, template }; + }, + args: { + title: 'Title', + subtitle: 'Caption', + }, + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + }, + }, +}; + +// ── Overlay ─────────────────────────────────────────────────────────────────── + +export const Overlay: Story = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Карточка с тенью (overlay).' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { SharedModule } from 'primeng/api'; +import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-card-overlay', + standalone: true, + imports: [CardComponent, ButtonComponent, SharedModule], + template: \` + + +
+ +
+
+ +

Карточка с тенью.

+
+ + + +
+ \`, +}) +export class CardOverlayComponent {} + `, + }, + }, + }, +}; + +// ── WithoutHeader ───────────────────────────────────────────────────────────── + +export const WithoutHeader: Story = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Карточка без изображения в шапке.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { SharedModule } from 'primeng/api'; +import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-card-without-header', + standalone: true, + imports: [CardComponent, ButtonComponent, SharedModule], + template: \` + + +

Карточка без изображения в шапке.

+
+ + + +
+ \`, +}) +export class CardWithoutHeaderComponent {} + `, + }, + }, + }, +}; + +// ── WithoutFooter ───────────────────────────────────────────────────────────── + +export const WithoutFooter: Story = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Карточка без футера с действиями.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { SharedModule } from 'primeng/api'; +import { CardComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-card-without-footer', + standalone: true, + imports: [CardComponent, SharedModule], + template: \` + + +
+ +
+
+ +

Карточка без футера.

+
+
+ \`, +}) +export class CardWithoutFooterComponent {} + `, + }, + }, + }, +}; + +// ── WithoutSubtitle ─────────────────────────────────────────────────────────── + +export const WithoutSubtitle: Story = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Карточка без подзаголовка.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { SharedModule } from 'primeng/api'; +import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-card-without-subtitle', + standalone: true, + imports: [CardComponent, ButtonComponent, SharedModule], + template: \` + + +
+ +
+
+ +

Карточка без подзаголовка.

+
+ + + +
+ \`, +}) +export class CardWithoutSubtitleComponent {} + `, + }, + }, + }, +}; diff --git a/src/stories/components/card/examples/card-overlay.component.ts b/src/stories/components/card/examples/card-overlay.component.ts new file mode 100644 index 00000000..a4ea6b49 --- /dev/null +++ b/src/stories/components/card/examples/card-overlay.component.ts @@ -0,0 +1,74 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { SharedModule } from 'primeng/api'; +import { CardComponent } from '../../../../lib/components/card/card.component'; +import { ButtonComponent } from '../../../../lib/components/button/button.component'; + +const template = ` +
+ + +
+ +
+
+ +

Карточка с тенью.

+
+ + + +
+
+`; +const styles = ''; + +@Component({ + selector: 'app-card-overlay', + standalone: true, + imports: [CardComponent, ButtonComponent, SharedModule], + template, + styles, +}) +export class CardOverlayComponent {} + +export const Overlay: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Карточка с тенью (overlay).' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { SharedModule } from 'primeng/api'; +import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-card-overlay', + standalone: true, + imports: [CardComponent, ButtonComponent, SharedModule], + template: \` + + +
+ +
+
+ +

Карточка с тенью.

+
+ + + +
+ \`, +}) +export class CardOverlayComponent {} + `, + }, + }, + }, +}; diff --git a/src/stories/components/card/examples/card-without-footer.component.ts b/src/stories/components/card/examples/card-without-footer.component.ts new file mode 100644 index 00000000..3257e18c --- /dev/null +++ b/src/stories/components/card/examples/card-without-footer.component.ts @@ -0,0 +1,67 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { SharedModule } from 'primeng/api'; +import { CardComponent } from '../../../../lib/components/card/card.component'; + +const template = ` +
+ + +
+ +
+
+ +

Карточка без футера.

+
+
+
+`; +const styles = ''; + +@Component({ + selector: 'app-card-without-footer', + standalone: true, + imports: [CardComponent, SharedModule], + template, + styles, +}) +export class CardWithoutFooterComponent {} + +export const WithoutFooter: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Карточка без футера с действиями.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { SharedModule } from 'primeng/api'; +import { CardComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-card-without-footer', + standalone: true, + imports: [CardComponent, SharedModule], + template: \` + + +
+ +
+
+ +

Карточка без футера.

+
+
+ \`, +}) +export class CardWithoutFooterComponent {} + `, + }, + }, + }, +}; diff --git a/src/stories/components/card/examples/card-without-header.component.ts b/src/stories/components/card/examples/card-without-header.component.ts new file mode 100644 index 00000000..2ea5acdf --- /dev/null +++ b/src/stories/components/card/examples/card-without-header.component.ts @@ -0,0 +1,64 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { SharedModule } from 'primeng/api'; +import { CardComponent } from '../../../../lib/components/card/card.component'; +import { ButtonComponent } from '../../../../lib/components/button/button.component'; + +const template = ` +
+ + +

Карточка без изображения в шапке.

+
+ + + +
+
+`; +const styles = ''; + +@Component({ + selector: 'app-card-without-header', + standalone: true, + imports: [CardComponent, ButtonComponent, SharedModule], + template, + styles, +}) +export class CardWithoutHeaderComponent {} + +export const WithoutHeader: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Карточка без изображения в шапке.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { SharedModule } from 'primeng/api'; +import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-card-without-header', + standalone: true, + imports: [CardComponent, ButtonComponent, SharedModule], + template: \` + + +

Карточка без изображения в шапке.

+
+ + + +
+ \`, +}) +export class CardWithoutHeaderComponent {} + `, + }, + }, + }, +}; diff --git a/src/stories/components/card/examples/card-without-subtitle.component.ts b/src/stories/components/card/examples/card-without-subtitle.component.ts new file mode 100644 index 00000000..17eb154d --- /dev/null +++ b/src/stories/components/card/examples/card-without-subtitle.component.ts @@ -0,0 +1,74 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { SharedModule } from 'primeng/api'; +import { CardComponent } from '../../../../lib/components/card/card.component'; +import { ButtonComponent } from '../../../../lib/components/button/button.component'; + +const template = ` +
+ + +
+ +
+
+ +

Карточка без подзаголовка.

+
+ + + +
+
+`; +const styles = ''; + +@Component({ + selector: 'app-card-without-subtitle', + standalone: true, + imports: [CardComponent, ButtonComponent, SharedModule], + template, + styles, +}) +export class CardWithoutSubtitleComponent {} + +export const WithoutSubtitle: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Карточка без подзаголовка.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { SharedModule } from 'primeng/api'; +import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-card-without-subtitle', + standalone: true, + imports: [CardComponent, ButtonComponent, SharedModule], + template: \` + + +
+ +
+
+ +

Карточка без подзаголовка.

+
+ + + +
+ \`, +}) +export class CardWithoutSubtitleComponent {} + `, + }, + }, + }, +}; From 6f0d72f862498b900895b9e0d6774026acb32d6e Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 8 Apr 2026 15:51:00 +0700 Subject: [PATCH 033/258] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=B1=D0=BB?= =?UTF-8?q?=D0=BE=D0=BA=D0=B0=20=D1=81=20=D0=B7=D0=B0=D0=B3=D0=BE=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=D0=BA=D0=B0=D0=BC=D0=B8=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D1=88=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/card/card.component.ts | 18 +++++++++++++----- src/prime-preset/tokens/components/card.ts | 7 +++++++ src/stories/components/card/card.stories.ts | 14 +++++++------- .../card/examples/card-overlay.component.ts | 6 +++--- .../examples/card-without-footer.component.ts | 4 ++-- .../examples/card-without-header.component.ts | 8 ++++---- .../card-without-subtitle.component.ts | 8 ++++---- 7 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/lib/components/card/card.component.ts b/src/lib/components/card/card.component.ts index 1192ce8c..e0354148 100644 --- a/src/lib/components/card/card.component.ts +++ b/src/lib/components/card/card.component.ts @@ -16,16 +16,24 @@ import { PrimeTemplate, SharedModule } from 'primeng/api'; standalone: true, imports: [Card, SharedModule, NgTemplateOutlet], template: ` - + @if (headerTpl) { } + @if (title || subtitle) { + +
+ @if (title) { +
{{ title }}
+ } + @if (subtitle) { +
{{ subtitle }}
+ } +
+
+ } @if (contentTpl) { diff --git a/src/prime-preset/tokens/components/card.ts b/src/prime-preset/tokens/components/card.ts index 57f5707f..7bfac62c 100644 --- a/src/prime-preset/tokens/components/card.ts +++ b/src/prime-preset/tokens/components/card.ts @@ -22,6 +22,13 @@ export const cardCss = ({ dt }: { dt: (token: string) => string }): string => ` box-shadow: ${dt('overlay.popover.shadow')}; } + /* ─── Caption (Title & Subtitle wrapper) ─── */ + .p-card-caption { + display: flex; + flex-direction: column; + gap: ${dt('card.caption.gap')}; + } + /* ─── Subtitle typography ─── */ .p-card-subtitle { font-family: ${dt('fonts.fontFamily.heading')}; diff --git a/src/stories/components/card/card.stories.ts b/src/stories/components/card/card.stories.ts index 16223bb4..4cb3a1ae 100644 --- a/src/stories/components/card/card.stories.ts +++ b/src/stories/components/card/card.stories.ts @@ -95,7 +95,7 @@ export const Default: Story = {

Контент карточки. Гибкая область для любого содержимого.

- + `; @@ -103,8 +103,8 @@ export const Default: Story = { return { props: args, template }; }, args: { - title: 'Title', - subtitle: 'Caption', + title: 'Заголовок', + subtitle: 'Подзаголовок', }, parameters: { docs: { @@ -136,7 +136,7 @@ import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [CardComponent, ButtonComponent, SharedModule], template: \` - +
@@ -179,7 +179,7 @@ import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [CardComponent, ButtonComponent, SharedModule], template: \` - +

Карточка без изображения в шапке.

@@ -217,7 +217,7 @@ import { CardComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [CardComponent, SharedModule], template: \` - +
@@ -257,7 +257,7 @@ import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [CardComponent, ButtonComponent, SharedModule], template: \` - +
diff --git a/src/stories/components/card/examples/card-overlay.component.ts b/src/stories/components/card/examples/card-overlay.component.ts index a4ea6b49..55b98410 100644 --- a/src/stories/components/card/examples/card-overlay.component.ts +++ b/src/stories/components/card/examples/card-overlay.component.ts @@ -6,7 +6,7 @@ import { ButtonComponent } from '../../../../lib/components/button/button.compon const template = `
- +
@@ -16,7 +16,7 @@ const template = `

Карточка с тенью.

- +
@@ -61,7 +61,7 @@ import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit';

Карточка с тенью.

- +
\`, diff --git a/src/stories/components/card/examples/card-without-footer.component.ts b/src/stories/components/card/examples/card-without-footer.component.ts index 3257e18c..00b806ca 100644 --- a/src/stories/components/card/examples/card-without-footer.component.ts +++ b/src/stories/components/card/examples/card-without-footer.component.ts @@ -5,7 +5,7 @@ import { CardComponent } from '../../../../lib/components/card/card.component'; const template = `
- +
@@ -47,7 +47,7 @@ import { CardComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [CardComponent, SharedModule], template: \` - +
diff --git a/src/stories/components/card/examples/card-without-header.component.ts b/src/stories/components/card/examples/card-without-header.component.ts index 2ea5acdf..e7a96254 100644 --- a/src/stories/components/card/examples/card-without-header.component.ts +++ b/src/stories/components/card/examples/card-without-header.component.ts @@ -6,12 +6,12 @@ import { ButtonComponent } from '../../../../lib/components/button/button.compon const template = `
- +

Карточка без изображения в шапке.

- +
@@ -46,12 +46,12 @@ import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [CardComponent, ButtonComponent, SharedModule], template: \` - +

Карточка без изображения в шапке.

- +
\`, diff --git a/src/stories/components/card/examples/card-without-subtitle.component.ts b/src/stories/components/card/examples/card-without-subtitle.component.ts index 17eb154d..414d26bf 100644 --- a/src/stories/components/card/examples/card-without-subtitle.component.ts +++ b/src/stories/components/card/examples/card-without-subtitle.component.ts @@ -6,7 +6,7 @@ import { ButtonComponent } from '../../../../lib/components/button/button.compon const template = `
- +
@@ -16,7 +16,7 @@ const template = `

Карточка без подзаголовка.

- +
@@ -51,7 +51,7 @@ import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [CardComponent, ButtonComponent, SharedModule], template: \` - +
@@ -61,7 +61,7 @@ import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit';

Карточка без подзаголовка.

- + \`, From 5003d558db9191cfb71f0004251066d1754292ea Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 8 Apr 2026 16:05:14 +0700 Subject: [PATCH 034/258] =?UTF-8?q?=D0=B8=D0=B7=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BC=D0=B0=D1=81=D0=BA=D0=BE?= =?UTF-8?q?=D1=82=D0=B0=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20placehold?= =?UTF-8?q?er?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/assets/mascot.jpg | Bin 0 -> 60421 bytes src/stories/components/card/card.stories.ts | 4 +--- .../card/examples/card-overlay.component.ts | 10 +++------- .../examples/card-without-footer.component.ts | 8 ++------ .../examples/card-without-subtitle.component.ts | 8 ++------ 5 files changed, 8 insertions(+), 22 deletions(-) create mode 100644 public/assets/mascot.jpg diff --git a/public/assets/mascot.jpg b/public/assets/mascot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..adb02e35f7348e8ce9e711fb7e9027825cd49f25 GIT binary patch literal 60421 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 literal 0 HcmV?d00001 diff --git a/src/stories/components/card/card.stories.ts b/src/stories/components/card/card.stories.ts index 4cb3a1ae..f685d36e 100644 --- a/src/stories/components/card/card.stories.ts +++ b/src/stories/components/card/card.stories.ts @@ -87,9 +87,7 @@ export const Default: Story = { const template = `

-
- -
+ Заголовок

Контент карточки. Гибкая область для любого содержимого.

diff --git a/src/stories/components/card/examples/card-overlay.component.ts b/src/stories/components/card/examples/card-overlay.component.ts index 55b98410..b2665463 100644 --- a/src/stories/components/card/examples/card-overlay.component.ts +++ b/src/stories/components/card/examples/card-overlay.component.ts @@ -8,9 +8,7 @@ const template = `
-
- -
+ Заголовок

Карточка с тенью.

@@ -51,11 +49,9 @@ import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [CardComponent, ButtonComponent, SharedModule], template: \` - + -
- -
+ Заголовок

Карточка с тенью.

diff --git a/src/stories/components/card/examples/card-without-footer.component.ts b/src/stories/components/card/examples/card-without-footer.component.ts index 00b806ca..e412af6b 100644 --- a/src/stories/components/card/examples/card-without-footer.component.ts +++ b/src/stories/components/card/examples/card-without-footer.component.ts @@ -7,9 +7,7 @@ const template = `
-
- -
+ Заголовок

Карточка без футера.

@@ -49,9 +47,7 @@ import { CardComponent } from '@cdek-it/angular-ui-kit'; template: \` -
- -
+ Заголовок

Карточка без футера.

diff --git a/src/stories/components/card/examples/card-without-subtitle.component.ts b/src/stories/components/card/examples/card-without-subtitle.component.ts index 414d26bf..0d7d91af 100644 --- a/src/stories/components/card/examples/card-without-subtitle.component.ts +++ b/src/stories/components/card/examples/card-without-subtitle.component.ts @@ -8,9 +8,7 @@ const template = `
-
- -
+ Заголовок

Карточка без подзаголовка.

@@ -53,9 +51,7 @@ import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; template: \` -
- -
+ Заголовок

Карточка без подзаголовка.

From c6a7ed0b90b3af0fd2215a4e38e6d244637ff112 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 8 Apr 2026 16:08:25 +0700 Subject: [PATCH 035/258] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D1=89=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D1=82=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D1=81=20=D0=B2=20=D0=B3=D1=80=D1=83=D0=BF=D0=BF=D1=83=20Panel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stories/components/card/card.stories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stories/components/card/card.stories.ts b/src/stories/components/card/card.stories.ts index f685d36e..1b9fc6f7 100644 --- a/src/stories/components/card/card.stories.ts +++ b/src/stories/components/card/card.stories.ts @@ -10,7 +10,7 @@ import { CardWithoutSubtitleComponent } from './examples/card-without-subtitle.c type CardArgs = CardComponent; const meta: Meta = { - title: 'Components/Card', + title: 'Components/Panel/Card', component: CardComponent, tags: ['autodocs'], decorators: [ From be033737b14c1642c7854c69423ae0055f7253fc Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 8 Apr 2026 16:33:36 +0700 Subject: [PATCH 036/258] =?UTF-8?q?divider:=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F,=20=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D1=81=D1=8B,=20=D0=BE=D0=B1=D1=91=D1=80=D1=82?= =?UTF-8?q?=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/divider/divider.component.ts | 26 +++ src/prime-preset/map-tokens.ts | 5 + src/prime-preset/tokens/components/divider.ts | 34 ++++ .../components/divider/divider.stories.ts | 176 ++++++++++++++++++ .../examples/divider-align-left.component.ts | 50 +++++ .../divider-with-content.component.ts | 50 +++++ .../examples/divider-with-icon.component.ts | 50 +++++ 7 files changed, 391 insertions(+) create mode 100644 src/lib/components/divider/divider.component.ts create mode 100644 src/prime-preset/tokens/components/divider.ts create mode 100644 src/stories/components/divider/divider.stories.ts create mode 100644 src/stories/components/divider/examples/divider-align-left.component.ts create mode 100644 src/stories/components/divider/examples/divider-with-content.component.ts create mode 100644 src/stories/components/divider/examples/divider-with-icon.component.ts diff --git a/src/lib/components/divider/divider.component.ts b/src/lib/components/divider/divider.component.ts new file mode 100644 index 00000000..20d634f5 --- /dev/null +++ b/src/lib/components/divider/divider.component.ts @@ -0,0 +1,26 @@ +import { Component, Input } from '@angular/core'; +import { Divider } from 'primeng/divider'; + +export type DividerLayout = 'horizontal' | 'vertical'; +export type DividerType = 'solid' | 'dashed' | 'dotted'; +export type DividerAlign = 'left' | 'center' | 'right' | 'top' | 'bottom'; + +@Component({ + selector: 'divider', + standalone: true, + imports: [Divider], + template: ` + + + + `, +}) +export class DividerComponent { + @Input() layout: DividerLayout = 'horizontal'; + @Input() type: DividerType = 'solid'; + @Input() align: DividerAlign = 'center'; +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 39627587..a70f34c4 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 { dividerCss } from './tokens/components/divider'; const presetTokens: Preset = { primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'], @@ -14,6 +15,10 @@ const presetTokens: Preset = { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), css: buttonCss, }, + divider: { + ...(tokens.components.divider as unknown as ComponentsDesignTokens['divider']), + css: dividerCss, + }, } as ComponentsDesignTokens, }; diff --git a/src/prime-preset/tokens/components/divider.ts b/src/prime-preset/tokens/components/divider.ts new file mode 100644 index 00000000..8661e435 --- /dev/null +++ b/src/prime-preset/tokens/components/divider.ts @@ -0,0 +1,34 @@ +/** + * Кастомная CSS-стилизация для компонента p-divider. + * Публикует extend-токены как CSS-переменные и применяет глобальные стили. + * Подключается в map-tokens.ts: `import { dividerCss } from './components/divider'` + */ +export const dividerCss = ({ dt }: { dt: (token: string) => string }): string => ` + /* ─── Divider extend: публикуем кастомные переменные в :root ─── */ + :root { + --p-divider-extend-content-gap: ${dt('divider.extend.content.gap')}; + --p-divider-extend-icon-size: ${dt('divider.extend.iconSize')}; + } + + /* ─── Контент разделителя ─── */ + .p-divider-content { + display: flex; + align-items: center; + gap: var(--p-divider-extend-content-gap); + font-family: ${dt('fonts.fontFamily.heading')}; + font-size: ${dt('fonts.fontSize.200')}; + font-weight: ${dt('fonts.fontWeight.regular')}; + } + + .p-divider-content .ti { + font-size: var(--p-divider-extend-icon-size); + } + + /* ─── Вертикальное выравнивание ─── */ + .p-divider.p-divider-vertical.p-divider-top .p-divider-content { + align-items: flex-start; + } + .p-divider.p-divider-vertical.p-divider-bottom .p-divider-content { + align-items: flex-end; + } +`; diff --git a/src/stories/components/divider/divider.stories.ts b/src/stories/components/divider/divider.stories.ts new file mode 100644 index 00000000..f5a2c62f --- /dev/null +++ b/src/stories/components/divider/divider.stories.ts @@ -0,0 +1,176 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { DividerComponent } from '../../../lib/components/divider/divider.component'; +import { DividerWithContentComponent, WithContent as WithContentStory } from './examples/divider-with-content.component'; +import { DividerWithIconComponent, WithIcon as WithIconStory } from './examples/divider-with-icon.component'; +import { DividerAlignLeftComponent, AlignLeft as AlignLeftStory } from './examples/divider-align-left.component'; + +const meta: Meta = { + title: 'Components/Panel/Divider', + component: DividerComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + DividerComponent, + DividerWithContentComponent, + DividerWithIconComponent, + DividerAlignLeftComponent, + ], + }), + ], + parameters: { + docs: { + description: { + component: `Разделитель для визуального разделения контента. Поддерживает горизонтальную и вертикальную ориентацию, различные стили линии и выравнивание. + +\`\`\`typescript +import { DividerModule } from 'primeng/divider'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-divider' }, + }, + argTypes: { + layout: { + control: 'select', + options: ['horizontal', 'vertical'], + description: 'Ориентация разделителя', + table: { + category: 'Props', + defaultValue: { summary: 'horizontal' }, + type: { summary: "'horizontal' | 'vertical'" }, + }, + }, + type: { + control: 'select', + options: ['solid', 'dashed', 'dotted'], + description: 'Стиль линии разделителя', + table: { + category: 'Props', + defaultValue: { summary: 'solid' }, + type: { summary: "'solid' | 'dashed' | 'dotted'" }, + }, + }, + align: { + control: 'select', + options: ['left', 'center', 'right', 'top', 'bottom'], + description: 'Выравнивание контента внутри разделителя', + table: { + category: 'Props', + defaultValue: { summary: 'center' }, + type: { summary: "'left' | 'center' | 'right' | 'top' | 'bottom'" }, + }, + }, + }, +}; + +const commonTemplate = ` + +`; + +export default meta; +type Story = StoryObj; + +// ── Default ─────────────────────────────────────────────────────────────────── + +export const Default: Story = { + name: 'Default', + render: (args) => { + const parts: string[] = []; + + if (args.layout && args.layout !== 'horizontal') parts.push(`layout="${args.layout}"`); + if (args.type && args.type !== 'solid') parts.push(`type="${args.type}"`); + if (args.align && args.align !== 'center') parts.push(`align="${args.align}"`); + + const template = parts.length + ? `` + : ``; + + return { props: args, template }; + }, + args: { + layout: 'horizontal', + type: 'solid', + align: 'center', + }, + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + }, + }, +}; + +// ── WithContent ─────────────────────────────────────────────────────────────── + +export const WithContent: Story = WithContentStory; + +// ── WithIcon ────────────────────────────────────────────────────────────────── + +export const WithIcon: Story = WithIconStory; + +// ── Vertical ────────────────────────────────────────────────────────────────── + +export const Vertical: Story = { + render: (args) => ({ props: args, template: commonTemplate }), + args: { + layout: 'vertical', + type: 'solid', + align: 'center', + }, + parameters: { + docs: { + description: { story: 'Вертикальный разделитель для разделения контента по горизонтали.' }, + source: { + code: ``, + }, + }, + }, +}; + +// ── Type ────────────────────────────────────────────────────────────────────── + +export const TypeDashed: Story = { + name: 'Dashed', + render: (args) => ({ props: args, template: commonTemplate }), + args: { + layout: 'horizontal', + type: 'dashed', + align: 'center', + }, + parameters: { + docs: { + description: { story: 'Разделитель с пунктирной линией.' }, + source: { + code: ``, + }, + }, + }, +}; + +export const TypeDotted: Story = { + name: 'Dotted', + render: (args) => ({ props: args, template: commonTemplate }), + args: { + layout: 'horizontal', + type: 'dotted', + align: 'center', + }, + parameters: { + docs: { + description: { story: 'Разделитель с точечной линией.' }, + source: { + code: ``, + }, + }, + }, +}; + +// ── Align ───────────────────────────────────────────────────────────────────── + +export const AlignLeft: Story = AlignLeftStory; diff --git a/src/stories/components/divider/examples/divider-align-left.component.ts b/src/stories/components/divider/examples/divider-align-left.component.ts new file mode 100644 index 00000000..244e3d44 --- /dev/null +++ b/src/stories/components/divider/examples/divider-align-left.component.ts @@ -0,0 +1,50 @@ +import { Component } from '@angular/core'; +import { DividerComponent } from '../../../../lib/components/divider/divider.component'; + +const template = ` +
+ + Отправитель + +
+`; +const styles = ''; + +@Component({ + selector: 'app-divider-align-left', + standalone: true, + imports: [DividerComponent], + template, + styles, +}) +export class DividerAlignLeftComponent {} + +export const AlignLeft = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Контент разделителя выровнен по левому краю.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DividerComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-divider-align-left', + standalone: true, + imports: [DividerComponent], + template: \` + + Отправитель + + \`, +}) +export class DividerAlignLeftComponent {} + `, + }, + }, + }, +}; diff --git a/src/stories/components/divider/examples/divider-with-content.component.ts b/src/stories/components/divider/examples/divider-with-content.component.ts new file mode 100644 index 00000000..b1b0b80f --- /dev/null +++ b/src/stories/components/divider/examples/divider-with-content.component.ts @@ -0,0 +1,50 @@ +import { Component } from '@angular/core'; +import { DividerComponent } from '../../../../lib/components/divider/divider.component'; + +const template = ` +
+ + Москва → Новосибирск + +
+`; +const styles = ''; + +@Component({ + selector: 'app-divider-with-content', + standalone: true, + imports: [DividerComponent], + template, + styles, +}) +export class DividerWithContentComponent {} + +export const WithContent = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Разделитель с текстовым контентом по центру.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DividerComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-divider-with-content', + standalone: true, + imports: [DividerComponent], + template: \` + + Москва → Новосибирск + + \`, +}) +export class DividerWithContentComponent {} + `, + }, + }, + }, +}; diff --git a/src/stories/components/divider/examples/divider-with-icon.component.ts b/src/stories/components/divider/examples/divider-with-icon.component.ts new file mode 100644 index 00000000..95d79871 --- /dev/null +++ b/src/stories/components/divider/examples/divider-with-icon.component.ts @@ -0,0 +1,50 @@ +import { Component } from '@angular/core'; +import { DividerComponent } from '../../../../lib/components/divider/divider.component'; + +const template = ` +
+ + + +
+`; +const styles = ''; + +@Component({ + selector: 'app-divider-with-icon', + standalone: true, + imports: [DividerComponent], + template, + styles, +}) +export class DividerWithIconComponent {} + +export const WithIcon = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Разделитель с иконкой.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DividerComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-divider-with-icon', + standalone: true, + imports: [DividerComponent], + template: \` + + + + \`, +}) +export class DividerWithIconComponent {} + `, + }, + }, + }, +}; From 4a2067514c6aea4fb03191b7570e8de746f5f394 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 8 Apr 2026 19:10:07 +0700 Subject: [PATCH 037/258] =?UTF-8?q?chip:=20=D1=81=D1=82=D0=B8=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F,=20=D1=81=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B8=D1=81=D1=8B,=20=D0=BE=D0=B1=D1=91=D1=80=D1=82=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/CLAUDE-v1.5.md | 730 ++++++++++++++++++ src/lib/components/chip/chip.component.ts | 24 + src/prime-preset/map-tokens.ts | 5 + src/prime-preset/tokens/components/chip.ts | 45 ++ src/stories/components/chip/chip.stories.ts | 144 ++++ .../chip/examples/chip-disabled.component.ts | 46 ++ .../chip-removable-with-icon.component.ts | 46 ++ .../chip/examples/chip-removable.component.ts | 46 ++ .../chip/examples/chip-with-icon.component.ts | 46 ++ 9 files changed, 1132 insertions(+) create mode 100644 .claude/CLAUDE-v1.5.md create mode 100644 src/lib/components/chip/chip.component.ts create mode 100644 src/prime-preset/tokens/components/chip.ts create mode 100644 src/stories/components/chip/chip.stories.ts create mode 100644 src/stories/components/chip/examples/chip-disabled.component.ts create mode 100644 src/stories/components/chip/examples/chip-removable-with-icon.component.ts create mode 100644 src/stories/components/chip/examples/chip-removable.component.ts create mode 100644 src/stories/components/chip/examples/chip-with-icon.component.ts diff --git a/.claude/CLAUDE-v1.5.md b/.claude/CLAUDE-v1.5.md new file mode 100644 index 00000000..cad6ce01 --- /dev/null +++ b/.claude/CLAUDE-v1.5.md @@ -0,0 +1,730 @@ +# 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"` (статичный шаблон) | +| ``; + 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"` (статичный шаблон) | +| `
`; - 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"` (статичный шаблон) | -| ``; - 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"` (статичный шаблон) | -| ``; - 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"` (статичный шаблон) | -| ` + } +
+ + + `, +}) +export class MessageComponent { + @Input() severity: MessageSeverity = 'info'; + @Input() summary = ''; + @Input() detail = ''; + @Input() icon: string | undefined = undefined; + @Input() closable = false; + @Input() life: number | undefined = undefined; + + @Output() onClose = new EventEmitter(); + + get resolvedIcon(): string { + return this.icon ?? SEVERITY_ICONS[this.severity] ?? 'ti ti-info-circle'; + } +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index a5dd6347..67f9dd9d 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -5,6 +5,7 @@ import type { AuraBaseDesignTokens } from '@primeuix/themes/aura/base'; import tokens from './tokens/tokens.json'; import { avatarCss } from './tokens/components/avatar'; import { buttonCss } from './tokens/components/button'; +import { messageCss } from './tokens/components/message'; import { tooltipCss } from './tokens/components/tooltip'; const presetTokens: Preset = { @@ -20,6 +21,10 @@ const presetTokens: Preset = { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), css: buttonCss, }, + message: { + ...(tokens.components.message as unknown as ComponentsDesignTokens['message']), + css: messageCss, + }, tooltip: { ...(tokens.components.tooltip as unknown as ComponentsDesignTokens['tooltip']), css: tooltipCss, diff --git a/src/prime-preset/tokens/components/message.ts b/src/prime-preset/tokens/components/message.ts new file mode 100644 index 00000000..084edd4f --- /dev/null +++ b/src/prime-preset/tokens/components/message.ts @@ -0,0 +1,151 @@ +export const messageCss = ({ dt }: { dt: (token: string) => string }): string => ` + /* Основной контейнер message */ + .p-message { + width: ${dt('message.extend.width')}; + overflow: hidden; + position: relative; + } + + /* border-radius для контента message */ + .p-message .p-message-content { + border-radius: ${dt('message.root.borderRadius')}; + } + + /* Контент message с приоритизацией align-items */ + .p-message .p-message-content { + display: flex; + align-items: flex-start; + } + + /* Текстовый блок message */ + .p-message-text { + flex: 1; + display: flex; + flex-direction: column; + gap: ${dt('message.extend.extText.gap')}; + } + + /* Заголовок message */ + .p-message-summary { + font-weight: ${dt('message.text.fontWeight')}; + line-height: ${dt('fonts.lineHeight.250')}; + font-size: ${dt('message.text.fontSize')}; + } + + /* Детальное описание message */ + .p-message .p-message-detail { + font-size: ${dt('fonts.fontSize.200')}; + line-height: ${dt('fonts.lineHeight.250')}; + font-weight: ${dt('fonts.fontWeight.regular')}; + } + + /* Кнопка закрытия message */ + .p-message .p-message-content .p-message-close-button { + width: ${dt('message.closeButton.width')}; + height: ${dt('message.closeButton.height')}; + margin: 0; + padding: 0; + right: 0; + } + + /* Общие стили border для кнопки закрытия всех типов message */ + .p-message-info .p-message-close-button, + .p-message-success .p-message-close-button, + .p-message-warn .p-message-close-button, + .p-message-error .p-message-close-button { + border: ${dt('message.extend.extCloseButton.width')} solid; + } + + /* Общие стили для акцентной линии всех типов message */ + .p-message-info .p-message-accent-line, + .p-message-success .p-message-accent-line, + .p-message-warn .p-message-accent-line, + .p-message-error .p-message-accent-line { + width: ${dt('message.extend.extAccentLine.width')}; + position: absolute; + left: 0; + top: 0; + bottom: 0; + border-radius: ${dt('message.root.borderRadius')} 0 0 ${dt('message.root.borderRadius')}; + } + + /* Стили для message типа Info */ + .p-message-info .p-message-icon { + color: ${dt('message.extend.extInfo.color')}; + } + + .p-message-info .p-message-close-button { + color: ${dt('message.extend.extInfo.closeButton.color')}; + border-color: ${dt('message.extend.extInfo.closeButton.borderColor')}; + } + + .p-message.p-message-info .p-message-close-button.p-button-text:not(:disabled):hover { + background: ${dt('message.colorScheme.light.info.closeButton.hoverBackground')}; + border-color: ${dt('message.extend.extInfo.closeButton.borderColor')}; + color: ${dt('message.extend.extInfo.closeButton.color')}; + } + + .p-message-info .p-message-accent-line { + background: ${dt('message.extend.extInfo.color')}; + } + + /* Стили для message типа Success */ + .p-message-success .p-message-icon { + color: ${dt('message.extend.extSuccess.color')}; + } + + .p-message-success .p-message-close-button { + color: ${dt('message.extend.extSuccess.closeButton.color')}; + border-color: ${dt('message.extend.extSuccess.closeButton.borderColor')}; + } + + .p-message.p-message-success .p-message-close-button.p-button-text:not(:disabled):hover { + background: ${dt('message.colorScheme.light.success.closeButton.hoverBackground')}; + border-color: ${dt('message.extend.extSuccess.closeButton.borderColor')}; + color: ${dt('message.extend.extSuccess.closeButton.color')}; + } + + .p-message-success .p-message-accent-line { + background: ${dt('message.extend.extSuccess.color')}; + } + + /* Стили для message типа Warn */ + .p-message-warn .p-message-icon { + color: ${dt('message.extend.extWarn.color')}; + } + + .p-message-warn .p-message-close-button { + color: ${dt('message.extend.extWarn.closeButton.color')}; + border-color: ${dt('message.extend.extWarn.closeButton.borderColor')}; + } + + .p-message.p-message-warn .p-message-close-button.p-button-text:not(:disabled):hover { + background: ${dt('message.colorScheme.light.warn.closeButton.hoverBackground')}; + border-color: ${dt('message.extend.extWarn.closeButton.borderColor')}; + color: ${dt('message.extend.extWarn.closeButton.color')}; + } + + .p-message-warn .p-message-accent-line { + background: ${dt('message.extend.extWarn.color')}; + } + + /* Стили для message типа Error */ + .p-message-error .p-message-icon { + color: ${dt('message.extend.extError.color')}; + } + + .p-message-error .p-message-close-button { + color: ${dt('message.extend.extError.closeButton.color')}; + border-color: ${dt('message.extend.extError.closeButton.borderColor')}; + } + + .p-message.p-message-error .p-message-close-button.p-button-text:not(:disabled):hover { + background: ${dt('message.colorScheme.light.error.closeButton.hoverBackground')}; + border-color: ${dt('message.extend.extError.closeButton.borderColor')}; + color: ${dt('message.extend.extError.closeButton.color')}; + } + + .p-message-error .p-message-accent-line { + background: ${dt('message.extend.extError.color')}; + } +`; diff --git a/src/stories/components/message/examples/message-severities.component.ts b/src/stories/components/message/examples/message-severities.component.ts new file mode 100644 index 00000000..9a42e4a8 --- /dev/null +++ b/src/stories/components/message/examples/message-severities.component.ts @@ -0,0 +1,41 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { MessageComponent } from '../../../../lib/components/message/message.component'; + +const template = ` +
+ + + + +
+`; + +@Component({ + selector: 'app-message-severities', + standalone: true, + imports: [MessageComponent], + template, +}) +export class MessageSeveritiesComponent {} + +export const Severities: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { story: 'Четыре типа сообщений: информация, успех, предупреждение, ошибка.' }, + source: { + language: 'html', + code: ` + + + + + `, + }, + }, + }, +}; diff --git a/src/stories/components/message/examples/message-with-close-button.component.ts b/src/stories/components/message/examples/message-with-close-button.component.ts new file mode 100644 index 00000000..a1195a18 --- /dev/null +++ b/src/stories/components/message/examples/message-with-close-button.component.ts @@ -0,0 +1,36 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { MessageComponent } from '../../../../lib/components/message/message.component'; + +const template = ` +
+ + + + +
+`; + +@Component({ + selector: 'app-message-with-close-button', + standalone: true, + imports: [MessageComponent], + template, +}) +export class MessageWithCloseButtonComponent {} + +export const WithCloseButton: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { story: 'Сообщения с кнопкой закрытия.' }, + source: { + language: 'html', + code: ``, + }, + }, + }, +}; diff --git a/src/stories/components/message/examples/message-with-content.component.ts b/src/stories/components/message/examples/message-with-content.component.ts new file mode 100644 index 00000000..5e42c03f --- /dev/null +++ b/src/stories/components/message/examples/message-with-content.component.ts @@ -0,0 +1,78 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { MessageComponent } from '../../../../lib/components/message/message.component'; + +const template = ` +
+ +
+
CONTENT
+
+
+
Cell 1
+
Cell 2
+
+
+ +
+
CONTENT
+
+
+
Cell 1
+
Cell 2
+
+
+ +
+
CONTENT
+
+
+
Cell 1
+
Cell 2
+
+
+ +
+
CONTENT
+
+
+
Cell 1
+
Cell 2
+
+
+
+`; + +@Component({ + selector: 'app-message-with-content', + standalone: true, + imports: [MessageComponent], + template, +}) +export class MessageWithContentComponent {} + +export const WithContent: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { story: 'Сообщения с дополнительным контентом и кнопкой закрытия.' }, + source: { + language: 'html', + code: ` + +
+
CONTENT
+
+
+
Cell 1
+
Cell 2
+
+
+ `, + }, + }, + }, +}; diff --git a/src/stories/components/message/message.stories.ts b/src/stories/components/message/message.stories.ts new file mode 100644 index 00000000..608d38f0 --- /dev/null +++ b/src/stories/components/message/message.stories.ts @@ -0,0 +1,125 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { MessageComponent } from '../../../lib/components/message/message.component'; +import { MessageSeveritiesComponent, Severities } from './examples/message-severities.component'; +import { MessageWithCloseButtonComponent, WithCloseButton } from './examples/message-with-close-button.component'; +import { MessageWithContentComponent, WithContent } from './examples/message-with-content.component'; + +type MessageArgs = MessageComponent; + +const meta: Meta = { + title: 'Components/Feedback/Message', + component: MessageComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + MessageComponent, + MessageSeveritiesComponent, + MessageWithCloseButtonComponent, + MessageWithContentComponent, + ], + }), + ], + parameters: { + designTokens: { prefix: '--p-message' }, + docs: { + description: { + component: `Компонент для отображения встроенных уведомлений с различными уровнями важности. + +\`\`\`typescript +import { MessageComponent } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + }, + argTypes: { + // ── Props ──────────────────────────────────────────────── + severity: { + control: 'select', + options: ['info', 'success', 'warn', 'error', 'secondary', 'contrast'], + description: 'Тип сообщения.', + table: { + category: 'Props', + defaultValue: { summary: 'info' }, + type: { summary: "'info' | 'success' | 'warn' | 'error' | 'secondary' | 'contrast'" }, + }, + }, + summary: { + control: 'text', + description: 'Заголовок сообщения.', + table: { category: 'Props', type: { summary: 'string' } }, + }, + detail: { + control: 'text', + description: 'Подробный текст сообщения.', + table: { category: 'Props', type: { summary: 'string' } }, + }, + icon: { + control: 'text', + description: 'CSS-класс иконки. По умолчанию подбирается по severity.', + table: { category: 'Props', type: { summary: 'string' } }, + }, + closable: { + control: 'boolean', + description: 'Показывает кнопку закрытия.', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + life: { + control: 'number', + description: 'Время автоматического закрытия в миллисекундах. 0 — отключено.', + table: { + category: 'Props', + defaultValue: { summary: '0' }, + type: { summary: 'number' }, + }, + }, + // ── Events ─────────────────────────────────────────────── + onClose: { + control: false, + description: 'Событие закрытия сообщения.', + table: { + category: 'Events', + type: { summary: 'EventEmitter' }, + }, + }, + }, + args: { + severity: 'info', + summary: 'Message', + detail: 'caption', + closable: false, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ────────────────────────────────────────────────────────────────── +export const Default: Story = { + name: 'Default', + render: (args) => { + const parts: string[] = [`severity="${args.severity}"`]; + if (args.summary) parts.push(`summary="${args.summary}"`); + if (args.detail) parts.push(`detail="${args.detail}"`); + if (args.icon) parts.push(`icon="${args.icon}"`); + if (args.closable) parts.push(`[closable]="true"`); + if (args.life) parts.push(`[life]="${args.life}"`); + + const template = ``; + return { props: args, template }; + }, + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + }, + }, +}; + +// ── Вариации ───────────────────────────────────────────────────────────────── +export { Severities, WithCloseButton, WithContent }; From fb55a4a8eeed91c6c550edb49710afb4792192f6 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 15 Apr 2026 13:40:18 +0700 Subject: [PATCH 088/258] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BD=20=D0=B4?= =?UTF-8?q?=D1=83=D0=B1=D0=BB=D1=8C=20wrapper;=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=20`font-family:=20PT=20Sans`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/CLAUDE-v1.6.md | 751 ------------------ .../components/message/message.component.ts | 36 +- src/prime-preset/tokens/components/message.ts | 9 +- 3 files changed, 21 insertions(+), 775 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"` (статичный шаблон) | -| ` +
+ +
+ {{ summary }} + @if (detail) { +
{{ detail }}
} +
+ @if (closable) { + + } `, diff --git a/src/prime-preset/tokens/components/message.ts b/src/prime-preset/tokens/components/message.ts index 084edd4f..6e39b2bc 100644 --- a/src/prime-preset/tokens/components/message.ts +++ b/src/prime-preset/tokens/components/message.ts @@ -6,15 +6,12 @@ export const messageCss = ({ dt }: { dt: (token: string) => string }): string => position: relative; } - /* border-radius для контента message */ - .p-message .p-message-content { - border-radius: ${dt('message.root.borderRadius')}; - } - /* Контент message с приоритизацией align-items */ .p-message .p-message-content { display: flex; align-items: flex-start; + width: stretch; + border-radius: ${dt('message.root.borderRadius')}; } /* Текстовый блок message */ @@ -27,6 +24,7 @@ export const messageCss = ({ dt }: { dt: (token: string) => string }): string => /* Заголовок message */ .p-message-summary { + font-family: ${dt('fonts.fontFamily.base')}; font-weight: ${dt('message.text.fontWeight')}; line-height: ${dt('fonts.lineHeight.250')}; font-size: ${dt('message.text.fontSize')}; @@ -34,6 +32,7 @@ export const messageCss = ({ dt }: { dt: (token: string) => string }): string => /* Детальное описание message */ .p-message .p-message-detail { + font-family: ${dt('fonts.fontFamily.base')}; font-size: ${dt('fonts.fontSize.200')}; line-height: ${dt('fonts.lineHeight.250')}; font-weight: ${dt('fonts.fontWeight.regular')}; From 699e0927ca161cc2773bcee7f1c2c87b8bcdb8ca Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 15 Apr 2026 13:42:13 +0700 Subject: [PATCH 089/258] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20fonts.fontWe?= =?UTF-8?q?ight.regular?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/divider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prime-preset/tokens/components/divider.ts b/src/prime-preset/tokens/components/divider.ts index 8661e435..de3e3581 100644 --- a/src/prime-preset/tokens/components/divider.ts +++ b/src/prime-preset/tokens/components/divider.ts @@ -17,7 +17,7 @@ export const dividerCss = ({ dt }: { dt: (token: string) => string }): string => gap: var(--p-divider-extend-content-gap); font-family: ${dt('fonts.fontFamily.heading')}; font-size: ${dt('fonts.fontSize.200')}; - font-weight: ${dt('fonts.fontWeight.regular')}; + font-weight: ${dt('fonts.fontWeight.demibold')}; } .p-divider-content .ti { From d199df911b1b5c431a1fc3e4a19e6071c52dbcb4 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 15 Apr 2026 14:28:17 +0700 Subject: [PATCH 090/258] =?UTF-8?q?toast:=20=D1=81=D1=82=D0=B8=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F,=20=D1=81=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B8=D1=81=D1=8B,=20=D0=BE=D0=B1=D1=91=D1=80=D1=82=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/CLAUDE-v1.6.md | 751 ------------------ src/lib/components/toast/toast.component.ts | 51 ++ src/prime-preset/map-tokens.ts | 6 + src/prime-preset/tokens/components/toast.ts | 144 ++++ .../toast/examples/toast-default.component.ts | 79 ++ .../examples/toast-position.component.ts | 83 ++ .../examples/toast-severities.component.ts | 117 +++ .../toast/examples/toast-width.component.ts | 97 +++ .../toast-with-close-button.component.ts | 105 +++ .../examples/toast-with-content.component.ts | 123 +++ src/stories/components/toast/toast.stories.ts | 123 +++ 11 files changed, 928 insertions(+), 751 deletions(-) delete mode 100644 .claude/CLAUDE-v1.6.md create mode 100644 src/lib/components/toast/toast.component.ts create mode 100644 src/prime-preset/tokens/components/toast.ts create mode 100644 src/stories/components/toast/examples/toast-default.component.ts create mode 100644 src/stories/components/toast/examples/toast-position.component.ts create mode 100644 src/stories/components/toast/examples/toast-severities.component.ts create mode 100644 src/stories/components/toast/examples/toast-width.component.ts create mode 100644 src/stories/components/toast/examples/toast-with-close-button.component.ts create mode 100644 src/stories/components/toast/examples/toast-with-content.component.ts create mode 100644 src/stories/components/toast/toast.stories.ts 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"` (статичный шаблон) | -| ` + \`, +}) +export class ExampleComponent { + constructor(private messageService: MessageService) {} + + show(): void { + this.messageService.add({ + group: 'my-toast', + severity: 'info', + summary: 'Сообщение', + detail: 'Подпись', + life: 5000, + icon: 'ti ti-info-circle', + }); + } +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/toast/examples/toast-width.component.ts b/src/stories/components/toast/examples/toast-width.component.ts new file mode 100644 index 00000000..70e81593 --- /dev/null +++ b/src/stories/components/toast/examples/toast-width.component.ts @@ -0,0 +1,97 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { Toast } from 'primeng/toast'; +import { Button } from 'primeng/button'; +import { MessageService, SharedModule } from 'primeng/api'; + +const SIZES = [ + { key: 'sm', label: 'Small (20rem)', width: '20rem' }, + { key: 'base', label: 'Base (25rem)', width: '25rem' }, + { key: 'lg', label: 'Large (30rem)', width: '30rem' }, + { key: 'xlg', label: 'X-Large (45rem)', width: '45rem' }, +] as const; + +@Component({ + selector: 'app-toast-width', + standalone: true, + imports: [Toast, Button, SharedModule], + providers: [MessageService], + template: ` + + +
+ +
+ {{ message.summary }} +
{{ message.detail }}
+
+
+
+ +
+ @for (s of sizes; track s.key) { +
+
+
+ +
+ Сообщение +
Ширина {{ s.key }}: {{ s.width }}
+
+
+
+ } +
+ +
+ @for (s of sizes; track s.key) { + + } +
+ `, +}) +export class ToastWidthComponent { + readonly sizes = SIZES; + currentWidth = '25rem'; + + constructor(private readonly messageService: MessageService) {} + + show(width: string): void { + this.currentWidth = width; + this.messageService.clear('width-preview'); + this.messageService.add({ + key: 'width-preview', + severity: 'info', + summary: 'Сообщение', + detail: 'Ширина: ' + width, + life: 3000, + icon: 'ti ti-info-circle', + }); + } +} + +export const Width: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Ширина задаётся через CSS-переменную `--p-toast-width` с помощью пропа `pt`.' }, + source: { + language: 'html', + code: ` + + ... + + `, + }, + }, + }, +}; diff --git a/src/stories/components/toast/examples/toast-with-close-button.component.ts b/src/stories/components/toast/examples/toast-with-close-button.component.ts new file mode 100644 index 00000000..821a75eb --- /dev/null +++ b/src/stories/components/toast/examples/toast-with-close-button.component.ts @@ -0,0 +1,105 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { Toast } from 'primeng/toast'; +import { Button } from 'primeng/button'; +import { MessageService, SharedModule } from 'primeng/api'; + +const SEVERITIES = [ + { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, + { type: 'success', icon: 'ti ti-circle-check', label: 'Успех' }, + { type: 'warn', icon: 'ti ti-alert-triangle', label: 'Предупреждение' }, + { type: 'error', icon: 'ti ti-alert-circle', label: 'Ошибка' }, +] as const; + +@Component({ + selector: 'app-toast-with-close-button', + standalone: true, + imports: [Toast, Button, SharedModule], + providers: [MessageService], + template: ` + + +
+ +
+ {{ message.summary }} +
{{ message.detail }}
+
+
+
+ +
+ @for (s of severities; track s.type) { +
+
+
+ +
+ Сообщение +
Подпись
+
+ +
+
+ } +
+ +
+ @for (s of severities; track s.type) { + + } +
+ `, +}) +export class ToastWithCloseButtonComponent { + readonly severities = SEVERITIES; + + constructor(private readonly messageService: MessageService) {} + + show(severity: string, icon: string): void { + this.messageService.add({ + key: 'with-close', + severity, + summary: 'Сообщение', + detail: 'Подпись', + life: 5000, + icon, + closable: true, + }); + } +} + +export const WithCloseButton: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Уведомления с кнопкой закрытия (closable: true).' }, + source: { + language: 'ts', + code: ` +this.messageService.add({ + group: 'my-toast', + severity: 'info', + summary: 'Сообщение', + detail: 'Подпись', + life: 5000, + icon: 'ti ti-info-circle', + closable: true, +}); + `, + }, + }, + }, +}; diff --git a/src/stories/components/toast/examples/toast-with-content.component.ts b/src/stories/components/toast/examples/toast-with-content.component.ts new file mode 100644 index 00000000..6f4453af --- /dev/null +++ b/src/stories/components/toast/examples/toast-with-content.component.ts @@ -0,0 +1,123 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { Toast } from 'primeng/toast'; +import { Button } from 'primeng/button'; +import { MessageService, SharedModule } from 'primeng/api'; + +const SEVERITIES = [ + { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, + { type: 'success', icon: 'ti ti-circle-check', label: 'Успех' }, + { type: 'warn', icon: 'ti ti-alert-triangle', label: 'Предупреждение' }, + { type: 'error', icon: 'ti ti-alert-circle', label: 'Ошибка' }, +] as const; + +@Component({ + selector: 'app-toast-with-content', + standalone: true, + imports: [Toast, Button, SharedModule], + providers: [MessageService], + template: ` + + +
+ +
+ {{ message.summary }} +
{{ message.detail }}
+
+
Дополнительный контент
+
+
+
Ячейка 1
+
Ячейка 2
+
+
+
+
+ +
+ @for (s of severities; track s.type) { +
+
+
+ +
+ Сообщение +
Подпись
+
+
Дополнительный контент
+
+
+
Ячейка 1
+
Ячейка 2
+
+
+ +
+
+ } +
+ +
+ @for (s of severities; track s.type) { + + } +
+ `, +}) +export class ToastWithContentComponent { + readonly severities = SEVERITIES; + + constructor(private readonly messageService: MessageService) {} + + show(severity: string, icon: string): void { + this.messageService.add({ + key: 'with-content', + severity, + summary: 'Сообщение', + detail: 'Подпись', + life: 5000, + icon, + closable: true, + }); + } +} + +export const WithContent: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Уведомления с дополнительным контентом под заголовком.' }, + source: { + language: 'html', + code: ` + + +
+ +
+ {{ message.summary }} +
{{ message.detail }}
+
+
Дополнительный контент
+
+
+
+
+ `, + }, + }, + }, +}; diff --git a/src/stories/components/toast/toast.stories.ts b/src/stories/components/toast/toast.stories.ts new file mode 100644 index 00000000..74f3aca7 --- /dev/null +++ b/src/stories/components/toast/toast.stories.ts @@ -0,0 +1,123 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { MessageService } from 'primeng/api'; +import { Toast } from 'primeng/toast'; +import { Button } from 'primeng/button'; +import { ToastComponent } from '../../../lib/components/toast/toast.component'; +import { ToastDefaultComponent } from './examples/toast-default.component'; +import { ToastSeveritiesComponent, Severities } from './examples/toast-severities.component'; +import { ToastWithCloseButtonComponent, WithCloseButton } from './examples/toast-with-close-button.component'; +import { ToastWithContentComponent, WithContent } from './examples/toast-with-content.component'; +import { ToastWidthComponent, Width } from './examples/toast-width.component'; +import { ToastPositionComponent, Position } from './examples/toast-position.component'; + +const meta: Meta = { + title: 'Components/Feedback/Toast', + component: ToastComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + ToastComponent, + ToastDefaultComponent, + ToastSeveritiesComponent, + ToastWithCloseButtonComponent, + ToastWithContentComponent, + ToastWidthComponent, + ToastPositionComponent, + Toast, + Button, + ], + providers: [MessageService], + }), + ], + parameters: { + designTokens: { prefix: '--p-toast' }, + docs: { + description: { + component: `Компонент для отображения всплывающих уведомлений поверх интерфейса. Требует подключения \`MessageService\`. + +\`\`\`typescript +import { ToastComponent } from '@cdek-it/angular-ui-kit'; +import { MessageService } from 'primeng/api'; + +@Component({ + providers: [MessageService], +}) +export class MyComponent { + constructor(private messageService: MessageService) {} + + show(): void { + this.messageService.add({ + severity: 'info', + summary: 'Сообщение', + detail: 'Подпись', + life: 5000, + icon: 'ti ti-info-circle', + }); + } +} +\`\`\``, + }, + }, + }, + argTypes: { + position: { + control: 'select', + options: ['top-right', 'top-left', 'top-center', 'bottom-right', 'bottom-left', 'bottom-center', 'center'], + description: 'Позиция тоста на экране.', + table: { + category: 'Props', + defaultValue: { summary: 'top-right' }, + type: { summary: "'top-right' | 'top-left' | 'top-center' | 'bottom-right' | 'bottom-left' | 'bottom-center' | 'center'" }, + }, + }, + key: { + control: 'text', + description: 'Ключ для адресной отправки сообщений через MessageService.', + table: { + category: 'Props', + type: { summary: 'string' }, + }, + }, + life: { + control: 'number', + description: 'Время (мс) до автоматического закрытия тоста.', + table: { + category: 'Props', + defaultValue: { summary: '5000' }, + type: { summary: 'number' }, + }, + }, + }, + args: { + position: 'top-right', + key: undefined, + life: 5000, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ────────────────────────────────────────────────────────────────── + +export const Default: Story = { + name: 'Default', + render: (args) => ({ + props: { + position: args.position, + life: args.life, + }, + template: ``, + }), + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для изменения позиции и времени жизни тоста.', + }, + }, + }, +}; + +// ── Re-exports from example components ──────────────────────────────────── +export { Severities, WithCloseButton, WithContent, Width, Position }; From 97e61d74a74cf507ee24c4b0c66a490b8ed7bb36 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 15 Apr 2026 14:54:06 +0700 Subject: [PATCH 091/258] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=81=D1=82?= =?UTF-8?q?=D0=B8=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B8=20?= =?UTF-8?q?=D1=81=D1=82=D0=BE=D1=80=D0=B8=D1=81=D0=BE=D0=B2=20=D1=81=D0=BE?= =?UTF-8?q?=D0=B3=D0=BB=D0=B0=D1=81=D0=BD=D0=BE=20=D0=BF=D0=B0=D1=82=D1=82?= =?UTF-8?q?=D0=B5=D1=80=D0=BD=D0=BE=D0=B2=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../toast/examples/toast-default.component.ts | 79 ----------- .../examples/toast-position.component.ts | 68 ++++----- .../examples/toast-severities.component.ts | 99 +++++++------ .../toast/examples/toast-width.component.ts | 101 +++++++------- .../toast-with-close-button.component.ts | 94 +++++++------ .../examples/toast-with-content.component.ts | 130 +++++++++--------- src/stories/components/toast/toast.stories.ts | 53 +------ 7 files changed, 262 insertions(+), 362 deletions(-) delete mode 100644 src/stories/components/toast/examples/toast-default.component.ts diff --git a/src/stories/components/toast/examples/toast-default.component.ts b/src/stories/components/toast/examples/toast-default.component.ts deleted file mode 100644 index 969a1ea1..00000000 --- a/src/stories/components/toast/examples/toast-default.component.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Component, Input, OnChanges } from '@angular/core'; -import { Toast } from 'primeng/toast'; -import { Button } from 'primeng/button'; -import { MessageService, SharedModule } from 'primeng/api'; - -const SEVERITIES = [ - { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, - { type: 'success', icon: 'ti ti-circle-check', label: 'Успех' }, - { type: 'warn', icon: 'ti ti-alert-triangle', label: 'Предупреждение' }, - { type: 'error', icon: 'ti ti-alert-circle', label: 'Ошибка' }, -] as const; - -@Component({ - selector: 'app-toast-default', - standalone: true, - imports: [Toast, Button, SharedModule], - providers: [MessageService], - template: ` - - -
- -
- {{ message.summary }} -
{{ message.detail }}
-
-
-
- -
- @for (s of severities; track s.type) { -
-
-
- -
- Сообщение -
Подпись
-
-
-
- } -
- -
- @for (s of severities; track s.type) { - - } -
- `, -}) -export class ToastDefaultComponent implements OnChanges { - @Input() position = 'top-right'; - @Input() life = 5000; - - readonly severities = SEVERITIES; - - constructor(private readonly messageService: MessageService) {} - - ngOnChanges(): void { - this.messageService.clear('default-story'); - } - - show(severity: string, icon: string): void { - this.messageService.add({ - key: 'default-story', - severity, - summary: 'Сообщение', - detail: 'Подпись', - life: this.life, - icon, - }); - } -} diff --git a/src/stories/components/toast/examples/toast-position.component.ts b/src/stories/components/toast/examples/toast-position.component.ts index 49a8738b..4b6492f2 100644 --- a/src/stories/components/toast/examples/toast-position.component.ts +++ b/src/stories/components/toast/examples/toast-position.component.ts @@ -13,35 +13,39 @@ const POSITIONS = [ { position: 'bottom-right', label: 'Вниз справа', key: 'pos-bottom-right' }, ] as const; +const template = ` +@for (p of positions; track p.key) { + + +
+ +
+ {{ message.summary }} +
{{ message.detail }}
+
+
+
+} + +
+ @for (p of positions; track p.key) { + + } +
+`; +const styles = ''; + @Component({ selector: 'app-toast-position', standalone: true, imports: [Toast, Button, SharedModule], providers: [MessageService], - template: ` - @for (p of positions; track p.key) { - - -
- -
- {{ message.summary }} -
{{ message.detail }}
-
-
-
- } - -
- @for (p of positions; track p.key) { - - } -
- `, + template, + styles, }) export class ToastPositionComponent { readonly positions = POSITIONS; @@ -66,16 +70,16 @@ export const Position: StoryObj = { }), parameters: { docs: { - description: { story: 'Расположение тоста задаётся через `position` и `group`.' }, + description: { story: 'Расположение тоста задаётся через `position` и `key`.' }, source: { - language: 'html', + language: 'ts', code: ` - - - - - - + + + + + + `, }, }, diff --git a/src/stories/components/toast/examples/toast-severities.component.ts b/src/stories/components/toast/examples/toast-severities.component.ts index 5b6e6f20..9dbbe33c 100644 --- a/src/stories/components/toast/examples/toast-severities.component.ts +++ b/src/stories/components/toast/examples/toast-severities.component.ts @@ -11,49 +11,53 @@ const SEVERITIES = [ { type: 'error', icon: 'ti ti-alert-circle', label: 'Ошибка' }, ] as const; -@Component({ - selector: 'app-toast-severities', - standalone: true, - imports: [Toast, Button, SharedModule], - providers: [MessageService], - template: ` - - +const template = ` + + +
+ +
+ {{ message.summary }} +
{{ message.detail }}
+
+
+
+ +
+ @for (s of severities; track s.type) { +
+
- +
- {{ message.summary }} -
{{ message.detail }}
+ Сообщение +
Подпись
- - - -
- @for (s of severities; track s.type) { -
-
-
- -
- Сообщение -
Подпись
-
-
-
- } +
+ } +
-
- @for (s of severities; track s.type) { - - } -
- `, +
+ @for (s of severities; track s.type) { + + } +
+`; +const styles = ''; + +@Component({ + selector: 'app-toast-severities', + standalone: true, + imports: [Toast, Button, SharedModule], + providers: [MessageService], + template, + styles, }) export class ToastSeveritiesComponent { readonly severities = SEVERITIES; @@ -83,16 +87,25 @@ export const Severities: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MessageService } from 'primeng/api'; -import { ToastComponent } from '@cdek-it/angular-ui-kit'; +import { MessageService, SharedModule } from 'primeng/api'; +import { Toast } from 'primeng/toast'; @Component({ selector: 'app-example', standalone: true, - imports: [ToastComponent], + imports: [Toast, SharedModule], providers: [MessageService], template: \` - + + +
+ +
+ {{ message.summary }} +
{{ message.detail }}
+
+
+
\`, }) @@ -101,7 +114,7 @@ export class ExampleComponent { show(): void { this.messageService.add({ - group: 'my-toast', + key: 'my-toast', severity: 'info', summary: 'Сообщение', detail: 'Подпись', diff --git a/src/stories/components/toast/examples/toast-width.component.ts b/src/stories/components/toast/examples/toast-width.component.ts index 70e81593..7c78814b 100644 --- a/src/stories/components/toast/examples/toast-width.component.ts +++ b/src/stories/components/toast/examples/toast-width.component.ts @@ -5,57 +5,64 @@ import { Button } from 'primeng/button'; import { MessageService, SharedModule } from 'primeng/api'; const SIZES = [ - { key: 'sm', label: 'Small (20rem)', width: '20rem' }, - { key: 'base', label: 'Base (25rem)', width: '25rem' }, - { key: 'lg', label: 'Large (30rem)', width: '30rem' }, - { key: 'xlg', label: 'X-Large (45rem)', width: '45rem' }, + { key: 'sm', label: 'Small (20rem)', width: '20rem', cssVar: '20rem' }, + { key: 'base', label: 'Base (25rem)', width: '25rem', cssVar: '25rem' }, + { key: 'lg', label: 'Large (30rem)', width: '30rem', cssVar: '30rem' }, + { key: 'xlg', label: 'X-Large (45rem)', width: '45rem', cssVar: '45rem' }, ] as const; -@Component({ - selector: 'app-toast-width', - standalone: true, - imports: [Toast, Button, SharedModule], - providers: [MessageService], - template: ` - + +
+ +
+ {{ message.summary }} +
{{ message.detail }}
+
+
+
+ +
+ @for (s of sizes; track s.key) { +
- +
- +
- {{ message.summary }} -
{{ message.detail }}
-
- - - -
- @for (s of sizes; track s.key) { -
-
-
- -
- Сообщение -
Ширина {{ s.key }}: {{ s.width }}
-
-
+ Сообщение +
Ширина {{ s.key }}: {{ s.width }}
- } +
+ } +
-
- @for (s of sizes; track s.key) { - - } -
- `, +
+ @for (s of sizes; track s.key) { + + } +
+`; +const styles = ''; + +@Component({ + selector: 'app-toast-width', + standalone: true, + imports: [Toast, Button, SharedModule], + providers: [MessageService], + template, + styles, }) export class ToastWidthComponent { readonly sizes = SIZES; @@ -63,14 +70,14 @@ export class ToastWidthComponent { constructor(private readonly messageService: MessageService) {} - show(width: string): void { - this.currentWidth = width; + show(cssVar: string): void { + this.currentWidth = cssVar; this.messageService.clear('width-preview'); this.messageService.add({ key: 'width-preview', severity: 'info', summary: 'Сообщение', - detail: 'Ширина: ' + width, + detail: 'Ширина: ' + cssVar, life: 3000, icon: 'ti ti-info-circle', }); @@ -85,7 +92,7 @@ export const Width: StoryObj = { docs: { description: { story: 'Ширина задаётся через CSS-переменную `--p-toast-width` с помощью пропа `pt`.' }, source: { - language: 'html', + language: 'ts', code: ` ... diff --git a/src/stories/components/toast/examples/toast-with-close-button.component.ts b/src/stories/components/toast/examples/toast-with-close-button.component.ts index 821a75eb..eabd523a 100644 --- a/src/stories/components/toast/examples/toast-with-close-button.component.ts +++ b/src/stories/components/toast/examples/toast-with-close-button.component.ts @@ -11,55 +11,59 @@ const SEVERITIES = [ { type: 'error', icon: 'ti ti-alert-circle', label: 'Ошибка' }, ] as const; -@Component({ - selector: 'app-toast-with-close-button', - standalone: true, - imports: [Toast, Button, SharedModule], - providers: [MessageService], - template: ` - - +const template = ` + + +
+ +
+ {{ message.summary }} +
{{ message.detail }}
+
+
+
+ +
+ @for (s of severities; track s.type) { +
+
- +
- {{ message.summary }} -
{{ message.detail }}
-
- - - -
- @for (s of severities; track s.type) { -
-
-
- -
- Сообщение -
Подпись
-
- -
+ Сообщение +
Подпись
- } + +
+ } +
-
- @for (s of severities; track s.type) { - - } -
- `, +
+ @for (s of severities; track s.type) { + + } +
+`; +const styles = ''; + +@Component({ + selector: 'app-toast-with-close-button', + standalone: true, + imports: [Toast, Button, SharedModule], + providers: [MessageService], + template, + styles, }) export class ToastWithCloseButtonComponent { readonly severities = SEVERITIES; @@ -90,7 +94,7 @@ export const WithCloseButton: StoryObj = { language: 'ts', code: ` this.messageService.add({ - group: 'my-toast', + key: 'my-toast', severity: 'info', summary: 'Сообщение', detail: 'Подпись', diff --git a/src/stories/components/toast/examples/toast-with-content.component.ts b/src/stories/components/toast/examples/toast-with-content.component.ts index 6f4453af..5aadaf6b 100644 --- a/src/stories/components/toast/examples/toast-with-content.component.ts +++ b/src/stories/components/toast/examples/toast-with-content.component.ts @@ -11,19 +11,34 @@ const SEVERITIES = [ { type: 'error', icon: 'ti ti-alert-circle', label: 'Ошибка' }, ] as const; -@Component({ - selector: 'app-toast-with-content', - standalone: true, - imports: [Toast, Button, SharedModule], - providers: [MessageService], - template: ` - - +const template = ` + + +
+ +
+ {{ message.summary }} +
{{ message.detail }}
+
+
Дополнительный контент
+
+
+
Ячейка 1
+
Ячейка 2
+
+
+
+
+ +
+ @for (s of severities; track s.type) { +
+
- +
- {{ message.summary }} -
{{ message.detail }}
+ Сообщение +
Подпись
Дополнительный контент
@@ -32,48 +47,37 @@ const SEVERITIES = [
Ячейка 2
- - - -
- @for (s of severities; track s.type) { -
-
-
- -
- Сообщение -
Подпись
-
-
Дополнительный контент
-
-
-
Ячейка 1
-
Ячейка 2
-
-
- -
-
- } + +
+ } +
-
- @for (s of severities; track s.type) { - - } -
- `, +
+ @for (s of severities; track s.type) { + + } +
+`; +const styles = ''; + +@Component({ + selector: 'app-toast-with-content', + standalone: true, + imports: [Toast, Button, SharedModule], + providers: [MessageService], + template, + styles, }) export class ToastWithContentComponent { readonly severities = SEVERITIES; @@ -101,21 +105,17 @@ export const WithContent: StoryObj = { docs: { description: { story: 'Уведомления с дополнительным контентом под заголовком.' }, source: { - language: 'html', + language: 'ts', code: ` - - -
- -
- {{ message.summary }} -
{{ message.detail }}
-
-
Дополнительный контент
-
-
-
-
+this.messageService.add({ + key: 'my-toast', + severity: 'info', + summary: 'Сообщение', + detail: 'Подпись', + life: 5000, + icon: 'ti ti-info-circle', + closable: true, +}); `, }, }, diff --git a/src/stories/components/toast/toast.stories.ts b/src/stories/components/toast/toast.stories.ts index 74f3aca7..6ca7b620 100644 --- a/src/stories/components/toast/toast.stories.ts +++ b/src/stories/components/toast/toast.stories.ts @@ -1,9 +1,6 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { MessageService } from 'primeng/api'; -import { Toast } from 'primeng/toast'; -import { Button } from 'primeng/button'; import { ToastComponent } from '../../../lib/components/toast/toast.component'; -import { ToastDefaultComponent } from './examples/toast-default.component'; import { ToastSeveritiesComponent, Severities } from './examples/toast-severities.component'; import { ToastWithCloseButtonComponent, WithCloseButton } from './examples/toast-with-close-button.component'; import { ToastWithContentComponent, WithContent } from './examples/toast-with-content.component'; @@ -18,14 +15,11 @@ const meta: Meta = { moduleMetadata({ imports: [ ToastComponent, - ToastDefaultComponent, ToastSeveritiesComponent, ToastWithCloseButtonComponent, ToastWithContentComponent, ToastWidthComponent, ToastPositionComponent, - Toast, - Button, ], providers: [MessageService], }), @@ -39,23 +33,6 @@ const meta: Meta = { \`\`\`typescript import { ToastComponent } from '@cdek-it/angular-ui-kit'; import { MessageService } from 'primeng/api'; - -@Component({ - providers: [MessageService], -}) -export class MyComponent { - constructor(private messageService: MessageService) {} - - show(): void { - this.messageService.add({ - severity: 'info', - summary: 'Сообщение', - detail: 'Подпись', - life: 5000, - icon: 'ti ti-info-circle', - }); - } -} \`\`\``, }, }, @@ -72,12 +49,7 @@ export class MyComponent { }, }, key: { - control: 'text', - description: 'Ключ для адресной отправки сообщений через MessageService.', - table: { - category: 'Props', - type: { summary: 'string' }, - }, + table: { disable: true }, }, life: { control: 'number', @@ -97,27 +69,6 @@ export class MyComponent { }; export default meta; -type Story = StoryObj; - -// ── Default ────────────────────────────────────────────────────────────────── - -export const Default: Story = { - name: 'Default', - render: (args) => ({ - props: { - position: args.position, - life: args.life, - }, - template: ``, - }), - parameters: { - docs: { - description: { - story: 'Базовый пример компонента. Используйте Controls для изменения позиции и времени жизни тоста.', - }, - }, - }, -}; // ── Re-exports from example components ──────────────────────────────────── -export { Severities, WithCloseButton, WithContent, Width, Position }; +export { Severities as Default, WithCloseButton, WithContent, Width, Position }; From d2b737a5e5f2081c4954b3e34917c08e520386e0 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 15 Apr 2026 15:50:09 +0700 Subject: [PATCH 092/258] =?UTF-8?q?map-tokens.ts=20=D0=B2=D0=BE=D1=81?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=B8?= =?UTF-8?q?=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/map-tokens.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 437e87f4..0194af83 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -6,6 +6,8 @@ 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 { progressspinnerCss } from './tokens/components/progressspinner'; +import { tagCss } from './tokens/components/tag'; import { tooltipCss } from './tokens/components/tooltip'; const presetTokens: Preset = { @@ -25,10 +27,18 @@ const presetTokens: Preset = { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), css: buttonCss, }, + progressspinner: { + ...(tokens.components.progressspinner as unknown as ComponentsDesignTokens['progressspinner']), + css: progressspinnerCss, + }, tag: { ...(tokens.components.tag as unknown as ComponentsDesignTokens['tag']), css: tagCss, }, + tooltip: { + ...(tokens.components.tooltip as unknown as ComponentsDesignTokens['tooltip']), + css: tooltipCss, + }, } as ComponentsDesignTokens, }; From 384c8257d1925cc32efe130bbb689e308853b6da Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 15 Apr 2026 21:33:25 +0700 Subject: [PATCH 093/258] =?UTF-8?q?tabs:=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 --- .claude/CLAUDE-v1.6.md | 751 ------------------ src/lib/components/tabs/tabs.component.ts | 59 ++ src/prime-preset/map-tokens.ts | 5 + src/prime-preset/tokens/components/tabs.ts | 26 + .../examples/tabs-with-badge.component.ts | 59 ++ .../examples/tabs-with-disabled.component.ts | 59 ++ src/stories/components/tabs/tabs.stories.ts | 113 +++ 7 files changed, 321 insertions(+), 751 deletions(-) delete mode 100644 .claude/CLAUDE-v1.6.md create mode 100644 src/lib/components/tabs/tabs.component.ts create mode 100644 src/prime-preset/tokens/components/tabs.ts create mode 100644 src/stories/components/tabs/examples/tabs-with-badge.component.ts create mode 100644 src/stories/components/tabs/examples/tabs-with-disabled.component.ts create mode 100644 src/stories/components/tabs/tabs.stories.ts 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"` (статичный шаблон) | -| ``; - 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"` (статичный шаблон) | -| ``; - 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"` (статичный шаблон) | -| `
`; @@ -12,7 +12,7 @@ const template = ` @Component({ selector: 'app-menu-popup', standalone: true, - imports: [MenuComponent, Button], + imports: [MenuComponent, ButtonComponent], template, }) export class MenuPopupComponent { diff --git a/src/stories/components/menu/menu.stories.ts b/src/stories/components/menu/menu.stories.ts index b226d219..65690f5d 100644 --- a/src/stories/components/menu/menu.stories.ts +++ b/src/stories/components/menu/menu.stories.ts @@ -61,15 +61,14 @@ export const Default: Story = { language: 'ts', code: ` import { Component, ViewChild } from '@angular/core'; -import { Button } from 'primeng/button'; -import { MenuComponent, MenuModel } from '@cdek-it/angular-ui-kit'; +import { MenuComponent, MenuModel, ButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-menu-popup', standalone: true, - imports: [MenuComponent, Button], + imports: [MenuComponent, ButtonComponent], template: \` - + \`, }) From ef0716bf09a43e151ac837ad2267f1a68696bb58 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Fri, 17 Apr 2026 16:30:11 +0700 Subject: [PATCH 107/258] =?UTF-8?q?regular=20=D0=B4=D0=BB=D1=8F=20fontWeig?= =?UTF-8?q?ht?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/tokens.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prime-preset/tokens/tokens.json b/src/prime-preset/tokens/tokens.json index 19d1ea50..34c03893 100644 --- a/src/prime-preset/tokens/tokens.json +++ b/src/prime-preset/tokens/tokens.json @@ -3372,7 +3372,7 @@ }, "submenuLabel": { "padding": "{navigation.submenuLabel.padding}", - "fontWeight": "{fonts.fontWeight.demibold}", + "fontWeight": "{fonts.fontWeight.regular}", "background": "{navigation.submenuLabel.background}", "color": "{navigation.submenuLabel.color}" }, From b729d9e51972032423c6b2b0c9131eb3649fa462 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Fri, 17 Apr 2026 16:42:31 +0700 Subject: [PATCH 108/258] =?UTF-8?q?dialog:=20=D0=BE=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=B0=D1=87=D0=B8=D0=B2=D0=B0=D0=B5=D0=BC=20footerTemplate=20?= =?UTF-8?q?=D0=B2=20@if,=20=D0=B0=D0=BD=D0=B0=D0=BB=D0=BE=D0=B3=D0=B8?= =?UTF-8?q?=D1=87=D0=BD=D0=BE=20headerTemplate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/dialog/dialog.component.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/lib/components/dialog/dialog.component.ts b/src/lib/components/dialog/dialog.component.ts index aa5722a8..7a9ca1c1 100644 --- a/src/lib/components/dialog/dialog.component.ts +++ b/src/lib/components/dialog/dialog.component.ts @@ -29,9 +29,11 @@ export type DialogSize = 'sm' | 'default' | 'lg' | 'xlg';
} - - - + @if (footerTemplate) { + + + + } `, }) From 44211171f554254d9552bc7bf2c3cc7ba2adfa06 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Fri, 17 Apr 2026 16:43:36 +0700 Subject: [PATCH 109/258] =?UTF-8?q?dialog=20=D1=81=D1=82=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D1=81:=20=D1=83=D0=B1=D0=B8=D1=80=D0=B0=D0=B5=D0=BC=20@ViewChi?= =?UTF-8?q?ld('footer'),=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=BD=D0=B0=D1=8F=20#footer=20=D0=B4=D0=BE=D1=81=D1=82=D1=83?= =?UTF-8?q?=D0=BF=D0=BD=D0=B0=20=D0=B8=D0=B7=20ng-template?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/dialog/dialog.stories.ts | 18 ++++++------------ .../examples/dialog-default.component.ts | 3 +-- .../examples/dialog-extra-large.component.ts | 3 +-- .../dialog/examples/dialog-large.component.ts | 3 +-- .../examples/dialog-no-header.component.ts | 3 +-- .../examples/dialog-no-modal.component.ts | 3 +-- .../dialog/examples/dialog-small.component.ts | 3 +-- 7 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/stories/components/dialog/dialog.stories.ts b/src/stories/components/dialog/dialog.stories.ts index 208fc2ce..aca195e1 100644 --- a/src/stories/components/dialog/dialog.stories.ts +++ b/src/stories/components/dialog/dialog.stories.ts @@ -135,7 +135,7 @@ export const Basic: Story = { source: { language: 'ts', code: ` -import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { DialogComponent } from '@cdek-it/angular-ui-kit'; @@ -146,7 +146,6 @@ import { DialogComponent } from '@cdek-it/angular-ui-kit'; template: \`${dialogDefaultTemplate}\`, }) export class DialogBasicComponent { - @ViewChild('footer') footer!: TemplateRef; visible = false; } `, @@ -167,7 +166,7 @@ export const Small: Story = { source: { language: 'ts', code: ` -import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { DialogComponent } from '@cdek-it/angular-ui-kit'; @@ -178,7 +177,6 @@ import { DialogComponent } from '@cdek-it/angular-ui-kit'; template: \`${dialogSmallTemplate}\`, }) export class DialogSmallComponent { - @ViewChild('footer') footer!: TemplateRef; visible = false; } `, @@ -199,7 +197,7 @@ export const Large: Story = { source: { language: 'ts', code: ` -import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { DialogComponent } from '@cdek-it/angular-ui-kit'; @@ -210,7 +208,6 @@ import { DialogComponent } from '@cdek-it/angular-ui-kit'; template: \`${dialogLargeTemplate}\`, }) export class DialogLargeComponent { - @ViewChild('footer') footer!: TemplateRef; visible = false; } `, @@ -231,7 +228,7 @@ export const ExtraLarge: Story = { source: { language: 'ts', code: ` -import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { DialogComponent } from '@cdek-it/angular-ui-kit'; @@ -242,7 +239,6 @@ import { DialogComponent } from '@cdek-it/angular-ui-kit'; template: \`${dialogExtraLargeTemplate}\`, }) export class DialogExtraLargeComponent { - @ViewChild('footer') footer!: TemplateRef; visible = false; } `, @@ -263,7 +259,7 @@ export const NoModal: Story = { source: { language: 'ts', code: ` -import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { DialogComponent } from '@cdek-it/angular-ui-kit'; @@ -274,7 +270,6 @@ import { DialogComponent } from '@cdek-it/angular-ui-kit'; template: \`${dialogNoModalTemplate}\`, }) export class DialogNoModalComponent { - @ViewChild('footer') footer!: TemplateRef; visible = false; } `, @@ -295,7 +290,7 @@ export const NoHeader: Story = { source: { language: 'ts', code: ` -import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { DialogComponent } from '@cdek-it/angular-ui-kit'; @@ -306,7 +301,6 @@ import { DialogComponent } from '@cdek-it/angular-ui-kit'; template: \`${dialogNoHeaderTemplate}\`, }) export class DialogNoHeaderComponent { - @ViewChild('footer') footer!: TemplateRef; visible = false; } `, diff --git a/src/stories/components/dialog/examples/dialog-default.component.ts b/src/stories/components/dialog/examples/dialog-default.component.ts index faa63269..5338a342 100644 --- a/src/stories/components/dialog/examples/dialog-default.component.ts +++ b/src/stories/components/dialog/examples/dialog-default.component.ts @@ -1,4 +1,4 @@ -import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; @@ -29,6 +29,5 @@ export const template = ` template, }) export class DialogDefaultComponent { - @ViewChild('footer') footer!: TemplateRef; visible = false; } diff --git a/src/stories/components/dialog/examples/dialog-extra-large.component.ts b/src/stories/components/dialog/examples/dialog-extra-large.component.ts index 88c43fac..b29e9e66 100644 --- a/src/stories/components/dialog/examples/dialog-extra-large.component.ts +++ b/src/stories/components/dialog/examples/dialog-extra-large.component.ts @@ -1,4 +1,4 @@ -import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; @@ -30,6 +30,5 @@ export const template = ` template, }) export class DialogExtraLargeComponent { - @ViewChild('footer') footer!: TemplateRef; visible = false; } diff --git a/src/stories/components/dialog/examples/dialog-large.component.ts b/src/stories/components/dialog/examples/dialog-large.component.ts index 3cd061a5..9888b6e7 100644 --- a/src/stories/components/dialog/examples/dialog-large.component.ts +++ b/src/stories/components/dialog/examples/dialog-large.component.ts @@ -1,4 +1,4 @@ -import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; @@ -30,6 +30,5 @@ export const template = ` template, }) export class DialogLargeComponent { - @ViewChild('footer') footer!: TemplateRef; visible = false; } diff --git a/src/stories/components/dialog/examples/dialog-no-header.component.ts b/src/stories/components/dialog/examples/dialog-no-header.component.ts index 6cdd7c4c..eafc7419 100644 --- a/src/stories/components/dialog/examples/dialog-no-header.component.ts +++ b/src/stories/components/dialog/examples/dialog-no-header.component.ts @@ -1,4 +1,4 @@ -import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; @@ -31,6 +31,5 @@ export const template = ` template, }) export class DialogNoHeaderComponent { - @ViewChild('footer') footer!: TemplateRef; visible = false; } diff --git a/src/stories/components/dialog/examples/dialog-no-modal.component.ts b/src/stories/components/dialog/examples/dialog-no-modal.component.ts index 6c9c5230..b014a108 100644 --- a/src/stories/components/dialog/examples/dialog-no-modal.component.ts +++ b/src/stories/components/dialog/examples/dialog-no-modal.component.ts @@ -1,4 +1,4 @@ -import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; @@ -30,6 +30,5 @@ export const template = ` template, }) export class DialogNoModalComponent { - @ViewChild('footer') footer!: TemplateRef; visible = false; } diff --git a/src/stories/components/dialog/examples/dialog-small.component.ts b/src/stories/components/dialog/examples/dialog-small.component.ts index 06fed64f..275cae90 100644 --- a/src/stories/components/dialog/examples/dialog-small.component.ts +++ b/src/stories/components/dialog/examples/dialog-small.component.ts @@ -1,4 +1,4 @@ -import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { Component } from '@angular/core'; import { Button } from 'primeng/button'; import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; @@ -30,6 +30,5 @@ export const template = ` template, }) export class DialogSmallComponent { - @ViewChild('footer') footer!: TemplateRef; visible = false; } From 0bc52f5624a8869ba398ba40291c1668dd922bd7 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Fri, 17 Apr 2026 16:44:47 +0700 Subject: [PATCH 110/258] =?UTF-8?q?dialog=20=D1=81=D1=82=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D1=81:=20=D0=B7=D0=B0=D0=BC=D0=B5=D0=BD=D1=8F=D0=B5=D0=BC=20p-?= =?UTF-8?q?button=20=D0=BD=D0=B0=20ButtonComponent,=20(onClick)=20?= =?UTF-8?q?=E2=86=92=20(click)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/dialog/dialog.stories.ts | 30 ++++++++----------- .../examples/dialog-default.component.ts | 10 +++---- .../examples/dialog-extra-large.component.ts | 10 +++---- .../dialog/examples/dialog-large.component.ts | 10 +++---- .../examples/dialog-no-header.component.ts | 8 ++--- .../examples/dialog-no-modal.component.ts | 10 +++---- .../dialog/examples/dialog-small.component.ts | 10 +++---- 7 files changed, 41 insertions(+), 47 deletions(-) diff --git a/src/stories/components/dialog/dialog.stories.ts b/src/stories/components/dialog/dialog.stories.ts index aca195e1..61c60fc3 100644 --- a/src/stories/components/dialog/dialog.stories.ts +++ b/src/stories/components/dialog/dialog.stories.ts @@ -136,13 +136,12 @@ export const Basic: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { Button } from 'primeng/button'; -import { DialogComponent } from '@cdek-it/angular-ui-kit'; +import { DialogComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-dialog-basic', standalone: true, - imports: [DialogComponent, Button], + imports: [DialogComponent, ButtonComponent], template: \`${dialogDefaultTemplate}\`, }) export class DialogBasicComponent { @@ -167,13 +166,12 @@ export const Small: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { Button } from 'primeng/button'; -import { DialogComponent } from '@cdek-it/angular-ui-kit'; +import { DialogComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-dialog-small', standalone: true, - imports: [DialogComponent, Button], + imports: [DialogComponent, ButtonComponent], template: \`${dialogSmallTemplate}\`, }) export class DialogSmallComponent { @@ -198,13 +196,12 @@ export const Large: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { Button } from 'primeng/button'; -import { DialogComponent } from '@cdek-it/angular-ui-kit'; +import { DialogComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-dialog-large', standalone: true, - imports: [DialogComponent, Button], + imports: [DialogComponent, ButtonComponent], template: \`${dialogLargeTemplate}\`, }) export class DialogLargeComponent { @@ -229,13 +226,12 @@ export const ExtraLarge: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { Button } from 'primeng/button'; -import { DialogComponent } from '@cdek-it/angular-ui-kit'; +import { DialogComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-dialog-extra-large', standalone: true, - imports: [DialogComponent, Button], + imports: [DialogComponent, ButtonComponent], template: \`${dialogExtraLargeTemplate}\`, }) export class DialogExtraLargeComponent { @@ -260,13 +256,12 @@ export const NoModal: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { Button } from 'primeng/button'; -import { DialogComponent } from '@cdek-it/angular-ui-kit'; +import { DialogComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-dialog-no-modal', standalone: true, - imports: [DialogComponent, Button], + imports: [DialogComponent, ButtonComponent], template: \`${dialogNoModalTemplate}\`, }) export class DialogNoModalComponent { @@ -291,13 +286,12 @@ export const NoHeader: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { Button } from 'primeng/button'; -import { DialogComponent } from '@cdek-it/angular-ui-kit'; +import { DialogComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-dialog-no-header', standalone: true, - imports: [DialogComponent, Button], + imports: [DialogComponent, ButtonComponent], template: \`${dialogNoHeaderTemplate}\`, }) export class DialogNoHeaderComponent { diff --git a/src/stories/components/dialog/examples/dialog-default.component.ts b/src/stories/components/dialog/examples/dialog-default.component.ts index 5338a342..31a2e5a3 100644 --- a/src/stories/components/dialog/examples/dialog-default.component.ts +++ b/src/stories/components/dialog/examples/dialog-default.component.ts @@ -1,14 +1,14 @@ import { Component } from '@angular/core'; -import { Button } from 'primeng/button'; +import { ButtonComponent } from '../../../../lib/components/button/button.component'; import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; export const template = `
- + - - + + - + - - + + - + - - + + - +
- +
@@ -27,7 +27,7 @@ export const template = ` @Component({ selector: 'app-dialog-no-header', standalone: true, - imports: [DialogComponent, Button], + imports: [DialogComponent, ButtonComponent], template, }) export class DialogNoHeaderComponent { diff --git a/src/stories/components/dialog/examples/dialog-no-modal.component.ts b/src/stories/components/dialog/examples/dialog-no-modal.component.ts index b014a108..fba236cb 100644 --- a/src/stories/components/dialog/examples/dialog-no-modal.component.ts +++ b/src/stories/components/dialog/examples/dialog-no-modal.component.ts @@ -1,14 +1,14 @@ import { Component } from '@angular/core'; -import { Button } from 'primeng/button'; +import { ButtonComponent } from '../../../../lib/components/button/button.component'; import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; export const template = `
- + - - + + - + - - + + Date: Fri, 17 Apr 2026 16:45:13 +0700 Subject: [PATCH 111/258] =?UTF-8?q?dialog:=20UiDialogService.providers()?= =?UTF-8?q?=20=D0=B8=D0=BD=D0=BA=D0=B0=D0=BF=D1=81=D1=83=D0=BB=D0=B8=D1=80?= =?UTF-8?q?=D1=83=D0=B5=D1=82=20DialogService,=20=D0=BF=D1=80=D0=B0=D0=B9?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2=D1=81=D0=BA=D0=B8=D0=B9=20=D0=B8=D0=BC=D0=BF?= =?UTF-8?q?=D0=BE=D1=80=D1=82=20=D1=83=D0=B1=D1=80=D0=B0=D0=BD=20=D0=B8?= =?UTF-8?q?=D0=B7=20=D1=81=D1=82=D0=BE=D1=80=D0=B8=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/dialog/dialog-open.service.ts | 4 ++++ src/stories/components/dialog/dialog.stories.ts | 16 +++++++--------- .../dialog/examples/dialog-dynamic.component.ts | 17 ++++++++--------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/lib/components/dialog/dialog-open.service.ts b/src/lib/components/dialog/dialog-open.service.ts index f82d0c31..4cd06c6a 100644 --- a/src/lib/components/dialog/dialog-open.service.ts +++ b/src/lib/components/dialog/dialog-open.service.ts @@ -11,6 +11,10 @@ export { DynamicDialogRef, DynamicDialogConfig }; @Injectable() export class UiDialogService { + static providers() { + return [DialogService, UiDialogService]; + } + constructor(private readonly primengDialogService: DialogService) {} open(componentType: Type, config: UiDynamicDialogConfig = {}): DynamicDialogRef | null { diff --git a/src/stories/components/dialog/dialog.stories.ts b/src/stories/components/dialog/dialog.stories.ts index 61c60fc3..64d7ef47 100644 --- a/src/stories/components/dialog/dialog.stories.ts +++ b/src/stories/components/dialog/dialog.stories.ts @@ -318,20 +318,18 @@ export const Dynamic: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { Button } from 'primeng/button'; -import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog'; -import { UiDialogService } from '@cdek-it/angular-ui-kit'; +import { ButtonComponent, DynamicDialogRef, UiDialogService } from '@cdek-it/angular-ui-kit'; // Содержимое диалога @Component({ selector: 'app-dialog-dynamic-content', standalone: true, - imports: [Button], + imports: [ButtonComponent], template: \`

Заявка на доставку груза №CDEK-2025-00478312 готова к оформлению.

- - + +
\`, }) @@ -343,10 +341,10 @@ export class DialogDynamicContentComponent { @Component({ selector: 'app-dialog-dynamic', standalone: true, - imports: [Button], - providers: [DialogService, UiDialogService], + imports: [ButtonComponent], + providers: [UiDialogService.providers()], template: \` - + \`, }) export class DialogDynamicComponent { diff --git a/src/stories/components/dialog/examples/dialog-dynamic.component.ts b/src/stories/components/dialog/examples/dialog-dynamic.component.ts index 32cb4bdd..b742336e 100644 --- a/src/stories/components/dialog/examples/dialog-dynamic.component.ts +++ b/src/stories/components/dialog/examples/dialog-dynamic.component.ts @@ -1,20 +1,19 @@ import { Component } from '@angular/core'; -import { Button } from 'primeng/button'; -import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog'; -import { UiDialogService } from '../../../../lib/components/dialog/dialog-open.service'; +import { ButtonComponent } from '../../../../lib/components/button/button.component'; +import { DynamicDialogRef, UiDialogService } from '../../../../lib/components/dialog/dialog-open.service'; // ── Содержимое диалога ──────────────────────────────────────────────────────── @Component({ selector: 'app-dialog-dynamic-content', standalone: true, - imports: [Button], + imports: [ButtonComponent], template: `

Заявка на доставку груза №CDEK-2025-00478312 готова к оформлению.

Вес отправления: 3,5 кг, габариты: 40×30×20 см. Ориентировочный срок — 3 рабочих дня.

- - + +
`, }) @@ -26,15 +25,15 @@ export class DialogDynamicContentComponent { export const template = `
- +
`; @Component({ selector: 'app-dialog-dynamic', standalone: true, - imports: [Button], - providers: [DialogService, UiDialogService], + imports: [ButtonComponent], + providers: [UiDialogService.providers()], template, }) export class DialogDynamicComponent { From 58640e1ad6b662b06051606d949051c33dcdb59e Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Fri, 17 Apr 2026 19:22:45 +0700 Subject: [PATCH 112/258] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0=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"` (статичный шаблон) | -| ` \`, }) export class DialogDynamicComponent { - constructor(private readonly dialogService: UiDialogService) {} + constructor( + private readonly dialogService: UiDialogService, + private readonly injector: Injector, + ) {} open(): void { - this.dialogService.open(DialogDynamicContentComponent, { + this.dialogService.open(DialogDynamicContentComponent, this.injector, { header: 'Подтверждение заявки', modal: true, }); diff --git a/src/stories/components/dialog/examples/dialog-dynamic.component.ts b/src/stories/components/dialog/examples/dialog-dynamic.component.ts index b742336e..48ecf6ae 100644 --- a/src/stories/components/dialog/examples/dialog-dynamic.component.ts +++ b/src/stories/components/dialog/examples/dialog-dynamic.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, Injector } from '@angular/core'; import { ButtonComponent } from '../../../../lib/components/button/button.component'; import { DynamicDialogRef, UiDialogService } from '../../../../lib/components/dialog/dialog-open.service'; @@ -33,14 +33,16 @@ export const template = ` selector: 'app-dialog-dynamic', standalone: true, imports: [ButtonComponent], - providers: [UiDialogService.providers()], template, }) export class DialogDynamicComponent { - constructor(private readonly dialogService: UiDialogService) {} + constructor( + private readonly dialogService: UiDialogService, + private readonly injector: Injector, + ) {} open(): void { - this.dialogService.open(DialogDynamicContentComponent, { + this.dialogService.open(DialogDynamicContentComponent, this.injector, { header: 'Подтверждение заявки', modal: true, }); From d2925f2bfbe19587c030bb9e6ed3f24259990eb3 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Fri, 17 Apr 2026 23:04:23 +0700 Subject: [PATCH 114/258] =?UTF-8?q?input-group:=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=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 --- .../inputgroup/input-group-addon.component.ts | 14 +++ .../inputgroup/input-group.component.ts | 24 +++++ src/prime-preset/map-tokens.ts | 5 + .../tokens/components/inputgroup.ts | 94 +++++++++++++++++++ .../inputgroup-addon-both.component.ts | 63 +++++++++++++ .../inputgroup-addon-right.component.ts | 61 ++++++++++++ .../examples/inputgroup-disabled.component.ts | 61 ++++++++++++ .../inputgroup-with-text.component.ts | 61 ++++++++++++ .../examples/inputgroup-xlarge.component.ts | 61 ++++++++++++ .../inputgroup/inputgroup.stories.ts | 92 ++++++++++++++++++ 10 files changed, 536 insertions(+) create mode 100644 src/lib/components/inputgroup/input-group-addon.component.ts create mode 100644 src/lib/components/inputgroup/input-group.component.ts create mode 100644 src/prime-preset/tokens/components/inputgroup.ts create mode 100644 src/stories/components/inputgroup/examples/inputgroup-addon-both.component.ts create mode 100644 src/stories/components/inputgroup/examples/inputgroup-addon-right.component.ts create mode 100644 src/stories/components/inputgroup/examples/inputgroup-disabled.component.ts create mode 100644 src/stories/components/inputgroup/examples/inputgroup-with-text.component.ts create mode 100644 src/stories/components/inputgroup/examples/inputgroup-xlarge.component.ts create mode 100644 src/stories/components/inputgroup/inputgroup.stories.ts diff --git a/src/lib/components/inputgroup/input-group-addon.component.ts b/src/lib/components/inputgroup/input-group-addon.component.ts new file mode 100644 index 00000000..fba19611 --- /dev/null +++ b/src/lib/components/inputgroup/input-group-addon.component.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; +import { InputGroupAddon } from 'primeng/inputgroupaddon'; + +@Component({ + selector: 'input-group-addon', + standalone: true, + imports: [InputGroupAddon], + template: ` + + + + `, +}) +export class InputGroupAddonComponent {} diff --git a/src/lib/components/inputgroup/input-group.component.ts b/src/lib/components/inputgroup/input-group.component.ts new file mode 100644 index 00000000..273624fc --- /dev/null +++ b/src/lib/components/inputgroup/input-group.component.ts @@ -0,0 +1,24 @@ +import { Component, Input } from '@angular/core'; +import { NgClass } from '@angular/common'; +import { InputGroup } from 'primeng/inputgroup'; + +export type InputGroupSize = 'small' | 'base' | 'large' | 'xlarge'; + +@Component({ + selector: 'input-group', + standalone: true, + imports: [InputGroup, NgClass], + template: ` + + + + `, +}) +export class InputGroupComponent { + @Input() size: InputGroupSize = 'base'; + + get sizeClass(): string { + if (this.size === 'xlarge') return 'p-inputgroup-xlg'; + return ''; + } +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 09d9449d..9690f080 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -9,6 +9,7 @@ import { checkboxCss } from './tokens/components/checkbox'; import { inputtextCss } from './tokens/components/inputtext'; import { progressspinnerCss } from './tokens/components/progressspinner'; import { tagCss } from './tokens/components/tag'; +import { inputgroupCss } from './tokens/components/inputgroup'; import { tooltipCss } from './tokens/components/tooltip'; const presetTokens: Preset = { @@ -32,6 +33,10 @@ const presetTokens: Preset = { ...(tokens.components.progressspinner as unknown as ComponentsDesignTokens['progressspinner']), css: progressspinnerCss, }, + inputgroup: { + ...(tokens.components.inputgroup as unknown as ComponentsDesignTokens['inputgroup']), + css: inputgroupCss, + }, inputtext: { ...(tokens.components.inputtext as unknown as ComponentsDesignTokens['inputtext']), css: inputtextCss, diff --git a/src/prime-preset/tokens/components/inputgroup.ts b/src/prime-preset/tokens/components/inputgroup.ts new file mode 100644 index 00000000..eaf2c78a --- /dev/null +++ b/src/prime-preset/tokens/components/inputgroup.ts @@ -0,0 +1,94 @@ +export const inputgroupCss = ({ dt }: { dt: (token: string) => string }): string => ` + +/* ─── Корректировка flex-layout через Angular-обёртки ─── */ + +/* + * display: contents делает враппер-элементы прозрачными в layout-дереве: + * p-inputgroupaddon и input.p-inputtext становятся прямыми flex-элементами + * p-inputgroup. Это позволяет: + * - align-items: stretch работать напрямую → правильная высота аддона + * - границам быть на одном уровне → нет удвоения top/bottom border + * - flex: 1 1 auto; width: 1% на input работать нативно через PrimeNG + * CSS-селекторы по-прежнему работают (DOM-дерево не меняется). + */ +.p-inputgroup > input-group-addon { + display: contents; +} + +.p-inputgroup > input-text { + display: contents; +} + +/* ─── Корректировка border-radius и границ ─── */ + +/* + * p-inputgroupaddon является :first-child И :last-child своего прямого родителя + * input-group-addon, поэтому PrimeNG добавляет ему оба inline-бордера. + * Сбрасываем их и переназначаем по позиции аддона в группе. + */ +.p-inputgroup > input-group-addon > .p-inputgroupaddon { + border-radius: 0; + border-inline-start: none; + border-inline-end: none; +} + +/* Первый элемент группы — аддон: левые углы + левая граница */ +.p-inputgroup > input-group-addon:first-child > .p-inputgroupaddon { + border-start-start-radius: ${dt('inputgroup.addon.borderRadius')}; + border-end-start-radius: ${dt('inputgroup.addon.borderRadius')}; + border-inline-start: ${dt('inputgroup.extend.borderWidth')} solid ${dt('inputgroup.addon.borderColor')}; +} + +/* Последний элемент группы — аддон: правые углы + правая граница */ +.p-inputgroup > input-group-addon:last-child > .p-inputgroupaddon { + border-start-end-radius: ${dt('inputgroup.addon.borderRadius')}; + border-end-end-radius: ${dt('inputgroup.addon.borderRadius')}; + border-inline-end: ${dt('inputgroup.extend.borderWidth')} solid ${dt('inputgroup.addon.borderColor')}; +} + +/* Аддон сразу после другого аддона: левая граница как разделитель */ +.p-inputgroup > input-group-addon + input-group-addon > .p-inputgroupaddon { + border-inline-start: ${dt('inputgroup.extend.borderWidth')} solid ${dt('inputgroup.addon.borderColor')}; +} + +/* Сброс border-radius у input внутри input-text-обёртки */ +.p-inputgroup > input-text .p-inputtext { + border-radius: 0; + margin: 0; +} + +/* Первый элемент группы — input: левые углы */ +.p-inputgroup > input-text:first-child .p-inputtext { + border-start-start-radius: ${dt('inputgroup.addon.borderRadius')}; + border-end-start-radius: ${dt('inputgroup.addon.borderRadius')}; +} + +/* Последний элемент группы — input: правые углы */ +.p-inputgroup > input-text:last-child .p-inputtext { + border-start-end-radius: ${dt('inputgroup.addon.borderRadius')}; + border-end-end-radius: ${dt('inputgroup.addon.borderRadius')}; +} + +/* ─── Addon в disabled состоянии ─── */ +.p-inputgroup:has(input[disabled]) .p-inputgroupaddon, +.p-inputgroup:has(.p-inputtext[disabled]) .p-inputgroupaddon, +.p-inputgroup:has(.p-component[disabled]) .p-inputgroupaddon { + background: ${dt('inputtext.root.disabledBackground')}; + color: ${dt('inputtext.root.disabledColor')}; +} + +/* ─── Иконка внутри addon ─── */ +.p-inputgroup .p-inputgroupaddon i { + font-size: ${dt('inputgroup.extend.iconSize')}; +} + +/* ─── Extra Large ─── */ +.p-inputgroup.p-inputgroup-xlg .p-inputgroupaddon { + font-size: ${dt('inputtext.extend.extXlg.fontSize')}; + padding: ${dt('inputtext.extend.extXlg.paddingY')} ${dt('inputtext.extend.extXlg.paddingX')}; +} + +.p-inputgroup.p-inputgroup-xlg .p-inputgroupaddon i { + font-size: ${dt('inputtext.extend.extXlg.fontSize')}; +} +`; diff --git a/src/stories/components/inputgroup/examples/inputgroup-addon-both.component.ts b/src/stories/components/inputgroup/examples/inputgroup-addon-both.component.ts new file mode 100644 index 00000000..0fe1a713 --- /dev/null +++ b/src/stories/components/inputgroup/examples/inputgroup-addon-both.component.ts @@ -0,0 +1,63 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { FormsModule } from '@angular/forms'; +import { InputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; +import { InputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; +import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; + +const template = ` +
+ + + + + +
+`; +const styles = ''; + +@Component({ + selector: 'app-inputgroup-addon-both', + standalone: true, + imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + template, + styles, +}) +export class InputGroupAddonBothComponent { + value = ''; +} + +export const AddonBoth: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Аддоны расположены с обеих сторон — например, иконка-префикс и кнопка поиска.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { InputGroupComponent, InputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-inputgroup-addon-both', + standalone: true, + imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + template: \` + + + + + + \`, +}) +export class InputGroupAddonBothComponent { + value = ''; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/inputgroup/examples/inputgroup-addon-right.component.ts b/src/stories/components/inputgroup/examples/inputgroup-addon-right.component.ts new file mode 100644 index 00000000..1871478d --- /dev/null +++ b/src/stories/components/inputgroup/examples/inputgroup-addon-right.component.ts @@ -0,0 +1,61 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { FormsModule } from '@angular/forms'; +import { InputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; +import { InputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; +import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; + +const template = ` +
+ + + руб. + +
+`; +const styles = ''; + +@Component({ + selector: 'app-inputgroup-addon-right', + standalone: true, + imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + template, + styles, +}) +export class InputGroupAddonRightComponent { + value = ''; +} + +export const AddonRight: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Аддон расположен справа — используется для единиц измерения, валюты или суффиксов.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { InputGroupComponent, InputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-inputgroup-addon-right', + standalone: true, + imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + template: \` + + + руб. + + \`, +}) +export class InputGroupAddonRightComponent { + value = ''; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/inputgroup/examples/inputgroup-disabled.component.ts b/src/stories/components/inputgroup/examples/inputgroup-disabled.component.ts new file mode 100644 index 00000000..a3a733ce --- /dev/null +++ b/src/stories/components/inputgroup/examples/inputgroup-disabled.component.ts @@ -0,0 +1,61 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { FormsModule } from '@angular/forms'; +import { InputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; +import { InputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; +import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; + +const template = ` +
+ + + + +
+`; +const styles = ''; + +@Component({ + selector: 'app-inputgroup-disabled', + standalone: true, + imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + template, + styles, +}) +export class InputGroupDisabledComponent { + value = ''; +} + +export const Disabled: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Отключённое состояние — аддоны автоматически получают стили disabled вместе с полем ввода.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { InputGroupComponent, InputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-inputgroup-disabled', + standalone: true, + imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + template: \` + + + + + \`, +}) +export class InputGroupDisabledComponent { + value = ''; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/inputgroup/examples/inputgroup-with-text.component.ts b/src/stories/components/inputgroup/examples/inputgroup-with-text.component.ts new file mode 100644 index 00000000..3af11c41 --- /dev/null +++ b/src/stories/components/inputgroup/examples/inputgroup-with-text.component.ts @@ -0,0 +1,61 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { FormsModule } from '@angular/forms'; +import { InputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; +import { InputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; +import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; + +const template = ` +
+ + @ + + +
+`; +const styles = ''; + +@Component({ + selector: 'app-inputgroup-with-text', + standalone: true, + imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + template, + styles, +}) +export class InputGroupWithTextComponent { + value = ''; +} + +export const WithText: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'В качестве наполнения аддона можно использовать обычный текст — например, символ валюты или префикс.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { InputGroupComponent, InputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-inputgroup-with-text', + standalone: true, + imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + template: \` + + @ + + + \`, +}) +export class InputGroupWithTextComponent { + value = ''; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/inputgroup/examples/inputgroup-xlarge.component.ts b/src/stories/components/inputgroup/examples/inputgroup-xlarge.component.ts new file mode 100644 index 00000000..37643d5a --- /dev/null +++ b/src/stories/components/inputgroup/examples/inputgroup-xlarge.component.ts @@ -0,0 +1,61 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { FormsModule } from '@angular/forms'; +import { InputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; +import { InputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; +import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; + +const template = ` +
+ + + + +
+`; +const styles = ''; + +@Component({ + selector: 'app-inputgroup-xlarge', + standalone: true, + imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + template, + styles, +}) +export class InputGroupXlargeComponent { + value = ''; +} + +export const XLarge: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Увеличенный размер группы ввода — для акцентных форм и поисковых строк.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { InputGroupComponent, InputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-inputgroup-xlarge', + standalone: true, + imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + template: \` + + + + + \`, +}) +export class InputGroupXlargeComponent { + value = ''; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/inputgroup/inputgroup.stories.ts b/src/stories/components/inputgroup/inputgroup.stories.ts new file mode 100644 index 00000000..d833fc31 --- /dev/null +++ b/src/stories/components/inputgroup/inputgroup.stories.ts @@ -0,0 +1,92 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { FormsModule } from '@angular/forms'; +import { InputGroupComponent } from '../../../lib/components/inputgroup/input-group.component'; +import { InputGroupAddonComponent } from '../../../lib/components/inputgroup/input-group-addon.component'; +import { InputTextComponent } from '../../../lib/components/inputtext/inputtext.component'; +import { InputGroupWithTextComponent, WithText } from './examples/inputgroup-with-text.component'; +import { InputGroupDisabledComponent, Disabled } from './examples/inputgroup-disabled.component'; +import { InputGroupXlargeComponent, XLarge } from './examples/inputgroup-xlarge.component'; +import { InputGroupAddonRightComponent, AddonRight } from './examples/inputgroup-addon-right.component'; +import { InputGroupAddonBothComponent, AddonBoth } from './examples/inputgroup-addon-both.component'; + +const meta: Meta = { + title: 'Components/Form/InputGroup', + component: InputGroupComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + InputGroupComponent, + InputGroupAddonComponent, + InputTextComponent, + FormsModule, + InputGroupWithTextComponent, + InputGroupDisabledComponent, + InputGroupXlargeComponent, + InputGroupAddonRightComponent, + InputGroupAddonBothComponent, + ], + }), + ], + parameters: { + docs: { + description: { + component: `Группа полей ввода для объединения с аддонами (иконками или текстом). + +\`\`\`typescript +import { InputGroupComponent, InputGroupAddonComponent } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-inputgroup' }, + }, + argTypes: { + size: { + control: 'select', + options: ['small', 'base', 'large', 'xlarge'], + description: 'Размер группы (влияет на паддинги и шрифты аддонов)', + table: { + category: 'Props', + defaultValue: { summary: "'base'" }, + type: { summary: "'small' | 'base' | 'large' | 'xlarge'" }, + }, + }, + }, + args: { + size: 'base', + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + name: 'Default', + render: (args) => { + const groupParts: string[] = []; + if (args.size && args.size !== 'base') groupParts.push(`size="${args.size}"`); + + const groupOpen = groupParts.length + ? `` + : ``; + + const inputSize = args.size && args.size !== 'base' ? ` size="${args.size}"` : ''; + + const template = ` +${groupOpen} + + +`; + + return { props: { ...args, value: '' }, template }; + }, + parameters: { + docs: { + description: { + story: 'Базовый пример группы ввода с иконкой. Используйте Controls для изменения размера.', + }, + }, + }, +}; + +export { WithText, AddonRight, AddonBoth, Disabled, XLarge }; From 99bfd5f021bcf53deb100d33ff62b30c7fcc95cc Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Sun, 19 Apr 2026 02:36:10 +0700 Subject: [PATCH 115/258] cr fixes --- src/lib/components/dialog/dialog-open.service.ts | 8 ++++++-- .../dialog/examples/dialog-dynamic.component.ts | 3 +-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/lib/components/dialog/dialog-open.service.ts b/src/lib/components/dialog/dialog-open.service.ts index c6b19ee6..1a91bb96 100644 --- a/src/lib/components/dialog/dialog-open.service.ts +++ b/src/lib/components/dialog/dialog-open.service.ts @@ -11,14 +11,18 @@ export { DynamicDialogRef, DynamicDialogConfig }; @Injectable({ providedIn: 'root' }) export class UiDialogService { - open(componentType: Type, injector: Injector, config: UiDynamicDialogConfig = {}): DynamicDialogRef | null { + + constructor(private readonly injector: Injector) { + } + + open(componentType: Type, config: UiDynamicDialogConfig = {}): DynamicDialogRef | null { const { size, styleClass, ...rest } = config; const sizeClass = this.toSizeClass(size); const mergedStyleClass = [sizeClass, styleClass].filter(Boolean).join(' '); const childInjector = Injector.create({ providers: [DialogService], - parent: injector, + parent: this.injector, }); const dialogService = childInjector.get(DialogService); diff --git a/src/stories/components/dialog/examples/dialog-dynamic.component.ts b/src/stories/components/dialog/examples/dialog-dynamic.component.ts index 48ecf6ae..fc4c7251 100644 --- a/src/stories/components/dialog/examples/dialog-dynamic.component.ts +++ b/src/stories/components/dialog/examples/dialog-dynamic.component.ts @@ -38,11 +38,10 @@ export const template = ` export class DialogDynamicComponent { constructor( private readonly dialogService: UiDialogService, - private readonly injector: Injector, ) {} open(): void { - this.dialogService.open(DialogDynamicContentComponent, this.injector, { + this.dialogService.open(DialogDynamicContentComponent, { header: 'Подтверждение заявки', modal: true, }); From 946783b490573cc33d3343380a2a552059781c76 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Sun, 19 Apr 2026 03:16:43 +0700 Subject: [PATCH 116/258] cr fixes --- .../components/listbox/listbox.component.ts | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/lib/components/listbox/listbox.component.ts b/src/lib/components/listbox/listbox.component.ts index 6d3a7366..7bbf753a 100644 --- a/src/lib/components/listbox/listbox.component.ts +++ b/src/lib/components/listbox/listbox.component.ts @@ -1,11 +1,14 @@ -import { Component, EventEmitter, Input, Optional, Output, Self } from '@angular/core'; -import { ControlValueAccessor, FormsModule, NgControl } from '@angular/forms'; +import { Component, EventEmitter, Input, Output, forwardRef } from '@angular/core'; +import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Listbox, ListboxChangeEvent } from 'primeng/listbox'; @Component({ selector: 'listbox', standalone: true, imports: [Listbox, FormsModule], + providers: [ + { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ListboxComponent), multi: true }, + ], template: ` `, }) @@ -51,16 +54,19 @@ export class ListboxComponent implements ControlValueAccessor { private _onChange: (value: any) => void = () => {}; private _onTouched: () => void = () => {}; - constructor(@Optional() @Self() private ngControl: NgControl) { - if (ngControl) ngControl.valueAccessor = this; - } - get isDisabled(): boolean { return this._disabled; } onChangeHandler(event: ListboxChangeEvent): void { + // Обновляем внутреннее значение и уведомляем форму об изменении. + this.modelValue = event.value; this._onChange(event.value); + } + + onBlurHandler(event: FocusEvent): void { + // emit external onBlur and mark control as touched for forms + this.onBlur.emit(event); this._onTouched(); } From f1cb0f5612a5d9feb05e43c49ec5c8de106fe8db Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 09:37:56 +0700 Subject: [PATCH 117/258] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D1=91=D0=BD=20.gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 808f9bdc..ce8e3c03 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ src/assets/components/themes /storybook-static /debug-storybook.log /documentation.json + +.claude/* \ No newline at end of file From e04c0f21435dbb5162dc38eeedd61342819ade33 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 09:51:07 +0700 Subject: [PATCH 118/258] =?UTF-8?q?refactor(toast):=20=D1=81=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=B0=D1=82=D1=8C=20UiToastService=20=D0=BA=D0=B0=D0=BA?= =?UTF-8?q?=20=D0=BE=D0=B1=D1=91=D1=80=D1=82=D0=BA=D1=83=20=D0=BD=D0=B0?= =?UTF-8?q?=D0=B4=20MessageService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Аналогично UiDialogService — сервис скрывает primeng от потребителей. ToastComponent: убран scoped MessageService, добавлен проброс pt. --- src/lib/components/toast/toast.component.ts | 5 ++-- src/lib/components/toast/toast.service.ts | 30 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 src/lib/components/toast/toast.service.ts diff --git a/src/lib/components/toast/toast.component.ts b/src/lib/components/toast/toast.component.ts index 21a557fd..d9a86641 100644 --- a/src/lib/components/toast/toast.component.ts +++ b/src/lib/components/toast/toast.component.ts @@ -1,6 +1,5 @@ import { Component, Input } from '@angular/core'; import { Toast } from 'primeng/toast'; -import { MessageService } from 'primeng/api'; import { SharedModule } from 'primeng/api'; export type ToastSeverity = 'success' | 'info' | 'warn' | 'error' | 'secondary' | 'contrast'; @@ -24,9 +23,8 @@ const SEVERITY_ICONS: Record = { selector: 'ui-toast', standalone: true, imports: [Toast, SharedModule], - providers: [MessageService], template: ` - +
@@ -44,6 +42,7 @@ export class ToastComponent { @Input() position: ToastPosition = 'top-right'; @Input() key: string | undefined = undefined; @Input() life = 5000; + @Input() pt: Record | undefined = undefined; resolveIcon(message: { severity?: string; icon?: string }): string { return message.icon ?? SEVERITY_ICONS[message.severity ?? 'info'] ?? 'ti ti-info-circle'; diff --git a/src/lib/components/toast/toast.service.ts b/src/lib/components/toast/toast.service.ts new file mode 100644 index 00000000..20b84326 --- /dev/null +++ b/src/lib/components/toast/toast.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { MessageService } from 'primeng/api'; +import { ToastSeverity } from './toast.component'; + +export interface UiToastMessage { + key?: string; + severity?: ToastSeverity; + summary?: string; + detail?: string; + life?: number; + icon?: string; + closable?: boolean; + data?: unknown; +} + +export { MessageService }; + +@Injectable({ providedIn: 'root' }) +export class UiToastService { + + constructor(private readonly messageService: MessageService) {} + + add(message: UiToastMessage): void { + this.messageService.add(message); + } + + clear(key?: string): void { + this.messageService.clear(key); + } +} From 0f944e8e682f5a7d5bbface5eb7d07f08bb6889d Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 09:51:14 +0700 Subject: [PATCH 119/258] =?UTF-8?q?refactor(toast):=20=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D1=81=D1=8B=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D1=83=D1=8E=D1=82=20ToastComponent=20=D0=B8=20UiToastSer?= =?UTF-8?q?vice=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20primeng?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Все toast example-компоненты переведены на ui-toast и UiToastService — прямые импорты Toast, MessageService, SharedModule из primeng убраны. --- .../examples/toast-position.component.ts | 34 +++++--------- .../examples/toast-severities.component.ts | 45 +++++-------------- .../toast/examples/toast-width.component.ts | 31 +++++-------- .../toast-with-close-button.component.ts | 26 ++++------- .../examples/toast-with-content.component.ts | 33 ++++---------- 5 files changed, 50 insertions(+), 119 deletions(-) diff --git a/src/stories/components/toast/examples/toast-position.component.ts b/src/stories/components/toast/examples/toast-position.component.ts index 4b6492f2..dcd3e43f 100644 --- a/src/stories/components/toast/examples/toast-position.component.ts +++ b/src/stories/components/toast/examples/toast-position.component.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { Toast } from 'primeng/toast'; import { Button } from 'primeng/button'; -import { MessageService, SharedModule } from 'primeng/api'; +import { ToastComponent } from '../../../../lib/components/toast/toast.component'; +import { UiToastService } from '../../../../lib/components/toast/toast.service'; const POSITIONS = [ { position: 'top-left', label: 'Вверх слева', key: 'pos-top-left' }, @@ -15,16 +15,7 @@ const POSITIONS = [ const template = ` @for (p of positions; track p.key) { - - -
- -
- {{ message.summary }} -
{{ message.detail }}
-
-
-
+ }
@@ -42,18 +33,17 @@ const styles = ''; @Component({ selector: 'app-toast-position', standalone: true, - imports: [Toast, Button, SharedModule], - providers: [MessageService], + imports: [ToastComponent, Button], template, styles, }) export class ToastPositionComponent { readonly positions = POSITIONS; - constructor(private readonly messageService: MessageService) {} + constructor(private readonly toastService: UiToastService) {} show(key: string, position: string): void { - this.messageService.add({ + this.toastService.add({ key, severity: 'info', summary: 'Сообщение', @@ -74,12 +64,12 @@ export const Position: StoryObj = { source: { language: 'ts', code: ` - - - - - - + + + + + + `, }, }, diff --git a/src/stories/components/toast/examples/toast-severities.component.ts b/src/stories/components/toast/examples/toast-severities.component.ts index 9dbbe33c..b6b60345 100644 --- a/src/stories/components/toast/examples/toast-severities.component.ts +++ b/src/stories/components/toast/examples/toast-severities.component.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { Toast } from 'primeng/toast'; import { Button } from 'primeng/button'; -import { MessageService, SharedModule } from 'primeng/api'; +import { ToastComponent } from '../../../../lib/components/toast/toast.component'; +import { UiToastService } from '../../../../lib/components/toast/toast.service'; const SEVERITIES = [ { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, @@ -12,16 +12,7 @@ const SEVERITIES = [ ] as const; const template = ` - - -
- -
- {{ message.summary }} -
{{ message.detail }}
-
-
-
+
@for (s of severities; track s.type) { @@ -54,20 +45,19 @@ const styles = ''; @Component({ selector: 'app-toast-severities', standalone: true, - imports: [Toast, Button, SharedModule], - providers: [MessageService], + imports: [ToastComponent, Button], template, styles, }) export class ToastSeveritiesComponent { readonly severities = SEVERITIES; - constructor(private readonly messageService: MessageService) {} + constructor(private readonly toastService: UiToastService) {} show(severity: string, icon: string): void { - this.messageService.add({ + this.toastService.add({ key: 'severities', - severity, + severity: severity as any, summary: 'Сообщение', detail: 'Подпись', life: 5000, @@ -87,33 +77,22 @@ export const Severities: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MessageService, SharedModule } from 'primeng/api'; -import { Toast } from 'primeng/toast'; +import { ToastComponent, UiToastService } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-example', standalone: true, - imports: [Toast, SharedModule], - providers: [MessageService], + imports: [ToastComponent], template: \` - - -
- -
- {{ message.summary }} -
{{ message.detail }}
-
-
-
+ \`, }) export class ExampleComponent { - constructor(private messageService: MessageService) {} + constructor(private toastService: UiToastService) {} show(): void { - this.messageService.add({ + this.toastService.add({ key: 'my-toast', severity: 'info', summary: 'Сообщение', diff --git a/src/stories/components/toast/examples/toast-width.component.ts b/src/stories/components/toast/examples/toast-width.component.ts index 7c78814b..5bbcf9e1 100644 --- a/src/stories/components/toast/examples/toast-width.component.ts +++ b/src/stories/components/toast/examples/toast-width.component.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { Toast } from 'primeng/toast'; import { Button } from 'primeng/button'; -import { MessageService, SharedModule } from 'primeng/api'; +import { ToastComponent } from '../../../../lib/components/toast/toast.component'; +import { UiToastService } from '../../../../lib/components/toast/toast.service'; const SIZES = [ { key: 'sm', label: 'Small (20rem)', width: '20rem', cssVar: '20rem' }, @@ -12,19 +12,10 @@ const SIZES = [ ] as const; const template = ` - - -
- -
- {{ message.summary }} -
{{ message.detail }}
-
-
-
+>
@for (s of sizes; track s.key) { @@ -59,8 +50,7 @@ const styles = ''; @Component({ selector: 'app-toast-width', standalone: true, - imports: [Toast, Button, SharedModule], - providers: [MessageService], + imports: [ToastComponent, Button], template, styles, }) @@ -68,12 +58,12 @@ export class ToastWidthComponent { readonly sizes = SIZES; currentWidth = '25rem'; - constructor(private readonly messageService: MessageService) {} + constructor(private readonly toastService: UiToastService) {} show(cssVar: string): void { this.currentWidth = cssVar; - this.messageService.clear('width-preview'); - this.messageService.add({ + this.toastService.clear('width-preview'); + this.toastService.add({ key: 'width-preview', severity: 'info', summary: 'Сообщение', @@ -94,9 +84,8 @@ export const Width: StoryObj = { source: { language: 'ts', code: ` - - ... - + + `, }, }, diff --git a/src/stories/components/toast/examples/toast-with-close-button.component.ts b/src/stories/components/toast/examples/toast-with-close-button.component.ts index eabd523a..f308c0a6 100644 --- a/src/stories/components/toast/examples/toast-with-close-button.component.ts +++ b/src/stories/components/toast/examples/toast-with-close-button.component.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { Toast } from 'primeng/toast'; import { Button } from 'primeng/button'; -import { MessageService, SharedModule } from 'primeng/api'; +import { ToastComponent } from '../../../../lib/components/toast/toast.component'; +import { UiToastService } from '../../../../lib/components/toast/toast.service'; const SEVERITIES = [ { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, @@ -12,16 +12,7 @@ const SEVERITIES = [ ] as const; const template = ` - - -
- -
- {{ message.summary }} -
{{ message.detail }}
-
-
-
+
@for (s of severities; track s.type) { @@ -60,20 +51,19 @@ const styles = ''; @Component({ selector: 'app-toast-with-close-button', standalone: true, - imports: [Toast, Button, SharedModule], - providers: [MessageService], + imports: [ToastComponent, Button], template, styles, }) export class ToastWithCloseButtonComponent { readonly severities = SEVERITIES; - constructor(private readonly messageService: MessageService) {} + constructor(private readonly toastService: UiToastService) {} show(severity: string, icon: string): void { - this.messageService.add({ + this.toastService.add({ key: 'with-close', - severity, + severity: severity as any, summary: 'Сообщение', detail: 'Подпись', life: 5000, @@ -93,7 +83,7 @@ export const WithCloseButton: StoryObj = { source: { language: 'ts', code: ` -this.messageService.add({ +this.toastService.add({ key: 'my-toast', severity: 'info', summary: 'Сообщение', diff --git a/src/stories/components/toast/examples/toast-with-content.component.ts b/src/stories/components/toast/examples/toast-with-content.component.ts index 5aadaf6b..cde8df69 100644 --- a/src/stories/components/toast/examples/toast-with-content.component.ts +++ b/src/stories/components/toast/examples/toast-with-content.component.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { Toast } from 'primeng/toast'; import { Button } from 'primeng/button'; -import { MessageService, SharedModule } from 'primeng/api'; +import { ToastComponent } from '../../../../lib/components/toast/toast.component'; +import { UiToastService } from '../../../../lib/components/toast/toast.service'; const SEVERITIES = [ { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, @@ -12,23 +12,7 @@ const SEVERITIES = [ ] as const; const template = ` - - -
- -
- {{ message.summary }} -
{{ message.detail }}
-
-
Дополнительный контент
-
-
-
Ячейка 1
-
Ячейка 2
-
-
-
-
+
@for (s of severities; track s.type) { @@ -74,20 +58,19 @@ const styles = ''; @Component({ selector: 'app-toast-with-content', standalone: true, - imports: [Toast, Button, SharedModule], - providers: [MessageService], + imports: [ToastComponent, Button], template, styles, }) export class ToastWithContentComponent { readonly severities = SEVERITIES; - constructor(private readonly messageService: MessageService) {} + constructor(private readonly toastService: UiToastService) {} show(severity: string, icon: string): void { - this.messageService.add({ + this.toastService.add({ key: 'with-content', - severity, + severity: severity as any, summary: 'Сообщение', detail: 'Подпись', life: 5000, @@ -107,7 +90,7 @@ export const WithContent: StoryObj = { source: { language: 'ts', code: ` -this.messageService.add({ +this.toastService.add({ key: 'my-toast', severity: 'info', summary: 'Сообщение', From 9dae52d7e11a5dd0945ed17f53b8a3fab0bad2b8 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 09:51:21 +0700 Subject: [PATCH 120/258] =?UTF-8?q?refactor(toast):=20=D0=BE=D0=B1=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=B8=D1=82=D1=8C=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=B0=D1=86=D0=B8=D1=8E=20stories=20=D0=BD?= =?UTF-8?q?=D0=B0=20UiToastService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Документация в toast.stories.ts теперь указывает на UiToastService вместо MessageService из primeng. --- src/stories/components/toast/toast.stories.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/stories/components/toast/toast.stories.ts b/src/stories/components/toast/toast.stories.ts index 6ca7b620..05b37cb5 100644 --- a/src/stories/components/toast/toast.stories.ts +++ b/src/stories/components/toast/toast.stories.ts @@ -28,11 +28,10 @@ const meta: Meta = { designTokens: { prefix: '--p-toast' }, docs: { description: { - component: `Компонент для отображения всплывающих уведомлений поверх интерфейса. Требует подключения \`MessageService\`. + component: `Компонент для отображения всплывающих уведомлений поверх интерфейса. Требует подключения \`UiToastService\`. \`\`\`typescript -import { ToastComponent } from '@cdek-it/angular-ui-kit'; -import { MessageService } from 'primeng/api'; +import { ToastComponent, UiToastService } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, From 0bf96eff066ec7f6ece0a5c85edb357a99531e6c Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 10:06:16 +0700 Subject: [PATCH 121/258] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D1=91=D0=BD=20.gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 808f9bdc..ce8e3c03 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ src/assets/components/themes /storybook-static /debug-storybook.log /documentation.json + +.claude/* \ No newline at end of file From 36fff85f5ea2b32cc1e3368b516a9e87621016a9 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 10:20:34 +0700 Subject: [PATCH 122/258] =?UTF-8?q?refactor(tabs):=20=D0=B7=D0=B0=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=82=D1=8C=20*ngFor=20=D0=BD=D0=B0=20@for?= =?UTF-8?q?=20=D0=B2=20=D1=88=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/tabs/tabs.component.ts | 42 +++++++++++++---------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/lib/components/tabs/tabs.component.ts b/src/lib/components/tabs/tabs.component.ts index bb25bf53..27d9f0f4 100644 --- a/src/lib/components/tabs/tabs.component.ts +++ b/src/lib/components/tabs/tabs.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { NgFor, NgIf } from '@angular/common'; +import { NgIf } from '@angular/common'; import { Tabs } from 'primeng/tabs'; import { TabList } from 'primeng/tabs'; import { Tab } from 'primeng/tabs'; @@ -20,7 +20,7 @@ export interface TabItem { @Component({ selector: 'tabs', standalone: true, - imports: [Tabs, TabList, Tab, TabPanels, TabPanel, Badge, NgFor, NgIf], + imports: [Tabs, TabList, Tab, TabPanels, TabPanel, Badge, NgIf], template: ` - - - {{ tab.label }} - - + @for (tab of tabs; track tab.value) { + + @if (tab.icon) { + + } + {{ tab.label }} + @if (tab.badge) { + + } + + } - -

{{ tab.content }}

-
+ @for (tab of tabs; track tab.value) { + +

{{ tab.content }}

+
+ }
`, From ee575749fb508c8854d2712d7af5ecf7e6bd34ac Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 10:20:50 +0700 Subject: [PATCH 123/258] =?UTF-8?q?refactor(tabs):=20=D0=B7=D0=B0=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=82=D1=8C=20*ngIf=20=D0=BD=D0=B0=20@if,=20?= =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D1=82=D1=8C=20NgIf=20=D0=B8=D0=BC?= =?UTF-8?q?=D0=BF=D0=BE=D1=80=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/tabs/tabs.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/components/tabs/tabs.component.ts b/src/lib/components/tabs/tabs.component.ts index 27d9f0f4..f88accd1 100644 --- a/src/lib/components/tabs/tabs.component.ts +++ b/src/lib/components/tabs/tabs.component.ts @@ -1,5 +1,4 @@ import { Component, Input } from '@angular/core'; -import { NgIf } from '@angular/common'; import { Tabs } from 'primeng/tabs'; import { TabList } from 'primeng/tabs'; import { Tab } from 'primeng/tabs'; @@ -20,7 +19,7 @@ export interface TabItem { @Component({ selector: 'tabs', standalone: true, - imports: [Tabs, TabList, Tab, TabPanels, TabPanel, Badge, NgIf], + imports: [Tabs, TabList, Tab, TabPanels, TabPanel, Badge], template: ` Date: Mon, 20 Apr 2026 10:21:09 +0700 Subject: [PATCH 124/258] =?UTF-8?q?refactor(tabs):=20=D0=B5=D0=B4=D0=B8?= =?UTF-8?q?=D0=BD=D0=BE=D0=BE=D0=B1=D1=80=D0=B0=D0=B7=D0=BD=D1=8B=D0=B9=20?= =?UTF-8?q?=D1=8D=D0=BA=D1=81=D0=BF=D0=BE=D1=80=D1=82=20=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D1=81=D0=BE=D0=B2=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7?= =?UTF-8?q?=20export=20{=20...=20}?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stories/components/tabs/tabs.stories.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/stories/components/tabs/tabs.stories.ts b/src/stories/components/tabs/tabs.stories.ts index c2fe769e..1f86ad7c 100644 --- a/src/stories/components/tabs/tabs.stories.ts +++ b/src/stories/components/tabs/tabs.stories.ts @@ -1,7 +1,7 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { TabsComponent } from '../../../lib/components/tabs/tabs.component'; -import { TabsWithBadgeComponent, WithBadge as WithBadgeStory } from './examples/tabs-with-badge.component'; -import { TabsWithDisabledComponent, WithDisabled as WithDisabledStory } from './examples/tabs-with-disabled.component'; +import { TabsWithBadgeComponent, WithBadge } from './examples/tabs-with-badge.component'; +import { TabsWithDisabledComponent, WithDisabled } from './examples/tabs-with-disabled.component'; const meta: Meta = { title: 'Components/Menu/Tabs', @@ -105,10 +105,4 @@ export const Default: Story = { }, }; -// ── WithBadge ───────────────────────────────────────────────────────────────── - -export const WithBadge: Story = WithBadgeStory; - -// ── WithDisabled ────────────────────────────────────────────────────────────── - -export const WithDisabled: Story = WithDisabledStory; +export { WithBadge, WithDisabled }; From 33e69badaa7dfe7c0276d2b81a3acaba2f13f83b Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 10:23:37 +0700 Subject: [PATCH 125/258] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D1=91=D0=BD=20.gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 808f9bdc..ce8e3c03 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ src/assets/components/themes /storybook-static /debug-storybook.log /documentation.json + +.claude/* \ No newline at end of file From dc980d116da8d1d085a41deb1bb26ee27b3fd21b Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 13:49:25 +0700 Subject: [PATCH 126/258] modified .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 808f9bdc..ce8e3c03 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ src/assets/components/themes /storybook-static /debug-storybook.log /documentation.json + +.claude/* \ No newline at end of file From 4706a04da43124c8339006934cd0ea09c961c4cb Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 19:47:04 +0700 Subject: [PATCH 127/258] =?UTF-8?q?textarea:=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=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 --- .gitignore | 2 + .../components/textarea/textarea.component.ts | 92 +++++++++ src/prime-preset/map-tokens.ts | 5 + .../tokens/components/textarea.ts | 27 +++ src/prime-preset/tokens/tokens.json | 31 +-- .../examples/textarea-autoresize.component.ts | 49 +++++ .../examples/textarea-disabled.component.ts | 45 ++++ .../examples/textarea-invalid.component.ts | 45 ++++ .../examples/textarea-readonly.component.ts | 45 ++++ .../examples/textarea-sizes.component.ts | 58 ++++++ .../components/textarea/textarea.stories.ts | 193 ++++++++++++++++++ 11 files changed, 579 insertions(+), 13 deletions(-) create mode 100644 src/lib/components/textarea/textarea.component.ts create mode 100644 src/prime-preset/tokens/components/textarea.ts create mode 100644 src/stories/components/textarea/examples/textarea-autoresize.component.ts create mode 100644 src/stories/components/textarea/examples/textarea-disabled.component.ts create mode 100644 src/stories/components/textarea/examples/textarea-invalid.component.ts create mode 100644 src/stories/components/textarea/examples/textarea-readonly.component.ts create mode 100644 src/stories/components/textarea/examples/textarea-sizes.component.ts create mode 100644 src/stories/components/textarea/textarea.stories.ts diff --git a/.gitignore b/.gitignore index 808f9bdc..ce8e3c03 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ src/assets/components/themes /storybook-static /debug-storybook.log /documentation.json + +.claude/* \ No newline at end of file diff --git a/src/lib/components/textarea/textarea.component.ts b/src/lib/components/textarea/textarea.component.ts new file mode 100644 index 00000000..52852c63 --- /dev/null +++ b/src/lib/components/textarea/textarea.component.ts @@ -0,0 +1,92 @@ +import { ChangeDetectionStrategy, Component, Input, Output, EventEmitter, forwardRef } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { NgClass } from '@angular/common'; +import { Textarea } from 'primeng/textarea'; + +export type TextareaSize = 'small' | 'base' | 'large' | 'xlarge'; +export type TextareaVariant = 'outlined' | 'filled'; + +@Component({ + selector: 'ui-textarea', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [Textarea, NgClass], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => TextareaComponent), + multi: true, + }, + ], + template: ` + + `, +}) +export class TextareaComponent implements ControlValueAccessor { + @Input() placeholder = ''; + @Input() size: TextareaSize = 'base'; + @Input() disabled = false; + @Input() readonly = false; + @Input() invalid = false; + @Input() fluid = false; + @Input() autoResize = false; + @Input() rows = 3; + @Input() cols?: number; + @Input() variant: TextareaVariant = 'outlined'; + + @Output() onResize = new EventEmitter<{ height: string }>(); + + modelValue = ''; + + private _onChange: (value: string) => void = () => {}; + + get primeSize(): 'small' | 'large' | undefined { + if (this.size === 'small') return 'small'; + if (this.size === 'large') return 'large'; + return undefined; + } + + get sizeClass(): Record { + return { 'p-textarea-xlg': this.size === 'xlarge' }; + } + + onInput(event: Event): void { + const value = (event.target as HTMLTextAreaElement).value; + this.modelValue = value; + this._onChange(value); + } + + onTouched: () => void = () => {}; + + writeValue(value: string): void { + this.modelValue = value ?? ''; + } + + registerOnChange(fn: (value: string) => void): void { + this._onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 09d9449d..353be0e4 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -9,6 +9,7 @@ import { checkboxCss } from './tokens/components/checkbox'; import { inputtextCss } from './tokens/components/inputtext'; import { progressspinnerCss } from './tokens/components/progressspinner'; import { tagCss } from './tokens/components/tag'; +import { textareaCss } from './tokens/components/textarea'; import { tooltipCss } from './tokens/components/tooltip'; const presetTokens: Preset = { @@ -40,6 +41,10 @@ const presetTokens: Preset = { ...(tokens.components.tag as unknown as ComponentsDesignTokens['tag']), css: tagCss, }, + textarea: { + ...(tokens.components.textarea as unknown as ComponentsDesignTokens['textarea']), + css: textareaCss, + }, tooltip: { ...(tokens.components.tooltip as unknown as ComponentsDesignTokens['tooltip']), css: tooltipCss, diff --git a/src/prime-preset/tokens/components/textarea.ts b/src/prime-preset/tokens/components/textarea.ts new file mode 100644 index 00000000..d35154ad --- /dev/null +++ b/src/prime-preset/tokens/components/textarea.ts @@ -0,0 +1,27 @@ +export const textareaCss = ({ dt }: { dt: (token: string) => string }): string => ` + +/* --- Base --- */ +.p-textarea { + border-width: ${dt('textarea.extend.borderWidth')}; + line-height: ${dt('fonts.lineHeight.250')}; + min-height: ${dt('textarea.extend.minHeight')}; +} + +/* --- Sizes --- */ +.p-textarea.p-textarea-xlg { + font-size: ${dt('textarea.extend.extXlg.fontSize')}; + padding: ${dt('textarea.extend.extXlg.paddingY')} ${dt('textarea.extend.extXlg.paddingX')}; +} + +/* --- States --- */ +.p-textarea:enabled:read-only { + background: ${dt('textarea.extend.readonlyBackground')}; +} + +.p-textarea:is(.p-disabled, :disabled) { + background: ${dt('textarea.disabled.background')}; + color: ${dt('textarea.disabled.color')}; + opacity: 1; +} + +`; diff --git a/src/prime-preset/tokens/tokens.json b/src/prime-preset/tokens/tokens.json index 6fd82189..0afd51d1 100644 --- a/src/prime-preset/tokens/tokens.json +++ b/src/prime-preset/tokens/tokens.json @@ -4703,7 +4703,12 @@ "readonlyBackground": "{form.readonlyBackground}", "borderWidth": "{form.borderWidth}", "iconSize": "{form.icon.300}", - "minHeight": "{form.size.900}" + "minHeight": "{form.size.900}", + "extXlg": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{form.padding.200}", + "paddingY": "{form.padding.500}" + } }, "root": { "background": "{form.background}", @@ -4720,8 +4725,8 @@ "placeholderColor": "{form.placeholderColor}", "invalidPlaceholderColor": "{form.invalidPlaceholderColor}", "shadow": "0", - "paddingX": "{form.paddingX}", - "paddingY": "{form.paddingY}", + "paddingX": "{form.padding.200}", + "paddingY": "{form.padding.300}", "borderRadius": "{form.borderRadius.200}", "transitionDuration": "{form.transitionDuration}", "focusRing": { @@ -4730,17 +4735,17 @@ "color": "{form.focusRing.color}", "offset": "{form.focusRing.offset}", "shadow": "0" + }, + "sm": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{form.padding.200}", + "paddingY": "{form.padding.200}" + }, + "lg": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{form.padding.200}", + "paddingY": "{form.padding.400}" } - }, - "sm": { - "fontSize": "{fonts.fontSize.300}", - "paddingX": "{form.padding.200}", - "paddingY": "{form.padding.200}" - }, - "lg": { - "fontSize": "{fonts.fontSize.300}", - "paddingX": "{form.padding.400}", - "paddingY": "{form.padding.400}" } }, "tieredmenu": { diff --git a/src/stories/components/textarea/examples/textarea-autoresize.component.ts b/src/stories/components/textarea/examples/textarea-autoresize.component.ts new file mode 100644 index 00000000..25913565 --- /dev/null +++ b/src/stories/components/textarea/examples/textarea-autoresize.component.ts @@ -0,0 +1,49 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; + +export const template = ` +
+ + +
+`; +const styles = ''; + +@Component({ + selector: 'app-textarea-autoresize', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TextareaComponent, FormsModule], + template, + styles, +}) +export class TextareaAutoResizeComponent { + value = ''; +} + +export const AutoResize: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Режим авторасширения — поле увеличивается по высоте по мере ввода текста.', + }, + source: { + language: 'ts', + code: `@Component({ + template: \`${template}\`, +})`, + }, + }, + }, +}; diff --git a/src/stories/components/textarea/examples/textarea-disabled.component.ts b/src/stories/components/textarea/examples/textarea-disabled.component.ts new file mode 100644 index 00000000..213d8f0c --- /dev/null +++ b/src/stories/components/textarea/examples/textarea-disabled.component.ts @@ -0,0 +1,45 @@ +import { StoryObj } from '@storybook/angular'; +import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; + +type Story = StoryObj; + +export const Disabled: Story = { + name: 'Disabled', + render: (args) => ({ + props: { ...args, value: 'Текст в заблокированном поле' }, + template: ` + + `, + }), + args: { + disabled: true, + placeholder: 'Введите текст...', + }, + parameters: { + docs: { + description: { + story: 'Отключённое состояние — поле недоступно для взаимодействия.', + }, + source: { + language: 'ts', + code: ` +import { TextareaComponent } from '@cdek-it/angular-ui-kit'; +import { FormsModule } from '@angular/forms'; + +// template: +// + `, + }, + }, + }, +}; diff --git a/src/stories/components/textarea/examples/textarea-invalid.component.ts b/src/stories/components/textarea/examples/textarea-invalid.component.ts new file mode 100644 index 00000000..0ab85e97 --- /dev/null +++ b/src/stories/components/textarea/examples/textarea-invalid.component.ts @@ -0,0 +1,45 @@ +import { StoryObj } from '@storybook/angular'; +import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; + +type Story = StoryObj; + +export const Invalid: Story = { + name: 'Invalid', + render: (args) => ({ + props: { ...args, value: '' }, + template: ` + + `, + }), + args: { + invalid: true, + placeholder: 'Обязательное поле', + }, + parameters: { + docs: { + description: { + story: 'Невалидное состояние — поле выделяется красной рамкой.', + }, + source: { + language: 'ts', + code: ` +import { TextareaComponent } from '@cdek-it/angular-ui-kit'; +import { FormsModule } from '@angular/forms'; + +// template: +// + `, + }, + }, + }, +}; diff --git a/src/stories/components/textarea/examples/textarea-readonly.component.ts b/src/stories/components/textarea/examples/textarea-readonly.component.ts new file mode 100644 index 00000000..71c1550d --- /dev/null +++ b/src/stories/components/textarea/examples/textarea-readonly.component.ts @@ -0,0 +1,45 @@ +import { StoryObj } from '@storybook/angular'; +import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; + +type Story = StoryObj; + +export const Readonly: Story = { + name: 'Readonly', + render: (args) => ({ + props: { ...args, value: 'Только для чтения — этот текст нельзя изменить.' }, + template: ` + + `, + }), + args: { + readonly: true, + placeholder: 'Введите текст...', + }, + parameters: { + docs: { + description: { + story: 'Режим только для чтения — содержимое отображается, но не редактируется.', + }, + source: { + language: 'ts', + code: ` +import { TextareaComponent } from '@cdek-it/angular-ui-kit'; +import { FormsModule } from '@angular/forms'; + +// template: +// + `, + }, + }, + }, +}; diff --git a/src/stories/components/textarea/examples/textarea-sizes.component.ts b/src/stories/components/textarea/examples/textarea-sizes.component.ts new file mode 100644 index 00000000..4643be86 --- /dev/null +++ b/src/stories/components/textarea/examples/textarea-sizes.component.ts @@ -0,0 +1,58 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; + +export const template = ` +
+
+
small
+ +
+
+
base
+ +
+
+
large
+ +
+
+
xlarge
+ +
+
+`; +const styles = ''; + +@Component({ + selector: 'app-textarea-sizes', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TextareaComponent, FormsModule], + template, + styles, +}) +export class TextareaSizesComponent { + value = ''; +} + +export const Sizes: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Все доступные размеры компонента: small, base, large, xlarge.', + }, + source: { + language: 'ts', + code: `@Component({ + template: \`${template}\`, +})`, + }, + }, + }, +}; diff --git a/src/stories/components/textarea/textarea.stories.ts b/src/stories/components/textarea/textarea.stories.ts new file mode 100644 index 00000000..7069b1ed --- /dev/null +++ b/src/stories/components/textarea/textarea.stories.ts @@ -0,0 +1,193 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { FormsModule } from '@angular/forms'; +import { TextareaComponent } from '../../../lib/components/textarea/textarea.component'; +import { Disabled } from './examples/textarea-disabled.component'; +import { Readonly } from './examples/textarea-readonly.component'; +import { Invalid } from './examples/textarea-invalid.component'; +import { AutoResize, TextareaAutoResizeComponent } from './examples/textarea-autoresize.component'; +import { Sizes, TextareaSizesComponent } from './examples/textarea-sizes.component'; + +type TextareaArgs = TextareaComponent; + +const meta: Meta = { + title: 'Components/Form/Textarea', + component: TextareaComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + TextareaComponent, + FormsModule, + TextareaAutoResizeComponent, + TextareaSizesComponent, + ], + }), + ], + parameters: { + designTokens: { prefix: '--p-textarea' }, + docs: { + description: { + component: `Многострочное текстовое поле для ввода данных. Поддерживает авторасширение, состояния disabled/readonly/invalid, размеры и интеграцию с формами через CVA. + +\`\`\`typescript +import { TextareaComponent } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + }, + argTypes: { + placeholder: { + control: 'text', + description: 'Подсказка при пустом поле', + table: { + category: 'Props', + defaultValue: { summary: "''" }, + type: { summary: 'string' }, + }, + }, + size: { + control: 'select', + options: ['small', 'base', 'large', 'xlarge'], + description: 'Размер поля', + table: { + category: 'Props', + defaultValue: { summary: "'base'" }, + type: { summary: "'small' | 'base' | 'large' | 'xlarge'" }, + }, + }, + disabled: { + control: 'boolean', + description: 'Отключает взаимодействие', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + readonly: { + control: 'boolean', + description: 'Только для чтения', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + invalid: { + control: 'boolean', + description: 'Невалидное состояние', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + fluid: { + control: 'boolean', + description: 'Растягивает поле на всю ширину контейнера', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + autoResize: { + control: 'boolean', + description: 'Автоматически увеличивает высоту по мере ввода', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + rows: { + control: 'number', + description: 'Количество видимых строк', + table: { + category: 'Props', + defaultValue: { summary: '3' }, + type: { summary: 'number' }, + }, + }, + cols: { + control: 'number', + description: 'Количество видимых столбцов', + table: { + category: 'Props', + defaultValue: { summary: 'undefined' }, + type: { summary: 'number' }, + }, + }, + variant: { + control: 'select', + options: ['outlined', 'filled'], + description: 'Визуальный вариант поля', + table: { + category: 'Props', + defaultValue: { summary: "'outlined'" }, + type: { summary: "'outlined' | 'filled'" }, + }, + }, + // Скрыть внутренние computed props + modelValue: { table: { disable: true } }, + primeSize: { table: { disable: true } }, + sizeClass: { table: { disable: true } }, + // Events + onResize: { + control: false, + description: 'Событие изменения высоты поля (при autoResize)', + table: { + category: 'Events', + type: { summary: 'EventEmitter<{ height: string }>' }, + }, + }, + }, + args: { + placeholder: 'Введите текст...', + size: 'base', + disabled: false, + readonly: false, + invalid: false, + fluid: false, + autoResize: false, + rows: 3, + variant: 'outlined', + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ────────────────────────────────────────────────────────────────── +export const Default: Story = { + name: 'Default', + render: (args) => { + const parts: string[] = []; + + if (args.placeholder) parts.push(`placeholder="${args.placeholder}"`); + if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); + if (args.disabled) parts.push(`[disabled]="true"`); + if (args.readonly) parts.push(`[readonly]="true"`); + if (args.invalid) parts.push(`[invalid]="true"`); + if (args.fluid) parts.push(`[fluid]="true"`); + if (args.autoResize) parts.push(`[autoResize]="true"`); + if (args.rows && args.rows !== 3) parts.push(`[rows]="${args.rows}"`); + if (args.cols) parts.push(`[cols]="${args.cols}"`); + if (args.variant && args.variant !== 'outlined') parts.push(`variant="${args.variant}"`); + parts.push(`[(ngModel)]="value"`); + + const template = ``; + + return { props: { ...args, value: '' }, template }; + }, + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + }, + }, +}; + +// ── Re-exports from example components ──────────────────────────────────── +export { Disabled, Readonly, Invalid, AutoResize, Sizes }; From 0f358a7c6df85ffb161972fe97e1156be48b5bac Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 20:27:09 +0700 Subject: [PATCH 128/258] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D1=80=D0=BE=D0=B2;=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D1=81=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B8=D1=81=20float=20label?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/tokens.json | 8 +- .../textarea-float-label.component.ts | 145 ++++++++++++++++++ .../examples/textarea-sizes.component.ts | 67 +++----- .../components/textarea/textarea.stories.ts | 13 +- 4 files changed, 183 insertions(+), 50 deletions(-) create mode 100644 src/stories/components/textarea/examples/textarea-float-label.component.ts diff --git a/src/prime-preset/tokens/tokens.json b/src/prime-preset/tokens/tokens.json index 0afd51d1..1121663f 100644 --- a/src/prime-preset/tokens/tokens.json +++ b/src/prime-preset/tokens/tokens.json @@ -4706,7 +4706,7 @@ "minHeight": "{form.size.900}", "extXlg": { "fontSize": "{fonts.fontSize.300}", - "paddingX": "{form.padding.200}", + "paddingX": "{form.padding.300}", "paddingY": "{form.padding.500}" } }, @@ -4725,7 +4725,7 @@ "placeholderColor": "{form.placeholderColor}", "invalidPlaceholderColor": "{form.invalidPlaceholderColor}", "shadow": "0", - "paddingX": "{form.padding.200}", + "paddingX": "{form.padding.300}", "paddingY": "{form.padding.300}", "borderRadius": "{form.borderRadius.200}", "transitionDuration": "{form.transitionDuration}", @@ -4738,12 +4738,12 @@ }, "sm": { "fontSize": "{fonts.fontSize.300}", - "paddingX": "{form.padding.200}", + "paddingX": "{form.padding.300}", "paddingY": "{form.padding.200}" }, "lg": { "fontSize": "{fonts.fontSize.300}", - "paddingX": "{form.padding.200}", + "paddingX": "{form.padding.300}", "paddingY": "{form.padding.400}" } } diff --git a/src/stories/components/textarea/examples/textarea-float-label.component.ts b/src/stories/components/textarea/examples/textarea-float-label.component.ts new file mode 100644 index 00000000..b02a6ce4 --- /dev/null +++ b/src/stories/components/textarea/examples/textarea-float-label.component.ts @@ -0,0 +1,145 @@ +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { NgClass } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { FloatLabel } from 'primeng/floatlabel'; +import { Textarea } from 'primeng/textarea'; +import { StoryObj } from '@storybook/angular'; +import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; + +export const sourceTemplate = ` + + + + +`; +const styles = ''; + +@Component({ + selector: 'app-textarea-float-label', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [Textarea, FloatLabel, FormsModule, NgClass], + template: ` +
+ + + + +
+ `, + styles, +}) +export class TextareaFloatLabelComponent { + @Input() size: TextareaComponent['size'] = 'base'; + @Input() disabled = false; + @Input() readonly = false; + @Input() invalid = false; + @Input() fluid = false; + @Input() rows = 3; + + value = ''; + + get primeSize(): 'small' | 'large' | undefined { + if (this.size === 'small') return 'small'; + if (this.size === 'large') return 'large'; + return undefined; + } + + get sizeClass(): Record { + return { 'p-textarea-xlg': this.size === 'xlarge' }; + } +} + +export const FloatLabelStory: StoryObj = { + name: 'FloatLabel', + render: (args) => ({ + props: { ...args }, + template: ` +
+ + + + +
+ `, + }), + argTypes: { + size: { table: { disable: true } }, + }, + args: { + disabled: false, + readonly: false, + invalid: false, + fluid: false, + rows: 3, + }, + parameters: { + docs: { + description: { + story: + 'Интеграция с `p-floatlabel variant="in"` — плавающая метка внутри поля. Кликните на поле чтобы увидеть анимацию. Требует нативный ` + + + \`, +}) +export class MyComponent { + value = ''; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/textarea/examples/textarea-sizes.component.ts b/src/stories/components/textarea/examples/textarea-sizes.component.ts index 4643be86..f74361d7 100644 --- a/src/stories/components/textarea/examples/textarea-sizes.component.ts +++ b/src/stories/components/textarea/examples/textarea-sizes.component.ts @@ -1,57 +1,38 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; -export const template = ` -
-
-
small
- -
-
-
base
- -
-
-
large
- -
-
-
xlarge
- -
-
-`; -const styles = ''; +type Story = StoryObj; -@Component({ - selector: 'app-textarea-sizes', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [TextareaComponent, FormsModule], - template, - styles, -}) -export class TextareaSizesComponent { - value = ''; -} - -export const Sizes: StoryObj = { - render: () => ({ - template: ``, +export const Sizes: Story = { + name: 'Sizes', + render: (args) => ({ + props: { ...args, value: '' }, + template: ` + + `, }), parameters: { - controls: { disable: true }, docs: { description: { - story: 'Все доступные размеры компонента: small, base, large, xlarge.', + story: 'Все доступные размеры компонента: small, base, large, xlarge. Выберите размер через Controls.', }, source: { language: 'ts', - code: `@Component({ - template: \`${template}\`, -})`, + code: ` + + +`, }, }, }, diff --git a/src/stories/components/textarea/textarea.stories.ts b/src/stories/components/textarea/textarea.stories.ts index 7069b1ed..c4bd17b8 100644 --- a/src/stories/components/textarea/textarea.stories.ts +++ b/src/stories/components/textarea/textarea.stories.ts @@ -1,11 +1,15 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { NgClass } from '@angular/common'; import { FormsModule } from '@angular/forms'; +import { FloatLabel } from 'primeng/floatlabel'; +import { Textarea } from 'primeng/textarea'; import { TextareaComponent } from '../../../lib/components/textarea/textarea.component'; import { Disabled } from './examples/textarea-disabled.component'; import { Readonly } from './examples/textarea-readonly.component'; import { Invalid } from './examples/textarea-invalid.component'; import { AutoResize, TextareaAutoResizeComponent } from './examples/textarea-autoresize.component'; -import { Sizes, TextareaSizesComponent } from './examples/textarea-sizes.component'; +import { Sizes } from './examples/textarea-sizes.component'; +import { FloatLabelStory, TextareaFloatLabelComponent } from './examples/textarea-float-label.component'; type TextareaArgs = TextareaComponent; @@ -18,8 +22,11 @@ const meta: Meta = { imports: [ TextareaComponent, FormsModule, + NgClass, + Textarea, + FloatLabel, TextareaAutoResizeComponent, - TextareaSizesComponent, + TextareaFloatLabelComponent, ], }), ], @@ -190,4 +197,4 @@ export const Default: Story = { }; // ── Re-exports from example components ──────────────────────────────────── -export { Disabled, Readonly, Invalid, AutoResize, Sizes }; +export { Disabled, Readonly, Invalid, AutoResize, Sizes, FloatLabelStory as FloatLabel }; From 4bae493a0eacc4709fa87fc7e45198ceeb6d7435 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 20:56:12 +0700 Subject: [PATCH 129/258] =?UTF-8?q?inputmask:=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=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 --- .gitignore | 2 + .../inputmask/inputmask.component.ts | 110 ++++++++ src/prime-preset/map-tokens.ts | 5 + .../tokens/components/inputmask.ts | 19 ++ src/prime-preset/tokens/tokens.json | 11 + .../examples/inputmask-disabled.component.ts | 37 +++ .../inputmask-float-label.component.ts | 67 +++++ .../examples/inputmask-invalid.component.ts | 37 +++ .../examples/inputmask-readonly.component.ts | 37 +++ .../examples/inputmask-sizes.component.ts | 50 ++++ .../components/inputmask/inputmask.stories.ts | 267 ++++++++++++++++++ 11 files changed, 642 insertions(+) create mode 100644 src/lib/components/inputmask/inputmask.component.ts create mode 100644 src/prime-preset/tokens/components/inputmask.ts create mode 100644 src/stories/components/inputmask/examples/inputmask-disabled.component.ts create mode 100644 src/stories/components/inputmask/examples/inputmask-float-label.component.ts create mode 100644 src/stories/components/inputmask/examples/inputmask-invalid.component.ts create mode 100644 src/stories/components/inputmask/examples/inputmask-readonly.component.ts create mode 100644 src/stories/components/inputmask/examples/inputmask-sizes.component.ts create mode 100644 src/stories/components/inputmask/inputmask.stories.ts diff --git a/.gitignore b/.gitignore index 808f9bdc..ce8e3c03 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ src/assets/components/themes /storybook-static /debug-storybook.log /documentation.json + +.claude/* \ No newline at end of file diff --git a/src/lib/components/inputmask/inputmask.component.ts b/src/lib/components/inputmask/inputmask.component.ts new file mode 100644 index 00000000..de822be4 --- /dev/null +++ b/src/lib/components/inputmask/inputmask.component.ts @@ -0,0 +1,110 @@ +import { ChangeDetectionStrategy, Component, Input, Output, EventEmitter, forwardRef } from '@angular/core'; +import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { NgClass } from '@angular/common'; +import { InputMask } from 'primeng/inputmask'; + +export type InputMaskSize = 'small' | 'base' | 'large' | 'xlarge'; +export type InputMaskVariant = 'outlined' | 'filled'; + +@Component({ + selector: 'input-mask', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputMask, NgClass, FormsModule], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => InputMaskComponent), + multi: true, + }, + ], + host: { style: 'display: block' }, + template: ` + + `, +}) +export class InputMaskComponent implements ControlValueAccessor { + @Input() mask = ''; + @Input() slotChar = '_'; + @Input() autoClear = true; + @Input() showClear = false; + @Input() unmask = false; + @Input() placeholder = ''; + @Input() size: InputMaskSize = 'base'; + @Input() disabled = false; + @Input() readonly = false; + @Input() invalid = false; + @Input() fluid = false; + @Input() variant: InputMaskVariant = 'outlined'; + @Input() characterPattern = '[A-Za-z]'; + @Input() keepBuffer = false; + @Input() autocomplete = ''; + + @Output() onComplete = new EventEmitter(); + @Output() onFocusEvent = new EventEmitter(); + @Output() onBlurEvent = new EventEmitter(); + @Output() onInputEvent = new EventEmitter(); + @Output() onKeydownEvent = new EventEmitter(); + @Output() onClearEvent = new EventEmitter(); + + modelValue: string | null = null; + + private _onChange: (value: string | null) => void = () => {}; + onTouched: () => void = () => {}; + + get primeSize(): 'small' | 'large' | undefined { + if (this.size === 'small') return 'small'; + if (this.size === 'large' || this.size === 'xlarge') return 'large'; + return undefined; + } + + get sizeClass(): Record { + return { 'p-inputmask-xlg': this.size === 'xlarge' }; + } + + onModelChange(value: string | null): void { + this.modelValue = value; + this._onChange(value); + } + + writeValue(value: string | null): void { + this.modelValue = value ?? null; + } + + registerOnChange(fn: (value: string | null) => void): void { + this._onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 09d9449d..e99caa59 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -6,6 +6,7 @@ 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 { inputmaskCss } from './tokens/components/inputmask'; import { inputtextCss } from './tokens/components/inputtext'; import { progressspinnerCss } from './tokens/components/progressspinner'; import { tagCss } from './tokens/components/tag'; @@ -36,6 +37,10 @@ const presetTokens: Preset = { ...(tokens.components.inputtext as unknown as ComponentsDesignTokens['inputtext']), css: inputtextCss, }, + inputmask: { + ...(tokens.components.inputmask as unknown as object), + css: inputmaskCss, + }, tag: { ...(tokens.components.tag as unknown as ComponentsDesignTokens['tag']), css: tagCss, diff --git a/src/prime-preset/tokens/components/inputmask.ts b/src/prime-preset/tokens/components/inputmask.ts new file mode 100644 index 00000000..6ee6cd8d --- /dev/null +++ b/src/prime-preset/tokens/components/inputmask.ts @@ -0,0 +1,19 @@ +export const inputmaskCss = ({ dt }: { dt: (token: string) => string }): string => ` + +/* ─── Base ─── */ +.p-inputmask { + border-width: ${dt('inputmask.extend.borderWidth')}; + line-height: ${dt('fonts.lineHeight.250')}; +} + +/* ─── Readonly ─── */ +.p-inputmask .p-inputtext:enabled:read-only { + background: ${dt('inputmask.extend.readonlyBackground')}; +} + +/* ─── Extra Large ─── */ +.p-inputmask.p-inputmask-xlg .p-inputtext { + font-size: ${dt('inputmask.extend.extXlg.fontSize')}; + padding: ${dt('inputmask.extend.extXlg.paddingY')} ${dt('inputmask.extend.extXlg.paddingX')}; +} +`; diff --git a/src/prime-preset/tokens/tokens.json b/src/prime-preset/tokens/tokens.json index 6fd82189..6dc0a92d 100644 --- a/src/prime-preset/tokens/tokens.json +++ b/src/prime-preset/tokens/tokens.json @@ -3114,6 +3114,17 @@ "width": "0rem" } }, + "inputmask": { + "extend": { + "borderWidth": "{form.borderWidth}", + "readonlyBackground": "{form.readonlyBackground}", + "extXlg": { + "fontSize": "{form.xlg.fontSize}", + "paddingX": "{form.padding.300}", + "paddingY": "{form.padding.600}" + } + } + }, "inputtext": { "extend": { "readonlyBackground": "{form.readonlyBackground}", diff --git a/src/stories/components/inputmask/examples/inputmask-disabled.component.ts b/src/stories/components/inputmask/examples/inputmask-disabled.component.ts new file mode 100644 index 00000000..6bc047e9 --- /dev/null +++ b/src/stories/components/inputmask/examples/inputmask-disabled.component.ts @@ -0,0 +1,37 @@ +import { StoryObj } from '@storybook/angular'; +import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; + +type Story = StoryObj; + +export const Disabled: Story = { + name: 'Disabled', + render: (args) => ({ + props: { ...args, value: '12-34-56' }, + template: ` + + `, + }), + args: { + mask: '99-99-99', + slotChar: '_', + disabled: true, + placeholder: '99-99-99', + }, + parameters: { + docs: { + description: { + story: 'Отключённое состояние — поле недоступно для взаимодействия.', + }, + source: { + language: 'html', + code: ``, + }, + }, + }, +}; diff --git a/src/stories/components/inputmask/examples/inputmask-float-label.component.ts b/src/stories/components/inputmask/examples/inputmask-float-label.component.ts new file mode 100644 index 00000000..1b34eda5 --- /dev/null +++ b/src/stories/components/inputmask/examples/inputmask-float-label.component.ts @@ -0,0 +1,67 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { InputMask } from 'primeng/inputmask'; +import { FloatLabel } from 'primeng/floatlabel'; + +export const template = ` +
+ + + + +
+`; +const styles = ''; + +@Component({ + selector: 'app-inputmask-float-label', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputMask, FloatLabel, FormsModule], + template, + styles, +}) +export class InputMaskFloatLabelComponent { + value = ''; +} + +export const FloatLabelStory: StoryObj = { + name: 'FloatLabel', + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: + 'Интеграция с `p-floatlabel` — плавающая метка внутри поля. Требует нативный `` как прямой дочерний элемент `p-floatlabel`.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { InputMask } from 'primeng/inputmask'; +import { FloatLabel } from 'primeng/floatlabel'; +import { FormsModule } from '@angular/forms'; + +@Component({ + selector: 'app-inputmask-float-label', + standalone: true, + imports: [InputMask, FloatLabel, FormsModule], + template: \` + + + + + \`, +}) +export class InputMaskFloatLabelComponent { + value = ''; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/inputmask/examples/inputmask-invalid.component.ts b/src/stories/components/inputmask/examples/inputmask-invalid.component.ts new file mode 100644 index 00000000..14780527 --- /dev/null +++ b/src/stories/components/inputmask/examples/inputmask-invalid.component.ts @@ -0,0 +1,37 @@ +import { StoryObj } from '@storybook/angular'; +import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; + +type Story = StoryObj; + +export const Invalid: Story = { + name: 'Invalid', + render: (args) => ({ + props: { ...args, value: '' }, + template: ` + + `, + }), + args: { + mask: '99-99-99', + slotChar: '_', + invalid: true, + placeholder: '99-99-99', + }, + parameters: { + docs: { + description: { + story: 'Невалидное состояние — поле отображает ошибку.', + }, + source: { + language: 'html', + code: ``, + }, + }, + }, +}; diff --git a/src/stories/components/inputmask/examples/inputmask-readonly.component.ts b/src/stories/components/inputmask/examples/inputmask-readonly.component.ts new file mode 100644 index 00000000..5a060ab2 --- /dev/null +++ b/src/stories/components/inputmask/examples/inputmask-readonly.component.ts @@ -0,0 +1,37 @@ +import { StoryObj } from '@storybook/angular'; +import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; + +type Story = StoryObj; + +export const Readonly: Story = { + name: 'Readonly', + render: (args) => ({ + props: { ...args, value: '12-34-56' }, + template: ` + + `, + }), + args: { + mask: '99-99-99', + slotChar: '_', + readonly: true, + placeholder: '99-99-99', + }, + parameters: { + docs: { + description: { + story: 'Режим только для чтения — поле отображает значение, но недоступно для редактирования.', + }, + source: { + language: 'html', + code: ``, + }, + }, + }, +}; diff --git a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts new file mode 100644 index 00000000..6658d66e --- /dev/null +++ b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts @@ -0,0 +1,50 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; + +export const template = ` +
+ + + + +
+`; +const styles = ''; + +@Component({ + selector: 'app-inputmask-sizes', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputMaskComponent, FormsModule], + template, + styles, +}) +export class InputMaskSizesComponent { + s = ''; + b = ''; + l = ''; + xl = ''; +} + +export const Sizes: StoryObj = { + name: 'Sizes', + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Четыре размера поля: small, base, large, xlarge.', + }, + source: { + language: 'ts', + code: `@Component({ + template: \`${template}\`, +})`, + }, + }, + }, +}; diff --git a/src/stories/components/inputmask/inputmask.stories.ts b/src/stories/components/inputmask/inputmask.stories.ts new file mode 100644 index 00000000..3ae81cf2 --- /dev/null +++ b/src/stories/components/inputmask/inputmask.stories.ts @@ -0,0 +1,267 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { FormsModule } from '@angular/forms'; +import { InputMaskComponent } from '../../../lib/components/inputmask/inputmask.component'; +import { InputMaskFloatLabelComponent, FloatLabelStory } from './examples/inputmask-float-label.component'; +import { InputMaskSizesComponent, Sizes } from './examples/inputmask-sizes.component'; +import { Disabled } from './examples/inputmask-disabled.component'; +import { Readonly } from './examples/inputmask-readonly.component'; +import { Invalid } from './examples/inputmask-invalid.component'; + +type InputMaskArgs = InputMaskComponent; + +const meta: Meta = { + title: 'Components/Form/InputMask', + component: InputMaskComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + InputMaskComponent, + FormsModule, + InputMaskFloatLabelComponent, + InputMaskSizesComponent, + ], + }), + ], + parameters: { + designTokens: { prefix: '--p-inputmask' }, + docs: { + description: { + component: `Компонент текстового ввода по маске. Используется для ввода данных в определённом формате: дата, телефон, серийный номер и т.д. + +\`\`\`typescript +import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + }, + argTypes: { + mask: { + control: 'text', + description: 'Маска ввода (9 — цифра, a — буква, * — любой символ)', + table: { + category: 'Props', + defaultValue: { summary: "''" }, + type: { summary: 'string' }, + }, + }, + slotChar: { + control: 'text', + description: 'Символ-заполнитель для пустых позиций маски', + table: { + category: 'Props', + defaultValue: { summary: "'_'" }, + type: { summary: 'string' }, + }, + }, + unmask: { + control: 'boolean', + description: 'Возвращать чистое значение без символов маски', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + autoClear: { + control: 'boolean', + description: 'Очищать незавершённое значение при потере фокуса', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + showClear: { + control: 'boolean', + description: 'Показывает иконку очистки при наличии значения', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + placeholder: { + control: 'text', + description: 'Подсказка при пустом поле', + table: { + category: 'Props', + defaultValue: { summary: "''" }, + type: { summary: 'string' }, + }, + }, + size: { + control: 'select', + options: ['small', 'base', 'large', 'xlarge'], + description: 'Размер поля', + table: { + category: 'Props', + defaultValue: { summary: "'base'" }, + type: { summary: "'small' | 'base' | 'large' | 'xlarge'" }, + }, + }, + disabled: { + control: 'boolean', + description: 'Отключает взаимодействие', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + readonly: { + control: 'boolean', + description: 'Только для чтения', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + invalid: { + control: 'boolean', + description: 'Невалидное состояние', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + fluid: { + control: 'boolean', + description: 'Растягивает поле на всю ширину контейнера', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + variant: { + control: 'select', + options: ['outlined', 'filled'], + description: 'Визуальный вариант поля', + table: { + category: 'Props', + defaultValue: { summary: "'outlined'" }, + type: { summary: "'outlined' | 'filled'" }, + }, + }, + characterPattern: { + control: 'text', + description: 'Регулярное выражение для символов типа a в маске', + table: { + category: 'Props', + defaultValue: { summary: "'[A-Za-z]'" }, + type: { summary: 'string' }, + }, + }, + keepBuffer: { + control: 'boolean', + description: 'Сохранять введённые символы при очистке маски', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + autocomplete: { + control: 'text', + description: 'Значение атрибута autocomplete для input', + table: { + category: 'Props', + defaultValue: { summary: "''" }, + type: { summary: 'string' }, + }, + }, + modelValue: { table: { disable: true } }, + primeSize: { table: { disable: true } }, + sizeClass: { table: { disable: true } }, + onTouched: { table: { disable: true } }, + onModelChange: { table: { disable: true } }, + writeValue: { table: { disable: true } }, + registerOnChange: { table: { disable: true } }, + registerOnTouched: { table: { disable: true } }, + setDisabledState: { table: { disable: true } }, + onComplete: { + control: false, + description: 'Событие завершения ввода маски', + table: { category: 'Events', type: { summary: 'EventEmitter' } }, + }, + onFocusEvent: { + control: false, + description: 'Событие фокуса', + table: { category: 'Events', type: { summary: 'EventEmitter' } }, + }, + onBlurEvent: { + control: false, + description: 'Событие потери фокуса', + table: { category: 'Events', type: { summary: 'EventEmitter' } }, + }, + onInputEvent: { + control: false, + description: 'Событие ввода', + table: { category: 'Events', type: { summary: 'EventEmitter' } }, + }, + onKeydownEvent: { + control: false, + description: 'Событие нажатия клавиши', + table: { category: 'Events', type: { summary: 'EventEmitter' } }, + }, + onClearEvent: { + control: false, + description: 'Событие очистки поля', + table: { category: 'Events', type: { summary: 'EventEmitter' } }, + }, + }, + args: { + mask: '99-99-99', + slotChar: '_', + unmask: false, + autoClear: true, + showClear: false, + placeholder: '99-99-99', + size: 'base', + disabled: false, + readonly: false, + invalid: false, + fluid: false, + variant: 'outlined', + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + name: 'Default', + render: (args) => { + const parts: string[] = []; + + if (args.mask) parts.push(`mask="${args.mask}"`); + if (args.slotChar && args.slotChar !== '_') parts.push(`slotChar="${args.slotChar}"`); + if (args.unmask) parts.push(`[unmask]="true"`); + if (!args.autoClear) parts.push(`[autoClear]="false"`); + if (args.showClear) parts.push(`[showClear]="true"`); + if (args.placeholder) parts.push(`placeholder="${args.placeholder}"`); + if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); + if (args.disabled) parts.push(`[disabled]="true"`); + if (args.readonly) parts.push(`[readonly]="true"`); + if (args.invalid) parts.push(`[invalid]="true"`); + if (args.fluid) parts.push(`[fluid]="true"`); + if (args.variant && args.variant !== 'outlined') parts.push(`variant="${args.variant}"`); + parts.push(`[(ngModel)]="value"`); + + const template = ``; + + return { props: { ...args, value: '' }, template }; + }, + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + }, + }, +}; + +export { Sizes, FloatLabelStory as FloatLabel, Disabled, Readonly, Invalid }; From 7fef133b1fb8f8fc720282c6eeca7bece5b56fb9 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 21:45:19 +0700 Subject: [PATCH 130/258] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=80=D0=BE=D0=BF=D1=81=D0=B0?= =?UTF-8?q?=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inputmask/inputmask.component.ts | 15 ++++++--------- src/prime-preset/map-tokens.ts | 1 - .../tokens/components/inputmask.ts | 19 ++++--------------- src/prime-preset/tokens/tokens.json | 11 ----------- .../components/inputmask/inputmask.stories.ts | 1 - 5 files changed, 10 insertions(+), 37 deletions(-) diff --git a/src/lib/components/inputmask/inputmask.component.ts b/src/lib/components/inputmask/inputmask.component.ts index de822be4..423e560f 100644 --- a/src/lib/components/inputmask/inputmask.component.ts +++ b/src/lib/components/inputmask/inputmask.component.ts @@ -1,6 +1,5 @@ import { ChangeDetectionStrategy, Component, Input, Output, EventEmitter, forwardRef } from '@angular/core'; import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { NgClass } from '@angular/common'; import { InputMask } from 'primeng/inputmask'; export type InputMaskSize = 'small' | 'base' | 'large' | 'xlarge'; @@ -10,7 +9,7 @@ export type InputMaskVariant = 'outlined' | 'filled'; selector: 'input-mask', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputMask, NgClass, FormsModule], + imports: [InputMask, FormsModule], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -18,11 +17,13 @@ export type InputMaskVariant = 'outlined' | 'filled'; multi: true, }, ], - host: { style: 'display: block' }, + host: { + style: 'display: block', + '[class.input-mask-xlg]': 'size === "xlarge"', + }, template: ` { - return { 'p-inputmask-xlg': this.size === 'xlarge' }; - } - onModelChange(value: string | null): void { this.modelValue = value; this._onChange(value); diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index e99caa59..470f2db5 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -38,7 +38,6 @@ const presetTokens: Preset = { css: inputtextCss, }, inputmask: { - ...(tokens.components.inputmask as unknown as object), css: inputmaskCss, }, tag: { diff --git a/src/prime-preset/tokens/components/inputmask.ts b/src/prime-preset/tokens/components/inputmask.ts index 6ee6cd8d..8132a1ac 100644 --- a/src/prime-preset/tokens/components/inputmask.ts +++ b/src/prime-preset/tokens/components/inputmask.ts @@ -1,19 +1,8 @@ export const inputmaskCss = ({ dt }: { dt: (token: string) => string }): string => ` -/* ─── Base ─── */ -.p-inputmask { - border-width: ${dt('inputmask.extend.borderWidth')}; - line-height: ${dt('fonts.lineHeight.250')}; -} - -/* ─── Readonly ─── */ -.p-inputmask .p-inputtext:enabled:read-only { - background: ${dt('inputmask.extend.readonlyBackground')}; -} - -/* ─── Extra Large ─── */ -.p-inputmask.p-inputmask-xlg .p-inputtext { - font-size: ${dt('inputmask.extend.extXlg.fontSize')}; - padding: ${dt('inputmask.extend.extXlg.paddingY')} ${dt('inputmask.extend.extXlg.paddingX')}; +/* ─── Sizes ─── */ +input-mask.input-mask-xlg .p-inputtext { + font-size: ${dt('inputtext.extend.extXlg.fontSize')}; + padding: ${dt('inputtext.extend.extXlg.paddingY')} ${dt('inputtext.extend.extXlg.paddingX')}; } `; diff --git a/src/prime-preset/tokens/tokens.json b/src/prime-preset/tokens/tokens.json index 6dc0a92d..6fd82189 100644 --- a/src/prime-preset/tokens/tokens.json +++ b/src/prime-preset/tokens/tokens.json @@ -3114,17 +3114,6 @@ "width": "0rem" } }, - "inputmask": { - "extend": { - "borderWidth": "{form.borderWidth}", - "readonlyBackground": "{form.readonlyBackground}", - "extXlg": { - "fontSize": "{form.xlg.fontSize}", - "paddingX": "{form.padding.300}", - "paddingY": "{form.padding.600}" - } - } - }, "inputtext": { "extend": { "readonlyBackground": "{form.readonlyBackground}", diff --git a/src/stories/components/inputmask/inputmask.stories.ts b/src/stories/components/inputmask/inputmask.stories.ts index 3ae81cf2..688e8c71 100644 --- a/src/stories/components/inputmask/inputmask.stories.ts +++ b/src/stories/components/inputmask/inputmask.stories.ts @@ -175,7 +175,6 @@ import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; }, modelValue: { table: { disable: true } }, primeSize: { table: { disable: true } }, - sizeClass: { table: { disable: true } }, onTouched: { table: { disable: true } }, onModelChange: { table: { disable: true } }, writeValue: { table: { disable: true } }, From d725e9871eb0125aea9a742bd43d825f06fed42b Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 22:05:25 +0700 Subject: [PATCH 131/258] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=81=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D1=81=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=BF=D1=81=D0=B0=20size;=20=D1=81=D1=82?= =?UTF-8?q?=D0=B8=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=B0=20=D1=81=D0=BE?= =?UTF-8?q?=D0=B3=D0=BB=D0=B0=D1=81=D0=BD=D0=BE=20=D0=B8=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=87=D0=BD=D0=B8=D0=BA=D0=B0=20inputtext?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/inputmask-disabled.component.ts | 17 ++++- .../inputmask-float-label.component.ts | 2 +- .../examples/inputmask-invalid.component.ts | 19 ++++-- .../examples/inputmask-readonly.component.ts | 17 ++++- .../examples/inputmask-sizes.component.ts | 66 +++++++++---------- .../components/inputmask/inputmask.stories.ts | 3 +- 6 files changed, 77 insertions(+), 47 deletions(-) diff --git a/src/stories/components/inputmask/examples/inputmask-disabled.component.ts b/src/stories/components/inputmask/examples/inputmask-disabled.component.ts index 6bc047e9..8674c9b7 100644 --- a/src/stories/components/inputmask/examples/inputmask-disabled.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-disabled.component.ts @@ -11,7 +11,13 @@ export const Disabled: Story = { @@ -19,7 +25,6 @@ export const Disabled: Story = { }), args: { mask: '99-99-99', - slotChar: '_', disabled: true, placeholder: '99-99-99', }, @@ -29,8 +34,14 @@ export const Disabled: Story = { story: 'Отключённое состояние — поле недоступно для взаимодействия.', }, source: { - language: 'html', - code: ``, + language: 'ts', + code: ` +import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +import { FormsModule } from '@angular/forms'; + +// template: +// + `, }, }, }, diff --git a/src/stories/components/inputmask/examples/inputmask-float-label.component.ts b/src/stories/components/inputmask/examples/inputmask-float-label.component.ts index 1b34eda5..d27a93ab 100644 --- a/src/stories/components/inputmask/examples/inputmask-float-label.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-float-label.component.ts @@ -36,7 +36,7 @@ export const FloatLabelStory: StoryObj = { docs: { description: { story: - 'Интеграция с `p-floatlabel` — плавающая метка внутри поля. Требует нативный `` как прямой дочерний элемент `p-floatlabel`.', + 'Интеграция с `p-floatlabel` — плавающая метка внутри поля. Кликните на поле чтобы увидеть анимацию. Требует нативный `` как прямой дочерний элемент `p-floatlabel`.', }, source: { language: 'ts', diff --git a/src/stories/components/inputmask/examples/inputmask-invalid.component.ts b/src/stories/components/inputmask/examples/inputmask-invalid.component.ts index 14780527..13a691a2 100644 --- a/src/stories/components/inputmask/examples/inputmask-invalid.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-invalid.component.ts @@ -11,7 +11,13 @@ export const Invalid: Story = { @@ -19,9 +25,8 @@ export const Invalid: Story = { }), args: { mask: '99-99-99', - slotChar: '_', invalid: true, - placeholder: '99-99-99', + placeholder: 'Обязательное поле', }, parameters: { docs: { @@ -29,8 +34,14 @@ export const Invalid: Story = { story: 'Невалидное состояние — поле отображает ошибку.', }, source: { - language: 'html', - code: ``, + language: 'ts', + code: ` +import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +import { FormsModule } from '@angular/forms'; + +// template: +// + `, }, }, }, diff --git a/src/stories/components/inputmask/examples/inputmask-readonly.component.ts b/src/stories/components/inputmask/examples/inputmask-readonly.component.ts index 5a060ab2..90685af9 100644 --- a/src/stories/components/inputmask/examples/inputmask-readonly.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-readonly.component.ts @@ -11,7 +11,13 @@ export const Readonly: Story = { @@ -19,7 +25,6 @@ export const Readonly: Story = { }), args: { mask: '99-99-99', - slotChar: '_', readonly: true, placeholder: '99-99-99', }, @@ -29,8 +34,14 @@ export const Readonly: Story = { story: 'Режим только для чтения — поле отображает значение, но недоступно для редактирования.', }, source: { - language: 'html', - code: ``, + language: 'ts', + code: ` +import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +import { FormsModule } from '@angular/forms'; + +// template: +// + `, }, }, }, diff --git a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts index 6658d66e..1cac61c9 100644 --- a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts @@ -1,49 +1,47 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; -export const template = ` -
- - - - -
-`; -const styles = ''; - -@Component({ - selector: 'app-inputmask-sizes', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputMaskComponent, FormsModule], - template, - styles, -}) -export class InputMaskSizesComponent { - s = ''; - b = ''; - l = ''; - xl = ''; -} +type Story = StoryObj; -export const Sizes: StoryObj = { +export const Sizes: Story = { name: 'Sizes', - render: () => ({ - template: ``, + render: (args) => ({ + props: { ...args, value: '' }, + template: ` + + `, }), + args: { + mask: '99-99-99', + size: 'small', + placeholder: '99-99-99', + }, parameters: { - controls: { disable: true }, docs: { description: { - story: 'Четыре размера поля: small, base, large, xlarge.', + story: 'Размеры поля: small, base, large, xlarge. Переключайте через Controls.', }, source: { language: 'ts', - code: `@Component({ - template: \`${template}\`, -})`, + code: ` +import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +import { FormsModule } from '@angular/forms'; + +// template: +// + `, }, }, }, diff --git a/src/stories/components/inputmask/inputmask.stories.ts b/src/stories/components/inputmask/inputmask.stories.ts index 688e8c71..f057ad87 100644 --- a/src/stories/components/inputmask/inputmask.stories.ts +++ b/src/stories/components/inputmask/inputmask.stories.ts @@ -2,7 +2,7 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormsModule } from '@angular/forms'; import { InputMaskComponent } from '../../../lib/components/inputmask/inputmask.component'; import { InputMaskFloatLabelComponent, FloatLabelStory } from './examples/inputmask-float-label.component'; -import { InputMaskSizesComponent, Sizes } from './examples/inputmask-sizes.component'; +import { Sizes } from './examples/inputmask-sizes.component'; import { Disabled } from './examples/inputmask-disabled.component'; import { Readonly } from './examples/inputmask-readonly.component'; import { Invalid } from './examples/inputmask-invalid.component'; @@ -19,7 +19,6 @@ const meta: Meta = { InputMaskComponent, FormsModule, InputMaskFloatLabelComponent, - InputMaskSizesComponent, ], }), ], From c92fb5a46556781a56e5d97653fecaae6861d8b6 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 22:14:14 +0700 Subject: [PATCH 132/258] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20tabindex=3D0=20=D0=B8=20=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D1=87=D0=B8=D0=BA=D0=B8=20=D0=BA=D0=BB=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D0=B0=D1=82=D1=83=D1=80=D1=8B=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D1=83=20=D0=BE=D1=87=D0=B8=D1=81?= =?UTF-8?q?=D1=82=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/inputtext/inputtext.component.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/components/inputtext/inputtext.component.ts b/src/lib/components/inputtext/inputtext.component.ts index 7d797239..864b30e7 100644 --- a/src/lib/components/inputtext/inputtext.component.ts +++ b/src/lib/components/inputtext/inputtext.component.ts @@ -38,9 +38,12 @@ export type InputTextVariant = 'outlined' | 'filled'; /> } @else { From 20a03311d693d2feb3b44881223a4b8230133b5e Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 22:15:08 +0700 Subject: [PATCH 133/258] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D1=91=D0=BD=20?= =?UTF-8?q?=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=20variant=20?= =?UTF-8?q?=E2=80=94=20=D0=BD=D0=B5=20=D0=B0=D0=BA=D1=82=D1=83=D0=B0=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/inputtext/inputtext.component.ts | 5 +---- .../inputtext/examples/inputtext-clear.component.ts | 1 - .../examples/inputtext-disabled.component.ts | 1 - .../examples/inputtext-invalid.component.ts | 1 - .../examples/inputtext-readonly.component.ts | 1 - .../components/inputtext/inputtext.stories.ts | 12 ------------ 6 files changed, 1 insertion(+), 20 deletions(-) diff --git a/src/lib/components/inputtext/inputtext.component.ts b/src/lib/components/inputtext/inputtext.component.ts index 864b30e7..505e4957 100644 --- a/src/lib/components/inputtext/inputtext.component.ts +++ b/src/lib/components/inputtext/inputtext.component.ts @@ -6,7 +6,7 @@ import { IconField } from 'primeng/iconfield'; import { InputIcon } from 'primeng/inputicon'; export type InputTextSize = 'small' | 'base' | 'large' | 'xlarge'; -export type InputTextVariant = 'outlined' | 'filled'; + @Component({ selector: 'input-text', @@ -31,7 +31,6 @@ export type InputTextVariant = 'outlined' | 'filled'; [invalid]="invalid" [placeholder]="placeholder" [fluid]="fluid" - [variant]="variant === 'filled' ? 'filled' : undefined" [value]="modelValue" (input)="onInput($event)" (blur)="onTouched()" @@ -56,7 +55,6 @@ export type InputTextVariant = 'outlined' | 'filled'; [invalid]="invalid" [placeholder]="placeholder" [fluid]="fluid" - [variant]="variant === 'filled' ? 'filled' : undefined" [value]="modelValue" (input)="onInput($event)" (blur)="onTouched()" @@ -72,7 +70,6 @@ export class InputTextComponent implements ControlValueAccessor { @Input() invalid = false; @Input() showClear = false; @Input() fluid = false; - @Input() variant: InputTextVariant = 'outlined'; @Output() onClear = new EventEmitter(); diff --git a/src/stories/components/inputtext/examples/inputtext-clear.component.ts b/src/stories/components/inputtext/examples/inputtext-clear.component.ts index bad41e50..ef6ef54f 100644 --- a/src/stories/components/inputtext/examples/inputtext-clear.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-clear.component.ts @@ -15,7 +15,6 @@ export const ClearButton: Story = { [readonly]="readonly" [invalid]="invalid" [fluid]="fluid" - [variant]="variant" [placeholder]="placeholder" [(ngModel)]="value" > diff --git a/src/stories/components/inputtext/examples/inputtext-disabled.component.ts b/src/stories/components/inputtext/examples/inputtext-disabled.component.ts index 68e1964e..40c116dc 100644 --- a/src/stories/components/inputtext/examples/inputtext-disabled.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-disabled.component.ts @@ -15,7 +15,6 @@ export const Disabled: Story = { [readonly]="readonly" [invalid]="invalid" [fluid]="fluid" - [variant]="variant" [placeholder]="placeholder" [(ngModel)]="value" > diff --git a/src/stories/components/inputtext/examples/inputtext-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-invalid.component.ts index 94c0ef8e..4b818d35 100644 --- a/src/stories/components/inputtext/examples/inputtext-invalid.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-invalid.component.ts @@ -15,7 +15,6 @@ export const Invalid: Story = { [readonly]="readonly" [invalid]="invalid" [fluid]="fluid" - [variant]="variant" [placeholder]="placeholder" [(ngModel)]="value" > diff --git a/src/stories/components/inputtext/examples/inputtext-readonly.component.ts b/src/stories/components/inputtext/examples/inputtext-readonly.component.ts index 678535a1..07f69d4a 100644 --- a/src/stories/components/inputtext/examples/inputtext-readonly.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-readonly.component.ts @@ -15,7 +15,6 @@ export const Readonly: Story = { [readonly]="readonly" [invalid]="invalid" [fluid]="fluid" - [variant]="variant" [placeholder]="placeholder" [(ngModel)]="value" > diff --git a/src/stories/components/inputtext/inputtext.stories.ts b/src/stories/components/inputtext/inputtext.stories.ts index a01dec9c..f667ee3b 100644 --- a/src/stories/components/inputtext/inputtext.stories.ts +++ b/src/stories/components/inputtext/inputtext.stories.ts @@ -100,16 +100,6 @@ import { InputTextModule } from 'primeng/inputtext'; type: { summary: 'boolean' }, }, }, - variant: { - control: 'select', - options: ['outlined', 'filled'], - description: 'Визуальный вариант поля', - table: { - category: 'Props', - defaultValue: { summary: "'outlined'" }, - type: { summary: "'outlined' | 'filled'" }, - }, - }, // Hidden computed props modelValue: { table: { disable: true } }, primeSize: { table: { disable: true } }, @@ -133,7 +123,6 @@ import { InputTextModule } from 'primeng/inputtext'; invalid: false, showClear: false, fluid: false, - variant: 'outlined', }, }; @@ -153,7 +142,6 @@ export const Default: Story = { if (args.invalid) parts.push(`[invalid]="true"`); if (args.showClear) parts.push(`[showClear]="true"`); if (args.fluid) parts.push(`[fluid]="true"`); - if (args.variant && args.variant !== 'outlined') parts.push(`variant="${args.variant}"`); parts.push(`[(ngModel)]="value"`); const template = ``; From 93702877dbaa1c007fb5ad21e02cc2ca6255c4af Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 22:15:23 +0700 Subject: [PATCH 134/258] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6?= =?UTF-8?q?=D0=BA=D0=B0=20=D1=82=D1=91=D0=BC=D0=BD=D0=BE=D0=B9=20=D1=82?= =?UTF-8?q?=D0=B5=D0=BC=D1=8B=20=D0=B4=D0=BB=D1=8F=20disabled/readonly=20b?= =?UTF-8?q?ackground=20=D0=B8=20color?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/inputtext.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/prime-preset/tokens/components/inputtext.ts b/src/prime-preset/tokens/components/inputtext.ts index 39c2be35..9172a0d7 100644 --- a/src/prime-preset/tokens/components/inputtext.ts +++ b/src/prime-preset/tokens/components/inputtext.ts @@ -6,9 +6,16 @@ export const inputtextCss = ({ dt }: { dt: (token: string) => string }): string line-height: ${dt('fonts.lineHeight.250')}; } +/* ─── Disabled ─── */ +.p-inputtext:disabled { + background: ${dt('inputtext.root.disabledBackground')}; + color: ${dt('inputtext.root.disabledColor')}; +} + /* ─── Readonly ─── */ .p-inputtext:enabled:read-only { background: ${dt('inputtext.extend.readonlyBackground')}; + color: ${dt('inputtext.root.color')}; } /* ─── Extra Large ─── */ From 798df8bff6ca7f62dc857a7469f6e1f81817c637 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 22:15:32 +0700 Subject: [PATCH 135/258] =?UTF-8?q?border=20=D0=B8=20box-shadow=20=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D1=8E=D1=82=D1=81=D1=8F=20=D0=BA=D1=80=D0=B0?= =?UTF-8?q?=D1=81=D0=BD=D1=8B=D0=BC=D0=B8=20=D0=BF=D1=80=D0=B8=20focus+inv?= =?UTF-8?q?alid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/inputtext.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/prime-preset/tokens/components/inputtext.ts b/src/prime-preset/tokens/components/inputtext.ts index 9172a0d7..c85601de 100644 --- a/src/prime-preset/tokens/components/inputtext.ts +++ b/src/prime-preset/tokens/components/inputtext.ts @@ -18,6 +18,12 @@ export const inputtextCss = ({ dt }: { dt: (token: string) => string }): string color: ${dt('inputtext.root.color')}; } +/* ─── Invalid + Focus ─── */ +.p-inputtext.p-invalid:focus { + border-color: ${dt('inputtext.root.invalidBorderColor')}; + box-shadow: 0 0 0 1px ${dt('inputtext.root.invalidBorderColor')}; +} + /* ─── Extra Large ─── */ .p-inputtext.p-inputtext-xlg { font-size: ${dt('inputtext.extend.extXlg.fontSize')}; From 28036b93f1ddf84609c158c5b536786863e06dd0 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 22:15:39 +0700 Subject: [PATCH 136/258] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20box-shadow=20=D0=BF=D1=80=D0=B8=20=D1=84=D0=BE?= =?UTF-8?q?=D0=BA=D1=83=D1=81=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/inputtext.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/prime-preset/tokens/components/inputtext.ts b/src/prime-preset/tokens/components/inputtext.ts index c85601de..6a2af63e 100644 --- a/src/prime-preset/tokens/components/inputtext.ts +++ b/src/prime-preset/tokens/components/inputtext.ts @@ -18,6 +18,11 @@ export const inputtextCss = ({ dt }: { dt: (token: string) => string }): string color: ${dt('inputtext.root.color')}; } +/* ─── Focus ─── */ +.p-inputtext:enabled:focus { + box-shadow: 0 0 0 1px ${dt('inputtext.root.focusBorderColor')}; +} + /* ─── Invalid + Focus ─── */ .p-inputtext.p-invalid:focus { border-color: ${dt('inputtext.root.invalidBorderColor')}; From a9fab15dd4c9a0f9d89079f058b5ebff2ece6378 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 22:15:51 +0700 Subject: [PATCH 137/258] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20ngClass=20!w-full=20=D0=BD=D0=B0=20iconfield=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=20fluid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/inputtext/inputtext.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/inputtext/inputtext.component.ts b/src/lib/components/inputtext/inputtext.component.ts index 505e4957..79aa12bf 100644 --- a/src/lib/components/inputtext/inputtext.component.ts +++ b/src/lib/components/inputtext/inputtext.component.ts @@ -21,7 +21,7 @@ export type InputTextSize = 'small' | 'base' | 'large' | 'xlarge'; ], template: ` @if (showClear) { - + Date: Tue, 21 Apr 2026 10:12:26 +0700 Subject: [PATCH 138/258] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20disabled/invalid=20=D0=B8=D0=B7=20@Input,=20=D0=B8?= =?UTF-8?q?=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D1=83=D1=8E=D1=82=D1=81?= =?UTF-8?q?=D1=8F=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20formControl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/inputtext/inputtext.component.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/components/inputtext/inputtext.component.ts b/src/lib/components/inputtext/inputtext.component.ts index 79aa12bf..cea025fe 100644 --- a/src/lib/components/inputtext/inputtext.component.ts +++ b/src/lib/components/inputtext/inputtext.component.ts @@ -65,12 +65,13 @@ export type InputTextSize = 'small' | 'base' | 'large' | 'xlarge'; export class InputTextComponent implements ControlValueAccessor { @Input() placeholder = ''; @Input() size: InputTextSize = 'base'; - @Input() disabled = false; @Input() readonly = false; - @Input() invalid = false; @Input() showClear = false; @Input() fluid = false; + disabled = false; + invalid = false; + @Output() onClear = new EventEmitter(); modelValue = ''; From 3216b4d00c566cedad888b349a5a53c1c7570cee Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 10:13:30 +0700 Subject: [PATCH 139/258] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20disabled/invalid/ngModel=20=D0=B8=D0=B7=20stories,=20?= =?UTF-8?q?=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D1=83=D1=8E=D1=82?= =?UTF-8?q?=D1=81=D1=8F=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20formControl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/inputtext-clear.component.ts | 8 ++--- .../examples/inputtext-disabled.component.ts | 13 ++++----- .../examples/inputtext-invalid.component.ts | 13 ++++----- .../examples/inputtext-readonly.component.ts | 8 ++--- .../components/inputtext/inputtext.stories.ts | 29 ++----------------- 5 files changed, 17 insertions(+), 54 deletions(-) diff --git a/src/stories/components/inputtext/examples/inputtext-clear.component.ts b/src/stories/components/inputtext/examples/inputtext-clear.component.ts index ef6ef54f..d0c13671 100644 --- a/src/stories/components/inputtext/examples/inputtext-clear.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-clear.component.ts @@ -6,17 +6,14 @@ type Story = StoryObj; export const ClearButton: Story = { name: 'ClearButton', render: (args) => ({ - props: { ...args, value: '' }, + props: { ...args }, template: ` `, }), @@ -33,10 +30,9 @@ export const ClearButton: Story = { language: 'ts', code: ` import { InputTextComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; // template: -// +// `, }, }, diff --git a/src/stories/components/inputtext/examples/inputtext-disabled.component.ts b/src/stories/components/inputtext/examples/inputtext-disabled.component.ts index 40c116dc..dc385cb8 100644 --- a/src/stories/components/inputtext/examples/inputtext-disabled.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-disabled.component.ts @@ -6,17 +6,14 @@ type Story = StoryObj; export const Disabled: Story = { name: 'Disabled', render: (args) => ({ - props: { ...args, value: 'Disabled с текстом' }, + props: { ...args }, template: ` `, }), @@ -27,16 +24,16 @@ export const Disabled: Story = { parameters: { docs: { description: { - story: 'Отключённое состояние — поле недоступно для взаимодействия.', + story: 'Отключённое состояние — управляется через formControl.', }, source: { language: 'ts', code: ` import { InputTextComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; -// template: -// +// formControl = new FormControl({ value: '', disabled: true }); +// `, }, }, diff --git a/src/stories/components/inputtext/examples/inputtext-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-invalid.component.ts index 4b818d35..a3610d03 100644 --- a/src/stories/components/inputtext/examples/inputtext-invalid.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-invalid.component.ts @@ -6,17 +6,14 @@ type Story = StoryObj; export const Invalid: Story = { name: 'Invalid', render: (args) => ({ - props: { ...args, value: '' }, + props: { ...args }, template: ` `, }), @@ -27,16 +24,16 @@ export const Invalid: Story = { parameters: { docs: { description: { - story: 'Невалидное состояние — поле отображает ошибку.', + story: 'Невалидное состояние — управляется через formControl валидацию.', }, source: { language: 'ts', code: ` import { InputTextComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; +import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; -// template: -// +// formControl = new FormControl('', Validators.required); +// `, }, }, diff --git a/src/stories/components/inputtext/examples/inputtext-readonly.component.ts b/src/stories/components/inputtext/examples/inputtext-readonly.component.ts index 07f69d4a..35ce1dee 100644 --- a/src/stories/components/inputtext/examples/inputtext-readonly.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-readonly.component.ts @@ -6,17 +6,14 @@ type Story = StoryObj; export const Readonly: Story = { name: 'Readonly', render: (args) => ({ - props: { ...args, value: 'Только для чтения' }, + props: { ...args }, template: ` `, }), @@ -33,10 +30,9 @@ export const Readonly: Story = { language: 'ts', code: ` import { InputTextComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; // template: -// +// `, }, }, diff --git a/src/stories/components/inputtext/inputtext.stories.ts b/src/stories/components/inputtext/inputtext.stories.ts index f667ee3b..fe639c98 100644 --- a/src/stories/components/inputtext/inputtext.stories.ts +++ b/src/stories/components/inputtext/inputtext.stories.ts @@ -1,5 +1,4 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { FormsModule } from '@angular/forms'; import { InputTextComponent } from '../../../lib/components/inputtext/inputtext.component'; import { ClearButton } from './examples/inputtext-clear.component'; import { InputTextFloatLabelComponent, FloatLabelStory } from './examples/inputtext-float-label.component'; @@ -17,7 +16,6 @@ const meta: Meta = { moduleMetadata({ imports: [ InputTextComponent, - FormsModule, InputTextFloatLabelComponent, ], }), @@ -55,15 +53,8 @@ import { InputTextModule } from 'primeng/inputtext'; type: { summary: "'small' | 'base' | 'large' | 'xlarge'" }, }, }, - disabled: { - control: 'boolean', - description: 'Отключает взаимодействие', - table: { - category: 'Props', - defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, - }, + disabled: { table: { disable: true } }, + invalid: { table: { disable: true } }, readonly: { control: 'boolean', description: 'Только для чтения', @@ -73,15 +64,6 @@ import { InputTextModule } from 'primeng/inputtext'; type: { summary: 'boolean' }, }, }, - invalid: { - control: 'boolean', - description: 'Невалидное состояние', - table: { - category: 'Props', - defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, - }, showClear: { control: 'boolean', description: 'Показывает иконку очистки при наличии значения', @@ -118,9 +100,7 @@ import { InputTextModule } from 'primeng/inputtext'; args: { placeholder: 'Введите текст...', size: 'base', - disabled: false, readonly: false, - invalid: false, showClear: false, fluid: false, }, @@ -137,16 +117,13 @@ export const Default: Story = { if (args.placeholder) parts.push(`placeholder="${args.placeholder}"`); if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); - if (args.disabled) parts.push(`[disabled]="true"`); if (args.readonly) parts.push(`[readonly]="true"`); - if (args.invalid) parts.push(`[invalid]="true"`); if (args.showClear) parts.push(`[showClear]="true"`); if (args.fluid) parts.push(`[fluid]="true"`); - parts.push(`[(ngModel)]="value"`); const template = ``; - return { props: { ...args, value: '' }, template }; + return { props: { ...args }, template }; }, parameters: { docs: { From 28735e7e59b0275fe46819217f6806c4b925ebf0 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 10:14:09 +0700 Subject: [PATCH 140/258] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20story=20FloatLabel=20+=20Invalid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...inputtext-float-label-invalid.component.ts | 66 +++++++++++++++++++ .../components/inputtext/inputtext.stories.ts | 4 +- 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts diff --git a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts new file mode 100644 index 00000000..7aa6147a --- /dev/null +++ b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts @@ -0,0 +1,66 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { InputText } from 'primeng/inputtext'; +import { FloatLabel } from 'primeng/floatlabel'; + +export const template = ` +
+ + + + +
+`; +const styles = ''; + +@Component({ + selector: 'app-inputtext-float-label-invalid', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputText, FloatLabel, FormsModule], + template, + styles, +}) +export class InputTextFloatLabelInvalidComponent { + value = ''; +} + +export const FloatLabelInvalid: StoryObj = { + name: 'FloatLabel + Invalid', + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'FloatLabel с невалидным состоянием — демонстрирует стилизацию ошибки в комбинации с плавающей меткой.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { InputText } from 'primeng/inputtext'; +import { FloatLabel } from 'primeng/floatlabel'; +import { FormsModule } from '@angular/forms'; + +@Component({ + selector: 'app-inputtext-float-label-invalid', + standalone: true, + imports: [InputText, FloatLabel, FormsModule], + template: \` + + + + + \`, +}) +export class InputTextFloatLabelInvalidComponent { + value = ''; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/inputtext/inputtext.stories.ts b/src/stories/components/inputtext/inputtext.stories.ts index fe639c98..04dcd13a 100644 --- a/src/stories/components/inputtext/inputtext.stories.ts +++ b/src/stories/components/inputtext/inputtext.stories.ts @@ -2,6 +2,7 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { InputTextComponent } from '../../../lib/components/inputtext/inputtext.component'; import { ClearButton } from './examples/inputtext-clear.component'; import { InputTextFloatLabelComponent, FloatLabelStory } from './examples/inputtext-float-label.component'; +import { InputTextFloatLabelInvalidComponent, FloatLabelInvalid } from './examples/inputtext-float-label-invalid.component'; import { Disabled } from './examples/inputtext-disabled.component'; import { Readonly } from './examples/inputtext-readonly.component'; import { Invalid } from './examples/inputtext-invalid.component'; @@ -17,6 +18,7 @@ const meta: Meta = { imports: [ InputTextComponent, InputTextFloatLabelComponent, + InputTextFloatLabelInvalidComponent, ], }), ], @@ -135,4 +137,4 @@ export const Default: Story = { }; // ── Re-exports from example components ──────────────────────────────────── -export { ClearButton, FloatLabelStory as FloatLabel, Disabled, Readonly, Invalid }; +export { ClearButton, FloatLabelStory as FloatLabel, FloatLabelInvalid, Disabled, Readonly, Invalid }; From aeed5636fd2271c51c35155f3ebf7169e2af4c04 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 19:07:20 +0700 Subject: [PATCH 141/258] modified .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 808f9bdc..ce8e3c03 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ src/assets/components/themes /storybook-static /debug-storybook.log /documentation.json + +.claude/* \ No newline at end of file From 10d763f9789ebe51a5eb2e675faa247875355302 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 19:15:45 +0700 Subject: [PATCH 142/258] =?UTF-8?q?=D0=B0=D0=B4=D0=B4=D0=BE=D0=BD=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA?= =?UTF-8?q?=D0=B8=20=D1=82=D1=91=D0=BC=D0=BD=D0=BE=D0=B9=20=D1=82=D0=B5?= =?UTF-8?q?=D0=BC=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .storybook/main.ts | 2 +- .storybook/preview.ts | 10 +++++++++- package-lock.json | 18 ++++++++++++++++++ package.json | 1 + 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/.storybook/main.ts b/.storybook/main.ts index 9c4112e5..fb574771 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -2,7 +2,7 @@ import type { StorybookConfig } from '@storybook/angular'; const config: StorybookConfig = { stories: ['../src/stories/**/*.mdx', '../src/stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'], - addons: ['@storybook/addon-a11y', '@storybook/addon-docs'], + addons: ['@storybook/addon-a11y', '@storybook/addon-docs', '@storybook/addon-themes'], framework: '@storybook/angular' }; export default config; diff --git a/.storybook/preview.ts b/.storybook/preview.ts index acc752b9..2b510880 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,5 +1,6 @@ import { applicationConfig, Preview } from '@storybook/angular'; import { setCompodocJson } from '@storybook/addon-docs/angular'; +import { withThemeByClassName } from '@storybook/addon-themes'; import docJson from '../documentation.json'; import { providePrimeNG } from 'primeng/config'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; @@ -19,12 +20,19 @@ const preview: Preview = { theme: { preset: Preset, options: { - darkModeSelector: false, + darkModeSelector: '.dark', cssLayer: false } } }) ] + }), + withThemeByClassName({ + themes: { + light: '', + dark: 'dark' + }, + defaultTheme: 'light' }) ], parameters: { diff --git a/package-lock.json b/package-lock.json index 9f93e08e..9fd05aaf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "@primeng/themes": "20.4.0", "@storybook/addon-a11y": "10.1.8", "@storybook/addon-docs": "10.1.8", + "@storybook/addon-themes": "^10.1.8", "@storybook/angular": "10.1.8", "@tabler/icons-webfont": "3.35.0", "@types/jasmine": "5.1.13", @@ -6656,6 +6657,23 @@ "storybook": "^10.1.8" } }, + "node_modules/@storybook/addon-themes": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/@storybook/addon-themes/-/addon-themes-10.1.8.tgz", + "integrity": "sha512-UqaajGe4F18Ne4Z5JUqq+OBS8CqgqvVja7J4ipRjvwP6Myh4/GZP7SXKcA17jrY7xWy4qnVdCSsEthviVMMLkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^10.1.8" + } + }, "node_modules/@storybook/angular": { "version": "10.1.8", "resolved": "https://registry.npmjs.org/@storybook/angular/-/angular-10.1.8.tgz", diff --git a/package.json b/package.json index b4ef8b1f..d98f557d 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@primeng/themes": "20.4.0", "@storybook/addon-a11y": "10.1.8", "@storybook/addon-docs": "10.1.8", + "@storybook/addon-themes": "^10.1.8", "@storybook/angular": "10.1.8", "@tabler/icons-webfont": "3.35.0", "@types/jasmine": "5.1.13", From 885170f8fe403eabaafc7156fcbc3031f9515d76 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 22:02:21 +0700 Subject: [PATCH 143/258] =?UTF-8?q?=D1=86=D0=B2=D0=B5=D1=82=20=D0=B8=20?= =?UTF-8?q?=D1=88=D0=B8=D1=80=D0=B8=D0=BD=D0=B0=20=D0=B4=D0=BB=D1=8F=20foc?= =?UTF-8?q?usRing=20=D0=B4=D0=BB=D1=8F=20=D1=81=D0=BE=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=8F=D0=BD=D0=B8=D1=8F=20focus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/inputtext.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prime-preset/tokens/components/inputtext.ts b/src/prime-preset/tokens/components/inputtext.ts index 6a2af63e..b6999d87 100644 --- a/src/prime-preset/tokens/components/inputtext.ts +++ b/src/prime-preset/tokens/components/inputtext.ts @@ -20,7 +20,7 @@ export const inputtextCss = ({ dt }: { dt: (token: string) => string }): string /* ─── Focus ─── */ .p-inputtext:enabled:focus { - box-shadow: 0 0 0 1px ${dt('inputtext.root.focusBorderColor')}; + box-shadow: 0 0 0 ${dt('inputtext.focusRing.width')} ${dt('inputtext.focusRing.color')}; } /* ─── Invalid + Focus ─── */ From d69122d0587e77f18f31f8f89f1463c25000d48a Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 22:09:09 +0700 Subject: [PATCH 144/258] =?UTF-8?q?inputtext:=20disabled/invalid=20=D0=B2?= =?UTF-8?q?=20stories=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20FormControl=20+?= =?UTF-8?q?=20NgControl=20=D0=B2=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inputtext/inputtext.component.ts | 18 ++++++-- .../examples/inputtext-disabled.component.ts | 43 +++++++++---------- .../examples/inputtext-invalid.component.ts | 43 +++++++++---------- .../components/inputtext/inputtext.stories.ts | 35 ++++++++++++--- 4 files changed, 84 insertions(+), 55 deletions(-) diff --git a/src/lib/components/inputtext/inputtext.component.ts b/src/lib/components/inputtext/inputtext.component.ts index cea025fe..3904b924 100644 --- a/src/lib/components/inputtext/inputtext.component.ts +++ b/src/lib/components/inputtext/inputtext.component.ts @@ -1,5 +1,5 @@ -import { Component, Input, Output, EventEmitter, forwardRef } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Component, Input, Output, EventEmitter, forwardRef, inject, Injector, OnInit } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms'; import { NgClass } from '@angular/common'; import { InputText } from 'primeng/inputtext'; import { IconField } from 'primeng/iconfield'; @@ -62,7 +62,14 @@ export type InputTextSize = 'small' | 'base' | 'large' | 'xlarge'; } `, }) -export class InputTextComponent implements ControlValueAccessor { +export class InputTextComponent implements ControlValueAccessor, OnInit { + private readonly _injector = inject(Injector); + private _ngControl: NgControl | null = null; + + ngOnInit(): void { + this._ngControl = this._injector.get(NgControl, null, { self: true, optional: true }); + } + @Input() placeholder = ''; @Input() size: InputTextSize = 'base'; @Input() readonly = false; @@ -70,7 +77,10 @@ export class InputTextComponent implements ControlValueAccessor { @Input() fluid = false; disabled = false; - invalid = false; + + get invalid(): boolean { + return this._ngControl?.invalid ?? false; + } @Output() onClear = new EventEmitter(); diff --git a/src/stories/components/inputtext/examples/inputtext-disabled.component.ts b/src/stories/components/inputtext/examples/inputtext-disabled.component.ts index dc385cb8..5fa97709 100644 --- a/src/stories/components/inputtext/examples/inputtext-disabled.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-disabled.component.ts @@ -1,39 +1,36 @@ +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; -type Story = StoryObj; - -export const Disabled: Story = { +export const Disabled: StoryObj = { name: 'Disabled', - render: (args) => ({ - props: { ...args }, - template: ` - - `, - }), - args: { - disabled: true, - placeholder: 'Введите текст...', + render: (args) => { + const control = new FormControl({ value: '', disabled: true }); + return { + props: { ...args, control }, + template: ``, + }; }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputTextComponent, ReactiveFormsModule], + }, + }), + ], parameters: { + controls: { disable: true }, docs: { - description: { - story: 'Отключённое состояние — управляется через formControl.', - }, + description: { story: 'Отключённое состояние — управляется через FormControl.' }, source: { language: 'ts', code: ` import { InputTextComponent } from '@cdek-it/angular-ui-kit'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -// formControl = new FormControl({ value: '', disabled: true }); -// +control = new FormControl({ value: '', disabled: true }); +// template: `, }, }, diff --git a/src/stories/components/inputtext/examples/inputtext-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-invalid.component.ts index a3610d03..6bb35aee 100644 --- a/src/stories/components/inputtext/examples/inputtext-invalid.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-invalid.component.ts @@ -1,39 +1,36 @@ +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; -type Story = StoryObj; - -export const Invalid: Story = { +export const Invalid: StoryObj = { name: 'Invalid', - render: (args) => ({ - props: { ...args }, - template: ` - - `, - }), - args: { - invalid: true, - placeholder: 'Обязательное поле', + render: (args) => { + const control = new FormControl('', Validators.required); + return { + props: { ...args, control }, + template: ``, + }; }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputTextComponent, ReactiveFormsModule], + }, + }), + ], parameters: { + controls: { disable: true }, docs: { - description: { - story: 'Невалидное состояние — управляется через formControl валидацию.', - }, + description: { story: 'Невалидное состояние — управляется через FormControl + Validators.' }, source: { language: 'ts', code: ` import { InputTextComponent } from '@cdek-it/angular-ui-kit'; import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; -// formControl = new FormControl('', Validators.required); -// +control = new FormControl('', Validators.required); +// template: `, }, }, diff --git a/src/stories/components/inputtext/inputtext.stories.ts b/src/stories/components/inputtext/inputtext.stories.ts index 04dcd13a..57545c18 100644 --- a/src/stories/components/inputtext/inputtext.stories.ts +++ b/src/stories/components/inputtext/inputtext.stories.ts @@ -1,4 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { InputTextComponent } from '../../../lib/components/inputtext/inputtext.component'; import { ClearButton } from './examples/inputtext-clear.component'; import { InputTextFloatLabelComponent, FloatLabelStory } from './examples/inputtext-float-label.component'; @@ -7,7 +8,7 @@ import { Disabled } from './examples/inputtext-disabled.component'; import { Readonly } from './examples/inputtext-readonly.component'; import { Invalid } from './examples/inputtext-invalid.component'; -type InputTextArgs = InputTextComponent; +type InputTextArgs = InputTextComponent & { disabled: boolean; invalid: boolean }; const meta: Meta = { title: 'Components/Form/InputText', @@ -17,6 +18,7 @@ const meta: Meta = { moduleMetadata({ imports: [ InputTextComponent, + ReactiveFormsModule, InputTextFloatLabelComponent, InputTextFloatLabelInvalidComponent, ], @@ -55,8 +57,24 @@ import { InputTextModule } from 'primeng/inputtext'; type: { summary: "'small' | 'base' | 'large' | 'xlarge'" }, }, }, - disabled: { table: { disable: true } }, - invalid: { table: { disable: true } }, + disabled: { + control: 'boolean', + description: 'Отключает взаимодействие — управляется через FormControl', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + invalid: { + control: 'boolean', + description: 'Невалидное состояние — управляется через FormControl', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, readonly: { control: 'boolean', description: 'Только для чтения', @@ -102,6 +120,8 @@ import { InputTextModule } from 'primeng/inputtext'; args: { placeholder: 'Введите текст...', size: 'base', + disabled: false, + invalid: false, readonly: false, showClear: false, fluid: false, @@ -123,9 +143,14 @@ export const Default: Story = { if (args.showClear) parts.push(`[showClear]="true"`); if (args.fluid) parts.push(`[fluid]="true"`); - const template = ``; + const validators = []; + if (args.invalid) validators.push(Validators.required); + + const control = new FormControl({ value: '', disabled: args.disabled }, validators); + + const template = ``; - return { props: { ...args }, template }; + return { props: { ...args, control }, template }; }, parameters: { docs: { From 0d78e17a20a66e831f1c2eaba5fc3273f4c578a6 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 22:16:42 +0700 Subject: [PATCH 145/258] =?UTF-8?q?=D1=80=D0=B0=D1=81=D0=BA=D0=BE=D0=BC?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=20?= =?UTF-8?q?source.code=20=D0=B2=20stories=20Disabled/Invalid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/inputtext-disabled.component.ts | 13 ++++++++++--- .../examples/inputtext-invalid.component.ts | 13 ++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/stories/components/inputtext/examples/inputtext-disabled.component.ts b/src/stories/components/inputtext/examples/inputtext-disabled.component.ts index 5fa97709..4bf1948d 100644 --- a/src/stories/components/inputtext/examples/inputtext-disabled.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-disabled.component.ts @@ -26,11 +26,18 @@ export const Disabled: StoryObj = { source: { language: 'ts', code: ` -import { InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { InputTextComponent } from '@cdek-it/angular-ui-kit'; -control = new FormControl({ value: '', disabled: true }); -// template: +@Component({ + standalone: true, + imports: [InputTextComponent, ReactiveFormsModule], + template: \`\`, +}) +export class DisabledExample { + control = new FormControl({ value: '', disabled: true }); +} `, }, }, diff --git a/src/stories/components/inputtext/examples/inputtext-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-invalid.component.ts index 6bb35aee..ee49015b 100644 --- a/src/stories/components/inputtext/examples/inputtext-invalid.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-invalid.component.ts @@ -26,11 +26,18 @@ export const Invalid: StoryObj = { source: { language: 'ts', code: ` -import { InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { Component } from '@angular/core'; import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; +import { InputTextComponent } from '@cdek-it/angular-ui-kit'; -control = new FormControl('', Validators.required); -// template: +@Component({ + standalone: true, + imports: [InputTextComponent, ReactiveFormsModule], + template: \`\`, +}) +export class InvalidExample { + control = new FormControl('', Validators.required); +} `, }, }, From 0acd486fdeb35af41aedfec15e498bebe1e68aa4 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 22:28:54 +0700 Subject: [PATCH 146/258] =?UTF-8?q?=D0=BC=D0=B0=D0=BA=D1=80=D0=B5=D1=80=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=8F=D0=B7=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D0=BF=D0=BE=D0=BB=D1=8F=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20FloatLabel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/inputtext-float-label-invalid.component.ts | 4 ++-- .../inputtext/examples/inputtext-float-label.component.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts index 7aa6147a..b6a5d606 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts @@ -8,7 +8,7 @@ export const template = `
- +
`; @@ -52,7 +52,7 @@ import { FormsModule } from '@angular/forms'; template: \` - + \`, }) diff --git a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts index 3977c822..8618a593 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts @@ -8,7 +8,7 @@ const template = `
- +
`; @@ -52,7 +52,7 @@ import { FormsModule } from '@angular/forms'; template: \` - + \`, }) From efee79f23787bc279b9c1cf5c1e74a194295baa7 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 22:31:40 +0700 Subject: [PATCH 147/258] =?UTF-8?q?=D0=B2=20Controls=20=D1=87=D0=B5=D0=BA?= =?UTF-8?q?=D0=B1=D0=BE=D0=BA=D1=81=20required=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BC=D0=B0=D1=80=D0=BA=D0=B5=D1=80=D0=B0=20req?= =?UTF-8?q?uired?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...inputtext-float-label-invalid.component.ts | 45 +++++++++++-------- .../inputtext-float-label.component.ts | 43 +++++++++++------- 2 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts index b6a5d606..35e09cc1 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts @@ -1,38 +1,48 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { NgIf } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; -export const template = ` +@Component({ + selector: 'app-inputtext-float-label-invalid', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputText, FloatLabel, FormsModule, NgIf], + template: `
- +
-`; -const styles = ''; - -@Component({ - selector: 'app-inputtext-float-label-invalid', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputText, FloatLabel, FormsModule], - template, - styles, +`, }) export class InputTextFloatLabelInvalidComponent { value = ''; + @Input() required = false; } export const FloatLabelInvalid: StoryObj = { name: 'FloatLabel + Invalid', - render: () => ({ - template: ``, + render: (args) => ({ + template: ``, + props: { required: args['required'] }, }), + args: { required: true }, + argTypes: { + required: { + control: 'boolean', + description: 'Показывает маркер обязательного поля `*` рядом с меткой', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + }, parameters: { - controls: { disable: true }, docs: { description: { story: 'FloatLabel с невалидным состоянием — демонстрирует стилизацию ошибки в комбинации с плавающей меткой.', @@ -46,7 +56,6 @@ import { FloatLabel } from 'primeng/floatlabel'; import { FormsModule } from '@angular/forms'; @Component({ - selector: 'app-inputtext-float-label-invalid', standalone: true, imports: [InputText, FloatLabel, FormsModule], template: \` @@ -56,7 +65,7 @@ import { FormsModule } from '@angular/forms'; \`, }) -export class InputTextFloatLabelInvalidComponent { +export class FloatLabelInvalidExample { value = ''; } `, diff --git a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts index 8618a593..2993498b 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts @@ -1,37 +1,47 @@ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; +import { NgIf } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; -const template = ` +@Component({ + selector: 'app-inputtext-float-label', + standalone: true, + imports: [InputText, FloatLabel, FormsModule, NgIf], + template: `
- +
-`; -const styles = ''; - -@Component({ - selector: 'app-inputtext-float-label', - standalone: true, - imports: [InputText, FloatLabel, FormsModule], - template, - styles, +`, }) export class InputTextFloatLabelComponent { value = ''; + @Input() required = false; } export const FloatLabelStory: StoryObj = { name: 'FloatLabel', - render: () => ({ - template: ``, + render: (args) => ({ + template: ``, + props: { required: args['required'] }, }), + args: { required: true }, + argTypes: { + required: { + control: 'boolean', + description: 'Показывает маркер обязательного поля `*` рядом с меткой', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + }, parameters: { - controls: { disable: true }, docs: { description: { story: @@ -46,7 +56,6 @@ import { FloatLabel } from 'primeng/floatlabel'; import { FormsModule } from '@angular/forms'; @Component({ - selector: 'app-inputtext-float-label', standalone: true, imports: [InputText, FloatLabel, FormsModule], template: \` @@ -56,7 +65,7 @@ import { FormsModule } from '@angular/forms'; \`, }) -export class InputTextFloatLabelComponent { +export class FloatLabelExample { value = ''; } `, From 6550075edcfcb3d83f7f5d6715c8d9a4d6a880c6 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 22:33:48 +0700 Subject: [PATCH 148/258] =?UTF-8?q?focusRing=20=D0=B4=D0=BB=D1=8F=20invali?= =?UTF-8?q?d=20=D0=BF=D1=80=D0=B8=20focus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/inputtext.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prime-preset/tokens/components/inputtext.ts b/src/prime-preset/tokens/components/inputtext.ts index b6999d87..027ae6cc 100644 --- a/src/prime-preset/tokens/components/inputtext.ts +++ b/src/prime-preset/tokens/components/inputtext.ts @@ -26,7 +26,7 @@ export const inputtextCss = ({ dt }: { dt: (token: string) => string }): string /* ─── Invalid + Focus ─── */ .p-inputtext.p-invalid:focus { border-color: ${dt('inputtext.root.invalidBorderColor')}; - box-shadow: 0 0 0 1px ${dt('inputtext.root.invalidBorderColor')}; + box-shadow: 0 0 0 ${dt('inputtext.focusRing.width')} ${dt('focusRing.extend.invalid')}; } /* ─── Extra Large ─── */ From b3be4c78962d31b7113b175345a2a051eadb19ba Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 22:43:13 +0700 Subject: [PATCH 149/258] =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D1=91=D0=BD=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=BF=D1=81=20variant=20=D0=B8=D0=B7=20Texta?= =?UTF-8?q?reaComponent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/textarea/textarea.component.ts | 2 -- src/stories/components/textarea/textarea.stories.ts | 12 ------------ 2 files changed, 14 deletions(-) diff --git a/src/lib/components/textarea/textarea.component.ts b/src/lib/components/textarea/textarea.component.ts index 52852c63..d843be98 100644 --- a/src/lib/components/textarea/textarea.component.ts +++ b/src/lib/components/textarea/textarea.component.ts @@ -4,7 +4,6 @@ import { NgClass } from '@angular/common'; import { Textarea } from 'primeng/textarea'; export type TextareaSize = 'small' | 'base' | 'large' | 'xlarge'; -export type TextareaVariant = 'outlined' | 'filled'; @Component({ selector: 'ui-textarea', @@ -48,7 +47,6 @@ export class TextareaComponent implements ControlValueAccessor { @Input() autoResize = false; @Input() rows = 3; @Input() cols?: number; - @Input() variant: TextareaVariant = 'outlined'; @Output() onResize = new EventEmitter<{ height: string }>(); diff --git a/src/stories/components/textarea/textarea.stories.ts b/src/stories/components/textarea/textarea.stories.ts index c4bd17b8..456bc00c 100644 --- a/src/stories/components/textarea/textarea.stories.ts +++ b/src/stories/components/textarea/textarea.stories.ts @@ -125,16 +125,6 @@ import { TextareaComponent } from '@cdek-it/angular-ui-kit'; type: { summary: 'number' }, }, }, - variant: { - control: 'select', - options: ['outlined', 'filled'], - description: 'Визуальный вариант поля', - table: { - category: 'Props', - defaultValue: { summary: "'outlined'" }, - type: { summary: "'outlined' | 'filled'" }, - }, - }, // Скрыть внутренние computed props modelValue: { table: { disable: true } }, primeSize: { table: { disable: true } }, @@ -158,7 +148,6 @@ import { TextareaComponent } from '@cdek-it/angular-ui-kit'; fluid: false, autoResize: false, rows: 3, - variant: 'outlined', }, }; @@ -180,7 +169,6 @@ export const Default: Story = { if (args.autoResize) parts.push(`[autoResize]="true"`); if (args.rows && args.rows !== 3) parts.push(`[rows]="${args.rows}"`); if (args.cols) parts.push(`[cols]="${args.cols}"`); - if (args.variant && args.variant !== 'outlined') parts.push(`variant="${args.variant}"`); parts.push(`[(ngModel)]="value"`); const template = ``; From eac3d7783de0bb5d0598fde28f8aae2da2bcb0d9 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 22:43:40 +0700 Subject: [PATCH 150/258] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20showClear=20+=20NgControl=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20invalid=20=D0=B2=20TextareaComponent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/textarea/textarea.component.ts | 98 ++++++++++++++----- 1 file changed, 75 insertions(+), 23 deletions(-) diff --git a/src/lib/components/textarea/textarea.component.ts b/src/lib/components/textarea/textarea.component.ts index d843be98..46dfc60f 100644 --- a/src/lib/components/textarea/textarea.component.ts +++ b/src/lib/components/textarea/textarea.component.ts @@ -1,7 +1,9 @@ -import { ChangeDetectionStrategy, Component, Input, Output, EventEmitter, forwardRef } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ChangeDetectionStrategy, Component, Input, Output, EventEmitter, forwardRef, inject, Injector, OnInit } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms'; import { NgClass } from '@angular/common'; import { Textarea } from 'primeng/textarea'; +import { IconField } from 'primeng/iconfield'; +import { InputIcon } from 'primeng/inputicon'; export type TextareaSize = 'small' | 'base' | 'large' | 'xlarge'; @@ -9,7 +11,7 @@ export type TextareaSize = 'small' | 'base' | 'large' | 'xlarge'; selector: 'ui-textarea', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [Textarea, NgClass], + imports: [Textarea, IconField, InputIcon, NgClass], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -18,37 +20,81 @@ export type TextareaSize = 'small' | 'base' | 'large' | 'xlarge'; }, ], template: ` - + @if (showClear) { + + + + + } @else { + + } `, }) -export class TextareaComponent implements ControlValueAccessor { +export class TextareaComponent implements ControlValueAccessor, OnInit { + private readonly _injector = inject(Injector); + private _ngControl: NgControl | null = null; + + ngOnInit(): void { + this._ngControl = this._injector.get(NgControl, null, { self: true, optional: true }); + } + @Input() placeholder = ''; @Input() size: TextareaSize = 'base'; - @Input() disabled = false; @Input() readonly = false; - @Input() invalid = false; + @Input() showClear = false; @Input() fluid = false; @Input() autoResize = false; @Input() rows = 3; @Input() cols?: number; + disabled = false; + + get invalid(): boolean { + return this._ngControl?.invalid ?? false; + } + @Output() onResize = new EventEmitter<{ height: string }>(); + @Output() onClear = new EventEmitter(); modelValue = ''; @@ -72,6 +118,12 @@ export class TextareaComponent implements ControlValueAccessor { onTouched: () => void = () => {}; + clearValue(): void { + this.modelValue = ''; + this._onChange(''); + this.onClear.emit(); + } + writeValue(value: string): void { this.modelValue = value ?? ''; } From 91907ead4a1817d0ad3b7ef0dbcc9d065b717d41 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 22:44:46 +0700 Subject: [PATCH 151/258] =?UTF-8?q?stories=20Textarea=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=D1=8B=20=D0=BD=D0=B0=20For?= =?UTF-8?q?mControl=20+=20NgControl=20=D0=B2=20=D0=BA=D0=BE=D0=BC=D0=BF?= =?UTF-8?q?=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/textarea-disabled.component.ts | 56 +++++++++---------- .../examples/textarea-invalid.component.ts | 56 +++++++++---------- .../components/textarea/textarea.stories.ts | 53 +++++++++++------- 3 files changed, 90 insertions(+), 75 deletions(-) diff --git a/src/stories/components/textarea/examples/textarea-disabled.component.ts b/src/stories/components/textarea/examples/textarea-disabled.component.ts index 213d8f0c..225fb177 100644 --- a/src/stories/components/textarea/examples/textarea-disabled.component.ts +++ b/src/stories/components/textarea/examples/textarea-disabled.component.ts @@ -1,43 +1,43 @@ +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; -type Story = StoryObj; - -export const Disabled: Story = { +export const Disabled: StoryObj = { name: 'Disabled', - render: (args) => ({ - props: { ...args, value: 'Текст в заблокированном поле' }, - template: ` - - `, - }), - args: { - disabled: true, - placeholder: 'Введите текст...', + render: (args) => { + const control = new FormControl({ value: 'Текст в заблокированном поле', disabled: true }); + return { + props: { ...args, control }, + template: ``, + }; }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [TextareaComponent, ReactiveFormsModule], + }, + }), + ], parameters: { + controls: { disable: true }, docs: { - description: { - story: 'Отключённое состояние — поле недоступно для взаимодействия.', - }, + description: { story: 'Отключённое состояние — управляется через FormControl.' }, source: { language: 'ts', code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { TextareaComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; -// template: -// +@Component({ + standalone: true, + imports: [TextareaComponent, ReactiveFormsModule], + template: \`\`, +}) +export class DisabledExample { + control = new FormControl({ value: '', disabled: true }); +} `, }, }, diff --git a/src/stories/components/textarea/examples/textarea-invalid.component.ts b/src/stories/components/textarea/examples/textarea-invalid.component.ts index 0ab85e97..021c56cc 100644 --- a/src/stories/components/textarea/examples/textarea-invalid.component.ts +++ b/src/stories/components/textarea/examples/textarea-invalid.component.ts @@ -1,43 +1,43 @@ +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; -type Story = StoryObj; - -export const Invalid: Story = { +export const Invalid: StoryObj = { name: 'Invalid', - render: (args) => ({ - props: { ...args, value: '' }, - template: ` - - `, - }), - args: { - invalid: true, - placeholder: 'Обязательное поле', + render: (args) => { + const control = new FormControl('', Validators.required); + return { + props: { ...args, control }, + template: ``, + }; }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [TextareaComponent, ReactiveFormsModule], + }, + }), + ], parameters: { + controls: { disable: true }, docs: { - description: { - story: 'Невалидное состояние — поле выделяется красной рамкой.', - }, + description: { story: 'Невалидное состояние — управляется через FormControl + Validators.' }, source: { language: 'ts', code: ` +import { Component } from '@angular/core'; +import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; import { TextareaComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; -// template: -// +@Component({ + standalone: true, + imports: [TextareaComponent, ReactiveFormsModule], + template: \`\`, +}) +export class InvalidExample { + control = new FormControl('', Validators.required); +} `, }, }, diff --git a/src/stories/components/textarea/textarea.stories.ts b/src/stories/components/textarea/textarea.stories.ts index 456bc00c..8f8400cb 100644 --- a/src/stories/components/textarea/textarea.stories.ts +++ b/src/stories/components/textarea/textarea.stories.ts @@ -1,8 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { NgClass } from '@angular/common'; -import { FormsModule } from '@angular/forms'; -import { FloatLabel } from 'primeng/floatlabel'; -import { Textarea } from 'primeng/textarea'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { TextareaComponent } from '../../../lib/components/textarea/textarea.component'; import { Disabled } from './examples/textarea-disabled.component'; import { Readonly } from './examples/textarea-readonly.component'; @@ -11,7 +8,7 @@ import { AutoResize, TextareaAutoResizeComponent } from './examples/textarea-aut import { Sizes } from './examples/textarea-sizes.component'; import { FloatLabelStory, TextareaFloatLabelComponent } from './examples/textarea-float-label.component'; -type TextareaArgs = TextareaComponent; +type TextareaArgs = TextareaComponent & { disabled: boolean; invalid: boolean }; const meta: Meta = { title: 'Components/Form/Textarea', @@ -21,10 +18,7 @@ const meta: Meta = { moduleMetadata({ imports: [ TextareaComponent, - FormsModule, - NgClass, - Textarea, - FloatLabel, + ReactiveFormsModule, TextareaAutoResizeComponent, TextareaFloatLabelComponent, ], @@ -64,7 +58,16 @@ import { TextareaComponent } from '@cdek-it/angular-ui-kit'; }, disabled: { control: 'boolean', - description: 'Отключает взаимодействие', + description: 'Отключает взаимодействие — управляется через FormControl', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + invalid: { + control: 'boolean', + description: 'Невалидное состояние — управляется через FormControl', table: { category: 'Props', defaultValue: { summary: 'false' }, @@ -80,9 +83,9 @@ import { TextareaComponent } from '@cdek-it/angular-ui-kit'; type: { summary: 'boolean' }, }, }, - invalid: { + showClear: { control: 'boolean', - description: 'Невалидное состояние', + description: 'Показывает иконку очистки при наличии значения', table: { category: 'Props', defaultValue: { summary: 'false' }, @@ -125,7 +128,7 @@ import { TextareaComponent } from '@cdek-it/angular-ui-kit'; type: { summary: 'number' }, }, }, - // Скрыть внутренние computed props + // Hidden computed props modelValue: { table: { disable: true } }, primeSize: { table: { disable: true } }, sizeClass: { table: { disable: true } }, @@ -138,13 +141,22 @@ import { TextareaComponent } from '@cdek-it/angular-ui-kit'; type: { summary: 'EventEmitter<{ height: string }>' }, }, }, + onClear: { + control: false, + description: 'Событие очистки поля (при showClear)', + table: { + category: 'Events', + type: { summary: 'EventEmitter' }, + }, + }, }, args: { placeholder: 'Введите текст...', size: 'base', disabled: false, - readonly: false, invalid: false, + readonly: false, + showClear: false, fluid: false, autoResize: false, rows: 3, @@ -162,18 +174,21 @@ export const Default: Story = { if (args.placeholder) parts.push(`placeholder="${args.placeholder}"`); if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); - if (args.disabled) parts.push(`[disabled]="true"`); if (args.readonly) parts.push(`[readonly]="true"`); - if (args.invalid) parts.push(`[invalid]="true"`); + if (args.showClear) parts.push(`[showClear]="true"`); if (args.fluid) parts.push(`[fluid]="true"`); if (args.autoResize) parts.push(`[autoResize]="true"`); if (args.rows && args.rows !== 3) parts.push(`[rows]="${args.rows}"`); if (args.cols) parts.push(`[cols]="${args.cols}"`); - parts.push(`[(ngModel)]="value"`); - const template = ``; + const validators = []; + if (args.invalid) validators.push(Validators.required); + + const control = new FormControl({ value: '', disabled: args.disabled }, validators); + + const template = ``; - return { props: { ...args, value: '' }, template }; + return { props: { ...args, control }, template }; }, parameters: { docs: { From 4a810b4e1a30f70257213539d84a6234ee528ccb Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 22:45:03 +0700 Subject: [PATCH 152/258] =?UTF-8?q?textarea:=20box-shadow=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=20=D1=84=D0=BE=D0=BA=D1=83=D1=81=D0=B5,=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20disabled/readonly?= =?UTF-8?q?=20CSS,=20invalid=20>=20focus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/textarea.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/prime-preset/tokens/components/textarea.ts b/src/prime-preset/tokens/components/textarea.ts index d35154ad..b66df116 100644 --- a/src/prime-preset/tokens/components/textarea.ts +++ b/src/prime-preset/tokens/components/textarea.ts @@ -16,12 +16,24 @@ export const textareaCss = ({ dt }: { dt: (token: string) => string }): string = /* --- States --- */ .p-textarea:enabled:read-only { background: ${dt('textarea.extend.readonlyBackground')}; + color: ${dt('textarea.color')}; } -.p-textarea:is(.p-disabled, :disabled) { - background: ${dt('textarea.disabled.background')}; - color: ${dt('textarea.disabled.color')}; +.p-textarea:disabled { + background: ${dt('textarea.disabledBackground')}; + color: ${dt('textarea.disabledColor')}; opacity: 1; } +/* --- Focus --- */ +.p-textarea:enabled:focus { + box-shadow: 0 0 0 ${dt('textarea.focusRing.width')} ${dt('textarea.focusRing.color')}; +} + +/* --- Invalid + Focus --- */ +.p-textarea.p-invalid:focus { + border-color: ${dt('textarea.invalidBorderColor')}; + box-shadow: 0 0 0 ${dt('textarea.focusRing.width')} ${dt('focusRing.extend.invalid')}; +} + `; From 46640874e8a835fba04b0055b6249b47f46d64fe Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 23:08:27 +0700 Subject: [PATCH 153/258] =?UTF-8?q?padding-right=20=D0=BA=D0=BE=D0=B3?= =?UTF-8?q?=D0=B4=D0=B0=20=D0=B0=D0=BA=D1=82=D0=B8=D0=B2=D0=B5=D0=BD=20sho?= =?UTF-8?q?wClear?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tokens/components/textarea.ts | 19 +++ .../examples/textarea-autoresize.component.ts | 1 - .../textarea-float-label.component.ts | 153 ++++++++---------- .../examples/textarea-readonly.component.ts | 56 +++---- .../examples/textarea-sizes.component.ts | 57 ++++--- 5 files changed, 145 insertions(+), 141 deletions(-) diff --git a/src/prime-preset/tokens/components/textarea.ts b/src/prime-preset/tokens/components/textarea.ts index b66df116..95854baa 100644 --- a/src/prime-preset/tokens/components/textarea.ts +++ b/src/prime-preset/tokens/components/textarea.ts @@ -36,4 +36,23 @@ export const textareaCss = ({ dt }: { dt: (token: string) => string }): string = box-shadow: 0 0 0 ${dt('textarea.focusRing.width')} ${dt('focusRing.extend.invalid')}; } +/* --- ClearButton (showClear) --- */ +.p-iconfield:has(.p-textarea) { + display: block; + width: fit-content; +} + +.p-iconfield:has(.p-textarea) .p-textarea { + padding-right: ${dt('form.padding.500')}; +} + +.p-iconfield:has(.p-textarea) .p-inputicon { + top: ${dt('form.padding.500')}; + transform: none; + font-size: ${dt('textarea.extend.iconSize')}; + width: ${dt('textarea.extend.iconSize')}; + height: ${dt('textarea.extend.iconSize')}; + cursor: pointer; +} + `; diff --git a/src/stories/components/textarea/examples/textarea-autoresize.component.ts b/src/stories/components/textarea/examples/textarea-autoresize.component.ts index 25913565..ee12d1f7 100644 --- a/src/stories/components/textarea/examples/textarea-autoresize.component.ts +++ b/src/stories/components/textarea/examples/textarea-autoresize.component.ts @@ -5,7 +5,6 @@ import { TextareaComponent } from '../../../../lib/components/textarea/textarea. export const template = `
- - - - -`; -const styles = ''; @Component({ selector: 'app-textarea-float-label', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [Textarea, FloatLabel, FormsModule, NgClass], + imports: [Textarea, FloatLabel, ReactiveFormsModule, NgIf], template: `
- +
`, - styles, }) export class TextareaFloatLabelComponent { - @Input() size: TextareaComponent['size'] = 'base'; - @Input() disabled = false; - @Input() readonly = false; - @Input() invalid = false; - @Input() fluid = false; - @Input() rows = 3; - - value = ''; - - get primeSize(): 'small' | 'large' | undefined { - if (this.size === 'small') return 'small'; - if (this.size === 'large') return 'large'; - return undefined; - } - - get sizeClass(): Record { - return { 'p-textarea-xlg': this.size === 'xlarge' }; - } + control = new FormControl(''); + @Input() label = 'Комментарий'; + @Input() required = false; } -export const FloatLabelStory: StoryObj = { +export const FloatLabelStory: StoryObj = { name: 'FloatLabel', - render: (args) => ({ - props: { ...args }, - template: ` -
- - - - -
- `, - }), - argTypes: { - size: { table: { disable: true } }, + render: (args) => { + const control = new FormControl(''); + return { + props: { ...args, control }, + template: ` +
+ + + + +
+ `, + }; }, args: { - disabled: false, - readonly: false, - invalid: false, - fluid: false, - rows: 3, + label: 'Комментарий', + required: false, + }, + argTypes: { + label: { + control: 'text', + description: 'Текст плавающей метки', + table: { + category: 'Props', + defaultValue: { summary: "'Комментарий'" }, + type: { summary: 'string' }, + }, + }, + required: { + control: 'boolean', + description: 'Показывает маркер обязательного поля `*` рядом с меткой', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [Textarea, FloatLabel, ReactiveFormsModule, NgIf], + }, + }), + ], parameters: { docs: { description: { story: - 'Интеграция с `p-floatlabel variant="in"` — плавающая метка внутри поля. Кликните на поле чтобы увидеть анимацию. Требует нативный ` - + \`, }) -export class MyComponent { - value = ''; +export class FloatLabelExample { + control = new FormControl(''); } `, }, diff --git a/src/stories/components/textarea/examples/textarea-readonly.component.ts b/src/stories/components/textarea/examples/textarea-readonly.component.ts index 71c1550d..184250a0 100644 --- a/src/stories/components/textarea/examples/textarea-readonly.component.ts +++ b/src/stories/components/textarea/examples/textarea-readonly.component.ts @@ -1,43 +1,43 @@ +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; -type Story = StoryObj; - -export const Readonly: Story = { +export const Readonly: StoryObj = { name: 'Readonly', - render: (args) => ({ - props: { ...args, value: 'Только для чтения — этот текст нельзя изменить.' }, - template: ` - - `, - }), - args: { - readonly: true, - placeholder: 'Введите текст...', + render: (args) => { + const control = new FormControl('Только для чтения — этот текст нельзя изменить.'); + return { + props: { ...args, control }, + template: ``, + }; }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [TextareaComponent, ReactiveFormsModule], + }, + }), + ], parameters: { + controls: { disable: true }, docs: { - description: { - story: 'Режим только для чтения — содержимое отображается, но не редактируется.', - }, + description: { story: 'Режим только для чтения — содержимое отображается, но не редактируется.' }, source: { language: 'ts', code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { TextareaComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; -// template: -// +@Component({ + standalone: true, + imports: [TextareaComponent, ReactiveFormsModule], + template: \`\`, +}) +export class ReadonlyExample { + control = new FormControl('Только для чтения.'); +} `, }, }, diff --git a/src/stories/components/textarea/examples/textarea-sizes.component.ts b/src/stories/components/textarea/examples/textarea-sizes.component.ts index f74361d7..c25eca2f 100644 --- a/src/stories/components/textarea/examples/textarea-sizes.component.ts +++ b/src/stories/components/textarea/examples/textarea-sizes.component.ts @@ -1,27 +1,34 @@ +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; -type Story = StoryObj; - -export const Sizes: Story = { +export const Sizes: StoryObj = { name: 'Sizes', - render: (args) => ({ - props: { ...args, value: '' }, - template: ` - - `, - }), + render: (args) => { + const control = new FormControl(''); + return { + props: { ...args, control }, + template: ``, + }; + }, + args: { + size: 'base', + placeholder: 'Введите текст...', + }, + argTypes: { + size: { + control: 'select', + options: ['small', 'base', 'large', 'xlarge'], + }, + }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [TextareaComponent, ReactiveFormsModule], + }, + }), + ], parameters: { docs: { description: { @@ -29,10 +36,12 @@ export const Sizes: Story = { }, source: { language: 'ts', - code: ` - - -`, + code: ` + + + + + `, }, }, }, From c9c90f49f303ee6a7d2c5f40036947323378d62f Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 23:22:35 +0700 Subject: [PATCH 154/258] =?UTF-8?q?=D0=B4=D0=BE=D0=B0=D0=B1=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D0=BF=D1=80=D0=BE=D0=BF=D1=81=D1=8B=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20FloatLabel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tokens/components/textarea.ts | 2 +- .../textarea-float-label.component.ts | 67 +++++++++---------- .../examples/textarea-sizes.component.ts | 2 +- .../components/textarea/textarea.stories.ts | 2 +- 4 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/prime-preset/tokens/components/textarea.ts b/src/prime-preset/tokens/components/textarea.ts index 95854baa..4619309c 100644 --- a/src/prime-preset/tokens/components/textarea.ts +++ b/src/prime-preset/tokens/components/textarea.ts @@ -43,7 +43,7 @@ export const textareaCss = ({ dt }: { dt: (token: string) => string }): string = } .p-iconfield:has(.p-textarea) .p-textarea { - padding-right: ${dt('form.padding.500')}; + padding-right: ${dt('form.padding.700')}; } .p-iconfield:has(.p-textarea) .p-inputicon { diff --git a/src/stories/components/textarea/examples/textarea-float-label.component.ts b/src/stories/components/textarea/examples/textarea-float-label.component.ts index ae734464..d780a5dc 100644 --- a/src/stories/components/textarea/examples/textarea-float-label.component.ts +++ b/src/stories/components/textarea/examples/textarea-float-label.component.ts @@ -3,22 +3,41 @@ import { NgIf } from '@angular/common'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { FloatLabel } from 'primeng/floatlabel'; import { Textarea } from 'primeng/textarea'; +import { IconField } from 'primeng/iconfield'; +import { InputIcon } from 'primeng/inputicon'; import { StoryObj } from '@storybook/angular'; @Component({ selector: 'app-textarea-float-label', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [Textarea, FloatLabel, ReactiveFormsModule, NgIf], + imports: [Textarea, FloatLabel, ReactiveFormsModule, NgIf, IconField, InputIcon], template: ` -
+
- + @if (showClear) { + + + + + } @else { + + }
@@ -28,29 +47,15 @@ export class TextareaFloatLabelComponent { control = new FormControl(''); @Input() label = 'Комментарий'; @Input() required = false; + @Input() showClear = false; } export const FloatLabelStory: StoryObj = { name: 'FloatLabel', - render: (args) => { - const control = new FormControl(''); - return { - props: { ...args, control }, - template: ` -
- - - - -
- `, - }; - }, + render: (args) => ({ + props: { label: args['label'], required: args['required'], showClear: args['showClear'] }, + template: ``, + }), args: { label: 'Комментарий', required: false, @@ -75,14 +80,6 @@ export const FloatLabelStory: StoryObj = { }, }, }, - decorators: [ - (story: any) => ({ - ...story(), - moduleMetadata: { - imports: [Textarea, FloatLabel, ReactiveFormsModule, NgIf], - }, - }), - ], parameters: { docs: { description: { diff --git a/src/stories/components/textarea/examples/textarea-sizes.component.ts b/src/stories/components/textarea/examples/textarea-sizes.component.ts index c25eca2f..9aaf6a79 100644 --- a/src/stories/components/textarea/examples/textarea-sizes.component.ts +++ b/src/stories/components/textarea/examples/textarea-sizes.component.ts @@ -8,7 +8,7 @@ export const Sizes: StoryObj = { const control = new FormControl(''); return { props: { ...args, control }, - template: ``, + template: ``, }; }, args: { diff --git a/src/stories/components/textarea/textarea.stories.ts b/src/stories/components/textarea/textarea.stories.ts index 8f8400cb..7b3b33b6 100644 --- a/src/stories/components/textarea/textarea.stories.ts +++ b/src/stories/components/textarea/textarea.stories.ts @@ -28,7 +28,7 @@ const meta: Meta = { designTokens: { prefix: '--p-textarea' }, docs: { description: { - component: `Многострочное текстовое поле для ввода данных. Поддерживает авторасширение, состояния disabled/readonly/invalid, размеры и интеграцию с формами через CVA. + component: `Многострочное текстовое поле для ввода данных. \`\`\`typescript import { TextareaComponent } from '@cdek-it/angular-ui-kit'; From 48ba27a5a10ca53e6b9d233eb22a98697df571fc Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 23:36:48 +0700 Subject: [PATCH 155/258] =?UTF-8?q?inputnumber:=20box-shadow=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D1=84=D0=BE=D0=BA=D1=83=D1=81=D0=B5,=20invalid?= =?UTF-8?q?=20border=20=D0=BF=D1=80=D0=B8=20focus,=20NgControl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inputnumber/inputnumber.component.ts | 21 ++++++++++++++----- .../tokens/components/inputnumber.ts | 11 ++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/lib/components/inputnumber/inputnumber.component.ts b/src/lib/components/inputnumber/inputnumber.component.ts index 4dd3e4e5..2a1dafe0 100644 --- a/src/lib/components/inputnumber/inputnumber.component.ts +++ b/src/lib/components/inputnumber/inputnumber.component.ts @@ -1,5 +1,5 @@ -import { Component, Input, Output, EventEmitter, forwardRef } from '@angular/core'; -import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Component, Input, Output, EventEmitter, forwardRef, inject, Injector, OnInit } from '@angular/core'; +import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms'; import { NgClass } from '@angular/common'; import { InputNumber } from 'primeng/inputnumber'; import { SharedModule } from 'primeng/api'; @@ -59,7 +59,14 @@ export type InputNumberButtonLayout = 'stacked' | 'horizontal' | 'vertical'; `, }) -export class InputNumberComponent implements ControlValueAccessor { +export class InputNumberComponent implements ControlValueAccessor, OnInit { + private readonly _injector = inject(Injector); + private _ngControl: NgControl | null = null; + + ngOnInit(): void { + this._ngControl = this._injector.get(NgControl, null, { self: true, optional: true }); + } + @Input() size: InputNumberSize = 'base'; @Input() showButtons = false; @Input() buttonLayout: InputNumberButtonLayout = 'stacked'; @@ -67,8 +74,6 @@ export class InputNumberComponent implements ControlValueAccessor { @Input() currency: string | undefined; @Input() locale: string | undefined; @Input() placeholder = ''; - @Input() disabled = false; - @Input() invalid = false; @Input() readonly = false; @Input() fluid = false; @Input() min: number | undefined; @@ -82,6 +87,12 @@ export class InputNumberComponent implements ControlValueAccessor { @Input() incrementButtonIcon: string | undefined; @Input() decrementButtonIcon: string | undefined; + disabled = false; + + get invalid(): boolean { + return this._ngControl?.invalid ?? false; + } + @Output() onInput = new EventEmitter<{ value: number | null }>(); modelValue: number | null = null; diff --git a/src/prime-preset/tokens/components/inputnumber.ts b/src/prime-preset/tokens/components/inputnumber.ts index dc4f5f57..ee036c31 100644 --- a/src/prime-preset/tokens/components/inputnumber.ts +++ b/src/prime-preset/tokens/components/inputnumber.ts @@ -14,6 +14,17 @@ export const inputnumberCss = ({ dt }: { dt: (token: string) => string }): strin border-right: none; } +/* ─── Focus ─── */ +.p-inputnumber .p-inputnumber-input:enabled:focus { + box-shadow: 0 0 0 ${dt('inputtext.focusRing.width')} ${dt('inputtext.focusRing.color')}; +} + +/* ─── Invalid + Focus ─── */ +.p-inputnumber.p-invalid .p-inputnumber-input:focus { + border-color: ${dt('inputtext.root.invalidBorderColor')}; + box-shadow: 0 0 0 1px ${dt('inputtext.root.invalidBorderColor')}; +} + /* ─── Disabled состояние ─── */ .p-inputnumber-horizontal:has(.p-inputnumber-input:disabled) .p-inputnumber-button { background: ${dt('inputtext.root.disabledBackground')}; From 4b749f6137818a798591e4cc625b64525c5b5160 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 23:36:53 +0700 Subject: [PATCH 156/258] =?UTF-8?q?inputnumber=20stories=20Buttons/Disable?= =?UTF-8?q?d/FloatLabel:=20formControl,=20source.code=20=D1=80=D0=B0=D1=81?= =?UTF-8?q?=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/inputnumber-buttons.component.ts | 46 ++++++++++++------ .../inputnumber-disabled.component.ts | 47 +++++++++++++------ .../inputnumber-float-label.component.ts | 22 ++++----- 3 files changed, 75 insertions(+), 40 deletions(-) diff --git a/src/stories/components/inputnumber/examples/inputnumber-buttons.component.ts b/src/stories/components/inputnumber/examples/inputnumber-buttons.component.ts index b366e5f8..9f774228 100644 --- a/src/stories/components/inputnumber/examples/inputnumber-buttons.component.ts +++ b/src/stories/components/inputnumber/examples/inputnumber-buttons.component.ts @@ -1,3 +1,4 @@ +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputNumberComponent } from '../../../../lib/components/inputnumber/inputnumber.component'; @@ -5,17 +6,27 @@ type Story = StoryObj; export const Buttons: Story = { name: 'Buttons', - render: (args) => ({ - props: { ...args, value: null }, - template: ` - - `, - }), - args: {}, + render: () => { + const control = new FormControl(null); + return { + props: { control }, + template: ` + + `, + }; + }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputNumberComponent, ReactiveFormsModule], + }, + }), + ], parameters: { controls: { disable: true }, docs: { @@ -25,11 +36,18 @@ export const Buttons: Story = { source: { language: 'ts', code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { InputNumberComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; -// template: -// +@Component({ + standalone: true, + imports: [InputNumberComponent, ReactiveFormsModule], + template: \`\`, +}) +export class ButtonsExample { + control = new FormControl(null); +} `, }, }, diff --git a/src/stories/components/inputnumber/examples/inputnumber-disabled.component.ts b/src/stories/components/inputnumber/examples/inputnumber-disabled.component.ts index 19d14edb..a2d3f495 100644 --- a/src/stories/components/inputnumber/examples/inputnumber-disabled.component.ts +++ b/src/stories/components/inputnumber/examples/inputnumber-disabled.component.ts @@ -1,3 +1,4 @@ +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputNumberComponent } from '../../../../lib/components/inputnumber/inputnumber.component'; @@ -5,18 +6,27 @@ type Story = StoryObj; export const Disabled: Story = { name: 'Disabled', - render: (args) => ({ - props: { ...args, value: 42 }, - template: ` - - `, - }), - args: {}, + render: () => { + const control = new FormControl({ value: 42, disabled: true }); + return { + props: { control }, + template: ` + + `, + }; + }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputNumberComponent, ReactiveFormsModule], + }, + }), + ], parameters: { controls: { disable: true }, docs: { @@ -26,11 +36,18 @@ export const Disabled: Story = { source: { language: 'ts', code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { InputNumberComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; -// template: -// +@Component({ + standalone: true, + imports: [InputNumberComponent, ReactiveFormsModule], + template: \`\`, +}) +export class DisabledExample { + control = new FormControl({ value: 42, disabled: true }); +} `, }, }, diff --git a/src/stories/components/inputnumber/examples/inputnumber-float-label.component.ts b/src/stories/components/inputnumber/examples/inputnumber-float-label.component.ts index d85ef06b..532093fb 100644 --- a/src/stories/components/inputnumber/examples/inputnumber-float-label.component.ts +++ b/src/stories/components/inputnumber/examples/inputnumber-float-label.component.ts @@ -1,5 +1,5 @@ -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputNumber } from 'primeng/inputnumber'; import { FloatLabel } from 'primeng/floatlabel'; @@ -8,7 +8,7 @@ import { SharedModule } from 'primeng/api'; const template = `
- + @@ -25,12 +25,13 @@ const styles = ''; @Component({ selector: 'app-inputnumber-float-label', standalone: true, - imports: [InputNumber, FloatLabel, FormsModule, SharedModule], + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputNumber, FloatLabel, ReactiveFormsModule, SharedModule], template, styles, }) export class InputNumberFloatLabelComponent { - value: number | null = null; + control = new FormControl(null); } export const FloatLabelStory: StoryObj = { @@ -49,18 +50,17 @@ export const FloatLabelStory: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { InputNumber } from 'primeng/inputnumber'; import { FloatLabel } from 'primeng/floatlabel'; import { SharedModule } from 'primeng/api'; -import { FormsModule } from '@angular/forms'; @Component({ - selector: 'app-inputnumber-float-label', standalone: true, - imports: [InputNumber, FloatLabel, FormsModule, SharedModule], + imports: [InputNumber, FloatLabel, ReactiveFormsModule, SharedModule], template: \` - + @@ -72,8 +72,8 @@ import { FormsModule } from '@angular/forms'; \`, }) -export class InputNumberFloatLabelComponent { - value: number | null = null; +export class InputNumberFloatLabelExample { + control = new FormControl(null); } `, }, From bdbe29aee9669dd2c8cb4dbb270f94befff9582e Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 23:36:59 +0700 Subject: [PATCH 157/258] =?UTF-8?q?inputnumber=20story=20Currency:=20mode?= =?UTF-8?q?=3Dcurrency=20=E2=86=92=20suffix=3D'=20=E2=82=BD'=20(=D0=B1?= =?UTF-8?q?=D0=B0=D0=B3=20PrimeNG=20=D1=81=20=D0=BA=D0=B0=D1=80=D0=B5?= =?UTF-8?q?=D1=82=D0=BA=D0=BE=D0=B9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inputnumber-currency.component.ts | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/src/stories/components/inputnumber/examples/inputnumber-currency.component.ts b/src/stories/components/inputnumber/examples/inputnumber-currency.component.ts index 186e3a9b..6bb38c49 100644 --- a/src/stories/components/inputnumber/examples/inputnumber-currency.component.ts +++ b/src/stories/components/inputnumber/examples/inputnumber-currency.component.ts @@ -1,3 +1,4 @@ +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputNumberComponent } from '../../../../lib/components/inputnumber/inputnumber.component'; @@ -5,36 +6,48 @@ type Story = StoryObj; export const Currency: Story = { name: 'Currency', - render: (args) => ({ - props: { ...args, value: null }, - template: ` - - `, - }), - args: { - mode: 'currency', - currency: 'RUB', - locale: 'ru-RU', + render: () => { + const control = new FormControl(null); + return { + props: { control }, + template: ` + + `, + }; }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputNumberComponent, ReactiveFormsModule], + }, + }), + ], parameters: { controls: { disable: true }, docs: { description: { - story: 'Форматирование значения как валюты (рубли). Используются `mode="currency"`, `currency="RUB"` и `locale="ru-RU"`.', + story: 'Форматирование значения как валюты через `suffix`. Режим `mode="currency"` не используется из-за известного бага PrimeNG с кареткой.', }, source: { language: 'ts', code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { InputNumberComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; -// template: -// +@Component({ + standalone: true, + imports: [InputNumberComponent, ReactiveFormsModule], + template: \`\`, +}) +export class CurrencyExample { + control = new FormControl(null); +} `, }, }, From 397206cedd8bc671b8c35495fed292265b15afbb Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 23:37:05 +0700 Subject: [PATCH 158/258] =?UTF-8?q?inputnumber=20stories:=20minFractionDig?= =?UTF-8?q?its/maxFractionDigits=20=D0=B2=20argTypes,=20Default=20?= =?UTF-8?q?=E2=86=92=20formControl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inputnumber/inputnumber.stories.ts | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/stories/components/inputnumber/inputnumber.stories.ts b/src/stories/components/inputnumber/inputnumber.stories.ts index 9a34f283..1f2d9d20 100644 --- a/src/stories/components/inputnumber/inputnumber.stories.ts +++ b/src/stories/components/inputnumber/inputnumber.stories.ts @@ -1,12 +1,12 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { FormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { InputNumberComponent } from '../../../lib/components/inputnumber/inputnumber.component'; import { InputNumberFloatLabelComponent, FloatLabelStory } from './examples/inputnumber-float-label.component'; import { Currency } from './examples/inputnumber-currency.component'; import { Buttons } from './examples/inputnumber-buttons.component'; import { Disabled } from './examples/inputnumber-disabled.component'; -type InputNumberArgs = InputNumberComponent; +type InputNumberArgs = InputNumberComponent & { disabled: boolean; invalid: boolean }; const meta: Meta = { title: 'Components/Form/InputNumber', @@ -16,7 +16,7 @@ const meta: Meta = { moduleMetadata({ imports: [ InputNumberComponent, - FormsModule, + ReactiveFormsModule, InputNumberFloatLabelComponent, ], }), @@ -103,7 +103,7 @@ import { InputNumberComponent } from '@cdek-it/angular-ui-kit'; }, disabled: { control: 'boolean', - description: 'Отключает взаимодействие', + description: 'Отключает взаимодействие — управляется через FormControl', table: { category: 'Props', defaultValue: { summary: 'false' }, @@ -112,7 +112,7 @@ import { InputNumberComponent } from '@cdek-it/angular-ui-kit'; }, invalid: { control: 'boolean', - description: 'Невалидное состояние', + description: 'Невалидное состояние — управляется через FormControl', table: { category: 'Props', defaultValue: { summary: 'false' }, @@ -191,6 +191,24 @@ import { InputNumberComponent } from '@cdek-it/angular-ui-kit'; type: { summary: 'string' }, }, }, + minFractionDigits: { + control: 'number', + description: 'Минимальное количество знаков после запятой', + table: { + category: 'Props', + defaultValue: { summary: 'undefined' }, + type: { summary: 'number' }, + }, + }, + maxFractionDigits: { + control: 'number', + description: 'Максимальное количество знаков после запятой', + table: { + category: 'Props', + defaultValue: { summary: 'undefined' }, + type: { summary: 'number' }, + }, + }, // Hidden computed props modelValue: { table: { disable: true } }, inputSizeClass: { table: { disable: true } }, @@ -237,8 +255,6 @@ export const Default: Story = { if (args.mode && args.mode !== 'decimal') parts.push(`mode="${args.mode}"`); if (args.currency) parts.push(`currency="${args.currency}"`); if (args.locale) parts.push(`locale="${args.locale}"`); - if (args.disabled) parts.push(`[disabled]="true"`); - if (args.invalid) parts.push(`[invalid]="true"`); if (args.readonly) parts.push(`[readonly]="true"`); if (args.fluid) parts.push(`[fluid]="true"`); if (args.min != null) parts.push(`[min]="${args.min}"`); @@ -246,12 +262,18 @@ export const Default: Story = { if (args.step && args.step !== 1) parts.push(`[step]="${args.step}"`); if (args.prefix) parts.push(`prefix="${args.prefix}"`); if (args.suffix) parts.push(`suffix="${args.suffix}"`); + if (args.minFractionDigits != null) parts.push(`[minFractionDigits]="${args.minFractionDigits}"`); + if (args.maxFractionDigits != null) parts.push(`[maxFractionDigits]="${args.maxFractionDigits}"`); if (!args.useGrouping) parts.push(`[useGrouping]="false"`); - parts.push(`[(ngModel)]="value"`); - const template = ``; + const validators = []; + if (args.invalid) validators.push(Validators.required); + + const control = new FormControl({ value: null, disabled: args.disabled }, validators); + + const template = ``; - return { props: { ...args, value: null }, template }; + return { props: { ...args, control }, template }; }, parameters: { docs: { From d59162d20d16628b376155b680f3a8ac3807a36a Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 23:38:26 +0700 Subject: [PATCH 159/258] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D1=91=D0=BD=20.gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 808f9bdc..ce8e3c03 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ src/assets/components/themes /storybook-static /debug-storybook.log /documentation.json + +.claude/* \ No newline at end of file From 626821cf4554eb1ec7968f3b0fd7573865af837e Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 21 Apr 2026 23:52:13 +0700 Subject: [PATCH 160/258] =?UTF-8?q?=D1=81=D0=BE=D1=80=D1=81=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D1=81=D0=BD=D0=B8=D0=BF=D0=BF=D0=B5=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/megamenu/megamenu.component.ts | 3 +- .../examples/megamenu-custom.component.ts | 12 +- .../components/megamenu/megamenu.stories.ts | 216 +++++++++++++++++- 3 files changed, 215 insertions(+), 16 deletions(-) diff --git a/src/lib/components/megamenu/megamenu.component.ts b/src/lib/components/megamenu/megamenu.component.ts index 9da0845d..6aad7573 100644 --- a/src/lib/components/megamenu/megamenu.component.ts +++ b/src/lib/components/megamenu/megamenu.component.ts @@ -6,9 +6,10 @@ import { Badge } from 'primeng/badge'; export type MegaMenuOrientation = 'horizontal' | 'vertical'; -export interface MegaMenuModel extends MegaMenuItem { +export interface MegaMenuModel extends Omit { description?: string; badge?: string; + items?: MegaMenuModel[][]; } @Component({ diff --git a/src/stories/components/megamenu/examples/megamenu-custom.component.ts b/src/stories/components/megamenu/examples/megamenu-custom.component.ts index 7568a9f5..966f7b3f 100644 --- a/src/stories/components/megamenu/examples/megamenu-custom.component.ts +++ b/src/stories/components/megamenu/examples/megamenu-custom.component.ts @@ -24,12 +24,12 @@ export class MegaMenuCustomComponent { description: 'Input, Select, Checkbox', icon: 'ti ti-forms', badge: 'New', - } as any, + }, { label: 'Button', description: 'Actions and triggers', icon: 'ti ti-hand-click', - } as any, + }, ], }, ], @@ -41,13 +41,13 @@ export class MegaMenuCustomComponent { label: 'Bar Chart', description: 'Categorical comparison', icon: 'ti ti-chart-bar', - } as any, + }, { label: 'Line Chart', description: 'Trends over time', icon: 'ti ti-chart-line', badge: 'Beta', - } as any, + }, ], }, ], @@ -65,13 +65,13 @@ export class MegaMenuCustomComponent { label: 'Analytics', description: 'Reports and dashboards', icon: 'ti ti-chart-dots', - } as any, + }, { label: 'CRM', description: 'Customer management', icon: 'ti ti-users', badge: 'Pro', - } as any, + }, ], }, ], diff --git a/src/stories/components/megamenu/megamenu.stories.ts b/src/stories/components/megamenu/megamenu.stories.ts index b2a0123b..7d2ca90c 100644 --- a/src/stories/components/megamenu/megamenu.stories.ts +++ b/src/stories/components/megamenu/megamenu.stories.ts @@ -151,7 +151,66 @@ export const Horizontal: Story = { docs: { description: { story: 'Горизонтальная ориентация (по умолчанию).' }, source: { - code: ``, + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { MegaMenuComponent, MegaMenuModel } from '@cdek-it/angular-ui-kit'; + +@Component({ + standalone: true, + imports: [MegaMenuComponent], + template: \`\`, +}) +export class HorizontalExample { + items: MegaMenuModel[] = [ + { + label: 'Products', + icon: 'ti ti-box', + items: [ + [ + { + label: 'UI Components', + items: [ + { label: 'Form', icon: 'ti ti-forms' }, + { label: 'Button', icon: 'ti ti-hand-click' }, + { label: 'Table', icon: 'ti ti-table' }, + ], + }, + ], + [ + { + label: 'Charts', + items: [ + { label: 'Bar Chart', icon: 'ti ti-chart-bar' }, + { label: 'Line Chart', icon: 'ti ti-chart-line' }, + ], + }, + ], + ], + }, + { + label: 'Solutions', + icon: 'ti ti-bulb', + items: [ + [ + { + label: 'Business', + items: [ + { label: 'Analytics', icon: 'ti ti-chart-dots' }, + { label: 'CRM', icon: 'ti ti-users' }, + ], + }, + ], + ], + }, + { + label: 'Contact', + icon: 'ti ti-mail', + disabled: true, + }, + ]; +} + `, }, }, }, @@ -168,7 +227,66 @@ export const Vertical: Story = { docs: { description: { story: 'Вертикальная ориентация.' }, source: { - code: ``, + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { MegaMenuComponent, MegaMenuModel } from '@cdek-it/angular-ui-kit'; + +@Component({ + standalone: true, + imports: [MegaMenuComponent], + template: \`\`, +}) +export class VerticalExample { + items: MegaMenuModel[] = [ + { + label: 'Products', + icon: 'ti ti-box', + items: [ + [ + { + label: 'UI Components', + items: [ + { label: 'Form', icon: 'ti ti-forms' }, + { label: 'Button', icon: 'ti ti-hand-click' }, + { label: 'Table', icon: 'ti ti-table' }, + ], + }, + ], + [ + { + label: 'Charts', + items: [ + { label: 'Bar Chart', icon: 'ti ti-chart-bar' }, + { label: 'Line Chart', icon: 'ti ti-chart-line' }, + ], + }, + ], + ], + }, + { + label: 'Solutions', + icon: 'ti ti-bulb', + items: [ + [ + { + label: 'Business', + items: [ + { label: 'Analytics', icon: 'ti ti-chart-dots' }, + { label: 'CRM', icon: 'ti ti-users' }, + ], + }, + ], + ], + }, + { + label: 'Contact', + icon: 'ti ti-mail', + disabled: true, + }, + ]; +} + `, }, }, }, @@ -189,12 +307,12 @@ const customItems: MegaMenuModel[] = [ description: 'Input, Select, Checkbox', icon: 'ti ti-forms', badge: 'New', - } as any, + }, { label: 'Button', description: 'Actions and triggers', icon: 'ti ti-hand-click', - } as any, + }, ], }, ], @@ -206,13 +324,13 @@ const customItems: MegaMenuModel[] = [ label: 'Bar Chart', description: 'Categorical comparison', icon: 'ti ti-chart-bar', - } as any, + }, { label: 'Line Chart', description: 'Trends over time', icon: 'ti ti-chart-line', badge: 'Beta', - } as any, + }, ], }, ], @@ -230,13 +348,13 @@ const customItems: MegaMenuModel[] = [ label: 'Analytics', description: 'Reports and dashboards', icon: 'ti ti-chart-dots', - } as any, + }, { label: 'CRM', description: 'Customer management', icon: 'ti ti-users', badge: 'Pro', - } as any, + }, ], }, ], @@ -255,7 +373,87 @@ export const Custom: Story = { story: 'Пункты меню с описанием (description) и бейджами.', }, source: { - code: ``, + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { MegaMenuComponent, MegaMenuModel } from '@cdek-it/angular-ui-kit'; + +@Component({ + standalone: true, + imports: [MegaMenuComponent], + template: \`\`, +}) +export class CustomExample { + items: MegaMenuModel[] = [ + { + label: 'Products', + icon: 'ti ti-box', + items: [ + [ + { + label: 'Components', + items: [ + { + label: 'Form', + description: 'Input, Select, Checkbox', + icon: 'ti ti-forms', + badge: 'New', + }, + { + label: 'Button', + description: 'Actions and triggers', + icon: 'ti ti-hand-click', + }, + ], + }, + ], + [ + { + label: 'Charts', + items: [ + { + label: 'Bar Chart', + description: 'Categorical comparison', + icon: 'ti ti-chart-bar', + }, + { + label: 'Line Chart', + description: 'Trends over time', + icon: 'ti ti-chart-line', + badge: 'Beta', + }, + ], + }, + ], + ], + }, + { + label: 'Solutions', + icon: 'ti ti-bulb', + items: [ + [ + { + label: 'Business', + items: [ + { + label: 'Analytics', + description: 'Reports and dashboards', + icon: 'ti ti-chart-dots', + }, + { + label: 'CRM', + description: 'Customer management', + icon: 'ti ti-users', + badge: 'Pro', + }, + ], + }, + ], + ], + }, + ]; +} + `, }, }, }, From 582250398499bbecd465e9fdc217159ea5c9db94 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 22 Apr 2026 11:38:55 +0700 Subject: [PATCH 161/258] MegaMenuModel.items -> MegaMenuModel[][] | MegaMenuModel[] --- src/lib/components/megamenu/megamenu.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/megamenu/megamenu.component.ts b/src/lib/components/megamenu/megamenu.component.ts index 6aad7573..1a8e9b66 100644 --- a/src/lib/components/megamenu/megamenu.component.ts +++ b/src/lib/components/megamenu/megamenu.component.ts @@ -9,7 +9,7 @@ export type MegaMenuOrientation = 'horizontal' | 'vertical'; export interface MegaMenuModel extends Omit { description?: string; badge?: string; - items?: MegaMenuModel[][]; + items?: MegaMenuModel[][] | MegaMenuModel[]; } @Component({ From 15817633e544aebb7b88a62ee0605c5f03f7f706 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 22 Apr 2026 11:43:48 +0700 Subject: [PATCH 162/258] =?UTF-8?q?paginator:=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=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 --- .../paginator/paginator.component.ts | 41 +++++ .../tokens/components/paginator.ts | 18 +++ ...paginator-current-page-report.component.ts | 78 ++++++++++ .../paginator-rows-per-page.component.ts | 78 ++++++++++ .../components/paginator/paginator.stories.ts | 146 ++++++++++++++++++ 5 files changed, 361 insertions(+) create mode 100644 src/lib/components/paginator/paginator.component.ts create mode 100644 src/prime-preset/tokens/components/paginator.ts create mode 100644 src/stories/components/paginator/examples/paginator-current-page-report.component.ts create mode 100644 src/stories/components/paginator/examples/paginator-rows-per-page.component.ts create mode 100644 src/stories/components/paginator/paginator.stories.ts diff --git a/src/lib/components/paginator/paginator.component.ts b/src/lib/components/paginator/paginator.component.ts new file mode 100644 index 00000000..61c28c17 --- /dev/null +++ b/src/lib/components/paginator/paginator.component.ts @@ -0,0 +1,41 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Paginator } from 'primeng/paginator'; +import type { PaginatorState } from 'primeng/types/paginator'; + +@Component({ + selector: 'paginator', + standalone: true, + imports: [Paginator], + template: ` + + `, +}) +export class PaginatorComponent { + @Input() first = 0; + @Input() rows = 10; + @Input() totalRecords = 0; + @Input() rowsPerPageOptions: any[] | undefined; + @Input() currentPageReportTemplate = '{currentPage} из {totalPages}'; + @Input() showCurrentPageReport = false; + @Input() showFirstLastIcon = true; + @Input() showJumpToPageDropdown = false; + @Input() showJumpToPageInput = false; + @Input() showPageLinks = true; + @Input() pageLinkSize = 5; + @Input() alwaysShow = true; + @Output() onPageChange = new EventEmitter(); +} diff --git a/src/prime-preset/tokens/components/paginator.ts b/src/prime-preset/tokens/components/paginator.ts new file mode 100644 index 00000000..061b759f --- /dev/null +++ b/src/prime-preset/tokens/components/paginator.ts @@ -0,0 +1,18 @@ +export const paginatorCss = ({ dt }: { dt: (token: string) => string }): string => ` + /* ─── Current page report ─── */ + .p-paginator .p-paginator-current { + font-family: ${dt('fonts.fontFamily.base')}; + font-size: ${dt('fonts.fontSize.300')}; + font-weight: ${dt('fonts.fontWeight.regular')}; + line-height: ${dt('fonts.lineHeight.250')}; + color: ${dt('paginator.currentPageReport.color')}; + } + + /* ─── Page number buttons ─── */ + .p-paginator .p-paginator-page { + font-family: ${dt('fonts.fontFamily.base')}; + font-size: ${dt('fonts.fontSize.300')}; + font-weight: ${dt('fonts.fontWeight.regular')}; + line-height: ${dt('fonts.lineHeight.250')}; + } +`; diff --git a/src/stories/components/paginator/examples/paginator-current-page-report.component.ts b/src/stories/components/paginator/examples/paginator-current-page-report.component.ts new file mode 100644 index 00000000..753c73f1 --- /dev/null +++ b/src/stories/components/paginator/examples/paginator-current-page-report.component.ts @@ -0,0 +1,78 @@ +import { Component } from '@angular/core'; +import { PaginatorComponent } from '../../../../lib/components/paginator/paginator.component'; +import type { PaginatorState } from 'primeng/types/paginator'; + +const template = ` + +`; +const styles = ''; + +@Component({ + selector: 'app-paginator-current-page-report', + standalone: true, + imports: [PaginatorComponent], + template, + styles, +}) +export class PaginatorCurrentPageReportComponent { + first = 0; + rows = 10; + + onPageChange(event: PaginatorState): void { + this.first = event.first ?? 0; + this.rows = event.rows ?? 10; + } +} + +export const CurrentPageReport = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { + story: 'Пагинатор с отображением текущей страницы и общего числа страниц.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { PaginatorComponent } from '@cdek-it/angular-ui-kit'; +import type { PaginatorState } from 'primeng/types/paginator'; + +@Component({ + selector: 'app-paginator-current-page-report', + standalone: true, + imports: [PaginatorComponent], + template: \` + + \`, +}) +export class PaginatorCurrentPageReportComponent { + first = 0; + rows = 10; + + onPageChange(event: PaginatorState): void { + this.first = event.first ?? 0; + this.rows = event.rows ?? 10; + } +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/paginator/examples/paginator-rows-per-page.component.ts b/src/stories/components/paginator/examples/paginator-rows-per-page.component.ts new file mode 100644 index 00000000..99daf055 --- /dev/null +++ b/src/stories/components/paginator/examples/paginator-rows-per-page.component.ts @@ -0,0 +1,78 @@ +import { Component } from '@angular/core'; +import { PaginatorComponent } from '../../../../lib/components/paginator/paginator.component'; +import type { PaginatorState } from 'primeng/types/paginator'; + +const template = ` + +`; +const styles = ''; + +@Component({ + selector: 'app-paginator-rows-per-page', + standalone: true, + imports: [PaginatorComponent], + template, + styles, +}) +export class PaginatorRowsPerPageComponent { + first = 0; + rows = 10; + + onPageChange(event: PaginatorState): void { + this.first = event.first ?? 0; + this.rows = event.rows ?? 10; + } +} + +export const RowsPerPage = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { + story: 'Пагинатор с выбором количества строк на странице и переходом на конкретную страницу.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { PaginatorComponent } from '@cdek-it/angular-ui-kit'; +import type { PaginatorState } from 'primeng/types/paginator'; + +@Component({ + selector: 'app-paginator-rows-per-page', + standalone: true, + imports: [PaginatorComponent], + template: \` + + \`, +}) +export class PaginatorRowsPerPageComponent { + first = 0; + rows = 10; + + onPageChange(event: PaginatorState): void { + this.first = event.first ?? 0; + this.rows = event.rows ?? 10; + } +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/paginator/paginator.stories.ts b/src/stories/components/paginator/paginator.stories.ts new file mode 100644 index 00000000..b8c787d7 --- /dev/null +++ b/src/stories/components/paginator/paginator.stories.ts @@ -0,0 +1,146 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { PaginatorComponent } from '../../../lib/components/paginator/paginator.component'; +import { PaginatorCurrentPageReportComponent, CurrentPageReport as CurrentPageReportStory } from './examples/paginator-current-page-report.component'; +import { PaginatorRowsPerPageComponent, RowsPerPage as RowsPerPageStory } from './examples/paginator-rows-per-page.component'; + +type PaginatorArgs = Pick< + PaginatorComponent, + 'totalRecords' | 'rows' | 'pageLinkSize' | 'showFirstLastIcon' | 'showPageLinks' | 'alwaysShow' +>; + +const meta: Meta = { + title: 'Components/Data/Paginator', + component: PaginatorComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + PaginatorComponent, + PaginatorCurrentPageReportComponent, + PaginatorRowsPerPageComponent, + ], + }), + ], + parameters: { + docs: { + description: { + component: `Отображает навигацию по страницам для больших наборов данных. + +\`\`\`typescript +import { PaginatorComponent } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-paginator' }, + }, + argTypes: { + totalRecords: { + control: { type: 'number', min: 0 }, + description: 'Общее количество записей', + table: { + category: 'Props', + defaultValue: { summary: '0' }, + type: { summary: 'number' }, + }, + }, + rows: { + control: { type: 'number', min: 1 }, + description: 'Количество строк на странице', + table: { + category: 'Props', + defaultValue: { summary: '10' }, + type: { summary: 'number' }, + }, + }, + pageLinkSize: { + control: { type: 'number', min: 1 }, + description: 'Количество отображаемых ссылок на страницы', + table: { + category: 'Props', + defaultValue: { summary: '5' }, + type: { summary: 'number' }, + }, + }, + showFirstLastIcon: { + control: 'boolean', + description: 'Показывать кнопки перехода на первую и последнюю страницу', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + showPageLinks: { + control: 'boolean', + description: 'Показывать номера страниц', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + alwaysShow: { + control: 'boolean', + description: 'Показывать пагинатор даже при единственной странице', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + }, + args: { + totalRecords: 120, + rows: 10, + pageLinkSize: 5, + showFirstLastIcon: true, + showPageLinks: true, + alwaysShow: true, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ─────────────────────────────────────────────────────────────────── + +export const Default: Story = { + name: 'Default', + render: (args) => ({ + props: args, + template: ` + + `, + }), + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + }, + }, +}; + +// ── CurrentPageReport ───────────────────────────────────────────────────────── + +export const CurrentPageReport: Story = CurrentPageReportStory; + +// ── RowsPerPage ─────────────────────────────────────────────────────────────── + +export const RowsPerPage: Story = { + ...RowsPerPageStory, + parameters: { + ...RowsPerPageStory.parameters, + docs: { + ...RowsPerPageStory.parameters?.docs, + story: { height: '200px' }, + }, + }, +}; From a6f00cabd59e2fdef3f760c8d9c3c53919c1e7be Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 22 Apr 2026 12:26:28 +0700 Subject: [PATCH 163/258] =?UTF-8?q?select:=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=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/select/select.component.ts | 156 ++++++++++++++ src/prime-preset/map-tokens.ts | 5 + src/prime-preset/tokens/components/select.ts | 53 +++++ src/prime-preset/tokens/tokens.json | 12 +- .../examples/select-custom.component.ts | 91 +++++++++ .../examples/select-disabled.component.ts | 69 +++++++ .../examples/select-editable.component.ts | 73 +++++++ .../examples/select-filter.component.ts | 77 +++++++ .../examples/select-float-label.component.ts | 87 ++++++++ .../examples/select-grouped.component.ts | 115 +++++++++++ .../components/select/select.stories.ts | 193 ++++++++++++++++++ 11 files changed, 929 insertions(+), 2 deletions(-) create mode 100644 src/lib/components/select/select.component.ts create mode 100644 src/prime-preset/tokens/components/select.ts create mode 100644 src/stories/components/select/examples/select-custom.component.ts create mode 100644 src/stories/components/select/examples/select-disabled.component.ts create mode 100644 src/stories/components/select/examples/select-editable.component.ts create mode 100644 src/stories/components/select/examples/select-filter.component.ts create mode 100644 src/stories/components/select/examples/select-float-label.component.ts create mode 100644 src/stories/components/select/examples/select-grouped.component.ts create mode 100644 src/stories/components/select/select.stories.ts diff --git a/src/lib/components/select/select.component.ts b/src/lib/components/select/select.component.ts new file mode 100644 index 00000000..5045f337 --- /dev/null +++ b/src/lib/components/select/select.component.ts @@ -0,0 +1,156 @@ +import { Component, EventEmitter, forwardRef, inject, Injector, Input, OnInit, Output, TemplateRef } from '@angular/core'; +import { NgClass, NgTemplateOutlet } from '@angular/common'; +import { ControlValueAccessor, NgControl, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { FormsModule } from '@angular/forms'; +import { Select } from 'primeng/select'; +import { PrimeTemplate } from 'primeng/api'; +import type { SelectChangeEvent, SelectFilterEvent } from 'primeng/types/select'; + +export type SelectSize = 'small' | 'base' | 'large' | 'xlarge'; + +@Component({ + selector: 'select-field', + standalone: true, + imports: [Select, NgClass, NgTemplateOutlet, PrimeTemplate, FormsModule], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => SelectComponent), + multi: true, + }, + ], + template: ` + + @if (optionTemplate) { + + + + } + @if (selectedItemTemplate) { + + + + } + @if (optionGroupTemplate) { + + + + } + + `, +}) +export class SelectComponent implements ControlValueAccessor, OnInit { + private readonly _injector = inject(Injector); + private _ngControl: NgControl | null = null; + + ngOnInit(): void { + this._ngControl = this._injector.get(NgControl, null, { self: true, optional: true }); + } + + @Input() options: any[] | null | undefined; + @Input() optionLabel: string | undefined; + @Input() optionValue: string | undefined; + @Input() optionDisabled: string | undefined; + @Input() optionGroupLabel: string | undefined; + @Input() optionGroupChildren = 'items'; + @Input() group = false; + @Input() placeholder = ''; + @Input() size: SelectSize = 'base'; + @Input() filter = false; + @Input() showClear = false; + @Input() editable = false; + @Input() readonly = false; + @Input() loading = false; + @Input() inputId: string | undefined; + @Input() appendTo: any = 'body'; + @Input() emptyMessage = 'Нет данных'; + @Input() emptyFilterMessage = 'Результаты не найдены'; + @Input() optionTemplate: TemplateRef | null = null; + @Input() selectedItemTemplate: TemplateRef | null = null; + @Input() optionGroupTemplate: TemplateRef | null = null; + + disabled = false; + modelValue: any = null; + + @Output() onClear = new EventEmitter(); + @Output() onFilter = new EventEmitter(); + @Output() onShow = new EventEmitter(); + @Output() onHide = new EventEmitter(); + @Output() onFocus = new EventEmitter(); + @Output() onBlur = new EventEmitter(); + + get invalid(): boolean { + return !!(this._ngControl?.invalid && this._ngControl?.touched); + } + + get primeSize(): 'small' | 'large' | undefined { + if (this.size === 'small') return 'small'; + if (this.size === 'large') return 'large'; + return undefined; + } + + get selectClasses(): Record { + return { + 'p-select-xlg': this.size === 'xlarge', + 'p-invalid': this.invalid, + }; + } + + private _onChange: (value: any) => void = () => {}; + private _onTouched: () => void = () => {}; + + onSelectChange(event: SelectChangeEvent): void { + this.modelValue = event.value; + this._onChange(event.value); + } + + handleBlur(event: Event): void { + this._onTouched(); + this.onBlur.emit(event); + } + + writeValue(value: any): void { + this.modelValue = value ?? null; + } + + registerOnChange(fn: (value: any) => void): void { + this._onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this._onTouched = fn; + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index c725c2b9..51acda5a 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -11,6 +11,7 @@ import { progressspinnerCss } from './tokens/components/progressspinner'; import { tagCss } from './tokens/components/tag'; import { tooltipCss } from './tokens/components/tooltip'; import { megamenuCss } from './tokens/components/megamenu'; +import { selectCss } from './tokens/components/select'; const presetTokens: Preset = { primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'], @@ -49,6 +50,10 @@ const presetTokens: Preset = { ...(tokens.components.megamenu as unknown as ComponentsDesignTokens['megamenu']), css: megamenuCss, }, + select: { + ...(tokens.components.select as unknown as ComponentsDesignTokens['select']), + css: selectCss, + }, } as ComponentsDesignTokens, }; diff --git a/src/prime-preset/tokens/components/select.ts b/src/prime-preset/tokens/components/select.ts new file mode 100644 index 00000000..26b0b33f --- /dev/null +++ b/src/prime-preset/tokens/components/select.ts @@ -0,0 +1,53 @@ +export const selectCss = ({ dt }: { dt: (token: string) => string }): string => ` + /* ─── Базовые стили ─── */ + .p-select.p-component { + width: 100%; + border-width: ${dt('select.extend.borderWidth')}; + line-height: ${dt('fonts.lineHeight.250')}; + } + + /* ─── Focus ─── */ + .p-select.p-component:not(.p-disabled).p-focus { + box-shadow: 0 0 0 ${dt('select.root.focusRing.width')} ${dt('select.root.focusRing.color')}; + } + + /* ─── Invalid + Focus ─── */ + .p-select.p-component.p-invalid.p-focus { + border-color: ${dt('select.root.invalidBorderColor')}; + box-shadow: 0 0 0 ${dt('select.root.focusRing.width')} ${dt('focusRing.extend.invalid')}; + } + + /* ─── Readonly ─── */ + .p-select.p-component[readonly] { + background: ${dt('select.extend.readonlyBackground')}; + border-color: ${dt('select.root.borderColor')}; + color: ${dt('select.root.color')}; + cursor: default; + pointer-events: none; + } + + .p-select.p-component[readonly] :is(.p-select-dropdown .p-select-dropdown-icon, .p-select-clear-icon) { + color: ${dt('select.root.placeholderColor')}; + } + + /* ─── XLarge ─── */ + .p-select.p-component.p-select-xlg .p-select-label { + font-size: ${dt('inputtext.extend.extXlg.fontSize')}; + padding-block: ${dt('inputtext.extend.extXlg.paddingY')}; + padding-inline: ${dt('inputtext.extend.extXlg.paddingX')}; + } + + /* ─── FloatLabel variant="in" ─── */ + .p-floatlabel-in .p-select.p-component .p-select-label { + padding-block-start: ${dt('floatlabel.in.input.paddingTop')}; + padding-block-end: ${dt('floatlabel.in.input.paddingBottom')}; + } + + /* ─── Иконки ─── */ + .p-select.p-component :is(.p-select-dropdown .p-select-dropdown-icon, .p-select-clear-icon, .p-select-loading-icon) { + font-size: ${dt('select.extend.iconSize')}; + width: ${dt('select.extend.iconSize')}; + height: ${dt('select.extend.iconSize')}; + color: ${dt('select.root.placeholderColor')}; + } +`; diff --git a/src/prime-preset/tokens/tokens.json b/src/prime-preset/tokens/tokens.json index 0df719aa..c9e3591c 100644 --- a/src/prime-preset/tokens/tokens.json +++ b/src/prime-preset/tokens/tokens.json @@ -542,7 +542,15 @@ "800": "{sizing.16x}", "900": "{sizing.20x}" }, - "width": "{sizing.68x}", + "width": { + "100": "{sizing.6x}", + "200": "{sizing.8x}", + "300": "{sizing.10x}", + "350": "{sizing.11x}", + "400": "{sizing.12x}", + "500": "{sizing.60x}", + "full": "{sizing.max}" + }, "gap": { "100": "{spacing.1x}", "200": "{spacing.2x}", @@ -4217,7 +4225,7 @@ "optionGroup": { "background": "{list.optionGroup.background}", "color": "{list.optionGroup.color}", - "fontWeight": "{fonts.fontWeight.demibold}", + "fontWeight": "{fonts.fontWeight.regular}", "padding": "{list.option.padding}" }, "clearIcon": { diff --git a/src/stories/components/select/examples/select-custom.component.ts b/src/stories/components/select/examples/select-custom.component.ts new file mode 100644 index 00000000..aa42a88a --- /dev/null +++ b/src/stories/components/select/examples/select-custom.component.ts @@ -0,0 +1,91 @@ +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { SelectComponent } from '../../../../lib/components/select/select.component'; + +const OPTIONS = [ + { name: 'Профиль', description: 'Настройки аккаунта', icon: 'ti ti-user' }, + { name: 'Настройки', description: 'Параметры приложения', icon: 'ti ti-settings' }, + { name: 'Сообщения', description: 'Входящие', icon: 'ti ti-message' }, +]; + +const template = ` + +
+ +
+
{{ option.name }}
+ {{ option.description }} +
+
+
+ +`; +const styles = ''; + +@Component({ + selector: 'app-select-custom', + standalone: true, + imports: [SelectComponent, ReactiveFormsModule], + template, + styles, +}) +export class SelectCustomComponent { + control = new FormControl(null); + options = OPTIONS; +} + +export const Custom = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Кастомный шаблон опции с иконкой и описанием.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { SelectComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + standalone: true, + imports: [SelectComponent, ReactiveFormsModule], + template: \` + +
+ +
+
{{ option.name }}
+ {{ option.description }} +
+
+
+ + \`, +}) +export class SelectCustomExample { + control = new FormControl(null); + options = [ + { name: 'Профиль', description: 'Настройки аккаунта', icon: 'ti ti-user' }, + { name: 'Настройки', description: 'Параметры приложения', icon: 'ti ti-settings' }, + { name: 'Сообщения', description: 'Входящие', icon: 'ti ti-message' }, + ]; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/select/examples/select-disabled.component.ts b/src/stories/components/select/examples/select-disabled.component.ts new file mode 100644 index 00000000..ea14fffd --- /dev/null +++ b/src/stories/components/select/examples/select-disabled.component.ts @@ -0,0 +1,69 @@ +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { SelectComponent } from '../../../../lib/components/select/select.component'; + +const OPTIONS = [ + { name: 'Новосибирск', code: 'NSK' }, + { name: 'Москва', code: 'MSK' }, + { name: 'Санкт-Петербург', code: 'SPB' }, +]; + +export const Disabled: StoryObj = { + name: 'Disabled', + render: () => { + const control = new FormControl({ value: null, disabled: true }); + return { + props: { control, options: OPTIONS }, + template: ` + + `, + }; + }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [SelectComponent, ReactiveFormsModule], + }, + }), + ], + parameters: { + controls: { disable: true }, + docs: { + description: { story: 'Отключённое состояние — управляется через FormControl.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { SelectComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + standalone: true, + imports: [SelectComponent, ReactiveFormsModule], + template: \` + + \`, +}) +export class SelectDisabledExample { + control = new FormControl({ value: null, disabled: true }); + options = [ + { name: 'Новосибирск', code: 'NSK' }, + { name: 'Москва', code: 'MSK' }, + ]; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/select/examples/select-editable.component.ts b/src/stories/components/select/examples/select-editable.component.ts new file mode 100644 index 00000000..e6a2f998 --- /dev/null +++ b/src/stories/components/select/examples/select-editable.component.ts @@ -0,0 +1,73 @@ +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { SelectComponent } from '../../../../lib/components/select/select.component'; + +const OPTIONS = [ + { name: 'Новосибирск', code: 'NSK' }, + { name: 'Москва', code: 'MSK' }, + { name: 'Санкт-Петербург', code: 'SPB' }, +]; + +const template = ` + +`; +const styles = ''; + +@Component({ + selector: 'app-select-editable', + standalone: true, + imports: [SelectComponent, ReactiveFormsModule], + template, + styles, +}) +export class SelectEditableComponent { + control = new FormControl(null); + options = OPTIONS; +} + +export const Editable = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Редактируемый режим — позволяет вводить произвольное значение.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { SelectComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + standalone: true, + imports: [SelectComponent, ReactiveFormsModule], + template: \` + + \`, +}) +export class SelectEditableExample { + control = new FormControl(null); + options = [ + { name: 'Новосибирск', code: 'NSK' }, + { name: 'Москва', code: 'MSK' }, + { name: 'Санкт-Петербург', code: 'SPB' }, + ]; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/select/examples/select-filter.component.ts b/src/stories/components/select/examples/select-filter.component.ts new file mode 100644 index 00000000..9a0772c1 --- /dev/null +++ b/src/stories/components/select/examples/select-filter.component.ts @@ -0,0 +1,77 @@ +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { SelectComponent } from '../../../../lib/components/select/select.component'; + +const OPTIONS = [ + { name: 'Новосибирск', code: 'NSK' }, + { name: 'Москва', code: 'MSK' }, + { name: 'Санкт-Петербург', code: 'SPB' }, + { name: 'Екатеринбург', code: 'EKB' }, + { name: 'Казань', code: 'KZN' }, +]; + +const template = ` + +`; +const styles = ''; + +@Component({ + selector: 'app-select-filter', + standalone: true, + imports: [SelectComponent, ReactiveFormsModule], + template, + styles, +}) +export class SelectFilterComponent { + control = new FormControl(null); + options = OPTIONS; +} + +export const Filter = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Выпадающий список с поиском по опциям.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { SelectComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + standalone: true, + imports: [SelectComponent, ReactiveFormsModule], + template: \` + + \`, +}) +export class SelectFilterExample { + control = new FormControl(null); + options = [ + { name: 'Новосибирск', code: 'NSK' }, + { name: 'Москва', code: 'MSK' }, + { name: 'Санкт-Петербург', code: 'SPB' }, + ]; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/select/examples/select-float-label.component.ts b/src/stories/components/select/examples/select-float-label.component.ts new file mode 100644 index 00000000..ad5eefb8 --- /dev/null +++ b/src/stories/components/select/examples/select-float-label.component.ts @@ -0,0 +1,87 @@ +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { FloatLabel } from 'primeng/floatlabel'; +import { SelectComponent } from '../../../../lib/components/select/select.component'; + +const OPTIONS = [ + { name: 'Новосибирск', code: 'NSK' }, + { name: 'Москва', code: 'MSK' }, + { name: 'Санкт-Петербург', code: 'SPB' }, + { name: 'Екатеринбург', code: 'EKB' }, +]; + +const template = ` +
+ + + + +
+`; +const styles = ''; + +@Component({ + selector: 'app-select-float-label', + standalone: true, + imports: [SelectComponent, FloatLabel, ReactiveFormsModule], + template, + styles, +}) +export class SelectFloatLabelComponent { + control = new FormControl(null); + options = OPTIONS; +} + +export const FloatLabelStory = { + name: 'FloatLabel', + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { + story: 'Интеграция с `p-floatlabel` — плавающая метка внутри поля.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { FloatLabel } from 'primeng/floatlabel'; +import { SelectComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + standalone: true, + imports: [SelectComponent, FloatLabel, ReactiveFormsModule], + template: \` +
+ + + + +
+ \`, +}) +export class SelectFloatLabelExample { + control = new FormControl(null); + options = [ + { name: 'Новосибирск', code: 'NSK' }, + { name: 'Москва', code: 'MSK' }, + { name: 'Санкт-Петербург', code: 'SPB' }, + ]; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/select/examples/select-grouped.component.ts b/src/stories/components/select/examples/select-grouped.component.ts new file mode 100644 index 00000000..f53499a9 --- /dev/null +++ b/src/stories/components/select/examples/select-grouped.component.ts @@ -0,0 +1,115 @@ +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { SelectComponent } from '../../../../lib/components/select/select.component'; + +const GROUPED_OPTIONS = [ + { + label: 'Германия', + items: [ + { label: 'Берлин', value: 'BE' }, + { label: 'Франкфурт', value: 'FR' }, + { label: 'Гамбург', value: 'HA' }, + ], + }, + { + label: 'США', + items: [ + { label: 'Чикаго', value: 'CH' }, + { label: 'Лос-Анджелес', value: 'LA' }, + { label: 'Нью-Йорк', value: 'NY' }, + ], + }, +]; + +const template = ` + +
+ + {{ group.label }} +
+
+ +`; +const styles = ''; + +@Component({ + selector: 'app-select-grouped', + standalone: true, + imports: [SelectComponent, ReactiveFormsModule], + template, + styles, +}) +export class SelectGroupedComponent { + control = new FormControl(null); + options = GROUPED_OPTIONS; +} + +export const Grouped = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Опции, сгруппированные по категориям с кастомным заголовком группы.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { SelectComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + standalone: true, + imports: [SelectComponent, ReactiveFormsModule], + template: \` + +
+ + {{ group.label }} +
+
+ + \`, +}) +export class SelectGroupedExample { + control = new FormControl(null); + options = [ + { + label: 'Германия', + items: [ + { label: 'Берлин', value: 'BE' }, + { label: 'Франкфурт', value: 'FR' }, + ], + }, + { + label: 'США', + items: [ + { label: 'Нью-Йорк', value: 'NY' }, + { label: 'Чикаго', value: 'CH' }, + ], + }, + ]; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/select/select.stories.ts b/src/stories/components/select/select.stories.ts new file mode 100644 index 00000000..f577df78 --- /dev/null +++ b/src/stories/components/select/select.stories.ts @@ -0,0 +1,193 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; +import { FloatLabel as PrimeFloatLabel } from 'primeng/floatlabel'; +import { SelectComponent } from '../../../lib/components/select/select.component'; +import { SelectFilterComponent, Filter as FilterStory } from './examples/select-filter.component'; +import { SelectGroupedComponent, Grouped as GroupedStory } from './examples/select-grouped.component'; +import { SelectCustomComponent, Custom as CustomStory } from './examples/select-custom.component'; +import { SelectEditableComponent, Editable as EditableStory } from './examples/select-editable.component'; +import { Disabled as DisabledStory } from './examples/select-disabled.component'; +import { SelectFloatLabelComponent, FloatLabelStory } from './examples/select-float-label.component'; + +const BASIC_OPTIONS = [ + { name: 'Новосибирск', code: 'NSK' }, + { name: 'Москва', code: 'MSK' }, + { name: 'Санкт-Петербург', code: 'SPB' }, + { name: 'Екатеринбург', code: 'EKB' }, + { name: 'Казань', code: 'KZN' }, +]; + +type SelectArgs = Pick & { + disabled: boolean; + invalid: boolean; +}; + +const meta: Meta = { + title: 'Components/Form/Select', + component: SelectComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + SelectComponent, + ReactiveFormsModule, + PrimeFloatLabel, + SelectFilterComponent, + SelectGroupedComponent, + SelectCustomComponent, + SelectEditableComponent, + SelectFloatLabelComponent, + ], + }), + ], + parameters: { + docs: { + description: { + component: `Выпадающий список для выбора одного значения из набора опций. Поддерживает фильтрацию, группировку, кастомные шаблоны и редактируемый ввод. + +\`\`\`typescript +import { SelectComponent } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-select' }, + }, + argTypes: { + size: { + control: 'select', + options: ['small', 'base', 'large', 'xlarge'], + description: 'Размер поля', + table: { + category: 'Props', + defaultValue: { summary: "'base'" }, + type: { summary: "'small' | 'base' | 'large' | 'xlarge'" }, + }, + }, + placeholder: { + control: 'text', + description: 'Текст подсказки при пустом поле', + table: { + category: 'Props', + defaultValue: { summary: "''" }, + type: { summary: 'string' }, + }, + }, + showClear: { + control: 'boolean', + description: 'Отображает иконку очистки выбранного значения', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + filter: { + control: 'boolean', + description: 'Включает строку поиска в выпадающем списке', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + readonly: { + control: 'boolean', + description: 'Режим только для чтения', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + disabled: { + control: 'boolean', + description: 'Отключает взаимодействие — управляется через FormControl', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + invalid: { + control: 'boolean', + description: 'Невалидное состояние — управляется через FormControl', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + }, + args: { + size: 'base', + placeholder: 'Выберите город...', + showClear: true, + filter: false, + readonly: false, + disabled: false, + invalid: false, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ─────────────────────────────────────────────────────────────────── + +export const Default: Story = { + name: 'Default', + render: (args) => { + const control = new FormControl( + { value: null, disabled: !!args['disabled'] }, + args['invalid'] ? [Validators.required] : [] + ); + if (args['invalid']) control.markAsTouched(); + + return { + props: { ...args, control, options: BASIC_OPTIONS }, + template: ` + + `, + }; + }, + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + }, + }, +}; + +// ── Filter ──────────────────────────────────────────────────────────────────── + +export const Filter: Story = FilterStory; + +// ── Grouped ─────────────────────────────────────────────────────────────────── + +export const Grouped: Story = GroupedStory; + +// ── Custom ──────────────────────────────────────────────────────────────────── + +export const Custom: Story = CustomStory; + +// ── Editable ────────────────────────────────────────────────────────────────── + +export const Editable: Story = EditableStory; + +// ── Disabled ────────────────────────────────────────────────────────────────── + +export const Disabled: Story = DisabledStory; + +// ── FloatLabel ──────────────────────────────────────────────────────────────── + +export const FloatLabel: Story = FloatLabelStory; From f6065883a78e084717ca8c5c66c320df41869dc3 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 22 Apr 2026 12:41:54 +0700 Subject: [PATCH 164/258] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=BF=D1=81=D0=B0=20size=20=D0=B4=D0=BB=D1=8F=20filter,?= =?UTF-8?q?=20grouped,=20custom,=20editable;=20showClear=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20float-label?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/tokens.json | 16 ++++++++-------- .../select/examples/select-custom.component.ts | 11 +++++++---- .../select/examples/select-editable.component.ts | 11 +++++++---- .../select/examples/select-filter.component.ts | 11 +++++++---- .../examples/select-float-label.component.ts | 13 ++++++++++--- .../select/examples/select-grouped.component.ts | 11 +++++++---- 6 files changed, 46 insertions(+), 27 deletions(-) diff --git a/src/prime-preset/tokens/tokens.json b/src/prime-preset/tokens/tokens.json index c9e3591c..14eeb718 100644 --- a/src/prime-preset/tokens/tokens.json +++ b/src/prime-preset/tokens/tokens.json @@ -4171,19 +4171,19 @@ "placeholderColor": "{form.placeholderColor}", "invalidPlaceholderColor": "{form.invalidPlaceholderColor}", "shadow": "0", - "paddingX": "{form.paddingX}", - "paddingY": "{form.paddingY}", + "paddingX": "{form.padding.300}", + "paddingY": "{form.padding.300}", "borderRadius": "{form.borderRadius.200}", "transitionDuration": "{form.transitionDuration}", "sm": { - "fontSize": "{form.fontSize}", - "paddingX": "{form.paddingX}", - "paddingY": "{form.paddingY}" + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{form.padding.300}", + "paddingY": "{form.padding.200}" }, "lg": { - "fontSize": "{form.fontSize}", - "paddingX": "{form.paddingX}", - "paddingY": "{form.paddingY}" + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{form.padding.300}", + "paddingY": "{form.padding.400}" }, "focusRing": { "width": "{form.focusRing.width}", diff --git a/src/stories/components/select/examples/select-custom.component.ts b/src/stories/components/select/examples/select-custom.component.ts index aa42a88a..943bb98a 100644 --- a/src/stories/components/select/examples/select-custom.component.ts +++ b/src/stories/components/select/examples/select-custom.component.ts @@ -1,6 +1,6 @@ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { SelectComponent } from '../../../../lib/components/select/select.component'; +import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const OPTIONS = [ { name: 'Профиль', description: 'Настройки аккаунта', icon: 'ti ti-user' }, @@ -24,6 +24,7 @@ const template = ` optionLabel="name" placeholder="Выберите пункт..." [optionTemplate]="optTpl" + [size]="size" > `; const styles = ''; @@ -36,13 +37,15 @@ const styles = ''; styles, }) export class SelectCustomComponent { + @Input() size: SelectSize = 'base'; control = new FormControl(null); options = OPTIONS; } export const Custom = { - render: () => ({ - template: ``, + render: (args: any) => ({ + props: { size: args['size'] }, + template: ``, }), parameters: { docs: { diff --git a/src/stories/components/select/examples/select-editable.component.ts b/src/stories/components/select/examples/select-editable.component.ts index e6a2f998..e5c0b83f 100644 --- a/src/stories/components/select/examples/select-editable.component.ts +++ b/src/stories/components/select/examples/select-editable.component.ts @@ -1,6 +1,6 @@ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { SelectComponent } from '../../../../lib/components/select/select.component'; +import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const OPTIONS = [ { name: 'Новосибирск', code: 'NSK' }, @@ -15,6 +15,7 @@ const template = ` optionLabel="name" placeholder="Выберите или введите город..." [editable]="true" + [size]="size" > `; const styles = ''; @@ -27,13 +28,15 @@ const styles = ''; styles, }) export class SelectEditableComponent { + @Input() size: SelectSize = 'base'; control = new FormControl(null); options = OPTIONS; } export const Editable = { - render: () => ({ - template: ``, + render: (args: any) => ({ + props: { size: args['size'] }, + template: ``, }), parameters: { docs: { diff --git a/src/stories/components/select/examples/select-filter.component.ts b/src/stories/components/select/examples/select-filter.component.ts index 9a0772c1..db9ef969 100644 --- a/src/stories/components/select/examples/select-filter.component.ts +++ b/src/stories/components/select/examples/select-filter.component.ts @@ -1,6 +1,6 @@ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { SelectComponent } from '../../../../lib/components/select/select.component'; +import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const OPTIONS = [ { name: 'Новосибирск', code: 'NSK' }, @@ -18,6 +18,7 @@ const template = ` placeholder="Выберите город..." [filter]="true" [showClear]="true" + [size]="size" > `; const styles = ''; @@ -30,13 +31,15 @@ const styles = ''; styles, }) export class SelectFilterComponent { + @Input() size: SelectSize = 'base'; control = new FormControl(null); options = OPTIONS; } export const Filter = { - render: () => ({ - template: ``, + render: (args: any) => ({ + props: { size: args['size'] }, + template: ``, }), parameters: { docs: { diff --git a/src/stories/components/select/examples/select-float-label.component.ts b/src/stories/components/select/examples/select-float-label.component.ts index ad5eefb8..71bf3099 100644 --- a/src/stories/components/select/examples/select-float-label.component.ts +++ b/src/stories/components/select/examples/select-float-label.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { FloatLabel } from 'primeng/floatlabel'; import { SelectComponent } from '../../../../lib/components/select/select.component'; @@ -18,6 +18,7 @@ const template = ` [formControl]="control" [options]="options" optionLabel="name" + [showClear]="showClear" >
@@ -33,15 +34,20 @@ const styles = ''; styles, }) export class SelectFloatLabelComponent { + @Input() showClear = false; control = new FormControl(null); options = OPTIONS; } export const FloatLabelStory = { name: 'FloatLabel', - render: () => ({ - template: ``, + render: (args: any) => ({ + props: { showClear: args['showClear'] }, + template: ``, }), + argTypes: { + size: { table: { disable: true } }, + }, parameters: { docs: { description: { @@ -66,6 +72,7 @@ import { SelectComponent } from '@cdek-it/angular-ui-kit'; [formControl]="control" [options]="options" optionLabel="name" + [showClear]="true" > diff --git a/src/stories/components/select/examples/select-grouped.component.ts b/src/stories/components/select/examples/select-grouped.component.ts index f53499a9..40dfe36a 100644 --- a/src/stories/components/select/examples/select-grouped.component.ts +++ b/src/stories/components/select/examples/select-grouped.component.ts @@ -1,6 +1,6 @@ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { SelectComponent } from '../../../../lib/components/select/select.component'; +import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const GROUPED_OPTIONS = [ { @@ -37,6 +37,7 @@ const template = ` [group]="true" placeholder="Выберите город..." [optionGroupTemplate]="groupTpl" + [size]="size" > `; const styles = ''; @@ -49,13 +50,15 @@ const styles = ''; styles, }) export class SelectGroupedComponent { + @Input() size: SelectSize = 'base'; control = new FormControl(null); options = GROUPED_OPTIONS; } export const Grouped = { - render: () => ({ - template: ``, + render: (args: any) => ({ + props: { size: args['size'] }, + template: ``, }), parameters: { docs: { From 5ad5ca4bc74882798d75d8ba586bdd6dd215e80b Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 22 Apr 2026 12:45:05 +0700 Subject: [PATCH 165/258] =?UTF-8?q?Grouped,=20Custom=20=D0=B8=20Editable?= =?UTF-8?q?=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20@Input()?= =?UTF-8?q?=20showClear?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/megamenu/megamenu.component.ts | 2 +- .../components/select/examples/select-custom.component.ts | 6 ++++-- .../components/select/examples/select-editable.component.ts | 6 ++++-- .../components/select/examples/select-grouped.component.ts | 6 ++++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/lib/components/megamenu/megamenu.component.ts b/src/lib/components/megamenu/megamenu.component.ts index 6aad7573..1a8e9b66 100644 --- a/src/lib/components/megamenu/megamenu.component.ts +++ b/src/lib/components/megamenu/megamenu.component.ts @@ -9,7 +9,7 @@ export type MegaMenuOrientation = 'horizontal' | 'vertical'; export interface MegaMenuModel extends Omit { description?: string; badge?: string; - items?: MegaMenuModel[][]; + items?: MegaMenuModel[][] | MegaMenuModel[]; } @Component({ diff --git a/src/stories/components/select/examples/select-custom.component.ts b/src/stories/components/select/examples/select-custom.component.ts index 943bb98a..1da4c2a5 100644 --- a/src/stories/components/select/examples/select-custom.component.ts +++ b/src/stories/components/select/examples/select-custom.component.ts @@ -25,6 +25,7 @@ const template = ` placeholder="Выберите пункт..." [optionTemplate]="optTpl" [size]="size" + [showClear]="showClear" > `; const styles = ''; @@ -38,14 +39,15 @@ const styles = ''; }) export class SelectCustomComponent { @Input() size: SelectSize = 'base'; + @Input() showClear = false; control = new FormControl(null); options = OPTIONS; } export const Custom = { render: (args: any) => ({ - props: { size: args['size'] }, - template: ``, + props: { size: args['size'], showClear: args['showClear'] }, + template: ``, }), parameters: { docs: { diff --git a/src/stories/components/select/examples/select-editable.component.ts b/src/stories/components/select/examples/select-editable.component.ts index e5c0b83f..e89d5b4b 100644 --- a/src/stories/components/select/examples/select-editable.component.ts +++ b/src/stories/components/select/examples/select-editable.component.ts @@ -16,6 +16,7 @@ const template = ` placeholder="Выберите или введите город..." [editable]="true" [size]="size" + [showClear]="showClear" > `; const styles = ''; @@ -29,14 +30,15 @@ const styles = ''; }) export class SelectEditableComponent { @Input() size: SelectSize = 'base'; + @Input() showClear = false; control = new FormControl(null); options = OPTIONS; } export const Editable = { render: (args: any) => ({ - props: { size: args['size'] }, - template: ``, + props: { size: args['size'], showClear: args['showClear'] }, + template: ``, }), parameters: { docs: { diff --git a/src/stories/components/select/examples/select-grouped.component.ts b/src/stories/components/select/examples/select-grouped.component.ts index 40dfe36a..f6ca2205 100644 --- a/src/stories/components/select/examples/select-grouped.component.ts +++ b/src/stories/components/select/examples/select-grouped.component.ts @@ -38,6 +38,7 @@ const template = ` placeholder="Выберите город..." [optionGroupTemplate]="groupTpl" [size]="size" + [showClear]="showClear" > `; const styles = ''; @@ -51,14 +52,15 @@ const styles = ''; }) export class SelectGroupedComponent { @Input() size: SelectSize = 'base'; + @Input() showClear = false; control = new FormControl(null); options = GROUPED_OPTIONS; } export const Grouped = { render: (args: any) => ({ - props: { size: args['size'] }, - template: ``, + props: { size: args['size'], showClear: args['showClear'] }, + template: ``, }), parameters: { docs: { From 3f6c6ec749ffa6265d3174254efc8da14a2b0046 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 22 Apr 2026 16:06:38 +0700 Subject: [PATCH 166/258] =?UTF-8?q?TieredMenu:=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D1=91=D0=BD=20=D1=81=D1=82=D0=BE=D1=80=D0=B8=D1=81=20Default?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../tieredmenu/tieredmenu.stories.ts | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/src/stories/components/tieredmenu/tieredmenu.stories.ts b/src/stories/components/tieredmenu/tieredmenu.stories.ts index 66a825ca..9fb5b57f 100644 --- a/src/stories/components/tieredmenu/tieredmenu.stories.ts +++ b/src/stories/components/tieredmenu/tieredmenu.stories.ts @@ -3,7 +3,6 @@ import { TieredMenuComponent } from '../../../lib/components/tieredmenu/tieredme import { TieredMenuBasicComponent, Basic } from './examples/tieredmenu-basic.component'; import { TieredMenuSelectedComponent, WithSelected } from './examples/tieredmenu-selected.component'; import { TieredMenuCustomComponent, Custom } from './examples/tieredmenu-custom.component'; -import { basicItems } from './tieredmenu.data'; const meta: Meta = { title: 'Components/Menu/TieredMenu', @@ -54,41 +53,10 @@ import { TieredMenuComponent } from '@cdek-it/angular-ui-kit'; }, }, }, - args: { - autoDisplay: true, - }, }; export default meta; type Story = StoryObj; -// ── Default ─────────────────────────────────────────────────────────────────── - -export const Default: Story = { - name: 'Default', - render: (args) => { - const parts: string[] = [`[model]="model"`]; - if (!args.autoDisplay) parts.push(`[autoDisplay]="false"`); - if (args.tabindex !== undefined) parts.push(`[tabindex]="${args.tabindex}"`); - - const template = ``; - - return { - props: { - ...args, - model: basicItems, - }, - template, - }; - }, - parameters: { - docs: { - description: { - story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', - }, - }, - }, -}; - // ── Re-exports from example components ──────────────────────────────────── export { Basic, WithSelected, Custom }; From 8096b7ffe12eb83db0916d70c8f0662b247b77fa Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 22 Apr 2026 16:31:00 +0700 Subject: [PATCH 167/258] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=84=D0=B0=D0=B9=D0=BB=20map-tokens.ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ src/prime-preset/map-tokens.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 808f9bdc..ce8e3c03 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ src/assets/components/themes /storybook-static /debug-storybook.log /documentation.json + +.claude/* \ No newline at end of file diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 437e87f4..a4c0fe2e 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -6,7 +6,7 @@ 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 { tooltipCss } from './tokens/components/tooltip'; +import { tagCss } from './tokens/components/tag'; const presetTokens: Preset = { primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'], From 86da477d57f8a634658d793ab90d21c08f2a7cd2 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 22 Apr 2026 17:44:25 +0700 Subject: [PATCH 168/258] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20cardCss=20map-tokens.ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/map-tokens.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index a4c0fe2e..ab0dc279 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -6,6 +6,7 @@ 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 { cardCss } from './tokens/components/card'; import { tagCss } from './tokens/components/tag'; const presetTokens: Preset = { @@ -25,6 +26,10 @@ const presetTokens: Preset = { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), css: buttonCss, }, + card: { + ...(tokens.components.card as unknown as ComponentsDesignTokens['card']), + css: cardCss, + }, tag: { ...(tokens.components.tag as unknown as ComponentsDesignTokens['tag']), css: tagCss, From 1dbdb8167794c98e8a21411964865c4b105b0f8b Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 22 Apr 2026 19:16:16 +0700 Subject: [PATCH 169/258] =?UTF-8?q?cardCss=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=B2=20map-tokens.ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/map-tokens.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index c725c2b9..185240a8 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -5,6 +5,7 @@ import type { AuraBaseDesignTokens } from '@primeuix/themes/aura/base'; import tokens from './tokens/tokens.json'; import { avatarCss } from './tokens/components/avatar'; import { buttonCss } from './tokens/components/button'; +import { cardCss } from './tokens/components/card'; import { checkboxCss } from './tokens/components/checkbox'; import { inputtextCss } from './tokens/components/inputtext'; import { progressspinnerCss } from './tokens/components/progressspinner'; @@ -21,6 +22,10 @@ const presetTokens: Preset = { ...(tokens.components.avatar as unknown as ComponentsDesignTokens['avatar']), css: avatarCss, }, + card: { + ...(tokens.components.card as unknown as ComponentsDesignTokens['card']), + css: cardCss, + }, checkbox: { ...(tokens.components.checkbox as unknown as ComponentsDesignTokens['checkbox']), css: checkboxCss, From 7104feb14786fdbb86640e758b318f7d7464166c Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 22 Apr 2026 22:08:31 +0700 Subject: [PATCH 170/258] =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0?= =?UTF-8?q?=20=D1=81=D1=82=D0=B8=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ src/prime-preset/map-tokens.ts | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index 808f9bdc..ce8e3c03 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ src/assets/components/themes /storybook-static /debug-storybook.log /documentation.json + +.claude/* \ No newline at end of file diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 0194af83..52737285 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -6,6 +6,7 @@ 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 { messageCss } from './tokens/components/message'; import { progressspinnerCss } from './tokens/components/progressspinner'; import { tagCss } from './tokens/components/tag'; import { tooltipCss } from './tokens/components/tooltip'; @@ -27,6 +28,10 @@ const presetTokens: Preset = { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), css: buttonCss, }, + message: { + ...(tokens.components.message as unknown as ComponentsDesignTokens['message']), + css: messageCss, + }, progressspinner: { ...(tokens.components.progressspinner as unknown as ComponentsDesignTokens['progressspinner']), css: progressspinnerCss, From d6c3acdffd13dd633267f07b4ef746b38b8be6df Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 18:05:53 +0700 Subject: [PATCH 171/258] =?UTF-8?q?timeline:=20=D1=80=D0=B5=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BF=D1=80=D0=BE=D0=BF?= =?UTF-8?q?=D1=81=D0=B0=20showCaption?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/timeline/timeline.component.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib/components/timeline/timeline.component.ts b/src/lib/components/timeline/timeline.component.ts index 1a4fa0c1..f1c549fd 100644 --- a/src/lib/components/timeline/timeline.component.ts +++ b/src/lib/components/timeline/timeline.component.ts @@ -20,10 +20,12 @@ import { NgIf, NgTemplateOutlet } from '@angular/common'; - - + + + + +   -   @@ -40,6 +42,7 @@ export class TimelineComponent { @Input() value: any[] = []; @Input() align: 'left' | 'right' | 'alternate' | 'top' | 'bottom' = 'left'; @Input() layout: 'vertical' | 'horizontal' = 'vertical'; + @Input() showCaption: boolean = true; @ContentChild('content') contentTemplate?: TemplateRef; @ContentChild('opposite') oppositeTemplate?: TemplateRef; From 42f4853229288eda2cd3c4e01cc42e4dd3ad50f9 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 18:06:23 +0700 Subject: [PATCH 172/258] =?UTF-8?q?timeline:=20=D1=80=D0=B5=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BF=D1=80=D0=BE=D0=BF?= =?UTF-8?q?=D1=81=D0=B0=20line=20(solid/dashed/dotted/none)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/timeline/timeline.component.ts | 7 ++++- .../tokens/components/timeline.ts | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/lib/components/timeline/timeline.component.ts b/src/lib/components/timeline/timeline.component.ts index f1c549fd..1c221538 100644 --- a/src/lib/components/timeline/timeline.component.ts +++ b/src/lib/components/timeline/timeline.component.ts @@ -1,8 +1,10 @@ -import { Component, Input, ContentChild, TemplateRef } from '@angular/core'; +import { Component, Input, ContentChild, TemplateRef, HostBinding } from '@angular/core'; import { Timeline } from 'primeng/timeline'; import { SharedModule } from 'primeng/api'; import { NgIf, NgTemplateOutlet } from '@angular/common'; +export type TimelineLine = 'solid' | 'dashed' | 'dotted' | 'none'; + @Component({ selector: 'timeline', standalone: true, @@ -43,6 +45,9 @@ export class TimelineComponent { @Input() align: 'left' | 'right' | 'alternate' | 'top' | 'bottom' = 'left'; @Input() layout: 'vertical' | 'horizontal' = 'vertical'; @Input() showCaption: boolean = true; + @Input() line: TimelineLine = 'solid'; + + @HostBinding('attr.data-line') get dataLine() { return this.line; } @ContentChild('content') contentTemplate?: TemplateRef; @ContentChild('opposite') oppositeTemplate?: TemplateRef; diff --git a/src/prime-preset/tokens/components/timeline.ts b/src/prime-preset/tokens/components/timeline.ts index 1f00e361..8ddd4e2d 100644 --- a/src/prime-preset/tokens/components/timeline.ts +++ b/src/prime-preset/tokens/components/timeline.ts @@ -16,4 +16,30 @@ export const timelineCss = ({ dt }: { dt: (token: string) => string }): string = .p-timeline-event-connector { background: ${dt('timeline.eventConnector.color')}; } + +/* ─── Стиль линии ─── */ +timeline[data-line="dashed"] .p-timeline-event-connector { + background: none; + border-left: ${dt('timeline.eventConnector.size')} dashed ${dt('timeline.eventConnector.color')}; +} + +timeline[data-line="dotted"] .p-timeline-event-connector { + background: none; + border-left: ${dt('timeline.eventConnector.size')} dotted ${dt('timeline.eventConnector.color')}; +} + +timeline[data-line="none"] .p-timeline-event-connector { + background: none; +} + +/* Горизонтальная ориентация линии */ +timeline[data-line="dashed"] .p-timeline-horizontal .p-timeline-event-connector { + border-left: none; + border-top: ${dt('timeline.eventConnector.size')} dashed ${dt('timeline.eventConnector.color')}; +} + +timeline[data-line="dotted"] .p-timeline-horizontal .p-timeline-event-connector { + border-left: none; + border-top: ${dt('timeline.eventConnector.size')} dotted ${dt('timeline.eventConnector.color')}; +} `; From 5f8d1bc2b43b6dc42cb306c476b74712823337df Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 18:06:48 +0700 Subject: [PATCH 173/258] =?UTF-8?q?timeline:=20=D1=80=D0=B5=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BF=D1=80=D0=BE=D0=BF?= =?UTF-8?q?=D1=81=D0=B0=20icon=20=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=B0=D1=81?= =?UTF-8?q?=D1=82=D0=BE=D0=BC=D0=BD=D0=BE=D0=B9=20=D0=B8=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/timeline/timeline.component.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/lib/components/timeline/timeline.component.ts b/src/lib/components/timeline/timeline.component.ts index 1c221538..1cb0c66d 100644 --- a/src/lib/components/timeline/timeline.component.ts +++ b/src/lib/components/timeline/timeline.component.ts @@ -30,8 +30,15 @@ export type TimelineLine = 'solid' | 'dashed' | 'dotted' | 'none'; - - + + + + + + + + + @@ -46,6 +53,7 @@ export class TimelineComponent { @Input() layout: 'vertical' | 'horizontal' = 'vertical'; @Input() showCaption: boolean = true; @Input() line: TimelineLine = 'solid'; + @Input() icon = ''; @HostBinding('attr.data-line') get dataLine() { return this.line; } From 32e97ce21e2938b76d2381b58545f58bdb1c9677 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 18:07:14 +0700 Subject: [PATCH 174/258] =?UTF-8?q?timeline:=20=D0=BF=D0=BE=D0=B4=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=D0=B6=D0=BA=D0=B0=20=D1=82=D1=91=D0=BC=D0=BD=D0=BE?= =?UTF-8?q?=D0=B9=20=D1=82=D0=B5=D0=BC=D1=8B=20(=D1=86=D0=B2=D0=B5=D1=82?= =?UTF-8?q?=20=D1=82=D0=B5=D0=BA=D1=81=D1=82=D0=B0=20=D0=B8=20=D0=BC=D0=B0?= =?UTF-8?q?=D1=80=D0=BA=D0=B5=D1=80=D0=BE=D0=B2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/timeline.ts | 7 +++++++ src/prime-preset/tokens/tokens.json | 16 +++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/prime-preset/tokens/components/timeline.ts b/src/prime-preset/tokens/components/timeline.ts index 8ddd4e2d..575c976f 100644 --- a/src/prime-preset/tokens/components/timeline.ts +++ b/src/prime-preset/tokens/components/timeline.ts @@ -5,11 +5,18 @@ export const timelineCss = ({ dt }: { dt: (token: string) => string }): string = font-family: ${dt('fonts.fontFamily.base')}; font-size: ${dt('fonts.fontSize.300')}; line-height: ${dt('fonts.lineHeight.500')}; + color: ${dt('text.color')}; } /* ─── Маркер ─── */ .p-timeline-event-marker { border-width: ${dt('timeline.eventMarker.borderWidth')}; + background: ${dt('timeline.eventMarker.background')}; + border-color: ${dt('timeline.eventMarker.borderColor')}; +} + +.p-timeline-event-marker::before { + background: ${dt('timeline.eventMarker.content.background')}; } /* ─── Коннектор ─── */ diff --git a/src/prime-preset/tokens/tokens.json b/src/prime-preset/tokens/tokens.json index 8f56c2c9..92306e14 100644 --- a/src/prime-preset/tokens/tokens.json +++ b/src/prime-preset/tokens/tokens.json @@ -4826,6 +4826,20 @@ "eventConnector": { "color": "{content.borderColor}", "size": "{feedback.width.100}" + }, + "colorScheme": { + "light": { + "eventMarker": { + "background": "{content.background}", + "borderColor": "{primary.color}" + } + }, + "dark": { + "eventMarker": { + "background": "{content.background}", + "borderColor": "{primary.color}" + } + } } }, "togglebutton": { @@ -5020,4 +5034,4 @@ } } } -} \ No newline at end of file +} From 771fab6007c8bd98fc0154a4d9d91834b3856b05 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 18:07:37 +0700 Subject: [PATCH 175/258] =?UTF-8?q?timeline:=20=D1=80=D0=B5=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BF=D1=80=D0=BE=D0=BF?= =?UTF-8?q?=D1=81=D0=B0=20markerColor=20=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=B0?= =?UTF-8?q?=D1=81=D1=82=D0=BE=D0=BC=D0=BD=D0=BE=D0=B3=D0=BE=20=D1=86=D0=B2?= =?UTF-8?q?=D0=B5=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/timeline/timeline.component.ts | 2 ++ src/prime-preset/tokens/components/timeline.ts | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/lib/components/timeline/timeline.component.ts b/src/lib/components/timeline/timeline.component.ts index 1cb0c66d..7846393a 100644 --- a/src/lib/components/timeline/timeline.component.ts +++ b/src/lib/components/timeline/timeline.component.ts @@ -54,8 +54,10 @@ export class TimelineComponent { @Input() showCaption: boolean = true; @Input() line: TimelineLine = 'solid'; @Input() icon = ''; + @Input() markerColor = ''; @HostBinding('attr.data-line') get dataLine() { return this.line; } + @HostBinding('style.--timeline-marker-color') get markerColorVar() { return this.markerColor || null; } @ContentChild('content') contentTemplate?: TemplateRef; @ContentChild('opposite') oppositeTemplate?: TemplateRef; diff --git a/src/prime-preset/tokens/components/timeline.ts b/src/prime-preset/tokens/components/timeline.ts index 575c976f..28a6c2d8 100644 --- a/src/prime-preset/tokens/components/timeline.ts +++ b/src/prime-preset/tokens/components/timeline.ts @@ -49,4 +49,9 @@ timeline[data-line="dotted"] .p-timeline-horizontal .p-timeline-event-connector border-left: none; border-top: ${dt('timeline.eventConnector.size')} dotted ${dt('timeline.eventConnector.color')}; } + +/* ─── Кастомный цвет маркера ─── */ +timeline[style*="--timeline-marker-color"] .p-timeline-event-marker { + border-color: var(--timeline-marker-color); +} `; From 70fa4f2aaea71eb0c34213b372c18a12fdff2ca2 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 18:17:19 +0700 Subject: [PATCH 176/258] =?UTF-8?q?storybook:=20=D1=82=D0=BE=D0=B3=D0=B3?= =?UTF-8?q?=D0=BB=20=D1=81=D0=B2=D0=B5=D1=82=D0=BB=D0=BE=D0=B9/=D1=82?= =?UTF-8?q?=D1=91=D0=BC=D0=BD=D0=BE=D0=B9=20=D1=82=D0=B5=D0=BC=D1=8B=20?= =?UTF-8?q?=D0=B2=20=D1=82=D1=83=D0=BB=D0=B1=D0=B0=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .storybook/preview.ts | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/.storybook/preview.ts b/.storybook/preview.ts index acc752b9..edfd963c 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -10,8 +10,39 @@ import '!style-loader!css-loader!postcss-loader!sass-loader!../src/styles.scss'; setCompodocJson(docJson); +const DARK_MODE_SELECTOR = '.dark-mode'; + const preview: Preview = { + globalTypes: { + theme: { + description: 'Тема оформления', + toolbar: { + title: 'Тема', + icon: 'mirror', + items: [ + { value: 'light', title: 'Светлая', icon: 'sun' }, + { value: 'dark', title: 'Тёмная', icon: 'moon' }, + ], + dynamicTitle: true, + }, + }, + }, + initialGlobals: { + theme: 'light', + }, decorators: [ + (story, context) => { + const isDark = context.globals['theme'] === 'dark'; + const body = document.body; + + if (isDark) { + body.classList.add('dark-mode'); + } else { + body.classList.remove('dark-mode'); + } + + return story(); + }, applicationConfig({ providers: [ provideAnimationsAsync(), @@ -19,7 +50,7 @@ const preview: Preview = { theme: { preset: Preset, options: { - darkModeSelector: false, + darkModeSelector: DARK_MODE_SELECTOR, cssLayer: false } } From 8ebf03f6a021c0119bf0ac3625aa70f483719296 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 18:18:29 +0700 Subject: [PATCH 177/258] =?UTF-8?q?storybook:=20=D1=84=D0=BE=D0=BD=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20=D0=BC=D0=B5=D0=BD=D1=8F?= =?UTF-8?q?=D0=B5=D1=82=D1=81=D1=8F=20=D0=BF=D1=80=D0=B8=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D1=82=D1=91=D0=BC=D0=BD=D1=83=D1=8E=20=D1=82?= =?UTF-8?q?=D0=B5=D0=BC=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/styles.scss b/src/styles.scss index e9739e26..9449e0df 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -25,3 +25,11 @@ html { body .css-3rewwu { background: rgb(245 246 248); } + +body.dark-mode { + background: var(--p-content-background, #18181b); + + .css-3rewwu { + background: var(--p-content-background, #18181b); + } +} From 94b32de67fb7c33308449247cacca2fb3323903c Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 18:41:43 +0700 Subject: [PATCH 178/258] =?UTF-8?q?storybook:=20=D0=BE=D1=82=D0=BA=D0=BB?= =?UTF-8?q?=D1=8E=D1=87=D1=91=D0=BD=20=D0=B0=D0=B4=D0=B4=D0=BE=D0=BD=20cha?= =?UTF-8?q?nge=20background?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .storybook/preview.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/.storybook/preview.ts b/.storybook/preview.ts index edfd963c..315bcee1 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -59,6 +59,7 @@ const preview: Preview = { }) ], parameters: { + backgrounds: { disable: true }, controls: { matchers: { color: /(background|color)$/i, From df2927606d17229067d218125f575d5e002caf37 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 19:20:52 +0700 Subject: [PATCH 179/258] =?UTF-8?q?timeline:=20storybook-=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BC=D0=B5=D1=80=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=BF=D1=81=D0=B0=20line?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timeline-dashed-line.component.ts | 55 +++++++++++++++++++ .../components/timeline/timeline.stories.ts | 53 +++++++++++++++++- 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/stories/components/timeline/examples/timeline-dashed-line.component.ts diff --git a/src/stories/components/timeline/examples/timeline-dashed-line.component.ts b/src/stories/components/timeline/examples/timeline-dashed-line.component.ts new file mode 100644 index 00000000..1851d7a8 --- /dev/null +++ b/src/stories/components/timeline/examples/timeline-dashed-line.component.ts @@ -0,0 +1,55 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { TimelineComponent } from '../../../../lib/components/timeline/timeline.component'; + +const template = ` +
+ + + + +
+`; + +@Component({ + selector: 'app-timeline-dashed-line', + standalone: true, + imports: [TimelineComponent], + template, +}) +export class TimelineDashedLineComponent { + events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; +} + +export const DashedLine: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Варианты стиля линии: `solid`, `dashed`, `dotted`, `none`.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { TimelineComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-timeline-line', + standalone: true, + imports: [TimelineComponent], + template: \` + + \`, +}) +export class TimelineLineComponent { + events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/timeline/timeline.stories.ts b/src/stories/components/timeline/timeline.stories.ts index 72aa07a9..3ed05bc3 100644 --- a/src/stories/components/timeline/timeline.stories.ts +++ b/src/stories/components/timeline/timeline.stories.ts @@ -1,6 +1,9 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { TimelineComponent } from '../../../lib/components/timeline/timeline.component'; import { TimelineHorizontalComponent, Horizontal } from './examples/timeline-horizontal.component'; +import { TimelineDashedLineComponent, DashedLine } from './examples/timeline-dashed-line.component'; +import { TimelineCustomIconComponent, CustomIcon } from './examples/timeline-custom-icon.component'; +import { TimelineMarkerColorComponent, MarkerColor } from './examples/timeline-marker-color.component'; type TimelineArgs = TimelineComponent; type Story = StoryObj; @@ -11,7 +14,7 @@ const meta: Meta = { tags: ['autodocs'], decorators: [ moduleMetadata({ - imports: [TimelineComponent, TimelineHorizontalComponent], + imports: [TimelineComponent, TimelineHorizontalComponent, TimelineDashedLineComponent, TimelineCustomIconComponent, TimelineMarkerColorComponent], }), ], parameters: { @@ -52,6 +55,43 @@ const meta: Meta = { type: { summary: "'vertical' | 'horizontal'" }, }, }, + showCaption: { + control: 'boolean', + description: 'Показывать opposite-контент', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + line: { + control: 'select', + options: ['solid', 'dashed', 'dotted', 'none'], + description: 'Стиль линии коннектора', + table: { + category: 'Props', + defaultValue: { summary: "'solid'" }, + type: { summary: "'solid' | 'dashed' | 'dotted' | 'none'" }, + }, + }, + icon: { + control: 'text', + description: 'CSS-класс иконки маркера (например `ti ti-check`)', + table: { + category: 'Props', + defaultValue: { summary: "''" }, + type: { summary: 'string' }, + }, + }, + markerColor: { + control: 'color', + description: 'Кастомный цвет маркера', + table: { + category: 'Props', + defaultValue: { summary: "''" }, + type: { summary: 'string' }, + }, + }, contentTemplate: { table: { disable: true } }, oppositeTemplate: { table: { disable: true } }, markerTemplate: { table: { disable: true } }, @@ -60,6 +100,10 @@ const meta: Meta = { value: ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено'], align: 'left', layout: 'vertical', + showCaption: true, + line: 'solid', + icon: '', + markerColor: '', }, }; @@ -72,6 +116,10 @@ function renderStory(args: any) { parts.push(`[value]="value"`); if (args.align && args.align !== 'left') parts.push(`align="${args.align}"`); if (args.layout && args.layout !== 'vertical') parts.push(`layout="${args.layout}"`); + if (args.showCaption === false) parts.push(`[showCaption]="false"`); + if (args.line && args.line !== 'solid') parts.push(`line="${args.line}"`); + if (args.icon) parts.push(`icon="${args.icon}"`); + if (args.markerColor) parts.push(`markerColor="${args.markerColor}"`); const template = ``; @@ -93,3 +141,6 @@ export const Default: Story = { // ── Re-exports from example components ──────────────────────────────────── export { Horizontal }; +export { DashedLine }; +export { CustomIcon }; +export { MarkerColor }; From f3f5cdfb32c41cbb23db37922a28a3f0387eef86 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 19:20:56 +0700 Subject: [PATCH 180/258] =?UTF-8?q?timeline:=20storybook-=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BC=D0=B5=D1=80=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=BF=D1=81=D0=B0=20icon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timeline-custom-icon.component.ts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/stories/components/timeline/examples/timeline-custom-icon.component.ts diff --git a/src/stories/components/timeline/examples/timeline-custom-icon.component.ts b/src/stories/components/timeline/examples/timeline-custom-icon.component.ts new file mode 100644 index 00000000..33a4a840 --- /dev/null +++ b/src/stories/components/timeline/examples/timeline-custom-icon.component.ts @@ -0,0 +1,50 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { TimelineComponent } from '../../../../lib/components/timeline/timeline.component'; + +const template = ` + +`; + +@Component({ + selector: 'app-timeline-custom-icon', + standalone: true, + imports: [TimelineComponent], + template, +}) +export class TimelineCustomIconComponent { + events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; +} + +export const CustomIcon: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Кастомная иконка маркера через проп `icon` (CSS-класс иконки, например Tabler Icons).', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { TimelineComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-timeline-custom-icon', + standalone: true, + imports: [TimelineComponent], + template: \` + + \`, +}) +export class TimelineCustomIconComponent { + events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; +} + `, + }, + }, + }, +}; From 056c3e5e82a735d9a35dd0d93ff99d37a2235e88 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 19:21:01 +0700 Subject: [PATCH 181/258] =?UTF-8?q?timeline:=20storybook-=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BC=D0=B5=D1=80=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=BF=D1=81=D0=B0=20markerColor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../timeline-marker-color.component.ts | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/stories/components/timeline/examples/timeline-marker-color.component.ts diff --git a/src/stories/components/timeline/examples/timeline-marker-color.component.ts b/src/stories/components/timeline/examples/timeline-marker-color.component.ts new file mode 100644 index 00000000..6e26f7cc --- /dev/null +++ b/src/stories/components/timeline/examples/timeline-marker-color.component.ts @@ -0,0 +1,54 @@ +import { Component } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { TimelineComponent } from '../../../../lib/components/timeline/timeline.component'; + +const template = ` +
+ + + +
+`; + +@Component({ + selector: 'app-timeline-marker-color', + standalone: true, + imports: [TimelineComponent], + template, +}) +export class TimelineMarkerColorComponent { + events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; +} + +export const MarkerColor: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Кастомный цвет маркера через проп `markerColor`.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { TimelineComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-timeline-marker-color', + standalone: true, + imports: [TimelineComponent], + template: \` + + \`, +}) +export class TimelineMarkerColorComponent { + events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; +} + `, + }, + }, + }, +}; From dea280300829c2e03a43498872ed5ea91946f64a Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 20:22:36 +0700 Subject: [PATCH 182/258] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=BB=D1=8E=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20theme=20addon=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ .storybook/main.ts | 2 +- .storybook/manager.ts | 12 ++++++++++++ .storybook/preview.ts | 40 +++++++++++----------------------------- 4 files changed, 26 insertions(+), 30 deletions(-) create mode 100644 .storybook/manager.ts diff --git a/.gitignore b/.gitignore index 808f9bdc..ce8e3c03 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ src/assets/components/themes /storybook-static /debug-storybook.log /documentation.json + +.claude/* \ No newline at end of file diff --git a/.storybook/main.ts b/.storybook/main.ts index 9c4112e5..fb574771 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -2,7 +2,7 @@ import type { StorybookConfig } from '@storybook/angular'; const config: StorybookConfig = { stories: ['../src/stories/**/*.mdx', '../src/stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'], - addons: ['@storybook/addon-a11y', '@storybook/addon-docs'], + addons: ['@storybook/addon-a11y', '@storybook/addon-docs', '@storybook/addon-themes'], framework: '@storybook/angular' }; export default config; diff --git a/.storybook/manager.ts b/.storybook/manager.ts new file mode 100644 index 00000000..50bb7774 --- /dev/null +++ b/.storybook/manager.ts @@ -0,0 +1,12 @@ +import { addons } from 'storybook/manager-api'; + +addons.setConfig({ + layoutCustomisations: { + showToolbar(state, defaultValue) { + if (state.viewMode === 'docs') { + return false; + } + return defaultValue; + }, + }, +}); diff --git a/.storybook/preview.ts b/.storybook/preview.ts index 315bcee1..53ff5789 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,5 +1,6 @@ import { applicationConfig, Preview } from '@storybook/angular'; import { setCompodocJson } from '@storybook/addon-docs/angular'; +import { withThemeByClassName } from '@storybook/addon-themes'; import docJson from '../documentation.json'; import { providePrimeNG } from 'primeng/config'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; @@ -13,36 +14,7 @@ setCompodocJson(docJson); const DARK_MODE_SELECTOR = '.dark-mode'; const preview: Preview = { - globalTypes: { - theme: { - description: 'Тема оформления', - toolbar: { - title: 'Тема', - icon: 'mirror', - items: [ - { value: 'light', title: 'Светлая', icon: 'sun' }, - { value: 'dark', title: 'Тёмная', icon: 'moon' }, - ], - dynamicTitle: true, - }, - }, - }, - initialGlobals: { - theme: 'light', - }, decorators: [ - (story, context) => { - const isDark = context.globals['theme'] === 'dark'; - const body = document.body; - - if (isDark) { - body.classList.add('dark-mode'); - } else { - body.classList.remove('dark-mode'); - } - - return story(); - }, applicationConfig({ providers: [ provideAnimationsAsync(), @@ -56,10 +28,20 @@ const preview: Preview = { } }) ] + }), + withThemeByClassName({ + themes: { + light: '', + dark: 'dark-mode' + }, + defaultTheme: 'light' }) ], parameters: { backgrounds: { disable: true }, + docs: { + globals: { theme: 'light' }, + }, controls: { matchers: { color: /(background|color)$/i, From f53926be35263ad9913de36cb58aee91dc5dc147 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 21:51:59 +0700 Subject: [PATCH 183/258] =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=BF=D1=81=20layout?= =?UTF-8?q?=20=D0=BF=D0=BE=D0=BA=D0=B0=D0=B7=D1=8B=D0=B2=D0=B0=D0=B5=D1=82?= =?UTF-8?q?=20=D0=B2=D0=B0=D0=BB=D0=B8=D0=B4=D0=BD=D1=8B=D0=B5=20=D0=B7?= =?UTF-8?q?=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20align;=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D0=BE=D0=BA=20=D0=B4=D0=BB=D1=8F=20=D1=81?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D1=81=20Custom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tokens/components/timeline.ts | 14 ++ .../timeline-custom-icon.component.ts | 50 ----- .../timeline-dashed-line.component.ts | 55 ----- .../examples/timeline-horizontal.component.ts | 52 ----- .../timeline-marker-color.component.ts | 54 ----- .../components/timeline/timeline.stories.ts | 206 +++++++++++++++--- 6 files changed, 185 insertions(+), 246 deletions(-) delete mode 100644 src/stories/components/timeline/examples/timeline-custom-icon.component.ts delete mode 100644 src/stories/components/timeline/examples/timeline-dashed-line.component.ts delete mode 100644 src/stories/components/timeline/examples/timeline-horizontal.component.ts delete mode 100644 src/stories/components/timeline/examples/timeline-marker-color.component.ts diff --git a/src/prime-preset/tokens/components/timeline.ts b/src/prime-preset/tokens/components/timeline.ts index 28a6c2d8..562376ec 100644 --- a/src/prime-preset/tokens/components/timeline.ts +++ b/src/prime-preset/tokens/components/timeline.ts @@ -50,8 +50,22 @@ timeline[data-line="dotted"] .p-timeline-horizontal .p-timeline-event-connector border-top: ${dt('timeline.eventConnector.size')} dotted ${dt('timeline.eventConnector.color')}; } +/* ─── Маркер-иконка (без бордера и фона) ─── */ +.p-timeline-event-marker:has(i) { + border: none; + background: none; +} + +.p-timeline-event-marker:has(i)::before { + display: none; +} + /* ─── Кастомный цвет маркера ─── */ timeline[style*="--timeline-marker-color"] .p-timeline-event-marker { border-color: var(--timeline-marker-color); } + +timeline[style*="--timeline-marker-color"] .p-timeline-event-marker i { + color: var(--timeline-marker-color); +} `; diff --git a/src/stories/components/timeline/examples/timeline-custom-icon.component.ts b/src/stories/components/timeline/examples/timeline-custom-icon.component.ts deleted file mode 100644 index 33a4a840..00000000 --- a/src/stories/components/timeline/examples/timeline-custom-icon.component.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Component } from '@angular/core'; -import { StoryObj } from '@storybook/angular'; -import { TimelineComponent } from '../../../../lib/components/timeline/timeline.component'; - -const template = ` - -`; - -@Component({ - selector: 'app-timeline-custom-icon', - standalone: true, - imports: [TimelineComponent], - template, -}) -export class TimelineCustomIconComponent { - events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; -} - -export const CustomIcon: StoryObj = { - render: () => ({ - template: ``, - }), - parameters: { - controls: { disable: true }, - docs: { - description: { - story: 'Кастомная иконка маркера через проп `icon` (CSS-класс иконки, например Tabler Icons).', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { TimelineComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-timeline-custom-icon', - standalone: true, - imports: [TimelineComponent], - template: \` - - \`, -}) -export class TimelineCustomIconComponent { - events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; -} - `, - }, - }, - }, -}; diff --git a/src/stories/components/timeline/examples/timeline-dashed-line.component.ts b/src/stories/components/timeline/examples/timeline-dashed-line.component.ts deleted file mode 100644 index 1851d7a8..00000000 --- a/src/stories/components/timeline/examples/timeline-dashed-line.component.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Component } from '@angular/core'; -import { StoryObj } from '@storybook/angular'; -import { TimelineComponent } from '../../../../lib/components/timeline/timeline.component'; - -const template = ` -
- - - - -
-`; - -@Component({ - selector: 'app-timeline-dashed-line', - standalone: true, - imports: [TimelineComponent], - template, -}) -export class TimelineDashedLineComponent { - events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; -} - -export const DashedLine: StoryObj = { - render: () => ({ - template: ``, - }), - parameters: { - controls: { disable: true }, - docs: { - description: { - story: 'Варианты стиля линии: `solid`, `dashed`, `dotted`, `none`.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { TimelineComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-timeline-line', - standalone: true, - imports: [TimelineComponent], - template: \` - - \`, -}) -export class TimelineLineComponent { - events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; -} - `, - }, - }, - }, -}; diff --git a/src/stories/components/timeline/examples/timeline-horizontal.component.ts b/src/stories/components/timeline/examples/timeline-horizontal.component.ts deleted file mode 100644 index 9232ba13..00000000 --- a/src/stories/components/timeline/examples/timeline-horizontal.component.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Component } from '@angular/core'; -import { StoryObj } from '@storybook/angular'; -import { TimelineComponent } from '../../../../lib/components/timeline/timeline.component'; - -const template = ` - -`; -const styles = ''; - -@Component({ - selector: 'app-timeline-horizontal', - standalone: true, - imports: [TimelineComponent], - template, - styles, -}) -export class TimelineHorizontalComponent { - events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; -} - -export const Horizontal: StoryObj = { - render: () => ({ - template: ``, - }), - parameters: { - controls: { disable: true }, - docs: { - description: { - story: 'Горизонтальная ориентация через `layout="horizontal"` и `align="top"`.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { TimelineComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-timeline-horizontal', - standalone: true, - imports: [TimelineComponent], - template: \` - - \`, -}) -export class TimelineHorizontalComponent { - events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; -} - `, - }, - }, - }, -}; diff --git a/src/stories/components/timeline/examples/timeline-marker-color.component.ts b/src/stories/components/timeline/examples/timeline-marker-color.component.ts deleted file mode 100644 index 6e26f7cc..00000000 --- a/src/stories/components/timeline/examples/timeline-marker-color.component.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Component } from '@angular/core'; -import { StoryObj } from '@storybook/angular'; -import { TimelineComponent } from '../../../../lib/components/timeline/timeline.component'; - -const template = ` -
- - - -
-`; - -@Component({ - selector: 'app-timeline-marker-color', - standalone: true, - imports: [TimelineComponent], - template, -}) -export class TimelineMarkerColorComponent { - events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; -} - -export const MarkerColor: StoryObj = { - render: () => ({ - template: ``, - }), - parameters: { - controls: { disable: true }, - docs: { - description: { - story: 'Кастомный цвет маркера через проп `markerColor`.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { TimelineComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-timeline-marker-color', - standalone: true, - imports: [TimelineComponent], - template: \` - - \`, -}) -export class TimelineMarkerColorComponent { - events = ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено']; -} - `, - }, - }, - }, -}; diff --git a/src/stories/components/timeline/timeline.stories.ts b/src/stories/components/timeline/timeline.stories.ts index 3ed05bc3..41086ccf 100644 --- a/src/stories/components/timeline/timeline.stories.ts +++ b/src/stories/components/timeline/timeline.stories.ts @@ -1,63 +1,76 @@ -import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { Meta, StoryObj } from '@storybook/angular'; import { TimelineComponent } from '../../../lib/components/timeline/timeline.component'; -import { TimelineHorizontalComponent, Horizontal } from './examples/timeline-horizontal.component'; -import { TimelineDashedLineComponent, DashedLine } from './examples/timeline-dashed-line.component'; -import { TimelineCustomIconComponent, CustomIcon } from './examples/timeline-custom-icon.component'; -import { TimelineMarkerColorComponent, MarkerColor } from './examples/timeline-marker-color.component'; -type TimelineArgs = TimelineComponent; +type TimelineArgs = TimelineComponent & { verticalAlign: string; horizontalAlign: string }; type Story = StoryObj; +const defaultEvents = [ + { value: 'Заказ создан', caption: '15 апр 2026, 10:00' }, + { value: 'Принят на склад', caption: '16 апр 2026, 14:30' }, + { value: 'В пути', caption: '17 апр 2026, 09:15' }, + { value: 'Доставлен', caption: '18 апр 2026, 11:45' }, +]; + const meta: Meta = { title: 'Components/Data/Timeline', component: TimelineComponent, tags: ['autodocs'], - decorators: [ - moduleMetadata({ - imports: [TimelineComponent, TimelineHorizontalComponent, TimelineDashedLineComponent, TimelineCustomIconComponent, TimelineMarkerColorComponent], - }), - ], parameters: { designTokens: { prefix: '--p-timeline' }, docs: { description: { component: - 'Визуализация последовательности событий. Поддерживает вертикальную и горизонтальную ориентацию, а также выравнивание `left`, `right`, `alternate`.', + 'Компонент для визуализации последовательности событий в хронологическом порядке. Поддерживает горизонтальную и вертикальную ориентацию, кастомные маркеры.\n\n```typescript\nimport { TimelineComponent } from \'@cdek-it/angular-ui-kit\';\n```', }, }, }, argTypes: { value: { control: 'object', - description: 'Массив событий', + description: 'Массив событий для отображения', + table: { + category: 'Props', + type: { summary: '{ value: string, caption?: string }[]' }, + }, + }, + layout: { + control: 'select', + options: ['vertical', 'horizontal'], + description: 'Ориентация таймлайна', table: { category: 'Props', - type: { summary: 'any[]' }, + defaultValue: { summary: "'vertical'" }, + type: { summary: "'vertical' | 'horizontal'" }, }, }, - align: { + align: { table: { disable: true } }, + verticalAlign: { + name: 'align', control: 'select', - options: ['left', 'right', 'alternate', 'top', 'bottom'], - description: 'Выравнивание контента относительно линии', + options: ['left', 'right', 'alternate'], + description: 'Положение контента относительно маркера', table: { category: 'Props', defaultValue: { summary: "'left'" }, - type: { summary: "'left' | 'right' | 'alternate' | 'top' | 'bottom'" }, + type: { summary: "'left' | 'right' | 'alternate'" }, }, + if: { arg: 'layout', eq: 'vertical' }, }, - layout: { + horizontalAlign: { + name: 'align', control: 'select', - options: ['vertical', 'horizontal'], - description: 'Ориентация', + options: ['top', 'bottom', 'alternate'], + description: 'Положение контента относительно маркера', table: { category: 'Props', - defaultValue: { summary: "'vertical'" }, - type: { summary: "'vertical' | 'horizontal'" }, + defaultValue: { summary: "'top'" }, + type: { summary: "'top' | 'bottom' | 'alternate'" }, }, + if: { arg: 'layout', eq: 'horizontal' }, }, showCaption: { control: 'boolean', - description: 'Показывать opposite-контент', + description: 'Показывать описание (caption) под основным контентом', table: { category: 'Props', defaultValue: { summary: 'true' }, @@ -97,9 +110,10 @@ const meta: Meta = { markerTemplate: { table: { disable: true } }, }, args: { - value: ['Заказ создан', 'Оплата', 'Отправка', 'Доставлено'], - align: 'left', + value: defaultEvents, layout: 'vertical', + verticalAlign: 'left', + horizontalAlign: 'top', showCaption: true, line: 'solid', icon: '', @@ -111,17 +125,33 @@ export default meta; // eslint-disable-next-line @typescript-eslint/no-explicit-any function renderStory(args: any) { + const layout = args.layout ?? 'vertical'; + const align = layout === 'horizontal' + ? (args.horizontalAlign ?? 'top') + : (args.verticalAlign ?? 'left'); + + const defaultAlign = layout === 'horizontal' ? 'top' : 'left'; + const parts: string[] = []; parts.push(`[value]="value"`); - if (args.align && args.align !== 'left') parts.push(`align="${args.align}"`); - if (args.layout && args.layout !== 'vertical') parts.push(`layout="${args.layout}"`); - if (args.showCaption === false) parts.push(`[showCaption]="false"`); + if (align !== defaultAlign) parts.push(`align="${align}"`); + if (layout !== 'vertical') parts.push(`layout="${layout}"`); + parts.push(`[showCaption]="${args.showCaption}"`); if (args.line && args.line !== 'solid') parts.push(`line="${args.line}"`); if (args.icon) parts.push(`icon="${args.icon}"`); if (args.markerColor) parts.push(`markerColor="${args.markerColor}"`); - const template = ``; + const attrs = parts.join('\n '); + + const template = ` + +
{{ event.value }}
+ {{ event.caption }} +
+
`; return { props: { ...args, value: args.value }, template }; } @@ -139,8 +169,114 @@ export const Default: Story = { }, }; -// ── Re-exports from example components ──────────────────────────────────── -export { Horizontal }; -export { DashedLine }; -export { CustomIcon }; -export { MarkerColor }; +// ── Horizontal ─────────────────────────────────────────────────────────────── +export const Horizontal: Story = { + name: 'Horizontal', + render: (args) => renderStory(args), + args: { + layout: 'horizontal', + horizontalAlign: 'top', + }, + parameters: { + docs: { + description: { + story: 'Горизонтальная ориентация через `layout="horizontal"` и `align="top"`.', + }, + }, + }, +}; + +// ── Opposite ───────────────────────────────────────────────────────────────── +export const Opposite: Story = { + name: 'Opposite', + render: (args) => { + const layout = args.layout ?? 'vertical'; + const align = layout === 'horizontal' + ? (args.horizontalAlign ?? 'top') + : (args.verticalAlign ?? 'left'); + + const defaultAlign = layout === 'horizontal' ? 'top' : 'left'; + + const parts: string[] = []; + + parts.push(`[value]="value"`); + if (align !== defaultAlign) parts.push(`align="${align}"`); + if (layout !== 'vertical') parts.push(`layout="${layout}"`); + parts.push(`[showCaption]="${args.showCaption}"`); + if (args.line && args.line !== 'solid') parts.push(`line="${args.line}"`); + if (args.icon) parts.push(`icon="${args.icon}"`); + if (args.markerColor) parts.push(`markerColor="${args.markerColor}"`); + + const attrs = parts.join('\n '); + + const template = ` + {{ event.value }} + + {{ event.caption }} + +`; + + return { props: { ...args, value: args.value }, template }; + }, + args: { + verticalAlign: 'alternate', + }, + parameters: { + docs: { + description: { + story: 'Контент по другую сторону линии через шаблон `#opposite`. Отображается при `align="alternate"`, `"right"`, `"bottom"`.', + }, + }, + }, +}; + +// ── Dashed Line ────────────────────────────────────────────────────────────── +export const DashedLine: Story = { + name: 'Dashed Line', + render: (args) => renderStory(args), + args: { + line: 'dashed', + }, + parameters: { + docs: { + description: { + story: 'Пунктирная линия коннектора через проп `line="dashed"`. Другие варианты: `solid`, `dotted`, `none`.', + }, + }, + }, +}; + +// ── Custom Icon ────────────────────────────────────────────────────────────── +export const CustomIcon: Story = { + name: 'Custom Icon', + render: (args) => renderStory(args), + args: { + icon: 'ti ti-check', + markerColor: '#3182ce', + }, + parameters: { + docs: { + description: { + story: 'Кастомная иконка вместо маркера через проп `icon` (CSS-класс иконки, например Tabler Icons).', + }, + }, + }, +}; + +// ── Marker Color ───────────────────────────────────────────────────────────── +export const MarkerColor: Story = { + name: 'Marker Color', + render: (args) => renderStory(args), + args: { + markerColor: '#e53e3e', + }, + parameters: { + docs: { + description: { + story: 'Кастомный цвет маркера через проп `markerColor`.', + }, + }, + }, +}; From 1a585aee1a11b5e65fa962cb7a49f8509e3c38d5 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 22:06:35 +0700 Subject: [PATCH 184/258] =?UTF-8?q?select:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=BF=D1=80=D0=BE=D0=BF=D1=81=20flo?= =?UTF-8?q?atLabel=20=D1=81=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B5=D0=B9=20=D0=B8=20=D1=81=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/select/select.component.ts | 110 ++++++++++-------- .../examples/select-float-label.component.ts | 51 ++++---- .../components/select/select.stories.ts | 2 - 3 files changed, 87 insertions(+), 76 deletions(-) diff --git a/src/lib/components/select/select.component.ts b/src/lib/components/select/select.component.ts index 5045f337..fba71396 100644 --- a/src/lib/components/select/select.component.ts +++ b/src/lib/components/select/select.component.ts @@ -3,6 +3,7 @@ import { NgClass, NgTemplateOutlet } from '@angular/common'; import { ControlValueAccessor, NgControl, NG_VALUE_ACCESSOR } from '@angular/forms'; import { FormsModule } from '@angular/forms'; import { Select } from 'primeng/select'; +import { FloatLabel } from 'primeng/floatlabel'; import { PrimeTemplate } from 'primeng/api'; import type { SelectChangeEvent, SelectFilterEvent } from 'primeng/types/select'; @@ -11,7 +12,7 @@ export type SelectSize = 'small' | 'base' | 'large' | 'xlarge'; @Component({ selector: 'select-field', standalone: true, - imports: [Select, NgClass, NgTemplateOutlet, PrimeTemplate, FormsModule], + imports: [Select, NgClass, NgTemplateOutlet, PrimeTemplate, FormsModule, FloatLabel], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -20,52 +21,64 @@ export type SelectSize = 'small' | 'base' | 'large' | 'xlarge'; }, ], template: ` - - @if (optionTemplate) { - - - - } - @if (selectedItemTemplate) { - - - - } - @if (optionGroupTemplate) { - - - - } - + @if (floatLabel) { + + + + + } @else { + + } + + + + @if (optionTemplate) { + + + + } + @if (selectedItemTemplate) { + + + + } + @if (optionGroupTemplate) { + + + + } + + `, }) export class SelectComponent implements ControlValueAccessor, OnInit { @@ -92,6 +105,9 @@ export class SelectComponent implements ControlValueAccessor, OnInit { @Input() loading = false; @Input() inputId: string | undefined; @Input() appendTo: any = 'body'; + @Input() floatLabel = false; + @Input() label = ''; + @Input() dropdownIcon: string | undefined; @Input() emptyMessage = 'Нет данных'; @Input() emptyFilterMessage = 'Результаты не найдены'; @Input() optionTemplate: TemplateRef | null = null; diff --git a/src/stories/components/select/examples/select-float-label.component.ts b/src/stories/components/select/examples/select-float-label.component.ts index 71bf3099..a4359c05 100644 --- a/src/stories/components/select/examples/select-float-label.component.ts +++ b/src/stories/components/select/examples/select-float-label.component.ts @@ -1,6 +1,5 @@ import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { FloatLabel } from 'primeng/floatlabel'; import { SelectComponent } from '../../../../lib/components/select/select.component'; const OPTIONS = [ @@ -12,16 +11,15 @@ const OPTIONS = [ const template = `
- - - - +
`; const styles = ''; @@ -29,12 +27,13 @@ const styles = ''; @Component({ selector: 'app-select-float-label', standalone: true, - imports: [SelectComponent, FloatLabel, ReactiveFormsModule], + imports: [SelectComponent, ReactiveFormsModule], template, styles, }) export class SelectFloatLabelComponent { @Input() showClear = false; + @Input() label = 'Город'; control = new FormControl(null); options = OPTIONS; } @@ -42,8 +41,8 @@ export class SelectFloatLabelComponent { export const FloatLabelStory = { name: 'FloatLabel', render: (args: any) => ({ - props: { showClear: args['showClear'] }, - template: ``, + props: { showClear: args['showClear'], label: 'Город' }, + template: ``, }), argTypes: { size: { table: { disable: true } }, @@ -51,31 +50,29 @@ export const FloatLabelStory = { parameters: { docs: { description: { - story: 'Интеграция с `p-floatlabel` — плавающая метка внутри поля.', + story: 'Плавающая метка внутри поля. Используйте пропс `floatLabel` для встроенной интеграции с `p-floatlabel`.', }, source: { language: 'ts', code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { FloatLabel } from 'primeng/floatlabel'; import { SelectComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [SelectComponent, FloatLabel, ReactiveFormsModule], + imports: [SelectComponent, ReactiveFormsModule], template: \`
- - - - +
\`, }) diff --git a/src/stories/components/select/select.stories.ts b/src/stories/components/select/select.stories.ts index f577df78..95ac3008 100644 --- a/src/stories/components/select/select.stories.ts +++ b/src/stories/components/select/select.stories.ts @@ -1,6 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { FloatLabel as PrimeFloatLabel } from 'primeng/floatlabel'; import { SelectComponent } from '../../../lib/components/select/select.component'; import { SelectFilterComponent, Filter as FilterStory } from './examples/select-filter.component'; import { SelectGroupedComponent, Grouped as GroupedStory } from './examples/select-grouped.component'; @@ -31,7 +30,6 @@ const meta: Meta = { imports: [ SelectComponent, ReactiveFormsModule, - PrimeFloatLabel, SelectFilterComponent, SelectGroupedComponent, SelectCustomComponent, From 323a61a3643d298f273e3915dcc95a97f12d823a Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 22:07:09 +0700 Subject: [PATCH 185/258] =?UTF-8?q?select:=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=BF=D1=80=D0=BE=D0=BF=D1=81=20dro?= =?UTF-8?q?pdownIcon=20=D1=81=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B5=D0=B9=20=D0=B8=20=D1=81=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../select-dropdown-icon.component.ts | 94 +++++++++++++++++++ .../components/select/select.stories.ts | 6 ++ 2 files changed, 100 insertions(+) create mode 100644 src/stories/components/select/examples/select-dropdown-icon.component.ts diff --git a/src/stories/components/select/examples/select-dropdown-icon.component.ts b/src/stories/components/select/examples/select-dropdown-icon.component.ts new file mode 100644 index 00000000..bde79ef7 --- /dev/null +++ b/src/stories/components/select/examples/select-dropdown-icon.component.ts @@ -0,0 +1,94 @@ +import { Component, Input } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; + +const OPTIONS = [ + { name: 'Новосибирск', code: 'NSK' }, + { name: 'Москва', code: 'MSK' }, + { name: 'Санкт-Петербург', code: 'SPB' }, + { name: 'Екатеринбург', code: 'EKB' }, +]; + +const template = ` + +`; +const styles = ''; + +@Component({ + selector: 'app-select-dropdown-icon', + standalone: true, + imports: [SelectComponent, ReactiveFormsModule], + template, + styles, +}) +export class SelectDropdownIconComponent { + @Input() size: SelectSize = 'base'; + @Input() showClear = false; + @Input() dropdownIcon = 'ti ti-search'; + control = new FormControl(null); + options = OPTIONS; +} + +export const DropdownIcon = { + render: (args: any) => ({ + props: { size: args['size'], showClear: args['showClear'], dropdownIcon: args['dropdownIcon'] }, + template: ``, + }), + args: { + dropdownIcon: 'ti ti-search', + }, + argTypes: { + dropdownIcon: { + control: 'text', + description: 'CSS-класс иконки для выпадающего списка', + table: { + category: 'Props', + defaultValue: { summary: 'undefined' }, + type: { summary: 'string' }, + }, + }, + }, + parameters: { + docs: { + description: { story: 'Кастомная иконка раскрытия списка через пропс `dropdownIcon`.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { SelectComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + standalone: true, + imports: [SelectComponent, ReactiveFormsModule], + template: \` + + \`, +}) +export class SelectDropdownIconExample { + control = new FormControl(null); + options = [ + { name: 'Новосибирск', code: 'NSK' }, + { name: 'Москва', code: 'MSK' }, + { name: 'Санкт-Петербург', code: 'SPB' }, + ]; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/select/select.stories.ts b/src/stories/components/select/select.stories.ts index 95ac3008..7a93de7b 100644 --- a/src/stories/components/select/select.stories.ts +++ b/src/stories/components/select/select.stories.ts @@ -7,6 +7,7 @@ import { SelectCustomComponent, Custom as CustomStory } from './examples/select- import { SelectEditableComponent, Editable as EditableStory } from './examples/select-editable.component'; import { Disabled as DisabledStory } from './examples/select-disabled.component'; import { SelectFloatLabelComponent, FloatLabelStory } from './examples/select-float-label.component'; +import { SelectDropdownIconComponent, DropdownIcon as DropdownIconStory } from './examples/select-dropdown-icon.component'; const BASIC_OPTIONS = [ { name: 'Новосибирск', code: 'NSK' }, @@ -35,6 +36,7 @@ const meta: Meta = { SelectCustomComponent, SelectEditableComponent, SelectFloatLabelComponent, + SelectDropdownIconComponent, ], }), ], @@ -186,6 +188,10 @@ export const Editable: Story = EditableStory; export const Disabled: Story = DisabledStory; +// ── DropdownIcon ───────────────────────────────────────────────────────────── + +export const DropdownIcon: Story = DropdownIconStory; + // ── FloatLabel ──────────────────────────────────────────────────────────────── export const FloatLabel: Story = FloatLabelStory; From d824a71b1110b6b0a8594576a6b778b1a1cad849 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 22:10:27 +0700 Subject: [PATCH 186/258] =?UTF-8?q?fix:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20dropdownIcon=20=D0=B2=20SelectArgs=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=82=D0=B8=D0=BF=D0=B8=D0=B7=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B8=20=D1=81=D1=82=D0=BE=D1=80=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stories/components/select/select.stories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stories/components/select/select.stories.ts b/src/stories/components/select/select.stories.ts index 7a93de7b..30f07695 100644 --- a/src/stories/components/select/select.stories.ts +++ b/src/stories/components/select/select.stories.ts @@ -17,7 +17,7 @@ const BASIC_OPTIONS = [ { name: 'Казань', code: 'KZN' }, ]; -type SelectArgs = Pick & { +type SelectArgs = Pick & { disabled: boolean; invalid: boolean; }; From d78e70278ff9d019b1e66edb858b2225a35a9d4b Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 22:10:59 +0700 Subject: [PATCH 187/258] =?UTF-8?q?fix:=20control=20type=20=D0=B2=20argTyp?= =?UTF-8?q?es=20=D0=B4=D0=BB=D1=8F=20dropdownIcon=20=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../select/examples/select-dropdown-icon.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stories/components/select/examples/select-dropdown-icon.component.ts b/src/stories/components/select/examples/select-dropdown-icon.component.ts index bde79ef7..e7f3e146 100644 --- a/src/stories/components/select/examples/select-dropdown-icon.component.ts +++ b/src/stories/components/select/examples/select-dropdown-icon.component.ts @@ -47,7 +47,7 @@ export const DropdownIcon = { }, argTypes: { dropdownIcon: { - control: 'text', + control: { type: 'text' }, description: 'CSS-класс иконки для выпадающего списка', table: { category: 'Props', From 3f1a27a26bc916b0ce3564b14eb16d81e9057661 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 22:11:39 +0700 Subject: [PATCH 188/258] =?UTF-8?q?fix:=20=D0=BB=D0=B8=D1=82=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D1=82=D0=B8=D0=BF=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20control=20=D0=B2=20dropdownIcon=20argTypes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../select/examples/select-dropdown-icon.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stories/components/select/examples/select-dropdown-icon.component.ts b/src/stories/components/select/examples/select-dropdown-icon.component.ts index e7f3e146..d307ad9a 100644 --- a/src/stories/components/select/examples/select-dropdown-icon.component.ts +++ b/src/stories/components/select/examples/select-dropdown-icon.component.ts @@ -47,7 +47,7 @@ export const DropdownIcon = { }, argTypes: { dropdownIcon: { - control: { type: 'text' }, + control: 'text' as const, description: 'CSS-класс иконки для выпадающего списка', table: { category: 'Props', From 3a04377fb26de2ef2323aa880638a71278f38c91 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 22:19:37 +0700 Subject: [PATCH 189/258] =?UTF-8?q?select=20stories:=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BF=D1=80=D0=BE=D0=BF?= =?UTF-8?q?=D1=81=D1=8B=20readonly,=20disabled,=20invalid=20=D0=B2=D0=BE?= =?UTF-8?q?=20=D0=B2=D1=81=D0=B5=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../select/examples/select-custom.component.ts | 18 +++++++++++++++--- .../examples/select-dropdown-icon.component.ts | 18 +++++++++++++++--- .../examples/select-editable.component.ts | 18 +++++++++++++++--- .../select/examples/select-filter.component.ts | 18 +++++++++++++++--- .../examples/select-float-label.component.ts | 18 +++++++++++++++--- .../examples/select-grouped.component.ts | 18 +++++++++++++++--- 6 files changed, 90 insertions(+), 18 deletions(-) diff --git a/src/stories/components/select/examples/select-custom.component.ts b/src/stories/components/select/examples/select-custom.component.ts index 1da4c2a5..b8eefe6d 100644 --- a/src/stories/components/select/examples/select-custom.component.ts +++ b/src/stories/components/select/examples/select-custom.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const OPTIONS = [ @@ -26,6 +26,7 @@ const template = ` [optionTemplate]="optTpl" [size]="size" [showClear]="showClear" + [readonly]="readonly" > `; const styles = ''; @@ -40,14 +41,25 @@ const styles = ''; export class SelectCustomComponent { @Input() size: SelectSize = 'base'; @Input() showClear = false; + @Input() readonly = false; control = new FormControl(null); options = OPTIONS; + + @Input() set disabled(val: boolean) { + val ? this.control.disable() : this.control.enable(); + } + + @Input() set invalid(val: boolean) { + this.control.setValidators(val ? [Validators.required] : []); + this.control.updateValueAndValidity(); + if (val) this.control.markAsTouched(); + } } export const Custom = { render: (args: any) => ({ - props: { size: args['size'], showClear: args['showClear'] }, - template: ``, + props: { size: args['size'], showClear: args['showClear'], readonly: args['readonly'], disabled: args['disabled'], invalid: args['invalid'] }, + template: ``, }), parameters: { docs: { diff --git a/src/stories/components/select/examples/select-dropdown-icon.component.ts b/src/stories/components/select/examples/select-dropdown-icon.component.ts index d307ad9a..374db3ad 100644 --- a/src/stories/components/select/examples/select-dropdown-icon.component.ts +++ b/src/stories/components/select/examples/select-dropdown-icon.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const OPTIONS = [ @@ -18,6 +18,7 @@ const template = ` [dropdownIcon]="dropdownIcon" [size]="size" [showClear]="showClear" + [readonly]="readonly" > `; const styles = ''; @@ -32,15 +33,26 @@ const styles = ''; export class SelectDropdownIconComponent { @Input() size: SelectSize = 'base'; @Input() showClear = false; + @Input() readonly = false; @Input() dropdownIcon = 'ti ti-search'; control = new FormControl(null); options = OPTIONS; + + @Input() set disabled(val: boolean) { + val ? this.control.disable() : this.control.enable(); + } + + @Input() set invalid(val: boolean) { + this.control.setValidators(val ? [Validators.required] : []); + this.control.updateValueAndValidity(); + if (val) this.control.markAsTouched(); + } } export const DropdownIcon = { render: (args: any) => ({ - props: { size: args['size'], showClear: args['showClear'], dropdownIcon: args['dropdownIcon'] }, - template: ``, + props: { size: args['size'], showClear: args['showClear'], dropdownIcon: args['dropdownIcon'], readonly: args['readonly'], disabled: args['disabled'], invalid: args['invalid'] }, + template: ``, }), args: { dropdownIcon: 'ti ti-search', diff --git a/src/stories/components/select/examples/select-editable.component.ts b/src/stories/components/select/examples/select-editable.component.ts index e89d5b4b..6868d9d1 100644 --- a/src/stories/components/select/examples/select-editable.component.ts +++ b/src/stories/components/select/examples/select-editable.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const OPTIONS = [ @@ -17,6 +17,7 @@ const template = ` [editable]="true" [size]="size" [showClear]="showClear" + [readonly]="readonly" > `; const styles = ''; @@ -31,14 +32,25 @@ const styles = ''; export class SelectEditableComponent { @Input() size: SelectSize = 'base'; @Input() showClear = false; + @Input() readonly = false; control = new FormControl(null); options = OPTIONS; + + @Input() set disabled(val: boolean) { + val ? this.control.disable() : this.control.enable(); + } + + @Input() set invalid(val: boolean) { + this.control.setValidators(val ? [Validators.required] : []); + this.control.updateValueAndValidity(); + if (val) this.control.markAsTouched(); + } } export const Editable = { render: (args: any) => ({ - props: { size: args['size'], showClear: args['showClear'] }, - template: ``, + props: { size: args['size'], showClear: args['showClear'], readonly: args['readonly'], disabled: args['disabled'], invalid: args['invalid'] }, + template: ``, }), parameters: { docs: { diff --git a/src/stories/components/select/examples/select-filter.component.ts b/src/stories/components/select/examples/select-filter.component.ts index db9ef969..993c195d 100644 --- a/src/stories/components/select/examples/select-filter.component.ts +++ b/src/stories/components/select/examples/select-filter.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const OPTIONS = [ @@ -19,6 +19,7 @@ const template = ` [filter]="true" [showClear]="true" [size]="size" + [readonly]="readonly" > `; const styles = ''; @@ -32,14 +33,25 @@ const styles = ''; }) export class SelectFilterComponent { @Input() size: SelectSize = 'base'; + @Input() readonly = false; control = new FormControl(null); options = OPTIONS; + + @Input() set disabled(val: boolean) { + val ? this.control.disable() : this.control.enable(); + } + + @Input() set invalid(val: boolean) { + this.control.setValidators(val ? [Validators.required] : []); + this.control.updateValueAndValidity(); + if (val) this.control.markAsTouched(); + } } export const Filter = { render: (args: any) => ({ - props: { size: args['size'] }, - template: ``, + props: { size: args['size'], readonly: args['readonly'], disabled: args['disabled'], invalid: args['invalid'] }, + template: ``, }), parameters: { docs: { diff --git a/src/stories/components/select/examples/select-float-label.component.ts b/src/stories/components/select/examples/select-float-label.component.ts index a4359c05..d269013a 100644 --- a/src/stories/components/select/examples/select-float-label.component.ts +++ b/src/stories/components/select/examples/select-float-label.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { SelectComponent } from '../../../../lib/components/select/select.component'; const OPTIONS = [ @@ -19,6 +19,7 @@ const template = ` [floatLabel]="true" [label]="label" [showClear]="showClear" + [readonly]="readonly" >
`; @@ -33,16 +34,27 @@ const styles = ''; }) export class SelectFloatLabelComponent { @Input() showClear = false; + @Input() readonly = false; @Input() label = 'Город'; control = new FormControl(null); options = OPTIONS; + + @Input() set disabled(val: boolean) { + val ? this.control.disable() : this.control.enable(); + } + + @Input() set invalid(val: boolean) { + this.control.setValidators(val ? [Validators.required] : []); + this.control.updateValueAndValidity(); + if (val) this.control.markAsTouched(); + } } export const FloatLabelStory = { name: 'FloatLabel', render: (args: any) => ({ - props: { showClear: args['showClear'], label: 'Город' }, - template: ``, + props: { showClear: args['showClear'], label: 'Город', readonly: args['readonly'], disabled: args['disabled'], invalid: args['invalid'] }, + template: ``, }), argTypes: { size: { table: { disable: true } }, diff --git a/src/stories/components/select/examples/select-grouped.component.ts b/src/stories/components/select/examples/select-grouped.component.ts index f6ca2205..40fa483d 100644 --- a/src/stories/components/select/examples/select-grouped.component.ts +++ b/src/stories/components/select/examples/select-grouped.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const GROUPED_OPTIONS = [ @@ -39,6 +39,7 @@ const template = ` [optionGroupTemplate]="groupTpl" [size]="size" [showClear]="showClear" + [readonly]="readonly" > `; const styles = ''; @@ -53,14 +54,25 @@ const styles = ''; export class SelectGroupedComponent { @Input() size: SelectSize = 'base'; @Input() showClear = false; + @Input() readonly = false; control = new FormControl(null); options = GROUPED_OPTIONS; + + @Input() set disabled(val: boolean) { + val ? this.control.disable() : this.control.enable(); + } + + @Input() set invalid(val: boolean) { + this.control.setValidators(val ? [Validators.required] : []); + this.control.updateValueAndValidity(); + if (val) this.control.markAsTouched(); + } } export const Grouped = { render: (args: any) => ({ - props: { size: args['size'], showClear: args['showClear'] }, - template: ``, + props: { size: args['size'], showClear: args['showClear'], readonly: args['readonly'], disabled: args['disabled'], invalid: args['invalid'] }, + template: ``, }), parameters: { docs: { From 7127d505fbb4065db1a9cdc117ccdb2d5aefef24 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 22:30:46 +0700 Subject: [PATCH 190/258] =?UTF-8?q?select:=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=20.p-floatlabel=20label=20=D0=BF=D1=80=D0=B8=D0=B2=D1=8F?= =?UTF-8?q?=D0=B7=D0=B0=D0=BD=D1=8B=20=D0=BA=20dt()=20=D1=82=D0=BE=D0=BA?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=D0=BC=20=D1=88=D1=80=D0=B8=D1=84=D1=82=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/select.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/prime-preset/tokens/components/select.ts b/src/prime-preset/tokens/components/select.ts index 26b0b33f..afc56ec2 100644 --- a/src/prime-preset/tokens/components/select.ts +++ b/src/prime-preset/tokens/components/select.ts @@ -37,7 +37,20 @@ export const selectCss = ({ dt }: { dt: (token: string) => string }): string => padding-inline: ${dt('inputtext.extend.extXlg.paddingX')}; } - /* ─── FloatLabel variant="in" ─── */ + /* ─── FloatLabel ─── */ + .p-floatlabel:has(.p-select.p-component) label { + font-family: ${dt('fonts.fontFamily.base')}; + font-size: ${dt('fonts.fontSize.300')}; + font-weight: ${dt('floatlabel.root.fontWeight')}; + line-height: ${dt('fonts.lineHeight.250')}; + color: ${dt('floatlabel.root.color')}; + } + + .p-floatlabel:has(.p-select.p-component) .p-floatlabel-active label { + font-size: ${dt('floatlabel.root.active.fontSize')}; + font-weight: ${dt('floatlabel.root.active.fontWeight')}; + } + .p-floatlabel-in .p-select.p-component .p-select-label { padding-block-start: ${dt('floatlabel.in.input.paddingTop')}; padding-block-end: ${dt('floatlabel.in.input.paddingBottom')}; From 2d6b4cbdb05cae2494b43f21d31252d2c1298e99 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 22:33:47 +0700 Subject: [PATCH 191/258] =?UTF-8?q?select:=20font-family=20=D1=82=D0=BE?= =?UTF-8?q?=D0=BA=D0=B5=D0=BD=20=D0=B4=D0=BB=D1=8F=20.p-select-label.p-pla?= =?UTF-8?q?ceholder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/select.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/prime-preset/tokens/components/select.ts b/src/prime-preset/tokens/components/select.ts index afc56ec2..e58e8816 100644 --- a/src/prime-preset/tokens/components/select.ts +++ b/src/prime-preset/tokens/components/select.ts @@ -6,6 +6,10 @@ export const selectCss = ({ dt }: { dt: (token: string) => string }): string => line-height: ${dt('fonts.lineHeight.250')}; } + .p-select.p-component .p-select-label.p-placeholder { + font-family: ${dt('fonts.fontFamily.base')}; + } + /* ─── Focus ─── */ .p-select.p-component:not(.p-disabled).p-focus { box-shadow: 0 0 0 ${dt('select.root.focusRing.width')} ${dt('select.root.focusRing.color')}; @@ -40,14 +44,12 @@ export const selectCss = ({ dt }: { dt: (token: string) => string }): string => /* ─── FloatLabel ─── */ .p-floatlabel:has(.p-select.p-component) label { font-family: ${dt('fonts.fontFamily.base')}; - font-size: ${dt('fonts.fontSize.300')}; font-weight: ${dt('floatlabel.root.fontWeight')}; line-height: ${dt('fonts.lineHeight.250')}; color: ${dt('floatlabel.root.color')}; } .p-floatlabel:has(.p-select.p-component) .p-floatlabel-active label { - font-size: ${dt('floatlabel.root.active.fontSize')}; font-weight: ${dt('floatlabel.root.active.fontWeight')}; } From 902414a99e7bc09e270a5767ad334f399adbccd3 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 22:36:21 +0700 Subject: [PATCH 192/258] =?UTF-8?q?select:=20font-family=20=D1=82=D0=BE?= =?UTF-8?q?=D0=BA=D0=B5=D0=BD=20=D0=B4=D0=BB=D1=8F=20.p-floatlabel-in=20.p?= =?UTF-8?q?-select-label?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/select.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/prime-preset/tokens/components/select.ts b/src/prime-preset/tokens/components/select.ts index e58e8816..f86b39b2 100644 --- a/src/prime-preset/tokens/components/select.ts +++ b/src/prime-preset/tokens/components/select.ts @@ -7,7 +7,7 @@ export const selectCss = ({ dt }: { dt: (token: string) => string }): string => } .p-select.p-component .p-select-label.p-placeholder { - font-family: ${dt('fonts.fontFamily.base')}; + font-family: ${dt('fonts.fontFamily.base')}; } /* ─── Focus ─── */ @@ -54,6 +54,7 @@ export const selectCss = ({ dt }: { dt: (token: string) => string }): string => } .p-floatlabel-in .p-select.p-component .p-select-label { + font-family: ${dt('fonts.fontFamily.base')}; padding-block-start: ${dt('floatlabel.in.input.paddingTop')}; padding-block-end: ${dt('floatlabel.in.input.paddingBottom')}; } From 18e6b4ffe19a5a1f9cc928a130b0e7c5b43ee159 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 22:37:05 +0700 Subject: [PATCH 193/258] =?UTF-8?q?select:=20font-family=20=D1=82=D0=BE?= =?UTF-8?q?=D0=BA=D0=B5=D0=BD=20=D0=B4=D0=BB=D1=8F=20.p-select-label?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/select.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/prime-preset/tokens/components/select.ts b/src/prime-preset/tokens/components/select.ts index f86b39b2..3dd583f0 100644 --- a/src/prime-preset/tokens/components/select.ts +++ b/src/prime-preset/tokens/components/select.ts @@ -6,8 +6,8 @@ export const selectCss = ({ dt }: { dt: (token: string) => string }): string => line-height: ${dt('fonts.lineHeight.250')}; } - .p-select.p-component .p-select-label.p-placeholder { - font-family: ${dt('fonts.fontFamily.base')}; + .p-select.p-component .p-select-label { + font-family: ${dt('fonts.fontFamily.base')}; } /* ─── Focus ─── */ From ed958e1b53578f2b6e118057a01101ef0ad178d4 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 22:37:35 +0700 Subject: [PATCH 194/258] =?UTF-8?q?select:=20font-family=20=D1=82=D0=BE?= =?UTF-8?q?=D0=BA=D0=B5=D0=BD=20=D0=B4=D0=BB=D1=8F=20.p-select-option?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/select.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/prime-preset/tokens/components/select.ts b/src/prime-preset/tokens/components/select.ts index 3dd583f0..0c60380f 100644 --- a/src/prime-preset/tokens/components/select.ts +++ b/src/prime-preset/tokens/components/select.ts @@ -6,7 +6,8 @@ export const selectCss = ({ dt }: { dt: (token: string) => string }): string => line-height: ${dt('fonts.lineHeight.250')}; } - .p-select.p-component .p-select-label { + .p-select.p-component .p-select-label, + .p-select-option { font-family: ${dt('fonts.fontFamily.base')}; } From ed2983d5cce3aec702134ad9f62a84fac9c81621 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 23 Apr 2026 22:42:36 +0700 Subject: [PATCH 195/258] =?UTF-8?q?inputtext,=20textarea,=20inputnumber:?= =?UTF-8?q?=20font-family=20=D1=82=D0=BE=D0=BA=D0=B5=D0=BD=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=BF=D0=BE=D0=BB=D0=B5=D0=B9,=20placeholder=20=D0=B8?= =?UTF-8?q?=20floatlabel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/inputnumber.ts | 13 +++++++++++++ src/prime-preset/tokens/components/inputtext.ts | 9 +++++++++ src/prime-preset/tokens/components/textarea.ts | 9 +++++++++ 3 files changed, 31 insertions(+) diff --git a/src/prime-preset/tokens/components/inputnumber.ts b/src/prime-preset/tokens/components/inputnumber.ts index ee036c31..950a3c1c 100644 --- a/src/prime-preset/tokens/components/inputnumber.ts +++ b/src/prime-preset/tokens/components/inputnumber.ts @@ -1,5 +1,18 @@ export const inputnumberCss = ({ dt }: { dt: (token: string) => string }): string => ` +/* ─── Базовые стили ─── */ +.p-inputnumber .p-inputnumber-input { + font-family: ${dt('fonts.fontFamily.base')}; +} + +.p-inputnumber .p-inputnumber-input::placeholder { + font-family: ${dt('fonts.fontFamily.base')}; +} + +.p-floatlabel:has(.p-inputnumber) label { + font-family: ${dt('fonts.fontFamily.base')}; +} + /* ─── Кнопки увеличения/уменьшения ─── */ .p-inputnumber-button { border-width: ${dt('inputnumber.extend.borderWidth')}; diff --git a/src/prime-preset/tokens/components/inputtext.ts b/src/prime-preset/tokens/components/inputtext.ts index 027ae6cc..25541c20 100644 --- a/src/prime-preset/tokens/components/inputtext.ts +++ b/src/prime-preset/tokens/components/inputtext.ts @@ -4,6 +4,15 @@ export const inputtextCss = ({ dt }: { dt: (token: string) => string }): string .p-inputtext { border-width: ${dt('inputtext.extend.borderWidth')}; line-height: ${dt('fonts.lineHeight.250')}; + font-family: ${dt('fonts.fontFamily.base')}; +} + +.p-inputtext::placeholder { + font-family: ${dt('fonts.fontFamily.base')}; +} + +.p-floatlabel:has(.p-inputtext) label { + font-family: ${dt('fonts.fontFamily.base')}; } /* ─── Disabled ─── */ diff --git a/src/prime-preset/tokens/components/textarea.ts b/src/prime-preset/tokens/components/textarea.ts index 4619309c..263e6886 100644 --- a/src/prime-preset/tokens/components/textarea.ts +++ b/src/prime-preset/tokens/components/textarea.ts @@ -5,6 +5,15 @@ export const textareaCss = ({ dt }: { dt: (token: string) => string }): string = border-width: ${dt('textarea.extend.borderWidth')}; line-height: ${dt('fonts.lineHeight.250')}; min-height: ${dt('textarea.extend.minHeight')}; + font-family: ${dt('fonts.fontFamily.base')}; +} + +.p-textarea::placeholder { + font-family: ${dt('fonts.fontFamily.base')}; +} + +.p-floatlabel:has(.p-textarea) label { + font-family: ${dt('fonts.fontFamily.base')}; } /* --- Sizes --- */ From 47099dd61901468ea3eff91428eb3d6073082f70 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Fri, 24 Apr 2026 14:11:14 +0700 Subject: [PATCH 196/258] listbox: OnPush strategy, protected modelValue --- src/lib/components/listbox/listbox.component.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/components/listbox/listbox.component.ts b/src/lib/components/listbox/listbox.component.ts index 7bbf753a..2bfc135b 100644 --- a/src/lib/components/listbox/listbox.component.ts +++ b/src/lib/components/listbox/listbox.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, Output, forwardRef } from '@angular/core'; +import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, forwardRef } from '@angular/core'; import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Listbox, ListboxChangeEvent } from 'primeng/listbox'; @@ -6,6 +6,7 @@ import { Listbox, ListboxChangeEvent } from 'primeng/listbox'; selector: 'listbox', standalone: true, imports: [Listbox, FormsModule], + changeDetection: ChangeDetectionStrategy.OnPush, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ListboxComponent), multi: true }, ], @@ -48,7 +49,7 @@ export class ListboxComponent implements ControlValueAccessor { @Output() onFocus = new EventEmitter(); @Output() onBlur = new EventEmitter(); - modelValue: any = null; + protected modelValue: any = null; private _disabled = false; private _onChange: (value: any) => void = () => {}; From 151c768931037f4a5de3a7ff49885eef0f7dbf32 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Fri, 24 Apr 2026 17:09:10 +0700 Subject: [PATCH 197/258] =?UTF-8?q?select:=20=D0=B7=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=91=D0=BD=20dropdownIcon=20=D0=BD=D0=B0=20checkmark?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/select/select.component.ts | 4 +- .../select-dropdown-icon.component.ts | 106 ------------------ .../components/select/select.stories.ts | 20 ++-- 3 files changed, 15 insertions(+), 115 deletions(-) delete mode 100644 src/stories/components/select/examples/select-dropdown-icon.component.ts diff --git a/src/lib/components/select/select.component.ts b/src/lib/components/select/select.component.ts index fba71396..97e798e8 100644 --- a/src/lib/components/select/select.component.ts +++ b/src/lib/components/select/select.component.ts @@ -51,7 +51,7 @@ export type SelectSize = 'small' | 'base' | 'large' | 'xlarge'; [inputId]="inputId" [appendTo]="appendTo" [size]="primeSize" - [dropdownIcon]="dropdownIcon" + [checkmark]="checkmark" [emptyMessage]="emptyMessage" [emptyFilterMessage]="emptyFilterMessage" (onChange)="onSelectChange($event)" @@ -107,7 +107,7 @@ export class SelectComponent implements ControlValueAccessor, OnInit { @Input() appendTo: any = 'body'; @Input() floatLabel = false; @Input() label = ''; - @Input() dropdownIcon: string | undefined; + @Input() checkmark = true; @Input() emptyMessage = 'Нет данных'; @Input() emptyFilterMessage = 'Результаты не найдены'; @Input() optionTemplate: TemplateRef | null = null; diff --git a/src/stories/components/select/examples/select-dropdown-icon.component.ts b/src/stories/components/select/examples/select-dropdown-icon.component.ts deleted file mode 100644 index 374db3ad..00000000 --- a/src/stories/components/select/examples/select-dropdown-icon.component.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; - -const OPTIONS = [ - { name: 'Новосибирск', code: 'NSK' }, - { name: 'Москва', code: 'MSK' }, - { name: 'Санкт-Петербург', code: 'SPB' }, - { name: 'Екатеринбург', code: 'EKB' }, -]; - -const template = ` - -`; -const styles = ''; - -@Component({ - selector: 'app-select-dropdown-icon', - standalone: true, - imports: [SelectComponent, ReactiveFormsModule], - template, - styles, -}) -export class SelectDropdownIconComponent { - @Input() size: SelectSize = 'base'; - @Input() showClear = false; - @Input() readonly = false; - @Input() dropdownIcon = 'ti ti-search'; - control = new FormControl(null); - options = OPTIONS; - - @Input() set disabled(val: boolean) { - val ? this.control.disable() : this.control.enable(); - } - - @Input() set invalid(val: boolean) { - this.control.setValidators(val ? [Validators.required] : []); - this.control.updateValueAndValidity(); - if (val) this.control.markAsTouched(); - } -} - -export const DropdownIcon = { - render: (args: any) => ({ - props: { size: args['size'], showClear: args['showClear'], dropdownIcon: args['dropdownIcon'], readonly: args['readonly'], disabled: args['disabled'], invalid: args['invalid'] }, - template: ``, - }), - args: { - dropdownIcon: 'ti ti-search', - }, - argTypes: { - dropdownIcon: { - control: 'text' as const, - description: 'CSS-класс иконки для выпадающего списка', - table: { - category: 'Props', - defaultValue: { summary: 'undefined' }, - type: { summary: 'string' }, - }, - }, - }, - parameters: { - docs: { - description: { story: 'Кастомная иконка раскрытия списка через пропс `dropdownIcon`.' }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { SelectComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - standalone: true, - imports: [SelectComponent, ReactiveFormsModule], - template: \` - - \`, -}) -export class SelectDropdownIconExample { - control = new FormControl(null); - options = [ - { name: 'Новосибирск', code: 'NSK' }, - { name: 'Москва', code: 'MSK' }, - { name: 'Санкт-Петербург', code: 'SPB' }, - ]; -} - `, - }, - }, - }, -}; diff --git a/src/stories/components/select/select.stories.ts b/src/stories/components/select/select.stories.ts index 30f07695..bec20cc5 100644 --- a/src/stories/components/select/select.stories.ts +++ b/src/stories/components/select/select.stories.ts @@ -7,7 +7,7 @@ import { SelectCustomComponent, Custom as CustomStory } from './examples/select- import { SelectEditableComponent, Editable as EditableStory } from './examples/select-editable.component'; import { Disabled as DisabledStory } from './examples/select-disabled.component'; import { SelectFloatLabelComponent, FloatLabelStory } from './examples/select-float-label.component'; -import { SelectDropdownIconComponent, DropdownIcon as DropdownIconStory } from './examples/select-dropdown-icon.component'; + const BASIC_OPTIONS = [ { name: 'Новосибирск', code: 'NSK' }, @@ -17,7 +17,7 @@ const BASIC_OPTIONS = [ { name: 'Казань', code: 'KZN' }, ]; -type SelectArgs = Pick & { +type SelectArgs = Pick & { disabled: boolean; invalid: boolean; }; @@ -36,7 +36,6 @@ const meta: Meta = { SelectCustomComponent, SelectEditableComponent, SelectFloatLabelComponent, - SelectDropdownIconComponent, ], }), ], @@ -99,6 +98,15 @@ import { SelectComponent } from '@cdek-it/angular-ui-kit'; type: { summary: 'boolean' }, }, }, + checkmark: { + control: 'boolean', + description: 'Отображает иконку выбранного элемента в списке', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, disabled: { control: 'boolean', description: 'Отключает взаимодействие — управляется через FormControl', @@ -124,6 +132,7 @@ import { SelectComponent } from '@cdek-it/angular-ui-kit'; showClear: true, filter: false, readonly: false, + checkmark: true, disabled: false, invalid: false, }, @@ -155,6 +164,7 @@ export const Default: Story = { [showClear]="showClear" [filter]="filter" [readonly]="readonly" + [checkmark]="checkmark" > `, }; @@ -188,10 +198,6 @@ export const Editable: Story = EditableStory; export const Disabled: Story = DisabledStory; -// ── DropdownIcon ───────────────────────────────────────────────────────────── - -export const DropdownIcon: Story = DropdownIconStory; - // ── FloatLabel ──────────────────────────────────────────────────────────────── export const FloatLabel: Story = FloatLabelStory; From 7212b8bad955a1f7a710be7859c4a04649354296 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Sun, 26 Apr 2026 15:04:17 +0700 Subject: [PATCH 198/258] DS-559 --- .github/workflows/npm-publish.yml | 15 +- .storybook/preview.ts | 2 +- .storybook/tsconfig.json | 4 +- angular.json | 50 ++-- package-lock.json | 246 +++++++++++++++++- package.json | 5 +- scripts/prepare-theme.js | 0 src/app/app.config.ts | 2 +- src/app/provide-my-feature.ts | 0 src/lib/components/avatar/avatar.component.ts | 8 +- src/lib/components/avatar/ng-package.json | 6 + src/lib/components/avatar/public_api.ts | 1 + src/lib/components/badge/badge.component.ts | 4 +- src/lib/components/badge/ng-package.json | 7 + src/lib/components/badge/public_api.ts | 3 + .../breadcrumb/breadcrumb.component.ts | 4 +- src/lib/components/breadcrumb/ng-package.json | 7 + src/lib/components/breadcrumb/public_api.ts | 4 + src/lib/components/button/button.component.ts | 4 +- src/lib/components/button/ng-package.json | 7 + src/lib/components/button/public_api.ts | 4 + src/lib/components/card/card.component.ts | 4 +- src/lib/components/card/ng-package.json | 7 + src/lib/components/card/public_api.ts | 4 + .../components/checkbox/checkbox.component.ts | 16 +- src/lib/components/checkbox/ng-package.json | 7 + src/lib/components/checkbox/public_api.ts | 4 + src/lib/components/chip/chip.component.ts | 4 +- src/lib/components/chip/ng-package.json | 7 + src/lib/components/chip/public_api.ts | 4 + .../components/dialog/dialog-open.service.ts | 6 +- src/lib/components/dialog/dialog.component.ts | 4 +- src/lib/components/dialog/ng-package.json | 7 + src/lib/components/dialog/public_api.ts | 5 + .../components/divider/divider.component.ts | 4 +- src/lib/components/divider/ng-package.json | 7 + src/lib/components/divider/public_api.ts | 4 + .../inputtext/inputtext.component.ts | 14 +- src/lib/components/inputtext/ng-package.json | 7 + src/lib/components/inputtext/public_api.ts | 4 + .../components/megamenu/megamenu.component.ts | 4 +- src/lib/components/megamenu/ng-package.json | 7 + src/lib/components/megamenu/public_api.ts | 4 + .../metergroup/metergroup.component.ts | 4 +- src/lib/components/metergroup/ng-package.json | 7 + src/lib/components/metergroup/public_api.ts | 4 + .../components/progressbar/ng-package.json | 7 + .../progressbar/progressbar.component.ts | 4 +- src/lib/components/progressbar/public_api.ts | 2 + .../progressspinner/ng-package.json | 7 + .../progressspinner.component.ts | 4 +- .../components/progressspinner/public_api.ts | 4 + .../components/radiobutton/ng-package.json | 7 + src/lib/components/radiobutton/public_api.ts | 4 + .../radiobutton/radiobutton.component.ts | 8 +- src/lib/components/rating/ng-package.json | 7 + src/lib/components/rating/public_api.ts | 4 + src/lib/components/rating/rating.component.ts | 6 +- src/lib/components/skeleton/ng-package.json | 7 + src/lib/components/skeleton/public_api.ts | 4 + .../components/skeleton/skeleton.component.ts | 4 +- src/lib/components/slider/ng-package.json | 7 + src/lib/components/slider/public_api.ts | 4 + src/lib/components/slider/slider.component.ts | 6 +- src/lib/components/tag/ng-package.json | 7 + src/lib/components/tag/public_api.ts | 4 + src/lib/components/tag/tag.component.ts | 4 +- src/lib/components/tieredmenu/ng-package.json | 7 + src/lib/components/tieredmenu/public_api.ts | 4 + .../tieredmenu/tieredmenu.component.ts | 4 +- src/lib/components/timeline/ng-package.json | 7 + src/lib/components/timeline/public_api.ts | 4 + .../components/timeline/timeline.component.ts | 4 +- src/lib/components/tooltip/ng-package.json | 7 + src/lib/components/tooltip/public_api.ts | 4 + .../components/tooltip/tooltip.directive.ts | 4 +- src/lib/ng-package.json | 13 + src/lib/package.json | 13 + src/lib/providers/ng-package.json | 7 + .../providers}/prime-preset/map-tokens.ts | 3 +- .../providers}/prime-preset/theme.preset.ts | 0 .../prime-preset/tokens/components/avatar.ts | 0 .../prime-preset/tokens/components/badge.ts | 0 .../tokens/components/breadcrumb.ts | 0 .../prime-preset/tokens/components/button.ts | 0 .../prime-preset/tokens/components/card.ts | 0 .../tokens/components/checkbox.ts | 0 .../prime-preset/tokens/components/chip.ts | 0 .../prime-preset/tokens/components/dialog.ts | 0 .../prime-preset/tokens/components/divider.ts | 0 .../tokens/components/inputtext.ts | 0 .../tokens/components/megamenu.ts | 0 .../tokens/components/metergroup.ts | 0 .../tokens/components/progressbar.ts | 0 .../tokens/components/progressspinner.ts | 0 .../tokens/components/radiobutton.ts | 0 .../tokens/components/skeleton.ts | 0 .../prime-preset/tokens/components/slider.ts | 0 .../prime-preset/tokens/components/tag.ts | 0 .../tokens/components/tieredmenu.ts | 0 .../tokens/components/timeline.ts | 0 .../prime-preset/tokens/components/tooltip.ts | 0 .../prime-preset/tokens/tokens.json | 0 src/lib/providers/public_api.ts | 4 + src/lib/providers/theme-preset.ts | 17 ++ src/lib/public_api.ts | 1 + src/lib/tsconfig.lib.json | 31 +++ src/lib/tsconfig.lib.prod.json | 10 + src/lib/tsconfig.spec.json | 14 + .../components/avatar/avatar.stories.ts | 68 ++--- .../avatar/examples/avatar-group.component.ts | 36 +-- .../examples/avatar-icon-badge.component.ts | 16 +- .../avatar/examples/avatar-icon.component.ts | 20 +- .../examples/avatar-image-badge.component.ts | 24 +- .../avatar/examples/avatar-image.component.ts | 20 +- .../examples/avatar-label-badge.component.ts | 24 +- .../avatar/examples/avatar-label.component.ts | 20 +- .../examples/avatar-shapes.component.ts | 16 +- .../avatar/examples/avatar-sizes.component.ts | 20 +- src/stories/components/badge/badge.stories.ts | 10 +- .../badge/examples/badge-dot.component.ts | 8 +- .../examples/badge-severity.component.ts | 8 +- .../badge/examples/badge-sizes.component.ts | 8 +- .../breadcrumb/breadcrumb.stories.ts | 4 +- .../examples/breadcrumb-basic.component.ts | 10 +- .../breadcrumb-icons-only.component.ts | 10 +- .../components/button/button.stories.ts | 36 +-- src/stories/components/card/card.stories.ts | 183 ++++++------- .../card/examples/card-overlay.component.ts | 16 +- .../examples/card-without-footer.component.ts | 14 +- .../examples/card-without-header.component.ts | 16 +- .../card-without-subtitle.component.ts | 16 +- .../components/checkbox/checkbox.stories.ts | 4 +- src/stories/components/chip/chip.stories.ts | 10 +- .../components/dialog/dialog.stories.ts | 56 ++-- .../examples/dialog-default.component.ts | 14 +- .../examples/dialog-dynamic.component.ts | 16 +- .../examples/dialog-extra-large.component.ts | 16 +- .../dialog/examples/dialog-large.component.ts | 14 +- .../examples/dialog-no-header.component.ts | 14 +- .../examples/dialog-no-modal.component.ts | 16 +- .../dialog/examples/dialog-small.component.ts | 14 +- .../components/divider/divider.stories.ts | 16 +- .../examples/divider-align-left.component.ts | 8 +- .../divider-with-content.component.ts | 16 +- .../examples/divider-with-icon.component.ts | 8 +- .../components/inputtext/inputtext.stories.ts | 4 +- .../examples/megamenu-custom.component.ts | 6 +- .../examples/megamenu-horizontal.component.ts | 6 +- .../examples/megamenu-vertical.component.ts | 6 +- .../components/megamenu/megamenu.stories.ts | 38 +-- .../examples/metergroup-basic.component.ts | 6 +- .../metergroup-horizontal.component.ts | 12 +- .../examples/metergroup-icon.component.ts | 12 +- .../metergroup-label-start.component.ts | 12 +- .../metergroup-label-vertical.component.ts | 12 +- .../examples/metergroup-vertical.component.ts | 12 +- .../metergroup/metergroup.stories.ts | 8 +- .../progressbar-indeterminate.component.ts | 6 +- .../progressbar-no-label.component.ts | 6 +- .../progressbar/progressbar.stories.ts | 30 +-- .../progressspinner-monochrome.component.ts | 12 +- .../progressspinner-sizes.component.ts | 12 +- .../progressspinner.stories.ts | 20 +- .../radiobutton/radiobutton.stories.ts | 4 +- .../components/skeleton/skeleton.stories.ts | 6 +- .../examples/slider-disabled.component.ts | 12 +- .../slider/examples/slider-range.component.ts | 12 +- .../slider/examples/slider-step.component.ts | 12 +- .../examples/slider-vertical.component.ts | 12 +- .../components/slider/slider.stories.ts | 8 +- .../tag/examples/tag-icon.component.ts | 12 +- .../tag/examples/tag-rounded.component.ts | 12 +- .../tag/examples/tag-severity.component.ts | 12 +- src/stories/components/tag/tag.stories.ts | 34 +-- .../examples/tieredmenu-basic.component.ts | 10 +- .../examples/tieredmenu-selected.component.ts | 10 +- .../tieredmenu/tieredmenu.stories.ts | 6 +- .../components/timeline/timeline.stories.ts | 12 +- .../components/tooltip/tooltip.stories.ts | 25 +- 180 files changed, 1315 insertions(+), 730 deletions(-) create mode 100644 scripts/prepare-theme.js create mode 100644 src/app/provide-my-feature.ts create mode 100644 src/lib/components/avatar/ng-package.json create mode 100644 src/lib/components/avatar/public_api.ts create mode 100644 src/lib/components/badge/ng-package.json create mode 100644 src/lib/components/badge/public_api.ts create mode 100644 src/lib/components/breadcrumb/ng-package.json create mode 100644 src/lib/components/breadcrumb/public_api.ts create mode 100644 src/lib/components/button/ng-package.json create mode 100644 src/lib/components/button/public_api.ts create mode 100644 src/lib/components/card/ng-package.json create mode 100644 src/lib/components/card/public_api.ts create mode 100644 src/lib/components/checkbox/ng-package.json create mode 100644 src/lib/components/checkbox/public_api.ts create mode 100644 src/lib/components/chip/ng-package.json create mode 100644 src/lib/components/chip/public_api.ts create mode 100644 src/lib/components/dialog/ng-package.json create mode 100644 src/lib/components/dialog/public_api.ts create mode 100644 src/lib/components/divider/ng-package.json create mode 100644 src/lib/components/divider/public_api.ts create mode 100644 src/lib/components/inputtext/ng-package.json create mode 100644 src/lib/components/inputtext/public_api.ts create mode 100644 src/lib/components/megamenu/ng-package.json create mode 100644 src/lib/components/megamenu/public_api.ts create mode 100644 src/lib/components/metergroup/ng-package.json create mode 100644 src/lib/components/metergroup/public_api.ts create mode 100644 src/lib/components/progressbar/ng-package.json create mode 100644 src/lib/components/progressbar/public_api.ts create mode 100644 src/lib/components/progressspinner/ng-package.json create mode 100644 src/lib/components/progressspinner/public_api.ts create mode 100644 src/lib/components/radiobutton/ng-package.json create mode 100644 src/lib/components/radiobutton/public_api.ts create mode 100644 src/lib/components/rating/ng-package.json create mode 100644 src/lib/components/rating/public_api.ts create mode 100644 src/lib/components/skeleton/ng-package.json create mode 100644 src/lib/components/skeleton/public_api.ts create mode 100644 src/lib/components/slider/ng-package.json create mode 100644 src/lib/components/slider/public_api.ts create mode 100644 src/lib/components/tag/ng-package.json create mode 100644 src/lib/components/tag/public_api.ts create mode 100644 src/lib/components/tieredmenu/ng-package.json create mode 100644 src/lib/components/tieredmenu/public_api.ts create mode 100644 src/lib/components/timeline/ng-package.json create mode 100644 src/lib/components/timeline/public_api.ts create mode 100644 src/lib/components/tooltip/ng-package.json create mode 100644 src/lib/components/tooltip/public_api.ts create mode 100644 src/lib/ng-package.json create mode 100644 src/lib/package.json create mode 100644 src/lib/providers/ng-package.json rename src/{ => lib/providers}/prime-preset/map-tokens.ts (93%) rename src/{ => lib/providers}/prime-preset/theme.preset.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/avatar.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/badge.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/breadcrumb.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/button.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/card.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/checkbox.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/chip.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/dialog.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/divider.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/inputtext.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/megamenu.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/metergroup.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/progressbar.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/progressspinner.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/radiobutton.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/skeleton.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/slider.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/tag.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/tieredmenu.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/timeline.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/components/tooltip.ts (100%) rename src/{ => lib/providers}/prime-preset/tokens/tokens.json (100%) create mode 100644 src/lib/providers/public_api.ts create mode 100644 src/lib/providers/theme-preset.ts create mode 100644 src/lib/public_api.ts create mode 100644 src/lib/tsconfig.lib.json create mode 100644 src/lib/tsconfig.lib.prod.json create mode 100644 src/lib/tsconfig.spec.json diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index e3545785..d11dfef2 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -6,22 +6,31 @@ on: permissions: id-token: write - contents: read + contents: write jobs: publish-npm: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - uses: actions/setup-node@v4 with: node-version: 20 registry-url: https://registry.npmjs.org/ - name: Update npm run: npm install -g npm@latest - - run: npm ci --production + - run: npm ci - uses: reedyuk/npm-version@1.1.1 with: version: ${{github.ref_name}} - - run: npm run copy:dist + - name: Sync src/lib/package.json version with root package.json + run: | + node -e "const fs=require('fs'); const path='src/lib/package.json'; const root=JSON.parse(fs.readFileSync('package.json')); const lib=JSON.parse(fs.readFileSync(path)); if(lib.version===root.version){console.log('Already up-to-date'); process.exit(0);} lib.version=root.version; fs.writeFileSync(path, JSON.stringify(lib,null,2)+'\n'); console.log('Updated',path,'to',root.version);" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add src/lib/package.json + if git diff --cached --quiet; then echo "No changes to commit"; else git commit -m "chore(release): sync src/lib package version to ${{github.ref_name}}" && git push origin HEAD:refs/heads/${{ github.event.release.target_commitish }}; fi + - run: npm run build:lib - run: npm publish diff --git a/.storybook/preview.ts b/.storybook/preview.ts index c1a7382e..b5b8be0c 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -5,7 +5,7 @@ import docJson from '../documentation.json'; import { providePrimeNG } from 'primeng/config'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; -import Preset from '../src/prime-preset/theme.preset'; +import Preset from '../src/lib/providers/prime-preset/theme.preset'; import '!style-loader!css-loader!postcss-loader!sass-loader!../src/styles.scss'; diff --git a/.storybook/tsconfig.json b/.storybook/tsconfig.json index 507a7145..664578be 100644 --- a/.storybook/tsconfig.json +++ b/.storybook/tsconfig.json @@ -5,6 +5,8 @@ "allowSyntheticDefaultImports": true, "resolveJsonModule": true }, - "include": ["../src/stories/**/*.stories.*", "./preview.ts", "../src/prime-preset/**/*"], + "include": ["../src/stories/**/*.stories.*", "./preview.ts", + "../src/lib/providers/prime-preset/**/*" + ], "files": ["./typings.d.ts"] } diff --git a/angular.json b/angular.json index 15527515..8e1cf2a9 100644 --- a/angular.json +++ b/angular.json @@ -26,9 +26,7 @@ "input": "public" } ], - "styles": [ - "src/styles.scss" - ] + "styles": ["src/styles.scss"] }, "configurations": { "production": { @@ -80,9 +78,7 @@ "input": "public" } ], - "styles": [ - "src/styles.scss" - ] + "styles": ["src/styles.scss"] } }, "storybook": { @@ -91,12 +87,7 @@ "configDir": ".storybook", "browserTarget": "angular-ui-kit:build", "compodoc": true, - "compodocArgs": [ - "-e", - "json", - "-d", - "." - ], + "compodocArgs": ["-e", "json", "-d", "."], "port": 6006 } }, @@ -106,19 +97,40 @@ "configDir": ".storybook", "browserTarget": "angular-ui-kit:build", "compodoc": true, - "compodocArgs": [ - "-e", - "json", - "-d", - "." - ], + "compodocArgs": ["-e", "json", "-d", "."], "outputDir": "storybook-static" } } } + }, + "angular-ui-kit-lib": { + "projectType": "library", + "root": "src", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "src/lib/ng-package.json", + "tsConfig": "src/lib/tsconfig.lib.prod.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "tsConfig": "src/lib/tsconfig.spec.json", + "polyfills": ["zone.js", "zone.js/testing"] + } + }, + "lint": { + "builder": "@angular-eslint/builder:lint", + "options": { + "lintFilePatterns": ["src/lib/**/*.ts", "src/lib/**/*.html"] + } + } + } } }, "cli": { "analytics": false } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 9fd05aaf..5fe8bcf3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,6 +51,7 @@ "karma-coverage": "2.2.1", "karma-jasmine": "5.1.0", "karma-jasmine-html-reporter": "2.1.0", + "ng-packagr": "20.3.2", "prettier": "3.7.4", "primeng": "20.4.0", "rxjs": "7.8.2", @@ -1122,13 +1123,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -6184,6 +6185,57 @@ "node": ">=12.11.0" } }, + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.52.3", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.3.tgz", @@ -6492,6 +6544,26 @@ "win32" ] }, + "node_modules/@rollup/wasm-node": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/wasm-node/-/wasm-node-4.60.2.tgz", + "integrity": "sha512-FOfZOg752WSyKNefpSM3WrhggSTSuKuwcSfF7tdWC9PBYYg7BLwBR267uShFAI1ZyA0gNkdqK16LL9mNOPsQ1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -10091,6 +10163,13 @@ "node": ">= 12.0.0" } }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true, + "license": "ISC" + }, "node_modules/component-emitter": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-2.0.0.tgz", @@ -11265,6 +11344,16 @@ "node": ">= 0.8" } }, + "node_modules/dependency-graph": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz", + "integrity": "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -13127,6 +13216,23 @@ "node": ">= 0.6" } }, + "node_modules/find-cache-directory": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/find-cache-directory/-/find-cache-directory-6.0.0.tgz", + "integrity": "sha512-CvFd5ivA6HcSHbD+59P7CyzINHXzwhuQK8RY7CxJZtgDSAtRlHiCaQpZQ2lMR/WRyUIEmzUvL6G2AGurMfegZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^8.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/find-index": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", @@ -13150,6 +13256,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -14640,6 +14759,16 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/injection-js": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/injection-js/-/injection-js-2.6.1.tgz", + "integrity": "sha512-dbR5bdhi7TWDoCye9cByZqeg/gAfamm8Vu3G1KZOTYkOif8WkuM8CD0oeDPtZYMzT5YH76JAFB7bkmyY9OJi2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + } + }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -17647,6 +17776,56 @@ "node": ">= 10" } }, + "node_modules/ng-packagr": { + "version": "20.3.2", + "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-20.3.2.tgz", + "integrity": "sha512-yW5ME0hqTz38r/th/7zVwX5oSIw1FviSA2PUlGZdVjghDme/KX6iiwmOBmlt9E9whNmwijEC6Gn3KKbrsBx8ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@rollup/plugin-json": "^6.1.0", + "@rollup/wasm-node": "^4.24.0", + "ajv": "^8.17.1", + "ansi-colors": "^4.1.3", + "browserslist": "^4.22.1", + "chokidar": "^4.0.1", + "commander": "^14.0.0", + "dependency-graph": "^1.0.0", + "esbuild": "^0.25.0", + "find-cache-directory": "^6.0.0", + "injection-js": "^2.4.0", + "jsonc-parser": "^3.3.1", + "less": "^4.2.0", + "ora": "^8.2.0", + "piscina": "^5.0.0", + "postcss": "^8.4.47", + "rollup-plugin-dts": "^6.2.0", + "rxjs": "^7.8.1", + "sass": "^1.81.0", + "tinyglobby": "^0.2.12" + }, + "bin": { + "ng-packagr": "src/cli/main.js" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "optionalDependencies": { + "rollup": "^4.24.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^20.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "tslib": "^2.3.0", + "typescript": ">=5.8 <6.0" + }, + "peerDependenciesMeta": { + "tailwindcss": { + "optional": true + } + } + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -19101,6 +19280,22 @@ "node": ">=16.20.0" } }, + "node_modules/pkg-dir": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-8.0.0.tgz", + "integrity": "sha512-4peoBq4Wks0riS0z8741NVv+/8IiTvqnZAr8QGgtdifrtpdXbNw/FxRS1l6NFqm4EMzuS0EDqNNx4XGaz8cuyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/polka": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/polka/-/polka-0.5.2.tgz", @@ -20395,6 +20590,49 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup-plugin-dts": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-6.4.1.tgz", + "integrity": "sha512-l//F3Zf7ID5GoOfLfD8kroBjQKEKpy1qfhtAdnpibFZMffPaylrg1CoDC2vGkPeTeyxUe4bVFCln2EFuL7IGGg==", + "dev": true, + "license": "LGPL-3.0-only", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "@jridgewell/sourcemap-codec": "^1.5.5", + "convert-source-map": "^2.0.0", + "magic-string": "^0.30.21" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/Swatinem" + }, + "optionalDependencies": { + "@babel/code-frame": "^7.29.0" + }, + "peerDependencies": { + "rollup": "^3.29.4 || ^4", + "typescript": "^4.5 || ^5.0 || ^6.0" + } + }, + "node_modules/rollup-plugin-dts/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup-plugin-dts/node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", diff --git a/package.json b/package.json index d98f557d..8fa837c7 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,9 @@ "format:check": "prettier --check \"**/*.{js,ts,d.ts}\"", "build:check": "npm run format:check && npm run security:check", "build:storybook": "ng run angular-ui-kit:build-storybook", + "build:lib": "ng build angular-ui-kit-lib", "security:check": "npm audit --production --audit-level high", - "copy:dist": "cpx 'src/prime-preset/**/*.{json,ts}' dist/ && cpx 'src-tokens/theme.preset.ts' dist/" + "copy:dist": "cpx 'src/lib/providers/prime-preset/**/*.{json,ts}' dist/ && cpx 'src-tokens/theme.preset.ts' dist/" }, "repository": "github:cdek-it/angular-ui-kit", "devDependencies": { @@ -63,6 +64,8 @@ "karma-chrome-launcher": "3.2.0", "karma-coverage": "2.2.1", "karma-jasmine": "5.1.0", + "ng-packagr": "20.3.2", + "@primeuix/themes": "1.2.5", "karma-jasmine-html-reporter": "2.1.0", "prettier": "3.7.4", "primeng": "20.4.0", diff --git a/scripts/prepare-theme.js b/scripts/prepare-theme.js new file mode 100644 index 00000000..e69de29b diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 6bdbf574..95ad618d 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -3,7 +3,7 @@ import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; import { providePrimeNG } from 'primeng/config'; -import Preset from '../prime-preset/theme.preset'; +import Preset from '../lib/providers/prime-preset/theme.preset'; export const appConfig: ApplicationConfig = { providers: [ diff --git a/src/app/provide-my-feature.ts b/src/app/provide-my-feature.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/components/avatar/avatar.component.ts b/src/lib/components/avatar/avatar.component.ts index de933fd7..6abed91d 100644 --- a/src/lib/components/avatar/avatar.component.ts +++ b/src/lib/components/avatar/avatar.component.ts @@ -6,7 +6,7 @@ export type AvatarSize = 'normal' | 'large' | 'xlarge'; export type AvatarShape = 'square' | 'circle'; @Component({ - selector: 'avatar', + selector: 'extra-avatar', standalone: true, imports: [Avatar], template: ` @@ -19,7 +19,7 @@ export type AvatarShape = 'square' | 'circle'; > `, }) -export class AvatarComponent { +export class ExtraAvatarComponent { @Input() label = ''; @Input() icon = ''; @Input() image = ''; @@ -39,7 +39,7 @@ export class AvatarComponent { } @Component({ - selector: 'avatar-group', + selector: 'extra-avatar-group', standalone: true, imports: [AvatarGroup], template: ` @@ -48,4 +48,4 @@ export class AvatarComponent { `, }) -export class AvatarGroupComponent { } +export class ExtraAvatarGroupComponent { } diff --git a/src/lib/components/avatar/ng-package.json b/src/lib/components/avatar/ng-package.json new file mode 100644 index 00000000..3a74fd76 --- /dev/null +++ b/src/lib/components/avatar/ng-package.json @@ -0,0 +1,6 @@ +{ + "$schema": "ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public_api.ts" + } +} diff --git a/src/lib/components/avatar/public_api.ts b/src/lib/components/avatar/public_api.ts new file mode 100644 index 00000000..a1ddb6ff --- /dev/null +++ b/src/lib/components/avatar/public_api.ts @@ -0,0 +1 @@ +export * from './avatar.component'; diff --git a/src/lib/components/badge/badge.component.ts b/src/lib/components/badge/badge.component.ts index a5d5001e..2f6925d6 100644 --- a/src/lib/components/badge/badge.component.ts +++ b/src/lib/components/badge/badge.component.ts @@ -8,7 +8,7 @@ type PrimeBadgeSeverity = ReturnType; type PrimeBadgeSize = ReturnType; @Component({ - selector: 'badge', + selector: 'extra-badge', standalone: true, imports: [Badge], template: ` @@ -19,7 +19,7 @@ type PrimeBadgeSize = ReturnType; > ` }) -export class BadgeComponent { +export class ExtraBadgeComponent { @Input() value: string | number = ''; @Input() severity: BadgeSeverity = 'primary'; @Input() size: BadgeSize = 'base'; diff --git a/src/lib/components/badge/ng-package.json b/src/lib/components/badge/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/badge/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/badge/public_api.ts b/src/lib/components/badge/public_api.ts new file mode 100644 index 00000000..5f6ed3fe --- /dev/null +++ b/src/lib/components/badge/public_api.ts @@ -0,0 +1,3 @@ +export * from './badge.component'; + + diff --git a/src/lib/components/breadcrumb/breadcrumb.component.ts b/src/lib/components/breadcrumb/breadcrumb.component.ts index 740583cf..8b242e8e 100644 --- a/src/lib/components/breadcrumb/breadcrumb.component.ts +++ b/src/lib/components/breadcrumb/breadcrumb.component.ts @@ -3,7 +3,7 @@ import { Breadcrumb } from 'primeng/breadcrumb'; import { MenuItem } from 'primeng/api'; @Component({ - selector: 'breadcrumb', + selector: 'extra-breadcrumb', standalone: true, imports: [Breadcrumb], template: ` @@ -13,7 +13,7 @@ import { MenuItem } from 'primeng/api'; > `, }) -export class BreadcrumbComponent { +export class ExtraBreadcrumbComponent { @Input() model: MenuItem[] = []; @Input() home: MenuItem | undefined = undefined; } diff --git a/src/lib/components/breadcrumb/ng-package.json b/src/lib/components/breadcrumb/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/breadcrumb/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/breadcrumb/public_api.ts b/src/lib/components/breadcrumb/public_api.ts new file mode 100644 index 00000000..2def9761 --- /dev/null +++ b/src/lib/components/breadcrumb/public_api.ts @@ -0,0 +1,4 @@ +export * from './breadcrumb.component'; + + + diff --git a/src/lib/components/button/button.component.ts b/src/lib/components/button/button.component.ts index ab726609..47697892 100644 --- a/src/lib/components/button/button.component.ts +++ b/src/lib/components/button/button.component.ts @@ -9,7 +9,7 @@ export type BadgeSeverity = 'success' | 'info' | 'warning' | 'danger' | 'seconda type PrimeBadgeSeverity = Extract; @Component({ - selector: 'button', + selector: 'extra-button', standalone: true, imports: [Button], template: ` @@ -35,7 +35,7 @@ type PrimeBadgeSeverity = Extract; > ` }) -export class ButtonComponent { +export class ExtraButtonComponent { @Input() label = 'Button'; @Input() variant: ButtonVariant = 'primary'; @Input() severity: ButtonSeverity = null; diff --git a/src/lib/components/button/ng-package.json b/src/lib/components/button/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/button/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/button/public_api.ts b/src/lib/components/button/public_api.ts new file mode 100644 index 00000000..978e7b6f --- /dev/null +++ b/src/lib/components/button/public_api.ts @@ -0,0 +1,4 @@ +export * from './button.component'; + + + diff --git a/src/lib/components/card/card.component.ts b/src/lib/components/card/card.component.ts index e0354148..0979a4b2 100644 --- a/src/lib/components/card/card.component.ts +++ b/src/lib/components/card/card.component.ts @@ -11,7 +11,7 @@ import { Card } from 'primeng/card'; import { PrimeTemplate, SharedModule } from 'primeng/api'; @Component({ - selector: 'card', + selector: 'extra-card', host: { style: 'display: block' }, standalone: true, imports: [Card, SharedModule, NgTemplateOutlet], @@ -47,7 +47,7 @@ import { PrimeTemplate, SharedModule } from 'primeng/api'; `, }) -export class CardComponent implements AfterContentInit { +export class ExtraCardComponent implements AfterContentInit { @Input() title = ''; @Input() subtitle = ''; @Input() overlay = false; diff --git a/src/lib/components/card/ng-package.json b/src/lib/components/card/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/card/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/card/public_api.ts b/src/lib/components/card/public_api.ts new file mode 100644 index 00000000..af94fd1f --- /dev/null +++ b/src/lib/components/card/public_api.ts @@ -0,0 +1,4 @@ +export * from './card.component'; + + + diff --git a/src/lib/components/checkbox/checkbox.component.ts b/src/lib/components/checkbox/checkbox.component.ts index 8f0fc04a..52dd219c 100644 --- a/src/lib/components/checkbox/checkbox.component.ts +++ b/src/lib/components/checkbox/checkbox.component.ts @@ -1,20 +1,20 @@ import { Component, Input, Output, EventEmitter, forwardRef } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Checkbox, CheckboxChangeEvent } from 'primeng/checkbox'; export type CheckboxSize = 'small' | 'base' | 'large'; export type CheckboxVariant = 'outlined' | 'filled'; @Component({ - selector: 'checkbox', + selector: 'extra-checkbox', standalone: true, - imports: [Checkbox], + imports: [Checkbox, FormsModule], providers: [ { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => CheckboxComponent), - multi: true, - }, + useExisting: forwardRef(() => ExtraCheckboxComponent), + multi: true + } ], template: ` - `, + ` }) -export class CheckboxComponent implements ControlValueAccessor { +export class ExtraCheckboxComponent implements ControlValueAccessor { @Input() value: any = null; @Input() binary = false; @Input() disabled = false; diff --git a/src/lib/components/checkbox/ng-package.json b/src/lib/components/checkbox/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/checkbox/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/checkbox/public_api.ts b/src/lib/components/checkbox/public_api.ts new file mode 100644 index 00000000..ed763e4a --- /dev/null +++ b/src/lib/components/checkbox/public_api.ts @@ -0,0 +1,4 @@ +export * from './checkbox.component'; + + + diff --git a/src/lib/components/chip/chip.component.ts b/src/lib/components/chip/chip.component.ts index e8078d91..5c0ed938 100644 --- a/src/lib/components/chip/chip.component.ts +++ b/src/lib/components/chip/chip.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Chip } from 'primeng/chip'; @Component({ - selector: 'chip', + selector: 'extra-chip', standalone: true, imports: [Chip], template: ` @@ -15,7 +15,7 @@ import { Chip } from 'primeng/chip'; > `, }) -export class ChipComponent { +export class ExtraChipComponent { @Input() label = ''; @Input() icon = ''; @Input() removable = false; diff --git a/src/lib/components/chip/ng-package.json b/src/lib/components/chip/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/chip/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/chip/public_api.ts b/src/lib/components/chip/public_api.ts new file mode 100644 index 00000000..c4ac1a5b --- /dev/null +++ b/src/lib/components/chip/public_api.ts @@ -0,0 +1,4 @@ +export * from './chip.component'; + + + diff --git a/src/lib/components/dialog/dialog-open.service.ts b/src/lib/components/dialog/dialog-open.service.ts index 1a91bb96..3e36bc0d 100644 --- a/src/lib/components/dialog/dialog-open.service.ts +++ b/src/lib/components/dialog/dialog-open.service.ts @@ -2,7 +2,7 @@ import { Injectable, Injector, Type } from '@angular/core'; import { DialogService, DynamicDialogConfig, DynamicDialogRef } from 'primeng/dynamicdialog'; import { DialogSize } from './dialog.component'; -export type UiDynamicDialogConfig = Omit, 'styleClass'> & { +export type ExtraDynamicDialogConfig = Omit, 'styleClass'> & { size?: DialogSize; styleClass?: string; }; @@ -10,12 +10,12 @@ export type UiDynamicDialogConfig = Omit(componentType: Type, config: UiDynamicDialogConfig = {}): DynamicDialogRef | null { + open(componentType: Type, config: ExtraDynamicDialogConfig = {}): DynamicDialogRef | null { const { size, styleClass, ...rest } = config; const sizeClass = this.toSizeClass(size); const mergedStyleClass = [sizeClass, styleClass].filter(Boolean).join(' '); diff --git a/src/lib/components/dialog/dialog.component.ts b/src/lib/components/dialog/dialog.component.ts index 7a9ca1c1..17e498b9 100644 --- a/src/lib/components/dialog/dialog.component.ts +++ b/src/lib/components/dialog/dialog.component.ts @@ -6,7 +6,7 @@ import { PrimeTemplate } from 'primeng/api'; export type DialogSize = 'sm' | 'default' | 'lg' | 'xlg'; @Component({ - selector: 'dialog', + selector: 'extra-dialog', host: { style: 'display: contents' }, standalone: true, imports: [Dialog, NgTemplateOutlet, PrimeTemplate], @@ -37,7 +37,7 @@ export type DialogSize = 'sm' | 'default' | 'lg' | 'xlg'; `, }) -export class DialogComponent { +export class ExtraDialogComponent { @Input() header = ''; @Input() visible = false; @Input() modal = true; diff --git a/src/lib/components/dialog/ng-package.json b/src/lib/components/dialog/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/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/dialog/public_api.ts b/src/lib/components/dialog/public_api.ts new file mode 100644 index 00000000..49057693 --- /dev/null +++ b/src/lib/components/dialog/public_api.ts @@ -0,0 +1,5 @@ +export * from './dialog.component'; +export * from './dialog-open.service'; + + + diff --git a/src/lib/components/divider/divider.component.ts b/src/lib/components/divider/divider.component.ts index 20d634f5..28420442 100644 --- a/src/lib/components/divider/divider.component.ts +++ b/src/lib/components/divider/divider.component.ts @@ -6,7 +6,7 @@ export type DividerType = 'solid' | 'dashed' | 'dotted'; export type DividerAlign = 'left' | 'center' | 'right' | 'top' | 'bottom'; @Component({ - selector: 'divider', + selector: 'extra-divider', standalone: true, imports: [Divider], template: ` @@ -19,7 +19,7 @@ export type DividerAlign = 'left' | 'center' | 'right' | 'top' | 'bottom'; `, }) -export class DividerComponent { +export class ExtraDividerComponent { @Input() layout: DividerLayout = 'horizontal'; @Input() type: DividerType = 'solid'; @Input() align: DividerAlign = 'center'; diff --git a/src/lib/components/divider/ng-package.json b/src/lib/components/divider/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/divider/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/divider/public_api.ts b/src/lib/components/divider/public_api.ts new file mode 100644 index 00000000..3e85d710 --- /dev/null +++ b/src/lib/components/divider/public_api.ts @@ -0,0 +1,4 @@ +export * from './divider.component'; + + + diff --git a/src/lib/components/inputtext/inputtext.component.ts b/src/lib/components/inputtext/inputtext.component.ts index 3904b924..7bd73859 100644 --- a/src/lib/components/inputtext/inputtext.component.ts +++ b/src/lib/components/inputtext/inputtext.component.ts @@ -9,19 +9,19 @@ export type InputTextSize = 'small' | 'base' | 'large' | 'xlarge'; @Component({ - selector: 'input-text', + selector: 'extra-input-text', standalone: true, imports: [InputText, IconField, InputIcon, NgClass], providers: [ { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => InputTextComponent), - multi: true, - }, + useExisting: forwardRef(() => ExtraInputTextComponent), + multi: true + } ], template: ` @if (showClear) { - + } - `, + ` }) -export class InputTextComponent implements ControlValueAccessor, OnInit { +export class ExtraInputTextComponent implements ControlValueAccessor, OnInit { private readonly _injector = inject(Injector); private _ngControl: NgControl | null = null; diff --git a/src/lib/components/inputtext/ng-package.json b/src/lib/components/inputtext/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/inputtext/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/inputtext/public_api.ts b/src/lib/components/inputtext/public_api.ts new file mode 100644 index 00000000..52ee8fcb --- /dev/null +++ b/src/lib/components/inputtext/public_api.ts @@ -0,0 +1,4 @@ +export * from './inputtext.component'; + + + diff --git a/src/lib/components/megamenu/megamenu.component.ts b/src/lib/components/megamenu/megamenu.component.ts index 1a8e9b66..0a2d8947 100644 --- a/src/lib/components/megamenu/megamenu.component.ts +++ b/src/lib/components/megamenu/megamenu.component.ts @@ -13,7 +13,7 @@ export interface MegaMenuModel extends Omit { } @Component({ - selector: 'megamenu', + selector: 'extra-megamenu', host: { style: 'display: contents' }, standalone: true, imports: [MegaMenu, PrimeTemplate, NgTemplateOutlet, Badge], @@ -65,7 +65,7 @@ export interface MegaMenuModel extends Omit { `, }) -export class MegaMenuComponent { +export class ExtraMegaMenuComponent { @Input() model: MegaMenuModel[] = []; @Input() orientation: MegaMenuOrientation = 'horizontal'; @Input() breakpoint: string = '960px'; diff --git a/src/lib/components/megamenu/ng-package.json b/src/lib/components/megamenu/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/megamenu/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/megamenu/public_api.ts b/src/lib/components/megamenu/public_api.ts new file mode 100644 index 00000000..5f3522b1 --- /dev/null +++ b/src/lib/components/megamenu/public_api.ts @@ -0,0 +1,4 @@ +export * from './megamenu.component'; + + + diff --git a/src/lib/components/metergroup/metergroup.component.ts b/src/lib/components/metergroup/metergroup.component.ts index c0200df2..f19cd8e9 100644 --- a/src/lib/components/metergroup/metergroup.component.ts +++ b/src/lib/components/metergroup/metergroup.component.ts @@ -6,7 +6,7 @@ export type MeterGroupLabelPosition = 'start' | 'end'; export type MeterGroupLabelOrientation = 'horizontal' | 'vertical'; @Component({ - selector: 'metergroup', + selector: 'extra-metergroup', standalone: true, imports: [MeterGroup], template: ` @@ -18,7 +18,7 @@ export type MeterGroupLabelOrientation = 'horizontal' | 'vertical'; > `, }) -export class MeterGroupComponent { +export class ExtraMeterGroupComponent { @Input() value: MeterItem[] = []; @Input() orientation: MeterGroupOrientation = 'horizontal'; @Input() labelPosition: MeterGroupLabelPosition = 'end'; diff --git a/src/lib/components/metergroup/ng-package.json b/src/lib/components/metergroup/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/metergroup/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/metergroup/public_api.ts b/src/lib/components/metergroup/public_api.ts new file mode 100644 index 00000000..810d4058 --- /dev/null +++ b/src/lib/components/metergroup/public_api.ts @@ -0,0 +1,4 @@ +export * from './metergroup.component'; + + + diff --git a/src/lib/components/progressbar/ng-package.json b/src/lib/components/progressbar/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/progressbar/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/progressbar/progressbar.component.ts b/src/lib/components/progressbar/progressbar.component.ts index 641b117b..bbd0dc04 100644 --- a/src/lib/components/progressbar/progressbar.component.ts +++ b/src/lib/components/progressbar/progressbar.component.ts @@ -4,7 +4,7 @@ import { ProgressBar } from 'primeng/progressbar'; export type ProgressBarMode = 'determinate' | 'indeterminate'; @Component({ - selector: 'progressbar', + selector: 'extra-progressbar', standalone: true, imports: [ProgressBar], template: ` @@ -15,7 +15,7 @@ export type ProgressBarMode = 'determinate' | 'indeterminate'; > `, }) -export class ProgressBarComponent { +export class ExtraProgressBarComponent { @Input() value = 0; @Input() mode: ProgressBarMode = 'determinate'; @Input() showValue = true; diff --git a/src/lib/components/progressbar/public_api.ts b/src/lib/components/progressbar/public_api.ts new file mode 100644 index 00000000..472f668c --- /dev/null +++ b/src/lib/components/progressbar/public_api.ts @@ -0,0 +1,2 @@ +export * from './progressbar.component'; + diff --git a/src/lib/components/progressspinner/ng-package.json b/src/lib/components/progressspinner/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/progressspinner/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/progressspinner/progressspinner.component.ts b/src/lib/components/progressspinner/progressspinner.component.ts index d4647781..d5a24d8d 100644 --- a/src/lib/components/progressspinner/progressspinner.component.ts +++ b/src/lib/components/progressspinner/progressspinner.component.ts @@ -6,7 +6,7 @@ import { ProgressSpinner } from 'primeng/progressspinner'; export type ProgressSpinnerSize = 'small' | 'medium' | 'large' | 'xlarge'; @Component({ - selector: 'progressspinner', + selector: 'extra-progressspinner', standalone: true, imports: [ProgressSpinner], template: ` @@ -19,7 +19,7 @@ export type ProgressSpinnerSize = 'small' | 'medium' | 'large' | 'xlarge'; > ` }) -export class ProgressSpinnerComponent { +export class ExtraProgressSpinnerComponent { @Input() size: ProgressSpinnerSize = 'medium'; @Input() multicolor = true; @Input() strokeWidth = '2'; diff --git a/src/lib/components/progressspinner/public_api.ts b/src/lib/components/progressspinner/public_api.ts new file mode 100644 index 00000000..291ee78d --- /dev/null +++ b/src/lib/components/progressspinner/public_api.ts @@ -0,0 +1,4 @@ +export * from './progressspinner.component'; + + + diff --git a/src/lib/components/radiobutton/ng-package.json b/src/lib/components/radiobutton/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/radiobutton/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/radiobutton/public_api.ts b/src/lib/components/radiobutton/public_api.ts new file mode 100644 index 00000000..a5ada333 --- /dev/null +++ b/src/lib/components/radiobutton/public_api.ts @@ -0,0 +1,4 @@ +export * from './radiobutton.component'; + + + diff --git a/src/lib/components/radiobutton/radiobutton.component.ts b/src/lib/components/radiobutton/radiobutton.component.ts index e7d36073..b80f3513 100644 --- a/src/lib/components/radiobutton/radiobutton.component.ts +++ b/src/lib/components/radiobutton/radiobutton.component.ts @@ -6,20 +6,20 @@ export type RadiobuttonVariant = 'outlined' | 'filled'; export type RadiobuttonSize = 'small' | 'base' | 'large'; @Component({ - selector: 'radiobutton', + selector: 'extra-radiobutton', standalone: true, imports: [RadioButton, FormsModule], providers: [ { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => RadiobuttonComponent), + useExisting: forwardRef(() => ExtraRadiobuttonComponent), multi: true, }, ], template: ` `, }) -export class RadiobuttonComponent implements ControlValueAccessor { +export class ExtraRadiobuttonComponent implements ControlValueAccessor { @Input() value: any = null; @Input() name: string | undefined = undefined; @Input() disabled = false; diff --git a/src/lib/components/rating/ng-package.json b/src/lib/components/rating/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/rating/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/rating/public_api.ts b/src/lib/components/rating/public_api.ts new file mode 100644 index 00000000..832deb2b --- /dev/null +++ b/src/lib/components/rating/public_api.ts @@ -0,0 +1,4 @@ +export * from './rating.component'; + + + diff --git a/src/lib/components/rating/rating.component.ts b/src/lib/components/rating/rating.component.ts index cbb6a242..2baa883b 100644 --- a/src/lib/components/rating/rating.component.ts +++ b/src/lib/components/rating/rating.component.ts @@ -5,13 +5,13 @@ import { Rating } from 'primeng/rating'; export type RatingValue = number | null; @Component({ - selector: 'rating', + selector: 'extra-rating', standalone: true, imports: [Rating, FormsModule], providers: [ { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => RatingComponent), + useExisting: forwardRef(() => ExtraRatingComponent), multi: true, }, ], @@ -29,7 +29,7 @@ export type RatingValue = number | null; > `, }) -export class RatingComponent implements ControlValueAccessor { +export class ExtraRatingComponent implements ControlValueAccessor { @Input() stars = 5; @Input() readonly = false; @Input() disabled = false; diff --git a/src/lib/components/skeleton/ng-package.json b/src/lib/components/skeleton/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/skeleton/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/skeleton/public_api.ts b/src/lib/components/skeleton/public_api.ts new file mode 100644 index 00000000..baa522a2 --- /dev/null +++ b/src/lib/components/skeleton/public_api.ts @@ -0,0 +1,4 @@ +export * from './skeleton.component'; + + + diff --git a/src/lib/components/skeleton/skeleton.component.ts b/src/lib/components/skeleton/skeleton.component.ts index 5d5ca162..e97f3fe6 100644 --- a/src/lib/components/skeleton/skeleton.component.ts +++ b/src/lib/components/skeleton/skeleton.component.ts @@ -5,7 +5,7 @@ export type SkeletonShape = 'rectangle' | 'circle'; export type SkeletonAnimation = 'wave' | 'none'; @Component({ - selector: 'skeleton', + selector: 'extra-skeleton', host: { style: 'display: block' }, standalone: true, imports: [Skeleton], @@ -20,7 +20,7 @@ export type SkeletonAnimation = 'wave' | 'none'; > `, }) -export class SkeletonComponent { +export class ExtraSkeletonComponent { @Input() shape: SkeletonShape = 'rectangle'; @Input() animation: SkeletonAnimation = 'wave'; @Input() width = '100%'; diff --git a/src/lib/components/slider/ng-package.json b/src/lib/components/slider/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/slider/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/slider/public_api.ts b/src/lib/components/slider/public_api.ts new file mode 100644 index 00000000..7e3ff9d5 --- /dev/null +++ b/src/lib/components/slider/public_api.ts @@ -0,0 +1,4 @@ +export * from './slider.component'; + + + diff --git a/src/lib/components/slider/slider.component.ts b/src/lib/components/slider/slider.component.ts index 320bf2f4..30ae3c46 100644 --- a/src/lib/components/slider/slider.component.ts +++ b/src/lib/components/slider/slider.component.ts @@ -7,7 +7,7 @@ import { Subscription } from 'rxjs'; export type SliderOrientation = 'horizontal' | 'vertical'; @Component({ - selector: 'slider', + selector: 'extra-slider', host: { style: 'display: block' }, standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, @@ -15,7 +15,7 @@ export type SliderOrientation = 'horizontal' | 'vertical'; providers: [ { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => SliderComponent), + useExisting: forwardRef(() => ExtraSliderComponent), multi: true, }, ], @@ -31,7 +31,7 @@ export type SliderOrientation = 'horizontal' | 'vertical'; > `, }) -export class SliderComponent implements ControlValueAccessor, OnChanges, OnDestroy { +export class ExtraSliderComponent implements ControlValueAccessor, OnChanges, OnDestroy { @Input() min = 0; @Input() max = 100; @Input() step: number | undefined = undefined; diff --git a/src/lib/components/tag/ng-package.json b/src/lib/components/tag/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/tag/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/tag/public_api.ts b/src/lib/components/tag/public_api.ts new file mode 100644 index 00000000..cf42576c --- /dev/null +++ b/src/lib/components/tag/public_api.ts @@ -0,0 +1,4 @@ +export * from './tag.component'; + + + diff --git a/src/lib/components/tag/tag.component.ts b/src/lib/components/tag/tag.component.ts index a6f4a0d9..7aedbd14 100644 --- a/src/lib/components/tag/tag.component.ts +++ b/src/lib/components/tag/tag.component.ts @@ -4,7 +4,7 @@ import { Tag } from 'primeng/tag'; export type TagSeverity = 'primary' | 'secondary' | 'success' | 'info' | 'warn' | 'danger'; @Component({ - selector: 'tag', + selector: 'extra-tag', standalone: true, imports: [Tag], template: ` @@ -16,7 +16,7 @@ export type TagSeverity = 'primary' | 'secondary' | 'success' | 'info' | 'warn' > `, }) -export class TagComponent { +export class ExtraTagComponent { @Input() value = ''; @Input() severity: TagSeverity = 'primary'; @Input() rounded = false; diff --git a/src/lib/components/tieredmenu/ng-package.json b/src/lib/components/tieredmenu/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/tieredmenu/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/tieredmenu/public_api.ts b/src/lib/components/tieredmenu/public_api.ts new file mode 100644 index 00000000..7cf9805e --- /dev/null +++ b/src/lib/components/tieredmenu/public_api.ts @@ -0,0 +1,4 @@ +export * from './tieredmenu.component'; + + + diff --git a/src/lib/components/tieredmenu/tieredmenu.component.ts b/src/lib/components/tieredmenu/tieredmenu.component.ts index 662c26f0..d4f92f67 100644 --- a/src/lib/components/tieredmenu/tieredmenu.component.ts +++ b/src/lib/components/tieredmenu/tieredmenu.component.ts @@ -3,7 +3,7 @@ import { TieredMenu } from 'primeng/tieredmenu'; import { MenuItem } from 'primeng/api'; @Component({ - selector: 'tieredmenu', + selector: 'extra-tieredmenu', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [TieredMenu], @@ -15,7 +15,7 @@ import { MenuItem } from 'primeng/api'; > `, }) -export class TieredMenuComponent implements AfterViewChecked { +export class ExtraTieredMenuComponent implements AfterViewChecked { @Input() model: MenuItem[] = []; @Input() autoDisplay = true; @Input() tabindex: number | undefined = undefined; diff --git a/src/lib/components/timeline/ng-package.json b/src/lib/components/timeline/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/timeline/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/timeline/public_api.ts b/src/lib/components/timeline/public_api.ts new file mode 100644 index 00000000..0a2cf2e4 --- /dev/null +++ b/src/lib/components/timeline/public_api.ts @@ -0,0 +1,4 @@ +export * from './timeline.component'; + + + diff --git a/src/lib/components/timeline/timeline.component.ts b/src/lib/components/timeline/timeline.component.ts index 7846393a..4af9ebf4 100644 --- a/src/lib/components/timeline/timeline.component.ts +++ b/src/lib/components/timeline/timeline.component.ts @@ -6,7 +6,7 @@ import { NgIf, NgTemplateOutlet } from '@angular/common'; export type TimelineLine = 'solid' | 'dashed' | 'dotted' | 'none'; @Component({ - selector: 'timeline', + selector: 'extra-timeline', standalone: true, imports: [Timeline, SharedModule, NgIf, NgTemplateOutlet], template: ` @@ -47,7 +47,7 @@ export type TimelineLine = 'solid' | 'dashed' | 'dotted' | 'none'; `, }) -export class TimelineComponent { +export class ExtraTimelineComponent { @Input() value: any[] = []; @Input() align: 'left' | 'right' | 'alternate' | 'top' | 'bottom' = 'left'; @Input() layout: 'vertical' | 'horizontal' = 'vertical'; diff --git a/src/lib/components/tooltip/ng-package.json b/src/lib/components/tooltip/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/tooltip/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/tooltip/public_api.ts b/src/lib/components/tooltip/public_api.ts new file mode 100644 index 00000000..d1afcc18 --- /dev/null +++ b/src/lib/components/tooltip/public_api.ts @@ -0,0 +1,4 @@ +export * from './tooltip.directive'; + + + diff --git a/src/lib/components/tooltip/tooltip.directive.ts b/src/lib/components/tooltip/tooltip.directive.ts index 91084c3d..9995b2ae 100644 --- a/src/lib/components/tooltip/tooltip.directive.ts +++ b/src/lib/components/tooltip/tooltip.directive.ts @@ -5,7 +5,7 @@ export type TooltipPosition = 'right' | 'left' | 'top' | 'bottom'; export type TooltipEvent = 'hover' | 'focus' | 'both'; @Directive({ - selector: '[tooltip]', + selector: '[extra-tooltip]', standalone: true, hostDirectives: [ { @@ -27,7 +27,7 @@ export type TooltipEvent = 'hover' | 'focus' | 'both'; } ] }) -export class TooltipDirective { +export class ExtraTooltipDirective { @Input() tooltip: string | undefined; @Input() position: TooltipPosition = 'right'; @Input() event: TooltipEvent = 'hover'; diff --git a/src/lib/ng-package.json b/src/lib/ng-package.json new file mode 100644 index 00000000..61073a16 --- /dev/null +++ b/src/lib/ng-package.json @@ -0,0 +1,13 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist", + "deleteDestPath": true, + "lib": { + "entryFile": "public_api.ts" + }, + "allowedNonPeerDependencies": [ + "@primeng/themes", + "primeng", + "@primeuix/themes" + ] +} diff --git a/src/lib/package.json b/src/lib/package.json new file mode 100644 index 00000000..ef608e84 --- /dev/null +++ b/src/lib/package.json @@ -0,0 +1,13 @@ +{ + "name": "@cdek-it/angular-ui-kit", + "version": "0.0.3", + "peerDependencies": { + "@angular/common": "^20.3.15", + "@angular/core": "^20.3.15" + }, + "dependencies": { + "@primeng/themes": "20.4.0", + "primeng": "20.4.0", + "@primeuix/themes": "1.2.5" + } +} diff --git a/src/lib/providers/ng-package.json b/src/lib/providers/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/providers/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "ng-packagr/ng-package.schema.json", + "lib": { + "entryFile": "public_api.ts" + } +} + diff --git a/src/prime-preset/map-tokens.ts b/src/lib/providers/prime-preset/map-tokens.ts similarity index 93% rename from src/prime-preset/map-tokens.ts rename to src/lib/providers/prime-preset/map-tokens.ts index d0a44965..4f711e08 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/lib/providers/prime-preset/map-tokens.ts @@ -1,6 +1,7 @@ import { Preset } from '@primeuix/themes/types'; import type { ComponentsDesignTokens } from '@primeuix/themes/types'; -import type { AuraBaseDesignTokens } from '@primeuix/themes/aura/base'; +// по другому импорт не работает +import type { AuraBaseDesignTokens } from '../../../../node_modules/@primeuix/themes/dist/aura/base'; import tokens from './tokens/tokens.json'; import { avatarCss } from './tokens/components/avatar'; diff --git a/src/prime-preset/theme.preset.ts b/src/lib/providers/prime-preset/theme.preset.ts similarity index 100% rename from src/prime-preset/theme.preset.ts rename to src/lib/providers/prime-preset/theme.preset.ts diff --git a/src/prime-preset/tokens/components/avatar.ts b/src/lib/providers/prime-preset/tokens/components/avatar.ts similarity index 100% rename from src/prime-preset/tokens/components/avatar.ts rename to src/lib/providers/prime-preset/tokens/components/avatar.ts diff --git a/src/prime-preset/tokens/components/badge.ts b/src/lib/providers/prime-preset/tokens/components/badge.ts similarity index 100% rename from src/prime-preset/tokens/components/badge.ts rename to src/lib/providers/prime-preset/tokens/components/badge.ts diff --git a/src/prime-preset/tokens/components/breadcrumb.ts b/src/lib/providers/prime-preset/tokens/components/breadcrumb.ts similarity index 100% rename from src/prime-preset/tokens/components/breadcrumb.ts rename to src/lib/providers/prime-preset/tokens/components/breadcrumb.ts diff --git a/src/prime-preset/tokens/components/button.ts b/src/lib/providers/prime-preset/tokens/components/button.ts similarity index 100% rename from src/prime-preset/tokens/components/button.ts rename to src/lib/providers/prime-preset/tokens/components/button.ts diff --git a/src/prime-preset/tokens/components/card.ts b/src/lib/providers/prime-preset/tokens/components/card.ts similarity index 100% rename from src/prime-preset/tokens/components/card.ts rename to src/lib/providers/prime-preset/tokens/components/card.ts diff --git a/src/prime-preset/tokens/components/checkbox.ts b/src/lib/providers/prime-preset/tokens/components/checkbox.ts similarity index 100% rename from src/prime-preset/tokens/components/checkbox.ts rename to src/lib/providers/prime-preset/tokens/components/checkbox.ts diff --git a/src/prime-preset/tokens/components/chip.ts b/src/lib/providers/prime-preset/tokens/components/chip.ts similarity index 100% rename from src/prime-preset/tokens/components/chip.ts rename to src/lib/providers/prime-preset/tokens/components/chip.ts diff --git a/src/prime-preset/tokens/components/dialog.ts b/src/lib/providers/prime-preset/tokens/components/dialog.ts similarity index 100% rename from src/prime-preset/tokens/components/dialog.ts rename to src/lib/providers/prime-preset/tokens/components/dialog.ts diff --git a/src/prime-preset/tokens/components/divider.ts b/src/lib/providers/prime-preset/tokens/components/divider.ts similarity index 100% rename from src/prime-preset/tokens/components/divider.ts rename to src/lib/providers/prime-preset/tokens/components/divider.ts diff --git a/src/prime-preset/tokens/components/inputtext.ts b/src/lib/providers/prime-preset/tokens/components/inputtext.ts similarity index 100% rename from src/prime-preset/tokens/components/inputtext.ts rename to src/lib/providers/prime-preset/tokens/components/inputtext.ts diff --git a/src/prime-preset/tokens/components/megamenu.ts b/src/lib/providers/prime-preset/tokens/components/megamenu.ts similarity index 100% rename from src/prime-preset/tokens/components/megamenu.ts rename to src/lib/providers/prime-preset/tokens/components/megamenu.ts diff --git a/src/prime-preset/tokens/components/metergroup.ts b/src/lib/providers/prime-preset/tokens/components/metergroup.ts similarity index 100% rename from src/prime-preset/tokens/components/metergroup.ts rename to src/lib/providers/prime-preset/tokens/components/metergroup.ts diff --git a/src/prime-preset/tokens/components/progressbar.ts b/src/lib/providers/prime-preset/tokens/components/progressbar.ts similarity index 100% rename from src/prime-preset/tokens/components/progressbar.ts rename to src/lib/providers/prime-preset/tokens/components/progressbar.ts diff --git a/src/prime-preset/tokens/components/progressspinner.ts b/src/lib/providers/prime-preset/tokens/components/progressspinner.ts similarity index 100% rename from src/prime-preset/tokens/components/progressspinner.ts rename to src/lib/providers/prime-preset/tokens/components/progressspinner.ts diff --git a/src/prime-preset/tokens/components/radiobutton.ts b/src/lib/providers/prime-preset/tokens/components/radiobutton.ts similarity index 100% rename from src/prime-preset/tokens/components/radiobutton.ts rename to src/lib/providers/prime-preset/tokens/components/radiobutton.ts diff --git a/src/prime-preset/tokens/components/skeleton.ts b/src/lib/providers/prime-preset/tokens/components/skeleton.ts similarity index 100% rename from src/prime-preset/tokens/components/skeleton.ts rename to src/lib/providers/prime-preset/tokens/components/skeleton.ts diff --git a/src/prime-preset/tokens/components/slider.ts b/src/lib/providers/prime-preset/tokens/components/slider.ts similarity index 100% rename from src/prime-preset/tokens/components/slider.ts rename to src/lib/providers/prime-preset/tokens/components/slider.ts diff --git a/src/prime-preset/tokens/components/tag.ts b/src/lib/providers/prime-preset/tokens/components/tag.ts similarity index 100% rename from src/prime-preset/tokens/components/tag.ts rename to src/lib/providers/prime-preset/tokens/components/tag.ts diff --git a/src/prime-preset/tokens/components/tieredmenu.ts b/src/lib/providers/prime-preset/tokens/components/tieredmenu.ts similarity index 100% rename from src/prime-preset/tokens/components/tieredmenu.ts rename to src/lib/providers/prime-preset/tokens/components/tieredmenu.ts diff --git a/src/prime-preset/tokens/components/timeline.ts b/src/lib/providers/prime-preset/tokens/components/timeline.ts similarity index 100% rename from src/prime-preset/tokens/components/timeline.ts rename to src/lib/providers/prime-preset/tokens/components/timeline.ts diff --git a/src/prime-preset/tokens/components/tooltip.ts b/src/lib/providers/prime-preset/tokens/components/tooltip.ts similarity index 100% rename from src/prime-preset/tokens/components/tooltip.ts rename to src/lib/providers/prime-preset/tokens/components/tooltip.ts diff --git a/src/prime-preset/tokens/tokens.json b/src/lib/providers/prime-preset/tokens/tokens.json similarity index 100% rename from src/prime-preset/tokens/tokens.json rename to src/lib/providers/prime-preset/tokens/tokens.json diff --git a/src/lib/providers/public_api.ts b/src/lib/providers/public_api.ts new file mode 100644 index 00000000..a642deab --- /dev/null +++ b/src/lib/providers/public_api.ts @@ -0,0 +1,4 @@ +export * from './theme-preset'; + + + diff --git a/src/lib/providers/theme-preset.ts b/src/lib/providers/theme-preset.ts new file mode 100644 index 00000000..0c70c99b --- /dev/null +++ b/src/lib/providers/theme-preset.ts @@ -0,0 +1,17 @@ +import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'; +import { providePrimeNG } from 'primeng/config'; +import Preset from './prime-preset/theme.preset'; + +export function provideExtraThemes(): EnvironmentProviders { + return makeEnvironmentProviders([ + providePrimeNG({ + theme: { + preset: Preset, + options: { + darkModeSelector: false, + cssLayer: false + } + } + }) + ]); +} diff --git a/src/lib/public_api.ts b/src/lib/public_api.ts new file mode 100644 index 00000000..ff8b4c56 --- /dev/null +++ b/src/lib/public_api.ts @@ -0,0 +1 @@ +export default {}; diff --git a/src/lib/tsconfig.lib.json b/src/lib/tsconfig.lib.json new file mode 100644 index 00000000..011665c6 --- /dev/null +++ b/src/lib/tsconfig.lib.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "declaration": true, + "module": "es2022", + "target": "es2022", + "baseUrl": "./features", + "stripInternal": true, + "emitDecoratorMetadata": false, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "moduleResolution": "node", + "outDir": "../build", + "rootDir": ".", + "lib": ["es2022", "dom"], + "skipLibCheck": true, + "types": ["node"], + "paths": { + "@cdek-it/angular-ui-kit/*": ["./*/public_api"] + } + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": false, + "strictMetadataEmit": true, + "skipTemplateCodegen": true, + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true + }, + "files": ["./public_api.ts"] +} diff --git a/src/lib/tsconfig.lib.prod.json b/src/lib/tsconfig.lib.prod.json new file mode 100644 index 00000000..06de549e --- /dev/null +++ b/src/lib/tsconfig.lib.prod.json @@ -0,0 +1,10 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/src/lib/tsconfig.spec.json b/src/lib/tsconfig.spec.json new file mode 100644 index 00000000..ce7048bc --- /dev/null +++ b/src/lib/tsconfig.spec.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/src/stories/components/avatar/avatar.stories.ts b/src/stories/components/avatar/avatar.stories.ts index 6f760953..367c3f42 100644 --- a/src/stories/components/avatar/avatar.stories.ts +++ b/src/stories/components/avatar/avatar.stories.ts @@ -1,14 +1,14 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { OverlayBadge } from 'primeng/overlaybadge'; -import { AvatarComponent, AvatarGroupComponent } from '../../../lib/components/avatar/avatar.component'; +import { ExtraAvatarComponent, ExtraAvatarGroupComponent } from '../../../lib/components/avatar/avatar.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Misc/Avatar', - component: AvatarComponent, + component: ExtraAvatarComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ - imports: [AvatarComponent, AvatarGroupComponent, OverlayBadge], + imports: [ExtraAvatarComponent, ExtraAvatarGroupComponent, OverlayBadge], }), ], parameters: { @@ -17,7 +17,7 @@ const meta: Meta = { component: `Аватар представляет пользователя или сущность. Может содержать текст, иконку или изображение. [PrimeNG Avatar](https://primeng.org/avatar). \`\`\`typescript -import { AvatarComponent, AvatarGroupComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraAvatarComponent, ExtraAvatarGroupComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -76,17 +76,17 @@ import { AvatarComponent, AvatarGroupComponent } from '@cdek-it/angular-ui-kit'; }; const commonTemplate = ` - +> `; export default meta; -type Story = StoryObj; +type Story = StoryObj; // ── Default ────────────────────────────────────────────────────────────────── @@ -102,8 +102,8 @@ export const Default: Story = { if (args.shape && args.shape !== 'square') parts.push(`shape="${args.shape}"`); const template = parts.length - ? `` - : ``; + ? `` + : ``; return { props: args, template }; }, @@ -130,7 +130,7 @@ export const Label: Story = { docs: { description: { story: 'Аватар с текстовой меткой.' }, source: { - code: ``, + code: ``, }, }, }, @@ -145,7 +145,7 @@ export const Icon: Story = { docs: { description: { story: 'Аватар с иконкой.' }, source: { - code: ``, + code: ``, }, }, }, @@ -160,7 +160,7 @@ export const Image: Story = { docs: { description: { story: 'Аватар с изображением. shape="square" — без обрезки, shape="circle" — с обрезкой по кругу.' }, source: { - code: ``, + code: ``, }, }, }, @@ -175,7 +175,7 @@ export const Sizes: Story = { docs: { description: { story: 'Размер аватара. Доступны: normal, large, xlarge.' }, source: { - code: ``, + code: ``, }, }, }, @@ -190,7 +190,7 @@ export const Shapes: Story = { docs: { description: { story: 'Форма аватара. circle — круглый, square — квадратный (по умолчанию).' }, source: { - code: ``, + code: ``, }, }, }, @@ -203,25 +203,25 @@ export const Shapes: Story = { export const Group: Story = { render: () => ({ template: ` - - - - - - - - + + + + + + + + `, }), parameters: { docs: { description: { story: 'Группа аватаров с перекрытием.' }, source: { - code: ` - - - -`, + code: ` + + + +`, }, }, }, @@ -234,7 +234,7 @@ export const LabelWithBadge: Story = { props: args, template: ` - + `, }), @@ -243,7 +243,7 @@ export const LabelWithBadge: Story = { description: { story: 'Аватар с текстовой меткой и бейджем через OverlayBadge.' }, source: { code: ` - + `, }, }, @@ -257,7 +257,7 @@ export const IconWithBadge: Story = { props: args, template: ` - + `, }), @@ -266,7 +266,7 @@ export const IconWithBadge: Story = { description: { story: 'Аватар с иконкой и бейджем через OverlayBadge.' }, source: { code: ` - + `, }, }, @@ -280,7 +280,7 @@ export const ImageWithBadge: Story = { props: args, template: ` - + `, }), @@ -289,7 +289,7 @@ export const ImageWithBadge: Story = { description: { story: 'Аватар с изображением и бейджем через OverlayBadge.' }, source: { code: ` - + `, }, }, diff --git a/src/stories/components/avatar/examples/avatar-group.component.ts b/src/stories/components/avatar/examples/avatar-group.component.ts index 867d1b41..ebd968e3 100644 --- a/src/stories/components/avatar/examples/avatar-group.component.ts +++ b/src/stories/components/avatar/examples/avatar-group.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { AvatarComponent, AvatarGroupComponent } from '../../../../lib/components/avatar/avatar.component'; +import { ExtraAvatarComponent, ExtraAvatarGroupComponent } from '../../../../lib/components/avatar/avatar.component'; const template = `
- - - - - - - - + + + + + + + +
`; const styles = ''; @@ -19,7 +19,7 @@ const styles = ''; @Component({ selector: 'app-avatar-group', standalone: true, - imports: [AvatarComponent, AvatarGroupComponent], + imports: [ExtraAvatarComponent, ExtraAvatarGroupComponent], template, styles, }) @@ -38,19 +38,19 @@ export const Group: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { AvatarComponent, AvatarGroupComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraAvatarComponent, ExtraAvatarGroupComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-avatar-group', standalone: true, - imports: [AvatarComponent, AvatarGroupComponent], + imports: [ExtraAvatarComponent, ExtraAvatarGroupComponent], template: \` - - - - - - + + + + + + \`, }) export class AvatarGroupExampleComponent {} diff --git a/src/stories/components/avatar/examples/avatar-icon-badge.component.ts b/src/stories/components/avatar/examples/avatar-icon-badge.component.ts index e4b8fa96..9beedc02 100644 --- a/src/stories/components/avatar/examples/avatar-icon-badge.component.ts +++ b/src/stories/components/avatar/examples/avatar-icon-badge.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { OverlayBadge } from 'primeng/overlaybadge'; -import { AvatarComponent } from '../../../../lib/components/avatar/avatar.component'; +import { ExtraAvatarComponent } from '../../../../lib/components/avatar/avatar.component'; const template = `
- + - +
@@ -20,7 +20,7 @@ const styles = ''; @Component({ selector: 'app-avatar-icon-badge', standalone: true, - imports: [AvatarComponent, OverlayBadge], + imports: [ExtraAvatarComponent, OverlayBadge], template, styles, }) @@ -40,19 +40,19 @@ export const IconWithBadge: StoryObj = { code: ` import { Component } from '@angular/core'; import { OverlayBadge } from 'primeng/overlaybadge'; -import { AvatarComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraAvatarComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-avatar-icon-badge', standalone: true, - imports: [AvatarComponent, OverlayBadge], + imports: [ExtraAvatarComponent, OverlayBadge], template: \`
- + - +
\`, diff --git a/src/stories/components/avatar/examples/avatar-icon.component.ts b/src/stories/components/avatar/examples/avatar-icon.component.ts index 9dd91bdb..d5170612 100644 --- a/src/stories/components/avatar/examples/avatar-icon.component.ts +++ b/src/stories/components/avatar/examples/avatar-icon.component.ts @@ -1,13 +1,13 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { AvatarComponent } from '../../../../lib/components/avatar/avatar.component'; +import { ExtraAvatarComponent } from '../../../../lib/components/avatar/avatar.component'; const template = `
- - - + + +
`; @@ -16,7 +16,7 @@ const styles = ''; @Component({ selector: 'app-avatar-icon', standalone: true, - imports: [AvatarComponent], + imports: [ExtraAvatarComponent], template, styles, }) @@ -35,17 +35,17 @@ export const Icon: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { AvatarComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraAvatarComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-avatar-icon', standalone: true, - imports: [AvatarComponent], + imports: [ExtraAvatarComponent], template: \`
- - - + + +
\`, }) diff --git a/src/stories/components/avatar/examples/avatar-image-badge.component.ts b/src/stories/components/avatar/examples/avatar-image-badge.component.ts index 2117577b..30538bee 100644 --- a/src/stories/components/avatar/examples/avatar-image-badge.component.ts +++ b/src/stories/components/avatar/examples/avatar-image-badge.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { OverlayBadge } from 'primeng/overlaybadge'; -import { AvatarComponent } from '../../../../lib/components/avatar/avatar.component'; +import { ExtraAvatarComponent } from '../../../../lib/components/avatar/avatar.component'; const template = `
- + - +
@@ -20,7 +20,7 @@ const styles = ''; @Component({ selector: 'app-avatar-image-badge', standalone: true, - imports: [AvatarComponent, OverlayBadge], + imports: [ExtraAvatarComponent, OverlayBadge], template, styles, }) @@ -40,20 +40,20 @@ export const ImageWithBadge: StoryObj = { code: ` import { Component } from '@angular/core'; import { OverlayBadge } from 'primeng/overlaybadge'; -import { AvatarComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraAvatarComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-avatar-image-badge', standalone: true, - imports: [AvatarComponent, OverlayBadge], + imports: [ExtraAvatarComponent, OverlayBadge], template: \`
- - - - - - + + + + + +
\`, }) diff --git a/src/stories/components/avatar/examples/avatar-image.component.ts b/src/stories/components/avatar/examples/avatar-image.component.ts index c11580dc..b5b3c3ee 100644 --- a/src/stories/components/avatar/examples/avatar-image.component.ts +++ b/src/stories/components/avatar/examples/avatar-image.component.ts @@ -1,13 +1,13 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { AvatarComponent } from '../../../../lib/components/avatar/avatar.component'; +import { ExtraAvatarComponent } from '../../../../lib/components/avatar/avatar.component'; const template = `
- - - + + +
`; @@ -16,7 +16,7 @@ const styles = ''; @Component({ selector: 'app-avatar-image', standalone: true, - imports: [AvatarComponent], + imports: [ExtraAvatarComponent], template, styles, }) @@ -35,17 +35,17 @@ export const Image: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { AvatarComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraAvatarComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-avatar-image', standalone: true, - imports: [AvatarComponent], + imports: [ExtraAvatarComponent], template: \`
- - - + + +
\`, }) diff --git a/src/stories/components/avatar/examples/avatar-label-badge.component.ts b/src/stories/components/avatar/examples/avatar-label-badge.component.ts index bda2e9a0..9904edd1 100644 --- a/src/stories/components/avatar/examples/avatar-label-badge.component.ts +++ b/src/stories/components/avatar/examples/avatar-label-badge.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { OverlayBadge } from 'primeng/overlaybadge'; -import { AvatarComponent } from '../../../../lib/components/avatar/avatar.component'; +import { ExtraAvatarComponent } from '../../../../lib/components/avatar/avatar.component'; const template = `
- + - +
@@ -20,7 +20,7 @@ const styles = ''; @Component({ selector: 'app-avatar-label-badge', standalone: true, - imports: [AvatarComponent, OverlayBadge], + imports: [ExtraAvatarComponent, OverlayBadge], template, styles, }) @@ -40,20 +40,20 @@ export const LabelWithBadge: StoryObj = { code: ` import { Component } from '@angular/core'; import { OverlayBadge } from 'primeng/overlaybadge'; -import { AvatarComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraAvatarComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-avatar-label-badge', standalone: true, - imports: [AvatarComponent, OverlayBadge], + imports: [ExtraAvatarComponent, OverlayBadge], template: \`
- - - - - - + + + + + +
\`, }) diff --git a/src/stories/components/avatar/examples/avatar-label.component.ts b/src/stories/components/avatar/examples/avatar-label.component.ts index a33588c3..5475254a 100644 --- a/src/stories/components/avatar/examples/avatar-label.component.ts +++ b/src/stories/components/avatar/examples/avatar-label.component.ts @@ -1,13 +1,13 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { AvatarComponent } from '../../../../lib/components/avatar/avatar.component'; +import { ExtraAvatarComponent } from '../../../../lib/components/avatar/avatar.component'; const template = `
- - - + + +
`; @@ -16,7 +16,7 @@ const styles = ''; @Component({ selector: 'app-avatar-label', standalone: true, - imports: [AvatarComponent], + imports: [ExtraAvatarComponent], template, styles, }) @@ -35,17 +35,17 @@ export const Label: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { AvatarComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraAvatarComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-avatar-label', standalone: true, - imports: [AvatarComponent], + imports: [ExtraAvatarComponent], template: \`
- - - + + +
\`, }) diff --git a/src/stories/components/avatar/examples/avatar-shapes.component.ts b/src/stories/components/avatar/examples/avatar-shapes.component.ts index c4693b30..2ecd333b 100644 --- a/src/stories/components/avatar/examples/avatar-shapes.component.ts +++ b/src/stories/components/avatar/examples/avatar-shapes.component.ts @@ -1,12 +1,12 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { AvatarComponent } from '../../../../lib/components/avatar/avatar.component'; +import { ExtraAvatarComponent } from '../../../../lib/components/avatar/avatar.component'; const template = `
- - + +
`; @@ -15,7 +15,7 @@ const styles = ''; @Component({ selector: 'app-avatar-shapes', standalone: true, - imports: [AvatarComponent], + imports: [ExtraAvatarComponent], template, styles, }) @@ -34,16 +34,16 @@ export const Shapes: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { AvatarComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraAvatarComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-avatar-shapes', standalone: true, - imports: [AvatarComponent], + imports: [ExtraAvatarComponent], template: \`
- - + +
\`, }) diff --git a/src/stories/components/avatar/examples/avatar-sizes.component.ts b/src/stories/components/avatar/examples/avatar-sizes.component.ts index 99ff3370..97a71047 100644 --- a/src/stories/components/avatar/examples/avatar-sizes.component.ts +++ b/src/stories/components/avatar/examples/avatar-sizes.component.ts @@ -1,13 +1,13 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { AvatarComponent } from '../../../../lib/components/avatar/avatar.component'; +import { ExtraAvatarComponent } from '../../../../lib/components/avatar/avatar.component'; const template = `
- - - + + +
`; @@ -16,7 +16,7 @@ const styles = ''; @Component({ selector: 'app-avatar-sizes', standalone: true, - imports: [AvatarComponent], + imports: [ExtraAvatarComponent], template, styles, }) @@ -35,17 +35,17 @@ export const Sizes: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { AvatarComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraAvatarComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-avatar-sizes', standalone: true, - imports: [AvatarComponent], + imports: [ExtraAvatarComponent], template: \`
- - - + + +
\`, }) diff --git a/src/stories/components/badge/badge.stories.ts b/src/stories/components/badge/badge.stories.ts index 4da22cc9..d1d30ab4 100644 --- a/src/stories/components/badge/badge.stories.ts +++ b/src/stories/components/badge/badge.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { BadgeComponent } from '../../../lib/components/badge/badge.component'; +import { ExtraBadgeComponent } from '../../../lib/components/badge/badge.component'; import { BadgeSeverityComponent } from './examples/badge-severity.component'; import { BadgeSizesComponent } from './examples/badge-sizes.component'; import { BadgeDotComponent } from './examples/badge-dot.component'; @@ -8,13 +8,13 @@ export { Severity } from './examples/badge-severity.component'; export { Sizes } from './examples/badge-sizes.component'; export { Dot } from './examples/badge-dot.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Misc/Badge', - component: BadgeComponent, + component: ExtraBadgeComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ - imports: [BadgeComponent, BadgeSeverityComponent, BadgeSizesComponent, BadgeDotComponent] + imports: [ExtraBadgeComponent, BadgeSeverityComponent, BadgeSizesComponent, BadgeDotComponent] }) ], parameters: { @@ -69,7 +69,7 @@ import { BadgeModule } from 'primeng/badge'; }; export default meta; -type Story = StoryObj; +type Story = StoryObj; // ── Default ────────────────────────────────────────────────────────────────── diff --git a/src/stories/components/badge/examples/badge-dot.component.ts b/src/stories/components/badge/examples/badge-dot.component.ts index 923d01d8..d29b8210 100644 --- a/src/stories/components/badge/examples/badge-dot.component.ts +++ b/src/stories/components/badge/examples/badge-dot.component.ts @@ -1,10 +1,10 @@ import { Component, Input } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { BadgeComponent, BadgeSeverity, BadgeSize } from '../../../../lib/components/badge/badge.component'; +import { ExtraBadgeComponent, BadgeSeverity, BadgeSize } from '../../../../lib/components/badge/badge.component'; const template = `
- +
`; @@ -13,7 +13,7 @@ const styles = ''; @Component({ selector: 'app-badge-dot', standalone: true, - imports: [BadgeComponent], + imports: [ExtraBadgeComponent], template, styles }) @@ -46,7 +46,7 @@ export const Dot: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { BadgeComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraBadgeComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-badge-dot', diff --git a/src/stories/components/badge/examples/badge-severity.component.ts b/src/stories/components/badge/examples/badge-severity.component.ts index 50868f7b..95d0e4f4 100644 --- a/src/stories/components/badge/examples/badge-severity.component.ts +++ b/src/stories/components/badge/examples/badge-severity.component.ts @@ -1,10 +1,10 @@ import { Component, Input } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { BadgeComponent, BadgeSeverity, BadgeSize } from '../../../../lib/components/badge/badge.component'; +import { ExtraBadgeComponent, BadgeSeverity, BadgeSize } from '../../../../lib/components/badge/badge.component'; const template = `
- +
`; @@ -13,7 +13,7 @@ const styles = ''; @Component({ selector: 'app-badge-severity', standalone: true, - imports: [BadgeComponent], + imports: [ExtraBadgeComponent], template, styles }) @@ -52,7 +52,7 @@ export const Severity: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { BadgeComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraBadgeComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-badge-severity', diff --git a/src/stories/components/badge/examples/badge-sizes.component.ts b/src/stories/components/badge/examples/badge-sizes.component.ts index dc8ddd7d..ac656ece 100644 --- a/src/stories/components/badge/examples/badge-sizes.component.ts +++ b/src/stories/components/badge/examples/badge-sizes.component.ts @@ -1,10 +1,10 @@ import { Component, Input } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { BadgeComponent, BadgeSize } from '../../../../lib/components/badge/badge.component'; +import { ExtraBadgeComponent, BadgeSize } from '../../../../lib/components/badge/badge.component'; const template = `
- +
`; @@ -13,7 +13,7 @@ const styles = ''; @Component({ selector: 'app-badge-sizes', standalone: true, - imports: [BadgeComponent], + imports: [ExtraBadgeComponent], template, styles }) @@ -51,7 +51,7 @@ export const Sizes: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { BadgeComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraBadgeComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-badge-sizes', diff --git a/src/stories/components/breadcrumb/breadcrumb.stories.ts b/src/stories/components/breadcrumb/breadcrumb.stories.ts index 1f090d38..938cfbbb 100644 --- a/src/stories/components/breadcrumb/breadcrumb.stories.ts +++ b/src/stories/components/breadcrumb/breadcrumb.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { BreadcrumbComponent } from '../../../lib/components/breadcrumb/breadcrumb.component'; +import { ExtraBreadcrumbComponent as BreadcrumbComponent } from '../../../lib/components/breadcrumb/breadcrumb.component'; import { BreadcrumbBasicComponent, Basic } from './examples/breadcrumb-basic.component'; import { BreadcrumbIconsOnlyComponent, IconsOnly } from './examples/breadcrumb-icons-only.component'; import { commonHome, commonItems } from './breadcrumb.data'; @@ -60,7 +60,7 @@ export const Default: Story = { name: 'Default', render: (args) => ({ props: args, - template: ``, + template: ``, }), parameters: { docs: { diff --git a/src/stories/components/breadcrumb/examples/breadcrumb-basic.component.ts b/src/stories/components/breadcrumb/examples/breadcrumb-basic.component.ts index 066086f0..cfb582e8 100644 --- a/src/stories/components/breadcrumb/examples/breadcrumb-basic.component.ts +++ b/src/stories/components/breadcrumb/examples/breadcrumb-basic.component.ts @@ -1,18 +1,18 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { BreadcrumbComponent } from '../../../../lib/components/breadcrumb/breadcrumb.component'; +import { ExtraBreadcrumbComponent } from '../../../../lib/components/breadcrumb/breadcrumb.component'; import { commonHome, commonItems } from '../breadcrumb.data'; const template = `
- +
`; @Component({ selector: 'app-breadcrumb-basic', standalone: true, - imports: [BreadcrumbComponent], + imports: [ExtraBreadcrumbComponent], template, }) export class BreadcrumbBasicComponent { @@ -31,14 +31,14 @@ export const Basic: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { BreadcrumbComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraBreadcrumbComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-breadcrumb-basic', standalone: true, imports: [BreadcrumbComponent], template: \` - + \`, }) export class BreadcrumbBasicComponent { diff --git a/src/stories/components/breadcrumb/examples/breadcrumb-icons-only.component.ts b/src/stories/components/breadcrumb/examples/breadcrumb-icons-only.component.ts index 2b97a6e2..b8ea75b2 100644 --- a/src/stories/components/breadcrumb/examples/breadcrumb-icons-only.component.ts +++ b/src/stories/components/breadcrumb/examples/breadcrumb-icons-only.component.ts @@ -1,18 +1,18 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { BreadcrumbComponent } from '../../../../lib/components/breadcrumb/breadcrumb.component'; +import { ExtraBreadcrumbComponent } from '../../../../lib/components/breadcrumb/breadcrumb.component'; import { commonHome, iconOnlyItems } from '../breadcrumb.data'; const template = `
- +
`; @Component({ selector: 'app-breadcrumb-icons-only', standalone: true, - imports: [BreadcrumbComponent], + imports: [ExtraBreadcrumbComponent], template, }) export class BreadcrumbIconsOnlyComponent { @@ -31,14 +31,14 @@ export const IconsOnly: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { BreadcrumbComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraBreadcrumbComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-breadcrumb-icons-only', standalone: true, imports: [BreadcrumbComponent], template: \` - + \`, }) export class BreadcrumbIconsOnlyComponent { diff --git a/src/stories/components/button/button.stories.ts b/src/stories/components/button/button.stories.ts index 20bdfe81..e5d62fe2 100644 --- a/src/stories/components/button/button.stories.ts +++ b/src/stories/components/button/button.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { ButtonComponent } from '../../../lib/components/button/button.component'; +import { ExtraButtonComponent as ButtonComponent } from '../../../lib/components/button/button.component'; type ButtonArgs = ButtonComponent & { onClick?: (event: MouseEvent) => void }; @@ -214,7 +214,7 @@ import { ButtonModule } from 'primeng/button'; }; const commonTemplate = ` - +> `; export default meta; @@ -257,8 +257,8 @@ export const Default: Story = { if (args.loading) parts.push(`[loading]="true"`); const template = parts.length - ? `` - : ``; + ? `` + : ``; return { props: args, template }; }, @@ -287,10 +287,10 @@ export const Sizes: Story = { description: { story: 'Все доступные размеры: small, base, large, xlarge.' }, source: { code: ` - + - +
`; return { props: args, template }; @@ -125,58 +125,31 @@ export const Overlay: Story = { source: { language: 'ts', code: ` -import { Component } from '@angular/core'; -import { SharedModule } from 'primeng/api'; -import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-card-overlay', - standalone: true, - imports: [CardComponent, ButtonComponent, SharedModule], - template: \` - - -
- -
-
- -

Карточка с тенью.

-
- - - -
- \`, -}) -export class CardOverlayComponent {} - `, - }, - }, - }, -}; - -// ── WithoutHeader ───────────────────────────────────────────────────────────── - -export const WithoutHeader: Story = { - render: () => ({ - template: ``, - }), - parameters: { - docs: { - description: { story: 'Карточка без изображения в шапке.' }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { SharedModule } from 'primeng/api'; -import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ + import { Component } from '@angular/core'; + import { SharedModule } from 'primeng/api'; + import { ExtraCardComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; + + @Component({ + selector: 'app-card-without-header', + standalone: true, + imports: [ExtraCardComponent, ExtraButtonComponent, SharedModule], + template: \` + + +

Карточка без изображения в шапке.

+
+ + + +
+ \`, + }) + export class CardWithoutHeaderComponent {} + `, selector: 'app-card-without-header', standalone: true, imports: [CardComponent, ButtonComponent, SharedModule], - template: \` + template: `

Карточка без изображения в шапке.

@@ -205,30 +178,30 @@ export const WithoutFooter: Story = { description: { story: 'Карточка без футера с действиями.' }, source: { language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { SharedModule } from 'primeng/api'; -import { CardComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-card-without-footer', - standalone: true, - imports: [CardComponent, SharedModule], - template: \` - - -
- -
-
- -

Карточка без футера.

-
-
- \`, -}) -export class CardWithoutFooterComponent {} - `, + code: ` + import { Component } from '@angular/core'; + import { SharedModule } from 'primeng/api'; + import { ExtraCardComponent } from '@cdek-it/angular-ui-kit'; + + @Component({ + selector: 'app-card-without-footer', + standalone: true, + imports: [ExtraCardComponent, SharedModule], + template: \` + + +
+ +
+
+ +

Карточка без футера.

+
+
+ \`, + }) + export class CardWithoutFooterComponent {} + `, }, }, }, @@ -245,33 +218,33 @@ export const WithoutSubtitle: Story = { description: { story: 'Карточка без подзаголовка.' }, source: { language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { SharedModule } from 'primeng/api'; -import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-card-without-subtitle', - standalone: true, - imports: [CardComponent, ButtonComponent, SharedModule], - template: \` - - -
- -
-
- -

Карточка без подзаголовка.

-
- - - -
- \`, -}) -export class CardWithoutSubtitleComponent {} - `, + code: ` + import { Component } from '@angular/core'; + import { SharedModule } from 'primeng/api'; + import { ExtraCardComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; + + @Component({ + selector: 'app-card-without-subtitle', + standalone: true, + imports: [ExtraCardComponent, ExtraButtonComponent, SharedModule], + template: \` + + +
+ +
+
+ +

Карточка без подзаголовка.

+
+ + + +
+ \`, + }) + export class CardWithoutSubtitleComponent {} + `, }, }, }, diff --git a/src/stories/components/card/examples/card-overlay.component.ts b/src/stories/components/card/examples/card-overlay.component.ts index b2665463..2b503d00 100644 --- a/src/stories/components/card/examples/card-overlay.component.ts +++ b/src/stories/components/card/examples/card-overlay.component.ts @@ -1,12 +1,12 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { SharedModule } from 'primeng/api'; -import { CardComponent } from '../../../../lib/components/card/card.component'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraCardComponent } from '../../../../lib/components/card/card.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; const template = `
- + Заголовок @@ -24,7 +24,7 @@ const styles = ''; @Component({ selector: 'app-card-overlay', standalone: true, - imports: [CardComponent, ButtonComponent, SharedModule], + imports: [ExtraCardComponent, ExtraButtonComponent, SharedModule], template, styles, }) @@ -42,14 +42,14 @@ export const Overlay: StoryObj = { code: ` import { Component } from '@angular/core'; import { SharedModule } from 'primeng/api'; -import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraCardComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-card-overlay', standalone: true, imports: [CardComponent, ButtonComponent, SharedModule], template: \` - + Заголовок @@ -57,9 +57,9 @@ import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit';

Карточка с тенью.

- + -
+
\`, }) export class CardOverlayComponent {} diff --git a/src/stories/components/card/examples/card-without-footer.component.ts b/src/stories/components/card/examples/card-without-footer.component.ts index e412af6b..6db1baa1 100644 --- a/src/stories/components/card/examples/card-without-footer.component.ts +++ b/src/stories/components/card/examples/card-without-footer.component.ts @@ -1,18 +1,18 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { SharedModule } from 'primeng/api'; -import { CardComponent } from '../../../../lib/components/card/card.component'; +import { ExtraCardComponent } from '../../../../lib/components/card/card.component'; const template = `
- + Заголовок

Карточка без футера.

-
+
`; const styles = ''; @@ -20,7 +20,7 @@ const styles = ''; @Component({ selector: 'app-card-without-footer', standalone: true, - imports: [CardComponent, SharedModule], + imports: [ExtraCardComponent, SharedModule], template, styles, }) @@ -38,21 +38,21 @@ export const WithoutFooter: StoryObj = { code: ` import { Component } from '@angular/core'; import { SharedModule } from 'primeng/api'; -import { CardComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraCardComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-card-without-footer', standalone: true, imports: [CardComponent, SharedModule], template: \` - + Заголовок

Карточка без футера.

-
+ \`, }) export class CardWithoutFooterComponent {} diff --git a/src/stories/components/card/examples/card-without-header.component.ts b/src/stories/components/card/examples/card-without-header.component.ts index e7a96254..82778595 100644 --- a/src/stories/components/card/examples/card-without-header.component.ts +++ b/src/stories/components/card/examples/card-without-header.component.ts @@ -1,12 +1,12 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { SharedModule } from 'primeng/api'; -import { CardComponent } from '../../../../lib/components/card/card.component'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraCardComponent } from '../../../../lib/components/card/card.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; const template = `
- +

Карточка без изображения в шапке.

@@ -21,7 +21,7 @@ const styles = ''; @Component({ selector: 'app-card-without-header', standalone: true, - imports: [CardComponent, ButtonComponent, SharedModule], + imports: [ExtraCardComponent, ExtraButtonComponent, SharedModule], template, styles, }) @@ -39,21 +39,21 @@ export const WithoutHeader: StoryObj = { code: ` import { Component } from '@angular/core'; import { SharedModule } from 'primeng/api'; -import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraCardComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-card-without-header', standalone: true, imports: [CardComponent, ButtonComponent, SharedModule], template: \` - +

Карточка без изображения в шапке.

- + -
+
\`, }) export class CardWithoutHeaderComponent {} diff --git a/src/stories/components/card/examples/card-without-subtitle.component.ts b/src/stories/components/card/examples/card-without-subtitle.component.ts index 0d7d91af..e69116aa 100644 --- a/src/stories/components/card/examples/card-without-subtitle.component.ts +++ b/src/stories/components/card/examples/card-without-subtitle.component.ts @@ -1,12 +1,12 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { SharedModule } from 'primeng/api'; -import { CardComponent } from '../../../../lib/components/card/card.component'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraCardComponent } from '../../../../lib/components/card/card.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; const template = `
- + Заголовок @@ -24,7 +24,7 @@ const styles = ''; @Component({ selector: 'app-card-without-subtitle', standalone: true, - imports: [CardComponent, ButtonComponent, SharedModule], + imports: [ExtraCardComponent, ExtraButtonComponent, SharedModule], template, styles, }) @@ -42,14 +42,14 @@ export const WithoutSubtitle: StoryObj = { code: ` import { Component } from '@angular/core'; import { SharedModule } from 'primeng/api'; -import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraCardComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-card-without-subtitle', standalone: true, imports: [CardComponent, ButtonComponent, SharedModule], template: \` - + Заголовок @@ -57,9 +57,9 @@ import { CardComponent, ButtonComponent } from '@cdek-it/angular-ui-kit';

Карточка без подзаголовка.

- + -
+
\`, }) export class CardWithoutSubtitleComponent {} diff --git a/src/stories/components/checkbox/checkbox.stories.ts b/src/stories/components/checkbox/checkbox.stories.ts index 2e4423e4..623129e5 100644 --- a/src/stories/components/checkbox/checkbox.stories.ts +++ b/src/stories/components/checkbox/checkbox.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { CheckboxComponent } from '../../../lib/components/checkbox/checkbox.component'; +import { ExtraCheckboxComponent as CheckboxComponent } from '../../../lib/components/checkbox/checkbox.component'; import { FormsModule } from '@angular/forms'; import { CheckboxGroupComponent, Group } from './examples/checkbox-group.component'; import { CheckboxIndeterminateComponent, Indeterminate } from './examples/checkbox-indeterminate.component'; @@ -129,7 +129,7 @@ export const Default: Story = { if (args.indeterminate) parts.push(`[indeterminate]="true"`); parts.push(`[(ngModel)]="checked"`); - const template = ``; + const template = ``; return { props: { ...args, checked: false }, template }; }, diff --git a/src/stories/components/chip/chip.stories.ts b/src/stories/components/chip/chip.stories.ts index 5d4c7d11..dd44e9d8 100644 --- a/src/stories/components/chip/chip.stories.ts +++ b/src/stories/components/chip/chip.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { ChipComponent } from '../../../lib/components/chip/chip.component'; +import { ExtraChipComponent as ChipComponent } from '../../../lib/components/chip/chip.component'; import { ChipWithIconComponent, WithIcon as WithIconStory } from './examples/chip-with-icon.component'; import { ChipRemovableComponent, Removable as RemovableStory } from './examples/chip-removable.component'; import { ChipRemovableWithIconComponent, RemovableWithIcon as RemovableWithIconStory } from './examples/chip-removable-with-icon.component'; @@ -83,12 +83,12 @@ import { ChipComponent } from '@cdek-it/angular-ui-kit'; }; const commonTemplate = ` - +> `; export default meta; @@ -107,8 +107,8 @@ export const Default: Story = { if (args.disabled) parts.push(`[disabled]="true"`); const template = parts.length - ? `` - : ``; + ? `` + : ``; return { props: args, template }; }, diff --git a/src/stories/components/dialog/dialog.stories.ts b/src/stories/components/dialog/dialog.stories.ts index 1ed8d769..2f540ed8 100644 --- a/src/stories/components/dialog/dialog.stories.ts +++ b/src/stories/components/dialog/dialog.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { DialogComponent } from '../../../lib/components/dialog/dialog.component'; +import { ExtraDialogComponent } from '../../../lib/components/dialog/dialog.component'; import { DialogDefaultComponent, template as dialogDefaultTemplate } from './examples/dialog-default.component'; import { DialogSmallComponent, template as dialogSmallTemplate } from './examples/dialog-small.component'; import { DialogLargeComponent, template as dialogLargeTemplate } from './examples/dialog-large.component'; @@ -8,19 +8,19 @@ import { DialogNoModalComponent, template as dialogNoModalTemplate } from './exa import { DialogNoHeaderComponent, template as dialogNoHeaderTemplate } from './examples/dialog-no-header.component'; import { DialogDynamicComponent } from './examples/dialog-dynamic.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Overlay/Dialog', - component: DialogComponent, + component: ExtraDialogComponent, tags: ['autodocs'], parameters: { docs: { - description: { - component: `Dialog (модальное окно) — контейнер, отображающийся поверх основного содержимого страницы. + description: { + component: `Dialog (модальное окно) — контейнер, отображающийся поверх основного содержимого страницы. -\`\`\`typescript -import { DialogComponent } from '@cdek-it/angular-ui-kit'; -\`\`\``, - }, + \`\`\`typescript + import { ExtraDialogComponent } from '@cdek-it/angular-ui-kit'; + \`\`\``, + }, }, designTokens: { prefix: '--p-dialog' }, }, @@ -119,7 +119,7 @@ import { DialogComponent } from '@cdek-it/angular-ui-kit'; }; export default meta; -type Story = StoryObj; +type Story = StoryObj; // ── Basic ───────────────────────────────────────────────────────────────────── @@ -136,12 +136,12 @@ export const Basic: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DialogComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDialogComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-dialog-basic', standalone: true, - imports: [DialogComponent, ButtonComponent], + imports: [ExtraDialogComponent, ExtraButtonComponent], template: \`${dialogDefaultTemplate}\`, }) export class DialogBasicComponent { @@ -166,12 +166,12 @@ export const Small: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DialogComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDialogComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-dialog-small', standalone: true, - imports: [DialogComponent, ButtonComponent], + imports: [ExtraDialogComponent, ExtraButtonComponent], template: \`${dialogSmallTemplate}\`, }) export class DialogSmallComponent { @@ -196,12 +196,12 @@ export const Large: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DialogComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDialogComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-dialog-large', standalone: true, - imports: [DialogComponent, ButtonComponent], + imports: [ExtraDialogComponent, ExtraButtonComponent], template: \`${dialogLargeTemplate}\`, }) export class DialogLargeComponent { @@ -226,12 +226,12 @@ export const ExtraLarge: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DialogComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDialogComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-dialog-extra-large', standalone: true, - imports: [DialogComponent, ButtonComponent], + imports: [ExtraDialogComponent, ExtraButtonComponent], template: \`${dialogExtraLargeTemplate}\`, }) export class DialogExtraLargeComponent { @@ -256,12 +256,12 @@ export const NoModal: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DialogComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDialogComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-dialog-no-modal', standalone: true, - imports: [DialogComponent, ButtonComponent], + imports: [ExtraDialogComponent, ExtraButtonComponent], template: \`${dialogNoModalTemplate}\`, }) export class DialogNoModalComponent { @@ -286,12 +286,12 @@ export const NoHeader: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DialogComponent, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDialogComponent, ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-dialog-no-header', standalone: true, - imports: [DialogComponent, ButtonComponent], + imports: [ExtraDialogComponent, ExtraButtonComponent], template: \`${dialogNoHeaderTemplate}\`, }) export class DialogNoHeaderComponent { @@ -312,24 +312,24 @@ export const Dynamic: Story = { parameters: { docs: { description: { - story: 'Программное открытие диалога через `UiDialogService`. Содержимое — любой Angular-компонент, получающий `DynamicDialogRef` для закрытия.', + story: 'Программное открытие диалога через `ExtraDialogService`. Содержимое — любой Angular-компонент, получающий `DynamicDialogRef` для закрытия.', }, source: { language: 'ts', code: ` import { Component, Injector } from '@angular/core'; -import { ButtonComponent, DynamicDialogRef, UiDialogService } from '@cdek-it/angular-ui-kit'; +import { ExtraButtonComponent, DynamicDialogRef, ExtraDialogService } from '@cdek-it/angular-ui-kit'; // Содержимое диалога @Component({ selector: 'app-dialog-dynamic-content', standalone: true, - imports: [ButtonComponent], + imports: [ExtraButtonComponent], template: \`

Заявка на доставку груза №CDEK-2025-00478312 готова к оформлению.

- - + +
\`, }) @@ -348,7 +348,7 @@ export class DialogDynamicContentComponent { }) export class DialogDynamicComponent { constructor( - private readonly dialogService: UiDialogService, + private readonly dialogService: ExtraDialogService, private readonly injector: Injector, ) {} diff --git a/src/stories/components/dialog/examples/dialog-default.component.ts b/src/stories/components/dialog/examples/dialog-default.component.ts index 31a2e5a3..013adfad 100644 --- a/src/stories/components/dialog/examples/dialog-default.component.ts +++ b/src/stories/components/dialog/examples/dialog-default.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; -import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraDialogComponent } from '../../../../lib/components/dialog/dialog.component'; export const template = `
- + - - + + - Заявка на доставку груза №CDEK-2025-00478312 готова к оформлению.

Вес отправления: 3,5 кг, габариты: 40×30×20 см. Ориентировочный срок — 3 рабочих дня.

- - + +
`, }) @@ -25,19 +25,19 @@ export class DialogDynamicContentComponent { export const template = `
- +
`; @Component({ selector: 'app-dialog-dynamic', standalone: true, - imports: [ButtonComponent], + imports: [ExtraButtonComponent], template, }) export class DialogDynamicComponent { constructor( - private readonly dialogService: UiDialogService, + private readonly dialogService: ExtraDialogService, ) {} open(): void { diff --git a/src/stories/components/dialog/examples/dialog-extra-large.component.ts b/src/stories/components/dialog/examples/dialog-extra-large.component.ts index 6177db64..89d5be8e 100644 --- a/src/stories/components/dialog/examples/dialog-extra-large.component.ts +++ b/src/stories/components/dialog/examples/dialog-extra-large.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; -import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraDialogComponent } from '../../../../lib/components/dialog/dialog.component'; export const template = `
- + - - + + -

За апрель 2025 года обработано 4 872 отправления. Успешно доставлено — 4 641 (95,3%). Возвраты — 112 (2,3%). В пути — 119 (2,4%). Средний срок доставки по России составил 2,7 рабочего дня. Наиболее загруженные направления: Москва — Санкт-Петербург, Москва — Новосибирск, Москва — Екатеринбург.

-
+
`; @Component({ selector: 'app-dialog-extra-large', standalone: true, - imports: [DialogComponent, ButtonComponent], + imports: [ExtraDialogComponent, ExtraButtonComponent], template, }) export class DialogExtraLargeComponent { diff --git a/src/stories/components/dialog/examples/dialog-large.component.ts b/src/stories/components/dialog/examples/dialog-large.component.ts index 474ea38b..bd712044 100644 --- a/src/stories/components/dialog/examples/dialog-large.component.ts +++ b/src/stories/components/dialog/examples/dialog-large.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; -import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraDialogComponent } from '../../../../lib/components/dialog/dialog.component'; export const template = `
- + - - + + - - +
- +
-

Заявка на доставку принята в обработку. Трек-номер будет присвоен в течение 15 минут и отправлен на указанный email.

-
+
`; @Component({ selector: 'app-dialog-no-header', standalone: true, - imports: [DialogComponent, ButtonComponent], + imports: [ExtraDialogComponent, ExtraButtonComponent], template, }) export class DialogNoHeaderComponent { diff --git a/src/stories/components/dialog/examples/dialog-no-modal.component.ts b/src/stories/components/dialog/examples/dialog-no-modal.component.ts index fba236cb..03d643e7 100644 --- a/src/stories/components/dialog/examples/dialog-no-modal.component.ts +++ b/src/stories/components/dialog/examples/dialog-no-modal.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; -import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraDialogComponent } from '../../../../lib/components/dialog/dialog.component'; export const template = `
- + - - + + -

Маршрут отправления CDEK-2025-00478312: Москва (склад) → Новосибирск (сортировочный центр) → Новосибирск (пункт выдачи). Это окно не блокирует основной контент страницы.

-
+
`; @Component({ selector: 'app-dialog-no-modal', standalone: true, - imports: [DialogComponent, ButtonComponent], + imports: [ExtraDialogComponent, ExtraButtonComponent], template, }) export class DialogNoModalComponent { diff --git a/src/stories/components/dialog/examples/dialog-small.component.ts b/src/stories/components/dialog/examples/dialog-small.component.ts index 6b661e8d..ee677fdc 100644 --- a/src/stories/components/dialog/examples/dialog-small.component.ts +++ b/src/stories/components/dialog/examples/dialog-small.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; -import { DialogComponent } from '../../../../lib/components/dialog/dialog.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraDialogComponent } from '../../../../lib/components/dialog/dialog.component'; export const template = `
- + - - + + - +> `; export default meta; @@ -87,8 +87,8 @@ export const Default: Story = { if (args.align && args.align !== 'center') parts.push(`align="${args.align}"`); const template = parts.length - ? `` - : ``; + ? `` + : ``; return { props: args, template }; }, @@ -127,7 +127,7 @@ export const Vertical: Story = { docs: { description: { story: 'Вертикальный разделитель для разделения контента по горизонтали.' }, source: { - code: ``, + code: ``, }, }, }, @@ -147,7 +147,7 @@ export const TypeDashed: Story = { docs: { description: { story: 'Разделитель с пунктирной линией.' }, source: { - code: ``, + code: ``, }, }, }, @@ -165,7 +165,7 @@ export const TypeDotted: Story = { docs: { description: { story: 'Разделитель с точечной линией.' }, source: { - code: ``, + code: ``, }, }, }, diff --git a/src/stories/components/divider/examples/divider-align-left.component.ts b/src/stories/components/divider/examples/divider-align-left.component.ts index 244e3d44..5e9ad90e 100644 --- a/src/stories/components/divider/examples/divider-align-left.component.ts +++ b/src/stories/components/divider/examples/divider-align-left.component.ts @@ -3,9 +3,9 @@ import { DividerComponent } from '../../../../lib/components/divider/divider.com const template = `
- + Отправитель - +
`; const styles = ''; @@ -37,9 +37,9 @@ import { DividerComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [DividerComponent], template: \` - + Отправитель - + \`, }) export class DividerAlignLeftComponent {} diff --git a/src/stories/components/divider/examples/divider-with-content.component.ts b/src/stories/components/divider/examples/divider-with-content.component.ts index b1b0b80f..8daf3b8b 100644 --- a/src/stories/components/divider/examples/divider-with-content.component.ts +++ b/src/stories/components/divider/examples/divider-with-content.component.ts @@ -1,11 +1,11 @@ import { Component } from '@angular/core'; -import { DividerComponent } from '../../../../lib/components/divider/divider.component'; +import { ExtraDividerComponent } from '../../../../lib/components/divider/divider.component'; const template = `
- + Москва → Новосибирск - +
`; const styles = ''; @@ -13,7 +13,7 @@ const styles = ''; @Component({ selector: 'app-divider-with-content', standalone: true, - imports: [DividerComponent], + imports: [ExtraDividerComponent], template, styles, }) @@ -30,16 +30,16 @@ export const WithContent = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DividerComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDividerComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-divider-with-content', standalone: true, - imports: [DividerComponent], + imports: [ExtraDividerComponent], template: \` - + Москва → Новосибирск - + \`, }) export class DividerWithContentComponent {} diff --git a/src/stories/components/divider/examples/divider-with-icon.component.ts b/src/stories/components/divider/examples/divider-with-icon.component.ts index 95d79871..9312cd4c 100644 --- a/src/stories/components/divider/examples/divider-with-icon.component.ts +++ b/src/stories/components/divider/examples/divider-with-icon.component.ts @@ -3,9 +3,9 @@ import { DividerComponent } from '../../../../lib/components/divider/divider.com const template = `
- + - +
`; const styles = ''; @@ -37,9 +37,9 @@ import { DividerComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [DividerComponent], template: \` - + - + \`, }) export class DividerWithIconComponent {} diff --git a/src/stories/components/inputtext/inputtext.stories.ts b/src/stories/components/inputtext/inputtext.stories.ts index 57545c18..3aaf4116 100644 --- a/src/stories/components/inputtext/inputtext.stories.ts +++ b/src/stories/components/inputtext/inputtext.stories.ts @@ -1,6 +1,6 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { InputTextComponent } from '../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputTextComponent as InputTextComponent } from '../../../lib/components/inputtext/inputtext.component'; import { ClearButton } from './examples/inputtext-clear.component'; import { InputTextFloatLabelComponent, FloatLabelStory } from './examples/inputtext-float-label.component'; import { InputTextFloatLabelInvalidComponent, FloatLabelInvalid } from './examples/inputtext-float-label-invalid.component'; @@ -148,7 +148,7 @@ export const Default: Story = { const control = new FormControl({ value: '', disabled: args.disabled }, validators); - const template = ``; + const template = ``; return { props: { ...args, control }, template }; }, diff --git a/src/stories/components/megamenu/examples/megamenu-custom.component.ts b/src/stories/components/megamenu/examples/megamenu-custom.component.ts index 966f7b3f..a2bc0ab8 100644 --- a/src/stories/components/megamenu/examples/megamenu-custom.component.ts +++ b/src/stories/components/megamenu/examples/megamenu-custom.component.ts @@ -1,12 +1,12 @@ import { Component } from '@angular/core'; -import { MegaMenuComponent, MegaMenuModel } from '../../../../lib/components/megamenu/megamenu.component'; +import { ExtraMegaMenuComponent, MegaMenuModel } from '../../../../lib/components/megamenu/megamenu.component'; -const template = ``; +const template = ``; @Component({ selector: 'app-megamenu-custom', standalone: true, - imports: [MegaMenuComponent], + imports: [ExtraMegaMenuComponent], template, }) export class MegaMenuCustomComponent { diff --git a/src/stories/components/megamenu/examples/megamenu-horizontal.component.ts b/src/stories/components/megamenu/examples/megamenu-horizontal.component.ts index ce40470f..e494169c 100644 --- a/src/stories/components/megamenu/examples/megamenu-horizontal.component.ts +++ b/src/stories/components/megamenu/examples/megamenu-horizontal.component.ts @@ -1,12 +1,12 @@ import { Component } from '@angular/core'; -import { MegaMenuComponent, MegaMenuModel } from '../../../../lib/components/megamenu/megamenu.component'; +import { ExtraMegaMenuComponent, MegaMenuModel } from '../../../../lib/components/megamenu/megamenu.component'; -const template = ``; +const template = ``; @Component({ selector: 'app-megamenu-horizontal', standalone: true, - imports: [MegaMenuComponent], + imports: [ExtraMegaMenuComponent], template, }) export class MegaMenuHorizontalComponent { diff --git a/src/stories/components/megamenu/examples/megamenu-vertical.component.ts b/src/stories/components/megamenu/examples/megamenu-vertical.component.ts index 67978398..ed1a6e8a 100644 --- a/src/stories/components/megamenu/examples/megamenu-vertical.component.ts +++ b/src/stories/components/megamenu/examples/megamenu-vertical.component.ts @@ -1,12 +1,12 @@ import { Component } from '@angular/core'; -import { MegaMenuComponent, MegaMenuModel } from '../../../../lib/components/megamenu/megamenu.component'; +import { ExtraMegaMenuComponent, MegaMenuModel } from '../../../../lib/components/megamenu/megamenu.component'; -const template = ``; +const template = ``; @Component({ selector: 'app-megamenu-vertical', standalone: true, - imports: [MegaMenuComponent], + imports: [ExtraMegaMenuComponent], template, }) export class MegaMenuVerticalComponent { diff --git a/src/stories/components/megamenu/megamenu.stories.ts b/src/stories/components/megamenu/megamenu.stories.ts index 7d2ca90c..da8f8af7 100644 --- a/src/stories/components/megamenu/megamenu.stories.ts +++ b/src/stories/components/megamenu/megamenu.stories.ts @@ -1,13 +1,13 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { MegaMenuComponent, MegaMenuModel } from '../../../lib/components/megamenu/megamenu.component'; +import { ExtraMegaMenuComponent, MegaMenuModel } from '../../../lib/components/megamenu/megamenu.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Menu/MegaMenu', - component: MegaMenuComponent, + component: ExtraMegaMenuComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ - imports: [MegaMenuComponent], + imports: [ExtraMegaMenuComponent], }), ], parameters: { @@ -16,8 +16,8 @@ const meta: Meta = { component: `Расширенное меню с поддержкой многоколоночных подменю. Поддерживает горизонтальную и вертикальную ориентацию. \`\`\`typescript -import { MegaMenuComponent } from '@cdek-it/angular-ui-kit'; -\`\`\``, +import { ExtraMegaMenuComponent } from '@cdek-it/angular-ui-kit'; +\`\`\`, }, story: { height: '300px', @@ -61,7 +61,7 @@ import { MegaMenuComponent } from '@cdek-it/angular-ui-kit'; }; export default meta; -type Story = StoryObj; +type Story = StoryObj; const baseItems: MegaMenuModel[] = [ { @@ -112,11 +112,11 @@ const baseItems: MegaMenuModel[] = [ ]; const commonTemplate = ` - +> `; // ── Default ────────────────────────────────────────────────────────────────── @@ -128,7 +128,7 @@ export const Default: Story = { if (args.orientation && args.orientation !== 'horizontal') parts.push(`orientation="${args.orientation}"`); if (args.disabled) parts.push(`[disabled]="true"`); - const template = ``; + const template = ``; return { props: { ...args, model: baseItems }, template }; }, parameters: { @@ -154,12 +154,12 @@ export const Horizontal: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MegaMenuComponent, MegaMenuModel } from '@cdek-it/angular-ui-kit'; +import { ExtraMegaMenuComponent, MegaMenuModel } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [MegaMenuComponent], - template: \`\`, + imports: [ExtraMegaMenuComponent], + template: \`\`, }) export class HorizontalExample { items: MegaMenuModel[] = [ @@ -230,12 +230,12 @@ export const Vertical: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MegaMenuComponent, MegaMenuModel } from '@cdek-it/angular-ui-kit'; +import { ExtraMegaMenuComponent, MegaMenuModel } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [MegaMenuComponent], - template: \`\`, + imports: [ExtraMegaMenuComponent], + template: \`\`, }) export class VerticalExample { items: MegaMenuModel[] = [ @@ -376,12 +376,12 @@ export const Custom: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MegaMenuComponent, MegaMenuModel } from '@cdek-it/angular-ui-kit'; +import { ExtraMegaMenuComponent, MegaMenuModel } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [MegaMenuComponent], - template: \`\`, + imports: [ExtraMegaMenuComponent], + template: \`\`, }) export class CustomExample { items: MegaMenuModel[] = [ diff --git a/src/stories/components/metergroup/examples/metergroup-basic.component.ts b/src/stories/components/metergroup/examples/metergroup-basic.component.ts index b6089d41..2f0e2512 100644 --- a/src/stories/components/metergroup/examples/metergroup-basic.component.ts +++ b/src/stories/components/metergroup/examples/metergroup-basic.component.ts @@ -1,15 +1,15 @@ import { Component } from '@angular/core'; -import { MeterGroupComponent } from '../../../../lib/components/metergroup/metergroup.component'; +import { ExtraMeterGroupComponent } from '../../../../lib/components/metergroup/metergroup.component'; import { MeterItem } from 'primeng/metergroup'; import { defaultValue } from '../metergroup.data'; @Component({ selector: 'app-metergroup-basic', standalone: true, - imports: [MeterGroupComponent], + imports: [ExtraMeterGroupComponent], template: `
- +
`, }) diff --git a/src/stories/components/metergroup/examples/metergroup-horizontal.component.ts b/src/stories/components/metergroup/examples/metergroup-horizontal.component.ts index 1cb2ab96..5cbc6cf8 100644 --- a/src/stories/components/metergroup/examples/metergroup-horizontal.component.ts +++ b/src/stories/components/metergroup/examples/metergroup-horizontal.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { MeterGroupComponent } from '../../../../lib/components/metergroup/metergroup.component'; +import { ExtraMeterGroupComponent } from '../../../../lib/components/metergroup/metergroup.component'; import { MeterItem } from 'primeng/metergroup'; import { defaultValue } from '../metergroup.data'; @Component({ selector: 'app-metergroup-horizontal', standalone: true, - imports: [MeterGroupComponent], + imports: [ExtraMeterGroupComponent], template: `
- +
`, }) @@ -29,15 +29,15 @@ export const Horizontal: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MeterGroupComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraMeterGroupComponent } from '@cdek-it/angular-ui-kit'; import { MeterItem } from 'primeng/metergroup'; @Component({ selector: 'app-metergroup-horizontal', standalone: true, - imports: [MeterGroupComponent], + imports: [ExtraMeterGroupComponent], template: \` - + \`, }) export class MeterGroupHorizontalComponent { diff --git a/src/stories/components/metergroup/examples/metergroup-icon.component.ts b/src/stories/components/metergroup/examples/metergroup-icon.component.ts index 811104d9..856d0a0c 100644 --- a/src/stories/components/metergroup/examples/metergroup-icon.component.ts +++ b/src/stories/components/metergroup/examples/metergroup-icon.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { MeterGroupComponent } from '../../../../lib/components/metergroup/metergroup.component'; +import { ExtraMeterGroupComponent } from '../../../../lib/components/metergroup/metergroup.component'; import { MeterItem } from 'primeng/metergroup'; import { iconValue } from '../metergroup.data'; @Component({ selector: 'app-metergroup-icon', standalone: true, - imports: [MeterGroupComponent], + imports: [ExtraMeterGroupComponent], template: `
- +
`, }) @@ -29,15 +29,15 @@ export const Icon: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MeterGroupComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraMeterGroupComponent } from '@cdek-it/angular-ui-kit'; import { MeterItem } from 'primeng/metergroup'; @Component({ selector: 'app-metergroup-icon', standalone: true, - imports: [MeterGroupComponent], + imports: [ExtraMeterGroupComponent], template: \` - + \`, }) export class MeterGroupIconComponent { diff --git a/src/stories/components/metergroup/examples/metergroup-label-start.component.ts b/src/stories/components/metergroup/examples/metergroup-label-start.component.ts index b5f57f72..bf03d557 100644 --- a/src/stories/components/metergroup/examples/metergroup-label-start.component.ts +++ b/src/stories/components/metergroup/examples/metergroup-label-start.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { MeterGroupComponent } from '../../../../lib/components/metergroup/metergroup.component'; +import { ExtraMeterGroupComponent } from '../../../../lib/components/metergroup/metergroup.component'; import { MeterItem } from 'primeng/metergroup'; import { defaultValue } from '../metergroup.data'; @Component({ selector: 'app-metergroup-label-start', standalone: true, - imports: [MeterGroupComponent], + imports: [ExtraMeterGroupComponent], template: `
- +
`, }) @@ -29,15 +29,15 @@ export const LabelStart: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MeterGroupComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraMeterGroupComponent } from '@cdek-it/angular-ui-kit'; import { MeterItem } from 'primeng/metergroup'; @Component({ selector: 'app-metergroup-label-start', standalone: true, - imports: [MeterGroupComponent], + imports: [ExtraMeterGroupComponent], template: \` - + \`, }) export class MeterGroupLabelStartComponent { diff --git a/src/stories/components/metergroup/examples/metergroup-label-vertical.component.ts b/src/stories/components/metergroup/examples/metergroup-label-vertical.component.ts index d4d8fd6a..26ca91b4 100644 --- a/src/stories/components/metergroup/examples/metergroup-label-vertical.component.ts +++ b/src/stories/components/metergroup/examples/metergroup-label-vertical.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { MeterGroupComponent } from '../../../../lib/components/metergroup/metergroup.component'; +import { ExtraMeterGroupComponent } from '../../../../lib/components/metergroup/metergroup.component'; import { MeterItem } from 'primeng/metergroup'; import { defaultValue } from '../metergroup.data'; @Component({ selector: 'app-metergroup-label-vertical', standalone: true, - imports: [MeterGroupComponent], + imports: [ExtraMeterGroupComponent], template: `
- +
`, }) @@ -29,15 +29,15 @@ export const LabelVertical: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MeterGroupComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraMeterGroupComponent } from '@cdek-it/angular-ui-kit'; import { MeterItem } from 'primeng/metergroup'; @Component({ selector: 'app-metergroup-label-vertical', standalone: true, - imports: [MeterGroupComponent], + imports: [ExtraMeterGroupComponent], template: \` - + \`, }) export class MeterGroupLabelVerticalComponent { diff --git a/src/stories/components/metergroup/examples/metergroup-vertical.component.ts b/src/stories/components/metergroup/examples/metergroup-vertical.component.ts index f45e2eab..0abbd19f 100644 --- a/src/stories/components/metergroup/examples/metergroup-vertical.component.ts +++ b/src/stories/components/metergroup/examples/metergroup-vertical.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { MeterGroupComponent } from '../../../../lib/components/metergroup/metergroup.component'; +import { ExtraMeterGroupComponent } from '../../../../lib/components/metergroup/metergroup.component'; import { MeterItem } from 'primeng/metergroup'; import { defaultValue } from '../metergroup.data'; @Component({ selector: 'app-metergroup-vertical', standalone: true, - imports: [MeterGroupComponent], + imports: [ExtraMeterGroupComponent], template: `
- +
`, @@ -31,16 +31,16 @@ export const Vertical: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MeterGroupComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraMeterGroupComponent } from '@cdek-it/angular-ui-kit'; import { MeterItem } from 'primeng/metergroup'; @Component({ selector: 'app-metergroup-vertical', standalone: true, - imports: [MeterGroupComponent], + imports: [ExtraMeterGroupComponent], template: \`
- +
\`, }) diff --git a/src/stories/components/metergroup/metergroup.stories.ts b/src/stories/components/metergroup/metergroup.stories.ts index 37ff13b2..f4eb03d2 100644 --- a/src/stories/components/metergroup/metergroup.stories.ts +++ b/src/stories/components/metergroup/metergroup.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { MeterGroupComponent } from '../../../lib/components/metergroup/metergroup.component'; +import { ExtraMeterGroupComponent as MeterGroupComponent } from '../../../lib/components/metergroup/metergroup.component'; import { MeterGroupHorizontalComponent, Horizontal } from './examples/metergroup-horizontal.component'; import { MeterGroupVerticalComponent, Vertical } from './examples/metergroup-vertical.component'; import { MeterGroupIconComponent, Icon } from './examples/metergroup-icon.component'; @@ -31,7 +31,7 @@ const meta: Meta = { component: `Визуализирует несколько числовых значений в виде единой полосы прогресса с подписями. \`\`\`typescript -import { MeterGroupComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraMeterGroupComponent as MeterGroupComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -81,12 +81,12 @@ import { MeterGroupComponent } from '@cdek-it/angular-ui-kit'; }, }; -const commonTemplate = ``; +>`; export default meta; type Story = StoryObj; diff --git a/src/stories/components/progressbar/examples/progressbar-indeterminate.component.ts b/src/stories/components/progressbar/examples/progressbar-indeterminate.component.ts index bab48736..51ebe671 100644 --- a/src/stories/components/progressbar/examples/progressbar-indeterminate.component.ts +++ b/src/stories/components/progressbar/examples/progressbar-indeterminate.component.ts @@ -1,13 +1,13 @@ import { Component } from '@angular/core'; -import { ProgressBarComponent } from '../../../../lib/components/progressbar/progressbar.component'; +import { ExtraProgressBarComponent } from '../../../../lib/components/progressbar/progressbar.component'; @Component({ selector: 'app-progressbar-indeterminate', standalone: true, - imports: [ProgressBarComponent], + imports: [ExtraProgressBarComponent], template: `
- +
`, }) diff --git a/src/stories/components/progressbar/examples/progressbar-no-label.component.ts b/src/stories/components/progressbar/examples/progressbar-no-label.component.ts index 8fa5eb28..48718cf4 100644 --- a/src/stories/components/progressbar/examples/progressbar-no-label.component.ts +++ b/src/stories/components/progressbar/examples/progressbar-no-label.component.ts @@ -1,13 +1,13 @@ import { Component } from '@angular/core'; -import { ProgressBarComponent } from '../../../../lib/components/progressbar/progressbar.component'; +import { ExtraProgressBarComponent } from '../../../../lib/components/progressbar/progressbar.component'; @Component({ selector: 'app-progressbar-no-label', standalone: true, - imports: [ProgressBarComponent], + imports: [ExtraProgressBarComponent], template: `
- +
`, }) diff --git a/src/stories/components/progressbar/progressbar.stories.ts b/src/stories/components/progressbar/progressbar.stories.ts index 54de6614..9ff6b2fa 100644 --- a/src/stories/components/progressbar/progressbar.stories.ts +++ b/src/stories/components/progressbar/progressbar.stories.ts @@ -1,18 +1,18 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { ProgressBarComponent } from '../../../lib/components/progressbar/progressbar.component'; +import { ExtraProgressBarComponent } from '../../../lib/components/progressbar/progressbar.component'; import { ProgressBarIndeterminateComponent } from './examples/progressbar-indeterminate.component'; import { ProgressBarNoLabelComponent } from './examples/progressbar-no-label.component'; -type ProgressBarArgs = ProgressBarComponent; +type ProgressBarArgs = ExtraProgressBarComponent; const meta: Meta = { title: 'Components/Misc/ProgressBar', - component: ProgressBarComponent, + component: ExtraProgressBarComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - ProgressBarComponent, + ExtraProgressBarComponent, ProgressBarIndeterminateComponent, ProgressBarNoLabelComponent, ], @@ -24,7 +24,7 @@ const meta: Meta = { component: `Информирует пользователя о статусе длительного процесса. \`\`\`typescript -import { ProgressBarComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraProgressBarComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -64,11 +64,11 @@ import { ProgressBarComponent } from '@cdek-it/angular-ui-kit'; }, }; -const commonTemplate = ``; +>`; export default meta; type Story = StoryObj; @@ -85,8 +85,8 @@ export const Default: Story = { if (!args.showValue) parts.push(`[showValue]="false"`); const template = parts.length - ? `` - : ``; + ? `` + : ``; return { props: args, template }; }, @@ -119,15 +119,15 @@ export const Indeterminate: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ProgressBarComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraProgressBarComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-progressbar-indeterminate', standalone: true, - imports: [ProgressBarComponent], + imports: [ExtraProgressBarComponent], template: \`
- +
\`, }) @@ -151,15 +151,15 @@ export const NoLabel: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ProgressBarComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraProgressBarComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-progressbar-no-label', standalone: true, - imports: [ProgressBarComponent], + imports: [ExtraProgressBarComponent], template: \`
- +
\`, }) diff --git a/src/stories/components/progressspinner/examples/progressspinner-monochrome.component.ts b/src/stories/components/progressspinner/examples/progressspinner-monochrome.component.ts index 8e2f58f5..23d2934b 100644 --- a/src/stories/components/progressspinner/examples/progressspinner-monochrome.component.ts +++ b/src/stories/components/progressspinner/examples/progressspinner-monochrome.component.ts @@ -1,15 +1,15 @@ import { Component, Input } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { ProgressSpinnerComponent } from '../../../../lib/components/progressspinner/progressspinner.component'; +import { ExtraProgressSpinnerComponent } from '../../../../lib/components/progressspinner/progressspinner.component'; const template = ` - + `; @Component({ selector: 'progressspinner-monochrome', standalone: true, - imports: [ProgressSpinnerComponent], + imports: [ExtraProgressSpinnerComponent], template }) export class ProgressSpinnerMonochromeComponent { @@ -35,13 +35,13 @@ export const Monochrome: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ProgressSpinnerComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraProgressSpinnerComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'progressspinner-monochrome', standalone: true, - imports: [ProgressSpinnerComponent], - template: \`\` + imports: [ExtraProgressSpinnerComponent], + template: \`\` }) export class ProgressSpinnerMonochromeComponent {} ` diff --git a/src/stories/components/progressspinner/examples/progressspinner-sizes.component.ts b/src/stories/components/progressspinner/examples/progressspinner-sizes.component.ts index 397cc189..5fedd7a4 100644 --- a/src/stories/components/progressspinner/examples/progressspinner-sizes.component.ts +++ b/src/stories/components/progressspinner/examples/progressspinner-sizes.component.ts @@ -1,15 +1,15 @@ import { Component, Input } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { ProgressSpinnerComponent, ProgressSpinnerSize } from '../../../../lib/components/progressspinner/progressspinner.component'; +import { ExtraProgressSpinnerComponent, ProgressSpinnerSize } from '../../../../lib/components/progressspinner/progressspinner.component'; const template = ` - + `; @Component({ selector: 'progressspinner-sizes', standalone: true, - imports: [ProgressSpinnerComponent], + imports: [ExtraProgressSpinnerComponent], template }) export class ProgressSpinnerSizesComponent { @@ -35,13 +35,13 @@ export const Sizes: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ProgressSpinnerComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraProgressSpinnerComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'progressspinner-sizes', standalone: true, - imports: [ProgressSpinnerComponent], - template: \`\` + imports: [ExtraProgressSpinnerComponent], + template: \`\` }) export class ProgressSpinnerSizesComponent {} ` diff --git a/src/stories/components/progressspinner/progressspinner.stories.ts b/src/stories/components/progressspinner/progressspinner.stories.ts index 0676ec2b..98aa8e99 100644 --- a/src/stories/components/progressspinner/progressspinner.stories.ts +++ b/src/stories/components/progressspinner/progressspinner.stories.ts @@ -1,16 +1,16 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { ProgressSpinnerComponent } from '../../../lib/components/progressspinner/progressspinner.component'; +import { ExtraProgressSpinnerComponent } from '../../../lib/components/progressspinner/progressspinner.component'; import { Sizes, ProgressSpinnerSizesComponent } from './examples/progressspinner-sizes.component'; import { Monochrome, ProgressSpinnerMonochromeComponent } from './examples/progressspinner-monochrome.component'; -type ProgressSpinnerArgs = ProgressSpinnerComponent; +type ProgressSpinnerArgs = ExtraProgressSpinnerComponent; const meta: Meta = { title: 'Prime/Misc/ProgressSpinner', - component: ProgressSpinnerComponent, + component: ExtraProgressSpinnerComponent, tags: ['autodocs'], decorators: [ - moduleMetadata({ imports: [ProgressSpinnerComponent, ProgressSpinnerSizesComponent, ProgressSpinnerMonochromeComponent] }) + moduleMetadata({ imports: [ExtraProgressSpinnerComponent, ProgressSpinnerSizesComponent, ProgressSpinnerMonochromeComponent] }) ], parameters: { docs: { @@ -18,8 +18,8 @@ const meta: Meta = { component: `Используется для отображения индикатора процесса/состояния загрузки неопределенного времени. \`\`\`typescript -import { ProgressSpinnerComponent } from '@cdek-it/angular-ui-kit'; -\`\`\``, +import { ExtraProgressSpinnerComponent } from '@cdek-it/angular-ui-kit'; +\`\`\`, }, }, designTokens: { prefix: '--p-progressspinner' }, @@ -76,13 +76,13 @@ export default meta; type Story = StoryObj; const commonTemplate = ` - +> `; // ── Default ────────────────────────────────────────────────────────────────── @@ -90,7 +90,7 @@ export const Default: Story = { name: 'Default', render: (args) => { const parts: string[] = []; - + if (args.size && args.size !== 'medium') parts.push(`size="${args.size}"`); if (!args.multicolor) parts.push(`[multicolor]="false"`); if (args.strokeWidth && args.strokeWidth !== '2') parts.push(`strokeWidth="${args.strokeWidth}"`); @@ -100,7 +100,7 @@ export const Default: Story = { const properties = parts.length > 0 ? ' ' + parts.join('\n ') : ''; const template = ` - + `; return { props: args, template }; }, diff --git a/src/stories/components/radiobutton/radiobutton.stories.ts b/src/stories/components/radiobutton/radiobutton.stories.ts index 760cd599..c942f6b2 100644 --- a/src/stories/components/radiobutton/radiobutton.stories.ts +++ b/src/stories/components/radiobutton/radiobutton.stories.ts @@ -1,6 +1,6 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormsModule } from '@angular/forms'; -import { RadiobuttonComponent } from '../../../lib/components/radiobutton/radiobutton.component'; +import { ExtraRadiobuttonComponent as RadiobuttonComponent } from '../../../lib/components/radiobutton/radiobutton.component'; import { RadiobuttonGroupComponent, Group } from './examples/radiobutton-group.component'; import { RadiobuttonInvalidComponent, Invalid } from './examples/radiobutton-invalid.component'; import { RadiobuttonDisabledComponent, Disabled } from './examples/radiobutton-disabled.component'; @@ -106,7 +106,7 @@ export const Default: Story = { if (args.invalid) parts.push(`[invalid]="true"`); if (args.variant && args.variant !== 'outlined') parts.push(`variant="${args.variant}"`); - const template = ``; + const template = ``; return { props: { ...args, selected: 'option1' }, template }; }, parameters: { diff --git a/src/stories/components/skeleton/skeleton.stories.ts b/src/stories/components/skeleton/skeleton.stories.ts index 934ee651..752121ed 100644 --- a/src/stories/components/skeleton/skeleton.stories.ts +++ b/src/stories/components/skeleton/skeleton.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { SkeletonComponent } from '../../../lib/components/skeleton/skeleton.component'; +import { ExtraSkeletonComponent as SkeletonComponent } from '../../../lib/components/skeleton/skeleton.component'; import { SkeletonRectanglesComponent, Rectangles } from './examples/skeleton-rectangles.component'; import { SkeletonCircleComponent, Circle } from './examples/skeleton-circle.component'; import { SkeletonCardPlaceholderComponent, CardPlaceholder } from './examples/skeleton-card-placeholder.component'; @@ -121,8 +121,8 @@ export const Default: Story = { if (args.borderRadius) parts.push(`borderRadius="${args.borderRadius}"`); const template = parts.length - ? `` - : ``; + ? `` + : ``; return { props: { ...args, size: effectiveSize }, template }; }, diff --git a/src/stories/components/slider/examples/slider-disabled.component.ts b/src/stories/components/slider/examples/slider-disabled.component.ts index 8926e586..b1ff55fb 100644 --- a/src/stories/components/slider/examples/slider-disabled.component.ts +++ b/src/stories/components/slider/examples/slider-disabled.component.ts @@ -1,10 +1,10 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { SliderComponent } from '../../../../lib/components/slider/slider.component'; +import { ExtraSliderComponent } from '../../../../lib/components/slider/slider.component'; const template = `
- +
`; const styles = ''; @@ -12,7 +12,7 @@ const styles = ''; @Component({ selector: 'app-slider-disabled', standalone: true, - imports: [SliderComponent], + imports: [ExtraSliderComponent], template, styles, }) @@ -29,14 +29,14 @@ export const Disabled: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { SliderComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraSliderComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-slider-disabled', standalone: true, - imports: [SliderComponent], + imports: [ExtraSliderComponent], template: \` - + \`, }) export class SliderDisabledComponent {} diff --git a/src/stories/components/slider/examples/slider-range.component.ts b/src/stories/components/slider/examples/slider-range.component.ts index 246bdaf3..a7f72547 100644 --- a/src/stories/components/slider/examples/slider-range.component.ts +++ b/src/stories/components/slider/examples/slider-range.component.ts @@ -1,11 +1,11 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { SliderComponent } from '../../../../lib/components/slider/slider.component'; +import { ExtraSliderComponent } from '../../../../lib/components/slider/slider.component'; const template = `
- +
`; const styles = ''; @@ -13,7 +13,7 @@ const styles = ''; @Component({ selector: 'app-slider-range', standalone: true, - imports: [SliderComponent, FormsModule], + imports: [ExtraSliderComponent, FormsModule], template, styles, }) @@ -33,14 +33,14 @@ export const Range: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { SliderComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraSliderComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-slider-range', standalone: true, - imports: [SliderComponent, FormsModule], + imports: [ExtraSliderComponent, FormsModule], template: \` - + \`, }) export class SliderRangeComponent { diff --git a/src/stories/components/slider/examples/slider-step.component.ts b/src/stories/components/slider/examples/slider-step.component.ts index 0c37041a..4ea85e0f 100644 --- a/src/stories/components/slider/examples/slider-step.component.ts +++ b/src/stories/components/slider/examples/slider-step.component.ts @@ -1,11 +1,11 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { SliderComponent } from '../../../../lib/components/slider/slider.component'; +import { ExtraSliderComponent } from '../../../../lib/components/slider/slider.component'; const template = `
- +
`; const styles = ''; @@ -13,7 +13,7 @@ const styles = ''; @Component({ selector: 'app-slider-step', standalone: true, - imports: [SliderComponent, FormsModule], + imports: [ExtraSliderComponent, FormsModule], template, styles, }) @@ -33,14 +33,14 @@ export const Step: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { SliderComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraSliderComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-slider-step', standalone: true, - imports: [SliderComponent, FormsModule], + imports: [ExtraSliderComponent, FormsModule], template: \` - + \`, }) export class SliderStepComponent { diff --git a/src/stories/components/slider/examples/slider-vertical.component.ts b/src/stories/components/slider/examples/slider-vertical.component.ts index 9b792395..652f402e 100644 --- a/src/stories/components/slider/examples/slider-vertical.component.ts +++ b/src/stories/components/slider/examples/slider-vertical.component.ts @@ -1,11 +1,11 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { SliderComponent } from '../../../../lib/components/slider/slider.component'; +import { ExtraSliderComponent } from '../../../../lib/components/slider/slider.component'; const template = `
- +
`; const styles = ''; @@ -13,7 +13,7 @@ const styles = ''; @Component({ selector: 'app-slider-vertical', standalone: true, - imports: [SliderComponent, FormsModule], + imports: [ExtraSliderComponent, FormsModule], template, styles, }) @@ -33,15 +33,15 @@ export const Vertical: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { SliderComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraSliderComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-slider-vertical', standalone: true, - imports: [SliderComponent, FormsModule], + imports: [ExtraSliderComponent, FormsModule], template: \`
- +
\`, }) diff --git a/src/stories/components/slider/slider.stories.ts b/src/stories/components/slider/slider.stories.ts index f38d8f35..2366ad7d 100644 --- a/src/stories/components/slider/slider.stories.ts +++ b/src/stories/components/slider/slider.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { SliderComponent } from '../../../lib/components/slider/slider.component'; +import { ExtraSliderComponent as SliderComponent } from '../../../lib/components/slider/slider.component'; import { SliderRangeComponent, Range } from './examples/slider-range.component'; import { SliderStepComponent, Step } from './examples/slider-step.component'; import { SliderVerticalComponent, Vertical } from './examples/slider-vertical.component'; @@ -26,7 +26,7 @@ const meta: Meta = { component: `Слайдер позволяет выбрать числовое значение или диапазон путём перемещения ползунка. \`\`\`typescript -import { SliderComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraSliderComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -117,8 +117,8 @@ export const Default: Story = { if (args.disabled) parts.push(`[disabled]="true"`); const template = parts.length - ? `` - : ``; + ? `` + : ``; return { props: args, template }; }, diff --git a/src/stories/components/tag/examples/tag-icon.component.ts b/src/stories/components/tag/examples/tag-icon.component.ts index ac772d9e..58c16892 100644 --- a/src/stories/components/tag/examples/tag-icon.component.ts +++ b/src/stories/components/tag/examples/tag-icon.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { TagComponent } from '../../../../lib/components/tag/tag.component'; +import { ExtraTagComponent } from '../../../../lib/components/tag/tag.component'; const template = `
- +
`; @Component({ selector: 'app-tag-icon', standalone: true, - imports: [TagComponent], + imports: [ExtraTagComponent], template, }) export class TagIconComponent { } @@ -27,14 +27,14 @@ export const WithIcon: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { TagComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraTagComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-tag-icon', standalone: true, - imports: [TagComponent], + imports: [ExtraTagComponent], template: \` - + \`, }) export class TagIconComponent {} diff --git a/src/stories/components/tag/examples/tag-rounded.component.ts b/src/stories/components/tag/examples/tag-rounded.component.ts index 9a703701..ae2549dd 100644 --- a/src/stories/components/tag/examples/tag-rounded.component.ts +++ b/src/stories/components/tag/examples/tag-rounded.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { TagComponent } from '../../../../lib/components/tag/tag.component'; +import { ExtraTagComponent } from '../../../../lib/components/tag/tag.component'; const template = `
- +
`; @Component({ selector: 'app-tag-rounded', standalone: true, - imports: [TagComponent], + imports: [ExtraTagComponent], template, }) export class TagRoundedComponent { } @@ -27,14 +27,14 @@ export const Rounded: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { TagComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraTagComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-tag-rounded', standalone: true, - imports: [TagComponent], + imports: [ExtraTagComponent], template: \` - + \`, }) export class TagRoundedComponent {} diff --git a/src/stories/components/tag/examples/tag-severity.component.ts b/src/stories/components/tag/examples/tag-severity.component.ts index 127d773a..0aa66574 100644 --- a/src/stories/components/tag/examples/tag-severity.component.ts +++ b/src/stories/components/tag/examples/tag-severity.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { TagComponent } from '../../../../lib/components/tag/tag.component'; +import { ExtraTagComponent } from '../../../../lib/components/tag/tag.component'; const template = `
- +
`; @Component({ selector: 'app-tag-severity', standalone: true, - imports: [TagComponent], + imports: [ExtraTagComponent], template, }) export class TagSeverityComponent { } @@ -27,14 +27,14 @@ export const Severity: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { TagComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraTagComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-tag-severity', standalone: true, - imports: [TagComponent], + imports: [ExtraTagComponent], template: \` - + \`, }) export class TagSeverityComponent {} diff --git a/src/stories/components/tag/tag.stories.ts b/src/stories/components/tag/tag.stories.ts index c36ada31..7a4d9104 100644 --- a/src/stories/components/tag/tag.stories.ts +++ b/src/stories/components/tag/tag.stories.ts @@ -1,19 +1,19 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { TagComponent } from '../../../lib/components/tag/tag.component'; +import { ExtraTagComponent } from '../../../lib/components/tag/tag.component'; import { TagSeverityComponent } from './examples/tag-severity.component'; import { TagRoundedComponent } from './examples/tag-rounded.component'; import { TagIconComponent } from './examples/tag-icon.component'; -type TagArgs = TagComponent; +type TagArgs = ExtraTagComponent; const meta: Meta = { title: 'Components/Misc/Tag', - component: TagComponent, + component: ExtraTagComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - TagComponent, + ExtraTagComponent, TagSeverityComponent, TagRoundedComponent, TagIconComponent, @@ -78,12 +78,12 @@ export default meta; type Story = StoryObj; const commonTemplate = ` - +> `; // ── Default ────────────────────────────────────────────────────────────────── @@ -97,8 +97,8 @@ export const Default: Story = { if (args.icon) parts.push(`icon="${args.icon}"`); const template = parts.length - ? `` - : ``; + ? `` + : ``; return { props: args, template }; }, @@ -122,14 +122,14 @@ export const Severity: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { TagComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraTagComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-tag-severity', standalone: true, - imports: [TagComponent], + imports: [ExtraTagComponent], template: \` - + \`, }) export class TagSeverityComponent {} @@ -150,14 +150,14 @@ export const Rounded: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { TagComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraTagComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-tag-rounded', standalone: true, - imports: [TagComponent], + imports: [ExtraTagComponent], template: \` - + \`, }) export class TagRoundedComponent {} @@ -178,14 +178,14 @@ export const WithIcon: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { TagComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraTagComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-tag-icon', standalone: true, - imports: [TagComponent], + imports: [ExtraTagComponent], template: \` - + \`, }) export class TagIconComponent {} diff --git a/src/stories/components/tieredmenu/examples/tieredmenu-basic.component.ts b/src/stories/components/tieredmenu/examples/tieredmenu-basic.component.ts index 9b26b371..b902042f 100644 --- a/src/stories/components/tieredmenu/examples/tieredmenu-basic.component.ts +++ b/src/stories/components/tieredmenu/examples/tieredmenu-basic.component.ts @@ -1,12 +1,12 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { MenuItem } from 'primeng/api'; -import { TieredMenuComponent } from '../../../../lib/components/tieredmenu/tieredmenu.component'; +import { ExtraTieredMenuComponent } from '../../../../lib/components/tieredmenu/tieredmenu.component'; import { basicItems } from '../tieredmenu.data'; const template = `
- +
`; const styles = ''; @@ -14,7 +14,7 @@ const styles = ''; @Component({ selector: 'app-tieredmenu-basic', standalone: true, - imports: [TieredMenuComponent], + imports: [ExtraTieredMenuComponent], template, styles, }) @@ -34,12 +34,12 @@ export const Basic: StoryObj = { code: ` import { Component } from '@angular/core'; import { MenuItem } from 'primeng/api'; -import { TieredMenuComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraTieredMenuComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-tieredmenu-basic', standalone: true, - imports: [TieredMenuComponent], + imports: [ExtraTieredMenuComponent], template: \` \`, diff --git a/src/stories/components/tieredmenu/examples/tieredmenu-selected.component.ts b/src/stories/components/tieredmenu/examples/tieredmenu-selected.component.ts index dc31fe2e..b075cc2a 100644 --- a/src/stories/components/tieredmenu/examples/tieredmenu-selected.component.ts +++ b/src/stories/components/tieredmenu/examples/tieredmenu-selected.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { MenuItem } from 'primeng/api'; -import { TieredMenuComponent } from '../../../../lib/components/tieredmenu/tieredmenu.component'; +import { ExtraTieredMenuComponent } from '../../../../lib/components/tieredmenu/tieredmenu.component'; const template = `
@@ -13,7 +13,7 @@ const styles = ''; @Component({ selector: 'app-tieredmenu-selected', standalone: true, - imports: [TieredMenuComponent], + imports: [ExtraTieredMenuComponent], template, styles, }) @@ -37,14 +37,14 @@ export const WithSelected: StoryObj = { code: ` import { Component } from '@angular/core'; import { MenuItem } from 'primeng/api'; -import { TieredMenuComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraTieredMenuComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-tieredmenu-selected', standalone: true, - imports: [TieredMenuComponent], + imports: [ExtraTieredMenuComponent], template: \` - + \`, }) export class TieredMenuSelectedComponent { diff --git a/src/stories/components/tieredmenu/tieredmenu.stories.ts b/src/stories/components/tieredmenu/tieredmenu.stories.ts index 9fb5b57f..fed22009 100644 --- a/src/stories/components/tieredmenu/tieredmenu.stories.ts +++ b/src/stories/components/tieredmenu/tieredmenu.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { TieredMenuComponent } from '../../../lib/components/tieredmenu/tieredmenu.component'; +import { ExtraTieredMenuComponent as TieredMenuComponent } from '../../../lib/components/tieredmenu/tieredmenu.component'; import { TieredMenuBasicComponent, Basic } from './examples/tieredmenu-basic.component'; import { TieredMenuSelectedComponent, WithSelected } from './examples/tieredmenu-selected.component'; import { TieredMenuCustomComponent, Custom } from './examples/tieredmenu-custom.component'; @@ -24,8 +24,8 @@ const meta: Meta = { component: `Компонент для отображения иерархического меню с вложенными подменю, которые открываются в виде вложенных оверлеев при наведении на пункт. \`\`\`typescript -import { TieredMenuComponent } from '@cdek-it/angular-ui-kit'; -\`\`\``, +import { ExtraTieredMenuComponent as TieredMenuComponent } from '@cdek-it/angular-ui-kit'; +\`\`\`", }, }, designTokens: { prefix: '--p-tieredmenu' }, diff --git a/src/stories/components/timeline/timeline.stories.ts b/src/stories/components/timeline/timeline.stories.ts index 41086ccf..5f4d04f1 100644 --- a/src/stories/components/timeline/timeline.stories.ts +++ b/src/stories/components/timeline/timeline.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj } from '@storybook/angular'; -import { TimelineComponent } from '../../../lib/components/timeline/timeline.component'; +import { ExtraTimelineComponent as TimelineComponent } from '../../../lib/components/timeline/timeline.component'; type TimelineArgs = TimelineComponent & { verticalAlign: string; horizontalAlign: string }; type Story = StoryObj; @@ -20,7 +20,7 @@ const meta: Meta = { docs: { description: { component: - 'Компонент для визуализации последовательности событий в хронологическом порядке. Поддерживает горизонтальную и вертикальную ориентацию, кастомные маркеры.\n\n```typescript\nimport { TimelineComponent } from \'@cdek-it/angular-ui-kit\';\n```', + 'Компонент для визуализации последовательности событий в хронологическом порядке. Поддерживает горизонтальную и вертикальную ориентацию, кастомные маркеры.\n\n```typescript\nimport { ExtraTimelineComponent as TimelineComponent } from \'@cdek-it/angular-ui-kit\';\n```', }, }, }, @@ -144,14 +144,14 @@ function renderStory(args: any) { const attrs = parts.join('\n '); - const template = `
{{ event.value }}
{{ event.caption }}
-
`; +`; return { props: { ...args, value: args.value }, template }; } @@ -209,14 +209,14 @@ export const Opposite: Story = { const attrs = parts.join('\n '); - const template = ` {{ event.value }} {{ event.caption }} -`; +`; return { props: { ...args, value: args.value }, template }; }, diff --git a/src/stories/components/tooltip/tooltip.stories.ts b/src/stories/components/tooltip/tooltip.stories.ts index 2c46bd09..eae13e8f 100644 --- a/src/stories/components/tooltip/tooltip.stories.ts +++ b/src/stories/components/tooltip/tooltip.stories.ts @@ -1,6 +1,6 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { TooltipDirective } from '../../../lib/components/tooltip/tooltip.directive'; -import { ButtonComponent } from '../../../lib/components/button/button.component'; +import { ExtraTooltipDirective as TooltipDirective } from '../../../lib/components/tooltip/tooltip.directive'; +import { ExtraButtonComponent as ButtonComponent } from '../../../lib/components/button/button.component'; const meta: Meta = { title: 'Prime/Form/Tooltip', @@ -17,7 +17,7 @@ const meta: Meta = { component: `Компонент для отображения информационного текста при наведении на элемент. \`\`\`typescript -import { TooltipDirective } from '@cdek-it/angular-ui-kit'; +import { ExtraTooltipDirective as TooltipDirective } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -87,15 +87,16 @@ export default meta; type Story = StoryObj; const commonTemplate = ` - +> + `; // ── Default ────────────────────────────────────────────────────────────────── @@ -104,7 +105,7 @@ export const Default: Story = { render: (args) => { const parts: string[] = []; - if (args.tooltip) parts.push(`tooltip="${args.tooltip}"`); + if (args.tooltip) parts.push(`extra-tooltip="${args.tooltip}"`); if (args.position && args.position !== 'right') parts.push(`position="${args.position}"`); if (args.event && args.event !== 'hover') parts.push(`event="${args.event}"`); if (args.showDelay) parts.push(`[showDelay]="${args.showDelay}"`); @@ -113,7 +114,7 @@ export const Default: Story = { if (args.label) parts.push(`label="${args.label}"`); const template = ` - + `; return { props: args, template }; }, @@ -139,7 +140,7 @@ export const Positions: Story = { docs: { description: { story: 'Различные варианты позиционирования (измените через Controls).' }, source: { - code: `` + code: `` } } } @@ -156,7 +157,7 @@ export const Delay: Story = { docs: { description: { story: 'Подсказка может появляться или скрываться с задержкой в миллисекундах.' }, source: { - code: `` + code: `` } } } @@ -168,7 +169,7 @@ export const EventFocus: Story = { props: args, template: ` ` + code: `` } } } From f2553035a33a4170b845b3376a6cc6b894ee820b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Apr 2026 08:09:16 +0000 Subject: [PATCH 199/258] chore(release): sync src/lib package version to v0.0.3-test --- src/lib/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/package.json b/src/lib/package.json index ef608e84..f935a24f 100644 --- a/src/lib/package.json +++ b/src/lib/package.json @@ -1,6 +1,6 @@ { "name": "@cdek-it/angular-ui-kit", - "version": "0.0.3", + "version": "0.0.3-test", "peerDependencies": { "@angular/common": "^20.3.15", "@angular/core": "^20.3.15" From 9290bdc6fa2c3fc88aeb4aa2eda305f2af1c1ed8 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Sun, 26 Apr 2026 23:39:57 +0700 Subject: [PATCH 200/258] DS-559 --- .github/workflows/npm-publish.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index d11dfef2..c7fafd29 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -33,4 +33,28 @@ jobs: git add src/lib/package.json if git diff --cached --quiet; then echo "No changes to commit"; else git commit -m "chore(release): sync src/lib package version to ${{github.ref_name}}" && git push origin HEAD:refs/heads/${{ github.event.release.target_commitish }}; fi - run: npm run build:lib - - run: npm publish + - name: Prepare dist/package.json + run: | + set -euo pipefail + # Ensure dist exists and has its own package.json generated by the build + if [ ! -d dist ]; then echo "dist directory not found"; exit 1; fi + if [ ! -f dist/package.json ]; then echo "dist/package.json not found — expected build to generate it"; exit 1; fi + # Sync version in dist/package.json with root package.json + node -e "const fs=require('fs'); const root=JSON.parse(fs.readFileSync('package.json')); const p='dist/package.json'; const d=JSON.parse(fs.readFileSync(p)); if(d.version===root.version){console.log(p,'already has version',d.version); process.exit(0);} d.version=root.version; fs.writeFileSync(p, JSON.stringify(d,null,2)+'\n'); console.log('Updated',p,'with version',root.version);" + - name: Fix package.json issues inside dist (optional) + run: | + npm --prefix ./dist pkg fix || true + - name: Publish to npm from dist (use tag for prerelease versions) + run: | + set -euo pipefail + PACKAGE_DIR=dist + VERSION=$(node -e "console.log(require('./${PACKAGE_DIR}/package.json').version)") + echo "Package version: $VERSION (from ${PACKAGE_DIR}/package.json)" + if [[ "$VERSION" == *-* ]]; then + TAG=$(echo "$VERSION" | sed -E 's/^[0-9]+\.[0-9]+\.[0-9]+-([^\.]+).*/\1/') + echo "Detected prerelease tag: $TAG" + npm publish "$PACKAGE_DIR" --tag "$TAG" + else + echo "Publishing as latest" + npm publish "$PACKAGE_DIR" + fi From aeeba3a93999c67c976011fb94ee1ea9309da15b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Apr 2026 16:42:42 +0000 Subject: [PATCH 201/258] chore(release): sync src/lib package version to v0.0.4-test --- src/lib/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/package.json b/src/lib/package.json index f935a24f..56afc164 100644 --- a/src/lib/package.json +++ b/src/lib/package.json @@ -1,6 +1,6 @@ { "name": "@cdek-it/angular-ui-kit", - "version": "0.0.3-test", + "version": "0.0.4-test", "peerDependencies": { "@angular/common": "^20.3.15", "@angular/core": "^20.3.15" From 72c9e6249dd09ca3847e10f2f713062fa909a83a Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Sun, 26 Apr 2026 23:46:07 +0700 Subject: [PATCH 202/258] DS-559 --- src/lib/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/package.json b/src/lib/package.json index f935a24f..7990e662 100644 --- a/src/lib/package.json +++ b/src/lib/package.json @@ -1,6 +1,6 @@ { "name": "@cdek-it/angular-ui-kit", - "version": "0.0.3-test", + "version": "0.2.0-test", "peerDependencies": { "@angular/common": "^20.3.15", "@angular/core": "^20.3.15" From a6517b7ed823f0ef0b449e7b08aa15aa71eba34a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Apr 2026 16:48:29 +0000 Subject: [PATCH 203/258] chore(release): sync src/lib package version to v0.2.0-test --- src/lib/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/package.json b/src/lib/package.json index 56afc164..7990e662 100644 --- a/src/lib/package.json +++ b/src/lib/package.json @@ -1,6 +1,6 @@ { "name": "@cdek-it/angular-ui-kit", - "version": "0.0.4-test", + "version": "0.2.0-test", "peerDependencies": { "@angular/common": "^20.3.15", "@angular/core": "^20.3.15" From 28c8637f7b922b71abca1c29fe65e3aff300fd59 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Sun, 26 Apr 2026 23:50:36 +0700 Subject: [PATCH 204/258] DS-559 --- src/lib/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/package.json b/src/lib/package.json index 7990e662..7ec01eba 100644 --- a/src/lib/package.json +++ b/src/lib/package.json @@ -1,6 +1,6 @@ { "name": "@cdek-it/angular-ui-kit", - "version": "0.2.0-test", + "version": "0.2.1-test", "peerDependencies": { "@angular/common": "^20.3.15", "@angular/core": "^20.3.15" From c954f150ed2b094e5df3eb57b23c6cee439558fa Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Sun, 26 Apr 2026 23:59:33 +0700 Subject: [PATCH 205/258] DS-559 --- .github/workflows/npm-publish.yml | 39 ++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index c7fafd29..3542b204 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -44,17 +44,50 @@ jobs: - name: Fix package.json issues inside dist (optional) run: | npm --prefix ./dist pkg fix || true - - name: Publish to npm from dist (use tag for prerelease versions) + - name: Debug dist/package.json + run: | + echo "----- dist/package.json -----" + cat dist/package.json || true + echo "----- dist ls -----" + ls -la dist || true + - name: Normalize dist/package.json (ensure correct name & version) + run: | + node -e "const fs=require('fs'); const root=require('./package.json'); const srcExists=fs.existsSync('src/lib/package.json'); const src=srcExists? require('./src/lib/package.json'): null; const p='dist/package.json'; const d=JSON.parse(fs.readFileSync(p)); const wantedName= src? src.name : root.name; const wantedVersion=root.version; let changed=false; if(d.name!==wantedName){console.log('name:',d.name,'->',wantedName); d.name=wantedName; changed=true;} if(d.version!==wantedVersion){console.log('version:',d.version,'->',wantedVersion); d.version=wantedVersion; changed=true;} if(changed){fs.writeFileSync(p, JSON.stringify(d,null,2)+'\n'); console.log('Updated',p);} else {console.log(p,'already correct');}" + - name: Pack dist and verify package.json inside tarball run: | set -euo pipefail PACKAGE_DIR=dist VERSION=$(node -e "console.log(require('./${PACKAGE_DIR}/package.json').version)") echo "Package version: $VERSION (from ${PACKAGE_DIR}/package.json)" + # create tarball in workspace + TARFILE=$(npm pack "$PACKAGE_DIR") + echo "Created tarball: $TARFILE" + # extract package.json from tarball and print + mkdir -p verify_unpack + tar -xzf "$TARFILE" -C verify_unpack + echo "----- package.json inside tarball -----" + cat verify_unpack/package/package.json + # read version from inside tarball + INNER_VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('verify_unpack/package/package.json')).version)") + INNER_NAME=$(node -e "console.log(JSON.parse(require('fs').readFileSync('verify_unpack/package/package.json')).name)") + echo "Inner package name: $INNER_NAME, version: $INNER_VERSION" + if [ "$INNER_VERSION" != "$VERSION" ]; then + echo "Error: version inside tarball ($INNER_VERSION) does not match dist/package.json ($VERSION)"; exit 1 + fi + echo "Tarball verified." + # make TARFILE available to next step + echo "TARFILE=$TARFILE" >> $GITHUB_ENV + - name: Publish verified tarball to npm (use tag for prerelease versions) + run: | + set -euo pipefail + PACKAGE_DIR=dist + VERSION=$(node -e "console.log(require('./${PACKAGE_DIR}/package.json').version)") + TARFILE=${{ env.TARFILE }} if [[ "$VERSION" == *-* ]]; then TAG=$(echo "$VERSION" | sed -E 's/^[0-9]+\.[0-9]+\.[0-9]+-([^\.]+).*/\1/') echo "Detected prerelease tag: $TAG" - npm publish "$PACKAGE_DIR" --tag "$TAG" + npm publish "$TARFILE" --tag "$TAG" else echo "Publishing as latest" - npm publish "$PACKAGE_DIR" + npm publish "$TARFILE" fi From ad73c72901ec1d8a9895d4c1856d86f5a5dde657 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Apr 2026 17:01:32 +0000 Subject: [PATCH 206/258] chore(release): sync src/lib package version to v0.2.2-test --- src/lib/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/package.json b/src/lib/package.json index 7ec01eba..db1dcc1d 100644 --- a/src/lib/package.json +++ b/src/lib/package.json @@ -1,6 +1,6 @@ { "name": "@cdek-it/angular-ui-kit", - "version": "0.2.1-test", + "version": "0.2.2-test", "peerDependencies": { "@angular/common": "^20.3.15", "@angular/core": "^20.3.15" From 43ebf4facbbf433d9be545fb1dea9a7c77a321cc Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Mon, 27 Apr 2026 00:03:32 +0700 Subject: [PATCH 207/258] DS-559 --- .github/workflows/npm-publish.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 3542b204..28d3c01e 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -60,7 +60,8 @@ jobs: VERSION=$(node -e "console.log(require('./${PACKAGE_DIR}/package.json').version)") echo "Package version: $VERSION (from ${PACKAGE_DIR}/package.json)" # create tarball in workspace - TARFILE=$(npm pack "$PACKAGE_DIR") + # ensure we pack the local folder, not a package from the registry + TARFILE=$(npm pack "./$PACKAGE_DIR") echo "Created tarball: $TARFILE" # extract package.json from tarball and print mkdir -p verify_unpack From 2319fa402219275c01c2c55a8723900b18aece83 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Apr 2026 17:05:33 +0000 Subject: [PATCH 208/258] chore(release): sync src/lib package version to v0.2.3-test --- src/lib/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/package.json b/src/lib/package.json index db1dcc1d..e250e26e 100644 --- a/src/lib/package.json +++ b/src/lib/package.json @@ -1,6 +1,6 @@ { "name": "@cdek-it/angular-ui-kit", - "version": "0.2.2-test", + "version": "0.2.3-test", "peerDependencies": { "@angular/common": "^20.3.15", "@angular/core": "^20.3.15" From dc5fc709f8d9fee20624146b81cc31cd88af7835 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Mon, 27 Apr 2026 00:07:49 +0700 Subject: [PATCH 209/258] DS-559 --- .github/workflows/npm-publish.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 28d3c01e..a028c16d 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -50,9 +50,13 @@ jobs: cat dist/package.json || true echo "----- dist ls -----" ls -la dist || true - - name: Normalize dist/package.json (ensure correct name & version) + - name: Normalize dist/package.json (ensure correct name, version and repository) run: | - node -e "const fs=require('fs'); const root=require('./package.json'); const srcExists=fs.existsSync('src/lib/package.json'); const src=srcExists? require('./src/lib/package.json'): null; const p='dist/package.json'; const d=JSON.parse(fs.readFileSync(p)); const wantedName= src? src.name : root.name; const wantedVersion=root.version; let changed=false; if(d.name!==wantedName){console.log('name:',d.name,'->',wantedName); d.name=wantedName; changed=true;} if(d.version!==wantedVersion){console.log('version:',d.version,'->',wantedVersion); d.version=wantedVersion; changed=true;} if(changed){fs.writeFileSync(p, JSON.stringify(d,null,2)+'\n'); console.log('Updated',p);} else {console.log(p,'already correct');}" + node -e "const fs=require('fs'); const root=require('./package.json'); const srcExists=fs.existsSync('src/lib/package.json'); const src=srcExists? require('./src/lib/package.json'): null; const p='dist/package.json'; const d=JSON.parse(fs.readFileSync(p)); const wantedName= src? src.name : root.name; const wantedVersion=root.version; let changed=false; if(d.name!==wantedName){console.log('name:',d.name,'->',wantedName); d.name=wantedName; changed=true;} if(d.version!==wantedVersion){console.log('version:',d.version,'->',wantedVersion); d.version=wantedVersion; changed=true;} // ensure repository.url exists and matches root + const normalizeRepo=(r)=>{ if(!r) return null; if(typeof r==='string') return r.replace(/^git\+/, '').replace(/\.git$/,''); if(r.url) return r.url.replace(/^git\+/, '').replace(/\.git$/,''); return null; }; + const wantedRepo = normalizeRepo(root.repository) || (process.env.GITHUB_REPOSITORY? 'https://github.com/'+process.env.GITHUB_REPOSITORY : null); + if(wantedRepo){ if(!d.repository) { d.repository = { type: 'git', url: wantedRepo }; console.log('repository: set ->',wantedRepo); changed=true; } else { const currentRepo=normalizeRepo(d.repository); if(currentRepo!==wantedRepo){ console.log('repository:',currentRepo,'->',wantedRepo); d.repository = { type: 'git', url: wantedRepo }; changed=true; } } } + if(changed){fs.writeFileSync(p, JSON.stringify(d,null,2)+'\n'); console.log('Updated',p);} else {console.log(p,'already correct');}" - name: Pack dist and verify package.json inside tarball run: | set -euo pipefail From 5c84768bac71267c6d31b90a62acc274d755433a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Apr 2026 17:09:52 +0000 Subject: [PATCH 210/258] chore(release): sync src/lib package version to v0.2.4-test --- src/lib/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/package.json b/src/lib/package.json index e250e26e..90d73023 100644 --- a/src/lib/package.json +++ b/src/lib/package.json @@ -1,6 +1,6 @@ { "name": "@cdek-it/angular-ui-kit", - "version": "0.2.3-test", + "version": "0.2.4-test", "peerDependencies": { "@angular/common": "^20.3.15", "@angular/core": "^20.3.15" From 417d8223afeffcf9cc64e1258b4aaeb9badb23a3 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Mon, 27 Apr 2026 00:19:42 +0700 Subject: [PATCH 211/258] DS-559 --- .github/workflows/npm-publish.yml | 39 +++++++++---------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index a028c16d..25afca18 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -27,11 +27,12 @@ jobs: version: ${{github.ref_name}} - name: Sync src/lib/package.json version with root package.json run: | - node -e "const fs=require('fs'); const path='src/lib/package.json'; const root=JSON.parse(fs.readFileSync('package.json')); const lib=JSON.parse(fs.readFileSync(path)); if(lib.version===root.version){console.log('Already up-to-date'); process.exit(0);} lib.version=root.version; fs.writeFileSync(path, JSON.stringify(lib,null,2)+'\n'); console.log('Updated',path,'to',root.version);" + node -e "const fs=require('fs'); const path='src/lib/package.json'; const root=JSON.parse(fs.readFileSync('package.json')); const lib=JSON.parse(fs.readFileSync(path)); if(lib.version!==root.version){ lib.version=root.version; fs.writeFileSync(path, JSON.stringify(lib,null,2)+'\n'); }" git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git add src/lib/package.json - if git diff --cached --quiet; then echo "No changes to commit"; else git commit -m "chore(release): sync src/lib package version to ${{github.ref_name}}" && git push origin HEAD:refs/heads/${{ github.event.release.target_commitish }}; fi + # commit only if there are staged changes + git diff --cached --quiet || (git commit -m "chore(release): sync src/lib package version to ${{github.ref_name}}" && git push origin HEAD:refs/heads/${{ github.event.release.target_commitish }}) - run: npm run build:lib - name: Prepare dist/package.json run: | @@ -39,47 +40,29 @@ jobs: # Ensure dist exists and has its own package.json generated by the build if [ ! -d dist ]; then echo "dist directory not found"; exit 1; fi if [ ! -f dist/package.json ]; then echo "dist/package.json not found — expected build to generate it"; exit 1; fi - # Sync version in dist/package.json with root package.json - node -e "const fs=require('fs'); const root=JSON.parse(fs.readFileSync('package.json')); const p='dist/package.json'; const d=JSON.parse(fs.readFileSync(p)); if(d.version===root.version){console.log(p,'already has version',d.version); process.exit(0);} d.version=root.version; fs.writeFileSync(p, JSON.stringify(d,null,2)+'\n'); console.log('Updated',p,'with version',root.version);" + # Sync version in dist/package.json with root package.json (silent) + node -e "const fs=require('fs'); const root=JSON.parse(fs.readFileSync('package.json')); const p='dist/package.json'; const d=JSON.parse(fs.readFileSync(p)); if(d.version!==root.version){ d.version=root.version; fs.writeFileSync(p, JSON.stringify(d,null,2)+'\n'); }" - name: Fix package.json issues inside dist (optional) run: | npm --prefix ./dist pkg fix || true - - name: Debug dist/package.json - run: | - echo "----- dist/package.json -----" - cat dist/package.json || true - echo "----- dist ls -----" - ls -la dist || true - name: Normalize dist/package.json (ensure correct name, version and repository) run: | - node -e "const fs=require('fs'); const root=require('./package.json'); const srcExists=fs.existsSync('src/lib/package.json'); const src=srcExists? require('./src/lib/package.json'): null; const p='dist/package.json'; const d=JSON.parse(fs.readFileSync(p)); const wantedName= src? src.name : root.name; const wantedVersion=root.version; let changed=false; if(d.name!==wantedName){console.log('name:',d.name,'->',wantedName); d.name=wantedName; changed=true;} if(d.version!==wantedVersion){console.log('version:',d.version,'->',wantedVersion); d.version=wantedVersion; changed=true;} // ensure repository.url exists and matches root - const normalizeRepo=(r)=>{ if(!r) return null; if(typeof r==='string') return r.replace(/^git\+/, '').replace(/\.git$/,''); if(r.url) return r.url.replace(/^git\+/, '').replace(/\.git$/,''); return null; }; - const wantedRepo = normalizeRepo(root.repository) || (process.env.GITHUB_REPOSITORY? 'https://github.com/'+process.env.GITHUB_REPOSITORY : null); - if(wantedRepo){ if(!d.repository) { d.repository = { type: 'git', url: wantedRepo }; console.log('repository: set ->',wantedRepo); changed=true; } else { const currentRepo=normalizeRepo(d.repository); if(currentRepo!==wantedRepo){ console.log('repository:',currentRepo,'->',wantedRepo); d.repository = { type: 'git', url: wantedRepo }; changed=true; } } } - if(changed){fs.writeFileSync(p, JSON.stringify(d,null,2)+'\n'); console.log('Updated',p);} else {console.log(p,'already correct');}" + node -e "const fs=require('fs'); const root=require('./package.json'); const srcExists=fs.existsSync('src/lib/package.json'); const src=srcExists? require('./src/lib/package.json'): null; const p='dist/package.json'; const d=JSON.parse(fs.readFileSync(p)); const wantedName= src? src.name : root.name; const wantedVersion=root.version; let changed=false; if(d.name!==wantedName){ d.name=wantedName; changed=true;} if(d.version!==wantedVersion){ d.version=wantedVersion; changed=true;} const normalizeRepo=(r)=>{ if(!r) return null; if(typeof r==='string') return r.replace(/^git\+/, '').replace(/\.git$/,''); if(r.url) return r.url.replace(/^git\+/, '').replace(/\.git$/,''); return null; }; const wantedRepo = normalizeRepo(root.repository) || (process.env.GITHUB_REPOSITORY? 'https://github.com/'+process.env.GITHUB_REPOSITORY : null); if(wantedRepo){ if(!d.repository){ d.repository = { type: 'git', url: wantedRepo }; changed=true; } else { const currentRepo=normalizeRepo(d.repository); if(currentRepo!==wantedRepo){ d.repository = { type: 'git', url: wantedRepo }; changed=true; } } } if(changed){ fs.writeFileSync(p, JSON.stringify(d,null,2)+'\n'); }" - name: Pack dist and verify package.json inside tarball run: | set -euo pipefail PACKAGE_DIR=dist VERSION=$(node -e "console.log(require('./${PACKAGE_DIR}/package.json').version)") - echo "Package version: $VERSION (from ${PACKAGE_DIR}/package.json)" - # create tarball in workspace - # ensure we pack the local folder, not a package from the registry + # create tarball in workspace (pack local folder) TARFILE=$(npm pack "./$PACKAGE_DIR") - echo "Created tarball: $TARFILE" - # extract package.json from tarball and print mkdir -p verify_unpack tar -xzf "$TARFILE" -C verify_unpack - echo "----- package.json inside tarball -----" - cat verify_unpack/package/package.json # read version from inside tarball INNER_VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('verify_unpack/package/package.json')).version)") - INNER_NAME=$(node -e "console.log(JSON.parse(require('fs').readFileSync('verify_unpack/package/package.json')).name)") - echo "Inner package name: $INNER_NAME, version: $INNER_VERSION" if [ "$INNER_VERSION" != "$VERSION" ]; then - echo "Error: version inside tarball ($INNER_VERSION) does not match dist/package.json ($VERSION)"; exit 1 + echo "Error: version inside tarball ($INNER_VERSION) does not match dist/package.json ($VERSION)" >&2 + exit 1 fi - echo "Tarball verified." # make TARFILE available to next step echo "TARFILE=$TARFILE" >> $GITHUB_ENV - name: Publish verified tarball to npm (use tag for prerelease versions) @@ -88,11 +71,11 @@ jobs: PACKAGE_DIR=dist VERSION=$(node -e "console.log(require('./${PACKAGE_DIR}/package.json').version)") TARFILE=${{ env.TARFILE }} + NAME=$(node -e "console.log(require('./${PACKAGE_DIR}/package.json').name)") if [[ "$VERSION" == *-* ]]; then TAG=$(echo "$VERSION" | sed -E 's/^[0-9]+\.[0-9]+\.[0-9]+-([^\.]+).*/\1/') - echo "Detected prerelease tag: $TAG" npm publish "$TARFILE" --tag "$TAG" else - echo "Publishing as latest" npm publish "$TARFILE" fi + echo "Published ${NAME}@${VERSION}" From 39ddb8ca69f8c79601c2ed7cfe77fe261b25595a Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Mon, 27 Apr 2026 00:38:04 +0700 Subject: [PATCH 212/258] DS-559 --- README.md | 64 +++++++++++++++---------------------------------------- 1 file changed, 17 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 49f1abf4..726f97ae 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,35 @@ # angular-ui-kit -angular-ui-kit - это пресет темы для primeng, а также storybook с демонстрацией и документацией используемых компонентов. -Он позволяет быстро и легко строить новые интерфейсы в фирменном стиле CDEK. +`angular-ui-kit` — это полноценная библиотека UI-компонентов и сервисов для Angular с готовыми стилями, storybook для демонстрации и документацией. +Библиотека позволяет быстро и удобно добавлять готовые фирменные компоненты CDEK в приложения. ## Использование -1. Установите пакет @cdek-it/angular-ui-kit +1. Установите пакет `@cdek-it/angular-ui-kit` ```shell npm install @cdek-it/angular-ui-kit ``` -2. Импортируйте пресет темы в ваш angular-проект +2. Подключите провайдеры в ваш angular-проект. Важно: для корректной работы стилей необходимо использовать `provideExtraThemes()` в списке провайдеров, например: ```ts -import Preset from '@cdek-it/angular-ui-kit/dist/theme.preset.ts'; +import { provideExtraThemes } from '@cdek-it/angular-ui-kit'; +import { provideBrowserGlobalErrorListeners } from '@angular/platform-browser'; +import { importProvidersFrom } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; export const appConfig: ApplicationConfig = { providers: [ - ..., - provideAnimations(), - providePrimeNG({ - theme: { - preset: Preset, - options: { - darkModeSelector: false, - cssLayer: false - } - } - }) + provideBrowserGlobalErrorListeners(), + importProvidersFrom(BrowserModule), + provideExtraThemes(), ] }; ``` +`provideExtraThemes()` необходим для правильной интеграции стилей библиотеки в приложение. + ## Используемые технологии и связанные зависимости --- @@ -48,11 +45,14 @@ export const appConfig: ApplicationConfig = { - Storybook 10 +Важно: на данный момент компоненты библиотеки не работают без Zone.js. Убедитесь, что ваше приложение использует zone (Zone.js должен быть подключён). В большинстве стандартных Angular-приложений Zone.js подключён по умолчанию. + ## Структура проекта - `src/app` - базовое angular-приложение. Может использоваться как плейграунд для разработки и отладки. - `src/stories` - набор story с компонентами для storybook. -- `src/prime-preset` - пресет темы для primeng, а также токены. +- `src/prime-preset` - пресет темы и токены (используется библиотекой для совместимости с PrimeNG). +- `src/lib` - исходники компонентов и сервисов библиотеки (компоненты, сервисы, модули и публичный API). ## Запуск storybook @@ -77,33 +77,3 @@ npm run storybook 3. Убедитесь, что все состояния компонента выглядят верно. Если нет - смотрите раздел "[Правила доработки компонентов](#Правила доработки компонентов)" ниже. 4. Создать pull request в `main`, прикрепить его в задачу. Задачу отдать на ревью разработчикам и дизайнерам. В случае замечаний ориентируемся на пункт `3` выше. - -## Правила доработки компонентов - -### Компоненты primeng - -Если компонент несоответствует дизайну в figma, то: - -1. Проверяем верность токенов. Если есть ошибки - сообщаем мейнтейнеру. -2. Если токены верны, и проблему можно решить кастомизацией css - согласуем доработки с мейнтейнером. -3. Если кастомизации css недостаточно, но можно решить проблему через шаблоны - согласуем доработки с мейнтейнером. Пример ниже. -Например, для `inputtext` нужен крестик с очисткой. Непосредственно такой опции в primeng нет, но можно использовать `p-inputIcon` с иконкой крестика, и следующим `source`-кодом в story: - -``` -// template - - - - - -// ts -onClearClick() { - this.value = ''; -} -``` -Важно, что бы в story был верный `source`-код, что бы разработчики могли просто его копировать и с минимальными доработками использовать у себя. -4. Если вариантов решения проблемы через способы выше нет - сообщаем мейнтейнеру. Далее будет подниматься вопрос о необходимости написания своего компонента. - -### Кастомные компоненты - -*todo будут разработаны при необходимости* From 2b4f1de5c6c5eff031418a64c906801ec3980570 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Mon, 27 Apr 2026 00:46:42 +0700 Subject: [PATCH 213/258] DS-559 --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/README.md b/README.md index 726f97ae..9eaf1e4d 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,46 @@ export const appConfig: ApplicationConfig = { `provideExtraThemes()` необходим для правильной интеграции стилей библиотеки в приложение. +## Пример использования компонентов + +Ниже простой пример использования входящих в библиотеку компонентов (вариант — `extra-button` и `extra-tag`). Вставьте в шаблон компонента или story: + +```html +
+ + + + +
+``` + +Примечание: Нужно добавить импорт соответствующего модуля/компонентов библиотеки в ваш модуль или компонент. Пример для standalone-компонента (используется `imports` в декораторе): + +```ts +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ExtraButtonComponent, ExtraTagComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [ + ExtraButtonComponent, + CommonModule, + ExtraTagComponent, + ], + template: ` +
+ + + + +
+ ` +}) +export class AppExample {} +``` + ## Используемые технологии и связанные зависимости --- From 24833ff8e3a5b54dcaddb6ff49430337725eddbb Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 27 Apr 2026 21:12:30 +0700 Subject: [PATCH 214/258] =?UTF-8?q?select:=20checkmark=20=D0=B8=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D0=BA=D0=B0=20ti-check=20=D0=B2=D0=BC=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=BE=20=D0=BF=D1=83=D1=81=D1=82=D0=BE=D0=B3=D0=BE=20SVG?= =?UTF-8?q?=20+=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=20check?= =?UTF-8?q?markIcon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/select/select.component.ts | 6 +++ src/prime-preset/tokens/components/select.ts | 37 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/lib/components/select/select.component.ts b/src/lib/components/select/select.component.ts index 97e798e8..fdf23ce0 100644 --- a/src/lib/components/select/select.component.ts +++ b/src/lib/components/select/select.component.ts @@ -52,6 +52,7 @@ export type SelectSize = 'small' | 'base' | 'large' | 'xlarge'; [appendTo]="appendTo" [size]="primeSize" [checkmark]="checkmark" + [panelStyle]="panelStyle" [emptyMessage]="emptyMessage" [emptyFilterMessage]="emptyFilterMessage" (onChange)="onSelectChange($event)" @@ -108,6 +109,7 @@ export class SelectComponent implements ControlValueAccessor, OnInit { @Input() floatLabel = false; @Input() label = ''; @Input() checkmark = true; + @Input() checkmarkIcon = '\ea5e'; @Input() emptyMessage = 'Нет данных'; @Input() emptyFilterMessage = 'Результаты не найдены'; @Input() optionTemplate: TemplateRef | null = null; @@ -134,6 +136,10 @@ export class SelectComponent implements ControlValueAccessor, OnInit { return undefined; } + get panelStyle(): Record { + return { '--p-select-checkmark-content': `"\\${this.checkmarkIcon}"` }; + } + get selectClasses(): Record { return { 'p-select-xlg': this.size === 'xlarge', diff --git a/src/prime-preset/tokens/components/select.ts b/src/prime-preset/tokens/components/select.ts index 0c60380f..8a2b8bca 100644 --- a/src/prime-preset/tokens/components/select.ts +++ b/src/prime-preset/tokens/components/select.ts @@ -60,6 +60,43 @@ export const selectCss = ({ dt }: { dt: (token: string) => string }): string => padding-block-end: ${dt('floatlabel.in.input.paddingBottom')}; } + /* ─── Checkmark: выбранный элемент ─── */ + .p-select-option:has(.p-select-option-check-icon) { + background: ${dt('select.option.selectedBackground')}; + color: ${dt('select.option.selectedColor')}; + } + + .p-select-option:has(.p-select-option-check-icon).p-focus { + background: ${dt('select.option.selectedFocusBackground')}; + color: ${dt('select.option.selectedFocusColor')}; + } + + /* Скрываем пустой SVG и заменяем на tabler-иконку */ + .p-select-option-check-icon, + .p-select-option-blank-icon { + display: none; + } + + .p-select-option:has(.p-select-option-check-icon)::before { + font-family: 'tabler-icons'; + content: var(--p-select-checkmark-content, "\\ea5e"); + font-size: ${dt('select.extend.iconSize')}; + color: ${dt('select.option.selectedColor')}; + flex-shrink: 0; + } + + .p-select-option:has(.p-select-option-check-icon).p-focus::before { + color: ${dt('select.option.selectedFocusColor')}; + } + + .p-select-option:has(.p-select-option-blank-icon)::before { + font-family: 'tabler-icons'; + content: var(--p-select-checkmark-content, "\\ea5e"); + font-size: ${dt('select.extend.iconSize')}; + visibility: hidden; + flex-shrink: 0; + } + /* ─── Иконки ─── */ .p-select.p-component :is(.p-select-dropdown .p-select-dropdown-icon, .p-select-clear-icon, .p-select-loading-icon) { font-size: ${dt('select.extend.iconSize')}; From 27664721489c159252dc38ba013397f698ba3ec7 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 15:25:04 +0700 Subject: [PATCH 215/258] =?UTF-8?q?password:=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F,=20=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D1=81=D1=8B,=20=D0=BE=D0=B1=D1=91=D1=80=D1=82?= =?UTF-8?q?=D0=B8=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/password/password.component.ts | 99 ++++++++++ src/prime-preset/map-tokens.ts | 5 + .../tokens/components/password.ts | 56 ++++++ .../examples/password-disabled.component.ts | 51 +++++ .../examples/password-feedback.component.ts | 51 +++++ .../password-float-label.component.ts | 98 ++++++++++ .../examples/password-invalid.component.ts | 51 +++++ .../examples/password-toggle.component.ts | 51 +++++ .../components/password/password.stories.ts | 179 ++++++++++++++++++ 9 files changed, 641 insertions(+) create mode 100644 src/lib/components/password/password.component.ts create mode 100644 src/prime-preset/tokens/components/password.ts create mode 100644 src/stories/components/password/examples/password-disabled.component.ts create mode 100644 src/stories/components/password/examples/password-feedback.component.ts create mode 100644 src/stories/components/password/examples/password-float-label.component.ts create mode 100644 src/stories/components/password/examples/password-invalid.component.ts create mode 100644 src/stories/components/password/examples/password-toggle.component.ts create mode 100644 src/stories/components/password/password.stories.ts diff --git a/src/lib/components/password/password.component.ts b/src/lib/components/password/password.component.ts new file mode 100644 index 00000000..2568dd5c --- /dev/null +++ b/src/lib/components/password/password.component.ts @@ -0,0 +1,99 @@ +import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, forwardRef } from '@angular/core'; +import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Password } from 'primeng/password'; + +export type PasswordSize = 'small' | 'base' | 'large' | 'xlarge'; + +@Component({ + selector: 'password', + host: { style: 'display: block' }, + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [Password, FormsModule], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => PasswordComponent), + multi: true, + }, + ], + template: ` + + `, +}) +export class PasswordComponent implements ControlValueAccessor { + @Input() feedback = true; + @Input() toggleMask = false; + @Input() disabled = false; + @Input() placeholder: string | undefined = undefined; + @Input() size: PasswordSize = 'base'; + @Input() variant: 'filled' | 'outlined' = 'outlined'; + @Input() fluid = false; + @Input() invalid = false; + @Input() inputId: string | undefined = undefined; + @Input() inputStyleClass: string | undefined = undefined; + @Input() ariaLabel: string | undefined = undefined; + @Input() ariaLabelledBy: string | undefined = undefined; + @Input() autofocus = false; + + @Output() onFocus = new EventEmitter(); + @Output() onBlur = new EventEmitter(); + + get primeSize(): 'small' | 'large' | undefined { + if (this.size === 'small') return 'small'; + if (this.size === 'large' || this.size === 'xlarge') return 'large'; + return undefined; + } + + get sizeClass(): string { + return this.size === 'xlarge' ? 'p-inputtext-xlg' : ''; + } + + get computedInputStyleClass(): string { + return [this.sizeClass, this.inputStyleClass].filter(Boolean).join(' '); + } + + modelValue: string | null = null; + + private _onChange: (value: string | null) => void = () => {}; + private _onTouched: () => void = () => {}; + + handleChange(value: string | null): void { + this.modelValue = value; + this._onChange(value); + this._onTouched(); + } + + writeValue(value: string | null): void { + this.modelValue = value; + } + + registerOnChange(fn: (value: string | null) => void): void { + this._onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this._onTouched = fn; + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index d0a44965..631c7f97 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -11,6 +11,7 @@ import { inputtextCss } from './tokens/components/inputtext'; import { progressspinnerCss } from './tokens/components/progressspinner'; import { tagCss } from './tokens/components/tag'; import { timelineCss } from './tokens/components/timeline'; +import { passwordCss } from './tokens/components/password'; import { tooltipCss } from './tokens/components/tooltip'; import { megamenuCss } from './tokens/components/megamenu'; @@ -35,6 +36,10 @@ const presetTokens: Preset = { ...(tokens.components.button as unknown as ComponentsDesignTokens['button']), css: buttonCss, }, + password: { + ...(tokens.components.password as unknown as ComponentsDesignTokens['password']), + css: passwordCss, + }, progressspinner: { ...(tokens.components.progressspinner as unknown as ComponentsDesignTokens['progressspinner']), css: progressspinnerCss, diff --git a/src/prime-preset/tokens/components/password.ts b/src/prime-preset/tokens/components/password.ts new file mode 100644 index 00000000..01100dff --- /dev/null +++ b/src/prime-preset/tokens/components/password.ts @@ -0,0 +1,56 @@ +/** + * Кастомная CSS-стилизация для компонента p-password. + * Подключается в map-tokens.ts: `import { passwordCss } from './components/password'` + */ +export const passwordCss = ({ dt }: { dt: (token: string) => string }): string => ` + /* ─── Иконки управления ─── */ + .p-password-toggle-mask-icon, + .p-icon.p-password-toggle-mask-icon.p-password-unmask-icon { + cursor: pointer; + } + + /* ─── Оверлей и индикатор ─── */ + .p-password-overlay { + border-width: ${dt('password.extend.borderWidth')}; + } + + .p-password-meter-text { + color: ${dt('text.color')}; + font-size: ${dt('fonts.fontSize.200')}; + font-weight: ${dt('fonts.fontWeight.medium')}; + } + + /* ─── Кастомный контент (правила пароля) ─── */ + .p-password-rules { + display: flex; + flex-direction: column; + gap: ${dt('password.content.gap')}; + margin: 0; + padding: 0; + list-style: none; + } + + .p-password-rule { + display: flex; + align-items: center; + gap: ${dt('content.gap.200')}; + font-size: ${dt('fonts.fontSize.100')}; + } + + /* ─── Состояния иконок правил ─── */ + .p-password-rule i { + font-size: ${dt('fonts.fontSize.200')}; + } + + .p-password-rule .ti-circle { + color: ${dt('surface.400')}; + } + + .p-password-rule .ti-circle-check { + color: ${dt('password.colorScheme.light.strength.strongBackground')}; + } + + .p-password-rule .ti-circle-x { + color: ${dt('password.colorScheme.light.strength.weakBackground')}; + } +`; diff --git a/src/stories/components/password/examples/password-disabled.component.ts b/src/stories/components/password/examples/password-disabled.component.ts new file mode 100644 index 00000000..4c13c6df --- /dev/null +++ b/src/stories/components/password/examples/password-disabled.component.ts @@ -0,0 +1,51 @@ +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { PasswordComponent } from '../../../../lib/components/password/password.component'; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-password-disabled', + standalone: true, + imports: [PasswordComponent, FormsModule], + template, +}) +export class PasswordDisabledComponent { + value: string | null = 'secret123'; +} + +export const Disabled: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Поле ввода пароля в отключённом состоянии.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { PasswordComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-password-disabled', + standalone: true, + imports: [PasswordComponent, FormsModule], + template: \` + + \`, +}) +export class PasswordDisabledComponent { + value: string | null = 'secret123'; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/password/examples/password-feedback.component.ts b/src/stories/components/password/examples/password-feedback.component.ts new file mode 100644 index 00000000..829aacf4 --- /dev/null +++ b/src/stories/components/password/examples/password-feedback.component.ts @@ -0,0 +1,51 @@ +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { PasswordComponent } from '../../../../lib/components/password/password.component'; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-password-feedback', + standalone: true, + imports: [PasswordComponent, FormsModule], + template, +}) +export class PasswordFeedbackComponent { + value: string | null = null; +} + +export const Feedback: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Индикатор надёжности пароля с визуальной шкалой (слабый / средний / сильный).' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { PasswordComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-password-feedback', + standalone: true, + imports: [PasswordComponent, FormsModule], + template: \` + + \`, +}) +export class PasswordFeedbackComponent { + value: string | null = null; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/password/examples/password-float-label.component.ts b/src/stories/components/password/examples/password-float-label.component.ts new file mode 100644 index 00000000..ca9a37e9 --- /dev/null +++ b/src/stories/components/password/examples/password-float-label.component.ts @@ -0,0 +1,98 @@ +import { Component, Input } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { Password } from 'primeng/password'; +import { FloatLabel as PrimeFloatLabel } from 'primeng/floatlabel'; + +@Component({ + selector: 'app-password-float-label', + standalone: true, + imports: [Password, PrimeFloatLabel, FormsModule], + template: ` +
+ + + + +
+ `, +}) +export class PasswordFloatLabelComponent { + @Input() feedback = true; + @Input() toggleMask = false; + @Input() disabled = false; + @Input() invalid = false; + @Input() fluid = false; + @Input() placeholder: string | undefined = undefined; + value = ''; +} + +export const FloatLabel: StoryObj = { + name: 'FloatLabel', + render: (args) => { + const parts: string[] = []; + + if (!args.feedback) parts.push(`[feedback]="false"`); + if (args.toggleMask) parts.push(`[toggleMask]="true"`); + if (args.placeholder) parts.push(`placeholder="${args.placeholder}"`); + if (args.disabled) parts.push(`[disabled]="true"`); + if (args.invalid) parts.push(`[invalid]="true"`); + if (args.fluid) parts.push(`[fluid]="true"`); + + const attrs = parts.length ? `\n ${parts.join('\n ')}` : ''; + + return { + props: args, + template: ``, + }; + }, + args: { + feedback: true, + toggleMask: false, + placeholder: undefined, + disabled: false, + invalid: false, + fluid: false, + }, + parameters: { + docs: { + description: { + story: + 'Интеграция с `p-floatlabel` — плавающая метка внутри поля. Кликните на поле чтобы увидеть анимацию.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { Password } from 'primeng/password'; +import { FloatLabel } from 'primeng/floatlabel'; +import { FormsModule } from '@angular/forms'; + +@Component({ + selector: 'app-password-float-label', + standalone: true, + imports: [Password, FloatLabel, FormsModule], + template: \` + + + + + \`, +}) +export class PasswordFloatLabelComponent { + value = ''; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/password/examples/password-invalid.component.ts b/src/stories/components/password/examples/password-invalid.component.ts new file mode 100644 index 00000000..dace649f --- /dev/null +++ b/src/stories/components/password/examples/password-invalid.component.ts @@ -0,0 +1,51 @@ +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { PasswordComponent } from '../../../../lib/components/password/password.component'; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-password-invalid', + standalone: true, + imports: [PasswordComponent, FormsModule], + template, +}) +export class PasswordInvalidComponent { + value: string | null = null; +} + +export const Invalid: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Поле ввода пароля в состоянии ошибки валидации.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { PasswordComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-password-invalid', + standalone: true, + imports: [PasswordComponent, FormsModule], + template: \` + + \`, +}) +export class PasswordInvalidComponent { + value: string | null = null; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/password/examples/password-toggle.component.ts b/src/stories/components/password/examples/password-toggle.component.ts new file mode 100644 index 00000000..0fdb915e --- /dev/null +++ b/src/stories/components/password/examples/password-toggle.component.ts @@ -0,0 +1,51 @@ +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { PasswordComponent } from '../../../../lib/components/password/password.component'; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-password-toggle', + standalone: true, + imports: [PasswordComponent, FormsModule], + template, +}) +export class PasswordToggleComponent { + value: string | null = null; +} + +export const ToggleMask: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Возможность показать/скрыть введённый пароль по иконке.' }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { PasswordComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-password-toggle', + standalone: true, + imports: [PasswordComponent, FormsModule], + template: \` + + \`, +}) +export class PasswordToggleComponent { + value: string | null = null; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/password/password.stories.ts b/src/stories/components/password/password.stories.ts new file mode 100644 index 00000000..3dc2c98d --- /dev/null +++ b/src/stories/components/password/password.stories.ts @@ -0,0 +1,179 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { FormsModule } from '@angular/forms'; +import { PasswordComponent } from '../../../lib/components/password/password.component'; +import { PasswordToggleComponent, ToggleMask } from './examples/password-toggle.component'; +import { PasswordFeedbackComponent, Feedback } from './examples/password-feedback.component'; +import { PasswordDisabledComponent, Disabled } from './examples/password-disabled.component'; +import { PasswordInvalidComponent, Invalid } from './examples/password-invalid.component'; +import { PasswordFloatLabelComponent, FloatLabel } from './examples/password-float-label.component'; + +const meta: Meta = { + title: 'Components/Form/Password', + component: PasswordComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + PasswordComponent, + FormsModule, + PasswordToggleComponent, + PasswordFeedbackComponent, + PasswordDisabledComponent, + PasswordInvalidComponent, + PasswordFloatLabelComponent, + ], + }), + ], + parameters: { + designTokens: { prefix: '--p-password' }, + docs: { + description: { + component: `Поле ввода пароля с поддержкой индикатора надёжности и переключения видимости. + +\`\`\`typescript +import { PasswordComponent } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + }, + argTypes: { + feedback: { + control: 'boolean', + description: 'Показывать индикатор надёжности пароля', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + toggleMask: { + control: 'boolean', + description: 'Возможность показать/скрыть пароль', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + placeholder: { + control: 'text', + description: 'Текст-подсказка', + table: { + category: 'Props', + defaultValue: { summary: 'undefined' }, + type: { summary: 'string' }, + }, + }, + size: { + control: 'select', + options: ['small', 'base', 'large', 'xlarge'], + description: 'Размер поля', + table: { + category: 'Props', + defaultValue: { summary: 'base' }, + type: { summary: "'small' | 'base' | 'large' | 'xlarge'" }, + }, + }, + disabled: { + control: 'boolean', + description: 'Отключает возможность взаимодействия', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + invalid: { + control: 'boolean', + description: 'Подсвечивает поле как невалидное', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + fluid: { + control: 'boolean', + description: 'Растягивает поле на всю ширину контейнера', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + // Hidden props + variant: { table: { disable: true } }, + inputId: { table: { disable: true } }, + inputStyleClass: { table: { disable: true } }, + ariaLabel: { table: { disable: true } }, + ariaLabelledBy: { table: { disable: true } }, + autofocus: { table: { disable: true } }, + primeSize: { table: { disable: true } }, + sizeClass: { table: { disable: true } }, + computedInputStyleClass: { table: { disable: true } }, + + // Events + onFocus: { + control: false, + description: 'Событие фокуса', + table: { + category: 'Events', + type: { summary: 'EventEmitter' }, + }, + }, + onBlur: { + control: false, + description: 'Событие потери фокуса', + table: { + category: 'Events', + type: { summary: 'EventEmitter' }, + }, + }, + }, + args: { + feedback: true, + toggleMask: false, + placeholder: 'Введите пароль', + size: 'base', + disabled: false, + invalid: false, + fluid: false, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ────────────────────────────────────────────────────────────────── +export const Default: Story = { + name: 'Default', + render: (args) => { + const parts: string[] = []; + + if (!args.feedback) parts.push(`[feedback]="false"`); + if (args.toggleMask) parts.push(`[toggleMask]="true"`); + if (args.placeholder) parts.push(`placeholder="${args.placeholder}"`); + if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); + if (args.disabled) parts.push(`[disabled]="true"`); + if (args.invalid) parts.push(`[invalid]="true"`); + if (args.fluid) parts.push(`[fluid]="true"`); + + parts.push(`[(ngModel)]="value"`); + + const template = parts.length > 1 + ? `` + : ``; + + return { props: { ...args, value: null }, template }; + }, + parameters: { + docs: { + description: { + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + }, + }, +}; + +// ── Re-exports from example components ──────────────────────────────────── +export { ToggleMask, Feedback, Disabled, Invalid, FloatLabel }; From 6256c6d4b4af6d72de6530198f420b70ecbe2d67 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 20 Apr 2026 15:39:30 +0700 Subject: [PATCH 216/258] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=BE=D0=BC=D0=BF?= =?UTF-8?q?=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/password/password.component.ts | 19 ++-- .../examples/password-template.component.ts | 98 +++++++++++++++++++ .../components/password/password.stories.ts | 22 +++-- 3 files changed, 124 insertions(+), 15 deletions(-) create mode 100644 src/stories/components/password/examples/password-template.component.ts diff --git a/src/lib/components/password/password.component.ts b/src/lib/components/password/password.component.ts index 2568dd5c..22f93645 100644 --- a/src/lib/components/password/password.component.ts +++ b/src/lib/components/password/password.component.ts @@ -26,6 +26,10 @@ export type PasswordSize = 'small' | 'base' | 'large' | 'xlarge'; [inputStyleClass]="computedInputStyleClass" [disabled]="disabled" [placeholder]="placeholder" + [promptLabel]="promptLabel" + [weakLabel]="weakLabel" + [mediumLabel]="mediumLabel" + [strongLabel]="strongLabel" [variant]="variant" [fluid]="fluid" [invalid]="invalid" @@ -47,6 +51,10 @@ export class PasswordComponent implements ControlValueAccessor { @Input() variant: 'filled' | 'outlined' = 'outlined'; @Input() fluid = false; @Input() invalid = false; + @Input() promptLabel = 'Введите пароль'; + @Input() weakLabel = 'Слабый'; + @Input() mediumLabel = 'Средний'; + @Input() strongLabel = 'Надёжный'; @Input() inputId: string | undefined = undefined; @Input() inputStyleClass: string | undefined = undefined; @Input() ariaLabel: string | undefined = undefined; @@ -56,14 +64,11 @@ export class PasswordComponent implements ControlValueAccessor { @Output() onFocus = new EventEmitter(); @Output() onBlur = new EventEmitter(); - get primeSize(): 'small' | 'large' | undefined { - if (this.size === 'small') return 'small'; - if (this.size === 'large' || this.size === 'xlarge') return 'large'; - return undefined; - } - get sizeClass(): string { - return this.size === 'xlarge' ? 'p-inputtext-xlg' : ''; + if (this.size === 'small') return 'p-inputtext-sm'; + if (this.size === 'large') return 'p-inputtext-lg'; + if (this.size === 'xlarge') return 'p-inputtext-lg p-inputtext-xlg'; + return ''; } get computedInputStyleClass(): string { diff --git a/src/stories/components/password/examples/password-template.component.ts b/src/stories/components/password/examples/password-template.component.ts new file mode 100644 index 00000000..5d761fa0 --- /dev/null +++ b/src/stories/components/password/examples/password-template.component.ts @@ -0,0 +1,98 @@ +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { Password } from 'primeng/password'; +import { Divider } from 'primeng/divider'; + +@Component({ + selector: 'app-password-template', + standalone: true, + imports: [Password, Divider, FormsModule], + template: ` +
+ + +
Создание пароля
+
+ + +
    +
  • Минимум одна строчная буква
  • +
  • Минимум одна заглавная буква
  • +
  • Минимум одна цифра
  • +
  • Не менее 8 символов
  • +
+
+
+
+ `, +}) +export class PasswordTemplateComponent { + value: string | null = null; +} + +export const Template: StoryObj = { + name: 'Template', + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Кастомный контент через `ng-template`: заголовок, разделитель и список требований к паролю.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { Password } from 'primeng/password'; +import { Divider } from 'primeng/divider'; +import { FormsModule } from '@angular/forms'; + +@Component({ + selector: 'app-password-template', + standalone: true, + imports: [Password, Divider, FormsModule], + template: \` + + +
Создание пароля
+
+ + +
    +
  • Минимум одна строчная буква
  • +
  • Минимум одна заглавная буква
  • +
  • Минимум одна цифра
  • +
  • Не менее 8 символов
  • +
+
+
+ \`, +}) +export class PasswordTemplateComponent { + value: string | null = null; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/password/password.stories.ts b/src/stories/components/password/password.stories.ts index 3dc2c98d..4008f882 100644 --- a/src/stories/components/password/password.stories.ts +++ b/src/stories/components/password/password.stories.ts @@ -6,6 +6,7 @@ import { PasswordFeedbackComponent, Feedback } from './examples/password-feedbac import { PasswordDisabledComponent, Disabled } from './examples/password-disabled.component'; import { PasswordInvalidComponent, Invalid } from './examples/password-invalid.component'; import { PasswordFloatLabelComponent, FloatLabel } from './examples/password-float-label.component'; +import { PasswordTemplateComponent, Template } from './examples/password-template.component'; const meta: Meta = { title: 'Components/Form/Password', @@ -21,6 +22,7 @@ const meta: Meta = { PasswordDisabledComponent, PasswordInvalidComponent, PasswordFloatLabelComponent, + PasswordTemplateComponent, ], }), ], @@ -34,6 +36,7 @@ const meta: Meta = { import { PasswordComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, + story: { height: '280px' }, }, }, argTypes: { @@ -103,12 +106,15 @@ import { PasswordComponent } from '@cdek-it/angular-ui-kit'; }, // Hidden props variant: { table: { disable: true } }, + promptLabel: { table: { disable: true } }, + weakLabel: { table: { disable: true } }, + mediumLabel: { table: { disable: true } }, + strongLabel: { table: { disable: true } }, inputId: { table: { disable: true } }, inputStyleClass: { table: { disable: true } }, ariaLabel: { table: { disable: true } }, ariaLabelledBy: { table: { disable: true } }, autofocus: { table: { disable: true } }, - primeSize: { table: { disable: true } }, sizeClass: { table: { disable: true } }, computedInputStyleClass: { table: { disable: true } }, @@ -150,13 +156,13 @@ export const Default: Story = { render: (args) => { const parts: string[] = []; - if (!args.feedback) parts.push(`[feedback]="false"`); - if (args.toggleMask) parts.push(`[toggleMask]="true"`); - if (args.placeholder) parts.push(`placeholder="${args.placeholder}"`); + if (!args.feedback) parts.push(`[feedback]="false"`); + if (args.toggleMask) parts.push(`[toggleMask]="true"`); + if (args.placeholder) parts.push(`placeholder="${args.placeholder}"`); if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); - if (args.disabled) parts.push(`[disabled]="true"`); - if (args.invalid) parts.push(`[invalid]="true"`); - if (args.fluid) parts.push(`[fluid]="true"`); + if (args.disabled) parts.push(`[disabled]="true"`); + if (args.invalid) parts.push(`[invalid]="true"`); + if (args.fluid) parts.push(`[fluid]="true"`); parts.push(`[(ngModel)]="value"`); @@ -176,4 +182,4 @@ export const Default: Story = { }; // ── Re-exports from example components ──────────────────────────────────── -export { ToggleMask, Feedback, Disabled, Invalid, FloatLabel }; +export { ToggleMask, Feedback, Disabled, Invalid, FloatLabel, Template }; From 7591ddbed0a33975135521d115fd42dc03c3b67a Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 27 Apr 2026 22:09:25 +0700 Subject: [PATCH 217/258] =?UTF-8?q?password:=20=D1=86=D0=B2=D0=B5=D1=82=20?= =?UTF-8?q?meter-text=20=D0=BD=D0=B0=20text.mutedColor,=20focus=20box-shad?= =?UTF-8?q?ow,=20invalid=20focus,=20floatlabel=20=D1=81=D1=82=D0=B8=D0=BB?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tokens/components/password.ts | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/prime-preset/tokens/components/password.ts b/src/prime-preset/tokens/components/password.ts index 01100dff..2bb0a00c 100644 --- a/src/prime-preset/tokens/components/password.ts +++ b/src/prime-preset/tokens/components/password.ts @@ -15,11 +15,45 @@ export const passwordCss = ({ dt }: { dt: (token: string) => string }): string = } .p-password-meter-text { - color: ${dt('text.color')}; + color: ${dt('text.mutedColor')}; font-size: ${dt('fonts.fontSize.200')}; font-weight: ${dt('fonts.fontWeight.medium')}; } + /* ─── Focus ─── */ + .p-password:has(.p-inputtext:enabled:focus) { + box-shadow: 0 0 0 ${dt('inputtext.focusRing.width')} ${dt('inputtext.focusRing.color')}; + border-radius: ${dt('inputtext.root.borderRadius')}; + } + + /* ─── Invalid + Focus ─── */ + .p-password:has(.p-inputtext.p-invalid:focus) { + box-shadow: 0 0 0 ${dt('inputtext.focusRing.width')} ${dt('focusRing.extend.invalid')}; + border-radius: ${dt('inputtext.root.borderRadius')}; + } + + .p-password:has(.p-inputtext.p-invalid:focus) .p-inputtext { + border-color: ${dt('inputtext.root.invalidBorderColor')}; + } + + /* ─── FloatLabel ─── */ + .p-floatlabel:has(.p-password) label { + font-family: ${dt('fonts.fontFamily.base')}; + font-weight: ${dt('floatlabel.root.fontWeight')}; + line-height: ${dt('fonts.lineHeight.250')}; + color: ${dt('floatlabel.root.color')}; + } + + .p-floatlabel:has(.p-password) .p-floatlabel-active label { + font-weight: ${dt('floatlabel.root.active.fontWeight')}; + } + + .p-floatlabel-in .p-password .p-inputtext { + font-family: ${dt('fonts.fontFamily.base')}; + padding-block-start: ${dt('floatlabel.in.input.paddingTop')}; + padding-block-end: ${dt('floatlabel.in.input.paddingBottom')}; + } + /* ─── Кастомный контент (правила пароля) ─── */ .p-password-rules { display: flex; From 2707e745b82cefa2ee3d3202f9a6ad6889cd0ad7 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 27 Apr 2026 22:09:29 +0700 Subject: [PATCH 218/258] =?UTF-8?q?password:=20floatLabel=20=D0=B8=20label?= =?UTF-8?q?=20props=20=D1=81=20p-floatlabel=20=D0=BE=D0=B1=D1=91=D1=80?= =?UTF-8?q?=D1=82=D0=BA=D0=BE=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/password/password.component.ts | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/src/lib/components/password/password.component.ts b/src/lib/components/password/password.component.ts index 22f93645..9dba3fc4 100644 --- a/src/lib/components/password/password.component.ts +++ b/src/lib/components/password/password.component.ts @@ -1,6 +1,8 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, forwardRef } from '@angular/core'; import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { NgTemplateOutlet } from '@angular/common'; import { Password } from 'primeng/password'; +import { FloatLabel } from 'primeng/floatlabel'; export type PasswordSize = 'small' | 'base' | 'large' | 'xlarge'; @@ -9,7 +11,7 @@ export type PasswordSize = 'small' | 'base' | 'large' | 'xlarge'; host: { style: 'display: block' }, standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [Password, FormsModule], + imports: [Password, FormsModule, FloatLabel, NgTemplateOutlet], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -18,28 +20,39 @@ export type PasswordSize = 'small' | 'base' | 'large' | 'xlarge'; }, ], template: ` - + @if (floatLabel) { + + + + + } @else { + + } + + + + `, }) export class PasswordComponent implements ControlValueAccessor { @@ -51,6 +64,8 @@ export class PasswordComponent implements ControlValueAccessor { @Input() variant: 'filled' | 'outlined' = 'outlined'; @Input() fluid = false; @Input() invalid = false; + @Input() floatLabel = false; + @Input() label = ''; @Input() promptLabel = 'Введите пароль'; @Input() weakLabel = 'Слабый'; @Input() mediumLabel = 'Средний'; From ec63673825b7bac687c35eb338aee44f86062b9f Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 27 Apr 2026 22:09:34 +0700 Subject: [PATCH 219/258] =?UTF-8?q?password:=20=D1=81=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B8=20FloatLabel=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=91=D1=80=D1=82=D0=BA=D1=83,=20argTypes=20floatLabel?= =?UTF-8?q?=20=D0=B8=20label?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../password-float-label.component.ts | 58 ++++++------------- .../components/password/password.stories.ts | 22 +++++++ 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/stories/components/password/examples/password-float-label.component.ts b/src/stories/components/password/examples/password-float-label.component.ts index ca9a37e9..e75551fd 100644 --- a/src/stories/components/password/examples/password-float-label.component.ts +++ b/src/stories/components/password/examples/password-float-label.component.ts @@ -1,28 +1,26 @@ import { Component, Input } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { Password } from 'primeng/password'; -import { FloatLabel as PrimeFloatLabel } from 'primeng/floatlabel'; +import { PasswordComponent } from '../../../../lib/components/password/password.component'; @Component({ selector: 'app-password-float-label', standalone: true, - imports: [Password, PrimeFloatLabel, FormsModule], + imports: [PasswordComponent, FormsModule], template: `
- - - - +
`, }) @@ -33,6 +31,7 @@ export class PasswordFloatLabelComponent { @Input() invalid = false; @Input() fluid = false; @Input() placeholder: string | undefined = undefined; + @Input() label = 'Пароль'; value = ''; } @@ -62,36 +61,17 @@ export const FloatLabel: StoryObj = { disabled: false, invalid: false, fluid: false, + label: 'Пароль', }, parameters: { docs: { description: { story: - 'Интеграция с `p-floatlabel` — плавающая метка внутри поля. Кликните на поле чтобы увидеть анимацию.', + 'Интеграция с `floatLabel` — плавающая метка внутри поля. Кликните на поле чтобы увидеть анимацию.', }, source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { Password } from 'primeng/password'; -import { FloatLabel } from 'primeng/floatlabel'; -import { FormsModule } from '@angular/forms'; - -@Component({ - selector: 'app-password-float-label', - standalone: true, - imports: [Password, FloatLabel, FormsModule], - template: \` - - - - - \`, -}) -export class PasswordFloatLabelComponent { - value = ''; -} - `, + language: 'html', + code: ``, }, }, }, diff --git a/src/stories/components/password/password.stories.ts b/src/stories/components/password/password.stories.ts index 4008f882..22960f5a 100644 --- a/src/stories/components/password/password.stories.ts +++ b/src/stories/components/password/password.stories.ts @@ -104,6 +104,24 @@ import { PasswordComponent } from '@cdek-it/angular-ui-kit'; type: { summary: 'boolean' }, }, }, + floatLabel: { + control: 'boolean', + description: 'Плавающая метка внутри поля', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + label: { + control: 'text', + description: 'Текст плавающей метки (используется с floatLabel)', + table: { + category: 'Props', + defaultValue: { summary: "''" }, + type: { summary: 'string' }, + }, + }, // Hidden props variant: { table: { disable: true } }, promptLabel: { table: { disable: true } }, @@ -144,6 +162,8 @@ import { PasswordComponent } from '@cdek-it/angular-ui-kit'; disabled: false, invalid: false, fluid: false, + floatLabel: false, + label: '', }, }; @@ -163,6 +183,8 @@ export const Default: Story = { if (args.disabled) parts.push(`[disabled]="true"`); if (args.invalid) parts.push(`[invalid]="true"`); if (args.fluid) parts.push(`[fluid]="true"`); + if (args.floatLabel) parts.push(`[floatLabel]="true"`); + if (args.label) parts.push(`label="${args.label}"`); parts.push(`[(ngModel)]="value"`); From 21de7851eef7c21325cd35f6ac42cf46c20b9cea Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 27 Apr 2026 22:22:18 +0700 Subject: [PATCH 220/258] =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0?= =?UTF-8?q?=20=D1=81=D1=82=D0=B8=D0=BB=D0=B5=D0=B9=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=BE?= =?UTF-8?q?=D0=BC=20password?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/map-tokens.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index ce029c7e..434098f8 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -9,6 +9,7 @@ import { cardCss } from './tokens/components/card'; import { checkboxCss } from './tokens/components/checkbox'; import { inputtextCss } from './tokens/components/inputtext'; import { progressspinnerCss } from './tokens/components/progressspinner'; +import { passwordCss } from './tokens/components/password'; import { tagCss } from './tokens/components/tag'; import { textareaCss } from './tokens/components/textarea'; import { tooltipCss } from './tokens/components/tooltip'; From 084113a47a61b236e2d8c8580ec4ab6448bd150d Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 27 Apr 2026 22:29:52 +0700 Subject: [PATCH 221/258] =?UTF-8?q?paginator:=20=D0=BF=D1=80=D0=BE=D0=BF?= =?UTF-8?q?=D1=81=D1=8B=20showCurrentPageReport=20=D0=B8=20showJumpToPageI?= =?UTF-8?q?nput=20=D0=B2=20=D1=81=D1=82=D0=BE=D1=80=D0=B8=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/paginator/paginator.stories.ts | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/stories/components/paginator/paginator.stories.ts b/src/stories/components/paginator/paginator.stories.ts index b8c787d7..6fdfdfcd 100644 --- a/src/stories/components/paginator/paginator.stories.ts +++ b/src/stories/components/paginator/paginator.stories.ts @@ -5,7 +5,7 @@ import { PaginatorRowsPerPageComponent, RowsPerPage as RowsPerPageStory } from ' type PaginatorArgs = Pick< PaginatorComponent, - 'totalRecords' | 'rows' | 'pageLinkSize' | 'showFirstLastIcon' | 'showPageLinks' | 'alwaysShow' + 'totalRecords' | 'rows' | 'pageLinkSize' | 'showFirstLastIcon' | 'showPageLinks' | 'showCurrentPageReport' | 'showJumpToPageInput' | 'alwaysShow' >; const meta: Meta = { @@ -79,6 +79,24 @@ import { PaginatorComponent } from '@cdek-it/angular-ui-kit'; type: { summary: 'boolean' }, }, }, + showCurrentPageReport: { + control: 'boolean', + description: 'Показывать текст с текущей страницей и общим количеством', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + showJumpToPageInput: { + control: 'boolean', + description: 'Показывать поле ввода для перехода на конкретную страницу', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, alwaysShow: { control: 'boolean', description: 'Показывать пагинатор даже при единственной странице', @@ -95,6 +113,8 @@ import { PaginatorComponent } from '@cdek-it/angular-ui-kit'; pageLinkSize: 5, showFirstLastIcon: true, showPageLinks: true, + showCurrentPageReport: false, + showJumpToPageInput: false, alwaysShow: true, }, }; @@ -115,6 +135,8 @@ export const Default: Story = { [pageLinkSize]="pageLinkSize" [showFirstLastIcon]="showFirstLastIcon" [showPageLinks]="showPageLinks" + [showCurrentPageReport]="showCurrentPageReport" + [showJumpToPageInput]="showJumpToPageInput" [alwaysShow]="alwaysShow" > `, From decba7474297cbc7adcdca8e015e5ff4ded726af Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Tue, 28 Apr 2026 00:54:47 +0700 Subject: [PATCH 222/258] DS-559 --- .../components/button/button.stories.ts | 284 ++++-------------- .../button/examples/button-extra.component.ts | 2 +- .../button/examples/button-sizes.component.ts | 12 +- .../components/checkbox/checkbox.stories.ts | 46 +-- .../checkbox-custom-label.component.ts | 16 +- .../examples/checkbox-disabled.component.ts | 14 +- .../examples/checkbox-group.component.ts | 20 +- .../checkbox-indeterminate.component.ts | 14 +- .../examples/checkbox-invalid.component.ts | 14 +- .../examples/checkbox-label.component.ts | 14 +- .../chip/examples/chip-disabled.component.ts | 12 +- .../chip-removable-with-icon.component.ts | 12 +- .../chip/examples/chip-removable.component.ts | 12 +- .../chip/examples/chip-with-icon.component.ts | 12 +- .../examples/divider-align-left.component.ts | 8 +- .../examples/divider-with-icon.component.ts | 8 +- .../examples/inputtext-clear.component.ts | 12 +- .../examples/inputtext-disabled.component.ts | 14 +- .../examples/inputtext-invalid.component.ts | 14 +- .../examples/inputtext-readonly.component.ts | 14 +- .../components/megamenu/megamenu.stories.ts | 2 +- .../progressspinner.stories.ts | 18 +- .../radiobutton-disabled.component.ts | 16 +- .../examples/radiobutton-group.component.ts | 20 +- .../examples/radiobutton-invalid.component.ts | 18 +- .../examples/rating-disabled.component.ts | 10 +- .../examples/rating-readonly.component.ts | 10 +- .../components/rating/rating.stories.ts | 51 ++-- .../skeleton-card-placeholder.component.ts | 4 +- .../examples/skeleton-circle.component.ts | 4 +- .../skeleton-no-animation.component.ts | 4 +- .../examples/skeleton-rectangles.component.ts | 4 +- .../tieredmenu/tieredmenu.stories.ts | 2 +- 33 files changed, 271 insertions(+), 446 deletions(-) diff --git a/src/stories/components/button/button.stories.ts b/src/stories/components/button/button.stories.ts index e5d62fe2..afb1442a 100644 --- a/src/stories/components/button/button.stories.ts +++ b/src/stories/components/button/button.stories.ts @@ -1,15 +1,28 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { ExtraButtonComponent as ButtonComponent } from '../../../lib/components/button/button.component'; +import { ExtraButtonComponent } from '../../../lib/components/button/button.component'; +import { ButtonSizesComponent, Sizes } from './examples/button-sizes.component'; +import { Text } from './examples/button-text.component'; +import { Severity } from './examples/button-severity.component'; +import { Rounded } from './examples/button-rounded.component'; +import { Outlined } from './examples/button-outlined.component'; +import { Loading } from './examples/button-loading.component'; +import { Icon } from './examples/button-icon.component'; +import { Extra } from './examples/button-extra.component'; +import { Disabled } from './examples/button-disabled.component'; +import { Base } from './examples/button-base.component'; +import { Badge } from './examples/button-badge.component'; -type ButtonArgs = ButtonComponent & { onClick?: (event: MouseEvent) => void }; + + +type ButtonArgs = ExtraButtonComponent & { onClick?: (event: MouseEvent) => void }; const meta: Meta = { title: 'Components/Button', - component: ButtonComponent, + component: ExtraButtonComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ - imports: [ButtonComponent] + imports: [ExtraButtonComponent, ButtonSizesComponent] }) ], parameters: { @@ -18,10 +31,10 @@ const meta: Meta = { component: `Интерактивный элемент интерфейса. Используется для инициации действий, отправки форм и навигации. \`\`\`typescript -import { ButtonModule } from 'primeng/button'; -\`\`\``, - }, - }, +import { ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; +\`\`\`` + } + } }, argTypes: { // ── Props ──────────────────────────────────────────────── @@ -31,8 +44,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'Button' }, - type: { summary: 'string' }, - }, + type: { summary: 'string' } + } }, severity: { control: 'select', @@ -41,8 +54,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'null' }, - type: { summary: "'success' | 'info' | 'warning' | 'danger' | null" }, - }, + type: { summary: "'success' | 'info' | 'warning' | 'danger' | null" } + } }, variant: { control: 'select', @@ -51,8 +64,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'primary' }, - type: { summary: "'primary' | 'secondary' | 'outlined' | 'text' | 'link'" }, - }, + type: { summary: "'primary' | 'secondary' | 'outlined' | 'text' | 'link'" } + } }, size: { control: 'select', @@ -61,8 +74,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'base' }, - type: { summary: "'small' | 'base' | 'large' | 'xlarge'" }, - }, + type: { summary: "'small' | 'base' | 'large' | 'xlarge'" } + } }, icon: { control: 'text', @@ -70,8 +83,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: '' }, - type: { summary: 'string' }, - }, + type: { summary: 'string' } + } }, iconPos: { control: 'select', @@ -80,8 +93,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'null' }, - type: { summary: "'prefix' | 'postfix' | null" }, - }, + type: { summary: "'prefix' | 'postfix' | null" } + } }, iconOnly: { control: 'boolean', @@ -89,8 +102,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, rounded: { control: 'boolean', @@ -98,8 +111,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, disabled: { control: 'boolean', @@ -107,8 +120,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, loading: { control: 'boolean', @@ -116,8 +129,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, fluid: { control: 'boolean', @@ -125,8 +138,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, ariaLabel: { control: 'text', @@ -134,8 +147,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'undefined' }, - type: { summary: 'string' }, - }, + type: { summary: 'string' } + } }, autofocus: { control: 'boolean', @@ -143,8 +156,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, tabindex: { control: 'number', @@ -152,8 +165,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'undefined' }, - type: { summary: 'number' }, - }, + type: { summary: 'number' } + } }, text: { control: 'boolean', @@ -161,8 +174,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, // ── Badge ──────────────────────────────────────────────── badge: { @@ -171,8 +184,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Badge', defaultValue: { summary: '' }, - type: { summary: 'string' }, - }, + type: { summary: 'string' } + } }, badgeSeverity: { control: 'select', @@ -181,8 +194,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Badge', defaultValue: { summary: 'null' }, - type: { summary: "'success' | 'info' | 'warning' | 'danger' | 'secondary' | 'contrast' | null" }, - }, + type: { summary: "'success' | 'info' | 'warning' | 'danger' | 'secondary' | 'contrast' | null" } + } }, showBadge: { control: 'boolean', @@ -190,8 +203,8 @@ import { ButtonModule } from 'primeng/button'; table: { category: 'Badge', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, // ── Events ─────────────────────────────────────────────── onClick: { @@ -199,9 +212,9 @@ import { ButtonModule } from 'primeng/button'; description: 'Событие клика по кнопке', table: { category: 'Events', - type: { summary: 'EventEmitter' }, - }, - }, + type: { summary: 'EventEmitter' } + } + } }, args: { showBadge: false, @@ -209,8 +222,8 @@ import { ButtonModule } from 'primeng/button'; badgeSeverity: null, fluid: false, autofocus: false, - text: false, - }, + text: false + } }; const commonTemplate = ` @@ -274,175 +287,4 @@ export const Default: Story = { }, }; -// ── Stories ────────────────────────────────────────────────────────────────── - -export const Sizes: Story = { - render: (args) => ({ - props: args, - template: commonTemplate, - }), - args: { label: 'Button', size: 'large' }, - parameters: { - docs: { - description: { story: 'Все доступные размеры: small, base, large, xlarge.' }, - source: { - code: ` - - - -`, - }, - }, - }, -}; - -export const Icons: Story = { - render: (args) => ({ - props: args, - template: commonTemplate, - }), - args: { label: 'Button', icon: 'ti ti-check' }, - parameters: { - docs: { - description: { story: 'Кнопки с иконками (префикс по умолчанию).' }, - source: { - code: ``, - }, - }, - }, -}; - -export const IconOnly: Story = { - render: (args) => ({ - props: args, - template: commonTemplate, - }), - args: { icon: 'ti ti-check', iconOnly: true }, - parameters: { - docs: { - description: { story: 'Кнопки без текста, только с иконкой.' }, - source: { - code: ``, - }, - }, - }, -}; - -export const Loading: Story = { - render: (args) => ({ - props: args, - template: commonTemplate, - }), - args: { label: 'Button', loading: true }, - parameters: { - docs: { - description: { story: 'Состояние загрузки с индикатором.' }, - source: { - code: ``, - }, - }, - }, -}; - -export const Rounded: Story = { - render: (args) => ({ - props: args, - template: commonTemplate, - }), - args: { label: 'Button', rounded: true }, - parameters: { - docs: { - description: { story: 'Скруглённая форма кнопок.' }, - source: { - code: ``, - }, - }, - }, -}; - -export const Text: Story = { - render: (args) => ({ - props: args, - template: commonTemplate, - }), - args: { label: 'Button', variant: 'text' }, - parameters: { - docs: { - description: { story: 'Текстовый вариант кнопки (без заливки и границ).' }, - source: { - code: ``, - }, - }, - }, -}; - -export const Link: Story = { - render: (args) => ({ - props: args, - template: commonTemplate, - }), - args: { label: 'Link Button', variant: 'link' }, - parameters: { - docs: { - description: { story: 'Кнопка в виде ссылки.' }, - source: { - code: ``, - }, - }, - }, -}; - -export const Severity: Story = { - render: (args) => ({ - props: args, - template: commonTemplate, - }), - args: { label: 'Button', severity: 'success' }, - parameters: { - docs: { - description: { story: 'Цветовые схемы для различных контекстов: success, info, warning, danger.' }, - source: { - code: ``, - }, - }, - }, -}; - -export const Disabled: Story = { - render: (args) => ({ - props: args, - template: commonTemplate, - }), - args: { label: 'Button', disabled: true }, - parameters: { - docs: { - description: { story: 'Состояние кнопки, при котором взаимодействие заблокировано.' }, - source: { - code: ``, - }, - }, - }, -}; - -export const Badge: Story = { - render: (args) => ({ - props: args, - template: commonTemplate, - }), - args: { - label: 'Emails', - badge: '8', - severity: 'success', - badgeSeverity: 'danger', - showBadge: true, - }, - parameters: { - docs: { - description: { story: 'Примеры использования бейджей на кнопках с позиционированием в углу.' }, - source: { - code: ``, - }, - }, - }, -}; - +export { Sizes, Text, Severity, Rounded, Outlined, Loading, Icon, Extra, Disabled, Base, Badge }; diff --git a/src/stories/components/button/examples/button-extra.component.ts b/src/stories/components/button/examples/button-extra.component.ts index d5bf8f40..2bba46a4 100644 --- a/src/stories/components/button/examples/button-extra.component.ts +++ b/src/stories/components/button/examples/button-extra.component.ts @@ -1,6 +1,6 @@ import { StoryObj } from '@storybook/angular'; -export { ButtonComponent } from '../../../../lib/components/button/button.component'; +export { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; export const Extra: StoryObj = { render: (args) => ({ diff --git a/src/stories/components/button/examples/button-sizes.component.ts b/src/stories/components/button/examples/button-sizes.component.ts index 7b5b9a77..9581bda4 100644 --- a/src/stories/components/button/examples/button-sizes.component.ts +++ b/src/stories/components/button/examples/button-sizes.component.ts @@ -1,14 +1,14 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { Button } from 'primeng/button'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; const template = `
- - - - + + + +
`; @@ -18,7 +18,7 @@ const styles = ''; @Component({ selector: 'app-button-sizes', standalone: true, - imports: [Button], + imports: [ExtraButtonComponent], template, styles }) diff --git a/src/stories/components/checkbox/checkbox.stories.ts b/src/stories/components/checkbox/checkbox.stories.ts index 623129e5..5d6a8249 100644 --- a/src/stories/components/checkbox/checkbox.stories.ts +++ b/src/stories/components/checkbox/checkbox.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { ExtraCheckboxComponent as CheckboxComponent } from '../../../lib/components/checkbox/checkbox.component'; +import { ExtraCheckboxComponent } from '../../../lib/components/checkbox/checkbox.component'; import { FormsModule } from '@angular/forms'; import { CheckboxGroupComponent, Group } from './examples/checkbox-group.component'; import { CheckboxIndeterminateComponent, Indeterminate } from './examples/checkbox-indeterminate.component'; @@ -8,23 +8,23 @@ import { CheckboxInvalidComponent, Invalid } from './examples/checkbox-invalid.c import { CheckboxLabelComponent, Label } from './examples/checkbox-label.component'; import { CheckboxCustomLabelComponent, CustomLabel } from './examples/checkbox-custom-label.component'; -type CheckboxArgs = CheckboxComponent & { label?: string }; +type CheckboxArgs = ExtraCheckboxComponent & { label?: string }; const meta: Meta = { title: 'Components/Form/Checkbox', - component: CheckboxComponent, + component: ExtraCheckboxComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - CheckboxComponent, + ExtraCheckboxComponent, FormsModule, CheckboxGroupComponent, CheckboxIndeterminateComponent, CheckboxDisabledComponent, CheckboxInvalidComponent, CheckboxLabelComponent, - CheckboxCustomLabelComponent, + CheckboxCustomLabelComponent ] }) ], @@ -32,9 +32,9 @@ const meta: Meta = { designTokens: { prefix: '--p-checkbox' }, docs: { description: { - component: `Компонент для выбора одного или нескольких вариантов.`, - }, - }, + component: `Компонент для выбора одного или нескольких вариантов.` + } + } }, argTypes: { // ── Props ──────────────────────────────────────────────── @@ -45,8 +45,8 @@ const meta: Meta = { table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, disabled: { control: 'boolean', @@ -54,8 +54,8 @@ const meta: Meta = { table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, indeterminate: { control: 'boolean', @@ -63,8 +63,8 @@ const meta: Meta = { table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, // Hidden props size: { table: { disable: true } }, @@ -87,32 +87,32 @@ const meta: Meta = { description: 'Событие изменения значения', table: { category: 'Events', - type: { summary: 'EventEmitter' }, - }, + type: { summary: 'EventEmitter' } + } }, onFocus: { control: false, description: 'Событие фокуса', table: { category: 'Events', - type: { summary: 'EventEmitter' }, - }, + type: { summary: 'EventEmitter' } + } }, onBlur: { control: false, description: 'Событие потери фокуса', table: { category: 'Events', - type: { summary: 'EventEmitter' }, - }, - }, + type: { summary: 'EventEmitter' } + } + } }, args: { binary: true, disabled: false, invalid: false, - indeterminate: false, - }, + indeterminate: false + } }; export default meta; diff --git a/src/stories/components/checkbox/examples/checkbox-custom-label.component.ts b/src/stories/components/checkbox/examples/checkbox-custom-label.component.ts index 750bb55b..4fa63f2a 100644 --- a/src/stories/components/checkbox/examples/checkbox-custom-label.component.ts +++ b/src/stories/components/checkbox/examples/checkbox-custom-label.component.ts @@ -1,19 +1,19 @@ import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { CheckboxComponent } from '../../../../lib/components/checkbox/checkbox.component'; +import { ExtraCheckboxComponent } from '../../../../lib/components/checkbox/checkbox.component'; const styles = ''; @Component({ selector: 'app-checkbox-custom-label', standalone: true, - imports: [CheckboxComponent, ReactiveFormsModule], + imports: [ExtraCheckboxComponent, ReactiveFormsModule], styles, template: `
@if (labelPosition === 'left') { - + }
@@ -22,7 +22,7 @@ const styles = ''; }
@if (labelPosition === 'right') { - + }
`, @@ -103,16 +103,16 @@ export const CustomLabel: StoryObj = { code: ` import { Component, Input, OnChanges } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { CheckboxComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraCheckboxComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-checkbox-custom-label', standalone: true, - imports: [CheckboxComponent, ReactiveFormsModule], + imports: [ExtraCheckboxComponent, ReactiveFormsModule], template: \`
@if (labelPosition === 'left') { - + }
@@ -121,7 +121,7 @@ import { CheckboxComponent } from '@cdek-it/angular-ui-kit'; }
@if (labelPosition === 'right') { - + }
\`, diff --git a/src/stories/components/checkbox/examples/checkbox-disabled.component.ts b/src/stories/components/checkbox/examples/checkbox-disabled.component.ts index 6467a14c..7f8beca4 100644 --- a/src/stories/components/checkbox/examples/checkbox-disabled.component.ts +++ b/src/stories/components/checkbox/examples/checkbox-disabled.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { CheckboxComponent } from '../../../../lib/components/checkbox/checkbox.component'; +import { ExtraCheckboxComponent } from '../../../../lib/components/checkbox/checkbox.component'; const styles = ''; @Component({ selector: 'app-checkbox-disabled', standalone: true, - imports: [CheckboxComponent, FormsModule], + imports: [ExtraCheckboxComponent, FormsModule], styles, template: ` - + `, }) export class CheckboxDisabledComponent { @@ -21,7 +21,7 @@ export class CheckboxDisabledComponent { export const Disabled: StoryObj = { render: (args) => ({ props: { ...args, checked: true }, - template: ``, + template: ``, }), args: { disabled: true }, parameters: { @@ -32,14 +32,14 @@ export const Disabled: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { CheckboxComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraCheckboxComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-checkbox-disabled', standalone: true, - imports: [CheckboxComponent, ReactiveFormsModule], + imports: [ExtraCheckboxComponent, ReactiveFormsModule], template: \` - + \`, }) export class CheckboxDisabledComponent { diff --git a/src/stories/components/checkbox/examples/checkbox-group.component.ts b/src/stories/components/checkbox/examples/checkbox-group.component.ts index 1564a48f..61db85ad 100644 --- a/src/stories/components/checkbox/examples/checkbox-group.component.ts +++ b/src/stories/components/checkbox/examples/checkbox-group.component.ts @@ -2,20 +2,20 @@ import { Component } from '@angular/core'; import { JsonPipe } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { CheckboxComponent } from '../../../../lib/components/checkbox/checkbox.component'; +import { ExtraCheckboxComponent } from '../../../../lib/components/checkbox/checkbox.component'; const template = `
- - - + + +
`; @Component({ selector: 'app-checkbox-group', standalone: true, - imports: [CheckboxComponent, FormsModule, JsonPipe], + imports: [ExtraCheckboxComponent, FormsModule, JsonPipe], template, }) export class CheckboxGroupComponent { @@ -34,17 +34,17 @@ export const Group: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { CheckboxComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraCheckboxComponent } from '@cdek-it/angular-ui-kit'; import { FormsModule } from '@angular/forms'; @Component({ selector: 'app-checkbox-group', standalone: true, - imports: [CheckboxComponent, FormsModule], + imports: [ExtraCheckboxComponent, FormsModule], template: \` - - - + + + \`, }) export class CheckboxGroupComponent { diff --git a/src/stories/components/checkbox/examples/checkbox-indeterminate.component.ts b/src/stories/components/checkbox/examples/checkbox-indeterminate.component.ts index 8caae69a..acb35a25 100644 --- a/src/stories/components/checkbox/examples/checkbox-indeterminate.component.ts +++ b/src/stories/components/checkbox/examples/checkbox-indeterminate.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { CheckboxComponent } from '../../../../lib/components/checkbox/checkbox.component'; +import { ExtraCheckboxComponent } from '../../../../lib/components/checkbox/checkbox.component'; const styles = ''; @Component({ selector: 'app-checkbox-indeterminate', standalone: true, - imports: [CheckboxComponent, FormsModule], + imports: [ExtraCheckboxComponent, FormsModule], styles, template: ` - + `, }) export class CheckboxIndeterminateComponent { @@ -21,7 +21,7 @@ export class CheckboxIndeterminateComponent { export const Indeterminate: StoryObj = { render: (args) => ({ props: { ...args, checked: false }, - template: ``, + template: ``, }), args: { indeterminate: true }, parameters: { @@ -32,14 +32,14 @@ export const Indeterminate: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { CheckboxComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraCheckboxComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-checkbox-indeterminate', standalone: true, - imports: [CheckboxComponent, FormsModule], + imports: [ExtraCheckboxComponent, FormsModule], template: \` - + \`, }) export class CheckboxIndeterminateComponent { diff --git a/src/stories/components/checkbox/examples/checkbox-invalid.component.ts b/src/stories/components/checkbox/examples/checkbox-invalid.component.ts index 6bf93652..351d56f5 100644 --- a/src/stories/components/checkbox/examples/checkbox-invalid.component.ts +++ b/src/stories/components/checkbox/examples/checkbox-invalid.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { CheckboxComponent } from '../../../../lib/components/checkbox/checkbox.component'; +import { ExtraCheckboxComponent } from '../../../../lib/components/checkbox/checkbox.component'; const styles = ''; @Component({ selector: 'app-checkbox-invalid', standalone: true, - imports: [CheckboxComponent, FormsModule], + imports: [ExtraCheckboxComponent, FormsModule], styles, template: ` - + `, }) export class CheckboxInvalidComponent { @@ -21,7 +21,7 @@ export class CheckboxInvalidComponent { export const Invalid: StoryObj = { render: (args) => ({ props: { ...args, checked: false }, - template: ``, + template: ``, }), args: { invalid: true }, parameters: { @@ -32,14 +32,14 @@ export const Invalid: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { CheckboxComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraCheckboxComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-checkbox-invalid', standalone: true, - imports: [CheckboxComponent, ReactiveFormsModule], + imports: [ExtraCheckboxComponent, ReactiveFormsModule], template: \` - + \`, }) export class CheckboxInvalidComponent { diff --git a/src/stories/components/checkbox/examples/checkbox-label.component.ts b/src/stories/components/checkbox/examples/checkbox-label.component.ts index 8d555ef1..4bb3cb75 100644 --- a/src/stories/components/checkbox/examples/checkbox-label.component.ts +++ b/src/stories/components/checkbox/examples/checkbox-label.component.ts @@ -1,18 +1,18 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { CheckboxComponent } from '../../../../lib/components/checkbox/checkbox.component'; +import { ExtraCheckboxComponent } from '../../../../lib/components/checkbox/checkbox.component'; const styles = ''; @Component({ selector: 'app-checkbox-label', standalone: true, - imports: [CheckboxComponent, FormsModule], + imports: [ExtraCheckboxComponent, FormsModule], styles, template: `
- +
`, @@ -26,7 +26,7 @@ export const Label: StoryObj = { props: { ...args, checked: false }, template: `
- +
`, @@ -39,15 +39,15 @@ export const Label: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { CheckboxComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraCheckboxComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-checkbox-label', standalone: true, - imports: [CheckboxComponent, ReactiveFormsModule], + imports: [ExtraCheckboxComponent, ReactiveFormsModule], template: \`
- +
\`, diff --git a/src/stories/components/chip/examples/chip-disabled.component.ts b/src/stories/components/chip/examples/chip-disabled.component.ts index 57b42718..c235ca30 100644 --- a/src/stories/components/chip/examples/chip-disabled.component.ts +++ b/src/stories/components/chip/examples/chip-disabled.component.ts @@ -1,9 +1,9 @@ import { Component } from '@angular/core'; -import { ChipComponent } from '../../../../lib/components/chip/chip.component'; +import { ExtraChipComponent } from '../../../../lib/components/chip/chip.component'; const template = `
- +
`; const styles = ''; @@ -11,7 +11,7 @@ const styles = ''; @Component({ selector: 'app-chip-disabled', standalone: true, - imports: [ChipComponent], + imports: [ExtraChipComponent], template, styles, }) @@ -28,14 +28,14 @@ export const Disabled = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ChipComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraChipComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-chip-disabled', standalone: true, - imports: [ChipComponent], + imports: [ExtraChipComponent], template: \` - + \`, }) export class ChipDisabledComponent {} diff --git a/src/stories/components/chip/examples/chip-removable-with-icon.component.ts b/src/stories/components/chip/examples/chip-removable-with-icon.component.ts index 2a93ee12..b0d8254a 100644 --- a/src/stories/components/chip/examples/chip-removable-with-icon.component.ts +++ b/src/stories/components/chip/examples/chip-removable-with-icon.component.ts @@ -1,9 +1,9 @@ import { Component } from '@angular/core'; -import { ChipComponent } from '../../../../lib/components/chip/chip.component'; +import { ExtraChipComponent } from '../../../../lib/components/chip/chip.component'; const template = `
- +
`; const styles = ''; @@ -11,7 +11,7 @@ const styles = ''; @Component({ selector: 'app-chip-removable-with-icon', standalone: true, - imports: [ChipComponent], + imports: [ExtraChipComponent], template, styles, }) @@ -28,14 +28,14 @@ export const RemovableWithIcon = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ChipComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraChipComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-chip-removable-with-icon', standalone: true, - imports: [ChipComponent], + imports: [ExtraChipComponent], template: \` - + \`, }) export class ChipRemovableWithIconComponent {} diff --git a/src/stories/components/chip/examples/chip-removable.component.ts b/src/stories/components/chip/examples/chip-removable.component.ts index b15e35db..6e9627c8 100644 --- a/src/stories/components/chip/examples/chip-removable.component.ts +++ b/src/stories/components/chip/examples/chip-removable.component.ts @@ -1,9 +1,9 @@ import { Component } from '@angular/core'; -import { ChipComponent } from '../../../../lib/components/chip/chip.component'; +import { ExtraChipComponent } from '../../../../lib/components/chip/chip.component'; const template = `
- +
`; const styles = ''; @@ -11,7 +11,7 @@ const styles = ''; @Component({ selector: 'app-chip-removable', standalone: true, - imports: [ChipComponent], + imports: [ExtraChipComponent], template, styles, }) @@ -28,14 +28,14 @@ export const Removable = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ChipComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraChipComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-chip-removable', standalone: true, - imports: [ChipComponent], + imports: [ExtraChipComponent], template: \` - + \`, }) export class ChipRemovableComponent {} diff --git a/src/stories/components/chip/examples/chip-with-icon.component.ts b/src/stories/components/chip/examples/chip-with-icon.component.ts index bc3a125b..820ac811 100644 --- a/src/stories/components/chip/examples/chip-with-icon.component.ts +++ b/src/stories/components/chip/examples/chip-with-icon.component.ts @@ -1,9 +1,9 @@ import { Component } from '@angular/core'; -import { ChipComponent } from '../../../../lib/components/chip/chip.component'; +import { ExtraChipComponent } from '../../../../lib/components/chip/chip.component'; const template = `
- +
`; const styles = ''; @@ -11,7 +11,7 @@ const styles = ''; @Component({ selector: 'app-chip-with-icon', standalone: true, - imports: [ChipComponent], + imports: [ExtraChipComponent], template, styles, }) @@ -28,14 +28,14 @@ export const WithIcon = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ChipComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraChipComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-chip-with-icon', standalone: true, - imports: [ChipComponent], + imports: [ExtraChipComponent], template: \` - + \`, }) export class ChipWithIconComponent {} diff --git a/src/stories/components/divider/examples/divider-align-left.component.ts b/src/stories/components/divider/examples/divider-align-left.component.ts index 5e9ad90e..4348d483 100644 --- a/src/stories/components/divider/examples/divider-align-left.component.ts +++ b/src/stories/components/divider/examples/divider-align-left.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { DividerComponent } from '../../../../lib/components/divider/divider.component'; +import { ExtraDividerComponent } from '../../../../lib/components/divider/divider.component'; const template = `
@@ -13,7 +13,7 @@ const styles = ''; @Component({ selector: 'app-divider-align-left', standalone: true, - imports: [DividerComponent], + imports: [ExtraDividerComponent], template, styles, }) @@ -30,12 +30,12 @@ export const AlignLeft = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DividerComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDividerComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-divider-align-left', standalone: true, - imports: [DividerComponent], + imports: [ExtraDividerComponent], template: \` Отправитель diff --git a/src/stories/components/divider/examples/divider-with-icon.component.ts b/src/stories/components/divider/examples/divider-with-icon.component.ts index 9312cd4c..013ae2e0 100644 --- a/src/stories/components/divider/examples/divider-with-icon.component.ts +++ b/src/stories/components/divider/examples/divider-with-icon.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { DividerComponent } from '../../../../lib/components/divider/divider.component'; +import { ExtraDividerComponent } from '../../../../lib/components/divider/divider.component'; const template = `
@@ -13,7 +13,7 @@ const styles = ''; @Component({ selector: 'app-divider-with-icon', standalone: true, - imports: [DividerComponent], + imports: [ExtraDividerComponent], template, styles, }) @@ -30,12 +30,12 @@ export const WithIcon = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DividerComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraDividerComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-divider-with-icon', standalone: true, - imports: [DividerComponent], + imports: [ExtraDividerComponent], template: \` diff --git a/src/stories/components/inputtext/examples/inputtext-clear.component.ts b/src/stories/components/inputtext/examples/inputtext-clear.component.ts index d0c13671..7f710a90 100644 --- a/src/stories/components/inputtext/examples/inputtext-clear.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-clear.component.ts @@ -1,20 +1,20 @@ import { StoryObj } from '@storybook/angular'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; -type Story = StoryObj; +type Story = StoryObj; export const ClearButton: Story = { name: 'ClearButton', render: (args) => ({ props: { ...args }, template: ` - + > `, }), args: { @@ -29,10 +29,10 @@ export const ClearButton: Story = { source: { language: 'ts', code: ` -import { InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputTextComponent } from '@cdek-it/angular-ui-kit'; // template: -// +// `, }, }, diff --git a/src/stories/components/inputtext/examples/inputtext-disabled.component.ts b/src/stories/components/inputtext/examples/inputtext-disabled.component.ts index 4bf1948d..53d03a57 100644 --- a/src/stories/components/inputtext/examples/inputtext-disabled.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-disabled.component.ts @@ -1,21 +1,21 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; export const Disabled: StoryObj = { name: 'Disabled', render: (args) => { const control = new FormControl({ value: '', disabled: true }); return { - props: { ...args, control }, - template: ``, + props: { ...args, control }, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputTextComponent, ReactiveFormsModule], + imports: [ExtraInputTextComponent, ReactiveFormsModule], }, }), ], @@ -28,12 +28,12 @@ export const Disabled: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputTextComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputTextComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputTextComponent, ReactiveFormsModule], + template: \`\`, }) export class DisabledExample { control = new FormControl({ value: '', disabled: true }); diff --git a/src/stories/components/inputtext/examples/inputtext-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-invalid.component.ts index ee49015b..f3a8f25a 100644 --- a/src/stories/components/inputtext/examples/inputtext-invalid.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-invalid.component.ts @@ -1,21 +1,21 @@ import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; export const Invalid: StoryObj = { name: 'Invalid', render: (args) => { const control = new FormControl('', Validators.required); return { - props: { ...args, control }, - template: ``, + props: { ...args, control }, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputTextComponent, ReactiveFormsModule], + imports: [ExtraInputTextComponent, ReactiveFormsModule], }, }), ], @@ -28,12 +28,12 @@ export const Invalid: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; -import { InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputTextComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputTextComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputTextComponent, ReactiveFormsModule], + template: \`\`, }) export class InvalidExample { control = new FormControl('', Validators.required); diff --git a/src/stories/components/inputtext/examples/inputtext-readonly.component.ts b/src/stories/components/inputtext/examples/inputtext-readonly.component.ts index 35ce1dee..52164f36 100644 --- a/src/stories/components/inputtext/examples/inputtext-readonly.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-readonly.component.ts @@ -1,20 +1,20 @@ import { StoryObj } from '@storybook/angular'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; -type Story = StoryObj; +type Story = StoryObj; export const Readonly: Story = { name: 'Readonly', render: (args) => ({ props: { ...args }, - template: ` - + > `, }), args: { @@ -29,10 +29,10 @@ export const Readonly: Story = { source: { language: 'ts', code: ` -import { InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputTextComponent } from '@cdek-it/angular-ui-kit'; // template: -// +// `, }, }, diff --git a/src/stories/components/megamenu/megamenu.stories.ts b/src/stories/components/megamenu/megamenu.stories.ts index da8f8af7..c6c1cc02 100644 --- a/src/stories/components/megamenu/megamenu.stories.ts +++ b/src/stories/components/megamenu/megamenu.stories.ts @@ -17,7 +17,7 @@ const meta: Meta = { \`\`\`typescript import { ExtraMegaMenuComponent } from '@cdek-it/angular-ui-kit'; -\`\`\`, +\`\`\``, }, story: { height: '300px', diff --git a/src/stories/components/progressspinner/progressspinner.stories.ts b/src/stories/components/progressspinner/progressspinner.stories.ts index 98aa8e99..cc0ad2f3 100644 --- a/src/stories/components/progressspinner/progressspinner.stories.ts +++ b/src/stories/components/progressspinner/progressspinner.stories.ts @@ -3,9 +3,7 @@ import { ExtraProgressSpinnerComponent } from '../../../lib/components/progresss import { Sizes, ProgressSpinnerSizesComponent } from './examples/progressspinner-sizes.component'; import { Monochrome, ProgressSpinnerMonochromeComponent } from './examples/progressspinner-monochrome.component'; -type ProgressSpinnerArgs = ExtraProgressSpinnerComponent; - -const meta: Meta = { +const meta: Meta = { title: 'Prime/Misc/ProgressSpinner', component: ExtraProgressSpinnerComponent, tags: ['autodocs'], @@ -19,7 +17,7 @@ const meta: Meta = { \`\`\`typescript import { ExtraProgressSpinnerComponent } from '@cdek-it/angular-ui-kit'; -\`\`\`, +\`\`\``, }, }, designTokens: { prefix: '--p-progressspinner' }, @@ -73,17 +71,7 @@ import { ExtraProgressSpinnerComponent } from '@cdek-it/angular-ui-kit'; }; export default meta; -type Story = StoryObj; - -const commonTemplate = ` - -`; +type Story = StoryObj; // ── Default ────────────────────────────────────────────────────────────────── export const Default: Story = { diff --git a/src/stories/components/radiobutton/examples/radiobutton-disabled.component.ts b/src/stories/components/radiobutton/examples/radiobutton-disabled.component.ts index 497053dd..750b7e29 100644 --- a/src/stories/components/radiobutton/examples/radiobutton-disabled.component.ts +++ b/src/stories/components/radiobutton/examples/radiobutton-disabled.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { RadiobuttonComponent } from '../../../../lib/components/radiobutton/radiobutton.component'; +import { ExtraRadiobuttonComponent } from '../../../../lib/components/radiobutton/radiobutton.component'; const template = `
- +
- +
@@ -19,7 +19,7 @@ const template = ` @Component({ selector: 'app-radiobutton-disabled', standalone: true, - imports: [RadiobuttonComponent, FormsModule], + imports: [ExtraRadiobuttonComponent, FormsModule], template, }) export class RadiobuttonDisabledComponent { @@ -37,16 +37,16 @@ export const Disabled: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { RadiobuttonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraRadiobuttonComponent } from '@cdek-it/angular-ui-kit'; import { FormsModule } from '@angular/forms'; @Component({ selector: 'app-radiobutton-disabled', standalone: true, - imports: [RadiobuttonComponent, FormsModule], + imports: [ExtraRadiobuttonComponent, FormsModule], template: \` - - + + \`, }) export class RadiobuttonDisabledComponent { diff --git a/src/stories/components/radiobutton/examples/radiobutton-group.component.ts b/src/stories/components/radiobutton/examples/radiobutton-group.component.ts index 8bd36b0e..b3d63e02 100644 --- a/src/stories/components/radiobutton/examples/radiobutton-group.component.ts +++ b/src/stories/components/radiobutton/examples/radiobutton-group.component.ts @@ -1,20 +1,20 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { RadiobuttonComponent } from '../../../../lib/components/radiobutton/radiobutton.component'; +import { ExtraRadiobuttonComponent } from '../../../../lib/components/radiobutton/radiobutton.component'; const template = `
- +
- +
- +
@@ -23,7 +23,7 @@ const template = ` @Component({ selector: 'app-radiobutton-group', standalone: true, - imports: [RadiobuttonComponent, FormsModule], + imports: [ExtraRadiobuttonComponent, FormsModule], template, }) export class RadiobuttonGroupComponent { @@ -41,19 +41,19 @@ export const Group: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { RadiobuttonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraRadiobuttonComponent } from '@cdek-it/angular-ui-kit'; import { FormsModule } from '@angular/forms'; @Component({ selector: 'app-radiobutton-group', standalone: true, - imports: [RadiobuttonComponent, FormsModule], + imports: [ExtraRadiobuttonComponent, FormsModule], template: \` - + - + - + \`, }) diff --git a/src/stories/components/radiobutton/examples/radiobutton-invalid.component.ts b/src/stories/components/radiobutton/examples/radiobutton-invalid.component.ts index 430a3b93..ea028959 100644 --- a/src/stories/components/radiobutton/examples/radiobutton-invalid.component.ts +++ b/src/stories/components/radiobutton/examples/radiobutton-invalid.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { RadiobuttonComponent } from '../../../../lib/components/radiobutton/radiobutton.component'; +import { ExtraRadiobuttonComponent } from '../../../../lib/components/radiobutton/radiobutton.component'; const template = `
- +
- +
@@ -19,8 +19,8 @@ const template = ` @Component({ selector: 'app-radiobutton-invalid', standalone: true, - imports: [RadiobuttonComponent, FormsModule], - template, + imports: [ExtraRadiobuttonComponent, FormsModule], + template }) export class RadiobuttonInvalidComponent { selected = '2'; @@ -37,16 +37,16 @@ export const Invalid: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { RadiobuttonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraRadiobuttonComponent } from '@cdek-it/angular-ui-kit'; import { FormsModule } from '@angular/forms'; @Component({ selector: 'app-radiobutton-invalid', standalone: true, - imports: [RadiobuttonComponent, FormsModule], + imports: [ExtraRadiobuttonComponent, FormsModule], template: \` - - + + \`, }) export class RadiobuttonInvalidComponent { diff --git a/src/stories/components/rating/examples/rating-disabled.component.ts b/src/stories/components/rating/examples/rating-disabled.component.ts index e2bf475b..3ed4db9b 100644 --- a/src/stories/components/rating/examples/rating-disabled.component.ts +++ b/src/stories/components/rating/examples/rating-disabled.component.ts @@ -1,19 +1,19 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { RatingComponent } from '../../../../lib/components/rating/rating.component'; +import { ExtraRatingComponent } from '../../../../lib/components/rating/rating.component'; const template = `
- +
`; @Component({ selector: 'app-rating-disabled', standalone: true, - imports: [RatingComponent, FormsModule], - template, + imports: [ExtraRatingComponent, FormsModule], + template }) export class RatingDisabledComponent { value = 2; @@ -38,7 +38,7 @@ import { FormsModule } from '@angular/forms'; standalone: true, imports: [RatingComponent, FormsModule], template: \` - + \`, }) export class RatingDisabledComponent { diff --git a/src/stories/components/rating/examples/rating-readonly.component.ts b/src/stories/components/rating/examples/rating-readonly.component.ts index 6b82adaf..47e22bc3 100644 --- a/src/stories/components/rating/examples/rating-readonly.component.ts +++ b/src/stories/components/rating/examples/rating-readonly.component.ts @@ -1,19 +1,19 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { RatingComponent } from '../../../../lib/components/rating/rating.component'; +import { ExtraRatingComponent } from '../../../../lib/components/rating/rating.component'; const template = `
- +
`; @Component({ selector: 'app-rating-readonly', standalone: true, - imports: [RatingComponent, FormsModule], - template, + imports: [ExtraRatingComponent, FormsModule], + template }) export class RatingReadonlyComponent { value = 4; @@ -38,7 +38,7 @@ import { FormsModule } from '@angular/forms'; standalone: true, imports: [RatingComponent, FormsModule], template: \` - + \`, }) export class RatingReadonlyComponent { diff --git a/src/stories/components/rating/rating.stories.ts b/src/stories/components/rating/rating.stories.ts index 2d544ebe..6f1f147d 100644 --- a/src/stories/components/rating/rating.stories.ts +++ b/src/stories/components/rating/rating.stories.ts @@ -1,32 +1,27 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormsModule } from '@angular/forms'; -import { RatingComponent } from '../../../lib/components/rating/rating.component'; +import { ExtraRatingComponent } from '../../../lib/components/rating/rating.component'; import { RatingReadonlyComponent, ReadOnly } from './examples/rating-readonly.component'; import { RatingDisabledComponent, Disabled } from './examples/rating-disabled.component'; -type RatingArgs = RatingComponent; +type RatingArgs = ExtraRatingComponent; const meta: Meta = { title: 'Components/Form/Rating', - component: RatingComponent, + component: ExtraRatingComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ - imports: [ - RatingComponent, - FormsModule, - RatingReadonlyComponent, - RatingDisabledComponent, - ], - }), + imports: [ExtraRatingComponent, FormsModule, RatingReadonlyComponent, RatingDisabledComponent] + }) ], parameters: { designTokens: { prefix: '--p-rating' }, docs: { description: { - component: `Компонент для отображения и выбора оценки в виде звёзд.`, - }, - }, + component: `Компонент для отображения и выбора оценки в виде звёзд.` + } + } }, argTypes: { // ── Props ──────────────────────────────────────────────── @@ -36,8 +31,8 @@ const meta: Meta = { table: { category: 'Props', defaultValue: { summary: '5' }, - type: { summary: 'number' }, - }, + type: { summary: 'number' } + } }, readonly: { control: 'boolean', @@ -45,8 +40,8 @@ const meta: Meta = { table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, disabled: { control: 'boolean', @@ -54,8 +49,8 @@ const meta: Meta = { table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, autofocus: { table: { disable: true } }, @@ -65,31 +60,31 @@ const meta: Meta = { description: 'Событие изменения оценки', table: { category: 'Events', - type: { summary: 'EventEmitter' }, - }, + type: { summary: 'EventEmitter' } + } }, onFocus: { control: false, description: 'Событие фокуса', table: { category: 'Events', - type: { summary: 'EventEmitter' }, - }, + type: { summary: 'EventEmitter' } + } }, onBlur: { control: false, description: 'Событие потери фокуса', table: { category: 'Events', - type: { summary: 'EventEmitter' }, - }, - }, + type: { summary: 'EventEmitter' } + } + } }, args: { stars: 5, readonly: false, - disabled: false, - }, + disabled: false + } }; export default meta; diff --git a/src/stories/components/skeleton/examples/skeleton-card-placeholder.component.ts b/src/stories/components/skeleton/examples/skeleton-card-placeholder.component.ts index 69fcd072..3fd0b608 100644 --- a/src/stories/components/skeleton/examples/skeleton-card-placeholder.component.ts +++ b/src/stories/components/skeleton/examples/skeleton-card-placeholder.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { SkeletonComponent } from '../../../../lib/components/skeleton/skeleton.component'; +import { ExtraSkeletonComponent } from '../../../../lib/components/skeleton/skeleton.component'; const template = `
@@ -19,7 +19,7 @@ const styles = ''; @Component({ selector: 'app-skeleton-card-placeholder', standalone: true, - imports: [SkeletonComponent], + imports: [ExtraSkeletonComponent], template, styles, }) diff --git a/src/stories/components/skeleton/examples/skeleton-circle.component.ts b/src/stories/components/skeleton/examples/skeleton-circle.component.ts index 77d322a3..6fee4476 100644 --- a/src/stories/components/skeleton/examples/skeleton-circle.component.ts +++ b/src/stories/components/skeleton/examples/skeleton-circle.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { SkeletonComponent } from '../../../../lib/components/skeleton/skeleton.component'; +import { ExtraSkeletonComponent } from '../../../../lib/components/skeleton/skeleton.component'; const template = `
@@ -16,7 +16,7 @@ const styles = ''; @Component({ selector: 'app-skeleton-circle', standalone: true, - imports: [SkeletonComponent], + imports: [ExtraSkeletonComponent], template, styles, }) diff --git a/src/stories/components/skeleton/examples/skeleton-no-animation.component.ts b/src/stories/components/skeleton/examples/skeleton-no-animation.component.ts index 59e91787..14d25259 100644 --- a/src/stories/components/skeleton/examples/skeleton-no-animation.component.ts +++ b/src/stories/components/skeleton/examples/skeleton-no-animation.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { SkeletonComponent } from '../../../../lib/components/skeleton/skeleton.component'; +import { ExtraSkeletonComponent } from '../../../../lib/components/skeleton/skeleton.component'; const template = `
@@ -16,7 +16,7 @@ const styles = ''; @Component({ selector: 'app-skeleton-no-animation', standalone: true, - imports: [SkeletonComponent], + imports: [ExtraSkeletonComponent], template, styles, }) diff --git a/src/stories/components/skeleton/examples/skeleton-rectangles.component.ts b/src/stories/components/skeleton/examples/skeleton-rectangles.component.ts index 7dcee49b..cb4ac4a9 100644 --- a/src/stories/components/skeleton/examples/skeleton-rectangles.component.ts +++ b/src/stories/components/skeleton/examples/skeleton-rectangles.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { SkeletonComponent } from '../../../../lib/components/skeleton/skeleton.component'; +import { ExtraSkeletonComponent } from '../../../../lib/components/skeleton/skeleton.component'; const template = `
@@ -16,7 +16,7 @@ const styles = ''; @Component({ selector: 'app-skeleton-rectangles', standalone: true, - imports: [SkeletonComponent], + imports: [ExtraSkeletonComponent], template, styles, }) diff --git a/src/stories/components/tieredmenu/tieredmenu.stories.ts b/src/stories/components/tieredmenu/tieredmenu.stories.ts index fed22009..3513703d 100644 --- a/src/stories/components/tieredmenu/tieredmenu.stories.ts +++ b/src/stories/components/tieredmenu/tieredmenu.stories.ts @@ -25,7 +25,7 @@ const meta: Meta = { \`\`\`typescript import { ExtraTieredMenuComponent as TieredMenuComponent } from '@cdek-it/angular-ui-kit'; -\`\`\`", +\`\`\``, }, }, designTokens: { prefix: '--p-tieredmenu' }, From 251af5a27ed8de4159ade562f8730a2c909dec60 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 28 Apr 2026 17:44:53 +0700 Subject: [PATCH 223/258] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=BE=D1=82?= =?UTF-8?q?=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D0=BA=D0=B8=20=D0=B2=20option=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +++- src/lib/components/select/select.component.ts | 5 +++-- src/prime-preset/tokens/components/select.ts | 21 +++++++------------ 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index ce8e3c03..875d7dc9 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,6 @@ src/assets/components/themes /debug-storybook.log /documentation.json -.claude/* \ No newline at end of file +.claude/* + +.playwright-mcp/* \ No newline at end of file diff --git a/src/lib/components/select/select.component.ts b/src/lib/components/select/select.component.ts index fdf23ce0..9c1a2bc7 100644 --- a/src/lib/components/select/select.component.ts +++ b/src/lib/components/select/select.component.ts @@ -109,7 +109,7 @@ export class SelectComponent implements ControlValueAccessor, OnInit { @Input() floatLabel = false; @Input() label = ''; @Input() checkmark = true; - @Input() checkmarkIcon = '\ea5e'; + @Input() checkmarkIcon = 'ea5e'; @Input() emptyMessage = 'Нет данных'; @Input() emptyFilterMessage = 'Результаты не найдены'; @Input() optionTemplate: TemplateRef | null = null; @@ -137,7 +137,8 @@ export class SelectComponent implements ControlValueAccessor, OnInit { } get panelStyle(): Record { - return { '--p-select-checkmark-content': `"\\${this.checkmarkIcon}"` }; + const char = String.fromCodePoint(parseInt(this.checkmarkIcon, 16)); + return { '--p-select-checkmark-content': `"${char}"` }; } get selectClasses(): Record { diff --git a/src/prime-preset/tokens/components/select.ts b/src/prime-preset/tokens/components/select.ts index 8a2b8bca..4c3c1e80 100644 --- a/src/prime-preset/tokens/components/select.ts +++ b/src/prime-preset/tokens/components/select.ts @@ -71,30 +71,25 @@ export const selectCss = ({ dt }: { dt: (token: string) => string }): string => color: ${dt('select.option.selectedFocusColor')}; } - /* Скрываем пустой SVG и заменяем на tabler-иконку */ - .p-select-option-check-icon, - .p-select-option-blank-icon { + /* Скрываем PrimeNG SVG, заменяем на tabler-иконку */ + .p-select-option .p-select-option-check-icon, + .p-select-option .p-select-option-blank-icon { display: none; } - .p-select-option:has(.p-select-option-check-icon)::before { + .p-select-option:has(.p-select-option-check-icon)::before, + .p-select-option:has(.p-select-option-blank-icon)::before { font-family: 'tabler-icons'; content: var(--p-select-checkmark-content, "\\ea5e"); font-size: ${dt('select.extend.iconSize')}; - color: ${dt('select.option.selectedColor')}; + color: ${dt('select.checkmark.color')}; flex-shrink: 0; - } - - .p-select-option:has(.p-select-option-check-icon).p-focus::before { - color: ${dt('select.option.selectedFocusColor')}; + margin-inline-start: ${dt('select.checkmark.gutterStart')}; + margin-inline-end: ${dt('select.checkmark.gutterEnd')}; } .p-select-option:has(.p-select-option-blank-icon)::before { - font-family: 'tabler-icons'; - content: var(--p-select-checkmark-content, "\\ea5e"); - font-size: ${dt('select.extend.iconSize')}; visibility: hidden; - flex-shrink: 0; } /* ─── Иконки ─── */ From 6a6f41b6776b135e188a07f420ba90dc4d3bae5a Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 28 Apr 2026 18:10:00 +0700 Subject: [PATCH 224/258] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=81=D1=82?= =?UTF-8?q?=D0=B8=D0=BB=D0=B5=D0=B9=20=D0=B8=D0=BA=D0=BE=D0=BD=D0=BA=D0=B8?= =?UTF-8?q?=20=D1=87=D0=B5=D0=BA=D0=BC=D0=B0=D1=80=D0=BA=20=D0=B2=20=D1=81?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D0=BA=D1=82=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/select.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/prime-preset/tokens/components/select.ts b/src/prime-preset/tokens/components/select.ts index 4c3c1e80..9a3bfd52 100644 --- a/src/prime-preset/tokens/components/select.ts +++ b/src/prime-preset/tokens/components/select.ts @@ -82,12 +82,16 @@ export const selectCss = ({ dt }: { dt: (token: string) => string }): string => font-family: 'tabler-icons'; content: var(--p-select-checkmark-content, "\\ea5e"); font-size: ${dt('select.extend.iconSize')}; - color: ${dt('select.checkmark.color')}; + color: var(--p-select-option-selected-color); flex-shrink: 0; margin-inline-start: ${dt('select.checkmark.gutterStart')}; margin-inline-end: ${dt('select.checkmark.gutterEnd')}; } + .p-select-option:has(.p-select-option-check-icon).p-focus::before { + color: var(--p-select-option-focus-color); + } + .p-select-option:has(.p-select-option-blank-icon)::before { visibility: hidden; } From fcf206aa4d92ef34775a93591defda2e66753278 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 28 Apr 2026 18:57:11 +0700 Subject: [PATCH 225/258] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B5=D0=B2=D1=8C=D1=8E=20=D1=81=D1=82=D0=BE=D1=80=D0=B8=D1=81?= =?UTF-8?q?=D0=BE=D0=B2;=20=D0=B4=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20template?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/password/password.component.ts | 23 +++- .../tokens/components/password.ts | 15 ++- src/prime-preset/tokens/tokens.json | 10 ++ .../examples/password-template.component.ts | 110 +++++++++++++----- .../components/password/password.stories.ts | 4 + 5 files changed, 124 insertions(+), 38 deletions(-) diff --git a/src/lib/components/password/password.component.ts b/src/lib/components/password/password.component.ts index 9dba3fc4..2b1ebe0e 100644 --- a/src/lib/components/password/password.component.ts +++ b/src/lib/components/password/password.component.ts @@ -1,7 +1,8 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, forwardRef } from '@angular/core'; +import { ChangeDetectionStrategy, Component, ContentChild, EventEmitter, Input, Output, TemplateRef, forwardRef } from '@angular/core'; import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { NgTemplateOutlet } from '@angular/common'; import { Password } from 'primeng/password'; +import { PrimeTemplate } from 'primeng/api'; import { FloatLabel } from 'primeng/floatlabel'; export type PasswordSize = 'small' | 'base' | 'large' | 'xlarge'; @@ -11,7 +12,7 @@ export type PasswordSize = 'small' | 'base' | 'large' | 'xlarge'; host: { style: 'display: block' }, standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [Password, FormsModule, FloatLabel, NgTemplateOutlet], + imports: [Password, FormsModule, FloatLabel, NgTemplateOutlet, PrimeTemplate], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -48,14 +49,29 @@ export type PasswordSize = 'small' | 'base' | 'large' | 'xlarge'; [inputId]="inputId" [ariaLabel]="ariaLabel" [ariaLabelledBy]="ariaLabelledBy" + [appendTo]="appendTo" [autofocus]="autofocus" (onFocus)="onFocus.emit($event)" (onBlur)="onBlur.emit($event)" - > + > + @if (headerTemplate) { + + + + } + @if (footerTemplate) { + + + + } + `, }) export class PasswordComponent implements ControlValueAccessor { + @ContentChild('header') headerTemplate: TemplateRef | null = null; + @ContentChild('footer') footerTemplate: TemplateRef | null = null; + @Input() feedback = true; @Input() toggleMask = false; @Input() disabled = false; @@ -74,6 +90,7 @@ export class PasswordComponent implements ControlValueAccessor { @Input() inputStyleClass: string | undefined = undefined; @Input() ariaLabel: string | undefined = undefined; @Input() ariaLabelledBy: string | undefined = undefined; + @Input() appendTo: any = 'body'; @Input() autofocus = false; @Output() onFocus = new EventEmitter(); diff --git a/src/prime-preset/tokens/components/password.ts b/src/prime-preset/tokens/components/password.ts index 2bb0a00c..b682ad02 100644 --- a/src/prime-preset/tokens/components/password.ts +++ b/src/prime-preset/tokens/components/password.ts @@ -7,6 +7,7 @@ export const passwordCss = ({ dt }: { dt: (token: string) => string }): string = .p-password-toggle-mask-icon, .p-icon.p-password-toggle-mask-icon.p-password-unmask-icon { cursor: pointer; + color: ${dt('password.icon.color')}; } /* ─── Оверлей и индикатор ─── */ @@ -15,9 +16,11 @@ export const passwordCss = ({ dt }: { dt: (token: string) => string }): string = } .p-password-meter-text { - color: ${dt('text.mutedColor')}; + font-family: ${dt('fonts.fontFamily.base')}; font-size: ${dt('fonts.fontSize.200')}; - font-weight: ${dt('fonts.fontWeight.medium')}; + font-weight: ${dt('fonts.fontWeight.regular')}; + line-height: ${dt('fonts.lineHeight.250')}; + color: ${dt('password.overlay.color')}; } /* ─── Focus ─── */ @@ -67,8 +70,12 @@ export const passwordCss = ({ dt }: { dt: (token: string) => string }): string = .p-password-rule { display: flex; align-items: center; - gap: ${dt('content.gap.200')}; - font-size: ${dt('fonts.fontSize.100')}; + gap: ${dt('password.content.gap')}; + font-family: ${dt('fonts.fontFamily.base')}; + font-size: ${dt('fonts.fontSize.200')}; + font-weight: ${dt('fonts.fontWeight.regular')}; + line-height: ${dt('fonts.lineHeight.250')}; + color: ${dt('password.overlay.color')}; } /* ─── Состояния иконок правил ─── */ diff --git a/src/prime-preset/tokens/tokens.json b/src/prime-preset/tokens/tokens.json index 20c71fb1..d760d1d5 100644 --- a/src/prime-preset/tokens/tokens.json +++ b/src/prime-preset/tokens/tokens.json @@ -3960,6 +3960,16 @@ "icon": { "color": "{form.placeholderColor}" } + }, + "dark": { + "strength": { + "weakBackground": "{error.500}", + "mediumBackground": "{warn.500}", + "strongBackground": "{success.600}" + }, + "icon": { + "color": "{form.placeholderColor}" + } } }, "meter": { diff --git a/src/stories/components/password/examples/password-template.component.ts b/src/stories/components/password/examples/password-template.component.ts index 5d761fa0..063b24b5 100644 --- a/src/stories/components/password/examples/password-template.component.ts +++ b/src/stories/components/password/examples/password-template.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { Password } from 'primeng/password'; +import { PasswordComponent } from '../../../../lib/components/password/password.component'; import { Divider } from 'primeng/divider'; @Component({ selector: 'app-password-template', standalone: true, - imports: [Password, Divider, FormsModule], + imports: [PasswordComponent, Divider, FormsModule], template: `
- - -
Создание пароля
-
-
    -
  • Минимум одна строчная буква
  • -
  • Минимум одна заглавная буква
  • -
  • Минимум одна цифра
  • -
  • Не менее 8 символов
  • -
+
+
+ + Минимум одна строчная буква +
+
+ + Минимум одна заглавная буква +
+
+ + Минимум одна цифра +
+
+ + Не менее 8 символов +
+
-
+
`, }) export class PasswordTemplateComponent { value: string | null = null; + + get hasLowercase(): boolean { + return /[a-z]/.test(this.value ?? ''); + } + + get hasUppercase(): boolean { + return /[A-Z]/.test(this.value ?? ''); + } + + get hasDigit(): boolean { + return /\d/.test(this.value ?? ''); + } + + get hasMinLength(): boolean { + return (this.value ?? '').length >= 8; + } } export const Template: StoryObj = { @@ -49,22 +73,21 @@ export const Template: StoryObj = { controls: { disable: true }, docs: { description: { - story: 'Кастомный контент через `ng-template`: заголовок, разделитель и список требований к паролю.', + story: 'Кастомный контент через `ng-template`: разделитель и список требований к паролю с tabler-иконками.', }, source: { language: 'ts', code: ` import { Component } from '@angular/core'; -import { Password } from 'primeng/password'; -import { Divider } from 'primeng/divider'; import { FormsModule } from '@angular/forms'; +import { PasswordComponent } from '@cdek-it/angular-ui-kit'; +import { Divider } from 'primeng/divider'; @Component({ - selector: 'app-password-template', standalone: true, - imports: [Password, Divider, FormsModule], + imports: [PasswordComponent, Divider, FormsModule], template: \` - - -
Создание пароля
-
-
    -
  • Минимум одна строчная буква
  • -
  • Минимум одна заглавная буква
  • -
  • Минимум одна цифра
  • -
  • Не менее 8 символов
  • -
+
+
+ + Минимум одна строчная буква +
+
+ + Минимум одна заглавная буква +
+
+ + Минимум одна цифра +
+
+ + Не менее 8 символов +
+
-
+ \`, }) -export class PasswordTemplateComponent { +export class PasswordTemplateExample { value: string | null = null; + + get hasLowercase(): boolean { + return /[a-z]/.test(this.value ?? ''); + } + + get hasUppercase(): boolean { + return /[A-Z]/.test(this.value ?? ''); + } + + get hasDigit(): boolean { + return /\\d/.test(this.value ?? ''); + } + + get hasMinLength(): boolean { + return (this.value ?? '').length >= 8; + } } `, }, diff --git a/src/stories/components/password/password.stories.ts b/src/stories/components/password/password.stories.ts index 22960f5a..00306792 100644 --- a/src/stories/components/password/password.stories.ts +++ b/src/stories/components/password/password.stories.ts @@ -25,6 +25,10 @@ const meta: Meta = { PasswordTemplateComponent, ], }), + (story) => ({ + ...story(), + template: `
${story().template}
`, + }), ], parameters: { designTokens: { prefix: '--p-password' }, From a571d3cd196bea61e0538a71f05c27f0370a158b Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Tue, 28 Apr 2026 21:44:04 +0700 Subject: [PATCH 226/258] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=BF=D1=81=D0=B0=20floatLabel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/stories/components/password/password.stories.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/stories/components/password/password.stories.ts b/src/stories/components/password/password.stories.ts index 00306792..b7367373 100644 --- a/src/stories/components/password/password.stories.ts +++ b/src/stories/components/password/password.stories.ts @@ -167,7 +167,7 @@ import { PasswordComponent } from '@cdek-it/angular-ui-kit'; invalid: false, fluid: false, floatLabel: false, - label: '', + label: 'Пароль', }, }; @@ -182,13 +182,16 @@ export const Default: Story = { if (!args.feedback) parts.push(`[feedback]="false"`); if (args.toggleMask) parts.push(`[toggleMask]="true"`); - if (args.placeholder) parts.push(`placeholder="${args.placeholder}"`); + if (args.floatLabel) { + parts.push(`[floatLabel]="true"`); + if (args.label) parts.push(`label="${args.label}"`); + } else { + if (args.placeholder) parts.push(`placeholder="${args.placeholder}"`); + } if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); if (args.disabled) parts.push(`[disabled]="true"`); if (args.invalid) parts.push(`[invalid]="true"`); if (args.fluid) parts.push(`[fluid]="true"`); - if (args.floatLabel) parts.push(`[floatLabel]="true"`); - if (args.label) parts.push(`label="${args.label}"`); parts.push(`[(ngModel)]="value"`); From a7567ead40c69bac20ca8c2c3fa1f6ad26222ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=A7=D0=B8=D1=91=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 30 Apr 2026 11:47:47 +0700 Subject: [PATCH 227/258] ~fix(toggleswitch): fix ng control inject. --- .../toggleswitch/toggleswitch.component.ts | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/lib/components/toggleswitch/toggleswitch.component.ts b/src/lib/components/toggleswitch/toggleswitch.component.ts index 71358926..0d0f953f 100644 --- a/src/lib/components/toggleswitch/toggleswitch.component.ts +++ b/src/lib/components/toggleswitch/toggleswitch.component.ts @@ -1,11 +1,16 @@ -import { Component, EventEmitter, Optional, Output, Self } from '@angular/core'; -import { ControlValueAccessor, FormsModule, NgControl } from '@angular/forms'; +import { Component, EventEmitter, forwardRef, inject, Injector, OnInit, Optional, Output, Self } from '@angular/core'; +import { ControlValueAccessor, FormControl, FormsModule, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms'; import { ToggleSwitch } from 'primeng/toggleswitch'; @Component({ selector: 'toggleswitch', standalone: true, imports: [ToggleSwitch, FormsModule], + providers: [{ + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ToggleSwitchComponent), + multi: true, + }], template: ` `, }) -export class ToggleSwitchComponent implements ControlValueAccessor { - @Output() onChange = new EventEmitter(); - @Output() onFocus = new EventEmitter(); - @Output() onBlur = new EventEmitter(); +export class ToggleSwitchComponent implements OnInit, ControlValueAccessor { + @Output() onChange = new EventEmitter(); + @Output() onFocus = new EventEmitter(); + @Output() onBlur = new EventEmitter(); modelValue = false; + ngControl: NgControl | null = null; + + private injector = inject(Injector); + private _disabled = false; private _onChange: (value: boolean) => void = () => {}; private _onTouched: () => void = () => {}; - constructor(@Optional() @Self() private ngControl: NgControl) { - if (ngControl) { - ngControl.valueAccessor = this; - } - } get isDisabled(): boolean { return this._disabled; @@ -43,6 +47,10 @@ export class ToggleSwitchComponent implements ControlValueAccessor { return !!this.ngControl?.invalid; } + ngOnInit(): void { + this.ngControl = this.injector.get(NgControl, null, { self: true }); + } + handleChange(value: boolean): void { this.modelValue = value; this._onChange(value); From 6d37af619fb16bf469b11704a462f0e8b31d515b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=A7=D0=B8=D1=91=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 30 Apr 2026 12:01:10 +0700 Subject: [PATCH 228/258] ~cleanup --- .../toggleswitch/toggleswitch.component.ts | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/lib/components/toggleswitch/toggleswitch.component.ts b/src/lib/components/toggleswitch/toggleswitch.component.ts index 0d0f953f..30dc52e5 100644 --- a/src/lib/components/toggleswitch/toggleswitch.component.ts +++ b/src/lib/components/toggleswitch/toggleswitch.component.ts @@ -1,16 +1,11 @@ -import { Component, EventEmitter, forwardRef, inject, Injector, OnInit, Optional, Output, Self } from '@angular/core'; -import { ControlValueAccessor, FormControl, FormsModule, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms'; +import { Component, EventEmitter, Optional, Output, Self } from '@angular/core'; +import { ControlValueAccessor, FormsModule, NgControl } from '@angular/forms'; import { ToggleSwitch } from 'primeng/toggleswitch'; @Component({ selector: 'toggleswitch', standalone: true, imports: [ToggleSwitch, FormsModule], - providers: [{ - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => ToggleSwitchComponent), - multi: true, - }], template: ` `, }) -export class ToggleSwitchComponent implements OnInit, ControlValueAccessor { +export class ToggleSwitchComponent implements ControlValueAccessor { @Output() onChange = new EventEmitter(); @Output() onFocus = new EventEmitter(); @Output() onBlur = new EventEmitter(); modelValue = false; - ngControl: NgControl | null = null; - - private injector = inject(Injector); private _disabled = false; private _onChange: (value: boolean) => void = () => {}; private _onTouched: () => void = () => {}; + constructor(@Optional() @Self() private ngControl: NgControl) { + if (ngControl) { + ngControl.valueAccessor = this; + } + } get isDisabled(): boolean { return this._disabled; @@ -47,10 +44,6 @@ export class ToggleSwitchComponent implements OnInit, ControlValueAccessor { return !!this.ngControl?.invalid; } - ngOnInit(): void { - this.ngControl = this.injector.get(NgControl, null, { self: true }); - } - handleChange(value: boolean): void { this.modelValue = value; this._onChange(value); From 4317e14182ab9afaac46d4536ea845801da641a3 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 30 Apr 2026 13:14:02 +0700 Subject: [PATCH 229/258] =?UTF-8?q?=D1=80=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D1=80=D0=B8=D1=80=D0=BD=D0=B3:=20formControls?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 3 + .../inputmask/inputmask.component.ts | 57 ++++++++--------- .../examples/inputmask-disabled.component.ts | 58 +++++++++-------- .../examples/inputmask-invalid.component.ts | 62 +++++++++++-------- .../examples/inputmask-readonly.component.ts | 57 +++++++++-------- .../examples/inputmask-sizes.component.ts | 2 - .../components/inputmask/inputmask.stories.ts | 34 ++-------- 7 files changed, 135 insertions(+), 138 deletions(-) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..43042a87 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,3 @@ +# Project Rules + +Основные правила и запреты — в `.claude/skills/generate-component/references/red-lines.md`. diff --git a/src/lib/components/inputmask/inputmask.component.ts b/src/lib/components/inputmask/inputmask.component.ts index 423e560f..71d980c3 100644 --- a/src/lib/components/inputmask/inputmask.component.ts +++ b/src/lib/components/inputmask/inputmask.component.ts @@ -1,5 +1,6 @@ -import { ChangeDetectionStrategy, Component, Input, Output, EventEmitter, forwardRef } from '@angular/core'; -import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ChangeDetectionStrategy, Component, DestroyRef, inject, Injector, Input, OnInit, Output, EventEmitter } from '@angular/core'; +import { ControlValueAccessor, FormControl, NgControl, ReactiveFormsModule } from '@angular/forms'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { InputMask } from 'primeng/inputmask'; export type InputMaskSize = 'small' | 'base' | 'large' | 'xlarge'; @@ -9,14 +10,7 @@ export type InputMaskVariant = 'outlined' | 'filled'; selector: 'input-mask', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputMask, FormsModule], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => InputMaskComponent), - multi: true, - }, - ], + imports: [InputMask, ReactiveFormsModule], host: { style: 'display: block', '[class.input-mask-xlg]': 'size === "xlarge"', @@ -29,17 +23,15 @@ export type InputMaskVariant = 'outlined' | 'filled'; [autoClear]="autoClear" [showClear]="showClear" [unmask]="unmask" - [disabled]="disabled" [readonly]="readonly" - [invalid]="invalid" [placeholder]="placeholder" [fluid]="fluid" [variant]="variant === 'filled' ? 'filled' : undefined" [characterPattern]="characterPattern" [keepBuffer]="keepBuffer" + [invalid]="invalid" [autocomplete]="autocomplete" - [(ngModel)]="modelValue" - (ngModelChange)="onModelChange($event)" + [formControl]="control" (onComplete)="onComplete.emit($event)" (onFocus)="onFocusEvent.emit($event)" (onBlur)="onBlurEvent.emit($event)" @@ -49,7 +41,13 @@ export type InputMaskVariant = 'outlined' | 'filled'; > `, }) -export class InputMaskComponent implements ControlValueAccessor { +export class InputMaskComponent implements ControlValueAccessor, OnInit { + private readonly _injector = inject(Injector); + private readonly destroyRef = inject(DestroyRef); + private _ngControl: NgControl | null = null; + + readonly control = new FormControl(null); + @Input() mask = ''; @Input() slotChar = '_'; @Input() autoClear = true; @@ -57,9 +55,7 @@ export class InputMaskComponent implements ControlValueAccessor { @Input() unmask = false; @Input() placeholder = ''; @Input() size: InputMaskSize = 'base'; - @Input() disabled = false; @Input() readonly = false; - @Input() invalid = false; @Input() fluid = false; @Input() variant: InputMaskVariant = 'outlined'; @Input() characterPattern = '[A-Za-z]'; @@ -73,10 +69,20 @@ export class InputMaskComponent implements ControlValueAccessor { @Output() onKeydownEvent = new EventEmitter(); @Output() onClearEvent = new EventEmitter(); - modelValue: string | null = null; - private _onChange: (value: string | null) => void = () => {}; - onTouched: () => void = () => {}; + private _onTouched: () => void = () => {}; + + ngOnInit(): void { + this._ngControl = this._injector.get(NgControl, null, { self: true, optional: true }); + + this.control.valueChanges + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(v => this._onChange(v)); + } + + get invalid(): boolean { + return this._ngControl?.invalid ?? false; + } get primeSize(): 'small' | 'large' | undefined { if (this.size === 'small') return 'small'; @@ -84,13 +90,8 @@ export class InputMaskComponent implements ControlValueAccessor { return undefined; } - onModelChange(value: string | null): void { - this.modelValue = value; - this._onChange(value); - } - writeValue(value: string | null): void { - this.modelValue = value ?? null; + this.control.setValue(value ?? null, { emitEvent: false }); } registerOnChange(fn: (value: string | null) => void): void { @@ -98,10 +99,10 @@ export class InputMaskComponent implements ControlValueAccessor { } registerOnTouched(fn: () => void): void { - this.onTouched = fn; + this._onTouched = fn; } setDisabledState(isDisabled: boolean): void { - this.disabled = isDisabled; + isDisabled ? this.control.disable({ emitEvent: false }) : this.control.enable({ emitEvent: false }); } } diff --git a/src/stories/components/inputmask/examples/inputmask-disabled.component.ts b/src/stories/components/inputmask/examples/inputmask-disabled.component.ts index 8674c9b7..29206cc9 100644 --- a/src/stories/components/inputmask/examples/inputmask-disabled.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-disabled.component.ts @@ -1,46 +1,50 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; -type Story = StoryObj; +const styles = ''; -export const Disabled: Story = { +@Component({ + selector: 'app-inputmask-disabled', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputMaskComponent, ReactiveFormsModule], + template: ` + + `, + styles, +}) +class InputMaskDisabledComponent { + readonly control = new FormControl({ value: '12-34-56', disabled: true }); +} + +export const Disabled: StoryObj = { name: 'Disabled', - render: (args) => ({ - props: { ...args, value: '12-34-56' }, - template: ` - - `, + render: () => ({ + template: ``, }), - args: { - mask: '99-99-99', - disabled: true, - placeholder: '99-99-99', - }, parameters: { + controls: { disable: true }, docs: { description: { - story: 'Отключённое состояние — поле недоступно для взаимодействия.', + story: 'Отключённое состояние — управляется через `FormControl`.', }, source: { language: 'ts', code: ` import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; + +// В компоненте: +readonly control = new FormControl({ value: '12-34-56', disabled: true }); // template: -// +// `, }, }, diff --git a/src/stories/components/inputmask/examples/inputmask-invalid.component.ts b/src/stories/components/inputmask/examples/inputmask-invalid.component.ts index 13a691a2..7cee3d8f 100644 --- a/src/stories/components/inputmask/examples/inputmask-invalid.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-invalid.component.ts @@ -1,46 +1,54 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; -type Story = StoryObj; +const styles = ''; -export const Invalid: Story = { +@Component({ + selector: 'app-inputmask-invalid', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputMaskComponent, ReactiveFormsModule], + template: ` + + `, + styles, +}) +class InputMaskInvalidComponent { + readonly control = new FormControl('', Validators.required); + + constructor() { + this.control.markAsTouched(); + } +} + +export const Invalid: StoryObj = { name: 'Invalid', - render: (args) => ({ - props: { ...args, value: '' }, - template: ` - - `, + render: () => ({ + template: ``, }), - args: { - mask: '99-99-99', - invalid: true, - placeholder: 'Обязательное поле', - }, parameters: { + controls: { disable: true }, docs: { description: { - story: 'Невалидное состояние — поле отображает ошибку.', + story: 'Невалидное состояние — определяется через валидаторы `FormControl`.', }, source: { language: 'ts', code: ` import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; + +// В компоненте: +readonly control = new FormControl('', Validators.required); // template: -// +// `, }, }, diff --git a/src/stories/components/inputmask/examples/inputmask-readonly.component.ts b/src/stories/components/inputmask/examples/inputmask-readonly.component.ts index 90685af9..9bd85a84 100644 --- a/src/stories/components/inputmask/examples/inputmask-readonly.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-readonly.component.ts @@ -1,34 +1,36 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; -type Story = StoryObj; +const styles = ''; -export const Readonly: Story = { +@Component({ + selector: 'app-inputmask-readonly', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputMaskComponent, ReactiveFormsModule], + template: ` + + `, + styles, +}) +class InputMaskReadonlyComponent { + readonly control = new FormControl('12-34-56'); +} + +export const Readonly: StoryObj = { name: 'Readonly', - render: (args) => ({ - props: { ...args, value: '12-34-56' }, - template: ` - - `, + render: () => ({ + template: ``, }), - args: { - mask: '99-99-99', - readonly: true, - placeholder: '99-99-99', - }, parameters: { + controls: { disable: true }, docs: { description: { story: 'Режим только для чтения — поле отображает значение, но недоступно для редактирования.', @@ -37,10 +39,13 @@ export const Readonly: Story = { language: 'ts', code: ` import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; + +// В компоненте: +readonly control = new FormControl('12-34-56'); // template: -// +// `, }, }, diff --git a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts index 1cac61c9..5f9db99c 100644 --- a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts @@ -13,9 +13,7 @@ export const Sizes: Story = { [slotChar]="slotChar" [size]="size" [showClear]="showClear" - [disabled]="disabled" [readonly]="readonly" - [invalid]="invalid" [fluid]="fluid" [variant]="variant" [placeholder]="placeholder" diff --git a/src/stories/components/inputmask/inputmask.stories.ts b/src/stories/components/inputmask/inputmask.stories.ts index f057ad87..4a3054bd 100644 --- a/src/stories/components/inputmask/inputmask.stories.ts +++ b/src/stories/components/inputmask/inputmask.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { FormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { InputMaskComponent } from '../../../lib/components/inputmask/inputmask.component'; import { InputMaskFloatLabelComponent, FloatLabelStory } from './examples/inputmask-float-label.component'; import { Sizes } from './examples/inputmask-sizes.component'; @@ -18,6 +18,7 @@ const meta: Meta = { imports: [ InputMaskComponent, FormsModule, + ReactiveFormsModule, InputMaskFloatLabelComponent, ], }), @@ -91,7 +92,7 @@ import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; }, size: { control: 'select', - options: ['small', 'base', 'large', 'xlarge'], + options: ['small', 'base', 'large', 'xlarge'] as const, description: 'Размер поля', table: { category: 'Props', @@ -99,15 +100,6 @@ import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; type: { summary: "'small' | 'base' | 'large' | 'xlarge'" }, }, }, - disabled: { - control: 'boolean', - description: 'Отключает взаимодействие', - table: { - category: 'Props', - defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, - }, readonly: { control: 'boolean', description: 'Только для чтения', @@ -117,15 +109,6 @@ import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; type: { summary: 'boolean' }, }, }, - invalid: { - control: 'boolean', - description: 'Невалидное состояние', - table: { - category: 'Props', - defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, - }, fluid: { control: 'boolean', description: 'Растягивает поле на всю ширину контейнера', @@ -137,7 +120,7 @@ import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; }, variant: { control: 'select', - options: ['outlined', 'filled'], + options: ['outlined', 'filled'] as const, description: 'Визуальный вариант поля', table: { category: 'Props', @@ -172,10 +155,9 @@ import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; type: { summary: 'string' }, }, }, - modelValue: { table: { disable: true } }, + control: { table: { disable: true } }, + invalid: { table: { disable: true } }, primeSize: { table: { disable: true } }, - onTouched: { table: { disable: true } }, - onModelChange: { table: { disable: true } }, writeValue: { table: { disable: true } }, registerOnChange: { table: { disable: true } }, registerOnTouched: { table: { disable: true } }, @@ -219,9 +201,7 @@ import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; showClear: false, placeholder: '99-99-99', size: 'base', - disabled: false, readonly: false, - invalid: false, fluid: false, variant: 'outlined', }, @@ -242,9 +222,7 @@ export const Default: Story = { if (args.showClear) parts.push(`[showClear]="true"`); if (args.placeholder) parts.push(`placeholder="${args.placeholder}"`); if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); - if (args.disabled) parts.push(`[disabled]="true"`); if (args.readonly) parts.push(`[readonly]="true"`); - if (args.invalid) parts.push(`[invalid]="true"`); if (args.fluid) parts.push(`[fluid]="true"`); if (args.variant && args.variant !== 'outlined') parts.push(`variant="${args.variant}"`); parts.push(`[(ngModel)]="value"`); From 374267643648dc259876f0c958b5a38ca6474479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=A7=D0=B8=D1=91=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 30 Apr 2026 13:37:29 +0700 Subject: [PATCH 230/258] ~fix(inputgroup): add missing import. --- src/prime-preset/map-tokens.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 717c3322..61990e3c 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -11,6 +11,7 @@ import { progressspinnerCss } from './tokens/components/progressspinner'; import { tagCss } from './tokens/components/tag'; import { textareaCss } from './tokens/components/textarea'; import { tooltipCss } from './tokens/components/tooltip'; +import { inputgroupCss } from './tokens/components/inputgroup' const presetTokens: Preset = { primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'], From f81dcbb12e320c35de531bd80e2cd01dc1a98054 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 30 Apr 2026 17:11:23 +0700 Subject: [PATCH 231/258] formControl --- .../components/inputotp/inputotp.component.ts | 55 ++++++++++--------- src/prime-preset/map-tokens.ts | 1 + .../examples/inputotp-disabled.component.ts | 32 +++++------ .../inputotp-integeronly.component.ts | 30 ++++------ .../examples/inputotp-invalid.component.ts | 42 +++++++------- .../examples/inputotp-mask.component.ts | 30 ++++------ .../components/inputotp/inputotp.stories.ts | 41 ++++---------- 7 files changed, 97 insertions(+), 134 deletions(-) diff --git a/src/lib/components/inputotp/inputotp.component.ts b/src/lib/components/inputotp/inputotp.component.ts index 47a83cf2..d831a18c 100644 --- a/src/lib/components/inputotp/inputotp.component.ts +++ b/src/lib/components/inputotp/inputotp.component.ts @@ -1,5 +1,6 @@ -import { Component, Input, Output, EventEmitter, forwardRef } from '@angular/core'; -import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Component, DestroyRef, inject, Injector, Input, OnInit, Output, EventEmitter } from '@angular/core'; +import { ControlValueAccessor, FormControl, NgControl, ReactiveFormsModule } from '@angular/forms'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { NgClass } from '@angular/common'; import { InputOtp, InputOtpChangeEvent } from 'primeng/inputotp'; @@ -8,41 +9,36 @@ export type InputOtpSize = 'small' | 'base' | 'large' | 'xlarge'; @Component({ selector: 'input-otp', standalone: true, - imports: [InputOtp, FormsModule, NgClass], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => InputOtpComponent), - multi: true, - }, - ], + imports: [InputOtp, ReactiveFormsModule, NgClass], template: ` `, }) -export class InputOtpComponent implements ControlValueAccessor { +export class InputOtpComponent implements ControlValueAccessor, OnInit { + private readonly _injector = inject(Injector); + private readonly destroyRef = inject(DestroyRef); + private _ngControl: NgControl | null = null; + + readonly control = new FormControl(null); + @Input() length = 4; @Input() mask = false; @Input() integerOnly = false; - @Input() disabled = false; @Input() readonly = false; - @Input() invalid = false; @Input() size: InputOtpSize = 'base'; @Input() tabindex: number | null = null; @Input() autofocus = false; @@ -51,11 +47,24 @@ export class InputOtpComponent implements ControlValueAccessor { @Output() onFocus = new EventEmitter(); @Output() onBlur = new EventEmitter(); - modelValue: any = null; - private _onChange: (value: any) => void = () => {}; private _onTouched: () => void = () => {}; + ngOnInit(): void { + this._ngControl = this._injector.get(NgControl, null, { self: true, optional: true }); + + this.control.valueChanges + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(v => { + this._onChange(v); + this._onTouched(); + }); + } + + get invalid(): boolean { + return this._ngControl?.invalid ?? false; + } + get primeSize(): 'small' | 'large' | undefined { if (this.size === 'small') return 'small'; if (this.size === 'large' || this.size === 'xlarge') return 'large'; @@ -66,18 +75,12 @@ export class InputOtpComponent implements ControlValueAccessor { return { 'p-inputotp-xlg': this.size === 'xlarge' }; } - onModelChange(value: any): void { - this.modelValue = value; - this._onChange(value); - this._onTouched(); - } - onChangeHandler(event: InputOtpChangeEvent): void { this.onChange.emit(event); } writeValue(value: any): void { - this.modelValue = value; + this.control.setValue(value ?? null, { emitEvent: false }); } registerOnChange(fn: (value: any) => void): void { @@ -89,6 +92,6 @@ export class InputOtpComponent implements ControlValueAccessor { } setDisabledState(isDisabled: boolean): void { - this.disabled = isDisabled; + isDisabled ? this.control.disable({ emitEvent: false }) : this.control.enable({ emitEvent: false }); } } diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 26f33a58..4234f0b5 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -6,6 +6,7 @@ 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 { inputotpCss } from './tokens/components/inputotp'; import { inputtextCss } from './tokens/components/inputtext'; import { progressspinnerCss } from './tokens/components/progressspinner'; import { tagCss } from './tokens/components/tag'; diff --git a/src/stories/components/inputotp/examples/inputotp-disabled.component.ts b/src/stories/components/inputotp/examples/inputotp-disabled.component.ts index d5a74f60..2c0d6890 100644 --- a/src/stories/components/inputotp/examples/inputotp-disabled.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-disabled.component.ts @@ -1,5 +1,5 @@ -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; @@ -8,14 +8,15 @@ const styles = ''; @Component({ selector: 'app-inputotp-disabled', standalone: true, - imports: [InputOtpComponent, FormsModule], + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputOtpComponent, ReactiveFormsModule], styles, template: ` - + `, }) export class InputOtpDisabledComponent { - value = '1234'; + readonly control = new FormControl({ value: '1234', disabled: true }); } export const Disabled: StoryObj = { @@ -25,25 +26,18 @@ export const Disabled: StoryObj = { parameters: { controls: { disable: true }, docs: { - description: { story: 'Заблокированное состояние поля OTP.' }, + description: { story: 'Заблокированное состояние — управляется через `FormControl`.' }, source: { language: 'ts', code: ` -import { Component } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; -@Component({ - selector: 'app-inputotp-disabled', - standalone: true, - imports: [InputOtpComponent, ReactiveFormsModule], - template: \` - - \`, -}) -export class InputOtpDisabledComponent { - control = new FormControl({ value: '1234', disabled: true }); -} +// В компоненте: +readonly control = new FormControl({ value: '1234', disabled: true }); + +// template: +// `, }, }, diff --git a/src/stories/components/inputotp/examples/inputotp-integeronly.component.ts b/src/stories/components/inputotp/examples/inputotp-integeronly.component.ts index f11a55f7..fb41317e 100644 --- a/src/stories/components/inputotp/examples/inputotp-integeronly.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-integeronly.component.ts @@ -1,5 +1,5 @@ -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; @@ -8,14 +8,15 @@ const styles = ''; @Component({ selector: 'app-inputotp-integeronly', standalone: true, - imports: [InputOtpComponent, FormsModule], + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputOtpComponent, ReactiveFormsModule], styles, template: ` - + `, }) export class InputOtpIntegerOnlyComponent { - value: string | null = null; + readonly control = new FormControl(null); } export const IntegerOnly: StoryObj = { @@ -29,21 +30,14 @@ export const IntegerOnly: StoryObj = { source: { language: 'ts', code: ` -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; -@Component({ - selector: 'app-inputotp-integeronly', - standalone: true, - imports: [InputOtpComponent, FormsModule], - template: \` - - \`, -}) -export class InputOtpIntegerOnlyComponent { - value: string | null = null; -} +// В компоненте: +readonly control = new FormControl(null); + +// template: +// `, }, }, diff --git a/src/stories/components/inputotp/examples/inputotp-invalid.component.ts b/src/stories/components/inputotp/examples/inputotp-invalid.component.ts index 04e0a298..1e2f77f8 100644 --- a/src/stories/components/inputotp/examples/inputotp-invalid.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-invalid.component.ts @@ -1,5 +1,5 @@ -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; @@ -8,44 +8,40 @@ const styles = ''; @Component({ selector: 'app-inputotp-invalid', standalone: true, - imports: [InputOtpComponent, FormsModule], + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputOtpComponent, ReactiveFormsModule], styles, template: ` - + `, }) export class InputOtpInvalidComponent { - value: string | null = null; + readonly control = new FormControl('', Validators.required); + + constructor() { + this.control.markAsTouched(); + } } export const Invalid: StoryObj = { - render: (args) => ({ - props: { ...args }, - template: ``, + render: () => ({ + template: ``, }), - args: {}, parameters: { controls: { disable: true }, docs: { - description: { story: 'Невалидное состояние поля OTP.' }, + description: { story: 'Невалидное состояние — определяется через валидаторы `FormControl`.' }, source: { language: 'ts', code: ` -import { Component } from '@angular/core'; -import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -@Component({ - selector: 'app-inputotp-invalid', - standalone: true, - imports: [InputOtpComponent, ReactiveFormsModule], - template: \` - - \`, -}) -export class InputOtpInvalidComponent { - control = new FormControl('', [Validators.required]); -} +// В компоненте: +readonly control = new FormControl('', Validators.required); + +// template: +// `, }, }, diff --git a/src/stories/components/inputotp/examples/inputotp-mask.component.ts b/src/stories/components/inputotp/examples/inputotp-mask.component.ts index c1e7f8ad..778f7f5c 100644 --- a/src/stories/components/inputotp/examples/inputotp-mask.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-mask.component.ts @@ -1,5 +1,5 @@ -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; @@ -8,14 +8,15 @@ const styles = ''; @Component({ selector: 'app-inputotp-mask', standalone: true, - imports: [InputOtpComponent, FormsModule], + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [InputOtpComponent, ReactiveFormsModule], styles, template: ` - + `, }) export class InputOtpMaskComponent { - value = '1234'; + readonly control = new FormControl('1234'); } export const Mask: StoryObj = { @@ -29,21 +30,14 @@ export const Mask: StoryObj = { source: { language: 'ts', code: ` -import { Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; -@Component({ - selector: 'app-inputotp-mask', - standalone: true, - imports: [InputOtpComponent, FormsModule], - template: \` - - \`, -}) -export class InputOtpMaskComponent { - value = '1234'; -} +// В компоненте: +readonly control = new FormControl('1234'); + +// template: +// `, }, }, diff --git a/src/stories/components/inputotp/inputotp.stories.ts b/src/stories/components/inputotp/inputotp.stories.ts index db102c48..88f3f7e0 100644 --- a/src/stories/components/inputotp/inputotp.stories.ts +++ b/src/stories/components/inputotp/inputotp.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { FormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { InputOtpComponent } from '../../../lib/components/inputotp/inputotp.component'; import { InputOtpDisabledComponent, Disabled } from './examples/inputotp-disabled.component'; import { InputOtpInvalidComponent, Invalid } from './examples/inputotp-invalid.component'; @@ -17,6 +17,7 @@ const meta: Meta = { imports: [ InputOtpComponent, FormsModule, + ReactiveFormsModule, InputOtpDisabledComponent, InputOtpInvalidComponent, InputOtpMaskComponent, @@ -31,13 +32,12 @@ const meta: Meta = { component: `Компонент для ввода одноразовых паролей (OTP). \`\`\`typescript -import { InputOtpModule } from 'primeng/inputotp'; +import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, }, argTypes: { - // ── Props ──────────────────────────────────────────────── length: { control: 'number', description: 'Количество символов', @@ -65,27 +65,9 @@ import { InputOtpModule } from 'primeng/inputotp'; type: { summary: 'boolean' }, }, }, - disabled: { - control: 'boolean', - description: 'Отключает возможность взаимодействия', - table: { - category: 'Props', - defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, - }, - invalid: { - control: 'boolean', - description: 'Подсвечивает поле как невалидное', - table: { - category: 'Props', - defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, - }, size: { control: 'select', - options: ['small', 'base', 'large', 'xlarge'], + options: ['small', 'base', 'large', 'xlarge'] as const, description: 'Размер поля', table: { category: 'Props', @@ -98,11 +80,16 @@ import { InputOtpModule } from 'primeng/inputotp'; readonly: { table: { disable: true } }, tabindex: { table: { disable: true } }, autofocus: { table: { disable: true } }, - modelValue: { table: { disable: true } }, + control: { table: { disable: true } }, + invalid: { table: { disable: true } }, primeSize: { table: { disable: true } }, sizeClass: { table: { disable: true } }, + writeValue: { table: { disable: true } }, + registerOnChange: { table: { disable: true } }, + registerOnTouched: { table: { disable: true } }, + setDisabledState: { table: { disable: true } }, - // ── Events ─────────────────────────────────────────────── + // Events onChange: { control: false, description: 'Событие изменения значения', @@ -132,8 +119,6 @@ import { InputOtpModule } from 'primeng/inputotp'; length: 4, mask: false, integerOnly: false, - disabled: false, - invalid: false, size: 'base' as const, }, }; @@ -141,7 +126,6 @@ import { InputOtpModule } from 'primeng/inputotp'; export default meta; type Story = StoryObj; -// ── Default ────────────────────────────────────────────────────────────────── export const Default: Story = { name: 'Default', render: (args) => { @@ -150,8 +134,6 @@ export const Default: Story = { if (args.length !== 4) parts.push(`[length]="${args.length}"`); if (args.mask) parts.push(`[mask]="true"`); if (args.integerOnly) parts.push(`[integerOnly]="true"`); - if (args.disabled) parts.push(`[disabled]="true"`); - if (args.invalid) parts.push(`[invalid]="true"`); if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); parts.push(`[(ngModel)]="value"`); @@ -168,5 +150,4 @@ export const Default: Story = { }, }; -// ── Re-exports from example components ──────────────────────────────────── export { Disabled, Invalid, Mask, IntegerOnly }; From 12b2d227b369cf73f6e52f84b593cdcec39ec0b7 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 30 Apr 2026 17:18:19 +0700 Subject: [PATCH 232/258] =?UTF-8?q?stories:=20=D0=B7=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20ngModel=20=D0=BD=D0=B0=20formControl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/inputmask-float-label.component.ts | 16 ++++++++-------- .../examples/inputmask-sizes.component.ts | 13 +++++++++---- .../components/inputmask/inputmask.stories.ts | 6 +++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/stories/components/inputmask/examples/inputmask-float-label.component.ts b/src/stories/components/inputmask/examples/inputmask-float-label.component.ts index d27a93ab..8cd181b8 100644 --- a/src/stories/components/inputmask/examples/inputmask-float-label.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-float-label.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { FormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputMask } from 'primeng/inputmask'; import { FloatLabel } from 'primeng/floatlabel'; @@ -7,7 +7,7 @@ import { FloatLabel } from 'primeng/floatlabel'; export const template = `
- +
@@ -18,12 +18,12 @@ const styles = ''; selector: 'app-inputmask-float-label', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputMask, FloatLabel, FormsModule], + imports: [InputMask, FloatLabel, ReactiveFormsModule], template, styles, }) export class InputMaskFloatLabelComponent { - value = ''; + readonly control = new FormControl(''); } export const FloatLabelStory: StoryObj = { @@ -44,21 +44,21 @@ export const FloatLabelStory: StoryObj = { import { Component } from '@angular/core'; import { InputMask } from 'primeng/inputmask'; import { FloatLabel } from 'primeng/floatlabel'; -import { FormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; @Component({ selector: 'app-inputmask-float-label', standalone: true, - imports: [InputMask, FloatLabel, FormsModule], + imports: [InputMask, FloatLabel, ReactiveFormsModule], template: \` - + \`, }) export class InputMaskFloatLabelComponent { - value = ''; + readonly control = new FormControl(''); } `, }, diff --git a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts index 5f9db99c..f0ed514c 100644 --- a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts @@ -1,3 +1,5 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; @@ -6,7 +8,7 @@ type Story = StoryObj; export const Sizes: Story = { name: 'Sizes', render: (args) => ({ - props: { ...args, value: '' }, + props: { ...args, control: new FormControl('') }, template: ` `, }), @@ -35,10 +37,13 @@ export const Sizes: Story = { language: 'ts', code: ` import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; -import { FormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; + +// В компоненте: +readonly control = new FormControl(''); // template: -// +// `, }, }, diff --git a/src/stories/components/inputmask/inputmask.stories.ts b/src/stories/components/inputmask/inputmask.stories.ts index 4a3054bd..010b8963 100644 --- a/src/stories/components/inputmask/inputmask.stories.ts +++ b/src/stories/components/inputmask/inputmask.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { InputMaskComponent } from '../../../lib/components/inputmask/inputmask.component'; import { InputMaskFloatLabelComponent, FloatLabelStory } from './examples/inputmask-float-label.component'; import { Sizes } from './examples/inputmask-sizes.component'; @@ -225,11 +225,11 @@ export const Default: Story = { if (args.readonly) parts.push(`[readonly]="true"`); if (args.fluid) parts.push(`[fluid]="true"`); if (args.variant && args.variant !== 'outlined') parts.push(`variant="${args.variant}"`); - parts.push(`[(ngModel)]="value"`); + parts.push(`[formControl]="control"`); const template = ``; - return { props: { ...args, value: '' }, template }; + return { props: { ...args, control: new FormControl('') }, template }; }, parameters: { docs: { From 28aacbb80f214bf97fa09144a971f782de0c5f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=A7=D0=B8=D1=91=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 4 May 2026 11:01:53 +0700 Subject: [PATCH 233/258] ~fix(input-mask): fix import map tokens. --- src/prime-preset/map-tokens.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index c10bf322..4d14b9ba 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -15,6 +15,7 @@ import { timelineCss } from './tokens/components/timeline'; import { tooltipCss } from './tokens/components/tooltip'; import { megamenuCss } from './tokens/components/megamenu'; import { selectCss } from './tokens/components/select'; +import { messageCss } from './tokens/components/message'; const presetTokens: Preset = { primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'], From 852146c92436895c79316cd6f323d77ca52801f2 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 4 May 2026 13:22:16 +0700 Subject: [PATCH 234/258] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=B4=D0=B5=D1=80=D0=B0=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=82=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20dis?= =?UTF-8?q?abled,=20invalid,=20readonly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/inputmask-disabled.component.ts | 55 ++++++++--------- .../examples/inputmask-invalid.component.ts | 59 ++++++++----------- .../examples/inputmask-readonly.component.ts | 56 ++++++++---------- 3 files changed, 75 insertions(+), 95 deletions(-) diff --git a/src/stories/components/inputmask/examples/inputmask-disabled.component.ts b/src/stories/components/inputmask/examples/inputmask-disabled.component.ts index 29206cc9..9667d0ca 100644 --- a/src/stories/components/inputmask/examples/inputmask-disabled.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-disabled.component.ts @@ -1,33 +1,24 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; -const styles = ''; - -@Component({ - selector: 'app-inputmask-disabled', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputMaskComponent, ReactiveFormsModule], - template: ` - - `, - styles, -}) -class InputMaskDisabledComponent { - readonly control = new FormControl({ value: '12-34-56', disabled: true }); -} - export const Disabled: StoryObj = { name: 'Disabled', - render: () => ({ - template: ``, - }), + render: (args) => { + const control = new FormControl({ value: '12-34-56', disabled: true }); + return { + props: { ...args, control }, + template: ``, + }; + }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputMaskComponent, ReactiveFormsModule], + }, + }), + ], parameters: { controls: { disable: true }, docs: { @@ -37,14 +28,18 @@ export const Disabled: StoryObj = { source: { language: 'ts', code: ` -import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; -// В компоненте: -readonly control = new FormControl({ value: '12-34-56', disabled: true }); - -// template: -// +@Component({ + standalone: true, + imports: [InputMaskComponent, ReactiveFormsModule], + template: \`\`, +}) +export class DisabledExample { + control = new FormControl({ value: '12-34-56', disabled: true }); +} `, }, }, diff --git a/src/stories/components/inputmask/examples/inputmask-invalid.component.ts b/src/stories/components/inputmask/examples/inputmask-invalid.component.ts index 7cee3d8f..699a89bb 100644 --- a/src/stories/components/inputmask/examples/inputmask-invalid.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-invalid.component.ts @@ -1,37 +1,24 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; -const styles = ''; - -@Component({ - selector: 'app-inputmask-invalid', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputMaskComponent, ReactiveFormsModule], - template: ` - - `, - styles, -}) -class InputMaskInvalidComponent { - readonly control = new FormControl('', Validators.required); - - constructor() { - this.control.markAsTouched(); - } -} - export const Invalid: StoryObj = { name: 'Invalid', - render: () => ({ - template: ``, - }), + render: (args) => { + const control = new FormControl('', Validators.required); + return { + props: { ...args, control }, + template: ``, + }; + }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputMaskComponent, ReactiveFormsModule], + }, + }), + ], parameters: { controls: { disable: true }, docs: { @@ -41,14 +28,18 @@ export const Invalid: StoryObj = { source: { language: 'ts', code: ` +import { Component } from '@angular/core'; +import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; -import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -// В компоненте: -readonly control = new FormControl('', Validators.required); - -// template: -// +@Component({ + standalone: true, + imports: [InputMaskComponent, ReactiveFormsModule], + template: \`\`, +}) +export class InvalidExample { + control = new FormControl('', Validators.required); +} `, }, }, diff --git a/src/stories/components/inputmask/examples/inputmask-readonly.component.ts b/src/stories/components/inputmask/examples/inputmask-readonly.component.ts index 9bd85a84..b800f435 100644 --- a/src/stories/components/inputmask/examples/inputmask-readonly.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-readonly.component.ts @@ -1,34 +1,24 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; -const styles = ''; - -@Component({ - selector: 'app-inputmask-readonly', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputMaskComponent, ReactiveFormsModule], - template: ` - - `, - styles, -}) -class InputMaskReadonlyComponent { - readonly control = new FormControl('12-34-56'); -} - export const Readonly: StoryObj = { name: 'Readonly', - render: () => ({ - template: ``, - }), + render: (args) => { + const control = new FormControl('12-34-56'); + return { + props: { ...args, control }, + template: ``, + }; + }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputMaskComponent, ReactiveFormsModule], + }, + }), + ], parameters: { controls: { disable: true }, docs: { @@ -38,14 +28,18 @@ export const Readonly: StoryObj = { source: { language: 'ts', code: ` -import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; -// В компоненте: -readonly control = new FormControl('12-34-56'); - -// template: -// +@Component({ + standalone: true, + imports: [InputMaskComponent, ReactiveFormsModule], + template: \`\`, +}) +export class ReadonlyExample { + control = new FormControl('12-34-56'); +} `, }, }, From c804cb66c4dd6fb982861808cdf83a9eed73d378 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 4 May 2026 13:37:01 +0700 Subject: [PATCH 235/258] =?UTF-8?q?setDisabledState(true)=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=B7=D1=8B=D0=B2=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=20disabled=20FormControl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/inputotp/inputotp.component.ts | 15 ++++++++++-- .../tokens/components/inputotp.ts | 23 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/lib/components/inputotp/inputotp.component.ts b/src/lib/components/inputotp/inputotp.component.ts index d831a18c..f0f745db 100644 --- a/src/lib/components/inputotp/inputotp.component.ts +++ b/src/lib/components/inputotp/inputotp.component.ts @@ -1,5 +1,5 @@ -import { Component, DestroyRef, inject, Injector, Input, OnInit, Output, EventEmitter } from '@angular/core'; -import { ControlValueAccessor, FormControl, NgControl, ReactiveFormsModule } from '@angular/forms'; +import { Component, DestroyRef, forwardRef, inject, Injector, Input, OnInit, Output, EventEmitter } from '@angular/core'; +import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule } from '@angular/forms'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { NgClass } from '@angular/common'; import { InputOtp, InputOtpChangeEvent } from 'primeng/inputotp'; @@ -10,11 +10,19 @@ export type InputOtpSize = 'small' | 'base' | 'large' | 'xlarge'; selector: 'input-otp', standalone: true, imports: [InputOtp, ReactiveFormsModule, NgClass], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => InputOtpComponent), + multi: true, + }, + ], template: ` (); @Output() onFocus = new EventEmitter(); @Output() onBlur = new EventEmitter(); @@ -92,6 +102,7 @@ export class InputOtpComponent implements ControlValueAccessor, OnInit { } setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; isDisabled ? this.control.disable({ emitEvent: false }) : this.control.enable({ emitEvent: false }); } } diff --git a/src/prime-preset/tokens/components/inputotp.ts b/src/prime-preset/tokens/components/inputotp.ts index c1eaca0b..de80e1d9 100644 --- a/src/prime-preset/tokens/components/inputotp.ts +++ b/src/prime-preset/tokens/components/inputotp.ts @@ -5,6 +5,29 @@ export const inputotpCss = ({ dt }: { dt: (token: string) => string }): string = padding-inline: 0; } +/* ─── Disabled ─── */ +.p-inputotp.p-component .p-inputtext:disabled { + background: ${dt('inputtext.root.disabledBackground')}; + color: ${dt('inputtext.root.disabledColor')}; +} + +/* ─── Readonly ─── */ +.p-inputotp.p-component .p-inputtext:enabled:read-only { + background: ${dt('inputtext.extend.readonlyBackground')}; + color: ${dt('inputtext.root.color')}; +} + +/* ─── Focus ─── */ +.p-inputotp.p-component .p-inputtext:enabled:focus { + box-shadow: 0 0 0 ${dt('inputtext.focusRing.width')} ${dt('inputtext.focusRing.color')}; +} + +/* ─── Invalid + Focus ─── */ +.p-inputotp.p-component .p-inputtext.p-invalid:focus { + border-color: ${dt('inputtext.root.invalidBorderColor')}; + box-shadow: 0 0 0 ${dt('inputtext.focusRing.width')} ${dt('focusRing.extend.invalid')}; +} + /* ─── Small ─── */ .p-inputotp.p-component .p-inputtext.p-inputtext-sm { padding-block: ${dt('inputtext.root.sm.paddingY')}; From fb238153191d62e75eae9c1b88fbd5f5fc8f7552 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 4 May 2026 13:45:42 +0700 Subject: [PATCH 236/258] =?UTF-8?q?=D1=81=D0=BD=D0=B8=D0=BF=D0=BF=D0=B5?= =?UTF-8?q?=D1=82=20=D0=B4=D0=BB=D1=8F=20Sizes=20=D0=BE=D1=84=D0=BE=D1=80?= =?UTF-8?q?=D0=BC=D0=BB=D0=B5=D0=BD=20=D0=BA=D0=B0=D0=BA=20@Component=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/inputmask-sizes.component.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts index f0ed514c..e8f393c6 100644 --- a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts @@ -36,14 +36,18 @@ export const Sizes: Story = { source: { language: 'ts', code: ` -import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; -// В компоненте: -readonly control = new FormControl(''); - -// template: -// +@Component({ + standalone: true, + imports: [InputMaskComponent, ReactiveFormsModule], + template: \`\`, +}) +export class SizesExample { + control = new FormControl(''); +} `, }, }, From 2fa8f81fd88d1d7f2f4b88f812734ad7509aebed Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 4 May 2026 13:45:42 +0700 Subject: [PATCH 237/258] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B:=20=20=20-=20=D0=A2=D0=B8=D0=BF=20InputMaskVariant=20=20?= =?UTF-8?q?=20-=20@Input()=20variant=20=D0=B8=D0=B7=20=D0=BA=D0=BE=D0=BC?= =?UTF-8?q?=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=B0=20=20=20-=20[variant?= =?UTF-8?q?]=20binding=20=D0=B8=D0=B7=20=D1=88=D0=B0=D0=B1=D0=BB=D0=BE?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=20=20=20-=20variant=20argType,=20arg=20=D0=B8=20?= =?UTF-8?q?=D1=88=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4=20=D0=B8=D0=B7=20stories?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/inputmask/inputmask.component.ts | 5 ++--- .../inputmask/examples/inputmask-sizes.component.ts | 2 +- .../components/inputmask/inputmask.stories.ts | 12 ------------ 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/lib/components/inputmask/inputmask.component.ts b/src/lib/components/inputmask/inputmask.component.ts index 71d980c3..8abc2102 100644 --- a/src/lib/components/inputmask/inputmask.component.ts +++ b/src/lib/components/inputmask/inputmask.component.ts @@ -4,7 +4,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { InputMask } from 'primeng/inputmask'; export type InputMaskSize = 'small' | 'base' | 'large' | 'xlarge'; -export type InputMaskVariant = 'outlined' | 'filled'; + @Component({ selector: 'input-mask', @@ -26,7 +26,7 @@ export type InputMaskVariant = 'outlined' | 'filled'; [readonly]="readonly" [placeholder]="placeholder" [fluid]="fluid" - [variant]="variant === 'filled' ? 'filled' : undefined" + [characterPattern]="characterPattern" [keepBuffer]="keepBuffer" [invalid]="invalid" @@ -57,7 +57,6 @@ export class InputMaskComponent implements ControlValueAccessor, OnInit { @Input() size: InputMaskSize = 'base'; @Input() readonly = false; @Input() fluid = false; - @Input() variant: InputMaskVariant = 'outlined'; @Input() characterPattern = '[A-Za-z]'; @Input() keepBuffer = false; @Input() autocomplete = ''; diff --git a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts index e8f393c6..021d25e5 100644 --- a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts @@ -17,7 +17,7 @@ export const Sizes: Story = { [showClear]="showClear" [readonly]="readonly" [fluid]="fluid" - [variant]="variant" + [placeholder]="placeholder" [formControl]="control" > diff --git a/src/stories/components/inputmask/inputmask.stories.ts b/src/stories/components/inputmask/inputmask.stories.ts index 010b8963..924ccb50 100644 --- a/src/stories/components/inputmask/inputmask.stories.ts +++ b/src/stories/components/inputmask/inputmask.stories.ts @@ -118,16 +118,6 @@ import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; type: { summary: 'boolean' }, }, }, - variant: { - control: 'select', - options: ['outlined', 'filled'] as const, - description: 'Визуальный вариант поля', - table: { - category: 'Props', - defaultValue: { summary: "'outlined'" }, - type: { summary: "'outlined' | 'filled'" }, - }, - }, characterPattern: { control: 'text', description: 'Регулярное выражение для символов типа a в маске', @@ -203,7 +193,6 @@ import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; size: 'base', readonly: false, fluid: false, - variant: 'outlined', }, }; @@ -224,7 +213,6 @@ export const Default: Story = { if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); if (args.readonly) parts.push(`[readonly]="true"`); if (args.fluid) parts.push(`[fluid]="true"`); - if (args.variant && args.variant !== 'outlined') parts.push(`variant="${args.variant}"`); parts.push(`[formControl]="control"`); const template = ``; From 7f0993953bfe74ac84472c169517a5948d8b6016 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 4 May 2026 15:21:48 +0700 Subject: [PATCH 238/258] =?UTF-8?q?ngModel=20=D0=B7=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=91=D0=BD=20=D0=BD=D0=B0=20formControl;=20Code=20snipp?= =?UTF-8?q?ets=20=E2=80=94=20=D0=BE=D1=84=D0=BE=D1=80=D0=BC=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BA=D0=B0=D0=BA=20=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20@Component=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5?= =?UTF-8?q?=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/inputotp-disabled.component.ts | 56 ++++++++--------- .../inputotp-integeronly.component.ts | 56 ++++++++--------- .../examples/inputotp-invalid.component.ts | 60 +++++++++---------- .../examples/inputotp-mask.component.ts | 56 ++++++++--------- .../components/inputotp/inputotp.stories.ts | 20 +++---- 5 files changed, 124 insertions(+), 124 deletions(-) diff --git a/src/stories/components/inputotp/examples/inputotp-disabled.component.ts b/src/stories/components/inputotp/examples/inputotp-disabled.component.ts index 2c0d6890..4afef35f 100644 --- a/src/stories/components/inputotp/examples/inputotp-disabled.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-disabled.component.ts @@ -1,43 +1,45 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; -const styles = ''; - -@Component({ - selector: 'app-inputotp-disabled', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputOtpComponent, ReactiveFormsModule], - styles, - template: ` - - `, -}) -export class InputOtpDisabledComponent { - readonly control = new FormControl({ value: '1234', disabled: true }); -} - export const Disabled: StoryObj = { - render: () => ({ - template: ``, - }), + name: 'Disabled', + render: (args) => { + const control = new FormControl({ value: '1234', disabled: true }); + return { + props: { ...args, control }, + template: ``, + }; + }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputOtpComponent, ReactiveFormsModule], + }, + }), + ], parameters: { controls: { disable: true }, docs: { - description: { story: 'Заблокированное состояние — управляется через `FormControl`.' }, + description: { + story: 'Заблокированное состояние — управляется через `FormControl`.', + }, source: { language: 'ts', code: ` -import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; -// В компоненте: -readonly control = new FormControl({ value: '1234', disabled: true }); - -// template: -// +@Component({ + standalone: true, + imports: [InputOtpComponent, ReactiveFormsModule], + template: \`\`, +}) +export class DisabledExample { + control = new FormControl({ value: '1234', disabled: true }); +} `, }, }, diff --git a/src/stories/components/inputotp/examples/inputotp-integeronly.component.ts b/src/stories/components/inputotp/examples/inputotp-integeronly.component.ts index fb41317e..513d5377 100644 --- a/src/stories/components/inputotp/examples/inputotp-integeronly.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-integeronly.component.ts @@ -1,43 +1,45 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; -const styles = ''; - -@Component({ - selector: 'app-inputotp-integeronly', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputOtpComponent, ReactiveFormsModule], - styles, - template: ` - - `, -}) -export class InputOtpIntegerOnlyComponent { - readonly control = new FormControl(null); -} - export const IntegerOnly: StoryObj = { - render: () => ({ - template: ``, - }), + name: 'IntegerOnly', + render: (args) => { + const control = new FormControl(null); + return { + props: { ...args, control }, + template: ``, + }; + }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputOtpComponent, ReactiveFormsModule], + }, + }), + ], parameters: { controls: { disable: true }, docs: { - description: { story: 'Ввод только цифр.' }, + description: { + story: 'Ввод только цифр.', + }, source: { language: 'ts', code: ` -import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; -// В компоненте: -readonly control = new FormControl(null); - -// template: -// +@Component({ + standalone: true, + imports: [InputOtpComponent, ReactiveFormsModule], + template: \`\`, +}) +export class IntegerOnlyExample { + control = new FormControl(null); +} `, }, }, diff --git a/src/stories/components/inputotp/examples/inputotp-invalid.component.ts b/src/stories/components/inputotp/examples/inputotp-invalid.component.ts index 1e2f77f8..0b975f44 100644 --- a/src/stories/components/inputotp/examples/inputotp-invalid.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-invalid.component.ts @@ -1,47 +1,45 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; -const styles = ''; - -@Component({ - selector: 'app-inputotp-invalid', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputOtpComponent, ReactiveFormsModule], - styles, - template: ` - - `, -}) -export class InputOtpInvalidComponent { - readonly control = new FormControl('', Validators.required); - - constructor() { - this.control.markAsTouched(); - } -} - export const Invalid: StoryObj = { - render: () => ({ - template: ``, - }), + name: 'Invalid', + render: (args) => { + const control = new FormControl('', Validators.required); + return { + props: { ...args, control }, + template: ``, + }; + }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputOtpComponent, ReactiveFormsModule], + }, + }), + ], parameters: { controls: { disable: true }, docs: { - description: { story: 'Невалидное состояние — определяется через валидаторы `FormControl`.' }, + description: { + story: 'Невалидное состояние — определяется через валидаторы `FormControl`.', + }, source: { language: 'ts', code: ` +import { Component } from '@angular/core'; +import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; -import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -// В компоненте: -readonly control = new FormControl('', Validators.required); - -// template: -// +@Component({ + standalone: true, + imports: [InputOtpComponent, ReactiveFormsModule], + template: \`\`, +}) +export class InvalidExample { + control = new FormControl('', Validators.required); +} `, }, }, diff --git a/src/stories/components/inputotp/examples/inputotp-mask.component.ts b/src/stories/components/inputotp/examples/inputotp-mask.component.ts index 778f7f5c..4e4fd330 100644 --- a/src/stories/components/inputotp/examples/inputotp-mask.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-mask.component.ts @@ -1,43 +1,45 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; -const styles = ''; - -@Component({ - selector: 'app-inputotp-mask', - standalone: true, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputOtpComponent, ReactiveFormsModule], - styles, - template: ` - - `, -}) -export class InputOtpMaskComponent { - readonly control = new FormControl('1234'); -} - export const Mask: StoryObj = { - render: () => ({ - template: ``, - }), + name: 'Mask', + render: (args) => { + const control = new FormControl('1234'); + return { + props: { ...args, control }, + template: ``, + }; + }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputOtpComponent, ReactiveFormsModule], + }, + }), + ], parameters: { controls: { disable: true }, docs: { - description: { story: 'Маскированный ввод — символы скрыты.' }, + description: { + story: 'Маскированный ввод — символы скрыты.', + }, source: { language: 'ts', code: ` -import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; -// В компоненте: -readonly control = new FormControl('1234'); - -// template: -// +@Component({ + standalone: true, + imports: [InputOtpComponent, ReactiveFormsModule], + template: \`\`, +}) +export class MaskExample { + control = new FormControl('1234'); +} `, }, }, diff --git a/src/stories/components/inputotp/inputotp.stories.ts b/src/stories/components/inputotp/inputotp.stories.ts index 88f3f7e0..23c5c0bb 100644 --- a/src/stories/components/inputotp/inputotp.stories.ts +++ b/src/stories/components/inputotp/inputotp.stories.ts @@ -1,10 +1,10 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { InputOtpComponent } from '../../../lib/components/inputotp/inputotp.component'; -import { InputOtpDisabledComponent, Disabled } from './examples/inputotp-disabled.component'; -import { InputOtpInvalidComponent, Invalid } from './examples/inputotp-invalid.component'; -import { InputOtpMaskComponent, Mask } from './examples/inputotp-mask.component'; -import { InputOtpIntegerOnlyComponent, IntegerOnly } from './examples/inputotp-integeronly.component'; +import { Disabled } from './examples/inputotp-disabled.component'; +import { Invalid } from './examples/inputotp-invalid.component'; +import { Mask } from './examples/inputotp-mask.component'; +import { IntegerOnly } from './examples/inputotp-integeronly.component'; type InputOtpArgs = InputOtpComponent; @@ -16,12 +16,7 @@ const meta: Meta = { moduleMetadata({ imports: [ InputOtpComponent, - FormsModule, ReactiveFormsModule, - InputOtpDisabledComponent, - InputOtpInvalidComponent, - InputOtpMaskComponent, - InputOtpIntegerOnlyComponent, ], }), ], @@ -81,6 +76,7 @@ import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; tabindex: { table: { disable: true } }, autofocus: { table: { disable: true } }, control: { table: { disable: true } }, + disabled: { table: { disable: true } }, invalid: { table: { disable: true } }, primeSize: { table: { disable: true } }, sizeClass: { table: { disable: true } }, @@ -135,11 +131,11 @@ export const Default: Story = { if (args.mask) parts.push(`[mask]="true"`); if (args.integerOnly) parts.push(`[integerOnly]="true"`); if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); - parts.push(`[(ngModel)]="value"`); + parts.push(`[formControl]="control"`); const template = ``; - return { props: { ...args, value: null }, template }; + return { props: { ...args, control: new FormControl('') }, template }; }, parameters: { docs: { From 2925824f137546327206fc5511d8b7fd3d6edb53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=A7=D0=B8=D1=91=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 4 May 2026 15:31:28 +0700 Subject: [PATCH 239/258] ~fix(input-otp): add missing import. --- src/prime-preset/map-tokens.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 1e85abc5..05f227f9 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -16,6 +16,7 @@ import { tooltipCss } from './tokens/components/tooltip'; import { megamenuCss } from './tokens/components/megamenu'; import { selectCss } from './tokens/components/select'; import { messageCss } from './tokens/components/message'; +import { inputotpCss } from './tokens/components/inputotp'; const presetTokens: Preset = { primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'], From c3c09314435299feb6dd2d500cfd365f86ee541e Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 4 May 2026 15:34:50 +0700 Subject: [PATCH 240/258] =?UTF-8?q?argTypes:=20readonly,=20tabindex,=20aut?= =?UTF-8?q?ofocus=20=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B0=D1=8E?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20=D0=BD=D0=B0=20=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=86=D0=B5=20Docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/inputotp-readonly.component.ts | 47 +++++++++++++++++++ .../components/inputotp/inputotp.stories.ts | 40 ++++++++++++++-- 2 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 src/stories/components/inputotp/examples/inputotp-readonly.component.ts diff --git a/src/stories/components/inputotp/examples/inputotp-readonly.component.ts b/src/stories/components/inputotp/examples/inputotp-readonly.component.ts new file mode 100644 index 00000000..385ef945 --- /dev/null +++ b/src/stories/components/inputotp/examples/inputotp-readonly.component.ts @@ -0,0 +1,47 @@ +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { StoryObj } from '@storybook/angular'; +import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; + +export const Readonly: StoryObj = { + name: 'Readonly', + render: (args) => { + const control = new FormControl('1234'); + return { + props: { ...args, control }, + template: ``, + }; + }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputOtpComponent, ReactiveFormsModule], + }, + }), + ], + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Режим только для чтения — поле отображает значение, но недоступно для редактирования.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + standalone: true, + imports: [InputOtpComponent, ReactiveFormsModule], + template: \`\`, +}) +export class ReadonlyExample { + control = new FormControl('1234'); +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/inputotp/inputotp.stories.ts b/src/stories/components/inputotp/inputotp.stories.ts index 23c5c0bb..4e75a297 100644 --- a/src/stories/components/inputotp/inputotp.stories.ts +++ b/src/stories/components/inputotp/inputotp.stories.ts @@ -4,6 +4,7 @@ import { InputOtpComponent } from '../../../lib/components/inputotp/inputotp.com import { Disabled } from './examples/inputotp-disabled.component'; import { Invalid } from './examples/inputotp-invalid.component'; import { Mask } from './examples/inputotp-mask.component'; +import { Readonly } from './examples/inputotp-readonly.component'; import { IntegerOnly } from './examples/inputotp-integeronly.component'; type InputOtpArgs = InputOtpComponent; @@ -71,10 +72,35 @@ import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; }, }, + readonly: { + control: 'boolean', + description: 'Только для чтения', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + tabindex: { + control: 'number', + description: 'Значение атрибута tabindex', + table: { + category: 'Props', + defaultValue: { summary: 'null' }, + type: { summary: 'number | null' }, + }, + }, + autofocus: { + control: 'boolean', + description: 'Автоматический фокус при загрузке', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + // Hidden props - readonly: { table: { disable: true } }, - tabindex: { table: { disable: true } }, - autofocus: { table: { disable: true } }, control: { table: { disable: true } }, disabled: { table: { disable: true } }, invalid: { table: { disable: true } }, @@ -115,6 +141,9 @@ import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; length: 4, mask: false, integerOnly: false, + readonly: false, + autofocus: false, + tabindex: null, size: 'base' as const, }, }; @@ -131,6 +160,9 @@ export const Default: Story = { if (args.mask) parts.push(`[mask]="true"`); if (args.integerOnly) parts.push(`[integerOnly]="true"`); if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); + if (args.readonly) parts.push(`[readonly]="true"`); + if (args.autofocus) parts.push(`[autofocus]="true"`); + if (args.tabindex != null) parts.push(`[tabindex]="${args.tabindex}"`); parts.push(`[formControl]="control"`); const template = ``; @@ -146,4 +178,4 @@ export const Default: Story = { }, }; -export { Disabled, Invalid, Mask, IntegerOnly }; +export { Disabled, Readonly, Invalid, Mask, IntegerOnly }; From 27430984e8f07532a6b86cad412998f876a98d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=A7=D0=B8=D1=91=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 6 May 2026 14:40:31 +0700 Subject: [PATCH 241/258] ~fix: add password to map tokens. --- src/prime-preset/map-tokens.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 099454a8..932aefa1 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -79,6 +79,10 @@ const presetTokens: Preset = { ...(tokens.components.select as unknown as ComponentsDesignTokens['select']), css: selectCss, }, + passwordCss: { + ...(tokens.components.password as unknown as ComponentsDesignTokens['password']), + css: passwordCss + } } as ComponentsDesignTokens, }; From bfaac415198a6194266d2b9c9fa815a2773db308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=A7=D0=B8=D1=91=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 6 May 2026 14:45:22 +0700 Subject: [PATCH 242/258] ~update branch. --- src/prime-preset/map-tokens.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 50e81d5e..8b3204ef 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -60,6 +60,10 @@ const presetTokens: Preset = { inputmask: { css: inputmaskCss, }, + inputgroupCss: { + ...(tokens.components.inputgroup as unknown as ComponentsDesignTokens['inputgroup']), + css: inputgroupCss, + }, tag: { ...(tokens.components.tag as unknown as ComponentsDesignTokens['tag']), css: tagCss, From 00873ed9aef78cc221bb84a3516039509a7c5757 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 6 May 2026 15:00:18 +0700 Subject: [PATCH 243/258] =?UTF-8?q?=D1=80=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BD=D0=B0=20@Component=20?= =?UTF-8?q?=D1=81=20formControl;=20FloatLabel=20stories=20=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D1=81=20=D0=BD?= =?UTF-8?q?=D0=B0=D1=82=D0=B8=D0=B2=D0=BD=D1=8B=D0=BC=20pInputText,=20?= =?UTF-8?q?=D1=82.=D0=BA.=20p-floatlabel=20=D1=82=D1=80=D0=B5=D0=B1=D1=83?= =?UTF-8?q?=D0=B5=D1=82=20=20=D0=BA=D0=B0=D0=BA=20?= =?UTF-8?q?=D0=BF=D1=80=D1=8F=D0=BC=D0=BE=D0=B9=20=D0=B4=D0=BE=D1=87=D0=B5?= =?UTF-8?q?=D1=80=D0=BD=D0=B8=D0=B9=20=D1=8D=D0=BB=D0=B5=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=20=E2=80=94=20=D0=BE=D0=B1=D1=91=D1=80=D1=82=D0=BA=D0=B0?= =?UTF-8?q?=20input-text=20=D0=BD=D0=B5=20=D0=BF=D0=BE=D0=B4=D0=BE=D0=B9?= =?UTF-8?q?=D0=B4=D1=91=D1=82.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/inputtext-clear.component.ts | 52 ++++++++++++------- ...inputtext-float-label-invalid.component.ts | 16 +++--- .../inputtext-float-label.component.ts | 16 +++--- .../examples/inputtext-readonly.component.ts | 52 ++++++++++++------- .../components/inputtext/inputtext.stories.ts | 6 ++- 5 files changed, 86 insertions(+), 56 deletions(-) diff --git a/src/stories/components/inputtext/examples/inputtext-clear.component.ts b/src/stories/components/inputtext/examples/inputtext-clear.component.ts index d0c13671..7a2385b3 100644 --- a/src/stories/components/inputtext/examples/inputtext-clear.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-clear.component.ts @@ -1,27 +1,33 @@ +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; -type Story = StoryObj; +@Component({ + selector: 'app-inputtext-clear', + standalone: true, + imports: [InputTextComponent, ReactiveFormsModule], + template: ``, +}) +export class InputTextClearComponent { + control = new FormControl(''); +} -export const ClearButton: Story = { +export const ClearButton: StoryObj = { name: 'ClearButton', - render: (args) => ({ - props: { ...args }, - template: ` - - `, + render: () => ({ + template: ``, }), - args: { - showClear: true, - placeholder: 'Введите текст...', - }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputTextClearComponent], + }, + }), + ], parameters: { + controls: { disable: true }, docs: { description: { story: 'Поле с кнопкой очистки через `showClear`. Иконка × появляется при вводе первого символа.', @@ -29,10 +35,18 @@ export const ClearButton: Story = { source: { language: 'ts', code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { InputTextComponent } from '@cdek-it/angular-ui-kit'; -// template: -// +@Component({ + standalone: true, + imports: [InputTextComponent, ReactiveFormsModule], + template: \`\`, +}) +export class ClearButtonExample { + control = new FormControl(''); +} `, }, }, diff --git a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts index 35e09cc1..cec5823b 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { NgIf } from '@angular/common'; -import { FormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; @@ -9,18 +9,18 @@ import { FloatLabel } from 'primeng/floatlabel'; selector: 'app-inputtext-float-label-invalid', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputText, FloatLabel, FormsModule, NgIf], + imports: [InputText, FloatLabel, ReactiveFormsModule, NgIf], template: `
- +
`, }) export class InputTextFloatLabelInvalidComponent { - value = ''; + control = new FormControl(''); @Input() required = false; } @@ -51,22 +51,22 @@ export const FloatLabelInvalid: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; -import { FormsModule } from '@angular/forms'; @Component({ standalone: true, - imports: [InputText, FloatLabel, FormsModule], + imports: [InputText, FloatLabel, ReactiveFormsModule], template: \` - + \`, }) export class FloatLabelInvalidExample { - value = ''; + control = new FormControl(''); } `, }, diff --git a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts index 2993498b..2041e855 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { NgIf } from '@angular/common'; -import { FormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; @@ -8,18 +8,18 @@ import { FloatLabel } from 'primeng/floatlabel'; @Component({ selector: 'app-inputtext-float-label', standalone: true, - imports: [InputText, FloatLabel, FormsModule, NgIf], + imports: [InputText, FloatLabel, ReactiveFormsModule, NgIf], template: `
- +
`, }) export class InputTextFloatLabelComponent { - value = ''; + control = new FormControl(''); @Input() required = false; } @@ -51,22 +51,22 @@ export const FloatLabelStory: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; -import { FormsModule } from '@angular/forms'; @Component({ standalone: true, - imports: [InputText, FloatLabel, FormsModule], + imports: [InputText, FloatLabel, ReactiveFormsModule], template: \` - + \`, }) export class FloatLabelExample { - value = ''; + control = new FormControl(''); } `, }, diff --git a/src/stories/components/inputtext/examples/inputtext-readonly.component.ts b/src/stories/components/inputtext/examples/inputtext-readonly.component.ts index 35ce1dee..2fbd52db 100644 --- a/src/stories/components/inputtext/examples/inputtext-readonly.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-readonly.component.ts @@ -1,27 +1,33 @@ +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; -type Story = StoryObj; +@Component({ + selector: 'app-inputtext-readonly', + standalone: true, + imports: [InputTextComponent, ReactiveFormsModule], + template: ``, +}) +export class InputTextReadonlyComponent { + control = new FormControl(''); +} -export const Readonly: Story = { +export const Readonly: StoryObj = { name: 'Readonly', - render: (args) => ({ - props: { ...args }, - template: ` - - `, + render: () => ({ + template: ``, }), - args: { - readonly: true, - placeholder: 'Введите текст...', - }, + decorators: [ + (story: any) => ({ + ...story(), + moduleMetadata: { + imports: [InputTextReadonlyComponent], + }, + }), + ], parameters: { + controls: { disable: true }, docs: { description: { story: 'Режим только для чтения — поле отображает значение, но недоступно для редактирования.', @@ -29,10 +35,18 @@ export const Readonly: Story = { source: { language: 'ts', code: ` +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { InputTextComponent } from '@cdek-it/angular-ui-kit'; -// template: -// +@Component({ + standalone: true, + imports: [InputTextComponent, ReactiveFormsModule], + template: \`\`, +}) +export class ReadonlyExample { + control = new FormControl(''); +} `, }, }, diff --git a/src/stories/components/inputtext/inputtext.stories.ts b/src/stories/components/inputtext/inputtext.stories.ts index 57545c18..bc0c3b92 100644 --- a/src/stories/components/inputtext/inputtext.stories.ts +++ b/src/stories/components/inputtext/inputtext.stories.ts @@ -1,11 +1,11 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { InputTextComponent } from '../../../lib/components/inputtext/inputtext.component'; -import { ClearButton } from './examples/inputtext-clear.component'; +import { InputTextClearComponent, ClearButton } from './examples/inputtext-clear.component'; import { InputTextFloatLabelComponent, FloatLabelStory } from './examples/inputtext-float-label.component'; import { InputTextFloatLabelInvalidComponent, FloatLabelInvalid } from './examples/inputtext-float-label-invalid.component'; import { Disabled } from './examples/inputtext-disabled.component'; -import { Readonly } from './examples/inputtext-readonly.component'; +import { InputTextReadonlyComponent, Readonly } from './examples/inputtext-readonly.component'; import { Invalid } from './examples/inputtext-invalid.component'; type InputTextArgs = InputTextComponent & { disabled: boolean; invalid: boolean }; @@ -21,6 +21,8 @@ const meta: Meta = { ReactiveFormsModule, InputTextFloatLabelComponent, InputTextFloatLabelInvalidComponent, + InputTextReadonlyComponent, + InputTextClearComponent, ], }), ], From 5b38ebd62e7d84d3f2bf74c9543a8e3e9d8e9b13 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 6 May 2026 15:36:35 +0700 Subject: [PATCH 244/258] =?UTF-8?q?FloatLabel=20stories=20=D0=BD=D0=B0=20i?= =?UTF-8?q?nput-text;=20showClear=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=B8=D0=B2=D0=B0=D0=B5=D1=82=20=D0=B0=D1=82=D1=80=D0=B8?= =?UTF-8?q?=D0=B1=D1=83=D1=82=20=D0=B1=D0=B5=D0=B7=20=D0=B7=D0=BD=D0=B0?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inputtext/inputtext.component.ts | 4 ++-- .../examples/inputtext-clear.component.ts | 4 ++-- ...inputtext-float-label-invalid.component.ts | 20 +++++++++---------- .../inputtext-float-label.component.ts | 14 ++++++------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/lib/components/inputtext/inputtext.component.ts b/src/lib/components/inputtext/inputtext.component.ts index 3904b924..0b9b8e93 100644 --- a/src/lib/components/inputtext/inputtext.component.ts +++ b/src/lib/components/inputtext/inputtext.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, Output, EventEmitter, forwardRef, inject, Injector, OnInit } from '@angular/core'; +import { Component, Input, Output, EventEmitter, booleanAttribute, forwardRef, inject, Injector, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms'; import { NgClass } from '@angular/common'; import { InputText } from 'primeng/inputtext'; @@ -73,7 +73,7 @@ export class InputTextComponent implements ControlValueAccessor, OnInit { @Input() placeholder = ''; @Input() size: InputTextSize = 'base'; @Input() readonly = false; - @Input() showClear = false; + @Input({ transform: booleanAttribute }) showClear = false; @Input() fluid = false; disabled = false; diff --git a/src/stories/components/inputtext/examples/inputtext-clear.component.ts b/src/stories/components/inputtext/examples/inputtext-clear.component.ts index 7a2385b3..59aea394 100644 --- a/src/stories/components/inputtext/examples/inputtext-clear.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-clear.component.ts @@ -7,7 +7,7 @@ import { InputTextComponent } from '../../../../lib/components/inputtext/inputte selector: 'app-inputtext-clear', standalone: true, imports: [InputTextComponent, ReactiveFormsModule], - template: ``, + template: ``, }) export class InputTextClearComponent { control = new FormControl(''); @@ -42,7 +42,7 @@ import { InputTextComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, imports: [InputTextComponent, ReactiveFormsModule], - template: \`\`, + template: \`\`, }) export class ClearButtonExample { control = new FormControl(''); diff --git a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts index cec5823b..a336125c 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts @@ -1,26 +1,26 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { NgIf } from '@angular/common'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; +import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; @Component({ selector: 'app-inputtext-float-label-invalid', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputText, FloatLabel, ReactiveFormsModule, NgIf], + imports: [InputTextComponent, FloatLabel, ReactiveFormsModule, NgIf], template: `
- +
`, }) export class InputTextFloatLabelInvalidComponent { - control = new FormControl(''); + control = new FormControl('', Validators.required); @Input() required = false; } @@ -51,22 +51,22 @@ export const FloatLabelInvalid: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputText } from 'primeng/inputtext'; +import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; +import { InputTextComponent } from '@cdek-it/angular-ui-kit'; import { FloatLabel } from 'primeng/floatlabel'; @Component({ standalone: true, - imports: [InputText, FloatLabel, ReactiveFormsModule], + imports: [InputTextComponent, FloatLabel, ReactiveFormsModule], template: \` - + \`, }) export class FloatLabelInvalidExample { - control = new FormControl(''); + control = new FormControl('', Validators.required); } `, }, diff --git a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts index 2041e855..ef57c6da 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts @@ -2,17 +2,17 @@ import { Component, Input } from '@angular/core'; import { NgIf } from '@angular/common'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; +import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; @Component({ selector: 'app-inputtext-float-label', standalone: true, - imports: [InputText, FloatLabel, ReactiveFormsModule, NgIf], + imports: [InputTextComponent, FloatLabel, ReactiveFormsModule, NgIf], template: `
- +
@@ -45,22 +45,22 @@ export const FloatLabelStory: StoryObj = { docs: { description: { story: - 'Интеграция с `p-floatlabel` — плавающая метка внутри поля. Кликните на поле чтобы увидеть анимацию. Требует нативный `` как прямой дочерний элемент `p-floatlabel`.', + 'Интеграция с `p-floatlabel` — плавающая метка внутри поля.', }, source: { language: 'ts', code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputText } from 'primeng/inputtext'; +import { InputTextComponent } from '@cdek-it/angular-ui-kit'; import { FloatLabel } from 'primeng/floatlabel'; @Component({ standalone: true, - imports: [InputText, FloatLabel, ReactiveFormsModule], + imports: [InputTextComponent, FloatLabel, ReactiveFormsModule], template: \` - + \`, From 5d5800eeb0da167f35942b229bcc46e3b111f936 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 6 May 2026 16:17:13 +0700 Subject: [PATCH 245/258] =?UTF-8?q?FloatLabel:=20=D0=BD=D0=B0=D1=82=D0=B8?= =?UTF-8?q?=D0=B2=D0=BD=D1=8B=D0=B9=20pInputText=20=D1=81=20formControl=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=BE=D1=80=D1=80=D0=B5=D0=BA=D1=82?= =?UTF-8?q?=D0=BD=D0=BE=D0=B9=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20p-f?= =?UTF-8?q?loatlabel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inputtext-float-label-invalid.component.ts | 12 ++++++------ .../examples/inputtext-float-label.component.ts | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts index a336125c..dfb4f524 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts @@ -2,18 +2,18 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { NgIf } from '@angular/common'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; +import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; @Component({ selector: 'app-inputtext-float-label-invalid', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputTextComponent, FloatLabel, ReactiveFormsModule, NgIf], + imports: [InputText, FloatLabel, ReactiveFormsModule, NgIf], template: `
- +
@@ -52,15 +52,15 @@ export const FloatLabelInvalid: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; -import { InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; @Component({ standalone: true, - imports: [InputTextComponent, FloatLabel, ReactiveFormsModule], + imports: [InputText, FloatLabel, ReactiveFormsModule], template: \` - + \`, diff --git a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts index ef57c6da..f7727c0e 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts @@ -2,17 +2,17 @@ import { Component, Input } from '@angular/core'; import { NgIf } from '@angular/common'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; +import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; @Component({ selector: 'app-inputtext-float-label', standalone: true, - imports: [InputTextComponent, FloatLabel, ReactiveFormsModule, NgIf], + imports: [InputText, FloatLabel, ReactiveFormsModule, NgIf], template: `
- +
@@ -45,22 +45,22 @@ export const FloatLabelStory: StoryObj = { docs: { description: { story: - 'Интеграция с `p-floatlabel` — плавающая метка внутри поля.', + 'Интеграция с `p-floatlabel` — плавающая метка внутри поля. `p-floatlabel` требует нативный `` как прямой дочерний элемент.', }, source: { language: 'ts', code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; @Component({ standalone: true, - imports: [InputTextComponent, FloatLabel, ReactiveFormsModule], + imports: [InputText, FloatLabel, ReactiveFormsModule], template: \` - + \`, From 749e49192036be97428849198d099b42f513e4a5 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 6 May 2026 16:32:03 +0700 Subject: [PATCH 246/258] =?UTF-8?q?fix:=20FloatLabel=20=D1=81=20input-text?= =?UTF-8?q?=20=E2=80=94=20display:contents=20+=20placeholder=20=D1=83?= =?UTF-8?q?=D1=81=D0=BB=D0=BE=D0=B2=D0=BD=D1=8B=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/inputtext/inputtext.component.ts | 5 +++-- .../inputtext-float-label-invalid.component.ts | 12 ++++++------ .../examples/inputtext-float-label.component.ts | 14 +++++++------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/lib/components/inputtext/inputtext.component.ts b/src/lib/components/inputtext/inputtext.component.ts index 0b9b8e93..8ee93979 100644 --- a/src/lib/components/inputtext/inputtext.component.ts +++ b/src/lib/components/inputtext/inputtext.component.ts @@ -12,6 +12,7 @@ export type InputTextSize = 'small' | 'base' | 'large' | 'xlarge'; selector: 'input-text', standalone: true, imports: [InputText, IconField, InputIcon, NgClass], + host: { style: 'display: contents' }, providers: [ { provide: NG_VALUE_ACCESSOR, @@ -29,7 +30,7 @@ export type InputTextSize = 'small' | 'base' | 'large' | 'xlarge'; [disabled]="disabled" [readOnly]="readonly" [invalid]="invalid" - [placeholder]="placeholder" + [attr.placeholder]="placeholder || null" [fluid]="fluid" [value]="modelValue" (input)="onInput($event)" @@ -53,7 +54,7 @@ export type InputTextSize = 'small' | 'base' | 'large' | 'xlarge'; [disabled]="disabled" [readOnly]="readonly" [invalid]="invalid" - [placeholder]="placeholder" + [attr.placeholder]="placeholder || null" [fluid]="fluid" [value]="modelValue" (input)="onInput($event)" diff --git a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts index dfb4f524..a336125c 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts @@ -2,18 +2,18 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { NgIf } from '@angular/common'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; +import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; @Component({ selector: 'app-inputtext-float-label-invalid', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputText, FloatLabel, ReactiveFormsModule, NgIf], + imports: [InputTextComponent, FloatLabel, ReactiveFormsModule, NgIf], template: `
- +
@@ -52,15 +52,15 @@ export const FloatLabelInvalid: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; -import { InputText } from 'primeng/inputtext'; +import { InputTextComponent } from '@cdek-it/angular-ui-kit'; import { FloatLabel } from 'primeng/floatlabel'; @Component({ standalone: true, - imports: [InputText, FloatLabel, ReactiveFormsModule], + imports: [InputTextComponent, FloatLabel, ReactiveFormsModule], template: \` - + \`, diff --git a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts index f7727c0e..ef57c6da 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts @@ -2,17 +2,17 @@ import { Component, Input } from '@angular/core'; import { NgIf } from '@angular/common'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputText } from 'primeng/inputtext'; import { FloatLabel } from 'primeng/floatlabel'; +import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; @Component({ selector: 'app-inputtext-float-label', standalone: true, - imports: [InputText, FloatLabel, ReactiveFormsModule, NgIf], + imports: [InputTextComponent, FloatLabel, ReactiveFormsModule, NgIf], template: `
- +
@@ -45,22 +45,22 @@ export const FloatLabelStory: StoryObj = { docs: { description: { story: - 'Интеграция с `p-floatlabel` — плавающая метка внутри поля. `p-floatlabel` требует нативный `` как прямой дочерний элемент.', + 'Интеграция с `p-floatlabel` — плавающая метка внутри поля.', }, source: { language: 'ts', code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputText } from 'primeng/inputtext'; +import { InputTextComponent } from '@cdek-it/angular-ui-kit'; import { FloatLabel } from 'primeng/floatlabel'; @Component({ standalone: true, - imports: [InputText, FloatLabel, ReactiveFormsModule], + imports: [InputTextComponent, FloatLabel, ReactiveFormsModule], template: \` - + \`, From 2af660eab1060f0380357d8dc76d1e736e9007ee Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Wed, 6 May 2026 19:12:28 +0700 Subject: [PATCH 247/258] =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D1=82=D0=B8=D0=BB=D0=B5?= =?UTF-8?q?=D0=B9=20=D0=B4=D0=BB=D1=8F=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D1=82=D0=B0=20InputGroup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/map-tokens.ts | 2 +- src/prime-preset/tokens/components/inputgroup.ts | 6 ++++++ .../inputgroup/examples/inputgroup-xlarge.component.ts | 2 +- src/stories/components/inputgroup/inputgroup.stories.ts | 4 ++-- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 8b3204ef..6a64ff57 100644 --- a/src/prime-preset/map-tokens.ts +++ b/src/prime-preset/map-tokens.ts @@ -60,7 +60,7 @@ const presetTokens: Preset = { inputmask: { css: inputmaskCss, }, - inputgroupCss: { + inputgroup: { ...(tokens.components.inputgroup as unknown as ComponentsDesignTokens['inputgroup']), css: inputgroupCss, }, diff --git a/src/prime-preset/tokens/components/inputgroup.ts b/src/prime-preset/tokens/components/inputgroup.ts index eaf2c78a..5efcbff0 100644 --- a/src/prime-preset/tokens/components/inputgroup.ts +++ b/src/prime-preset/tokens/components/inputgroup.ts @@ -57,6 +57,12 @@ export const inputgroupCss = ({ dt }: { dt: (token: string) => string }): string margin: 0; } +/* Аддон: только горизонтальные границы (top/bottom), inline-бордеры управляются позиционно */ +.p-inputgroup > input-group-addon > .p-inputgroupaddon { + border-block-start: ${dt('inputgroup.extend.borderWidth')} solid ${dt('inputgroup.addon.borderColor')}; + border-block-end: ${dt('inputgroup.extend.borderWidth')} solid ${dt('inputgroup.addon.borderColor')}; +} + /* Первый элемент группы — input: левые углы */ .p-inputgroup > input-text:first-child .p-inputtext { border-start-start-radius: ${dt('inputgroup.addon.borderRadius')}; diff --git a/src/stories/components/inputgroup/examples/inputgroup-xlarge.component.ts b/src/stories/components/inputgroup/examples/inputgroup-xlarge.component.ts index 37643d5a..47e61b57 100644 --- a/src/stories/components/inputgroup/examples/inputgroup-xlarge.component.ts +++ b/src/stories/components/inputgroup/examples/inputgroup-xlarge.component.ts @@ -26,7 +26,7 @@ export class InputGroupXlargeComponent { value = ''; } -export const XLarge: StoryObj = { +export const Sizes: StoryObj = { render: () => ({ template: ``, }), diff --git a/src/stories/components/inputgroup/inputgroup.stories.ts b/src/stories/components/inputgroup/inputgroup.stories.ts index d833fc31..888a7ce7 100644 --- a/src/stories/components/inputgroup/inputgroup.stories.ts +++ b/src/stories/components/inputgroup/inputgroup.stories.ts @@ -5,7 +5,7 @@ import { InputGroupAddonComponent } from '../../../lib/components/inputgroup/inp import { InputTextComponent } from '../../../lib/components/inputtext/inputtext.component'; import { InputGroupWithTextComponent, WithText } from './examples/inputgroup-with-text.component'; import { InputGroupDisabledComponent, Disabled } from './examples/inputgroup-disabled.component'; -import { InputGroupXlargeComponent, XLarge } from './examples/inputgroup-xlarge.component'; +import { InputGroupXlargeComponent, Sizes } from './examples/inputgroup-xlarge.component'; import { InputGroupAddonRightComponent, AddonRight } from './examples/inputgroup-addon-right.component'; import { InputGroupAddonBothComponent, AddonBoth } from './examples/inputgroup-addon-both.component'; @@ -89,4 +89,4 @@ ${groupOpen} }, }; -export { WithText, AddonRight, AddonBoth, Disabled, XLarge }; +export { WithText, AddonRight, AddonBoth, Disabled, Sizes }; From 6c75f2066ef3fe5cd86bed6873532678f9b3b225 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Mon, 18 May 2026 01:40:02 +0700 Subject: [PATCH 248/258] DS-559 --- .../inputgroup/input-group-addon.component.ts | 4 +- .../inputgroup/input-group.component.ts | 4 +- src/lib/components/inputgroup/ng-package.json | 7 ++ src/lib/components/inputgroup/public_api.ts | 3 + .../inputmask/inputmask.component.ts | 4 +- src/lib/components/inputmask/ng-package.json | 7 ++ src/lib/components/inputmask/public_api.ts | 2 + .../inputnumber/inputnumber.component.ts | 6 +- .../components/inputnumber/ng-package.json | 7 ++ src/lib/components/inputnumber/public_api.ts | 2 + .../components/inputotp/inputotp.component.ts | 6 +- src/lib/components/inputotp/ng-package.json | 7 ++ src/lib/components/inputotp/public_api.ts | 2 + .../inputtext/inputtext.component.ts | 4 +- .../components/megamenu/megamenu.component.ts | 2 +- .../components/message/message.component.ts | 4 +- src/lib/components/message/ng-package.json | 7 ++ src/lib/components/message/public_api.ts | 2 + src/lib/components/paginator/ng-package.json | 7 ++ .../paginator/paginator.component.ts | 4 +- src/lib/components/paginator/public_api.ts | 2 + src/lib/components/panelmenu/ng-package.json | 7 ++ .../panelmenu/panelmenu.component.ts | 4 +- src/lib/components/panelmenu/public_api.ts | 2 + src/lib/components/password/ng-package.json | 7 ++ .../components/password/password.component.ts | 6 +- src/lib/components/password/public_api.ts | 2 + .../components/scroll-panel/ng-package.json | 7 ++ src/lib/components/scroll-panel/public_api.ts | 2 + .../scroll-panel/scroll-panel.component.ts | 4 +- src/lib/components/select/ng-package.json | 7 ++ src/lib/components/select/public_api.ts | 2 + src/lib/components/select/select.component.ts | 15 ++- src/lib/components/textarea/ng-package.json | 7 ++ src/lib/components/textarea/public_api.ts | 2 + .../components/textarea/textarea.component.ts | 12 +- .../components/timeline/timeline.component.ts | 50 ++++---- .../components/toggleswitch/ng-package.json | 7 ++ src/lib/components/toggleswitch/public_api.ts | 2 + .../toggleswitch/toggleswitch.component.ts | 6 +- .../components/button/button.stories.ts | 45 +++++--- .../card/examples/card-overlay.component.ts | 4 +- .../examples/card-without-header.component.ts | 4 +- .../card-without-subtitle.component.ts | 4 +- .../examples/dialog-default.component.ts | 2 +- .../dialog/examples/dialog-large.component.ts | 2 +- .../dialog/examples/dialog-small.component.ts | 2 +- .../inputgroup-addon-both.component.ts | 34 +++--- .../inputgroup-addon-right.component.ts | 30 ++--- .../examples/inputgroup-disabled.component.ts | 30 ++--- .../inputgroup-with-text.component.ts | 30 ++--- .../examples/inputgroup-xlarge.component.ts | 30 ++--- .../inputgroup/inputgroup.stories.ts | 52 ++++----- .../examples/inputmask-disabled.component.ts | 12 +- .../examples/inputmask-invalid.component.ts | 12 +- .../examples/inputmask-readonly.component.ts | 12 +- .../examples/inputmask-sizes.component.ts | 14 +-- .../components/inputmask/inputmask.stories.ts | 12 +- .../examples/inputnumber-buttons.component.ts | 16 +-- .../inputnumber-currency.component.ts | 16 +-- .../inputnumber-disabled.component.ts | 16 +-- .../inputnumber/inputnumber.stories.ts | 12 +- .../examples/inputotp-disabled.component.ts | 12 +- .../inputotp-integeronly.component.ts | 12 +- .../examples/inputotp-invalid.component.ts | 12 +- .../examples/inputotp-mask.component.ts | 12 +- .../examples/inputotp-readonly.component.ts | 12 +- .../components/inputotp/inputotp.stories.ts | 12 +- .../examples/inputtext-clear.component.ts | 8 +- ...inputtext-float-label-invalid.component.ts | 26 +++-- .../inputtext-float-label.component.ts | 26 +++-- .../examples/inputtext-readonly.component.ts | 8 +- .../components/inputtext/inputtext.stories.ts | 24 ++-- .../examples/message-severities.component.ts | 20 ++-- .../message-with-close-button.component.ts | 14 +-- .../message-with-content.component.ts | 24 ++-- .../components/message/message.stories.ts | 12 +- ...paginator-current-page-report.component.ts | 16 +-- .../paginator-rows-per-page.component.ts | 16 +-- .../components/paginator/paginator.stories.ts | 14 +-- .../examples/panelmenu-basic.component.ts | 12 +- .../examples/panelmenu-custom.component.ts | 48 ++++---- .../examples/panelmenu-multiple.component.ts | 12 +- .../components/panelmenu/panelmenu.stories.ts | 14 +-- .../examples/password-disabled.component.ts | 12 +- .../examples/password-feedback.component.ts | 12 +- .../password-float-label.component.ts | 10 +- .../examples/password-invalid.component.ts | 12 +- .../examples/password-template.component.ts | 16 +-- .../examples/password-toggle.component.ts | 12 +- .../components/password/password.stories.ts | 16 +-- .../examples/scroll-panel-both.component.ts | 8 +- .../scroll-panel-horizontal.component.ts | 8 +- .../scroll-panel/scroll-panel.stories.ts | 32 ++--- .../examples/select-custom.component.ts | 16 +-- .../examples/select-disabled.component.ts | 16 +-- .../examples/select-editable.component.ts | 16 +-- .../examples/select-filter.component.ts | 16 +-- .../examples/select-float-label.component.ts | 16 +-- .../examples/select-grouped.component.ts | 16 +-- .../components/select/select.stories.ts | 14 +-- .../skeleton-card-placeholder.component.ts | 16 +-- .../examples/skeleton-circle.component.ts | 14 +-- .../skeleton-no-animation.component.ts | 12 +- .../examples/skeleton-rectangles.component.ts | 12 +- src/stories/components/tag/tag.stories.ts | 90 +-------------- .../examples/textarea-autoresize.component.ts | 8 +- .../examples/textarea-disabled.component.ts | 12 +- .../textarea-float-label.component.ts | 5 +- .../examples/textarea-invalid.component.ts | 12 +- .../examples/textarea-readonly.component.ts | 12 +- .../examples/textarea-sizes.component.ts | 34 +++--- .../components/textarea/textarea.stories.ts | 12 +- .../examples/tieredmenu-basic.component.ts | 2 +- .../examples/tieredmenu-custom.component.ts | 44 ++++--- .../examples/tieredmenu-selected.component.ts | 2 +- .../tieredmenu/tieredmenu.stories.ts | 36 +++--- .../components/timeline/timeline.stories.ts | 2 +- .../toggleswitch-checked.component.ts | 8 +- .../toggleswitch-disabled.component.ts | 8 +- .../toggleswitch-invalid.component.ts | 8 +- .../toggleswitch/toggleswitch.stories.ts | 109 ++---------------- 122 files changed, 843 insertions(+), 864 deletions(-) create mode 100644 src/lib/components/inputgroup/ng-package.json create mode 100644 src/lib/components/inputgroup/public_api.ts create mode 100644 src/lib/components/inputmask/ng-package.json create mode 100644 src/lib/components/inputmask/public_api.ts create mode 100644 src/lib/components/inputnumber/ng-package.json create mode 100644 src/lib/components/inputnumber/public_api.ts create mode 100644 src/lib/components/inputotp/ng-package.json create mode 100644 src/lib/components/inputotp/public_api.ts create mode 100644 src/lib/components/message/ng-package.json create mode 100644 src/lib/components/message/public_api.ts create mode 100644 src/lib/components/paginator/ng-package.json create mode 100644 src/lib/components/paginator/public_api.ts create mode 100644 src/lib/components/panelmenu/ng-package.json create mode 100644 src/lib/components/panelmenu/public_api.ts create mode 100644 src/lib/components/password/ng-package.json create mode 100644 src/lib/components/password/public_api.ts create mode 100644 src/lib/components/scroll-panel/ng-package.json create mode 100644 src/lib/components/scroll-panel/public_api.ts create mode 100644 src/lib/components/select/ng-package.json create mode 100644 src/lib/components/select/public_api.ts create mode 100644 src/lib/components/textarea/ng-package.json create mode 100644 src/lib/components/textarea/public_api.ts create mode 100644 src/lib/components/toggleswitch/ng-package.json create mode 100644 src/lib/components/toggleswitch/public_api.ts diff --git a/src/lib/components/inputgroup/input-group-addon.component.ts b/src/lib/components/inputgroup/input-group-addon.component.ts index fba19611..d547bdae 100644 --- a/src/lib/components/inputgroup/input-group-addon.component.ts +++ b/src/lib/components/inputgroup/input-group-addon.component.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { InputGroupAddon } from 'primeng/inputgroupaddon'; @Component({ - selector: 'input-group-addon', + selector: 'extra-input-group-addon', standalone: true, imports: [InputGroupAddon], template: ` @@ -11,4 +11,4 @@ import { InputGroupAddon } from 'primeng/inputgroupaddon'; `, }) -export class InputGroupAddonComponent {} +export class ExtraInputGroupAddonComponent {} diff --git a/src/lib/components/inputgroup/input-group.component.ts b/src/lib/components/inputgroup/input-group.component.ts index 273624fc..80e129a9 100644 --- a/src/lib/components/inputgroup/input-group.component.ts +++ b/src/lib/components/inputgroup/input-group.component.ts @@ -5,7 +5,7 @@ import { InputGroup } from 'primeng/inputgroup'; export type InputGroupSize = 'small' | 'base' | 'large' | 'xlarge'; @Component({ - selector: 'input-group', + selector: 'extra-input-group', standalone: true, imports: [InputGroup, NgClass], template: ` @@ -14,7 +14,7 @@ export type InputGroupSize = 'small' | 'base' | 'large' | 'xlarge'; `, }) -export class InputGroupComponent { +export class ExtraInputGroupComponent { @Input() size: InputGroupSize = 'base'; get sizeClass(): string { diff --git a/src/lib/components/inputgroup/ng-package.json b/src/lib/components/inputgroup/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/inputgroup/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/inputgroup/public_api.ts b/src/lib/components/inputgroup/public_api.ts new file mode 100644 index 00000000..613429b8 --- /dev/null +++ b/src/lib/components/inputgroup/public_api.ts @@ -0,0 +1,3 @@ +export * from './input-group.component'; +export * from './input-group-addon.component'; + diff --git a/src/lib/components/inputmask/inputmask.component.ts b/src/lib/components/inputmask/inputmask.component.ts index 8abc2102..59e19c22 100644 --- a/src/lib/components/inputmask/inputmask.component.ts +++ b/src/lib/components/inputmask/inputmask.component.ts @@ -7,7 +7,7 @@ export type InputMaskSize = 'small' | 'base' | 'large' | 'xlarge'; @Component({ - selector: 'input-mask', + selector: 'extra-input-mask', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [InputMask, ReactiveFormsModule], @@ -41,7 +41,7 @@ export type InputMaskSize = 'small' | 'base' | 'large' | 'xlarge'; > `, }) -export class InputMaskComponent implements ControlValueAccessor, OnInit { +export class ExtraInputMaskComponent implements ControlValueAccessor, OnInit { private readonly _injector = inject(Injector); private readonly destroyRef = inject(DestroyRef); private _ngControl: NgControl | null = null; diff --git a/src/lib/components/inputmask/ng-package.json b/src/lib/components/inputmask/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/inputmask/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/inputmask/public_api.ts b/src/lib/components/inputmask/public_api.ts new file mode 100644 index 00000000..8a0a90ff --- /dev/null +++ b/src/lib/components/inputmask/public_api.ts @@ -0,0 +1,2 @@ +export * from './inputmask.component'; + diff --git a/src/lib/components/inputnumber/inputnumber.component.ts b/src/lib/components/inputnumber/inputnumber.component.ts index 2a1dafe0..4fd05a8c 100644 --- a/src/lib/components/inputnumber/inputnumber.component.ts +++ b/src/lib/components/inputnumber/inputnumber.component.ts @@ -8,13 +8,13 @@ export type InputNumberSize = 'small' | 'base' | 'large' | 'xlarge'; export type InputNumberButtonLayout = 'stacked' | 'horizontal' | 'vertical'; @Component({ - selector: 'input-number', + selector: 'extra-input-number', standalone: true, imports: [InputNumber, SharedModule, FormsModule, NgClass], providers: [ { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => InputNumberComponent), + useExisting: forwardRef(() => ExtraInputNumberComponent), multi: true, }, ], @@ -59,7 +59,7 @@ export type InputNumberButtonLayout = 'stacked' | 'horizontal' | 'vertical'; `, }) -export class InputNumberComponent implements ControlValueAccessor, OnInit { +export class ExtraInputNumberComponent implements ControlValueAccessor, OnInit { private readonly _injector = inject(Injector); private _ngControl: NgControl | null = null; diff --git a/src/lib/components/inputnumber/ng-package.json b/src/lib/components/inputnumber/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/inputnumber/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/inputnumber/public_api.ts b/src/lib/components/inputnumber/public_api.ts new file mode 100644 index 00000000..f3c2de28 --- /dev/null +++ b/src/lib/components/inputnumber/public_api.ts @@ -0,0 +1,2 @@ +export * from './inputnumber.component'; + diff --git a/src/lib/components/inputotp/inputotp.component.ts b/src/lib/components/inputotp/inputotp.component.ts index f0f745db..41893730 100644 --- a/src/lib/components/inputotp/inputotp.component.ts +++ b/src/lib/components/inputotp/inputotp.component.ts @@ -7,13 +7,13 @@ import { InputOtp, InputOtpChangeEvent } from 'primeng/inputotp'; export type InputOtpSize = 'small' | 'base' | 'large' | 'xlarge'; @Component({ - selector: 'input-otp', + selector: 'extra-input-otp', standalone: true, imports: [InputOtp, ReactiveFormsModule, NgClass], providers: [ { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => InputOtpComponent), + useExisting: forwardRef(() => ExtraInputOtpComponent), multi: true, }, ], @@ -36,7 +36,7 @@ export type InputOtpSize = 'small' | 'base' | 'large' | 'xlarge'; >
`, }) -export class InputOtpComponent implements ControlValueAccessor, OnInit { +export class ExtraInputOtpComponent implements ControlValueAccessor, OnInit { private readonly _injector = inject(Injector); private readonly destroyRef = inject(DestroyRef); private _ngControl: NgControl | null = null; diff --git a/src/lib/components/inputotp/ng-package.json b/src/lib/components/inputotp/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/inputotp/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/inputotp/public_api.ts b/src/lib/components/inputotp/public_api.ts new file mode 100644 index 00000000..e0badf94 --- /dev/null +++ b/src/lib/components/inputotp/public_api.ts @@ -0,0 +1,2 @@ +export * from './inputotp.component'; + diff --git a/src/lib/components/inputtext/inputtext.component.ts b/src/lib/components/inputtext/inputtext.component.ts index af96be07..a4c32932 100644 --- a/src/lib/components/inputtext/inputtext.component.ts +++ b/src/lib/components/inputtext/inputtext.component.ts @@ -89,10 +89,10 @@ export class ExtraInputTextComponent implements ControlValueAccessor, OnInit { private _onChange: (value: string) => void = () => {}; - get primeSize(): 'small' | 'large' | undefined { + get primeSize(): 'small' | 'large' | never { if (this.size === 'small') return 'small'; if (this.size === 'large' || this.size === 'xlarge') return 'large'; - return undefined; + return undefined as never; } get sizeClass(): Record { diff --git a/src/lib/components/megamenu/megamenu.component.ts b/src/lib/components/megamenu/megamenu.component.ts index 0a2d8947..27305dda 100644 --- a/src/lib/components/megamenu/megamenu.component.ts +++ b/src/lib/components/megamenu/megamenu.component.ts @@ -66,7 +66,7 @@ export interface MegaMenuModel extends Omit { `, }) export class ExtraMegaMenuComponent { - @Input() model: MegaMenuModel[] = []; + @Input() model: MegaMenuItem[] = []; @Input() orientation: MegaMenuOrientation = 'horizontal'; @Input() breakpoint: string = '960px'; @Input() scrollHeight: string = ''; diff --git a/src/lib/components/message/message.component.ts b/src/lib/components/message/message.component.ts index b9932512..ac46e2cc 100644 --- a/src/lib/components/message/message.component.ts +++ b/src/lib/components/message/message.component.ts @@ -13,7 +13,7 @@ const SEVERITY_ICONS: Record = { }; @Component({ - selector: 'ui-message', + selector: 'extra-message', standalone: true, imports: [Message, ButtonDirective, SharedModule], template: ` @@ -42,7 +42,7 @@ const SEVERITY_ICONS: Record = { `, }) -export class MessageComponent { +export class ExtraMessageComponent { @Input() severity: MessageSeverity = 'info'; @Input() summary = ''; @Input() detail = ''; diff --git a/src/lib/components/message/ng-package.json b/src/lib/components/message/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/message/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/message/public_api.ts b/src/lib/components/message/public_api.ts new file mode 100644 index 00000000..df5522d9 --- /dev/null +++ b/src/lib/components/message/public_api.ts @@ -0,0 +1,2 @@ +export * from './message.component'; + diff --git a/src/lib/components/paginator/ng-package.json b/src/lib/components/paginator/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/paginator/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/paginator/paginator.component.ts b/src/lib/components/paginator/paginator.component.ts index 61c28c17..6eab1b75 100644 --- a/src/lib/components/paginator/paginator.component.ts +++ b/src/lib/components/paginator/paginator.component.ts @@ -3,7 +3,7 @@ import { Paginator } from 'primeng/paginator'; import type { PaginatorState } from 'primeng/types/paginator'; @Component({ - selector: 'paginator', + selector: 'extra-paginator', standalone: true, imports: [Paginator], template: ` @@ -24,7 +24,7 @@ import type { PaginatorState } from 'primeng/types/paginator'; > `, }) -export class PaginatorComponent { +export class ExtraPaginatorComponent { @Input() first = 0; @Input() rows = 10; @Input() totalRecords = 0; diff --git a/src/lib/components/paginator/public_api.ts b/src/lib/components/paginator/public_api.ts new file mode 100644 index 00000000..e7878634 --- /dev/null +++ b/src/lib/components/paginator/public_api.ts @@ -0,0 +1,2 @@ +export * from './paginator.component'; + diff --git a/src/lib/components/panelmenu/ng-package.json b/src/lib/components/panelmenu/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/panelmenu/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/panelmenu/panelmenu.component.ts b/src/lib/components/panelmenu/panelmenu.component.ts index efb3516b..2dd63adc 100644 --- a/src/lib/components/panelmenu/panelmenu.component.ts +++ b/src/lib/components/panelmenu/panelmenu.component.ts @@ -3,7 +3,7 @@ import { PanelMenu } from 'primeng/panelmenu'; import { MenuItem } from 'primeng/api'; @Component({ - selector: 'panelmenu', + selector: 'extra-panelmenu', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [PanelMenu], @@ -15,7 +15,7 @@ import { MenuItem } from 'primeng/api'; > `, }) -export class PanelMenuComponent implements AfterViewChecked { +export class ExtraPanelMenuComponent implements AfterViewChecked { @Input() model: MenuItem[] = []; @Input() multiple = false; @Input() tabindex: number | undefined = undefined; diff --git a/src/lib/components/panelmenu/public_api.ts b/src/lib/components/panelmenu/public_api.ts new file mode 100644 index 00000000..dc4de688 --- /dev/null +++ b/src/lib/components/panelmenu/public_api.ts @@ -0,0 +1,2 @@ +export * from './panelmenu.component'; + diff --git a/src/lib/components/password/ng-package.json b/src/lib/components/password/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/password/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/password/password.component.ts b/src/lib/components/password/password.component.ts index 2b1ebe0e..a93017be 100644 --- a/src/lib/components/password/password.component.ts +++ b/src/lib/components/password/password.component.ts @@ -8,7 +8,7 @@ import { FloatLabel } from 'primeng/floatlabel'; export type PasswordSize = 'small' | 'base' | 'large' | 'xlarge'; @Component({ - selector: 'password', + selector: 'extra-password', host: { style: 'display: block' }, standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, @@ -16,7 +16,7 @@ export type PasswordSize = 'small' | 'base' | 'large' | 'xlarge'; providers: [ { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => PasswordComponent), + useExisting: forwardRef(() => ExtraPasswordComponent), multi: true, }, ], @@ -68,7 +68,7 @@ export type PasswordSize = 'small' | 'base' | 'large' | 'xlarge'; `, }) -export class PasswordComponent implements ControlValueAccessor { +export class ExtraPasswordComponent implements ControlValueAccessor { @ContentChild('header') headerTemplate: TemplateRef | null = null; @ContentChild('footer') footerTemplate: TemplateRef | null = null; diff --git a/src/lib/components/password/public_api.ts b/src/lib/components/password/public_api.ts new file mode 100644 index 00000000..60d0b863 --- /dev/null +++ b/src/lib/components/password/public_api.ts @@ -0,0 +1,2 @@ +export * from './password.component'; + diff --git a/src/lib/components/scroll-panel/ng-package.json b/src/lib/components/scroll-panel/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/scroll-panel/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/scroll-panel/public_api.ts b/src/lib/components/scroll-panel/public_api.ts new file mode 100644 index 00000000..dd07e831 --- /dev/null +++ b/src/lib/components/scroll-panel/public_api.ts @@ -0,0 +1,2 @@ +export * from './scroll-panel.component'; + diff --git a/src/lib/components/scroll-panel/scroll-panel.component.ts b/src/lib/components/scroll-panel/scroll-panel.component.ts index 76a35a66..b340ba03 100644 --- a/src/lib/components/scroll-panel/scroll-panel.component.ts +++ b/src/lib/components/scroll-panel/scroll-panel.component.ts @@ -2,7 +2,7 @@ import { Component, Input } from '@angular/core'; import { ScrollPanel } from 'primeng/scrollpanel'; @Component({ - selector: 'scroll-panel', + selector: 'extra-scroll-panel', host: { style: 'display: block' }, standalone: true, imports: [ScrollPanel], @@ -15,7 +15,7 @@ import { ScrollPanel } from 'primeng/scrollpanel'; `, }) -export class ScrollPanelComponent { +export class ExtraScrollPanelComponent { @Input() step = 10; @Input() height = '100px'; @Input() width = '100%'; diff --git a/src/lib/components/select/ng-package.json b/src/lib/components/select/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/select/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/select/public_api.ts b/src/lib/components/select/public_api.ts new file mode 100644 index 00000000..fa139e5f --- /dev/null +++ b/src/lib/components/select/public_api.ts @@ -0,0 +1,2 @@ +export * from './select.component'; + diff --git a/src/lib/components/select/select.component.ts b/src/lib/components/select/select.component.ts index 9c1a2bc7..e07291bc 100644 --- a/src/lib/components/select/select.component.ts +++ b/src/lib/components/select/select.component.ts @@ -5,18 +5,23 @@ import { FormsModule } from '@angular/forms'; import { Select } from 'primeng/select'; import { FloatLabel } from 'primeng/floatlabel'; import { PrimeTemplate } from 'primeng/api'; +import { AnimationEvent as NativeAnimationEvent } from '@angular/animations'; import type { SelectChangeEvent, SelectFilterEvent } from 'primeng/types/select'; export type SelectSize = 'small' | 'base' | 'large' | 'xlarge'; +export interface AnimationEvent extends NativeAnimationEvent {} + +// export class AnimationEvent + @Component({ - selector: 'select-field', + selector: 'extra-select', standalone: true, imports: [Select, NgClass, NgTemplateOutlet, PrimeTemplate, FormsModule, FloatLabel], providers: [ { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => SelectComponent), + useExisting: forwardRef(() => ExtraSelectComponent), multi: true, }, ], @@ -82,7 +87,7 @@ export type SelectSize = 'small' | 'base' | 'large' | 'xlarge'; `, }) -export class SelectComponent implements ControlValueAccessor, OnInit { +export class ExtraSelectComponent implements ControlValueAccessor, OnInit { private readonly _injector = inject(Injector); private _ngControl: NgControl | null = null; @@ -121,8 +126,8 @@ export class SelectComponent implements ControlValueAccessor, OnInit { @Output() onClear = new EventEmitter(); @Output() onFilter = new EventEmitter(); - @Output() onShow = new EventEmitter(); - @Output() onHide = new EventEmitter(); + @Output() onShow = new EventEmitter(); + @Output() onHide = new EventEmitter(); @Output() onFocus = new EventEmitter(); @Output() onBlur = new EventEmitter(); diff --git a/src/lib/components/textarea/ng-package.json b/src/lib/components/textarea/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/textarea/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/textarea/public_api.ts b/src/lib/components/textarea/public_api.ts new file mode 100644 index 00000000..1e7c627e --- /dev/null +++ b/src/lib/components/textarea/public_api.ts @@ -0,0 +1,2 @@ +export * from './textarea.component'; + diff --git a/src/lib/components/textarea/textarea.component.ts b/src/lib/components/textarea/textarea.component.ts index 46dfc60f..dbfe2595 100644 --- a/src/lib/components/textarea/textarea.component.ts +++ b/src/lib/components/textarea/textarea.component.ts @@ -8,14 +8,14 @@ import { InputIcon } from 'primeng/inputicon'; export type TextareaSize = 'small' | 'base' | 'large' | 'xlarge'; @Component({ - selector: 'ui-textarea', + selector: 'extra-textarea', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [Textarea, IconField, InputIcon, NgClass], providers: [ { provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => TextareaComponent), + useExisting: forwardRef(() => ExtraTextareaComponent), multi: true, }, ], @@ -70,7 +70,7 @@ export type TextareaSize = 'small' | 'base' | 'large' | 'xlarge'; } `, }) -export class TextareaComponent implements ControlValueAccessor, OnInit { +export class ExtraTextareaComponent implements ControlValueAccessor, OnInit { private readonly _injector = inject(Injector); private _ngControl: NgControl | null = null; @@ -93,17 +93,17 @@ export class TextareaComponent implements ControlValueAccessor, OnInit { return this._ngControl?.invalid ?? false; } - @Output() onResize = new EventEmitter<{ height: string }>(); + @Output() onResize = new EventEmitter<{ height: string } | {}>(); @Output() onClear = new EventEmitter(); modelValue = ''; private _onChange: (value: string) => void = () => {}; - get primeSize(): 'small' | 'large' | undefined { + get primeSize(): 'small' | 'large' | never { if (this.size === 'small') return 'small'; if (this.size === 'large') return 'large'; - return undefined; + return undefined as never; } get sizeClass(): Record { diff --git a/src/lib/components/timeline/timeline.component.ts b/src/lib/components/timeline/timeline.component.ts index 4af9ebf4..c8297b06 100644 --- a/src/lib/components/timeline/timeline.component.ts +++ b/src/lib/components/timeline/timeline.component.ts @@ -1,20 +1,16 @@ import { Component, Input, ContentChild, TemplateRef, HostBinding } from '@angular/core'; import { Timeline } from 'primeng/timeline'; import { SharedModule } from 'primeng/api'; -import { NgIf, NgTemplateOutlet } from '@angular/common'; +import { NgTemplateOutlet } from '@angular/common'; export type TimelineLine = 'solid' | 'dashed' | 'dotted' | 'none'; @Component({ selector: 'extra-timeline', standalone: true, - imports: [Timeline, SharedModule, NgIf, NgTemplateOutlet], + imports: [Timeline, SharedModule, NgTemplateOutlet], template: ` - + - - + @if (showCaption) { + @if (oppositeTemplate) { - -   - + } @else { +   + } + } - - - - - - - - + @if (markerTemplate || icon) { + + @if (markerTemplate) { + + } @else { + + + + } - + } {{ event }} - `, + ` }) export class ExtraTimelineComponent { @Input() value: any[] = []; @@ -56,8 +54,12 @@ export class ExtraTimelineComponent { @Input() icon = ''; @Input() markerColor = ''; - @HostBinding('attr.data-line') get dataLine() { return this.line; } - @HostBinding('style.--timeline-marker-color') get markerColorVar() { return this.markerColor || null; } + @HostBinding('attr.data-line') get dataLine() { + return this.line; + } + @HostBinding('style.--timeline-marker-color') get markerColorVar() { + return this.markerColor || null; + } @ContentChild('content') contentTemplate?: TemplateRef; @ContentChild('opposite') oppositeTemplate?: TemplateRef; diff --git a/src/lib/components/toggleswitch/ng-package.json b/src/lib/components/toggleswitch/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/toggleswitch/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/toggleswitch/public_api.ts b/src/lib/components/toggleswitch/public_api.ts new file mode 100644 index 00000000..b72d0762 --- /dev/null +++ b/src/lib/components/toggleswitch/public_api.ts @@ -0,0 +1,2 @@ +export * from './toggleswitch.component'; + diff --git a/src/lib/components/toggleswitch/toggleswitch.component.ts b/src/lib/components/toggleswitch/toggleswitch.component.ts index 30dc52e5..2be71acf 100644 --- a/src/lib/components/toggleswitch/toggleswitch.component.ts +++ b/src/lib/components/toggleswitch/toggleswitch.component.ts @@ -3,7 +3,7 @@ import { ControlValueAccessor, FormsModule, NgControl } from '@angular/forms'; import { ToggleSwitch } from 'primeng/toggleswitch'; @Component({ - selector: 'toggleswitch', + selector: 'extra-toggleswitch', standalone: true, imports: [ToggleSwitch, FormsModule], template: ` @@ -18,13 +18,13 @@ import { ToggleSwitch } from 'primeng/toggleswitch'; > `, }) -export class ToggleSwitchComponent implements ControlValueAccessor { +export class ExtraToggleSwitchComponent implements ControlValueAccessor { @Output() onChange = new EventEmitter(); @Output() onFocus = new EventEmitter(); @Output() onBlur = new EventEmitter(); modelValue = false; - + private _disabled = false; private _onChange: (value: boolean) => void = () => {}; diff --git a/src/stories/components/button/button.stories.ts b/src/stories/components/button/button.stories.ts index afb1442a..95eae973 100644 --- a/src/stories/components/button/button.stories.ts +++ b/src/stories/components/button/button.stories.ts @@ -1,18 +1,16 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { ExtraButtonComponent } from '../../../lib/components/button/button.component'; import { ButtonSizesComponent, Sizes } from './examples/button-sizes.component'; -import { Text } from './examples/button-text.component'; -import { Severity } from './examples/button-severity.component'; -import { Rounded } from './examples/button-rounded.component'; -import { Outlined } from './examples/button-outlined.component'; -import { Loading } from './examples/button-loading.component'; -import { Icon } from './examples/button-icon.component'; +import { ButtonTextComponent, Text } from './examples/button-text.component'; +import { ButtonSeverityComponent, Severity } from './examples/button-severity.component'; +import { ButtonRoundedComponent, Rounded } from './examples/button-rounded.component'; +import { ButtonOutlinedComponent, Outlined } from './examples/button-outlined.component'; +import { ButtonLoadingComponent, Loading } from './examples/button-loading.component'; +import { ButtonIconComponent, Icon } from './examples/button-icon.component'; import { Extra } from './examples/button-extra.component'; -import { Disabled } from './examples/button-disabled.component'; -import { Base } from './examples/button-base.component'; -import { Badge } from './examples/button-badge.component'; - - +import { ButtonDisabledComponent, Disabled } from './examples/button-disabled.component'; +import { Base, ButtonBaseComponent } from './examples/button-base.component'; +import { Badge, ButtonBadgeComponent } from './examples/button-badge.component'; type ButtonArgs = ExtraButtonComponent & { onClick?: (event: MouseEvent) => void }; @@ -22,7 +20,20 @@ const meta: Meta = { tags: ['autodocs'], decorators: [ moduleMetadata({ - imports: [ExtraButtonComponent, ButtonSizesComponent] + imports: [ + ExtraButtonComponent, + ButtonSizesComponent, + ButtonBadgeComponent, + ButtonBaseComponent, + ButtonDisabledComponent, + ButtonIconComponent, + ButtonLoadingComponent, + ButtonOutlinedComponent, + ButtonRoundedComponent, + ButtonSeverityComponent, + ButtonSizesComponent, + ButtonTextComponent + ] }) ], parameters: { @@ -276,15 +287,15 @@ export const Default: Story = { return { props: args, template }; }, args: { - label: 'Button', + label: 'Button' }, parameters: { docs: { description: { - story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', - }, - }, - }, + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.' + } + } + } }; export { Sizes, Text, Severity, Rounded, Outlined, Loading, Icon, Extra, Disabled, Base, Badge }; diff --git a/src/stories/components/card/examples/card-overlay.component.ts b/src/stories/components/card/examples/card-overlay.component.ts index 2b503d00..cd02e1c0 100644 --- a/src/stories/components/card/examples/card-overlay.component.ts +++ b/src/stories/components/card/examples/card-overlay.component.ts @@ -14,9 +14,9 @@ const template = `

Карточка с тенью.

- + - +
`; const styles = ''; diff --git a/src/stories/components/card/examples/card-without-header.component.ts b/src/stories/components/card/examples/card-without-header.component.ts index 82778595..8a9ad93c 100644 --- a/src/stories/components/card/examples/card-without-header.component.ts +++ b/src/stories/components/card/examples/card-without-header.component.ts @@ -11,9 +11,9 @@ const template = `

Карточка без изображения в шапке.

- + - +
`; const styles = ''; diff --git a/src/stories/components/card/examples/card-without-subtitle.component.ts b/src/stories/components/card/examples/card-without-subtitle.component.ts index e69116aa..09198187 100644 --- a/src/stories/components/card/examples/card-without-subtitle.component.ts +++ b/src/stories/components/card/examples/card-without-subtitle.component.ts @@ -14,9 +14,9 @@ const template = `

Карточка без подзаголовка.

- + - +
`; const styles = ''; diff --git a/src/stories/components/dialog/examples/dialog-default.component.ts b/src/stories/components/dialog/examples/dialog-default.component.ts index 013adfad..c85128c1 100644 --- a/src/stories/components/dialog/examples/dialog-default.component.ts +++ b/src/stories/components/dialog/examples/dialog-default.component.ts @@ -18,7 +18,7 @@ export const template = ` [footerTemplate]="footer" >

Заявка на доставку груза №CDEK-2025-00478312 готова к оформлению. Вес отправления: 3,5 кг, габариты: 40×30×20 см. Ориентировочный срок доставки — 3 рабочих дня.

-
+
`; diff --git a/src/stories/components/dialog/examples/dialog-large.component.ts b/src/stories/components/dialog/examples/dialog-large.component.ts index bd712044..ecee283c 100644 --- a/src/stories/components/dialog/examples/dialog-large.component.ts +++ b/src/stories/components/dialog/examples/dialog-large.component.ts @@ -19,7 +19,7 @@ export const template = ` [footerTemplate]="footer" >

Отправление CDEK-2025-00478312 передано курьеру для доставки до двери получателя. Последнее обновление: 09.04.2025, 14:35. Адрес доставки: г. Новосибирск, ул. Ленина, 42, кв. 8. Получатель: Иванов И.И., +7 913 000-00-00.

-
+
`; diff --git a/src/stories/components/dialog/examples/dialog-small.component.ts b/src/stories/components/dialog/examples/dialog-small.component.ts index ee677fdc..79257d6f 100644 --- a/src/stories/components/dialog/examples/dialog-small.component.ts +++ b/src/stories/components/dialog/examples/dialog-small.component.ts @@ -19,7 +19,7 @@ export const template = ` [footerTemplate]="footer" >

Отправление CDEK-2025-00478312 прибыло на сортировочный центр г. Новосибирск и готово к передаче курьеру.

-
+
`; diff --git a/src/stories/components/inputgroup/examples/inputgroup-addon-both.component.ts b/src/stories/components/inputgroup/examples/inputgroup-addon-both.component.ts index 0fe1a713..1ab9e802 100644 --- a/src/stories/components/inputgroup/examples/inputgroup-addon-both.component.ts +++ b/src/stories/components/inputgroup/examples/inputgroup-addon-both.component.ts @@ -1,17 +1,17 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { FormsModule } from '@angular/forms'; -import { InputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; -import { InputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; +import { ExtraInputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; const template = `
- - - - - + + + + +
`; const styles = ''; @@ -19,9 +19,9 @@ const styles = ''; @Component({ selector: 'app-inputgroup-addon-both', standalone: true, - imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + imports: [ExtraInputGroupComponent, ExtraInputGroupAddonComponent, ExtraInputTextComponent, FormsModule], template, - styles, + styles }) export class InputGroupAddonBothComponent { value = ''; @@ -39,18 +39,18 @@ export const AddonBoth: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { InputGroupComponent, InputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputGroupComponent, ExtraInputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-inputgroup-addon-both', standalone: true, - imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + imports: [ExtraInputGroupComponent, ExtraInputGroupAddonComponent, InputTextComponent, FormsModule], template: \` - - - - - + + + + + \`, }) export class InputGroupAddonBothComponent { diff --git a/src/stories/components/inputgroup/examples/inputgroup-addon-right.component.ts b/src/stories/components/inputgroup/examples/inputgroup-addon-right.component.ts index 1871478d..84098c30 100644 --- a/src/stories/components/inputgroup/examples/inputgroup-addon-right.component.ts +++ b/src/stories/components/inputgroup/examples/inputgroup-addon-right.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { FormsModule } from '@angular/forms'; -import { InputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; -import { InputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; +import { ExtraInputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; const template = `
- - - руб. - + + + руб. +
`; const styles = ''; @@ -18,9 +18,9 @@ const styles = ''; @Component({ selector: 'app-inputgroup-addon-right', standalone: true, - imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + imports: [ExtraInputGroupComponent, ExtraInputGroupAddonComponent, ExtraInputTextComponent, FormsModule], template, - styles, + styles }) export class InputGroupAddonRightComponent { value = ''; @@ -38,17 +38,17 @@ export const AddonRight: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { InputGroupComponent, InputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputGroupComponent, ExtraInputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-inputgroup-addon-right', standalone: true, - imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + imports: [ExtraInputGroupComponent, ExtraInputGroupAddonComponent, InputTextComponent, FormsModule], template: \` - - - руб. - + + + руб. + \`, }) export class InputGroupAddonRightComponent { diff --git a/src/stories/components/inputgroup/examples/inputgroup-disabled.component.ts b/src/stories/components/inputgroup/examples/inputgroup-disabled.component.ts index a3a733ce..ce45d214 100644 --- a/src/stories/components/inputgroup/examples/inputgroup-disabled.component.ts +++ b/src/stories/components/inputgroup/examples/inputgroup-disabled.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { FormsModule } from '@angular/forms'; -import { InputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; -import { InputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; +import { ExtraInputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; const template = `
- - - - + + + +
`; const styles = ''; @@ -18,9 +18,9 @@ const styles = ''; @Component({ selector: 'app-inputgroup-disabled', standalone: true, - imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + imports: [ExtraInputGroupComponent, ExtraInputGroupAddonComponent, ExtraInputTextComponent, FormsModule], template, - styles, + styles }) export class InputGroupDisabledComponent { value = ''; @@ -38,17 +38,17 @@ export const Disabled: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { InputGroupComponent, InputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputGroupComponent, ExtraInputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-inputgroup-disabled', standalone: true, - imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + imports: [ExtraInputGroupComponent, ExtraInputGroupAddonComponent, InputTextComponent, FormsModule], template: \` - - - - + + + + \`, }) export class InputGroupDisabledComponent { diff --git a/src/stories/components/inputgroup/examples/inputgroup-with-text.component.ts b/src/stories/components/inputgroup/examples/inputgroup-with-text.component.ts index 3af11c41..fbb887de 100644 --- a/src/stories/components/inputgroup/examples/inputgroup-with-text.component.ts +++ b/src/stories/components/inputgroup/examples/inputgroup-with-text.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { FormsModule } from '@angular/forms'; -import { InputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; -import { InputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; +import { ExtraInputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; const template = `
- - @ - - + + @ + +
`; const styles = ''; @@ -18,9 +18,9 @@ const styles = ''; @Component({ selector: 'app-inputgroup-with-text', standalone: true, - imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + imports: [ExtraInputGroupComponent, ExtraInputGroupAddonComponent, ExtraInputTextComponent, FormsModule], template, - styles, + styles }) export class InputGroupWithTextComponent { value = ''; @@ -38,17 +38,17 @@ export const WithText: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { InputGroupComponent, InputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputGroupComponent, ExtraInputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-inputgroup-with-text', standalone: true, - imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + imports: [ExtraInputGroupComponent, ExtraInputGroupAddonComponent, InputTextComponent, FormsModule], template: \` - - @ - - + + @ + + \`, }) export class InputGroupWithTextComponent { diff --git a/src/stories/components/inputgroup/examples/inputgroup-xlarge.component.ts b/src/stories/components/inputgroup/examples/inputgroup-xlarge.component.ts index 47e61b57..0eef686a 100644 --- a/src/stories/components/inputgroup/examples/inputgroup-xlarge.component.ts +++ b/src/stories/components/inputgroup/examples/inputgroup-xlarge.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { FormsModule } from '@angular/forms'; -import { InputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; -import { InputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputGroupComponent } from '../../../../lib/components/inputgroup/input-group.component'; +import { ExtraInputGroupAddonComponent } from '../../../../lib/components/inputgroup/input-group-addon.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; const template = `
- - - - + + + +
`; const styles = ''; @@ -18,9 +18,9 @@ const styles = ''; @Component({ selector: 'app-inputgroup-xlarge', standalone: true, - imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + imports: [ExtraInputGroupComponent, ExtraInputGroupAddonComponent, ExtraInputTextComponent, FormsModule], template, - styles, + styles }) export class InputGroupXlargeComponent { value = ''; @@ -38,17 +38,17 @@ export const Sizes: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { InputGroupComponent, InputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputGroupComponent, ExtraInputGroupAddonComponent, InputTextComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-inputgroup-xlarge', standalone: true, - imports: [InputGroupComponent, InputGroupAddonComponent, InputTextComponent, FormsModule], + imports: [ExtraInputGroupComponent, ExtraInputGroupAddonComponent, InputTextComponent, FormsModule], template: \` - - - - + + + + \`, }) export class InputGroupXlargeComponent { diff --git a/src/stories/components/inputgroup/inputgroup.stories.ts b/src/stories/components/inputgroup/inputgroup.stories.ts index 888a7ce7..5ba75c71 100644 --- a/src/stories/components/inputgroup/inputgroup.stories.ts +++ b/src/stories/components/inputgroup/inputgroup.stories.ts @@ -1,32 +1,32 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormsModule } from '@angular/forms'; -import { InputGroupComponent } from '../../../lib/components/inputgroup/input-group.component'; -import { InputGroupAddonComponent } from '../../../lib/components/inputgroup/input-group-addon.component'; -import { InputTextComponent } from '../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputGroupComponent } from '../../../lib/components/inputgroup/input-group.component'; +import { ExtraInputGroupAddonComponent } from '../../../lib/components/inputgroup/input-group-addon.component'; +import { ExtraInputTextComponent } from '../../../lib/components/inputtext/inputtext.component'; import { InputGroupWithTextComponent, WithText } from './examples/inputgroup-with-text.component'; import { InputGroupDisabledComponent, Disabled } from './examples/inputgroup-disabled.component'; import { InputGroupXlargeComponent, Sizes } from './examples/inputgroup-xlarge.component'; import { InputGroupAddonRightComponent, AddonRight } from './examples/inputgroup-addon-right.component'; import { InputGroupAddonBothComponent, AddonBoth } from './examples/inputgroup-addon-both.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Form/InputGroup', - component: InputGroupComponent, + component: ExtraInputGroupComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - InputGroupComponent, - InputGroupAddonComponent, - InputTextComponent, + ExtraInputGroupComponent, + ExtraInputGroupAddonComponent, + ExtraInputTextComponent, FormsModule, InputGroupWithTextComponent, InputGroupDisabledComponent, InputGroupXlargeComponent, InputGroupAddonRightComponent, - InputGroupAddonBothComponent, - ], - }), + InputGroupAddonBothComponent + ] + }) ], parameters: { docs: { @@ -34,11 +34,11 @@ const meta: Meta = { component: `Группа полей ввода для объединения с аддонами (иконками или текстом). \`\`\`typescript -import { InputGroupComponent, InputGroupAddonComponent } from '@cdek-it/angular-ui-kit'; -\`\`\``, - }, +import { ExtraInputGroupComponent, ExtraInputGroupAddonComponent } from '@cdek-it/angular-ui-kit'; +\`\`\`` + } }, - designTokens: { prefix: '--p-inputgroup' }, + designTokens: { prefix: '--p-inputgroup' } }, argTypes: { size: { @@ -48,17 +48,17 @@ import { InputGroupComponent, InputGroupAddonComponent } from '@cdek-it/angular- table: { category: 'Props', defaultValue: { summary: "'base'" }, - type: { summary: "'small' | 'base' | 'large' | 'xlarge'" }, - }, - }, + type: { summary: "'small' | 'base' | 'large' | 'xlarge'" } + } + } }, args: { - size: 'base', - }, + size: 'base' + } }; export default meta; -type Story = StoryObj; +type Story = StoryObj; export const Default: Story = { name: 'Default', @@ -67,16 +67,16 @@ export const Default: Story = { if (args.size && args.size !== 'base') groupParts.push(`size="${args.size}"`); const groupOpen = groupParts.length - ? `` - : ``; + ? `` + : ``; const inputSize = args.size && args.size !== 'base' ? ` size="${args.size}"` : ''; const template = ` ${groupOpen} - - -`; + + +`; return { props: { ...args, value: '' }, template }; }, diff --git a/src/stories/components/inputmask/examples/inputmask-disabled.component.ts b/src/stories/components/inputmask/examples/inputmask-disabled.component.ts index 9667d0ca..22a08a8b 100644 --- a/src/stories/components/inputmask/examples/inputmask-disabled.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-disabled.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; +import { ExtraInputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; export const Disabled: StoryObj = { name: 'Disabled', @@ -8,14 +8,14 @@ export const Disabled: StoryObj = { const control = new FormControl({ value: '12-34-56', disabled: true }); return { props: { ...args, control }, - template: ``, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputMaskComponent, ReactiveFormsModule], + imports: [ExtraInputMaskComponent, ReactiveFormsModule], }, }), ], @@ -30,12 +30,12 @@ export const Disabled: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputMaskComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputMaskComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputMaskComponent, ReactiveFormsModule], + template: \`\`, }) export class DisabledExample { control = new FormControl({ value: '12-34-56', disabled: true }); diff --git a/src/stories/components/inputmask/examples/inputmask-invalid.component.ts b/src/stories/components/inputmask/examples/inputmask-invalid.component.ts index 699a89bb..c183d3b8 100644 --- a/src/stories/components/inputmask/examples/inputmask-invalid.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-invalid.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; +import { ExtraInputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; export const Invalid: StoryObj = { name: 'Invalid', @@ -8,14 +8,14 @@ export const Invalid: StoryObj = { const control = new FormControl('', Validators.required); return { props: { ...args, control }, - template: ``, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputMaskComponent, ReactiveFormsModule], + imports: [ExtraInputMaskComponent, ReactiveFormsModule], }, }), ], @@ -30,12 +30,12 @@ export const Invalid: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; -import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputMaskComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputMaskComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputMaskComponent, ReactiveFormsModule], + template: \`\`, }) export class InvalidExample { control = new FormControl('', Validators.required); diff --git a/src/stories/components/inputmask/examples/inputmask-readonly.component.ts b/src/stories/components/inputmask/examples/inputmask-readonly.component.ts index b800f435..f3d12028 100644 --- a/src/stories/components/inputmask/examples/inputmask-readonly.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-readonly.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; +import { ExtraInputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; export const Readonly: StoryObj = { name: 'Readonly', @@ -8,14 +8,14 @@ export const Readonly: StoryObj = { const control = new FormControl('12-34-56'); return { props: { ...args, control }, - template: ``, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputMaskComponent, ReactiveFormsModule], + imports: [ExtraInputMaskComponent, ReactiveFormsModule], }, }), ], @@ -30,12 +30,12 @@ export const Readonly: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputMaskComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputMaskComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputMaskComponent, ReactiveFormsModule], + template: \`\`, }) export class ReadonlyExample { control = new FormControl('12-34-56'); diff --git a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts index 021d25e5..470d8bc0 100644 --- a/src/stories/components/inputmask/examples/inputmask-sizes.component.ts +++ b/src/stories/components/inputmask/examples/inputmask-sizes.component.ts @@ -1,16 +1,16 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; +import { ExtraInputMaskComponent } from '../../../../lib/components/inputmask/inputmask.component'; -type Story = StoryObj; +type Story = StoryObj; export const Sizes: Story = { name: 'Sizes', render: (args) => ({ props: { ...args, control: new FormControl('') }, template: ` - + > `, }), args: { @@ -38,12 +38,12 @@ export const Sizes: Story = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputMaskComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputMaskComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputMaskComponent, ReactiveFormsModule], + template: \`\`, }) export class SizesExample { control = new FormControl(''); diff --git a/src/stories/components/inputmask/inputmask.stories.ts b/src/stories/components/inputmask/inputmask.stories.ts index 924ccb50..4fcd0308 100644 --- a/src/stories/components/inputmask/inputmask.stories.ts +++ b/src/stories/components/inputmask/inputmask.stories.ts @@ -1,22 +1,22 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { InputMaskComponent } from '../../../lib/components/inputmask/inputmask.component'; +import { ExtraInputMaskComponent } from '../../../lib/components/inputmask/inputmask.component'; import { InputMaskFloatLabelComponent, FloatLabelStory } from './examples/inputmask-float-label.component'; import { Sizes } from './examples/inputmask-sizes.component'; import { Disabled } from './examples/inputmask-disabled.component'; import { Readonly } from './examples/inputmask-readonly.component'; import { Invalid } from './examples/inputmask-invalid.component'; -type InputMaskArgs = InputMaskComponent; +type InputMaskArgs = ExtraInputMaskComponent; const meta: Meta = { title: 'Components/Form/InputMask', - component: InputMaskComponent, + component: ExtraInputMaskComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - InputMaskComponent, + ExtraInputMaskComponent, FormsModule, ReactiveFormsModule, InputMaskFloatLabelComponent, @@ -30,7 +30,7 @@ const meta: Meta = { component: `Компонент текстового ввода по маске. Используется для ввода данных в определённом формате: дата, телефон, серийный номер и т.д. \`\`\`typescript -import { InputMaskComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputMaskComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -215,7 +215,7 @@ export const Default: Story = { if (args.fluid) parts.push(`[fluid]="true"`); parts.push(`[formControl]="control"`); - const template = ``; + const template = ``; return { props: { ...args, control: new FormControl('') }, template }; }, diff --git a/src/stories/components/inputnumber/examples/inputnumber-buttons.component.ts b/src/stories/components/inputnumber/examples/inputnumber-buttons.component.ts index 9f774228..74b29b56 100644 --- a/src/stories/components/inputnumber/examples/inputnumber-buttons.component.ts +++ b/src/stories/components/inputnumber/examples/inputnumber-buttons.component.ts @@ -1,8 +1,8 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputNumberComponent } from '../../../../lib/components/inputnumber/inputnumber.component'; +import { ExtraInputNumberComponent } from '../../../../lib/components/inputnumber/inputnumber.component'; -type Story = StoryObj; +type Story = StoryObj; export const Buttons: Story = { name: 'Buttons', @@ -11,11 +11,11 @@ export const Buttons: Story = { return { props: { control }, template: ` - + > `, }; }, @@ -23,7 +23,7 @@ export const Buttons: Story = { (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputNumberComponent, ReactiveFormsModule], + imports: [ExtraInputNumberComponent, ReactiveFormsModule], }, }), ], @@ -38,12 +38,12 @@ export const Buttons: Story = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputNumberComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputNumberComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputNumberComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputNumberComponent, ReactiveFormsModule], + template: \`\`, }) export class ButtonsExample { control = new FormControl(null); diff --git a/src/stories/components/inputnumber/examples/inputnumber-currency.component.ts b/src/stories/components/inputnumber/examples/inputnumber-currency.component.ts index 6bb38c49..dad66ae0 100644 --- a/src/stories/components/inputnumber/examples/inputnumber-currency.component.ts +++ b/src/stories/components/inputnumber/examples/inputnumber-currency.component.ts @@ -1,8 +1,8 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputNumberComponent } from '../../../../lib/components/inputnumber/inputnumber.component'; +import { ExtraInputNumberComponent } from '../../../../lib/components/inputnumber/inputnumber.component'; -type Story = StoryObj; +type Story = StoryObj; export const Currency: Story = { name: 'Currency', @@ -11,11 +11,11 @@ export const Currency: Story = { return { props: { control }, template: ` - + > `, }; }, @@ -23,7 +23,7 @@ export const Currency: Story = { (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputNumberComponent, ReactiveFormsModule], + imports: [ExtraInputNumberComponent, ReactiveFormsModule], }, }), ], @@ -38,12 +38,12 @@ export const Currency: Story = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputNumberComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputNumberComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputNumberComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputNumberComponent, ReactiveFormsModule], + template: \`\`, }) export class CurrencyExample { control = new FormControl(null); diff --git a/src/stories/components/inputnumber/examples/inputnumber-disabled.component.ts b/src/stories/components/inputnumber/examples/inputnumber-disabled.component.ts index a2d3f495..3ffa1903 100644 --- a/src/stories/components/inputnumber/examples/inputnumber-disabled.component.ts +++ b/src/stories/components/inputnumber/examples/inputnumber-disabled.component.ts @@ -1,8 +1,8 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputNumberComponent } from '../../../../lib/components/inputnumber/inputnumber.component'; +import { ExtraInputNumberComponent } from '../../../../lib/components/inputnumber/inputnumber.component'; -type Story = StoryObj; +type Story = StoryObj; export const Disabled: Story = { name: 'Disabled', @@ -11,11 +11,11 @@ export const Disabled: Story = { return { props: { control }, template: ` - + > `, }; }, @@ -23,7 +23,7 @@ export const Disabled: Story = { (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputNumberComponent, ReactiveFormsModule], + imports: [ExtraInputNumberComponent, ReactiveFormsModule], }, }), ], @@ -38,12 +38,12 @@ export const Disabled: Story = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputNumberComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputNumberComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputNumberComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputNumberComponent, ReactiveFormsModule], + template: \`\`, }) export class DisabledExample { control = new FormControl({ value: 42, disabled: true }); diff --git a/src/stories/components/inputnumber/inputnumber.stories.ts b/src/stories/components/inputnumber/inputnumber.stories.ts index 1f2d9d20..9c171e80 100644 --- a/src/stories/components/inputnumber/inputnumber.stories.ts +++ b/src/stories/components/inputnumber/inputnumber.stories.ts @@ -1,21 +1,21 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { InputNumberComponent } from '../../../lib/components/inputnumber/inputnumber.component'; +import { ExtraInputNumberComponent } from '../../../lib/components/inputnumber/inputnumber.component'; import { InputNumberFloatLabelComponent, FloatLabelStory } from './examples/inputnumber-float-label.component'; import { Currency } from './examples/inputnumber-currency.component'; import { Buttons } from './examples/inputnumber-buttons.component'; import { Disabled } from './examples/inputnumber-disabled.component'; -type InputNumberArgs = InputNumberComponent & { disabled: boolean; invalid: boolean }; +type InputNumberArgs = ExtraInputNumberComponent & { disabled: boolean; invalid: boolean }; const meta: Meta = { title: 'Components/Form/InputNumber', - component: InputNumberComponent, + component: ExtraInputNumberComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - InputNumberComponent, + ExtraInputNumberComponent, ReactiveFormsModule, InputNumberFloatLabelComponent, ], @@ -28,7 +28,7 @@ const meta: Meta = { component: `Числовое поле ввода с поддержкой форматирования, валюты и кнопок увеличения/уменьшения. \`\`\`typescript -import { InputNumberComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputNumberComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -271,7 +271,7 @@ export const Default: Story = { const control = new FormControl({ value: null, disabled: args.disabled }, validators); - const template = ``; + const template = ``; return { props: { ...args, control }, template }; }, diff --git a/src/stories/components/inputotp/examples/inputotp-disabled.component.ts b/src/stories/components/inputotp/examples/inputotp-disabled.component.ts index 4afef35f..d0dcffa5 100644 --- a/src/stories/components/inputotp/examples/inputotp-disabled.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-disabled.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; +import { ExtraInputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; export const Disabled: StoryObj = { name: 'Disabled', @@ -8,14 +8,14 @@ export const Disabled: StoryObj = { const control = new FormControl({ value: '1234', disabled: true }); return { props: { ...args, control }, - template: ``, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputOtpComponent, ReactiveFormsModule], + imports: [ExtraInputOtpComponent, ReactiveFormsModule], }, }), ], @@ -30,12 +30,12 @@ export const Disabled: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputOtpComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputOtpComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputOtpComponent, ReactiveFormsModule], + template: \`\`, }) export class DisabledExample { control = new FormControl({ value: '1234', disabled: true }); diff --git a/src/stories/components/inputotp/examples/inputotp-integeronly.component.ts b/src/stories/components/inputotp/examples/inputotp-integeronly.component.ts index 513d5377..462dc73c 100644 --- a/src/stories/components/inputotp/examples/inputotp-integeronly.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-integeronly.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; +import { ExtraInputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; export const IntegerOnly: StoryObj = { name: 'IntegerOnly', @@ -8,14 +8,14 @@ export const IntegerOnly: StoryObj = { const control = new FormControl(null); return { props: { ...args, control }, - template: ``, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputOtpComponent, ReactiveFormsModule], + imports: [ExtraInputOtpComponent, ReactiveFormsModule], }, }), ], @@ -30,12 +30,12 @@ export const IntegerOnly: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputOtpComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputOtpComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputOtpComponent, ReactiveFormsModule], + template: \`\`, }) export class IntegerOnlyExample { control = new FormControl(null); diff --git a/src/stories/components/inputotp/examples/inputotp-invalid.component.ts b/src/stories/components/inputotp/examples/inputotp-invalid.component.ts index 0b975f44..1d0e89ca 100644 --- a/src/stories/components/inputotp/examples/inputotp-invalid.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-invalid.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; +import { ExtraInputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; export const Invalid: StoryObj = { name: 'Invalid', @@ -8,14 +8,14 @@ export const Invalid: StoryObj = { const control = new FormControl('', Validators.required); return { props: { ...args, control }, - template: ``, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputOtpComponent, ReactiveFormsModule], + imports: [ExtraInputOtpComponent, ReactiveFormsModule], }, }), ], @@ -30,12 +30,12 @@ export const Invalid: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; -import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputOtpComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputOtpComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputOtpComponent, ReactiveFormsModule], + template: \`\`, }) export class InvalidExample { control = new FormControl('', Validators.required); diff --git a/src/stories/components/inputotp/examples/inputotp-mask.component.ts b/src/stories/components/inputotp/examples/inputotp-mask.component.ts index 4e4fd330..3f3a5f83 100644 --- a/src/stories/components/inputotp/examples/inputotp-mask.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-mask.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; +import { ExtraInputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; export const Mask: StoryObj = { name: 'Mask', @@ -8,14 +8,14 @@ export const Mask: StoryObj = { const control = new FormControl('1234'); return { props: { ...args, control }, - template: ``, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputOtpComponent, ReactiveFormsModule], + imports: [ExtraInputOtpComponent, ReactiveFormsModule], }, }), ], @@ -30,12 +30,12 @@ export const Mask: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputOtpComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputOtpComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputOtpComponent, ReactiveFormsModule], + template: \`\`, }) export class MaskExample { control = new FormControl('1234'); diff --git a/src/stories/components/inputotp/examples/inputotp-readonly.component.ts b/src/stories/components/inputotp/examples/inputotp-readonly.component.ts index 385ef945..7fea5939 100644 --- a/src/stories/components/inputotp/examples/inputotp-readonly.component.ts +++ b/src/stories/components/inputotp/examples/inputotp-readonly.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; +import { ExtraInputOtpComponent } from '../../../../lib/components/inputotp/inputotp.component'; export const Readonly: StoryObj = { name: 'Readonly', @@ -8,14 +8,14 @@ export const Readonly: StoryObj = { const control = new FormControl('1234'); return { props: { ...args, control }, - template: ``, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [InputOtpComponent, ReactiveFormsModule], + imports: [ExtraInputOtpComponent, ReactiveFormsModule], }, }), ], @@ -30,12 +30,12 @@ export const Readonly: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputOtpComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [InputOtpComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraInputOtpComponent, ReactiveFormsModule], + template: \`\`, }) export class ReadonlyExample { control = new FormControl('1234'); diff --git a/src/stories/components/inputotp/inputotp.stories.ts b/src/stories/components/inputotp/inputotp.stories.ts index 4e75a297..3d74f486 100644 --- a/src/stories/components/inputotp/inputotp.stories.ts +++ b/src/stories/components/inputotp/inputotp.stories.ts @@ -1,22 +1,22 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { InputOtpComponent } from '../../../lib/components/inputotp/inputotp.component'; +import { ExtraInputOtpComponent } from '../../../lib/components/inputotp/inputotp.component'; import { Disabled } from './examples/inputotp-disabled.component'; import { Invalid } from './examples/inputotp-invalid.component'; import { Mask } from './examples/inputotp-mask.component'; import { Readonly } from './examples/inputotp-readonly.component'; import { IntegerOnly } from './examples/inputotp-integeronly.component'; -type InputOtpArgs = InputOtpComponent; +type InputOtpArgs = ExtraInputOtpComponent; const meta: Meta = { title: 'Components/Form/InputOtp', - component: InputOtpComponent, + component: ExtraInputOtpComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - InputOtpComponent, + ExtraInputOtpComponent, ReactiveFormsModule, ], }), @@ -28,7 +28,7 @@ const meta: Meta = { component: `Компонент для ввода одноразовых паролей (OTP). \`\`\`typescript -import { InputOtpComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraInputOtpComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -165,7 +165,7 @@ export const Default: Story = { if (args.tabindex != null) parts.push(`[tabindex]="${args.tabindex}"`); parts.push(`[formControl]="control"`); - const template = ``; + const template = ``; return { props: { ...args, control: new FormControl('') }, template }; }, diff --git a/src/stories/components/inputtext/examples/inputtext-clear.component.ts b/src/stories/components/inputtext/examples/inputtext-clear.component.ts index 59aea394..42937835 100644 --- a/src/stories/components/inputtext/examples/inputtext-clear.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-clear.component.ts @@ -1,13 +1,13 @@ import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; @Component({ selector: 'app-inputtext-clear', standalone: true, - imports: [InputTextComponent, ReactiveFormsModule], - template: ``, + imports: [ExtraInputTextComponent, ReactiveFormsModule], + template: `` }) export class InputTextClearComponent { control = new FormControl(''); @@ -42,7 +42,7 @@ import { InputTextComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, imports: [InputTextComponent, ReactiveFormsModule], - template: \`\`, + template: \`\`, }) export class ClearButtonExample { control = new FormControl(''); diff --git a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts index a336125c..3be8f15c 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label-invalid.component.ts @@ -1,23 +1,27 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; -import { NgIf } from '@angular/common'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { FloatLabel } from 'primeng/floatlabel'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; @Component({ selector: 'app-inputtext-float-label-invalid', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [InputTextComponent, FloatLabel, ReactiveFormsModule, NgIf], + imports: [ExtraInputTextComponent, FloatLabel, ReactiveFormsModule], template: ` -
- - - - -
-`, +
+ + + + +
+ ` }) export class InputTextFloatLabelInvalidComponent { control = new FormControl('', Validators.required); @@ -60,7 +64,7 @@ import { FloatLabel } from 'primeng/floatlabel'; imports: [InputTextComponent, FloatLabel, ReactiveFormsModule], template: \` - + \`, diff --git a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts index ef57c6da..717eff65 100644 --- a/src/stories/components/inputtext/examples/inputtext-float-label.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-float-label.component.ts @@ -1,22 +1,26 @@ import { Component, Input } from '@angular/core'; -import { NgIf } from '@angular/common'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { FloatLabel } from 'primeng/floatlabel'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; @Component({ selector: 'app-inputtext-float-label', standalone: true, - imports: [InputTextComponent, FloatLabel, ReactiveFormsModule, NgIf], + imports: [ExtraInputTextComponent, FloatLabel, ReactiveFormsModule], template: ` -
- - - - -
-`, +
+ + + + +
+ ` }) export class InputTextFloatLabelComponent { control = new FormControl(''); @@ -60,7 +64,7 @@ import { FloatLabel } from 'primeng/floatlabel'; imports: [InputTextComponent, FloatLabel, ReactiveFormsModule], template: \` - + \`, diff --git a/src/stories/components/inputtext/examples/inputtext-readonly.component.ts b/src/stories/components/inputtext/examples/inputtext-readonly.component.ts index 2fbd52db..37a12849 100644 --- a/src/stories/components/inputtext/examples/inputtext-readonly.component.ts +++ b/src/stories/components/inputtext/examples/inputtext-readonly.component.ts @@ -1,13 +1,13 @@ import { Component } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { InputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputTextComponent } from '../../../../lib/components/inputtext/inputtext.component'; @Component({ selector: 'app-inputtext-readonly', standalone: true, - imports: [InputTextComponent, ReactiveFormsModule], - template: ``, + imports: [ExtraInputTextComponent, ReactiveFormsModule, FormsModule], + template: `` }) export class InputTextReadonlyComponent { control = new FormControl(''); diff --git a/src/stories/components/inputtext/inputtext.stories.ts b/src/stories/components/inputtext/inputtext.stories.ts index bc0c3b92..5b459de9 100644 --- a/src/stories/components/inputtext/inputtext.stories.ts +++ b/src/stories/components/inputtext/inputtext.stories.ts @@ -1,6 +1,6 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { InputTextComponent } from '../../../lib/components/inputtext/inputtext.component'; +import { ExtraInputTextComponent } from '../../../lib/components/inputtext/inputtext.component'; import { InputTextClearComponent, ClearButton } from './examples/inputtext-clear.component'; import { InputTextFloatLabelComponent, FloatLabelStory } from './examples/inputtext-float-label.component'; import { InputTextFloatLabelInvalidComponent, FloatLabelInvalid } from './examples/inputtext-float-label-invalid.component'; @@ -8,16 +8,16 @@ import { Disabled } from './examples/inputtext-disabled.component'; import { InputTextReadonlyComponent, Readonly } from './examples/inputtext-readonly.component'; import { Invalid } from './examples/inputtext-invalid.component'; -type InputTextArgs = InputTextComponent & { disabled: boolean; invalid: boolean }; +type InputTextArgs = ExtraInputTextComponent & { disabled: boolean; invalid: boolean }; const meta: Meta = { title: 'Components/Form/InputText', - component: InputTextComponent, + component: ExtraInputTextComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - InputTextComponent, + ExtraInputTextComponent, ReactiveFormsModule, InputTextFloatLabelComponent, InputTextFloatLabelInvalidComponent, @@ -136,19 +136,19 @@ type Story = StoryObj; // ── Default ────────────────────────────────────────────────────────────────── export const Default: Story = { name: 'Default', - render: (args) => { + render: (args: Record) => { const parts: string[] = []; - if (args.placeholder) parts.push(`placeholder="${args.placeholder}"`); - if (args.size && args.size !== 'base') parts.push(`size="${args.size}"`); - if (args.readonly) parts.push(`[readonly]="true"`); - if (args.showClear) parts.push(`[showClear]="true"`); - if (args.fluid) parts.push(`[fluid]="true"`); + if (args['placeholder']) parts.push(`placeholder="${args['placeholder']}"`); + if (args['size'] && args['size'] !== 'base') parts.push(`size="${args['size']}"`); + if (args['readonly']) parts.push(`[readonly]="true"`); + if (args['showClear']) parts.push(`[showClear]="true"`); + if (args['fluid']) parts.push(`[fluid]="true"`); const validators = []; - if (args.invalid) validators.push(Validators.required); + if (args['invalid']) validators.push(Validators.required); - const control = new FormControl({ value: '', disabled: args.disabled }, validators); + const control = new FormControl({ value: '', disabled: args['disabled'] as boolean }, validators); const template = ``; diff --git a/src/stories/components/message/examples/message-severities.component.ts b/src/stories/components/message/examples/message-severities.component.ts index 9a42e4a8..ffa64456 100644 --- a/src/stories/components/message/examples/message-severities.component.ts +++ b/src/stories/components/message/examples/message-severities.component.ts @@ -1,20 +1,20 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { MessageComponent } from '../../../../lib/components/message/message.component'; +import { ExtraMessageComponent } from '../../../../lib/components/message/message.component'; const template = `
- - - - + + + +
`; @Component({ selector: 'app-message-severities', standalone: true, - imports: [MessageComponent], + imports: [ExtraMessageComponent], template, }) export class MessageSeveritiesComponent {} @@ -30,10 +30,10 @@ export const Severities: StoryObj = { source: { language: 'html', code: ` - - - - + + + + `, }, }, diff --git a/src/stories/components/message/examples/message-with-close-button.component.ts b/src/stories/components/message/examples/message-with-close-button.component.ts index a1195a18..0e59bdf1 100644 --- a/src/stories/components/message/examples/message-with-close-button.component.ts +++ b/src/stories/components/message/examples/message-with-close-button.component.ts @@ -1,20 +1,20 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { MessageComponent } from '../../../../lib/components/message/message.component'; +import { ExtraMessageComponent } from '../../../../lib/components/message/message.component'; const template = `
- - - - + + + +
`; @Component({ selector: 'app-message-with-close-button', standalone: true, - imports: [MessageComponent], + imports: [ExtraMessageComponent], template, }) export class MessageWithCloseButtonComponent {} @@ -29,7 +29,7 @@ export const WithCloseButton: StoryObj = { description: { story: 'Сообщения с кнопкой закрытия.' }, source: { language: 'html', - code: ``, + code: ``, }, }, }, diff --git a/src/stories/components/message/examples/message-with-content.component.ts b/src/stories/components/message/examples/message-with-content.component.ts index 5e42c03f..c5889796 100644 --- a/src/stories/components/message/examples/message-with-content.component.ts +++ b/src/stories/components/message/examples/message-with-content.component.ts @@ -1,10 +1,10 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { MessageComponent } from '../../../../lib/components/message/message.component'; +import { ExtraMessageComponent } from '../../../../lib/components/message/message.component'; const template = `
- +
CONTENT
@@ -12,8 +12,8 @@ const template = `
Cell 1
Cell 2
- - + +
CONTENT
@@ -21,8 +21,8 @@ const template = `
Cell 1
Cell 2
- - + +
CONTENT
@@ -30,8 +30,8 @@ const template = `
Cell 1
Cell 2
- - + +
CONTENT
@@ -39,14 +39,14 @@ const template = `
Cell 1
Cell 2
- +
`; @Component({ selector: 'app-message-with-content', standalone: true, - imports: [MessageComponent], + imports: [ExtraMessageComponent], template, }) export class MessageWithContentComponent {} @@ -62,7 +62,7 @@ export const WithContent: StoryObj = { source: { language: 'html', code: ` - +
CONTENT
@@ -70,7 +70,7 @@ export const WithContent: StoryObj = {
Cell 1
Cell 2
- + `, }, }, diff --git a/src/stories/components/message/message.stories.ts b/src/stories/components/message/message.stories.ts index 608d38f0..a31111cd 100644 --- a/src/stories/components/message/message.stories.ts +++ b/src/stories/components/message/message.stories.ts @@ -1,19 +1,19 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { MessageComponent } from '../../../lib/components/message/message.component'; +import { ExtraMessageComponent } from '../../../lib/components/message/message.component'; import { MessageSeveritiesComponent, Severities } from './examples/message-severities.component'; import { MessageWithCloseButtonComponent, WithCloseButton } from './examples/message-with-close-button.component'; import { MessageWithContentComponent, WithContent } from './examples/message-with-content.component'; -type MessageArgs = MessageComponent; +type MessageArgs = ExtraMessageComponent; const meta: Meta = { title: 'Components/Feedback/Message', - component: MessageComponent, + component: ExtraMessageComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - MessageComponent, + ExtraMessageComponent, MessageSeveritiesComponent, MessageWithCloseButtonComponent, MessageWithContentComponent, @@ -27,7 +27,7 @@ const meta: Meta = { component: `Компонент для отображения встроенных уведомлений с различными уровнями важности. \`\`\`typescript -import { MessageComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraMessageComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -109,7 +109,7 @@ export const Default: Story = { if (args.closable) parts.push(`[closable]="true"`); if (args.life) parts.push(`[life]="${args.life}"`); - const template = ``; + const template = ``; return { props: args, template }; }, parameters: { diff --git a/src/stories/components/paginator/examples/paginator-current-page-report.component.ts b/src/stories/components/paginator/examples/paginator-current-page-report.component.ts index 753c73f1..ad370181 100644 --- a/src/stories/components/paginator/examples/paginator-current-page-report.component.ts +++ b/src/stories/components/paginator/examples/paginator-current-page-report.component.ts @@ -1,23 +1,23 @@ import { Component } from '@angular/core'; -import { PaginatorComponent } from '../../../../lib/components/paginator/paginator.component'; +import { ExtraPaginatorComponent } from '../../../../lib/components/paginator/paginator.component'; import type { PaginatorState } from 'primeng/types/paginator'; const template = ` - +> `; const styles = ''; @Component({ selector: 'app-paginator-current-page-report', standalone: true, - imports: [PaginatorComponent], + imports: [ExtraPaginatorComponent], template, styles, }) @@ -44,22 +44,22 @@ export const CurrentPageReport = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { PaginatorComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraPaginatorComponent } from '@cdek-it/angular-ui-kit'; import type { PaginatorState } from 'primeng/types/paginator'; @Component({ selector: 'app-paginator-current-page-report', standalone: true, - imports: [PaginatorComponent], + imports: [ExtraPaginatorComponent], template: \` - + > \`, }) export class PaginatorCurrentPageReportComponent { diff --git a/src/stories/components/paginator/examples/paginator-rows-per-page.component.ts b/src/stories/components/paginator/examples/paginator-rows-per-page.component.ts index 99daf055..1c2792fd 100644 --- a/src/stories/components/paginator/examples/paginator-rows-per-page.component.ts +++ b/src/stories/components/paginator/examples/paginator-rows-per-page.component.ts @@ -1,23 +1,23 @@ import { Component } from '@angular/core'; -import { PaginatorComponent } from '../../../../lib/components/paginator/paginator.component'; +import { ExtraPaginatorComponent } from '../../../../lib/components/paginator/paginator.component'; import type { PaginatorState } from 'primeng/types/paginator'; const template = ` - +> `; const styles = ''; @Component({ selector: 'app-paginator-rows-per-page', standalone: true, - imports: [PaginatorComponent], + imports: [ExtraPaginatorComponent], template, styles, }) @@ -44,22 +44,22 @@ export const RowsPerPage = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { PaginatorComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraPaginatorComponent } from '@cdek-it/angular-ui-kit'; import type { PaginatorState } from 'primeng/types/paginator'; @Component({ selector: 'app-paginator-rows-per-page', standalone: true, - imports: [PaginatorComponent], + imports: [ExtraPaginatorComponent], template: \` - + > \`, }) export class PaginatorRowsPerPageComponent { diff --git a/src/stories/components/paginator/paginator.stories.ts b/src/stories/components/paginator/paginator.stories.ts index 6fdfdfcd..22159d45 100644 --- a/src/stories/components/paginator/paginator.stories.ts +++ b/src/stories/components/paginator/paginator.stories.ts @@ -1,21 +1,21 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { PaginatorComponent } from '../../../lib/components/paginator/paginator.component'; +import { ExtraPaginatorComponent } from '../../../lib/components/paginator/paginator.component'; import { PaginatorCurrentPageReportComponent, CurrentPageReport as CurrentPageReportStory } from './examples/paginator-current-page-report.component'; import { PaginatorRowsPerPageComponent, RowsPerPage as RowsPerPageStory } from './examples/paginator-rows-per-page.component'; type PaginatorArgs = Pick< - PaginatorComponent, + ExtraPaginatorComponent, 'totalRecords' | 'rows' | 'pageLinkSize' | 'showFirstLastIcon' | 'showPageLinks' | 'showCurrentPageReport' | 'showJumpToPageInput' | 'alwaysShow' >; const meta: Meta = { title: 'Components/Data/Paginator', - component: PaginatorComponent, + component: ExtraPaginatorComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - PaginatorComponent, + ExtraPaginatorComponent, PaginatorCurrentPageReportComponent, PaginatorRowsPerPageComponent, ], @@ -27,7 +27,7 @@ const meta: Meta = { component: `Отображает навигацию по страницам для больших наборов данных. \`\`\`typescript -import { PaginatorComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraPaginatorComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -129,7 +129,7 @@ export const Default: Story = { render: (args) => ({ props: args, template: ` - + > `, }), parameters: { diff --git a/src/stories/components/panelmenu/examples/panelmenu-basic.component.ts b/src/stories/components/panelmenu/examples/panelmenu-basic.component.ts index d19cafd4..086e7a15 100644 --- a/src/stories/components/panelmenu/examples/panelmenu-basic.component.ts +++ b/src/stories/components/panelmenu/examples/panelmenu-basic.component.ts @@ -1,11 +1,11 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { MenuItem } from 'primeng/api'; -import { PanelMenuComponent } from '../../../../lib/components/panelmenu/panelmenu.component'; +import { ExtraPanelMenuComponent } from '../../../../lib/components/panelmenu/panelmenu.component'; const template = `
- +
`; const styles = ''; @@ -13,7 +13,7 @@ const styles = ''; @Component({ selector: 'app-panelmenu-basic', standalone: true, - imports: [PanelMenuComponent], + imports: [ExtraPanelMenuComponent], template, styles, }) @@ -53,14 +53,14 @@ export const Basic: StoryObj = { code: ` import { Component } from '@angular/core'; import { MenuItem } from 'primeng/api'; -import { PanelMenuComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraPanelMenuComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-panelmenu-basic', standalone: true, - imports: [PanelMenuComponent], + imports: [ExtraPanelMenuComponent], template: \` - + \`, }) export class PanelMenuBasicComponent { diff --git a/src/stories/components/panelmenu/examples/panelmenu-custom.component.ts b/src/stories/components/panelmenu/examples/panelmenu-custom.component.ts index 3a1ac663..2bc5bb34 100644 --- a/src/stories/components/panelmenu/examples/panelmenu-custom.component.ts +++ b/src/stories/components/panelmenu/examples/panelmenu-custom.component.ts @@ -3,20 +3,19 @@ import { StoryObj } from '@storybook/angular'; import { MenuItem } from 'primeng/api'; import { PanelMenu } from 'primeng/panelmenu'; import { Badge } from 'primeng/badge'; -import { NgIf, NgClass } from '@angular/common'; const template = `
- + @if (item.icon) {}
{{ item.label }} - {{ item['description'] }} + @if (item['description']) {{{ item['description'] }}}
- - + @if (item['badge']) {} + @if (hasSubmenu) {}
@@ -27,9 +26,9 @@ const styles = ''; @Component({ selector: 'app-panelmenu-custom', standalone: true, - imports: [PanelMenu, Badge, NgIf, NgClass], + imports: [PanelMenu, Badge], template, - styles, + styles }) export class PanelMenuCustomComponent { items: MenuItem[] = [ @@ -40,14 +39,14 @@ export class PanelMenuCustomComponent { items: [ { label: 'Аналитика', icon: 'ti ti-chart-line', description: 'Аналитика данных' }, { label: 'Отчёты', icon: 'ti ti-file-analytics', description: 'Сводные отчёты' }, - { label: 'Статистика', icon: 'ti ti-chart-bar', description: 'Показатели доставки' }, - ], + { label: 'Статистика', icon: 'ti ti-chart-bar', description: 'Показатели доставки' } + ] }, { label: 'Отправления', icon: 'ti ti-package', description: 'Управление заказами', - badge: 'New', + badge: 'New' }, { label: 'Склады', @@ -55,21 +54,21 @@ export class PanelMenuCustomComponent { description: 'Складское хранение', items: [ { label: 'Документы', icon: 'ti ti-file-text', description: 'Накладные и акты' }, - { label: 'Фото', icon: 'ti ti-photo', description: 'Фотофиксация грузов' }, - ], + { label: 'Фото', icon: 'ti ti-photo', description: 'Фотофиксация грузов' } + ] }, { label: 'Настройки', icon: 'ti ti-settings', description: 'Параметры системы', - disabled: true, - }, + disabled: true + } ]; } export const Custom: StoryObj = { render: () => ({ - template: ``, + template: `` }), parameters: { docs: { @@ -81,23 +80,22 @@ import { Component } from '@angular/core'; import { MenuItem } from 'primeng/api'; import { PanelMenu } from 'primeng/panelmenu'; import { Badge } from 'primeng/badge'; -import { NgIf } from '@angular/common'; @Component({ selector: 'app-panelmenu-custom', standalone: true, - imports: [PanelMenu, Badge, NgIf], + imports: [PanelMenu, Badge], template: \` - + @if (item.icon) {}
{{ item.label }} - {{ item['description'] }} + @if (item['description']) {{{ item['description'] }}}
- - + @if (item['badge']) {} + @if (hasSubmenu) {}
@@ -127,8 +125,8 @@ export class PanelMenuCustomComponent { { label: 'Настройки', icon: 'ti ti-settings', description: 'Параметры системы', disabled: true }, ]; } - `, - }, - }, - }, + ` + } + } + } }; diff --git a/src/stories/components/panelmenu/examples/panelmenu-multiple.component.ts b/src/stories/components/panelmenu/examples/panelmenu-multiple.component.ts index 606aaa41..110e2da6 100644 --- a/src/stories/components/panelmenu/examples/panelmenu-multiple.component.ts +++ b/src/stories/components/panelmenu/examples/panelmenu-multiple.component.ts @@ -1,11 +1,11 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { MenuItem } from 'primeng/api'; -import { PanelMenuComponent } from '../../../../lib/components/panelmenu/panelmenu.component'; +import { ExtraPanelMenuComponent } from '../../../../lib/components/panelmenu/panelmenu.component'; const template = `
- +
`; const styles = ''; @@ -13,7 +13,7 @@ const styles = ''; @Component({ selector: 'app-panelmenu-multiple', standalone: true, - imports: [PanelMenuComponent], + imports: [ExtraPanelMenuComponent], template, styles, }) @@ -59,14 +59,14 @@ export const Multiple: StoryObj = { code: ` import { Component } from '@angular/core'; import { MenuItem } from 'primeng/api'; -import { PanelMenuComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraPanelMenuComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-panelmenu-multiple', standalone: true, - imports: [PanelMenuComponent], + imports: [ExtraPanelMenuComponent], template: \` - + \`, }) export class PanelMenuMultipleComponent { diff --git a/src/stories/components/panelmenu/panelmenu.stories.ts b/src/stories/components/panelmenu/panelmenu.stories.ts index 8a600d6d..601617f9 100644 --- a/src/stories/components/panelmenu/panelmenu.stories.ts +++ b/src/stories/components/panelmenu/panelmenu.stories.ts @@ -1,17 +1,17 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { PanelMenuComponent } from '../../../lib/components/panelmenu/panelmenu.component'; +import { ExtraPanelMenuComponent } from '../../../lib/components/panelmenu/panelmenu.component'; import { PanelMenuBasicComponent, Basic } from './examples/panelmenu-basic.component'; import { PanelMenuMultipleComponent, Multiple } from './examples/panelmenu-multiple.component'; import { PanelMenuCustomComponent, Custom } from './examples/panelmenu-custom.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Menu/PanelMenu', - component: PanelMenuComponent, + component: ExtraPanelMenuComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - PanelMenuComponent, + ExtraPanelMenuComponent, PanelMenuBasicComponent, PanelMenuMultipleComponent, PanelMenuCustomComponent, @@ -24,7 +24,7 @@ const meta: Meta = { component: `Аккордеон-меню с поддержкой вложенных подменю и раскрытием нескольких панелей. \`\`\`typescript -import { PanelMenuComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraPanelMenuComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -59,7 +59,7 @@ import { PanelMenuComponent } from '@cdek-it/angular-ui-kit'; }; export default meta; -type Story = StoryObj; +type Story = StoryObj; // ── Default ─────────────────────────────────────────────────────────────────── @@ -70,7 +70,7 @@ export const Default: Story = { if (args.multiple) parts.push(`[multiple]="true"`); if (args.tabindex !== undefined) parts.push(`[tabindex]="${args.tabindex}"`); - const template = ``; + const template = ``; return { props: { diff --git a/src/stories/components/password/examples/password-disabled.component.ts b/src/stories/components/password/examples/password-disabled.component.ts index 4c13c6df..0f87111d 100644 --- a/src/stories/components/password/examples/password-disabled.component.ts +++ b/src/stories/components/password/examples/password-disabled.component.ts @@ -1,18 +1,18 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { PasswordComponent } from '../../../../lib/components/password/password.component'; +import { ExtraPasswordComponent } from '../../../../lib/components/password/password.component'; const template = `
- +
`; @Component({ selector: 'app-password-disabled', standalone: true, - imports: [PasswordComponent, FormsModule], + imports: [ExtraPasswordComponent, FormsModule], template, }) export class PasswordDisabledComponent { @@ -31,14 +31,14 @@ export const Disabled: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { PasswordComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraPasswordComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-password-disabled', standalone: true, - imports: [PasswordComponent, FormsModule], + imports: [ExtraPasswordComponent, FormsModule], template: \` - + \`, }) export class PasswordDisabledComponent { diff --git a/src/stories/components/password/examples/password-feedback.component.ts b/src/stories/components/password/examples/password-feedback.component.ts index 829aacf4..811ff78b 100644 --- a/src/stories/components/password/examples/password-feedback.component.ts +++ b/src/stories/components/password/examples/password-feedback.component.ts @@ -1,18 +1,18 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { PasswordComponent } from '../../../../lib/components/password/password.component'; +import { ExtraPasswordComponent } from '../../../../lib/components/password/password.component'; const template = `
- +
`; @Component({ selector: 'app-password-feedback', standalone: true, - imports: [PasswordComponent, FormsModule], + imports: [ExtraPasswordComponent, FormsModule], template, }) export class PasswordFeedbackComponent { @@ -31,14 +31,14 @@ export const Feedback: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { PasswordComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraPasswordComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-password-feedback', standalone: true, - imports: [PasswordComponent, FormsModule], + imports: [ExtraPasswordComponent, FormsModule], template: \` - + \`, }) export class PasswordFeedbackComponent { diff --git a/src/stories/components/password/examples/password-float-label.component.ts b/src/stories/components/password/examples/password-float-label.component.ts index e75551fd..46015ccf 100644 --- a/src/stories/components/password/examples/password-float-label.component.ts +++ b/src/stories/components/password/examples/password-float-label.component.ts @@ -1,15 +1,15 @@ import { Component, Input } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { PasswordComponent } from '../../../../lib/components/password/password.component'; +import { ExtraPasswordComponent } from '../../../../lib/components/password/password.component'; @Component({ selector: 'app-password-float-label', standalone: true, - imports: [PasswordComponent, FormsModule], + imports: [ExtraPasswordComponent, FormsModule], template: `
- + >
`, }) @@ -71,7 +71,7 @@ export const FloatLabel: StoryObj = { }, source: { language: 'html', - code: ``, + code: ``, }, }, }, diff --git a/src/stories/components/password/examples/password-invalid.component.ts b/src/stories/components/password/examples/password-invalid.component.ts index dace649f..4f8f63da 100644 --- a/src/stories/components/password/examples/password-invalid.component.ts +++ b/src/stories/components/password/examples/password-invalid.component.ts @@ -1,18 +1,18 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { PasswordComponent } from '../../../../lib/components/password/password.component'; +import { ExtraPasswordComponent } from '../../../../lib/components/password/password.component'; const template = `
- +
`; @Component({ selector: 'app-password-invalid', standalone: true, - imports: [PasswordComponent, FormsModule], + imports: [ExtraPasswordComponent, FormsModule], template, }) export class PasswordInvalidComponent { @@ -31,14 +31,14 @@ export const Invalid: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { PasswordComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraPasswordComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-password-invalid', standalone: true, - imports: [PasswordComponent, FormsModule], + imports: [ExtraPasswordComponent, FormsModule], template: \` - + \`, }) export class PasswordInvalidComponent { diff --git a/src/stories/components/password/examples/password-template.component.ts b/src/stories/components/password/examples/password-template.component.ts index 063b24b5..28908205 100644 --- a/src/stories/components/password/examples/password-template.component.ts +++ b/src/stories/components/password/examples/password-template.component.ts @@ -1,16 +1,16 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { PasswordComponent } from '../../../../lib/components/password/password.component'; +import { ExtraPasswordComponent } from '../../../../lib/components/password/password.component'; import { Divider } from 'primeng/divider'; @Component({ selector: 'app-password-template', standalone: true, - imports: [PasswordComponent, Divider, FormsModule], + imports: [ExtraPasswordComponent, Divider, FormsModule], template: `
-
- +
`, }) @@ -80,14 +80,14 @@ export const Template: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { PasswordComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraPasswordComponent } from '@cdek-it/angular-ui-kit'; import { Divider } from 'primeng/divider'; @Component({ standalone: true, - imports: [PasswordComponent, Divider, FormsModule], + imports: [ExtraPasswordComponent, Divider, FormsModule], template: \` -
- + \`, }) export class PasswordTemplateExample { diff --git a/src/stories/components/password/examples/password-toggle.component.ts b/src/stories/components/password/examples/password-toggle.component.ts index 0fdb915e..28fda1de 100644 --- a/src/stories/components/password/examples/password-toggle.component.ts +++ b/src/stories/components/password/examples/password-toggle.component.ts @@ -1,18 +1,18 @@ import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { PasswordComponent } from '../../../../lib/components/password/password.component'; +import { ExtraPasswordComponent } from '../../../../lib/components/password/password.component'; const template = `
- +
`; @Component({ selector: 'app-password-toggle', standalone: true, - imports: [PasswordComponent, FormsModule], + imports: [ExtraPasswordComponent, FormsModule], template, }) export class PasswordToggleComponent { @@ -31,14 +31,14 @@ export const ToggleMask: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { PasswordComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraPasswordComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-password-toggle', standalone: true, - imports: [PasswordComponent, FormsModule], + imports: [ExtraPasswordComponent, FormsModule], template: \` - + \`, }) export class PasswordToggleComponent { diff --git a/src/stories/components/password/password.stories.ts b/src/stories/components/password/password.stories.ts index b7367373..4e7d2596 100644 --- a/src/stories/components/password/password.stories.ts +++ b/src/stories/components/password/password.stories.ts @@ -1,6 +1,6 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormsModule } from '@angular/forms'; -import { PasswordComponent } from '../../../lib/components/password/password.component'; +import { ExtraPasswordComponent } from '../../../lib/components/password/password.component'; import { PasswordToggleComponent, ToggleMask } from './examples/password-toggle.component'; import { PasswordFeedbackComponent, Feedback } from './examples/password-feedback.component'; import { PasswordDisabledComponent, Disabled } from './examples/password-disabled.component'; @@ -8,14 +8,14 @@ import { PasswordInvalidComponent, Invalid } from './examples/password-invalid.c import { PasswordFloatLabelComponent, FloatLabel } from './examples/password-float-label.component'; import { PasswordTemplateComponent, Template } from './examples/password-template.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Form/Password', - component: PasswordComponent, + component: ExtraPasswordComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - PasswordComponent, + ExtraPasswordComponent, FormsModule, PasswordToggleComponent, PasswordFeedbackComponent, @@ -37,7 +37,7 @@ const meta: Meta = { component: `Поле ввода пароля с поддержкой индикатора надёжности и переключения видимости. \`\`\`typescript -import { PasswordComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraPasswordComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, story: { height: '280px' }, @@ -172,7 +172,7 @@ import { PasswordComponent } from '@cdek-it/angular-ui-kit'; }; export default meta; -type Story = StoryObj; +type Story = StoryObj; // ── Default ────────────────────────────────────────────────────────────────── export const Default: Story = { @@ -196,8 +196,8 @@ export const Default: Story = { parts.push(`[(ngModel)]="value"`); const template = parts.length > 1 - ? `` - : ``; + ? `` + : ``; return { props: { ...args, value: null }, template }; }, diff --git a/src/stories/components/scroll-panel/examples/scroll-panel-both.component.ts b/src/stories/components/scroll-panel/examples/scroll-panel-both.component.ts index 7969b9d3..b0324e31 100644 --- a/src/stories/components/scroll-panel/examples/scroll-panel-both.component.ts +++ b/src/stories/components/scroll-panel/examples/scroll-panel-both.component.ts @@ -1,9 +1,9 @@ import { Component } from '@angular/core'; -import { ScrollPanelComponent } from '../../../../lib/components/scroll-panel/scroll-panel.component'; +import { ExtraScrollPanelComponent } from '../../../../lib/components/scroll-panel/scroll-panel.component'; const template = `
- +

№ЦД-00123456 · Москва → Новосибирск · 2.5 кг · 3 места · Принят 14 апр 09:15 · Доставлен 15 апр 14:20

№ЦД-00123457 · Санкт-Петербург → Казань · 0.8 кг · 1 место · Принят 13 апр 11:00 · Доставлен 15 апр 10:30

@@ -14,7 +14,7 @@ const template = `

№ЦД-00123462 · Пермь → Иркутск · 2.0 кг · 2 места · Принят 13 апр 09:30 · В пути

№ЦД-00123463 · Воронеж → Красноярск · 4.5 кг · 3 места · Принят 12 апр 16:00 · В пути

-
+
`; const styles = ''; @@ -22,7 +22,7 @@ const styles = ''; @Component({ selector: 'app-scroll-panel-both', standalone: true, - imports: [ScrollPanelComponent], + imports: [ExtraScrollPanelComponent], template, styles, }) diff --git a/src/stories/components/scroll-panel/examples/scroll-panel-horizontal.component.ts b/src/stories/components/scroll-panel/examples/scroll-panel-horizontal.component.ts index 54de4a10..3becdf99 100644 --- a/src/stories/components/scroll-panel/examples/scroll-panel-horizontal.component.ts +++ b/src/stories/components/scroll-panel/examples/scroll-panel-horizontal.component.ts @@ -1,13 +1,13 @@ import { Component } from '@angular/core'; -import { ScrollPanelComponent } from '../../../../lib/components/scroll-panel/scroll-panel.component'; +import { ExtraScrollPanelComponent } from '../../../../lib/components/scroll-panel/scroll-panel.component'; const template = `
- +

Заказ №ЦД-00123456 · Москва → Новосибирск · Принят 14 апр 09:15 · Передан перевозчику 14 апр 14:30 · Отправлен из Москвы 14 апр 23:50 · Прибыл в Новосибирск 15 апр 08:00 · Передан курьеру Петрову А.В. 15 апр 12:00 · Доставлен получателю 15 апр 14:20

-
+
`; const styles = ''; @@ -15,7 +15,7 @@ const styles = ''; @Component({ selector: 'app-scroll-panel-horizontal', standalone: true, - imports: [ScrollPanelComponent], + imports: [ExtraScrollPanelComponent], template, styles, }) diff --git a/src/stories/components/scroll-panel/scroll-panel.stories.ts b/src/stories/components/scroll-panel/scroll-panel.stories.ts index 03bfc329..7d765632 100644 --- a/src/stories/components/scroll-panel/scroll-panel.stories.ts +++ b/src/stories/components/scroll-panel/scroll-panel.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { ScrollPanelComponent } from '../../../lib/components/scroll-panel/scroll-panel.component'; +import { ExtraScrollPanelComponent } from '../../../lib/components/scroll-panel/scroll-panel.component'; import { ScrollPanelHorizontalComponent } from './examples/scroll-panel-horizontal.component'; import { ScrollPanelBothComponent } from './examples/scroll-panel-both.component'; @@ -36,14 +36,14 @@ const BOTH_CONTENT = `
`; -const meta: Meta = { +const meta: Meta = { title: 'Components/Panel/ScrollPanel', - component: ScrollPanelComponent, + component: ExtraScrollPanelComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - ScrollPanelComponent, + ExtraScrollPanelComponent, ScrollPanelHorizontalComponent, ScrollPanelBothComponent, ], @@ -98,7 +98,7 @@ import { ScrollPanelModule } from 'primeng/scrollpanel'; }; export default meta; -type Story = StoryObj; +type Story = StoryObj; // ── Default ────────────────────────────────────────────────────────────────── @@ -112,7 +112,7 @@ export const Default: Story = { if (args.step !== 10) parts.push(`[step]="${args.step}"`); const attrStr = parts.length ? `\n ${parts.join('\n ')}\n` : ''; - const template = `${TRACKING_CONTENT}`; + const template = `${TRACKING_CONTENT}`; return { props: args, template }; }, @@ -130,7 +130,7 @@ export const Default: Story = { export const Horizontal: Story = { render: (args) => ({ props: args, - template: `${HORIZONTAL_CONTENT}`, + template: `${HORIZONTAL_CONTENT}`, }), args: { step: 10, height: '80px', width: '100%' }, parameters: { @@ -140,18 +140,18 @@ export const Horizontal: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ScrollPanelComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraScrollPanelComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-scroll-panel-horizontal', standalone: true, - imports: [ScrollPanelComponent], + imports: [ExtraScrollPanelComponent], template: \` - +

Заказ №ЦД-00123456 · Москва → Новосибирск · Принят 14 апр 09:15 · Передан перевозчику 14 апр 14:30 · Отправлен из Москвы 14 апр 23:50 · Прибыл в Новосибирск 15 апр 08:00 · Доставлен получателю 15 апр 14:20

-
+ \`, }) export class ScrollPanelHorizontalComponent {} @@ -164,7 +164,7 @@ export class ScrollPanelHorizontalComponent {} export const Both: Story = { render: (args) => ({ props: args, - template: `${BOTH_CONTENT}`, + template: `${BOTH_CONTENT}`, }), args: { step: 10, height: '200px', width: '50%' }, parameters: { @@ -174,14 +174,14 @@ export const Both: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ScrollPanelComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraScrollPanelComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-scroll-panel-both', standalone: true, - imports: [ScrollPanelComponent], + imports: [ExtraScrollPanelComponent], template: \` - +

№ЦД-00123456 · Москва → Новосибирск · 2.5 кг · 3 места · Принят 14 апр · Доставлен 15 апр

№ЦД-00123457 · Санкт-Петербург → Казань · 0.8 кг · 1 место · Принят 13 апр · Доставлен 15 апр

@@ -189,7 +189,7 @@ import { ScrollPanelComponent } from '@cdek-it/angular-ui-kit';

№ЦД-00123459 · Нижний Новгород → Омск · 1.1 кг · 1 место · Принят 14 апр · Ожидает отправки

№ЦД-00123460 · Самара → Ростов-на-Дону · 3.7 кг · 4 места · Принят 11 апр · Доставлен 14 апр

-
+ \`, }) export class ScrollPanelBothComponent {} diff --git a/src/stories/components/select/examples/select-custom.component.ts b/src/stories/components/select/examples/select-custom.component.ts index b8eefe6d..dee3aa0f 100644 --- a/src/stories/components/select/examples/select-custom.component.ts +++ b/src/stories/components/select/examples/select-custom.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; +import { ExtraSelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const OPTIONS = [ { name: 'Профиль', description: 'Настройки аккаунта', icon: 'ti ti-user' }, @@ -18,7 +18,7 @@ const template = `
- +> `; const styles = ''; @Component({ selector: 'app-select-custom', standalone: true, - imports: [SelectComponent, ReactiveFormsModule], + imports: [ExtraSelectComponent, ReactiveFormsModule], template, styles, }) @@ -69,11 +69,11 @@ export const Custom = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { SelectComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraSelectComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [SelectComponent, ReactiveFormsModule], + imports: [ExtraSelectComponent, ReactiveFormsModule], template: \`
@@ -84,13 +84,13 @@ import { SelectComponent } from '@cdek-it/angular-ui-kit';
- + > \`, }) export class SelectCustomExample { diff --git a/src/stories/components/select/examples/select-disabled.component.ts b/src/stories/components/select/examples/select-disabled.component.ts index ea14fffd..14a6143e 100644 --- a/src/stories/components/select/examples/select-disabled.component.ts +++ b/src/stories/components/select/examples/select-disabled.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { SelectComponent } from '../../../../lib/components/select/select.component'; +import { ExtraSelectComponent } from '../../../../lib/components/select/select.component'; const OPTIONS = [ { name: 'Новосибирск', code: 'NSK' }, @@ -15,12 +15,12 @@ export const Disabled: StoryObj = { return { props: { control, options: OPTIONS }, template: ` - + > `, }; }, @@ -28,7 +28,7 @@ export const Disabled: StoryObj = { (story: any) => ({ ...story(), moduleMetadata: { - imports: [SelectComponent, ReactiveFormsModule], + imports: [ExtraSelectComponent, ReactiveFormsModule], }, }), ], @@ -41,18 +41,18 @@ export const Disabled: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { SelectComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraSelectComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [SelectComponent, ReactiveFormsModule], + imports: [ExtraSelectComponent, ReactiveFormsModule], template: \` - + > \`, }) export class SelectDisabledExample { diff --git a/src/stories/components/select/examples/select-editable.component.ts b/src/stories/components/select/examples/select-editable.component.ts index 6868d9d1..bab7fc85 100644 --- a/src/stories/components/select/examples/select-editable.component.ts +++ b/src/stories/components/select/examples/select-editable.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; +import { ExtraSelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const OPTIONS = [ { name: 'Новосибирск', code: 'NSK' }, @@ -9,7 +9,7 @@ const OPTIONS = [ ]; const template = ` - +> `; const styles = ''; @Component({ selector: 'app-select-editable', standalone: true, - imports: [SelectComponent, ReactiveFormsModule], + imports: [ExtraSelectComponent, ReactiveFormsModule], template, styles, }) @@ -60,19 +60,19 @@ export const Editable = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { SelectComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraSelectComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [SelectComponent, ReactiveFormsModule], + imports: [ExtraSelectComponent, ReactiveFormsModule], template: \` - + > \`, }) export class SelectEditableExample { diff --git a/src/stories/components/select/examples/select-filter.component.ts b/src/stories/components/select/examples/select-filter.component.ts index 993c195d..fa83be8b 100644 --- a/src/stories/components/select/examples/select-filter.component.ts +++ b/src/stories/components/select/examples/select-filter.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; +import { ExtraSelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const OPTIONS = [ { name: 'Новосибирск', code: 'NSK' }, @@ -11,7 +11,7 @@ const OPTIONS = [ ]; const template = ` - +> `; const styles = ''; @Component({ selector: 'app-select-filter', standalone: true, - imports: [SelectComponent, ReactiveFormsModule], + imports: [ExtraSelectComponent, ReactiveFormsModule], template, styles, }) @@ -61,20 +61,20 @@ export const Filter = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { SelectComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraSelectComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [SelectComponent, ReactiveFormsModule], + imports: [ExtraSelectComponent, ReactiveFormsModule], template: \` - + > \`, }) export class SelectFilterExample { diff --git a/src/stories/components/select/examples/select-float-label.component.ts b/src/stories/components/select/examples/select-float-label.component.ts index d269013a..f1aa5c34 100644 --- a/src/stories/components/select/examples/select-float-label.component.ts +++ b/src/stories/components/select/examples/select-float-label.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { SelectComponent } from '../../../../lib/components/select/select.component'; +import { ExtraSelectComponent } from '../../../../lib/components/select/select.component'; const OPTIONS = [ { name: 'Новосибирск', code: 'NSK' }, @@ -11,7 +11,7 @@ const OPTIONS = [ const template = `
- + >
`; const styles = ''; @@ -28,7 +28,7 @@ const styles = ''; @Component({ selector: 'app-select-float-label', standalone: true, - imports: [SelectComponent, ReactiveFormsModule], + imports: [ExtraSelectComponent, ReactiveFormsModule], template, styles, }) @@ -69,14 +69,14 @@ export const FloatLabelStory = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { SelectComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraSelectComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [SelectComponent, ReactiveFormsModule], + imports: [ExtraSelectComponent, ReactiveFormsModule], template: \`
- + >
\`, }) diff --git a/src/stories/components/select/examples/select-grouped.component.ts b/src/stories/components/select/examples/select-grouped.component.ts index 40fa483d..19b893dd 100644 --- a/src/stories/components/select/examples/select-grouped.component.ts +++ b/src/stories/components/select/examples/select-grouped.component.ts @@ -1,6 +1,6 @@ import { Component, Input } from '@angular/core'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { SelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; +import { ExtraSelectComponent, SelectSize } from '../../../../lib/components/select/select.component'; const GROUPED_OPTIONS = [ { @@ -28,7 +28,7 @@ const template = ` {{ group.label }}
- +> `; const styles = ''; @Component({ selector: 'app-select-grouped', standalone: true, - imports: [SelectComponent, ReactiveFormsModule], + imports: [ExtraSelectComponent, ReactiveFormsModule], template, styles, }) @@ -82,11 +82,11 @@ export const Grouped = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { SelectComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraSelectComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [SelectComponent, ReactiveFormsModule], + imports: [ExtraSelectComponent, ReactiveFormsModule], template: \`
@@ -94,7 +94,7 @@ import { SelectComponent } from '@cdek-it/angular-ui-kit'; {{ group.label }}
- + > \`, }) export class SelectGroupedExample { diff --git a/src/stories/components/select/select.stories.ts b/src/stories/components/select/select.stories.ts index bec20cc5..1e66cd37 100644 --- a/src/stories/components/select/select.stories.ts +++ b/src/stories/components/select/select.stories.ts @@ -1,6 +1,6 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { SelectComponent } from '../../../lib/components/select/select.component'; +import { ExtraSelectComponent } from '../../../lib/components/select/select.component'; import { SelectFilterComponent, Filter as FilterStory } from './examples/select-filter.component'; import { SelectGroupedComponent, Grouped as GroupedStory } from './examples/select-grouped.component'; import { SelectCustomComponent, Custom as CustomStory } from './examples/select-custom.component'; @@ -17,19 +17,19 @@ const BASIC_OPTIONS = [ { name: 'Казань', code: 'KZN' }, ]; -type SelectArgs = Pick & { +type SelectArgs = Pick & { disabled: boolean; invalid: boolean; }; const meta: Meta = { title: 'Components/Form/Select', - component: SelectComponent, + component: ExtraSelectComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - SelectComponent, + ExtraSelectComponent, ReactiveFormsModule, SelectFilterComponent, SelectGroupedComponent, @@ -45,7 +45,7 @@ const meta: Meta = { component: `Выпадающий список для выбора одного значения из набора опций. Поддерживает фильтрацию, группировку, кастомные шаблоны и редактируемый ввод. \`\`\`typescript -import { SelectComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraSelectComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -155,7 +155,7 @@ export const Default: Story = { return { props: { ...args, control, options: BASIC_OPTIONS }, template: ` - + > `, }; }, diff --git a/src/stories/components/skeleton/examples/skeleton-card-placeholder.component.ts b/src/stories/components/skeleton/examples/skeleton-card-placeholder.component.ts index 3fd0b608..a36f5ff2 100644 --- a/src/stories/components/skeleton/examples/skeleton-card-placeholder.component.ts +++ b/src/stories/components/skeleton/examples/skeleton-card-placeholder.component.ts @@ -5,11 +5,11 @@ import { ExtraSkeletonComponent } from '../../../../lib/components/skeleton/skel const template = `
- +
- - - + + +
@@ -44,11 +44,11 @@ import { SkeletonComponent } from '@cdek-it/angular-ui-kit'; imports: [SkeletonComponent], template: \`
- +
- - - + + +
\`, diff --git a/src/stories/components/skeleton/examples/skeleton-circle.component.ts b/src/stories/components/skeleton/examples/skeleton-circle.component.ts index 6fee4476..42d9e380 100644 --- a/src/stories/components/skeleton/examples/skeleton-circle.component.ts +++ b/src/stories/components/skeleton/examples/skeleton-circle.component.ts @@ -5,9 +5,9 @@ import { ExtraSkeletonComponent } from '../../../../lib/components/skeleton/skel const template = `
- - - + + +
`; @@ -40,10 +40,10 @@ import { SkeletonComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [SkeletonComponent], template: \` -
- - - +
+ + +
\`, }) diff --git a/src/stories/components/skeleton/examples/skeleton-no-animation.component.ts b/src/stories/components/skeleton/examples/skeleton-no-animation.component.ts index 14d25259..7798a6e2 100644 --- a/src/stories/components/skeleton/examples/skeleton-no-animation.component.ts +++ b/src/stories/components/skeleton/examples/skeleton-no-animation.component.ts @@ -5,9 +5,9 @@ import { ExtraSkeletonComponent } from '../../../../lib/components/skeleton/skel const template = `
- - - + + +
`; @@ -41,9 +41,9 @@ import { SkeletonComponent } from '@cdek-it/angular-ui-kit'; imports: [SkeletonComponent], template: \`
- - - + + +
\`, }) diff --git a/src/stories/components/skeleton/examples/skeleton-rectangles.component.ts b/src/stories/components/skeleton/examples/skeleton-rectangles.component.ts index cb4ac4a9..3800faeb 100644 --- a/src/stories/components/skeleton/examples/skeleton-rectangles.component.ts +++ b/src/stories/components/skeleton/examples/skeleton-rectangles.component.ts @@ -5,9 +5,9 @@ import { ExtraSkeletonComponent } from '../../../../lib/components/skeleton/skel const template = `
- - - + + +
`; @@ -41,9 +41,9 @@ import { SkeletonComponent } from '@cdek-it/angular-ui-kit'; imports: [SkeletonComponent], template: \`
- - - + + +
\`, }) diff --git a/src/stories/components/tag/tag.stories.ts b/src/stories/components/tag/tag.stories.ts index 7a4d9104..ba1ac98f 100644 --- a/src/stories/components/tag/tag.stories.ts +++ b/src/stories/components/tag/tag.stories.ts @@ -1,8 +1,8 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { ExtraTagComponent } from '../../../lib/components/tag/tag.component'; -import { TagSeverityComponent } from './examples/tag-severity.component'; -import { TagRoundedComponent } from './examples/tag-rounded.component'; -import { TagIconComponent } from './examples/tag-icon.component'; +import { TagSeverityComponent, Severity } from './examples/tag-severity.component'; +import { TagRoundedComponent, Rounded } from './examples/tag-rounded.component'; +import { TagIconComponent, WithIcon } from './examples/tag-icon.component'; type TagArgs = ExtraTagComponent; @@ -111,86 +111,4 @@ export const Default: Story = { }, }; -// ── Severity ────────────────────────────────────────────────────────────────── -export const Severity: Story = { - render: (args) => ({ props: args, template: commonTemplate }), - args: { value: 'Success', severity: 'success' }, - parameters: { - docs: { - description: { story: 'Вариант цветового оформления. Доступные значения: primary, secondary, success, info, warn, danger.' }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraTagComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-tag-severity', - standalone: true, - imports: [ExtraTagComponent], - template: \` - - \`, -}) -export class TagSeverityComponent {} - `, - }, - }, - }, -}; - -// ── Rounded ─────────────────────────────────────────────────────────────────── -export const Rounded: Story = { - render: (args) => ({ props: args, template: commonTemplate }), - args: { value: 'Rounded', severity: 'success', rounded: true }, - parameters: { - docs: { - description: { story: 'Скруглённый вариант тега.' }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraTagComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-tag-rounded', - standalone: true, - imports: [ExtraTagComponent], - template: \` - - \`, -}) -export class TagRoundedComponent {} - `, - }, - }, - }, -}; - -// ── WithIcon ────────────────────────────────────────────────────────────────── -export const WithIcon: Story = { - render: (args) => ({ props: args, template: commonTemplate }), - args: { value: 'Verified', severity: 'info', icon: 'ti ti-check' }, - parameters: { - docs: { - description: { story: 'Тег с иконкой из библиотеки Tabler Icons.' }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraTagComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-tag-icon', - standalone: true, - imports: [ExtraTagComponent], - template: \` - - \`, -}) -export class TagIconComponent {} - `, - }, - }, - }, -}; +export { WithIcon, Rounded, Severity }; diff --git a/src/stories/components/textarea/examples/textarea-autoresize.component.ts b/src/stories/components/textarea/examples/textarea-autoresize.component.ts index ee12d1f7..86403613 100644 --- a/src/stories/components/textarea/examples/textarea-autoresize.component.ts +++ b/src/stories/components/textarea/examples/textarea-autoresize.component.ts @@ -1,16 +1,16 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; +import { ExtraTextareaComponent } from '../../../../lib/components/textarea/textarea.component'; export const template = `
- + >
`; const styles = ''; @@ -19,7 +19,7 @@ const styles = ''; selector: 'app-textarea-autoresize', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [TextareaComponent, FormsModule], + imports: [ExtraTextareaComponent, FormsModule], template, styles, }) diff --git a/src/stories/components/textarea/examples/textarea-disabled.component.ts b/src/stories/components/textarea/examples/textarea-disabled.component.ts index 225fb177..075381be 100644 --- a/src/stories/components/textarea/examples/textarea-disabled.component.ts +++ b/src/stories/components/textarea/examples/textarea-disabled.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; +import { ExtraTextareaComponent } from '../../../../lib/components/textarea/textarea.component'; export const Disabled: StoryObj = { name: 'Disabled', @@ -8,14 +8,14 @@ export const Disabled: StoryObj = { const control = new FormControl({ value: 'Текст в заблокированном поле', disabled: true }); return { props: { ...args, control }, - template: ``, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [TextareaComponent, ReactiveFormsModule], + imports: [ExtraTextareaComponent, ReactiveFormsModule], }, }), ], @@ -28,12 +28,12 @@ export const Disabled: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { TextareaComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraTextareaComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [TextareaComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraTextareaComponent, ReactiveFormsModule], + template: \`\`, }) export class DisabledExample { control = new FormControl({ value: '', disabled: true }); diff --git a/src/stories/components/textarea/examples/textarea-float-label.component.ts b/src/stories/components/textarea/examples/textarea-float-label.component.ts index d780a5dc..4da826a8 100644 --- a/src/stories/components/textarea/examples/textarea-float-label.component.ts +++ b/src/stories/components/textarea/examples/textarea-float-label.component.ts @@ -1,5 +1,4 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; -import { NgIf } from '@angular/common'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { FloatLabel } from 'primeng/floatlabel'; import { Textarea } from 'primeng/textarea'; @@ -11,7 +10,7 @@ import { StoryObj } from '@storybook/angular'; selector: 'app-textarea-float-label', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [Textarea, FloatLabel, ReactiveFormsModule, NgIf, IconField, InputIcon], + imports: [Textarea, FloatLabel, ReactiveFormsModule, IconField, InputIcon], template: `
@@ -38,7 +37,7 @@ import { StoryObj } from '@storybook/angular'; [formControl]="control" > } - +
`, diff --git a/src/stories/components/textarea/examples/textarea-invalid.component.ts b/src/stories/components/textarea/examples/textarea-invalid.component.ts index 021c56cc..b5ba07ab 100644 --- a/src/stories/components/textarea/examples/textarea-invalid.component.ts +++ b/src/stories/components/textarea/examples/textarea-invalid.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; +import { ExtraTextareaComponent } from '../../../../lib/components/textarea/textarea.component'; export const Invalid: StoryObj = { name: 'Invalid', @@ -8,14 +8,14 @@ export const Invalid: StoryObj = { const control = new FormControl('', Validators.required); return { props: { ...args, control }, - template: ``, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [TextareaComponent, ReactiveFormsModule], + imports: [ExtraTextareaComponent, ReactiveFormsModule], }, }), ], @@ -28,12 +28,12 @@ export const Invalid: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms'; -import { TextareaComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraTextareaComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [TextareaComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraTextareaComponent, ReactiveFormsModule], + template: \`\`, }) export class InvalidExample { control = new FormControl('', Validators.required); diff --git a/src/stories/components/textarea/examples/textarea-readonly.component.ts b/src/stories/components/textarea/examples/textarea-readonly.component.ts index 184250a0..996da6d3 100644 --- a/src/stories/components/textarea/examples/textarea-readonly.component.ts +++ b/src/stories/components/textarea/examples/textarea-readonly.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; +import { ExtraTextareaComponent } from '../../../../lib/components/textarea/textarea.component'; export const Readonly: StoryObj = { name: 'Readonly', @@ -8,14 +8,14 @@ export const Readonly: StoryObj = { const control = new FormControl('Только для чтения — этот текст нельзя изменить.'); return { props: { ...args, control }, - template: ``, + template: ``, }; }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [TextareaComponent, ReactiveFormsModule], + imports: [ExtraTextareaComponent, ReactiveFormsModule], }, }), ], @@ -28,12 +28,12 @@ export const Readonly: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { TextareaComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraTextareaComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, - imports: [TextareaComponent, ReactiveFormsModule], - template: \`\`, + imports: [ExtraTextareaComponent, ReactiveFormsModule], + template: \`\`, }) export class ReadonlyExample { control = new FormControl('Только для чтения.'); diff --git a/src/stories/components/textarea/examples/textarea-sizes.component.ts b/src/stories/components/textarea/examples/textarea-sizes.component.ts index 9aaf6a79..0341cd21 100644 --- a/src/stories/components/textarea/examples/textarea-sizes.component.ts +++ b/src/stories/components/textarea/examples/textarea-sizes.component.ts @@ -1,6 +1,6 @@ import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { TextareaComponent } from '../../../../lib/components/textarea/textarea.component'; +import { ExtraTextareaComponent } from '../../../../lib/components/textarea/textarea.component'; export const Sizes: StoryObj = { name: 'Sizes', @@ -8,41 +8,41 @@ export const Sizes: StoryObj = { const control = new FormControl(''); return { props: { ...args, control }, - template: ``, + template: `` }; }, args: { size: 'base', - placeholder: 'Введите текст...', + placeholder: 'Введите текст...' }, argTypes: { size: { control: 'select', - options: ['small', 'base', 'large', 'xlarge'], - }, + options: ['small', 'base', 'large', 'xlarge'] + } }, decorators: [ (story: any) => ({ ...story(), moduleMetadata: { - imports: [TextareaComponent, ReactiveFormsModule], - }, - }), + imports: [ExtraTextareaComponent, ReactiveFormsModule] + } + }) ], parameters: { docs: { description: { - story: 'Все доступные размеры компонента: small, base, large, xlarge. Выберите размер через Controls.', + story: 'Все доступные размеры компонента: small, base, large, xlarge. Выберите размер через Controls.' }, source: { language: 'ts', code: ` - - - - - `, - }, - }, - }, + + + + + ` + } + } + } }; diff --git a/src/stories/components/textarea/textarea.stories.ts b/src/stories/components/textarea/textarea.stories.ts index 7b3b33b6..098fe865 100644 --- a/src/stories/components/textarea/textarea.stories.ts +++ b/src/stories/components/textarea/textarea.stories.ts @@ -1,6 +1,6 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { TextareaComponent } from '../../../lib/components/textarea/textarea.component'; +import { ExtraTextareaComponent } from '../../../lib/components/textarea/textarea.component'; import { Disabled } from './examples/textarea-disabled.component'; import { Readonly } from './examples/textarea-readonly.component'; import { Invalid } from './examples/textarea-invalid.component'; @@ -8,16 +8,16 @@ import { AutoResize, TextareaAutoResizeComponent } from './examples/textarea-aut import { Sizes } from './examples/textarea-sizes.component'; import { FloatLabelStory, TextareaFloatLabelComponent } from './examples/textarea-float-label.component'; -type TextareaArgs = TextareaComponent & { disabled: boolean; invalid: boolean }; +type TextareaArgs = ExtraTextareaComponent & { disabled: boolean; invalid: boolean }; const meta: Meta = { title: 'Components/Form/Textarea', - component: TextareaComponent, + component: ExtraTextareaComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - TextareaComponent, + ExtraTextareaComponent, ReactiveFormsModule, TextareaAutoResizeComponent, TextareaFloatLabelComponent, @@ -31,7 +31,7 @@ const meta: Meta = { component: `Многострочное текстовое поле для ввода данных. \`\`\`typescript -import { TextareaComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraTextareaComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -186,7 +186,7 @@ export const Default: Story = { const control = new FormControl({ value: '', disabled: args.disabled }, validators); - const template = ``; + const template = ``; return { props: { ...args, control }, template }; }, diff --git a/src/stories/components/tieredmenu/examples/tieredmenu-basic.component.ts b/src/stories/components/tieredmenu/examples/tieredmenu-basic.component.ts index b902042f..b6c1f11d 100644 --- a/src/stories/components/tieredmenu/examples/tieredmenu-basic.component.ts +++ b/src/stories/components/tieredmenu/examples/tieredmenu-basic.component.ts @@ -41,7 +41,7 @@ import { ExtraTieredMenuComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [ExtraTieredMenuComponent], template: \` - + \`, }) export class TieredMenuBasicComponent { diff --git a/src/stories/components/tieredmenu/examples/tieredmenu-custom.component.ts b/src/stories/components/tieredmenu/examples/tieredmenu-custom.component.ts index c10f489e..051ceceb 100644 --- a/src/stories/components/tieredmenu/examples/tieredmenu-custom.component.ts +++ b/src/stories/components/tieredmenu/examples/tieredmenu-custom.component.ts @@ -1,25 +1,32 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { MenuItem } from 'primeng/api'; -import { TieredMenu } from 'primeng/tieredmenu'; import { Badge } from 'primeng/badge'; -import { NgIf } from '@angular/common'; +import { ExtraTieredMenuComponent } from '../../../../lib/components/tieredmenu/tieredmenu.component'; const template = ` `; const styles = ''; @@ -27,7 +34,7 @@ const styles = ''; @Component({ selector: 'app-tieredmenu-custom', standalone: true, - imports: [TieredMenu, Badge, NgIf], + imports: [ExtraTieredMenuComponent, Badge], template, styles, }) @@ -80,23 +87,30 @@ import { Component } from '@angular/core'; import { MenuItem } from 'primeng/api'; import { TieredMenu } from 'primeng/tieredmenu'; import { Badge } from 'primeng/badge'; -import { NgIf } from '@angular/common'; @Component({ selector: 'app-tieredmenu-custom', standalone: true, - imports: [TieredMenu, Badge, NgIf], + imports: [TieredMenu, Badge], template: \` - + @if (item.icon) { + + }
{{ item.label }} - {{ item['description'] }} + @if (item['description']) { + {{ item['description'] }} + }
- - + @if (item['badge']) { + + } + @if (hasSubmenu) { + + }
diff --git a/src/stories/components/tieredmenu/examples/tieredmenu-selected.component.ts b/src/stories/components/tieredmenu/examples/tieredmenu-selected.component.ts index b075cc2a..b584309a 100644 --- a/src/stories/components/tieredmenu/examples/tieredmenu-selected.component.ts +++ b/src/stories/components/tieredmenu/examples/tieredmenu-selected.component.ts @@ -5,7 +5,7 @@ import { ExtraTieredMenuComponent } from '../../../../lib/components/tieredmenu/ const template = `
- +
`; const styles = ''; diff --git a/src/stories/components/tieredmenu/tieredmenu.stories.ts b/src/stories/components/tieredmenu/tieredmenu.stories.ts index 3513703d..f460f4dd 100644 --- a/src/stories/components/tieredmenu/tieredmenu.stories.ts +++ b/src/stories/components/tieredmenu/tieredmenu.stories.ts @@ -1,22 +1,22 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { ExtraTieredMenuComponent as TieredMenuComponent } from '../../../lib/components/tieredmenu/tieredmenu.component'; +import { ExtraTieredMenuComponent } from '../../../lib/components/tieredmenu/tieredmenu.component'; import { TieredMenuBasicComponent, Basic } from './examples/tieredmenu-basic.component'; import { TieredMenuSelectedComponent, WithSelected } from './examples/tieredmenu-selected.component'; import { TieredMenuCustomComponent, Custom } from './examples/tieredmenu-custom.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Menu/TieredMenu', - component: TieredMenuComponent, + component: ExtraTieredMenuComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - TieredMenuComponent, + ExtraTieredMenuComponent, TieredMenuBasicComponent, TieredMenuSelectedComponent, - TieredMenuCustomComponent, - ], - }), + TieredMenuCustomComponent + ] + }) ], parameters: { docs: { @@ -25,14 +25,14 @@ const meta: Meta = { \`\`\`typescript import { ExtraTieredMenuComponent as TieredMenuComponent } from '@cdek-it/angular-ui-kit'; -\`\`\``, - }, +\`\`\`` + } }, - designTokens: { prefix: '--p-tieredmenu' }, + designTokens: { prefix: '--p-tieredmenu' } }, argTypes: { model: { - table: { disable: true }, + table: { disable: true } }, autoDisplay: { control: 'boolean', @@ -40,8 +40,8 @@ import { ExtraTieredMenuComponent as TieredMenuComponent } from '@cdek-it/angula table: { category: 'Props', defaultValue: { summary: 'true' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, tabindex: { control: 'number', @@ -49,14 +49,14 @@ import { ExtraTieredMenuComponent as TieredMenuComponent } from '@cdek-it/angula table: { category: 'Props', defaultValue: { summary: 'undefined' }, - type: { summary: 'number' }, - }, - }, - }, + type: { summary: 'number' } + } + } + } }; export default meta; -type Story = StoryObj; +type Story = StoryObj; // ── Re-exports from example components ──────────────────────────────────── export { Basic, WithSelected, Custom }; diff --git a/src/stories/components/timeline/timeline.stories.ts b/src/stories/components/timeline/timeline.stories.ts index 5f4d04f1..eb440f10 100644 --- a/src/stories/components/timeline/timeline.stories.ts +++ b/src/stories/components/timeline/timeline.stories.ts @@ -149,7 +149,7 @@ function renderStory(args: any) { >
{{ event.value }}
- {{ event.caption }} + @if (${args.showCaption}) {{{ event.caption }}}
`; diff --git a/src/stories/components/toggleswitch/examples/toggleswitch-checked.component.ts b/src/stories/components/toggleswitch/examples/toggleswitch-checked.component.ts index b0c6a885..a64d5301 100644 --- a/src/stories/components/toggleswitch/examples/toggleswitch-checked.component.ts +++ b/src/stories/components/toggleswitch/examples/toggleswitch-checked.component.ts @@ -1,14 +1,14 @@ import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { ToggleSwitchComponent } from '../../../../lib/components/toggleswitch/toggleswitch.component'; +import { ExtraToggleSwitchComponent } from '../../../../lib/components/toggleswitch/toggleswitch.component'; @Component({ selector: 'app-toggleswitch-checked', standalone: true, - imports: [ToggleSwitchComponent, ReactiveFormsModule], + imports: [ExtraToggleSwitchComponent, ReactiveFormsModule], template: ` - + `, }) export class ToggleSwitchCheckedComponent { @@ -34,7 +34,7 @@ import { ToggleSwitchComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [ToggleSwitchComponent, ReactiveFormsModule], template: \` - + \`, }) export class ToggleSwitchCheckedComponent { diff --git a/src/stories/components/toggleswitch/examples/toggleswitch-disabled.component.ts b/src/stories/components/toggleswitch/examples/toggleswitch-disabled.component.ts index 7d041f46..993e7061 100644 --- a/src/stories/components/toggleswitch/examples/toggleswitch-disabled.component.ts +++ b/src/stories/components/toggleswitch/examples/toggleswitch-disabled.component.ts @@ -1,14 +1,14 @@ import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { ToggleSwitchComponent } from '../../../../lib/components/toggleswitch/toggleswitch.component'; +import { ExtraToggleSwitchComponent } from '../../../../lib/components/toggleswitch/toggleswitch.component'; @Component({ selector: 'app-toggleswitch-disabled', standalone: true, - imports: [ToggleSwitchComponent, ReactiveFormsModule], + imports: [ExtraToggleSwitchComponent, ReactiveFormsModule], template: ` - + `, }) export class ToggleSwitchDisabledComponent { @@ -34,7 +34,7 @@ import { ToggleSwitchComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [ToggleSwitchComponent, ReactiveFormsModule], template: \` - + \`, }) export class ToggleSwitchDisabledComponent { diff --git a/src/stories/components/toggleswitch/examples/toggleswitch-invalid.component.ts b/src/stories/components/toggleswitch/examples/toggleswitch-invalid.component.ts index aced21f3..b9eb6e74 100644 --- a/src/stories/components/toggleswitch/examples/toggleswitch-invalid.component.ts +++ b/src/stories/components/toggleswitch/examples/toggleswitch-invalid.component.ts @@ -1,14 +1,14 @@ import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { ToggleSwitchComponent } from '../../../../lib/components/toggleswitch/toggleswitch.component'; +import { ExtraToggleSwitchComponent } from '../../../../lib/components/toggleswitch/toggleswitch.component'; @Component({ selector: 'app-toggleswitch-invalid', standalone: true, - imports: [ToggleSwitchComponent, ReactiveFormsModule], + imports: [ExtraToggleSwitchComponent, ReactiveFormsModule], template: ` - + `, }) export class ToggleSwitchInvalidComponent { @@ -35,7 +35,7 @@ import { ToggleSwitchComponent } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [ToggleSwitchComponent, ReactiveFormsModule], template: \` - + \`, }) export class ToggleSwitchInvalidComponent { diff --git a/src/stories/components/toggleswitch/toggleswitch.stories.ts b/src/stories/components/toggleswitch/toggleswitch.stories.ts index 640568da..d2919200 100644 --- a/src/stories/components/toggleswitch/toggleswitch.stories.ts +++ b/src/stories/components/toggleswitch/toggleswitch.stories.ts @@ -1,18 +1,18 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { ToggleSwitchComponent } from '../../../lib/components/toggleswitch/toggleswitch.component'; -import { ToggleSwitchCheckedComponent } from './examples/toggleswitch-checked.component'; -import { ToggleSwitchInvalidComponent } from './examples/toggleswitch-invalid.component'; -import { ToggleSwitchDisabledComponent } from './examples/toggleswitch-disabled.component'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { ExtraToggleSwitchComponent } from '../../../lib/components/toggleswitch/toggleswitch.component'; +import { ToggleSwitchCheckedComponent, Checked } from './examples/toggleswitch-checked.component'; +import { ToggleSwitchInvalidComponent, Invalid } from './examples/toggleswitch-invalid.component'; +import { ToggleSwitchDisabledComponent, Disabled } from './examples/toggleswitch-disabled.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Form/ToggleSwitch', - component: ToggleSwitchComponent, + component: ExtraToggleSwitchComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ imports: [ - ToggleSwitchComponent, + ExtraToggleSwitchComponent, ReactiveFormsModule, ToggleSwitchCheckedComponent, ToggleSwitchInvalidComponent, @@ -58,14 +58,14 @@ const meta: Meta = { }; export default meta; -type Story = StoryObj; +type Story = StoryObj; // ── Default ────────────────────────────────────────────────────────────────── export const Default: Story = { name: 'Default', render: () => ({ props: { control: new FormControl(false) }, - template: ``, + template: ``, }), parameters: { docs: { @@ -82,7 +82,7 @@ import { ToggleSwitchComponent } from '@cdek-it/angular-ui-kit'; @Component({ standalone: true, imports: [ToggleSwitchComponent, ReactiveFormsModule], - template: \`\`, + template: \`\`, }) export class Example { control = new FormControl(false); @@ -93,89 +93,4 @@ export class Example { }, }; -// ── Checked ─────────────────────────────────────────────────────────────────── -export const Checked: Story = { - render: () => ({ - template: ``, - }), - parameters: { - docs: { - description: { story: 'Переключатель во включённом состоянии.' }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { ToggleSwitchComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - standalone: true, - imports: [ToggleSwitchComponent, ReactiveFormsModule], - template: \`\`, -}) -export class ToggleSwitchCheckedComponent { - control = new FormControl(true); -} - `, - }, - }, - }, -}; - -// ── Invalid ─────────────────────────────────────────────────────────────────── -export const Invalid: Story = { - render: () => ({ - template: ``, - }), - parameters: { - docs: { - description: { story: 'Невалидное состояние через `FormControl` и `Validators`.' }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; -import { ToggleSwitchComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - standalone: true, - imports: [ToggleSwitchComponent, ReactiveFormsModule], - template: \`\`, -}) -export class ToggleSwitchInvalidComponent { - control = new FormControl(false, [Validators.requiredTrue]); -} - `, - }, - }, - }, -}; - -// ── Disabled ────────────────────────────────────────────────────────────────── -export const Disabled: Story = { - render: () => ({ - template: ``, - }), - parameters: { - docs: { - description: { story: 'Заблокированное состояние через `FormControl`.' }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { ToggleSwitchComponent } from '@cdek-it/angular-ui-kit'; - -@Component({ - standalone: true, - imports: [ToggleSwitchComponent, ReactiveFormsModule], - template: \`\`, -}) -export class ToggleSwitchDisabledComponent { - control = new FormControl({ value: false, disabled: true }); -} - `, - }, - }, - }, -}; +export { Checked, Disabled, Invalid }; From 9277af502fd68d2a350c0c6133f083fd6348c120 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Mon, 18 May 2026 22:34:40 +0700 Subject: [PATCH 249/258] DS-502 --- src/lib/components/tabs/ng-package.json | 7 +++ src/lib/components/tabs/public_api.ts | 4 ++ src/lib/components/tabs/tabs.component.ts | 6 +-- .../examples/tabs-with-badge.component.ts | 26 +++++------ .../examples/tabs-with-disabled.component.ts | 26 +++++------ src/stories/components/tabs/tabs.stories.ts | 46 +++++++++---------- 6 files changed, 61 insertions(+), 54 deletions(-) create mode 100644 src/lib/components/tabs/ng-package.json create mode 100644 src/lib/components/tabs/public_api.ts diff --git a/src/lib/components/tabs/ng-package.json b/src/lib/components/tabs/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/tabs/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/tabs/public_api.ts b/src/lib/components/tabs/public_api.ts new file mode 100644 index 00000000..26af794e --- /dev/null +++ b/src/lib/components/tabs/public_api.ts @@ -0,0 +1,4 @@ +export * from './tabs.component'; + + + diff --git a/src/lib/components/tabs/tabs.component.ts b/src/lib/components/tabs/tabs.component.ts index f88accd1..5fa9f6e7 100644 --- a/src/lib/components/tabs/tabs.component.ts +++ b/src/lib/components/tabs/tabs.component.ts @@ -17,7 +17,7 @@ export interface TabItem { } @Component({ - selector: 'tabs', + selector: 'extra-tabs', standalone: true, imports: [Tabs, TabList, Tab, TabPanels, TabPanel, Badge], template: ` @@ -56,8 +56,8 @@ export interface TabItem { `, }) -export class TabsComponent { - @Input() value: string | number = '0'; +export class ExtraTabsComponent { + @Input() value: string | number | undefined = '0'; @Input() tabs: TabItem[] = []; @Input() scrollable = false; @Input() lazy = false; diff --git a/src/stories/components/tabs/examples/tabs-with-badge.component.ts b/src/stories/components/tabs/examples/tabs-with-badge.component.ts index 21a15122..afc3e868 100644 --- a/src/stories/components/tabs/examples/tabs-with-badge.component.ts +++ b/src/stories/components/tabs/examples/tabs-with-badge.component.ts @@ -1,10 +1,10 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { TabsComponent, TabItem } from '../../../../lib/components/tabs/tabs.component'; +import { ExtraTabsComponent, TabItem } from '../../../../lib/components/tabs/tabs.component'; const template = `
- +
`; const styles = ''; @@ -12,21 +12,21 @@ const styles = ''; @Component({ selector: 'app-tabs-with-badge', standalone: true, - imports: [TabsComponent], + imports: [ExtraTabsComponent], template, - styles, + styles }) export class TabsWithBadgeComponent { tabs: TabItem[] = [ { value: '0', label: 'Tab 1', icon: 'ti ti-user', badge: '99+', content: 'Tab 1 Content' }, { value: '1', label: 'Tab 2', icon: 'ti ti-settings', badge: '5', content: 'Tab 2 Content' }, - { value: '2', label: 'Tab 3', icon: 'ti ti-bell', badge: '2', content: 'Tab 3 Content' }, + { value: '2', label: 'Tab 3', icon: 'ti ti-bell', badge: '2', content: 'Tab 3 Content' } ]; } export const WithBadge: StoryObj = { render: () => ({ - template: ``, + template: `` }), parameters: { docs: { @@ -35,14 +35,14 @@ export const WithBadge: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { TabsComponent, TabItem } from '@cdek-it/angular-ui-kit'; +import { ExtraTabsComponent, TabItem } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-tabs-with-badge', standalone: true, - imports: [TabsComponent], + imports: [ExtraTabsComponent], template: \` - + \`, }) export class TabsWithBadgeComponent { @@ -52,8 +52,8 @@ export class TabsWithBadgeComponent { { value: '2', label: 'Tab 3', icon: 'ti ti-bell', badge: '2', content: 'Tab 3 Content' }, ]; } - `, - }, - }, - }, + ` + } + } + } }; diff --git a/src/stories/components/tabs/examples/tabs-with-disabled.component.ts b/src/stories/components/tabs/examples/tabs-with-disabled.component.ts index 33a560c4..7e0f49dc 100644 --- a/src/stories/components/tabs/examples/tabs-with-disabled.component.ts +++ b/src/stories/components/tabs/examples/tabs-with-disabled.component.ts @@ -1,10 +1,10 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { TabsComponent, TabItem } from '../../../../lib/components/tabs/tabs.component'; +import { ExtraTabsComponent, TabItem } from '../../../../lib/components/tabs/tabs.component'; const template = `
- +
`; const styles = ''; @@ -12,21 +12,21 @@ const styles = ''; @Component({ selector: 'app-tabs-with-disabled', standalone: true, - imports: [TabsComponent], + imports: [ExtraTabsComponent], template, - styles, + styles }) export class TabsWithDisabledComponent { tabs: TabItem[] = [ { value: '0', label: 'Active Tab', icon: 'ti ti-user', content: 'Active Tab Content' }, { value: '1', label: 'Default Tab', icon: 'ti ti-settings', content: 'Default Tab Content' }, - { value: '2', label: 'Disabled Tab', icon: 'ti ti-bell', disabled: true, content: 'Disabled Tab Content' }, + { value: '2', label: 'Disabled Tab', icon: 'ti ti-bell', disabled: true, content: 'Disabled Tab Content' } ]; } export const WithDisabled: StoryObj = { render: () => ({ - template: ``, + template: `` }), parameters: { docs: { @@ -35,14 +35,14 @@ export const WithDisabled: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { TabsComponent, TabItem } from '@cdek-it/angular-ui-kit'; +import { ExtraTabsComponent, TabItem } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-tabs-with-disabled', standalone: true, - imports: [TabsComponent], + imports: [ExtraTabsComponent], template: \` - + \`, }) export class TabsWithDisabledComponent { @@ -52,8 +52,8 @@ export class TabsWithDisabledComponent { { value: '2', label: 'Disabled Tab', icon: 'ti ti-bell', disabled: true, content: 'Disabled Tab Content' }, ]; } - `, - }, - }, - }, + ` + } + } + } }; diff --git a/src/stories/components/tabs/tabs.stories.ts b/src/stories/components/tabs/tabs.stories.ts index 1f86ad7c..14a14b4b 100644 --- a/src/stories/components/tabs/tabs.stories.ts +++ b/src/stories/components/tabs/tabs.stories.ts @@ -1,20 +1,16 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { TabsComponent } from '../../../lib/components/tabs/tabs.component'; +import { ExtraTabsComponent } from '../../../lib/components/tabs/tabs.component'; import { TabsWithBadgeComponent, WithBadge } from './examples/tabs-with-badge.component'; import { TabsWithDisabledComponent, WithDisabled } from './examples/tabs-with-disabled.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Menu/Tabs', - component: TabsComponent, + component: ExtraTabsComponent, tags: ['autodocs'], decorators: [ moduleMetadata({ - imports: [ - TabsComponent, - TabsWithBadgeComponent, - TabsWithDisabledComponent, - ], - }), + imports: [ExtraTabsComponent, TabsWithBadgeComponent, TabsWithDisabledComponent] + }) ], parameters: { docs: { @@ -22,11 +18,11 @@ const meta: Meta = { component: `Организует контент по вкладкам с возможностью переключения между ними. \`\`\`typescript -import { TabsComponent, TabItem } from '@cdek-it/angular-ui-kit'; -\`\`\``, - }, +import { ExtraTabsComponent, TabItem } from '@cdek-it/angular-ui-kit'; +\`\`\`` + } }, - designTokens: { prefix: '--p-tabs' }, + designTokens: { prefix: '--p-tabs' } }, argTypes: { value: { @@ -35,8 +31,8 @@ import { TabsComponent, TabItem } from '@cdek-it/angular-ui-kit'; table: { category: 'Props', defaultValue: { summary: '0' }, - type: { summary: 'string | number' }, - }, + type: { summary: 'string | number' } + } }, scrollable: { control: 'boolean', @@ -44,8 +40,8 @@ import { TabsComponent, TabItem } from '@cdek-it/angular-ui-kit'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, lazy: { control: 'boolean', @@ -53,22 +49,22 @@ import { TabsComponent, TabItem } from '@cdek-it/angular-ui-kit'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, tabs: { control: 'object', description: 'Массив вкладок', table: { category: 'Props', - type: { summary: 'TabItem[]' }, - }, - }, - }, + type: { summary: 'TabItem[]' } + } + } + } }; export default meta; -type Story = StoryObj; +type Story = StoryObj; // ── Default ─────────────────────────────────────────────────────────────────── @@ -82,7 +78,7 @@ export const Default: Story = { if (args.scrollable) parts.push(`[scrollable]="true"`); if (args.lazy) parts.push(`[lazy]="true"`); - const template = ``; + const template = ``; return { props: args, template }; }, From 28926a8d4d164824ff9c5b0180b3188a65cf811a Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Tue, 19 May 2026 20:01:57 +0700 Subject: [PATCH 250/258] DS-502 --- .../components/listbox/listbox.component.ts | 6 ++--- src/lib/components/listbox/ng-package.json | 7 ++++++ src/lib/components/listbox/public_api.ts | 4 ++++ .../examples/listbox-checkmark.component.ts | 12 +++++----- .../examples/listbox-disabled.component.ts | 12 +++++----- .../examples/listbox-filter.component.ts | 12 +++++----- .../examples/listbox-grouped.component.ts | 16 +++++++------- .../examples/listbox-multiple.component.ts | 12 +++++----- .../components/listbox/listbox.stories.ts | 22 +++++++++---------- 9 files changed, 57 insertions(+), 46 deletions(-) create mode 100644 src/lib/components/listbox/ng-package.json create mode 100644 src/lib/components/listbox/public_api.ts diff --git a/src/lib/components/listbox/listbox.component.ts b/src/lib/components/listbox/listbox.component.ts index 2bfc135b..91bdbbc7 100644 --- a/src/lib/components/listbox/listbox.component.ts +++ b/src/lib/components/listbox/listbox.component.ts @@ -3,12 +3,12 @@ import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/f import { Listbox, ListboxChangeEvent } from 'primeng/listbox'; @Component({ - selector: 'listbox', + selector: 'extra-listbox', standalone: true, imports: [Listbox, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [ - { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ListboxComponent), multi: true }, + { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ExtraListboxComponent), multi: true }, ], template: ` `, }) -export class ListboxComponent implements ControlValueAccessor { +export class ExtraListboxComponent implements ControlValueAccessor { @Input() options: any[] = []; @Input() optionLabel = 'label'; @Input() optionValue: string | undefined = undefined; diff --git a/src/lib/components/listbox/ng-package.json b/src/lib/components/listbox/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/listbox/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/listbox/public_api.ts b/src/lib/components/listbox/public_api.ts new file mode 100644 index 00000000..fb44d91e --- /dev/null +++ b/src/lib/components/listbox/public_api.ts @@ -0,0 +1,4 @@ +export * from './listbox.component'; + + + diff --git a/src/stories/components/listbox/examples/listbox-checkmark.component.ts b/src/stories/components/listbox/examples/listbox-checkmark.component.ts index e83ad951..b5ccb60f 100644 --- a/src/stories/components/listbox/examples/listbox-checkmark.component.ts +++ b/src/stories/components/listbox/examples/listbox-checkmark.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { ListboxComponent } from '../../../../lib/components/listbox/listbox.component'; +import { ExtraListboxComponent } from '../../../../lib/components/listbox/listbox.component'; const options = [ { label: 'New York', value: 'NY' }, @@ -12,14 +12,14 @@ const options = [ ]; const template = ` - + `; const styles = ''; @Component({ selector: 'app-listbox-checkmark', standalone: true, - imports: [ListboxComponent, ReactiveFormsModule], + imports: [ExtraListboxComponent, ReactiveFormsModule], template, styles, }) @@ -41,14 +41,14 @@ export const Checkmark: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { ListboxComponent } from '@cdek-it/angular-ui-kit'; + import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-listbox-checkmark', standalone: true, - imports: [ListboxComponent, ReactiveFormsModule], + imports: [ExtraListboxComponent, ReactiveFormsModule], template: \` - + \`, }) export class ListboxCheckmarkComponent { diff --git a/src/stories/components/listbox/examples/listbox-disabled.component.ts b/src/stories/components/listbox/examples/listbox-disabled.component.ts index 8d36ba4c..3d59b2a6 100644 --- a/src/stories/components/listbox/examples/listbox-disabled.component.ts +++ b/src/stories/components/listbox/examples/listbox-disabled.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { ListboxComponent } from '../../../../lib/components/listbox/listbox.component'; +import { ExtraListboxComponent } from '../../../../lib/components/listbox/listbox.component'; const options = [ { label: 'New York', value: 'NY' }, @@ -12,14 +12,14 @@ const options = [ ]; const template = ` - + `; const styles = ''; @Component({ selector: 'app-listbox-disabled', standalone: true, - imports: [ListboxComponent, ReactiveFormsModule], + imports: [ExtraListboxComponent, ReactiveFormsModule], template, styles, }) @@ -41,14 +41,14 @@ export const Disabled: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { ListboxComponent } from '@cdek-it/angular-ui-kit'; + import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-listbox-disabled', standalone: true, - imports: [ListboxComponent, ReactiveFormsModule], + imports: [ExtraListboxComponent, ReactiveFormsModule], template: \` - + \`, }) export class ListboxDisabledComponent { diff --git a/src/stories/components/listbox/examples/listbox-filter.component.ts b/src/stories/components/listbox/examples/listbox-filter.component.ts index 6469829d..931910fe 100644 --- a/src/stories/components/listbox/examples/listbox-filter.component.ts +++ b/src/stories/components/listbox/examples/listbox-filter.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { ListboxComponent } from '../../../../lib/components/listbox/listbox.component'; +import { ExtraListboxComponent } from '../../../../lib/components/listbox/listbox.component'; const options = [ { label: 'New York', value: 'NY' }, @@ -12,14 +12,14 @@ const options = [ ]; const template = ` - + `; const styles = ''; @Component({ selector: 'app-listbox-filter', standalone: true, - imports: [ListboxComponent, ReactiveFormsModule], + imports: [ExtraListboxComponent, ReactiveFormsModule], template, styles, }) @@ -41,14 +41,14 @@ export const Filter: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { ListboxComponent } from '@cdek-it/angular-ui-kit'; + import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-listbox-filter', standalone: true, - imports: [ListboxComponent, ReactiveFormsModule], + imports: [ExtraListboxComponent, ReactiveFormsModule], template: \` - + \`, }) export class ListboxFilterComponent { diff --git a/src/stories/components/listbox/examples/listbox-grouped.component.ts b/src/stories/components/listbox/examples/listbox-grouped.component.ts index 29fa608d..7b0938c9 100644 --- a/src/stories/components/listbox/examples/listbox-grouped.component.ts +++ b/src/stories/components/listbox/examples/listbox-grouped.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { ListboxComponent } from '../../../../lib/components/listbox/listbox.component'; +import { ExtraListboxComponent } from '../../../../lib/components/listbox/listbox.component'; const groupedOptions = [ { @@ -23,21 +23,21 @@ const groupedOptions = [ ]; const template = ` - +> `; const styles = ''; @Component({ selector: 'app-listbox-grouped', standalone: true, - imports: [ListboxComponent, ReactiveFormsModule], + imports: [ExtraListboxComponent, ReactiveFormsModule], template, styles, }) @@ -59,21 +59,21 @@ export const Grouped: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { ListboxComponent } from '@cdek-it/angular-ui-kit'; + import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-listbox-grouped', standalone: true, - imports: [ListboxComponent, ReactiveFormsModule], + imports: [ExtraListboxComponent, ReactiveFormsModule], template: \` - + > \`, }) export class ListboxGroupedComponent { diff --git a/src/stories/components/listbox/examples/listbox-multiple.component.ts b/src/stories/components/listbox/examples/listbox-multiple.component.ts index 371be1c1..92be37d0 100644 --- a/src/stories/components/listbox/examples/listbox-multiple.component.ts +++ b/src/stories/components/listbox/examples/listbox-multiple.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { ListboxComponent } from '../../../../lib/components/listbox/listbox.component'; +import { ExtraListboxComponent } from '../../../../lib/components/listbox/listbox.component'; const options = [ { label: 'New York', value: 'NY' }, @@ -12,14 +12,14 @@ const options = [ ]; const template = ` - + `; const styles = ''; @Component({ selector: 'app-listbox-multiple', standalone: true, - imports: [ListboxComponent, ReactiveFormsModule], + imports: [ExtraListboxComponent, ReactiveFormsModule], template, styles, }) @@ -41,14 +41,14 @@ export const Multiple: StoryObj = { code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { ListboxComponent } from '@cdek-it/angular-ui-kit'; + import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-listbox-multiple', standalone: true, - imports: [ListboxComponent, ReactiveFormsModule], + imports: [ExtraListboxComponent, ReactiveFormsModule], template: \` - + \`, }) export class ListboxMultipleComponent { diff --git a/src/stories/components/listbox/listbox.stories.ts b/src/stories/components/listbox/listbox.stories.ts index 095a9c42..a6f7be6a 100644 --- a/src/stories/components/listbox/listbox.stories.ts +++ b/src/stories/components/listbox/listbox.stories.ts @@ -1,7 +1,7 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { Listbox } from 'primeng/listbox'; -import { ListboxComponent } from '../../../lib/components/listbox/listbox.component'; +import { ExtraListboxComponent } from '../../../lib/components/listbox/listbox.component'; import { ListboxCheckmarkComponent, Checkmark } from './examples/listbox-checkmark.component'; import { ListboxFilterComponent, Filter } from './examples/listbox-filter.component'; import { ListboxMultipleComponent, Multiple } from './examples/listbox-multiple.component'; @@ -9,18 +9,18 @@ import { ListboxGroupedComponent, Grouped } from './examples/listbox-grouped.com import { ListboxCustomComponent, Custom } from './examples/listbox-custom.component'; import { ListboxDisabledComponent, Disabled } from './examples/listbox-disabled.component'; -type ListboxArgs = ListboxComponent; +type ListboxArgs = ExtraListboxComponent; const meta: Meta = { title: 'Components/Form/Listbox', - component: ListboxComponent, + component: ExtraListboxComponent, tags: ['autodocs'], decorators: [ - moduleMetadata({ - imports: [ - ListboxComponent, - ReactiveFormsModule, - Listbox, + moduleMetadata({ + imports: [ + ExtraListboxComponent, + ReactiveFormsModule, + Listbox, ListboxCheckmarkComponent, ListboxFilterComponent, ListboxMultipleComponent, @@ -37,7 +37,7 @@ const meta: Meta = { component: `Список опций с поддержкой одиночного и множественного выбора. Поддерживает группировку, фильтрацию, галочку выбора и кастомные шаблоны пунктов. \`\`\`typescript -import { ListboxComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -178,7 +178,7 @@ export const Default: Story = { options: defaultOptions, }, template: ` -`, +>`, }), parameters: { docs: { From 91405b595a5cf3e59ee1f44bb23ccb91f6665df3 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Tue, 19 May 2026 20:33:36 +0700 Subject: [PATCH 251/258] DS-513 --- .../components/listbox/listbox.component.ts | 56 ++++++++++++++++--- .../examples/listbox-custom.component.ts | 14 ++--- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/lib/components/listbox/listbox.component.ts b/src/lib/components/listbox/listbox.component.ts index 91bdbbc7..9ca7d020 100644 --- a/src/lib/components/listbox/listbox.component.ts +++ b/src/lib/components/listbox/listbox.component.ts @@ -1,15 +1,26 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, forwardRef } from '@angular/core'; +import { + AfterContentInit, + ChangeDetectionStrategy, + Component, + ContentChildren, + ChangeDetectorRef, + EventEmitter, + Input, + Output, + QueryList, + forwardRef +} from '@angular/core'; import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Listbox, ListboxChangeEvent } from 'primeng/listbox'; +import { PrimeTemplate, SharedModule } from 'primeng/api'; +import { NgTemplateOutlet } from '@angular/common'; @Component({ selector: 'extra-listbox', standalone: true, - imports: [Listbox, FormsModule], + imports: [Listbox, FormsModule, SharedModule, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, - providers: [ - { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ExtraListboxComponent), multi: true }, - ], + providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ExtraListboxComponent), multi: true }], template: ` - `, + > + + + + + + @if (itemTpl) { + + } + + + ` }) -export class ExtraListboxComponent implements ControlValueAccessor { +export class ExtraListboxComponent implements ControlValueAccessor, AfterContentInit { @Input() options: any[] = []; @Input() optionLabel = 'label'; @Input() optionValue: string | undefined = undefined; @@ -51,6 +75,9 @@ export class ExtraListboxComponent implements ControlValueAccessor { protected modelValue: any = null; + @ContentChildren(PrimeTemplate) templates!: QueryList; + itemTpl?: PrimeTemplate; + private _disabled = false; private _onChange: (value: any) => void = () => {}; private _onTouched: () => void = () => {}; @@ -59,6 +86,19 @@ export class ExtraListboxComponent implements ControlValueAccessor { return this._disabled; } + constructor(private cdr: ChangeDetectorRef) {} + + ngAfterContentInit(): void { + this.templates.forEach((tpl) => { + switch (tpl.getType()) { + case 'item': + this.itemTpl = tpl; + break; + } + }); + this.cdr.detectChanges(); + } + onChangeHandler(event: ListboxChangeEvent): void { // Обновляем внутреннее значение и уведомляем форму об изменении. this.modelValue = event.value; diff --git a/src/stories/components/listbox/examples/listbox-custom.component.ts b/src/stories/components/listbox/examples/listbox-custom.component.ts index 12345c5d..be05b8e9 100644 --- a/src/stories/components/listbox/examples/listbox-custom.component.ts +++ b/src/stories/components/listbox/examples/listbox-custom.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; -import { Listbox } from 'primeng/listbox'; +import { ExtraListboxComponent } from '../../../../lib/components/listbox/listbox.component'; import { SharedModule } from 'primeng/api'; const options = [ @@ -11,7 +11,7 @@ const options = [ ]; const template = ` - +
@@ -19,14 +19,14 @@ const template = ` {{ item.description }}
-
+ `; const styles = ''; @Component({ selector: 'app-listbox-custom', standalone: true, - imports: [Listbox, SharedModule, ReactiveFormsModule], + imports: [ExtraListboxComponent, SharedModule, ReactiveFormsModule], template, styles, }) @@ -54,9 +54,9 @@ import { SharedModule } from 'primeng/api'; @Component({ selector: 'app-listbox-custom', standalone: true, - imports: [Listbox, SharedModule, ReactiveFormsModule], + imports: [ExtraListboxComponent, SharedModule, ReactiveFormsModule], template: \` - +
@@ -64,7 +64,7 @@ import { SharedModule } from 'primeng/api'; {{ item.description }}
-
+ \`, }) export class ListboxCustomComponent { From 0dc7706264739df7e44591412c25a2381c8f0f08 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Tue, 19 May 2026 20:52:19 +0700 Subject: [PATCH 252/258] DS-513 --- src/lib/components/menu/menu.component.ts | 8 +- src/lib/components/menu/ng-package.json | 7 ++ src/lib/components/menu/public_api.ts | 4 + .../components/listbox/listbox.stories.ts | 88 +++++++++---------- .../menu/examples/menu-basic.component.ts | 8 +- .../menu/examples/menu-custom.component.ts | 8 +- .../menu/examples/menu-grouped.component.ts | 8 +- .../menu/examples/menu-popup.component.ts | 14 +-- .../examples/menu-with-icons.component.ts | 8 +- src/stories/components/menu/menu.stories.ts | 54 ++++++------ 10 files changed, 109 insertions(+), 98 deletions(-) create mode 100644 src/lib/components/menu/ng-package.json create mode 100644 src/lib/components/menu/public_api.ts diff --git a/src/lib/components/menu/menu.component.ts b/src/lib/components/menu/menu.component.ts index a692f69c..21b87981 100644 --- a/src/lib/components/menu/menu.component.ts +++ b/src/lib/components/menu/menu.component.ts @@ -3,12 +3,12 @@ import { NgTemplateOutlet } from '@angular/common'; import { Menu } from 'primeng/menu'; import { MenuItem, PrimeTemplate } from 'primeng/api'; -export interface MenuModel extends MenuItem { +export interface ExtraMenuModel extends MenuItem { caption?: string; } @Component({ - selector: 'menu', + selector: 'extra-menu', host: { style: 'display: contents' }, standalone: true, imports: [Menu, PrimeTemplate, NgTemplateOutlet], @@ -46,10 +46,10 @@ export interface MenuModel extends MenuItem { `, }) -export class MenuComponent { +export class ExtraMenuComponent { @ViewChild('menuRef') menuRef!: Menu; - @Input() model: MenuModel[] = []; + @Input() model: ExtraMenuModel[] = []; @Input() popup = false; @Input() itemTemplate: TemplateRef | null = null; diff --git a/src/lib/components/menu/ng-package.json b/src/lib/components/menu/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/menu/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/menu/public_api.ts b/src/lib/components/menu/public_api.ts new file mode 100644 index 00000000..50e5b520 --- /dev/null +++ b/src/lib/components/menu/public_api.ts @@ -0,0 +1,4 @@ +export * from './menu.component'; + + + diff --git a/src/stories/components/listbox/listbox.stories.ts b/src/stories/components/listbox/listbox.stories.ts index a6f7be6a..0e0933d5 100644 --- a/src/stories/components/listbox/listbox.stories.ts +++ b/src/stories/components/listbox/listbox.stories.ts @@ -13,22 +13,22 @@ type ListboxArgs = ExtraListboxComponent; const meta: Meta = { title: 'Components/Form/Listbox', - component: ExtraListboxComponent, + component: ExtraListboxComponent, tags: ['autodocs'], decorators: [ - moduleMetadata({ - imports: [ - ExtraListboxComponent, - ReactiveFormsModule, - Listbox, + moduleMetadata({ + imports: [ + ExtraListboxComponent, + ReactiveFormsModule, + Listbox, ListboxCheckmarkComponent, ListboxFilterComponent, ListboxMultipleComponent, ListboxGroupedComponent, ListboxCustomComponent, - ListboxDisabledComponent, - ], - }), + ListboxDisabledComponent + ] + }) ], parameters: { designTokens: { prefix: '--p-listbox' }, @@ -38,9 +38,9 @@ const meta: Meta = { \`\`\`typescript import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; -\`\`\``, - }, - }, +\`\`\`` + } + } }, argTypes: { options: { table: { disable: true } }, @@ -53,8 +53,8 @@ import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; table: { category: 'Props', defaultValue: { summary: 'label' }, - type: { summary: 'string' }, - }, + type: { summary: 'string' } + } }, optionValue: { control: 'text', @@ -62,8 +62,8 @@ import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; table: { category: 'Props', defaultValue: { summary: 'undefined' }, - type: { summary: 'string' }, - }, + type: { summary: 'string' } + } }, multiple: { control: 'boolean', @@ -71,8 +71,8 @@ import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, filter: { control: 'boolean', @@ -80,8 +80,8 @@ import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, filterPlaceHolder: { control: 'text', @@ -89,8 +89,8 @@ import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; table: { category: 'Props', defaultValue: { summary: 'undefined' }, - type: { summary: 'string' }, - }, + type: { summary: 'string' } + } }, checkmark: { control: 'boolean', @@ -98,8 +98,8 @@ import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, group: { control: 'boolean', @@ -107,8 +107,8 @@ import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; table: { category: 'Props', defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, + type: { summary: 'boolean' } + } }, scrollHeight: { control: 'text', @@ -116,8 +116,8 @@ import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; table: { category: 'Props', defaultValue: { summary: '200px' }, - type: { summary: 'string' }, - }, + type: { summary: 'string' } + } }, emptyMessage: { control: 'text', @@ -125,8 +125,8 @@ import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; table: { category: 'Props', defaultValue: { summary: 'undefined' }, - type: { summary: 'string' }, - }, + type: { summary: 'string' } + } }, // ── Events ─────────────────────────────────────────────── onFocus: { @@ -134,17 +134,17 @@ import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; description: 'Событие фокуса', table: { category: 'Events', - type: { summary: 'EventEmitter' }, - }, + type: { summary: 'EventEmitter' } + } }, onBlur: { control: false, description: 'Событие потери фокуса', table: { category: 'Events', - type: { summary: 'EventEmitter' }, - }, - }, + type: { summary: 'EventEmitter' } + } + } }, args: { optionLabel: 'label', @@ -152,8 +152,8 @@ import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; filter: false, checkmark: false, group: false, - scrollHeight: '200px', - }, + scrollHeight: '200px' + } }; export default meta; @@ -164,7 +164,7 @@ const defaultOptions = [ { label: 'Rome', value: 'RM' }, { label: 'London', value: 'LDN' }, { label: 'Istanbul', value: 'IST' }, - { label: 'Paris', value: 'PRS' }, + { label: 'Paris', value: 'PRS' } ]; // ── Default ────────────────────────────────────────────────────────────────── @@ -175,7 +175,7 @@ export const Default: Story = { props: { ...args, ctrl: new FormControl(null), - options: defaultOptions, + options: defaultOptions }, template: ` `, +>` }), parameters: { docs: { description: { - story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', - }, - }, - }, + story: 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.' + } + } + } }; // ── Варианты ───────────────────────────────────────────────────────────────── diff --git a/src/stories/components/menu/examples/menu-basic.component.ts b/src/stories/components/menu/examples/menu-basic.component.ts index e18fe088..48d59eed 100644 --- a/src/stories/components/menu/examples/menu-basic.component.ts +++ b/src/stories/components/menu/examples/menu-basic.component.ts @@ -1,20 +1,20 @@ import { Component } from '@angular/core'; -import { MenuComponent, MenuModel } from '../../../../lib/components/menu/menu.component'; +import { ExtraMenuComponent, ExtraMenuModel } from '../../../../lib/components/menu/menu.component'; const template = `
- +
`; @Component({ selector: 'app-menu-basic', standalone: true, - imports: [MenuComponent], + imports: [ExtraMenuComponent], template, }) export class MenuBasicComponent { - items: MenuModel[] = [ + items: ExtraMenuModel[] = [ { label: 'Новый заказ' }, { label: 'Поиск отправления' }, { separator: true }, diff --git a/src/stories/components/menu/examples/menu-custom.component.ts b/src/stories/components/menu/examples/menu-custom.component.ts index 3d04f2b6..e3378ae8 100644 --- a/src/stories/components/menu/examples/menu-custom.component.ts +++ b/src/stories/components/menu/examples/menu-custom.component.ts @@ -1,20 +1,20 @@ import { Component } from '@angular/core'; -import { MenuComponent, MenuModel } from '../../../../lib/components/menu/menu.component'; +import { ExtraMenuComponent, ExtraMenuModel } from '../../../../lib/components/menu/menu.component'; const template = `
- +
`; @Component({ selector: 'app-menu-custom', standalone: true, - imports: [MenuComponent], + imports: [ExtraMenuComponent], template, }) export class MenuCustomComponent { - items: MenuModel[] = [ + items: ExtraMenuModel[] = [ { label: 'Создать отправление', caption: 'Оформление нового заказа', diff --git a/src/stories/components/menu/examples/menu-grouped.component.ts b/src/stories/components/menu/examples/menu-grouped.component.ts index d1050f38..3d838ce1 100644 --- a/src/stories/components/menu/examples/menu-grouped.component.ts +++ b/src/stories/components/menu/examples/menu-grouped.component.ts @@ -1,20 +1,20 @@ import { Component } from '@angular/core'; -import { MenuComponent, MenuModel } from '../../../../lib/components/menu/menu.component'; +import { ExtraMenuComponent, ExtraMenuModel } from '../../../../lib/components/menu/menu.component'; const template = `
- +
`; @Component({ selector: 'app-menu-grouped', standalone: true, - imports: [MenuComponent], + imports: [ExtraMenuComponent], template, }) export class MenuGroupedComponent { - items: MenuModel[] = [ + items: ExtraMenuModel[] = [ { label: 'Заказы', items: [ diff --git a/src/stories/components/menu/examples/menu-popup.component.ts b/src/stories/components/menu/examples/menu-popup.component.ts index 09241ca4..fd222ee4 100644 --- a/src/stories/components/menu/examples/menu-popup.component.ts +++ b/src/stories/components/menu/examples/menu-popup.component.ts @@ -1,24 +1,24 @@ import { Component, ViewChild } from '@angular/core'; -import { MenuComponent, MenuModel } from '../../../../lib/components/menu/menu.component'; -import { ButtonComponent } from '../../../../lib/components/button/button.component'; +import { ExtraMenuComponent, ExtraMenuModel } from '../../../../lib/components/menu/menu.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; const template = `
- - + +
`; @Component({ selector: 'app-menu-popup', standalone: true, - imports: [MenuComponent, ButtonComponent], + imports: [ExtraMenuComponent, ExtraButtonComponent], template, }) export class MenuPopupComponent { - @ViewChild('menuRef') menuRef!: MenuComponent; + @ViewChild('menuRef') menuRef!: ExtraMenuComponent; - items: MenuModel[] = [ + items: ExtraMenuModel[] = [ { label: 'Создать отправление', icon: 'ti ti-file-plus' }, { label: 'Найти по трек-номеру', icon: 'ti ti-search' }, { separator: true }, diff --git a/src/stories/components/menu/examples/menu-with-icons.component.ts b/src/stories/components/menu/examples/menu-with-icons.component.ts index dbffd8d0..061da8d6 100644 --- a/src/stories/components/menu/examples/menu-with-icons.component.ts +++ b/src/stories/components/menu/examples/menu-with-icons.component.ts @@ -1,20 +1,20 @@ import { Component } from '@angular/core'; -import { MenuComponent, MenuModel } from '../../../../lib/components/menu/menu.component'; +import { ExtraMenuComponent, ExtraMenuModel } from '../../../../lib/components/menu/menu.component'; const template = `
- +
`; @Component({ selector: 'app-menu-with-icons', standalone: true, - imports: [MenuComponent], + imports: [ExtraMenuComponent], template, }) export class MenuWithIconsComponent { - items: MenuModel[] = [ + items: ExtraMenuModel[] = [ { label: 'Создать отправление', icon: 'ti ti-file-plus' }, { label: 'Открыть список заказов', icon: 'ti ti-folder-open' }, { label: 'Сохранить черновик', icon: 'ti ti-device-floppy' }, diff --git a/src/stories/components/menu/menu.stories.ts b/src/stories/components/menu/menu.stories.ts index 65690f5d..d96b0449 100644 --- a/src/stories/components/menu/menu.stories.ts +++ b/src/stories/components/menu/menu.stories.ts @@ -1,14 +1,14 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { MenuComponent } from '../../../lib/components/menu/menu.component'; +import { ExtraMenuComponent } from '../../../lib/components/menu/menu.component'; import { MenuPopupComponent } from './examples/menu-popup.component'; import { MenuBasicComponent } from './examples/menu-basic.component'; import { MenuWithIconsComponent } from './examples/menu-with-icons.component'; import { MenuGroupedComponent } from './examples/menu-grouped.component'; import { MenuCustomComponent } from './examples/menu-custom.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Menu/Menu', - component: MenuComponent, + component: ExtraMenuComponent, tags: ['autodocs'], parameters: { docs: { @@ -16,7 +16,7 @@ const meta: Meta = { component: `Компонент навигационного меню. Поддерживает режим popup (по нажатию на триггер) и inline-отображение, группировку пунктов и пункты с описанием (caption). \`\`\`typescript -import { MenuComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraMenuComponent } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -28,7 +28,7 @@ import { MenuComponent } from '@cdek-it/angular-ui-kit'; description: 'Массив пунктов меню.', table: { category: 'Props', - type: { summary: 'MenuModel[]' }, + type: { summary: 'ExtraMenuModel[]' }, }, }, popup: { @@ -44,7 +44,7 @@ import { MenuComponent } from '@cdek-it/angular-ui-kit'; }; export default meta; -type Story = StoryObj; +type Story = StoryObj; // ── Popup ───────────────────────────────────────────────────────────────────── @@ -61,21 +61,21 @@ export const Default: Story = { language: 'ts', code: ` import { Component, ViewChild } from '@angular/core'; -import { MenuComponent, MenuModel, ButtonComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraMenuComponent, ExtraMenuModel, ButtonComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-menu-popup', standalone: true, - imports: [MenuComponent, ButtonComponent], + imports: [ExtraMenuComponent, ButtonComponent], template: \` - + \`, }) export class MenuPopupComponent { - @ViewChild('menuRef') menuRef!: MenuComponent; + @ViewChild('menuRef') menuRef!: ExtraMenuComponent; - items: MenuModel[] = [ + items: ExtraMenuModel[] = [ { label: 'Создать отправление', icon: 'ti ti-file-plus' }, { label: 'Найти по трек-номеру', icon: 'ti ti-search' }, { separator: true }, @@ -107,18 +107,18 @@ export const Basic: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MenuComponent, MenuModel } from '@cdek-it/angular-ui-kit'; +import { ExtraMenuComponent, ExtraMenuModel } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-menu-basic', standalone: true, - imports: [MenuComponent], + imports: [ExtraMenuComponent], template: \` - + \`, }) export class MenuBasicComponent { - items: MenuModel[] = [ + items: ExtraMenuModel[] = [ { label: 'Новый заказ' }, { label: 'Поиск отправления' }, { separator: true }, @@ -146,18 +146,18 @@ export const WithIcons: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MenuComponent, MenuModel } from '@cdek-it/angular-ui-kit'; +import { ExtraMenuComponent, ExtraMenuModel } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-menu-with-icons', standalone: true, - imports: [MenuComponent], + imports: [ExtraMenuComponent], template: \` - + \`, }) export class MenuWithIconsComponent { - items: MenuModel[] = [ + items: ExtraMenuModel[] = [ { label: 'Создать отправление', icon: 'ti ti-file-plus' }, { label: 'Открыть список заказов', icon: 'ti ti-folder-open' }, { label: 'Сохранить черновик', icon: 'ti ti-device-floppy' }, @@ -187,18 +187,18 @@ export const Grouped: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MenuComponent, MenuModel } from '@cdek-it/angular-ui-kit'; +import { ExtraMenuComponent, ExtraMenuModel } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-menu-grouped', standalone: true, - imports: [MenuComponent], + imports: [ExtraMenuComponent], template: \` - + \`, }) export class MenuGroupedComponent { - items: MenuModel[] = [ + items: ExtraMenuModel[] = [ { label: 'Заказы', items: [ @@ -238,18 +238,18 @@ export const Custom: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { MenuComponent, MenuModel } from '@cdek-it/angular-ui-kit'; +import { ExtraMenuComponent, ExtraMenuModel } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-menu-custom', standalone: true, - imports: [MenuComponent], + imports: [ExtraMenuComponent], template: \` - + \`, }) export class MenuCustomComponent { - items: MenuModel[] = [ + items: ExtraMenuModel[] = [ { label: 'Создать отправление', caption: 'Оформление нового заказа', From d35df90c89f7051d770719ae3881df3d0eb000de Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Fri, 22 May 2026 13:39:55 +0700 Subject: [PATCH 253/258] DS-513 --- .../components/listbox/listbox.component.ts | 38 ++++---------- .../examples/listbox-custom.component.ts | 50 +++++++++---------- .../menu/examples/menu-custom.component.ts | 38 +++++++++++++- src/stories/components/menu/menu.stories.ts | 40 ++++++++++++++- 4 files changed, 108 insertions(+), 58 deletions(-) diff --git a/src/lib/components/listbox/listbox.component.ts b/src/lib/components/listbox/listbox.component.ts index 9ca7d020..2ed2f0e8 100644 --- a/src/lib/components/listbox/listbox.component.ts +++ b/src/lib/components/listbox/listbox.component.ts @@ -1,18 +1,15 @@ import { - AfterContentInit, ChangeDetectionStrategy, Component, - ContentChildren, - ChangeDetectorRef, EventEmitter, Input, Output, - QueryList, + TemplateRef, forwardRef } from '@angular/core'; import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Listbox, ListboxChangeEvent } from 'primeng/listbox'; -import { PrimeTemplate, SharedModule } from 'primeng/api'; +import { SharedModule } from 'primeng/api'; import { NgTemplateOutlet } from '@angular/common'; @Component({ @@ -41,22 +38,18 @@ import { NgTemplateOutlet } from '@angular/common'; (onFocus)="onFocus.emit($event)" (onBlur)="onBlurHandler($event)" > - - - - - - @if (itemTpl) { + @if (itemTemplate) { + - } - + + } ` }) -export class ExtraListboxComponent implements ControlValueAccessor, AfterContentInit { +export class ExtraListboxComponent implements ControlValueAccessor { @Input() options: any[] = []; @Input() optionLabel = 'label'; @Input() optionValue: string | undefined = undefined; @@ -69,14 +62,13 @@ export class ExtraListboxComponent implements ControlValueAccessor, AfterContent @Input() optionGroupChildren: string | undefined = undefined; @Input() scrollHeight = '200px'; @Input() emptyMessage: string | undefined = undefined; + @Input() itemTemplate: TemplateRef | null = null; @Output() onFocus = new EventEmitter(); @Output() onBlur = new EventEmitter(); protected modelValue: any = null; - @ContentChildren(PrimeTemplate) templates!: QueryList; - itemTpl?: PrimeTemplate; private _disabled = false; private _onChange: (value: any) => void = () => {}; @@ -86,18 +78,6 @@ export class ExtraListboxComponent implements ControlValueAccessor, AfterContent return this._disabled; } - constructor(private cdr: ChangeDetectorRef) {} - - ngAfterContentInit(): void { - this.templates.forEach((tpl) => { - switch (tpl.getType()) { - case 'item': - this.itemTpl = tpl; - break; - } - }); - this.cdr.detectChanges(); - } onChangeHandler(event: ListboxChangeEvent): void { // Обновляем внутреннее значение и уведомляем форму об изменении. diff --git a/src/stories/components/listbox/examples/listbox-custom.component.ts b/src/stories/components/listbox/examples/listbox-custom.component.ts index be05b8e9..1643bed9 100644 --- a/src/stories/components/listbox/examples/listbox-custom.component.ts +++ b/src/stories/components/listbox/examples/listbox-custom.component.ts @@ -2,7 +2,6 @@ import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { StoryObj } from '@storybook/angular'; import { ExtraListboxComponent } from '../../../../lib/components/listbox/listbox.component'; -import { SharedModule } from 'primeng/api'; const options = [ { name: 'Profile', description: 'Manage your account', icon: 'ti ti-user' }, @@ -11,24 +10,22 @@ const options = [ ]; const template = ` - - - -
- {{ item.name }} - {{ item.description }} -
-
-
+ + + + +
+ {{ item.name }} + {{ item.description }} +
+
`; -const styles = ''; @Component({ selector: 'app-listbox-custom', standalone: true, - imports: [ExtraListboxComponent, SharedModule, ReactiveFormsModule], + imports: [ExtraListboxComponent, ReactiveFormsModule], template, - styles, }) export class ListboxCustomComponent { ctrl = new FormControl(null); @@ -42,29 +39,28 @@ export const Custom: StoryObj = { parameters: { controls: { disable: true }, docs: { - description: { story: 'Кастомный шаблон элемента с иконкой и подписью.' }, + description: { story: 'Кастомный шаблон элемента с иконкой и подписью через `itemTemplate`.' }, source: { language: 'ts', code: ` import { Component } from '@angular/core'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; -import { Listbox } from 'primeng/listbox'; -import { SharedModule } from 'primeng/api'; +import { ExtraListboxComponent } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-listbox-custom', standalone: true, - imports: [ExtraListboxComponent, SharedModule, ReactiveFormsModule], + imports: [ExtraListboxComponent, ReactiveFormsModule], template: \` - - - -
- {{ item.name }} - {{ item.description }} -
-
-
+ + + + +
+ {{ item.name }} + {{ item.description }} +
+
\`, }) export class ListboxCustomComponent { @@ -80,3 +76,5 @@ export class ListboxCustomComponent { }, }, }; + + diff --git a/src/stories/components/menu/examples/menu-custom.component.ts b/src/stories/components/menu/examples/menu-custom.component.ts index e3378ae8..12237473 100644 --- a/src/stories/components/menu/examples/menu-custom.component.ts +++ b/src/stories/components/menu/examples/menu-custom.component.ts @@ -3,8 +3,37 @@ import { ExtraMenuComponent, ExtraMenuModel } from '../../../../lib/components/m const template = `
- +
+ + + + @if (item.icon) { + + } +
+ {{ item.label }} + @if (item.caption) { + {{ item.caption }} + } +
+ @if (item.badge) { + + {{ item.badge }} + + } +
+
`; @Component({ @@ -19,6 +48,7 @@ export class MenuCustomComponent { label: 'Создать отправление', caption: 'Оформление нового заказа', icon: 'ti ti-file-plus', + badge: 'Новое', }, { label: 'Найти посылку', @@ -31,5 +61,11 @@ export class MenuCustomComponent { caption: 'Выгрузка в CSV или Excel', icon: 'ti ti-download', }, + { + label: 'Удалить', + caption: 'Действие недоступно', + icon: 'ti ti-trash', + disabled: true, + }, ]; } diff --git a/src/stories/components/menu/menu.stories.ts b/src/stories/components/menu/menu.stories.ts index d96b0449..42349142 100644 --- a/src/stories/components/menu/menu.stories.ts +++ b/src/stories/components/menu/menu.stories.ts @@ -232,7 +232,7 @@ export const Custom: Story = { parameters: { docs: { description: { - story: 'Пункты меню с иконкой и описанием (caption). Поле caption передаётся через MenuModel.', + story: 'Кастомизация отображения пунктов меню через входной параметр `itemTemplate`. Передайте `ng-template` с произвольной разметкой — он получит объект пункта меню через `let-item`.', }, source: { language: 'ts', @@ -245,7 +245,36 @@ import { ExtraMenuComponent, ExtraMenuModel } from '@cdek-it/angular-ui-kit'; standalone: true, imports: [ExtraMenuComponent], template: \` - + + + + + @if (item.icon) { + + } +
+ {{ item.label }} + @if (item.caption) { + {{ item.caption }} + } +
+ @if (item.badge) { + + {{ item.badge }} + + } +
+
\`, }) export class MenuCustomComponent { @@ -254,6 +283,7 @@ export class MenuCustomComponent { label: 'Создать отправление', caption: 'Оформление нового заказа', icon: 'ti ti-file-plus', + badge: 'Новое', }, { label: 'Найти посылку', @@ -266,6 +296,12 @@ export class MenuCustomComponent { caption: 'Выгрузка в CSV или Excel', icon: 'ti ti-download', }, + { + label: 'Удалить', + caption: 'Действие недоступно', + icon: 'ti ti-trash', + disabled: true, + }, ]; } `, From daf8812ca46382c86475f796a35d7baf9ff4a308 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Fri, 22 May 2026 14:12:21 +0700 Subject: [PATCH 254/258] DS-513 --- src/lib/components/toast/ng-package.json | 7 +++ src/lib/components/toast/provide-toast.ts | 17 +++++++ src/lib/components/toast/public_api.ts | 6 +++ src/lib/components/toast/toast.component.ts | 4 +- src/lib/components/toast/toast.service.ts | 8 ++-- .../examples/toast-position.component.ts | 22 ++++----- .../examples/toast-severities.component.ts | 18 ++++---- .../toast/examples/toast-width.component.ts | 16 +++---- .../toast-with-close-button.component.ts | 10 ++--- .../examples/toast-with-content.component.ts | 10 ++--- src/stories/components/toast/toast.stories.ts | 45 +++++++++++++++---- 11 files changed, 109 insertions(+), 54 deletions(-) create mode 100644 src/lib/components/toast/ng-package.json create mode 100644 src/lib/components/toast/provide-toast.ts create mode 100644 src/lib/components/toast/public_api.ts diff --git a/src/lib/components/toast/ng-package.json b/src/lib/components/toast/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/toast/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/toast/provide-toast.ts b/src/lib/components/toast/provide-toast.ts new file mode 100644 index 00000000..639e9f51 --- /dev/null +++ b/src/lib/components/toast/provide-toast.ts @@ -0,0 +1,17 @@ +import { EnvironmentProviders, makeEnvironmentProviders } from '@angular/core'; +import { MessageService } from 'primeng/api'; + +/** + * Регистрирует зависимости, необходимые для работы `ExtraToastService` и ``. + * Вызывать один раз в `ApplicationConfig.providers` или в `bootstrapApplication`. + * + * @example + * // app.config.ts + * export const appConfig: ApplicationConfig = { + * providers: [provideExtraToast()], + * }; + */ +export function provideExtraToast(): EnvironmentProviders { + return makeEnvironmentProviders([MessageService]); +} + diff --git a/src/lib/components/toast/public_api.ts b/src/lib/components/toast/public_api.ts new file mode 100644 index 00000000..b4c66422 --- /dev/null +++ b/src/lib/components/toast/public_api.ts @@ -0,0 +1,6 @@ +export * from './toast.component'; +export * from './toast.service'; +export * from './provide-toast'; + + + diff --git a/src/lib/components/toast/toast.component.ts b/src/lib/components/toast/toast.component.ts index d9a86641..6fedad9a 100644 --- a/src/lib/components/toast/toast.component.ts +++ b/src/lib/components/toast/toast.component.ts @@ -20,7 +20,7 @@ const SEVERITY_ICONS: Record = { }; @Component({ - selector: 'ui-toast', + selector: 'extra-toast', standalone: true, imports: [Toast, SharedModule], template: ` @@ -38,7 +38,7 @@ const SEVERITY_ICONS: Record = { `, }) -export class ToastComponent { +export class ExtraToastComponent { @Input() position: ToastPosition = 'top-right'; @Input() key: string | undefined = undefined; @Input() life = 5000; diff --git a/src/lib/components/toast/toast.service.ts b/src/lib/components/toast/toast.service.ts index 20b84326..eac20f46 100644 --- a/src/lib/components/toast/toast.service.ts +++ b/src/lib/components/toast/toast.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { MessageService } from 'primeng/api'; import { ToastSeverity } from './toast.component'; -export interface UiToastMessage { +export interface ExtraToastMessage { key?: string; severity?: ToastSeverity; summary?: string; @@ -13,14 +13,12 @@ export interface UiToastMessage { data?: unknown; } -export { MessageService }; - @Injectable({ providedIn: 'root' }) -export class UiToastService { +export class ExtraToastService { constructor(private readonly messageService: MessageService) {} - add(message: UiToastMessage): void { + add(message: ExtraToastMessage): void { this.messageService.add(message); } diff --git a/src/stories/components/toast/examples/toast-position.component.ts b/src/stories/components/toast/examples/toast-position.component.ts index dcd3e43f..1dcf7ca4 100644 --- a/src/stories/components/toast/examples/toast-position.component.ts +++ b/src/stories/components/toast/examples/toast-position.component.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { Button } from 'primeng/button'; -import { ToastComponent } from '../../../../lib/components/toast/toast.component'; -import { UiToastService } from '../../../../lib/components/toast/toast.service'; +import { ExtraToastComponent } from '../../../../lib/components/toast/toast.component'; +import { ExtraToastService } from '../../../../lib/components/toast/toast.service'; const POSITIONS = [ { position: 'top-left', label: 'Вверх слева', key: 'pos-top-left' }, @@ -15,7 +15,7 @@ const POSITIONS = [ const template = ` @for (p of positions; track p.key) { - + }
@@ -33,14 +33,14 @@ const styles = ''; @Component({ selector: 'app-toast-position', standalone: true, - imports: [ToastComponent, Button], + imports: [ExtraToastComponent, Button], template, styles, }) export class ToastPositionComponent { readonly positions = POSITIONS; - constructor(private readonly toastService: UiToastService) {} + constructor(private readonly toastService: ExtraToastService) {} show(key: string, position: string): void { this.toastService.add({ @@ -64,12 +64,12 @@ export const Position: StoryObj = { source: { language: 'ts', code: ` - - - - - - + + + + + + `, }, }, diff --git a/src/stories/components/toast/examples/toast-severities.component.ts b/src/stories/components/toast/examples/toast-severities.component.ts index b6b60345..c5ba2f79 100644 --- a/src/stories/components/toast/examples/toast-severities.component.ts +++ b/src/stories/components/toast/examples/toast-severities.component.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { Button } from 'primeng/button'; -import { ToastComponent } from '../../../../lib/components/toast/toast.component'; -import { UiToastService } from '../../../../lib/components/toast/toast.service'; +import { ExtraToastComponent } from '../../../../lib/components/toast/toast.component'; +import { ExtraToastService } from '../../../../lib/components/toast/toast.service'; const SEVERITIES = [ { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, @@ -12,7 +12,7 @@ const SEVERITIES = [ ] as const; const template = ` - +
@for (s of severities; track s.type) { @@ -45,14 +45,14 @@ const styles = ''; @Component({ selector: 'app-toast-severities', standalone: true, - imports: [ToastComponent, Button], + imports: [ExtraToastComponent, Button], template, styles, }) export class ToastSeveritiesComponent { readonly severities = SEVERITIES; - constructor(private readonly toastService: UiToastService) {} + constructor(private readonly toastService: ExtraToastService) {} show(severity: string, icon: string): void { this.toastService.add({ @@ -77,19 +77,19 @@ export const Severities: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ToastComponent, UiToastService } from '@cdek-it/angular-ui-kit'; +import { ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-example', standalone: true, - imports: [ToastComponent], + imports: [ExtraToastComponent], template: \` - + \`, }) export class ExampleComponent { - constructor(private toastService: UiToastService) {} + constructor(private toastService: ExtraToastService) {} show(): void { this.toastService.add({ diff --git a/src/stories/components/toast/examples/toast-width.component.ts b/src/stories/components/toast/examples/toast-width.component.ts index 5bbcf9e1..ea823172 100644 --- a/src/stories/components/toast/examples/toast-width.component.ts +++ b/src/stories/components/toast/examples/toast-width.component.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { Button } from 'primeng/button'; -import { ToastComponent } from '../../../../lib/components/toast/toast.component'; -import { UiToastService } from '../../../../lib/components/toast/toast.service'; +import { ExtraToastComponent } from '../../../../lib/components/toast/toast.component'; +import { ExtraToastService } from '../../../../lib/components/toast/toast.service'; const SIZES = [ { key: 'sm', label: 'Small (20rem)', width: '20rem', cssVar: '20rem' }, @@ -12,10 +12,10 @@ const SIZES = [ ] as const; const template = ` - +>
@for (s of sizes; track s.key) { @@ -50,7 +50,7 @@ const styles = ''; @Component({ selector: 'app-toast-width', standalone: true, - imports: [ToastComponent, Button], + imports: [ExtraToastComponent, Button], template, styles, }) @@ -58,7 +58,7 @@ export class ToastWidthComponent { readonly sizes = SIZES; currentWidth = '25rem'; - constructor(private readonly toastService: UiToastService) {} + constructor(private readonly toastService: ExtraToastService) {} show(cssVar: string): void { this.currentWidth = cssVar; @@ -84,8 +84,8 @@ export const Width: StoryObj = { source: { language: 'ts', code: ` - - + + `, }, }, diff --git a/src/stories/components/toast/examples/toast-with-close-button.component.ts b/src/stories/components/toast/examples/toast-with-close-button.component.ts index f308c0a6..04b4ef4e 100644 --- a/src/stories/components/toast/examples/toast-with-close-button.component.ts +++ b/src/stories/components/toast/examples/toast-with-close-button.component.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { Button } from 'primeng/button'; -import { ToastComponent } from '../../../../lib/components/toast/toast.component'; -import { UiToastService } from '../../../../lib/components/toast/toast.service'; +import { ExtraToastComponent } from '../../../../lib/components/toast/toast.component'; +import { ExtraToastService } from '../../../../lib/components/toast/toast.service'; const SEVERITIES = [ { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, @@ -12,7 +12,7 @@ const SEVERITIES = [ ] as const; const template = ` - +
@for (s of severities; track s.type) { @@ -51,14 +51,14 @@ const styles = ''; @Component({ selector: 'app-toast-with-close-button', standalone: true, - imports: [ToastComponent, Button], + imports: [ExtraToastComponent, Button], template, styles, }) export class ToastWithCloseButtonComponent { readonly severities = SEVERITIES; - constructor(private readonly toastService: UiToastService) {} + constructor(private readonly toastService: ExtraToastService) {} show(severity: string, icon: string): void { this.toastService.add({ diff --git a/src/stories/components/toast/examples/toast-with-content.component.ts b/src/stories/components/toast/examples/toast-with-content.component.ts index cde8df69..dea3c99c 100644 --- a/src/stories/components/toast/examples/toast-with-content.component.ts +++ b/src/stories/components/toast/examples/toast-with-content.component.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; import { Button } from 'primeng/button'; -import { ToastComponent } from '../../../../lib/components/toast/toast.component'; -import { UiToastService } from '../../../../lib/components/toast/toast.service'; +import { ExtraToastComponent } from '../../../../lib/components/toast/toast.component'; +import { ExtraToastService } from '../../../../lib/components/toast/toast.service'; const SEVERITIES = [ { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, @@ -12,7 +12,7 @@ const SEVERITIES = [ ] as const; const template = ` - +
@for (s of severities; track s.type) { @@ -58,14 +58,14 @@ const styles = ''; @Component({ selector: 'app-toast-with-content', standalone: true, - imports: [ToastComponent, Button], + imports: [ExtraToastComponent, Button], template, styles, }) export class ToastWithContentComponent { readonly severities = SEVERITIES; - constructor(private readonly toastService: UiToastService) {} + constructor(private readonly toastService: ExtraToastService) {} show(severity: string, icon: string): void { this.toastService.add({ diff --git a/src/stories/components/toast/toast.stories.ts b/src/stories/components/toast/toast.stories.ts index 05b37cb5..e349a19b 100644 --- a/src/stories/components/toast/toast.stories.ts +++ b/src/stories/components/toast/toast.stories.ts @@ -1,37 +1,64 @@ -import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { MessageService } from 'primeng/api'; -import { ToastComponent } from '../../../lib/components/toast/toast.component'; +import { Meta, applicationConfig, moduleMetadata } from '@storybook/angular'; +import { ExtraToastComponent } from '../../../lib/components/toast/toast.component'; +import { provideExtraToast } from '../../../lib/components/toast/provide-toast'; import { ToastSeveritiesComponent, Severities } from './examples/toast-severities.component'; import { ToastWithCloseButtonComponent, WithCloseButton } from './examples/toast-with-close-button.component'; import { ToastWithContentComponent, WithContent } from './examples/toast-with-content.component'; import { ToastWidthComponent, Width } from './examples/toast-width.component'; import { ToastPositionComponent, Position } from './examples/toast-position.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Feedback/Toast', - component: ToastComponent, + component: ExtraToastComponent, tags: ['autodocs'], decorators: [ + applicationConfig({ providers: [provideExtraToast()] }), moduleMetadata({ imports: [ - ToastComponent, + ExtraToastComponent, ToastSeveritiesComponent, ToastWithCloseButtonComponent, ToastWithContentComponent, ToastWidthComponent, ToastPositionComponent, ], - providers: [MessageService], }), ], parameters: { designTokens: { prefix: '--p-toast' }, docs: { description: { - component: `Компонент для отображения всплывающих уведомлений поверх интерфейса. Требует подключения \`UiToastService\`. + component: `Компонент для отображения всплывающих уведомлений поверх интерфейса. + +## Подключение + +Добавьте \`provideExtraToast()\` в провайдеры приложения: \`\`\`typescript -import { ToastComponent, UiToastService } from '@cdek-it/angular-ui-kit'; +// app.config.ts +import { provideExtraToast } from '@cdek-it/angular-ui-kit'; + +export const appConfig: ApplicationConfig = { + providers: [provideExtraToast()], +}; +\`\`\` + +## Использование + +\`\`\`typescript +import { ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; + +@Component({ + imports: [ExtraToastComponent], + template: \`\`, +}) +export class AppComponent { + private toast = inject(ExtraToastService); + + show() { + this.toast.add({ severity: 'success', summary: 'Готово', detail: 'Операция выполнена успешно' }); + } +} \`\`\``, }, }, From e46f4c807243d3ccf705f638cf0940e3ca8d4521 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Fri, 22 May 2026 14:16:35 +0700 Subject: [PATCH 255/258] DS-516 --- .../examples/toast-position.component.ts | 55 ++++++++++++-- .../examples/toast-severities.component.ts | 34 +++++++-- .../toast/examples/toast-width.component.ts | 53 +++++++++++++- .../toast-with-close-button.component.ts | 56 ++++++++++++--- .../examples/toast-with-content.component.ts | 71 ++++++++++++++++--- 5 files changed, 236 insertions(+), 33 deletions(-) diff --git a/src/stories/components/toast/examples/toast-position.component.ts b/src/stories/components/toast/examples/toast-position.component.ts index 1dcf7ca4..bed9bfa4 100644 --- a/src/stories/components/toast/examples/toast-position.component.ts +++ b/src/stories/components/toast/examples/toast-position.component.ts @@ -64,12 +64,55 @@ export const Position: StoryObj = { source: { language: 'ts', code: ` - - - - - - +import { Component } from '@angular/core'; +import { ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; +import { Button } from 'primeng/button'; + +const POSITIONS = [ + { position: 'top-left', label: 'Вверх слева', key: 'pos-top-left' }, + { position: 'top-center', label: 'Вверх по центру', key: 'pos-top-center' }, + { position: 'top-right', label: 'Вверх справа', key: 'pos-top-right' }, + { position: 'bottom-left', label: 'Вниз слева', key: 'pos-bottom-left' }, + { position: 'bottom-center', label: 'Вниз по центру', key: 'pos-bottom-center' }, + { position: 'bottom-right', label: 'Вниз справа', key: 'pos-bottom-right' }, +] as const; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [ExtraToastComponent, Button], + template: \` + @for (p of positions; track p.key) { + + } + +
+ @for (p of positions; track p.key) { + + } +
+ \`, +}) +export class ExampleComponent { + readonly positions = POSITIONS; + + constructor(private toastService: ExtraToastService) {} + + show(key: string, position: string): void { + this.toastService.add({ + key, + severity: 'info', + summary: 'Сообщение', + detail: 'Позиция: ' + position, + life: 3000, + icon: 'ti ti-info-circle', + }); + } +} `, }, }, diff --git a/src/stories/components/toast/examples/toast-severities.component.ts b/src/stories/components/toast/examples/toast-severities.component.ts index c5ba2f79..a7bb19b6 100644 --- a/src/stories/components/toast/examples/toast-severities.component.ts +++ b/src/stories/components/toast/examples/toast-severities.component.ts @@ -78,27 +78,47 @@ export const Severities: StoryObj = { code: ` import { Component } from '@angular/core'; import { ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; +import { Button } from 'primeng/button'; + +const SEVERITIES = [ + { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, + { type: 'success', icon: 'ti ti-circle-check', label: 'Успех' }, + { type: 'warn', icon: 'ti ti-alert-triangle', label: 'Предупреждение' }, + { type: 'error', icon: 'ti ti-alert-circle', label: 'Ошибка' }, +] as const; @Component({ selector: 'app-example', standalone: true, - imports: [ExtraToastComponent], + imports: [ExtraToastComponent, Button], template: \` - - + + +
+ @for (s of severities; track s.type) { + + } +
\`, }) export class ExampleComponent { + readonly severities = SEVERITIES; + constructor(private toastService: ExtraToastService) {} - show(): void { + show(severity: string, icon: string): void { this.toastService.add({ - key: 'my-toast', - severity: 'info', + key: 'severities', + severity: severity as any, summary: 'Сообщение', detail: 'Подпись', life: 5000, - icon: 'ti ti-info-circle', + icon, }); } } diff --git a/src/stories/components/toast/examples/toast-width.component.ts b/src/stories/components/toast/examples/toast-width.component.ts index ea823172..9af4f71d 100644 --- a/src/stories/components/toast/examples/toast-width.component.ts +++ b/src/stories/components/toast/examples/toast-width.component.ts @@ -84,8 +84,57 @@ export const Width: StoryObj = { source: { language: 'ts', code: ` - - +import { Component } from '@angular/core'; +import { ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; +import { Button } from 'primeng/button'; + +const SIZES = [ + { key: 'sm', label: 'Small (20rem)', cssVar: '20rem' }, + { key: 'base', label: 'Base (25rem)', cssVar: '25rem' }, + { key: 'lg', label: 'Large (30rem)', cssVar: '30rem' }, + { key: 'xlg', label: 'X-Large (45rem)', cssVar: '45rem' }, +] as const; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [ExtraToastComponent, Button], + template: \` + + +
+ @for (s of sizes; track s.key) { + + } +
+ \`, +}) +export class ExampleComponent { + readonly sizes = SIZES; + currentWidth = '25rem'; + + constructor(private toastService: ExtraToastService) {} + + show(cssVar: string): void { + this.currentWidth = cssVar; + this.toastService.clear('width-preview'); + this.toastService.add({ + key: 'width-preview', + severity: 'info', + summary: 'Сообщение', + detail: 'Ширина: ' + cssVar, + life: 3000, + icon: 'ti ti-info-circle', + }); + } +} `, }, }, diff --git a/src/stories/components/toast/examples/toast-with-close-button.component.ts b/src/stories/components/toast/examples/toast-with-close-button.component.ts index 04b4ef4e..39ae8968 100644 --- a/src/stories/components/toast/examples/toast-with-close-button.component.ts +++ b/src/stories/components/toast/examples/toast-with-close-button.component.ts @@ -83,15 +83,53 @@ export const WithCloseButton: StoryObj = { source: { language: 'ts', code: ` -this.toastService.add({ - key: 'my-toast', - severity: 'info', - summary: 'Сообщение', - detail: 'Подпись', - life: 5000, - icon: 'ti ti-info-circle', - closable: true, -}); +import { Component } from '@angular/core'; +import { ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; +import { Button } from 'primeng/button'; + +const SEVERITIES = [ + { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, + { type: 'success', icon: 'ti ti-circle-check', label: 'Успех' }, + { type: 'warn', icon: 'ti ti-alert-triangle', label: 'Предупреждение' }, + { type: 'error', icon: 'ti ti-alert-circle', label: 'Ошибка' }, +] as const; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [ExtraToastComponent, Button], + template: \` + + +
+ @for (s of severities; track s.type) { + + } +
+ \`, +}) +export class ExampleComponent { + readonly severities = SEVERITIES; + + constructor(private toastService: ExtraToastService) {} + + show(severity: string, icon: string): void { + this.toastService.add({ + key: 'with-close', + severity: severity as any, + summary: 'Сообщение', + detail: 'Подпись', + life: 5000, + icon, + closable: true, + }); + } +} `, }, }, diff --git a/src/stories/components/toast/examples/toast-with-content.component.ts b/src/stories/components/toast/examples/toast-with-content.component.ts index dea3c99c..c8dea34a 100644 --- a/src/stories/components/toast/examples/toast-with-content.component.ts +++ b/src/stories/components/toast/examples/toast-with-content.component.ts @@ -90,15 +90,68 @@ export const WithContent: StoryObj = { source: { language: 'ts', code: ` -this.toastService.add({ - key: 'my-toast', - severity: 'info', - summary: 'Сообщение', - detail: 'Подпись', - life: 5000, - icon: 'ti ti-info-circle', - closable: true, -}); +import { Component } from '@angular/core'; +import { ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; +import { Button } from 'primeng/button'; + +const SEVERITIES = [ + { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, + { type: 'success', icon: 'ti ti-circle-check', label: 'Успех' }, + { type: 'warn', icon: 'ti ti-alert-triangle', label: 'Предупреждение' }, + { type: 'error', icon: 'ti ti-alert-circle', label: 'Ошибка' }, +] as const; + +// Кастомный шаблон сообщения передаётся через ng-template +@Component({ + selector: 'app-example', + standalone: true, + imports: [ExtraToastComponent, Button], + template: \` + + +
+ {{ message.summary }} +
{{ message.detail }}
+
+
Дополнительный контент
+
+
+
Ячейка 1
+
Ячейка 2
+
+
+
+
+ +
+ @for (s of severities; track s.type) { + + } +
+ \`, +}) +export class ExampleComponent { + readonly severities = SEVERITIES; + + constructor(private toastService: ExtraToastService) {} + + show(severity: string, icon: string): void { + this.toastService.add({ + key: 'with-content', + severity: severity as any, + summary: 'Сообщение', + detail: 'Подпись', + life: 5000, + icon, + closable: true, + }); + } +} `, }, }, From 971c49deb2e0da624f08145a7b363388eb2afe75 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Fri, 22 May 2026 14:27:56 +0700 Subject: [PATCH 256/258] DS-516 --- .../examples/toast-position.component.ts | 25 +++++++++---------- .../examples/toast-severities.component.ts | 25 +++++++++---------- .../toast/examples/toast-width.component.ts | 25 +++++++++---------- .../toast-with-close-button.component.ts | 25 +++++++++---------- .../examples/toast-with-content.component.ts | 25 +++++++++---------- 5 files changed, 60 insertions(+), 65 deletions(-) diff --git a/src/stories/components/toast/examples/toast-position.component.ts b/src/stories/components/toast/examples/toast-position.component.ts index bed9bfa4..2aedab9c 100644 --- a/src/stories/components/toast/examples/toast-position.component.ts +++ b/src/stories/components/toast/examples/toast-position.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { Button } from 'primeng/button'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; import { ExtraToastComponent } from '../../../../lib/components/toast/toast.component'; import { ExtraToastService } from '../../../../lib/components/toast/toast.service'; @@ -20,11 +20,11 @@ const template = `
@for (p of positions; track p.key) { - + variant="outlined" + (click)="show(p.key, p.position)" + > }
`; @@ -33,7 +33,7 @@ const styles = ''; @Component({ selector: 'app-toast-position', standalone: true, - imports: [ExtraToastComponent, Button], + imports: [ExtraToastComponent, ExtraButtonComponent], template, styles, }) @@ -65,8 +65,7 @@ export const Position: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; -import { Button } from 'primeng/button'; +import { ExtraButtonComponent, ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; const POSITIONS = [ { position: 'top-left', label: 'Вверх слева', key: 'pos-top-left' }, @@ -80,7 +79,7 @@ const POSITIONS = [ @Component({ selector: 'app-example', standalone: true, - imports: [ExtraToastComponent, Button], + imports: [ExtraToastComponent, ExtraButtonComponent], template: \` @for (p of positions; track p.key) { @@ -88,11 +87,11 @@ const POSITIONS = [
@for (p of positions; track p.key) { - + variant="outlined" + (click)="show(p.key, p.position)" + > }
\`, diff --git a/src/stories/components/toast/examples/toast-severities.component.ts b/src/stories/components/toast/examples/toast-severities.component.ts index a7bb19b6..f521fce8 100644 --- a/src/stories/components/toast/examples/toast-severities.component.ts +++ b/src/stories/components/toast/examples/toast-severities.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { Button } from 'primeng/button'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; import { ExtraToastComponent } from '../../../../lib/components/toast/toast.component'; import { ExtraToastService } from '../../../../lib/components/toast/toast.service'; @@ -31,12 +31,12 @@ const template = `
@for (s of severities; track s.type) { - + (click)="show(s.type, s.icon)" + > }
`; @@ -45,7 +45,7 @@ const styles = ''; @Component({ selector: 'app-toast-severities', standalone: true, - imports: [ExtraToastComponent, Button], + imports: [ExtraToastComponent, ExtraButtonComponent], template, styles, }) @@ -77,8 +77,7 @@ export const Severities: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; -import { Button } from 'primeng/button'; +import { ExtraButtonComponent, ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; const SEVERITIES = [ { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, @@ -90,18 +89,18 @@ const SEVERITIES = [ @Component({ selector: 'app-example', standalone: true, - imports: [ExtraToastComponent, Button], + imports: [ExtraToastComponent, ExtraButtonComponent], template: \`
@for (s of severities; track s.type) { - + (click)="show(s.type, s.icon)" + > }
\`, diff --git a/src/stories/components/toast/examples/toast-width.component.ts b/src/stories/components/toast/examples/toast-width.component.ts index 9af4f71d..a8349746 100644 --- a/src/stories/components/toast/examples/toast-width.component.ts +++ b/src/stories/components/toast/examples/toast-width.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { Button } from 'primeng/button'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; import { ExtraToastComponent } from '../../../../lib/components/toast/toast.component'; import { ExtraToastService } from '../../../../lib/components/toast/toast.service'; @@ -37,11 +37,11 @@ const template = `
@for (s of sizes; track s.key) { - + variant="outlined" + (click)="show(s.cssVar)" + > }
`; @@ -50,7 +50,7 @@ const styles = ''; @Component({ selector: 'app-toast-width', standalone: true, - imports: [ExtraToastComponent, Button], + imports: [ExtraToastComponent, ExtraButtonComponent], template, styles, }) @@ -85,8 +85,7 @@ export const Width: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; -import { Button } from 'primeng/button'; +import { ExtraButtonComponent, ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; const SIZES = [ { key: 'sm', label: 'Small (20rem)', cssVar: '20rem' }, @@ -98,7 +97,7 @@ const SIZES = [ @Component({ selector: 'app-example', standalone: true, - imports: [ExtraToastComponent, Button], + imports: [ExtraToastComponent, ExtraButtonComponent], template: \` @for (s of sizes; track s.key) { - + variant="outlined" + (click)="show(s.cssVar)" + > }
\`, diff --git a/src/stories/components/toast/examples/toast-with-close-button.component.ts b/src/stories/components/toast/examples/toast-with-close-button.component.ts index 39ae8968..08116a6b 100644 --- a/src/stories/components/toast/examples/toast-with-close-button.component.ts +++ b/src/stories/components/toast/examples/toast-with-close-button.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { Button } from 'primeng/button'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; import { ExtraToastComponent } from '../../../../lib/components/toast/toast.component'; import { ExtraToastService } from '../../../../lib/components/toast/toast.service'; @@ -37,12 +37,12 @@ const template = `
@for (s of severities; track s.type) { - + (click)="show(s.type, s.icon)" + > }
`; @@ -51,7 +51,7 @@ const styles = ''; @Component({ selector: 'app-toast-with-close-button', standalone: true, - imports: [ExtraToastComponent, Button], + imports: [ExtraToastComponent, ExtraButtonComponent], template, styles, }) @@ -84,8 +84,7 @@ export const WithCloseButton: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; -import { Button } from 'primeng/button'; +import { ExtraButtonComponent, ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; const SEVERITIES = [ { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, @@ -97,18 +96,18 @@ const SEVERITIES = [ @Component({ selector: 'app-example', standalone: true, - imports: [ExtraToastComponent, Button], + imports: [ExtraToastComponent, ExtraButtonComponent], template: \`
@for (s of severities; track s.type) { - + (click)="show(s.type, s.icon)" + > }
\`, diff --git a/src/stories/components/toast/examples/toast-with-content.component.ts b/src/stories/components/toast/examples/toast-with-content.component.ts index c8dea34a..db2a2de5 100644 --- a/src/stories/components/toast/examples/toast-with-content.component.ts +++ b/src/stories/components/toast/examples/toast-with-content.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; import { StoryObj } from '@storybook/angular'; -import { Button } from 'primeng/button'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; import { ExtraToastComponent } from '../../../../lib/components/toast/toast.component'; import { ExtraToastService } from '../../../../lib/components/toast/toast.service'; @@ -44,12 +44,12 @@ const template = `
@for (s of severities; track s.type) { - + (click)="show(s.type, s.icon)" + > }
`; @@ -58,7 +58,7 @@ const styles = ''; @Component({ selector: 'app-toast-with-content', standalone: true, - imports: [ExtraToastComponent, Button], + imports: [ExtraToastComponent, ExtraButtonComponent], template, styles, }) @@ -91,8 +91,7 @@ export const WithContent: StoryObj = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; -import { Button } from 'primeng/button'; +import { ExtraButtonComponent, ExtraToastComponent, ExtraToastService } from '@cdek-it/angular-ui-kit'; const SEVERITIES = [ { type: 'info', icon: 'ti ti-info-circle', label: 'Информация' }, @@ -105,7 +104,7 @@ const SEVERITIES = [ @Component({ selector: 'app-example', standalone: true, - imports: [ExtraToastComponent, Button], + imports: [ExtraToastComponent, ExtraButtonComponent], template: \` @@ -125,12 +124,12 @@ const SEVERITIES = [
@for (s of severities; track s.type) { - + (click)="show(s.type, s.icon)" + > }
\`, From 76ceddd2e7e193a5ffdf9d32bfa1a188fe11141a Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Fri, 22 May 2026 14:28:34 +0700 Subject: [PATCH 257/258] DS-516 --- .github/workflows/deploy-pages.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index 344714b4..e9a6b86c 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - styles-debug # Allows you to run this workflow manually from the Actions tab workflow_dispatch: From ef31f605008b424550c35b06660d4b6b20e25b4f Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Fri, 22 May 2026 15:07:16 +0700 Subject: [PATCH 258/258] DS-516 --- .github/workflows/deploy-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index e9a6b86c..f100a9cb 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -4,7 +4,7 @@ on: push: branches: - main - - styles-debug + - feature/styles-debug # Allows you to run this workflow manually from the Actions tab workflow_dispatch: