From 605aaf58f1cc8d3a35e2e211a353a1c416f4e9a1 Mon Sep 17 00:00:00 2001 From: Alex Inkin Date: Mon, 18 Sep 2023 17:33:27 +0400 Subject: [PATCH] feat(experimental): `Button` add new component (#5416) --- projects/core/styles/theme/wrapper/base.less | 2 +- .../core/styles/theme/wrapper/secondary.less | 36 +++++- projects/demo/src/modules/app/app.routes.ts | 8 ++ projects/demo/src/modules/app/pages.ts | 6 + .../directives/present/present.template.html | 2 +- .../experimental/avatar/avatar.template.html | 6 +- .../experimental/button/button.component.ts | 51 +++++++++ .../experimental/button/button.module.ts | 38 +++++++ .../experimental/button/button.template.html | 105 ++++++++++++++++++ .../experimental/button/examples/1/index.html | 27 +++++ .../experimental/button/examples/1/index.less | 4 + .../experimental/button/examples/1/index.ts | 12 ++ .../experimental/button/examples/2/index.html | 41 +++++++ .../experimental/button/examples/2/index.less | 5 + .../experimental/button/examples/2/index.ts | 12 ++ .../experimental/button/examples/3/index.html | 42 +++++++ .../experimental/button/examples/3/index.less | 5 + .../experimental/button/examples/3/index.ts | 12 ++ .../experimental/button/examples/4/index.html | 8 ++ .../experimental/button/examples/4/index.ts | 19 ++++ .../button/examples/import/import-module.md | 13 +++ .../button/examples/import/insert-template.md | 4 + .../avatar-stack/avatar-stack.style.less | 28 ++--- .../components/avatar/avatar.style.less | 40 +++---- .../button-loader/button-loader.component.ts | 34 ++++++ .../button-loader/button-loader.module.ts | 12 ++ .../button-loader/button-loader.style.less | 16 +++ .../button-loader/button-loader.template.html | 7 ++ .../components/button-loader/index.ts | 2 + .../components/button-loader/ng-package.json | 8 ++ .../components/button/button.component.ts | 9 ++ .../components/button/button.directive.ts | 41 +++++++ .../components/button/button.module.ts | 10 ++ .../components/button/button.style.less | 103 +++++++++++++++++ .../experimental/components/button/index.ts | 3 + .../components/button/ng-package.json | 8 ++ projects/experimental/components/index.ts | 2 + 37 files changed, 736 insertions(+), 45 deletions(-) create mode 100644 projects/demo/src/modules/experimental/button/button.component.ts create mode 100644 projects/demo/src/modules/experimental/button/button.module.ts create mode 100644 projects/demo/src/modules/experimental/button/button.template.html create mode 100644 projects/demo/src/modules/experimental/button/examples/1/index.html create mode 100644 projects/demo/src/modules/experimental/button/examples/1/index.less create mode 100644 projects/demo/src/modules/experimental/button/examples/1/index.ts create mode 100644 projects/demo/src/modules/experimental/button/examples/2/index.html create mode 100644 projects/demo/src/modules/experimental/button/examples/2/index.less create mode 100644 projects/demo/src/modules/experimental/button/examples/2/index.ts create mode 100644 projects/demo/src/modules/experimental/button/examples/3/index.html create mode 100644 projects/demo/src/modules/experimental/button/examples/3/index.less create mode 100644 projects/demo/src/modules/experimental/button/examples/3/index.ts create mode 100644 projects/demo/src/modules/experimental/button/examples/4/index.html create mode 100644 projects/demo/src/modules/experimental/button/examples/4/index.ts create mode 100644 projects/demo/src/modules/experimental/button/examples/import/import-module.md create mode 100644 projects/demo/src/modules/experimental/button/examples/import/insert-template.md create mode 100644 projects/experimental/components/button-loader/button-loader.component.ts create mode 100644 projects/experimental/components/button-loader/button-loader.module.ts create mode 100644 projects/experimental/components/button-loader/button-loader.style.less create mode 100644 projects/experimental/components/button-loader/button-loader.template.html create mode 100644 projects/experimental/components/button-loader/index.ts create mode 100644 projects/experimental/components/button-loader/ng-package.json create mode 100644 projects/experimental/components/button/button.component.ts create mode 100644 projects/experimental/components/button/button.directive.ts create mode 100644 projects/experimental/components/button/button.module.ts create mode 100644 projects/experimental/components/button/button.style.less create mode 100644 projects/experimental/components/button/index.ts create mode 100644 projects/experimental/components/button/ng-package.json diff --git a/projects/core/styles/theme/wrapper/base.less b/projects/core/styles/theme/wrapper/base.less index 3798beea13b9..b1a0695bffa5 100644 --- a/projects/core/styles/theme/wrapper/base.less +++ b/projects/core/styles/theme/wrapper/base.less @@ -11,7 +11,7 @@ border-radius: inherit; &:after { - .transition(box-shadow); + .transition(~'box-shadow, color'); .fullsize(absolute, inset); content: ''; border-radius: inherit; diff --git a/projects/core/styles/theme/wrapper/secondary.less b/projects/core/styles/theme/wrapper/secondary.less index 483cb22949e7..2a75b2d8472c 100644 --- a/projects/core/styles/theme/wrapper/secondary.less +++ b/projects/core/styles/theme/wrapper/secondary.less @@ -2,7 +2,8 @@ /* stylelint-disable order/order */ [tuiWrapper][data-appearance='secondary'], -[tuiWrapper][data-appearance='flat'] { +[tuiWrapper][data-appearance='flat'], +[tuiWrapper][data-appearance='destructive'] { background: var(--tui-secondary); color: var(--tui-link); @@ -12,7 +13,6 @@ .wrapper-hover({ background: var(--tui-clear-inverse-hover); - color: var(--tui-text-01-night); }); .wrapper-active({ @@ -30,7 +30,6 @@ .wrapper-hover({ background: var(--tui-clear-hover); - color: var(--tui-text-01); }); .wrapper-active({ @@ -40,7 +39,6 @@ .wrapper-hover({ background: var(--tui-secondary-hover); - color: var(--tui-link-hover); }); .wrapper-active({ @@ -48,7 +46,7 @@ }); .wrapper-invalid({ - color: var(--tui-error-fill); + color: var(--tui-negative); background: var(--tui-error-bg); .wrapper-hover({ @@ -56,7 +54,7 @@ }); .wrapper-focus({ - --tui-focus: var(--tui-error-fill); + --tui-focus: var(--tui-negative); }); }); } @@ -69,3 +67,29 @@ background: transparent; } } + +[tuiWrapper][data-appearance='destructive'] { + color: var(--tui-negative); + background: var(--tui-error-bg); + + .wrapper-hover({ + background: var(--tui-error-bg-hover); + }); + + .wrapper-active({ + background: var(--tui-error-bg-hover); + }); + + &[data-mode='onDark'] { + color: var(--tui-negative-night); + background: var(--tui-error-bg-night); + + .wrapper-hover({ + background: var(--tui-error-bg-night-hover); + }); + + .wrapper-active({ + background: var(--tui-error-bg-night-hover); + }); + } +} diff --git a/projects/demo/src/modules/app/app.routes.ts b/projects/demo/src/modules/app/app.routes.ts index b759a02f0552..fe20f4a99731 100644 --- a/projects/demo/src/modules/app/app.routes.ts +++ b/projects/demo/src/modules/app/app.routes.ts @@ -214,6 +214,14 @@ export const ROUTES: Routes = [ title: `Badge `, }, }, + { + path: `experimental/button`, + loadChildren: async () => + (await import(`../experimental/button/button.module`)).ExampleTuiButtonModule, + data: { + title: `Button `, + }, + }, { path: `experimental/fade`, loadChildren: async () => diff --git a/projects/demo/src/modules/app/pages.ts b/projects/demo/src/modules/app/pages.ts index 10b46710c50b..1d340d0c66eb 100644 --- a/projects/demo/src/modules/app/pages.ts +++ b/projects/demo/src/modules/app/pages.ts @@ -827,6 +827,12 @@ export const pages = [ keywords: `бэдж, бейдж, овал, badge, нотификация`, route: `/experimental/badge`, }, + { + section: `Experimental`, + title: `Button`, + keywords: `кнопка, button, icon-button, иконка`, + route: `/experimental/button`, + }, { section: `Experimental`, title: `Fade`, diff --git a/projects/demo/src/modules/directives/present/present.template.html b/projects/demo/src/modules/directives/present/present.template.html index ae0697f9b341..376a13286ac6 100644 --- a/projects/demo/src/modules/directives/present/present.template.html +++ b/projects/demo/src/modules/directives/present/present.template.html @@ -1,6 +1,6 @@ diff --git a/projects/demo/src/modules/experimental/avatar/avatar.template.html b/projects/demo/src/modules/experimental/avatar/avatar.template.html index 0382f40984aa..5d157a6b49fd 100644 --- a/projects/demo/src/modules/experimental/avatar/avatar.template.html +++ b/projects/demo/src/modules/experimental/avatar/avatar.template.html @@ -18,7 +18,7 @@ [content]="example1" > - This example uses pipe from + This example requires import of TuiFallbackSrcModule @@ -30,7 +30,7 @@ [content]="example2" > - This example uses directive from + This example requires import of TuiFadeModule @@ -50,7 +50,7 @@ [content]="example4" > - This example uses component from + This example requires import of TuiAvatarStackModule diff --git a/projects/demo/src/modules/experimental/button/button.component.ts b/projects/demo/src/modules/experimental/button/button.component.ts new file mode 100644 index 000000000000..ba371542c121 --- /dev/null +++ b/projects/demo/src/modules/experimental/button/button.component.ts @@ -0,0 +1,51 @@ +import {Component} from '@angular/core'; +import {changeDetection} from '@demo/emulate/change-detection'; +import {RawLoaderContent, TuiDocExample} from '@taiga-ui/addon-doc'; +import {TuiSizeL, TuiSizeXS} from '@taiga-ui/core'; + +@Component({ + selector: 'example-button', + templateUrl: './button.template.html', + changeDetection, +}) +export class ExampleTuiButtonComponent { + readonly exampleModule: RawLoaderContent = import( + './examples/import/import-module.md?raw' + ); + + readonly exampleHtml: RawLoaderContent = import( + './examples/import/insert-template.md?raw' + ); + + readonly example1: TuiDocExample = { + HTML: import('./examples/1/index.html?raw'), + }; + + readonly example2: TuiDocExample = { + HTML: import('./examples/2/index.html?raw'), + }; + + readonly example3: TuiDocExample = { + HTML: import('./examples/3/index.html?raw'), + }; + + readonly example4: TuiDocExample = { + TypeScript: import('./examples/4/index.ts?raw'), + HTML: import('./examples/4/index.html?raw'), + }; + + readonly sizes: ReadonlyArray = ['xs', 's', 'm', 'l']; + + size = this.sizes[3]; + + readonly appearances = [ + 'primary', + 'accent', + 'secondary', + 'destructive', + 'flat', + 'outline', + ]; + + appearance = this.appearances[0]; +} diff --git a/projects/demo/src/modules/experimental/button/button.module.ts b/projects/demo/src/modules/experimental/button/button.module.ts new file mode 100644 index 000000000000..92580f186ee2 --- /dev/null +++ b/projects/demo/src/modules/experimental/button/button.module.ts @@ -0,0 +1,38 @@ +import {CommonModule} from '@angular/common'; +import {NgModule} from '@angular/core'; +import {RouterModule} from '@angular/router'; +import {TuiAddonDocModule, tuiGenerateRoutes} from '@taiga-ui/addon-doc'; +import {TuiNotificationModule, TuiSvgModule} from '@taiga-ui/core'; +import { + TuiAvatarModule, + TuiButtonLoaderModule, + TuiButtonModule, +} from '@taiga-ui/experimental'; + +import {ExampleTuiButtonComponent} from './button.component'; +import {TuiButtonExample1} from './examples/1'; +import {TuiButtonExample2} from './examples/2'; +import {TuiButtonExample3} from './examples/3'; +import {TuiButtonExample4} from './examples/4'; + +@NgModule({ + imports: [ + CommonModule, + TuiButtonModule, + TuiButtonLoaderModule, + TuiNotificationModule, + TuiSvgModule, + TuiAvatarModule, + TuiAddonDocModule, + RouterModule.forChild(tuiGenerateRoutes(ExampleTuiButtonComponent)), + ], + declarations: [ + ExampleTuiButtonComponent, + TuiButtonExample1, + TuiButtonExample2, + TuiButtonExample3, + TuiButtonExample4, + ], + exports: [ExampleTuiButtonComponent], +}) +export class ExampleTuiButtonModule {} diff --git a/projects/demo/src/modules/experimental/button/button.template.html b/projects/demo/src/modules/experimental/button/button.template.html new file mode 100644 index 000000000000..64c40536b75f --- /dev/null +++ b/projects/demo/src/modules/experimental/button/button.template.html @@ -0,0 +1,105 @@ + + + + This code is + experimental + and is a subject to change. Expect final solution to be shipped in the next major version + + +

New version for Button component following updated design specs.

+ + + + + + + + + + + + + + + + This example requires import of + TuiButtonLoaderModule + + + +
+ + + + + + + + Size + + + Size + + + + + +
    +
  1. +

    Import module

    + + +
  2. + +
  3. +

    Add to the template:

    + + +
  4. +
+
+
diff --git a/projects/demo/src/modules/experimental/button/examples/1/index.html b/projects/demo/src/modules/experimental/button/examples/1/index.html new file mode 100644 index 000000000000..c1f0ea099336 --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/1/index.html @@ -0,0 +1,27 @@ + + + + + + + diff --git a/projects/demo/src/modules/experimental/button/examples/1/index.less b/projects/demo/src/modules/experimental/button/examples/1/index.less new file mode 100644 index 000000000000..e8c357f08e0d --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/1/index.less @@ -0,0 +1,4 @@ +:host { + display: flex; + gap: 1rem; +} diff --git a/projects/demo/src/modules/experimental/button/examples/1/index.ts b/projects/demo/src/modules/experimental/button/examples/1/index.ts new file mode 100644 index 000000000000..e8c2550491cb --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/1/index.ts @@ -0,0 +1,12 @@ +import {Component} from '@angular/core'; +import {changeDetection} from '@demo/emulate/change-detection'; +import {encapsulation} from '@demo/emulate/encapsulation'; + +@Component({ + selector: 'tui-button-example-1', + templateUrl: './index.html', + styleUrls: ['./index.less'], + changeDetection, + encapsulation, +}) +export class TuiButtonExample1 {} diff --git a/projects/demo/src/modules/experimental/button/examples/2/index.html b/projects/demo/src/modules/experimental/button/examples/2/index.html new file mode 100644 index 000000000000..08711a1dac2e --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/2/index.html @@ -0,0 +1,41 @@ + + + + + + + + + + + diff --git a/projects/demo/src/modules/experimental/button/examples/2/index.less b/projects/demo/src/modules/experimental/button/examples/2/index.less new file mode 100644 index 000000000000..eed5e8299353 --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/2/index.less @@ -0,0 +1,5 @@ +:host { + display: flex; + gap: 1rem; + flex-wrap: wrap; +} diff --git a/projects/demo/src/modules/experimental/button/examples/2/index.ts b/projects/demo/src/modules/experimental/button/examples/2/index.ts new file mode 100644 index 000000000000..6147ca57104a --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/2/index.ts @@ -0,0 +1,12 @@ +import {Component} from '@angular/core'; +import {changeDetection} from '@demo/emulate/change-detection'; +import {encapsulation} from '@demo/emulate/encapsulation'; + +@Component({ + selector: 'tui-button-example-2', + templateUrl: './index.html', + styleUrls: ['./index.less'], + changeDetection, + encapsulation, +}) +export class TuiButtonExample2 {} diff --git a/projects/demo/src/modules/experimental/button/examples/3/index.html b/projects/demo/src/modules/experimental/button/examples/3/index.html new file mode 100644 index 000000000000..6f370b96b898 --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/3/index.html @@ -0,0 +1,42 @@ + + + + + + + diff --git a/projects/demo/src/modules/experimental/button/examples/3/index.less b/projects/demo/src/modules/experimental/button/examples/3/index.less new file mode 100644 index 000000000000..23d25a3bb0a1 --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/3/index.less @@ -0,0 +1,5 @@ +:host { + display: flex; + flex-direction: column; + gap: 1rem; +} diff --git a/projects/demo/src/modules/experimental/button/examples/3/index.ts b/projects/demo/src/modules/experimental/button/examples/3/index.ts new file mode 100644 index 000000000000..87dc46a61dc5 --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/3/index.ts @@ -0,0 +1,12 @@ +import {Component} from '@angular/core'; +import {changeDetection} from '@demo/emulate/change-detection'; +import {encapsulation} from '@demo/emulate/encapsulation'; + +@Component({ + selector: 'tui-button-example-3', + templateUrl: './index.html', + styleUrls: ['./index.less'], + changeDetection, + encapsulation, +}) +export class TuiButtonExample3 {} diff --git a/projects/demo/src/modules/experimental/button/examples/4/index.html b/projects/demo/src/modules/experimental/button/examples/4/index.html new file mode 100644 index 000000000000..a39c618c1d75 --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/4/index.html @@ -0,0 +1,8 @@ + diff --git a/projects/demo/src/modules/experimental/button/examples/4/index.ts b/projects/demo/src/modules/experimental/button/examples/4/index.ts new file mode 100644 index 000000000000..477fd596f3f4 --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/4/index.ts @@ -0,0 +1,19 @@ +import {Component} from '@angular/core'; +import {changeDetection} from '@demo/emulate/change-detection'; +import {encapsulation} from '@demo/emulate/encapsulation'; +import {ALWAYS_FALSE_HANDLER} from '@taiga-ui/cdk'; +import {Subject, timer} from 'rxjs'; +import {map, startWith, switchMap} from 'rxjs/operators'; + +@Component({ + selector: 'tui-button-example-4', + templateUrl: './index.html', + changeDetection, + encapsulation, +}) +export class TuiButtonExample4 { + readonly trigger$ = new Subject(); + readonly loading$ = this.trigger$.pipe( + switchMap(() => timer(2000).pipe(map(ALWAYS_FALSE_HANDLER), startWith(true))), + ); +} diff --git a/projects/demo/src/modules/experimental/button/examples/import/import-module.md b/projects/demo/src/modules/experimental/button/examples/import/import-module.md new file mode 100644 index 000000000000..fcd7d9836617 --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/import/import-module.md @@ -0,0 +1,13 @@ +```ts +import {NgModule} from '@angular/core'; +import {TuiButtonModule} from '@taiga-ui/experimental'; +// ... + +@NgModule({ + imports: [ + // ... + TuiButtonModule, + ], +}) +export class MyModule {} +``` diff --git a/projects/demo/src/modules/experimental/button/examples/import/insert-template.md b/projects/demo/src/modules/experimental/button/examples/import/insert-template.md new file mode 100644 index 000000000000..127b3063f522 --- /dev/null +++ b/projects/demo/src/modules/experimental/button/examples/import/insert-template.md @@ -0,0 +1,4 @@ +```html + +Press me +``` diff --git a/projects/experimental/components/avatar-stack/avatar-stack.style.less b/projects/experimental/components/avatar-stack/avatar-stack.style.less index 48381843b994..c78e86450195 100644 --- a/projects/experimental/components/avatar-stack/avatar-stack.style.less +++ b/projects/experimental/components/avatar-stack/avatar-stack.style.less @@ -2,39 +2,39 @@ // prettier-ignore tui-avatar-stack { display: flex; - --gap: 0.125rem; + --t-gap: 0.125rem; tui-avatar { mask-size: - calc(var(--radius) + var(--gap)) calc(var(--radius) + var(--gap)), - calc(var(--radius) + var(--gap)) calc(var(--radius) + var(--gap)), + calc(var(--t-radius) + var(--t-gap)) calc(var(--t-radius) + var(--t-gap)), + calc(var(--t-radius) + var(--t-gap)) calc(var(--t-radius) + var(--t-gap)), 100%; mask-repeat: no-repeat; } &[data-direction='left'] tui-avatar:not(:first-child) { mask-image: - radial-gradient(circle at 0% 100%, transparent calc(var(--radius) + var(--gap)), #000 calc(var(--radius) + var(--gap) + 0.2px)), - radial-gradient(circle at 0% 0%, transparent calc(var(--radius) + var(--gap)), #000 calc(var(--radius) + var(--gap) + 0.2px)), - linear-gradient(to right, transparent calc(50% + var(--gap)), #000 calc(50% + var(--gap))); + radial-gradient(circle at 0% 100%, transparent calc(var(--t-radius) + var(--t-gap)), #000 calc(var(--t-radius) + var(--t-gap) + 0.2px)), + radial-gradient(circle at 0% 0%, transparent calc(var(--t-radius) + var(--t-gap)), #000 calc(var(--t-radius) + var(--t-gap) + 0.2px)), + linear-gradient(to right, transparent calc(50% + var(--t-gap)), #000 calc(50% + var(--t-gap))); mask-position: - calc(50% - (var(--radius) - var(--gap)) / 2) calc(-1 * var(--gap)), - calc(50% - (var(--radius) - var(--gap)) / 2) calc(100% + var(--gap)), + calc(50% - (var(--t-radius) - var(--t-gap)) / 2) calc(-1 * var(--t-gap)), + calc(50% - (var(--t-radius) - var(--t-gap)) / 2) calc(100% + var(--t-gap)), bottom; } &[data-direction='right'] tui-avatar:not(:last-child) { mask-image: - radial-gradient(circle at 150% 100%, transparent calc(var(--radius) + var(--gap)), #000 calc(var(--radius) + var(--gap) + 0.2px)), - radial-gradient(circle at 150% 0%, transparent calc(var(--radius) + var(--gap)), #000 calc(var(--radius) + var(--gap) + 0.2px)), - linear-gradient(to left, transparent calc(50% + var(--gap)), #000 calc(50% + var(--gap))); + radial-gradient(circle at 150% 100%, transparent calc(var(--t-radius) + var(--t-gap)), #000 calc(var(--t-radius) + var(--t-gap) + 0.2px)), + radial-gradient(circle at 150% 0%, transparent calc(var(--t-radius) + var(--t-gap)), #000 calc(var(--t-radius) + var(--t-gap) + 0.2px)), + linear-gradient(to left, transparent calc(50% + var(--t-gap)), #000 calc(50% + var(--t-gap))); mask-position: - calc(50% - var(--gap)) calc(-1 * var(--gap)), - calc(50% - var(--gap)) calc(100% + var(--gap)), + calc(50% - var(--t-gap)) calc(-1 * var(--t-gap)), + calc(50% - var(--t-gap)) calc(100% + var(--t-gap)), bottom; } tui-avatar:not(:last-child) { - margin-right: calc(var(--size) / -2); + margin-right: calc(var(--t-size) / -2); } } diff --git a/projects/experimental/components/avatar/avatar.style.less b/projects/experimental/components/avatar/avatar.style.less index 4bb47c874aa3..7099202b7a77 100644 --- a/projects/experimental/components/avatar/avatar.style.less +++ b/projects/experimental/components/avatar/avatar.style.less @@ -1,20 +1,20 @@ :host { - --size: 3.5rem; - --radius: 0.75rem; + --t-size: 3.5rem; + --t-radius: 0.75rem; display: inline-flex; - width: var(--size); - height: var(--size); + width: var(--t-size); + height: var(--t-size); align-items: center; justify-content: center; overflow: hidden; white-space: nowrap; - border-radius: var(--radius); + border-radius: var(--t-radius); background: var(--tui-secondary); color: var(--tui-text-02); &[data-size='xxs'] { - --size: 1.5rem; - --radius: 0.5rem; + --t-size: 1.5rem; + --t-radius: 0.5rem; font: var(--tui-font-text-xs); font-weight: bold; @@ -25,8 +25,8 @@ } &[data-size='xs'] { - --size: 2rem; - --radius: 0.5rem; + --t-size: 2rem; + --t-radius: 0.5rem; font: var(--tui-font-text-s); font-weight: bold; @@ -37,8 +37,8 @@ } &[data-size='s'] { - --size: 2.5rem; - --radius: 0.75rem; + --t-size: 2.5rem; + --t-radius: 0.75rem; font: var(--tui-font-text-l); font-weight: bold; @@ -49,8 +49,8 @@ } &[data-size='m'] { - --size: 3.5rem; - --radius: 0.75rem; + --t-size: 3.5rem; + --t-radius: 0.75rem; font: var(--tui-font-heading-5); .t-content { @@ -60,8 +60,8 @@ } &[data-size='l'] { - --size: 5rem; - --radius: 0.75rem; + --t-size: 5rem; + --t-radius: 0.75rem; font: var(--tui-font-heading-3); .t-content { @@ -70,8 +70,8 @@ } &[data-size='xl'] { - --size: 6rem; - --radius: 1rem; + --t-size: 6rem; + --t-radius: 1rem; font: var(--tui-font-heading-3); .t-content { @@ -80,8 +80,8 @@ } &[data-size='xxl'] { - --size: 8rem; - --radius: 1.25rem; + --t-size: 8rem; + --t-radius: 1.25rem; font: var(--tui-font-heading-2); .t-content { @@ -90,7 +90,7 @@ } &._round { - --radius: calc(var(--size) / 2); + --t-radius: calc(var(--t-size) / 2); } &._img { diff --git a/projects/experimental/components/button-loader/button-loader.component.ts b/projects/experimental/components/button-loader/button-loader.component.ts new file mode 100644 index 000000000000..726fd4f5754e --- /dev/null +++ b/projects/experimental/components/button-loader/button-loader.component.ts @@ -0,0 +1,34 @@ +import { + ChangeDetectionStrategy, + Component, + Input, + ViewEncapsulation, +} from '@angular/core'; +import {tuiSizeBigger, TuiSizeL, TuiSizeS, TuiSizeXS} from '@taiga-ui/core'; + +@Component({ + selector: + 'a[tuiButton][loading],button[tuiButton][loading],a[tuiIconButton][loading],button[tuiIconButton][loading]', + templateUrl: './button-loader.template.html', + styleUrls: ['./button-loader.style.less'], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + host: { + '[disabled]': 'disabled || loading', + '[class._loading]': 'loading', + }, +}) +export class TuiButtonLoaderComponent { + @Input() + size: TuiSizeL | TuiSizeXS = 'l'; + + @Input() + loading = false; + + @Input() + disabled = false; + + get loaderSize(): TuiSizeS { + return tuiSizeBigger(this.size) ? 'm' : 's'; + } +} diff --git a/projects/experimental/components/button-loader/button-loader.module.ts b/projects/experimental/components/button-loader/button-loader.module.ts new file mode 100644 index 000000000000..8a6fd002573b --- /dev/null +++ b/projects/experimental/components/button-loader/button-loader.module.ts @@ -0,0 +1,12 @@ +import {CommonModule} from '@angular/common'; +import {NgModule} from '@angular/core'; +import {TuiLoaderModule} from '@taiga-ui/core'; + +import {TuiButtonLoaderComponent} from './button-loader.component'; + +@NgModule({ + imports: [CommonModule, TuiLoaderModule], + declarations: [TuiButtonLoaderComponent], + exports: [TuiButtonLoaderComponent], +}) +export class TuiButtonLoaderModule {} diff --git a/projects/experimental/components/button-loader/button-loader.style.less b/projects/experimental/components/button-loader/button-loader.style.less new file mode 100644 index 000000000000..788592863f9b --- /dev/null +++ b/projects/experimental/components/button-loader/button-loader.style.less @@ -0,0 +1,16 @@ +@import 'taiga-ui-local'; + +// TODO: Change to [tuiButton] in 4.0 +[tuiButtonNew]._loading { + --tui-disabled-opacity: 1; + -webkit-text-fill-color: transparent; + + > * { + opacity: 0; + } + + .t-loader { + .fullsize(); + opacity: 1; + } +} diff --git a/projects/experimental/components/button-loader/button-loader.template.html b/projects/experimental/components/button-loader/button-loader.template.html new file mode 100644 index 000000000000..f3419403c409 --- /dev/null +++ b/projects/experimental/components/button-loader/button-loader.template.html @@ -0,0 +1,7 @@ + + diff --git a/projects/experimental/components/button-loader/index.ts b/projects/experimental/components/button-loader/index.ts new file mode 100644 index 000000000000..5bb590d3b123 --- /dev/null +++ b/projects/experimental/components/button-loader/index.ts @@ -0,0 +1,2 @@ +export * from './button-loader.component'; +export * from './button-loader.module'; diff --git a/projects/experimental/components/button-loader/ng-package.json b/projects/experimental/components/button-loader/ng-package.json new file mode 100644 index 000000000000..bab5ebcdb74a --- /dev/null +++ b/projects/experimental/components/button-loader/ng-package.json @@ -0,0 +1,8 @@ +{ + "lib": { + "entryFile": "index.ts", + "styleIncludePaths": [ + "../../../core/styles" + ] + } +} diff --git a/projects/experimental/components/button/button.component.ts b/projects/experimental/components/button/button.component.ts new file mode 100644 index 000000000000..388a396289ca --- /dev/null +++ b/projects/experimental/components/button/button.component.ts @@ -0,0 +1,9 @@ +import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/core'; + +@Component({ + template: '', + styleUrls: ['./button.style.less'], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, +}) +export class TuiButtonComponent {} diff --git a/projects/experimental/components/button/button.directive.ts b/projects/experimental/components/button/button.directive.ts new file mode 100644 index 000000000000..2e8e915dfbc5 --- /dev/null +++ b/projects/experimental/components/button/button.directive.ts @@ -0,0 +1,41 @@ +import {Directive, Inject, Input} from '@angular/core'; +import {TUI_PLATFORM, TuiDirectiveStylesService, TuiPlatform} from '@taiga-ui/cdk'; +import { + MODE_PROVIDER, + TUI_MODE, + TuiAppearance, + TuiBrightness, + TuiSizeL, + TuiSizeXS, +} from '@taiga-ui/core'; +import {Observable} from 'rxjs'; + +import {TuiButtonComponent} from './button.component'; + +@Directive({ + selector: 'a[tuiButton],button[tuiButton],a[tuiIconButton],button[tuiIconButton]', + providers: [MODE_PROVIDER], + host: { + tuiButtonNew: '', + tuiWrapper: '', + '[attr.data-size]': 'size', + '[attr.data-appearance]': 'appearance', + '[attr.data-platform]': 'platform', + '($.data-mode.attr)': 'mode$', + }, +}) +export class TuiButtonDirective { + @Input() + size: TuiSizeL | TuiSizeXS = 'l'; + + @Input() + appearance: string | keyof Record = 'primary'; + + constructor( + @Inject(TUI_PLATFORM) readonly platform: TuiPlatform, + @Inject(TUI_MODE) readonly mode$: Observable, + @Inject(TuiDirectiveStylesService) directiveStyles: TuiDirectiveStylesService, + ) { + directiveStyles.addComponent(TuiButtonComponent); + } +} diff --git a/projects/experimental/components/button/button.module.ts b/projects/experimental/components/button/button.module.ts new file mode 100644 index 000000000000..14a2625105df --- /dev/null +++ b/projects/experimental/components/button/button.module.ts @@ -0,0 +1,10 @@ +import {NgModule} from '@angular/core'; + +import {TuiButtonComponent} from './button.component'; +import {TuiButtonDirective} from './button.directive'; + +@NgModule({ + declarations: [TuiButtonDirective, TuiButtonComponent], + exports: [TuiButtonDirective], +}) +export class TuiButtonModule {} diff --git a/projects/experimental/components/button/button.style.less b/projects/experimental/components/button/button.style.less new file mode 100644 index 000000000000..4a05a2d34995 --- /dev/null +++ b/projects/experimental/components/button/button.style.less @@ -0,0 +1,103 @@ +@import 'taiga-ui-local'; + +// TODO: Change to [tuiButton] in 4.0 +[tuiButtonNew] { + .clearbtn(); + display: inline-flex; + height: var(--t-size); + align-items: center; + justify-content: center; + width: min-content; + white-space: nowrap; + border-radius: var(--t-radius); + user-select: none; + outline: none; + cursor: pointer; + + &[data-size='xs'] { + --t-size: var(--tui-height-xs); + --t-radius: var(--tui-radius-xs); + font: var(--tui-font-text-s); + padding: 0 0.375rem 0 0.25rem; + text-indent: 0.125rem; + gap: 0.125rem; + + tui-svg { + width: 1rem; + } + } + + &[data-size='s'] { + --t-size: var(--tui-height-s); + --t-radius: var(--tui-radius-s); + font: var(--tui-font-text-s); + padding: 0 0.625rem 0 0.5rem; + text-indent: 0.125rem; + gap: 0.125rem; + + tui-svg { + width: 1rem; + } + } + + &[data-size='m'] { + --t-size: var(--tui-height-m); + --t-radius: var(--tui-radius-m); + font: var(--tui-font-text-m); + padding: 0 1rem 0 0.625rem; + text-indent: 0.375rem; + gap: 0.125rem; + } + + &[data-size='l'] { + --t-size: var(--tui-height-l); + --t-radius: var(--tui-radius-l); + font: var(--tui-font-text-m); + padding: 0 1.25rem 0 1rem; + text-indent: 0.25rem; + gap: 0.25rem; + } + + &[data-platform='ios'], + &[data-platform='android'] { + width: 100%; + + &[data-size='xs'], + &[data-size='s'], + &[data-size='l'] { + --t-radius: 1rem; + } + + &[data-size='m'] { + --t-radius: 0.75rem; + } + } + + * { + text-indent: 0; + } +} + +[tuiButtonNew] [tuiIconRight] { + width: 1rem; + order: 999; + margin-inline-start: 0.125rem; + margin-inline-end: -0.125rem; +} + +[tuiButtonNew][data-size='m'] [tuiIconRight] { + margin-inline-start: 0.375rem; +} + +[tuiButtonNew][data-size='l'] [tuiIconRight] { + margin-inline-start: 0.25rem; + margin-inline-end: -0.25rem; +} + +[tuiIconButton][tuiButtonNew] { + width: var(--t-size); + font-size: 0; + padding: 0; + text-indent: 0; + gap: 0; +} diff --git a/projects/experimental/components/button/index.ts b/projects/experimental/components/button/index.ts new file mode 100644 index 000000000000..38235a1ee25e --- /dev/null +++ b/projects/experimental/components/button/index.ts @@ -0,0 +1,3 @@ +export * from './button.component'; +export * from './button.directive'; +export * from './button.module'; diff --git a/projects/experimental/components/button/ng-package.json b/projects/experimental/components/button/ng-package.json new file mode 100644 index 000000000000..bab5ebcdb74a --- /dev/null +++ b/projects/experimental/components/button/ng-package.json @@ -0,0 +1,8 @@ +{ + "lib": { + "entryFile": "index.ts", + "styleIncludePaths": [ + "../../../core/styles" + ] + } +} diff --git a/projects/experimental/components/index.ts b/projects/experimental/components/index.ts index c4020863924a..6cbc9699eb9c 100644 --- a/projects/experimental/components/index.ts +++ b/projects/experimental/components/index.ts @@ -1,3 +1,5 @@ export * from '@taiga-ui/experimental/components/avatar'; export * from '@taiga-ui/experimental/components/avatar-stack'; export * from '@taiga-ui/experimental/components/badge'; +export * from '@taiga-ui/experimental/components/button'; +export * from '@taiga-ui/experimental/components/button-loader';