arekui 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +198 -198
  3. package/arekui.css +3279 -3279
  4. package/arekui.d.ts +328 -328
  5. package/arekui.js +450 -450
  6. package/package.json +59 -57
  7. package/scripts/build-custom.js +318 -318
  8. package/src/arekui.css +55 -55
  9. package/src/base/neo-overrides.css +317 -317
  10. package/src/base/reset.css +67 -67
  11. package/src/base/tokens.css +304 -304
  12. package/src/components/accordion.css +34 -34
  13. package/src/components/alert.css +26 -26
  14. package/src/components/badge.css +33 -33
  15. package/src/components/breadcrumb.css +33 -33
  16. package/src/components/button.css +103 -103
  17. package/src/components/card.css +24 -24
  18. package/src/components/carousel.css +14 -14
  19. package/src/components/chat.css +78 -78
  20. package/src/components/drawer.css +53 -53
  21. package/src/components/file-upload.css +51 -51
  22. package/src/components/footer.css +26 -26
  23. package/src/components/forms.css +69 -69
  24. package/src/components/hero.css +22 -22
  25. package/src/components/join.css +14 -14
  26. package/src/components/link.css +24 -24
  27. package/src/components/menu.css +56 -56
  28. package/src/components/misc.css +57 -57
  29. package/src/components/modal.css +32 -32
  30. package/src/components/navbar.css +37 -37
  31. package/src/components/pagination.css +46 -46
  32. package/src/components/popover.css +70 -70
  33. package/src/components/progress.css +19 -19
  34. package/src/components/prose.css +80 -80
  35. package/src/components/rating.css +37 -37
  36. package/src/components/scroll-top.css +36 -36
  37. package/src/components/skeleton.css +54 -54
  38. package/src/components/swap.css +45 -45
  39. package/src/components/table.css +22 -22
  40. package/src/components/tabs.css +24 -24
  41. package/src/components/tag.css +101 -101
  42. package/src/components/textured.css +34 -34
  43. package/src/components/timeline.css +34 -34
  44. package/src/components/toast.css +134 -134
  45. package/src/components/tooltip.css +24 -24
  46. package/src/utilities/borders.css +152 -152
  47. package/src/utilities/colors.css +73 -73
  48. package/src/utilities/hover.css +33 -33
  49. package/src/utilities/layout.css +100 -100
  50. package/src/utilities/neo-utilities.css +95 -95
  51. package/src/utilities/responsive.css +128 -128
  52. package/src/utilities/sizing.css +91 -91
  53. package/src/utilities/spacing.css +130 -130
  54. package/src/utilities/typography.css +94 -94
