|
- import { css } from '@tesseract-design/goofy-goober';
-
- export enum ButtonSize {
- SMALL = 'small',
- MEDIUM = 'medium',
- LARGE = 'large',
- }
-
- export enum ButtonVariant {
- OUTLINE = 'outline',
- FILLED = 'filled',
- }
-
- export type ButtonBaseArgs = {
- /**
- * Size of the component.
- */
- size: ButtonSize,
- /**
- * Will the component occupy the whole width of its container?
- */
- block: boolean,
- /**
- * Stylistic variant of the component.
- */
- variant: ButtonVariant,
- /**
- * Will the component display a surrounding border?
- */
- border: boolean,
- /**
- * Will the component reject any activation?
- */
- disabled: boolean,
- /**
- * Will the component conserve visual space?
- */
- compact: boolean,
- /**
- * Is the component an item inside a menu?
- */
- menuItem: boolean,
- }
-
- const MIN_HEIGHTS: Record<ButtonSize, string> = {
- [ButtonSize.SMALL]: '2.5rem',
- [ButtonSize.MEDIUM]: '3rem',
- [ButtonSize.LARGE]: '4rem',
- };
-
- export const Button = ({
- size,
- block,
- variant,
- disabled,
- compact,
- }: ButtonBaseArgs): string => css.cx(
- css`
- box-sizing: border-box;
- vertical-align: middle;
- appearance: none;
- font: inherit;
- font-family: var(--font-family-base, sans-serif);
- text-transform: uppercase;
- font-weight: bolder;
- border-radius: 0.25rem;
- justify-content: center;
- align-items: center;
- position: relative;
- border: 0;
- user-select: none;
- text-decoration: none;
- white-space: nowrap;
- line-height: 1;
-
- & > :first-child::before {
- box-shadow: 0 0 0 0 var(--color-accent, blue);
- transition-property: box-shadow;
- transition-duration: 150ms;
- transition-timing-function: linear;
- }
-
- &:disabled {
- opacity: 0.5;
- cursor: not-allowed;
- }
-
- &::-moz-focus-inner {
- outline: 0;
- border: 0;
- }
-
- &:focus > :first-child::before {
- box-shadow: 0 0 0 0.375rem var(--color-accent, blue);
- }
-
- &:disabled > :first-child::before {
- box-shadow: 0 0 0 0 var(--color-accent, blue) !important;
- }
- `,
-
- css.dynamic({
- 'min-height': MIN_HEIGHTS[size],
- }),
-
- css.if (disabled) (
- css`
- --color-accent: var(--color-primary, blue);
- opacity: 0.5;
- cursor: not-allowed;
- `
- ).else (
- css`
- cursor: pointer;
- &:hover {
- --color-accent: var(--color-hover, blue);
- outline: 0;
- }
-
- &:focus {
- --color-accent: var(--color-hover, blue);
- outline: 0;
- }
-
- &:active {
- --color-accent: var(--color-active, red);
- outline: 0;
- }
-
- &:hover > :first-child::before {
- box-shadow: 0 0 0 0.375rem var(--color-accent, blue);
- }
- `
- ),
-
- css.if (block) (
- css`
- width: 100%;
- display: flex;
- `
- ).else (
- css`
- display: inline-flex;
- `
- ),
-
- css.if (compact) (
- css`
- font-stretch: condensed;
- padding: 0 0.5rem;
- `
- ).else(
- css`
- padding: 0 1rem;
- `
- ),
-
- css.if (variant === ButtonVariant.FILLED) (
- css`
- background-color: var(--color-accent, blue);
- color: var(--color-bg, white) !important;
- `
- ),
-
- css.if (variant === ButtonVariant.OUTLINE) (
- css`
- background-color: var(--color-bg, white);
- color: var(--color-accent, blue);
- `
- ),
- );
-
- export const Border = ({
- border
- }: ButtonBaseArgs): string => css.cx(
- css.if (border) (
- css`
- border-color: var(--color-accent, blue);
- box-sizing: border-box;
- display: inline-block;
- border-width: 0.125rem;
- border-style: solid;
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- border-radius: inherit;
- pointer-events: none;
- &::before {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- content: '';
- border-radius: 0.125rem;
- opacity: 0.5;
- pointer-events: none;
- }
- `
- ),
- );
-
- export const Label = ({
- compact,
- menuItem,
- }: ButtonBaseArgs): string => css.cx(
- css`
- display: block;
- flex-grow: 1;
- flex-basis: 0;
- min-width: 0;
- `,
-
- css.if (compact || menuItem) (
- css`
- text-align: left;
- `
- ).else (
- css`
- text-align: center;
- `
- ),
-
- css.if (compact) (
- css`
- & ~ :last-child {
- margin-right: -0.5rem;
- }
- `
- ).else (
- css`
- & ~ :last-child {
- margin-right: -1rem;
- }
- `
- ),
- );
-
- export const BadgeContainer = ({
- size,
- }: ButtonBaseArgs): string => css.cx(
- css`
- width: 2rem;
- text-align: center;
- flex-shrink: 0;
- & + * {
- margin-left: -0.5rem;
- }
- `,
- css.nest('&:last-child')(
- css.dynamic({
- width: MIN_HEIGHTS[size],
- })
- ),
- );
-
- export const OverflowText = (): string => css.cx(
- css`
- width: 100%;
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
- height: 1.1em;
- line-height: 1;
- `,
- );
-
- export const IndicatorWrapper = ({
- size
- }: ButtonBaseArgs): string => css.cx(
- css`
- flex-shrink: 0;
- box-sizing: border-box;
- display: grid;
- place-content: center;
- padding: 0 1rem;
- z-index: 1;
- pointer-events: none;
- line-height: 1;
- user-select: none;
- `,
- css.dynamic({
- width: `calc(${MIN_HEIGHTS[size]} * 0.75)`,
- height: MIN_HEIGHTS[size],
- }),
- );
-
- export const Indicator = () => css.cx(
- css`
- width: 1.5em;
- height: 1.5em;
- fill: none;
- stroke: currentColor;
- stroke-width: 2;
- stroke-linecap: round;
- stroke-linejoin: round;
- `,
- );
-
- export const MainText = () => css.cx(
- css`
- width: 100%;
- `,
- );
-
- export const Subtext = () => css.cx(
- css`
- display: block;
- height: 1.1em;
- line-height: 1.1;
- width: 100%;
- font-size: 0.875em;
- text-transform: none;
- font-weight: var(--font-weight-base, normal);
- `,
- );
|