@synergy-design-system/components
Version:
This package provides the base of the Synergy Design System as native web components. It uses [lit](https://www.lit.dev) and parts of [shoelace](https://shoelace.style/). Synergy officially supports the latest two versions of all major browsers (as define
411 lines (403 loc) • 12.8 kB
JavaScript
import {
drawer_custom_styles_default
} from "./chunk.I4FIU7FA.js";
import {
drawer_styles_default
} from "./chunk.N7QJ54ZM.js";
import {
Modal
} from "./chunk.AYAX7BG7.js";
import {
lockBodyScrolling,
unlockBodyScrolling
} from "./chunk.5732DMBC.js";
import {
blurActiveElement
} from "./chunk.WXVOTRW5.js";
import {
SynIconButton
} from "./chunk.BANJ5DAQ.js";
import {
waitForEvent
} from "./chunk.C2ENQBPM.js";
import {
animateTo,
stopAnimations
} from "./chunk.G6ITZTTW.js";
import {
getAnimation,
setDefaultAnimation
} from "./chunk.7JGKUB4A.js";
import {
LocalizeController
} from "./chunk.OAQRCZOO.js";
import {
HasSlotController
} from "./chunk.WVVQK5TE.js";
import {
watch
} from "./chunk.BVZQ6QSY.js";
import {
component_styles_default
} from "./chunk.NLYVOJGK.js";
import {
SynergyElement
} from "./chunk.3AZFEB6D.js";
import {
__decorateClass
} from "./chunk.Z4XV3SMG.js";
// src/components/drawer/drawer.component.ts
import { classMap } from "lit/directives/class-map.js";
import { html } from "lit";
import { ifDefined } from "lit/directives/if-defined.js";
import { property, query, state } from "lit/decorators.js";
// src/internal/string.ts
function uppercaseFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
// src/components/drawer/drawer.component.ts
var SynDrawer = class extends SynergyElement {
constructor() {
super(...arguments);
this.hasSlotController = new HasSlotController(this, "footer");
this.localize = new LocalizeController(this);
this.modal = new Modal(this);
this.isVisible = false;
this.open = false;
this.label = "";
this.placement = "end";
this.contained = false;
this.noHeader = false;
this.handleDocumentKeyDown = (event) => {
if (this.contained) {
return;
}
if (event.key === "Escape" && this.modal.isActive() && this.open) {
event.stopImmediatePropagation();
this.requestClose("keyboard");
}
};
}
firstUpdated() {
this.drawer.hidden = this.isVisible ? false : !this.open;
if (this.open) {
this.addOpenListeners();
if (!this.contained) {
this.modal.activate();
lockBodyScrolling(this);
}
}
}
disconnectedCallback() {
super.disconnectedCallback();
unlockBodyScrolling(this);
this.removeOpenListeners();
}
requestClose(source) {
const slRequestClose = this.emit("syn-request-close", {
cancelable: true,
detail: { source }
});
if (slRequestClose.defaultPrevented) {
const animation = getAnimation(this, "drawer.denyClose", { dir: this.localize.dir() });
animateTo(this.panel, animation.keyframes, animation.options);
return;
}
this.hide();
}
addOpenListeners() {
var _a;
if ("CloseWatcher" in window) {
(_a = this.closeWatcher) == null ? void 0 : _a.destroy();
if (!this.contained) {
this.closeWatcher = new CloseWatcher();
this.closeWatcher.onclose = () => this.requestClose("keyboard");
}
} else {
document.addEventListener("keydown", this.handleDocumentKeyDown);
}
}
removeOpenListeners() {
var _a;
document.removeEventListener("keydown", this.handleDocumentKeyDown);
(_a = this.closeWatcher) == null ? void 0 : _a.destroy();
}
async handleOpenChange() {
if (this.open) {
this.emit("syn-show");
this.addOpenListeners();
this.originalTrigger = document.activeElement;
if (!this.contained) {
this.modal.activate();
lockBodyScrolling(this);
}
const autoFocusTarget = this.querySelector("[autofocus]");
if (autoFocusTarget) {
autoFocusTarget.removeAttribute("autofocus");
}
await Promise.all([stopAnimations(this.drawer), stopAnimations(this.overlay)]);
this.drawer.hidden = false;
requestAnimationFrame(() => {
const slInitialFocus = this.emit("syn-initial-focus", { cancelable: true });
if (!slInitialFocus.defaultPrevented) {
if (autoFocusTarget) {
autoFocusTarget.focus({ preventScroll: true });
} else {
this.panel.focus({ preventScroll: true });
}
}
if (autoFocusTarget) {
autoFocusTarget.setAttribute("autofocus", "");
}
});
const panelAnimation = getAnimation(this, `drawer.show${uppercaseFirstLetter(this.placement)}`, {
dir: this.localize.dir()
});
const overlayAnimation = getAnimation(this, "drawer.overlay.show", { dir: this.localize.dir() });
await Promise.all([
animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options),
animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options)
]);
this.emit("syn-after-show");
} else {
blurActiveElement(this);
this.emit("syn-hide");
this.removeOpenListeners();
if (!this.contained) {
this.modal.deactivate();
unlockBodyScrolling(this);
}
await Promise.all([stopAnimations(this.drawer), stopAnimations(this.overlay)]);
const panelAnimation = getAnimation(this, `drawer.hide${uppercaseFirstLetter(this.placement)}`, {
dir: this.localize.dir()
});
const overlayAnimation = getAnimation(this, "drawer.overlay.hide", { dir: this.localize.dir() });
await Promise.all([
animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options).then(() => {
this.overlay.hidden = true;
}),
animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options).then(() => {
this.panel.hidden = true;
})
]);
this.drawer.hidden = !this.isVisible;
this.overlay.hidden = false;
this.panel.hidden = false;
const trigger = this.originalTrigger;
if (typeof (trigger == null ? void 0 : trigger.focus) === "function") {
setTimeout(() => trigger.focus());
}
this.emit("syn-after-hide");
}
}
handleNoModalChange() {
if (this.open && !this.contained) {
this.modal.activate();
lockBodyScrolling(this);
}
if (this.open && this.contained) {
this.modal.deactivate();
unlockBodyScrolling(this);
}
}
/** Shows the drawer. */
async show() {
if (this.open) {
return void 0;
}
this.open = true;
return waitForEvent(this, "syn-after-show");
}
/** Hides the drawer */
async hide() {
if (!this.open) {
return void 0;
}
this.open = false;
return waitForEvent(this, "syn-after-hide");
}
// Forces the visibility of the drawer even with `open` set to false. This is needed for the `rail` and `sticky` variant of the syn-side-nav
forceVisibility(isVisible) {
this.isVisible = isVisible;
this.drawer.hidden = isVisible ? false : !this.open;
}
render() {
return html`
<div
part="base"
class=${classMap({
drawer: true,
"drawer--open": this.open,
"drawer--top": this.placement === "top",
"drawer--end": this.placement === "end",
"drawer--bottom": this.placement === "bottom",
"drawer--start": this.placement === "start",
"drawer--contained": this.contained,
"drawer--fixed": !this.contained,
"drawer--rtl": this.localize.dir() === "rtl",
"drawer--has-footer": this.hasSlotController.test("footer")
})}
>
<div part="overlay" class="drawer__overlay" @click=${() => this.requestClose("overlay")} tabindex="-1"></div>
<div
part="panel"
class="drawer__panel"
role="dialog"
aria-modal="true"
aria-hidden=${this.isVisible ? "false" : this.open ? "false" : "true"}
aria-label=${ifDefined(this.noHeader ? this.label : void 0)}
aria-labelledby=${ifDefined(!this.noHeader ? "title" : void 0)}
tabindex="0"
>
${!this.noHeader ? html`
<header part="header" class="drawer__header">
<h2 part="title" class="drawer__title" id="title">
<!-- If there's no label, use an invisible character to prevent the header from collapsing -->
<slot name="label"> ${this.label.length > 0 ? this.label : String.fromCharCode(65279)} </slot>
</h2>
<div part="header-actions" class="drawer__header-actions">
<slot name="header-actions"></slot>
<syn-icon-button
part="close-button"
exportparts="base:close-button__base"
class="drawer__close"
name="x-lg"
label=${this.localize.term("close")}
library="system"
@click=${() => this.requestClose("close-button")}
></syn-icon-button>
</div>
</header>
` : ""}
<slot part="body" class="drawer__body"></slot>
<footer part="footer" class="drawer__footer">
<slot name="footer"></slot>
</footer>
</div>
</div>
`;
}
};
SynDrawer.styles = [component_styles_default, drawer_styles_default, drawer_custom_styles_default];
SynDrawer.dependencies = { "syn-icon-button": SynIconButton };
__decorateClass([
state()
], SynDrawer.prototype, "isVisible", 2);
__decorateClass([
query(".drawer")
], SynDrawer.prototype, "drawer", 2);
__decorateClass([
query(".drawer__panel")
], SynDrawer.prototype, "panel", 2);
__decorateClass([
query(".drawer__overlay")
], SynDrawer.prototype, "overlay", 2);
__decorateClass([
property({ type: Boolean, reflect: true })
], SynDrawer.prototype, "open", 2);
__decorateClass([
property({ reflect: true })
], SynDrawer.prototype, "label", 2);
__decorateClass([
property({ reflect: true })
], SynDrawer.prototype, "placement", 2);
__decorateClass([
property({ type: Boolean, reflect: true })
], SynDrawer.prototype, "contained", 2);
__decorateClass([
property({ attribute: "no-header", type: Boolean, reflect: true })
], SynDrawer.prototype, "noHeader", 2);
__decorateClass([
watch("open", { waitUntilFirstUpdate: true })
], SynDrawer.prototype, "handleOpenChange", 1);
__decorateClass([
watch("contained", { waitUntilFirstUpdate: true })
], SynDrawer.prototype, "handleNoModalChange", 1);
setDefaultAnimation("drawer.showTop", {
keyframes: [
{ opacity: 0, translate: "0 -100%" },
{ opacity: 1, translate: "0 0" }
],
options: { duration: 250, easing: "ease" }
});
setDefaultAnimation("drawer.hideTop", {
keyframes: [
{ opacity: 1, translate: "0 0" },
{ opacity: 0, translate: "0 -100%" }
],
options: { duration: 250, easing: "ease" }
});
setDefaultAnimation("drawer.showEnd", {
keyframes: [
{ opacity: 0, translate: "100%" },
{ opacity: 1, translate: "0" }
],
rtlKeyframes: [
{ opacity: 0, translate: "-100%" },
{ opacity: 1, translate: "0" }
],
options: { duration: 250, easing: "ease" }
});
setDefaultAnimation("drawer.hideEnd", {
keyframes: [
{ opacity: 1, translate: "0" },
{ opacity: 0, translate: "100%" }
],
rtlKeyframes: [
{ opacity: 1, translate: "0" },
{ opacity: 0, translate: "-100%" }
],
options: { duration: 250, easing: "ease" }
});
setDefaultAnimation("drawer.showBottom", {
keyframes: [
{ opacity: 0, translate: "0 100%" },
{ opacity: 1, translate: "0 0" }
],
options: { duration: 250, easing: "ease" }
});
setDefaultAnimation("drawer.hideBottom", {
keyframes: [
{ opacity: 1, translate: "0 0" },
{ opacity: 0, translate: "0 100%" }
],
options: { duration: 250, easing: "ease" }
});
setDefaultAnimation("drawer.showStart", {
keyframes: [
{ opacity: 0, translate: "-100%" },
{ opacity: 1, translate: "0" }
],
rtlKeyframes: [
{ opacity: 0, translate: "100%" },
{ opacity: 1, translate: "0" }
],
options: { duration: 250, easing: "ease" }
});
setDefaultAnimation("drawer.hideStart", {
keyframes: [
{ opacity: 1, translate: "0" },
{ opacity: 0, translate: "-100%" }
],
rtlKeyframes: [
{ opacity: 1, translate: "0" },
{ opacity: 0, translate: "100%" }
],
options: { duration: 250, easing: "ease" }
});
setDefaultAnimation("drawer.denyClose", {
keyframes: [{ scale: 1 }, { scale: 1.01 }, { scale: 1 }],
options: { duration: 250 }
});
setDefaultAnimation("drawer.overlay.show", {
keyframes: [{ opacity: 0 }, { opacity: 1 }],
options: { duration: 250 }
});
setDefaultAnimation("drawer.overlay.hide", {
keyframes: [{ opacity: 1 }, { opacity: 0 }],
options: { duration: 250 }
});
export {
SynDrawer
};
//# sourceMappingURL=chunk.RN7MBD4H.js.map