@use 'sass:math';
@use '../../compiled/tokens/scss/brightness';
@use '../../compiled/tokens/scss/color';
@use '../../compiled/tokens/scss/ease';
@use '../../compiled/tokens/scss/font-weight';
@use '../../compiled/tokens/scss/line-height';
@use '../../compiled/tokens/scss/scale';
@use '../../compiled/tokens/scss/size';
@use '../../compiled/tokens/scss/transition';
@use '../../mixins/focus';
@use '../../mixins/ms';
@use '../../mixins/theme';
@use '../../mixins/unit';

// Defines the hit area for actionable elements, specifically the height of
// links and the width/height of "previous" and "next" affordances.
$action-size: size.$height-control-default;

// Amount of padding within action elements. Used to minimize visual competition
// between actions and direction affordances.
$action-pad: ms.step(-6);

// Default dimensions for a small affordance used to indicate different states
// of individual pages. The dimensions change slightly for the current state
// indicator. We use edge tokens because the indicator feels similar in visual
// appearance to a border or outline.
$indicator-height: size.$edge-medium;
$indicator-width: ms.step(-1);
$indicator-height-current: size.$edge-large;
$indicator-width-current: $indicator-height-current;

/**
 * Themed properties
 */

@include theme.props {
  --theme-color-background-pagination-control: transparent;
  --theme-color-border-pagination-control: #{color.$base-gray-light};
}

@include theme.props(dark) {
  --theme-color-background-pagination-control: var(
    --theme-color-background-secondary
  );
  --theme-color-border-pagination-control: transparent;
}

/**
 * We have no styles to apply to the root `c-pagination` class, but we don't
 * want to encourage usage of this component _without_ a containing `<nav>`
 * element for accessibility, so we kick off our styles one element deep.
 * Perhaps in the future the extra containing element will come in handy for
 * modifiers and such?
 */

/**
 * List containing page links
 *
 * 1. Arrange children horizontally.
 * 2. Override default list styles. It's important that this element have
 *    `role="list"` set to avoid accessibility issues in Safari/VoiceOver.
 * 3. Setting this allows us to position "previous" and "next" affordances
 *    of individual items relative to this container.
 *
 * @see https://www.scottohara.me/blog/2019/01/12/lists-and-safari.html
 */

.c-pagination__items {
  display: flex; /* 1 */
  list-style: none; /* 2 */
  padding-inline-start: 0; /* 2 */
  position: relative; /* 3 */
}

/**
 * We initialize the list's pseudo elements so they will reserve space for the
 * "previous" and "next" affordances.
 */

.c-pagination__items::before,
.c-pagination__items::after {
  content: '';
}

/**
 * Make the pseudo elements _and_ list items occupy equal amounts of space.
 * This gives us nice, even spacing without having to know the exact number of
 * items beforehand.
 */

.c-pagination__items::before,
.c-pagination__items::after,
.c-pagination__item {
  flex: 100%;
}

/**
 * The element that navigates to a page. Currently only intended for links, but
 * in the future this could be extended to support `<button>` if we wanted.
 *
 * It's important to avoid setting `position` on this element or we'll disrupt
 * our ability to position "previous" and "next" affordances without requiring
 * redundant elements.
 */

.c-pagination__action {
  align-items: center;
  block-size: $action-size;
  display: flex;
  justify-content: center;
  text-decoration: none;
  user-select: none;
}

/**
 * The current state should inherit the parent element's text color to appear
 * just a bit muted.
 */

.c-pagination__action[aria-current] {
  color: inherit;
}

/**
 * When an action element has `is-previous` or `is-next` state classes applied,
 * we absolute-position pseudo elements that provide extra "previous" and "next"
 * affordances without requiring any additional markup.
 */

.c-pagination__action.is-previous::before,
.c-pagination__action.is-next::after {
  background-color: var(--theme-color-background-pagination-control);
  background-position: center;
  background-repeat: no-repeat;
  background-size: size.$square-control-icon;
  block-size: $action-size;
  border: size.$edge-small solid var(--theme-color-border-pagination-control);
  border-radius: size.$border-radius-full;
  content: '';
  inline-size: $action-size;
  inset-block: 0;
  margin: auto;
  position: absolute;
  transition: filter transition.$slow ease.$out,
    transform transition.$quick ease.$out;
}

