From ae3ea2d6db6c9153d661c62df16bdb7b8cee0ee4 Mon Sep 17 00:00:00 2001 From: Alex Inkin Date: Fri, 30 Aug 2024 17:18:52 +0400 Subject: [PATCH] chore(demo): update appearances customization page (#8761) Co-authored-by: taiga-family-bot --- projects/demo/src/modules/app/app.routes.ts | 6 +- projects/demo/src/modules/app/demo-routes.ts | 1 + projects/demo/src/modules/app/pages.ts | 4 +- .../examples/1/index.html | 23 ++--- .../examples/1/index.less | 90 +++++++++---------- .../appearances/examples/1/index.ts | 30 +++++++ .../customization/appearances/index.html | 75 ++++++++++++++++ .../{wrapper => appearances}/index.ts | 13 +-- .../customization/wrapper/examples/1/index.ts | 32 ------- .../modules/customization/wrapper/index.html | 34 ------- .../appearance/examples/3/index.less | 4 +- .../components/checkbox/checkbox.component.ts | 4 +- .../components/checkbox/checkbox.options.ts | 2 +- .../kit/components/radio/radio.component.ts | 5 +- .../kit/components/radio/radio.options.ts | 2 +- 15 files changed, 179 insertions(+), 146 deletions(-) rename projects/demo/src/modules/customization/{wrapper => appearances}/examples/1/index.html (51%) rename projects/demo/src/modules/customization/{wrapper => appearances}/examples/1/index.less (53%) create mode 100644 projects/demo/src/modules/customization/appearances/examples/1/index.ts create mode 100644 projects/demo/src/modules/customization/appearances/index.html rename projects/demo/src/modules/customization/{wrapper => appearances}/index.ts (76%) delete mode 100644 projects/demo/src/modules/customization/wrapper/examples/1/index.ts delete mode 100644 projects/demo/src/modules/customization/wrapper/index.html diff --git a/projects/demo/src/modules/app/app.routes.ts b/projects/demo/src/modules/app/app.routes.ts index 7cc3f734b4cf..a4e0f7d314d0 100644 --- a/projects/demo/src/modules/app/app.routes.ts +++ b/projects/demo/src/modules/app/app.routes.ts @@ -57,9 +57,9 @@ export const ROUTES: Routes = [ loadComponent: async () => import('../customization/variables'), }), route({ - path: DemoRoute.Wrapper, - title: 'Wrapper', - loadComponent: async () => import('../customization/wrapper'), + path: DemoRoute.Appearances, + title: 'Appearances', + loadComponent: async () => import('../customization/appearances'), }), route({ path: DemoRoute.DialogCustom, diff --git a/projects/demo/src/modules/app/demo-routes.ts b/projects/demo/src/modules/app/demo-routes.ts index ddc41f13f47c..f66d35033796 100644 --- a/projects/demo/src/modules/app/demo-routes.ts +++ b/projects/demo/src/modules/app/demo-routes.ts @@ -23,6 +23,7 @@ export const DemoRoute = { Amount: '/pipes/amount', Emails: '/pipes/emails', Appearance: '/directives/appearance', + Appearances: '/appearances', FluidTypography: '/directives/fluid-typography', Chip: '/components/chip', Title: '/components/title', diff --git a/projects/demo/src/modules/app/pages.ts b/projects/demo/src/modules/app/pages.ts index a4cd26f6e74c..fec36a0b2bb7 100644 --- a/projects/demo/src/modules/app/pages.ts +++ b/projects/demo/src/modules/app/pages.ts @@ -1082,9 +1082,9 @@ export const pages: TuiDocRoutePages = [ }, { section: 'Customization', - title: 'Wrapper', + title: 'Appearances', keywords: 'colors, css, theme, custom, style', - route: DemoRoute.Wrapper, + route: DemoRoute.Appearances, }, { section: 'Customization', diff --git a/projects/demo/src/modules/customization/wrapper/examples/1/index.html b/projects/demo/src/modules/customization/appearances/examples/1/index.html similarity index 51% rename from projects/demo/src/modules/customization/wrapper/examples/1/index.html rename to projects/demo/src/modules/customization/appearances/examples/1/index.html index e45fbfa9a88b..6e4dcddea11f 100644 --- a/projects/demo/src/modules/customization/wrapper/examples/1/index.html +++ b/projects/demo/src/modules/customization/appearances/examples/1/index.html @@ -1,9 +1,11 @@ - - Input example - + + + + - + diff --git a/projects/demo/src/modules/customization/wrapper/examples/1/index.less b/projects/demo/src/modules/customization/appearances/examples/1/index.less similarity index 53% rename from projects/demo/src/modules/customization/wrapper/examples/1/index.less rename to projects/demo/src/modules/customization/appearances/examples/1/index.less index 79692c1df309..476ede5f91c3 100644 --- a/projects/demo/src/modules/customization/wrapper/examples/1/index.less +++ b/projects/demo/src/modules/customization/appearances/examples/1/index.less @@ -1,58 +1,50 @@ -@import '@taiga-ui/legacy/styles/taiga-ui-local'; +@import '@taiga-ui/core/styles/taiga-ui-local'; -[tuiWrapper][data-appearance='material-textfield'] { +tui-wrapper-example-1 { + --tui-background-accent-1: #6200ee; + --tui-background-accent-1-hover: #6e14ef; + --tui-background-accent-1-pressed: #6e14ef; + --tui-text-primary-on-accent-1: #fff; +} + +[tuiAppearance][data-appearance='material-textfield'] { + .transition(~'background, box-shadow'); background: #f5f5f5; + outline: none; color: rgba(0, 0, 0, 0.87); border-radius: 0.25rem 0.25rem 0 0; + box-shadow: inset 0 -1px #8e8e8e; - &:after { - .transition(all); - height: 0.0625rem; - background: #8e8e8e; - top: auto; - border: none; - transform-origin: bottom; - } - - .wrapper-hover({ + .appearance-hover({ background: #ececec; - - &:after { - background: #1f1f1f; - } + box-shadow: inset 0 -1px #1f1f1f; }); - .wrapper-focus({ + .appearance-focus({ background: #dcdcdc; + box-shadow: inset 0 -2px var(--tui-background-accent-1) !important; - // TODO: Better internal elements customization - label { - color: #6200ee !important; - } - - &:after { - background: #6200ee; - transform: scaleY(2); + ~ label { + --tui-text-primary: var(--tui-background-accent-1); } }); - .wrapper-invalid({ - // TODO: Better internal elements customization - label { - color: #b00020 !important; - } + &:invalid { + --tui-background-accent-1: #b00020; + box-shadow: inset 0 -1px var(--tui-background-accent-1) !important; - &:after { - background: #b00020; + ~ label { + --tui-text-primary: #b00020 !important; } - }); + } } [tuiAppearance][data-appearance='material-button'] { .transition(all); border-radius: 0.25rem; - background: #6200ee; - color: #fff; + background: var(--tui-background-accent-1); + color: var(--tui-text-primary-on-accent-1); + outline: none; text-transform: uppercase; font-weight: bold; box-shadow: @@ -61,34 +53,30 @@ 0rem 0.0625rem 0.3125rem 0rem rgba(0, 0, 0, 0.12); .appearance-hover({ - background: #6e14ef; + background: var(--tui-background-accent-1-hover); box-shadow: 0 0.125rem 0.25rem -0.0625rem rgba(0, 0, 0, 0.2), 0rem 0.25rem 0.3125rem 0rem rgba(0, 0, 0, 0.14), 0rem 0.0625rem 0.625rem 0rem rgba(0, 0, 0, 0.12); }); .appearance-active({ - background: #6e14ef; + background: var(--tui-background-accent-1-pressed); box-shadow: 0 0.3125rem 0.3125rem -0.1875rem rgba(0, 0, 0, 0.2), 0rem 0.5rem 0.625rem 0.0625rem rgba(0, 0, 0, 0.14), 0rem 0.1875rem 0.875rem 0.125rem rgba(0, 0, 0, 0.12); }); .appearance-focus({ background: #883df2; - - &:after { - display: none; - } }); } -[tuiAppearance][data-appearance='material-checkbox-on'], -[tuiAppearance][data-appearance='material-checkbox-off'] { - color: #fff; +[tuiAppearance][data-appearance='material-checkbox'] { + color: var(--tui-text-primary-on-accent-1); border-radius: 0.125rem; border: 0.125rem solid rgba(0, 0, 0, 0.54); + outline: none; &:after { - .transition(opacity); + .transition(all); content: ''; position: absolute; top: -0.625rem; @@ -98,28 +86,32 @@ border-radius: 100%; background: #000; opacity: 0; + transform: scale(0); } .appearance-hover({ &:after { opacity: 0.05; + transform: none; } }); .appearance-active({ &:after { opacity: 0.1; + transform: none; } }); .appearance-focus({ &:after { opacity: 0.1; + transform: none; } }); -} -[tuiAppearance][data-appearance='material-checkbox-on'] { - background: #6200ee; - border-color: transparent; + &:checked { + background: var(--tui-background-accent-1); + border-color: transparent; + } } diff --git a/projects/demo/src/modules/customization/appearances/examples/1/index.ts b/projects/demo/src/modules/customization/appearances/examples/1/index.ts new file mode 100644 index 000000000000..768d8fa849e7 --- /dev/null +++ b/projects/demo/src/modules/customization/appearances/examples/1/index.ts @@ -0,0 +1,30 @@ +import {Component, signal, ViewEncapsulation} from '@angular/core'; +import {FormsModule} from '@angular/forms'; +import { + TuiButton, + tuiButtonOptionsProvider, + TuiTextfield, + tuiTextfieldOptionsProvider, +} from '@taiga-ui/core'; +import {TuiCheckbox, tuiCheckboxOptionsProvider} from '@taiga-ui/kit'; + +@Component({ + standalone: true, + selector: 'tui-wrapper-example-1', + imports: [FormsModule, TuiCheckbox, TuiButton, TuiTextfield], + templateUrl: './index.html', + styleUrls: ['./index.less'], + encapsulation: ViewEncapsulation.None, + providers: [ + tuiButtonOptionsProvider({appearance: 'material-button', size: 's'}), + tuiCheckboxOptionsProvider({appearance: 'material-checkbox'}), + tuiTextfieldOptionsProvider({ + appearance: signal('material-textfield'), + cleaner: signal(false), + }), + ], +}) +export class TuiWrapperExample1 { + protected value = ''; + protected checkbox = false; +} diff --git a/projects/demo/src/modules/customization/appearances/index.html b/projects/demo/src/modules/customization/appearances/index.html new file mode 100644 index 000000000000..5b17a7c6345a --- /dev/null +++ b/projects/demo/src/modules/customization/appearances/index.html @@ -0,0 +1,75 @@ + +

+ Most Taiga UI components rely on + + Appearance + + directive to represent their interactive state — you will find + appearance + input on many components, such as + + Button + + , + + Chip + + , + + Notification + + etc. +

+

+ When you include Taiga UI theme what you do is define light and dark mode values for CSS + + variables + + and make built-in appearances, such as + primary + or + outline + , available to use in components. +

+

+ You can easily create your own appearances with the help of mixins (both LESS and SCSS) to define style rules + for particular states: +

+
    +
  • + + {{ item }} + +
  • +
+

+ Don't forget to import + @import '@taiga-ui/core/styles/taiga-ui-local'; +

+ + + + +
diff --git a/projects/demo/src/modules/customization/wrapper/index.ts b/projects/demo/src/modules/customization/appearances/index.ts similarity index 76% rename from projects/demo/src/modules/customization/wrapper/index.ts rename to projects/demo/src/modules/customization/appearances/index.ts index 9b2b22e46208..b2639d099493 100644 --- a/projects/demo/src/modules/customization/wrapper/index.ts +++ b/projects/demo/src/modules/customization/appearances/index.ts @@ -1,6 +1,7 @@ import {ClipboardModule} from '@angular/cdk/clipboard'; import {Component, ViewEncapsulation} from '@angular/core'; import {changeDetection} from '@demo/emulate/change-detection'; +import {DemoRoute} from '@demo/routes'; import {TuiDemo} from '@demo/utils'; import {TuiLink} from '@taiga-ui/core'; @@ -21,11 +22,11 @@ export default class Page { }; protected readonly mixins = [ - '.wrapper-hover(@ruleset)', - '.wrapper-active(@ruleset)', - '.wrapper-readonly(@ruleset)', - '.wrapper-disabled(@ruleset)', - '.wrapper-focus(@ruleset)', - '.wrapper-invalid(@ruleset)', + '.appearance-hover(@ruleset)', + '.appearance-active(@ruleset)', + '.appearance-disabled(@ruleset)', + '.appearance-focus(@ruleset)', ]; + + protected readonly routes = DemoRoute; } diff --git a/projects/demo/src/modules/customization/wrapper/examples/1/index.ts b/projects/demo/src/modules/customization/wrapper/examples/1/index.ts deleted file mode 100644 index 3be6ffa87ba7..000000000000 --- a/projects/demo/src/modules/customization/wrapper/examples/1/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {Component, ViewEncapsulation} from '@angular/core'; -import {FormsModule} from '@angular/forms'; -import {TuiButton, TuiLabel} from '@taiga-ui/core'; -import {TuiCheckbox, tuiCheckboxOptionsProvider} from '@taiga-ui/kit'; -import {TUI_TEXTFIELD_APPEARANCE_DIRECTIVE, TuiInputModule} from '@taiga-ui/legacy'; - -@Component({ - standalone: true, - selector: 'tui-wrapper-example-1', - imports: [TuiInputModule, FormsModule, TuiLabel, TuiCheckbox, TuiButton], - templateUrl: './index.html', - styleUrls: ['./index.less'], - encapsulation: ViewEncapsulation.None, - providers: [ - { - provide: TUI_TEXTFIELD_APPEARANCE_DIRECTIVE, - useValue: { - appearance: 'material-textfield', - }, - }, - tuiCheckboxOptionsProvider({ - appearance: (el) => - el.checked || el.indeterminate - ? 'material-checkbox-on' - : 'material-checkbox-off', - }), - ], -}) -export class TuiWrapperExample1 { - protected value = ''; - protected checkbox = false; -} diff --git a/projects/demo/src/modules/customization/wrapper/index.html b/projects/demo/src/modules/customization/wrapper/index.html deleted file mode 100644 index 4b802a70d7a8..000000000000 --- a/projects/demo/src/modules/customization/wrapper/index.html +++ /dev/null @@ -1,34 +0,0 @@ - -

