import { RevealStateManager } from './RevealStateManager.js';
import { config } from './config.js';
class ServerSideHTMLElement {
    constructor() {
        this.root = {
            innerHTML: '',
            querySelector: (_x) => null,
        };
        this.attachShadow = () => null;
    }
}
const PatchedHTMLElement = typeof globalThis.Window === 'undefined'
    ? ServerSideHTMLElement
    : HTMLElement;
export class AxRevealProvider extends PatchedHTMLElement {
    constructor() {
        super(...arguments);
        this.stateManager = new RevealStateManager();
    }
}
AxRevealProvider.ElementName = 'ax-reveal-provider';
export class AxRevealBoundary extends PatchedHTMLElement {
    constructor() {
        super();
        this.root = this.attachShadow({ mode: 'open' });
        /**
         * Update the position of your pointer.
         * @param ev Pointer event from the listener.
         */
        this.updatePointerPosition = (ev) => {
            this.waitForStorage(storage => {
                storage.clientX = ev.clientX;
                storage.clientY = ev.clientY;
            });
        };
        this.handlePointerEnter = () => this.waitForStorage(storage => storage.onPointerEnterBoundary());
        this.handlePointerLeave = () => this.waitForStorage(storage => storage.onPointerLeaveBoundary());
        this.handlePointerMove = (ev) => this.updatePointerPosition(ev);
        this.handlePointerUp = (ev) => {
            if (ev.pointerType === 'mouse') {
                this.waitForStorage(storage => storage.switchAnimation());
            }
            else {
                this.waitForStorage(storage => storage.clearAll());
            }
        };
        this.handlePointerDown = (ev) => this.waitForStorage(storage => {
            this.setPointerCapture(ev.pointerId);
            this.updatePointerPosition(ev);
            storage.initializeAnimation();
        });
        this.root.innerHTML = `
<div>
    <slot></slot>
</div>`;
    }
    get storage() {
        return this._storage;
    }
    set storage(newStorage) {
        const oldStorage = this._storage;
        if (oldStorage) {
            this.dispatchEvent(new CustomEvent(AxRevealBoundary.removeStorageEvent, { detail: oldStorage }));
            AxRevealBoundary.stateManager.removeBoundary(oldStorage);
        }
        if (newStorage) {
            this._storage = newStorage;
            this.dispatchEvent(new CustomEvent(AxRevealBoundary.attachStorageEvent, { detail: newStorage }));
        }
        if (oldStorage && newStorage) {
            this.dispatchEvent(new CustomEvent(AxRevealBoundary.replaceStorageEvent, {
                detail: { old: oldStorage, new: newStorage },
            }));
        }
    }
    waitForStorage(f) {
        if (this.storage === undefined) {
            this.addEventListener(AxRevealBoundary.attachStorageEvent, () => f(this.storage), { once: true });
        }
        else {
            f(this.storage);
        }
    }
    appendStorage(force = false) {
        if (!force && this.storage) {
            return;
        }
        const parent = this.closest(AxRevealProvider.ElementName);
        const stateManager = parent ? parent.stateManager : AxRevealBoundary.stateManager;
        this.storage = stateManager.newBoundary(this);
    }
    connectedCallback() {
        this.appendStorage(true);
        if (config.borderDetectionMode === 'strictEdge') {
            this.addEventListener('pointerenter', this.handlePointerEnter);
            this.addEventListener('pointerleave', this.handlePointerLeave);
            this.addEventListener('pointermove', this.handlePointerMove);
        }
        this.addEventListener('pointerdown', this.handlePointerDown);
        this.addEventListener('pointerup', this.handlePointerUp);
    }
    disconnectedCallback() {
        this.storage = undefined;
    }
}
AxRevealBoundary.ElementName = 'ax-reveal-bound';
AxRevealBoundary.removeStorageEvent = 'removeStorage';
AxRevealBoundary.attachStorageEvent = 'attachStorage';
AxRevealBoundary.replaceStorageEvent = 'replaceStorage';
AxRevealBoundary.stateManager = new RevealStateManager();
export class AxReveal extends PatchedHTMLElement {
    constructor() {
        super();
        this.root = this.attachShadow({ mode: 'open' });
        this.root.innerHTML = `
<div class="ax-reveal">
    <canvas></canvas>
    <div class="content"><slot></slot></div>
    </div>
<style>
    .ax-reveal { display: content; }
    .ax-design * { user-drag: none; touch-action: none; }
    .content { position: relative; }
    canvas { top: 0; left: 0; pointer-events: none; width: 100%; height: 100%; position: absolute; }
    :host { display: inline-block; position: relative; }
    :host([block]) { display: block; }
    :host([inline-block]) { display: inline-block; }
    :host([flex]) { display: flex; }
    :host([inline-flex]) { display: inline-flex; }
    :host([grid]) { display: grid; }
    :host([inline-grid]) { display: inline-grid; }
    ::slotted(*) { user-drag: none; touch-action: none; }
    ::slotted(button) { outline:none; }
</style>`;
        this.canvas = this.root.querySelector('canvas');
    }
    adoptedCallback() {
        this.disconnectedCallback();
        this.connectedCallback();
    }
    disconnectedCallback() {
        this.boundary && this.boundary.waitForStorage(storage => storage.removeReveal(this.canvas));
    }
    connectedCallback() {
        this.boundary = this.closest(AxRevealBoundary.ElementName);
        if (!this.boundary)
            throw new SyntaxError('You must use ' + AxRevealBoundary.ElementName + ' as the boundary of acrylic!');
        this.boundary.waitForStorage(storage => setTimeout(() => storage.addReveal(this.canvas, this), 0));
    }
}
AxReveal.ElementName = 'ax-reveal';
//# sourceMappingURL=CustomElements.js.map