// Copyright 2016 Palantir Technologies, Inc. All rights reserved.
// Licensed under the BSD-3 License as modified (the “License”); you may obtain a copy
// of the license at https://github.com/palantir/blueprint/blob/master/LICENSE
// and https://github.com/palantir/blueprint/blob/master/PATENTS

@import "~bourbon/app/assets/stylesheets/bourbon";
@import "../../common/variables";
@import "../../common/react-transition";

/*
Toasts

A toast is a lightweight, ephemeral notice from an application in direct response to a user's action.

`Toast`s have a built-in timeout of five seconds. Users can also dismiss them manually by clicking the &times; button.
Hovering the cursor over a toast prevents it from disappearing. When the cursor leaves the toast, the toast's timeout restarts.
Similarly, focusing the toast (for example, by hitting the <kbd class="pt-key">tab</kbd> key) halts the timeout, and
blurring restarts the timeout.

You can add one additional action button to a toast. You might use this to undo the user's action, for example.

You can also apply the same visual intent styles to `Toast`s that you can to [`Button`s](components.button.css).

Toasts can be configured to appear at either the top or the bottom of an application window, and it is possible to
have more than one toast onscreen at a time.

@react-example ToastExample

Styleguide components.toaster
*/

/*
JavaScript API

The `Toast` and `Toaster` components are available in the __@blueprintjs/core__ package.
Make sure to review the [general usage docs for JS components](#components.usage).

The `Toaster` component provides the static `create` method that returns a new `Toaster` instance, rendered into an
element attached to `<body>`. (You can also specify the element to render into if desired.) A `Toaster` instance
has a collection of methods to show and hide toasts in its given container.

Your application can contain several `Toaster` instances and easily share them across the codebase as modules.

```
// toaster.ts
import { Position, Toaster } from "@blueprintjs/core";

export const OurToaster = Toaster.create({
    className: "my-toaster",
    position: Position.BOTTOM_RIGHT,
});
```

```
// application.ts
import { OurToaster } from "./toaster";

const key = OurToaster.show({ message: "Toasted!" });
OurToaster.update(key, { message: "Still toasted!" });
```

<div class="pt-callout pt-intent-primary pt-icon-info-sign">
  <h5>Working with multiple toasters</h5>
  You can have multiple toasters in a single application, but you must ensure that each has a unique
  `position` to prevent overlap.
</div>

<div class="pt-callout pt-intent-primary pt-icon-info-sign">
  <h5>Toaster focus</h5>
  `Toaster` always disables `Overlay`'s `enforceFocus` behavior (meaning that you're not blocked
  from accessing other parts of the application while a toast is active), and by default also
  disables `autoFocus` (meaning that focus will not switch to a toast when it appears). You can
  enable `autoFocus` for a `Toaster` via a prop, if desired.
</div>

Styleguide components.toaster.js
*/

/*
Static method

```ts
Toaster.create(props?: IToasterProps, container = document.body): IToaster
```

Create a new `Toaster` instance. The `Toaster` will be rendered into a new element appended to the
given `container`. The `container` determines which element toasts are positioned relative to; the
default value of `<body>` allows them to use the entire viewport.

Note that the return type is `IToaster`, which is a minimal interface that exposes only the instance
methods detailed below. It can be thought of as `Toaster` minus the `React.Component` methods,
because the `Toaster` should not be treated as a normal React component.

@interface IToasterProps

Styleguide components.toaster.js.create
*/

/*
Instance methods

<div class="docs-interface-name">IToaster</div>

- `show(props: IToastProps): string` &ndash; Show a new toast to the user.
  Returns the unique key of the new toast.
- `update(key: string, props: IToastProps): void` &ndash;
  Updates the toast with the given key to use the new props.
  Updating a key that does not exist is effectively a no-op.
- `dismiss(key: string): void` &ndash; Dismiss the given toast instantly.
- `clear(): void` &ndash; Dismiss all toasts instantly.
- `getToasts(): IToastProps[]` &ndash; Returns the options for all current toasts.

@interface IToastProps

Styleguide components.toaster.js.instance
*/

/*
React component

The `Toaster` React component is a stateful container for a single list of toasts. Internally, it
uses [`Overlay`](#components.overlay) to manage children and transitions. It can be vertically
aligned along the top or bottom edge of its container (new toasts will slide in from that edge) and
horizontally aligned along the left edge, center, or right edge of its container.

You should use [`Toaster.create`](#components.toaster.js.create), rather than using the `Toaster`
component API directly in React, to avoid having to use `ref` to access the instance.

```
import { Button, Position, Toaster } from "@blueprintjs/core";

class MyComponent extends React.Component<{}, {}> {
    private toaster: Toaster;
    private refHandlers = {
        toaster: (ref: Toaster) => this.toaster = ref,
    };

    public render() {
        return (
            <div>
                <Button onClick={this.addToast} text="Procure toast" />
                <Toaster position={Position.TOP_RIGHT} ref={this.refHandlers.toaster} />
            </div>
        )
    }

    private addToast = () => {
        this.toaster.show({ message: "Toasted!" });
    }
}
```

Styleguide components.toaster.js.react
*/