- Many Taiga UI components use - tui-wrapper - component internally. It is responsible for display of various interactive states and is controlled with CSS. - Buttons provide a direct input for - appearance - while others, like input fields, are configurable through Dependency Injection. -

-

- Built-in appearances come with Taiga UI theme. You can extend or completely replace them with your own in global - non-encapsulated styles. Use the following mixins from - @import '@taiga-ui/core/styles/taiga-ui-local.less'; - : -

-
    -
  • - - {{ item }} - -
  • -
- - - - -
diff --git a/projects/demo/src/modules/directives/appearance/examples/3/index.less b/projects/demo/src/modules/directives/appearance/examples/3/index.less index c73ae9f07853..82e647b2a870 100644 --- a/projects/demo/src/modules/directives/appearance/examples/3/index.less +++ b/projects/demo/src/modules/directives/appearance/examples/3/index.less @@ -10,11 +10,11 @@ .fullsize(); content: ''; background: currentColor; - mask: url(https://taiga-ui.dev/assets/taiga-ui/icons/heart.svg) no-repeat center; + mask: url(/assets/taiga-ui/icons/heart.svg) no-repeat center; } &:checked:before { color: var(--tui-text-negative); - mask: url(https://taiga-ui.dev/assets/taiga-ui/icons/heart.svg) no-repeat center; + mask: url(/assets/taiga-ui/icons/heart-filled.svg) no-repeat center; } } diff --git a/projects/kit/components/checkbox/checkbox.component.ts b/projects/kit/components/checkbox/checkbox.component.ts index 9982862c4831..2bfa2dbaab60 100644 --- a/projects/kit/components/checkbox/checkbox.component.ts +++ b/projects/kit/components/checkbox/checkbox.component.ts @@ -69,7 +69,9 @@ export class TuiCheckbox implements OnInit, DoCheck { } public ngDoCheck(): void { - this.appearance.tuiAppearance = this.options.appearance(this.el); + this.appearance.tuiAppearance = tuiIsString(this.options.appearance) + ? this.options.appearance + : this.options.appearance(this.el); } protected getIcon(state: 'checked' | 'indeterminate'): string { diff --git a/projects/kit/components/checkbox/checkbox.options.ts b/projects/kit/components/checkbox/checkbox.options.ts index 5105d55d17af..dc44ff52145a 100644 --- a/projects/kit/components/checkbox/checkbox.options.ts +++ b/projects/kit/components/checkbox/checkbox.options.ts @@ -5,7 +5,7 @@ import type {TuiSizeS} from '@taiga-ui/core/types'; export interface TuiCheckboxOptions { readonly size: TuiSizeS; - readonly appearance: TuiStringHandler; + readonly appearance: TuiStringHandler | string; readonly icons: Readonly<{ checked: TuiStringHandler | string; indeterminate: TuiStringHandler | string; diff --git a/projects/kit/components/radio/radio.component.ts b/projects/kit/components/radio/radio.component.ts index 2bd6f241458d..14f8f8d9ffab 100644 --- a/projects/kit/components/radio/radio.component.ts +++ b/projects/kit/components/radio/radio.component.ts @@ -9,6 +9,7 @@ import { import {NgControl} from '@angular/forms'; import {TuiNativeValidator} from '@taiga-ui/cdk/directives/native-validator'; import {tuiInjectElement} from '@taiga-ui/cdk/utils/dom'; +import {tuiIsString} from '@taiga-ui/cdk/utils/miscellaneous'; import {TuiAppearance, TuiWithAppearance} from '@taiga-ui/core/directives/appearance'; import type {TuiSizeS} from '@taiga-ui/core/types'; @@ -39,6 +40,8 @@ export class TuiRadioComponent implements DoCheck { public size: TuiSizeS = this.options.size; public ngDoCheck(): void { - this.appearance.tuiAppearance = this.options.appearance(this.el); + this.appearance.tuiAppearance = tuiIsString(this.options.appearance) + ? this.options.appearance + : this.options.appearance(this.el); } } diff --git a/projects/kit/components/radio/radio.options.ts b/projects/kit/components/radio/radio.options.ts index 842c93d2a6cd..a9666603b530 100644 --- a/projects/kit/components/radio/radio.options.ts +++ b/projects/kit/components/radio/radio.options.ts @@ -4,7 +4,7 @@ import {tuiCreateToken, tuiProvideOptions} from '@taiga-ui/cdk/utils/miscellaneo import type {TuiSizeS} from '@taiga-ui/core/types'; export interface TuiRadioOptions { - readonly appearance: TuiStringHandler; + readonly appearance: TuiStringHandler | string; readonly size: TuiSizeS; }