UNPKG

wj-elements

Version:

WebJET Elements is a modern set of user interface tools harnessing the power of web components designed to simplify web application development.

478 lines (477 loc) 15.3 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import WJElement from "./wje-element.js"; const styles = ":host {\n display: block;\n z-index: 1000;\n /* make css property for width height position and if it is on top lef bottom right */\n}\n\n.sliding-container-wrapper {\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n\n.native-sliding-container {\n overflow: auto;\n}\n"; class SlidingContainer extends WJElement { /** * Creates an instance of SlidingContainer. * @class */ constructor() { super(); __publicField(this, "className", "SlidingContainer"); /** * Triggers the event based on the target element. * If the target element is different from the last caller, it refreshes the children by calling the `open` method. * If the target element is the same as the last caller, it toggles the state by calling the `toggle` method. * @param {Event} e The event object. */ __publicField(this, "triggerEvent", async (e) => { if (this._lastCaller && this._lastCaller !== e.composedPath()[0]) { await this.open(e); } else { await this.toggle(e); } this._lastCaller = e.composedPath()[0]; }); this._isOpen = false; this._lastCaller = null; this._resizeObserver = new ResizeObserver((entries) => { for (let entry of entries) { if (entry.contentBoxSize) { if (this.drawingStatus < 3) return; if (this.screenBreakPoint && window.innerWidth <= this.screenBreakPoint) { if (this.variant !== "over") { this.variant = "over"; } else { this.checkForVariant(this.variant); } } else { if (this.variant !== "in-place") { this.variant = "in-place"; } else { this.checkForVariant(this.variant); } } } } }); this._resizeObserver.observe(document.documentElement); } set maxWidth(value) { this.setAttribute("max-width", value); } get maxWidth() { return this.getAttribute("max-width") ?? "auto"; } set maxHeight(value) { this.setAttribute("max-height", value); } get maxHeight() { return this.getAttribute("max-height") ?? "auto"; } set trigger(value) { this.setAttribute("trigger", value); } get trigger() { return this.getAttribute("trigger") ?? "sliding-container"; } set direction(value) { this.setAttribute("direction", value); } get direction() { return this.getAttribute("direction") ?? "right"; } set removeChildAfterClose(value) { this.setAttribute("remove-child-after-close", value); } get removeChildAfterClose() { return this.hasAttribute("remove-child-after-close") ?? false; } set variant(value) { this.setAttribute("variant", value); } get variant() { return this.getAttribute("variant") ?? "in-place"; } get screenBreakPoint() { return this.getAttribute("screen-break-point"); } set screenBreakPoint(value) { this.setAttribute("screen-break-point", value); } get animationDuration() { return this.getAttribute("animation-duration") ?? "500"; } set animationDuration(value) { this.setAttribute("animation-duration", value); } get animationEasing() { return this.getAttribute("animation-easing") ?? "linear"; } set animationEasing(value) { this.setAttribute("animation-easing", value); } get hasOpacity() { return this.hasAttribute("has-opacity") ?? false; } get addToHeight() { return this.getAttribute("add-to-height") ?? "0"; } set addToHeight(value) { this.setAttribute("add-to-height", value); } get isOpen() { return this._isOpen; } /** * Returns the observed attributes for the component. * @returns {string[]} */ static get observedAttributes() { return [ "max-width", "max-height", "trigger", "direction", "variant", "screen-break-point", "remove-child-after-close", "animation-duration", "animation-easing", "has-opacity" ]; } /** * Returns the CSS styles for the component. * @static * @returns {CSSStyleSheet} */ static get cssStyleSheet() { return styles; } /** * Sets up the attributes for the component. */ setupAttributes() { this.isShadowRoot = "open"; } /** * Draws the component. * @param {object} context The context for drawing. * @param {object} store The store for drawing. * @param {object} params The parameters for drawing. * @returns {DocumentFragment} */ draw(context, store, params) { let fragment = document.createDocumentFragment(); this.style.position = "relative"; this.style.height = "100%"; this.style.right = "unset"; this.style.left = "unset"; this.wrapperDiv = document.createElement("div"); this.wrapperDiv.classList.add("sliding-container-wrapper"); this.transparentDiv = document.createElement("div"); this.transparentDiv.classList.add("sliding-container-transparent"); if (this._isOpen) { this.transparentDiv.style.width = this.maxWidth; } let native = document.createElement("div"); native.style.position = "absolute"; native.style.width = 0; if (this.hasOpacity) { native.style.opacity = 0; } if (this._isOpen) { native.style.width = this.maxWidth; if (this.hasOpacity) { native.style.opacity = 1; } } native.style.height = "100%"; native.classList.add("native-sliding-container"); native.setAttribute("part", "sliding-container"); if (this.direction === "right") { native.style.right = 0; } else { native.style.left = 0; } let slot = document.createElement("slot"); const nativeInner = document.createElement("div"); nativeInner.classList.add("native-sliding-container-inner"); nativeInner.style.height = "100%"; nativeInner.style.position = "absolute"; nativeInner.style.width = this.maxWidth; nativeInner.appendChild(slot); nativeInner.appendChild(this.getCloseButton()); native.appendChild(nativeInner); this.wrapperDiv.appendChild(this.transparentDiv); this.wrapperDiv.appendChild(native); fragment.appendChild(this.wrapperDiv); this.nativeElement = native; return fragment; } /** * Creates and returns a close button element. * @returns {HTMLElement} The close button element. */ getCloseButton() { let closeButton = document.createElement("wje-button"); closeButton.setAttribute("part", "close-button"); closeButton.style.position = "absolute"; closeButton.style.top = "0"; closeButton.style.right = "0"; closeButton.style.zIndex = "1000"; let icon = document.createElement("wje-icon"); icon.setAttribute("slot", "icon-only"); icon.setAttribute("name", "x"); closeButton.appendChild(icon); closeButton.addEventListener("click", () => { this.close(); }); return closeButton; } /** * Executes before drawing the element. */ beforeDraw() { var _a, _b; (_a = this.animation) == null ? void 0 : _a.cancel(); (_b = this.nativeAnimation) == null ? void 0 : _b.cancel(); document.removeEventListener(this.trigger, this.triggerEvent); } /** * Performs actions after the element is drawn on the screen. * Attaches an event listener to the document based on the specified trigger. * Sets the variant to "over" if the document width is smaller than the screen break point. * Calls the checkForVariant method with the current variant. */ afterDraw() { document.addEventListener(this.trigger, this.triggerEvent); if (this.screenBreakPoint && window.innerWidth <= this.screenBreakPoint) { this.variant = "over"; } this.checkForVariant(this.variant); } getParentElement() { let parentElement = this.parentElement; if (!parentElement) { parentElement = this.getRootNode().host; } return parentElement; } /** * Checks for a specific variant and applies corresponding styles. * @param {string} variant The variant to check for. */ checkForVariant(variant) { if (variant === "over") { this.style.position = "fixed"; let computentStyleOfParent = window.getComputedStyle(this.getParentElement()); let parentElementBoundingbox = this.getParentElement().getBoundingClientRect(); let heightOfParrentElement = parseFloat(computentStyleOfParent.height); let topOfParrentElement = parseFloat(computentStyleOfParent.top); this.style.height = heightOfParrentElement + +this.addToHeight + "px"; this.wrapperDiv.style.height = heightOfParrentElement + +this.addToHeight + "px"; this.style.top = topOfParrentElement + "px"; const leftSibling = this.previousElementSibling; const rightSibling = this.nextElementSibling; const leftSiblingBoundingbox = leftSibling == null ? void 0 : leftSibling.getBoundingClientRect(); const rightSiblingBoundingbox = rightSibling == null ? void 0 : rightSibling.getBoundingClientRect(); if (this.direction === "right") { if (leftSiblingBoundingbox) { this.style.left = leftSiblingBoundingbox.left + leftSiblingBoundingbox.width + "px"; } else { this.style.left = parentElementBoundingbox.left + "px"; } } else { if (rightSiblingBoundingbox) { this.style.right = window.innerWidth - rightSiblingBoundingbox.left + "px"; } else { this.style.right = window.innerWidth - (parentElementBoundingbox.left + parentElementBoundingbox.width) + "px"; } } } } /** * Executes before the element is opened. */ beforeOpen(event) { } /** * Callback function called after the element is opened. */ afterOpen(event) { } /** * Executes before closing the element. */ beforeClose(event) { } /** * Callback function that is called after the container is closed. */ afterClose(event) { } /** * Animates the transition of the element's width from 0 to the maximum width or vice versa. * @returns {Promise<void>} A promise that resolves when the animation is complete. */ doAnimateTransition() { var _a, _b, _c, _d; const options = { delay: 0, endDelay: 0, fill: "forwards", duration: +this.animationDuration, iterationStart: 0, iterations: 1, direction: "normal", easing: this.animationEasing }; if (this.animation && ((_b = (_a = this.animation) == null ? void 0 : _a.effect) == null ? void 0 : _b.target) !== this.transparentDiv) { this.animation.cancel(); this.animation = null; } if (this.nativeAnimation && ((_d = (_c = this.nativeAnimation) == null ? void 0 : _c.effect) == null ? void 0 : _d.target) !== this.nativeElement) { this.nativeAnimation.cancel(); this.nativeAnimation = null; } if (!this._isOpen) { if (this.animation && this.nativeAnimation) { this.animation.reverse(); this.nativeAnimation.reverse(); } else { this.animation = this.transparentDiv.animate( [ { width: 0 }, { width: this.maxWidth } ], options ); this.nativeAnimation = this.nativeElement.animate( [ { ...this.hasOpacity ? { opacity: 0 } : {}, width: 0 }, { ...this.hasOpacity ? { opacity: 1 } : {}, width: this.maxWidth } ], options ); } } else { if (this.animation && this.nativeAnimation) { this.animation.reverse(); this.nativeAnimation.reverse(); } else { this.animation = this.transparentDiv.animate( [ { width: this.maxWidth }, { width: 0 } ], options ); this.nativeAnimation = this.nativeElement.animate( [ { ...this.hasOpacity ? { opacity: 1 } : {}, width: this.maxWidth }, { ...this.hasOpacity ? { opacity: 0 } : {}, width: 0 } ], options ); } } return new Promise((resolve, reject) => { this.animation.onfinish = () => { this._isOpen = !this._isOpen; resolve(); }; }); } /** * Opens the container with an animation. * @returns {Promise<void>} A promise that resolves when the container is opened. */ async open(event) { await Promise.resolve(this.beforeOpen(event)).then(async () => { if (!this._isOpen) { this.dispatchEvent( new CustomEvent("wje-sliding-container:beforeOpen", { bubbles: true, composed: true }) ); this.checkForVariant(this.variant); await this.doAnimateTransition(); await Promise.resolve(this.afterOpen(event)).then(() => { this.dispatchEvent( new CustomEvent("wje-sliding-container:open", { bubbles: true, composed: true }) ); }); } }); } /** * Closes the animation container. * @returns {Promise<void>} A promise that resolves when the container is closed. */ async close(event) { await Promise.resolve(this.beforeClose(event)).then(async () => { if (this._isOpen) { this.dispatchEvent( new CustomEvent("wje-sliding-container:beforeClose", { bubbles: true, composed: true }) ); await this.doAnimateTransition(); await Promise.resolve(this.afterClose(event)).then(() => { if (this.removeChildAfterClose) { this.childNodes.forEach((child) => { child.remove(); }); } this.dispatchEvent( new CustomEvent("wje-sliding-container:close", { bubbles: true, composed: true }) ); }); } }); } /** * Toggles the state of the element. * If the element is open, it will be closed. If it is closed, it will be opened. * @returns {Promise<void>} A promise that resolves when the toggle operation is complete. */ async toggle(event) { if (this._isOpen) { await this.close(event); } else { await this.open(event); } } componentCleanup() { var _a; (_a = this._resizeObserver) == null ? void 0 : _a.disconnect(); this._resizeObserver = null; } } SlidingContainer.define("wje-sliding-container", SlidingContainer); export { SlidingContainer as default }; //# sourceMappingURL=wje-sliding-container.js.map