From b9db1e583cec4b0cc53a559e2e6da07959bdde64 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Thu, 9 Apr 2026 20:34:00 +0700 Subject: [PATCH 1/7] =?UTF-8?q?data-table:=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 --- .../data-table/data-table.component.ts | 94 +++ src/prime-preset/map-tokens.ts | 5 + .../tokens/components/data-table.ts | 28 + .../data-table/data-table.stories.ts | 569 ++++++++++++++++++ .../examples/data-table-default.component.ts | 38 ++ .../data-table-grid-lines.component.ts | 35 ++ .../data-table-pagination.component.ts | 44 ++ .../data-table-scroll-horizontal.component.ts | 37 ++ .../data-table-scroll-vertical.component.ts | 42 ++ .../data-table-selectable.component.ts | 42 ++ ...data-table-selection-checkbox.component.ts | 42 ++ .../data-table-selection-radio.component.ts | 42 ++ .../data-table-striped-rows.component.ts | 35 ++ 13 files changed, 1053 insertions(+) create mode 100644 src/lib/components/data-table/data-table.component.ts create mode 100644 src/prime-preset/tokens/components/data-table.ts create mode 100644 src/stories/components/data-table/data-table.stories.ts create mode 100644 src/stories/components/data-table/examples/data-table-default.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-grid-lines.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-pagination.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-selectable.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-selection-radio.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-striped-rows.component.ts diff --git a/src/lib/components/data-table/data-table.component.ts b/src/lib/components/data-table/data-table.component.ts new file mode 100644 index 00000000..798bf685 --- /dev/null +++ b/src/lib/components/data-table/data-table.component.ts @@ -0,0 +1,94 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { TableModule } from 'primeng/table'; +import { PrimeTemplate } from 'primeng/api'; + +export interface DataTableColumn { + field?: string; + header?: string; + sortable?: boolean; + style?: string; + headerStyle?: string; + selectionMode?: 'single' | 'multiple'; +} + +@Component({ + selector: 'data-table', + host: { style: 'display: block' }, + standalone: true, + imports: [TableModule, PrimeTemplate], + template: ` + + + + @for (col of columns; track $index) { + @if (col.selectionMode === 'single') { + + } @else if (col.selectionMode === 'multiple') { + + + + } @else if (col.sortable) { + + {{ col.header }} + + + } @else { + {{ col.header }} + } + } + + + + + + @for (col of columns; track $index) { + @if (col.selectionMode === 'single') { + + + + } @else if (col.selectionMode === 'multiple') { + + + + } @else { + {{ rowData[col.field] }} + } + } + + + + `, +}) +export class DataTableComponent { + @Input() value: any[] = []; + @Input() columns: DataTableColumn[] = []; + @Input() stripedRows = false; + @Input() showGridlines = false; + @Input() loading = false; + @Input() size: 'small' | 'large' | undefined = undefined; + @Input() scrollable = false; + @Input() scrollHeight = ''; + @Input() paginator = false; + @Input() rows = 5; + @Input() rowsPerPageOptions: number[] = [5, 10, 25]; + @Input() selectionMode: 'single' | 'multiple' | undefined = undefined; + @Input() selection: any = null; + @Output() selectionChange = new EventEmitter(); + @Input() dataKey = 'id'; +} diff --git a/src/prime-preset/map-tokens.ts b/src/prime-preset/map-tokens.ts index 39627587..7fbaefa1 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 { dataTableCss } from './tokens/components/data-table'; 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, }, + datatable: { + ...(tokens.components.datatable as unknown as ComponentsDesignTokens['datatable']), + css: dataTableCss, + }, } as ComponentsDesignTokens, }; diff --git a/src/prime-preset/tokens/components/data-table.ts b/src/prime-preset/tokens/components/data-table.ts new file mode 100644 index 00000000..f770594c --- /dev/null +++ b/src/prime-preset/tokens/components/data-table.ts @@ -0,0 +1,28 @@ +export const dataTableCss = ({ dt }: { dt: (token: string) => string }): string => ` + .p-datatable .p-datatable-thead > tr > th { + font-weight: ${dt('datatable.columnTitle.fontWeight')}; + } + + .p-datatable .p-datatable-tfoot > tr > td { + font-weight: ${dt('datatable.columnFooter.fontWeight')}; + } + + .p-datatable .p-datatable-sort-icon { + width: ${dt('datatable.sortIcon.size')}; + height: ${dt('datatable.sortIcon.size')}; + } + + .p-datatable .p-datatable-loading-icon { + width: ${dt('datatable.loadingIcon.size')}; + height: ${dt('datatable.loadingIcon.size')}; + } + + .p-datatable .p-datatable-row-toggle-button { + width: ${dt('datatable.rowToggleButton.size')}; + height: ${dt('datatable.rowToggleButton.size')}; + } + + .p-datatable .p-datatable-sortable-column:not(.p-datatable-column-sorted):hover { + color: ${dt('datatable.headerCell.hoverColor')}; + } +`; diff --git a/src/stories/components/data-table/data-table.stories.ts b/src/stories/components/data-table/data-table.stories.ts new file mode 100644 index 00000000..6ea5f7f4 --- /dev/null +++ b/src/stories/components/data-table/data-table.stories.ts @@ -0,0 +1,569 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { DataTableComponent } from '../../../lib/components/data-table/data-table.component'; +import { DataTableDefaultComponent } from './examples/data-table-default.component'; +import { DataTableStripedRowsComponent } from './examples/data-table-striped-rows.component'; +import { DataTableSelectableComponent } from './examples/data-table-selectable.component'; +import { DataTableGridLinesComponent } from './examples/data-table-grid-lines.component'; +import { DataTablePaginationComponent } from './examples/data-table-pagination.component'; +import { DataTableSelectionRadioComponent } from './examples/data-table-selection-radio.component'; +import { DataTableSelectionCheckboxComponent } from './examples/data-table-selection-checkbox.component'; +import { DataTableScrollVerticalComponent } from './examples/data-table-scroll-vertical.component'; +import { DataTableScrollHorizontalComponent } from './examples/data-table-scroll-horizontal.component'; + +const meta: Meta = { + title: 'Components/Data/DataTable', + component: DataTableComponent, + tags: ['autodocs'], + parameters: { + docs: { + description: { + component: `Таблица данных с поддержкой сортировки, пагинации, выбора строк и прокрутки. + +\`\`\`typescript +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-datatable' }, + }, + argTypes: { + value: { + control: false, + description: 'Массив данных для отображения в таблице.', + table: { + category: 'Props', + type: { summary: 'any[]' }, + }, + }, + columns: { + control: false, + description: 'Определения столбцов таблицы.', + table: { + category: 'Props', + type: { summary: 'DataTableColumn[]' }, + }, + }, + stripedRows: { + control: 'boolean', + description: 'Чередование цвета строк.', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + showGridlines: { + 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' }, + }, + }, + size: { + control: 'select', + options: ['small', 'large', undefined], + description: 'Размер таблицы.', + table: { + category: 'Props', + defaultValue: { summary: 'undefined (normal)' }, + type: { summary: "'small' | 'large' | undefined" }, + }, + }, + scrollable: { + control: 'boolean', + description: 'Включает прокрутку таблицы.', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + scrollHeight: { + control: 'text', + description: 'Высота области прокрутки (например "400px"). Работает только при scrollable=true.', + table: { + category: 'Props', + defaultValue: { summary: "''" }, + type: { summary: 'string' }, + }, + }, + paginator: { + control: 'boolean', + description: 'Включает пагинацию.', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + rows: { + control: 'number', + description: 'Количество строк на странице (при paginator=true).', + table: { + category: 'Props', + defaultValue: { summary: '5' }, + type: { summary: 'number' }, + }, + }, + selectionMode: { + control: 'select', + options: ['single', 'multiple', undefined], + description: 'Режим выбора строк.', + table: { + category: 'Props', + defaultValue: { summary: 'undefined' }, + type: { summary: "'single' | 'multiple' | undefined" }, + }, + }, + dataKey: { + control: 'text', + description: 'Поле объекта, используемое как уникальный идентификатор строки.', + table: { + category: 'Props', + defaultValue: { summary: "'id'" }, + type: { summary: 'string' }, + }, + }, + selectionChange: { + control: false, + description: 'Событие изменения выбранных строк.', + table: { + category: 'Events', + type: { summary: 'EventEmitter' }, + }, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ─────────────────────────────────────────────────────────────────── + +export const Default: Story = { + name: 'DataTable', + decorators: [moduleMetadata({ imports: [DataTableDefaultComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Базовая таблица отправлений с сортировкой по всем столбцам.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-default', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableDefaultComponent { + shipments = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + ]; + + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, + ]; +} + `, + }, + }, + }, +}; + +// ── StripedRows ─────────────────────────────────────────────────────────────── + +export const StripedRows: Story = { + name: 'StripedRows', + decorators: [moduleMetadata({ imports: [DataTableStripedRowsComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Чередование цвета строк для улучшения читаемости.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-striped-rows', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableStripedRowsComponent { + shipments = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + ]; + + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, + ]; +} + `, + }, + }, + }, +}; + +// ── Selectable ──────────────────────────────────────────────────────────────── + +export const Selectable: Story = { + name: 'Selectable', + decorators: [moduleMetadata({ imports: [DataTableSelectableComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Выбор строки кликом. Режим single — выбирается одна строка.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-selectable', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableSelectableComponent { + shipments = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + ]; + + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, + ]; + + selected: any = null; +} + `, + }, + }, + }, +}; + +// ── GridLines ───────────────────────────────────────────────────────────────── + +export const GridLines: Story = { + name: 'GridLines', + decorators: [moduleMetadata({ imports: [DataTableGridLinesComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Сетка между ячейками для наглядного разграничения данных.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-grid-lines', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableGridLinesComponent { + shipments = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + ]; + + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, + ]; +} + `, + }, + }, + }, +}; + +// ── Pagination ──────────────────────────────────────────────────────────────── + +export const Pagination: Story = { + name: 'Pagination', + decorators: [moduleMetadata({ imports: [DataTablePaginationComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Пагинация для больших наборов данных. Управление количеством строк на странице.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-pagination', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTablePaginationComponent { + shipments = [...]; // массив отправлений + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, + ]; +} + `, + }, + }, + }, +}; + +// ── SelectionRadio ──────────────────────────────────────────────────────────── + +export const SelectionRadio: Story = { + name: 'Row Selection: RadioButton', + decorators: [moduleMetadata({ imports: [DataTableSelectionRadioComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Выбор одной строки через радио-кнопку. Укажите selectionMode: "single" в первом столбце.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-selection-radio', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableSelectionRadioComponent { + shipments = [...]; // массив отправлений + columns: DataTableColumn[] = [ + { selectionMode: 'single' }, + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + ]; + selected: any = null; +} + `, + }, + }, + }, +}; + +// ── SelectionCheckbox ───────────────────────────────────────────────────────── + +export const SelectionCheckbox: Story = { + name: 'Row Selection: Checkbox', + decorators: [moduleMetadata({ imports: [DataTableSelectionCheckboxComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Множественный выбор строк через чекбоксы. Первый столбец с selectionMode: "multiple" добавляет чекбокс в заголовок.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-selection-checkbox', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableSelectionCheckboxComponent { + shipments = [...]; // массив отправлений + columns: DataTableColumn[] = [ + { selectionMode: 'multiple' }, + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + ]; + selected: any[] = []; +} + `, + }, + }, + }, +}; + +// ── ScrollVertical ──────────────────────────────────────────────────────────── + +export const ScrollVertical: Story = { + name: 'Scroll: Vertical', + decorators: [moduleMetadata({ imports: [DataTableScrollVerticalComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Вертикальная прокрутка с фиксированной высотой контейнера. Заголовок остаётся видимым.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-scroll-vertical', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableScrollVerticalComponent { + shipments = [...]; // большой массив отправлений + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + ]; +} + `, + }, + }, + }, +}; + +// ── ScrollHorizontal ────────────────────────────────────────────────────────── + +export const ScrollHorizontal: Story = { + name: 'Scroll: Horizontal', + decorators: [moduleMetadata({ imports: [DataTableScrollHorizontalComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Горизонтальная прокрутка при большом количестве столбцов. Используйте style с min-width на столбцах.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; + +@Component({ + selector: 'app-data-table-scroll-horizontal', + standalone: true, + imports: [DataTableComponent], + template: \` + + \`, +}) +export class DataTableScrollHorizontalComponent { + shipments = [...]; // массив отправлений + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true, style: 'min-width: 160px' }, + { field: 'sender', header: 'Отправитель', sortable: true, style: 'min-width: 160px' }, + { field: 'destination', header: 'Назначение', sortable: true, style: 'min-width: 160px' }, + { field: 'status', header: 'Статус', sortable: true, style: 'min-width: 140px' }, + { field: 'weight', header: 'Вес, кг', sortable: true, style: 'min-width: 120px' }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true, style: 'min-width: 140px' }, + { field: 'dimensions', header: 'Габариты', sortable: false, style: 'min-width: 160px' }, + ]; +} + `, + }, + }, + }, +}; diff --git a/src/stories/components/data-table/examples/data-table-default.component.ts b/src/stories/components/data-table/examples/data-table-default.component.ts new file mode 100644 index 00000000..db4cdd08 --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-default.component.ts @@ -0,0 +1,38 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-default', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableDefaultComponent { + shipments = SHIPMENTS; + columns = COLUMNS; +} diff --git a/src/stories/components/data-table/examples/data-table-grid-lines.component.ts b/src/stories/components/data-table/examples/data-table-grid-lines.component.ts new file mode 100644 index 00000000..2aa5bed3 --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-grid-lines.component.ts @@ -0,0 +1,35 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-grid-lines', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableGridLinesComponent { + shipments = SHIPMENTS; + columns = COLUMNS; +} diff --git a/src/stories/components/data-table/examples/data-table-pagination.component.ts b/src/stories/components/data-table/examples/data-table-pagination.component.ts new file mode 100644 index 00000000..275670db --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-pagination.component.ts @@ -0,0 +1,44 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-pagination', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTablePaginationComponent { + shipments = SHIPMENTS; + columns = COLUMNS; +} diff --git a/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts b/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts new file mode 100644 index 00000000..3c6962b8 --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts @@ -0,0 +1,37 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', sender: 'Иванов И.И.', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200, dimensions: '30×20×15 см' }, + { id: 2, trackNumber: 'ЦД-00123457', sender: 'Петров П.П.', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450, dimensions: '10×10×10 см' }, + { id: 3, trackNumber: 'ЦД-00123458', sender: 'Сидоров С.С.', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100, dimensions: '50×40×30 см' }, + { id: 4, trackNumber: 'ЦД-00123459', sender: 'Козлов К.К.', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750, dimensions: '20×15×10 см' }, + { id: 5, trackNumber: 'ЦД-00123460', sender: 'Новиков Н.Н.', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800, dimensions: '40×30×20 см' }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true, style: 'min-width: 160px' }, + { field: 'sender', header: 'Отправитель', sortable: true, style: 'min-width: 160px' }, + { field: 'destination', header: 'Назначение', sortable: true, style: 'min-width: 160px' }, + { field: 'status', header: 'Статус', sortable: true, style: 'min-width: 140px' }, + { field: 'weight', header: 'Вес, кг', sortable: true, style: 'min-width: 120px' }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true, style: 'min-width: 140px' }, + { field: 'dimensions', header: 'Габариты', sortable: false, style: 'min-width: 160px' }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-scroll-horizontal', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableScrollHorizontalComponent { + shipments = SHIPMENTS; + columns = COLUMNS; +} diff --git a/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts b/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts new file mode 100644 index 00000000..f819b9e3 --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const BASE_SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-scroll-vertical', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableScrollVerticalComponent { + shipments = [...BASE_SHIPMENTS, ...BASE_SHIPMENTS, ...BASE_SHIPMENTS]; + columns = COLUMNS; +} diff --git a/src/stories/components/data-table/examples/data-table-selectable.component.ts b/src/stories/components/data-table/examples/data-table-selectable.component.ts new file mode 100644 index 00000000..2b9eb35f --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-selectable.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-selectable', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableSelectableComponent { + shipments = SHIPMENTS; + columns = COLUMNS; + selected: any = null; +} diff --git a/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts b/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts new file mode 100644 index 00000000..ea9120e5 --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { selectionMode: 'multiple' }, + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-selection-checkbox', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableSelectionCheckboxComponent { + shipments = SHIPMENTS; + columns = COLUMNS; + selected: any[] = []; +} diff --git a/src/stories/components/data-table/examples/data-table-selection-radio.component.ts b/src/stories/components/data-table/examples/data-table-selection-radio.component.ts new file mode 100644 index 00000000..fe6c4114 --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-selection-radio.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { selectionMode: 'single' }, + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-selection-radio', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableSelectionRadioComponent { + shipments = SHIPMENTS; + columns = COLUMNS; + selected: any = null; +} diff --git a/src/stories/components/data-table/examples/data-table-striped-rows.component.ts b/src/stories/components/data-table/examples/data-table-striped-rows.component.ts new file mode 100644 index 00000000..e86ca8dd --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-striped-rows.component.ts @@ -0,0 +1,35 @@ +import { Component } from '@angular/core'; +import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-striped-rows', + standalone: true, + imports: [DataTableComponent], + template, +}) +export class DataTableStripedRowsComponent { + shipments = SHIPMENTS; + columns = COLUMNS; +} From cf0045f068e3306fc5f2d92435ff7734d20710d0 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 13 Apr 2026 19:04:19 +0700 Subject: [PATCH 2/7] =?UTF-8?q?sortable=20=D1=81=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=B2=D0=BD=D1=83=D1=82=D1=80=D0=B5=D0=BD=D0=BD?= =?UTF-8?q?=D0=B8=D0=BC=20=D1=83=D1=81=D0=BB=D0=BE=D0=B2=D0=B8=D0=B5=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/components/data-table/data-table.component.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/components/data-table/data-table.component.ts b/src/lib/components/data-table/data-table.component.ts index 798bf685..75d3d3b5 100644 --- a/src/lib/components/data-table/data-table.component.ts +++ b/src/lib/components/data-table/data-table.component.ts @@ -43,13 +43,13 @@ export interface DataTableColumn { - } @else if (col.sortable) { - + } @else { + {{ col.header }} - + @if (col.sortable) { + + } - } @else { - {{ col.header }} } } From 6927c6299677926d3a5a65dc61bc00013ca61849 Mon Sep 17 00:00:00 2001 From: Danil Khaliulin Date: Mon, 13 Apr 2026 19:18:23 +0700 Subject: [PATCH 3/7] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=82=D0=B5?= =?UTF-8?q?=D0=BA=D1=81=D1=82=D0=B0=20=D0=BF=D1=80=D0=B8=20=D0=BD=D0=B0?= =?UTF-8?q?=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=D0=B8=D0=B8=20=D0=B2=20headerCel?= =?UTF-8?q?l?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prime-preset/tokens/components/data-table.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prime-preset/tokens/components/data-table.ts b/src/prime-preset/tokens/components/data-table.ts index f770594c..d5d0960e 100644 --- a/src/prime-preset/tokens/components/data-table.ts +++ b/src/prime-preset/tokens/components/data-table.ts @@ -23,6 +23,6 @@ export const dataTableCss = ({ dt }: { dt: (token: string) => string }): string } .p-datatable .p-datatable-sortable-column:not(.p-datatable-column-sorted):hover { - color: ${dt('datatable.headerCell.hoverColor')}; + color: ${dt('text.hoverColor')}; } `; From 952dcecc9c0570fa1742da761018321e75e998a8 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Mon, 25 May 2026 22:50:11 +0700 Subject: [PATCH 4/7] DS-517 --- .../data-table/data-table.component.ts | 4 +- src/lib/components/data-table/ng-package.json | 7 ++ src/lib/components/data-table/public_api.ts | 4 + .../data-table/data-table.stories.ts | 74 +++++++++---------- .../examples/data-table-default.component.ts | 6 +- .../data-table-grid-lines.component.ts | 6 +- .../data-table-pagination.component.ts | 8 +- .../data-table-scroll-horizontal.component.ts | 6 +- .../data-table-scroll-vertical.component.ts | 8 +- .../data-table-selectable.component.ts | 8 +- ...data-table-selection-checkbox.component.ts | 8 +- .../data-table-selection-radio.component.ts | 8 +- .../data-table-striped-rows.component.ts | 6 +- 13 files changed, 82 insertions(+), 71 deletions(-) create mode 100644 src/lib/components/data-table/ng-package.json create mode 100644 src/lib/components/data-table/public_api.ts diff --git a/src/lib/components/data-table/data-table.component.ts b/src/lib/components/data-table/data-table.component.ts index 75d3d3b5..54f5bd8c 100644 --- a/src/lib/components/data-table/data-table.component.ts +++ b/src/lib/components/data-table/data-table.component.ts @@ -12,7 +12,7 @@ export interface DataTableColumn { } @Component({ - selector: 'data-table', + selector: 'extra-data-table', host: { style: 'display: block' }, standalone: true, imports: [TableModule, PrimeTemplate], @@ -75,7 +75,7 @@ export interface DataTableColumn { `, }) -export class DataTableComponent { +export class ExtraDataTableComponent { @Input() value: any[] = []; @Input() columns: DataTableColumn[] = []; @Input() stripedRows = false; diff --git a/src/lib/components/data-table/ng-package.json b/src/lib/components/data-table/ng-package.json new file mode 100644 index 00000000..ecdf8fea --- /dev/null +++ b/src/lib/components/data-table/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/data-table/public_api.ts b/src/lib/components/data-table/public_api.ts new file mode 100644 index 00000000..8b3cbf32 --- /dev/null +++ b/src/lib/components/data-table/public_api.ts @@ -0,0 +1,4 @@ +export * from './data-table.component'; + + + diff --git a/src/stories/components/data-table/data-table.stories.ts b/src/stories/components/data-table/data-table.stories.ts index 6ea5f7f4..03d2fd92 100644 --- a/src/stories/components/data-table/data-table.stories.ts +++ b/src/stories/components/data-table/data-table.stories.ts @@ -1,5 +1,5 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { DataTableComponent } from '../../../lib/components/data-table/data-table.component'; +import { ExtraDataTableComponent } from '../../../lib/components/data-table/data-table.component'; import { DataTableDefaultComponent } from './examples/data-table-default.component'; import { DataTableStripedRowsComponent } from './examples/data-table-striped-rows.component'; import { DataTableSelectableComponent } from './examples/data-table-selectable.component'; @@ -10,9 +10,9 @@ import { DataTableSelectionCheckboxComponent } from './examples/data-table-selec import { DataTableScrollVerticalComponent } from './examples/data-table-scroll-vertical.component'; import { DataTableScrollHorizontalComponent } from './examples/data-table-scroll-horizontal.component'; -const meta: Meta = { +const meta: Meta = { title: 'Components/Data/DataTable', - component: DataTableComponent, + component: ExtraDataTableComponent, tags: ['autodocs'], parameters: { docs: { @@ -20,7 +20,7 @@ const meta: Meta = { component: `Таблица данных с поддержкой сортировки, пагинации, выбора строк и прокрутки. \`\`\`typescript -import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; \`\`\``, }, }, @@ -147,7 +147,7 @@ import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; }; export default meta; -type Story = StoryObj; +type Story = StoryObj; // ── Default ─────────────────────────────────────────────────────────────────── @@ -164,14 +164,14 @@ export const Default: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-data-table-default', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template: \` - + \`, }) export class DataTableDefaultComponent { @@ -209,14 +209,14 @@ export const StripedRows: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-data-table-striped-rows', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template: \` - + \`, }) export class DataTableStripedRowsComponent { @@ -254,20 +254,20 @@ export const Selectable: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-data-table-selectable', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template: \` - + > \`, }) export class DataTableSelectableComponent { @@ -307,14 +307,14 @@ export const GridLines: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-data-table-grid-lines', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template: \` - + \`, }) export class DataTableGridLinesComponent { @@ -352,20 +352,20 @@ export const Pagination: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-data-table-pagination', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template: \` - + > \`, }) export class DataTablePaginationComponent { @@ -399,20 +399,20 @@ export const SelectionRadio: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-data-table-selection-radio', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template: \` - + > \`, }) export class DataTableSelectionRadioComponent { @@ -447,20 +447,20 @@ export const SelectionCheckbox: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-data-table-selection-checkbox', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template: \` - + > \`, }) export class DataTableSelectionCheckboxComponent { @@ -495,19 +495,19 @@ export const ScrollVertical: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-data-table-scroll-vertical', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template: \` - + > \`, }) export class DataTableScrollVerticalComponent { @@ -540,14 +540,14 @@ export const ScrollHorizontal: Story = { language: 'ts', code: ` import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; @Component({ selector: 'app-data-table-scroll-horizontal', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template: \` - + \`, }) export class DataTableScrollHorizontalComponent { diff --git a/src/stories/components/data-table/examples/data-table-default.component.ts b/src/stories/components/data-table/examples/data-table-default.component.ts index db4cdd08..434a4c03 100644 --- a/src/stories/components/data-table/examples/data-table-default.component.ts +++ b/src/stories/components/data-table/examples/data-table-default.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; +import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; const SHIPMENTS = [ { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, @@ -22,14 +22,14 @@ const COLUMNS: DataTableColumn[] = [ const template = `
- +
`; @Component({ selector: 'app-data-table-default', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template, }) export class DataTableDefaultComponent { diff --git a/src/stories/components/data-table/examples/data-table-grid-lines.component.ts b/src/stories/components/data-table/examples/data-table-grid-lines.component.ts index 2aa5bed3..1f7a94bd 100644 --- a/src/stories/components/data-table/examples/data-table-grid-lines.component.ts +++ b/src/stories/components/data-table/examples/data-table-grid-lines.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; +import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; const SHIPMENTS = [ { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, @@ -19,14 +19,14 @@ const COLUMNS: DataTableColumn[] = [ const template = `
- +
`; @Component({ selector: 'app-data-table-grid-lines', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template, }) export class DataTableGridLinesComponent { diff --git a/src/stories/components/data-table/examples/data-table-pagination.component.ts b/src/stories/components/data-table/examples/data-table-pagination.component.ts index 275670db..09180b9b 100644 --- a/src/stories/components/data-table/examples/data-table-pagination.component.ts +++ b/src/stories/components/data-table/examples/data-table-pagination.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; +import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; const SHIPMENTS = [ { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, @@ -22,20 +22,20 @@ const COLUMNS: DataTableColumn[] = [ const template = `
- + >
`; @Component({ selector: 'app-data-table-pagination', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template, }) export class DataTablePaginationComponent { diff --git a/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts b/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts index 3c6962b8..0428887d 100644 --- a/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts +++ b/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; +import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; const SHIPMENTS = [ { id: 1, trackNumber: 'ЦД-00123456', sender: 'Иванов И.И.', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200, dimensions: '30×20×15 см' }, @@ -21,14 +21,14 @@ const COLUMNS: DataTableColumn[] = [ const template = `
- +
`; @Component({ selector: 'app-data-table-scroll-horizontal', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template, }) export class DataTableScrollHorizontalComponent { diff --git a/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts b/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts index f819b9e3..c7773a5e 100644 --- a/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts +++ b/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; +import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; const BASE_SHIPMENTS = [ { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, @@ -21,19 +21,19 @@ const COLUMNS: DataTableColumn[] = [ const template = `
- + >
`; @Component({ selector: 'app-data-table-scroll-vertical', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template, }) export class DataTableScrollVerticalComponent { diff --git a/src/stories/components/data-table/examples/data-table-selectable.component.ts b/src/stories/components/data-table/examples/data-table-selectable.component.ts index 2b9eb35f..4d0e1b8a 100644 --- a/src/stories/components/data-table/examples/data-table-selectable.component.ts +++ b/src/stories/components/data-table/examples/data-table-selectable.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; +import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; const SHIPMENTS = [ { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, @@ -19,20 +19,20 @@ const COLUMNS: DataTableColumn[] = [ const template = `
- + >
`; @Component({ selector: 'app-data-table-selectable', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template, }) export class DataTableSelectableComponent { diff --git a/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts b/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts index ea9120e5..20a18330 100644 --- a/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts +++ b/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; +import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; const SHIPMENTS = [ { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, @@ -19,20 +19,20 @@ const COLUMNS: DataTableColumn[] = [ const template = `
- + >
`; @Component({ selector: 'app-data-table-selection-checkbox', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template, }) export class DataTableSelectionCheckboxComponent { diff --git a/src/stories/components/data-table/examples/data-table-selection-radio.component.ts b/src/stories/components/data-table/examples/data-table-selection-radio.component.ts index fe6c4114..1aeb0883 100644 --- a/src/stories/components/data-table/examples/data-table-selection-radio.component.ts +++ b/src/stories/components/data-table/examples/data-table-selection-radio.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; +import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; const SHIPMENTS = [ { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, @@ -19,20 +19,20 @@ const COLUMNS: DataTableColumn[] = [ const template = `
- + >
`; @Component({ selector: 'app-data-table-selection-radio', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template, }) export class DataTableSelectionRadioComponent { diff --git a/src/stories/components/data-table/examples/data-table-striped-rows.component.ts b/src/stories/components/data-table/examples/data-table-striped-rows.component.ts index e86ca8dd..2f78155d 100644 --- a/src/stories/components/data-table/examples/data-table-striped-rows.component.ts +++ b/src/stories/components/data-table/examples/data-table-striped-rows.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { DataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; +import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; const SHIPMENTS = [ { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, @@ -19,14 +19,14 @@ const COLUMNS: DataTableColumn[] = [ const template = `
- +
`; @Component({ selector: 'app-data-table-striped-rows', standalone: true, - imports: [DataTableComponent], + imports: [ExtraDataTableComponent], template, }) export class DataTableStripedRowsComponent { From 70f940dbbebf5a5ccc44eda11c7ac6f22d1780da Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Fri, 29 May 2026 16:51:20 +0700 Subject: [PATCH 5/7] DS-517 --- .../data-table/data-table.component.ts | 408 ++++++++++++++++-- .../data-table/data-table.stories.ts | 150 +++++++ .../data-table-custom-body.component.ts | 81 ++++ .../examples/data-table-lazy.component.ts | 66 +++ .../p-data-table-custom-body.component.ts | 58 +++ .../p-data-table-default.component.ts | 44 ++ .../p-data-table-grid-lines.component.ts | 41 ++ .../examples/p-data-table-lazy.component.ts | 85 ++++ .../p-data-table-pagination.component.ts | 44 ++ ...-data-table-scroll-horizontal.component.ts | 57 +++ .../p-data-table-scroll-vertical.component.ts | 42 ++ .../p-data-table-selectable.component.ts | 42 ++ ...data-table-selection-checkbox.component.ts | 46 ++ .../p-data-table-selection-radio.component.ts | 44 ++ .../p-data-table-striped-rows.component.ts | 44 ++ .../p-data-table/p-data-table.stories.ts | 198 +++++++++ 16 files changed, 1405 insertions(+), 45 deletions(-) create mode 100644 src/stories/components/data-table/examples/data-table-custom-body.component.ts create mode 100644 src/stories/components/data-table/examples/data-table-lazy.component.ts create mode 100644 src/stories/components/p-data-table/examples/p-data-table-custom-body.component.ts create mode 100644 src/stories/components/p-data-table/examples/p-data-table-default.component.ts create mode 100644 src/stories/components/p-data-table/examples/p-data-table-grid-lines.component.ts create mode 100644 src/stories/components/p-data-table/examples/p-data-table-lazy.component.ts create mode 100644 src/stories/components/p-data-table/examples/p-data-table-pagination.component.ts create mode 100644 src/stories/components/p-data-table/examples/p-data-table-scroll-horizontal.component.ts create mode 100644 src/stories/components/p-data-table/examples/p-data-table-scroll-vertical.component.ts create mode 100644 src/stories/components/p-data-table/examples/p-data-table-selectable.component.ts create mode 100644 src/stories/components/p-data-table/examples/p-data-table-selection-checkbox.component.ts create mode 100644 src/stories/components/p-data-table/examples/p-data-table-selection-radio.component.ts create mode 100644 src/stories/components/p-data-table/examples/p-data-table-striped-rows.component.ts create mode 100644 src/stories/components/p-data-table/p-data-table.stories.ts diff --git a/src/lib/components/data-table/data-table.component.ts b/src/lib/components/data-table/data-table.component.ts index 54f5bd8c..0e72e028 100644 --- a/src/lib/components/data-table/data-table.component.ts +++ b/src/lib/components/data-table/data-table.component.ts @@ -1,6 +1,40 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { + AfterContentInit, + Component, + ContentChildren, + EventEmitter, + Input, + Output, + QueryList, + TemplateRef, + ViewChild, +} from '@angular/core'; +import { NgTemplateOutlet } from '@angular/common'; import { TableModule } from 'primeng/table'; -import { PrimeTemplate } from 'primeng/api'; +import { + PrimeTemplate, + SortMeta, + FilterMetadata, + ScrollerOptions, +} from 'primeng/api'; +import { + TableLazyLoadEvent, + TableRowSelectEvent, + TableRowUnSelectEvent, + TablePageEvent, + TableFilterEvent, + TableRowExpandEvent, + TableRowCollapseEvent, + TableContextMenuSelectEvent, + TableColResizeEvent, + TableColumnReorderEvent, + TableRowReorderEvent, + TableEditInitEvent, + TableEditCompleteEvent, + TableEditCancelEvent, + TableHeaderCheckboxToggleEvent, + TableSelectAllChangeEvent, +} from 'primeng/types/table'; export interface DataTableColumn { field?: string; @@ -15,8 +49,49 @@ export interface DataTableColumn { selector: 'extra-data-table', host: { style: 'display: block' }, standalone: true, - imports: [TableModule, PrimeTemplate], + imports: [TableModule, PrimeTemplate, NgTemplateOutlet], template: ` + + + + @for (col of columns; track $index) { + @if (col.selectionMode === 'single') { + + } @else if (col.selectionMode === 'multiple') { + + + + } @else { + + {{ col.header }} + @if (col.sortable) { + + } + + } + } + + + + + + + @for (col of columns; track $index) { + @if (col.selectionMode === 'single') { + + + + } @else if (col.selectionMode === 'multiple') { + + + + } @else { + {{ rowData[col.field] }} + } + } + + + + - - @for (col of columns; track $index) { - @if (col.selectionMode === 'single') { - - } @else if (col.selectionMode === 'multiple') { - - - - } @else { - - {{ col.header }} - @if (col.sortable) { - - } - - } - } - + - - - @for (col of columns; track $index) { - @if (col.selectionMode === 'single') { - - - - } @else if (col.selectionMode === 'multiple') { - - - - } @else { - {{ rowData[col.field] }} - } - } - + + + + + + @if (captionTemplate) { + + + + } + @if (footerTemplate) { + + + + } + @if (summaryTemplate) { + + + + } + @if (emptyMessageTemplate) { + + + + } + @if (rowExpansionTemplate) { + + + + } + @if (groupHeaderTemplate) { + + + + } + @if (groupFooterTemplate) { + + + + } + @if (paginatorLeftTemplate) { + + + + } + @if (paginatorRightTemplate) { + + + + } + @if (loadingIconTemplate) { + + + + } `, }) -export class ExtraDataTableComponent { +export class ExtraDataTableComponent implements AfterContentInit { + // ── Data ────────────────────────────────────────────────────────────────── @Input() value: any[] = []; @Input() columns: DataTableColumn[] = []; + + // ── Appearance ──────────────────────────────────────────────────────────── @Input() stripedRows = false; @Input() showGridlines = false; - @Input() loading = false; @Input() size: 'small' | 'large' | undefined = undefined; - @Input() scrollable = false; - @Input() scrollHeight = ''; + @Input() styleClass: string | undefined = undefined; + @Input() tableStyle: { [key: string]: any } | undefined = undefined; + @Input() tableStyleClass: string | undefined = undefined; + + // ── Loading ─────────────────────────────────────────────────────────────── + @Input() loading = false; + + // ── Pagination ──────────────────────────────────────────────────────────── @Input() paginator = false; - @Input() rows = 5; - @Input() rowsPerPageOptions: number[] = [5, 10, 25]; + @Input() rows = 10; + @Input() rowsPerPageOptions: number[] = []; + @Input() first: number | null | undefined = 0; + @Input() totalRecords = 0; + @Output() firstChange = new EventEmitter(); + + // ── Scroll ──────────────────────────────────────────────────────────────── + @Input() scrollable = false; + @Input() scrollHeight: string | undefined = undefined; + + // ── Virtual Scroll ──────────────────────────────────────────────────────── + @Input() virtualScroll: boolean | undefined = undefined; + @Input() virtualScrollItemSize: number | undefined = undefined; + @Input() virtualScrollOptions: ScrollerOptions | undefined = undefined; + @Input() virtualScrollDelay = 250; + + // ── Lazy loading ────────────────────────────────────────────────────────── + @Input() lazy = false; + @Input() lazyLoadOnInit = true; + @Output() onLazyLoad = new EventEmitter(); + + // ── Sorting ─────────────────────────────────────────────────────────────── + @Input() sortField: string | undefined | null = undefined; + @Input() sortOrder = 1; + @Input() defaultSortOrder = 1; + @Input() sortMode: 'single' | 'multiple' = 'single'; + @Input() multiSortMeta: SortMeta[] | undefined | null = undefined; + @Input() customSort = false; + @Output() onSort = new EventEmitter(); + @Output() sortFunction = new EventEmitter(); + + // ── Selection ───────────────────────────────────────────────────────────── @Input() selectionMode: 'single' | 'multiple' | undefined = undefined; @Input() selection: any = null; - @Output() selectionChange = new EventEmitter(); @Input() dataKey = 'id'; + @Input() metaKeySelection = false; + @Input() rowSelectable: ((row: { data: any; index: number }) => boolean | undefined) | undefined = undefined; + @Input() selectAll: boolean | null = null; + @Output() selectionChange = new EventEmitter(); + @Output() selectAllChange = new EventEmitter(); + @Output() onRowSelect = new EventEmitter(); + @Output() onRowUnselect = new EventEmitter>(); + @Output() onHeaderCheckboxToggle = new EventEmitter(); + + // ── Context Menu ────────────────────────────────────────────────────────── + @Input() contextMenu: any = undefined; + @Input() contextMenuSelection: any = undefined; + @Output() contextMenuSelectionChange = new EventEmitter(); + @Output() onContextMenuSelect = new EventEmitter(); + + // ── Row Expand ──────────────────────────────────────────────────────────── + @Input() expandedRowKeys: { [s: string]: boolean } = {}; + @Input() rowExpandMode: 'multiple' | 'single' = 'multiple'; + @Output() onRowExpand = new EventEmitter(); + @Output() onRowCollapse = new EventEmitter(); + + // ── Row Group ───────────────────────────────────────────────────────────── + @Input() rowGroupMode: 'subheader' | 'rowspan' | undefined = undefined; + @Input() groupRowsBy: string | undefined = undefined; + @Input() groupRowsByOrder = 1; + + // ── Edit ────────────────────────────────────────────────────────────────── + @Input() editMode: 'cell' | 'row' = 'cell'; + @Output() onEditInit = new EventEmitter(); + @Output() onEditComplete = new EventEmitter(); + @Output() onEditCancel = new EventEmitter(); + + // ── Column Resize ───────────────────────────────────────────────────────── + @Input() resizableColumns = false; + @Input() columnResizeMode: 'fit' | 'expand' = 'fit'; + @Output() onColResize = new EventEmitter(); + + // ── Column Reorder ──────────────────────────────────────────────────────── + @Input() reorderableColumns = false; + @Output() onColReorder = new EventEmitter(); + + // ── Row Reorder ─────────────────────────────────────────────────────────── + @Output() onRowReorder = new EventEmitter(); + + // ── Row Hover ───────────────────────────────────────────────────────────── + @Input() rowHover = false; + + // ── Filter ──────────────────────────────────────────────────────────────── + @Input() filters: { [s: string]: FilterMetadata | FilterMetadata[] } = {}; + @Input() globalFilterFields: string[] | undefined = undefined; + @Input() filterDelay = 300; + @Output() onFilter = new EventEmitter(); + + // ── Pagination events ───────────────────────────────────────────────────── + @Output() onPage = new EventEmitter(); + + // ── State ───────────────────────────────────────────────────────────────── + @Input() stateKey: string | undefined = undefined; + @Input() stateStorage: 'session' | 'local' = 'session'; + + // ── Default templates ───────────────────────────────────────────────────── + @ViewChild('defaultHeaderTpl') defaultHeaderTpl!: TemplateRef; + @ViewChild('defaultBodyTpl') defaultBodyTpl!: TemplateRef; + + // ── User-provided content templates ────────────────────────────────────── + @ContentChildren(PrimeTemplate) templates!: QueryList; + + headerTemplate: TemplateRef | null = null; + bodyTemplate: TemplateRef | null = null; + captionTemplate: TemplateRef | null = null; + footerTemplate: TemplateRef | null = null; + summaryTemplate: TemplateRef | null = null; + emptyMessageTemplate: TemplateRef | null = null; + rowExpansionTemplate: TemplateRef | null = null; + groupHeaderTemplate: TemplateRef | null = null; + groupFooterTemplate: TemplateRef | null = null; + paginatorLeftTemplate: TemplateRef | null = null; + paginatorRightTemplate: TemplateRef | null = null; + loadingIconTemplate: TemplateRef | null = null; + + ngAfterContentInit(): void { + this.templates.forEach((t) => { + switch (t.getType()) { + case 'header': + this.headerTemplate = t.template; + break; + case 'body': + this.bodyTemplate = t.template; + break; + case 'caption': + this.captionTemplate = t.template; + break; + case 'footer': + this.footerTemplate = t.template; + break; + case 'summary': + this.summaryTemplate = t.template; + break; + case 'emptymessage': + this.emptyMessageTemplate = t.template; + break; + case 'rowexpansion': + this.rowExpansionTemplate = t.template; + break; + case 'groupheader': + this.groupHeaderTemplate = t.template; + break; + case 'groupfooter': + this.groupFooterTemplate = t.template; + break; + case 'paginatorleft': + this.paginatorLeftTemplate = t.template; + break; + case 'paginatorright': + this.paginatorRightTemplate = t.template; + break; + case 'loadingicon': + this.loadingIconTemplate = t.template; + break; + } + }); + } } diff --git a/src/stories/components/data-table/data-table.stories.ts b/src/stories/components/data-table/data-table.stories.ts index 03d2fd92..3d614feb 100644 --- a/src/stories/components/data-table/data-table.stories.ts +++ b/src/stories/components/data-table/data-table.stories.ts @@ -9,6 +9,8 @@ import { DataTableSelectionRadioComponent } from './examples/data-table-selectio import { DataTableSelectionCheckboxComponent } from './examples/data-table-selection-checkbox.component'; import { DataTableScrollVerticalComponent } from './examples/data-table-scroll-vertical.component'; import { DataTableScrollHorizontalComponent } from './examples/data-table-scroll-horizontal.component'; +import { DataTableCustomBodyComponent } from './examples/data-table-custom-body.component'; +import { DataTableLazyComponent } from './examples/data-table-lazy.component'; const meta: Meta = { title: 'Components/Data/DataTable', @@ -567,3 +569,151 @@ export class DataTableScrollHorizontalComponent { }, }, }; + +// ── CustomBody ──────────────────────────────────────────────────────────────── + +export const CustomBody: Story = { + name: 'Custom Templates', + decorators: [moduleMetadata({ imports: [DataTableCustomBodyComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: + 'Кастомные шаблоны для заголовка и тела таблицы. Передайте `ng-template` с директивой `pTemplate` внутрь ``. Поддерживаются шаблоны: `header`, `body`, `footer`, `caption`, `summary`, `emptymessage`, `rowexpansion`, `groupheader`, `groupfooter`, `paginatorleft`, `paginatorright`, `loadingicon`.', + }, + source: { + language: 'ts', + code: ` +import { Component } from '@angular/core'; +import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +import { PrimeTemplate } from 'primeng/api'; +import { TagModule } from 'primeng/tag'; + +@Component({ + selector: 'app-data-table-custom-body', + standalone: true, + imports: [ExtraDataTableComponent, PrimeTemplate, TagModule], + template: \` + + + + + @for (col of columns; track col.field) { + + {{ col.header }} + @if (col.sortable) { } + + } + + + + + + {{ row.trackNumber }} + {{ row.destination }} + + + + {{ row.weight }} кг + {{ row.cost | currency:'RUB':'symbol':'1.0-0':'ru' }} + + + + + Нет данных для отображения + + + + \`, +}) +export class DataTableCustomBodyComponent { + shipments = [...]; + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, + ]; + + getSeverity(status: string) { + switch (status) { + case 'Доставлен': return 'success'; + case 'В пути': return 'info'; + case 'Задержан': return 'danger'; + default: return 'warn'; + } + } +} + `, + }, + }, + }, +}; + +// ── Lazy loading ────────────────────────────────────────────────────────────── + +export const LazyLoading: Story = { + name: 'Lazy Loading', + decorators: [moduleMetadata({ imports: [DataTableLazyComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: + 'Ленивая подгрузка данных с сервера при пагинации/сортировке. Используйте `[lazy]="true"`, `[totalRecords]` и `(onLazyLoad)` для управления загрузкой.', + }, + source: { + language: 'ts', + code: ` +import { Component, OnInit } from '@angular/core'; +import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; +import { TableLazyLoadEvent } from 'primeng/types/table'; + +@Component({ + selector: 'app-data-table-lazy', + standalone: true, + imports: [ExtraDataTableComponent], + template: \` + + \`, +}) +export class DataTableLazyComponent implements OnInit { + shipments: any[] = []; + columns: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, + ]; + totalRecords = 0; + loading = true; + + onLazyLoad(event: TableLazyLoadEvent): void { + this.loading = true; + // Запрос к серверу с event.first, event.rows, event.sortField, event.sortOrder + myApiService.getShipments(event).subscribe(result => { + this.shipments = result.data; + this.totalRecords = result.total; + this.loading = false; + }); + } +} + `, + }, + }, + }, +}; + diff --git a/src/stories/components/data-table/examples/data-table-custom-body.component.ts b/src/stories/components/data-table/examples/data-table-custom-body.component.ts new file mode 100644 index 00000000..f3b95ecb --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-custom-body.component.ts @@ -0,0 +1,81 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; +import { PrimeTemplate } from 'primeng/api'; +import { TagModule } from 'primeng/tag'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, +]; + +const template = ` +
+ + + + + @for (col of columns; track col.field) { + + {{ col.header }} + @if (col.sortable) { } + + } + + + + + + {{ row.trackNumber }} + {{ row.destination }} + + + + {{ row.weight }} кг + {{ row.cost | currency:'RUB':'symbol':'1.0-0':'ru' }} + + + + + Нет данных для отображения + + + +
+`; + +@Component({ + selector: 'app-data-table-custom-body', + standalone: true, + imports: [ExtraDataTableComponent, PrimeTemplate, TagModule, CommonModule], + template, +}) +export class DataTableCustomBodyComponent { + shipments = SHIPMENTS; + columns = COLUMNS; + + getSeverity(status: string): 'success' | 'warn' | 'danger' | 'info' | 'secondary' | undefined { + switch (status) { + case 'Доставлен': return 'success'; + case 'В пути': return 'info'; + case 'Задержан': return 'danger'; + case 'Ожидание': return 'warn'; + default: return 'secondary'; + } + } +} + diff --git a/src/stories/components/data-table/examples/data-table-lazy.component.ts b/src/stories/components/data-table/examples/data-table-lazy.component.ts new file mode 100644 index 00000000..9ca1f978 --- /dev/null +++ b/src/stories/components/data-table/examples/data-table-lazy.component.ts @@ -0,0 +1,66 @@ +import { Component, OnInit } from '@angular/core'; +import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; +import { PrimeTemplate } from 'primeng/api'; +import { TableLazyLoadEvent } from 'primeng/types/table'; + +const ALL_SHIPMENTS = Array.from({ length: 100 }, (_, i) => ({ + id: i + 1, + trackNumber: `ЦД-${String(i + 100000).padStart(8, '0')}`, + destination: ['Москва', 'Новосибирск', 'Екатеринбург', 'Казань', 'Краснодар'][i % 5], + status: ['В пути', 'Доставлен', 'Задержан', 'Ожидание'][i % 4], + weight: Number((Math.random() * 10).toFixed(1)), + cost: Math.floor(Math.random() * 5000) + 200, +})); + +const COLUMNS: DataTableColumn[] = [ + { field: 'trackNumber', header: 'Трек-номер', sortable: true }, + { field: 'destination', header: 'Назначение', sortable: true }, + { field: 'status', header: 'Статус', sortable: true }, + { field: 'weight', header: 'Вес, кг', sortable: true }, + { field: 'cost', header: 'Стоимость, ₽', sortable: true }, +]; + +const template = ` +
+ +
+`; + +@Component({ + selector: 'app-data-table-lazy', + standalone: true, + imports: [ExtraDataTableComponent, PrimeTemplate], + template, +}) +export class DataTableLazyComponent implements OnInit { + shipments: any[] = []; + columns = COLUMNS; + totalRecords = ALL_SHIPMENTS.length; + loading = true; + + ngOnInit(): void { + // Initial load happens via onLazyLoad + } + + onLazyLoad(event: TableLazyLoadEvent): void { + this.loading = true; + // Simulate async server request + setTimeout(() => { + const start = event.first ?? 0; + const end = start + (event.rows ?? 10); + this.shipments = ALL_SHIPMENTS.slice(start, end); + this.loading = false; + }, 500); + } +} + diff --git a/src/stories/components/p-data-table/examples/p-data-table-custom-body.component.ts b/src/stories/components/p-data-table/examples/p-data-table-custom-body.component.ts new file mode 100644 index 00000000..bd448577 --- /dev/null +++ b/src/stories/components/p-data-table/examples/p-data-table-custom-body.component.ts @@ -0,0 +1,58 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { TableModule } from 'primeng/table'; +import { TagModule } from 'primeng/tag'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +@Component({ + selector: 'app-p-data-table-custom-body', + standalone: true, + imports: [CommonModule, TableModule, TagModule], + template: ` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + + + + {{ shipment.weight }} кг + {{ shipment.cost | currency:'RUB':'symbol':'1.0-0':'ru' }} + + + + Нет данных для отображения + + + `, +}) +export class PDataTableCustomBodyComponent { + shipments = SHIPMENTS; + + getSeverity(status: string): 'success' | 'warn' | 'danger' | 'info' | 'secondary' | undefined { + switch (status) { + case 'Доставлен': return 'success'; + case 'В пути': return 'info'; + case 'Задержан': return 'danger'; + case 'Ожидание': return 'warn'; + default: return 'secondary'; + } + } +} \ No newline at end of file diff --git a/src/stories/components/p-data-table/examples/p-data-table-default.component.ts b/src/stories/components/p-data-table/examples/p-data-table-default.component.ts new file mode 100644 index 00000000..e16de983 --- /dev/null +++ b/src/stories/components/p-data-table/examples/p-data-table-default.component.ts @@ -0,0 +1,44 @@ +import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +@Component({ + selector: 'app-p-data-table-default', + standalone: true, + imports: [TableModule], + template: ` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + `, +}) +export class PDataTableDefaultComponent { + shipments = SHIPMENTS; +} \ No newline at end of file diff --git a/src/stories/components/p-data-table/examples/p-data-table-grid-lines.component.ts b/src/stories/components/p-data-table/examples/p-data-table-grid-lines.component.ts new file mode 100644 index 00000000..ce4e45e8 --- /dev/null +++ b/src/stories/components/p-data-table/examples/p-data-table-grid-lines.component.ts @@ -0,0 +1,41 @@ +import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +@Component({ + selector: 'app-p-data-table-grid-lines', + standalone: true, + imports: [TableModule], + template: ` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + `, +}) +export class PDataTableGridLinesComponent { + shipments = SHIPMENTS; +} \ No newline at end of file diff --git a/src/stories/components/p-data-table/examples/p-data-table-lazy.component.ts b/src/stories/components/p-data-table/examples/p-data-table-lazy.component.ts new file mode 100644 index 00000000..4b2ee67f --- /dev/null +++ b/src/stories/components/p-data-table/examples/p-data-table-lazy.component.ts @@ -0,0 +1,85 @@ +import { Component, OnInit } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const ALL_SHIPMENTS = Array.from({ length: 500 }, (_, i) => ({ + id: i + 1, + trackNumber: `ЦД-${String(i + 100000).padStart(8, '0')}`, + destination: ['Москва', 'Новосибирск', 'Екатеринбург', 'Казань', 'Краснодар', 'Санкт-Петербург', 'Воронеж', 'Самара', 'Ростов-на-Дону', 'Уфа'][i % 10], + status: ['В пути', 'Доставлен', 'Задержан', 'Ожидание'][i % 4], + weight: Number(((i * 0.37 + 0.5) % 10).toFixed(1)), + cost: ((i * 137 + 200) % 5000) + 200, +})); + +const PAGE_SIZE = 50; + +@Component({ + selector: 'app-p-data-table-lazy', + standalone: true, + imports: [TableModule], + template: ` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment?.trackNumber }} + {{ shipment?.destination }} + {{ shipment?.status }} + {{ shipment?.weight }} + {{ shipment?.cost }} + + + + + Загрузка… + + + + `, +}) +export class PDataTableLazyComponent implements OnInit { + readonly PAGE_SIZE = PAGE_SIZE; + + shipments: any[] = Array.from({ length: ALL_SHIPMENTS.length }); + totalRecords = ALL_SHIPMENTS.length; + loading = false; + + ngOnInit(): void { + // shipments pre-filled with placeholders so virtual scroll knows total size + } + + onLazyLoad(event: any): void { + this.loading = true; + const start = event.first ?? 0; + const end = start + (event.rows ?? PAGE_SIZE); + + // Simulate async server request + setTimeout(() => { + const page = ALL_SHIPMENTS.slice(start, end); + const updated = [...this.shipments]; + for (let i = 0; i < page.length; i++) { + updated[start + i] = page[i]; + } + this.shipments = updated; + this.loading = false; + }, 300); + } +} diff --git a/src/stories/components/p-data-table/examples/p-data-table-pagination.component.ts b/src/stories/components/p-data-table/examples/p-data-table-pagination.component.ts new file mode 100644 index 00000000..c6af7b1e --- /dev/null +++ b/src/stories/components/p-data-table/examples/p-data-table-pagination.component.ts @@ -0,0 +1,44 @@ +import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +@Component({ + selector: 'app-p-data-table-pagination', + standalone: true, + imports: [TableModule], + template: ` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + `, +}) +export class PDataTablePaginationComponent { + shipments = SHIPMENTS; +} \ No newline at end of file diff --git a/src/stories/components/p-data-table/examples/p-data-table-scroll-horizontal.component.ts b/src/stories/components/p-data-table/examples/p-data-table-scroll-horizontal.component.ts new file mode 100644 index 00000000..46bd0e84 --- /dev/null +++ b/src/stories/components/p-data-table/examples/p-data-table-scroll-horizontal.component.ts @@ -0,0 +1,57 @@ +import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', sender: 'Иванов И.И.', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200, dimensions: '30×20×15 см' }, + { id: 2, trackNumber: 'ЦД-00123457', sender: 'Петров П.П.', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450, dimensions: '10×10×10 см' }, + { id: 3, trackNumber: 'ЦД-00123458', sender: 'Сидоров С.С.', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100, dimensions: '50×40×30 см' }, + { id: 4, trackNumber: 'ЦД-00123459', sender: 'Козлов К.К.', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750, dimensions: '20×15×10 см' }, + { id: 5, trackNumber: 'ЦД-00123460', sender: 'Новиков Н.Н.', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800, dimensions: '40×30×20 см' }, +]; + +@Component({ + selector: 'app-p-data-table-scroll-horizontal', + standalone: true, + imports: [TableModule], + template: ` + + + + + Трек-номер + + + Отправитель + + + Назначение + + + Статус + + + Вес, кг + + + Стоимость, ₽ + + Габариты + + + + + {{ shipment.trackNumber }} + {{ shipment.sender }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + {{ shipment.dimensions }} + + + + `, +}) +export class PDataTableScrollHorizontalComponent { + shipments = SHIPMENTS; +} \ No newline at end of file diff --git a/src/stories/components/p-data-table/examples/p-data-table-scroll-vertical.component.ts b/src/stories/components/p-data-table/examples/p-data-table-scroll-vertical.component.ts new file mode 100644 index 00000000..d3b808a3 --- /dev/null +++ b/src/stories/components/p-data-table/examples/p-data-table-scroll-vertical.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const BASE_SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1 }, +]; + +@Component({ + selector: 'app-p-data-table-scroll-vertical', + standalone: true, + imports: [TableModule], + template: ` + + + + Трек-номер + Назначение + Статус + Вес, кг + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + + + + `, +}) +export class PDataTableScrollVerticalComponent { + shipments = [...BASE_SHIPMENTS, ...BASE_SHIPMENTS, ...BASE_SHIPMENTS]; +} \ No newline at end of file diff --git a/src/stories/components/p-data-table/examples/p-data-table-selectable.component.ts b/src/stories/components/p-data-table/examples/p-data-table-selectable.component.ts new file mode 100644 index 00000000..5265ad9a --- /dev/null +++ b/src/stories/components/p-data-table/examples/p-data-table-selectable.component.ts @@ -0,0 +1,42 @@ +import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +@Component({ + selector: 'app-p-data-table-selectable', + standalone: true, + imports: [TableModule], + template: ` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + `, +}) +export class PDataTableSelectableComponent { + shipments = SHIPMENTS; + selected: any = null; +} \ No newline at end of file diff --git a/src/stories/components/p-data-table/examples/p-data-table-selection-checkbox.component.ts b/src/stories/components/p-data-table/examples/p-data-table-selection-checkbox.component.ts new file mode 100644 index 00000000..63e165ea --- /dev/null +++ b/src/stories/components/p-data-table/examples/p-data-table-selection-checkbox.component.ts @@ -0,0 +1,46 @@ +import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, +]; + +@Component({ + selector: 'app-p-data-table-selection-checkbox', + standalone: true, + imports: [TableModule], + template: ` + + + + + + + Трек-номер + Назначение + Статус + Вес, кг + + + + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + + + + `, +}) +export class PDataTableSelectionCheckboxComponent { + shipments = SHIPMENTS; + selected: any[] = []; +} \ No newline at end of file diff --git a/src/stories/components/p-data-table/examples/p-data-table-selection-radio.component.ts b/src/stories/components/p-data-table/examples/p-data-table-selection-radio.component.ts new file mode 100644 index 00000000..0fa3686a --- /dev/null +++ b/src/stories/components/p-data-table/examples/p-data-table-selection-radio.component.ts @@ -0,0 +1,44 @@ +import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, +]; + +@Component({ + selector: 'app-p-data-table-selection-radio', + standalone: true, + imports: [TableModule], + template: ` + + + + + Трек-номер + Назначение + Статус + Вес, кг + + + + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + + + + `, +}) +export class PDataTableSelectionRadioComponent { + shipments = SHIPMENTS; + selected: any = null; +} \ No newline at end of file diff --git a/src/stories/components/p-data-table/examples/p-data-table-striped-rows.component.ts b/src/stories/components/p-data-table/examples/p-data-table-striped-rows.component.ts new file mode 100644 index 00000000..4ffba2ac --- /dev/null +++ b/src/stories/components/p-data-table/examples/p-data-table-striped-rows.component.ts @@ -0,0 +1,44 @@ +import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +@Component({ + selector: 'app-p-data-table-striped-rows', + standalone: true, + imports: [TableModule], + template: ` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + `, +}) +export class PDataTableStripedRowsComponent { + shipments = SHIPMENTS; +} \ No newline at end of file diff --git a/src/stories/components/p-data-table/p-data-table.stories.ts b/src/stories/components/p-data-table/p-data-table.stories.ts new file mode 100644 index 00000000..7008be57 --- /dev/null +++ b/src/stories/components/p-data-table/p-data-table.stories.ts @@ -0,0 +1,198 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { TableModule } from 'primeng/table'; +import { PDataTableDefaultComponent } from './examples/p-data-table-default.component'; +import { PDataTableStripedRowsComponent } from './examples/p-data-table-striped-rows.component'; +import { PDataTableSelectableComponent } from './examples/p-data-table-selectable.component'; +import { PDataTableGridLinesComponent } from './examples/p-data-table-grid-lines.component'; +import { PDataTablePaginationComponent } from './examples/p-data-table-pagination.component'; +import { PDataTableSelectionRadioComponent } from './examples/p-data-table-selection-radio.component'; +import { PDataTableSelectionCheckboxComponent } from './examples/p-data-table-selection-checkbox.component'; +import { PDataTableScrollVerticalComponent } from './examples/p-data-table-scroll-vertical.component'; +import { PDataTableScrollHorizontalComponent } from './examples/p-data-table-scroll-horizontal.component'; +import { PDataTableCustomBodyComponent } from './examples/p-data-table-custom-body.component'; +import { PDataTableLazyComponent } from './examples/p-data-table-lazy.component'; + +const meta: Meta = { + title: 'Components/Data/DataTable (PrimeNG)', + tags: ['autodocs'], + parameters: { + docs: { + description: { + component: `Таблица данных на базе PrimeNG pTable с поддержкой сортировки, пагинации, выбора строк и прокрутки. + +\`\`\`typescript +import { TableModule } from 'primeng/table'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-datatable' }, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ─────────────────────────────────────────────────────────────────── + +export const Default: Story = { + name: 'DataTable', + decorators: [moduleMetadata({ imports: [PDataTableDefaultComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Базовая таблица отправлений с сортировкой по всем столбцам на базе PrimeNG pTable.', + }, + }, + }, +}; + +// ── StripedRows ─────────────────────────────────────────────────────────────── + +export const StripedRows: Story = { + name: 'StripedRows', + decorators: [moduleMetadata({ imports: [PDataTableStripedRowsComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Чередование цвета строк для улучшения читаемости на базе PrimeNG pTable.', + }, + }, + }, +}; + +// ── Selectable ──────────────────────────────────────────────────────────────── + +export const Selectable: Story = { + name: 'Selectable', + decorators: [moduleMetadata({ imports: [PDataTableSelectableComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Выбор строки кликом. Режим single — выбирается одна строка на базе PrimeNG pTable.', + }, + }, + }, +}; + +// ── GridLines ───────────────────────────────────────────────────────────────── + +export const GridLines: Story = { + name: 'GridLines', + decorators: [moduleMetadata({ imports: [PDataTableGridLinesComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Сетка между ячейками для наглядного разграничения данных на базе PrimeNG pTable.', + }, + }, + }, +}; + +// ── Pagination ──────────────────────────────────────────────────────────────── + +export const Pagination: Story = { + name: 'Pagination', + decorators: [moduleMetadata({ imports: [PDataTablePaginationComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Пагинация для больших наборов данных на базе PrimeNG pTable.', + }, + }, + }, +}; + +// ── SelectionRadio ──────────────────────────────────────────────────────────── + +export const SelectionRadio: Story = { + name: 'Row Selection: RadioButton', + decorators: [moduleMetadata({ imports: [PDataTableSelectionRadioComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Выбор одной строки через радио-кнопку на базе PrimeNG pTable.', + }, + }, + }, +}; + +// ── SelectionCheckbox ───────────────────────────────────────────────────────── + +export const SelectionCheckbox: Story = { + name: 'Row Selection: Checkbox', + decorators: [moduleMetadata({ imports: [PDataTableSelectionCheckboxComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Множественный выбор строк через чекбоксы на базе PrimeNG pTable.', + }, + }, + }, +}; + +// ── ScrollVertical ──────────────────────────────────────────────────────────── + +export const ScrollVertical: Story = { + name: 'Scroll: Vertical', + decorators: [moduleMetadata({ imports: [PDataTableScrollVerticalComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Вертикальная прокрутка с фиксированной высотой контейнера на базе PrimeNG pTable.', + }, + }, + }, +}; + +// ── ScrollHorizontal ────────────────────────────────────────────────────────── + +export const ScrollHorizontal: Story = { + name: 'Scroll: Horizontal', + decorators: [moduleMetadata({ imports: [PDataTableScrollHorizontalComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Горизонтальная прокрутка при большом количестве столбцов на базе PrimeNG pTable.', + }, + }, + }, +}; + +// ── CustomBody ──────────────────────────────────────────────────────────────── + +export const CustomBody: Story = { + name: 'Custom Templates', + decorators: [moduleMetadata({ imports: [PDataTableCustomBodyComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Кастомные шаблоны для заголовка и тела таблицы на базе PrimeNG pTable.', + }, + }, + }, +}; + +// ── Lazy loading ────────────────────────────────────────────────────────────── + +export const LazyLoading: Story = { + name: 'Lazy Loading', + decorators: [moduleMetadata({ imports: [PDataTableLazyComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Lazy Loading + Virtual Scroll для работы с большими наборами данных. Данные подгружаются порциями при прокрутке таблицы. Используйте `[lazy]="true"`, `[virtualScroll]="true"`, `[virtualScrollItemSize]`, `[totalRecords]` и `(onLazyLoad)` для управления загрузкой данных с сервера.', + }, + }, + }, +}; From d5197b7df59d77e4ec99141732e530ba9cf68a82 Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Fri, 29 May 2026 18:40:20 +0700 Subject: [PATCH 6/7] DS-517 --- .../data-table/data-table.component.ts | 412 ---------- src/lib/components/data-table/ng-package.json | 7 - src/lib/components/data-table/public_api.ts | 4 - .../data-table/data-table.stories.ts | 719 ---------------- .../data-table-custom-body.component.ts | 81 -- .../examples/data-table-default.component.ts | 38 - .../data-table-grid-lines.component.ts | 35 - .../examples/data-table-lazy.component.ts | 66 -- .../data-table-pagination.component.ts | 44 - .../data-table-scroll-horizontal.component.ts | 37 - .../data-table-scroll-vertical.component.ts | 42 - .../data-table-selectable.component.ts | 42 - ...data-table-selection-checkbox.component.ts | 42 - .../data-table-selection-radio.component.ts | 42 - .../data-table-striped-rows.component.ts | 35 - ...=> primeng-table-custom-body.component.ts} | 2 +- ....ts => primeng-table-default.component.ts} | 2 +- ... => primeng-table-grid-lines.component.ts} | 2 +- ...ent.ts => primeng-table-lazy.component.ts} | 2 +- ... => primeng-table-pagination.component.ts} | 2 +- ...meng-table-scroll-horizontal.component.ts} | 2 +- ...rimeng-table-scroll-vertical.component.ts} | 2 +- ... => primeng-table-selectable.component.ts} | 2 +- ...eng-table-selection-checkbox.component.ts} | 2 +- ...rimeng-table-selection-radio.component.ts} | 2 +- ...> primeng-table-striped-rows.component.ts} | 2 +- .../p-data-table/p-data-table.stories.ts | 198 ----- .../primeng-data-table.stories.ts | 777 ++++++++++++++++++ 28 files changed, 788 insertions(+), 1855 deletions(-) delete mode 100644 src/lib/components/data-table/data-table.component.ts delete mode 100644 src/lib/components/data-table/ng-package.json delete mode 100644 src/lib/components/data-table/public_api.ts delete mode 100644 src/stories/components/data-table/data-table.stories.ts delete mode 100644 src/stories/components/data-table/examples/data-table-custom-body.component.ts delete mode 100644 src/stories/components/data-table/examples/data-table-default.component.ts delete mode 100644 src/stories/components/data-table/examples/data-table-grid-lines.component.ts delete mode 100644 src/stories/components/data-table/examples/data-table-lazy.component.ts delete mode 100644 src/stories/components/data-table/examples/data-table-pagination.component.ts delete mode 100644 src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts delete mode 100644 src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts delete mode 100644 src/stories/components/data-table/examples/data-table-selectable.component.ts delete mode 100644 src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts delete mode 100644 src/stories/components/data-table/examples/data-table-selection-radio.component.ts delete mode 100644 src/stories/components/data-table/examples/data-table-striped-rows.component.ts rename src/stories/components/p-data-table/examples/{p-data-table-custom-body.component.ts => primeng-table-custom-body.component.ts} (98%) rename src/stories/components/p-data-table/examples/{p-data-table-default.component.ts => primeng-table-default.component.ts} (98%) rename src/stories/components/p-data-table/examples/{p-data-table-grid-lines.component.ts => primeng-table-grid-lines.component.ts} (97%) rename src/stories/components/p-data-table/examples/{p-data-table-lazy.component.ts => primeng-table-lazy.component.ts} (98%) rename src/stories/components/p-data-table/examples/{p-data-table-pagination.component.ts => primeng-table-pagination.component.ts} (98%) rename src/stories/components/p-data-table/examples/{p-data-table-scroll-horizontal.component.ts => primeng-table-scroll-horizontal.component.ts} (98%) rename src/stories/components/p-data-table/examples/{p-data-table-scroll-vertical.component.ts => primeng-table-scroll-vertical.component.ts} (97%) rename src/stories/components/p-data-table/examples/{p-data-table-selectable.component.ts => primeng-table-selectable.component.ts} (97%) rename src/stories/components/p-data-table/examples/{p-data-table-selection-checkbox.component.ts => primeng-table-selection-checkbox.component.ts} (97%) rename src/stories/components/p-data-table/examples/{p-data-table-selection-radio.component.ts => primeng-table-selection-radio.component.ts} (97%) rename src/stories/components/p-data-table/examples/{p-data-table-striped-rows.component.ts => primeng-table-striped-rows.component.ts} (98%) delete mode 100644 src/stories/components/p-data-table/p-data-table.stories.ts create mode 100644 src/stories/components/p-data-table/primeng-data-table.stories.ts diff --git a/src/lib/components/data-table/data-table.component.ts b/src/lib/components/data-table/data-table.component.ts deleted file mode 100644 index 0e72e028..00000000 --- a/src/lib/components/data-table/data-table.component.ts +++ /dev/null @@ -1,412 +0,0 @@ -import { - AfterContentInit, - Component, - ContentChildren, - EventEmitter, - Input, - Output, - QueryList, - TemplateRef, - ViewChild, -} from '@angular/core'; -import { NgTemplateOutlet } from '@angular/common'; -import { TableModule } from 'primeng/table'; -import { - PrimeTemplate, - SortMeta, - FilterMetadata, - ScrollerOptions, -} from 'primeng/api'; -import { - TableLazyLoadEvent, - TableRowSelectEvent, - TableRowUnSelectEvent, - TablePageEvent, - TableFilterEvent, - TableRowExpandEvent, - TableRowCollapseEvent, - TableContextMenuSelectEvent, - TableColResizeEvent, - TableColumnReorderEvent, - TableRowReorderEvent, - TableEditInitEvent, - TableEditCompleteEvent, - TableEditCancelEvent, - TableHeaderCheckboxToggleEvent, - TableSelectAllChangeEvent, -} from 'primeng/types/table'; - -export interface DataTableColumn { - field?: string; - header?: string; - sortable?: boolean; - style?: string; - headerStyle?: string; - selectionMode?: 'single' | 'multiple'; -} - -@Component({ - selector: 'extra-data-table', - host: { style: 'display: block' }, - standalone: true, - imports: [TableModule, PrimeTemplate, NgTemplateOutlet], - template: ` - - - - @for (col of columns; track $index) { - @if (col.selectionMode === 'single') { - - } @else if (col.selectionMode === 'multiple') { - - - - } @else { - - {{ col.header }} - @if (col.sortable) { - - } - - } - } - - - - - - - @for (col of columns; track $index) { - @if (col.selectionMode === 'single') { - - - - } @else if (col.selectionMode === 'multiple') { - - - - } @else { - {{ rowData[col.field] }} - } - } - - - - - - - - - - - - - - - - @if (captionTemplate) { - - - - } - @if (footerTemplate) { - - - - } - @if (summaryTemplate) { - - - - } - @if (emptyMessageTemplate) { - - - - } - @if (rowExpansionTemplate) { - - - - } - @if (groupHeaderTemplate) { - - - - } - @if (groupFooterTemplate) { - - - - } - @if (paginatorLeftTemplate) { - - - - } - @if (paginatorRightTemplate) { - - - - } - @if (loadingIconTemplate) { - - - - } - - `, -}) -export class ExtraDataTableComponent implements AfterContentInit { - // ── Data ────────────────────────────────────────────────────────────────── - @Input() value: any[] = []; - @Input() columns: DataTableColumn[] = []; - - // ── Appearance ──────────────────────────────────────────────────────────── - @Input() stripedRows = false; - @Input() showGridlines = false; - @Input() size: 'small' | 'large' | undefined = undefined; - @Input() styleClass: string | undefined = undefined; - @Input() tableStyle: { [key: string]: any } | undefined = undefined; - @Input() tableStyleClass: string | undefined = undefined; - - // ── Loading ─────────────────────────────────────────────────────────────── - @Input() loading = false; - - // ── Pagination ──────────────────────────────────────────────────────────── - @Input() paginator = false; - @Input() rows = 10; - @Input() rowsPerPageOptions: number[] = []; - @Input() first: number | null | undefined = 0; - @Input() totalRecords = 0; - @Output() firstChange = new EventEmitter(); - - // ── Scroll ──────────────────────────────────────────────────────────────── - @Input() scrollable = false; - @Input() scrollHeight: string | undefined = undefined; - - // ── Virtual Scroll ──────────────────────────────────────────────────────── - @Input() virtualScroll: boolean | undefined = undefined; - @Input() virtualScrollItemSize: number | undefined = undefined; - @Input() virtualScrollOptions: ScrollerOptions | undefined = undefined; - @Input() virtualScrollDelay = 250; - - // ── Lazy loading ────────────────────────────────────────────────────────── - @Input() lazy = false; - @Input() lazyLoadOnInit = true; - @Output() onLazyLoad = new EventEmitter(); - - // ── Sorting ─────────────────────────────────────────────────────────────── - @Input() sortField: string | undefined | null = undefined; - @Input() sortOrder = 1; - @Input() defaultSortOrder = 1; - @Input() sortMode: 'single' | 'multiple' = 'single'; - @Input() multiSortMeta: SortMeta[] | undefined | null = undefined; - @Input() customSort = false; - @Output() onSort = new EventEmitter(); - @Output() sortFunction = new EventEmitter(); - - // ── Selection ───────────────────────────────────────────────────────────── - @Input() selectionMode: 'single' | 'multiple' | undefined = undefined; - @Input() selection: any = null; - @Input() dataKey = 'id'; - @Input() metaKeySelection = false; - @Input() rowSelectable: ((row: { data: any; index: number }) => boolean | undefined) | undefined = undefined; - @Input() selectAll: boolean | null = null; - @Output() selectionChange = new EventEmitter(); - @Output() selectAllChange = new EventEmitter(); - @Output() onRowSelect = new EventEmitter(); - @Output() onRowUnselect = new EventEmitter>(); - @Output() onHeaderCheckboxToggle = new EventEmitter(); - - // ── Context Menu ────────────────────────────────────────────────────────── - @Input() contextMenu: any = undefined; - @Input() contextMenuSelection: any = undefined; - @Output() contextMenuSelectionChange = new EventEmitter(); - @Output() onContextMenuSelect = new EventEmitter(); - - // ── Row Expand ──────────────────────────────────────────────────────────── - @Input() expandedRowKeys: { [s: string]: boolean } = {}; - @Input() rowExpandMode: 'multiple' | 'single' = 'multiple'; - @Output() onRowExpand = new EventEmitter(); - @Output() onRowCollapse = new EventEmitter(); - - // ── Row Group ───────────────────────────────────────────────────────────── - @Input() rowGroupMode: 'subheader' | 'rowspan' | undefined = undefined; - @Input() groupRowsBy: string | undefined = undefined; - @Input() groupRowsByOrder = 1; - - // ── Edit ────────────────────────────────────────────────────────────────── - @Input() editMode: 'cell' | 'row' = 'cell'; - @Output() onEditInit = new EventEmitter(); - @Output() onEditComplete = new EventEmitter(); - @Output() onEditCancel = new EventEmitter(); - - // ── Column Resize ───────────────────────────────────────────────────────── - @Input() resizableColumns = false; - @Input() columnResizeMode: 'fit' | 'expand' = 'fit'; - @Output() onColResize = new EventEmitter(); - - // ── Column Reorder ──────────────────────────────────────────────────────── - @Input() reorderableColumns = false; - @Output() onColReorder = new EventEmitter(); - - // ── Row Reorder ─────────────────────────────────────────────────────────── - @Output() onRowReorder = new EventEmitter(); - - // ── Row Hover ───────────────────────────────────────────────────────────── - @Input() rowHover = false; - - // ── Filter ──────────────────────────────────────────────────────────────── - @Input() filters: { [s: string]: FilterMetadata | FilterMetadata[] } = {}; - @Input() globalFilterFields: string[] | undefined = undefined; - @Input() filterDelay = 300; - @Output() onFilter = new EventEmitter(); - - // ── Pagination events ───────────────────────────────────────────────────── - @Output() onPage = new EventEmitter(); - - // ── State ───────────────────────────────────────────────────────────────── - @Input() stateKey: string | undefined = undefined; - @Input() stateStorage: 'session' | 'local' = 'session'; - - // ── Default templates ───────────────────────────────────────────────────── - @ViewChild('defaultHeaderTpl') defaultHeaderTpl!: TemplateRef; - @ViewChild('defaultBodyTpl') defaultBodyTpl!: TemplateRef; - - // ── User-provided content templates ────────────────────────────────────── - @ContentChildren(PrimeTemplate) templates!: QueryList; - - headerTemplate: TemplateRef | null = null; - bodyTemplate: TemplateRef | null = null; - captionTemplate: TemplateRef | null = null; - footerTemplate: TemplateRef | null = null; - summaryTemplate: TemplateRef | null = null; - emptyMessageTemplate: TemplateRef | null = null; - rowExpansionTemplate: TemplateRef | null = null; - groupHeaderTemplate: TemplateRef | null = null; - groupFooterTemplate: TemplateRef | null = null; - paginatorLeftTemplate: TemplateRef | null = null; - paginatorRightTemplate: TemplateRef | null = null; - loadingIconTemplate: TemplateRef | null = null; - - ngAfterContentInit(): void { - this.templates.forEach((t) => { - switch (t.getType()) { - case 'header': - this.headerTemplate = t.template; - break; - case 'body': - this.bodyTemplate = t.template; - break; - case 'caption': - this.captionTemplate = t.template; - break; - case 'footer': - this.footerTemplate = t.template; - break; - case 'summary': - this.summaryTemplate = t.template; - break; - case 'emptymessage': - this.emptyMessageTemplate = t.template; - break; - case 'rowexpansion': - this.rowExpansionTemplate = t.template; - break; - case 'groupheader': - this.groupHeaderTemplate = t.template; - break; - case 'groupfooter': - this.groupFooterTemplate = t.template; - break; - case 'paginatorleft': - this.paginatorLeftTemplate = t.template; - break; - case 'paginatorright': - this.paginatorRightTemplate = t.template; - break; - case 'loadingicon': - this.loadingIconTemplate = t.template; - break; - } - }); - } -} diff --git a/src/lib/components/data-table/ng-package.json b/src/lib/components/data-table/ng-package.json deleted file mode 100644 index ecdf8fea..00000000 --- a/src/lib/components/data-table/ng-package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "$schema": "ng-packagr/ng-package.schema.json", - "lib": { - "entryFile": "public_api.ts" - } -} - diff --git a/src/lib/components/data-table/public_api.ts b/src/lib/components/data-table/public_api.ts deleted file mode 100644 index 8b3cbf32..00000000 --- a/src/lib/components/data-table/public_api.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './data-table.component'; - - - diff --git a/src/stories/components/data-table/data-table.stories.ts b/src/stories/components/data-table/data-table.stories.ts deleted file mode 100644 index 3d614feb..00000000 --- a/src/stories/components/data-table/data-table.stories.ts +++ /dev/null @@ -1,719 +0,0 @@ -import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { ExtraDataTableComponent } from '../../../lib/components/data-table/data-table.component'; -import { DataTableDefaultComponent } from './examples/data-table-default.component'; -import { DataTableStripedRowsComponent } from './examples/data-table-striped-rows.component'; -import { DataTableSelectableComponent } from './examples/data-table-selectable.component'; -import { DataTableGridLinesComponent } from './examples/data-table-grid-lines.component'; -import { DataTablePaginationComponent } from './examples/data-table-pagination.component'; -import { DataTableSelectionRadioComponent } from './examples/data-table-selection-radio.component'; -import { DataTableSelectionCheckboxComponent } from './examples/data-table-selection-checkbox.component'; -import { DataTableScrollVerticalComponent } from './examples/data-table-scroll-vertical.component'; -import { DataTableScrollHorizontalComponent } from './examples/data-table-scroll-horizontal.component'; -import { DataTableCustomBodyComponent } from './examples/data-table-custom-body.component'; -import { DataTableLazyComponent } from './examples/data-table-lazy.component'; - -const meta: Meta = { - title: 'Components/Data/DataTable', - component: ExtraDataTableComponent, - tags: ['autodocs'], - parameters: { - docs: { - description: { - component: `Таблица данных с поддержкой сортировки, пагинации, выбора строк и прокрутки. - -\`\`\`typescript -import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; -\`\`\``, - }, - }, - designTokens: { prefix: '--p-datatable' }, - }, - argTypes: { - value: { - control: false, - description: 'Массив данных для отображения в таблице.', - table: { - category: 'Props', - type: { summary: 'any[]' }, - }, - }, - columns: { - control: false, - description: 'Определения столбцов таблицы.', - table: { - category: 'Props', - type: { summary: 'DataTableColumn[]' }, - }, - }, - stripedRows: { - control: 'boolean', - description: 'Чередование цвета строк.', - table: { - category: 'Props', - defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, - }, - showGridlines: { - 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' }, - }, - }, - size: { - control: 'select', - options: ['small', 'large', undefined], - description: 'Размер таблицы.', - table: { - category: 'Props', - defaultValue: { summary: 'undefined (normal)' }, - type: { summary: "'small' | 'large' | undefined" }, - }, - }, - scrollable: { - control: 'boolean', - description: 'Включает прокрутку таблицы.', - table: { - category: 'Props', - defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, - }, - scrollHeight: { - control: 'text', - description: 'Высота области прокрутки (например "400px"). Работает только при scrollable=true.', - table: { - category: 'Props', - defaultValue: { summary: "''" }, - type: { summary: 'string' }, - }, - }, - paginator: { - control: 'boolean', - description: 'Включает пагинацию.', - table: { - category: 'Props', - defaultValue: { summary: 'false' }, - type: { summary: 'boolean' }, - }, - }, - rows: { - control: 'number', - description: 'Количество строк на странице (при paginator=true).', - table: { - category: 'Props', - defaultValue: { summary: '5' }, - type: { summary: 'number' }, - }, - }, - selectionMode: { - control: 'select', - options: ['single', 'multiple', undefined], - description: 'Режим выбора строк.', - table: { - category: 'Props', - defaultValue: { summary: 'undefined' }, - type: { summary: "'single' | 'multiple' | undefined" }, - }, - }, - dataKey: { - control: 'text', - description: 'Поле объекта, используемое как уникальный идентификатор строки.', - table: { - category: 'Props', - defaultValue: { summary: "'id'" }, - type: { summary: 'string' }, - }, - }, - selectionChange: { - control: false, - description: 'Событие изменения выбранных строк.', - table: { - category: 'Events', - type: { summary: 'EventEmitter' }, - }, - }, - }, -}; - -export default meta; -type Story = StoryObj; - -// ── Default ─────────────────────────────────────────────────────────────────── - -export const Default: Story = { - name: 'DataTable', - decorators: [moduleMetadata({ imports: [DataTableDefaultComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Базовая таблица отправлений с сортировкой по всем столбцам.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-data-table-default', - standalone: true, - imports: [ExtraDataTableComponent], - template: \` - - \`, -}) -export class DataTableDefaultComponent { - shipments = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - ]; - - columns: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, - ]; -} - `, - }, - }, - }, -}; - -// ── StripedRows ─────────────────────────────────────────────────────────────── - -export const StripedRows: Story = { - name: 'StripedRows', - decorators: [moduleMetadata({ imports: [DataTableStripedRowsComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Чередование цвета строк для улучшения читаемости.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-data-table-striped-rows', - standalone: true, - imports: [ExtraDataTableComponent], - template: \` - - \`, -}) -export class DataTableStripedRowsComponent { - shipments = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - ]; - - columns: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, - ]; -} - `, - }, - }, - }, -}; - -// ── Selectable ──────────────────────────────────────────────────────────────── - -export const Selectable: Story = { - name: 'Selectable', - decorators: [moduleMetadata({ imports: [DataTableSelectableComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Выбор строки кликом. Режим single — выбирается одна строка.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-data-table-selectable', - standalone: true, - imports: [ExtraDataTableComponent], - template: \` - - \`, -}) -export class DataTableSelectableComponent { - shipments = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - ]; - - columns: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, - ]; - - selected: any = null; -} - `, - }, - }, - }, -}; - -// ── GridLines ───────────────────────────────────────────────────────────────── - -export const GridLines: Story = { - name: 'GridLines', - decorators: [moduleMetadata({ imports: [DataTableGridLinesComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Сетка между ячейками для наглядного разграничения данных.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-data-table-grid-lines', - standalone: true, - imports: [ExtraDataTableComponent], - template: \` - - \`, -}) -export class DataTableGridLinesComponent { - shipments = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - ]; - - columns: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, - ]; -} - `, - }, - }, - }, -}; - -// ── Pagination ──────────────────────────────────────────────────────────────── - -export const Pagination: Story = { - name: 'Pagination', - decorators: [moduleMetadata({ imports: [DataTablePaginationComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Пагинация для больших наборов данных. Управление количеством строк на странице.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-data-table-pagination', - standalone: true, - imports: [ExtraDataTableComponent], - template: \` - - \`, -}) -export class DataTablePaginationComponent { - shipments = [...]; // массив отправлений - columns: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, - ]; -} - `, - }, - }, - }, -}; - -// ── SelectionRadio ──────────────────────────────────────────────────────────── - -export const SelectionRadio: Story = { - name: 'Row Selection: RadioButton', - decorators: [moduleMetadata({ imports: [DataTableSelectionRadioComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Выбор одной строки через радио-кнопку. Укажите selectionMode: "single" в первом столбце.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-data-table-selection-radio', - standalone: true, - imports: [ExtraDataTableComponent], - template: \` - - \`, -}) -export class DataTableSelectionRadioComponent { - shipments = [...]; // массив отправлений - columns: DataTableColumn[] = [ - { selectionMode: 'single' }, - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - ]; - selected: any = null; -} - `, - }, - }, - }, -}; - -// ── SelectionCheckbox ───────────────────────────────────────────────────────── - -export const SelectionCheckbox: Story = { - name: 'Row Selection: Checkbox', - decorators: [moduleMetadata({ imports: [DataTableSelectionCheckboxComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Множественный выбор строк через чекбоксы. Первый столбец с selectionMode: "multiple" добавляет чекбокс в заголовок.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-data-table-selection-checkbox', - standalone: true, - imports: [ExtraDataTableComponent], - template: \` - - \`, -}) -export class DataTableSelectionCheckboxComponent { - shipments = [...]; // массив отправлений - columns: DataTableColumn[] = [ - { selectionMode: 'multiple' }, - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - ]; - selected: any[] = []; -} - `, - }, - }, - }, -}; - -// ── ScrollVertical ──────────────────────────────────────────────────────────── - -export const ScrollVertical: Story = { - name: 'Scroll: Vertical', - decorators: [moduleMetadata({ imports: [DataTableScrollVerticalComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Вертикальная прокрутка с фиксированной высотой контейнера. Заголовок остаётся видимым.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-data-table-scroll-vertical', - standalone: true, - imports: [ExtraDataTableComponent], - template: \` - - \`, -}) -export class DataTableScrollVerticalComponent { - shipments = [...]; // большой массив отправлений - columns: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - ]; -} - `, - }, - }, - }, -}; - -// ── ScrollHorizontal ────────────────────────────────────────────────────────── - -export const ScrollHorizontal: Story = { - name: 'Scroll: Horizontal', - decorators: [moduleMetadata({ imports: [DataTableScrollHorizontalComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Горизонтальная прокрутка при большом количестве столбцов. Используйте style с min-width на столбцах.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; - -@Component({ - selector: 'app-data-table-scroll-horizontal', - standalone: true, - imports: [ExtraDataTableComponent], - template: \` - - \`, -}) -export class DataTableScrollHorizontalComponent { - shipments = [...]; // массив отправлений - columns: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true, style: 'min-width: 160px' }, - { field: 'sender', header: 'Отправитель', sortable: true, style: 'min-width: 160px' }, - { field: 'destination', header: 'Назначение', sortable: true, style: 'min-width: 160px' }, - { field: 'status', header: 'Статус', sortable: true, style: 'min-width: 140px' }, - { field: 'weight', header: 'Вес, кг', sortable: true, style: 'min-width: 120px' }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true, style: 'min-width: 140px' }, - { field: 'dimensions', header: 'Габариты', sortable: false, style: 'min-width: 160px' }, - ]; -} - `, - }, - }, - }, -}; - -// ── CustomBody ──────────────────────────────────────────────────────────────── - -export const CustomBody: Story = { - name: 'Custom Templates', - decorators: [moduleMetadata({ imports: [DataTableCustomBodyComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: - 'Кастомные шаблоны для заголовка и тела таблицы. Передайте `ng-template` с директивой `pTemplate` внутрь ``. Поддерживаются шаблоны: `header`, `body`, `footer`, `caption`, `summary`, `emptymessage`, `rowexpansion`, `groupheader`, `groupfooter`, `paginatorleft`, `paginatorright`, `loadingicon`.', - }, - source: { - language: 'ts', - code: ` -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; -import { PrimeTemplate } from 'primeng/api'; -import { TagModule } from 'primeng/tag'; - -@Component({ - selector: 'app-data-table-custom-body', - standalone: true, - imports: [ExtraDataTableComponent, PrimeTemplate, TagModule], - template: \` - - - - - @for (col of columns; track col.field) { - - {{ col.header }} - @if (col.sortable) { } - - } - - - - - - {{ row.trackNumber }} - {{ row.destination }} - - - - {{ row.weight }} кг - {{ row.cost | currency:'RUB':'symbol':'1.0-0':'ru' }} - - - - - Нет данных для отображения - - - - \`, -}) -export class DataTableCustomBodyComponent { - shipments = [...]; - columns: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, - ]; - - getSeverity(status: string) { - switch (status) { - case 'Доставлен': return 'success'; - case 'В пути': return 'info'; - case 'Задержан': return 'danger'; - default: return 'warn'; - } - } -} - `, - }, - }, - }, -}; - -// ── Lazy loading ────────────────────────────────────────────────────────────── - -export const LazyLoading: Story = { - name: 'Lazy Loading', - decorators: [moduleMetadata({ imports: [DataTableLazyComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: - 'Ленивая подгрузка данных с сервера при пагинации/сортировке. Используйте `[lazy]="true"`, `[totalRecords]` и `(onLazyLoad)` для управления загрузкой.', - }, - source: { - language: 'ts', - code: ` -import { Component, OnInit } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '@cdek-it/angular-ui-kit'; -import { TableLazyLoadEvent } from 'primeng/types/table'; - -@Component({ - selector: 'app-data-table-lazy', - standalone: true, - imports: [ExtraDataTableComponent], - template: \` - - \`, -}) -export class DataTableLazyComponent implements OnInit { - shipments: any[] = []; - columns: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, - ]; - totalRecords = 0; - loading = true; - - onLazyLoad(event: TableLazyLoadEvent): void { - this.loading = true; - // Запрос к серверу с event.first, event.rows, event.sortField, event.sortOrder - myApiService.getShipments(event).subscribe(result => { - this.shipments = result.data; - this.totalRecords = result.total; - this.loading = false; - }); - } -} - `, - }, - }, - }, -}; - diff --git a/src/stories/components/data-table/examples/data-table-custom-body.component.ts b/src/stories/components/data-table/examples/data-table-custom-body.component.ts deleted file mode 100644 index f3b95ecb..00000000 --- a/src/stories/components/data-table/examples/data-table-custom-body.component.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { Component } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; -import { PrimeTemplate } from 'primeng/api'; -import { TagModule } from 'primeng/tag'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, -]; - -const COLUMNS: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, -]; - -const template = ` -
- - - - - @for (col of columns; track col.field) { - - {{ col.header }} - @if (col.sortable) { } - - } - - - - - - {{ row.trackNumber }} - {{ row.destination }} - - - - {{ row.weight }} кг - {{ row.cost | currency:'RUB':'symbol':'1.0-0':'ru' }} - - - - - Нет данных для отображения - - - -
-`; - -@Component({ - selector: 'app-data-table-custom-body', - standalone: true, - imports: [ExtraDataTableComponent, PrimeTemplate, TagModule, CommonModule], - template, -}) -export class DataTableCustomBodyComponent { - shipments = SHIPMENTS; - columns = COLUMNS; - - getSeverity(status: string): 'success' | 'warn' | 'danger' | 'info' | 'secondary' | undefined { - switch (status) { - case 'Доставлен': return 'success'; - case 'В пути': return 'info'; - case 'Задержан': return 'danger'; - case 'Ожидание': return 'warn'; - default: return 'secondary'; - } - } -} - diff --git a/src/stories/components/data-table/examples/data-table-default.component.ts b/src/stories/components/data-table/examples/data-table-default.component.ts deleted file mode 100644 index 434a4c03..00000000 --- a/src/stories/components/data-table/examples/data-table-default.component.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, - { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, - { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, - { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, -]; - -const COLUMNS: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, -]; - -const template = ` -
- -
-`; - -@Component({ - selector: 'app-data-table-default', - standalone: true, - imports: [ExtraDataTableComponent], - template, -}) -export class DataTableDefaultComponent { - shipments = SHIPMENTS; - columns = COLUMNS; -} diff --git a/src/stories/components/data-table/examples/data-table-grid-lines.component.ts b/src/stories/components/data-table/examples/data-table-grid-lines.component.ts deleted file mode 100644 index 1f7a94bd..00000000 --- a/src/stories/components/data-table/examples/data-table-grid-lines.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, -]; - -const COLUMNS: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, -]; - -const template = ` -
- -
-`; - -@Component({ - selector: 'app-data-table-grid-lines', - standalone: true, - imports: [ExtraDataTableComponent], - template, -}) -export class DataTableGridLinesComponent { - shipments = SHIPMENTS; - columns = COLUMNS; -} diff --git a/src/stories/components/data-table/examples/data-table-lazy.component.ts b/src/stories/components/data-table/examples/data-table-lazy.component.ts deleted file mode 100644 index 9ca1f978..00000000 --- a/src/stories/components/data-table/examples/data-table-lazy.component.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; -import { PrimeTemplate } from 'primeng/api'; -import { TableLazyLoadEvent } from 'primeng/types/table'; - -const ALL_SHIPMENTS = Array.from({ length: 100 }, (_, i) => ({ - id: i + 1, - trackNumber: `ЦД-${String(i + 100000).padStart(8, '0')}`, - destination: ['Москва', 'Новосибирск', 'Екатеринбург', 'Казань', 'Краснодар'][i % 5], - status: ['В пути', 'Доставлен', 'Задержан', 'Ожидание'][i % 4], - weight: Number((Math.random() * 10).toFixed(1)), - cost: Math.floor(Math.random() * 5000) + 200, -})); - -const COLUMNS: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, -]; - -const template = ` -
- -
-`; - -@Component({ - selector: 'app-data-table-lazy', - standalone: true, - imports: [ExtraDataTableComponent, PrimeTemplate], - template, -}) -export class DataTableLazyComponent implements OnInit { - shipments: any[] = []; - columns = COLUMNS; - totalRecords = ALL_SHIPMENTS.length; - loading = true; - - ngOnInit(): void { - // Initial load happens via onLazyLoad - } - - onLazyLoad(event: TableLazyLoadEvent): void { - this.loading = true; - // Simulate async server request - setTimeout(() => { - const start = event.first ?? 0; - const end = start + (event.rows ?? 10); - this.shipments = ALL_SHIPMENTS.slice(start, end); - this.loading = false; - }, 500); - } -} - diff --git a/src/stories/components/data-table/examples/data-table-pagination.component.ts b/src/stories/components/data-table/examples/data-table-pagination.component.ts deleted file mode 100644 index 09180b9b..00000000 --- a/src/stories/components/data-table/examples/data-table-pagination.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, - { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, - { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, - { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, -]; - -const COLUMNS: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, -]; - -const template = ` -
- -
-`; - -@Component({ - selector: 'app-data-table-pagination', - standalone: true, - imports: [ExtraDataTableComponent], - template, -}) -export class DataTablePaginationComponent { - shipments = SHIPMENTS; - columns = COLUMNS; -} diff --git a/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts b/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts deleted file mode 100644 index 0428887d..00000000 --- a/src/stories/components/data-table/examples/data-table-scroll-horizontal.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', sender: 'Иванов И.И.', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200, dimensions: '30×20×15 см' }, - { id: 2, trackNumber: 'ЦД-00123457', sender: 'Петров П.П.', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450, dimensions: '10×10×10 см' }, - { id: 3, trackNumber: 'ЦД-00123458', sender: 'Сидоров С.С.', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100, dimensions: '50×40×30 см' }, - { id: 4, trackNumber: 'ЦД-00123459', sender: 'Козлов К.К.', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750, dimensions: '20×15×10 см' }, - { id: 5, trackNumber: 'ЦД-00123460', sender: 'Новиков Н.Н.', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800, dimensions: '40×30×20 см' }, -]; - -const COLUMNS: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true, style: 'min-width: 160px' }, - { field: 'sender', header: 'Отправитель', sortable: true, style: 'min-width: 160px' }, - { field: 'destination', header: 'Назначение', sortable: true, style: 'min-width: 160px' }, - { field: 'status', header: 'Статус', sortable: true, style: 'min-width: 140px' }, - { field: 'weight', header: 'Вес, кг', sortable: true, style: 'min-width: 120px' }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true, style: 'min-width: 140px' }, - { field: 'dimensions', header: 'Габариты', sortable: false, style: 'min-width: 160px' }, -]; - -const template = ` -
- -
-`; - -@Component({ - selector: 'app-data-table-scroll-horizontal', - standalone: true, - imports: [ExtraDataTableComponent], - template, -}) -export class DataTableScrollHorizontalComponent { - shipments = SHIPMENTS; - columns = COLUMNS; -} diff --git a/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts b/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts deleted file mode 100644 index c7773a5e..00000000 --- a/src/stories/components/data-table/examples/data-table-scroll-vertical.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; - -const BASE_SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, - { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5 }, - { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0 }, - { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1 }, -]; - -const COLUMNS: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, -]; - -const template = ` -
- -
-`; - -@Component({ - selector: 'app-data-table-scroll-vertical', - standalone: true, - imports: [ExtraDataTableComponent], - template, -}) -export class DataTableScrollVerticalComponent { - shipments = [...BASE_SHIPMENTS, ...BASE_SHIPMENTS, ...BASE_SHIPMENTS]; - columns = COLUMNS; -} diff --git a/src/stories/components/data-table/examples/data-table-selectable.component.ts b/src/stories/components/data-table/examples/data-table-selectable.component.ts deleted file mode 100644 index 4d0e1b8a..00000000 --- a/src/stories/components/data-table/examples/data-table-selectable.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, -]; - -const COLUMNS: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, -]; - -const template = ` -
- -
-`; - -@Component({ - selector: 'app-data-table-selectable', - standalone: true, - imports: [ExtraDataTableComponent], - template, -}) -export class DataTableSelectableComponent { - shipments = SHIPMENTS; - columns = COLUMNS; - selected: any = null; -} diff --git a/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts b/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts deleted file mode 100644 index 20a18330..00000000 --- a/src/stories/components/data-table/examples/data-table-selection-checkbox.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, -]; - -const COLUMNS: DataTableColumn[] = [ - { selectionMode: 'multiple' }, - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, -]; - -const template = ` -
- -
-`; - -@Component({ - selector: 'app-data-table-selection-checkbox', - standalone: true, - imports: [ExtraDataTableComponent], - template, -}) -export class DataTableSelectionCheckboxComponent { - shipments = SHIPMENTS; - columns = COLUMNS; - selected: any[] = []; -} diff --git a/src/stories/components/data-table/examples/data-table-selection-radio.component.ts b/src/stories/components/data-table/examples/data-table-selection-radio.component.ts deleted file mode 100644 index 1aeb0883..00000000 --- a/src/stories/components/data-table/examples/data-table-selection-radio.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, -]; - -const COLUMNS: DataTableColumn[] = [ - { selectionMode: 'single' }, - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, -]; - -const template = ` -
- -
-`; - -@Component({ - selector: 'app-data-table-selection-radio', - standalone: true, - imports: [ExtraDataTableComponent], - template, -}) -export class DataTableSelectionRadioComponent { - shipments = SHIPMENTS; - columns = COLUMNS; - selected: any = null; -} diff --git a/src/stories/components/data-table/examples/data-table-striped-rows.component.ts b/src/stories/components/data-table/examples/data-table-striped-rows.component.ts deleted file mode 100644 index 2f78155d..00000000 --- a/src/stories/components/data-table/examples/data-table-striped-rows.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Component } from '@angular/core'; -import { ExtraDataTableComponent, DataTableColumn } from '../../../../lib/components/data-table/data-table.component'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, -]; - -const COLUMNS: DataTableColumn[] = [ - { field: 'trackNumber', header: 'Трек-номер', sortable: true }, - { field: 'destination', header: 'Назначение', sortable: true }, - { field: 'status', header: 'Статус', sortable: true }, - { field: 'weight', header: 'Вес, кг', sortable: true }, - { field: 'cost', header: 'Стоимость, ₽', sortable: true }, -]; - -const template = ` -
- -
-`; - -@Component({ - selector: 'app-data-table-striped-rows', - standalone: true, - imports: [ExtraDataTableComponent], - template, -}) -export class DataTableStripedRowsComponent { - shipments = SHIPMENTS; - columns = COLUMNS; -} diff --git a/src/stories/components/p-data-table/examples/p-data-table-custom-body.component.ts b/src/stories/components/p-data-table/examples/primeng-table-custom-body.component.ts similarity index 98% rename from src/stories/components/p-data-table/examples/p-data-table-custom-body.component.ts rename to src/stories/components/p-data-table/examples/primeng-table-custom-body.component.ts index bd448577..edd8a3eb 100644 --- a/src/stories/components/p-data-table/examples/p-data-table-custom-body.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-custom-body.component.ts @@ -12,7 +12,7 @@ const SHIPMENTS = [ ]; @Component({ - selector: 'app-p-data-table-custom-body', + selector: 'app-primeng-table-custom-body', standalone: true, imports: [CommonModule, TableModule, TagModule], template: ` diff --git a/src/stories/components/p-data-table/examples/p-data-table-default.component.ts b/src/stories/components/p-data-table/examples/primeng-table-default.component.ts similarity index 98% rename from src/stories/components/p-data-table/examples/p-data-table-default.component.ts rename to src/stories/components/p-data-table/examples/primeng-table-default.component.ts index e16de983..0df4bcc9 100644 --- a/src/stories/components/p-data-table/examples/p-data-table-default.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-default.component.ts @@ -13,7 +13,7 @@ const SHIPMENTS = [ ]; @Component({ - selector: 'app-p-data-table-default', + selector: 'app-primeng-table-default', standalone: true, imports: [TableModule], template: ` diff --git a/src/stories/components/p-data-table/examples/p-data-table-grid-lines.component.ts b/src/stories/components/p-data-table/examples/primeng-table-grid-lines.component.ts similarity index 97% rename from src/stories/components/p-data-table/examples/p-data-table-grid-lines.component.ts rename to src/stories/components/p-data-table/examples/primeng-table-grid-lines.component.ts index ce4e45e8..5478270e 100644 --- a/src/stories/components/p-data-table/examples/p-data-table-grid-lines.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-grid-lines.component.ts @@ -10,7 +10,7 @@ const SHIPMENTS = [ ]; @Component({ - selector: 'app-p-data-table-grid-lines', + selector: 'app-primeng-table-grid-lines', standalone: true, imports: [TableModule], template: ` diff --git a/src/stories/components/p-data-table/examples/p-data-table-lazy.component.ts b/src/stories/components/p-data-table/examples/primeng-table-lazy.component.ts similarity index 98% rename from src/stories/components/p-data-table/examples/p-data-table-lazy.component.ts rename to src/stories/components/p-data-table/examples/primeng-table-lazy.component.ts index 4b2ee67f..44e4b920 100644 --- a/src/stories/components/p-data-table/examples/p-data-table-lazy.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-lazy.component.ts @@ -13,7 +13,7 @@ const ALL_SHIPMENTS = Array.from({ length: 500 }, (_, i) => ({ const PAGE_SIZE = 50; @Component({ - selector: 'app-p-data-table-lazy', + selector: 'app-primeng-table-lazy', standalone: true, imports: [TableModule], template: ` diff --git a/src/stories/components/p-data-table/examples/p-data-table-pagination.component.ts b/src/stories/components/p-data-table/examples/primeng-table-pagination.component.ts similarity index 98% rename from src/stories/components/p-data-table/examples/p-data-table-pagination.component.ts rename to src/stories/components/p-data-table/examples/primeng-table-pagination.component.ts index c6af7b1e..3bb24c9c 100644 --- a/src/stories/components/p-data-table/examples/p-data-table-pagination.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-pagination.component.ts @@ -13,7 +13,7 @@ const SHIPMENTS = [ ]; @Component({ - selector: 'app-p-data-table-pagination', + selector: 'app-primeng-table-pagination', standalone: true, imports: [TableModule], template: ` diff --git a/src/stories/components/p-data-table/examples/p-data-table-scroll-horizontal.component.ts b/src/stories/components/p-data-table/examples/primeng-table-scroll-horizontal.component.ts similarity index 98% rename from src/stories/components/p-data-table/examples/p-data-table-scroll-horizontal.component.ts rename to src/stories/components/p-data-table/examples/primeng-table-scroll-horizontal.component.ts index 46bd0e84..8128b89f 100644 --- a/src/stories/components/p-data-table/examples/p-data-table-scroll-horizontal.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-scroll-horizontal.component.ts @@ -10,7 +10,7 @@ const SHIPMENTS = [ ]; @Component({ - selector: 'app-p-data-table-scroll-horizontal', + selector: 'app-primeng-table-scroll-horizontal', standalone: true, imports: [TableModule], template: ` diff --git a/src/stories/components/p-data-table/examples/p-data-table-scroll-vertical.component.ts b/src/stories/components/p-data-table/examples/primeng-table-scroll-vertical.component.ts similarity index 97% rename from src/stories/components/p-data-table/examples/p-data-table-scroll-vertical.component.ts rename to src/stories/components/p-data-table/examples/primeng-table-scroll-vertical.component.ts index d3b808a3..800b185d 100644 --- a/src/stories/components/p-data-table/examples/p-data-table-scroll-vertical.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-scroll-vertical.component.ts @@ -13,7 +13,7 @@ const BASE_SHIPMENTS = [ ]; @Component({ - selector: 'app-p-data-table-scroll-vertical', + selector: 'app-primeng-table-scroll-vertical', standalone: true, imports: [TableModule], template: ` diff --git a/src/stories/components/p-data-table/examples/p-data-table-selectable.component.ts b/src/stories/components/p-data-table/examples/primeng-table-selectable.component.ts similarity index 97% rename from src/stories/components/p-data-table/examples/p-data-table-selectable.component.ts rename to src/stories/components/p-data-table/examples/primeng-table-selectable.component.ts index 5265ad9a..58607acb 100644 --- a/src/stories/components/p-data-table/examples/p-data-table-selectable.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-selectable.component.ts @@ -10,7 +10,7 @@ const SHIPMENTS = [ ]; @Component({ - selector: 'app-p-data-table-selectable', + selector: 'app-primeng-table-selectable', standalone: true, imports: [TableModule], template: ` diff --git a/src/stories/components/p-data-table/examples/p-data-table-selection-checkbox.component.ts b/src/stories/components/p-data-table/examples/primeng-table-selection-checkbox.component.ts similarity index 97% rename from src/stories/components/p-data-table/examples/p-data-table-selection-checkbox.component.ts rename to src/stories/components/p-data-table/examples/primeng-table-selection-checkbox.component.ts index 63e165ea..c03764b6 100644 --- a/src/stories/components/p-data-table/examples/p-data-table-selection-checkbox.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-selection-checkbox.component.ts @@ -10,7 +10,7 @@ const SHIPMENTS = [ ]; @Component({ - selector: 'app-p-data-table-selection-checkbox', + selector: 'app-primeng-table-selection-checkbox', standalone: true, imports: [TableModule], template: ` diff --git a/src/stories/components/p-data-table/examples/p-data-table-selection-radio.component.ts b/src/stories/components/p-data-table/examples/primeng-table-selection-radio.component.ts similarity index 97% rename from src/stories/components/p-data-table/examples/p-data-table-selection-radio.component.ts rename to src/stories/components/p-data-table/examples/primeng-table-selection-radio.component.ts index 0fa3686a..e31ecaa5 100644 --- a/src/stories/components/p-data-table/examples/p-data-table-selection-radio.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-selection-radio.component.ts @@ -10,7 +10,7 @@ const SHIPMENTS = [ ]; @Component({ - selector: 'app-p-data-table-selection-radio', + selector: 'app-primeng-table-selection-radio', standalone: true, imports: [TableModule], template: ` diff --git a/src/stories/components/p-data-table/examples/p-data-table-striped-rows.component.ts b/src/stories/components/p-data-table/examples/primeng-table-striped-rows.component.ts similarity index 98% rename from src/stories/components/p-data-table/examples/p-data-table-striped-rows.component.ts rename to src/stories/components/p-data-table/examples/primeng-table-striped-rows.component.ts index 4ffba2ac..6ca59979 100644 --- a/src/stories/components/p-data-table/examples/p-data-table-striped-rows.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-striped-rows.component.ts @@ -13,7 +13,7 @@ const SHIPMENTS = [ ]; @Component({ - selector: 'app-p-data-table-striped-rows', + selector: 'app-primeng-table-striped-rows', standalone: true, imports: [TableModule], template: ` diff --git a/src/stories/components/p-data-table/p-data-table.stories.ts b/src/stories/components/p-data-table/p-data-table.stories.ts deleted file mode 100644 index 7008be57..00000000 --- a/src/stories/components/p-data-table/p-data-table.stories.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { TableModule } from 'primeng/table'; -import { PDataTableDefaultComponent } from './examples/p-data-table-default.component'; -import { PDataTableStripedRowsComponent } from './examples/p-data-table-striped-rows.component'; -import { PDataTableSelectableComponent } from './examples/p-data-table-selectable.component'; -import { PDataTableGridLinesComponent } from './examples/p-data-table-grid-lines.component'; -import { PDataTablePaginationComponent } from './examples/p-data-table-pagination.component'; -import { PDataTableSelectionRadioComponent } from './examples/p-data-table-selection-radio.component'; -import { PDataTableSelectionCheckboxComponent } from './examples/p-data-table-selection-checkbox.component'; -import { PDataTableScrollVerticalComponent } from './examples/p-data-table-scroll-vertical.component'; -import { PDataTableScrollHorizontalComponent } from './examples/p-data-table-scroll-horizontal.component'; -import { PDataTableCustomBodyComponent } from './examples/p-data-table-custom-body.component'; -import { PDataTableLazyComponent } from './examples/p-data-table-lazy.component'; - -const meta: Meta = { - title: 'Components/Data/DataTable (PrimeNG)', - tags: ['autodocs'], - parameters: { - docs: { - description: { - component: `Таблица данных на базе PrimeNG pTable с поддержкой сортировки, пагинации, выбора строк и прокрутки. - -\`\`\`typescript -import { TableModule } from 'primeng/table'; -\`\`\``, - }, - }, - designTokens: { prefix: '--p-datatable' }, - }, -}; - -export default meta; -type Story = StoryObj; - -// ── Default ─────────────────────────────────────────────────────────────────── - -export const Default: Story = { - name: 'DataTable', - decorators: [moduleMetadata({ imports: [PDataTableDefaultComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Базовая таблица отправлений с сортировкой по всем столбцам на базе PrimeNG pTable.', - }, - }, - }, -}; - -// ── StripedRows ─────────────────────────────────────────────────────────────── - -export const StripedRows: Story = { - name: 'StripedRows', - decorators: [moduleMetadata({ imports: [PDataTableStripedRowsComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Чередование цвета строк для улучшения читаемости на базе PrimeNG pTable.', - }, - }, - }, -}; - -// ── Selectable ──────────────────────────────────────────────────────────────── - -export const Selectable: Story = { - name: 'Selectable', - decorators: [moduleMetadata({ imports: [PDataTableSelectableComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Выбор строки кликом. Режим single — выбирается одна строка на базе PrimeNG pTable.', - }, - }, - }, -}; - -// ── GridLines ───────────────────────────────────────────────────────────────── - -export const GridLines: Story = { - name: 'GridLines', - decorators: [moduleMetadata({ imports: [PDataTableGridLinesComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Сетка между ячейками для наглядного разграничения данных на базе PrimeNG pTable.', - }, - }, - }, -}; - -// ── Pagination ──────────────────────────────────────────────────────────────── - -export const Pagination: Story = { - name: 'Pagination', - decorators: [moduleMetadata({ imports: [PDataTablePaginationComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Пагинация для больших наборов данных на базе PrimeNG pTable.', - }, - }, - }, -}; - -// ── SelectionRadio ──────────────────────────────────────────────────────────── - -export const SelectionRadio: Story = { - name: 'Row Selection: RadioButton', - decorators: [moduleMetadata({ imports: [PDataTableSelectionRadioComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Выбор одной строки через радио-кнопку на базе PrimeNG pTable.', - }, - }, - }, -}; - -// ── SelectionCheckbox ───────────────────────────────────────────────────────── - -export const SelectionCheckbox: Story = { - name: 'Row Selection: Checkbox', - decorators: [moduleMetadata({ imports: [PDataTableSelectionCheckboxComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Множественный выбор строк через чекбоксы на базе PrimeNG pTable.', - }, - }, - }, -}; - -// ── ScrollVertical ──────────────────────────────────────────────────────────── - -export const ScrollVertical: Story = { - name: 'Scroll: Vertical', - decorators: [moduleMetadata({ imports: [PDataTableScrollVerticalComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Вертикальная прокрутка с фиксированной высотой контейнера на базе PrimeNG pTable.', - }, - }, - }, -}; - -// ── ScrollHorizontal ────────────────────────────────────────────────────────── - -export const ScrollHorizontal: Story = { - name: 'Scroll: Horizontal', - decorators: [moduleMetadata({ imports: [PDataTableScrollHorizontalComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Горизонтальная прокрутка при большом количестве столбцов на базе PrimeNG pTable.', - }, - }, - }, -}; - -// ── CustomBody ──────────────────────────────────────────────────────────────── - -export const CustomBody: Story = { - name: 'Custom Templates', - decorators: [moduleMetadata({ imports: [PDataTableCustomBodyComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Кастомные шаблоны для заголовка и тела таблицы на базе PrimeNG pTable.', - }, - }, - }, -}; - -// ── Lazy loading ────────────────────────────────────────────────────────────── - -export const LazyLoading: Story = { - name: 'Lazy Loading', - decorators: [moduleMetadata({ imports: [PDataTableLazyComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Lazy Loading + Virtual Scroll для работы с большими наборами данных. Данные подгружаются порциями при прокрутке таблицы. Используйте `[lazy]="true"`, `[virtualScroll]="true"`, `[virtualScrollItemSize]`, `[totalRecords]` и `(onLazyLoad)` для управления загрузкой данных с сервера.', - }, - }, - }, -}; diff --git a/src/stories/components/p-data-table/primeng-data-table.stories.ts b/src/stories/components/p-data-table/primeng-data-table.stories.ts new file mode 100644 index 00000000..ed973d8e --- /dev/null +++ b/src/stories/components/p-data-table/primeng-data-table.stories.ts @@ -0,0 +1,777 @@ +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { PDataTableDefaultComponent } from './examples/primeng-table-default.component'; +import { PDataTableStripedRowsComponent } from './examples/primeng-table-striped-rows.component'; +import { PDataTableSelectableComponent } from './examples/primeng-table-selectable.component'; +import { PDataTableGridLinesComponent } from './examples/primeng-table-grid-lines.component'; +import { PDataTablePaginationComponent } from './examples/primeng-table-pagination.component'; +import { PDataTableSelectionRadioComponent } from './examples/primeng-table-selection-radio.component'; +import { PDataTableSelectionCheckboxComponent } from './examples/primeng-table-selection-checkbox.component'; +import { PDataTableScrollVerticalComponent } from './examples/primeng-table-scroll-vertical.component'; +import { PDataTableScrollHorizontalComponent } from './examples/primeng-table-scroll-horizontal.component'; +import { PDataTableCustomBodyComponent } from './examples/primeng-table-custom-body.component'; +import { PDataTableLazyComponent } from './examples/primeng-table-lazy.component'; + +const meta: Meta = { + title: 'Components/Data/DataTable (PrimeNG)', + tags: ['autodocs'], + parameters: { + docs: { + description: { + component: `Таблица данных на базе PrimeNG pTable с поддержкой сортировки, пагинации, выбора строк и прокрутки. + +\`\`\`typescript +import { TableModule } from 'primeng/table'; +\`\`\``, + }, + }, + designTokens: { prefix: '--p-datatable' }, + }, +}; + +export default meta; +type Story = StoryObj; + +// ── Default ─────────────────────────────────────────────────────────────────── + +export const Default: Story = { + name: 'DataTable', + decorators: [moduleMetadata({ imports: [PDataTableDefaultComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Базовая таблица отправлений с сортировкой по всем столбцам на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +@Component({ + selector: 'app-primeng-table-default', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + \`, +}) +export class PDataTableDefaultComponent { + shipments = SHIPMENTS; +}`, + }, + }, + }, +}; + +// ── StripedRows ─────────────────────────────────────────────────────────────── + +export const StripedRows: Story = { + name: 'StripedRows', + decorators: [moduleMetadata({ imports: [PDataTableStripedRowsComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Чередование цвета строк для улучшения читаемости на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +@Component({ + selector: 'app-primeng-table-striped-rows', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + \`, +}) +export class PDataTableStripedRowsComponent { + shipments = SHIPMENTS; +}`, + }, + }, + }, +}; + +// ── Selectable ──────────────────────────────────────────────────────────────── + +export const Selectable: Story = { + name: 'Selectable', + decorators: [moduleMetadata({ imports: [PDataTableSelectableComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Выбор строки кликом. Режим single — выбирается одна строка на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +@Component({ + selector: 'app-primeng-table-selectable', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + \`, +}) +export class PDataTableSelectableComponent { + shipments = SHIPMENTS; + selected: any = null; +}`, + }, + }, + }, +}; + +// ── GridLines ───────────────────────────────────────────────────────────────── + +export const GridLines: Story = { + name: 'GridLines', + decorators: [moduleMetadata({ imports: [PDataTableGridLinesComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Сетка между ячейками для наглядного разграничения данных на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +@Component({ + selector: 'app-primeng-table-grid-lines', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + \`, +}) +export class PDataTableGridLinesComponent { + shipments = SHIPMENTS; +}`, + }, + }, + }, +}; + +// ── Pagination ──────────────────────────────────────────────────────────────── + +export const Pagination: Story = { + name: 'Pagination', + decorators: [moduleMetadata({ imports: [PDataTablePaginationComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Пагинация для больших наборов данных на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +@Component({ + selector: 'app-primeng-table-pagination', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + \`, +}) +export class PDataTablePaginationComponent { + shipments = SHIPMENTS; +}`, + }, + }, + }, +}; + +// ── SelectionRadio ──────────────────────────────────────────────────────────── + +export const SelectionRadio: Story = { + name: 'Row Selection: RadioButton', + decorators: [moduleMetadata({ imports: [PDataTableSelectionRadioComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Выбор одной строки через радио-кнопку на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, +]; + +@Component({ + selector: 'app-primeng-table-selection-radio', + standalone: true, + imports: [TableModule], + template: \` + + + + + Трек-номер + Назначение + Статус + Вес, кг + + + + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + + + + \`, +}) +export class PDataTableSelectionRadioComponent { + shipments = SHIPMENTS; + selected: any = null; +}`, + }, + }, + }, +}; + +// ── SelectionCheckbox ───────────────────────────────────────────────────────── + +export const SelectionCheckbox: Story = { + name: 'Row Selection: Checkbox', + decorators: [moduleMetadata({ imports: [PDataTableSelectionCheckboxComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Множественный выбор строк через чекбоксы на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, +]; + +@Component({ + selector: 'app-primeng-table-selection-checkbox', + standalone: true, + imports: [TableModule], + template: \` + + + + + + + Трек-номер + Назначение + Статус + Вес, кг + + + + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + + + + \`, +}) +export class PDataTableSelectionCheckboxComponent { + shipments = SHIPMENTS; + selected: any[] = []; +}`, + }, + }, + }, +}; + +// ── ScrollVertical ──────────────────────────────────────────────────────────── + +export const ScrollVertical: Story = { + name: 'Scroll: Vertical', + decorators: [moduleMetadata({ imports: [PDataTableScrollVerticalComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Вертикальная прокрутка с фиксированной высотой контейнера на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const BASE_SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1 }, +]; + +@Component({ + selector: 'app-primeng-table-scroll-vertical', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + + + + \`, +}) +export class PDataTableScrollVerticalComponent { + shipments = [...BASE_SHIPMENTS, ...BASE_SHIPMENTS, ...BASE_SHIPMENTS]; +}`, + }, + }, + }, +}; + +// ── ScrollHorizontal ────────────────────────────────────────────────────────── + +export const ScrollHorizontal: Story = { + name: 'Scroll: Horizontal', + decorators: [moduleMetadata({ imports: [PDataTableScrollHorizontalComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Горизонтальная прокрутка при большом количестве столбцов на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', sender: 'Иванов И.И.', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200, dimensions: '30×20×15 см' }, + { id: 2, trackNumber: 'ЦД-00123457', sender: 'Петров П.П.', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450, dimensions: '10×10×10 см' }, + { id: 3, trackNumber: 'ЦД-00123458', sender: 'Сидоров С.С.', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100, dimensions: '50×40×30 см' }, + { id: 4, trackNumber: 'ЦД-00123459', sender: 'Козлов К.К.', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750, dimensions: '20×15×10 см' }, + { id: 5, trackNumber: 'ЦД-00123460', sender: 'Новиков Н.Н.', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800, dimensions: '40×30×20 см' }, +]; + +@Component({ + selector: 'app-primeng-table-scroll-horizontal', + standalone: true, + imports: [TableModule], + template: \` + + + + + Трек-номер + + + Отправитель + + + Назначение + + + Статус + + + Вес, кг + + + Стоимость, ₽ + + Габариты + + + + + {{ shipment.trackNumber }} + {{ shipment.sender }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + {{ shipment.dimensions }} + + + + \`, +}) +export class PDataTableScrollHorizontalComponent { + shipments = SHIPMENTS; +}`, + }, + }, + }, +}; + +// ── CustomBody ──────────────────────────────────────────────────────────────── + +export const CustomBody: Story = { + name: 'Custom Templates', + decorators: [moduleMetadata({ imports: [PDataTableCustomBodyComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Кастомные шаблоны для заголовка и тела таблицы на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { TableModule } from 'primeng/table'; +import { TagModule } from 'primeng/tag'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +@Component({ + selector: 'app-primeng-table-custom-body', + standalone: true, + imports: [CommonModule, TableModule, TagModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + + + + {{ shipment.weight }} кг + {{ shipment.cost | currency:'RUB':'symbol':'1.0-0':'ru' }} + + + + Нет данных для отображения + + + \`, +}) +export class PDataTableCustomBodyComponent { + shipments = SHIPMENTS; + + getSeverity(status: string): 'success' | 'warn' | 'danger' | 'info' | 'secondary' | undefined { + switch (status) { + case 'Доставлен': return 'success'; + case 'В пути': return 'info'; + case 'Задержан': return 'danger'; + case 'Ожидание': return 'warn'; + default: return 'secondary'; + } + } +}`, + }, + }, + }, +}; + +// ── Lazy loading ────────────────────────────────────────────────────────────── + +export const LazyLoading: Story = { + name: 'Lazy Loading', + decorators: [moduleMetadata({ imports: [PDataTableLazyComponent] })], + render: () => ({ template: `` }), + parameters: { + docs: { + description: { + story: 'Lazy Loading + Virtual Scroll для работы с большими наборами данных. Данные подгружаются порциями при прокрутке таблицы. Используйте `[lazy]="true"`, `[virtualScroll]="true"`, `[virtualScrollItemSize]`, `[totalRecords]` и `(onLazyLoad)` для управления загрузкой данных с сервера.', + }, + source: { + language: 'ts', + code: `import { Component, OnInit } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const ALL_SHIPMENTS = Array.from({ length: 500 }, (_, i) => ({ + id: i + 1, + trackNumber: \`ЦД-\${String(i + 100000).padStart(8, '0')}\`, + destination: ['Москва', 'Новосибирск', 'Екатеринбург', 'Казань', 'Краснодар', 'Санкт-Петербург', 'Воронеж', 'Самара', 'Ростов-на-Дону', 'Уфа'][i % 10], + status: ['В пути', 'Доставлен', 'Задержан', 'Ожидание'][i % 4], + weight: Number(((i * 0.37 + 0.5) % 10).toFixed(1)), + cost: ((i * 137 + 200) % 5000) + 200, +})); + +const PAGE_SIZE = 50; + +@Component({ + selector: 'app-primeng-table-lazy', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment?.trackNumber }} + {{ shipment?.destination }} + {{ shipment?.status }} + {{ shipment?.weight }} + {{ shipment?.cost }} + + + + + Загрузка… + + + + \`, +}) +export class PDataTableLazyComponent implements OnInit { + readonly PAGE_SIZE = PAGE_SIZE; + + shipments: any[] = Array.from({ length: ALL_SHIPMENTS.length }); + totalRecords = ALL_SHIPMENTS.length; + loading = false; + + ngOnInit(): void { + // shipments pre-filled with placeholders so virtual scroll knows total size + } + + onLazyLoad(event: any): void { + this.loading = true; + const start = event.first ?? 0; + const end = start + (event.rows ?? PAGE_SIZE); + + // Simulate async server request + setTimeout(() => { + const page = ALL_SHIPMENTS.slice(start, end); + const updated = [...this.shipments]; + for (let i = 0; i < page.length; i++) { + updated[start + i] = page[i]; + } + this.shipments = updated; + this.loading = false; + }, 300); + } +}`, + }, + }, + }, +}; From 5b3fd845c05fad159b7b297321a7ef8531c7b4fb Mon Sep 17 00:00:00 2001 From: "ak.dmitriev" Date: Fri, 29 May 2026 19:02:10 +0700 Subject: [PATCH 7/7] DS-517 --- .../primeng-table-custom-body.component.ts | 78 +- .../primeng-table-default.component.ts | 64 +- .../primeng-table-grid-lines.component.ts | 61 +- .../examples/primeng-table-lazy.component.ts | 105 ++- .../primeng-table-pagination.component.ts | 64 +- ...imeng-table-scroll-horizontal.component.ts | 77 +- ...primeng-table-scroll-vertical.component.ts | 62 +- .../primeng-table-selectable.component.ts | 62 +- ...meng-table-selection-checkbox.component.ts | 66 +- ...primeng-table-selection-radio.component.ts | 64 +- .../primeng-table-striped-rows.component.ts | 64 +- .../primeng-data-table.stories.ts | 794 +----------------- 12 files changed, 793 insertions(+), 768 deletions(-) diff --git a/src/stories/components/p-data-table/examples/primeng-table-custom-body.component.ts b/src/stories/components/p-data-table/examples/primeng-table-custom-body.component.ts index edd8a3eb..f3920a93 100644 --- a/src/stories/components/p-data-table/examples/primeng-table-custom-body.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-custom-body.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { StoryObj, moduleMetadata } from '@storybook/angular'; import { CommonModule } from '@angular/common'; import { TableModule } from 'primeng/table'; import { TagModule } from 'primeng/tag'; @@ -55,4 +56,79 @@ export class PDataTableCustomBodyComponent { default: return 'secondary'; } } -} \ No newline at end of file +} + +export const CustomBody: StoryObj = { + name: 'Custom Templates', + decorators: [moduleMetadata({ imports: [PDataTableCustomBodyComponent] })], + render: () => ({ template: `` }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Кастомные шаблоны для заголовка и тела таблицы на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { TableModule } from 'primeng/table'; +import { TagModule } from 'primeng/tag'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [CommonModule, TableModule, TagModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + + + + {{ shipment.weight }} кг + {{ shipment.cost | currency:'RUB':'symbol':'1.0-0':'ru' }} + + + + Нет данных для отображения + + + \`, +}) +export class ExampleComponent { + shipments = SHIPMENTS; + + getSeverity(status: string): 'success' | 'warn' | 'danger' | 'info' | 'secondary' | undefined { + switch (status) { + case 'Доставлен': return 'success'; + case 'В пути': return 'info'; + case 'Задержан': return 'danger'; + case 'Ожидание': return 'warn'; + default: return 'secondary'; + } + } +}`, + }, + }, + }, +}; diff --git a/src/stories/components/p-data-table/examples/primeng-table-default.component.ts b/src/stories/components/p-data-table/examples/primeng-table-default.component.ts index 0df4bcc9..f50fd9a5 100644 --- a/src/stories/components/p-data-table/examples/primeng-table-default.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-default.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { StoryObj, moduleMetadata } from '@storybook/angular'; import { TableModule } from 'primeng/table'; const SHIPMENTS = [ @@ -41,4 +42,65 @@ const SHIPMENTS = [ }) export class PDataTableDefaultComponent { shipments = SHIPMENTS; -} \ No newline at end of file +} + +export const Default: StoryObj = { + name: 'DataTable', + decorators: [moduleMetadata({ imports: [PDataTableDefaultComponent] })], + render: () => ({ template: `` }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Базовая таблица отправлений с сортировкой по всем столбцам на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + \`, +}) +export class ExampleComponent { + shipments = SHIPMENTS; +}`, + }, + }, + }, +}; diff --git a/src/stories/components/p-data-table/examples/primeng-table-grid-lines.component.ts b/src/stories/components/p-data-table/examples/primeng-table-grid-lines.component.ts index 5478270e..4eb8316b 100644 --- a/src/stories/components/p-data-table/examples/primeng-table-grid-lines.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-grid-lines.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { StoryObj, moduleMetadata } from '@storybook/angular'; import { TableModule } from 'primeng/table'; const SHIPMENTS = [ @@ -38,4 +39,62 @@ const SHIPMENTS = [ }) export class PDataTableGridLinesComponent { shipments = SHIPMENTS; -} \ No newline at end of file +} + +export const GridLines: StoryObj = { + name: 'GridLines', + decorators: [moduleMetadata({ imports: [PDataTableGridLinesComponent] })], + render: () => ({ template: `` }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Сетка между ячейками для наглядного разграничения данных на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + \`, +}) +export class ExampleComponent { + shipments = SHIPMENTS; +}`, + }, + }, + }, +}; diff --git a/src/stories/components/p-data-table/examples/primeng-table-lazy.component.ts b/src/stories/components/p-data-table/examples/primeng-table-lazy.component.ts index 44e4b920..62c6905b 100644 --- a/src/stories/components/p-data-table/examples/primeng-table-lazy.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-lazy.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit } from '@angular/core'; +import { StoryObj, moduleMetadata } from '@storybook/angular'; import { TableModule } from 'primeng/table'; const ALL_SHIPMENTS = Array.from({ length: 500 }, (_, i) => ({ @@ -62,16 +63,13 @@ export class PDataTableLazyComponent implements OnInit { totalRecords = ALL_SHIPMENTS.length; loading = false; - ngOnInit(): void { - // shipments pre-filled with placeholders so virtual scroll knows total size - } + ngOnInit(): void {} onLazyLoad(event: any): void { this.loading = true; const start = event.first ?? 0; const end = start + (event.rows ?? PAGE_SIZE); - // Simulate async server request setTimeout(() => { const page = ALL_SHIPMENTS.slice(start, end); const updated = [...this.shipments]; @@ -83,3 +81,102 @@ export class PDataTableLazyComponent implements OnInit { }, 300); } } + +export const LazyLoading: StoryObj = { + name: 'Lazy Loading', + decorators: [moduleMetadata({ imports: [PDataTableLazyComponent] })], + render: () => ({ template: `` }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Lazy Loading + Virtual Scroll для работы с большими наборами данных. Данные подгружаются порциями при прокрутке таблицы. Используйте `[lazy]="true"`, `[virtualScroll]="true"`, `[virtualScrollItemSize]`, `[totalRecords]` и `(onLazyLoad)` для управления загрузкой данных с сервера.', + }, + source: { + language: 'ts', + code: `import { Component, OnInit } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const ALL_SHIPMENTS = Array.from({ length: 500 }, (_, i) => ({ + id: i + 1, + trackNumber: \`ЦД-\${String(i + 100000).padStart(8, '0')}\`, + destination: ['Москва', 'Новосибирск', 'Екатеринбург', 'Казань', 'Краснодар', 'Санкт-Петербург', 'Воронеж', 'Самара', 'Ростов-на-Дону', 'Уфа'][i % 10], + status: ['В пути', 'Доставлен', 'Задержан', 'Ожидание'][i % 4], + weight: Number(((i * 0.37 + 0.5) % 10).toFixed(1)), + cost: ((i * 137 + 200) % 5000) + 200, +})); + +const PAGE_SIZE = 50; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment?.trackNumber }} + {{ shipment?.destination }} + {{ shipment?.status }} + {{ shipment?.weight }} + {{ shipment?.cost }} + + + + + Загрузка… + + + + \`, +}) +export class ExampleComponent implements OnInit { + readonly PAGE_SIZE = PAGE_SIZE; + + shipments: any[] = Array.from({ length: ALL_SHIPMENTS.length }); + totalRecords = ALL_SHIPMENTS.length; + loading = false; + + ngOnInit(): void {} + + onLazyLoad(event: any): void { + this.loading = true; + const start = event.first ?? 0; + const end = start + (event.rows ?? PAGE_SIZE); + + setTimeout(() => { + const page = ALL_SHIPMENTS.slice(start, end); + const updated = [...this.shipments]; + for (let i = 0; i < page.length; i++) { + updated[start + i] = page[i]; + } + this.shipments = updated; + this.loading = false; + }, 300); + } +}`, + }, + }, + }, +}; diff --git a/src/stories/components/p-data-table/examples/primeng-table-pagination.component.ts b/src/stories/components/p-data-table/examples/primeng-table-pagination.component.ts index 3bb24c9c..3c4446c7 100644 --- a/src/stories/components/p-data-table/examples/primeng-table-pagination.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-pagination.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { StoryObj, moduleMetadata } from '@storybook/angular'; import { TableModule } from 'primeng/table'; const SHIPMENTS = [ @@ -41,4 +42,65 @@ const SHIPMENTS = [ }) export class PDataTablePaginationComponent { shipments = SHIPMENTS; -} \ No newline at end of file +} + +export const Pagination: StoryObj = { + name: 'Pagination', + decorators: [moduleMetadata({ imports: [PDataTablePaginationComponent] })], + render: () => ({ template: `` }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Пагинация для больших наборов данных на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + \`, +}) +export class ExampleComponent { + shipments = SHIPMENTS; +}`, + }, + }, + }, +}; diff --git a/src/stories/components/p-data-table/examples/primeng-table-scroll-horizontal.component.ts b/src/stories/components/p-data-table/examples/primeng-table-scroll-horizontal.component.ts index 8128b89f..9e3cb8ca 100644 --- a/src/stories/components/p-data-table/examples/primeng-table-scroll-horizontal.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-scroll-horizontal.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { StoryObj, moduleMetadata } from '@storybook/angular'; import { TableModule } from 'primeng/table'; const SHIPMENTS = [ @@ -54,4 +55,78 @@ const SHIPMENTS = [ }) export class PDataTableScrollHorizontalComponent { shipments = SHIPMENTS; -} \ No newline at end of file +} + +export const ScrollHorizontal: StoryObj = { + name: 'Scroll: Horizontal', + decorators: [moduleMetadata({ imports: [PDataTableScrollHorizontalComponent] })], + render: () => ({ template: `` }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Горизонтальная прокрутка при большом количестве столбцов на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', sender: 'Иванов И.И.', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200, dimensions: '30×20×15 см' }, + { id: 2, trackNumber: 'ЦД-00123457', sender: 'Петров П.П.', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450, dimensions: '10×10×10 см' }, + { id: 3, trackNumber: 'ЦД-00123458', sender: 'Сидоров С.С.', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100, dimensions: '50×40×30 см' }, + { id: 4, trackNumber: 'ЦД-00123459', sender: 'Козлов К.К.', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750, dimensions: '20×15×10 см' }, + { id: 5, trackNumber: 'ЦД-00123460', sender: 'Новиков Н.Н.', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800, dimensions: '40×30×20 см' }, +]; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [TableModule], + template: \` + + + + + Трек-номер + + + Отправитель + + + Назначение + + + Статус + + + Вес, кг + + + Стоимость, ₽ + + Габариты + + + + + {{ shipment.trackNumber }} + {{ shipment.sender }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + {{ shipment.dimensions }} + + + + \`, +}) +export class ExampleComponent { + shipments = SHIPMENTS; +}`, + }, + }, + }, +}; diff --git a/src/stories/components/p-data-table/examples/primeng-table-scroll-vertical.component.ts b/src/stories/components/p-data-table/examples/primeng-table-scroll-vertical.component.ts index 800b185d..ea9a6cc9 100644 --- a/src/stories/components/p-data-table/examples/primeng-table-scroll-vertical.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-scroll-vertical.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { StoryObj, moduleMetadata } from '@storybook/angular'; import { TableModule } from 'primeng/table'; const BASE_SHIPMENTS = [ @@ -39,4 +40,63 @@ const BASE_SHIPMENTS = [ }) export class PDataTableScrollVerticalComponent { shipments = [...BASE_SHIPMENTS, ...BASE_SHIPMENTS, ...BASE_SHIPMENTS]; -} \ No newline at end of file +} + +export const ScrollVertical: StoryObj = { + name: 'Scroll: Vertical', + decorators: [moduleMetadata({ imports: [PDataTableScrollVerticalComponent] })], + render: () => ({ template: `` }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Вертикальная прокрутка с фиксированной высотой контейнера на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const BASE_SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1 }, +]; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + + + + \`, +}) +export class ExampleComponent { + shipments = [...BASE_SHIPMENTS, ...BASE_SHIPMENTS, ...BASE_SHIPMENTS]; +}`, + }, + }, + }, +}; diff --git a/src/stories/components/p-data-table/examples/primeng-table-selectable.component.ts b/src/stories/components/p-data-table/examples/primeng-table-selectable.component.ts index 58607acb..58b0f541 100644 --- a/src/stories/components/p-data-table/examples/primeng-table-selectable.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-selectable.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { StoryObj, moduleMetadata } from '@storybook/angular'; import { TableModule } from 'primeng/table'; const SHIPMENTS = [ @@ -39,4 +40,63 @@ const SHIPMENTS = [ export class PDataTableSelectableComponent { shipments = SHIPMENTS; selected: any = null; -} \ No newline at end of file +} + +export const Selectable: StoryObj = { + name: 'Selectable', + decorators: [moduleMetadata({ imports: [PDataTableSelectableComponent] })], + render: () => ({ template: `` }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Выбор строки кликом. Режим single — выбирается одна строка на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, +]; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + \`, +}) +export class ExampleComponent { + shipments = SHIPMENTS; + selected: any = null; +}`, + }, + }, + }, +}; diff --git a/src/stories/components/p-data-table/examples/primeng-table-selection-checkbox.component.ts b/src/stories/components/p-data-table/examples/primeng-table-selection-checkbox.component.ts index c03764b6..76ad3882 100644 --- a/src/stories/components/p-data-table/examples/primeng-table-selection-checkbox.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-selection-checkbox.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { StoryObj, moduleMetadata } from '@storybook/angular'; import { TableModule } from 'primeng/table'; const SHIPMENTS = [ @@ -43,4 +44,67 @@ const SHIPMENTS = [ export class PDataTableSelectionCheckboxComponent { shipments = SHIPMENTS; selected: any[] = []; -} \ No newline at end of file +} + +export const SelectionCheckbox: StoryObj = { + name: 'Row Selection: Checkbox', + decorators: [moduleMetadata({ imports: [PDataTableSelectionCheckboxComponent] })], + render: () => ({ template: `` }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Множественный выбор строк через чекбоксы на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, +]; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [TableModule], + template: \` + + + + + + + Трек-номер + Назначение + Статус + Вес, кг + + + + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + + + + \`, +}) +export class ExampleComponent { + shipments = SHIPMENTS; + selected: any[] = []; +}`, + }, + }, + }, +}; diff --git a/src/stories/components/p-data-table/examples/primeng-table-selection-radio.component.ts b/src/stories/components/p-data-table/examples/primeng-table-selection-radio.component.ts index e31ecaa5..f955a99e 100644 --- a/src/stories/components/p-data-table/examples/primeng-table-selection-radio.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-selection-radio.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { StoryObj, moduleMetadata } from '@storybook/angular'; import { TableModule } from 'primeng/table'; const SHIPMENTS = [ @@ -41,4 +42,65 @@ const SHIPMENTS = [ export class PDataTableSelectionRadioComponent { shipments = SHIPMENTS; selected: any = null; -} \ No newline at end of file +} + +export const SelectionRadio: StoryObj = { + name: 'Row Selection: RadioButton', + decorators: [moduleMetadata({ imports: [PDataTableSelectionRadioComponent] })], + render: () => ({ template: `` }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Выбор одной строки через радио-кнопку на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, +]; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [TableModule], + template: \` + + + + + Трек-номер + Назначение + Статус + Вес, кг + + + + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + + + + \`, +}) +export class ExampleComponent { + shipments = SHIPMENTS; + selected: any = null; +}`, + }, + }, + }, +}; diff --git a/src/stories/components/p-data-table/examples/primeng-table-striped-rows.component.ts b/src/stories/components/p-data-table/examples/primeng-table-striped-rows.component.ts index 6ca59979..52ef46c9 100644 --- a/src/stories/components/p-data-table/examples/primeng-table-striped-rows.component.ts +++ b/src/stories/components/p-data-table/examples/primeng-table-striped-rows.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { StoryObj, moduleMetadata } from '@storybook/angular'; import { TableModule } from 'primeng/table'; const SHIPMENTS = [ @@ -41,4 +42,65 @@ const SHIPMENTS = [ }) export class PDataTableStripedRowsComponent { shipments = SHIPMENTS; -} \ No newline at end of file +} + +export const StripedRows: StoryObj = { + name: 'StripedRows', + decorators: [moduleMetadata({ imports: [PDataTableStripedRowsComponent] })], + render: () => ({ template: `` }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Чередование цвета строк для улучшения читаемости на базе PrimeNG pTable.', + }, + source: { + language: 'ts', + code: `import { Component } from '@angular/core'; +import { TableModule } from 'primeng/table'; + +const SHIPMENTS = [ + { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, + { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, + { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, + { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, + { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, + { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, + { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, + { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, +]; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [TableModule], + template: \` + + + + Трек-номер + Назначение + Статус + Вес, кг + Стоимость, ₽ + + + + + {{ shipment.trackNumber }} + {{ shipment.destination }} + {{ shipment.status }} + {{ shipment.weight }} + {{ shipment.cost }} + + + + \`, +}) +export class ExampleComponent { + shipments = SHIPMENTS; +}`, + }, + }, + }, +}; diff --git a/src/stories/components/p-data-table/primeng-data-table.stories.ts b/src/stories/components/p-data-table/primeng-data-table.stories.ts index ed973d8e..a711e0d2 100644 --- a/src/stories/components/p-data-table/primeng-data-table.stories.ts +++ b/src/stories/components/p-data-table/primeng-data-table.stories.ts @@ -1,19 +1,36 @@ import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; -import { PDataTableDefaultComponent } from './examples/primeng-table-default.component'; -import { PDataTableStripedRowsComponent } from './examples/primeng-table-striped-rows.component'; -import { PDataTableSelectableComponent } from './examples/primeng-table-selectable.component'; -import { PDataTableGridLinesComponent } from './examples/primeng-table-grid-lines.component'; -import { PDataTablePaginationComponent } from './examples/primeng-table-pagination.component'; -import { PDataTableSelectionRadioComponent } from './examples/primeng-table-selection-radio.component'; -import { PDataTableSelectionCheckboxComponent } from './examples/primeng-table-selection-checkbox.component'; -import { PDataTableScrollVerticalComponent } from './examples/primeng-table-scroll-vertical.component'; -import { PDataTableScrollHorizontalComponent } from './examples/primeng-table-scroll-horizontal.component'; -import { PDataTableCustomBodyComponent } from './examples/primeng-table-custom-body.component'; -import { PDataTableLazyComponent } from './examples/primeng-table-lazy.component'; +import { PDataTableDefaultComponent, Default } from './examples/primeng-table-default.component'; +import { PDataTableStripedRowsComponent, StripedRows } from './examples/primeng-table-striped-rows.component'; +import { PDataTableSelectableComponent, Selectable } from './examples/primeng-table-selectable.component'; +import { PDataTableGridLinesComponent, GridLines } from './examples/primeng-table-grid-lines.component'; +import { PDataTablePaginationComponent, Pagination } from './examples/primeng-table-pagination.component'; +import { PDataTableSelectionRadioComponent, SelectionRadio } from './examples/primeng-table-selection-radio.component'; +import { PDataTableSelectionCheckboxComponent, SelectionCheckbox } from './examples/primeng-table-selection-checkbox.component'; +import { PDataTableScrollVerticalComponent, ScrollVertical } from './examples/primeng-table-scroll-vertical.component'; +import { PDataTableScrollHorizontalComponent, ScrollHorizontal } from './examples/primeng-table-scroll-horizontal.component'; +import { PDataTableCustomBodyComponent, CustomBody } from './examples/primeng-table-custom-body.component'; +import { PDataTableLazyComponent, LazyLoading } from './examples/primeng-table-lazy.component'; const meta: Meta = { title: 'Components/Data/DataTable (PrimeNG)', tags: ['autodocs'], + decorators: [ + moduleMetadata({ + imports: [ + PDataTableDefaultComponent, + PDataTableStripedRowsComponent, + PDataTableSelectableComponent, + PDataTableGridLinesComponent, + PDataTablePaginationComponent, + PDataTableSelectionRadioComponent, + PDataTableSelectionCheckboxComponent, + PDataTableScrollVerticalComponent, + PDataTableScrollHorizontalComponent, + PDataTableCustomBodyComponent, + PDataTableLazyComponent, + ], + }), + ], parameters: { docs: { description: { @@ -31,747 +48,16 @@ import { TableModule } from 'primeng/table'; export default meta; type Story = StoryObj; -// ── Default ─────────────────────────────────────────────────────────────────── - -export const Default: Story = { - name: 'DataTable', - decorators: [moduleMetadata({ imports: [PDataTableDefaultComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Базовая таблица отправлений с сортировкой по всем столбцам на базе PrimeNG pTable.', - }, - source: { - language: 'ts', - code: `import { Component } from '@angular/core'; -import { TableModule } from 'primeng/table'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, - { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, - { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, - { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, -]; - -@Component({ - selector: 'app-primeng-table-default', - standalone: true, - imports: [TableModule], - template: \` - - - - Трек-номер - Назначение - Статус - Вес, кг - Стоимость, ₽ - - - - - {{ shipment.trackNumber }} - {{ shipment.destination }} - {{ shipment.status }} - {{ shipment.weight }} - {{ shipment.cost }} - - - - \`, -}) -export class PDataTableDefaultComponent { - shipments = SHIPMENTS; -}`, - }, - }, - }, -}; - -// ── StripedRows ─────────────────────────────────────────────────────────────── - -export const StripedRows: Story = { - name: 'StripedRows', - decorators: [moduleMetadata({ imports: [PDataTableStripedRowsComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Чередование цвета строк для улучшения читаемости на базе PrimeNG pTable.', - }, - source: { - language: 'ts', - code: `import { Component } from '@angular/core'; -import { TableModule } from 'primeng/table'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, - { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, - { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, - { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, -]; - -@Component({ - selector: 'app-primeng-table-striped-rows', - standalone: true, - imports: [TableModule], - template: \` - - - - Трек-номер - Назначение - Статус - Вес, кг - Стоимость, ₽ - - - - - {{ shipment.trackNumber }} - {{ shipment.destination }} - {{ shipment.status }} - {{ shipment.weight }} - {{ shipment.cost }} - - - - \`, -}) -export class PDataTableStripedRowsComponent { - shipments = SHIPMENTS; -}`, - }, - }, - }, -}; - -// ── Selectable ──────────────────────────────────────────────────────────────── - -export const Selectable: Story = { - name: 'Selectable', - decorators: [moduleMetadata({ imports: [PDataTableSelectableComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Выбор строки кликом. Режим single — выбирается одна строка на базе PrimeNG pTable.', - }, - source: { - language: 'ts', - code: `import { Component } from '@angular/core'; -import { TableModule } from 'primeng/table'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, -]; - -@Component({ - selector: 'app-primeng-table-selectable', - standalone: true, - imports: [TableModule], - template: \` - - - - Трек-номер - Назначение - Статус - Вес, кг - Стоимость, ₽ - - - - - {{ shipment.trackNumber }} - {{ shipment.destination }} - {{ shipment.status }} - {{ shipment.weight }} - {{ shipment.cost }} - - - - \`, -}) -export class PDataTableSelectableComponent { - shipments = SHIPMENTS; - selected: any = null; -}`, - }, - }, - }, -}; - -// ── GridLines ───────────────────────────────────────────────────────────────── - -export const GridLines: Story = { - name: 'GridLines', - decorators: [moduleMetadata({ imports: [PDataTableGridLinesComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Сетка между ячейками для наглядного разграничения данных на базе PrimeNG pTable.', - }, - source: { - language: 'ts', - code: `import { Component } from '@angular/core'; -import { TableModule } from 'primeng/table'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, -]; - -@Component({ - selector: 'app-primeng-table-grid-lines', - standalone: true, - imports: [TableModule], - template: \` - - - - Трек-номер - Назначение - Статус - Вес, кг - Стоимость, ₽ - - - - - {{ shipment.trackNumber }} - {{ shipment.destination }} - {{ shipment.status }} - {{ shipment.weight }} - {{ shipment.cost }} - - - - \`, -}) -export class PDataTableGridLinesComponent { - shipments = SHIPMENTS; -}`, - }, - }, - }, -}; - -// ── Pagination ──────────────────────────────────────────────────────────────── - -export const Pagination: Story = { - name: 'Pagination', - decorators: [moduleMetadata({ imports: [PDataTablePaginationComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Пагинация для больших наборов данных на базе PrimeNG pTable.', - }, - source: { - language: 'ts', - code: `import { Component } from '@angular/core'; -import { TableModule } from 'primeng/table'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, - { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5, cost: 350 }, - { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0, cost: 3200 }, - { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1, cost: 980 }, -]; - -@Component({ - selector: 'app-primeng-table-pagination', - standalone: true, - imports: [TableModule], - template: \` - - - - Трек-номер - Назначение - Статус - Вес, кг - Стоимость, ₽ - - - - - {{ shipment.trackNumber }} - {{ shipment.destination }} - {{ shipment.status }} - {{ shipment.weight }} - {{ shipment.cost }} - - - - \`, -}) -export class PDataTablePaginationComponent { - shipments = SHIPMENTS; -}`, - }, - }, - }, -}; - -// ── SelectionRadio ──────────────────────────────────────────────────────────── - -export const SelectionRadio: Story = { - name: 'Row Selection: RadioButton', - decorators: [moduleMetadata({ imports: [PDataTableSelectionRadioComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Выбор одной строки через радио-кнопку на базе PrimeNG pTable.', - }, - source: { - language: 'ts', - code: `import { Component } from '@angular/core'; -import { TableModule } from 'primeng/table'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, -]; - -@Component({ - selector: 'app-primeng-table-selection-radio', - standalone: true, - imports: [TableModule], - template: \` - - - - - Трек-номер - Назначение - Статус - Вес, кг - - - - - - - - {{ shipment.trackNumber }} - {{ shipment.destination }} - {{ shipment.status }} - {{ shipment.weight }} - - - - \`, -}) -export class PDataTableSelectionRadioComponent { - shipments = SHIPMENTS; - selected: any = null; -}`, - }, - }, - }, -}; - -// ── SelectionCheckbox ───────────────────────────────────────────────────────── - -export const SelectionCheckbox: Story = { - name: 'Row Selection: Checkbox', - decorators: [moduleMetadata({ imports: [PDataTableSelectionCheckboxComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Множественный выбор строк через чекбоксы на базе PrimeNG pTable.', - }, - source: { - language: 'ts', - code: `import { Component } from '@angular/core'; -import { TableModule } from 'primeng/table'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, -]; - -@Component({ - selector: 'app-primeng-table-selection-checkbox', - standalone: true, - imports: [TableModule], - template: \` - - - - - - - Трек-номер - Назначение - Статус - Вес, кг - - - - - - - - {{ shipment.trackNumber }} - {{ shipment.destination }} - {{ shipment.status }} - {{ shipment.weight }} - - - - \`, -}) -export class PDataTableSelectionCheckboxComponent { - shipments = SHIPMENTS; - selected: any[] = []; -}`, - }, - }, - }, -}; - -// ── ScrollVertical ──────────────────────────────────────────────────────────── - -export const ScrollVertical: Story = { - name: 'Scroll: Vertical', - decorators: [moduleMetadata({ imports: [PDataTableScrollVerticalComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Вертикальная прокрутка с фиксированной высотой контейнера на базе PrimeNG pTable.', - }, - source: { - language: 'ts', - code: `import { Component } from '@angular/core'; -import { TableModule } from 'primeng/table'; - -const BASE_SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7 }, - { id: 6, trackNumber: 'ЦД-00123461', destination: 'Воронеж', status: 'Ожидание', weight: 0.5 }, - { id: 7, trackNumber: 'ЦД-00123462', destination: 'Самара', status: 'В пути', weight: 8.0 }, - { id: 8, trackNumber: 'ЦД-00123463', destination: 'Ростов-на-Дону', status: 'Доставлен', weight: 2.1 }, -]; - -@Component({ - selector: 'app-primeng-table-scroll-vertical', - standalone: true, - imports: [TableModule], - template: \` - - - - Трек-номер - Назначение - Статус - Вес, кг - - - - - {{ shipment.trackNumber }} - {{ shipment.destination }} - {{ shipment.status }} - {{ shipment.weight }} - - - - \`, -}) -export class PDataTableScrollVerticalComponent { - shipments = [...BASE_SHIPMENTS, ...BASE_SHIPMENTS, ...BASE_SHIPMENTS]; -}`, - }, - }, - }, -}; - -// ── ScrollHorizontal ────────────────────────────────────────────────────────── - -export const ScrollHorizontal: Story = { - name: 'Scroll: Horizontal', - decorators: [moduleMetadata({ imports: [PDataTableScrollHorizontalComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Горизонтальная прокрутка при большом количестве столбцов на базе PrimeNG pTable.', - }, - source: { - language: 'ts', - code: `import { Component } from '@angular/core'; -import { TableModule } from 'primeng/table'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', sender: 'Иванов И.И.', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200, dimensions: '30×20×15 см' }, - { id: 2, trackNumber: 'ЦД-00123457', sender: 'Петров П.П.', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450, dimensions: '10×10×10 см' }, - { id: 3, trackNumber: 'ЦД-00123458', sender: 'Сидоров С.С.', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100, dimensions: '50×40×30 см' }, - { id: 4, trackNumber: 'ЦД-00123459', sender: 'Козлов К.К.', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750, dimensions: '20×15×10 см' }, - { id: 5, trackNumber: 'ЦД-00123460', sender: 'Новиков Н.Н.', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800, dimensions: '40×30×20 см' }, -]; - -@Component({ - selector: 'app-primeng-table-scroll-horizontal', - standalone: true, - imports: [TableModule], - template: \` - - - - - Трек-номер - - - Отправитель - - - Назначение - - - Статус - - - Вес, кг - - - Стоимость, ₽ - - Габариты - - - - - {{ shipment.trackNumber }} - {{ shipment.sender }} - {{ shipment.destination }} - {{ shipment.status }} - {{ shipment.weight }} - {{ shipment.cost }} - {{ shipment.dimensions }} - - - - \`, -}) -export class PDataTableScrollHorizontalComponent { - shipments = SHIPMENTS; -}`, - }, - }, - }, -}; - -// ── CustomBody ──────────────────────────────────────────────────────────────── - -export const CustomBody: Story = { - name: 'Custom Templates', - decorators: [moduleMetadata({ imports: [PDataTableCustomBodyComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Кастомные шаблоны для заголовка и тела таблицы на базе PrimeNG pTable.', - }, - source: { - language: 'ts', - code: `import { Component } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { TableModule } from 'primeng/table'; -import { TagModule } from 'primeng/tag'; - -const SHIPMENTS = [ - { id: 1, trackNumber: 'ЦД-00123456', destination: 'Москва', status: 'В пути', weight: 2.5, cost: 1200 }, - { id: 2, trackNumber: 'ЦД-00123457', destination: 'Новосибирск', status: 'Доставлен', weight: 0.8, cost: 450 }, - { id: 3, trackNumber: 'ЦД-00123458', destination: 'Екатеринбург', status: 'Задержан', weight: 5.2, cost: 2100 }, - { id: 4, trackNumber: 'ЦД-00123459', destination: 'Казань', status: 'В пути', weight: 1.3, cost: 750 }, - { id: 5, trackNumber: 'ЦД-00123460', destination: 'Краснодар', status: 'Доставлен', weight: 3.7, cost: 1800 }, -]; - -@Component({ - selector: 'app-primeng-table-custom-body', - standalone: true, - imports: [CommonModule, TableModule, TagModule], - template: \` - - - - Трек-номер - Назначение - Статус - Вес, кг - Стоимость, ₽ - - - - - {{ shipment.trackNumber }} - {{ shipment.destination }} - - - - {{ shipment.weight }} кг - {{ shipment.cost | currency:'RUB':'symbol':'1.0-0':'ru' }} - - - - Нет данных для отображения - - - \`, -}) -export class PDataTableCustomBodyComponent { - shipments = SHIPMENTS; - - getSeverity(status: string): 'success' | 'warn' | 'danger' | 'info' | 'secondary' | undefined { - switch (status) { - case 'Доставлен': return 'success'; - case 'В пути': return 'info'; - case 'Задержан': return 'danger'; - case 'Ожидание': return 'warn'; - default: return 'secondary'; - } - } -}`, - }, - }, - }, -}; - -// ── Lazy loading ────────────────────────────────────────────────────────────── - -export const LazyLoading: Story = { - name: 'Lazy Loading', - decorators: [moduleMetadata({ imports: [PDataTableLazyComponent] })], - render: () => ({ template: `` }), - parameters: { - docs: { - description: { - story: 'Lazy Loading + Virtual Scroll для работы с большими наборами данных. Данные подгружаются порциями при прокрутке таблицы. Используйте `[lazy]="true"`, `[virtualScroll]="true"`, `[virtualScrollItemSize]`, `[totalRecords]` и `(onLazyLoad)` для управления загрузкой данных с сервера.', - }, - source: { - language: 'ts', - code: `import { Component, OnInit } from '@angular/core'; -import { TableModule } from 'primeng/table'; - -const ALL_SHIPMENTS = Array.from({ length: 500 }, (_, i) => ({ - id: i + 1, - trackNumber: \`ЦД-\${String(i + 100000).padStart(8, '0')}\`, - destination: ['Москва', 'Новосибирск', 'Екатеринбург', 'Казань', 'Краснодар', 'Санкт-Петербург', 'Воронеж', 'Самара', 'Ростов-на-Дону', 'Уфа'][i % 10], - status: ['В пути', 'Доставлен', 'Задержан', 'Ожидание'][i % 4], - weight: Number(((i * 0.37 + 0.5) % 10).toFixed(1)), - cost: ((i * 137 + 200) % 5000) + 200, -})); - -const PAGE_SIZE = 50; - -@Component({ - selector: 'app-primeng-table-lazy', - standalone: true, - imports: [TableModule], - template: \` - - - - Трек-номер - Назначение - Статус - Вес, кг - Стоимость, ₽ - - - - - {{ shipment?.trackNumber }} - {{ shipment?.destination }} - {{ shipment?.status }} - {{ shipment?.weight }} - {{ shipment?.cost }} - - - - - Загрузка… - - - - \`, -}) -export class PDataTableLazyComponent implements OnInit { - readonly PAGE_SIZE = PAGE_SIZE; - - shipments: any[] = Array.from({ length: ALL_SHIPMENTS.length }); - totalRecords = ALL_SHIPMENTS.length; - loading = false; - - ngOnInit(): void { - // shipments pre-filled with placeholders so virtual scroll knows total size - } - - onLazyLoad(event: any): void { - this.loading = true; - const start = event.first ?? 0; - const end = start + (event.rows ?? PAGE_SIZE); - - // Simulate async server request - setTimeout(() => { - const page = ALL_SHIPMENTS.slice(start, end); - const updated = [...this.shipments]; - for (let i = 0; i < page.length; i++) { - updated[start + i] = page[i]; - } - this.shipments = updated; - this.loading = false; - }, 300); - } -}`, - }, - }, - }, +export { + Default, + StripedRows, + Selectable, + GridLines, + Pagination, + SelectionRadio, + SelectionCheckbox, + ScrollVertical, + ScrollHorizontal, + CustomBody, + LazyLoading, };