/**
 * @license
 * Copyright 2022 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { __esDecorate, __runInitializers } from "tslib";
import { html, LitElement } from 'lit';
import { property, query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { Easing } from '../../motion/animation.js';
const PRESS_GROW_MS = 450;
const MINIMUM_PRESS_MS = 80;
const INITIAL_ORIGIN_SCALE = 0.2;
const PADDING = 10;
const SOFT_EDGE_MINIMUM_SIZE = 75;
const SOFT_EDGE_CONTAINER_RATIO = 0.35;
const PRESS_PSEUDO = '::after';
const ANIMATION_FILL = 'forwards';
let UiRipple = (() => {
    let _classSuper = LitElement;
    let _mdRoot_decorators;
    let _mdRoot_initializers = [];
    let _mdRoot_extraInitializers = [];
    let _unbounded_decorators;
    let _unbounded_initializers = [];
    let _unbounded_extraInitializers = [];
    let _disabled_decorators;
    let _disabled_initializers = [];
    let _disabled_extraInitializers = [];
    let _hovered_decorators;
    let _hovered_initializers = [];
    let _hovered_extraInitializers = [];
    let _focused_decorators;
    let _focused_initializers = [];
    let _focused_extraInitializers = [];
    let _pressed_decorators;
    let _pressed_initializers = [];
    let _pressed_extraInitializers = [];
    return class UiRipple extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _mdRoot_decorators = [query('.surface')];
            _unbounded_decorators = [property({ type: Boolean })];
            _disabled_decorators = [property({ type: Boolean, reflect: true })];
            _hovered_decorators = [state()];
            _focused_decorators = [state()];
            _pressed_decorators = [state()];
            __esDecorate(this, null, _mdRoot_decorators, { kind: "accessor", name: "mdRoot", static: false, private: false, access: { has: obj => "mdRoot" in obj, get: obj => obj.mdRoot, set: (obj, value) => { obj.mdRoot = value; } }, metadata: _metadata }, _mdRoot_initializers, _mdRoot_extraInitializers);
            __esDecorate(this, null, _unbounded_decorators, { kind: "accessor", name: "unbounded", static: false, private: false, access: { has: obj => "unbounded" in obj, get: obj => obj.unbounded, set: (obj, value) => { obj.unbounded = value; } }, metadata: _metadata }, _unbounded_initializers, _unbounded_extraInitializers);
            __esDecorate(this, null, _disabled_decorators, { kind: "accessor", name: "disabled", static: false, private: false, access: { has: obj => "disabled" in obj, get: obj => obj.disabled, set: (obj, value) => { obj.disabled = value; } }, metadata: _metadata }, _disabled_initializers, _disabled_extraInitializers);
            __esDecorate(this, null, _hovered_decorators, { kind: "accessor", name: "hovered", static: false, private: false, access: { has: obj => "hovered" in obj, get: obj => obj.hovered, set: (obj, value) => { obj.hovered = value; } }, metadata: _metadata }, _hovered_initializers, _hovered_extraInitializers);
            __esDecorate(this, null, _focused_decorators, { kind: "accessor", name: "focused", static: false, private: false, access: { has: obj => "focused" in obj, get: obj => obj.focused, set: (obj, value) => { obj.focused = value; } }, metadata: _metadata }, _focused_initializers, _focused_extraInitializers);
            __esDecorate(this, null, _pressed_decorators, { kind: "accessor", name: "pressed", static: false, private: false, access: { has: obj => "pressed" in obj, get: obj => obj.pressed, set: (obj, value) => { obj.pressed = value; } }, metadata: _metadata }, _pressed_initializers, _pressed_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        #mdRoot_accessor_storage = __runInitializers(this, _mdRoot_initializers, void 0);
        get mdRoot() { return this.#mdRoot_accessor_storage; }
        set mdRoot(value) { this.#mdRoot_accessor_storage = value; }
        #unbounded_accessor_storage = (__runInitializers(this, _mdRoot_extraInitializers), __runInitializers(this, _unbounded_initializers, false
        /**
         * @attribute
         */
        ));
        /**
         * @attribute
         */
        get unbounded() { return this.#unbounded_accessor_storage; }
        set unbounded(value) { this.#unbounded_accessor_storage = value; }
        #disabled_accessor_storage = (__runInitializers(this, _unbounded_extraInitializers), __runInitializers(this, _disabled_initializers, false));
        /**
         * @attribute
         */
        get disabled() { return this.#disabled_accessor_storage; }
        set disabled(value) { this.#disabled_accessor_storage = value; }
        #hovered_accessor_storage = (__runInitializers(this, _disabled_extraInitializers), __runInitializers(this, _hovered_initializers, false));
        get hovered() { return this.#hovered_accessor_storage; }
        set hovered(value) { this.#hovered_accessor_storage = value; }
        #focused_accessor_storage = (__runInitializers(this, _hovered_extraInitializers), __runInitializers(this, _focused_initializers, false));
        get focused() { return this.#focused_accessor_storage; }
        set focused(value) { this.#focused_accessor_storage = value; }
        #pressed_accessor_storage = (__runInitializers(this, _focused_extraInitializers), __runInitializers(this, _pressed_initializers, false));
        get pressed() { return this.#pressed_accessor_storage; }
        set pressed(value) { this.#pressed_accessor_storage = value; }
        get isPressed() {
            return this.pressed;
        }
        rippleSize = (__runInitializers(this, _pressed_extraInitializers), '');
        rippleScale = '';
        initialSize = 0;
        rippleStartEvent;
        // protected pressAnimationSignal = createAnimationSignal()
        growAnimation = null;
        delayedEndPressHandle = null;
        render() {
            return html `<div class="surface ${classMap(this.getRenderRippleClasses())}"></div>`;
        }
        /** @soyTemplate */
        getRenderRippleClasses() {
            return {
                hovered: this.hovered,
                focused: this.focused,
                pressed: this.pressed,
                unbounded: this.unbounded,
            };
        }
        willUpdate(changed) {
            super.willUpdate(changed);
            if (changed.has('hovered') || changed.has('focused') || changed.has('pressed')) {
                this.manageActivated();
            }
        }
        update(changedProps) {
            if (changedProps.has('disabled') && this.disabled) {
                this.endHover();
                this.endFocus();
                this.endPress();
            }
            super.update(changedProps);
        }
        getDimensions() {
            return (this.parentElement ?? this).getBoundingClientRect();
        }
        determineRippleSize() {
            const { height, width } = this.getDimensions();
            const maxDim = Math.max(height, width);
            const softEdgeSize = Math.max(SOFT_EDGE_CONTAINER_RATIO * maxDim, SOFT_EDGE_MINIMUM_SIZE);
            let maxRadius = maxDim;
            let initialSize = Math.floor(maxDim * INITIAL_ORIGIN_SCALE);
            const hypotenuse = Math.sqrt(width ** 2 + height ** 2);
            maxRadius = hypotenuse + PADDING;
            // ensure `initialSize` is even for unbounded
            if (this.unbounded) {
                initialSize -= initialSize % 2;
            }
            this.initialSize = initialSize;
            this.rippleScale = `${(maxRadius + softEdgeSize) / initialSize}`;
            this.rippleSize = `${this.initialSize}px`;
        }
        getNormalizedPointerEventCoords(pointerEvent) {
            const { scrollX, scrollY } = window;
            const { left, top } = this.getDimensions();
            const documentX = scrollX + left;
            const documentY = scrollY + top;
            const { pageX, pageY } = pointerEvent;
            return { x: pageX - documentX, y: pageY - documentY };
        }
        getTranslationCoordinates(positionEvent) {
            const { height, width } = this.getDimensions();
            // end in the center
            const endPoint = {
                x: (width - this.initialSize) / 2,
                y: (height - this.initialSize) / 2,
            };
            let startPoint;
            if (positionEvent instanceof PointerEvent) {
                startPoint = this.getNormalizedPointerEventCoords(positionEvent);
            }
            else {
                startPoint = {
                    x: width / 2,
                    y: height / 2,
                };
            }
            // center around start point
            startPoint = {
                x: startPoint.x - this.initialSize / 2,
                y: startPoint.y - this.initialSize / 2,
            };
            return { startPoint, endPoint };
        }
        startPressAnimation(positionEvent) {
            const { mdRoot } = this;
            if (!mdRoot) {
                return;
            }
            this.pressed = true;
            this.growAnimation?.cancel();
            this.determineRippleSize();
            const { startPoint, endPoint } = this.getTranslationCoordinates(positionEvent);
            const translateStart = `${startPoint.x}px, ${startPoint.y}px`;
            const translateEnd = `${endPoint.x}px, ${endPoint.y}px`;
            const growAnimation = mdRoot.animate({
                top: [0, 0],
                left: [0, 0],
                height: [this.rippleSize, this.rippleSize],
                width: [this.rippleSize, this.rippleSize],
                transform: [`translate(${translateStart}) scale(1)`, `translate(${translateEnd}) scale(${this.rippleScale})`],
            }, {
                pseudoElement: PRESS_PSEUDO,
                duration: PRESS_GROW_MS,
                easing: Easing.STANDARD,
                fill: ANIMATION_FILL,
            });
            this.growAnimation = growAnimation;
        }
        async endPressAnimation() {
            this.rippleStartEvent = undefined;
            const animation = this.growAnimation;
            let pressAnimationPlayState = Infinity;
            if (typeof animation?.currentTime === 'number') {
                pressAnimationPlayState = animation.currentTime;
            }
            else if (animation?.currentTime) {
                pressAnimationPlayState = animation.currentTime.to('ms').value;
            }
            if (pressAnimationPlayState >= MINIMUM_PRESS_MS) {
                this.pressed = false;
                return;
            }
            await new Promise((resolve) => {
                setTimeout(resolve, MINIMUM_PRESS_MS - pressAnimationPlayState);
            });
            if (this.growAnimation !== animation) {
                // A new press animation was started. The old animation was canceled and
                // should not finish the pressed state.
                return;
            }
            this.pressed = false;
        }
        beginHover(hoverEvent) {
            if (hoverEvent?.pointerType !== 'touch') {
                this.hovered = true;
                this.manageActivated();
            }
        }
        endHover() {
            this.hovered = false;
            this.manageActivated();
        }
        beginFocus() {
            this.focused = true;
            this.manageActivated();
        }
        endFocus() {
            this.focused = false;
            this.manageActivated();
        }
        beginPress(positionEvent) {
            this.pressed = true;
            this.rippleStartEvent = positionEvent;
            if (this.delayedEndPressHandle !== null) {
                clearTimeout(this.delayedEndPressHandle);
                this.delayedEndPressHandle = null;
            }
            this.startPressAnimation(positionEvent);
            this.manageActivated();
        }
        endPress() {
            const pressAnimationPlayState = (this.growAnimation?.currentTime ?? Infinity);
            if (pressAnimationPlayState >= MINIMUM_PRESS_MS) {
                this.pressed = false;
            }
            else {
                this.delayedEndPressHandle = setTimeout(() => {
                    this.pressed = false;
                    this.delayedEndPressHandle = null;
                }, MINIMUM_PRESS_MS - pressAnimationPlayState);
            }
            this.endPressAnimation();
            this.manageActivated();
        }
        manageActivated() {
            if (this.pressed || this.hovered || this.focused) {
                this.classList.add('activated');
            }
            else {
                this.classList.remove('activated');
            }
        }
    };
})();
export default UiRipple;
//# sourceMappingURL=ripple.js.map