/**
 * These affordances have similar hover and active states to buttons. We apply
 * these styles relative to the action state (rather than the pseudo element)
 * so hovering over a page number will _also_ trigger the animation on the
 * affordance, which helps enforce the action being considered.
 */

.c-pagination__action.is-previous:hover::before,
.c-pagination__action.is-next:hover::after {
  filter: brightness(brightness.$control-brighten);
  transform: scale(scale.$effect-grow);
}

.c-pagination__action.is-previous:active::before,
.c-pagination__action.is-next:active::after {
  filter: brightness(brightness.$control-dim);
  transform: scale(scale.$effect-shrink);
}

/**
 * Direction-specific icons and positioning
 */

.c-pagination__action.is-previous::before {
  inset-inline-start: 0;

  /**
   * Inline SVGs aren't aware of custom properties, so we have to do a bit
   * of theming trickery here
   */

  @include theme.styles {
    background-image: svg-load(
      'icons/arrow-left.svg',
      stroke=color.$brand-primary
    );
  }

  @include theme.styles(dark) {
    background-image: svg-load(
      'icons/arrow-left.svg',
      stroke=color.$text-light-emphasis
    );
  }
}

.c-pagination__action.is-next::after {
  inset-inline-end: 0;

  /**
   * Inline SVGs aren't aware of custom properties, so we have to do a bit
   * of theming trickery here
   */

  @include theme.styles {
    background-image: svg-load(
      'icons/arrow-right.svg',
      stroke=color.$brand-primary
    );
  }

  @include theme.styles(dark) {
    background-image: svg-load(
      'icons/arrow-right.svg',
      stroke=color.$text-light-emphasis
    );
  }
}

/**
 * The inner number element gives us a means of positioning indicator pseudo
 * elements relative to the action content without disrupting the "previous"
 * and "next" affordances.
 *
 * 1. Constrain the focus ring (not visible initially) to a circle slightly
 *    smaller than the "previous" and "next" affordances.
 * 2. Fixes an issue where Chrome renders the digits a pixel or two higher
 *    than in other browsers.
 * 3. The aforementioned means of positioning the indicator pseudo element.
 */

.c-pagination__number {
  align-items: center;
  block-size: ($action-size - $action-pad * 2); /* 1 */
  border-radius: size.$border-radius-full; /* 1 */
  display: flex;
  font-weight: font-weight.$medium;
  inline-size: 100%; /* 1 */
  justify-content: center;
  line-height: line-height.$tighter; /* 2 */
  max-inline-size: ($action-size - $action-pad * 2); /* 1 */
  position: relative; /* 3 */
}

/**
 * When keyboard navigation is detected on the containing action, apply a
 * focus ring similar to other components to the number element.
 */

// stylelint-disable-next-line no-duplicate-selectors
.c-pagination__action {
  @include focus.focus-visible {
    .c-pagination__number {
      box-shadow: 0 0 0 size.$edge-large color.$brand-primary-lighter;
    }
  }
}

/**
 * Hover and current indicators
 *
 * 1. Might seem odd compared to `bottom: 0`, but this places the affordance
 *    within the action padding, which feels nicely balanced.
 */

.c-pagination__number::after {
  background: currentColor;
  block-size: $indicator-height;
  border-radius: size.$border-radius-full;
  content: '';
  inline-size: $indicator-width;
  inset-block-start: 100%; /* 1 */
  inset-inline: 0;
  margin: auto;
  position: absolute;
  transition-duration: transition.$quick;
  transition-property: opacity, transform;
  transition-timing-function: ease.$out;

  /**
   * Unless the containing action is the current page or is being hovered,
   * set this element to its initial animation state.
   */

  .c-pagination__action:not(:hover):not([aria-current]) & {
    opacity: 0;
    transform: scaleX(
      math.div(unit.strip($indicator-height), unit.strip($indicator-width))
    );
  }

  /**
  * Apply unique dimensions to the current state so it feels more like a
  * pagination dot, as seen in many app interfaces.
  */

  .c-pagination__action[aria-current] & {
    block-size: $indicator-height-current;
    inline-size: $indicator-width-current;
  }
}
