PageSourceSearch

https://toolingmetrics.com/assets/controllers/drawer_controller-ace253de.js

js toolingmetrics.com collected 2026-10-06 08:52:19 UTC 3,958 bytes, 132 lines download raw bytes

1import { Controller } from "@hotwired/stimulus";
2
3const placements = {
4  top: {
5    base: ["top-0", "left-0", "right-0"],
6    active: ["transform-none"],
7    inactive: ["-translate-y-full"],
8  },
9  right: { base: ["right-0", "top-0"], active: ["transform-none"], inactive: ["translate-x-full"] },
10  bottom: {
11    base: ["bottom-0", "left-0", "right-0"],
12    active: ["transform-none"],
13    inactive: ["translate-y-full"],
14  },
15  left: { base: ["left-0", "top-0"], active: ["transform-none"], inactive: ["-translate-x-full"] },
16};
17
18export default class extends Controller {
19  connect() {
20    this.drawers = new Map();
21    this.handleKeydown = this.handleKeydown.bind(this);
22    document.addEventListener("keydown", this.handleKeydown);
23  }
24
25  disconnect() {
26    document.removeEventListener("keydown", this.handleKeydown);
27    this.drawers.forEach((drawer) => {
28      drawer.backdropElement?.remove();
29    });
30    document.body.classList.remove("overflow-hidden");
31  }
32
33  show(event) {
34    event.preventDefault();
35
36    const drawer = this.drawerFor(event.params);
37    if (!drawer || drawer.visible) return;
38
39    drawer.trigger = event.currentTarget;
40    drawer.panel.classList.add(...drawer.classes.active);
41    drawer.panel.classList.remove(...drawer.classes.inactive);
42    drawer.panel.setAttribute("aria-modal", "true");
43    drawer.panel.setAttribute("role", "dialog");
44    drawer.panel.removeAttribute("aria-hidden");
45    drawer.trigger.setAttribute("aria-expanded", "true");
46    drawer.visible = true;
47
48    if (!drawer.bodyScrolling) document.body.classList.add("overflow-hidden");
49    if (drawer.backdrop) this.createBackdrop(drawer);
50
51    drawer.panel.focus({ preventScroll: true });
52  }
53
54  hide(event) {
55    event.preventDefault();
56
57    const drawer = this.drawers.get(event.params.id);
58    if (drawer) this.hideDrawer(drawer);
59  }
60
61  toggle(event) {
62    const drawer = this.drawerFor(event.params);
63    if (!drawer) return;
64
65    drawer.visible ? this.hide(event) : this.show(event);
66  }
67
68  handleKeydown(event) {
69    if (event.key !== "Escape") return;
70
71    const drawer = [...this.drawers.values()].reverse().find(({ visible }) => visible);
72    if (drawer) this.hideDrawer(drawer);
73  }
74
75  drawerFor({ id, placement = "right", backdrop = true, bodyScrolling = false }) {
76    if (!id) return;
77
78    const existingDrawer = this.drawers.get(id);
79    if (existingDrawer) return existingDrawer;
80
81    const panel = document.getElementById(id);
82    if (!panel) return;
83
84    const classes = placements[placement] || placements.right;
85    const drawer = {
86      panel,
87      classes,
88      backdrop,
89      bodyScrolling,
90      visible: false,
91      trigger: null,
92      backdropElement: null,
93    };
94
95    panel.classList.add(...classes.base, ...classes.inactive);
96    panel.setAttribute("aria-hidden", "true");
97    this.drawers.set(id, drawer);
98
99    return drawer;
100  }
101
102  hideDrawer(drawer) {
103    if (!drawer.visible) return;
104
105    drawer.panel.classList.remove(...drawer.classes.active);
106    drawer.panel.classList.add(...drawer.classes.inactive);
107    drawer.panel.setAttribute("aria-hidden", "true");
108    drawer.panel.removeAttribute("aria-modal");
109    drawer.panel.removeAttribute("role");
110    drawer.trigger?.setAttribute("aria-expanded", "false");
111    drawer.backdropElement?.remove();
112    drawer.backdropElement = null;
113    drawer.visible = false;
114
115    if (
116      ![...this.drawers.values()].some(({ visible, bodyScrolling }) => visible && !bodyScrolling)
117    ) {
118      document.body.classList.remove("overflow-hidden");
119    }
120
121    drawer.trigger?.focus({ preventScroll: true });
122  }
123
124  createBackdrop(drawer) {
125    if (drawer.backdropElement) return;
126
127    drawer.backdropElement = document.createElement("div");
128    drawer.backdropElement.className = "fixed inset-0 z-30 bg-zinc-900/50 dark:bg-zinc-900/80";
129    drawer.backdropElement.addEventListener("click", () => this.hideDrawer(drawer));
130    document.body.appendChild(drawer.backdropElement);
131  }
132}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.