package/arekui.js CHANGED
@@ -1,450 +1,450 @@
1
- /*!
2
- * Arekui v1.0.0 — optional vanilla JS (no dependencies).
3
- * data-ar-* driven behaviors: theme toggle, modal, drawer, tabs, dropdown, accordion, toast, rating, popover, file upload, scroll-to-top.
4
- */
5
- (() => {
6
- var STORAGE_KEY = "arekui-theme";
7
-
8
- var THEMES_LIGHT_DARK = ["light", "dark"];
9
- var THEMES_DEFAULT_NEO = ["light", "neo"];
10
-
11
- function getTheme() {
12
- return document.documentElement.getAttribute("data-theme");
13
- }
14
-
15
- function setTheme(theme) {
16
- document.documentElement.setAttribute("data-theme", theme);
17
- document.documentElement.classList.toggle("dark", theme === "dark");
18
- }
19
-
20
- function initTheme() {
21
- var stored = localStorage.getItem(STORAGE_KEY);
22
- var allThemes = THEMES_LIGHT_DARK.concat(THEMES_DEFAULT_NEO);
23
- if (stored && allThemes.indexOf(stored) !== -1) {
24
- setTheme(stored);
25
- } else {
26
- var prefersDark = window.matchMedia(
27
- "(prefers-color-scheme: dark)",
28
- ).matches;
29
- setTheme(prefersDark ? "dark" : "light");
30
- }
31
- }
32
-
33
- function syncToggles() {
34
- var current = getTheme();
35
- document.querySelectorAll("[data-ar-theme-toggle]").forEach((el) => {
36
- if (el.matches('input[type="checkbox"]')) {
37
- el.checked = current === "dark";
38
- } else {
39
- el.setAttribute("aria-pressed", String(current === "dark"));
40
- }
41
- });
42
- document.querySelectorAll("[data-ar-neo-toggle]").forEach((el) => {
43
- var isNeo = current === "neo";
44
- if (el.matches('input[type="checkbox"]')) {
45
- el.checked = isNeo;
46
- } else {
47
- el.setAttribute("aria-pressed", String(isNeo));
48
- el.textContent = isNeo ? "Default" : "Neo";
49
- }
50
- });
51
- }
52
-
53
- function initThemeToggle() {
54
- document.addEventListener("click", (e) => {
55
- var toggle = e.target.closest("[data-ar-theme-toggle]");
56
- if (!toggle) return;
57
- var current = getTheme() || "light";
58
- var idx = THEMES_LIGHT_DARK.indexOf(current);
59
- var next = THEMES_LIGHT_DARK[(idx + 1) % THEMES_LIGHT_DARK.length];
60
- setTheme(next);
61
- localStorage.setItem(STORAGE_KEY, next);
62
- syncToggles();
63
- });
64
- }
65
-
66
- function initNeoToggle() {
67
- document.addEventListener("click", (e) => {
68
- var toggle = e.target.closest("[data-ar-neo-toggle]");
69
- if (!toggle) return;
70
- var current = getTheme() || "light";
71
- var idx = THEMES_DEFAULT_NEO.indexOf(current);
72
- var next = THEMES_DEFAULT_NEO[(idx + 1) % THEMES_DEFAULT_NEO.length];
73
- setTheme(next);
74
- localStorage.setItem(STORAGE_KEY, next);
75
- syncToggles();
76
- });
77
- }
78
-
79
- function initModals() {
80
- document.querySelectorAll("[data-ar-open]").forEach((opener) => {
81
- opener.addEventListener("click", (e) => {
82
- e.preventDefault();
83
- var target = document.getElementById(
84
- opener.getAttribute("data-ar-open"),
85
- );
86
- if (target && typeof target.showModal === "function")
87
- target.showModal();
88
- });
89
- });
90
- document.querySelectorAll("[data-ar-close]").forEach((closer) => {
91
- closer.addEventListener("click", () => {
92
- var modal = closer.closest("dialog");
93
- if (modal && typeof modal.close === "function") modal.close();
94
- });
95
- });
96
- document
97
- .querySelectorAll("dialog[data-ar-backdrop-close]")
98
- .forEach((modal) => {
99
- modal.addEventListener("click", (e) => {
100
- if (e.target === modal) modal.close();
101
- });
102
- });
103
- }
104
-
105
- function initDrawers() {
106
- document.querySelectorAll("[data-ar-drawer-toggle]").forEach((btn) => {
107
- btn.addEventListener("click", () => {
108
- var id = btn.getAttribute("data-ar-drawer-toggle");
109
- var checkbox = document.getElementById(id);
110
- if (checkbox) checkbox.checked = !checkbox.checked;
111
- });
112
- });
113
- }
114
-
115
- function initTabs() {
116
- document.querySelectorAll("[data-ar-tab]").forEach((tab) => {
117
- tab.addEventListener("click", () => {
118
- var group = tab.closest(".ar-tabs");
119
- if (!group) return;
120
- group.querySelectorAll("[data-ar-tab]").forEach((t) => {
121
- t.classList.remove("ar-tab-active");
122
- });
123
- tab.classList.add("ar-tab-active");
124
- var panelId = tab.getAttribute("data-ar-tab");
125
- var groupPanel = group.getAttribute("data-ar-tabs-panel");
126
- if (groupPanel) {
127
- document.querySelectorAll("[" + groupPanel + "]").forEach((p) => {
128
- p.style.display = p.id === panelId ? "" : "none";
129
- });
130
- }
131
- });
132
- });
133
- }
134
-
135
- function closeDropdown(dropdown) {
136
- dropdown.classList.remove("ar-dropdown-open");
137
- var trigger = dropdown.querySelector(":scope > button, :scope > a");
138
- if (trigger) trigger.blur();
139
- }
140
-
141
- function initDropdowns() {
142
- document.querySelectorAll(".ar-dropdown").forEach((dropdown) => {
143
- var content = dropdown.querySelector(".ar-dropdown-content");
144
- if (!content) return;
145
-
146
- dropdown.addEventListener("click", (e) => {
147
- if (content.contains(e.target)) {
148
- closeDropdown(dropdown);
149
- return;
150
- }
151
- if (dropdown.classList.contains("ar-dropdown-open")) {
152
- closeDropdown(dropdown);
153
- } else {
154
- dropdown.classList.add("ar-dropdown-open");
155
- }
156
- });
157
- });
158
-
159
- document.addEventListener("click", (e) => {
160
- document
161
- .querySelectorAll(".ar-dropdown.ar-dropdown-open")
162
- .forEach((dd) => {
163
- if (!dd.contains(e.target)) dd.classList.remove("ar-dropdown-open");
164
- });
165
- });
166
-
167
- document.addEventListener("keydown", (e) => {
168
- if (e.key === "Escape") {
169
- document
170
- .querySelectorAll(".ar-dropdown.ar-dropdown-open")
171
- .forEach(closeDropdown);
172
- }
173
- });
174
- }
175
-
176
- function initAccordion() {
177
- document.querySelectorAll(".ar-accordion details").forEach((d) => {
178
- var first = d.querySelector("summary");
179
- if (first)
180
- first.addEventListener("click", () => {
181
- if (d.getAttribute("data-ar-exclusive") !== null) return;
182
- var parent = d.closest(".ar-accordion");
183
- if (!parent) return;
184
- parent.querySelectorAll("details[open]").forEach((other) => {
185
- if (other !== d) other.removeAttribute("open");
186
- });
187
- });
188
- });
189
- }
190
-
191
- var toastContainers = {};
192
-
193
- function getToastContainer(position) {
194
- if (toastContainers[position]) return toastContainers[position];
195
- var container = document.createElement("div");
196
- container.className = "ar-toast-container";
197
- container.setAttribute("data-ar-toast-position", position);
198
- document.body.appendChild(container);
199
- toastContainers[position] = container;
200
- return container;
201
- }
202
-
203
- function toast(message, options) {
204
- var opts = options || {};
205
- var type = opts.type || "";
206
- var duration = typeof opts.duration === "number" ? opts.duration : 4000;
207
- var position = opts.position || "top-right";
208
- var closable = opts.closable !== false;
209
- var icon = opts.icon || null;
210
-
211
- var container = getToastContainer(position);
212
- var el = document.createElement("div");
213
- el.className = "ar-toast" + (type ? " ar-toast-" + type : "");
214
- el.style.position = "relative";
215
-
216
- if (icon) {
217
- var iconEl = document.createElement("span");
218
- iconEl.className = "ar-toast-icon";
219
- iconEl.textContent = icon;
220
- el.appendChild(iconEl);
221
- }
222
-
223
- var msgEl = document.createElement("span");
224
- msgEl.className = "ar-toast-message";
225
- msgEl.textContent = message;
226
- el.appendChild(msgEl);
227
-
228
- if (closable) {
229
- var closeBtn = document.createElement("button");
230
- closeBtn.className = "ar-toast-close";
231
- closeBtn.textContent = "\u2715";
232
- closeBtn.setAttribute("aria-label", "Close");
233
- closeBtn.addEventListener("click", () => {
234
- dismissToast(el);
235
- });
236
- el.appendChild(closeBtn);
237
- }
238
-
239
- if (duration > 0) {
240
- var progress = document.createElement("div");
241
- progress.className = "ar-toast-progress";
242
- progress.style.animationDuration = duration + "ms";
243
- el.appendChild(progress);
244
- }
245
-
246
- container.appendChild(el);
247
-
248
- var timer;
249
- if (duration > 0) {
250
- timer = setTimeout(() => {
251
- dismissToast(el);
252
- }, duration);
253
- }
254
-
255
- el.addEventListener("mouseenter", () => {
256
- if (timer) clearTimeout(timer);
257
- if (el.querySelector(".ar-toast-progress")) {
258
- el.querySelector(".ar-toast-progress").style.animationPlayState =
259
- "paused";
260
- }
261
- });
262
- el.addEventListener("mouseleave", () => {
263
- if (duration > 0) {
264
- var remaining = duration * 0.3;
265
- timer = setTimeout(() => {
266
- dismissToast(el);
267
- }, remaining);
268
- if (el.querySelector(".ar-toast-progress")) {
269
- el.querySelector(".ar-toast-progress").style.animationPlayState =
270
- "running";
271
- }
272
- }
273
- });
274
-
275
- return el;
276
- }
277
-
278
- function dismissToast(el) {
279
- if (el.classList.contains("ar-toast-out")) return;
280
- el.classList.add("ar-toast-out");
281
- el.addEventListener("animationend", () => {
282
- el.remove();
283
- });
284
- }
285
-
286
- function initRatings() {
287
- document.querySelectorAll("[data-ar-rating]").forEach((group) => {
288
- var inputs = group.querySelectorAll("input");
289
- inputs.forEach((input) => {
290
- input.addEventListener("change", () => {
291
- var event = new CustomEvent("ar-rating-change", {
292
- detail: { value: Number(input.value) },
293
- bubbles: true,
294
- });
295
- group.dispatchEvent(event);
296
- });
297
- });
298
- });
299
- }
300
-
301
- function getRating(container) {
302
- var checked = container.querySelector("input:checked");
303
- return checked ? Number(checked.value) : 0;
304
- }
305
-
306
- function setRating(container, value) {
307
- var input = container.querySelector('input[value="' + value + '"]');
308
- if (input) {
309
- input.checked = true;
310
- input.dispatchEvent(new Event("change"));
311
- }
312
- }
313
-
314
- function initPopovers() {
315
- // Click toggle
316
- document.addEventListener("click", (e) => {
317
- var trigger = e.target.closest("[data-ar-popover]");
318
- if (trigger) {
319
- e.preventDefault();
320
- var id = trigger.getAttribute("data-ar-popover");
321
- var popover = id
322
- ? document.getElementById(id)
323
- : trigger.querySelector(".ar-popover-content");
324
- if (!popover) return;
325
- var wrapper =
326
- popover.closest(".ar-popover") || trigger.closest(".ar-popover");
327
- if (!wrapper) return;
328
- document.querySelectorAll(".ar-popover-open").forEach((p) => {
329
- if (p !== wrapper) p.classList.remove("ar-popover-open");
330
- });
331
- wrapper.classList.toggle("ar-popover-open");
332
- return;
333
- }
334
- if (!e.target.closest(".ar-popover")) {
335
- document.querySelectorAll(".ar-popover-open").forEach((p) => {
336
- p.classList.remove("ar-popover-open");
337
- });
338
- }
339
- });
340
- document.addEventListener("keydown", (e) => {
341
- if (e.key === "Escape") {
342
- document.querySelectorAll(".ar-popover-open").forEach((p) => {
343
- p.classList.remove("ar-popover-open");
344
- });
345
- }
346
- });
347
- }
348
-
349
- function openPopover(id) {
350
- var el = document.getElementById(id);
351
- if (el) {
352
- var wrapper = el.closest(".ar-popover");
353
- if (wrapper) wrapper.classList.add("ar-popover-open");
354
- }
355
- }
356
-
357
- function closePopover(id) {
358
- var el = document.getElementById(id);
359
- if (el) {
360
- var wrapper = el.closest(".ar-popover");
361
- if (wrapper) wrapper.classList.remove("ar-popover-open");
362
- }
363
- }
364
-
365
- function initFileUploads() {
366
- document.querySelectorAll(".ar-file-upload").forEach((zone) => {
367
- var input = zone.querySelector('input[type="file"]');
368
- if (!input) return;
369
- ["dragenter", "dragover"].forEach((evt) => {
370
- zone.addEventListener(evt, (e) => {
371
- e.preventDefault();
372
- zone.classList.add("ar-file-upload-dragover");
373
- });
374
- });
375
- ["dragleave", "drop"].forEach((evt) => {
376
- zone.addEventListener(evt, (e) => {
377
- e.preventDefault();
378
- zone.classList.remove("ar-file-upload-dragover");
379
- });
380
- });
381
- input.addEventListener("change", () => {
382
- var event = new CustomEvent("ar-file-change", {
383
- detail: { files: input.files },
384
- bubbles: true,
385
- });
386
- zone.dispatchEvent(event);
387
- });
388
- });
389
- }
390
-
391
- function initScrollTop() {
392
- var btns = document.querySelectorAll("[data-ar-scroll-top]");
393
- if (!btns.length) return;
394
-
395
- function toggle() {
396
- var show = window.scrollY > 300;
397
- btns.forEach((btn) => {
398
- btn.classList.toggle("ar-scroll-top-visible", show);
399
- });
400
- }
401
-
402
- window.addEventListener("scroll", toggle, { passive: true });
403
- toggle();
404
-
405
- btns.forEach((btn) => {
406
- btn.addEventListener("click", () => {
407
- window.scrollTo({ top: 0, behavior: "smooth" });
408
- });
409
- });
410
- }
411
-
412
- function init() {
413
- if (document.readyState === "loading") {
414
- document.addEventListener("DOMContentLoaded", ready);
415
- } else {
416
- ready();
417
- }
418
- }
419
-
420
- function ready() {
421
- if (!getTheme()) initTheme();
422
- syncToggles();
423
- initThemeToggle();
424
- initNeoToggle();
425
- initModals();
426
- initDrawers();
427
- initTabs();
428
- initDropdowns();
429
- initAccordion();
430
- initRatings();
431
- initPopovers();
432
- initFileUploads();
433
- initScrollTop();
434
- }
435
-
436
- window.ARStyle = {
437
- setTheme: setTheme,
438
- getTheme: getTheme,
439
- initTheme: initTheme,
440
- init: init,
441
- toast: toast,
442
- dismissToast: dismissToast,
443
- getRating: getRating,
444
- setRating: setRating,
445
- openPopover: openPopover,
446
- closePopover: closePopover,
447
- };
448
-
449
- init();
450
- })();
1
+ /*!
2
+ * Arekui v1.0.0 — optional vanilla JS (no dependencies).
3
+ * data-ar-* driven behaviors: theme toggle, modal, drawer, tabs, dropdown, accordion, toast, rating, popover, file upload, scroll-to-top.
4
+ */
5
+ (() => {
6
+ var STORAGE_KEY = "arekui-theme";
7
+
8
+ var THEMES_LIGHT_DARK = ["light", "dark"];
9
+ var THEMES_DEFAULT_NEO = ["light", "neo"];
10
+
11
+ function getTheme() {
12
+ return document.documentElement.getAttribute("data-theme");
13
+ }
14
+
15
+ function setTheme(theme) {
16
+ document.documentElement.setAttribute("data-theme", theme);
17
+ document.documentElement.classList.toggle("dark", theme === "dark");
18
+ }
19
+
20
+ function initTheme() {
21
+ var stored = localStorage.getItem(STORAGE_KEY);
22
+ var allThemes = THEMES_LIGHT_DARK.concat(THEMES_DEFAULT_NEO);
23
+ if (stored && allThemes.indexOf(stored) !== -1) {
24
+ setTheme(stored);
25
+ } else {
26
+ var prefersDark = window.matchMedia(
27
+ "(prefers-color-scheme: dark)",
28
+ ).matches;
29
+ setTheme(prefersDark ? "dark" : "light");
30
+ }
31
+ }
32
+
33
+ function syncToggles() {
34
+ var current = getTheme();
35
+ document.querySelectorAll("[data-ar-theme-toggle]").forEach((el) => {
36
+ if (el.matches('input[type="checkbox"]')) {
37
+ el.checked = current === "dark";
38
+ } else {
39
+ el.setAttribute("aria-pressed", String(current === "dark"));
40
+ }
41
+ });
42
+ document.querySelectorAll("[data-ar-neo-toggle]").forEach((el) => {
43
+ var isNeo = current === "neo";
44
+ if (el.matches('input[type="checkbox"]')) {
45
+ el.checked = isNeo;
46
+ } else {
47
+ el.setAttribute("aria-pressed", String(isNeo));
48
+ el.textContent = isNeo ? "Default" : "Neo";
49
+ }
50
+ });
51
+ }
52
+
53
+ function initThemeToggle() {
54
+ document.addEventListener("click", (e) => {
55
+ var toggle = e.target.closest("[data-ar-theme-toggle]");
56
+ if (!toggle) return;
57
+ var current = getTheme() || "light";
58
+ var idx = THEMES_LIGHT_DARK.indexOf(current);
59
+ var next = THEMES_LIGHT_DARK[(idx + 1) % THEMES_LIGHT_DARK.length];
60
+ setTheme(next);
61
+ localStorage.setItem(STORAGE_KEY, next);
62
+ syncToggles();
63
+ });
64
+ }
65
+
66
+ function initNeoToggle() {
67
+ document.addEventListener("click", (e) => {
68
+ var toggle = e.target.closest("[data-ar-neo-toggle]");
69
+ if (!toggle) return;
70
+ var current = getTheme() || "light";
71
+ var idx = THEMES_DEFAULT_NEO.indexOf(current);
72
+ var next = THEMES_DEFAULT_NEO[(idx + 1) % THEMES_DEFAULT_NEO.length];
73
+ setTheme(next);
74
+ localStorage.setItem(STORAGE_KEY, next);
75
+ syncToggles();
76
+ });
77
+ }
78
+
79
+ function initModals() {
80
+ document.querySelectorAll("[data-ar-open]").forEach((opener) => {
81
+ opener.addEventListener("click", (e) => {
82
+ e.preventDefault();
83
+ var target = document.getElementById(
84
+ opener.getAttribute("data-ar-open"),
85
+ );
86
+ if (target && typeof target.showModal === "function")
87
+ target.showModal();
88
+ });
89
+ });
90
+ document.querySelectorAll("[data-ar-close]").forEach((closer) => {
91
+ closer.addEventListener("click", () => {
92
+ var modal = closer.closest("dialog");
93
+ if (modal && typeof modal.close === "function") modal.close();
94
+ });
95
+ });
96
+ document
97
+ .querySelectorAll("dialog[data-ar-backdrop-close]")
98
+ .forEach((modal) => {
99
+ modal.addEventListener("click", (e) => {
100
+ if (e.target === modal) modal.close();
101
+ });
102
+ });
103
+ }
104
+
105
+ function initDrawers() {
106
+ document.querySelectorAll("[data-ar-drawer-toggle]").forEach((btn) => {
107
+ btn.addEventListener("click", () => {
108
+ var id = btn.getAttribute("data-ar-drawer-toggle");
109
+ var checkbox = document.getElementById(id);
110
+ if (checkbox) checkbox.checked = !checkbox.checked;
111
+ });
112
+ });
113
+ }
114
+
115
+ function initTabs() {
116
+ document.querySelectorAll("[data-ar-tab]").forEach((tab) => {
117
+ tab.addEventListener("click", () => {
118
+ var group = tab.closest(".ar-tabs");
119
+ if (!group) return;
120
+ group.querySelectorAll("[data-ar-tab]").forEach((t) => {
121
+ t.classList.remove("ar-tab-active");
122
+ });
123
+ tab.classList.add("ar-tab-active");
124
+ var panelId = tab.getAttribute("data-ar-tab");
125
+ var groupPanel = group.getAttribute("data-ar-tabs-panel");
126
+ if (groupPanel) {
127
+ document.querySelectorAll("[" + groupPanel + "]").forEach((p) => {
128
+ p.style.display = p.id === panelId ? "" : "none";
129
+ });
130
+ }
131
+ });
132
+ });
133
+ }
134
+
135
+ function closeDropdown(dropdown) {
136
+ dropdown.classList.remove("ar-dropdown-open");
137
+ var trigger = dropdown.querySelector(":scope > button, :scope > a");
138
+ if (trigger) trigger.blur();
139
+ }
140
+
141
+ function initDropdowns() {
142
+ document.querySelectorAll(".ar-dropdown").forEach((dropdown) => {
143
+ var content = dropdown.querySelector(".ar-dropdown-content");
144
+ if (!content) return;
145
+
146
+ dropdown.addEventListener("click", (e) => {
147
+ if (content.contains(e.target)) {
148
+ closeDropdown(dropdown);
149
+ return;
150
+ }
151
+ if (dropdown.classList.contains("ar-dropdown-open")) {
152
+ closeDropdown(dropdown);
153
+ } else {
154
+ dropdown.classList.add("ar-dropdown-open");
155
+ }
156
+ });
157
+ });
158
+
159
+ document.addEventListener("click", (e) => {
160
+ document
161
+ .querySelectorAll(".ar-dropdown.ar-dropdown-open")
162
+ .forEach((dd) => {
163
+ if (!dd.contains(e.target)) dd.classList.remove("ar-dropdown-open");
164
+ });
165
+ });
166
+
167
+ document.addEventListener("keydown", (e) => {
168
+ if (e.key === "Escape") {
169
+ document
170
+ .querySelectorAll(".ar-dropdown.ar-dropdown-open")
171
+ .forEach(closeDropdown);
172
+ }
173
+ });
174
+ }
175
+
176
+ function initAccordion() {
177
+ document.querySelectorAll(".ar-accordion details").forEach((d) => {
178
+ var first = d.querySelector("summary");
179
+ if (first)
180
+ first.addEventListener("click", () => {
181
+ if (d.getAttribute("data-ar-exclusive") !== null) return;
182
+ var parent = d.closest(".ar-accordion");
183
+ if (!parent) return;
184
+ parent.querySelectorAll("details[open]").forEach((other) => {
185
+ if (other !== d) other.removeAttribute("open");
186
+ });
187
+ });
188
+ });
189
+ }
190
+
191
+ var toastContainers = {};
192
+
193
+ function getToastContainer(position) {
194
+ if (toastContainers[position]) return toastContainers[position];
195
+ var container = document.createElement("div");
196
+ container.className = "ar-toast-container";
197
+ container.setAttribute("data-ar-toast-position", position);
198
+ document.body.appendChild(container);
199
+ toastContainers[position] = container;
200
+ return container;
201
+ }
202
+
203
+ function toast(message, options) {
204
+ var opts = options || {};
205
+ var type = opts.type || "";
206
+ var duration = typeof opts.duration === "number" ? opts.duration : 4000;
207
+ var position = opts.position || "top-right";
208
+ var closable = opts.closable !== false;
209
+ var icon = opts.icon || null;
210
+
211
+ var container = getToastContainer(position);
212
+ var el = document.createElement("div");
213
+ el.className = "ar-toast" + (type ? " ar-toast-" + type : "");
214
+ el.style.position = "relative";
215
+
216
+ if (icon) {
217
+ var iconEl = document.createElement("span");
218
+ iconEl.className = "ar-toast-icon";
219
+ iconEl.textContent = icon;
220
+ el.appendChild(iconEl);
221
+ }
222
+
223
+ var msgEl = document.createElement("span");
224
+ msgEl.className = "ar-toast-message";
225
+ msgEl.textContent = message;
226
+ el.appendChild(msgEl);
227
+
228
+ if (closable) {
229
+ var closeBtn = document.createElement("button");
230
+ closeBtn.className = "ar-toast-close";
231
+ closeBtn.textContent = "\u2715";
232
+ closeBtn.setAttribute("aria-label", "Close");
233
+ closeBtn.addEventListener("click", () => {
234
+ dismissToast(el);
235
+ });
236
+ el.appendChild(closeBtn);
237
+ }
238
+
239
+ if (duration > 0) {
240
+ var progress = document.createElement("div");
241
+ progress.className = "ar-toast-progress";
242
+ progress.style.animationDuration = duration + "ms";
243
+ el.appendChild(progress);
244
+ }
245
+
246
+ container.appendChild(el);
247
+
248
+ var timer;
249
+ if (duration > 0) {
250
+ timer = setTimeout(() => {
251
+ dismissToast(el);
252
+ }, duration);
253
+ }
254
+
255
+ el.addEventListener("mouseenter", () => {
256
+ if (timer) clearTimeout(timer);
257
+ if (el.querySelector(".ar-toast-progress")) {
258
+ el.querySelector(".ar-toast-progress").style.animationPlayState =
259
+ "paused";
260
+ }
261
+ });
262
+ el.addEventListener("mouseleave", () => {
263
+ if (duration > 0) {
264
+ var remaining = duration * 0.3;
265
+ timer = setTimeout(() => {
266
+ dismissToast(el);
267
+ }, remaining);
268
+ if (el.querySelector(".ar-toast-progress")) {
269
+ el.querySelector(".ar-toast-progress").style.animationPlayState =
270
+ "running";
271
+ }
272
+ }
273
+ });
274
+
275
+ return el;
276
+ }
277
+
278
+ function dismissToast(el) {
279
+ if (el.classList.contains("ar-toast-out")) return;
280
+ el.classList.add("ar-toast-out");
281
+ el.addEventListener("animationend", () => {
282
+ el.remove();
283
+ });
284
+ }
285
+
286
+ function initRatings() {
287
+ document.querySelectorAll("[data-ar-rating]").forEach((group) => {
288
+ var inputs = group.querySelectorAll("input");
289
+ inputs.forEach((input) => {
290
+ input.addEventListener("change", () => {
291
+ var event = new CustomEvent("ar-rating-change", {
292
+ detail: { value: Number(input.value) },
293
+ bubbles: true,
294
+ });
295
+ group.dispatchEvent(event);
296
+ });
297
+ });
298
+ });
299
+ }
300
+
301
+ function getRating(container) {
302
+ var checked = container.querySelector("input:checked");
303
+ return checked ? Number(checked.value) : 0;
304
+ }
305
+
306
+ function setRating(container, value) {
307
+ var input = container.querySelector('input[value="' + value + '"]');
308
+ if (input) {
309
+ input.checked = true;
310
+ input.dispatchEvent(new Event("change"));
311
+ }
312
+ }
313
+
314
+ function initPopovers() {
315
+ // Click toggle
316
+ document.addEventListener("click", (e) => {
317
+ var trigger = e.target.closest("[data-ar-popover]");
318
+ if (trigger) {
319
+ e.preventDefault();
320
+ var id = trigger.getAttribute("data-ar-popover");
321
+ var popover = id
322
+ ? document.getElementById(id)
323
+ : trigger.querySelector(".ar-popover-content");
324
+ if (!popover) return;
325
+ var wrapper =
326
+ popover.closest(".ar-popover") || trigger.closest(".ar-popover");
327
+ if (!wrapper) return;
328
+ document.querySelectorAll(".ar-popover-open").forEach((p) => {
329
+ if (p !== wrapper) p.classList.remove("ar-popover-open");
330
+ });
331
+ wrapper.classList.toggle("ar-popover-open");
332
+ return;
333
+ }
334
+ if (!e.target.closest(".ar-popover")) {
335
+ document.querySelectorAll(".ar-popover-open").forEach((p) => {
336
+ p.classList.remove("ar-popover-open");
337
+ });
338
+ }
339
+ });
340
+ document.addEventListener("keydown", (e) => {
341
+ if (e.key === "Escape") {
342
+ document.querySelectorAll(".ar-popover-open").forEach((p) => {
343
+ p.classList.remove("ar-popover-open");
344
+ });
345
+ }
346
+ });
347
+ }
348
+
349
+ function openPopover(id) {
350
+ var el = document.getElementById(id);
351
+ if (el) {
352
+ var wrapper = el.closest(".ar-popover");
353
+ if (wrapper) wrapper.classList.add("ar-popover-open");
354
+ }
355
+ }
356
+
357
+ function closePopover(id) {
358
+ var el = document.getElementById(id);
359
+ if (el) {
360
+ var wrapper = el.closest(".ar-popover");
361
+ if (wrapper) wrapper.classList.remove("ar-popover-open");
362
+ }
363
+ }
364
+
365
+ function initFileUploads() {
366
+ document.querySelectorAll(".ar-file-upload").forEach((zone) => {
367
+ var input = zone.querySelector('input[type="file"]');
368
+ if (!input) return;
369
+ ["dragenter", "dragover"].forEach((evt) => {
370
+ zone.addEventListener(evt, (e) => {
371
+ e.preventDefault();
372
+ zone.classList.add("ar-file-upload-dragover");
373
+ });
374
+ });
375
+ ["dragleave", "drop"].forEach((evt) => {
376
+ zone.addEventListener(evt, (e) => {
377
+ e.preventDefault();
378
+ zone.classList.remove("ar-file-upload-dragover");
379
+ });
380
+ });
381
+ input.addEventListener("change", () => {
382
+ var event = new CustomEvent("ar-file-change", {
383
+ detail: { files: input.files },
384
+ bubbles: true,
385
+ });
386
+ zone.dispatchEvent(event);
387
+ });
388
+ });
389
+ }
390
+
391
+ function initScrollTop() {
392
+ var btns = document.querySelectorAll("[data-ar-scroll-top]");
393
+ if (!btns.length) return;
394
+
395
+ function toggle() {
396
+ var show = window.scrollY > 300;
397
+ btns.forEach((btn) => {
398
+ btn.classList.toggle("ar-scroll-top-visible", show);
399
+ });
400
+ }
401
+
402
+ window.addEventListener("scroll", toggle, { passive: true });
403
+ toggle();
404
+
405
+ btns.forEach((btn) => {
406
+ btn.addEventListener("click", () => {
407
+ window.scrollTo({ top: 0, behavior: "smooth" });
408
+ });
409
+ });
410
+ }
411
+
412
+ function init() {
413
+ if (document.readyState === "loading") {
414
+ document.addEventListener("DOMContentLoaded", ready);
415
+ } else {
416
+ ready();
417
+ }
418
+ }
419
+
420
+ function ready() {
421
+ if (!getTheme()) initTheme();
422
+ syncToggles();
423
+ initThemeToggle();
424
+ initNeoToggle();
425
+ initModals();
426
+ initDrawers();
427
+ initTabs();
428
+ initDropdowns();
429
+ initAccordion();
430
+ initRatings();
431
+ initPopovers();
432
+ initFileUploads();
433
+ initScrollTop();
434
+ }
435
+
436
+ window.ARStyle = {
437
+ setTheme: setTheme,
438
+ getTheme: getTheme,
439
+ initTheme: initTheme,
440
+ init: init,
441
+ toast: toast,
442
+ dismissToast: dismissToast,
443
+ getRating: getRating,
444
+ setRating: setRating,
445
+ openPopover: openPopover,
446
+ closePopover: closePopover,
447
+ };
448
+
449
+ init();
450
+ })();