mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
226 lines
13 KiB
226 lines
13 KiB
@use '../core/m2/palette' as m2-palette;
|
|
@use '../core/tokens/m2-utils';
|
|
@use '../core/tokens/m3-utils';
|
|
@use '../core/theming/inspection';
|
|
@use '../core/theming/theming';
|
|
@use 'sass:color';
|
|
@use 'sass:map';
|
|
@use 'sass:math';
|
|
@use 'sass:meta';
|
|
|
|
@function get-tokens($theme) {
|
|
$system: m2-utils.get-system($theme);
|
|
$disabled: m3-utils.color-with-opacity(map.get($system, on-surface), 38%);
|
|
|
|
// TODO: Use system colors instead of checking theme type
|
|
$is-dark: false;
|
|
@if (meta.type-of($theme) == map and map.get($theme, color)) {
|
|
$is-dark: inspection.get-theme-type($theme) == dark;
|
|
}
|
|
|
|
// Note the spelling of the `GrayText` here which is a system color. See:
|
|
// https://developer.mozilla.org/en-US/docs/Web/CSS/system-color
|
|
$select-disabled-option-text-color: GrayText;
|
|
$select-option-text-color: inherit;
|
|
|
|
@if ($is-dark) {
|
|
// On dark themes we set the native `select` color to some shade of white,
|
|
// however the color propagates to all of the `option` elements, which are
|
|
// always on a white background inside the dropdown, causing them to blend in.
|
|
// Since we can't change background of the dropdown, we need to explicitly
|
|
// reset the color of the options to something dark.
|
|
$select-option-text-color: m2-palette.$dark-primary-text;
|
|
$select-disabled-option-text-color: m2-palette.$dark-disabled-text;
|
|
}
|
|
|
|
@return (
|
|
base: (
|
|
form-field-filled-active-indicator-height: 1px,
|
|
form-field-filled-focus-active-indicator-height: 2px,
|
|
form-field-filled-container-shape: 4px,
|
|
form-field-outlined-outline-width: 1px,
|
|
form-field-outlined-focus-outline-width: 2px,
|
|
form-field-outlined-container-shape: 4px,
|
|
),
|
|
color: map.merge(private-get-color-palette-color-tokens($theme, primary), (
|
|
// MDC has a token for the enabled placeholder, but not for the disabled one.
|
|
form-field-disabled-input-text-placeholder-color: $disabled,
|
|
form-field-state-layer-color: map.get($system, on-surface),
|
|
form-field-error-text-color: map.get($system, error),
|
|
form-field-select-option-text-color: $select-option-text-color,
|
|
form-field-select-disabled-option-text-color: $select-disabled-option-text-color,
|
|
|
|
// These tokens are necessary for M3. MDC has them built in already, but:
|
|
// 1. They are too specific, breaking a lot of internal clients.
|
|
// 2. The larger selectors result in a larger bundle.
|
|
// Note: MDC has tokens for all the various states of the icons. Some of them are ommitted,
|
|
// because they resolve to the same value (e.g. focus and base states for the leading icon
|
|
// are the same).
|
|
form-field-leading-icon-color: unset,
|
|
form-field-disabled-leading-icon-color: unset,
|
|
form-field-trailing-icon-color: unset,
|
|
form-field-disabled-trailing-icon-color: unset,
|
|
form-field-error-focus-trailing-icon-color: unset,
|
|
form-field-error-hover-trailing-icon-color: unset,
|
|
form-field-error-trailing-icon-color: unset,
|
|
form-field-enabled-select-arrow-color: map.get($system, on-surface-variant),
|
|
form-field-disabled-select-arrow-color: $disabled,
|
|
form-field-hover-state-layer-opacity: map.get($system, hover-state-layer-opacity),
|
|
form-field-focus-state-layer-opacity: map.get($system, focus-state-layer-opacity),
|
|
form-field-filled-container-color: map.get($system, surface-variant),
|
|
form-field-filled-disabled-container-color:
|
|
m3-utils.color-with-opacity(map.get($system, on-surface), 4%),
|
|
form-field-filled-label-text-color: map.get($system, on-surface-variant),
|
|
form-field-filled-hover-label-text-color: map.get($system, on-surface-variant),
|
|
form-field-filled-disabled-label-text-color: $disabled,
|
|
form-field-filled-input-text-color: map.get($system, on-surface),
|
|
form-field-filled-disabled-input-text-color: $disabled,
|
|
form-field-filled-input-text-placeholder-color: map.get($system, on-surface-variant),
|
|
form-field-filled-error-hover-label-text-color: map.get($system, error),
|
|
form-field-filled-error-focus-label-text-color: map.get($system, error),
|
|
form-field-filled-error-label-text-color: map.get($system, error),
|
|
form-field-filled-error-caret-color: map.get($system, error),
|
|
form-field-filled-active-indicator-color: map.get($system, on-surface-variant),
|
|
form-field-filled-disabled-active-indicator-color:
|
|
m3-utils.color-with-opacity(map.get($system, on-surface), 12%),
|
|
form-field-filled-hover-active-indicator-color: map.get($system, on-surface),
|
|
form-field-filled-error-active-indicator-color: map.get($system, error),
|
|
form-field-filled-error-focus-active-indicator-color: map.get($system, error),
|
|
form-field-filled-error-hover-active-indicator-color: map.get($system, error),
|
|
form-field-outlined-label-text-color: map.get($system, on-surface-variant),
|
|
form-field-outlined-hover-label-text-color: map.get($system, on-surface),
|
|
form-field-outlined-disabled-label-text-color: $disabled,
|
|
form-field-outlined-input-text-color: map.get($system, on-surface),
|
|
form-field-outlined-disabled-input-text-color: $disabled,
|
|
form-field-outlined-input-text-placeholder-color: map.get($system, on-surface-variant),
|
|
form-field-outlined-error-caret-color: map.get($system, error),
|
|
form-field-outlined-error-focus-label-text-color: map.get($system, error),
|
|
form-field-outlined-error-label-text-color: map.get($system, error),
|
|
form-field-outlined-error-hover-label-text-color: map.get($system, error),
|
|
form-field-outlined-outline-color: map.get($system, outline-variant),
|
|
form-field-outlined-disabled-outline-color:
|
|
m3-utils.color-with-opacity(map.get($system, on-surface), 12%),
|
|
form-field-outlined-hover-outline-color: map.get($system, on-surface),
|
|
form-field-outlined-error-focus-outline-color: map.get($system, error),
|
|
form-field-outlined-error-hover-outline-color: map.get($system, error),
|
|
form-field-outlined-error-outline-color: map.get($system, error),
|
|
)),
|
|
typography: (
|
|
// MDC uses `subtitle1` for the input value, placeholder and floating label. The spec
|
|
// shows `body1` for text fields though, so we manually override the typography.
|
|
// Note: Form controls inherit the typography from the parent form field.
|
|
form-field-container-text-font: map.get($system, body-large-font),
|
|
form-field-container-text-line-height: map.get($system, body-large-line-height),
|
|
form-field-container-text-size: map.get($system, body-large-size),
|
|
form-field-container-text-tracking: map.get($system, body-large-tracking),
|
|
form-field-container-text-weight: map.get($system, body-large-weight),
|
|
|
|
// In container styles, we updated the floating label to use the `body-1` typography level.
|
|
// The MDC notched outline overrides this accidentally (only when the label floats) to a
|
|
// `rem`-based value. This results in different label widths when floated/docked and then
|
|
// breaks the notch width as it has been measured in the docked state (where `body-1` is
|
|
// applied). We try to unset these styles set by the `mdc-notched-outline`:
|
|
// https://github.com/material-components/material-components-web/blob/master/packages/mdc-notched-outline/_mixins.scss#L272-L292.
|
|
// This is why we can't use their `label-text-populated-size` token and we have to declare
|
|
// our own version of it.
|
|
form-field-outlined-label-text-populated-size: map.get($system, body-large-size),
|
|
|
|
form-field-subscript-text-font: map.get($system, body-small-font),
|
|
form-field-subscript-text-line-height: map.get($system, body-small-line-height),
|
|
form-field-subscript-text-size: map.get($system, body-small-size),
|
|
form-field-subscript-text-tracking: map.get($system, body-small-tracking),
|
|
form-field-subscript-text-weight: map.get($system, body-small-weight),
|
|
form-field-filled-label-text-font: map.get($system, body-large-font),
|
|
form-field-filled-label-text-size: map.get($system, body-large-size),
|
|
form-field-filled-label-text-tracking: map.get($system, body-large-tracking),
|
|
form-field-filled-label-text-weight: map.get($system, body-large-weight),
|
|
form-field-outlined-label-text-font: map.get($system, body-large-font),
|
|
form-field-outlined-label-text-size: map.get($system, body-large-size),
|
|
form-field-outlined-label-text-tracking: map.get($system, body-large-tracking),
|
|
form-field-outlined-label-text-weight: map.get($system, body-large-weight),
|
|
),
|
|
density: get-density-tokens($theme),
|
|
);
|
|
}
|
|
|
|
// Generates the mapping for the properties that change based on the form field color.
|
|
@function private-get-color-palette-color-tokens($theme, $color-variant) {
|
|
$system: m2-utils.get-system($theme);
|
|
$system: m3-utils.replace-colors-with-variant($system, primary, $color-variant);
|
|
|
|
@return (
|
|
form-field-focus-select-arrow-color:
|
|
m3-utils.color-with-opacity(map.get($system, primary), 87%),
|
|
form-field-filled-caret-color: map.get($system, primary),
|
|
form-field-filled-focus-active-indicator-color: map.get($system, primary),
|
|
form-field-filled-focus-label-text-color:
|
|
m3-utils.color-with-opacity(map.get($system, primary), 87%),
|
|
form-field-outlined-caret-color: map.get($system, primary),
|
|
form-field-outlined-focus-outline-color: map.get($system, primary),
|
|
form-field-outlined-focus-label-text-color:
|
|
m3-utils.color-with-opacity(map.get($system, primary), 87%),
|
|
);
|
|
}
|
|
|
|
// Tokens that can be configured through Angular Material's density theming API.
|
|
@function get-density-tokens($theme) {
|
|
$system: m2-utils.get-system($theme);
|
|
$density-scale: theming.clamp-density(map.get($system, density-scale), -5);
|
|
$size-scale: (
|
|
0: 56px,
|
|
-1: 52px,
|
|
-2: 48px,
|
|
-3: 44px,
|
|
-4: 40px,
|
|
-5: 36px,
|
|
);
|
|
$height: map.get($size-scale, $density-scale);
|
|
$hide-label: $height < 52px;
|
|
|
|
// We computed the desired height of the form-field using the density configuration. The
|
|
// spec only describes vertical spacing/alignment in non-dense mode. This means that we
|
|
// cannot update the spacing to explicit numbers based on the density scale. Instead, we
|
|
// determine the height reduction and equally subtract it from the default `top` and `bottom`
|
|
// padding that is provided by the Material Design specification.
|
|
$vertical-deduction: math.div(56px - $height, 2);
|
|
|
|
// Note: these calculations are trivial enough that we could do them at runtime with `calc`
|
|
// and the value of the `height` token. The problem is that because we need to hide the label
|
|
// if the container becomes too short, we have to change the padding calculation. This is
|
|
// complicated further by the fact that filled form fields without labels have the same
|
|
// vertical padding as outlined ones. Alternatives:
|
|
// 1. Using container queries to hide the label and change the padding - this doesn't work
|
|
// because size container queries require setting the `container-type` property which breaks
|
|
// the form field layout. We could use style queries, but they're only supported in Chrome.
|
|
// 2. Monitoring the size of the label - we already have a `ResizeObserver` on the label so we
|
|
// could reuse it to also check when it becomes `display: none`. This would allows us to remove
|
|
// the three padding tokens. We don't do it, because it would require us to always set up
|
|
// the resize observer, as opposed to currently where it's only set up for outlined form fields.
|
|
// This may lead to performance regressions.
|
|
// 3. Conditionally adding `::before` and `::after` to the infix with positive and negative
|
|
// margin respectively - this works, but is likely to break a lot of overrides that are targeting
|
|
// a specific padding. It also runs the risk of overflowing the container.
|
|
// TODO: switch the padding tokens to style-based container queries
|
|
// when they become available in all the browsers we support.
|
|
$filled-with-label-padding-top: 24px - $vertical-deduction;
|
|
$filled-with-label-padding-bottom: 8px - $vertical-deduction;
|
|
$vertical-padding: 16px - $vertical-deduction;
|
|
$filled-label-display: block;
|
|
$filled-with-label-container-padding-top: $filled-with-label-padding-top;
|
|
$filled-with-label-container-padding-bottom: $filled-with-label-padding-bottom;
|
|
|
|
@if ($hide-label) {
|
|
$filled-label-display: none;
|
|
$filled-with-label-container-padding-top: $vertical-padding;
|
|
$filled-with-label-container-padding-bottom: $vertical-padding;
|
|
}
|
|
|
|
@return (
|
|
form-field-container-height: $height,
|
|
form-field-filled-label-display: $filled-label-display,
|
|
form-field-container-vertical-padding: $vertical-padding,
|
|
form-field-filled-with-label-container-padding-top: $filled-with-label-container-padding-top,
|
|
form-field-filled-with-label-container-padding-bottom:
|
|
$filled-with-label-container-padding-bottom,
|
|
);
|
|
}
|
|
|