| @use "sass:color"; |
| @use "sass:list"; |
| @use "sass:map"; |
| @use "sass:meta"; |
| @use "../colors" as *; |
| @use "../config" as *; |
| @use "../theme" as *; |
| @use "../variables" as *; |
| @use "../functions" as *; |
| @use "../vendor/rfs" as *; |
| @use "../mixins/border-radius" as *; |
| @use "../mixins/box-shadow" as *; |
| @use "../mixins/focus-ring" as *; |
| @use "../mixins/gradients" as *; |
| @use "../mixins/transition" as *; |
| @use "button-variables" as *; |
| |
| // scss-docs-start btn-variants |
| $button-variants: ( |
| "solid": ( |
| "base": ( |
| "bg": "bg", |
| "color": "contrast", |
| "border-color": "bg" |
| ), |
| "hover": ( |
| "bg": "bg", |
| "border-color": "bg", |
| "color": "contrast" |
| ), |
| "active": ( |
| "bg": "bg", |
| "border-color": "bg", |
| "color": "contrast" |
| ) |
| ), |
| "outline": ( |
| "base": ( |
| "bg": "transparent", |
| "color": "text", |
| "border-color": "border" |
| ), |
| "hover": ( |
| "bg": "bg", |
| "color": "contrast", |
| "border-color": "bg" |
| ), |
| "active": ( |
| "bg": "bg", |
| "color": "contrast", |
| "border-color": "bg" |
| ) |
| ), |
| "subtle": ( |
| "base": ( |
| "bg": "bg-subtle", |
| "color": "text", |
| "border-color": "transparent" |
| ), |
| "hover": ( |
| "bg": ("bg-muted", "bg-subtle"), |
| "color": "text-emphasis" |
| ), |
| "active": ( |
| "bg": "bg-subtle", |
| "color": "text-emphasis" |
| ) |
| ), |
| "text": ( |
| "base": ( |
| "color": "text", |
| "bg": "transparent", |
| "border-color": "transparent" |
| ), |
| "hover": ( |
| "color": "text", |
| "bg": "bg-subtle" |
| ), |
| "active": ( |
| "color": "text", |
| "bg": "bg-subtle" |
| ) |
| ) |
| ) !default; |
| // scss-docs-end btn-variants |
| |
| // // Main button style generator mixin |
| |
| // Generate button variant classes (e.g., .btn-solid, .btn-outline, etc.) |
| // scss-docs-start btn-variant-mixin |
| @each $variant, $_ in $button-variants { |
| .btn-#{$variant} { |
| @each $property, $value in map.get($button-variants, $variant, "base") { |
| @if $value == "transparent" { |
| --#{$prefix}btn-#{$property}: transparent; |
| } @else { |
| --#{$prefix}btn-#{$property}: var(--#{$prefix}theme-#{$value}); |
| } |
| } |
| |
| &:hover { |
| @each $property, $value in map.get($button-variants, $variant, "hover") { |
| @if $value == "transparent" { |
| --#{$prefix}btn-hover-#{$property}: transparent; |
| } @else if meta.type-of($value) == "list" { |
| $first-value: list.nth($value, 1); |
| $second-value: list.nth($value, 2); |
| --#{$prefix}btn-hover-#{$property}: color-mix(in oklch, var(--#{$prefix}theme-#{$first-value}) 50%, var(--#{$prefix}theme-#{$second-value})); |
| } @else if $value == "bg-subtle" { |
| --#{$prefix}btn-hover-#{$property}: var(--#{$prefix}theme-#{$value}); |
| } @else { |
| --#{$prefix}btn-hover-#{$property}: oklch(from var(--#{$prefix}theme-#{$value}) calc(l * .95) calc(c * 1.1) h); |
| } |
| } |
| } |
| |
| &:focus-visible { |
| outline-color: var(--#{$prefix}theme-focus-ring); |
| } |
| |
| &:active, |
| &.active { |
| @each $property, $value in map.get($button-variants, $variant, "active") { |
| @if $value == "transparent" { |
| --#{$prefix}btn-active-#{$property}: transparent; |
| } @else if $value == "bg-subtle" { |
| --#{$prefix}btn-active-#{$property}: var(--#{$prefix}theme-#{$value}); |
| } @else { |
| --#{$prefix}btn-active-#{$property}: oklch(from var(--#{$prefix}theme-#{$value}) calc(l * .9) calc(c * 1.15) h); |
| } |
| } |
| } |
| } |
| } |
| // scss-docs-end btn-variant-mixin |
| |
| // scss-docs-start btn-size-mixin |
| @mixin button-size($padding-y, $padding-x, $font-size, $border-radius) { |
| --#{$prefix}btn-padding-y: #{$padding-y}; |
| --#{$prefix}btn-padding-x: #{$padding-x}; |
| @include rfs($font-size, --#{$prefix}btn-font-size); |
| --#{$prefix}btn-border-radius: #{$border-radius}; |
| } |
| // scss-docs-end btn-size-mixin |
| |
| // |
| // Base styles |
| // |
| |
| @layer components { |
| .btn, |
| [class*="btn-"] { |
| // scss-docs-start btn-css-vars |
| --#{$prefix}btn-padding-x: #{$btn-padding-x}; |
| --#{$prefix}btn-padding-y: #{$btn-padding-y}; |
| --#{$prefix}btn-font-family: #{$btn-font-family}; |
| @include rfs($btn-font-size, --#{$prefix}btn-font-size); |
| --#{$prefix}btn-font-weight: #{$btn-font-weight}; |
| --#{$prefix}btn-line-height: #{$btn-line-height}; |
| --#{$prefix}btn-color: #{$btn-color}; |
| --#{$prefix}btn-bg: transparent; |
| --#{$prefix}btn-border-width: #{$btn-border-width}; |
| --#{$prefix}btn-border-color: transparent; |
| --#{$prefix}btn-border-radius: #{$btn-border-radius}; |
| --#{$prefix}btn-hover-border-color: transparent; |
| --#{$prefix}btn-box-shadow: #{$btn-box-shadow}; |
| --#{$prefix}btn-disabled-opacity: #{$btn-disabled-opacity}; |
| // --#{$prefix}btn-focus-box-shadow: 0 0 0 #{$btn-focus-width} rgba(var(--#{$prefix}btn-focus-shadow-rgb), .5); |
| // scss-docs-end btn-css-vars |
| |
| display: inline-block; |
| padding: var(--#{$prefix}btn-padding-y) var(--#{$prefix}btn-padding-x); |
| font-family: var(--#{$prefix}btn-font-family); |
| @include font-size(var(--#{$prefix}btn-font-size)); |
| font-weight: var(--#{$prefix}btn-font-weight); |
| line-height: var(--#{$prefix}btn-line-height); |
| color: var(--#{$prefix}btn-color); |
| text-align: center; |
| text-decoration: none; |
| white-space: $btn-white-space; |
| vertical-align: middle; |
| cursor: if($enable-button-pointers, pointer, null); |
| user-select: none; |
| border: var(--#{$prefix}btn-border-width) solid var(--#{$prefix}btn-border-color); |
| @include border-radius(var(--#{$prefix}btn-border-radius)); |
| @include gradient-bg(var(--#{$prefix}btn-bg)); |
| @include box-shadow(var(--#{$prefix}btn-box-shadow)); |
| @include transition($btn-transition); |
| |
| &:hover { |
| color: var(--#{$prefix}btn-hover-color); |
| background-color: var(--#{$prefix}btn-hover-bg); |
| border-color: var(--#{$prefix}btn-hover-border-color); |
| } |
| |
| .btn-check + &:hover { |
| // override for the checkbox/radio buttons |
| color: var(--#{$prefix}btn-color); |
| background-color: var(--#{$prefix}btn-bg); |
| border-color: var(--#{$prefix}btn-border-color); |
| } |
| |
| &:focus-visible { |
| @include focus-ring(true); |
| --#{$prefix}focus-ring-offset: 1px; |
| } |
| |
| .btn-check:focus-visible + & { |
| @include focus-ring(true); |
| } |
| |
| .btn-check:checked + &, |
| :not(.btn-check) + &:active, |
| &:first-child:active, |
| &.active, |
| &.show { |
| color: var(--#{$prefix}btn-active-color); |
| background-color: var(--#{$prefix}btn-active-bg); |
| // Remove CSS gradients if they're enabled |
| background-image: if($enable-gradients, none, null); |
| border-color: var(--#{$prefix}btn-active-border-color); |
| @include box-shadow(var(--#{$prefix}btn-active-shadow)); |
| |
| &:focus-visible { |
| @include focus-ring(true); |
| } |
| } |
| |
| .btn-check:checked:focus-visible + & { |
| @include focus-ring(true); |
| } |
| |
| &:disabled, |
| &.disabled, |
| fieldset:disabled & { |
| color: var(--#{$prefix}btn-disabled-color); |
| pointer-events: none; |
| background-color: var(--#{$prefix}btn-disabled-bg); |
| background-image: if($enable-gradients, none, null); |
| border-color: var(--#{$prefix}btn-disabled-border-color); |
| opacity: var(--#{$prefix}btn-disabled-opacity); |
| @include box-shadow(none); |
| } |
| } |
| |
| // |
| // Link buttons |
| // |
| |
| // Make a button look and behave like a link |
| .btn-link { |
| --#{$prefix}btn-font-weight: #{$font-weight-normal}; |
| --#{$prefix}btn-color: #{$btn-link-color}; |
| --#{$prefix}btn-bg: transparent; |
| --#{$prefix}btn-border-color: transparent; |
| --#{$prefix}btn-hover-color: #{$btn-link-hover-color}; |
| --#{$prefix}btn-hover-border-color: transparent; |
| --#{$prefix}btn-active-color: #{$btn-link-hover-color}; |
| --#{$prefix}btn-active-border-color: transparent; |
| --#{$prefix}btn-disabled-color: #{$btn-link-disabled-color}; |
| --#{$prefix}btn-disabled-border-color: transparent; |
| --#{$prefix}btn-box-shadow: 0 0 0 #000; // Can't use `none` as keyword negates all values when used with multiple shadows |
| // --#{$prefix}btn-focus-shadow-rgb: #{$btn-link-focus-shadow-rgb}; |
| |
| text-decoration: var(--#{$prefix}link-decoration); |
| |
| @if $enable-gradients { |
| background-image: none; |
| } |
| |
| &:focus-visible { |
| color: var(--#{$prefix}btn-color); |
| } |
| |
| &:hover { |
| color: var(--#{$prefix}btn-hover-color); |
| } |
| |
| // No need for an active state here |
| } |
| |
| |
| // |
| // Button Sizes |
| // |
| |
| .btn-lg { |
| @include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg); |
| } |
| |
| .btn-sm { |
| @include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm); |
| } |
| |
| .btn-check { |
| position: absolute; |
| clip: rect(0, 0, 0, 0); |
| pointer-events: none; |
| |
| &[disabled], |
| &:disabled { |
| + .btn { |
| pointer-events: none; |
| filter: none; |
| opacity: .65; |
| } |
| } |
| } |
| } |