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
JavaScript
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