@use 'sass:math'; @use '@angular/cdk'; @use '../core/style/vendor-prefixes'; @use '../core/style/variables'; @use '../core/tokens/token-utils'; @use '../core/tokens/m2/mat/select' as tokens-mat-select; $mat-select-arrow-size: 5px !default; $mat-select-arrow-margin: 4px !default; $mat-select-panel-max-height: 275px !default; $mat-select-placeholder-arrow-space: 2 * ($mat-select-arrow-size + $mat-select-arrow-margin); $leading-width: 12px !default; $scale: 0.75 !default; .mat-mdc-select { display: inline-block; width: 100%; outline: none; @include token-utils.use-tokens( tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) { @include vendor-prefixes.smooth-font(); @include token-utils.create-token-slot(color, enabled-trigger-text-color); @include token-utils.create-token-slot(font-family, trigger-text-font); @include token-utils.create-token-slot(line-height, trigger-text-line-height); @include token-utils.create-token-slot(font-size, trigger-text-size); @include token-utils.create-token-slot(font-weight, trigger-text-weight); @include token-utils.create-token-slot(letter-spacing, trigger-text-tracking); } } @include token-utils.use-tokens(tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) { div.mat-mdc-select-panel { @include token-utils.create-token-slot(box-shadow, container-elevation-shadow); } } .mat-mdc-select-disabled { @include token-utils.use-tokens( tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) { @include token-utils.create-token-slot(color, disabled-trigger-text-color); } } .mat-mdc-select-trigger { display: inline-flex; align-items: center; cursor: pointer; position: relative; box-sizing: border-box; width: 100%; .mat-mdc-select-disabled & { @include vendor-prefixes.user-select(none); cursor: default; } } .mat-mdc-select-value { width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .mat-mdc-select-value-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .mat-mdc-select-arrow-wrapper { height: 24px; flex-shrink: 0; display: inline-flex; align-items: center; .mat-form-field-appearance-fill .mdc-text-field--no-label & { transform: none; } } .mat-mdc-form-field .mat-mdc-select.mat-mdc-select-invalid .mat-mdc-select-arrow, .mat-form-field-invalid:not(.mat-form-field-disabled) .mat-mdc-form-field-infix::after { @include token-utils.use-tokens(tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) { @include token-utils.create-token-slot(color, invalid-arrow-color); } } .mat-mdc-select-arrow { width: $mat-select-arrow-size * 2; height: $mat-select-arrow-size; position: relative; @include token-utils.use-tokens( tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) { @include token-utils.create-token-slot(color, enabled-arrow-color); .mat-mdc-form-field.mat-focused & { @include token-utils.create-token-slot(color, focused-arrow-color); } .mat-mdc-form-field .mat-mdc-select.mat-mdc-select-disabled & { @include token-utils.create-token-slot(color, disabled-arrow-color); } } svg { fill: currentColor; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); @include cdk.high-contrast { // On Chromium browsers the `currentColor` blends in with the // background for SVGs so we have to fall back to `CanvasText`. fill: CanvasText; .mat-mdc-select-disabled & { fill: GrayText; } } } } // Even though we don't use the MDC styles, we need to keep the classes in the // DOM for the Gmat versions to work. We need to bump up the specificity here // so that it's higher than MDC's styles. div.mat-mdc-select-panel { width: 100%; // Ensures that the panel matches the overlay width. max-height: $mat-select-panel-max-height; outline: 0; overflow: auto; padding: 8px 0; border-radius: 4px; box-sizing: border-box; // Workaround in case other MDC menu surface styles bleed in. position: static; @include token-utils.use-tokens( tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) { @include token-utils.create-token-slot(background-color, panel-background-color); } @include cdk.high-contrast { outline: solid 1px; } .cdk-overlay-pane:not(.mat-mdc-select-panel-above) & { border-top-left-radius: 0; border-top-right-radius: 0; transform-origin: top center; } .mat-mdc-select-panel-above & { border-bottom-left-radius: 0; border-bottom-right-radius: 0; transform-origin: bottom center; } .mat-mdc-option { --mdc-list-list-item-container-color: var(--mat-select-panel-background-color); } } .mat-mdc-select-placeholder { // Delay the transition until the label has animated about a third of the way through, in // order to prevent the placeholder from overlapping for a split second. transition: color variables.$swift-ease-out-duration math.div(variables.$swift-ease-out-duration, 3) variables.$swift-ease-out-timing-function; @include token-utils.use-tokens( tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) { @include token-utils.create-token-slot(color, placeholder-text-color); } ._mat-animation-noopable & { transition: none; } .mat-form-field-hide-placeholder & { color: transparent; // Overwrite browser specific CSS properties that can overwrite the `color` property. // Some developers seem to use this approach to easily overwrite the placeholder / label color. -webkit-text-fill-color: transparent; // Remove the transition to prevent the placeholder // from overlapping when the label comes back down. transition: none; // Prevents the '...' from showing on the parent element. display: block; } } // Our MDC form field implementation is based on the MDC text field which doesn't include styles // for select. The select specific styles are not present as they don't use their text field as a // container. Below are the styles to account for the select arrow icon at the end. .mat-mdc-form-field-type-mat-select { &:not(.mat-form-field-disabled) .mat-mdc-text-field-wrapper { cursor: pointer; } &.mat-form-field-appearance-fill { .mat-mdc-floating-label { max-width: calc(100% - #{$mat-select-placeholder-arrow-space}); } .mdc-floating-label--float-above { $arrow-scale: math.div($mat-select-placeholder-arrow-space, $scale); max-width: calc(100% / #{$scale} - #{$arrow-scale}); } } &.mat-form-field-appearance-outline { .mdc-notched-outline__notch { max-width: calc(100% - #{2 * ($mat-select-placeholder-arrow-space + $leading-width)}); } .mdc-text-field--label-floating .mdc-notched-outline__notch { max-width: calc(100% - #{$leading-width * 2}); } } } // Used to prevent inline elements from collapsing if their text bindings // become empty. This is preferrable to inserting a blank space, because the // space can be read out by screen readers (see #21725). .mat-mdc-select-min-line:empty::before { content: ' '; white-space: pre; width: 1px; display: inline-block; // Prevents some browsers from rendering the element in high contrast mode. Use `visibility` // instead of `opacity` since VoiceOver + Chrome still reads out the space with the latter. visibility: hidden; } @include token-utils.use-tokens(tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) { .mat-form-field-appearance-fill .mat-mdc-select-arrow-wrapper { @include token-utils.create-token-slot(transform, arrow-transform); } }