$toast-height: $pt-button-height-large !default;
$toast-min-width: $pt-grid-size * 30 !default;
$toast-max-width: $pt-grid-size * 50 !default;
$toast-margin: $pt-grid-size * 1.5 !default;

.pt-toast {
  // toast transition properties
  $enter-translate: (transform: translateY(-$toast-height) translateY(0));
  $leave-blur: (opacity: 0 1, filter: blur($pt-grid-size) blur(0));

  // new toasts slide in from the top
  @include react-transition-phase(
    "pt-toast",
    "enter",
    $enter-translate,
    $duration: $pt-transition-duration * 3,
    $easing: $pt-transition-ease-bounce,
    $before: "&"
  );
  @include react-transition-phase(
    "pt-toast",
    "enter",
    $enter-translate,
    $duration: $pt-transition-duration * 3,
    $easing: $pt-transition-ease-bounce,
    $before: "&",
    $after: "~ &"
  );
  // leaving toasts simply fade away
  @include react-transition-phase(
    "pt-toast",
    "leave",
    $leave-blur,
    $duration: $pt-transition-duration * 3,
    $before: "&"
  );
  // younger siblings of leaving toasts wait a moment before moving to fill gap
  @include react-transition-phase(
    "pt-toast",
    "leave",
    $enter-translate,
    $delay: $pt-transition-duration / 2,
    $before: "&",
    $after: "~ &"
  );

  display: flex;
  align-items: flex-start;

  // toasts rely on relative positioning for stacking; override inline overlay styles (#367)
  // stylelint-disable-next-line declaration-no-important
  position: relative !important;
  margin: $toast-margin 0 0;
  border-radius: $pt-border-radius;
  box-shadow: $pt-elevation-shadow-3;
  background-color: $white;
  min-width: $toast-min-width;
  max-width: $toast-max-width;

  // toast is interactive even though container isn't
  pointer-events: all;

  .pt-button-group {
    flex: 0 0 auto;
    padding: ($toast-height - $pt-button-height) / 2;
    padding-left: 0;
  }

  > .pt-icon-standard {
    padding: ($toast-height - $pt-icon-size-standard) / 2;
    padding-right: 0;
  }

  &.pt-dark,
  .pt-dark & {
    box-shadow: $pt-dark-elevation-shadow-3;
    background-color: $dark-gray5;
  }

  &[class*="pt-intent-"] {
    a {
      color: rgba($white, 0.7);

      &:hover {
        color: $white;
      }
    }

    > .pt-icon-standard {
      color: $white;
    }
  }

  // HACKHACK custom colors for buttons on intent background so they always show up nice
  // stylelint-disable declaration-no-important
  &[class*="pt-intent-"] .pt-button {
    &,
    &::before,
    &:active {
      color: rgba($white, 0.7) !important;
    }

    &:focus {
      // blue outline color shows poorly on colored bg
      outline-color: rgba($white, 0.5);
    }

    &:hover {
      background-color: rgba($white, 0.15) !important;
      color: $white !important;
    }

    &:active {
      background-color: rgba($white, 0.3) !important;
      color: $white !important;
    }

    &::after {
      background: rgba($white, 0.3) !important;
    }
  }
  // stylelint-enable declaration-no-important

  // define these last so they override default dark colors above
  @each $intent, $color in $pt-intent-colors {
    &.pt-intent-#{$intent} {
      background-color: $color;
      color: $white;
    }
  }
}

.pt-toast-message {
  flex: 1 1 auto;
  padding: centered-text($toast-height);
}

.pt-toast-container {
  @include position(fixed, null 0 null);
  // #975 ensure toasts are on top of everything (esp dialogs)
  z-index: $pt-z-index-overlay * 2;
  // toasts have margin-top so omit it on container
  padding: 0 $toast-margin $toast-margin;

  // container will not block clicks on elements behind it
  pointer-events: none;

  // CSSTransitionGroup
  > span {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  &.pt-toast-container-top {
    top: 0;
  }

  &.pt-toast-container-bottom {
    bottom: 0;

    > span {
      flex-direction: column-reverse;
    }
  }

  &.pt-toast-container-left > span {
    align-items: flex-start;
  }

  &.pt-toast-container-right > span {
    align-items: flex-end;
  }
}

.pt-toast-container-bottom .pt-toast {
  // minimal diff in react-transition styles so we can avoid calling those mixins again
  &.pt-toast-enter:not(.pt-toast-enter-active),
  &.pt-toast-enter:not(.pt-toast-enter-active) ~ .pt-toast,
  &.pt-toast-leave-active ~ .pt-toast {
    transform: translateY($toast-margin + $toast-height);
  }
}
