diff --git a/projects/igniteui-angular/core/src/core/styles/components/grid-summary/_grid-summary-theme.scss b/projects/igniteui-angular/core/src/core/styles/components/grid-summary/_grid-summary-theme.scss index 716d32d1ffc..51f95f417c5 100644 --- a/projects/igniteui-angular/core/src/core/styles/components/grid-summary/_grid-summary-theme.scss +++ b/projects/igniteui-angular/core/src/core/styles/components/grid-summary/_grid-summary-theme.scss @@ -44,7 +44,7 @@ outline-style: none; @if $variant == 'indigo' { - border-top: rem(1px) solid var-get($theme, 'border-color'); + border-top: var-get($theme, 'border-width') var-get($theme, 'border-style') var-get($theme, 'border-color'); } } diff --git a/projects/igniteui-angular/core/src/core/styles/themes/_standalone.scss b/projects/igniteui-angular/core/src/core/styles/themes/_standalone.scss index f9a5e4fbe6f..dfdf5574cd3 100644 --- a/projects/igniteui-angular/core/src/core/styles/themes/_standalone.scss +++ b/projects/igniteui-angular/core/src/core/styles/themes/_standalone.scss @@ -2,6 +2,7 @@ @use 'sass:map'; @use 'igniteui-theming/sass/bem' as *; @use 'igniteui-theming/sass/themes' as *; +@use 'igniteui-theming/sass/themes/schemas' as schemas; @forward 'igniteui-theming/sass/themes'; @forward 'igniteui-theming/sass/bem'; @@ -98,3 +99,16 @@ @return ($map-1, $map-2); } + +/// All theme/variant/schema combinations used by derived component styles. +/// @access private +$derived-schemas: ( + ('material', 'light', schemas.$light-material-schema), + ('material', 'dark', schemas.$dark-material-schema), + ('bootstrap', 'light', schemas.$light-bootstrap-schema), + ('bootstrap', 'dark', schemas.$dark-bootstrap-schema), + ('fluent', 'light', schemas.$light-fluent-schema), + ('fluent', 'dark', schemas.$dark-fluent-schema), + ('indigo', 'light', schemas.$light-indigo-schema), + ('indigo', 'dark', schemas.$dark-indigo-schema), +); diff --git a/projects/igniteui-angular/grids/core/src/column-actions/column-actions.component.scss b/projects/igniteui-angular/grids/core/src/column-actions/column-actions.component.scss index dd684163cd7..30d99ab12d3 100644 --- a/projects/igniteui-angular/grids/core/src/column-actions/column-actions.component.scss +++ b/projects/igniteui-angular/grids/core/src/column-actions/column-actions.component.scss @@ -2,3 +2,4 @@ @use 'themes/shared'; @use 'themes/light'; @use 'themes/dark'; +@use 'themes/derived'; diff --git a/projects/igniteui-angular/grids/core/src/column-actions/themes/_base.scss b/projects/igniteui-angular/grids/core/src/column-actions/themes/_base.scss index bc0294c0de7..4963996f5eb 100644 --- a/projects/igniteui-angular/grids/core/src/column-actions/themes/_base.scss +++ b/projects/igniteui-angular/grids/core/src/column-actions/themes/_base.scss @@ -12,7 +12,7 @@ $_theme: $material; @include b(igx-column-actions) { display: flex; flex-flow: column nowrap; - background: var-get($_theme, 'background-color'); + background: var-get($_theme, 'background'); box-shadow: var(--ig-elevation-8); width: 100%; flex: 1 1 auto; diff --git a/projects/igniteui-angular/grids/core/src/column-actions/themes/_derived.scss b/projects/igniteui-angular/grids/core/src/column-actions/themes/_derived.scss new file mode 100644 index 00000000000..c824486f38a --- /dev/null +++ b/projects/igniteui-angular/grids/core/src/column-actions/themes/_derived.scss @@ -0,0 +1,81 @@ +@use 'sass:map'; +@use 'igniteui-theming/sass/themes' as *; +@use 'styles/themes/standalone' as *; + +/// Applies all sub-component token overrides used by the column-actions component. +/// @access private + +@each $theme-name, $variant-name, $schema in $derived-schemas { + @include layer(derived) { + @scope ([data-ig-theme='#{$theme-name}'][data-ig-theme-variant='#{$variant-name}']) { + :where(igx-column-actions) { + --_column-actions-background: var(--background, var(--ig-column-actions-background)); + --_column-actions-foreground: var(--foreground, var(--ig-column-actions-foreground)); + --_column-actions-accent-color: var(--accent-color, var(--ig-column-actions-accent-color)); + + @include tokens( + checkbox-theme( + $schema: $schema, + $empty-color: color-mix(in srgb, var(--_column-actions-foreground) 80%, var(--_column-actions-background)), + $empty-fill-color: var(--_column-actions-background), + $tick-color-hover: color-mix(in srgb, var(--_column-actions-foreground) 40%, var(--_column-actions-background)), + $fill-color: var(--_column-actions-accent-color), + $label-color: var(--_column-actions-foreground), + $disabled-color: color-mix(in srgb, var(--_column-actions-foreground) 50%, var(--_column-actions-background)), + ) + ); + + @include tokens( + drop-down-theme( + $schema: $schema, + $background-color: var(--_column-actions-background), + $item-text-color: var(--_column-actions-foreground), + $border-color: color-mix(in srgb, var(--_column-actions-foreground) 12%, var(--_column-actions-background)), + $hover-item-background: color-mix(in srgb, var(--_column-actions-accent-color) 8%, var(--_column-actions-background)), + $focused-item-background: color-mix(in srgb, var(--_column-actions-accent-color) 12%, var(--_column-actions-background)), + $selected-item-background: color-mix(in srgb, var(--_column-actions-accent-color) 12%, var(--_column-actions-background)), + $selected-hover-item-background: color-mix(in srgb, var(--_column-actions-accent-color) 16%, var(--_column-actions-background)), + $selected-focus-item-background: color-mix(in srgb, var(--_column-actions-accent-color) 24%, var(--_column-actions-background)), + ) + ); + + @include tokens( + flat-button-theme( + $schema: $schema, + $foreground: var(--_column-actions-accent-color), + $disabled-background: transparent, + $disabled-foreground: color-mix(in srgb, var(--_column-actions-accent-color) 50%, var(--_column-actions-background)), + ) + ); + + @include tokens( + input-group-theme( + $schema: $schema, + $idle-bottom-line-color: var(--_column-actions-accent-color), + $border-color: var(--_column-actions-accent-color), + $idle-text-color: var(--_column-actions-foreground), + $placeholder-color: color-mix(in srgb, var(--_column-actions-foreground) 80%, var(--_column-actions-background)), + ) + ); + + $scrollbar-theme: digest-schema(map.get($schema, 'scrollbar')); + $scrollbar-bg-color: map.get($scrollbar-theme, 'sb-track-bg-color'); + $scrollbar-thumb-color: map.get($scrollbar-theme, 'sb-thumb-bg-color'); + $scrollbar-track-border-color: map.get($scrollbar-theme, 'sb-track-border-color'); + + --_scrollbar-thumb-color: color-mix(in srgb, var(--_column-actions-foreground) 50%, var(--_column-actions-background)); + --_scrollbar-track-border-color: color-mix(in srgb, var(--_column-actions-foreground) 16%, var(--_column-actions-background)); + + @include tokens( + scrollbar-theme( + $schema: $schema, + $sb-track-bg-color: var(--_column-actions-background, $scrollbar-bg-color), + $sb-thumb-bg-color: var(--_scrollbar-thumb-color, $scrollbar-thumb-color), + $sb-track-border-color: var(--_scrollbar-track-border-color, $scrollbar-track-border-color), + ), + $mode: 'scoped' + ); + } + } + } +} diff --git a/projects/igniteui-angular/grids/core/src/filtering/excel-style/excel-style-filtering.component.scss b/projects/igniteui-angular/grids/core/src/filtering/excel-style/excel-style-filtering.component.scss index dd684163cd7..30d99ab12d3 100644 --- a/projects/igniteui-angular/grids/core/src/filtering/excel-style/excel-style-filtering.component.scss +++ b/projects/igniteui-angular/grids/core/src/filtering/excel-style/excel-style-filtering.component.scss @@ -2,3 +2,4 @@ @use 'themes/shared'; @use 'themes/light'; @use 'themes/dark'; +@use 'themes/derived'; diff --git a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/_base.scss b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/_base.scss index 95375a431e5..ffb07ec5bc3 100644 --- a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/_base.scss +++ b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/_base.scss @@ -38,19 +38,23 @@ $checkbox-indent: ( padding-inline: pad-inline(rem(4px), rem(8px), rem(16px)); cursor: pointer; - // TODO MOVE excel-filtering-actions-foreground TO THE FILTERING SCHEMA and use it here. - //color: var-get($theme, 'excel-filtering-actions-foreground'); - color: color($color: 'gray', $variant: 700); + color: var-get($theme, 'actions-foreground'); outline-style: none; + igx-icon { + color: var-get($theme, 'actions-icon-color'); + } + &:hover, &:focus { - // TODO MOVE excel-filtering-actions-hover-foreground TO THE FILTERING SCHEMA and use it here. - //color: var-get($theme, 'excel-filtering-actions-hover-foreground'); - color: color($color: 'gray', $variant: 700); + color: var-get($theme, 'actions-hover-foreground'); + + background: var-get($theme, 'actions-hover-background'); - background: color($color: 'gray', $variant: 100); + igx-icon { + color: var-get($theme, 'actions-hover-icon-color'); + } } [dir='rtl'] & { @@ -78,9 +82,7 @@ $checkbox-indent: ( header { @include type-style('overline'); - // TODO MOVE excel-filtering-subheader-foreground TO THE FILTERING SCHEMA and use it here. - //color: var-get($theme, 'excel-filtering-subheader-foreground'); - color: color($color: 'gray', $variant: 700); + color: var-get($theme, 'subheader-foreground'); margin-block-end: rem(4px); } @@ -105,7 +107,7 @@ $checkbox-indent: ( height: 100%; flex-grow: 1; box-shadow: elevation(12); - background: var(--filtering-row-background); + background: var-get($theme, 'background'); @include e(sizing) { @include sizable(); @@ -124,31 +126,7 @@ $checkbox-indent: ( // TODO: The border-radius should not be hardcoded. border-radius: border-radius(rem(4px)); - background: var(--filtering-row-background); - - .igx-button-group { - --elevation: none !important; - - - --item-background: var(--filtering-row-background); - - --item-hover-background: #{color($color: 'gray', $variant: 100)} !important; - --item-selected-background: #{color($color: 'gray', $variant: 100)} !important; - --item-text-color: #{color($color: 'gray', $variant: 700)} !important; - --item-icon-color: #{color($color: 'gray', $variant: 700)} !important; - --item-hover-text-color: #{color($color: 'gray', $variant: 800)} !important; - --item-hover-icon-color: #{color($color: 'gray', $variant: 800)} !important; - --item-selected-text-color: color($color: 'secondary', $variant: 500) !important; - --item-selected-icon-color: color($color: 'secondary', $variant: 500) !important; - --item-selected-hover-icon-color: contrast-color($color: 'gray', $variant: 50) !important; - --item-border-color: transparent !important; - --item-hover-border-color: transparent !important; - --item-focused-border-color: transparent !important; - --item-selected-border-color: transparent !important; - --item-selected-hover-border-color: transparent !important; - --item-disabled-border: transparent !important; - --disabled-selected-border-color: transparent !important; - } + background: var-get($theme, 'background'); .igx-tree-node__wrapper { padding: 0; @@ -183,9 +161,7 @@ $checkbox-indent: ( @include type-style('h6'); } - // TODO MOVE excel-filtering-header-foreground TO THE FILTERING SCHEMA and use it here. - //color: var-get($theme, 'excel-filtering-header-foreground'); - color: color($color: 'gray', $variant: 700); + color: var-get($theme, 'header-foreground'); } @include e(menu-main) { @@ -201,19 +177,19 @@ $checkbox-indent: ( overflow: hidden; margin-inline: calc(#{sizable(rem(-4px), rem(-8px), rem(-16px))} * -1); border: 0; - border-top: rem(1px) dashed color($color: 'gray', $variant: 300); - border-bottom: rem(1px) dashed color($color: 'gray', $variant: 300); + border-top: rem(1px) dashed var-get($theme, 'border-color'); + border-bottom: rem(1px) dashed var-get($theme, 'border-color'); } } @include e(tree) { - background: color($color: 'surface'); + background: var-get($theme, 'secondary-background'); overflow-y: auto; margin-inline: calc(#{pad-inline(rem(-4px), rem(-8px), rem(-16px))} * -1); margin-block: 0; flex: 1; - border-top: rem(1px) dashed color($color: 'gray', $variant: 300); - border-bottom: rem(1px) dashed color($color: 'gray', $variant: 300); + border-top: rem(1px) dashed var-get($theme, 'border-color'); + border-bottom: rem(1px) dashed var-get($theme, 'border-color'); igx-icon { width: var(--ig-icon-size, #{$tree-node-expander-size}); @@ -252,7 +228,7 @@ $checkbox-indent: ( } @include e(tree-alike) { - background: color($color: 'surface'); + background: var-get($theme, 'secondary-background'); display: flex; flex-direction: column; z-index: 1; @@ -266,11 +242,11 @@ $checkbox-indent: ( map.get($tree-node-height, 'cosy'), map.get($tree-node-height, 'comfortable') ); - background: color($color: 'surface'); + background: var-get($theme, 'secondary-background'); &:hover, &:focus { - background: color($color: 'gray', $variant: 200); + background: color-mix(in srgb, var(--_excel-filtering-foreground) 12%, var-get($theme, 'background')); } > igx-checkbox { @@ -311,9 +287,7 @@ $checkbox-indent: ( @include e(actions-pin, $m: disabled) { @extend %grid-excel-actions__action !optional; - // TODO MOVE excel-filtering-actions-disabled-foreground TO THE FILTERING SCHEMA and use it here. - //color: var-get($theme, 'excel-filtering-actions-disabled-foreground'); - color: color($color: 'gray', $variant: 400); + color: var-get($theme, 'actions-disabled-foreground'); pointer-events: none; } @@ -334,7 +308,7 @@ $checkbox-indent: ( @extend %grid-excel-actions__action !optional; igx-icon { - color: color($color: 'secondary', $variant: 500); + color: var-get($theme, 'actions-selected-icon-color'); } } @@ -345,11 +319,8 @@ $checkbox-indent: ( @include e(actions-filter, $m: active) { @extend %grid-excel-actions__action !optional; - background: color($color: 'gray', $variant: 100); - - // TODO MOVE excel-filtering-actions-hover-foreground TO THE FILTERING SCHEMA and use it here. - //color: var-get($theme, 'excel-filtering-actions-hover-foreground'); - color: color($color: 'gray', $variant: 700); + background: color-mix(in srgb, var(--_excel-filtering-accent-color) 8%, var-get($theme, 'background')); + color: var-get($theme, 'actions-hover-foreground'); } @include e(actions-clear) { @@ -359,9 +330,7 @@ $checkbox-indent: ( @include e(actions-clear, $m: disabled) { @extend %grid-excel-actions__action !optional; - // TODO MOVE excel-filtering-actions-disabled-foreground TO THE FILTERING SCHEMA and use it here. - //color: var-get($theme, 'excel-filtering-actions-disabled-foreground'); - color: color($color: 'gray', $variant: 400); + color: var-get($theme, 'actions-disabled-foreground'); pointer-events: none; } @@ -374,7 +343,11 @@ $checkbox-indent: ( // Filtering @include e(secondary-header) { - border-block-end: rem(1px) solid color($color: 'gray', $variant: 300); + display: flex; + align-items: center; + padding: pad(rem(4px), rem(8px), rem(16px)); + color: var-get($theme, 'header-foreground'); + border-block-end: rem(1px) solid var-get($theme, 'border-color'); > h4 { @include type-style('h6') @@ -415,6 +388,11 @@ $checkbox-indent: ( } @include e(menu, $m: compact) { + .igx-excel-filter__actions-select, + .igx-excel-filter__actions-selected { + justify-content: center; + } + .igx-excel-filter__sort { @extend %grid-excel-action--compact; @@ -424,10 +402,12 @@ $checkbox-indent: ( header { @include type-style('body-2'); + + text-transform: capitalize; } } - igx-excel-filter__move { + .igx-excel-filter__move { @extend %grid-excel-action--compact; igx-buttongroup { @@ -438,15 +418,14 @@ $checkbox-indent: ( @include type-style('body-2'); text-transform: capitalize; - } } - .igx-excel-filter__menu-header { + .igx-excel-filter__menu-header > h4 { @include type-style('subtitle-1') } - .igx-excel-filter__menu-header-actions { + .igx-excel-filter__menu-header-actions { span { @include type-style('body-2'); } @@ -457,8 +436,96 @@ $checkbox-indent: ( } } + @include e(menu, $m: cosy) { + .igx-excel-filter__actions-select, + .igx-excel-filter__actions-selected { + justify-content: center; + } + } + @include e(clear) { flex-grow: 1; } + + @include e(secondary) { + --component-size: var(--ig-size, var(--ig-size-large)); + + width: rem(520px); + min-width: rem(520px); + background: var-get($theme, 'background'); + box-shadow: elevation(12); + border-radius: border-radius(rem(4px)); + display: flex; + flex-direction: column; + } + + @include e(secondary-main) { + height: rem(232px); + overflow: auto; + } + + @include e(secondary-footer) { + --ig-size: 2; + + display: flex; + justify-content: space-between; + padding-inline: pad-inline(rem(24px)); + padding-block-end: pad-block(rem(24px)); + + .igx-excel-filter__clear { + flex-grow: 1; + } + + .igx-excel-filter__apply, + .igx-excel-filter__cancel { + flex-grow: 0; + } + } + + @include e(cancel) { + + .igx-excel-filter__apply { + margin-inline-start: rem(16px); + } + } + + @include e(condition) { + display: flex; + flex-wrap: wrap; + align-items: center; + padding-inline: pad-inline(rem(4px), rem(8px), rem(16px)); + padding-block: 0; + + igx-select { + flex-grow: 1; + flex-basis: 40%; + margin-block: rem(16px); + + ~ igx-input-group, + ~ igx-date-picker, + ~ igx-time-picker { + margin-inline-start: rem(16px); + } + } + + igx-buttongroup { + min-width: 30%; + } + + [igxIconButton] { + --component-size: var(--ig-size, var(--ig-size-large)); + margin-inline-start: rem(16px); + } + } + + @include e(add-filter) { + margin-inline: pad-inline(rem(4px), rem(4px), rem(16px)); + margin-block-start: 0; + + igx-icon { + width: var(--ig-icon-size, #{rem(18px)}); + height: var(--ig-icon-size, #{rem(18px)}); + font-size: var(--ig-icon-size, #{rem(18px)}); + } + } } } diff --git a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/_derived.scss b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/_derived.scss new file mode 100644 index 00000000000..b9ea994af47 --- /dev/null +++ b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/_derived.scss @@ -0,0 +1,191 @@ +@use 'sass:map'; +@use 'igniteui-theming/sass/themes' as *; +@use 'igniteui-theming/sass/color' as *; +@use 'styles/themes/standalone' as *; + +/// Applies all sub-component token overrides used by the excel style filtering. +/// @access private +@each $theme-name, $variant-name, $schema in $derived-schemas { + @include layer(derived) { + @scope ([data-ig-theme='#{$theme-name}'][data-ig-theme-variant='#{$variant-name}']) { + :where( + igx-grid-excel-style-filtering, + .igx-excel-filter__secondary + ) { + --_excel-filtering-background: var(--background, var(--ig-excel-filtering-background)); + --_excel-filtering-secondary-background: var(--secondary-background, var(--ig-excel-filtering-secondary-background)); + --_excel-filtering-foreground: var(--foreground, var(--ig-excel-filtering-foreground)); + --_excel-filtering-accent-color: var(--accent-color, var(--ig-excel-filtering-accent-color)); + + .igx-excel-filter__menu .igx-button-group, + .igx-button-group { + --ig-btn-group-selected-bg: color-mix(in srgb, var(--_excel-filtering-accent-color) 8%, var(--_excel-filtering-background)); + + @include tokens( + button-group-theme( + $schema: $schema, + $item-background: transparent, + $item-border-color: transparent, + $item-text-color: var(--_excel-filtering-foreground, #{color($color: 'gray', $variant: 700)}), + $item-selected-background: if( + $theme-name == 'indigo', + var(--ig-btn-group-selected-bg, var(--ig-primary-500)), + var(--ig-btn-group-selected-bg, #{color($color: 'gray', $variant: 100)}), + ), + $item-hover-background: var(--item-selected-background), + $item-hover-text-color: var(--_excel-filtering-foreground, #{color($color: 'gray', $variant: 700)}), + $item-active-border-color: transparent, + $item-selected-text-color: var(--_excel-filtering-accent-color, #{if( + $theme-name == 'indigo', + contrast-color($color: 'primary'), + if($theme-name == 'material', + color($color: 'secondary', $variant: 500), + color($color: 'primary', $variant: 500) + ) + )}), + $item-selected-active-border-color: transparent, + $item-selected-hover-text-color: var(--_excel-filtering-accent-color, #{if( + $theme-name == 'indigo', + contrast-color($color: 'primary'), + if($theme-name == 'material', + color($color: 'secondary', $variant: 500), + color($color: 'primary', $variant: 500) + ) + )}), + $item-selected-hover-background: dynamic-shade(var(--item-hover-background), $offset: 3), + $shadow: none + ), + $mode: 'scoped' + ); + } + + @include tokens( + contained-button-theme( + $schema: $schema, + $background: var(--_excel-filtering-accent-color), + $disabled-background: color-mix(in srgb, var(--_excel-filtering-accent-color) 50%, var(--_excel-filtering-background)), + $disabled-foreground: color-mix(in srgb, var(--_excel-filtering-foreground) 50%, var(--_excel-filtering-background)), + ) + ); + + @include tokens( + flat-button-theme( + $schema: $schema, + $foreground: var(--_excel-filtering-accent-color), + $disabled-background: transparent, + $disabled-foreground: color-mix(in srgb, var(--_excel-filtering-accent-color) 50%, var(--_excel-filtering-background)), + ) + ); + + @include tokens( + checkbox-theme( + $schema: $schema, + $empty-color: color-mix(in srgb, var(--_excel-filtering-foreground) 80%, var(--_excel-filtering-background)), + $empty-fill-color: transparent, + $tick-color-hover: color-mix(in srgb, var(--_excel-filtering-foreground) 40%, var(--_excel-filtering-background)), + $fill-color: var(--_excel-filtering-accent-color), + $label-color: var(--_excel-filtering-foreground), + $disabled-color: color-mix(in srgb, var(--_excel-filtering-foreground) 50%, var(--_excel-filtering-background)), + ) + ); + + @include tokens( + drop-down-theme( + $schema: $schema, + $background-color: var(--_excel-filtering-background), + $item-text-color: var(--_excel-filtering-foreground), + $border-color: color-mix(in srgb, var(--_excel-filtering-foreground) 12%, var(--_excel-filtering-background)), + $hover-item-background: color-mix(in srgb, var(--_excel-filtering-accent-color) 8%, var(--_excel-filtering-background)), + $focused-item-background: color-mix(in srgb, var(--_excel-filtering-accent-color) 12%, var(--_excel-filtering-background)), + $selected-item-background: color-mix(in srgb, var(--_excel-filtering-accent-color) 12%, var(--_excel-filtering-background)), + $selected-hover-item-background: color-mix(in srgb, var(--_excel-filtering-accent-color) 16%, var(--_excel-filtering-background)), + $selected-focus-item-background: color-mix(in srgb, var(--_excel-filtering-accent-color) 24%, var(--_excel-filtering-background)), + ) + ); + + @if $theme-name == 'material' { + @include tokens( + input-group-theme( + $schema: $schema, + $box-background: var(--_excel-filtering-background), + $idle-bottom-line-color: var(--_excel-filtering-accent-color), + $idle-text-color: var(--_excel-filtering-foreground), + $placeholder-color: color-mix(in srgb, var(--_excel-filtering-foreground) 80%, var(--_excel-filtering-background)), + ) + ); + } @else if $theme-name == 'indigo' { + @include tokens( + input-group-theme( + $schema: $schema, + $idle-bottom-line-color: var(--_excel-filtering-accent-color), + $idle-text-color: var(--_excel-filtering-foreground), + $placeholder-color: color-mix(in srgb, var(--_excel-filtering-foreground) 80%, var(--_excel-filtering-background)), + ) + ); + } @else { + @include tokens( + input-group-theme( + $schema: $schema, + $border-color: var(--_excel-filtering-accent-color), + $idle-text-color: var(--_excel-filtering-foreground), + $placeholder-color: color-mix(in srgb, var(--_excel-filtering-foreground) 80%, var(--_excel-filtering-background)), + $input-prefix-background: var(--_excel-filtering-accent-color), + ) + ); + } + + @if $theme-name == 'indigo' { + @include tokens( + select-theme( + $schema: $schema, + $toggle-button-foreground: var(--_excel-filtering-accent-color), + $toggle-button-foreground-disabled: color-mix(in srgb, var(--_excel-filtering-accent-color) 50%, var(--_excel-filtering-background)), + ) + ); + } @else { + @include tokens( + select-theme( + $schema: $schema, + $toggle-button-background: var(--_excel-filtering-accent-color), + ) + ); + } + + @include tokens( + flat-icon-button-theme( + $schema: $schema, + $foreground: var(--_excel-filtering-foreground), + $disabled-background: transparent, + $disabled-foreground: color-mix(in srgb, var(--_excel-filtering-accent-color) 50%, var(--_excel-filtering-background)), + ) + ); + + @include tokens( + list-theme( + $schema: $schema, + $background: var(--_excel-filtering-secondary-background), + $item-background-hover: color-mix(in srgb, var(--_excel-filtering-accent-color) 8%, var(--_excel-filtering-background)) + ) + ); + + $scrollbar-theme: digest-schema(map.get($schema, 'scrollbar')); + $scrollbar-bg-color: map.get($scrollbar-theme, 'sb-track-bg-color'); + $scrollbar-thumb-color: map.get($scrollbar-theme, 'sb-thumb-bg-color'); + $scrollbar-track-border-color: map.get($scrollbar-theme, 'sb-track-border-color'); + + --_scrollbar-thumb-color: color-mix(in srgb, var(--_excel-filtering-foreground) 50%, var(--_excel-filtering-background)); + --_scrollbar-track-border-color: color-mix(in srgb, var(--_excel-filtering-foreground) 16%, var(--_excel-filtering-background)); + + @include tokens( + scrollbar-theme( + $schema: $schema, + $sb-track-bg-color: var(--_excel-filtering-background, $scrollbar-bg-color), + $sb-thumb-bg-color: var(--_scrollbar-thumb-color, $scrollbar-thumb-color), + $sb-track-border-color: var(--_scrollbar-track-border-color, $scrollbar-track-border-color), + ), + $mode: 'scoped' + ); + } + } + } +} diff --git a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/dark/_index.scss b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/dark/_index.scss index c6dfd747325..859431fb689 100644 --- a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/dark/_index.scss +++ b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/dark/_index.scss @@ -1,7 +1,7 @@ @use 'sass:meta'; @use 'tokens'; @use 'styles/themes/standalone' as *; -@use 'indigo'; $tokens: meta.module-variables(tokens); @include themes(igx-excel-filter, $tokens, dark); +@include themes(igx-excel-filter__secondary, $tokens, dark); diff --git a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/dark/_indigo.scss b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/dark/_indigo.scss deleted file mode 100644 index 5fe4866f646..00000000000 --- a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/dark/_indigo.scss +++ /dev/null @@ -1,81 +0,0 @@ -@use 'igniteui-theming/sass/bem' as *; -@use 'igniteui-theming/sass/color/functions' as *; -@use 'igniteui-theming/sass/typography/functions' as *; -@use 'igniteui-theming/sass/elevations' as *; -@use 'styles/themes/standalone' as *; - -@include themed-block(igx-excel-filter, indigo, dark) { - %grid-excel-actions__action { - background: contrast-color($color: 'gray', $variant: 50, $opacity: .1); - - &:hover, - &:focus { - igx-icon { - color: contrast-color($color: 'gray', $variant: 50, $opacity: .8); - - } - } - - igx-icon { - color: contrast-color($color: 'gray', $variant: 50, $opacity: .6); - } - } - - @include e(actions-pin) { - @extend %grid-excel-actions__action !optional; - } - - @include e(actions-pin, $m: disabled) { - @extend %grid-excel-actions__action !optional; - } - - @include e(actions-unpin) { - @extend %grid-excel-actions__action !optional; - } - - @include e(actions-hide) { - @extend %grid-excel-actions__action !optional; - } - - @include e(actions-select) { - @extend %grid-excel-actions__action !optional; - } - - @include e(actions-selected) { - @extend %grid-excel-actions__action !optional; - } - - @include e(actions-filter) { - @extend %grid-excel-actions__action !optional; - } - - @include e(actions-filter, $m: active) { - @extend %grid-excel-actions__action !optional; - } - - @include e(actions-clear) { - @extend %grid-excel-actions__action !optional; - } - - @include e(actions-clear, $m: disabled) { - @extend %grid-excel-actions__action !optional; - } - - @include e(menu) { - background: color($color: 'gray', $variant: 50); - - .igx-button-group { - --item-text-color: #{contrast-color($color: 'surface', $variant: 500)}; - } - } - - @include e(menu-main) { - border-block: rem(1px) dashed color($color: 'gray', $variant: 100); - } - - @include e(tree) { - %igx-excel-filter__tree { - border-block: rem(1px) dashed color($color: 'gray', $variant: 100); - } - } -} diff --git a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/dark/_tokens.scss b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/dark/_tokens.scss index e2944e3883f..702fb205540 100644 --- a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/dark/_tokens.scss +++ b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/dark/_tokens.scss @@ -1,7 +1,7 @@ @use 'igniteui-theming/sass/themes' as *; -@use 'igniteui-theming/sass/themes/schemas/components/dark/grid-filtering' as *; +@use 'igniteui-theming/sass/themes/schemas/components/dark/grid-excel-filtering' as *; -$material: digest-schema($dark-material-grid-filtering); -$bootstrap: digest-schema($dark-bootstrap-grid-filtering); -$fluent: digest-schema($dark-fluent-grid-filtering); -$indigo: digest-schema($dark-indigo-grid-filtering); +$material: digest-schema($dark-material-excel-filtering); +$bootstrap: digest-schema($dark-bootstrap-excel-filtering); +$fluent: digest-schema($dark-fluent-excel-filtering); +$indigo: digest-schema($dark-indigo-excel-filtering); diff --git a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/light/_index.scss b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/light/_index.scss index 7aa5f25945f..3bc7c216688 100644 --- a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/light/_index.scss +++ b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/light/_index.scss @@ -4,3 +4,4 @@ $tokens: meta.module-variables(tokens); @include themes(igx-excel-filter, $tokens, light); +@include themes(igx-excel-filter__secondary, $tokens, light); diff --git a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/light/_tokens.scss b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/light/_tokens.scss index c481da18361..6158e7a3661 100644 --- a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/light/_tokens.scss +++ b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/light/_tokens.scss @@ -1,8 +1,8 @@ @use 'igniteui-theming/sass/themes' as *; -@use 'igniteui-theming/sass/themes/schemas/components/light/grid-filtering' as *; +@use 'igniteui-theming/sass/themes/schemas/components/light/grid-excel-filtering' as *; -$base: digest-schema($light-grid-filtering); -$material: digest-schema($material-grid-filtering); -$bootstrap: digest-schema($bootstrap-grid-filtering); -$fluent: digest-schema($fluent-grid-filtering); -$indigo: digest-schema($indigo-grid-filtering); +$base: digest-schema($light-excel-filtering); +$material: digest-schema($material-excel-filtering); +$bootstrap: digest-schema($bootstrap-excel-filtering); +$fluent: digest-schema($fluent-excel-filtering); +$indigo: digest-schema($indigo-excel-filtering); diff --git a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/shared/_bootstrap.scss b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/shared/_bootstrap.scss index 06e696ef72c..52b78c1b26f 100644 --- a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/shared/_bootstrap.scss +++ b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/shared/_bootstrap.scss @@ -3,22 +3,26 @@ @use 'igniteui-theming/sass/typography/mixins' as *; @use 'igniteui-theming/sass/color/functions' as *; @use 'styles/themes/standalone' as *; +@use '../light/tokens' as *; + +$_theme: $bootstrap; +$derived-border-color: color-mix(in srgb, var(--ig-excel-filtering-accent-color) 16%, var(--ig-excel-filtering-background)); @include themed-block(igx-excel-filter, bootstrap) { @include e(secondary-header) { - border-block-end: rem(1px) solid color($color: 'gray', $variant: 100); + border-block-end: rem(1px) solid var-get($_theme, 'border-color'); } @include e(secondary-footer) { padding-inline: pad-inline(rem(16px)); padding-block: pad-block(rem(16px)); - border-top: rem(1px) solid color($color: 'gray', $variant: 300); + border-top: rem(1px) solid var-get($_theme, 'border-color'); } @include e(menu-main) { igx-list { - border-top: rem(1px) dashed var(--ig-gray-100); - border-bottom: rem(1px) dashed var(--ig-gray-100); + --_border-color: #{$derived-border-color}; + border-block: rem(1px) dashed var(--_border-color, var(--ig-gray-100)); } } diff --git a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/shared/_fluent.scss b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/shared/_fluent.scss index b702498a688..2390ee8a08c 100644 --- a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/shared/_fluent.scss +++ b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/shared/_fluent.scss @@ -1,12 +1,4 @@ -@use 'igniteui-theming/sass/bem' as *; -@use 'igniteui-theming/sass/typography/functions' as *; @use 'styles/themes/standalone' as *; @include themed-block(igx-excel-filter, fluent) { - @include m(menu) { - .igx-button-group { - --item-selected-hover-icon-color: color($color: 'secondary', $variant: 500); - --item-focused-border-color: color($color: 'gray', $variant: 700); - } - } } diff --git a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/shared/_indigo.scss b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/shared/_indigo.scss index afec9a7451a..b1371e0e89a 100644 --- a/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/shared/_indigo.scss +++ b/projects/igniteui-angular/grids/core/src/filtering/excel-style/themes/shared/_indigo.scss @@ -1,12 +1,17 @@ @use 'igniteui-theming/sass/bem' as *; @use 'igniteui-theming/sass/typography' as *; @use 'igniteui-theming/sass/color/functions' as *; +@use 'igniteui-theming/sass/elevations' as *; @use 'styles/themes/standalone' as *; +@use '../light/tokens' as *; + +$_theme: $indigo; // TODO type style is throwing an error @include themed-block(igx-excel-filter, indigo) { - box-shadow: elevation(3); + box-shadow: elevation(3), 0 0 0 rem(1px) var-get($_theme, 'border-color'); + border-radius: border-radius(rem(4px)); %grid-excel-actions__action { padding-block: pad-block(rem(4px), rem(6px), rem(8px)); @@ -15,12 +20,18 @@ margin-block-end: rem(4px); border-radius: rem(4px); + igx-icon { + --component-size: 2; + + color: var-get($_theme, 'actions-icon-color'); + } + &:hover, &:focus { - background: color($color: 'gray', $variant: 200); + background: var-get($_theme, 'actions-hover-background'); igx-icon { - color: color($color: 'gray', $variant: 700); + color: var-get($_theme, 'actions-hover-icon-color'); } } @@ -28,7 +39,7 @@ igx-icon { --component-size: 2; - color: color($color: 'gray', $variant: 600); + // color: color($color: 'gray', $variant: 600); } } @@ -86,28 +97,13 @@ } @include e(menu) { - background: contrast-color($color: 'gray', $variant: 900); + background: var-get($_theme, 'background'); .igx-button-group__item { &:not(:nth-child(1)) { margin: 0; } } - - .igx-button-group { - --item-background: transparent !important; - --border-color: transparent !important; - --item-border-color: transparent !important; - --item-focused-border-color: transparent !important; - --item-hover-border-color: transparent !important; - --item-selected-border-color: transparent !important; - --item-selected-hover-border-color: transparent !important; - --item-disabled-border: transparent !important; - --disabled-selected-border-color: transparent !important; - --elevation: none !important; - --item-selected-text-color: contrast-color($color: 'surface') !important; - --item-selected-icon-color: contrast-color($color: 'surface') !important; - } } @include e(menu-header) { @@ -119,8 +115,10 @@ gap: sizable(rem(16px)); igx-list { - --background: #{color($color: 'surface', $variant: 500)}; + --background: #{var-get($_theme, 'secondary-background')}; + --_border-color: #{color-mix(in srgb, var(--ig-excel-filtering-accent-color) 16%, var(--ig-excel-filtering-background))}; + border-block: rem(1px) dashed var(--_border-color, var(--ig-gray-100)); margin-inline: calc(#{sizable(rem(-16px))} * -1); // This is the only way to take the gap from the list, @@ -144,17 +142,13 @@ @include e(actions-pin, $m: disabled) { igx-icon { - // TODO MOVE excel-filtering-actions-disabled-foreground TO THE FILTERING SCHEMA and use it here. - //color: var-get($theme, 'excel-filtering-actions-disabled-foreground'); - color: color($color: 'gray', $variant: 900, $opacity: .2); + color: var-get($_theme, 'actions-disabled-foreground'); } } @include e(actions-clear, $m: disabled) { igx-icon { - // TODO MOVE excel-filtering-actions-disabled-foreground TO THE FILTERING SCHEMA and use it here. - //color: var-get($theme, 'excel-filtering-actions-disabled-foreground'); - color: color($color: 'gray', $variant: 900, $opacity: .2); + color: var-get($_theme, 'actions-disabled-foreground'); } } diff --git a/projects/igniteui-angular/grids/core/src/summaries/themes/_base.scss b/projects/igniteui-angular/grids/core/src/summaries/themes/_base.scss index 15763328d3f..0d5a2bddc66 100644 --- a/projects/igniteui-angular/grids/core/src/summaries/themes/_base.scss +++ b/projects/igniteui-angular/grids/core/src/summaries/themes/_base.scss @@ -24,8 +24,7 @@ $_theme: $material; overflow: hidden; outline-style: none; - // TODO MAYBE WE SHOULD RENAME THIS VARIABLES SO THE CAN BE USED IN THE SUMMARY AND grid BODY - border-inline-end: var(--header-border-width) var(--header-border-style) var-get($_theme, 'border-color'); + border-inline-end: var-get($_theme, 'border-width') var-get($_theme, 'border-style') var-get($_theme, 'border-color'); @include e(item) { display: flex; @@ -95,13 +94,13 @@ $_theme: $material; border-inline-end: map.get($cell-pin, 'style') #999; } - &:dir(ltr) { - box-shadow: inset rem(-1px) 0 0 0 var-get($_theme, 'pinned-border-color'); - } + // &:dir(ltr) { + // box-shadow: inset rem(-1px) 0 0 0 var-get($_theme, 'pinned-border-color'); + // } - &:dir(rtl) { - box-shadow: inset rem(1px) 0 0 0 var-get($_theme, 'pinned-border-color'); - } + // &:dir(rtl) { + // box-shadow: inset rem(1px) 0 0 0 var-get($_theme, 'pinned-border-color'); + // } } @include m(fw) { diff --git a/projects/igniteui-angular/grids/core/src/summaries/themes/shared/_indigo.scss b/projects/igniteui-angular/grids/core/src/summaries/themes/shared/_indigo.scss index fb95206a05c..accde05e5ca 100644 --- a/projects/igniteui-angular/grids/core/src/summaries/themes/shared/_indigo.scss +++ b/projects/igniteui-angular/grids/core/src/summaries/themes/shared/_indigo.scss @@ -7,7 +7,7 @@ $_theme: $indigo; @include themed-block(igx-grid-summary, indigo) { padding-inline: pad-inline(rem(8px), rem(12px), rem(16px)); - border-top: rem(1px) solid var-get($_theme, 'border-color'); + border-top: var-get($_theme, 'border-width') var-get($_theme, 'border-style') var-get($_theme, 'border-color'); @include e(item) { min-height: sizable(rem(24px), rem(30px), rem(36px)); diff --git a/projects/igniteui-angular/grids/core/src/toolbar/grid-toolbar.component.scss b/projects/igniteui-angular/grids/core/src/toolbar/grid-toolbar.component.scss index dd684163cd7..30d99ab12d3 100644 --- a/projects/igniteui-angular/grids/core/src/toolbar/grid-toolbar.component.scss +++ b/projects/igniteui-angular/grids/core/src/toolbar/grid-toolbar.component.scss @@ -2,3 +2,4 @@ @use 'themes/shared'; @use 'themes/light'; @use 'themes/dark'; +@use 'themes/derived'; diff --git a/projects/igniteui-angular/grids/core/src/toolbar/themes/_base.scss b/projects/igniteui-angular/grids/core/src/toolbar/themes/_base.scss index 515522c8f52..0a3f759e146 100644 --- a/projects/igniteui-angular/grids/core/src/toolbar/themes/_base.scss +++ b/projects/igniteui-angular/grids/core/src/toolbar/themes/_base.scss @@ -20,7 +20,7 @@ $theme: $base; grid-row: 1; font-size: rem(16px); border-bottom: rem(1px) solid var-get($theme, 'border-color'); - background: var-get($theme, 'background-color'); + background: var-get($theme, 'background'); height: auto; min-height: var-get($theme, 'size'); padding-block: 0; @@ -109,7 +109,7 @@ $theme: $base; bottom: rem(-1px); height: rem(2px); overflow: hidden; - background: var-get($theme, 'background-color'); + background: var-get($theme, 'background'); igx-linear-bar > * { border-radius: 0; diff --git a/projects/igniteui-angular/grids/core/src/toolbar/themes/_derived.scss b/projects/igniteui-angular/grids/core/src/toolbar/themes/_derived.scss new file mode 100644 index 00000000000..757815bfe00 --- /dev/null +++ b/projects/igniteui-angular/grids/core/src/toolbar/themes/_derived.scss @@ -0,0 +1,38 @@ +@use 'sass:map'; +@use 'igniteui-theming/sass/themes' as *; +@use 'styles/themes/standalone' as *; + +/// Applies all sub-component token overrides used by the grid toolbar component. +/// @access private +@each $theme-name, $variant-name, $schema in $derived-schemas { + @include layer(derived) { + @scope ([data-ig-theme='#{$theme-name}'][data-ig-theme-variant='#{$variant-name}']) { + :where(igx-grid-toolbar) { + --_grid-toolbar-background: var(--background, var(--ig-grid-toolbar-background)); + --_grid-toolbar-foreground: var(--foreground, var(--ig-grid-toolbar-foreground)); + --_grid-toolbar-accent-color: var(--accent-color, var(--ig-grid-toolbar-accent-color)); + --ig-grid-toolbar-title-text-color: var(--_grid-toolbar-foreground); + + @include tokens( + column-actions-theme( + $schema: $schema, + $background: var(--_grid-toolbar-background), + $foreground: var(--_grid-toolbar-foreground), + $title-color: var(--_grid-toolbar-accent-color), + $accent-color: var(--_grid-toolbar-accent-color) + ) + ); + + @include tokens( + outlined-button-theme( + $schema: $schema, + $foreground: var(--_grid-toolbar-accent-color), + $disabled-background: transparent, + $disabled-foreground: color-mix(in srgb, var(--_grid-toolbar-accent-color) 50%, var(--_grid-toolbar-background)), + $disabled-border-color: color-mix(in srgb, var(--_grid-toolbar-accent-color) 50%, var(--_grid-toolbar-background)), + ) + ); + } + } + } +} diff --git a/projects/igniteui-angular/grids/core/src/toolbar/themes/dark/_tokens.scss b/projects/igniteui-angular/grids/core/src/toolbar/themes/dark/_tokens.scss index 9154c469099..f97fbc9e3d8 100644 --- a/projects/igniteui-angular/grids/core/src/toolbar/themes/dark/_tokens.scss +++ b/projects/igniteui-angular/grids/core/src/toolbar/themes/dark/_tokens.scss @@ -3,9 +3,7 @@ @use 'igniteui-theming/sass/themes' as *; @use 'igniteui-theming/sass/themes/schemas/components/dark/grid-toolbar' as *; -$props: ('background-color', 'title-text-color', 'border-color', 'size'); - -$material: list.nth(split-map(digest-schema($dark-material-grid-toolbar), $props), 1); -$bootstrap: list.nth(split-map(digest-schema($dark-bootstrap-grid-toolbar), $props), 1); -$fluent: list.nth(split-map(digest-schema($dark-fluent-grid-toolbar), $props), 1); -$indigo: list.nth(split-map(digest-schema($dark-indigo-grid-toolbar), $props), 1); +$material: digest-schema($dark-material-grid-toolbar); +$bootstrap: digest-schema($dark-bootstrap-grid-toolbar); +$fluent: digest-schema($dark-fluent-grid-toolbar); +$indigo: digest-schema($dark-indigo-grid-toolbar); diff --git a/projects/igniteui-angular/grids/grid/src/grid-base.styles.scss b/projects/igniteui-angular/grids/grid/src/grid-base.styles.scss index 41d4e903297..4e9ddebcd14 100644 --- a/projects/igniteui-angular/grids/grid/src/grid-base.styles.scss +++ b/projects/igniteui-angular/grids/grid/src/grid-base.styles.scss @@ -2,3 +2,4 @@ @use '../../themes/shared'; @use '../../themes/light'; @use '../../themes/dark'; +@use '../../themes/derived'; diff --git a/projects/igniteui-angular/grids/themes/_base.scss b/projects/igniteui-angular/grids/themes/_base.scss index 141fb0e12c9..a7aa5e36754 100644 --- a/projects/igniteui-angular/grids/themes/_base.scss +++ b/projects/igniteui-angular/grids/themes/_base.scss @@ -15,7 +15,7 @@ $cell-editing-outline-width: rem(1px); $grid-header-border: var-get($theme, 'header-border-width') var-get($theme, 'header-border-style') var-get($theme, 'header-border-color'); $grid-body-column-border-odd: var-get($theme, 'header-border-width') var-get($theme, 'active-state-border-style') var-get($theme, 'body-column-border-color-odd'); $grid-body-column-border-even: var-get($theme, 'header-border-width') var-get($theme, 'active-state-border-style') var-get($theme, 'body-column-border-color-even'); -$grid-active-state-border: var-get($theme, 'header-border-width') var-get($theme, 'active-state-border-style') var-get($theme, 'cell-active-border-color'); +$grid-active-state-border: var-get($theme, 'cell-active-border-width') var-get($theme, 'active-state-border-style') var-get($theme, 'cell-active-border-color'); $cell-padding-sm: rem(12px); $cell-padding-md: rem(16px); $cell-padding-lg: rem(24px); @@ -73,7 +73,7 @@ $z-grid-loading: 10003; font-weight: 600; border-inline-end: $grid-header-border; overflow: hidden; - transition: color 250ms ease-in-out; + transition: color 120ms ease-in-out; outline-style: none; } @@ -332,18 +332,18 @@ $z-grid-loading: 10003; display: flex; flex-flow: row nowrap; width: 100%; - background: var-get($theme, 'header-background'); + background: var(--_grid-background, var-get($theme, 'content-background')); z-index: $z-grid-scroll; } // Scroll start section @include e(scroll-start) { - background: var-get($theme, 'header-background'); - border-inline-end: $grid-header-border; + background: var(--_grid-background, var-get($theme, 'content-background')); + // border-inline-end: 1px solid var-get($theme, 'pinned-border-color'); } @include e(scroll-end) { - background: var-get($theme, 'header-background'); + background: var(--_grid-background, var-get($theme, 'content-background')); border-inline-start: $grid-header-border; } @@ -396,7 +396,13 @@ $z-grid-loading: 10003; position: absolute; top: 0; inset-inline-end: 0; - background: var-get($theme, 'header-background'); + background: var( + --igx-grid-summary-background-color, + var( + --ig-grid-summary-background-color, + var(--_grid-background, var-get($theme, 'content-background')) + ) + ); } // Grid footer @@ -409,7 +415,7 @@ $z-grid-loading: 10003; position: relative; display: flex; outline-style: none; - border-bottom: rem(1px) solid var-get($theme, 'row-border-color'); + border-bottom: var-get($theme, 'row-border-width') var-get($theme, 'row-border-style') var-get($theme, 'row-border-color'); // (!) the background-clip: padding-box; makes sure the background never go under the border, // this is very important especially if the borders have slide alpha @@ -723,7 +729,7 @@ $z-grid-loading: 10003; // First pinned column (left border) @include e(td, $m: pinned-first) { - border-inline-start: var-get($theme, 'pinned-border-width') solid var-get($theme, 'pinned-border-color'); + border-inline-start: var-get($theme, 'pinned-border-style') var-get($theme, 'pinned-border-width') var-get($theme, 'pinned-border-color'); &::after { width: calc(100% - $pinned-shadow-size); @@ -734,7 +740,7 @@ $z-grid-loading: 10003; // Last pinned column (right border) @include e(td, $m: pinned-last) { - border-inline-end: var-get($theme, 'pinned-border-width') solid var-get($theme, 'pinned-border-color'); + border-inline-end: var-get($theme, 'pinned-border-style') var-get($theme, 'pinned-border-width') var-get($theme, 'pinned-border-color'); } // Pinned cell when selected @@ -1215,7 +1221,7 @@ $z-grid-loading: 10003; background: var-get($theme, 'group-row-background'); display: flex; outline-style: none; - border-bottom: rem(1px) solid var-get($theme, 'row-border-color'); + border-block: var-get($theme, 'row-border-width') var-get($theme, 'row-border-style') var-get($theme, 'row-border-color'); min-height: var(--header-size); &::after { @@ -1850,7 +1856,13 @@ $z-grid-loading: 10003; display: flex; overflow: hidden; outline-style: none; - background-color: var-get($theme, 'summaries-patch-background'); + background-color: var( + --igx-grid-summary-background-color, + var( + --ig-grid-summary-background-color, + var-get($theme, 'summaries-patch-background') + ) + ); igx-display-container { overflow: visible !important; @@ -2105,7 +2117,7 @@ $z-grid-loading: 10003; font-weight: 600; border-inline-end: $grid-header-border; overflow: hidden; - transition: color 250ms ease-in-out; + transition: color 120ms ease-in-out; outline-style: none; @include e(expander) { @@ -2138,7 +2150,6 @@ $z-grid-loading: 10003; cursor: initial; flex-grow: 1; line-height: var(--header-size); - transition: color 250ms ease-in-out; } @include e(icons) { @@ -2340,7 +2351,7 @@ $z-grid-loading: 10003; // Pinned header (first pinned column) @include m(pinned-first) { - border-inline-start: var-get($theme, 'pinned-border-width') solid var-get($theme, 'pinned-border-color'); + border-inline-start: var-get($theme, 'pinned-border-width') var-get($theme, 'pinned-border-style') var-get($theme, 'pinned-border-color'); &:dir(ltr) { border-inline-start-color: var-get($theme, 'pinned-border-color'); @@ -2358,11 +2369,13 @@ $z-grid-loading: 10003; &:dir(ltr) { border-inline-end-color: var-get($theme, 'pinned-border-color'); border-inline-end-width: var-get($theme, 'pinned-border-width'); + border-inline-end-style: var-get($theme, 'pinned-border-style'); } &:dir(rtl) { border-inline-start-color: var-get($theme, 'pinned-border-color'); border-inline-start-width: var-get($theme, 'pinned-border-width'); + border-inline-start-style: var-get($theme, 'pinned-border-style'); } } @@ -2577,6 +2590,7 @@ $z-grid-loading: 10003; @include e(thumb) { background: var-get($theme, 'header-background'); border-block-end: $grid-header-border; + border-inline-start: $grid-header-border; } // Pivot grid modifier @@ -2688,19 +2702,6 @@ $z-grid-loading: 10003; } @include b(igx-advanced-filter) { - background: color($color: 'surface', $variant: 500); - box-shadow: elevation(24); - - igx-query-builder { - box-shadow: none !important; - border: none !important; - border-radius: inherit !important; - } - - igx-query-builder-header { - cursor: grab; - } - .igx-excel-filter__secondary-footer { --ig-size: 2; diff --git a/projects/igniteui-angular/grids/themes/_derived.scss b/projects/igniteui-angular/grids/themes/_derived.scss new file mode 100644 index 00000000000..9a9e1370784 --- /dev/null +++ b/projects/igniteui-angular/grids/themes/_derived.scss @@ -0,0 +1,344 @@ +@use 'sass:map'; +@use 'igniteui-theming/sass/themes' as *; +@use 'styles/themes/standalone' as *; + +/// Applies all sub-component token overrides used by the grid. +/// @access private +@each $theme-name, $variant-name, $schema in $derived-schemas { + @include layer(derived) { + @scope ([data-ig-theme='#{$theme-name}'][data-ig-theme-variant='#{$variant-name}']) { + :where( + igx-grid, + igc-grid, + igx-tree-grid, + igc-tree-grid, + igx-hierarchical-grid, + igc-hierarchical-grid, + igx-pivot-grid, + igc-pivot-grid, + igx-grid-lite, + igc-grid-lite + ) { + --_grid-background: var(--background, var(--ig-grid-background)); + --_grid-foreground: var(--foreground, var(--ig-grid-foreground)); + --_grid-accent-color: var(--accent-color, var(--ig-grid-accent-color)); + + @include tokens( + action-strip-theme( + $schema: $schema, + $background: color-mix(in srgb, var(--_grid-accent-color) 12%, transparent), + $actions-background: color-mix(in srgb, var(--_grid-accent-color) 12%, var(--_grid-background)), + $icon-color: var(--_grid-accent-color), + ) + ); + + @include tokens( + badge-theme( + $schema: $schema, + $background-color: var(--_grid-accent-color), + ) + ); + + @include tokens( + banner-theme( + $schema: $schema, + $banner-background: var(--_grid-background), + $banner-message-color: var(--_grid-foreground), + $banner-illustration-color: var(--_grid-foreground), + $banner-border-color: color-mix(in srgb, var(--_grid-foreground) 20%, var(--_grid-background)) + ) + ); + + @include tokens( + calendar-theme( + $header-background: var(--_grid-accent-color), + $content-background: var(--_grid-background), + $content-foreground: var(--_grid-foreground), + ) + ); + + @include tokens( + checkbox-theme( + $schema: $schema, + $empty-color: color-mix(in srgb, var(--_grid-foreground) 80%, var(--_grid-background)), + $empty-fill-color: var(--_grid-background), + $tick-color-hover: color-mix(in srgb, var(--_grid-foreground) 40%, var(--_grid-background)), + $fill-color: var(--_grid-accent-color), + $label-color: var(--_grid-foreground), + $disabled-color: color-mix(in srgb, var(--_grid-foreground) 50%, var(--_grid-background)), + ) + ); + + igx-grid-header-row { + @include tokens( + checkbox-theme( + $schema: $schema, + $empty-color: var(--header-text-color), + $empty-fill-color: var(--header-background), + $tick-color-hover: color-mix(in srgb, var(--header-text-color) 40%, var(--header-background)), + $fill-color: var(--_grid-accent-color), + $label-color: var(--header-text-color), + $disabled-color: color-mix(in srgb, var(--header-text-color) 50%, var(--header-background)), + ) + ); + } + + @include tokens( + chip-theme( + $schema: $schema, + $background: color-mix(in srgb, var(--_grid-foreground) 12%, var(--_grid-background)), + $text-color: var(--_grid-foreground), + $ghost-background: color-mix(in srgb, var(--_grid-foreground) 12%, var(--_grid-background)), + $ghost-text-color: var(--_grid-foreground), + $disabled-background: color-mix(in srgb, var(--_grid-foreground) 12%, var(--_grid-background)), + $disabled-text-color: color-mix(in srgb, var(--_grid-foreground) 50%, var(--_grid-background)), + $disabled-border-color: color-mix(in srgb, var(--_grid-foreground) 24%, var(--_grid-background)), + ) + ); + + @include tokens( + contained-button-theme( + $schema: $schema, + $background: var(--_grid-accent-color), + $disabled-background: color-mix(in srgb, var(--_grid-accent-color) 50%, var(--_grid-background)), + $disabled-foreground: color-mix(in srgb, var(--_grid-foreground) 50%, var(--_grid-background)), + ) + ); + + @include tokens( + drop-down-theme( + $schema: $schema, + $background-color: var(--_grid-background), + $item-text-color: var(--_grid-foreground), + $border-color: color-mix(in srgb, var(--_grid-foreground) 12%, var(--_grid-background)), + $hover-item-background: color-mix(in srgb, var(--_grid-accent-color) 8%, var(--_grid-background)), + $focused-item-background: color-mix(in srgb, var(--_grid-accent-color) 12%, var(--_grid-background)), + $selected-item-background: color-mix(in srgb, var(--_grid-accent-color) 12%, var(--_grid-background)), + $selected-hover-item-background: color-mix(in srgb, var(--_grid-accent-color) 16%, var(--_grid-background)), + $selected-focus-item-background: color-mix(in srgb, var(--_grid-accent-color) 24%, var(--_grid-background)), + ) + ); + + @include tokens( + excel-filtering-theme( + $background: var(--_grid-background), + $foreground: var(--_grid-foreground), + $accent-color: var(--_grid-accent-color), + ) + ); + + @include tokens( + flat-button-theme( + $schema: $schema, + $foreground: var(--_grid-accent-color), + $disabled-background: transparent, + $disabled-foreground: color-mix(in srgb, var(--_grid-accent-color) 50%, var(--_grid-background)), + ) + ); + + @include tokens( + flat-icon-button-theme( + $schema: $schema, + $foreground: var(--_grid-accent-color), + $disabled-background: transparent, + $disabled-foreground: color-mix(in srgb, var(--_grid-accent-color) 50%, var(--_grid-background)), + ) + ); + + @include tokens( + grid-summary-theme( + $schema: $schema, + $background-color: color-mix(in srgb, var(--_grid-foreground) 12%, var(--_grid-background)), + $border-color: color-mix(in srgb, var(--_grid-foreground) 20%, var(--_grid-background)), + $pinned-border-color: color-mix(in srgb, var(--_grid-foreground) 30%, var(--_grid-background)), + $label-color: var(--_grid-accent-color), + $result-color: var(--_grid-foreground) + ) + ); + + @include tokens( + grid-toolbar-theme( + $schema: $schema, + $background: var(--_grid-background), + $foreground: var(--_grid-foreground), + $title-text-color: var(--_grid-foreground), + $accent-color: var(--_grid-accent-color) + ) + ); + + @include tokens( + highlight-theme( + $schema: $schema, + $resting-background: color-mix(in srgb, var(--_grid-foreground) 80%, var(--_grid-background)), + $active-background: var(--_grid-accent-color) + ) + ); + + @if $theme-name == 'material' { + @include tokens( + input-group-theme( + $schema: $schema, + $box-background: var(--_grid-background), + $search-background: color-mix(in srgb, var(--_grid-foreground) 6%, var(--_grid-background)), + $idle-bottom-line-color: var(--_grid-accent-color), + $idle-secondary-color: var(--_grid-foreground), + $focused-secondary-color: var(--_grid-accent-color), + $border-color: var(--_grid-accent-color), + $idle-text-color: var(--_grid-foreground), + $placeholder-color: color-mix(in srgb, var(--_grid-foreground) 80%, var(--_grid-background)), + ) + ); + } @else if $theme-name == 'indigo' { + @include tokens( + input-group-theme( + $schema: $schema, + $idle-bottom-line-color: var(--_grid-accent-color), + $idle-text-color: var(--_grid-foreground), + $placeholder-color: color-mix(in srgb, var(--_grid-foreground) 80%, var(--_grid-background)), + ) + ); + } @else { + @include tokens( + input-group-theme( + $schema: $schema, + $border-color: var(--_grid-accent-color), + $idle-text-color: var(--_grid-foreground), + $placeholder-color: color-mix(in srgb, var(--_grid-foreground) 80%, var(--_grid-background)), + $input-prefix-background: var(--_grid-accent-color), + $border-disabled-background: transparent, + $disabled-border-color: color-mix(in srgb, var(--_grid-accent-color) 50%, transparent), + ) + ); + } + + @include tokens( + outlined-button-theme( + $schema: $schema, + $foreground: var(--_grid-accent-color), + $disabled-background: transparent, + $disabled-foreground: color-mix(in srgb, var(--_grid-accent-color) 50%, var(--_grid-background)), + $disabled-border-color: color-mix(in srgb, var(--_grid-accent-color) 50%, var(--_grid-background)), + ) + ); + + @include tokens( + outlined-icon-button-theme( + $schema: $schema, + $foreground: var(--_grid-accent-color), + $disabled-background: transparent, + $disabled-foreground: color-mix(in srgb, var(--_grid-accent-color) 50%, var(--_grid-background)), + $disabled-border-color: color-mix(in srgb, var(--_grid-accent-color) 50%, var(--_grid-background)) + ) + ); + + @include tokens( + paginator-theme( + $schema: $schema, + $background: var(--_grid-background), + $foreground: var(--_grid-foreground), + $border-color: color-mix(in srgb, var(--_grid-foreground) 16%, var(--_grid-background)), + $accent-color: var(--_grid-accent-color) + ) + ); + + @include tokens( + progress-circular-theme( + $schema: $schema, + $track-color: color-mix(in srgb, var(--_grid-foreground) 12%, var(--_grid-background)), + $fill-color-default: var(--_grid-accent-color), + $text-color: var(--_grid-foreground) + ) + ); + + @include tokens( + progress-linear-theme( + $schema: $schema, + $track-color: color-mix(in srgb, var(--_grid-foreground) 12%, var(--_grid-background)), + $fill-color-default: var(--_grid-accent-color), + $text-color: var(--_grid-foreground) + ), + ); + + @if $theme-name == 'bootstrap' { + @include tokens( + query-builder-theme( + $schema: $schema, + $background: var(--_grid-background), + $foreground: var(--_grid-foreground), + $accent-color: var(--_grid-accent-color), + $header-border: color-mix(in srgb, var(--_grid-foreground) 20%, var(--_grid-background)), + ) + ); + } @else { + @include tokens( + query-builder-theme( + $schema: $schema, + $background: var(--_grid-background), + $foreground: var(--_grid-foreground), + $accent-color: var(--_grid-accent-color), + $header-foreground: var(--_grid-foreground), + ) + ); + } + + $scrollbar-theme: digest-schema(map.get($schema, 'scrollbar')); + $scrollbar-bg-color: map.get($scrollbar-theme, 'sb-track-bg-color'); + $scrollbar-thumb-color: map.get($scrollbar-theme, 'sb-thumb-bg-color'); + $scrollbar-track-border-color: map.get($scrollbar-theme, 'sb-track-border-color'); + + --_scrollbar-thumb-color: color-mix(in srgb, var(--_grid-foreground) 50%, var(--_grid-background)); + --_scrollbar-track-border-color: color-mix(in srgb, var(--_grid-foreground) 16%, var(--_grid-background)); + + @include tokens( + scrollbar-theme( + $schema: $schema, + $sb-track-bg-color: var(--_grid-background, $scrollbar-bg-color), + $sb-thumb-bg-color: var(--_scrollbar-thumb-color, $scrollbar-thumb-color), + $sb-track-border-color: var(--_scrollbar-track-border-color, $scrollbar-track-border-color), + ), + $mode: 'scoped' + ); + + @if $theme-name == 'indigo' { + @include tokens( + select-theme( + $schema: $schema, + $toggle-button-foreground: var(--_grid-accent-color), + $toggle-button-foreground-disabled: color-mix(in srgb, var(--_grid-accent-color) 50%, var(--_grid-background)), + ) + ); + } @else { + @include tokens( + select-theme( + $schema: $schema, + $toggle-button-background: var(--_grid-accent-color), + ) + ); + } + + @include tokens( + tooltip-theme( + $schema: $schema, + $background: hsl(from var(--_grid-foreground) h s l / 80%) + ), + ); + + @include tokens( + tree-theme( + $schema: $schema, + $background: var(--_grid-background) + ), + ); + + @include tokens( + watermark-theme( + $schema: $schema, + $base-color: color-mix(in srgb, var(--_grid-accent-color) 50%, var(--_grid-background)), + $color: var(--_grid-foreground), + $border-color: color-mix(in srgb, var(--_grid-accent-color) 16%, var(--_grid-background)) + ) + ); + } + } + } +} diff --git a/projects/igniteui-angular/grids/themes/dark/_indigo.scss b/projects/igniteui-angular/grids/themes/dark/_indigo.scss index 677d32af454..d7d2ca5d278 100644 --- a/projects/igniteui-angular/grids/themes/dark/_indigo.scss +++ b/projects/igniteui-angular/grids/themes/dark/_indigo.scss @@ -68,6 +68,3 @@ } } -@include themed-block(igx-advanced-filter, indigo, dark) { - background: color($color: 'gray', $variant: 50); -} diff --git a/projects/igniteui-angular/grids/themes/shared/_bootstrap.scss b/projects/igniteui-angular/grids/themes/shared/_bootstrap.scss index 34fee932199..04715e828ab 100644 --- a/projects/igniteui-angular/grids/themes/shared/_bootstrap.scss +++ b/projects/igniteui-angular/grids/themes/shared/_bootstrap.scss @@ -131,11 +131,3 @@ } } -@include themed-block(igx-advanced-filter, bootstrap) { - border-radius: rem(4px); - - .igx-excel-filter__secondary-footer { - padding: rem(16px); - border-top: rem(1px) solid color($color: 'gray', $variant: 300); - } -} diff --git a/projects/igniteui-angular/grids/themes/shared/_fluent.scss b/projects/igniteui-angular/grids/themes/shared/_fluent.scss index 4af329aef16..5aea02a0b41 100644 --- a/projects/igniteui-angular/grids/themes/shared/_fluent.scss +++ b/projects/igniteui-angular/grids/themes/shared/_fluent.scss @@ -24,6 +24,3 @@ $_theme: $fluent; } } -@include themed-block(igx-advanced-filter, bootstrap) { - border-radius: rem(2px); -} diff --git a/projects/igniteui-angular/grids/themes/shared/_indigo.scss b/projects/igniteui-angular/grids/themes/shared/_indigo.scss index ffe22c90338..038b6121ef7 100644 --- a/projects/igniteui-angular/grids/themes/shared/_indigo.scss +++ b/projects/igniteui-angular/grids/themes/shared/_indigo.scss @@ -193,8 +193,3 @@ } } -@include themed-block(igx-advanced-filter, indigo) { - background: contrast-color($color: 'gray', $variant: 900); - box-shadow: elevation(24); - border-radius: rem(10px); -} diff --git a/projects/igniteui-angular/grids/themes/shared/_material.scss b/projects/igniteui-angular/grids/themes/shared/_material.scss index 91109257747..77d6232679e 100644 --- a/projects/igniteui-angular/grids/themes/shared/_material.scss +++ b/projects/igniteui-angular/grids/themes/shared/_material.scss @@ -135,6 +135,3 @@ } } -@include themed-block(igx-advanced-filter, material) { - border-radius: rem(4px); -} diff --git a/projects/igniteui-angular/paginator/src/paginator/paginator.component.scss b/projects/igniteui-angular/paginator/src/paginator/paginator.component.scss index dd684163cd7..30d99ab12d3 100644 --- a/projects/igniteui-angular/paginator/src/paginator/paginator.component.scss +++ b/projects/igniteui-angular/paginator/src/paginator/paginator.component.scss @@ -2,3 +2,4 @@ @use 'themes/shared'; @use 'themes/light'; @use 'themes/dark'; +@use 'themes/derived'; diff --git a/projects/igniteui-angular/paginator/src/paginator/themes/_base.scss b/projects/igniteui-angular/paginator/src/paginator/themes/_base.scss index 97a58f83083..af226860a3b 100644 --- a/projects/igniteui-angular/paginator/src/paginator/themes/_base.scss +++ b/projects/igniteui-angular/paginator/src/paginator/themes/_base.scss @@ -15,8 +15,8 @@ $_theme: $material; display: flex; justify-content: space-between; align-items: center; - color: var-get($_theme, 'text-color'); - background: var-get($_theme, 'background-color'); + color: var-get($_theme, 'foreground'); + background: var-get($_theme, 'background'); font-size: rem(12px); border-top: rem(1px) solid var-get($_theme, 'border-color'); z-index: 1; diff --git a/projects/igniteui-angular/paginator/src/paginator/themes/_derived.scss b/projects/igniteui-angular/paginator/src/paginator/themes/_derived.scss new file mode 100644 index 00000000000..a3c1f71222c --- /dev/null +++ b/projects/igniteui-angular/paginator/src/paginator/themes/_derived.scss @@ -0,0 +1,71 @@ +@use 'sass:map'; +@use 'igniteui-theming/sass/themes' as *; +@use 'styles/themes/standalone' as *; + +/// Applies all sub-component token overrides used by the paginator component. +/// @access private +@each $theme-name, $variant-name, $schema in $derived-schemas { + @include layer(derived) { + @scope ([data-ig-theme='#{$theme-name}'][data-ig-theme-variant='#{$variant-name}']) { + :where(igx-paginator) { + --_paginator-background: var(--background, var(--ig-paginator-background)); + --_paginator-foreground: var(--foreground, var(--ig-paginator-foreground)); + --_paginator-accent-color: var( + --igx-paginator-accent-color, + var(--ig-paginator-accent-color, var(--accent-color)) + ); + + @include tokens( + drop-down-theme( + $schema: $schema, + $background-color: var(--_paginator-background), + $item-text-color: var(--_paginator-foreground), + $border-color: color-mix(in srgb, var(--_paginator-foreground) 12%, var(--_paginator-background)), + $hover-item-background: color-mix(in srgb, var(--_paginator-accent-color) 8%, var(--_paginator-background)), + $focused-item-background: color-mix(in srgb, var(--_paginator-accent-color) 12%, var(--_paginator-background)), + $selected-item-background: color-mix(in srgb, var(--_paginator-accent-color) 12%, var(--_paginator-background)), + $selected-hover-item-background: color-mix(in srgb, var(--_paginator-accent-color) 16%, var(--_paginator-background)), + $selected-focus-item-background: color-mix(in srgb, var(--_paginator-accent-color) 24%, var(--_paginator-background)), + ) + ); + + @include tokens( + flat-icon-button-theme( + $schema: $schema, + $foreground: var(--_paginator-accent-color), + $disabled-background: transparent, + $disabled-foreground: color-mix(in srgb, var(--_paginator-accent-color) 50%, var(--_paginator-background)), + ) + ); + + @include tokens( + input-group-theme( + $schema: $schema, + $idle-bottom-line-color: var(--_paginator-accent-color), + $border-color: var(--_paginator-accent-color), + $idle-text-color: var(--_paginator-foreground), + $placeholder-color: color-mix(in srgb, var(--_paginator-foreground) 80%, var(--_paginator-background)), + ) + ); + + @if $theme-name == 'indigo' { + @include tokens( + select-theme( + $schema: $schema, + $toggle-button-foreground: var(--_paginator-accent-color), + $toggle-button-foreground-disabled: color-mix(in srgb, var(--_paginator-accent-color) 50%, var(--_paginator-background)), + ) + ); + } @else { + @include tokens( + select-theme( + $schema: $schema, + $toggle-button-background: var(--_paginator-accent-color), + $toggle-button-background-focus--border: var(--_paginator-accent-color) + ) + ); + } + } + } + } +} diff --git a/projects/igniteui-angular/query-builder/src/query-builder/query-builder.component.scss b/projects/igniteui-angular/query-builder/src/query-builder/query-builder.component.scss index dd684163cd7..30d99ab12d3 100644 --- a/projects/igniteui-angular/query-builder/src/query-builder/query-builder.component.scss +++ b/projects/igniteui-angular/query-builder/src/query-builder/query-builder.component.scss @@ -2,3 +2,4 @@ @use 'themes/shared'; @use 'themes/light'; @use 'themes/dark'; +@use 'themes/derived'; diff --git a/projects/igniteui-angular/query-builder/src/query-builder/themes/_base.scss b/projects/igniteui-angular/query-builder/src/query-builder/themes/_base.scss index dc795c9a808..cfc8fc67070 100644 --- a/projects/igniteui-angular/query-builder/src/query-builder/themes/_base.scss +++ b/projects/igniteui-angular/query-builder/src/query-builder/themes/_base.scss @@ -417,4 +417,20 @@ $icon-size: rem(18px); margin: 0 !important; } } + + @include b(igx-advanced-filter) { + background: var-get($theme, 'background'); + box-shadow: elevation(24); + border-radius: $border-radius; + + igx-query-builder { + box-shadow: none; + border: none; + border-radius: inherit; + } + + igx-query-builder-header { + cursor: grab; + } + } } diff --git a/projects/igniteui-angular/query-builder/src/query-builder/themes/_derived.scss b/projects/igniteui-angular/query-builder/src/query-builder/themes/_derived.scss new file mode 100644 index 00000000000..d1294136049 --- /dev/null +++ b/projects/igniteui-angular/query-builder/src/query-builder/themes/_derived.scss @@ -0,0 +1,194 @@ +@use 'sass:map'; +@use 'igniteui-theming/sass/themes' as *; +@use 'styles/themes/standalone' as *; + +/// Applies all sub-component token overrides used by the query-builder component. +/// @access private +@each $theme-name, $variant-name, $schema in $derived-schemas { + @include layer(derived) { + @scope ([data-ig-theme='#{$theme-name}'][data-ig-theme-variant='#{$variant-name}']) { + :where(igx-query-builder, igx-advanced-filtering-dialog) { + --_query-builder-background: var(--background, var(--ig-query-builder-background)); + --_query-builder-foreground: var(--foreground, var(--ig-query-builder-foreground)); + --_query-builder-accent-color: var(--accent-color, var(--ig-query-builder-accent-color)); + + @include tokens(query-builder-theme($schema: $schema), $mode: 'scoped'); + + @include tokens( + checkbox-theme( + $schema: $schema, + $empty-color: color-mix(in srgb, var(--_query-builder-foreground) 80%, var(--_query-builder-background)), + $empty-fill-color: var(--_query-builder-background), + $tick-color-hover: color-mix(in srgb, var(--_query-builder-foreground) 40%, var(--_query-builder-background)), + $fill-color: var(--_query-builder-accent-color), + $label-color: var(--_query-builder-foreground), + $disabled-color: color-mix(in srgb, var(--_query-builder-foreground) 50%, var(--_query-builder-background)), + ) + ); + + @include tokens( + chip-theme( + $schema: $schema, + $background: color-mix(in srgb, var(--_query-builder-foreground) 12%, var(--_query-builder-background)), + $text-color: var(--_query-builder-foreground), + $ghost-background: color-mix(in srgb, var(--_query-builder-foreground) 12%, var(--_query-builder-background)), + $ghost-text-color: var(--_query-builder-foreground), + $disabled-background: color-mix(in srgb, var(--_query-builder-foreground) 12%, var(--_query-builder-background)), + $disabled-text-color: color-mix(in srgb, var(--_query-builder-foreground) 50%, var(--_query-builder-background)), + $disabled-border-color: color-mix(in srgb, var(--_query-builder-foreground) 24%, var(--_query-builder-background)), + ) + ); + + @if $theme-name == 'indigo' { + @include tokens( + combo-theme( + $schema: $schema, + $toggle-button-foreground: var(--_query-builder-accent-color), + $toggle-button-foreground-disabled: color-mix(in srgb, var(--_query-builder-accent-color) 50%, var(--_query-builder-background)), + $clear-button-foreground: var(--_query-builder-foreground) + ) + ); + } @else { + @include tokens( + combo-theme( + $schema: $schema, + $toggle-button-background: var(--_query-builder-accent-color), + $clear-button-foreground: var(--_query-builder-foreground) + ) + ); + } + + @include tokens( + contained-button-theme( + $schema: $schema, + $background: var(--_query-builder-accent-color), + $disabled-background: color-mix(in srgb, var(--_query-builder-accent-color) 50%, var(--_query-builder-background)), + $disabled-foreground: color-mix(in srgb, var(--_query-builder-foreground) 50%, var(--_query-builder-background)), + ) + ); + + @include tokens( + drop-down-theme( + $schema: $schema, + $background-color: var(--_query-builder-background), + $item-text-color: var(--_query-builder-foreground), + $border-color: color-mix(in srgb, var(--_query-builder-foreground) 12%, var(--_query-builder-background)), + $hover-item-background: color-mix(in srgb, var(--_query-builder-accent-color) 8%, var(--_query-builder-background)), + $focused-item-background: color-mix(in srgb, var(--_query-builder-accent-color) 12%, var(--_query-builder-background)), + $selected-item-background: color-mix(in srgb, var(--_query-builder-accent-color) 12%, var(--_query-builder-background)), + $selected-hover-item-background: color-mix(in srgb, var(--_query-builder-accent-color) 16%, var(--_query-builder-background)), + $selected-focus-item-background: color-mix(in srgb, var(--_query-builder-accent-color) 24%, var(--_query-builder-background)), + ) + ); + + @include tokens( + flat-button-theme( + $schema: $schema, + $foreground: var(--_query-builder-accent-color), + $disabled-background: transparent, + $disabled-foreground: color-mix(in srgb, var(--_query-builder-accent-color) 50%, var(--_query-builder-background)), + ) + ); + + @if $theme-name == 'material' { + @include tokens( + input-group-theme( + $schema: $schema, + $box-background: var(--_query-builder-background), + $search-background: color-mix(in srgb, var(--_query-builder-foreground) 6%, var(--_query-builder-background)), + $idle-bottom-line-color: var(--_query-builder-accent-color), + $idle-secondary-color: var(--_query-builder-foreground), + $focused-secondary-color: var(--_query-builder-accent-color), + $border-color: var(--_query-builder-accent-color), + $idle-text-color: var(--_query-builder-foreground), + $placeholder-color: color-mix(in srgb, var(--_query-builder-foreground) 80%, var(--_query-builder-background)), + ) + ); + } @else if $theme-name == 'indigo' { + @include tokens( + input-group-theme( + $schema: $schema, + $idle-bottom-line-color: var(--_query-builder-accent-color), + $idle-text-color: var(--_query-builder-foreground), + $placeholder-color: color-mix(in srgb, var(--_query-builder-foreground) 80%, var(--_query-builder-background)), + ) + ); + } @else { + @include tokens( + input-group-theme( + $schema: $schema, + $border-color: var(--_query-builder-accent-color), + $idle-text-color: var(--_query-builder-foreground), + $placeholder-color: color-mix(in srgb, var(--_query-builder-foreground) 80%, var(--_query-builder-background)), + $input-prefix-background: var(--_query-builder-accent-color), + $border-disabled-background: transparent, + $disabled-border-color: color-mix(in srgb, var(--_query-builder-accent-color) 50%, transparent), + ) + ); + } + + @include tokens( + outlined-button-theme( + $schema: $schema, + $foreground: var(--_query-builder-accent-color), + $disabled-background: transparent, + $disabled-foreground: color-mix(in srgb, var(--_query-builder-accent-color) 50%, var(--_query-builder-background)), + $disabled-border-color: color-mix(in srgb, var(--_query-builder-accent-color) 50%, var(--_query-builder-background)), + ) + ); + + @include tokens( + outlined-icon-button-theme( + $schema: $schema, + $foreground: var(--_query-builder-accent-color), + $disabled-background: transparent, + $disabled-foreground: color-mix(in srgb, var(--_query-builder-accent-color) 50%, var(--_query-builder-background)), + $disabled-border-color: color-mix(in srgb, var(--_query-builder-accent-color) 50%, var(--_query-builder-background)) + ) + ); + + $scrollbar-theme: digest-schema(map.get($schema, 'scrollbar')); + $scrollbar-bg-color: map.get($scrollbar-theme, 'sb-track-bg-color'); + $scrollbar-thumb-color: map.get($scrollbar-theme, 'sb-thumb-bg-color'); + $scrollbar-track-border-color: map.get($scrollbar-theme, 'sb-track-border-color'); + + --_scrollbar-thumb-color: color-mix(in srgb, var(--_query-builder-foreground) 50%, var(--_query-builder-background)); + --_scrollbar-track-border-color: color-mix(in srgb, var(--_query-builder-foreground) 16%, var(--_query-builder-background)); + + @include tokens( + scrollbar-theme( + $schema: $schema, + $sb-track-bg-color: var(--_query-builder-background, $scrollbar-bg-color), + $sb-thumb-bg-color: var(--_scrollbar-thumb-color, $scrollbar-thumb-color), + $sb-track-border-color: var(--_scrollbar-track-border-color, $scrollbar-track-border-color), + ), + $mode: 'scoped' + ); + + @if $theme-name == 'indigo' { + @include tokens( + select-theme( + $schema: $schema, + $toggle-button-foreground: var(--_query-builder-accent-color), + $toggle-button-foreground-disabled: color-mix(in srgb, var(--_query-builder-accent-color) 50%, var(--_query-builder-background)), + ) + ); + } @else { + @include tokens( + select-theme( + $schema: $schema, + $toggle-button-background: var(--_query-builder-accent-color), + ) + ); + } + + @include tokens( + tooltip-theme( + $schema: $schema, + $background: hsl(from var(--_query-builder-foreground) h s l / 80%) + ), + ); + } + } + } +} diff --git a/projects/igniteui-angular/query-builder/src/query-builder/themes/dark/_index.scss b/projects/igniteui-angular/query-builder/src/query-builder/themes/dark/_index.scss index 21c6bc193df..b930fd91698 100644 --- a/projects/igniteui-angular/query-builder/src/query-builder/themes/dark/_index.scss +++ b/projects/igniteui-angular/query-builder/src/query-builder/themes/dark/_index.scss @@ -5,3 +5,4 @@ $tokens: meta.module-variables(tokens); @include themes(igx-query-builder, $tokens, dark); +@include themes(igx-advanced-filtering-dialog, $tokens, dark); diff --git a/projects/igniteui-angular/query-builder/src/query-builder/themes/light/_index.scss b/projects/igniteui-angular/query-builder/src/query-builder/themes/light/_index.scss index e0cfcc87afc..541cba7b0da 100644 --- a/projects/igniteui-angular/query-builder/src/query-builder/themes/light/_index.scss +++ b/projects/igniteui-angular/query-builder/src/query-builder/themes/light/_index.scss @@ -5,3 +5,4 @@ $tokens: meta.module-variables(tokens); @include themes(igx-query-builder, $tokens, light); +@include themes(igx-advanced-filtering-dialog, $tokens, light); diff --git a/projects/igniteui-angular/query-builder/src/query-builder/themes/shared/_bootstrap.scss b/projects/igniteui-angular/query-builder/src/query-builder/themes/shared/_bootstrap.scss index 55b8409cdcd..03eb98d6695 100644 --- a/projects/igniteui-angular/query-builder/src/query-builder/themes/shared/_bootstrap.scss +++ b/projects/igniteui-angular/query-builder/src/query-builder/themes/shared/_bootstrap.scss @@ -23,6 +23,13 @@ $_theme: $bootstrap; } } +@include themed-block(igx-advanced-filter, bootstrap) { + .igx-excel-filter__secondary-footer { + padding: rem(16px); + border-top: rem(1px) solid var-get($_theme, 'header-border'); + } +} + @include themed-block(igx-filter-tree, bootstrap) { @include e(button, $m: 'and') { &[igxButton='flat'] { diff --git a/projects/igniteui-angular/query-builder/src/query-builder/themes/shared/_indigo.scss b/projects/igniteui-angular/query-builder/src/query-builder/themes/shared/_indigo.scss index 4062a8d7442..8a51053e5b7 100644 --- a/projects/igniteui-angular/query-builder/src/query-builder/themes/shared/_indigo.scss +++ b/projects/igniteui-angular/query-builder/src/query-builder/themes/shared/_indigo.scss @@ -8,6 +8,10 @@ $_theme: $indigo; +@include themed-block(igx-advanced-filter, indigo) { + box-shadow: elevation(24); +} + @include themed-block(igx-query-builder, indigo) { &:has(.igx-query-builder-header) { .igx-query-builder-tree--level-0 { diff --git a/src/app/app.component.html b/src/app/app.component.html index 0e5c3eebadd..22754c0f556 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -109,7 +109,7 @@ } -@let config = (propertyChangeService.panelConfig | async | keyvalue)?.length > 0; +@let config = ((propertyChangeService.panelConfig | async | keyvalue)?.length > 0) || !!(propertyChangeService.customControlsSource | async);
diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 3d03634ef73..be473050df3 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -32,12 +32,19 @@ --sb-track-bg-color-hover: var(--ig-gray-100); --sb-thumb-bg-color: var(--ig-gray-200); --sb-thumb-bg-color-hover: var(--ig-gray-200); - + .igx-nav-drawer__aside { padding-top: 0; } } + .demos-settings-nav { + .igx-nav-drawer__aside { + overflow-y: auto; + scrollbar-gutter: stable; + } + } + [data-ig-theme='fluent'] { .demos-settings-nav { --aside-padding: 1rem; @@ -75,7 +82,7 @@ overflow-y: auto; padding: var(--content-spacing); color: var(--ig-gray-900); - + > div { max-width: 1200px; width: 100%; diff --git a/src/app/grid-theme-builder/grid-theme-builder.sample.html b/src/app/grid-theme-builder/grid-theme-builder.sample.html index a8454b64fba..9b476ea987e 100644 --- a/src/app/grid-theme-builder/grid-theme-builder.sample.html +++ b/src/app/grid-theme-builder/grid-theme-builder.sample.html @@ -1,29 +1,45 @@
- -
- - - - - - - @if (gridForeground()) { - - - } @else { - - } - - - - - -
- + [style.--ig-grid-accent-color]="gridAccentColor() || null" + [style.--ig-grid-header-background]="gridHeaderBackground() || null" + [style.--ig-grid-header-text-color]="gridHeaderTextColor() || null" + [style.--ig-grid-header-border-width]="gridHeaderBorderWidth() || null" + [style.--ig-grid-header-border-style]="gridHeaderBorderStyle() || null" + [style.--ig-grid-header-border-color]="gridHeaderBorderColor() || null" + [style.--ig-grid-cell-active-border-width]="gridCellActiveBorderWidth() || null" + [style.--ig-grid-active-state-border-style]="gridCellActiveBorderStyle() || null" + [style.--ig-grid-cell-active-border-color]="gridCellActiveBorderColor() || null" + [style.--ig-grid-cell-selected-within-background]="gridCellSelectedWithinBackground() || null" + [style.--ig-grid-cell-selected-within-text-color]="gridCellSelectedWithinTextColor() || null" + [style.--ig-grid-cell-selected-background]="gridCellSelectedBackground() || null" + [style.--ig-grid-cell-selected-text-color]="gridCellSelectedTextColor() || null" + [style.--ig-grid-pinned-border-width]="gridPinnedBorderWidth() || null" + [style.--ig-grid-pinned-border-style]="gridPinnedBorderStyle() || null" + [style.--ig-grid-pinned-border-color]="gridPinnedBorderColor() || null" + [style.--ig-grid-row-odd-background]="gridRowOddBackground() || null" + [style.--ig-grid-row-odd-text-color]="gridRowOddTextColor() || null" + [style.--ig-grid-row-even-background]="gridRowEvenBackground() || null" + [style.--ig-grid-row-even-text-color]="gridRowEvenTextColor() || null" + [style.--ig-grid-row-border-width]="gridRowBorderWidth() || null" + [style.--ig-grid-row-border-style]="gridRowBorderStyle() || null" + [style.--ig-grid-row-border-color]="gridRowBorderColor() || null"> - + Customer Data @@ -124,6 +143,811 @@ - + + + + + + + Hierarchical Grid + + + + + + + + + + + + + + + + + + Child Grid + + + + + + + + + + + + + Child of the Child + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + General + +
+
+ Background + + + + + + + + + +
+
+ Foreground + + + + + + + + + + + @if (gridForeground()) { + + + + } + +
+
+ Accent Color + + + + + + + + + +
+
+
+
+ + Header + +
+
+ Background + + + + + + + + + + + @if (gridHeaderBackground()) { + + + + } + +
+
+ Text Color + + + + + + + + + + + @if (gridHeaderTextColor()) { + + + + } + +
+
+
+
+ + Borders + +
+ @for (rule of borderRules(); track $index; let ruleIndex = $index) { + @if (activeBorderRuleIndex() !== ruleIndex) { +
+ + +
+ } + } + + @if (borderEditorOpen()) { +
+
+ Borders + + +
+
+ Border Color + + + + + + + + + + + @if (draftBorderColor()) { + + + + } + +
+
+ Border Width + + + +
+
+ Border Style + + Solid + Dashed + Dotted + Double + None + +
+
+ + +
+
+ } + @if (canAddBorderRule()) { + + } +
+
+
+ + Active Cell + +
+
+ Border Color + + + + + + + + + + + @if (gridCellActiveBorderColor()) { + + + + } + +
+
+ Border Width + + + +
+
+ Border Style + + Solid + Dashed + Dotted + Double + None + +
+
+ Selected Background + + + + + + + + + + + @if (gridCellSelectedBackground()) { + + + + } + +
+
+ Selected Text Color + + + + + + + + + + + @if (gridCellSelectedTextColor()) { + + + + } + +
+
+ Selected-Within Background + + + + + + + + + + + @if (gridCellSelectedWithinBackground()) { + + + + } + +
+
+ Selected-Within Text Color + + + + + + + + + + + @if (gridCellSelectedWithinTextColor()) { + + + + } + +
+
+
+
+ + + Child Components + + + + Grid Summary + +
+
+ Background + + + + + + + + + + + @if (gridSummaryBackground()) { + + + + } + +
+
+ Foreground + + + + + + + + + + + @if (gridSummaryLabelColor()) { + + + + } + +
+
+ Result Color + + + + + + + + + + + @if (gridSummaryResultColor()) { + + + + } + +
+
+
+
+ + Grid Toolbar + +
+
+ Background + + + + + + + + + + + @if (gridToolbarBackground()) { + + + + } + +
+
+ Foreground + + + + + + + + + + + @if (gridToolbarForeground()) { + + + + } + +
+
+ Accent Color + + + + + + + + + + + @if (gridToolbarAccentColor()) { + + + + } + +
+
+
+
+ + Advanced Filtering + +
+ + + +
+
+
+ + Excel Style Filtering + +
+ + + +
+
+
+ + Paginator + +
+
+ Background + + + + + + + + + + + @if (paginatorBackground()) { + + + + } + +
+
+ Foreground + + + + + + + + + + + @if (paginatorForeground()) { + + + + } + +
+
+ Accent Color + + + + + + + + + + + @if (paginatorAccentColor()) { + + + + } + +
+
+
+
+
+
+
+
+ +
+ + + @if (showExport()) { +
+
+ Export theme +
+ + @if (exportCode()) { + +
{{ exportCode() }}
+ } + @if (!exportCssVars() && !exportCode()) { +

No customizations applied yet.

+ } +
+ } +
+
+ + +
+ {{ label }} + + + + + + + + + + + @if (color()) { + + + + } + +
+
diff --git a/src/app/grid-theme-builder/grid-theme-builder.sample.scss b/src/app/grid-theme-builder/grid-theme-builder.sample.scss index 36e1c26a0f8..8e9ea14867d 100644 --- a/src/app/grid-theme-builder/grid-theme-builder.sample.scss +++ b/src/app/grid-theme-builder/grid-theme-builder.sample.scss @@ -2,67 +2,354 @@ @use '../../styles/variables' as vars; .sample { - display: flex; - flex-direction: column; - gap: 24px; - padding-block-end: 64px; + // @include tokens( + // grid-theme( + // $schema: vars.$schema, + // $background: #f7f4f0, + // $accent-color: #5b8f8a, + // ) + // ); @include tokens( grid-theme( $schema: vars.$schema, - $background: #f7f4f0, - $accent-color: #5B8F8A + $background: #21242c, + $accent-color: #77ac82 ) - ); + ) +} + +.hierarchical-grid-preview { + margin-block-start: rem(24px); +} + +igx-expansion-panel { + --ig-expansion-panel-header-focus-background: transparent; +} + +.igx-checkbox__ripple { + opacity: 0; } .color-pickers { display: flex; - align-items: center; - gap: 24px; - padding: 8px 0; + flex-direction: column; + gap: rem(12px); +} + +.color-pickers__title { + font-size: rem(15px); + font-weight: 600; + letter-spacing: .06em; + color: var(--ig-gray-600); + margin: 0; + margin-block-end: rem(4px); } .color-picker-item { display: flex; - align-items: center; - gap: 8px; - font-size: 14px; - - input[type='color'] { - -webkit-appearance: none; - appearance: none; - width: 36px; - height: 36px; - border: 1px solid currentColor; - padding: 0; - cursor: pointer; + flex-direction: column; + gap: rem(6px); + + &__label { + font-size: rem(12px); + color: var(--ig-gray-700); - &::-webkit-color-swatch-wrapper { padding: 0; } - &::-webkit-color-swatch { border: none; } - &::-moz-color-swatch { border: none; } + &--scrub { + cursor: ns-resize; + user-select: none; + } } - .no-color { + &__control { + display: flex; + align-items: center; + gap: rem(10px); + } + + igx-input-group { + --ig-input-group-focused-border-color: var(--ig-gray-500); + + [igxInput] { + font-size: rem(13px); + font-weight: 400; + } + } + + &__swatch-wrap { position: relative; - width: 36px; - height: 36px; - border: 1px solid currentColor; - background: transparent; - cursor: pointer; + width: rem(28px); + height: rem(28px); + flex-shrink: 0; - &::before, - &::after { - content: ''; + input[type='color'] { + -webkit-appearance: none; + appearance: none; position: absolute; inset: 0; - margin: auto; - width: 1px; - height: 70%; - background: red; + opacity: 0; + width: 100%; + height: 100%; + cursor: pointer; + border: none; + padding: 0; + margin: 0; + } + } + + &__swatch { + position: absolute; + inset: 0; + border-radius: rem(5px); + border: 1px solid var(--ig-gray-400); + pointer-events: none; + + svg { + display: none; + } + } + + &__swatch--auto { + display: flex; + align-items: center; + justify-content: center; + background: var(--ig-gray-200); + color: var(--ig-gray-500); + + svg { + display: block; + width: rem(12px); + height: rem(12px); + } + } + + &__value { + flex: 1; + min-width: 0; + font-size: rem(13px); + cursor: default; + } + + &__reset { + display: inline-flex; + align-items: center; + justify-content: center; + width: rem(24px); + height: rem(24px); + border: none; + border-radius: rem(4px); + background: transparent; + color: var(--ig-gray-600); + font-size: rem(14px); + cursor: pointer; + transition: color 120ms ease, background 120ms ease; + + &:hover { + color: var(--ig-gray-700); } + } + +} + +.border-rules { + display: grid; + gap: rem(8px); + padding-block-end: rem(12px); + + &__add { + width: 100%; + } +} + +.border-combo { + width: 100%; +} + +.border-rule { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + align-items: center; + gap: rem(4px); + min-height: rem(40px); + border-block-end: 1px solid var(--ig-gray-200); + + &__summary { + display: grid; + grid-template-columns: rem(16px) minmax(0, 1fr); + gap: rem(2px) rem(8px); + align-items: center; + min-width: 0; + padding: rem(6px) 0; + border: 0; + background: transparent; + color: inherit; + text-align: start; + cursor: pointer; + } + + &__swatch { + grid-row: 1 / span 2; + width: rem(16px); + height: rem(16px); + border: 1px solid var(--ig-gray-300); + border-radius: rem(3px); + + &--auto { + background: + linear-gradient(135deg, transparent 45%, var(--ig-gray-400) 45%, var(--ig-gray-400) 55%, transparent 55%), + var(--ig-gray-100); + } + } + + &__label { + overflow: hidden; + color: var(--ig-gray-800); + font-size: rem(13px); + font-weight: 500; + text-overflow: ellipsis; + white-space: nowrap; + } + + &__value { + overflow: hidden; + color: var(--ig-gray-600); + font-size: rem(11px); + text-overflow: ellipsis; + white-space: nowrap; + } + + &__remove { + font-size: rem(11px); + } +} + +.border-rule-editor { + display: grid; + gap: rem(12px); + padding-block: rem(4px) rem(12px); + border-block-end: 1px solid var(--ig-gray-200); + + &__actions { + display: flex; + justify-content: flex-end; + gap: rem(4px); + } +} + +.theme-panel-accordion { + --theme: material; + + .igx-input-group__bundle-main { + border: none; + box-shadow: none; + transition: none; + } + + .igx-input-group__bundle-start { + visibility: visible; + } + + .igx-expansion-panel__header-inner { + padding: rem(8px) 0; + } + + igx-expansion-panel + igx-expansion-panel { + border-block-start: 1px solid var(--ig-gray-200); + } + + igx-expansion-panel-header { + padding-inline-start: 0; + } + + igx-expansion-panel-title { + font-size: rem(14px); + font-weight: 500; + letter-spacing: .06em; + color: var(--ig-gray-700); + } + + .color-pickers { + padding-block-end: rem(12px); + } +} + +.border-target { + display: flex; + align-items: center; + gap: rem(8px); + font-size: rem(13px); + color: var(--ig-gray-700); + cursor: pointer; + user-select: none; + + input[type='checkbox'] { + accent-color: var(--ig-primary-500); + width: rem(14px); + height: rem(14px); + cursor: pointer; + flex-shrink: 0; + } +} + +.theme-export { + margin-block-start: rem(20px); + + &__btn { + width: 100%; + gap: rem(8px); + font-size: rem(13px); + letter-spacing: .04em; + } + + &__panel { + margin-block-start: rem(10px); + border: 1px solid var(--ig-gray-300); + border-radius: rem(6px); + overflow: hidden; + } + + &__panel-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: rem(6px) rem(10px) rem(6px) rem(12px); + font-size: rem(12px); + color: var(--ig-gray-600); + background: var(--ig-gray-100); + border-block-end: 1px solid var(--ig-gray-300); + } + + &__section-label { + display: flex; + align-items: center; + justify-content: space-between; + gap: rem(8px); + padding: rem(6px) rem(12px) rem(4px); + font-size: rem(11px); + font-weight: 600; + letter-spacing: .05em; + color: var(--ig-gray-500); + background: var(--ig-gray-100); + border-block-end: 1px solid var(--ig-gray-300); + } + + &__copy { + font-size: rem(12px); + white-space: nowrap; + } + + &__code + &__section-label { + border-block-start: 1px solid var(--ig-gray-300); + } - &::before { transform: rotate(45deg); } - &::after { transform: rotate(-45deg); } + &__code { + margin: 0; + padding: rem(12px) rem(14px); + font-size: rem(12px); + font-family: 'JetBrains Mono', 'Fira Code', Consolas, monospace; + color: var(--ig-gray-700); + background: var(--ig-surface-500); + overflow-x: auto; + white-space: pre-wrap; } } diff --git a/src/app/grid-theme-builder/grid-theme-builder.sample.ts b/src/app/grid-theme-builder/grid-theme-builder.sample.ts index 37da5b043cf..c453ed2b3eb 100644 --- a/src/app/grid-theme-builder/grid-theme-builder.sample.ts +++ b/src/app/grid-theme-builder/grid-theme-builder.sample.ts @@ -1,6 +1,28 @@ -import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, OnInit, signal, viewChild } from '@angular/core'; +import { NgTemplateOutlet } from '@angular/common'; +import { AfterViewInit, ChangeDetectionStrategy, Component, computed, effect, ElementRef, inject, OnInit, signal, TemplateRef, viewChild, ViewEncapsulation, WritableSignal } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { IGX_GRID_DIRECTIVES, IgxActionStripComponent, IgxButtonDirective, IgxGridComponent, IgxNumberSummaryOperand, IgxSummaryResult } from 'igniteui-angular'; +import { IgxAccordionComponent } from 'igniteui-angular/accordion'; +import { IgxComboComponent } from 'igniteui-angular/combo'; +import { IGX_EXPANSION_PANEL_DIRECTIVES } from 'igniteui-angular/expansion-panel'; +import { IgxHierarchicalGridComponent, IgxRowIslandComponent } from 'igniteui-angular/grids/hierarchical-grid'; +import { IgxInputGroupComponent, IgxInputDirective, IgxPrefixDirective, IgxSuffixDirective } from 'igniteui-angular/input-group'; +import { IGX_SELECT_DIRECTIVES } from 'igniteui-angular/select'; +import { PropertyChangeService } from '../properties-panel/property-change.service'; import { SAMPLE_DATA } from '../shared/sample-data'; -import { IGX_GRID_DIRECTIVES, IgxActionStripComponent, IgxGridComponent, IgxNumberSummaryOperand, IgxSummaryResult } from 'igniteui-angular'; + +type BorderTarget = 'header' | 'row' | 'pinned' | 'summaryPinned' | 'summary' | 'activeCell'; + +interface BorderSignals { + color: WritableSignal; + width: WritableSignal; + style: WritableSignal; +} + +interface BorderOption { + value: BorderTarget; + label: string; +} class EmployeesSummary extends IgxNumberSummaryOperand { public override operate(data?: any[]): IgxSummaryResult[] { @@ -14,19 +36,583 @@ class EmployeesSummary extends IgxNumberSummaryOperand { styleUrls: ['grid-theme-builder.sample.scss'], templateUrl: 'grid-theme-builder.sample.html', changeDetection: ChangeDetectionStrategy.OnPush, - imports: [IGX_GRID_DIRECTIVES, IgxActionStripComponent] + encapsulation: ViewEncapsulation.None, + imports: [FormsModule, NgTemplateOutlet, IGX_GRID_DIRECTIVES, IgxHierarchicalGridComponent, IgxRowIslandComponent, IgxActionStripComponent, IgxButtonDirective, IgxAccordionComponent, IgxComboComponent, IGX_EXPANSION_PANEL_DIRECTIVES, IGX_SELECT_DIRECTIVES, IgxInputGroupComponent, IgxInputDirective, IgxPrefixDirective, IgxSuffixDirective] }) export class GridThemeBuilderSampleComponent implements OnInit, AfterViewInit { protected readonly gridForeground = signal(''); protected readonly gridBackground = signal(''); protected readonly gridAccentColor = signal(''); + protected readonly gridHeaderBackground = signal(''); + protected readonly gridHeaderTextColor = signal(''); + protected readonly gridRowOddBackground = signal(''); + protected readonly gridRowOddTextColor = signal(''); + protected readonly gridRowEvenBackground = signal(''); + protected readonly gridRowEvenTextColor = signal(''); + protected readonly gridRowBorderWidth = signal(''); + protected readonly gridRowBorderStyle = signal(''); + protected readonly gridRowBorderColor = signal(''); + protected readonly gridHeaderBorderWidth = signal(''); + protected readonly gridHeaderBorderStyle = signal(''); + protected readonly gridHeaderBorderColor = signal(''); + protected readonly gridPinnedBorderWidth = signal(''); + protected readonly gridPinnedBorderStyle = signal(''); + protected readonly gridPinnedBorderColor = signal(''); + protected readonly gridSummaryPinnedBorderWidth = signal(''); + protected readonly gridSummaryPinnedBorderStyle = signal(''); + protected readonly gridSummaryBackground = signal(''); + protected readonly gridSummaryLabelColor = signal(''); + protected readonly gridSummaryResultColor = signal(''); + protected readonly gridSummaryPinnedBorderColor = signal(''); + protected readonly gridSummaryBorderColor = signal(''); + protected readonly gridSummaryBorderWidth = signal(''); + protected readonly gridSummaryBorderStyle = signal(''); + protected readonly gridToolbarBackground = signal(''); + protected readonly gridToolbarForeground = signal(''); + protected readonly gridToolbarAccentColor = signal(''); + protected readonly paginatorBackground = signal(''); + protected readonly paginatorForeground = signal(''); + protected readonly paginatorAccentColor = signal(''); + protected readonly advancedFilteringBackground = signal(''); + protected readonly advancedFilteringForeground = signal(''); + protected readonly advancedFilteringAccentColor = signal(''); + protected readonly excelStyleFilteringBackground = signal(''); + protected readonly excelStyleFilteringForeground = signal(''); + protected readonly excelStyleFilteringAccentColor = signal(''); + protected readonly borderOptions: BorderOption[] = [ + { value: 'header', label: 'Header' }, + { value: 'row', label: 'Rows' }, + { value: 'pinned', label: 'Pinned columns' }, + { value: 'summaryPinned', label: 'Summary Pinned Border' }, + { value: 'summary', label: 'Summary Borders' }, + { value: 'activeCell', label: 'Active cell' }, + ]; + protected readonly borderRules = signal([]); + protected readonly borderEditorOpen = signal(true); + protected readonly activeBorderRuleIndex = signal(null); + protected readonly activeBorderTargets = signal([]); + protected readonly draftBorderColor = signal(''); + protected readonly draftBorderWidth = signal(''); + protected readonly draftBorderStyle = signal(''); + protected readonly availableBorderOptions = computed(() => { + const activeIndex = this.activeBorderRuleIndex(); + const unavailableTargets = this.borderRules().flatMap((rule, index) => index === activeIndex ? [] : rule); + return this.borderOptions.filter(option => !unavailableTargets.includes(option.value)); + }); + protected readonly canAddBorderRule = computed(() => { + const activeIndex = this.activeBorderRuleIndex(); + const activeTargets = this.activeBorderTargets(); + const assignedTargets = this.borderRules().flatMap((rule, index) => + index === activeIndex ? activeTargets : rule + ); + if (activeIndex === null) assignedTargets.push(...activeTargets); + return this.borderOptions.some(option => !assignedTargets.includes(option.value)); + }); + protected readonly isEditingBorderRule = computed(() => this.activeBorderRuleIndex() !== null); + protected readonly gridCellActiveBorderWidth = signal(''); + protected readonly gridCellActiveBorderStyle = signal(''); + protected readonly gridCellActiveBorderColor = signal(''); + protected readonly gridCellSelectedWithinBackground = signal(''); + protected readonly gridCellSelectedWithinTextColor = signal(''); + protected readonly gridCellSelectedBackground = signal(''); + protected readonly gridCellSelectedTextColor = signal(''); protected readonly gridRef = viewChild.required('grid'); private readonly sampleEl = viewChild.required('sampleEl'); + private readonly customControlsTemplate = viewChild.required>('customControls'); + + protected readonly showExport = signal(false); + protected readonly copiedExport = signal<'css' | 'scss' | null>(null); + private borderEditorSnapshot = new Map(); + + protected readonly exportCode = computed(() => { + const gridLines: string[] = []; + const summaryLines: string[] = []; + const toolbarLines: string[] = []; + const paginatorLines: string[] = []; + const advancedFilteringLines: string[] = []; + const excelStyleFilteringLines: string[] = []; + const add = (lines: string[], token: string, value: string) => { + if (value) lines.push(` ${token}: ${value},`); + }; + + add(gridLines, '$background', this.gridBackground()); + add(gridLines, '$foreground', this.gridForeground()); + add(gridLines, '$accent-color', this.gridAccentColor()); + add(gridLines, '$header-background', this.gridHeaderBackground()); + add(gridLines, '$header-text-color', this.gridHeaderTextColor()); + add(gridLines, '$row-odd-background', this.gridRowOddBackground()); + add(gridLines, '$row-odd-text-color', this.gridRowOddTextColor()); + add(gridLines, '$row-even-background', this.gridRowEvenBackground()); + add(gridLines, '$row-even-text-color', this.gridRowEvenTextColor()); + add(gridLines, '$row-border-width', this.borderExportValue('row', 'width')); + add(gridLines, '$row-border-style', this.borderExportValue('row', 'style')); + add(gridLines, '$row-border-color', this.borderExportValue('row', 'color')); + add(gridLines, '$header-border-width', this.borderExportValue('header', 'width')); + add(gridLines, '$header-border-style', this.borderExportValue('header', 'style')); + add(gridLines, '$header-border-color', this.borderExportValue('header', 'color')); + add(gridLines, '$pinned-border-width', this.borderExportValue('pinned', 'width')); + add(gridLines, '$pinned-border-style', this.borderExportValue('pinned', 'style')); + add(gridLines, '$pinned-border-color', this.borderExportValue('pinned', 'color')); + add(gridLines, '$cell-active-border-width', this.borderExportValue('activeCell', 'width')); + add(gridLines, '$active-state-border-style', this.borderExportValue('activeCell', 'style')); + add(gridLines, '$cell-active-border-color', this.borderExportValue('activeCell', 'color')); + add(gridLines, '$cell-selected-within-background', this.gridCellSelectedWithinBackground()); + add(gridLines, '$cell-selected-within-text-color', this.gridCellSelectedWithinTextColor()); + add(gridLines, '$cell-selected-background', this.gridCellSelectedBackground()); + add(gridLines, '$cell-selected-text-color', this.gridCellSelectedTextColor()); + + add(summaryLines, '$background-color', this.gridSummaryBackground()); + add(summaryLines, '$label-color', this.gridSummaryLabelColor()); + add(summaryLines, '$result-color', this.gridSummaryResultColor()); + add(summaryLines, '$border-width', this.borderExportValue('summary', 'width')); + add(summaryLines, '$border-style', this.borderExportValue('summary', 'style')); + add(summaryLines, '$border-color', this.borderExportValue('summary', 'color')); + add(summaryLines, '$pinned-border-width', this.borderExportValue('summaryPinned', 'width')); + add(summaryLines, '$pinned-border-style', this.borderExportValue('summaryPinned', 'style')); + add(summaryLines, '$pinned-border-color', this.borderExportValue('summaryPinned', 'color')); + + add(toolbarLines, '$background', this.gridToolbarBackground()); + add(toolbarLines, '$foreground', this.gridToolbarForeground()); + add(toolbarLines, '$accent-color', this.gridToolbarAccentColor()); + + add(paginatorLines, '$background', this.paginatorBackground()); + add(paginatorLines, '$foreground', this.paginatorForeground()); + add(paginatorLines, '$accent-color', this.paginatorAccentColor()); + + add(advancedFilteringLines, '$background', this.advancedFilteringBackground()); + add(advancedFilteringLines, '$foreground', this.advancedFilteringForeground()); + add(advancedFilteringLines, '$accent-color', this.advancedFilteringAccentColor()); + + add(excelStyleFilteringLines, '$background', this.excelStyleFilteringBackground()); + add(excelStyleFilteringLines, '$foreground', this.excelStyleFilteringForeground()); + add(excelStyleFilteringLines, '$accent-color', this.excelStyleFilteringAccentColor()); + + const themes: string[] = []; + if (gridLines.length) { + themes.push(`@include tokens(\n grid-theme(\n${gridLines.join('\n')}\n )\n);`); + } + if (summaryLines.length) { + themes.push(`@include tokens(\n grid-summary-theme(\n${summaryLines.join('\n')}\n )\n);`); + } + if (toolbarLines.length) { + themes.push(`@include tokens(\n grid-toolbar-theme(\n${toolbarLines.join('\n')}\n )\n);`); + } + if (paginatorLines.length) { + themes.push(`@include tokens(\n paginator-theme(\n${paginatorLines.join('\n')}\n )\n);`); + } + if (advancedFilteringLines.length) { + themes.push(`@include tokens(\n query-builder-theme(\n${advancedFilteringLines.join('\n')}\n )\n);`); + } + if (excelStyleFilteringLines.length) { + themes.push(`@include tokens(\n excel-filtering-theme(\n${excelStyleFilteringLines.join('\n')}\n )\n);`); + } + + return themes.length ? themes.join('\n\n') : null; + }); + + protected readonly exportCssVars = computed(() => { + const gridVars: string[] = []; + const toolbarVars: string[] = []; + const paginatorVars: string[] = []; + const advancedFilteringVars: string[] = []; + const excelStyleFilteringVars: string[] = []; + const add = (vars: string[], prefix: string, token: string, value: string) => { + if (value) vars.push(` --ig-${prefix}-${token}: ${value};`); + }; + + add(gridVars, 'grid', 'background', this.gridBackground()); + add(gridVars, 'grid', 'foreground', this.gridForeground()); + add(gridVars, 'grid', 'accent-color', this.gridAccentColor()); + add(gridVars, 'grid', 'header-background', this.gridHeaderBackground()); + add(gridVars, 'grid', 'header-text-color', this.gridHeaderTextColor()); + add(gridVars, 'grid', 'row-odd-background', this.gridRowOddBackground()); + add(gridVars, 'grid', 'row-odd-text-color', this.gridRowOddTextColor()); + add(gridVars, 'grid', 'row-even-background', this.gridRowEvenBackground()); + add(gridVars, 'grid', 'row-even-text-color', this.gridRowEvenTextColor()); + add(gridVars, 'grid', 'row-border-width', this.borderExportValue('row', 'width')); + add(gridVars, 'grid', 'row-border-style', this.borderExportValue('row', 'style')); + add(gridVars, 'grid', 'row-border-color', this.borderExportValue('row', 'color')); + add(gridVars, 'grid', 'header-border-width', this.borderExportValue('header', 'width')); + add(gridVars, 'grid', 'header-border-style', this.borderExportValue('header', 'style')); + add(gridVars, 'grid', 'header-border-color', this.borderExportValue('header', 'color')); + add(gridVars, 'grid', 'pinned-border-width', this.borderExportValue('pinned', 'width')); + add(gridVars, 'grid', 'pinned-border-style', this.borderExportValue('pinned', 'style')); + add(gridVars, 'grid', 'pinned-border-color', this.borderExportValue('pinned', 'color')); + add(gridVars, 'grid', 'summary-background-color', this.gridSummaryBackground()); + add(gridVars, 'grid', 'summary-label-color', this.gridSummaryLabelColor()); + add(gridVars, 'grid', 'summary-result-color', this.gridSummaryResultColor()); + add(gridVars, 'grid', 'summary-pinned-border-width', this.borderExportValue('summaryPinned', 'width')); + add(gridVars, 'grid', 'summary-pinned-border-style', this.borderExportValue('summaryPinned', 'style')); + add(gridVars, 'grid', 'summary-pinned-border-color', this.borderExportValue('summaryPinned', 'color')); + add(gridVars, 'grid', 'summary-border-width', this.borderExportValue('summary', 'width')); + add(gridVars, 'grid', 'summary-border-style', this.borderExportValue('summary', 'style')); + add(gridVars, 'grid', 'summary-border-color', this.borderExportValue('summary', 'color')); + add(gridVars, 'grid', 'cell-active-border-width', this.borderExportValue('activeCell', 'width')); + add(gridVars, 'grid', 'active-state-border-style', this.borderExportValue('activeCell', 'style')); + add(gridVars, 'grid', 'cell-active-border-color', this.borderExportValue('activeCell', 'color')); + add(gridVars, 'grid', 'cell-selected-within-background', this.gridCellSelectedWithinBackground()); + add(gridVars, 'grid', 'cell-selected-within-text-color', this.gridCellSelectedWithinTextColor()); + add(gridVars, 'grid', 'cell-selected-background', this.gridCellSelectedBackground()); + add(gridVars, 'grid', 'cell-selected-text-color', this.gridCellSelectedTextColor()); + + add(toolbarVars, 'grid-toolbar', 'background', this.gridToolbarBackground()); + add(toolbarVars, 'grid-toolbar', 'foreground', this.gridToolbarForeground()); + add(toolbarVars, 'grid-toolbar', 'accent-color', this.gridToolbarAccentColor()); + + add(paginatorVars, 'paginator', 'background', this.paginatorBackground()); + add(paginatorVars, 'paginator', 'foreground', this.paginatorForeground()); + add(paginatorVars, 'paginator', 'accent-color', this.paginatorAccentColor()); + + add(advancedFilteringVars, 'query-builder', 'background', this.advancedFilteringBackground()); + add(advancedFilteringVars, 'query-builder', 'foreground', this.advancedFilteringForeground()); + add(advancedFilteringVars, 'query-builder', 'accent-color', this.advancedFilteringAccentColor()); + + add(excelStyleFilteringVars, 'excel-filtering', 'background', this.excelStyleFilteringBackground()); + add(excelStyleFilteringVars, 'excel-filtering', 'foreground', this.excelStyleFilteringForeground()); + add(excelStyleFilteringVars, 'excel-filtering', 'accent-color', this.excelStyleFilteringAccentColor()); + + const blocks: string[] = []; + if (gridVars.length) blocks.push(`.my-grid {\n${gridVars.join('\n')}\n}`); + if (toolbarVars.length) blocks.push(`.my-grid igx-grid-toolbar {\n${toolbarVars.join('\n')}\n}`); + if (paginatorVars.length) blocks.push(`.my-grid igx-paginator {\n${paginatorVars.join('\n')}\n}`); + if (advancedFilteringVars.length) blocks.push(`.my-grid igx-advanced-filtering-dialog {\n${advancedFilteringVars.join('\n')}\n}`); + if (excelStyleFilteringVars.length) { + blocks.push(`.my-grid igx-grid-excel-style-filtering, + .my-grid .igx-excel-filter__secondary) {\n${excelStyleFilteringVars.join('\n')}\n}`); + } + + return blocks.length ? blocks.join('\n\n') : null; + }); + + private readonly propertyChangeService = inject(PropertyChangeService); + + constructor() { + effect(() => { + this.exportCode(); + this.exportCssVars(); + this.copiedExport.set(null); + }, { allowSignalWrites: true }); + } public data: Array; + public readonly hierarchicalData = this.generateHierarchicalData(10, 3); public readonly employeesSummary = EmployeesSummary; + private readonly borderDefaults: Record = { + header: { color: '', width: '1px', style: 'solid' }, + row: { color: '', width: '1px', style: 'solid' }, + pinned: { color: '', width: '2px', style: 'solid' }, + summaryPinned: { color: '', width: '1px', style: 'solid' }, + summary: { color: '', width: '1px', style: 'solid' }, + activeCell: { color: '', width: '1px', style: 'solid' }, + }; + + private borderExportValue(target: BorderTarget, property: keyof BorderSignals): string { + const value = this.getBorderSignals(target)[property](); + return value === this.borderDefaults[target][property] ? '' : value; + } + + private generateHierarchicalData(count: number, level: number, parentID: string = null): Array { + const rows = []; + const currentLevel = level; + let children; + + for (let i = 0; i < count; i++) { + const rowID = parentID ? parentID + i : i.toString(); + if (level > 0) { + children = this.generateHierarchicalData(((i % 2) + 1) * Math.round(count / 3), currentLevel - 1, rowID); + } + + rows.push({ + ID: rowID, + ChildLevels: currentLevel, + ProductName: 'Product: A' + i, + childData: children + }); + } + + return rows; + } + + protected addBorderRule(): void { + if (this.borderEditorOpen()) { + if (!this.activeBorderTargets().length) return; + this.completeBorderRule(); + } + + this.borderEditorSnapshot.clear(); + this.activeBorderRuleIndex.set(null); + this.activeBorderTargets.set([]); + this.draftBorderColor.set(''); + this.draftBorderWidth.set(''); + this.draftBorderStyle.set(''); + this.borderEditorOpen.set(true); + } + + protected setActiveBorderTargets(targets: BorderTarget[]): void { + const previousTargets = this.activeBorderTargets(); + const addedTargets = targets.filter(target => !previousTargets.includes(target)); + const removedTargets = previousTargets.filter(target => !targets.includes(target)); + + for (const target of addedTargets) { + this.captureBorderTarget(target); + } + for (const target of removedTargets) { + this.restoreBorderTarget(target); + } + + if (!previousTargets.length && targets.length) { + const signals = this.getBorderSignals(targets[0]); + this.draftBorderColor.set(signals.color()); + this.draftBorderWidth.set(signals.width() || this.borderDefaults[targets[0]].width); + this.draftBorderStyle.set(signals.style() || this.borderDefaults[targets[0]].style); + } + + this.activeBorderTargets.set(targets); + this.applyBorderDraft(targets); + } + + protected completeBorderRule(): void { + const targets = this.activeBorderTargets(); + if (!targets.length) return; + + const activeIndex = this.activeBorderRuleIndex(); + if (activeIndex === null) { + this.borderRules.update(rules => [...rules, targets]); + } else { + const previousTargets = this.borderRules()[activeIndex]; + for (const target of previousTargets.filter(previousTarget => !targets.includes(previousTarget))) { + this.resetBorderTarget(target); + } + this.borderRules.update(rules => rules.map((rule, index) => index === activeIndex ? targets : rule)); + } + + this.closeBorderEditor(); + } + + protected cancelBorderRule(): void { + for (const [target, snapshot] of this.borderEditorSnapshot) { + const signals = this.getBorderSignals(target); + signals.color.set(snapshot.color); + signals.width.set(snapshot.width); + signals.style.set(snapshot.style); + } + this.closeBorderEditor(); + } + + protected editBorderRule(index: number): void { + const targets = this.borderRules()[index]; + this.borderEditorSnapshot.clear(); + for (const target of targets) { + this.captureBorderTarget(target); + } + + const signals = this.getBorderSignals(targets[0]); + this.activeBorderRuleIndex.set(index); + this.activeBorderTargets.set([...targets]); + this.draftBorderColor.set(signals.color()); + this.draftBorderWidth.set(signals.width() || this.borderDefaults[targets[0]].width); + this.draftBorderStyle.set(signals.style() || this.borderDefaults[targets[0]].style); + this.borderEditorOpen.set(true); + } + + protected removeBorderRule(index: number): void { + for (const target of this.borderRules()[index]) { + this.resetBorderTarget(target); + } + this.borderRules.update(rules => rules.filter((_, ruleIndex) => ruleIndex !== index)); + } + + protected borderRuleLabel(targets: BorderTarget[]): string { + return targets.map(target => + this.borderOptions.find(option => option.value === target)?.label ?? target + ).join(', '); + } + + protected borderRuleSummary(targets: BorderTarget[]): string { + const target = targets[0]; + const signals = this.getBorderSignals(target); + const defaults = this.borderDefaults[target]; + return `${signals.width() || defaults.width} ${signals.style() || defaults.style} ${signals.color() || 'auto'}`; + } + + protected borderRuleColor(targets: BorderTarget[]): string { + return this.getBorderSignals(targets[0]).color(); + } + + protected activeBorderDefaultWidth(): string { + const target = this.activeBorderTargets()[0]; + return target ? this.borderDefaults[target].width : '1px'; + } + + protected activeBorderDefaultStyle(): string { + const target = this.activeBorderTargets()[0]; + return target ? this.borderDefaults[target].style : 'Solid'; + } + + protected setActiveBorderColor(value: string): void { + this.draftBorderColor.set(value); + this.applyBorderDraft(this.activeBorderTargets()); + } + + protected applyActiveBorderColor(event: Event): void { + const input = event.target as HTMLInputElement; + let value = input.value.trim(); + if (!value.startsWith('#')) value = '#' + value; + if (/^#[0-9a-fA-F]{3}$/.test(value)) { + value = '#' + value[1] + value[1] + value[2] + value[2] + value[3] + value[3]; + } + if (/^#[0-9a-fA-F]{6}$/i.test(value)) { + this.setActiveBorderColor(value.toUpperCase()); + } + input.value = this.draftBorderColor(); + } + + protected resetActiveBorderColor(): void { + this.setActiveBorderColor(''); + } + + protected setActiveBorderWidth(value: string): void { + this.draftBorderWidth.set(value.trim()); + this.applyBorderDraft(this.activeBorderTargets()); + } + + protected startActiveBorderWidthScrub(event: PointerEvent): void { + this.startScrub(this.draftBorderWidth, this.activeBorderDefaultWidth(), event, () => { + this.applyBorderDraft(this.activeBorderTargets()); + }); + } + + protected scrubActiveBorderWidth(event: KeyboardEvent): void { + this.scrubKeydown(this.draftBorderWidth, this.activeBorderDefaultWidth(), event); + this.applyBorderDraft(this.activeBorderTargets()); + } + + protected setActiveBorderStyle(style: string): void { + this.draftBorderStyle.set(style); + this.applyBorderDraft(this.activeBorderTargets()); + } + + private applyBorderDraft(targets: BorderTarget[]): void { + for (const target of targets) { + const signals = this.getBorderSignals(target); + signals.color.set(this.draftBorderColor()); + signals.width.set(this.draftBorderWidth()); + signals.style.set(this.draftBorderStyle()); + } + } + + private captureBorderTarget(target: BorderTarget): void { + if (this.borderEditorSnapshot.has(target)) return; + + const signals = this.getBorderSignals(target); + this.borderEditorSnapshot.set(target, { + color: signals.color(), + width: signals.width(), + style: signals.style() + }); + } + + private restoreBorderTarget(target: BorderTarget): void { + const snapshot = this.borderEditorSnapshot.get(target); + if (!snapshot) return; + + const signals = this.getBorderSignals(target); + signals.color.set(snapshot.color); + signals.width.set(snapshot.width); + signals.style.set(snapshot.style); + } + + private closeBorderEditor(): void { + this.borderEditorSnapshot.clear(); + this.activeBorderRuleIndex.set(null); + this.activeBorderTargets.set([]); + this.borderEditorOpen.set(false); + } + + private resetBorderTarget(target: BorderTarget): void { + const signals = this.getBorderSignals(target); + signals.color.set(''); + signals.width.set(''); + signals.style.set(''); + } + + private getBorderSignals(target: BorderTarget): BorderSignals { + const map: Record = { + header: { color: this.gridHeaderBorderColor, width: this.gridHeaderBorderWidth, style: this.gridHeaderBorderStyle }, + row: { color: this.gridRowBorderColor, width: this.gridRowBorderWidth, style: this.gridRowBorderStyle }, + pinned: { color: this.gridPinnedBorderColor, width: this.gridPinnedBorderWidth, style: this.gridPinnedBorderStyle }, + summaryPinned: { color: this.gridSummaryPinnedBorderColor, width: this.gridSummaryPinnedBorderWidth, style: this.gridSummaryPinnedBorderStyle }, + summary: { color: this.gridSummaryBorderColor, width: this.gridSummaryBorderWidth, style: this.gridSummaryBorderStyle }, + activeCell: { color: this.gridCellActiveBorderColor, width: this.gridCellActiveBorderWidth, style: this.gridCellActiveBorderStyle }, + }; + return map[target]; + } + + protected applyColor(sig: WritableSignal, event: Event): void { + const input = event.target as HTMLInputElement; + let v = input.value.trim(); + if (!v.startsWith('#')) v = '#' + v; + if (/^#[0-9a-fA-F]{3}$/.test(v)) { + v = '#' + v[1] + v[1] + v[2] + v[2] + v[3] + v[3]; + } + if (/^#[0-9a-fA-F]{6}$/i.test(v)) { + sig.set(v.toUpperCase()); + } + input.value = sig(); + } + + protected startScrub(sig: WritableSignal, fallback: string, event: PointerEvent, onChange?: () => void): void { + const el = event.currentTarget as HTMLElement; + el.setPointerCapture(event.pointerId); + let lastY = event.clientY; + + const onMove = (e: PointerEvent) => { + const delta = lastY - e.clientY; + lastY = e.clientY; + if (delta === 0) return; + const current = sig() || fallback; + const match = current.match(/^([\d.]+)(\D*)$/); + if (!match) return; + const unit = match[2] || 'px'; + const step = unit === 'px' ? 1 : 0.1; + const next = Math.max(0, Math.round((parseFloat(match[1]) + delta * step) * 10) / 10); + sig.set(`${next}${unit}`); + onChange?.(); + }; + + const onUp = () => { + el.removeEventListener('pointermove', onMove as EventListener); + el.removeEventListener('pointerup', onUp); + }; + + el.addEventListener('pointermove', onMove as EventListener); + el.addEventListener('pointerup', onUp); + } + + protected scrubKeydown(sig: WritableSignal, fallback: string, event: KeyboardEvent): void { + if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return; + event.preventDefault(); + const current = sig() || fallback; + const match = current.match(/^([\d.]+)(\D*)$/); + if (!match) return; + const unit = match[2] || 'px'; + const step = unit === 'px' ? 1 : 0.1; + const delta = event.key === 'ArrowUp' ? step : -step; + const next = Math.max(0, Math.round((parseFloat(match[1]) + delta) * 10) / 10); + sig.set(`${next}${unit}`); + (event.target as HTMLInputElement).value = sig(); + } + + protected copyExport(code: string | null, format: 'css' | 'scss'): void { + if (!code) return; + + navigator.clipboard.writeText(code).then(() => { + this.copiedExport.set(format); + }); + } + public ngOnInit(): void { this.data = SAMPLE_DATA; } @@ -35,9 +621,8 @@ export class GridThemeBuilderSampleComponent implements OnInit, AfterViewInit { const styles = getComputedStyle(this.sampleEl().nativeElement); this.gridBackground.set(styles.getPropertyValue('--ig-grid-background').trim()); this.gridAccentColor.set(styles.getPropertyValue('--ig-grid-accent-color').trim()); + this.propertyChangeService.setCustomControls(this.customControlsTemplate()); + this.propertyChangeService.setPanelTitle('Grid Theming'); } - protected resetForeground(): void { - this.gridForeground.set(''); - } } diff --git a/src/app/pageHeading/pageHeading.template.html b/src/app/pageHeading/pageHeading.template.html index f00e56896f1..3bd6c1f1264 100644 --- a/src/app/pageHeading/pageHeading.template.html +++ b/src/app/pageHeading/pageHeading.template.html @@ -1,4 +1,4 @@ -@let config = (propertyChangeService.panelConfig | async | keyvalue)?.length > 0; +@let config = ((propertyChangeService.panelConfig | async | keyvalue)?.length > 0) || !!(propertyChangeService.customControlsSource | async); diff --git a/src/app/properties-panel/properties-panel.component.html b/src/app/properties-panel/properties-panel.component.html index 1fa51950f40..ca3de61472e 100644 --- a/src/app/properties-panel/properties-panel.component.html +++ b/src/app/properties-panel/properties-panel.component.html @@ -1,6 +1,6 @@
- Properties Panel + {{ (propertyChangeService.panelTitle | async) || 'Properties Panel' }}
@for( key of getConfigKeys(); track key ) {
diff --git a/src/app/properties-panel/property-change.service.ts b/src/app/properties-panel/property-change.service.ts index b6f0344d107..a4ea3a8bfc1 100644 --- a/src/app/properties-panel/property-change.service.ts +++ b/src/app/properties-panel/property-change.service.ts @@ -43,12 +43,14 @@ export class PropertyChangeService { public propertyChanges = new BehaviorSubject({}); public panelConfig = new BehaviorSubject({}); public customControlsSource = new BehaviorSubject | null>(null); + public panelTitle = new BehaviorSubject(null); constructor(private router: Router) { this.router.events.subscribe(event => { if (event instanceof ActivationStart) { this.clearPanelConfig(); this.clearCustomControls(); + this.panelTitle.next(null); } }); @@ -97,4 +99,8 @@ export class PropertyChangeService { public clearCustomControls(): void { this.customControlsSource.next(null); } + + public setPanelTitle(title: string): void { + this.panelTitle.next(title); + } }