Added new Drawer Component

This commit is contained in:
2025-08-22 15:23:39 +05:30
parent 589d6fd7d1
commit c854d0733e
9 changed files with 885 additions and 43 deletions
+8 -8
View File
@@ -64,7 +64,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<input <input
type="text" type="text"
id={`${fieldId}-display`} id={`${fieldId}-display`}
class="wr:w-full wr:px-3 wr:py-2 wr:pr-10 wr:border wr:border-border wr:rounded-lg wr:bg-background wr:text-foreground focus:wr:ring-2 focus:wr:ring-primary focus:wr:border-primary disabled:wr:opacity-50" class="wr:w-full wr:px-3 wr:py-2 wr:pr-10 wr:border wr:border-border wr:rounded-lg wr:bg-background wr:text-foreground wr:focus:ring-2 wr:focus:ring-primary wr:focus:border-primary wr:disabled:opacity-50"
placeholder={placeholder} placeholder={placeholder}
readonly readonly
disabled={disabled} disabled={disabled}
@@ -75,7 +75,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<button <button
type="button" type="button"
id={`${fieldId}-trigger`} id={`${fieldId}-trigger`}
class="wr:absolute wr:right-0 wr:top-0 wr:h-full wr:px-3 wr:flex wr:items-center wr:text-muted-foreground hover:wr:text-foreground disabled:wr:opacity-50" class="wr:absolute wr:right-0 wr:top-0 wr:h-full wr:px-3 wr:flex wr:items-center wr:text-muted-foreground wr:hover:text-foreground wr:disabled:opacity-50"
disabled={disabled} disabled={disabled}
aria-label="Open calendar" aria-label="Open calendar"
> >
@@ -107,7 +107,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<button <button
type="button" type="button"
id={`${fieldId}-prev-month`} id={`${fieldId}-prev-month`}
class="wr:p-1 wr:rounded wr:hover:wr:bg-muted" class="wr:p-1 wr:rounded wr:hover:bg-muted"
aria-label="Previous month" aria-label="Previous month"
> >
<svg <svg
@@ -124,19 +124,19 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<div class="wr:flex wr:gap-2"> <div class="wr:flex wr:gap-2">
<select <select
id={`${fieldId}-month-select`} id={`${fieldId}-month-select`}
class="wr:bg-card wr:border-none wr:text-sm wr:font-medium wr:text-foreground focus:wr:outline-none" class="wr:bg-card wr:border-none wr:text-sm wr:font-medium wr:text-foreground wr:focus:outline-none"
></select> ></select>
<!-- UPDATED: Year dropdown instead of input --> <!-- UPDATED: Year dropdown instead of input -->
<select <select
id={`${fieldId}-year-select`} id={`${fieldId}-year-select`}
class="wr:bg-card wr:border-none wr:text-sm wr:font-medium wr:text-foreground focus:wr:outline-none" class="wr:bg-card wr:border-none wr:text-sm wr:font-medium wr:text-foreground wr:focus:outline-none"
></select> ></select>
</div> </div>
<button <button
type="button" type="button"
id={`${fieldId}-next-month`} id={`${fieldId}-next-month`}
class="wr:p-1 wr:rounded wr:hover:wr:bg-muted" class="wr:p-1 wr:rounded wr:hover:bg-muted"
aria-label="Next month" aria-label="Next month"
> >
<svg <svg
@@ -202,7 +202,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<button <button
type="button" type="button"
id={`${fieldId}-today`} id={`${fieldId}-today`}
class="wr:px-3 wr:py-1 wr:text-sm wr:text-primary hover:wr:bg-primary/10 wr:rounded" class="wr:px-3 wr:py-1 wr:text-sm wr:text-primary wr:hover:bg-primary/10 wr:rounded"
> >
Today Today
</button> </button>
@@ -417,7 +417,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
dayButton.type = "button"; dayButton.type = "button";
dayButton.textContent = day; dayButton.textContent = day;
dayButton.className = dayButton.className =
"wr:w-8 wr:h-8 wr:text-sm wr:rounded wr:transition-colors wr:hover:wr:bg-muted focus:wr:outline-none focus:wr:ring-2 focus:wr:ring-primary"; "wr:w-8 wr:h-8 wr:text-sm wr:rounded wr:transition-colors wr:hover:bg-muted wr:focus:outline-none wr:focus:ring-2 wr:focus:ring-primary";
const isDisabled = this.isDateDisabled(currentDate); const isDisabled = this.isDateDisabled(currentDate);
if (isDisabled) { if (isDisabled) {
+13 -13
View File
@@ -76,7 +76,7 @@ if (value) {
<input <input
type="text" type="text"
id={`${fieldId}-display`} id={`${fieldId}-display`}
class="wr:w-full wr:px-3 wr:py-2 wr:pr-10 wr:border wr:border-border wr:rounded-lg wr:bg-background wr:text-foreground focus:wr:ring-2 focus:wr:ring-primary focus:wr:border-primary disabled:wr:opacity-50" class="wr:w-full wr:px-3 wr:py-2 wr:pr-10 wr:border wr:border-border wr:rounded-lg wr:bg-background wr:text-foreground wr:focus:ring-2 wr:focus:ring-primary wr:focus:border-primary wr:disabled:opacity-50"
placeholder={placeholder} placeholder={placeholder}
readonly readonly
disabled={disabled} disabled={disabled}
@@ -87,7 +87,7 @@ if (value) {
<button <button
type="button" type="button"
id={`${fieldId}-trigger`} id={`${fieldId}-trigger`}
class="wr:absolute wr:right-0 wr:top-0 wr:h-full wr:px-3 wr:flex wr:items-center wr:text-muted-foreground hover:wr:text-foreground disabled:wr:opacity-50" class="wr:absolute wr:right-0 wr:top-0 wr:h-full wr:px-3 wr:flex wr:items-center wr:text-muted-foreground wr:hover:text-foreground wr:disabled:opacity-50"
disabled={disabled} disabled={disabled}
aria-label="Open datetime picker" aria-label="Open datetime picker"
> >
@@ -128,7 +128,7 @@ if (value) {
<button <button
type="button" type="button"
id={`${fieldId}-time-tab`} id={`${fieldId}-time-tab`}
class="wr:flex-1 wr:px-4 wr:py-2 wr:text-sm wr:font-medium wr:border-b-2 wr:border-transparent wr:text-muted-foreground hover:wr:text-foreground" class="wr:flex-1 wr:px-4 wr:py-2 wr:text-sm wr:font-medium wr:border-b-2 wr:border-transparent wr:text-muted-foreground wr:hover:text-foreground"
data-tab="time" data-tab="time"
> >
Time Time
@@ -144,7 +144,7 @@ if (value) {
<button <button
type="button" type="button"
id={`${fieldId}-prev-month`} id={`${fieldId}-prev-month`}
class="wr:p-1 wr:rounded wr:hover:wr:bg-muted" class="wr:p-1 wr:rounded wr:hover:bg-muted"
> >
<svg <svg
class="wr:w-4 wr:h-4" class="wr:w-4 wr:h-4"
@@ -171,7 +171,7 @@ if (value) {
<button <button
type="button" type="button"
id={`${fieldId}-next-month`} id={`${fieldId}-next-month`}
class="wr:p-1 wr:rounded wr:hover:wr:bg-muted" class="wr:p-1 wr:rounded wr:hover:bg-muted"
> >
<svg <svg
class="wr:w-4 wr:h-4" class="wr:w-4 wr:h-4"
@@ -249,7 +249,7 @@ if (value) {
> >
<select <select
id={`${fieldId}-hour`} id={`${fieldId}-hour`}
class="wr:w-full wr:px-2 wr:py-1 wr:text-center wr:border wr:border-border wr:rounded focus:wr:ring-1 focus:wr:ring-primary wr:bg-background" class="wr:w-full wr:px-2 wr:py-1 wr:text-center wr:border wr:border-border wr:rounded wr:focus:ring-1 wr:focus:ring-primary wr:bg-background"
></select> ></select>
</div> </div>
<div <div
@@ -264,7 +264,7 @@ if (value) {
> >
<select <select
id={`${fieldId}-minute`} id={`${fieldId}-minute`}
class="wr:w-full wr:px-2 wr:py-1 wr:text-center wr:border wr:border-border wr:rounded focus:wr:ring-1 focus:wr:ring-primary wr:bg-background" class="wr:w-full wr:px-2 wr:py-1 wr:text-center wr:border wr:border-border wr:rounded wr:focus:ring-1 wr:focus:ring-primary wr:bg-background"
></select> ></select>
</div> </div>
{ {
@@ -275,7 +275,7 @@ if (value) {
</label> </label>
<select <select
id={`${fieldId}-period`} id={`${fieldId}-period`}
class="wr:w-full wr:px-2 wr:py-1 wr:border wr:border-border wr:rounded focus:wr:ring-1 focus:wr:ring-primary wr:bg-background" class="wr:w-full wr:px-2 wr:py-1 wr:border wr:border-border wr:rounded wr:focus:ring-1 wr:focus:ring-primary wr:bg-background"
> >
<option value="AM">AM</option> <option value="AM">AM</option>
<option value="PM">PM</option> <option value="PM">PM</option>
@@ -302,14 +302,14 @@ if (value) {
<button <button
type="button" type="button"
id={`${fieldId}-now`} id={`${fieldId}-now`}
class="wr:px-3 wr:py-1 wr:text-sm wr:text-primary hover:wr:bg-primary/10 wr:rounded" class="wr:px-3 wr:py-1 wr:text-sm wr:text-primary wr:hover:bg-primary/10 wr:rounded"
> >
Now Now
</button> </button>
<button <button
type="button" type="button"
id={`${fieldId}-apply`} id={`${fieldId}-apply`}
class="wr:px-3 wr:py-1 wr:text-sm wr:bg-primary wr:text-primary-foreground hover:wr:bg-primary/90 wr:rounded" class="wr:px-3 wr:py-1 wr:text-sm wr:bg-primary wr:text-primary-foreground wr:hover:bg-primary/90 wr:rounded"
> >
Apply Apply
</button> </button>
@@ -556,7 +556,7 @@ if (value) {
dayButton.type = "button"; dayButton.type = "button";
dayButton.textContent = day; dayButton.textContent = day;
dayButton.className = dayButton.className =
"wr:w-8 wr:h-8 wr:text-sm wr:rounded wr:transition-colors wr:hover:wr:bg-muted focus:wr:outline-none focus:wr:ring-2 focus:wr:ring-primary"; "wr:w-8 wr:h-8 wr:text-sm wr:rounded wr:transition-colors wr:hover:bg-muted wr:focus:outline-none wr:focus:ring-2 wr:focus:ring-primary";
const dateStr = currentDate.toISOString().split("T")[0]; const dateStr = currentDate.toISOString().split("T")[0];
if (this.selectedDate === dateStr) { if (this.selectedDate === dateStr) {
@@ -639,14 +639,14 @@ if (value) {
this.dateTab.className = this.dateTab.className =
"wr:flex-1 wr:px-4 wr:py-2 wr:text-sm wr:font-medium wr:border-b-2 wr:border-primary wr:text-primary"; "wr:flex-1 wr:px-4 wr:py-2 wr:text-sm wr:font-medium wr:border-b-2 wr:border-primary wr:text-primary";
this.timeTab.className = this.timeTab.className =
"wr:flex-1 wr:px-4 wr:py-2 wr:text-sm wr:font-medium wr:border-b-2 wr:border-transparent wr:text-muted-foreground hover:wr:text-foreground"; "wr:flex-1 wr:px-4 wr:py-2 wr:text-sm wr:font-medium wr:border-b-2 wr:border-transparent wr:text-muted-foreground wr:hover:text-foreground";
this.datePanel.className = "wr:block"; this.datePanel.className = "wr:block";
this.timePanel.className = "wr:hidden"; this.timePanel.className = "wr:hidden";
} else { } else {
this.timeTab.className = this.timeTab.className =
"wr:flex-1 wr:px-4 wr:py-2 wr:text-sm wr:font-medium wr:border-b-2 wr:border-primary wr:text-primary"; "wr:flex-1 wr:px-4 wr:py-2 wr:text-sm wr:font-medium wr:border-b-2 wr:border-primary wr:text-primary";
this.dateTab.className = this.dateTab.className =
"wr:flex-1 wr:px-4 wr:py-2 wr:text-sm wr:font-medium wr:border-b-2 wr:border-transparent wr:text-muted-foreground hover:wr:text-foreground"; "wr:flex-1 wr:px-4 wr:py-2 wr:text-sm wr:font-medium wr:border-b-2 wr:border-transparent wr:text-muted-foreground wr:hover:text-foreground";
this.timePanel.className = "wr:block"; this.timePanel.className = "wr:block";
this.datePanel.className = "wr:hidden"; this.datePanel.className = "wr:hidden";
} }
+531
View File
@@ -0,0 +1,531 @@
---
// Drawer.astro
export interface Props {
position?: "left" | "right" | "top" | "bottom";
size?: string;
overlay?: boolean;
closeOnOverlayClick?: boolean;
closeOnEsc?: boolean;
showCloseButton?: boolean;
animationDuration?: number;
zIndex?: number;
id?: string;
class?: string;
lockScroll?: boolean;
persistent?: boolean;
blurBackground?: boolean;
}
const {
position = "right",
size = "320px",
overlay = true,
closeOnOverlayClick = true,
closeOnEsc = true,
showCloseButton = true,
animationDuration = 300,
zIndex = 1000,
id = `drawer-${Math.random().toString(36).slice(2)}`,
class: className = "",
lockScroll = true,
persistent = false,
blurBackground = false,
} = Astro.props;
const isHorizontal = position === "left" || position === "right";
const sizeProperty = isHorizontal ? "width" : "height";
---
<div class={`drawer-container ${className}`} id={id}>
<!-- Trigger Slot -->
<div class="drawer-trigger">
<slot name="trigger" />
</div>
<!-- Drawer Overlay & Panel -->
<div
class="drawer-overlay wr:fixed wr:inset-0 wr:z-[1000] wr:hidden wr:transition-all wr:duration-300"
data-drawer-overlay
style={`z-index: ${zIndex}; transition-duration: ${animationDuration}ms;`}
>
<!-- Background Overlay -->
{
overlay && (
<div
class={`drawer-backdrop wr:absolute wr:inset-0 wr:bg-black/50 wr:opacity-0 wr:transition-opacity ${blurBackground ? "wr:backdrop-blur-sm" : ""}`}
data-drawer-backdrop
style={`transition-duration: ${animationDuration}ms;`}
/>
)
}
<!-- Drawer Panel -->
<div
class={`drawer-panel wr:fixed wr:bg-card wr:shadow-xl wr:transition-transform wr:flex wr:flex-col ${
position === "left"
? "wr:left-0 wr:top-0 wr:bottom-0 wr:border-r wr:border-border wr:-translate-x-full"
: position === "right"
? "wr:right-0 wr:top-0 wr:bottom-0 wr:border-l wr:border-border wr:translate-x-full"
: position === "top"
? "wr:top-0 wr:left-0 wr:right-0 wr:border-b wr:border-border wr:-translate-y-full"
: "wr:bottom-0 wr:left-0 wr:right-0 wr:border-t wr:border-border wr:translate-y-full"
}`}
data-drawer-panel
role="dialog"
aria-modal="true"
aria-labelledby={`${id}-title`}
tabindex="-1"
style={`${sizeProperty}: ${size}; transition-duration: ${animationDuration}ms; z-index: ${zIndex + 1};`}
>
<!-- Drawer Header -->
<div
class="drawer-header wr:flex wr:items-center wr:justify-between wr:p-4 wr:border-b wr:border-border wr:min-h-[60px]"
>
<div class="drawer-title" id={`${id}-title`}>
<slot name="title">
<h2
class="wr:text-lg wr:font-semibold wr:text-foreground wr:m-0"
>
Drawer
</h2>
</slot>
</div>
{
showCloseButton && (
<button
type="button"
class="drawer-close-btn wr:p-2 wr:rounded-lg wr:hover:bg-muted wr:transition-colors wr:text-muted-foreground wr:hover:text-foreground wr:focus:outline-none wr:focus:ring-2 wr:focus:ring-primary wr:focus:ring-offset-1"
data-drawer-close
aria-label="Close drawer"
>
<svg
class="wr:w-5 wr:h-5"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" />
</svg>
</button>
)
}
</div>
<!-- Drawer Content -->
<div class="drawer-content wr:flex-1 wr:overflow-y-auto wr:p-4">
<slot />
</div>
<!-- Drawer Footer -->
<div class="drawer-footer">
<slot name="footer" />
</div>
</div>
</div>
</div>
<script
is:inline
define:vars={{
id,
position,
closeOnOverlayClick,
closeOnEsc,
animationDuration,
lockScroll,
persistent,
}}
>
class Drawer {
constructor() {
this.id = id;
this.position = position;
this.closeOnOverlayClick = closeOnOverlayClick;
this.closeOnEsc = closeOnEsc;
this.animationDuration = animationDuration;
this.lockScroll = lockScroll;
this.persistent = persistent;
this.isOpen = false;
this.isAnimating = false;
this.container = document.getElementById(this.id);
this.trigger = this.container?.querySelector(".drawer-trigger");
this.overlay = this.container?.querySelector(
"[data-drawer-overlay]",
);
this.backdrop = this.container?.querySelector(
"[data-drawer-backdrop]",
);
this.panel = this.container?.querySelector("[data-drawer-panel]");
this.closeBtn = this.container?.querySelector(
"[data-drawer-close]",
);
this.focusableElements = [];
this.firstFocusableElement = null;
this.lastFocusableElement = null;
this.previousActiveElement = null;
this.initializeEventListeners();
// FIXED: Register instance to window object immediately
this.registerToWindow();
}
// FIXED: Method to register instance to window
registerToWindow() {
const windowKey = `drawer_${this.id.replace(/-/g, "_")}`;
if (!window.drawerInstances) {
window.drawerInstances = {};
}
window.drawerInstances[this.id] = this;
window[windowKey] = this;
// Also register with original ID for backward compatibility
window[`drawer_${this.id}`] = this;
}
initializeEventListeners() {
if (!this.container) return;
// Trigger click events
if (this.trigger) {
const triggerElements = this.trigger.querySelectorAll(
'button, a, [role="button"], [tabindex]',
);
if (triggerElements.length === 0) {
// If no interactive elements, make the trigger itself clickable
this.trigger.style.cursor = "pointer";
this.trigger.addEventListener("click", () => this.open());
} else {
triggerElements.forEach((el) => {
el.addEventListener("click", (e) => {
e.preventDefault();
this.open();
});
});
}
}
// Close button
this.closeBtn?.addEventListener("click", () => this.close());
// Backdrop click
if (this.closeOnOverlayClick && this.backdrop) {
this.backdrop.addEventListener("click", () => {
if (!this.persistent) this.close();
});
}
// Prevent panel click from closing
this.panel?.addEventListener("click", (e) => {
e.stopPropagation();
});
// Escape key
if (this.closeOnEsc) {
document.addEventListener(
"keydown",
this.handleKeydown.bind(this),
);
}
// Focus trap
this.panel?.addEventListener(
"keydown",
this.handleFocusTrap.bind(this),
);
}
handleKeydown(e) {
if (e.key === "Escape" && this.isOpen && !this.persistent) {
this.close();
}
}
handleFocusTrap(e) {
if (!this.isOpen) return;
if (e.key === "Tab") {
if (e.shiftKey) {
// Shift + Tab
if (document.activeElement === this.firstFocusableElement) {
e.preventDefault();
this.lastFocusableElement?.focus();
}
} else {
// Tab
if (document.activeElement === this.lastFocusableElement) {
e.preventDefault();
this.firstFocusableElement?.focus();
}
}
}
}
getFocusableElements() {
if (!this.panel) return;
const selectors = [
"a[href]",
"button:not([disabled])",
"textarea:not([disabled])",
"input:not([disabled])",
"select:not([disabled])",
'[tabindex]:not([tabindex="-1"])',
"[contenteditable]",
];
this.focusableElements = Array.from(
this.panel.querySelectorAll(selectors.join(", ")),
).filter((el) => {
return (
el.offsetWidth > 0 &&
el.offsetHeight > 0 &&
!el.hasAttribute("hidden")
);
});
this.firstFocusableElement = this.focusableElements[0] || null;
this.lastFocusableElement =
this.focusableElements[this.focusableElements.length - 1] ||
null;
}
async open() {
if (this.isOpen || this.isAnimating) return;
this.isAnimating = true;
this.previousActiveElement = document.activeElement;
// Emit opening event
const openingEvent = new CustomEvent("drawer:opening", {
detail: { drawerId: this.id },
bubbles: true,
cancelable: true,
});
this.container.dispatchEvent(openingEvent);
if (openingEvent.defaultPrevented) {
this.isAnimating = false;
return;
}
// Lock scroll
if (this.lockScroll) {
document.body.style.overflow = "hidden";
document.body.style.paddingRight =
this.getScrollbarWidth() + "px";
}
// Show overlay
this.overlay.classList.remove("wr:hidden");
this.overlay.classList.add("wr:flex");
// Force reflow
this.overlay.offsetHeight;
// Animate backdrop
if (this.backdrop) {
this.backdrop.classList.remove("wr:opacity-0");
this.backdrop.classList.add("wr:opacity-100");
}
// Animate panel
this.panel.classList.remove(this.getTransformClass(false));
this.panel.classList.add(this.getTransformClass(true));
// Wait for animation
await this.delay(this.animationDuration);
this.isOpen = true;
this.isAnimating = false;
// Focus management
this.getFocusableElements();
if (this.firstFocusableElement) {
this.firstFocusableElement.focus();
} else {
this.panel.focus();
}
// Emit opened event
this.container.dispatchEvent(
new CustomEvent("drawer:opened", {
detail: { drawerId: this.id },
bubbles: true,
}),
);
}
async close() {
if (!this.isOpen || this.isAnimating) return;
this.isAnimating = true;
// Emit closing event
const closingEvent = new CustomEvent("drawer:closing", {
detail: { drawerId: this.id },
bubbles: true,
cancelable: true,
});
this.container.dispatchEvent(closingEvent);
if (closingEvent.defaultPrevented) {
this.isAnimating = false;
return;
}
// Animate panel
this.panel.classList.remove(this.getTransformClass(true));
this.panel.classList.add(this.getTransformClass(false));
// Animate backdrop
if (this.backdrop) {
this.backdrop.classList.remove("wr:opacity-100");
this.backdrop.classList.add("wr:opacity-0");
}
// Wait for animation
await this.delay(this.animationDuration);
// Hide overlay
this.overlay.classList.remove("wr:flex");
this.overlay.classList.add("wr:hidden");
// Unlock scroll
if (this.lockScroll) {
document.body.style.overflow = "";
document.body.style.paddingRight = "";
}
this.isOpen = false;
this.isAnimating = false;
// Restore focus
if (this.previousActiveElement) {
this.previousActiveElement.focus();
this.previousActiveElement = null;
}
// Emit closed event
this.container.dispatchEvent(
new CustomEvent("drawer:closed", {
detail: { drawerId: this.id },
bubbles: true,
}),
);
}
toggle() {
return this.isOpen ? this.close() : this.open();
}
getTransformClass(isOpen) {
const transformMap = {
left: isOpen ? "wr:translate-x-0" : "wr:-translate-x-full",
right: isOpen ? "wr:translate-x-0" : "wr:translate-x-full",
top: isOpen ? "wr:translate-y-0" : "wr:-translate-y-full",
bottom: isOpen ? "wr:translate-y-0" : "wr:translate-y-full",
};
return transformMap[this.position];
}
getScrollbarWidth() {
const scrollDiv = document.createElement("div");
scrollDiv.style.cssText =
"width: 100px; height: 100px; overflow: scroll; position: absolute; top: -9999px;";
document.body.appendChild(scrollDiv);
const scrollbarWidth =
scrollDiv.offsetWidth - scrollDiv.clientWidth;
document.body.removeChild(scrollDiv);
return scrollbarWidth;
}
delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// Public API methods
isOpened() {
return this.isOpen;
}
destroy() {
// Remove all event listeners and cleanup
if (this.lockScroll && this.isOpen) {
document.body.style.overflow = "";
document.body.style.paddingRight = "";
}
this.container?.remove();
}
openDrawer() {
return this.open();
}
closeDrawer() {
return this.close();
}
toggleDrawer() {
return this.toggle();
}
getState() {
return {
isOpen: this.isOpen,
isAnimating: this.isAnimating,
id: this.id,
};
}
}
const init = () => {
const drawerElement = document.getElementById(id);
if (!drawerElement) {
console.warn(`Drawer element with id "${id}" not found`);
return;
}
// Avoid double initialization
if (drawerElement.drawerInstance) {
console.log(`Drawer "${id}" already initialized`);
return;
}
try {
const drawer = new Drawer();
drawerElement.drawerInstance = drawer;
// FIXED: Emit initialization event
const initEvent = new CustomEvent("drawer:initialized", {
detail: { drawerId: id, instance: drawer },
bubbles: true,
});
drawerElement.dispatchEvent(initEvent);
console.log(`Drawer "${id}" initialized successfully`);
} catch (error) {
console.error(`Failed to initialize drawer "${id}":`, error);
}
};
// FIXED: Multiple initialization strategies
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
// Use setTimeout to ensure DOM is fully ready
setTimeout(init, 0);
}
// Astro page transitions
document.addEventListener("astro:page-load", init);
// FIXED: Also try initialization after a small delay for complex components
setTimeout(init, 100);
</script>
+1 -1
View File
@@ -172,7 +172,7 @@ const controlWrap = "wr:relative";
{p.kind === "password" && ( {p.kind === "password" && (
<button <button
type="button" type="button"
class="wr:absolute wr:inset-y-0 wr:right-0 wr:pr-3 wr:flex wr:items-center wr:text-muted-foreground hover:wr:text-foreground" class="wr:absolute wr:inset-y-0 wr:right-0 wr:pr-3 wr:flex wr:items-center wr:text-muted-foreground wr:hover:text-foreground"
onclick={`const i = this.previousElementSibling; i.type = i.type === 'password' ? 'text' : 'password';`} onclick={`const i = this.previousElementSibling; i.type = i.type === 'password' ? 'text' : 'password';`}
> >
<Icon name="mdi:eye" class={iconSize} /> <Icon name="mdi:eye" class={iconSize} />
+7 -7
View File
@@ -93,7 +93,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<!-- Drop Zone --> <!-- Drop Zone -->
<div <div
id="drop-zone" id="drop-zone"
class="wr:border-2 wr:border-dashed wr:border-border wr:rounded-lg wr:p-6 wr:text-center wr:bg-background/50 wr:transition-all wr:duration-300 wr:cursor-pointer wr:min-h-[120px] wr:flex wr:items-center wr:justify-center hover:wr:border-primary hover:wr:bg-background focus:wr:outline-none focus:wr:ring-2 focus:wr:ring-primary focus:wr:ring-offset-2" class="wr:border-2 wr:border-dashed wr:border-border wr:rounded-lg wr:p-6 wr:text-center wr:bg-background/50 wr:transition-all wr:duration-300 wr:cursor-pointer wr:min-h-[120px] wr:flex wr:items-center wr:justify-center wr:hover:border-primary wr:hover:bg-background wr:focus:outline-none wr:focus:ring-2 wr:focus:ring-primary wr:focus:ring-offset-2"
tabindex="0" tabindex="0"
role="button" role="button"
aria-label="Click to select files or drag and drop files here" aria-label="Click to select files or drag and drop files here"
@@ -113,7 +113,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
Drop files here or <button Drop files here or <button
type="button" type="button"
id="browse-btn" id="browse-btn"
class="wr:text-primary wr:underline wr:font-medium wr:pointer-events-auto wr:bg-none wr:border-none wr:cursor-pointer hover:wr:text-primary/80" class="wr:text-primary wr:underline wr:font-medium wr:pointer-events-auto wr:bg-none wr:border-none wr:cursor-pointer wr:hover:text-primary/80"
>browse</button >browse</button
> >
</p> </p>
@@ -163,7 +163,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<button <button
type="button" type="button"
id="upload-btn" id="upload-btn"
class="wr:flex wr:items-center wr:gap-2 wr:px-4 wr:py-2 wr:rounded-lg wr:text-sm wr:font-medium wr:bg-primary wr:text-primary-foreground hover:wr:bg-primary/90 disabled:wr:opacity-50 disabled:wr:cursor-not-allowed focus:wr:outline-none focus:wr:ring-2 focus:wr:ring-primary focus:wr:ring-offset-1" class="wr:flex wr:items-center wr:gap-2 wr:px-4 wr:py-2 wr:rounded-lg wr:text-sm wr:font-medium wr:bg-primary wr:text-primary-foreground wr:hover:bg-primary/90 wr:disabled:opacity-50 wr:disabled:cursor-not-allowed wr:focus:outline-none wr:focus:ring-2 wr:focus:ring-primary wr:focus:ring-offset-1"
> >
<svg <svg
class="wr:w-4 wr:h-4" class="wr:w-4 wr:h-4"
@@ -178,7 +178,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<button <button
type="button" type="button"
id="clear-btn" id="clear-btn"
class="wr:flex wr:items-center wr:gap-2 wr:px-4 wr:py-2 wr:rounded-lg wr:text-sm wr:font-medium wr:bg-secondary wr:text-secondary-foreground wr:border wr:border-border hover:wr:bg-secondary/80 focus:wr:outline-none focus:wr:ring-2 focus:wr:ring-secondary focus:wr:ring-offset-1" class="wr:flex wr:items-center wr:gap-2 wr:px-4 wr:py-2 wr:rounded-lg wr:text-sm wr:font-medium wr:bg-secondary wr:text-secondary-foreground wr:border wr:border-border wr:hover:bg-secondary/80 wr:focus:outline-none wr:focus:ring-2 wr:focus:ring-secondary wr:focus:ring-offset-1"
> >
<svg <svg
class="wr:w-4 wr:h-4" class="wr:w-4 wr:h-4"
@@ -480,7 +480,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
const fileItem = document.createElement("div"); const fileItem = document.createElement("div");
fileItem.className = fileItem.className =
"wr:flex wr:items-center wr:gap-3 wr:p-3 wr:border wr:border-border wr:rounded-lg wr:bg-background wr:transition-all wr:duration-200 hover:wr:shadow-sm"; "wr:flex wr:items-center wr:gap-3 wr:p-3 wr:border wr:border-border wr:rounded-lg wr:bg-background wr:transition-all wr:duration-200 wr:hover:shadow-sm";
// Create preview // Create preview
const previewUrl = file.type.startsWith("image/") const previewUrl = file.type.startsWith("image/")
@@ -524,7 +524,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
${ ${
status === "pending" && !this.autoUpload && this.uploadFunction status === "pending" && !this.autoUpload && this.uploadFunction
? ` ? `
<button class="wr:p-1 wr:rounded wr:bg-primary/10 wr:text-primary wr:border wr:border-primary/20 hover:wr:bg-primary/20" <button class="wr:p-1 wr:rounded wr:bg-primary/10 wr:text-primary wr:border wr:border-primary/20 wr:hover:bg-primary/20"
data-action="process" data-action="process"
data-index="${index}" data-index="${index}"
title="Process"> title="Process">
@@ -536,7 +536,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
: "" : ""
} }
<button class="wr:p-1 wr:rounded wr:bg-danger/10 wr:text-danger wr:border wr:border-danger/20 hover:wr:bg-danger/20 ${status === "processing" ? "wr:opacity-50 wr:cursor-not-allowed" : ""}" <button class="wr:p-1 wr:rounded wr:bg-danger/10 wr:text-danger wr:border wr:border-danger/20 wr:hover:bg-danger/20 ${status === "processing" ? "wr:opacity-50 wr:cursor-not-allowed" : ""}"
data-action="delete" data-action="delete"
data-index="${index}" data-index="${index}"
title="Remove" title="Remove"
+3 -3
View File
@@ -46,7 +46,7 @@ const inputCls = cn(
"wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-border wr:rounded-lg wr:sm:text-sm wr:focus:border-border wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-input wr:dark:border-border wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600", "wr:py-2.5 wr:sm:py-3 wr:px-4 wr:block wr:w-full wr:border-border wr:rounded-lg wr:sm:text-sm wr:focus:border-border wr:focus:ring-blue-500 wr:disabled:opacity-50 wr:disabled:pointer-events-none wr:dark:bg-input wr:dark:border-border wr:dark:text-neutral-400 wr:dark:placeholder-neutral-500 wr:dark:focus:ring-neutral-600",
sizeKls, sizeKls,
"wr:pr-10", // space for eye button "wr:pr-10", // space for eye button
p.error && "wr:border-danger wr:focus-visible:wr:ring-danger/40", p.error && "wr:border-danger wr:focus-visible:ring-danger/40",
); );
const containerId = `pf-${Math.random().toString(36).slice(2)}`; const containerId = `pf-${Math.random().toString(36).slice(2)}`;
@@ -104,7 +104,7 @@ const showChecklist = p.showChecklist ?? true;
<button <button
type="button" type="button"
aria-label="Toggle password" aria-label="Toggle password"
class="wr:absolute wr:inset-y-0 wr:right-0 wr:pr-3 wr:flex wr:items-center wr:text-muted-foreground hover:wr:text-foreground wr:z-20" class="wr:absolute wr:inset-y-0 wr:right-0 wr:pr-3 wr:flex wr:items-center wr:text-muted-foreground wr:hover:text-foreground wr:z-20"
onclick={`const i = this.previousElementSibling; i.type = i.type === 'password' ? 'text' : 'password';`} onclick={`const i = this.previousElementSibling; i.type = i.type === 'password' ? 'text' : 'password';`}
tabindex="-1" tabindex="-1"
> >
@@ -202,7 +202,7 @@ const showChecklist = p.showChecklist ?? true;
p.description && ( p.description && (
<p <p
id={descId} id={descId}
class="wr:text-sm wr:text-gray-500 dark:wr:text-neutral-500" class="wr:text-sm wr:text-gray-500 wr:dark:text-neutral-500"
> >
{p.description} {p.description}
</p> </p>
+11 -11
View File
@@ -64,7 +64,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<input <input
type="text" type="text"
id={`${fieldId}-display`} id={`${fieldId}-display`}
class="wr:w-full wr:px-3 wr:py-2 wr:pr-10 wr:border wr:border-border wr:rounded-lg wr:bg-background wr:text-foreground focus:wr:ring-2 focus:wr:ring-primary focus:wr:border-primary disabled:wr:opacity-50" class="wr:w-full wr:px-3 wr:py-2 wr:pr-10 wr:border wr:border-border wr:rounded-lg wr:bg-background wr:text-foreground wr:focus:ring-2 wr:focus:ring-primary wr:focus:border-primary wr:disabled:opacity-50"
placeholder={placeholder} placeholder={placeholder}
readonly readonly
disabled={disabled} disabled={disabled}
@@ -75,7 +75,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<button <button
type="button" type="button"
id={`${fieldId}-trigger`} id={`${fieldId}-trigger`}
class="wr:absolute wr:right-0 wr:top-0 wr:h-full wr:px-3 wr:flex wr:items-center wr:text-muted-foreground hover:wr:text-foreground disabled:wr:opacity-50" class="wr:absolute wr:right-0 wr:top-0 wr:h-full wr:px-3 wr:flex wr:items-center wr:text-muted-foreground wr:hover:text-foreground wr:disabled:opacity-50"
disabled={disabled} disabled={disabled}
aria-label="Open time picker" aria-label="Open time picker"
> >
@@ -107,7 +107,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
> >
<select <select
id={`${fieldId}-hour`} id={`${fieldId}-hour`}
class="wr:w-full wr:px-2 wr:py-1 wr:text-center wr:border wr:border-border wr:rounded focus:wr:ring-1 focus:wr:ring-primary focus:wr:border-primary wr:bg-background" class="wr:w-full wr:px-2 wr:py-1 wr:text-center wr:border wr:border-border wr:rounded wr:focus:ring-1 wr:focus:ring-primary wr:focus:border-primary wr:bg-background"
></select> ></select>
</div> </div>
@@ -124,7 +124,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
> >
<select <select
id={`${fieldId}-minute`} id={`${fieldId}-minute`}
class="wr:w-full wr:px-2 wr:py-1 wr:text-center wr:border wr:border-border wr:rounded focus:wr:ring-1 focus:wr:ring-primary focus:wr:border-primary wr:bg-background" class="wr:w-full wr:px-2 wr:py-1 wr:text-center wr:border wr:border-border wr:rounded wr:focus:ring-1 wr:focus:ring-primary wr:focus:border-primary wr:bg-background"
></select> ></select>
</div> </div>
@@ -136,7 +136,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
</label> </label>
<select <select
id={`${fieldId}-period`} id={`${fieldId}-period`}
class="wr:w-full wr:px-2 wr:py-1 wr:border wr:border-border wr:rounded focus:wr:ring-1 focus:wr:ring-primary focus:wr:border-primary wr:bg-background" class="wr:w-full wr:px-2 wr:py-1 wr:border wr:border-border wr:rounded wr:focus:ring-1 wr:focus:ring-primary wr:focus:border-primary wr:bg-background"
> >
<option value="AM">AM</option> <option value="AM">AM</option>
<option value="PM">PM</option> <option value="PM">PM</option>
@@ -149,17 +149,17 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<div class="wr:grid wr:grid-cols-3 wr:gap-1 wr:mb-4"> <div class="wr:grid wr:grid-cols-3 wr:gap-1 wr:mb-4">
<button <button
type="button" type="button"
class="wr:px-2 wr:py-1 wr:text-xs wr:bg-muted wr:rounded hover:wr:bg-muted/80" class="wr:px-2 wr:py-1 wr:text-xs wr:bg-muted wr:rounded wr:hover:bg-muted/80"
data-time="09:00">9:00</button data-time="09:00">9:00</button
> >
<button <button
type="button" type="button"
class="wr:px-2 wr:py-1 wr:text-xs wr:bg-muted wr:rounded hover:wr:bg-muted/80" class="wr:px-2 wr:py-1 wr:text-xs wr:bg-muted wr:rounded wr:hover:bg-muted/80"
data-time="12:00">12:00</button data-time="12:00">12:00</button
> >
<button <button
type="button" type="button"
class="wr:px-2 wr:py-1 wr:text-xs wr:bg-muted wr:rounded hover:wr:bg-muted/80" class="wr:px-2 wr:py-1 wr:text-xs wr:bg-muted wr:rounded wr:hover:bg-muted/80"
data-time="17:00">17:00</button data-time="17:00">17:00</button
> >
</div> </div>
@@ -168,7 +168,7 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<button <button
type="button" type="button"
id={`${fieldId}-now`} id={`${fieldId}-now`}
class="wr:px-3 wr:py-1 wr:text-sm wr:text-primary hover:wr:bg-primary/10 wr:rounded" class="wr:px-3 wr:py-1 wr:text-sm wr:text-primary wr:hover:bg-primary/10 wr:rounded"
> >
Now Now
</button> </button>
@@ -176,14 +176,14 @@ const fieldId = `field-${name.replace(/[[\]]/g, "-")}`;
<button <button
type="button" type="button"
id={`${fieldId}-cancel`} id={`${fieldId}-cancel`}
class="wr:px-3 wr:py-1 wr:text-sm wr:text-muted-foreground hover:wr:bg-muted wr:rounded" class="wr:px-3 wr:py-1 wr:text-sm wr:text-muted-foreground wr:hover:bg-muted wr:rounded"
> >
Cancel Cancel
</button> </button>
<button <button
type="button" type="button"
id={`${fieldId}-apply`} id={`${fieldId}-apply`}
class="wr:px-3 wr:py-1 wr:text-sm wr:bg-primary wr:text-primary-foreground hover:wr:bg-primary/90 wr:rounded" class="wr:px-3 wr:py-1 wr:text-sm wr:bg-primary wr:text-primary-foreground wr:hover:bg-primary/90 wr:rounded"
> >
Apply Apply
</button> </button>
+3
View File
@@ -53,6 +53,9 @@ import Base from "./Base.astro";
<li class="list-item"> <li class="list-item">
<a href="/dropdown">Dropdown</a> <a href="/dropdown">Dropdown</a>
</li> </li>
<li class="list-item">
<a href="/drawer">Drawer</a>
</li>
</ul> </ul>
</div> </div>
+308
View File
@@ -0,0 +1,308 @@
---
import Drawer from "../components/Drawer.astro";
import ComponentLayout from "../layouts/ComponentLayout.astro";
---
<ComponentLayout>
<Drawer
position="right"
size="400px"
overlay={true}
closeOnOverlayClick={false}
id="first-drawer"
>
<button
slot="trigger"
class="wr:px-4 wr:py-2 wr:bg-primary wr:text-primary-foreground wr:rounded-lg"
>
Open Settings
</button>
<div slot="title">
<h2 class="wr:text-xl wr:font-bold">Settings</h2>
</div>
<div class="wr:space-y-4">
<div>
<label class="wr:block wr:text-sm wr:font-medium wr:mb-2"
>Theme</label
>
<select
class="wr:w-full wr:px-3 wr:py-2 wr:border wr:border-border wr:rounded-lg"
>
<option>Light</option>
<option>Dark</option>
<option>System</option>
</select>
</div>
<div>
<label class="wr:block wr:text-sm wr:font-medium wr:mb-2"
>Language</label
>
<select
class="wr:w-full wr:px-3 wr:py-2 wr:border wr:border-border wr:rounded-lg"
>
<option>English</option>
<option>Spanish</option>
<option>French</option>
</select>
</div>
</div>
<div
slot="footer"
class="wr:p-4 wr:border-t wr:border-border wr:flex wr:gap-2 wr:justify-end"
>
<button
type="button"
id="cancle-button"
class="wr:px-4 wr:py-2 wr:text-muted-foreground wr:rounded-lg hover:wr:bg-muted"
>Cancel</button
>
<button
class="wr:px-4 wr:py-2 wr:bg-primary wr:text-primary-foreground wr:rounded-lg"
>Save</button
>
</div>
</Drawer>
<Drawer position="left" size="280px" id="nav-drawer">
<div slot="trigger">
<button class="wr:p-2 wr:rounded-lg wr:hover:wr:bg-muted">
<svg
class="wr:w-6 wr:h-6"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
>
<line x1="3" y1="6" x2="21" y2="6"></line>
<line x1="3" y1="12" x2="21" y2="12"></line>
<line x1="3" y1="18" x2="21" y2="18"></line>
</svg>
</button>
</div>
<div slot="title">
<h2 class="wr:text-lg wr:font-bold">Navigation</h2>
</div>
<nav class="wr:space-y-1">
<a
href="/"
class="wr:flex wr:items-center wr:gap-3 wr:px-3 wr:py-2 wr:rounded-lg wr:hover:wr:bg-muted"
>
<svg
class="wr:w-5 wr:h-5"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
>
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"
></path>
</svg>
Home
</a>
<a
href="/about"
class="wr:flex wr:items-center wr:gap-3 wr:px-3 wr:py-2 wr:rounded-lg wr:hover:wr:bg-muted"
>
<svg
class="wr:w-5 wr:h-5"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
>
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
About
</a>
<a
href="/contact"
class="wr:flex wr:items-center wr:gap-3 wr:px-3 wr:py-2 wr:rounded-lg wr:hover:wr:bg-muted"
>
<svg
class="wr:w-5 wr:h-5"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
>
<path
d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2-2z"
></path>
<polyline points="22,6 12,13 2,6"></polyline>
</svg>
Contact
</a>
</nav>
</Drawer>
<Drawer
position="top"
size="200px"
overlay={false}
animationDuration={400}
blurBackground={true}
>
<div slot="trigger">
<button
class="wr:relative wr:p-2 wr:rounded-lg wr:hover:wr:bg-muted"
>
<svg
class="wr:w-6 wr:h-6"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
>
<path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"></path>
<path d="m13.73 21a2 2 0 0 1-3.46 0"></path>
</svg>
<span
class="wr:absolute wr:-top-1 wr:-right-1 wr:w-3 wr:h-3 wr:bg-danger wr:rounded-full"
></span>
</button>
</div>
<div slot="title">
<h3 class="wr:text-lg wr:font-semibold">Notifications</h3>
</div>
<div class="wr:space-y-3">
<div class="wr:p-3 wr:border wr:border-border wr:rounded-lg">
<h4 class="wr:font-medium wr:text-sm">New message from John</h4>
<p class="wr:text-xs wr:text-muted-foreground wr:mt-1">
5 minutes ago
</p>
</div>
<div class="wr:p-3 wr:border wr:border-border wr:rounded-lg">
<h4 class="wr:font-medium wr:text-sm">
System update available
</h4>
<p class="wr:text-xs wr:text-muted-foreground wr:mt-1">
1 hour ago
</p>
</div>
</div>
</Drawer>
<Drawer
position="right"
size="50vw"
persistent={false}
lockScroll={true}
showCloseButton={false}
id="advanced-drawer"
>
<div slot="trigger">
<button
class="wr:px-6 wr:py-3 wr:bg-secondary wr:text-secondary-foreground wr:rounded-lg wr:font-medium"
>
Open Advanced Drawer
</button>
</div>
<div slot="title">
<div class="wr:flex wr:items-center wr:gap-2">
<svg
class="wr:w-5 wr:h-5"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
>
<path
d="M12 2L2 7v10c0 5.55 3.84 9.74 9 11 5.16-1.26 9-5.45 9-11V7l-10-5z"
></path>
</svg>
<span class="wr:text-lg wr:font-semibold"
>Advanced Settings</span
>
</div>
</div>
<div class="wr:space-y-6">
<section>
<h3 class="wr:text-base wr:font-semibold wr:mb-3">Security</h3>
<div class="wr:space-y-3">
<label class="wr:flex wr:items-center wr:gap-2">
<input
type="checkbox"
class="wr:rounded wr:border-border"
/>
<span class="wr:text-sm">Two-factor authentication</span
>
</label>
<label class="wr:flex wr:items-center wr:gap-2">
<input
type="checkbox"
class="wr:rounded wr:border-border"
/>
<span class="wr:text-sm">Login notifications</span>
</label>
</div>
</section>
<section>
<h3 class="wr:text-base wr:font-semibold wr:mb-3">Privacy</h3>
<div class="wr:space-y-3">
<label class="wr:flex wr:items-center wr:gap-2">
<input
type="checkbox"
class="wr:rounded wr:border-border"
/>
<span class="wr:text-sm">Allow analytics</span>
</label>
<label class="wr:flex wr:items-center wr:gap-2">
<input
type="checkbox"
class="wr:rounded wr:border-border"
/>
<span class="wr:text-sm">Share usage data</span>
</label>
</div>
</section>
</div>
<div
slot="footer"
class="wr:p-4 wr:border-t wr:border-border wr:flex wr:gap-3 wr:justify-end"
>
<button
class="wr:px-4 wr:py-2 wr:text-muted-foreground wr:rounded-lg wr:border wr:border-border hover:wr:bg-muted"
>
Reset
</button>
<button
class="wr:px-4 wr:py-2 wr:bg-primary wr:text-primary-foreground wr:rounded-lg wr:font-medium"
>
Apply Changes
</button>
</div>
</Drawer>
</ComponentLayout>
<script>
// Listen to drawer events
document.addEventListener("drawer:opened", (e) => {
console.log("Drawer opened:", e.detail.drawerId);
});
document.addEventListener("drawer:closed", (e) => {
console.log("Drawer closed:", e.detail.drawerId);
});
// Programmatic control
document.addEventListener("DOMContentLoaded", () => {
const advancedDrawer = window.drawer_advanced_drawer;
// You can control the drawer programmatically
advancedDrawer.open();
// advancedDrawer.close();
// advancedDrawer.toggle();
});
const cancelButton = document.getElementById("cancle-button");
cancelButton?.addEventListener("click", () => {
const advancedDrawer = window.drawer_first_drawer;
advancedDrawer.close();
});
</script>