From 7604429b428b8678abbd7b0ce7133761ecb0cb26 Mon Sep 17 00:00:00 2001 From: Sergei Klimenko Date: Wed, 24 Jun 2020 12:54:36 +0300 Subject: [PATCH 01/12] feat: add file-list component --- .../ui/file-list/__specs__/file-list.spec.ts | 105 ++++++++++++++++++ .../file-list-story-basic.component.html | 7 ++ .../file-list-story-basic.component.ts | 39 +++++++ .../file-list-story-basic.module.ts | 13 +++ .../file-list-story-basic.source.ts | 52 +++++++++ .../file-list-story-basic/index.ts | 3 + .../file-list-story-locale.component.html | 1 + .../file-list-story-locale.component.ts | 64 +++++++++++ .../file-list-story-locale.module.ts | 15 +++ .../file-list-story-locale.source.ts | 11 ++ .../file-list-story-locale/index.ts | 3 + .../__stories__/file-list.stories.mdx | 86 ++++++++++++++ .../src/ui/file-list/file-list.component.html | 41 +++++++ .../file-list/file-list.component.locale.ts | 13 +++ .../src/ui/file-list/file-list.component.scss | 61 ++++++++++ .../src/ui/file-list/file-list.component.ts | 94 ++++++++++++++++ .../src/ui/file-list/file-list.module.ts | 13 +++ .../src/ui/file-list/file-list.types.ts | 15 +++ .../ui/file-list/fixtures/files.fixture.ts | 36 ++++++ projects/elonkit/src/ui/file-list/index.ts | 1 + .../elonkit/src/ui/file-list/ng-package.json | 5 + .../elonkit/src/ui/file-list/public-api.ts | 3 + .../elonkit/storybook/assets/icons/doc.svg | 4 + .../storybook/assets/icons/doc_download.svg | 5 + 24 files changed, 690 insertions(+) create mode 100644 projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.html create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.module.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.source.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/index.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.html create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.source.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/index.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx create mode 100644 projects/elonkit/src/ui/file-list/file-list.component.html create mode 100644 projects/elonkit/src/ui/file-list/file-list.component.locale.ts create mode 100644 projects/elonkit/src/ui/file-list/file-list.component.scss create mode 100644 projects/elonkit/src/ui/file-list/file-list.component.ts create mode 100644 projects/elonkit/src/ui/file-list/file-list.module.ts create mode 100644 projects/elonkit/src/ui/file-list/file-list.types.ts create mode 100644 projects/elonkit/src/ui/file-list/fixtures/files.fixture.ts create mode 100644 projects/elonkit/src/ui/file-list/index.ts create mode 100644 projects/elonkit/src/ui/file-list/ng-package.json create mode 100644 projects/elonkit/src/ui/file-list/public-api.ts create mode 100644 projects/elonkit/storybook/assets/icons/doc.svg create mode 100644 projects/elonkit/storybook/assets/icons/doc_download.svg diff --git a/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts b/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts new file mode 100644 index 00000000..6382b5c5 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts @@ -0,0 +1,105 @@ +import { render } from '@testing-library/angular'; +import { MatIconTestingModule } from '@angular/material/icon/testing'; + +import { ESFileListModule } from '../file-list.module'; +import { ESFileListComponent } from '../file-list.component'; +import { filesFixture } from '../fixtures/files.fixture'; +import { ESFileListLocale, ESFileListLocaleRU } from '../file-list.component.locale'; + +describe('File List', () => { + it('Should render all files', async () => { + const component = await render(ESFileListComponent, { + componentProperties: { + files: filesFixture + }, + imports: [ESFileListModule, MatIconTestingModule], + excludeComponentDeclaration: true + }); + expect(component.container.querySelectorAll('.file-list__file')).toHaveLength( + filesFixture.length + ); + }); + + it('Should render remove button on canRemove input', async () => { + const component = await render(ESFileListComponent, { + componentProperties: { + files: filesFixture, + canRemove: true + }, + imports: [ESFileListModule, MatIconTestingModule], + excludeComponentDeclaration: true + }); + expect(component.container.querySelector('.file-list__remove')).toBeInTheDocument(); + }); + + it('Should remove file on remove button click', async () => { + const onRemove = jest.fn(); + const component = await render(ESFileListComponent, { + componentProperties: { + files: filesFixture, + canRemove: true, + remove: { + emit: onRemove + } as any + }, + imports: [ESFileListModule, MatIconTestingModule], + excludeComponentDeclaration: true + }); + const removeButton = component.container.querySelector('.file-list__remove'); + component.click(removeButton); + expect(onRemove).toHaveBeenCalled(); + }); + + it('Should render download icon on canDownload input', async () => { + const component = await render(ESFileListComponent, { + componentProperties: { + files: filesFixture, + canDownload: true + }, + imports: [ESFileListModule, MatIconTestingModule], + excludeComponentDeclaration: true + }); + expect(component.container.querySelector('.file-list__icon_download')).toBeInTheDocument(); + }); + + it('Should download file on download icon click', async () => { + const component = await render(ESFileListComponent, { + componentProperties: { + files: filesFixture, + canDownload: true + }, + imports: [ESFileListModule, MatIconTestingModule], + excludeComponentDeclaration: true + }); + const componentInstance = component.fixture.componentInstance; + spyOn(componentInstance, 'downloadFile').and.returnValue(true); + component.click(component.container.querySelector('.file-list__icon_download')); + expect(componentInstance.downloadFile).toHaveBeenCalled(); + }); + + it('Should not render image files on hideImages input', async () => { + const component = await render(ESFileListComponent, { + componentProperties: { + files: filesFixture, + hideImages: true + }, + imports: [ESFileListModule, MatIconTestingModule], + excludeComponentDeclaration: true + }); + expect(component.container.querySelectorAll('.file-list__file')).toHaveLength(1); + }); + + it('Should change locale', async () => { + const component = await render(ESFileListComponent, { + componentProperties: { + files: filesFixture + }, + imports: [ESFileListModule, MatIconTestingModule], + providers: [{ provide: ESFileListLocale, useClass: ESFileListLocaleRU }], + excludeComponentDeclaration: true + }); + expect( + component.container.querySelector('.file-list__subtitle-size').textContent.includes('КБ') + ).toBeTruthy(); + }); +}); diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.html b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.html new file mode 100644 index 00000000..04225c3e --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.html @@ -0,0 +1,7 @@ + diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.ts new file mode 100644 index 00000000..c870f6fb --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.ts @@ -0,0 +1,39 @@ +import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; +import { MatIconRegistry } from '@angular/material/icon'; +import { DomSanitizer } from '@angular/platform-browser'; + +import { ESFileListFile } from '../../file-list.types'; +import { filesFixture } from '../../fixtures/files.fixture'; + +@Component({ + selector: 'es-file-list-basic', + templateUrl: './file-list-story-basic.component.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class FileListStoryBasicComponent { + @Input() + public canRemove: boolean; + @Input() + public canDownload: boolean; + @Input() + public hideImages: boolean; + + public files: ESFileListFile[] = filesFixture; + + private icons = [ + { + name: 'doc', + url: '/icons/doc.svg' + }, + { + name: 'doc_download', + url: '/icons/doc_download.svg' + } + ]; + + constructor(private matIconRegistry: MatIconRegistry, private sanitizer: DomSanitizer) { + this.icons.forEach(icon => { + matIconRegistry.addSvgIcon(icon.name, sanitizer.bypassSecurityTrustResourceUrl(icon.url)); + }); + } +} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.module.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.module.ts new file mode 100644 index 00000000..df8a95e8 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; + +import { FileListStoryBasicComponent } from './file-list-story-basic.component'; +import { ESFileListModule } from '../../file-list.module'; + +@NgModule({ + declarations: [FileListStoryBasicComponent], + imports: [CommonModule, HttpClientModule, ESFileListModule], + exports: [FileListStoryBasicComponent] +}) +export class FileListStoryBasicModule {} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.source.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.source.ts new file mode 100644 index 00000000..3830956c --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.source.ts @@ -0,0 +1,52 @@ +export const FILE_LIST_STORY_BASIC_SOURCE = { + ts: ` + @Component({ + ... + }) + export class AppComponent { + public files: ESFileListFile[] = [ + { + id: 1, + type: 'image', + file: 'https://dummyimage.com/400x400/405ed6/fff.jpg&text=ES', + name: 'FileName1.jpg', + size: 45678, + content: null + }, + { + id: 2, + type: 'image', + file: 'https://dummyimage.com/400x400/228a0f/fff.jpg&text=ES', + name: 'FileName2.jpg', + size: 456789, + content: null + }, + { + id: 3, + type: 'application/pdf', + file: 'https://dummyimage.com/400x400/d6761c/fff.jpg&text=ES', + name: 'FileName3.pdf', + size: 4567, + content: null + }, + { + id: 4, + type: 'image', + file: 'https://dummyimage.com/400x400/2dbdb8/fff.jpg&text=ES', + name: 'FileName4.jpg', + size: 456, + content: null + } + ]; + } + `, + html: ` + + ` +}; diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/index.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/index.ts new file mode 100644 index 00000000..95ffa3a3 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/index.ts @@ -0,0 +1,3 @@ +export { FileListStoryBasicComponent } from './file-list-story-basic.component'; +export { FileListStoryBasicModule } from './file-list-story-basic.module'; +export { FILE_LIST_STORY_BASIC_SOURCE } from './file-list-story-basic.source'; diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.html b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.html new file mode 100644 index 00000000..8cd20511 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.html @@ -0,0 +1 @@ + diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.ts new file mode 100644 index 00000000..48be8172 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.ts @@ -0,0 +1,64 @@ +import { Component, ChangeDetectionStrategy } from '@angular/core'; +import { MatIconRegistry } from '@angular/material/icon'; +import { DomSanitizer } from '@angular/platform-browser'; + +import { ESFileListFile } from '../../file-list.types'; + +@Component({ + selector: 'es-file-list-locale', + templateUrl: './file-list-story-locale.component.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class FileListStoryLocaleComponent { + public files: ESFileListFile[] = [ + { + id: 1, + type: 'image', + file: 'https://dummyimage.com/400x400/405ed6/fff.jpg&text=ES', + name: 'FileName1.jpg', + size: 45678, + content: null + }, + { + id: 2, + type: 'image', + file: 'https://dummyimage.com/400x400/228a0f/fff.jpg&text=ES', + name: 'FileName2.jpg', + size: 456789, + content: null + }, + { + id: 3, + type: 'application/pdf', + file: 'https://dummyimage.com/400x400/d6761c/fff.jpg&text=ES', + name: 'FileName3.pdf', + size: 4567, + content: null + }, + { + id: 4, + type: 'image', + file: 'https://dummyimage.com/400x400/2dbdb8/fff.jpg&text=ES', + name: 'FileName4.jpg', + size: 456, + content: null + } + ]; + + private icons = [ + { + name: 'doc', + url: '/icons/doc.svg' + }, + { + name: 'doc_download', + url: '/icons/doc_download.svg' + } + ]; + + constructor(private matIconRegistry: MatIconRegistry, private sanitizer: DomSanitizer) { + this.icons.forEach(icon => { + matIconRegistry.addSvgIcon(icon.name, sanitizer.bypassSecurityTrustResourceUrl(icon.url)); + }); + } +} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts new file mode 100644 index 00000000..29f19989 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; + +import { FileListStoryLocaleComponent } from './file-list-story-locale.component'; +import { ESFileListModule } from '../../file-list.module'; +import { ESFileListLocale, ESFileListLocaleRU } from '../../file-list.component.locale'; + +@NgModule({ + declarations: [FileListStoryLocaleComponent], + imports: [CommonModule, HttpClientModule, ESFileListModule], + exports: [FileListStoryLocaleComponent], + providers: [{ provide: ESFileListLocale, useClass: ESFileListLocaleRU }] +}) +export class FileListStoryLocaleModule {} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.source.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.source.ts new file mode 100644 index 00000000..c30298f2 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.source.ts @@ -0,0 +1,11 @@ +export const FILE_LIST_STORY_LOCALE_SOURCE = { + ts: ` + import { ESFileListLocale, ESFileListLocaleRU } from '@elonsoft/elonkit/ui/file-list'; + + @NgModule({ + ... + providers: [{ provide: ESFileListLocale, useClass: ESFileListLocaleRU }] + }) + export class AppModule {} + ` +}; diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/index.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/index.ts new file mode 100644 index 00000000..269306dd --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/index.ts @@ -0,0 +1,3 @@ +export { FileListStoryLocaleComponent } from './file-list-story-locale.component'; +export { FileListStoryLocaleModule } from './file-list-story-locale.module'; +export { FILE_LIST_STORY_LOCALE_SOURCE } from './file-list-story-locale.source'; diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx b/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx new file mode 100644 index 00000000..a24cad8c --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx @@ -0,0 +1,86 @@ +import { Meta, Story, Props } from '@storybook/addon-docs/blocks'; +import { Preview } from '~storybook/components'; + +import { withA11y } from '@storybook/addon-a11y'; +import { action } from '@storybook/addon-actions'; +import { withKnobs, boolean } from '@storybook/addon-knobs'; + +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; + +import { ESFileListComponent } from '..'; + +import { + FileListStoryBasicComponent, + FileListStoryBasicModule, + FILE_LIST_STORY_BASIC_SOURCE +} from './file-list-story-basic'; + +import { + FileListStoryLocaleComponent, + FileListStoryLocaleModule, + FILE_LIST_STORY_LOCALE_SOURCE +} from './file-list-story-locale'; + + + +# File List + +This component displays a list of files. + +## Demos + + + + {{ + component: FileListStoryBasicComponent, + moduleMetadata: { + imports: [BrowserAnimationsModule, FileListStoryBasicModule] + }, + props: { + canRemove: boolean('canRemove', false), + canDownload: boolean('canDownload', false), + hideImages: boolean('hideImages', false), + onRemove: action('onRemove') + } + }} + + + +We can override default locale which is used for file size units. + + + + {{ + component: FileListStoryLocaleComponent, + moduleMetadata: { + imports: [BrowserAnimationsModule, FileListStoryLocaleModule] + } + }} + + + +## API + + + +## Interfaces + +```ts +interface ESFileListFile { + id?: number; + deleted?: boolean; + type?: string; + base64?: string; + file?: string; + name: string; + size: number; + content: File; +} +``` + +```ts +interface ESFileListRemoveAction { + file: IESFileListFile; + index: number; +} +``` diff --git a/projects/elonkit/src/ui/file-list/file-list.component.html b/projects/elonkit/src/ui/file-list/file-list.component.html new file mode 100644 index 00000000..23c51e80 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/file-list.component.html @@ -0,0 +1,41 @@ +
+ + +
+
+ + +
+
+
+
{{ file.name }}
+ +
+
+
{{ getFileSize(file) }}
+ +
+
+ {{ file.updatedAt | date: 'dd MMM' | lowercase }} at + {{ file.updatedAt | date: 'HH:mm:ss' }} +
+
+
+
+
+
+
+
diff --git a/projects/elonkit/src/ui/file-list/file-list.component.locale.ts b/projects/elonkit/src/ui/file-list/file-list.component.locale.ts new file mode 100644 index 00000000..ab052baf --- /dev/null +++ b/projects/elonkit/src/ui/file-list/file-list.component.locale.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ providedIn: 'root' }) +export class ESFileListLocale { + labelKB = 'KB'; + labelMB = 'MB'; +} + +@Injectable() +export class ESFileListLocaleRU extends ESFileListLocale { + labelKB = 'КБ'; + labelMB = 'МБ'; +} diff --git a/projects/elonkit/src/ui/file-list/file-list.component.scss b/projects/elonkit/src/ui/file-list/file-list.component.scss new file mode 100644 index 00000000..70c574d5 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/file-list.component.scss @@ -0,0 +1,61 @@ +.file-list { + margin-top: 24px; + + &__file { + display: flex; + + &:not(:last-child) { + margin-bottom: 16px; + } + } + + &__icon { + &.mat-icon { + height: 40px; + margin-right: 12px; + width: 32px; + } + + &_download.mat-icon { + cursor: pointer; + } + } + + &__title { + display: flex; + } + + &__remove.mat-icon-button { + $size: 20px; + height: $size; + line-height: $size; + width: $size; + + mat-icon { + color: rgba(0, 0, 0, 0.24); + font-size: $size; + height: $size; + line-height: $size; + width: $size; + } + } + + &__name { + line-height: 20px; + margin-bottom: 2px; + margin-right: 8px; + } + + &__subtitle { + align-items: center; + color: rgba(0, 0, 0, 0.38); + display: flex; + font-size: 12px; + line-height: 16px; + + &-point { + font-size: 12px; + margin: 0 8px; + } + } +} diff --git a/projects/elonkit/src/ui/file-list/file-list.component.ts b/projects/elonkit/src/ui/file-list/file-list.component.ts new file mode 100644 index 00000000..97dad08e --- /dev/null +++ b/projects/elonkit/src/ui/file-list/file-list.component.ts @@ -0,0 +1,94 @@ +import { + Component, + Input, + Output, + EventEmitter, + ChangeDetectionStrategy, + ViewEncapsulation +} from '@angular/core'; + +import { ESFileListLocale } from './file-list.component.locale'; +import { ESFileListFile, ESFileListRemoveAction } from './file-list.types'; + +@Component({ + selector: 'es-file-list', + templateUrl: './file-list.component.html', + styleUrls: ['./file-list.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None +}) +export class ESFileListComponent { + /** + * Array of file types to be considered an image. + */ + @Input() + public imageTypes: string[] = ['image/png', 'image/jpg', 'image/jpeg', 'image']; + + /** + * Hide image files from the list. + */ + @Input() + public hideImages: boolean; + + /** + * Can remove files from the list. + */ + @Input() + public canRemove: boolean; + + /** + * Can download files from the list. + */ + @Input() + public canDownload: boolean; + + /** + * Array of files to display. + */ + @Input() + public files: ESFileListFile[]; + + /** + * Object with removed file and its index is emitted. + */ + @Output() + public remove: EventEmitter = new EventEmitter(); + + constructor(private locale: ESFileListLocale) {} + + /** + * @internal + * @ignore + */ + public getFileSize(file: ESFileListFile): string { + const { labelKB, labelMB } = this.locale; + const sizeKB = file.size / 1024; + const sizeMB = file.size / 1024 / 1024; + return sizeKB < 1024 ? `${sizeKB.toFixed(1)} ${labelKB}` : `${sizeMB.toFixed(1)} ${labelMB}`; + } + + /** + * @internal + * @ignore + */ + public removeFile(file: ESFileListRemoveAction): void { + this.remove.emit(file); + } + + /** + * @internal + * @ignore + */ + public downloadFile(file: ESFileListFile): void { + this.save(file.file, file.name); + } + + private save(file: Blob | string, name?: string): void { + const url = typeof file === 'string' ? file : URL.createObjectURL(file); + const downloadLink = document.createElement('a'); + downloadLink.setAttribute('href', url); + downloadLink.setAttribute('target', '_self'); + downloadLink.setAttribute('download', name ? name : ''); + downloadLink.click(); + } +} diff --git a/projects/elonkit/src/ui/file-list/file-list.module.ts b/projects/elonkit/src/ui/file-list/file-list.module.ts new file mode 100644 index 00000000..7edba140 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/file-list.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; + +import { ESFileListComponent } from './file-list.component'; + +@NgModule({ + declarations: [ESFileListComponent], + imports: [CommonModule, MatButtonModule, MatIconModule], + exports: [ESFileListComponent] +}) +export class ESFileListModule {} diff --git a/projects/elonkit/src/ui/file-list/file-list.types.ts b/projects/elonkit/src/ui/file-list/file-list.types.ts new file mode 100644 index 00000000..aadcc48c --- /dev/null +++ b/projects/elonkit/src/ui/file-list/file-list.types.ts @@ -0,0 +1,15 @@ +export interface ESFileListFile { + id?: number; + deleted?: boolean; + type?: string; + base64?: string; + file?: string; + name: string; + size: number; + content: File; +} + +export interface ESFileListRemoveAction { + file: ESFileListFile; + index: number; +} diff --git a/projects/elonkit/src/ui/file-list/fixtures/files.fixture.ts b/projects/elonkit/src/ui/file-list/fixtures/files.fixture.ts new file mode 100644 index 00000000..5878b04d --- /dev/null +++ b/projects/elonkit/src/ui/file-list/fixtures/files.fixture.ts @@ -0,0 +1,36 @@ +import { ESFileListFile } from '../file-list.types'; + +export const filesFixture: ESFileListFile[] = [ + { + id: 1, + type: 'image', + file: 'https://dummyimage.com/400x400/405ed6/fff.jpg&text=ES', + name: 'FileName1.jpg', + size: 45678, + content: null + }, + { + id: 2, + type: 'image', + file: 'https://dummyimage.com/400x400/228a0f/fff.jpg&text=ES', + name: 'FileName2.jpg', + size: 456789, + content: null + }, + { + id: 3, + type: 'application/pdf', + file: 'https://dummyimage.com/400x400/d6761c/fff.jpg&text=ES', + name: 'FileName3.pdf', + size: 4567, + content: null + }, + { + id: 4, + type: 'image', + file: 'https://dummyimage.com/400x400/2dbdb8/fff.jpg&text=ES', + name: 'FileName4.jpg', + size: 456, + content: null + } +]; diff --git a/projects/elonkit/src/ui/file-list/index.ts b/projects/elonkit/src/ui/file-list/index.ts new file mode 100644 index 00000000..7e1a213e --- /dev/null +++ b/projects/elonkit/src/ui/file-list/index.ts @@ -0,0 +1 @@ +export * from './public-api'; diff --git a/projects/elonkit/src/ui/file-list/ng-package.json b/projects/elonkit/src/ui/file-list/ng-package.json new file mode 100644 index 00000000..789c95e4 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/ng-package.json @@ -0,0 +1,5 @@ +{ + "lib": { + "entryFile": "public-api.ts" + } +} diff --git a/projects/elonkit/src/ui/file-list/public-api.ts b/projects/elonkit/src/ui/file-list/public-api.ts new file mode 100644 index 00000000..16c6fa03 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/public-api.ts @@ -0,0 +1,3 @@ +export * from './file-list.module'; +export * from './file-list.component'; +export * from './file-list.component.locale'; diff --git a/projects/elonkit/storybook/assets/icons/doc.svg b/projects/elonkit/storybook/assets/icons/doc.svg new file mode 100644 index 00000000..91b47100 --- /dev/null +++ b/projects/elonkit/storybook/assets/icons/doc.svg @@ -0,0 +1,4 @@ + + + + diff --git a/projects/elonkit/storybook/assets/icons/doc_download.svg b/projects/elonkit/storybook/assets/icons/doc_download.svg new file mode 100644 index 00000000..07c144a1 --- /dev/null +++ b/projects/elonkit/storybook/assets/icons/doc_download.svg @@ -0,0 +1,5 @@ + + + + + From c139f16b0daf570722e1ecaf3ce29661f012eec1 Mon Sep 17 00:00:00 2001 From: Sergei Klimenko Date: Fri, 3 Jul 2020 18:07:46 +0300 Subject: [PATCH 02/12] refactor: refactor according to suggesions in MR discussion --- .../ui/file-list/__specs__/file-list.spec.ts | 20 ++++++++--- .../file-list-story-basic.component.html | 8 +++-- .../file-list-story-basic.source.ts | 8 +++-- .../__stories__/file-list.stories.mdx | 9 +++++ .../src/ui/file-list/file-list.component.html | 10 +++--- .../src/ui/file-list/file-list.component.ts | 35 ++++++++----------- .../src/ui/file-list/file-list.types.ts | 7 ++++ .../elonkit/src/ui/file-list/public-api.ts | 7 ++-- .../elonkit/storybook/assets/icons/doc.svg | 5 +-- .../storybook/assets/icons/doc_download.svg | 6 +--- 10 files changed, 68 insertions(+), 47 deletions(-) diff --git a/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts b/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts index 6382b5c5..df237d67 100644 --- a/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts +++ b/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts @@ -24,7 +24,9 @@ describe('File List', () => { const component = await render(ESFileListComponent, { componentProperties: { files: filesFixture, - canRemove: true + options: { + canRemove: true + } }, imports: [ESFileListModule, MatIconTestingModule], excludeComponentDeclaration: true @@ -37,7 +39,9 @@ describe('File List', () => { const component = await render(ESFileListComponent, { componentProperties: { files: filesFixture, - canRemove: true, + options: { + canRemove: true + }, remove: { emit: onRemove } as any @@ -54,7 +58,9 @@ describe('File List', () => { const component = await render(ESFileListComponent, { componentProperties: { files: filesFixture, - canDownload: true + options: { + canDownload: true + } }, imports: [ESFileListModule, MatIconTestingModule], excludeComponentDeclaration: true @@ -66,7 +72,9 @@ describe('File List', () => { const component = await render(ESFileListComponent, { componentProperties: { files: filesFixture, - canDownload: true + options: { + canDownload: true + } }, imports: [ESFileListModule, MatIconTestingModule], excludeComponentDeclaration: true @@ -81,7 +89,9 @@ describe('File List', () => { const component = await render(ESFileListComponent, { componentProperties: { files: filesFixture, - hideImages: true + options: { + hideImages: true + } }, imports: [ESFileListModule, MatIconTestingModule], excludeComponentDeclaration: true diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.html b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.html index 04225c3e..44a97f7f 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.html +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.html @@ -1,7 +1,9 @@ diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.source.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.source.ts index 3830956c..73859db6 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.source.ts +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.source.ts @@ -42,9 +42,11 @@ export const FILE_LIST_STORY_BASIC_SOURCE = { `, html: ` diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx b/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx index a24cad8c..482d90e1 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx @@ -84,3 +84,12 @@ interface ESFileListRemoveAction { index: number; } ``` + +```ts +interface ESFileListOptions { + imageTypes: string[]; + hideImages: boolean; + canRemove: boolean; + canDownload: boolean; +} +``` diff --git a/projects/elonkit/src/ui/file-list/file-list.component.html b/projects/elonkit/src/ui/file-list/file-list.component.html index 23c51e80..21116193 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.html +++ b/projects/elonkit/src/ui/file-list/file-list.component.html @@ -1,11 +1,13 @@
- +
- +
{{ file.name }}
-
-
{{ getFileSize(file) }}
+
+
{{ getFileSize(file) }}
-
-
+
+
{{ file.updatedAt | date: 'dd MMM' | lowercase }} at {{ file.updatedAt | date: 'HH:mm:ss' }}
diff --git a/projects/elonkit/src/ui/file-list/file-list.component.scss b/projects/elonkit/src/ui/file-list/file-list.component.scss index 70c574d5..9e398aa2 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.scss +++ b/projects/elonkit/src/ui/file-list/file-list.component.scss @@ -1,4 +1,4 @@ -.file-list { +.es-file-list { margin-top: 24px; &__file { @@ -11,6 +11,7 @@ &__icon { &.mat-icon { + font-size: 40px; height: 40px; margin-right: 12px; width: 32px; diff --git a/projects/elonkit/src/ui/file-list/file-list.component.ts b/projects/elonkit/src/ui/file-list/file-list.component.ts index 43f74e81..386c6182 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.ts +++ b/projects/elonkit/src/ui/file-list/file-list.component.ts @@ -4,12 +4,19 @@ import { Output, EventEmitter, ChangeDetectionStrategy, - ViewEncapsulation + ViewEncapsulation, + InjectionToken, + Optional, + Inject } from '@angular/core'; import { ESFileListLocale } from './file-list.component.locale'; import { ESFileListFile, ESFileListRemoveAction, ESFileListOptions } from './file-list.types'; +export const ES_FILE_LIST_DEFAULT_OPTIONS = new InjectionToken( + 'ES_FILE_LIST_DEFAULT_OPTIONS' +); + @Component({ selector: 'es-file-list', templateUrl: './file-list.component.html', @@ -18,13 +25,13 @@ import { ESFileListFile, ESFileListRemoveAction, ESFileListOptions } from './fil encapsulation: ViewEncapsulation.None }) export class ESFileListComponent { - private readonly DEFAULT_OPTIONS = { - imageTypes: ['image/png', 'image/jpg', 'image/jpeg', 'image'], + private readonly DEFAULT_OPTIONS: ESFileListOptions = { + imageTypes: 'image/*', hideImages: false, canRemove: false, canDownload: false }; - private _options: ESFileListOptions = this.DEFAULT_OPTIONS; + private _options: ESFileListOptions; /** * Options object to apply to component. @@ -34,7 +41,7 @@ export class ESFileListComponent { return this._options; } public set options(value: ESFileListOptions) { - this._options = { ...this.DEFAULT_OPTIONS, ...value }; + this._options = { ...this.DEFAULT_OPTIONS, ...this.defaultOptions, ...value }; } /** @@ -49,7 +56,20 @@ export class ESFileListComponent { @Output() public remove: EventEmitter = new EventEmitter(); - constructor(private locale: ESFileListLocale) {} + /** + * File is emitted on download. + */ + @Output() + public download: EventEmitter = new EventEmitter(); + + constructor( + private locale: ESFileListLocale, + @Optional() + @Inject(ES_FILE_LIST_DEFAULT_OPTIONS) + private defaultOptions: ESFileListOptions + ) { + this.options = { ...this.DEFAULT_OPTIONS, ...defaultOptions }; + } /** * @internal @@ -75,15 +95,33 @@ export class ESFileListComponent { * @ignore */ public downloadFile(file: ESFileListFile): void { - this.save(file.file, file.name); + this.download.emit(file); } - private save(file: Blob | string, name?: string): void { - const url = typeof file === 'string' ? file : URL.createObjectURL(file); - const downloadLink = document.createElement('a'); - downloadLink.setAttribute('href', url); - downloadLink.setAttribute('target', '_self'); - downloadLink.setAttribute('download', name ? name : ''); - downloadLink.click(); + /** + * @internal + * @ignore + */ + public validateFileType(file: ESFileListFile): boolean { + const types = this.options.imageTypes.split(',').map(v => v.trim()); + + if (types.includes('*')) { + return true; + } + + for (const type of types) { + if (type.charAt(0) === '.' && file.name.toLowerCase().endsWith(type)) { + return true; + } + + if (type.endsWith('/*') && file.type.startsWith(type.replace(/\/.*$/, ''))) { + return true; + } + + if (file.type === type) { + return true; + } + } + return false; } } diff --git a/projects/elonkit/src/ui/file-list/file-list.types.ts b/projects/elonkit/src/ui/file-list/file-list.types.ts index 7dfd4757..eee2a60b 100644 --- a/projects/elonkit/src/ui/file-list/file-list.types.ts +++ b/projects/elonkit/src/ui/file-list/file-list.types.ts @@ -6,7 +6,7 @@ export interface ESFileListFile { file?: string; name: string; size: number; - content: File; + content: File | string; } export interface ESFileListRemoveAction { @@ -15,7 +15,7 @@ export interface ESFileListRemoveAction { } export interface ESFileListOptions { - imageTypes?: string[]; + imageTypes?: string; hideImages?: boolean; canRemove?: boolean; canDownload?: boolean; diff --git a/projects/elonkit/src/ui/file-list/fixtures/files.fixture.ts b/projects/elonkit/src/ui/file-list/fixtures/files.fixture.ts index 5878b04d..f86d0b83 100644 --- a/projects/elonkit/src/ui/file-list/fixtures/files.fixture.ts +++ b/projects/elonkit/src/ui/file-list/fixtures/files.fixture.ts @@ -3,7 +3,7 @@ import { ESFileListFile } from '../file-list.types'; export const filesFixture: ESFileListFile[] = [ { id: 1, - type: 'image', + type: 'image/jpg', file: 'https://dummyimage.com/400x400/405ed6/fff.jpg&text=ES', name: 'FileName1.jpg', size: 45678, @@ -11,7 +11,7 @@ export const filesFixture: ESFileListFile[] = [ }, { id: 2, - type: 'image', + type: 'image/jpg', file: 'https://dummyimage.com/400x400/228a0f/fff.jpg&text=ES', name: 'FileName2.jpg', size: 456789, @@ -27,7 +27,7 @@ export const filesFixture: ESFileListFile[] = [ }, { id: 4, - type: 'image', + type: 'image/jpg', file: 'https://dummyimage.com/400x400/2dbdb8/fff.jpg&text=ES', name: 'FileName4.jpg', size: 456, diff --git a/projects/elonkit/src/ui/file-list/public-api.ts b/projects/elonkit/src/ui/file-list/public-api.ts index aa770151..8cdac27e 100644 --- a/projects/elonkit/src/ui/file-list/public-api.ts +++ b/projects/elonkit/src/ui/file-list/public-api.ts @@ -1,4 +1,4 @@ export { ESFileListModule } from './file-list.module'; -export { ESFileListComponent } from './file-list.component'; +export { ESFileListComponent, ES_FILE_LIST_DEFAULT_OPTIONS } from './file-list.component'; export { ESFileListLocale, ESFileListLocaleRU } from './file-list.component.locale'; export { ESFileListFile, ESFileListOptions, ESFileListRemoveAction } from './file-list.types'; diff --git a/projects/elonkit/storybook/assets/icons/doc.svg b/projects/elonkit/storybook/assets/icons/file.svg similarity index 100% rename from projects/elonkit/storybook/assets/icons/doc.svg rename to projects/elonkit/storybook/assets/icons/file.svg diff --git a/projects/elonkit/storybook/assets/icons/doc_download.svg b/projects/elonkit/storybook/assets/icons/file_download.svg similarity index 100% rename from projects/elonkit/storybook/assets/icons/doc_download.svg rename to projects/elonkit/storybook/assets/icons/file_download.svg From 81e26b6f4a2d901250dbcb5731a1277e70c2981b Mon Sep 17 00:00:00 2001 From: Sergei Klimenko Date: Fri, 17 Jul 2020 14:20:57 +0300 Subject: [PATCH 04/12] refactor(file-list): move file validation to utils, add locale to aria labels --- jest.config.js | 8 ++++- projects/elonkit/src/public-api.ts | 1 + .../src/ui/file-list/file-list.component.html | 6 ++-- .../file-list/file-list.component.locale.ts | 4 +++ .../src/ui/file-list/file-list.component.ts | 34 ++++--------------- .../elonkit/src/utils/validate-file-type.ts | 18 ++++++++++ projects/elonkit/storybook/main.js | 1 + tsconfig.json | 3 +- 8 files changed, 42 insertions(+), 33 deletions(-) create mode 100644 projects/elonkit/src/utils/validate-file-type.ts diff --git a/jest.config.js b/jest.config.js index ac4d43a4..e76b2533 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,3 +1,6 @@ +const { pathsToModuleNameMapper } = require('ts-jest/utils'); +const { compilerOptions } = require('./tsconfig'); + module.exports = { setupFilesAfterEnv: ['./jest.setup.ts'], globals: { @@ -5,5 +8,8 @@ module.exports = { diagnostics: false } }, - testPathIgnorePatterns: ['/dist/'] + testPathIgnorePatterns: ['/dist/'], + roots: [''], + modulePaths: [''], + moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths) }; diff --git a/projects/elonkit/src/public-api.ts b/projects/elonkit/src/public-api.ts index f21e3f10..192d0192 100644 --- a/projects/elonkit/src/public-api.ts +++ b/projects/elonkit/src/public-api.ts @@ -1,5 +1,6 @@ export * from './ui/breadcrumbs'; export * from './ui/counter'; +export * from './ui/file-list'; export * from './ui/inline-form-field'; export * from './ui/paginator'; export * from './ui/timepicker'; diff --git a/projects/elonkit/src/ui/file-list/file-list.component.html b/projects/elonkit/src/ui/file-list/file-list.component.html index b6cbc53b..b8013c9f 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.html +++ b/projects/elonkit/src/ui/file-list/file-list.component.html @@ -1,6 +1,6 @@
- +
@@ -25,7 +25,7 @@ (click)="removeFile({ file: file, index: i })" mat-icon-button class="es-file-list__remove" - aria-label="Remove" + [attr.aria-label]="locale.labelRemove" > close diff --git a/projects/elonkit/src/ui/file-list/file-list.component.locale.ts b/projects/elonkit/src/ui/file-list/file-list.component.locale.ts index ab052baf..1f82cc95 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.locale.ts +++ b/projects/elonkit/src/ui/file-list/file-list.component.locale.ts @@ -2,12 +2,16 @@ import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class ESFileListLocale { + labelDownload = 'Download'; + labelRemove = 'Remove'; labelKB = 'KB'; labelMB = 'MB'; } @Injectable() export class ESFileListLocaleRU extends ESFileListLocale { + labelDownload = 'Скачать'; + labelRemove = 'Удалить'; labelKB = 'КБ'; labelMB = 'МБ'; } diff --git a/projects/elonkit/src/ui/file-list/file-list.component.ts b/projects/elonkit/src/ui/file-list/file-list.component.ts index 386c6182..49d80002 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.ts +++ b/projects/elonkit/src/ui/file-list/file-list.component.ts @@ -10,6 +10,7 @@ import { Inject } from '@angular/core'; +import { validateFileType } from '~utils/validate-file-type'; import { ESFileListLocale } from './file-list.component.locale'; import { ESFileListFile, ESFileListRemoveAction, ESFileListOptions } from './file-list.types'; @@ -62,8 +63,12 @@ export class ESFileListComponent { @Output() public download: EventEmitter = new EventEmitter(); + public fileTypeValid(file: ESFileListFile): boolean { + return validateFileType(file, this.options.imageTypes); + } + constructor( - private locale: ESFileListLocale, + public locale: ESFileListLocale, @Optional() @Inject(ES_FILE_LIST_DEFAULT_OPTIONS) private defaultOptions: ESFileListOptions @@ -97,31 +102,4 @@ export class ESFileListComponent { public downloadFile(file: ESFileListFile): void { this.download.emit(file); } - - /** - * @internal - * @ignore - */ - public validateFileType(file: ESFileListFile): boolean { - const types = this.options.imageTypes.split(',').map(v => v.trim()); - - if (types.includes('*')) { - return true; - } - - for (const type of types) { - if (type.charAt(0) === '.' && file.name.toLowerCase().endsWith(type)) { - return true; - } - - if (type.endsWith('/*') && file.type.startsWith(type.replace(/\/.*$/, ''))) { - return true; - } - - if (file.type === type) { - return true; - } - } - return false; - } } diff --git a/projects/elonkit/src/utils/validate-file-type.ts b/projects/elonkit/src/utils/validate-file-type.ts new file mode 100644 index 00000000..464c5402 --- /dev/null +++ b/projects/elonkit/src/utils/validate-file-type.ts @@ -0,0 +1,18 @@ +export const validateFileType = (file: any, types: string): boolean => { + const typesArr = types.split(',').map(v => v.trim()); + return typesArr.includes('*') || typesMatch(typesArr, file); +}; + +const typesMatch = (types: string[], file: File): boolean => + types.some( + type => + type === file.type || + typeMatchesFileType(type, file.type) || + typeMatchesFilenameExtension(type, file.name) + ); + +const typeMatchesFilenameExtension = (type: string, fileName: string): boolean => + type.charAt(0) === '.' && fileName.toLowerCase().endsWith(type); + +const typeMatchesFileType = (type: string, fileType: string): boolean => + type.endsWith('/*') && fileType.startsWith(type.replace(/\/.*$/, '')); diff --git a/projects/elonkit/storybook/main.js b/projects/elonkit/storybook/main.js index 4b703bd0..3e5ac13e 100644 --- a/projects/elonkit/storybook/main.js +++ b/projects/elonkit/storybook/main.js @@ -18,6 +18,7 @@ module.exports = { ], webpackFinal: async config => { config.resolve.alias['~storybook'] = path.resolve(__dirname); + config.resolve.alias['~utils'] = path.resolve(__dirname, '../src/utils'); return config; } }; diff --git a/tsconfig.json b/tsconfig.json index 17ed2818..21a41c81 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,7 +17,8 @@ "paths": { "elonkit": ["dist/elonkit"], "elonkit/*": ["dist/elonkit/*"], - "~storybook/*": ["projects/elonkit/storybook/*"] + "~storybook/*": ["projects/elonkit/storybook/*"], + "~utils/*": ["projects/elonkit/src/utils/*"] }, "types": ["jest"], "jsx": "react" From 858d77706e6455a201b1d4d99ece639870f886c2 Mon Sep 17 00:00:00 2001 From: Sergei Klimenko Date: Mon, 20 Jul 2020 13:42:34 +0300 Subject: [PATCH 05/12] refactor(file-list): refactor inputs --- .../ui/file-list/__specs__/file-list.spec.ts | 20 ++--- .../file-list-story-basic.component.html | 10 +-- .../file-list-story-basic.source.ts | 10 +-- .../__stories__/file-list.stories.mdx | 11 --- .../src/ui/file-list/file-list.component.html | 12 +-- .../src/ui/file-list/file-list.component.ts | 76 ++++++++++++++----- 6 files changed, 76 insertions(+), 63 deletions(-) diff --git a/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts b/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts index eb9c2f65..ec9f868f 100644 --- a/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts +++ b/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts @@ -22,9 +22,7 @@ describe('File List', () => { const component = await render(ESFileListComponent, { componentProperties: { files: filesFixture, - options: { - canRemove: true - } + canRemove: true }, imports: [ESFileListModule, MatIconTestingModule], excludeComponentDeclaration: true @@ -37,9 +35,7 @@ describe('File List', () => { const component = await render(ESFileListComponent, { componentProperties: { files: filesFixture, - options: { - canRemove: true - }, + canRemove: true, remove: { emit: onRemove } as any @@ -58,9 +54,7 @@ describe('File List', () => { const component = await render(ESFileListComponent, { componentProperties: { files: filesFixture, - options: { - canDownload: true - } + canDownload: true }, imports: [ESFileListModule, MatIconTestingModule], excludeComponentDeclaration: true @@ -73,9 +67,7 @@ describe('File List', () => { const component = await render(ESFileListComponent, { componentProperties: { files: filesFixture, - options: { - canDownload: true - }, + canDownload: true, download: { emit: onDownload } as any @@ -94,9 +86,7 @@ describe('File List', () => { const component = await render(ESFileListComponent, { componentProperties: { files: filesFixture, - options: { - hideImages: true - } + hideImages: true }, imports: [ESFileListModule, MatIconTestingModule], excludeComponentDeclaration: true diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.html b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.html index ed3842cc..b2900f6b 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.html +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.html @@ -1,10 +1,8 @@ - +
+ -
{{ file.name }}
-
{{ getFileSize(file) }}
+
+ {{ getFileSize(file) }} +
-
-
+
+
{{ file.updatedAt | date: 'dd MMM' | lowercase }} at {{ file.updatedAt | date: 'HH:mm:ss' }}
diff --git a/projects/elonkit/src/ui/file-list/file-list.component.scss b/projects/elonkit/src/ui/file-list/file-list.component.scss index 9e398aa2..4156017b 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.scss +++ b/projects/elonkit/src/ui/file-list/file-list.component.scss @@ -2,6 +2,7 @@ margin-top: 24px; &__file { + align-items: center; display: flex; &:not(:last-child) { @@ -9,17 +10,13 @@ } } - &__icon { - &.mat-icon { - font-size: 40px; - height: 40px; - margin-right: 12px; - width: 32px; - } + &__icon-wrapper { + margin-right: 12px; + } - &_download.mat-icon { - cursor: pointer; - } + &__icon { + height: 48px; + width: 36px; } &__title { @@ -27,22 +24,20 @@ } &__remove.mat-icon-button { - $size: 20px; - height: $size; - line-height: $size; - width: $size; - - mat-icon { - color: rgba(0, 0, 0, 0.24); - font-size: $size; - height: $size; - line-height: $size; - width: $size; - } + height: 22px; + line-height: 22px; + width: 22px; + } + + &__remove &__remove-icon.mat-icon { + color: rgba(0, 0, 0, 0.38); + font-size: 20px; + height: 20px; + line-height: 19px; + width: 20px; } &__name { - line-height: 20px; margin-bottom: 2px; margin-right: 8px; } @@ -51,11 +46,8 @@ align-items: center; color: rgba(0, 0, 0, 0.38); display: flex; - font-size: 12px; - line-height: 16px; &-point { - font-size: 12px; margin: 0 8px; } } diff --git a/projects/elonkit/src/ui/file-list/file-list.component.ts b/projects/elonkit/src/ui/file-list/file-list.component.ts index c6d74f6e..8c9d9043 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.ts +++ b/projects/elonkit/src/ui/file-list/file-list.component.ts @@ -76,6 +76,30 @@ export class ESFileListComponent { } private _canDownload: boolean; + /** + * Class applied to file name text. + */ + @Input() + public get fileNameTypography(): string { + return this._fileNameTypography; + } + public set fileNameTypography(value: string) { + this._fileNameTypography = value || this.defaultOptions?.fileNameTypography || 'mat-body-1'; + } + private _fileNameTypography: string; + + /** + * Class applied to file size text. + */ + @Input() + public get fileSizeTypography(): string { + return this._fileSizeTypography; + } + public set fileSizeTypography(value: string) { + this._fileSizeTypography = value || this.defaultOptions?.fileSizeTypography || 'mat-caption'; + } + private _fileSizeTypography: string; + /** * Array of files to display. */ @@ -108,6 +132,8 @@ export class ESFileListComponent { this.hideImages = this.defaultOptions?.hideImages; this.canDownload = this.defaultOptions?.canDownload; this.canRemove = this.defaultOptions?.canRemove; + this.fileNameTypography = this.defaultOptions?.fileNameTypography; + this.fileSizeTypography = this.defaultOptions?.fileSizeTypography; } /** @@ -141,7 +167,24 @@ export class ESFileListComponent { * @internal * @ignore */ - public downloadFile(file: ESFileListFile): void { + public downloadFile(e: MouseEvent, file: ESFileListFile): void { + e.preventDefault(); this.download.emit(file); } + + /** + * @internal + * @ignore + */ + public get src(): string { + return './assets/elonkit/file-list/file.svg'; + } + + /** + * @internal + * @ignore + */ + public get srcDownload(): string { + return './assets/elonkit/file-list/file_download.svg'; + } } diff --git a/projects/elonkit/src/ui/file-list/file-list.types.ts b/projects/elonkit/src/ui/file-list/file-list.types.ts index eee2a60b..9432d160 100644 --- a/projects/elonkit/src/ui/file-list/file-list.types.ts +++ b/projects/elonkit/src/ui/file-list/file-list.types.ts @@ -19,4 +19,6 @@ export interface ESFileListOptions { hideImages?: boolean; canRemove?: boolean; canDownload?: boolean; + fileNameTypography?: string; + fileSizeTypography?: string; } diff --git a/projects/elonkit/storybook/assets/icons/file.svg b/projects/elonkit/storybook/assets/icons/file.svg deleted file mode 100644 index afd4e6ae..00000000 --- a/projects/elonkit/storybook/assets/icons/file.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/projects/elonkit/storybook/assets/icons/file_download.svg b/projects/elonkit/storybook/assets/icons/file_download.svg deleted file mode 100644 index dee3b56a..00000000 --- a/projects/elonkit/storybook/assets/icons/file_download.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 8a4d7823701ecf9aefaf0f1430d815fecf435721 Mon Sep 17 00:00:00 2001 From: Sergei Klimenko Date: Fri, 24 Jul 2020 13:05:38 +0300 Subject: [PATCH 07/12] refactor(file-list): add typography story --- .../file-list-story-basic.component.ts | 19 ----------- .../file-list-story-basic.module.ts | 3 +- .../file-list-story-locale.component.ts | 19 ----------- .../file-list-story-locale.module.ts | 3 +- .../file-list-story-typography.component.html | 5 +++ .../file-list-story-typography.component.scss | 15 +++++++++ .../file-list-story-typography.component.ts | 15 +++++++++ .../file-list-story-typography.module.ts | 12 +++++++ .../file-list-story-typography.source.ts | 33 +++++++++++++++++++ .../file-list-story-typography/index.ts | 3 ++ .../__stories__/file-list.stories.mdx | 26 ++++++++++++--- .../src/ui/file-list/file-list.component.scss | 1 - 12 files changed, 107 insertions(+), 47 deletions(-) create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.html create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.scss create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.module.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.source.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/index.ts diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.ts index edf383c8..6ef70549 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.ts +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.component.ts @@ -1,6 +1,4 @@ import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; -import { MatIconRegistry } from '@angular/material/icon'; -import { DomSanitizer } from '@angular/platform-browser'; import { ESFileListFile } from '../../file-list.types'; import { filesFixture } from '../../fixtures/files.fixture'; @@ -21,21 +19,4 @@ export class FileListStoryBasicComponent { public imageTypes: string; public files: ESFileListFile[] = filesFixture; - - private icons = [ - { - name: 'file', - url: '/icons/file.svg' - }, - { - name: 'file_download', - url: '/icons/file_download.svg' - } - ]; - - constructor(private matIconRegistry: MatIconRegistry, private sanitizer: DomSanitizer) { - this.icons.forEach(icon => { - matIconRegistry.addSvgIcon(icon.name, sanitizer.bypassSecurityTrustResourceUrl(icon.url)); - }); - } } diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.module.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.module.ts index df8a95e8..bbf9d3f8 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.module.ts +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-basic/file-list-story-basic.module.ts @@ -1,13 +1,12 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { HttpClientModule } from '@angular/common/http'; import { FileListStoryBasicComponent } from './file-list-story-basic.component'; import { ESFileListModule } from '../../file-list.module'; @NgModule({ declarations: [FileListStoryBasicComponent], - imports: [CommonModule, HttpClientModule, ESFileListModule], + imports: [CommonModule, ESFileListModule], exports: [FileListStoryBasicComponent] }) export class FileListStoryBasicModule {} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.ts index f1339372..2aa3a5cc 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.ts +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.ts @@ -1,6 +1,4 @@ import { Component, ChangeDetectionStrategy } from '@angular/core'; -import { MatIconRegistry } from '@angular/material/icon'; -import { DomSanitizer } from '@angular/platform-browser'; import { ESFileListFile } from '../../file-list.types'; import { filesFixture } from '../../fixtures/files.fixture'; @@ -12,21 +10,4 @@ import { filesFixture } from '../../fixtures/files.fixture'; }) export class FileListStoryLocaleComponent { public files: ESFileListFile[] = filesFixture; - - private icons = [ - { - name: 'file', - url: '/icons/file.svg' - }, - { - name: 'file_download', - url: '/icons/file_download.svg' - } - ]; - - constructor(private matIconRegistry: MatIconRegistry, private sanitizer: DomSanitizer) { - this.icons.forEach(icon => { - matIconRegistry.addSvgIcon(icon.name, sanitizer.bypassSecurityTrustResourceUrl(icon.url)); - }); - } } diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts index 29f19989..c4a62539 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts @@ -1,6 +1,5 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { HttpClientModule } from '@angular/common/http'; import { FileListStoryLocaleComponent } from './file-list-story-locale.component'; import { ESFileListModule } from '../../file-list.module'; @@ -8,7 +7,7 @@ import { ESFileListLocale, ESFileListLocaleRU } from '../../file-list.component. @NgModule({ declarations: [FileListStoryLocaleComponent], - imports: [CommonModule, HttpClientModule, ESFileListModule], + imports: [CommonModule, ESFileListModule], exports: [FileListStoryLocaleComponent], providers: [{ provide: ESFileListLocale, useClass: ESFileListLocaleRU }] }) diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.html b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.html new file mode 100644 index 00000000..7598e8b3 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.html @@ -0,0 +1,5 @@ + diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.scss b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.scss new file mode 100644 index 00000000..53e1952c --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.scss @@ -0,0 +1,15 @@ +.typography { + &-body-1 { + color: rgba(0, 0, 0, 0.88); + font-family: 'Roboto', sans-serif; + font-size: 16px; + line-height: 24px; + } + + &-caption { + color: rgba(0, 0, 0, 0.54); + font-family: 'Roboto', sans-serif; + font-size: 12px; + line-height: 16px; + } +} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.ts new file mode 100644 index 00000000..f46782c8 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.ts @@ -0,0 +1,15 @@ +import { Component, Input, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core'; + +import { ESFileListFile } from '../../file-list.types'; +import { filesFixture } from '../../fixtures/files.fixture'; + +@Component({ + selector: 'es-file-list-typography', + templateUrl: './file-list-story-typography.component.html', + styleUrls: ['./file-list-story-typography.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None +}) +export class FileListStoryTypographyComponent { + public files: ESFileListFile[] = filesFixture; +} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.module.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.module.ts new file mode 100644 index 00000000..bc7f6981 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { FileListStoryTypographyComponent } from './file-list-story-typography.component'; +import { ESFileListModule } from '../../file-list.module'; + +@NgModule({ + declarations: [FileListStoryTypographyComponent], + imports: [CommonModule, ESFileListModule], + exports: [FileListStoryTypographyComponent] +}) +export class FileListStoryTypographyModule {} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.source.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.source.ts new file mode 100644 index 00000000..fba7a500 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.source.ts @@ -0,0 +1,33 @@ +export const FILE_LIST_STORY_TYPOGRAPHY_SOURCE = { + html: ` + + `, + ts: ` + @Component({ + ... + encapsulation: ViewEncapsulation.None + }) + export class AppComponent { + } + `, + scss: ` + .typography { + &-body-1 { + color: rgba(0, 0, 0, 0.88); + font-family: 'Roboto', sans-serif; + font-size: 16px; + line-height: 24px; + } + + &-caption { + color: rgba(0, 0, 0, 0.54); + font-family: 'Roboto', sans-serif; + font-size: 12px; + line-height: 16px; + } + }` +}; diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/index.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/index.ts new file mode 100644 index 00000000..8915c7f0 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/index.ts @@ -0,0 +1,3 @@ +export { FileListStoryTypographyComponent } from './file-list-story-typography.component'; +export { FileListStoryTypographyModule } from './file-list-story-typography.module'; +export { FILE_LIST_STORY_TYPOGRAPHY_SOURCE } from './file-list-story-typography.source'; diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx b/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx index a3e75a8b..10f8edd9 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx @@ -21,17 +21,22 @@ import { FILE_LIST_STORY_LOCALE_SOURCE } from './file-list-story-locale'; +import { + FileListStoryTypographyComponent, + FileListStoryTypographyModule, + FILE_LIST_STORY_TYPOGRAPHY_SOURCE +} from './file-list-story-typography'; + # File List -This component displays a list of files. Requires `file` and `file_download` svg icons to display -an icon next to file name. +This component displays a list of files. ## Demos - + {{ component: FileListStoryBasicComponent, moduleMetadata: { @@ -52,7 +57,7 @@ an icon next to file name. We can override default locale which is used for file size units. - + {{ component: FileListStoryLocaleComponent, moduleMetadata: { @@ -62,6 +67,19 @@ We can override default locale which is used for file size units. +We can use typography inputs in order to change text presentation. + + + + {{ + component: FileListStoryTypographyComponent, + moduleMetadata: { + imports: [BrowserAnimationsModule, FileListStoryTypographyModule] + } + }} + + + ## API diff --git a/projects/elonkit/src/ui/file-list/file-list.component.scss b/projects/elonkit/src/ui/file-list/file-list.component.scss index 4156017b..a96bc450 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.scss +++ b/projects/elonkit/src/ui/file-list/file-list.component.scss @@ -38,7 +38,6 @@ } &__name { - margin-bottom: 2px; margin-right: 8px; } From 0a85a633b497f8f84532d4debbcdf27386735aca Mon Sep 17 00:00:00 2001 From: Sergei Klimenko Date: Fri, 24 Jul 2020 13:14:35 +0300 Subject: [PATCH 08/12] docs(file-list): update ESFileListOptions in file list docs --- .../elonkit/src/ui/file-list/__stories__/file-list.stories.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx b/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx index 10f8edd9..9d815ee2 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx @@ -114,6 +114,8 @@ interface ESFileListOptions { hideImages?: boolean; canRemove?: boolean; canDownload?: boolean; + fileNameTypography?: string; + fileSizeTypography?: string; } ``` From a655cb96afafbcf9255f38696edc82c8cd0c5cd5 Mon Sep 17 00:00:00 2001 From: Sergei Klimenko Date: Mon, 31 Aug 2020 19:20:34 +0300 Subject: [PATCH 09/12] refactor(file-list): change download button, add custom icon story --- .../elonkit/file-list/file_download.svg | 2 +- ...file-list-story-custom-icon.component.html | 1 + .../file-list-story-custom-icon.component.ts | 14 +++++ .../file-list-story-custom-icon.module.ts | 12 +++++ .../file-list-story-custom-icon.source.ts | 4 ++ .../file-list-story-custom-icon/index.ts | 3 ++ .../file-list-story-locale.module.ts | 12 +++-- .../file-list-story-locale.source.ts | 9 +++- .../__stories__/file-list.stories.mdx | 53 ++++++++++++------- .../src/ui/file-list/file-list.component.html | 23 ++++---- .../file-list/file-list.component.locale.ts | 2 + .../src/ui/file-list/file-list.component.scss | 34 +++++++++--- .../src/ui/file-list/file-list.component.ts | 19 +++++-- .../src/ui/file-list/file-list.types.ts | 3 +- .../ui/file-list/fixtures/files.fixture.ts | 15 +++--- .../elonkit/src/ui/file-list/public-api.ts | 6 ++- .../storybook/assets/icons/file-list/file.svg | 1 + 17 files changed, 158 insertions(+), 55 deletions(-) create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.html create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.module.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.source.ts create mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/index.ts create mode 100644 projects/elonkit/storybook/assets/icons/file-list/file.svg diff --git a/projects/elonkit/src/assets/elonkit/file-list/file_download.svg b/projects/elonkit/src/assets/elonkit/file-list/file_download.svg index ef419baa..d9408366 100644 --- a/projects/elonkit/src/assets/elonkit/file-list/file_download.svg +++ b/projects/elonkit/src/assets/elonkit/file-list/file_download.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.html b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.html new file mode 100644 index 00000000..1c770f87 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.html @@ -0,0 +1 @@ + diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.ts new file mode 100644 index 00000000..65aa6048 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.ts @@ -0,0 +1,14 @@ +import { Component, ChangeDetectionStrategy } from '@angular/core'; + +import { ESFileListFile } from '../../file-list.types'; +import { filesFixture } from '../../fixtures/files.fixture'; + +@Component({ + selector: 'es-file-list-custom-icon', + templateUrl: './file-list-story-custom-icon.component.html', + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class FileListStoryCustomIconComponent { + public files: ESFileListFile[] = filesFixture; + public customIcon = '/icons/file-list/file.svg'; +} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.module.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.module.ts new file mode 100644 index 00000000..649724d2 --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { FileListStoryCustomIconComponent } from './file-list-story-custom-icon.component'; +import { ESFileListModule } from '../../file-list.module'; + +@NgModule({ + declarations: [FileListStoryCustomIconComponent], + imports: [CommonModule, ESFileListModule], + exports: [FileListStoryCustomIconComponent] +}) +export class FileListStoryCustomIconModule {} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.source.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.source.ts new file mode 100644 index 00000000..95cae37b --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.source.ts @@ -0,0 +1,4 @@ +export const FILE_LIST_STORY_CUSTOM_ICON_SOURCE = { + html: ` + ` +}; diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/index.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/index.ts new file mode 100644 index 00000000..0abaceec --- /dev/null +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/index.ts @@ -0,0 +1,3 @@ +export { FileListStoryCustomIconComponent } from './file-list-story-custom-icon.component'; +export { FileListStoryCustomIconModule } from './file-list-story-custom-icon.module'; +export { FILE_LIST_STORY_CUSTOM_ICON_SOURCE } from './file-list-story-custom-icon.source'; diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts index c4a62539..01d655ee 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts @@ -1,14 +1,20 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; +import { LOCALE_ID, NgModule } from '@angular/core'; +import { CommonModule, registerLocaleData } from '@angular/common'; +import localeRu from '@angular/common/locales/ru'; import { FileListStoryLocaleComponent } from './file-list-story-locale.component'; import { ESFileListModule } from '../../file-list.module'; import { ESFileListLocale, ESFileListLocaleRU } from '../../file-list.component.locale'; +registerLocaleData(localeRu, 'ru'); + @NgModule({ declarations: [FileListStoryLocaleComponent], imports: [CommonModule, ESFileListModule], exports: [FileListStoryLocaleComponent], - providers: [{ provide: ESFileListLocale, useClass: ESFileListLocaleRU }] + providers: [ + { provide: ESFileListLocale, useClass: ESFileListLocaleRU }, + { provide: LOCALE_ID, useValue: 'ru' } + ] }) export class FileListStoryLocaleModule {} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.source.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.source.ts index c30298f2..46215acd 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.source.ts +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.source.ts @@ -1,10 +1,17 @@ export const FILE_LIST_STORY_LOCALE_SOURCE = { ts: ` + import { LOCALE_ID, NgModule } from '@angular/core'; + import { CommonModule, registerLocaleData } from '@angular/common'; + import localeRu from '@angular/common/locales/ru'; import { ESFileListLocale, ESFileListLocaleRU } from '@elonsoft/elonkit/ui/file-list'; + registerLocaleData(localeRu, 'ru'); @NgModule({ ... - providers: [{ provide: ESFileListLocale, useClass: ESFileListLocaleRU }] + providers: [ + { provide: ESFileListLocale, useClass: ESFileListLocaleRU }, + { provide: LOCALE_ID, useValue: 'ru' } + ] }) export class AppModule {} ` diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx b/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx index 9d815ee2..78f9de8d 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list.stories.mdx @@ -1,11 +1,8 @@ -import { Meta, Story, Props } from '@storybook/addon-docs/blocks'; -import { Preview } from '~storybook/components'; +import { Meta, Story, ArgsTable } from '@storybook/addon-docs/blocks'; +import { Canvas } from '~storybook/components'; -import { withA11y } from '@storybook/addon-a11y'; import { action } from '@storybook/addon-actions'; -import { withKnobs, boolean, text } from '@storybook/addon-knobs'; - -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { boolean, text } from '@storybook/addon-knobs'; import { ESFileListComponent } from '..'; @@ -21,13 +18,19 @@ import { FILE_LIST_STORY_LOCALE_SOURCE } from './file-list-story-locale'; +import { + FileListStoryCustomIconComponent, + FileListStoryCustomIconModule, + FILE_LIST_STORY_CUSTOM_ICON_SOURCE +} from './file-list-story-custom-icon'; + import { FileListStoryTypographyComponent, FileListStoryTypographyModule, FILE_LIST_STORY_TYPOGRAPHY_SOURCE } from './file-list-story-typography'; - + # File List @@ -35,12 +38,12 @@ This component displays a list of files. ## Demos - + {{ component: FileListStoryBasicComponent, moduleMetadata: { - imports: [BrowserAnimationsModule, FileListStoryBasicModule] + imports: [FileListStoryBasicModule] }, props: { canRemove: boolean('canRemove', false), @@ -52,37 +55,50 @@ This component displays a list of files. } }} - + We can override default locale which is used for file size units. - + {{ component: FileListStoryLocaleComponent, moduleMetadata: { - imports: [BrowserAnimationsModule, FileListStoryLocaleModule] + imports: [FileListStoryLocaleModule] + } + }} + + + +We can use custom icon for files. + + + + {{ + component: FileListStoryCustomIconComponent, + moduleMetadata: { + imports: [FileListStoryCustomIconModule] } }} - + We can use typography inputs in order to change text presentation. - + {{ component: FileListStoryTypographyComponent, moduleMetadata: { - imports: [BrowserAnimationsModule, FileListStoryTypographyModule] + imports: [FileListStoryTypographyModule] } }} - + ## API - + ## Interfaces @@ -93,6 +109,7 @@ interface ESFileListFile { type?: string; base64?: string; file?: string; + updatedAt?: string; name: string; size: number; content: File | string; @@ -109,7 +126,7 @@ interface ESFileListRemoveAction { Image types string should contain types separated by a comma, e.g. `image/png,image/jpg,image/jpeg` ```ts -interface ESFileListOptions { +interface ESFileListDefaultOptions { imageTypes?: string; hideImages?: boolean; canRemove?: boolean; diff --git a/projects/elonkit/src/ui/file-list/file-list.component.html b/projects/elonkit/src/ui/file-list/file-list.component.html index c19dc426..212fac94 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.html +++ b/projects/elonkit/src/ui/file-list/file-list.component.html @@ -2,18 +2,19 @@
-
+ - - -
{{ file.name }}
@@ -35,7 +36,7 @@
- {{ file.updatedAt | date: 'dd MMM' | lowercase }} at + {{ file.updatedAt | date: 'd MMM yyyy' | lowercase }} {{ locale.labelAt }} {{ file.updatedAt | date: 'HH:mm:ss' }}
diff --git a/projects/elonkit/src/ui/file-list/file-list.component.locale.ts b/projects/elonkit/src/ui/file-list/file-list.component.locale.ts index 1f82cc95..e8c3be79 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.locale.ts +++ b/projects/elonkit/src/ui/file-list/file-list.component.locale.ts @@ -6,6 +6,7 @@ export class ESFileListLocale { labelRemove = 'Remove'; labelKB = 'KB'; labelMB = 'MB'; + labelAt = 'at'; } @Injectable() @@ -14,4 +15,5 @@ export class ESFileListLocaleRU extends ESFileListLocale { labelRemove = 'Удалить'; labelKB = 'КБ'; labelMB = 'МБ'; + labelAt = 'в'; } diff --git a/projects/elonkit/src/ui/file-list/file-list.component.scss b/projects/elonkit/src/ui/file-list/file-list.component.scss index a96bc450..8a56bb1c 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.scss +++ b/projects/elonkit/src/ui/file-list/file-list.component.scss @@ -11,30 +11,48 @@ } &__icon-wrapper { + display: flex; margin-right: 12px; + position: relative; + } + + &__icon-btn.mat-icon-button { + display: flex; + height: 24px; + justify-content: center; + left: 50%; + line-height: 24px; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + width: 24px; + } + + &__icon-btn.mat-icon-button &__icon { + height: 14px; + width: 14px; } &__icon { - height: 48px; - width: 36px; + height: 100%; + width: 100%; } &__title { + align-items: center; display: flex; + min-height: 24px; } &__remove.mat-icon-button { - height: 22px; + height: 24px; line-height: 22px; - width: 22px; + width: 24px; } &__remove &__remove-icon.mat-icon { color: rgba(0, 0, 0, 0.38); - font-size: 20px; - height: 20px; - line-height: 19px; - width: 20px; + font-size: 24px; } &__name { diff --git a/projects/elonkit/src/ui/file-list/file-list.component.ts b/projects/elonkit/src/ui/file-list/file-list.component.ts index 8c9d9043..c2459b41 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.ts +++ b/projects/elonkit/src/ui/file-list/file-list.component.ts @@ -12,10 +12,14 @@ import { import { validateFileType } from '~utils/validate-file-type'; import { ESFileListLocale } from './file-list.component.locale'; -import { ESFileListFile, ESFileListRemoveAction, ESFileListOptions } from './file-list.types'; +import { + ESFileListFile, + ESFileListRemoveAction, + ESFileListDefaultOptions +} from './file-list.types'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; -export const ES_FILE_LIST_DEFAULT_OPTIONS = new InjectionToken( +export const ES_FILE_LIST_DEFAULT_OPTIONS = new InjectionToken( 'ES_FILE_LIST_DEFAULT_OPTIONS' ); @@ -36,7 +40,7 @@ export class ESFileListComponent { return this._imageTypes; } public set imageTypes(value: string) { - this._imageTypes = value ?? this.defaultOptions?.imageTypes ?? 'image/*'; + this._imageTypes = value || this.defaultOptions?.imageTypes || 'image/*'; } private _imageTypes: string; @@ -106,6 +110,11 @@ export class ESFileListComponent { @Input() public files: ESFileListFile[]; + /** + * Path to image to display as file icon instead of the prebuilt icon. + */ + @Input() fileIconSrc?: string; + /** * Object with removed file and its index is emitted. */ @@ -126,7 +135,7 @@ export class ESFileListComponent { public locale: ESFileListLocale, @Optional() @Inject(ES_FILE_LIST_DEFAULT_OPTIONS) - private defaultOptions: ESFileListOptions + private defaultOptions: ESFileListDefaultOptions ) { this.imageTypes = this.defaultOptions?.imageTypes; this.hideImages = this.defaultOptions?.hideImages; @@ -177,7 +186,7 @@ export class ESFileListComponent { * @ignore */ public get src(): string { - return './assets/elonkit/file-list/file.svg'; + return this.fileIconSrc || './assets/elonkit/file-list/file.svg'; } /** diff --git a/projects/elonkit/src/ui/file-list/file-list.types.ts b/projects/elonkit/src/ui/file-list/file-list.types.ts index 9432d160..2ea19931 100644 --- a/projects/elonkit/src/ui/file-list/file-list.types.ts +++ b/projects/elonkit/src/ui/file-list/file-list.types.ts @@ -4,6 +4,7 @@ export interface ESFileListFile { type?: string; base64?: string; file?: string; + updatedAt?: string; name: string; size: number; content: File | string; @@ -14,7 +15,7 @@ export interface ESFileListRemoveAction { index: number; } -export interface ESFileListOptions { +export interface ESFileListDefaultOptions { imageTypes?: string; hideImages?: boolean; canRemove?: boolean; diff --git a/projects/elonkit/src/ui/file-list/fixtures/files.fixture.ts b/projects/elonkit/src/ui/file-list/fixtures/files.fixture.ts index f86d0b83..23dfa408 100644 --- a/projects/elonkit/src/ui/file-list/fixtures/files.fixture.ts +++ b/projects/elonkit/src/ui/file-list/fixtures/files.fixture.ts @@ -7,29 +7,32 @@ export const filesFixture: ESFileListFile[] = [ file: 'https://dummyimage.com/400x400/405ed6/fff.jpg&text=ES', name: 'FileName1.jpg', size: 45678, - content: null + content: null, + updatedAt: '2014-09-08T08:02:17-05:00' }, { id: 2, type: 'image/jpg', file: 'https://dummyimage.com/400x400/228a0f/fff.jpg&text=ES', - name: 'FileName2.jpg', + name: 'Ochen_Dlinnoe_nazvanie_faila.jpg', size: 456789, - content: null + content: null, + updatedAt: '2020-10-11T08:12:17-05:00' }, { id: 3, type: 'application/pdf', file: 'https://dummyimage.com/400x400/d6761c/fff.jpg&text=ES', - name: 'FileName3.pdf', + name: 'Nazvanie_faila.pdf', size: 4567, - content: null + content: null, + updatedAt: '2009-04-02T08:08:12-05:00' }, { id: 4, type: 'image/jpg', file: 'https://dummyimage.com/400x400/2dbdb8/fff.jpg&text=ES', - name: 'FileName4.jpg', + name: 'Vtoroe_nazvanie_faila.jpg', size: 456, content: null } diff --git a/projects/elonkit/src/ui/file-list/public-api.ts b/projects/elonkit/src/ui/file-list/public-api.ts index 8cdac27e..da8281c3 100644 --- a/projects/elonkit/src/ui/file-list/public-api.ts +++ b/projects/elonkit/src/ui/file-list/public-api.ts @@ -1,4 +1,8 @@ export { ESFileListModule } from './file-list.module'; export { ESFileListComponent, ES_FILE_LIST_DEFAULT_OPTIONS } from './file-list.component'; export { ESFileListLocale, ESFileListLocaleRU } from './file-list.component.locale'; -export { ESFileListFile, ESFileListOptions, ESFileListRemoveAction } from './file-list.types'; +export { + ESFileListFile, + ESFileListDefaultOptions, + ESFileListRemoveAction +} from './file-list.types'; diff --git a/projects/elonkit/storybook/assets/icons/file-list/file.svg b/projects/elonkit/storybook/assets/icons/file-list/file.svg new file mode 100644 index 00000000..a1a6d2b7 --- /dev/null +++ b/projects/elonkit/storybook/assets/icons/file-list/file.svg @@ -0,0 +1 @@ + \ No newline at end of file From e107d3548c7c70923ae28efc2faa2017712669b9 Mon Sep 17 00:00:00 2001 From: Sergei Klimenko Date: Thu, 3 Sep 2020 12:32:34 +0300 Subject: [PATCH 10/12] refactor(file-list): fix linting error --- .../elonkit/src/ui/file-list/__specs__/file-list.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts b/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts index 9052eb4a..7c58630d 100644 --- a/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts +++ b/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts @@ -62,7 +62,7 @@ describe('File List', () => { excludeComponentDeclaration: true }); const removeButtons = component.getAllByLabelText(locale.labelRemove); - removeButtons.forEach(btn => { + removeButtons.forEach((btn) => { component.click(btn); }); expect(onRemove).toHaveBeenCalledTimes(filesFixture.length); @@ -94,7 +94,7 @@ describe('File List', () => { excludeComponentDeclaration: true }); const downloadButtons = component.getAllByLabelText(locale.labelDownload); - downloadButtons.forEach(btn => { + downloadButtons.forEach((btn) => { component.click(btn); }); expect(onDownload).toHaveBeenCalledTimes(filesFixture.length); @@ -109,7 +109,7 @@ describe('File List', () => { imports: [ESFileListModule, MatIconTestingModule], excludeComponentDeclaration: true }); - const nonImageFixture = filesFixture.filter(file => !file.type.startsWith('image')); + const nonImageFixture = filesFixture.filter((file) => !file.type.startsWith('image')); expect(component.getAllByTestId('file')).toHaveLength(nonImageFixture.length); }); From 854a5570e2bb8cd53502381a46eea1a3531cd5ea Mon Sep 17 00:00:00 2001 From: Sergei Klimenko Date: Thu, 3 Sep 2020 12:40:57 +0300 Subject: [PATCH 11/12] refactor(file-list): fix linter errors --- projects/elonkit/src/utils/validate-file-type.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/elonkit/src/utils/validate-file-type.ts b/projects/elonkit/src/utils/validate-file-type.ts index 464c5402..239442f5 100644 --- a/projects/elonkit/src/utils/validate-file-type.ts +++ b/projects/elonkit/src/utils/validate-file-type.ts @@ -1,11 +1,11 @@ export const validateFileType = (file: any, types: string): boolean => { - const typesArr = types.split(',').map(v => v.trim()); + const typesArr = types.split(',').map((v) => v.trim()); return typesArr.includes('*') || typesMatch(typesArr, file); }; const typesMatch = (types: string[], file: File): boolean => types.some( - type => + (type) => type === file.type || typeMatchesFileType(type, file.type) || typeMatchesFilenameExtension(type, file.name) From dfdc27257306c5ab23c9f2f1ccd49857891996af Mon Sep 17 00:00:00 2001 From: Sergei Klimenko Date: Fri, 4 Sep 2020 12:12:18 +0300 Subject: [PATCH 12/12] refactor(file-list): change knobs to controls, update to new locale system --- .../ui/file-list/__specs__/file-list.spec.ts | 31 ++++++----- ...file-list-story-custom-icon.component.html | 9 ++- .../file-list-story-custom-icon.component.ts | 11 +++- .../file-list-story-locale.component.html | 1 - .../file-list-story-locale.component.ts | 13 ----- .../file-list-story-locale.module.ts | 20 ------- .../file-list-story-locale.source.ts | 18 ------ .../file-list-story-locale/index.ts | 3 - .../file-list-story-typography.component.html | 4 ++ .../file-list-story-typography.component.ts | 9 +++ .../__stories__/file-list.stories.mdx | 55 ++++++++----------- .../src/ui/file-list/file-list.component.html | 8 +-- .../file-list/file-list.component.locale.ts | 19 ------- .../src/ui/file-list/file-list.component.ts | 27 +++++++-- .../elonkit/src/ui/file-list/public-api.ts | 1 - projects/elonkit/src/ui/locale/locales/en.ts | 7 +++ projects/elonkit/src/ui/locale/locales/ru.ts | 7 +++ 17 files changed, 111 insertions(+), 132 deletions(-) delete mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.html delete mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.ts delete mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts delete mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.source.ts delete mode 100644 projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/index.ts delete mode 100644 projects/elonkit/src/ui/file-list/file-list.component.locale.ts diff --git a/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts b/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts index 7c58630d..368f7006 100644 --- a/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts +++ b/projects/elonkit/src/ui/file-list/__specs__/file-list.spec.ts @@ -4,10 +4,7 @@ import { MatIconTestingModule } from '@angular/material/icon/testing'; import { ESFileListModule } from '../file-list.module'; import { ESFileListComponent } from '../file-list.component'; import { filesFixture } from '../fixtures/files.fixture'; -import { ESFileListLocale, ESFileListLocaleRU } from '../file-list.component.locale'; - -const locale = new ESFileListLocale(); -const localeRU = new ESFileListLocaleRU(); +import { ESLocaleService, en, ru } from '../../locale'; describe('File List', () => { it('Should render all files', async () => { @@ -33,7 +30,7 @@ describe('File List', () => { excludeComponentDeclaration: true }); expect(component.getByText(file.name)).toHaveClass('app-body-1'); - expect(component.getByText(locale.labelKB, { exact: false })).toHaveClass('app-caption'); + expect(component.getByText(en.fileList.labelKB, { exact: false })).toHaveClass('app-caption'); }); it('Should render remove button on canRemove input', async () => { @@ -45,7 +42,7 @@ describe('File List', () => { imports: [ESFileListModule, MatIconTestingModule], excludeComponentDeclaration: true }); - expect(component.getAllByLabelText(locale.labelRemove)).toHaveLength(filesFixture.length); + expect(component.getAllByLabelText(en.fileList.labelRemove)).toHaveLength(filesFixture.length); }); it('Should remove file on remove button click', async () => { @@ -61,7 +58,7 @@ describe('File List', () => { imports: [ESFileListModule, MatIconTestingModule], excludeComponentDeclaration: true }); - const removeButtons = component.getAllByLabelText(locale.labelRemove); + const removeButtons = component.getAllByLabelText(en.fileList.labelRemove); removeButtons.forEach((btn) => { component.click(btn); }); @@ -77,7 +74,9 @@ describe('File List', () => { imports: [ESFileListModule, MatIconTestingModule], excludeComponentDeclaration: true }); - expect(component.getAllByLabelText(locale.labelDownload)).toHaveLength(filesFixture.length); + expect(component.getAllByLabelText(en.fileList.labelDownload)).toHaveLength( + filesFixture.length + ); }); it('Should download file on download icon click', async () => { @@ -93,7 +92,7 @@ describe('File List', () => { imports: [ESFileListModule, MatIconTestingModule], excludeComponentDeclaration: true }); - const downloadButtons = component.getAllByLabelText(locale.labelDownload); + const downloadButtons = component.getAllByLabelText(en.fileList.labelDownload); downloadButtons.forEach((btn) => { component.click(btn); }); @@ -114,6 +113,10 @@ describe('File List', () => { }); it('Should change locale', async () => { + const localeService = new ESLocaleService(); + localeService.register('ru', ru); + localeService.use('ru'); + const component = await render(ESFileListComponent, { componentProperties: { files: filesFixture, @@ -121,12 +124,14 @@ describe('File List', () => { canRemove: true }, imports: [ESFileListModule, MatIconTestingModule], - providers: [{ provide: ESFileListLocale, useClass: ESFileListLocaleRU }], + providers: [{ provide: ESLocaleService, useValue: localeService }], excludeComponentDeclaration: true }); - expect(component.getAllByLabelText(localeRU.labelDownload)).toHaveLength(filesFixture.length); - expect(component.getAllByLabelText(localeRU.labelRemove)).toHaveLength(filesFixture.length); - expect(component.getAllByText(localeRU.labelKB, { exact: false })).toHaveLength( + expect(component.getAllByLabelText(ru.fileList.labelDownload)).toHaveLength( + filesFixture.length + ); + expect(component.getAllByLabelText(ru.fileList.labelRemove)).toHaveLength(filesFixture.length); + expect(component.getAllByText(ru.fileList.labelKB, { exact: false })).toHaveLength( filesFixture.length ); }); diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.html b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.html index 1c770f87..0c468fab 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.html +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.html @@ -1 +1,8 @@ - + diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.ts index 65aa6048..02df1d48 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.ts +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-custom-icon/file-list-story-custom-icon.component.ts @@ -1,4 +1,4 @@ -import { Component, ChangeDetectionStrategy } from '@angular/core'; +import { Component, ChangeDetectionStrategy, Input } from '@angular/core'; import { ESFileListFile } from '../../file-list.types'; import { filesFixture } from '../../fixtures/files.fixture'; @@ -9,6 +9,15 @@ import { filesFixture } from '../../fixtures/files.fixture'; changeDetection: ChangeDetectionStrategy.OnPush }) export class FileListStoryCustomIconComponent { + @Input() + public canRemove: boolean; + @Input() + public canDownload: boolean; + @Input() + public hideImages: boolean; + @Input() + public imageTypes: string; + public files: ESFileListFile[] = filesFixture; public customIcon = '/icons/file-list/file.svg'; } diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.html b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.html deleted file mode 100644 index 8cd20511..00000000 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.ts deleted file mode 100644 index 2aa3a5cc..00000000 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component, ChangeDetectionStrategy } from '@angular/core'; - -import { ESFileListFile } from '../../file-list.types'; -import { filesFixture } from '../../fixtures/files.fixture'; - -@Component({ - selector: 'es-file-list-locale', - templateUrl: './file-list-story-locale.component.html', - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class FileListStoryLocaleComponent { - public files: ESFileListFile[] = filesFixture; -} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts deleted file mode 100644 index 01d655ee..00000000 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.module.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { LOCALE_ID, NgModule } from '@angular/core'; -import { CommonModule, registerLocaleData } from '@angular/common'; -import localeRu from '@angular/common/locales/ru'; - -import { FileListStoryLocaleComponent } from './file-list-story-locale.component'; -import { ESFileListModule } from '../../file-list.module'; -import { ESFileListLocale, ESFileListLocaleRU } from '../../file-list.component.locale'; - -registerLocaleData(localeRu, 'ru'); - -@NgModule({ - declarations: [FileListStoryLocaleComponent], - imports: [CommonModule, ESFileListModule], - exports: [FileListStoryLocaleComponent], - providers: [ - { provide: ESFileListLocale, useClass: ESFileListLocaleRU }, - { provide: LOCALE_ID, useValue: 'ru' } - ] -}) -export class FileListStoryLocaleModule {} diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.source.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.source.ts deleted file mode 100644 index 46215acd..00000000 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/file-list-story-locale.source.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const FILE_LIST_STORY_LOCALE_SOURCE = { - ts: ` - import { LOCALE_ID, NgModule } from '@angular/core'; - import { CommonModule, registerLocaleData } from '@angular/common'; - import localeRu from '@angular/common/locales/ru'; - import { ESFileListLocale, ESFileListLocaleRU } from '@elonsoft/elonkit/ui/file-list'; - registerLocaleData(localeRu, 'ru'); - - @NgModule({ - ... - providers: [ - { provide: ESFileListLocale, useClass: ESFileListLocaleRU }, - { provide: LOCALE_ID, useValue: 'ru' } - ] - }) - export class AppModule {} - ` -}; diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/index.ts b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/index.ts deleted file mode 100644 index 269306dd..00000000 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-locale/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { FileListStoryLocaleComponent } from './file-list-story-locale.component'; -export { FileListStoryLocaleModule } from './file-list-story-locale.module'; -export { FILE_LIST_STORY_LOCALE_SOURCE } from './file-list-story-locale.source'; diff --git a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.html b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.html index 7598e8b3..18be56c3 100644 --- a/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.html +++ b/projects/elonkit/src/ui/file-list/__stories__/file-list-story-typography/file-list-story-typography.component.html @@ -1,4 +1,8 @@ + # File List @@ -40,33 +41,17 @@ This component displays a list of files. - {{ + {((args, context) => ({ component: FileListStoryBasicComponent, moduleMetadata: { imports: [FileListStoryBasicModule] }, props: { - canRemove: boolean('canRemove', false), - canDownload: boolean('canDownload', false), - hideImages: boolean('hideImages', false), - imageTypes: text('imageTypes', 'image/png,image/jpg,image/jpeg'), + ...args, onRemove: action('onRemove'), onDownload: action('onDownload') } - }} - - - -We can override default locale which is used for file size units. - - - - {{ - component: FileListStoryLocaleComponent, - moduleMetadata: { - imports: [FileListStoryLocaleModule] - } - }} + })).bind({})} @@ -74,12 +59,15 @@ We can use custom icon for files. - {{ + {((args, context) => ({ component: FileListStoryCustomIconComponent, moduleMetadata: { imports: [FileListStoryCustomIconModule] + }, + props: { + ...args } - }} + })).bind({})} @@ -87,18 +75,21 @@ We can use typography inputs in order to change text presentation. - {{ + {((args, context) => ({ component: FileListStoryTypographyComponent, moduleMetadata: { imports: [FileListStoryTypographyModule] + }, + props: { + ...args } - }} + })).bind({})} ## API - + ## Interfaces diff --git a/projects/elonkit/src/ui/file-list/file-list.component.html b/projects/elonkit/src/ui/file-list/file-list.component.html index 212fac94..a90ee8ef 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.html +++ b/projects/elonkit/src/ui/file-list/file-list.component.html @@ -1,4 +1,4 @@ -
+
@@ -7,7 +7,7 @@ close
- {{ getFileSize(file) }} + {{ getFileSize(file) | async }}
diff --git a/projects/elonkit/src/ui/file-list/file-list.component.locale.ts b/projects/elonkit/src/ui/file-list/file-list.component.locale.ts deleted file mode 100644 index e8c3be79..00000000 --- a/projects/elonkit/src/ui/file-list/file-list.component.locale.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable({ providedIn: 'root' }) -export class ESFileListLocale { - labelDownload = 'Download'; - labelRemove = 'Remove'; - labelKB = 'KB'; - labelMB = 'MB'; - labelAt = 'at'; -} - -@Injectable() -export class ESFileListLocaleRU extends ESFileListLocale { - labelDownload = 'Скачать'; - labelRemove = 'Удалить'; - labelKB = 'КБ'; - labelMB = 'МБ'; - labelAt = 'в'; -} diff --git a/projects/elonkit/src/ui/file-list/file-list.component.ts b/projects/elonkit/src/ui/file-list/file-list.component.ts index c2459b41..ce68a751 100644 --- a/projects/elonkit/src/ui/file-list/file-list.component.ts +++ b/projects/elonkit/src/ui/file-list/file-list.component.ts @@ -11,13 +11,15 @@ import { } from '@angular/core'; import { validateFileType } from '~utils/validate-file-type'; -import { ESFileListLocale } from './file-list.component.locale'; import { ESFileListFile, ESFileListRemoveAction, ESFileListDefaultOptions } from './file-list.types'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { Observable } from 'rxjs'; +import { ESLocale, ESLocaleService } from '../locale'; +import { map } from 'rxjs/operators'; export const ES_FILE_LIST_DEFAULT_OPTIONS = new InjectionToken( 'ES_FILE_LIST_DEFAULT_OPTIONS' @@ -113,7 +115,8 @@ export class ESFileListComponent { /** * Path to image to display as file icon instead of the prebuilt icon. */ - @Input() fileIconSrc?: string; + @Input() + public fileIconSrc?: string; /** * Object with removed file and its index is emitted. @@ -127,16 +130,23 @@ export class ESFileListComponent { @Output() public download: EventEmitter = new EventEmitter(); + /** + * @internal + * @ignore + */ + public locale$: Observable; + /** * @internal * @ignore */ constructor( - public locale: ESFileListLocale, + private localeService: ESLocaleService, @Optional() @Inject(ES_FILE_LIST_DEFAULT_OPTIONS) private defaultOptions: ESFileListDefaultOptions ) { + this.locale$ = this.localeService.locale(); this.imageTypes = this.defaultOptions?.imageTypes; this.hideImages = this.defaultOptions?.hideImages; this.canDownload = this.defaultOptions?.canDownload; @@ -149,11 +159,16 @@ export class ESFileListComponent { * @internal * @ignore */ - public getFileSize(file: ESFileListFile): string { - const { labelKB, labelMB } = this.locale; + public getFileSize(file: ESFileListFile): Observable { const sizeKB = file.size / 1024; const sizeMB = file.size / 1024 / 1024; - return sizeKB < 1024 ? `${sizeKB.toFixed(1)} ${labelKB}` : `${sizeMB.toFixed(1)} ${labelMB}`; + return this.locale$.pipe( + map((translation) => + sizeKB < 1024 + ? `${sizeKB.toFixed(1)} ${translation.fileList.labelKB}` + : `${sizeMB.toFixed(1)} ${translation.fileList.labelMB}` + ) + ); } /** diff --git a/projects/elonkit/src/ui/file-list/public-api.ts b/projects/elonkit/src/ui/file-list/public-api.ts index da8281c3..af2b770d 100644 --- a/projects/elonkit/src/ui/file-list/public-api.ts +++ b/projects/elonkit/src/ui/file-list/public-api.ts @@ -1,6 +1,5 @@ export { ESFileListModule } from './file-list.module'; export { ESFileListComponent, ES_FILE_LIST_DEFAULT_OPTIONS } from './file-list.component'; -export { ESFileListLocale, ESFileListLocaleRU } from './file-list.component.locale'; export { ESFileListFile, ESFileListDefaultOptions, diff --git a/projects/elonkit/src/ui/locale/locales/en.ts b/projects/elonkit/src/ui/locale/locales/en.ts index ba3b5730..19624191 100644 --- a/projects/elonkit/src/ui/locale/locales/en.ts +++ b/projects/elonkit/src/ui/locale/locales/en.ts @@ -22,5 +22,12 @@ export const en = { labelHH: 'HH', labelMM: 'MM', labelSS: 'SS' + }, + fileList: { + labelDownload: 'Download', + labelRemove: 'Remove', + labelKB: 'KB', + labelMB: 'MB', + labelAt: 'at' } }; diff --git a/projects/elonkit/src/ui/locale/locales/ru.ts b/projects/elonkit/src/ui/locale/locales/ru.ts index f7aa4a18..75402ede 100644 --- a/projects/elonkit/src/ui/locale/locales/ru.ts +++ b/projects/elonkit/src/ui/locale/locales/ru.ts @@ -22,5 +22,12 @@ export const ru = { labelHH: 'ЧЧ', labelMM: 'ММ', labelSS: 'СС' + }, + fileList: { + labelDownload: 'Скачать', + labelRemove: 'Удалить', + labelKB: 'КБ', + labelMB: 'МБ', + labelAt: 'в' } };