@use "sass:color";
@use "@wordpress/base-styles/colors" as *;
@use "@wordpress/base-styles/variables" as *;
@use "../utils/theme-variables" as *;

/**
 * For easier testing of potential regressions, you can use a Button variant matrix
 * available in a special Storybook instance by running `npm run storybook:e2e:dev`.
 *
 * @see https://github.com/WordPress/gutenberg/blob/trunk/test/storybook-playwright/README.md
 */

.components-button {
	display: inline-flex;
	text-decoration: none;
	font-family: inherit;
	font-size: $default-font-size;
	font-weight: $font-weight-medium;
	margin: 0;
	border: 0;
	cursor: var(--wpds-cursor-control);
	appearance: none;
	background: none;

	@media not ( prefers-reduced-motion ) {
		transition: box-shadow 0.1s linear;
	}

	height: $button-size;
	align-items: center;
	box-sizing: border-box;
	padding: 4px 12px; // Allows 32px min-height.
	border-radius: $radius-small;
	color: $components-color-foreground;

	&.is-next-40px-default-size {
		height: $button-size-next-default-40px;
	}

	&[aria-expanded="true"],
	&:hover:not(:disabled, [aria-disabled="true"]) {
		color: $components-color-accent;
	}

	// Focus.
	// See https://github.com/WordPress/gutenberg/issues/13267 for more context on these selectors.
	&:focus:not(:active) {
		box-shadow: 0 0 0 var(--wp-admin-border-width-focus) $components-color-accent;
	}

	/**
	 * Primary button style.
	 */

	&.is-primary {
		white-space: nowrap;
		background: $components-color-accent;
		color: $components-color-accent-inverted;
		text-decoration: none;
		text-shadow: none;

		// Show the boundary of the button, in High Contrast Mode.
		outline: 1px solid transparent;

		&:hover:not(:disabled) {
			background: $components-color-accent-darker-10;
			color: $components-color-accent-inverted;
		}

		&:active:not(:disabled) {
			background: $components-color-accent-darker-20;
			border-color: $components-color-accent-darker-20;
			color: $components-color-accent-inverted;
		}

		&:focus:not(:active) {
			box-shadow: inset 0 0 0 1px $components-color-background, 0 0 0 var(--wp-admin-border-width-focus) $components-color-accent;
		}

		&:disabled,
		&:disabled:active:enabled,
		&[aria-disabled="true"],
		&[aria-disabled="true"]:enabled, // This catches a situation where a Button is aria-disabled, but not disabled.
		&[aria-disabled="true"]:active:enabled {
			// TODO: Prepare for theming (https://github.com/WordPress/gutenberg/pull/45466/files#r1030872724)
			color: rgba($white, 0.4);
			background: $components-color-accent;
			border-color: $components-color-accent;
			outline: none;

			&:focus:enabled {
				box-shadow: inset 0 0 0 1px $components-color-background, 0 0 0 var(--wp-admin-border-width-focus) $components-color-accent;
			}
		}

		&.is-busy,
		&.is-busy:disabled,
		&.is-busy[aria-disabled="true"] {
			color: $components-color-accent-inverted;
			background-size: 100px 100%;
			/* stylelint-disable -- Disable reason: This function call looks nicer when each argument is on its own line. */
			background-image: linear-gradient(
				-45deg,
				$components-color-accent 33%,
				$components-color-accent-darker-20 33%,
				$components-color-accent-darker-20 70%,
				$components-color-accent 70%
			);
			/* stylelint-enable */
			border-color: $components-color-accent;
		}
	}

	/**
	 * Secondary and tertiary buttons.
	 */

	&.is-secondary,
	&.is-tertiary {
		// Show the boundary of the button, in High Contrast Mode.
		outline: 1px solid transparent;

		&:active:not(:disabled) {
			box-shadow: none;
		}

		&:disabled,
		&[aria-disabled="true"],
		&[aria-disabled="true"]:hover {
			color: $gray-600;
			background: transparent;
			transform: none;
		}
	}

	/**
	 * Secondary button style.
	 */

	&.is-secondary {
		box-shadow: inset 0 0 0 $border-width $components-color-accent, 0 0 0 currentColor;
		outline: 1px solid transparent; // Shown in high contrast mode.
		white-space: nowrap;
		color: $components-color-accent;
		background: transparent;

		&:hover:not(:disabled, [aria-disabled="true"], .is-pressed) {
			box-shadow: inset 0 0 0 $border-width $components-color-accent-darker-20;
			color: $components-color-accent-darker-20;
			background: color-mix(in srgb, $components-color-accent 4%, transparent);
		}

		&:disabled:not(:focus),
		&[aria-disabled="true"]:not(:focus),
		&[aria-disabled="true"]:hover:not(:focus) {
			box-shadow: inset 0 0 0 $border-width $gray-300;
		}

		&:focus:not(:active) {
			box-shadow: 0 0 0 currentColor inset, 0 0 0 var(--wp-admin-border-width-focus) $components-color-accent;
		}
	}

	/**
	 * Tertiary buttons.
	 */

	&.is-tertiary {
		white-space: nowrap;
		color: $components-color-accent;
		background: transparent;

		&:hover:not(:disabled, [aria-disabled="true"], .is-pressed) {
			background: color-mix(in srgb, $components-color-accent 4%, transparent);
			color: $components-color-accent-darker-20;
		}

		&:active:not(:disabled, [aria-disabled="true"]) {
			background: color-mix(in srgb, $components-color-accent 8%, transparent);
		}

		// Pull left if the tertiary button stands alone after a description, so as to vertically align with items above.
		p + & {
			margin-left: -($grid-unit-15 * 0.5);
		}

		&:disabled,
		&[aria-disabled="true"],
		&[aria-disabled="true"]:hover {
			&:not(:focus) {
				box-shadow: none;
				outline: none;
			}
		}
	}

	/**
	 * Destructive buttons.
	 */
	&.is-destructive {
		--wp-components-color-accent: #{$alert-red};
		--wp-components-color-accent-darker-10: #{color.adjust($alert-red, $lightness: -10%)};
		--wp-components-color-accent-darker-20: #{color.adjust($alert-red, $lightness: -20%)};

		// Only the default variant is styled differently from the non-destructive counterparts.
		&:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link) {
			color: $alert-red;

			&:hover:not(:disabled, [aria-disabled="true"]) {
				color: color.adjust($alert-red, $lightness: -20%);
			}

			&:focus:not(:active) {
				box-shadow: 0 0 0 var(--wp-admin-border-width-focus) $alert-red;
			}

			&:active:not(:disabled, [aria-disabled="true"]) {
				background: $gray-400;
			}

			&:disabled,
			&[aria-disabled="true"] {
				color: $gray-600;
			}
		}

		&.is-tertiary,
		&.is-secondary {
			&:hover:not(:disabled, [aria-disabled="true"]) {
				background: rgba($alert-red, 0.04);
			}

			&:active:not(:disabled, [aria-disabled="true"]) {
				background: rgba($alert-red, 0.08);
			}
		}
	}

	/**
	 * Link buttons.
	 */

	&.is-link {
		margin: 0;
		padding: 0;
		box-shadow: none;
		border: 0;
		border-radius: 0;
		background: none;
		outline: none;
		text-align: left;
		font-weight: $font-weight-regular;
		color: $components-color-accent;
		text-decoration: underline;

		@media not (prefers-reduced-motion) {
			transition-property: border, background, color;
			transition-duration: 0.05s;
			transition-timing-function: ease-in-out;
		}

		height: auto;

		&:focus {
			border-radius: $radius-small;
		}

		&:disabled,
		&[aria-disabled="true"] {
			color: $gray-600;
		}
	}

	// Windows High Contrast mode will show this outline, but not the box-shadow.
	// This rule is placed after variant outline declarations (e.g. is-primary,
	// is-secondary, is-tertiary) to ensure it wins by source order at the same
	// specificity, while not using `:not(:active)` to avoid outline flicker.
	&:focus {
		outline: 3px solid transparent;
	}

	&:not(:disabled, [aria-disabled="true"]):active {
		color: $components-color-foreground;
	}

	&:disabled,
	&[aria-disabled="true"] {
		cursor: default;
		color: $gray-600;
	}

	&.is-busy,
	&.is-secondary.is-busy,
	&.is-secondary.is-busy:disabled,
	&.is-secondary.is-busy[aria-disabled="true"] {
		@media not (prefers-reduced-motion) {
			animation: components-button__busy-animation 2500ms infinite linear;
		}
		background-size: 100px 100%;
		/* stylelint-disable -- Disable reason: This function call looks nicer when each argument is on its own line. */
		background-image: linear-gradient(
			-45deg,
			// TODO: Prepare for theming (https://github.com/WordPress/gutenberg/pull/45466/files#r1030872724)
			color.adjust($white, $lightness: -2%) 33%,
			color.adjust($white, $lightness: -12%) 33%,
			color.adjust($white, $lightness: -12%) 70%,
			color.adjust($white, $lightness: -2%) 70%
		);
		/* stylelint-enable */
	}

	&.is-compact {
		height: $button-size-compact;

		&.has-icon:not(.has-text) {
			padding: 0;
			min-width: $button-size-compact;
		}
	}

	&.is-small {
		height: $button-size-small;
		line-height: 22px;
		padding: 0 8px;
		font-size: 11px;

		&.has-icon:not(.has-text) {
			padding: 0;
			min-width: $button-size-small;
		}
	}

	&.has-icon {
		padding: 6px; // Works for 24px icons. Smaller icons are vertically centered by flex alignments.

		// Icon buttons are square.
		min-width: $button-size;
		justify-content: center;

		&.is-next-40px-default-size {
			min-width: $button-size-next-default-40px;
		}

		.dashicon {
			display: inline-flex;
			justify-content: center;
			align-items: center;
			padding: 2px;
			box-sizing: content-box;
		}

		&.has-text {
			justify-content: start;
			padding-right: $grid-unit-15;
			padding-left: $grid-unit-10;
			gap: $grid-unit-05;
			&.has-icon-right {
				padding-right: $grid-unit-10;
				padding-left: $grid-unit-15;
			}
		}
	}

	// Toggled style.
	&.is-pressed {
		&,
		&:hover {
			color: $components-color-foreground-inverted;
			&:not(:disabled, [aria-disabled="true"]) {
				background: $components-color-foreground;
			}
		}

		&:disabled,
		&[aria-disabled="true"] {
			color: $gray-600;

			&:not(.is-primary):not(.is-secondary):not(.is-tertiary) {
				color: $components-color-foreground-inverted;
				background: $gray-600;
			}
		}

		&:focus:not(:active) {
			box-shadow: inset 0 0 0 1px $components-color-background, 0 0 0 var(--wp-admin-border-width-focus) $components-color-accent;
		}

		// Windows High Contrast mode will show this outline, but not the box-shadow.
		&:focus {
			outline: 2px solid transparent;
		}
	}

	// Hide focus outline on :active to provide click feedback in forced-colors
	// mode, where box-shadow is not visible. Higher specificity (0,3,0)
	// ensures this wins over variant outline declarations. Placed after
	// .is-pressed to also win by source order at equal specificity (0,3,0).
	&:focus:active {
		outline: none;
	}

	svg {
		fill: currentColor;
		outline: none;
		flex-shrink: 0;

		// Optimize for high contrast modes.
		// See also https://blogs.windows.com/msedgedev/2020/09/17/styling-for-windows-high-contrast-with-new-standards-for-forced-colors/.
		@media (forced-colors: active) {
			fill: CanvasText;
		}
	}
}

@keyframes components-button__busy-animation {
	0% {
		background-position: 200px 0;
	}
}
