diff --git a/src/lib/components/popover/ng-package.json b/src/lib/components/popover/ng-package.json new file mode 100644 index 0000000..ecdf8fe --- /dev/null +++ b/src/lib/components/popover/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/popover/popover.component.ts b/src/lib/components/popover/popover.component.ts new file mode 100644 index 0000000..4f60b4d --- /dev/null +++ b/src/lib/components/popover/popover.component.ts @@ -0,0 +1,26 @@ +import { ChangeDetectionStrategy, Component, Input, ViewChild } from '@angular/core'; +import { Popover } from 'primeng/popover'; +import { SharedModule } from 'primeng/api'; + +@Component({ + selector: 'extra-popover', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [Popover, SharedModule], + host: { style: 'display: contents' }, + template: ` + + + + ` +}) +export class ExtraPopoverComponent { + @Input() dismissable = true; + @Input() appendTo: string | HTMLElement = 'body'; + + @ViewChild('op') private op!: Popover; + + toggle(event: Event): void { + this.op.toggle(event); + } +} diff --git a/src/lib/components/popover/public_api.ts b/src/lib/components/popover/public_api.ts new file mode 100644 index 0000000..2bc70dc --- /dev/null +++ b/src/lib/components/popover/public_api.ts @@ -0,0 +1,2 @@ +export * from './popover.component'; + diff --git a/src/lib/providers/prime-preset/map-tokens.ts b/src/lib/providers/prime-preset/map-tokens.ts index 3c1c783..bbd8a95 100644 --- a/src/lib/providers/prime-preset/map-tokens.ts +++ b/src/lib/providers/prime-preset/map-tokens.ts @@ -49,6 +49,7 @@ import { timelineCss } from './tokens/components/timeline'; import { toastCss } from './tokens/components/toast'; import { toggleswitchCss } from './tokens/components/toggleswitch'; import { autocompleteCss } from './tokens/components/autocomplete'; +import { popoverCss } from './tokens/components/popover'; const presetTokens: Preset = { primitive: tokens.primitive as unknown as AuraBaseDesignTokens['primitive'], @@ -233,6 +234,10 @@ const presetTokens: Preset = { autocomplete: { ...(tokens.components.autocomplete as unknown as ComponentsDesignTokens['autocomplete']), css: autocompleteCss + }, + popover: { + ...(tokens.components.popover as unknown as ComponentsDesignTokens['popover']), + css: popoverCss } } as ComponentsDesignTokens }; diff --git a/src/lib/providers/prime-preset/tokens/components/popover.ts b/src/lib/providers/prime-preset/tokens/components/popover.ts new file mode 100644 index 0000000..296010d --- /dev/null +++ b/src/lib/providers/prime-preset/tokens/components/popover.ts @@ -0,0 +1,10 @@ +export const popoverCss = ({ dt }: { dt: (token: string) => string }): string => ` + .p-popover.p-component::before { + border-width: 0.73rem; + margin-left: -0.86rem; + } + + .p-popover.p-component::after { + margin-left: calc(-1 * ${dt('popover.extend.arrow.width')}); + } +`; diff --git a/src/lib/providers/prime-preset/tokens/tokens.json b/src/lib/providers/prime-preset/tokens/tokens.json index 0851bf9..c0f9ed7 100644 --- a/src/lib/providers/prime-preset/tokens/tokens.json +++ b/src/lib/providers/prime-preset/tokens/tokens.json @@ -4021,8 +4021,9 @@ "color": "{overlay.popover.color}", "borderRadius": "{overlay.popover.borderRadius}", "shadow": "{overlay.popover.shadow}", - "gutter": "{overlay.gap.100}", - "arrowOffset": "{overlay.popover.padding.200}" + "gutter": "{overlay.gap.300}", + "arrowOffset": "{overlay.popover.padding.200}", + "arrowLeft": "0px" }, "content": { "padding": "{overlay.popover.padding.100}" diff --git a/src/stories/components/popover/examples/popover-basic.component.ts b/src/stories/components/popover/examples/popover-basic.component.ts new file mode 100644 index 0000000..33c887d --- /dev/null +++ b/src/stories/components/popover/examples/popover-basic.component.ts @@ -0,0 +1,61 @@ +import { Component, ViewChild } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { ExtraPopoverComponent } from '../../../../lib/components/popover/popover.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; + +const template = ` + + + + + Содержимое popover. + + + +`; +const styles = ''; + +@Component({ + selector: 'app-popover-basic', + standalone: true, + imports: [ExtraPopoverComponent, ExtraButtonComponent], + template, + styles, +}) +export class PopoverBasicComponent { + @ViewChild('popover') popover!: ExtraPopoverComponent; +} + +export const Basic: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Базовый popover с текстовым содержимым.' }, + source: { + language: 'ts', + code: ` +import { Component, ViewChild } from '@angular/core'; +import { ExtraPopoverComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-popover-basic', + standalone: true, + imports: [ExtraPopoverComponent, ExtraButtonComponent], + template: \` + + + Содержимое popover. + + \`, +}) +export class PopoverBasicComponent { + @ViewChild('popover') popover!: ExtraPopoverComponent; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/popover/examples/popover-rich-content.component.ts b/src/stories/components/popover/examples/popover-rich-content.component.ts new file mode 100644 index 0000000..717c3e7 --- /dev/null +++ b/src/stories/components/popover/examples/popover-rich-content.component.ts @@ -0,0 +1,67 @@ +import { Component, ViewChild } from '@angular/core'; +import { StoryObj } from '@storybook/angular'; +import { ExtraPopoverComponent } from '../../../../lib/components/popover/popover.component'; +import { ExtraButtonComponent } from '../../../../lib/components/button/button.component'; + +const template = ` + + + + + + Заголовок + Дополнительное описание или любой произвольный контент внутри popover. + + + + +`; +const styles = ''; + +@Component({ + selector: 'app-popover-rich-content', + standalone: true, + imports: [ExtraPopoverComponent, ExtraButtonComponent], + template, + styles, +}) +export class PopoverRichContentComponent { + @ViewChild('popover') popover!: ExtraPopoverComponent; +} + +export const RichContent: StoryObj = { + render: () => ({ + template: ``, + }), + parameters: { + docs: { + description: { story: 'Popover с расширенным содержимым: заголовок и описание.' }, + source: { + language: 'ts', + code: ` +import { Component, ViewChild } from '@angular/core'; +import { ExtraPopoverComponent } from '@cdek-it/angular-ui-kit'; +import { ExtraButtonComponent } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-popover-rich-content', + standalone: true, + imports: [ExtraPopoverComponent, ExtraButtonComponent], + template: \` + + + + Заголовок + Дополнительное описание или любой произвольный контент внутри popover. + + + \`, +}) +export class PopoverRichContentComponent { + @ViewChild('popover') popover!: ExtraPopoverComponent; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/popover/popover.stories.ts b/src/stories/components/popover/popover.stories.ts new file mode 100644 index 0000000..a2975a9 --- /dev/null +++ b/src/stories/components/popover/popover.stories.ts @@ -0,0 +1,71 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { ExtraPopoverComponent } from '../../../lib/components/popover/popover.component'; +import { PopoverBasicComponent } from './examples/popover-basic.component'; +import { PopoverRichContentComponent, RichContent } from './examples/popover-rich-content.component'; + +const meta: Meta = { + title: 'Components/Overlay/Popover', + component: ExtraPopoverComponent, + tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + ExtraPopoverComponent, + PopoverBasicComponent, + PopoverRichContentComponent, + ], + }), + ], + parameters: { + docs: { + description: { + component: `Всплывающее наложение, привязанное к целевому элементу. + +\`\`\`typescript +import { ExtraPopoverComponent } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-popover' }, + }, + argTypes: { + dismissable: { + control: 'boolean', + description: 'Закрывает popover при клике вне его области.', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + appendTo: { + control: 'text', + description: 'Элемент, к которому присоединяется popover в DOM.', + table: { + category: 'Props', + defaultValue: { summary: 'body' }, + type: { summary: 'string' }, + }, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + name: 'Default', + render: () => ({ + template: ``, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Базовый пример компонента.', + }, + }, + }, +}; + +export { RichContent };
Содержимое popover.
Дополнительное описание или любой произвольный контент внутри popover.