Files
twenty/packages/twenty-ui/src/input/IconButton/IconButton.module.scss
T
Thomas des Francs e609320666 Squirclesssss 🟦🔵 (#22535)
2026-07-04 07:07:29 +02:00

311 lines
9.8 KiB
SCSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@use 'sass:map';
// The variant × accent × disabled × focus matrix below is ported
// token-for-token from computeIconButtonDynamicStyles in the deprecated
// IconButton.tsx. Matrix rules only assign CSS custom properties; the actual
// declarations live on the flat .button class so twenty-front
// styled(IconButton) overrides keep beating them at (0,1,0) specificity,
// exactly like the legacy single Linaria class did.
// Cascade order inside each branch: base, then [data-focus], then
// [data-disabled] — later rules win, which replicates the legacy switch
// precedence (disabled > focus > base).
.button {
align-items: center;
background: var(--icon-button-bg, transparent);
border-color: var(--icon-button-border-color, transparent);
border-radius: var(--icon-button-radius, var(--t-border-radius-md));
border-style: solid;
border-width: var(--icon-button-border-width, 1px);
box-shadow: var(--icon-button-box-shadow, none);
box-sizing: border-box;
color: var(--icon-button-color, var(--t-font-color-secondary));
cursor: pointer;
display: flex;
flex-direction: row;
font-family: var(--t-font-family);
font-weight: 500;
gap: var(--t-spacing-1);
justify-content: center;
opacity: var(--icon-button-opacity, 1);
padding: 0;
transition: background 0.1s ease;
white-space: nowrap;
&:hover {
background: var(--icon-button-hover-bg, transparent);
}
&:active {
background: var(--icon-button-active-bg, transparent);
}
&:focus {
outline: none;
}
@include focus-ring;
&[data-disabled] {
cursor: not-allowed;
}
}
.small {
height: 24px;
min-width: 24px;
}
.medium {
height: 32px;
min-width: 32px;
}
// position only reshapes the border radius; standalone keeps the .button
// fallback radius. Grouped IconButtons abut flush (no framing container), so
// their outer corners share the standalone md radius.
.button[data-position='left'] {
--icon-button-radius: var(--t-border-radius-md) 0px 0px
var(--t-border-radius-md);
}
.button[data-position='middle'] {
--icon-button-radius: 0px;
}
.button[data-position='right'] {
--icon-button-radius: 0px var(--t-border-radius-md) var(--t-border-radius-md)
0px;
}
// Default border widths: tertiary is borderless and middle collapses the
// horizontal borders for primary/secondary; the .button fallback covers the
// remaining 1px cases.
.button[data-variant='tertiary'] {
--icon-button-border-width: 0;
}
.button[data-position='middle']:is(
[data-variant='primary'],
[data-variant='secondary']
) {
--icon-button-border-width: 1px 0px;
}
// focusOverride from the legacy source: an enabled focused button always
// shows a full 1px border, even for tertiary (borderless) and middle
// (collapsed) buttons.
.button[data-focus]:not([data-disabled]) {
--icon-button-border-width: 1px 1px;
}
// variant=primary, keyed by accent. Null entries mean the disabled state
// keeps the base/focus value, mirroring the legacy switch.
$primary-accents: (
'default': (
bg: var(--t-background-transparent-lighter),
border: var(--t-background-transparent-light),
border-focus: var(--t-color-blue),
border-disabled: null,
shadow-focus: var(--t-accent-tertiary),
color: var(--t-font-color-secondary),
color-disabled: var(--t-font-color-extra-light),
opacity-disabled: null,
hover: var(--t-background-tertiary),
active: var(--t-background-quaternary),
hover-disabled: var(--t-background-transparent-lighter),
active-disabled: var(--t-background-transparent-lighter),
),
'blue': (
bg: var(--t-color-blue),
border: var(--t-background-transparent-light),
border-focus: var(--t-color-blue),
border-disabled: transparent,
shadow-focus: var(--t-accent-tertiary),
color: var(--t-gray-scale-gray1),
color-disabled: null,
opacity-disabled: 0.24,
hover: var(--t-color-blue10),
active: var(--t-color-blue12),
hover-disabled: var(--t-color-blue),
active-disabled: var(--t-color-blue),
),
'danger': (
bg: var(--t-color-red),
border: var(--t-background-transparent-light),
border-focus: var(--t-color-red),
border-disabled: transparent,
shadow-focus: var(--t-color-red3),
color: var(--t-gray-scale-gray1),
color-disabled: null,
opacity-disabled: 0.24,
hover: var(--t-color-red10),
active: var(--t-color-red10),
hover-disabled: var(--t-color-red),
active-disabled: var(--t-color-red),
),
);
@each $accent, $tokens in $primary-accents {
.button[data-variant='primary'][data-accent='#{$accent}'] {
--icon-button-bg: #{map.get($tokens, bg)};
--icon-button-border-color: #{map.get($tokens, border)};
--icon-button-color: #{map.get($tokens, color)};
--icon-button-hover-bg: #{map.get($tokens, hover)};
--icon-button-active-bg: #{map.get($tokens, active)};
}
// borderColor follows the raw focus flag in the legacy source, so
// disabled+focus keeps it unless the accent defines border-disabled.
.button[data-variant='primary'][data-accent='#{$accent}'][data-focus] {
--icon-button-border-color: #{map.get($tokens, border-focus)};
--icon-button-box-shadow: 0 0 0 3px #{map.get($tokens, shadow-focus)};
}
.button[data-variant='primary'][data-accent='#{$accent}'][data-disabled] {
--icon-button-box-shadow: none;
--icon-button-hover-bg: #{map.get($tokens, hover-disabled)};
--icon-button-active-bg: #{map.get($tokens, active-disabled)};
@if map.get($tokens, border-disabled) {
--icon-button-border-color: #{map.get($tokens, border-disabled)};
}
@if map.get($tokens, color-disabled) {
--icon-button-color: #{map.get($tokens, color-disabled)};
}
@if map.get($tokens, opacity-disabled) {
--icon-button-opacity: #{map.get($tokens, opacity-disabled)};
}
}
}
// variant=secondary|tertiary. The two variants share backgrounds and disabled
// treatment; they differ in their resting border (secondary is outlined,
// tertiary borderless) and in how that border reacts to focus, so the border
// logic is spelled out per accent instead of mapped.
// accent=default
.button:is(
[data-variant='secondary'],
[data-variant='tertiary']
)[data-accent='default'] {
--icon-button-hover-bg: var(--t-background-transparent-light);
--icon-button-active-bg: var(--t-background-transparent-light);
}
.button[data-variant='secondary'][data-accent='default'] {
--icon-button-border-color: var(--t-background-transparent-medium);
--icon-button-color: var(--t-font-color-secondary);
}
.button[data-variant='tertiary'][data-accent='default'] {
--icon-button-color: var(--t-font-color-tertiary);
}
// background follows the raw focus flag (it stays on for disabled+focus).
.button:is(
[data-variant='secondary'],
[data-variant='tertiary']
)[data-accent='default'][data-focus] {
--icon-button-bg: var(--t-background-transparent-primary);
--icon-button-border-color: var(--t-color-blue);
--icon-button-box-shadow: 0 0 0 3px var(--t-accent-tertiary);
}
.button:is(
[data-variant='secondary'],
[data-variant='tertiary']
)[data-accent='default'][data-disabled] {
--icon-button-box-shadow: none;
--icon-button-color: var(--t-font-color-extra-light);
--icon-button-hover-bg: transparent;
--icon-button-active-bg: transparent;
}
// The secondary border only turns blue on enabled focus; tertiary keeps the
// blue border even for disabled+focus (raw focus in the legacy source).
.button[data-variant='secondary'][data-accent='default'][data-disabled] {
--icon-button-border-color: var(--t-background-transparent-medium);
}
// accent=blue
.button:is(
[data-variant='secondary'],
[data-variant='tertiary']
)[data-accent='blue'] {
--icon-button-color: var(--t-color-blue);
--icon-button-hover-bg: var(--t-accent-tertiary);
--icon-button-active-bg: var(--t-accent-secondary);
}
.button[data-variant='secondary'][data-accent='blue'] {
--icon-button-border-color: var(--t-color-blue);
}
.button:is(
[data-variant='secondary'],
[data-variant='tertiary']
)[data-accent='blue'][data-focus] {
--icon-button-bg: var(--t-background-transparent-primary);
--icon-button-box-shadow: 0 0 0 3px var(--t-accent-tertiary);
}
// Only the tertiary border reacts to focus for the blue accent; the
// secondary border is keyed on disabled alone.
.button[data-variant='tertiary'][data-accent='blue'][data-focus] {
--icon-button-border-color: var(--t-color-blue);
}
.button:is(
[data-variant='secondary'],
[data-variant='tertiary']
)[data-accent='blue'][data-disabled] {
--icon-button-box-shadow: none;
--icon-button-color: var(--t-accent-accent4060);
--icon-button-hover-bg: transparent;
--icon-button-active-bg: transparent;
}
.button[data-variant='secondary'][data-accent='blue'][data-disabled] {
--icon-button-border-color: var(--t-color-blue5);
}
// accent=danger
.button:is(
[data-variant='secondary'],
[data-variant='tertiary']
)[data-accent='danger'] {
--icon-button-color: var(--t-font-color-danger);
--icon-button-hover-bg: var(--t-background-danger);
--icon-button-active-bg: var(--t-background-danger);
}
.button[data-variant='secondary'][data-accent='danger'] {
--icon-button-border-color: var(--t-border-color-danger);
}
// danger keeps a transparent background even on focus; only the shadow and
// the tertiary border react.
.button:is(
[data-variant='secondary'],
[data-variant='tertiary']
)[data-accent='danger'][data-focus] {
--icon-button-box-shadow: 0 0 0 3px var(--t-color-red3);
}
.button[data-variant='tertiary'][data-accent='danger'][data-focus] {
--icon-button-border-color: var(--t-color-red);
}
.button:is(
[data-variant='secondary'],
[data-variant='tertiary']
)[data-accent='danger'][data-disabled] {
--icon-button-box-shadow: none;
--icon-button-color: var(--t-color-red5);
--icon-button-hover-bg: transparent;
--icon-button-active-bg: transparent;
}