@alivecss/aliveui 1.2.0 → 1.3.1

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.
package/dist/runtime.js CHANGED
@@ -268,6 +268,79 @@ function wireMagnetic(el, root) {
268
268
  registerCleanup(root, moveCleanup);
269
269
  registerCleanup(root, leaveCleanup);
270
270
  }
271
+ function resetSceneAnimations(scene) {
272
+ const animated = scene.querySelectorAll(
273
+ '[class*="alive-enter"], [class*="alive-loop"], .alive-typewriter, .alive-typewriter-fast, .alive-typewriter-slow, .alive-word-reveal > *, .alive-kinetic-slam, .alive-metric-card, .alive-toast, .alive-badge-pulse, .alive-spotlight, .alive-code-block'
274
+ );
275
+ animated.forEach((el) => {
276
+ const saved = el.style.animationName;
277
+ el.style.animationName = "none";
278
+ void el.offsetHeight;
279
+ el.style.animationName = saved;
280
+ });
281
+ }
282
+ function wireVideoSequence(container, root) {
283
+ const scenes = [...container.querySelectorAll(":scope > [data-alive-scene]")];
284
+ if (scenes.length === 0) return;
285
+ const loop = container.hasAttribute("data-alive-loop");
286
+ let current = 0;
287
+ let timeoutId = null;
288
+ const containerEl = container;
289
+ if (getComputedStyle(containerEl).position === "static") {
290
+ containerEl.style.position = "relative";
291
+ }
292
+ containerEl.style.overflow = "hidden";
293
+ scenes.forEach((s) => {
294
+ s.style.position = "absolute";
295
+ s.style.inset = "0";
296
+ s.classList.remove("is-active");
297
+ });
298
+ function activate(index) {
299
+ const scene = scenes[index];
300
+ resetSceneAnimations(scene);
301
+ scene.classList.add("is-active");
302
+ scene.style.zIndex = "1";
303
+ }
304
+ function scheduleNext(fromIndex) {
305
+ const scene = scenes[fromIndex];
306
+ const duration = parseInt(scene.getAttribute("data-alive-duration") ?? "3000", 10);
307
+ timeoutId = setTimeout(() => {
308
+ const nextIndex = fromIndex + 1;
309
+ const toIndex = nextIndex >= scenes.length ? loop ? 0 : -1 : nextIndex;
310
+ if (toIndex === -1) return;
311
+ doTransition(fromIndex, toIndex);
312
+ }, duration);
313
+ }
314
+ function doTransition(fromIndex, toIndex) {
315
+ const outScene = scenes[fromIndex];
316
+ const inScene = scenes[toIndex];
317
+ const transType = outScene.getAttribute("data-alive-transition") ?? "fade";
318
+ const transDur = parseInt(outScene.getAttribute("data-alive-trans-duration") ?? "600", 10);
319
+ const outClass = `alive-transition-${transType}-out`;
320
+ const inClass = `alive-transition-${transType}-in`;
321
+ outScene.style.setProperty("--alive-tr-dur", `${transDur}ms`);
322
+ inScene.style.setProperty("--alive-tr-dur", `${transDur}ms`);
323
+ outScene.style.zIndex = "2";
324
+ outScene.classList.add(outClass);
325
+ inScene.style.zIndex = "1";
326
+ resetSceneAnimations(inScene);
327
+ inScene.classList.add("is-active", inClass);
328
+ timeoutId = setTimeout(() => {
329
+ outScene.classList.remove("is-active", outClass);
330
+ outScene.style.zIndex = "";
331
+ outScene.style.removeProperty("--alive-tr-dur");
332
+ inScene.classList.remove(inClass);
333
+ inScene.style.removeProperty("--alive-tr-dur");
334
+ current = toIndex;
335
+ scheduleNext(current);
336
+ }, transDur);
337
+ }
338
+ activate(current);
339
+ scheduleNext(current);
340
+ registerCleanup(root, () => {
341
+ if (timeoutId) clearTimeout(timeoutId);
342
+ });
343
+ }
271
344
  function init(root = document.documentElement) {
272
345
  root.querySelectorAll("[data-alive-accordion]").forEach((el) => wireAccordion(el, root));
273
346
  root.querySelectorAll("[data-alive-modal]").forEach((el) => wireModal(el, root));
@@ -278,6 +351,7 @@ function init(root = document.documentElement) {
278
351
  root.querySelectorAll("[data-alive-stagger]").forEach((el) => wireStagger(el));
279
352
  root.querySelectorAll("[data-alive-tilt]").forEach((el) => wireTilt(el, root));
280
353
  root.querySelectorAll("[data-alive-magnetic]").forEach((el) => wireMagnetic(el, root));
354
+ root.querySelectorAll("[data-alive-sequence]").forEach((el) => wireVideoSequence(el, root));
281
355
  }
282
356
  function destroy(root = document.documentElement) {
283
357
  const cleanups = cleanupRegistry.get(root) ?? [];
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/runtime.ts"],"sourcesContent":["/**\n * AliveUI Runtime\n *\n * Provides data-attribute-driven interactivity for accordion, modal, drawer,\n * dropdown, and tabs components — zero dependencies, ~2 KB.\n *\n * Usage:\n * import { init } from '@alivecss/aliveui/runtime'\n * init() // wire everything in document\n * init(myRootElement) // wire a subtree\n */\n\ntype Cleanup = () => void\n\nconst cleanupRegistry = new WeakMap<Element, Cleanup[]>()\n\nfunction registerCleanup(root: Element, fn: Cleanup): void {\n const existing = cleanupRegistry.get(root) ?? []\n existing.push(fn)\n cleanupRegistry.set(root, existing)\n}\n\nfunction addListener<K extends keyof HTMLElementEventMap>(\n el: EventTarget,\n type: K,\n handler: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): Cleanup {\n el.addEventListener(type, handler as EventListener, options)\n return () => el.removeEventListener(type, handler as EventListener, options)\n}\n\n// ── Accordion ─────────────────────────────────────────────────────────────────\n\nfunction wireAccordion(container: Element, root: Element): void {\n const triggers = container.querySelectorAll<HTMLElement>('[data-alive-trigger]')\n triggers.forEach(trigger => {\n const item = trigger.closest('[data-alive-accordion-item]') ?? trigger.parentElement\n if (!item) return\n\n const cleanup = addListener(trigger, 'click', () => {\n const isOpen = item.classList.contains('is-open')\n // Close all items if not multi-open\n if (!container.hasAttribute('data-alive-multi')) {\n container.querySelectorAll('[data-alive-accordion-item]').forEach(i => {\n i.classList.remove('is-open')\n i.querySelector('[data-alive-trigger]')?.setAttribute('aria-expanded', 'false')\n })\n }\n if (!isOpen) {\n item.classList.add('is-open')\n trigger.setAttribute('aria-expanded', 'true')\n }\n })\n registerCleanup(root, cleanup)\n })\n}\n\n// ── Modal ─────────────────────────────────────────────────────────────────────\n\nfunction wireModal(modal: Element, root: Element): void {\n const id = modal.getAttribute('data-alive-modal')\n if (!id) return\n\n // Open triggers\n const openers = document.querySelectorAll<HTMLElement>(`[data-alive-open=\"${id}\"]`)\n openers.forEach(opener => {\n const cleanup = addListener(opener, 'click', () => openModal(id))\n registerCleanup(root, cleanup)\n })\n\n // Close triggers inside the modal\n modal.querySelectorAll<HTMLElement>('[data-alive-close]').forEach(closer => {\n const cleanup = addListener(closer, 'click', () => closeModal(id))\n registerCleanup(root, cleanup)\n })\n\n // Backdrop click to close (click on the modal wrapper, not the content)\n const cleanup = addListener(modal, 'click', (e) => {\n if (e.target === modal) closeModal(id)\n })\n registerCleanup(root, cleanup)\n\n // ESC key\n const escCleanup = addListener(document, 'keydown', (e) => {\n if (e.key === 'Escape' && modal.classList.contains('is-open')) closeModal(id)\n })\n registerCleanup(root, escCleanup)\n}\n\nexport function openModal(id: string): void {\n const modal = document.querySelector<HTMLElement>(`[data-alive-modal=\"${id}\"]`)\n if (!modal) return\n modal.classList.add('is-open')\n modal.setAttribute('aria-hidden', 'false')\n document.body.style.overflow = 'hidden'\n // Focus first focusable element\n const focusable = modal.querySelector<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n )\n focusable?.focus()\n}\n\nexport function closeModal(id: string): void {\n const modal = document.querySelector<HTMLElement>(`[data-alive-modal=\"${id}\"]`)\n if (!modal) return\n modal.classList.remove('is-open')\n modal.setAttribute('aria-hidden', 'true')\n document.body.style.overflow = ''\n}\n\n// ── Drawer ────────────────────────────────────────────────────────────────────\n\nfunction wireDrawer(drawer: Element, root: Element): void {\n const id = drawer.getAttribute('data-alive-drawer')\n if (!id) return\n\n const openers = document.querySelectorAll<HTMLElement>(`[data-alive-open=\"${id}\"]`)\n openers.forEach(opener => {\n const cleanup = addListener(opener, 'click', () => openDrawer(id))\n registerCleanup(root, cleanup)\n })\n\n drawer.querySelectorAll<HTMLElement>('[data-alive-close]').forEach(closer => {\n const cleanup = addListener(closer, 'click', () => closeDrawer(id))\n registerCleanup(root, cleanup)\n })\n\n const backdropCleanup = addListener(drawer, 'click', (e) => {\n if (e.target === drawer) closeDrawer(id)\n })\n registerCleanup(root, backdropCleanup)\n\n const escCleanup = addListener(document, 'keydown', (e) => {\n if (e.key === 'Escape' && drawer.classList.contains('is-open')) closeDrawer(id)\n })\n registerCleanup(root, escCleanup)\n}\n\nexport function openDrawer(id: string): void {\n const drawer = document.querySelector<HTMLElement>(`[data-alive-drawer=\"${id}\"]`)\n if (!drawer) return\n drawer.classList.add('is-open')\n drawer.setAttribute('aria-hidden', 'false')\n document.body.style.overflow = 'hidden'\n}\n\nexport function closeDrawer(id: string): void {\n const drawer = document.querySelector<HTMLElement>(`[data-alive-drawer=\"${id}\"]`)\n if (!drawer) return\n drawer.classList.remove('is-open')\n drawer.setAttribute('aria-hidden', 'true')\n document.body.style.overflow = ''\n}\n\n// ── Dropdown ──────────────────────────────────────────────────────────────────\n\nfunction wireDropdown(container: Element, root: Element): void {\n const trigger = container.querySelector<HTMLElement>('[data-alive-trigger]')\n const menu = container.querySelector<HTMLElement>('[data-alive-dropdown-menu]')\n if (!trigger || !menu) return\n\n const toggleCleanup = addListener(trigger, 'click', (e) => {\n e.stopPropagation()\n toggleDropdown(container)\n })\n registerCleanup(root, toggleCleanup)\n\n // Close on outside click\n const outsideCleanup = addListener(document, 'click', (e) => {\n if (!container.contains(e.target as Node)) {\n menu.classList.remove('is-open')\n trigger.setAttribute('aria-expanded', 'false')\n }\n })\n registerCleanup(root, outsideCleanup)\n\n // Close on ESC\n const escCleanup = addListener(document, 'keydown', (e) => {\n if (e.key === 'Escape' && menu.classList.contains('is-open')) {\n menu.classList.remove('is-open')\n trigger.setAttribute('aria-expanded', 'false')\n trigger.focus()\n }\n })\n registerCleanup(root, escCleanup)\n}\n\nexport function toggleDropdown(container: Element): void {\n const trigger = container.querySelector<HTMLElement>('[data-alive-trigger]')\n const menu = container.querySelector<HTMLElement>('[data-alive-dropdown-menu]')\n if (!menu) return\n const isOpen = menu.classList.toggle('is-open')\n trigger?.setAttribute('aria-expanded', String(isOpen))\n if (isOpen) {\n // Focus first item\n menu.querySelector<HTMLElement>('[role=\"menuitem\"], button, a')?.focus()\n }\n}\n\n// ── Tabs ──────────────────────────────────────────────────────────────────────\n\nfunction wireTabs(container: Element, root: Element): void {\n const tabs = container.querySelectorAll<HTMLElement>('[data-alive-tab]')\n tabs.forEach(tab => {\n const cleanup = addListener(tab, 'click', () => {\n const panelId = tab.getAttribute('data-alive-tab')\n if (!panelId) return\n activateTab(container, panelId)\n })\n registerCleanup(root, cleanup)\n\n // Keyboard navigation\n const keyCleanup = addListener(tab, 'keydown', (e) => {\n const allTabs = [...container.querySelectorAll<HTMLElement>('[data-alive-tab]')]\n const idx = allTabs.indexOf(tab)\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault()\n allTabs[(idx + 1) % allTabs.length]?.focus()\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault()\n allTabs[(idx - 1 + allTabs.length) % allTabs.length]?.focus()\n }\n })\n registerCleanup(root, keyCleanup)\n })\n}\n\nfunction activateTab(container: Element, panelId: string): void {\n // Deactivate all tabs + panels within this tabs container\n container.querySelectorAll('[data-alive-tab]').forEach(t => {\n t.classList.remove('is-active')\n t.setAttribute('aria-selected', 'false')\n t.setAttribute('tabindex', '-1')\n })\n\n // Find panels — look in the container, then in the whole document\n const searchRoot = container.closest('[data-alive-tabs-panels]') ?? document\n searchRoot.querySelectorAll('[data-alive-panel]').forEach(p => {\n p.classList.remove('is-active')\n p.setAttribute('aria-hidden', 'true')\n })\n\n // Activate the selected tab\n const activeTab = container.querySelector<HTMLElement>(`[data-alive-tab=\"${panelId}\"]`)\n activeTab?.classList.add('is-active')\n activeTab?.setAttribute('aria-selected', 'true')\n activeTab?.setAttribute('tabindex', '0')\n\n // Activate the matching panel\n const activePanel = searchRoot.querySelector<HTMLElement>(`[data-alive-panel=\"${panelId}\"]`)\n activePanel?.classList.add('is-active')\n activePanel?.setAttribute('aria-hidden', 'false')\n}\n\n// ── Scroll Reveal ──────────────────────────────────────────────────────────────\n\nfunction wireScroll(el: Element, root: Element): void {\n const obs = new IntersectionObserver(\n (entries) => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n entry.target.classList.add('is-visible')\n obs.unobserve(entry.target)\n }\n })\n },\n { threshold: 0.1, rootMargin: '0px 0px -40px 0px' },\n )\n obs.observe(el)\n registerCleanup(root, () => obs.disconnect())\n}\n\n// ── Auto-Stagger ───────────────────────────────────────────────────────────────\n\nfunction wireStagger(container: Element): void {\n const children = [...container.children] as HTMLElement[]\n children.forEach((child, i) => {\n child.style.setProperty('--alive-index', String(i))\n })\n}\n\n// ── 3D Tilt ────────────────────────────────────────────────────────────────────\n\nfunction wireTilt(el: Element, root: Element): void {\n const htmlEl = el as HTMLElement\n const STRENGTH = 8\n\n const moveCleanup = addListener(htmlEl, 'mousemove', (e) => {\n const rect = htmlEl.getBoundingClientRect()\n const x = (e.clientX - rect.left) / rect.width - 0.5\n const y = (e.clientY - rect.top) / rect.height - 0.5\n htmlEl.style.transform = `perspective(800px) rotateY(${x * STRENGTH}deg) rotateX(${-y * STRENGTH}deg) scale(1.01)`\n htmlEl.style.transition = 'transform 0.1s ease-out'\n })\n\n const leaveCleanup = addListener(htmlEl, 'mouseleave', () => {\n htmlEl.style.transform = ''\n htmlEl.style.transition = 'transform 0.4s cubic-bezier(0.16, 1, 0.3, 1)'\n })\n\n registerCleanup(root, moveCleanup)\n registerCleanup(root, leaveCleanup)\n}\n\n// ── Magnetic Follow ────────────────────────────────────────────────────────────\n\nfunction wireMagnetic(el: Element, root: Element): void {\n const htmlEl = el as HTMLElement\n const PULL = 0.35\n\n const moveCleanup = addListener(htmlEl, 'mousemove', (e) => {\n const rect = htmlEl.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n const dx = (e.clientX - cx) * PULL\n const dy = (e.clientY - cy) * PULL\n htmlEl.style.transform = `translate(${dx}px, ${dy}px)`\n htmlEl.style.transition = 'transform 0.2s cubic-bezier(0.16, 1, 0.3, 1)'\n })\n\n const leaveCleanup = addListener(htmlEl, 'mouseleave', () => {\n htmlEl.style.transform = ''\n htmlEl.style.transition = 'transform 0.5s cubic-bezier(0.16, 1, 0.3, 1)'\n })\n\n registerCleanup(root, moveCleanup)\n registerCleanup(root, leaveCleanup)\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\n/**\n * Wire all data-alive-* components within `root` (defaults to document.documentElement).\n * Safe to call multiple times — existing listeners are tracked and replaced on `destroy()`.\n */\nexport function init(root: Element = document.documentElement): void {\n // Accordion\n root.querySelectorAll('[data-alive-accordion]').forEach(el => wireAccordion(el, root))\n\n // Modal\n root.querySelectorAll('[data-alive-modal]').forEach(el => wireModal(el, root))\n\n // Drawer\n root.querySelectorAll('[data-alive-drawer]').forEach(el => wireDrawer(el, root))\n\n // Dropdown\n root.querySelectorAll('[data-alive-dropdown]').forEach(el => wireDropdown(el, root))\n\n // Tabs\n root.querySelectorAll('[data-alive-tabs]').forEach(el => wireTabs(el, root))\n\n // Scroll reveal\n root.querySelectorAll('[data-alive-scroll]').forEach(el => wireScroll(el, root))\n\n // Auto-stagger children\n root.querySelectorAll('[data-alive-stagger]').forEach(el => wireStagger(el))\n\n // 3D tilt\n root.querySelectorAll('[data-alive-tilt]').forEach(el => wireTilt(el, root))\n\n // Magnetic follow\n root.querySelectorAll('[data-alive-magnetic]').forEach(el => wireMagnetic(el, root))\n}\n\n/**\n * Remove all event listeners registered by `init(root)`.\n */\nexport function destroy(root: Element = document.documentElement): void {\n const cleanups = cleanupRegistry.get(root) ?? []\n cleanups.forEach(fn => fn())\n cleanupRegistry.delete(root)\n}\n"],"mappings":"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","names":["cleanup"]}
1
+ {"version":3,"sources":["../src/runtime.ts"],"sourcesContent":["/**\n * AliveUI Runtime\n *\n * Provides data-attribute-driven interactivity for accordion, modal, drawer,\n * dropdown, and tabs components — zero dependencies, ~2 KB.\n *\n * Usage:\n * import { init } from '@alivecss/aliveui/runtime'\n * init() // wire everything in document\n * init(myRootElement) // wire a subtree\n */\n\ntype Cleanup = () => void\n\nconst cleanupRegistry = new WeakMap<Element, Cleanup[]>()\n\nfunction registerCleanup(root: Element, fn: Cleanup): void {\n const existing = cleanupRegistry.get(root) ?? []\n existing.push(fn)\n cleanupRegistry.set(root, existing)\n}\n\nfunction addListener<K extends keyof HTMLElementEventMap>(\n el: EventTarget,\n type: K,\n handler: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): Cleanup {\n el.addEventListener(type, handler as EventListener, options)\n return () => el.removeEventListener(type, handler as EventListener, options)\n}\n\n// ── Accordion ─────────────────────────────────────────────────────────────────\n\nfunction wireAccordion(container: Element, root: Element): void {\n const triggers = container.querySelectorAll<HTMLElement>('[data-alive-trigger]')\n triggers.forEach(trigger => {\n const item = trigger.closest('[data-alive-accordion-item]') ?? trigger.parentElement\n if (!item) return\n\n const cleanup = addListener(trigger, 'click', () => {\n const isOpen = item.classList.contains('is-open')\n // Close all items if not multi-open\n if (!container.hasAttribute('data-alive-multi')) {\n container.querySelectorAll('[data-alive-accordion-item]').forEach(i => {\n i.classList.remove('is-open')\n i.querySelector('[data-alive-trigger]')?.setAttribute('aria-expanded', 'false')\n })\n }\n if (!isOpen) {\n item.classList.add('is-open')\n trigger.setAttribute('aria-expanded', 'true')\n }\n })\n registerCleanup(root, cleanup)\n })\n}\n\n// ── Modal ─────────────────────────────────────────────────────────────────────\n\nfunction wireModal(modal: Element, root: Element): void {\n const id = modal.getAttribute('data-alive-modal')\n if (!id) return\n\n // Open triggers\n const openers = document.querySelectorAll<HTMLElement>(`[data-alive-open=\"${id}\"]`)\n openers.forEach(opener => {\n const cleanup = addListener(opener, 'click', () => openModal(id))\n registerCleanup(root, cleanup)\n })\n\n // Close triggers inside the modal\n modal.querySelectorAll<HTMLElement>('[data-alive-close]').forEach(closer => {\n const cleanup = addListener(closer, 'click', () => closeModal(id))\n registerCleanup(root, cleanup)\n })\n\n // Backdrop click to close (click on the modal wrapper, not the content)\n const cleanup = addListener(modal, 'click', (e) => {\n if (e.target === modal) closeModal(id)\n })\n registerCleanup(root, cleanup)\n\n // ESC key\n const escCleanup = addListener(document, 'keydown', (e) => {\n if (e.key === 'Escape' && modal.classList.contains('is-open')) closeModal(id)\n })\n registerCleanup(root, escCleanup)\n}\n\nexport function openModal(id: string): void {\n const modal = document.querySelector<HTMLElement>(`[data-alive-modal=\"${id}\"]`)\n if (!modal) return\n modal.classList.add('is-open')\n modal.setAttribute('aria-hidden', 'false')\n document.body.style.overflow = 'hidden'\n // Focus first focusable element\n const focusable = modal.querySelector<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n )\n focusable?.focus()\n}\n\nexport function closeModal(id: string): void {\n const modal = document.querySelector<HTMLElement>(`[data-alive-modal=\"${id}\"]`)\n if (!modal) return\n modal.classList.remove('is-open')\n modal.setAttribute('aria-hidden', 'true')\n document.body.style.overflow = ''\n}\n\n// ── Drawer ────────────────────────────────────────────────────────────────────\n\nfunction wireDrawer(drawer: Element, root: Element): void {\n const id = drawer.getAttribute('data-alive-drawer')\n if (!id) return\n\n const openers = document.querySelectorAll<HTMLElement>(`[data-alive-open=\"${id}\"]`)\n openers.forEach(opener => {\n const cleanup = addListener(opener, 'click', () => openDrawer(id))\n registerCleanup(root, cleanup)\n })\n\n drawer.querySelectorAll<HTMLElement>('[data-alive-close]').forEach(closer => {\n const cleanup = addListener(closer, 'click', () => closeDrawer(id))\n registerCleanup(root, cleanup)\n })\n\n const backdropCleanup = addListener(drawer, 'click', (e) => {\n if (e.target === drawer) closeDrawer(id)\n })\n registerCleanup(root, backdropCleanup)\n\n const escCleanup = addListener(document, 'keydown', (e) => {\n if (e.key === 'Escape' && drawer.classList.contains('is-open')) closeDrawer(id)\n })\n registerCleanup(root, escCleanup)\n}\n\nexport function openDrawer(id: string): void {\n const drawer = document.querySelector<HTMLElement>(`[data-alive-drawer=\"${id}\"]`)\n if (!drawer) return\n drawer.classList.add('is-open')\n drawer.setAttribute('aria-hidden', 'false')\n document.body.style.overflow = 'hidden'\n}\n\nexport function closeDrawer(id: string): void {\n const drawer = document.querySelector<HTMLElement>(`[data-alive-drawer=\"${id}\"]`)\n if (!drawer) return\n drawer.classList.remove('is-open')\n drawer.setAttribute('aria-hidden', 'true')\n document.body.style.overflow = ''\n}\n\n// ── Dropdown ──────────────────────────────────────────────────────────────────\n\nfunction wireDropdown(container: Element, root: Element): void {\n const trigger = container.querySelector<HTMLElement>('[data-alive-trigger]')\n const menu = container.querySelector<HTMLElement>('[data-alive-dropdown-menu]')\n if (!trigger || !menu) return\n\n const toggleCleanup = addListener(trigger, 'click', (e) => {\n e.stopPropagation()\n toggleDropdown(container)\n })\n registerCleanup(root, toggleCleanup)\n\n // Close on outside click\n const outsideCleanup = addListener(document, 'click', (e) => {\n if (!container.contains(e.target as Node)) {\n menu.classList.remove('is-open')\n trigger.setAttribute('aria-expanded', 'false')\n }\n })\n registerCleanup(root, outsideCleanup)\n\n // Close on ESC\n const escCleanup = addListener(document, 'keydown', (e) => {\n if (e.key === 'Escape' && menu.classList.contains('is-open')) {\n menu.classList.remove('is-open')\n trigger.setAttribute('aria-expanded', 'false')\n trigger.focus()\n }\n })\n registerCleanup(root, escCleanup)\n}\n\nexport function toggleDropdown(container: Element): void {\n const trigger = container.querySelector<HTMLElement>('[data-alive-trigger]')\n const menu = container.querySelector<HTMLElement>('[data-alive-dropdown-menu]')\n if (!menu) return\n const isOpen = menu.classList.toggle('is-open')\n trigger?.setAttribute('aria-expanded', String(isOpen))\n if (isOpen) {\n // Focus first item\n menu.querySelector<HTMLElement>('[role=\"menuitem\"], button, a')?.focus()\n }\n}\n\n// ── Tabs ──────────────────────────────────────────────────────────────────────\n\nfunction wireTabs(container: Element, root: Element): void {\n const tabs = container.querySelectorAll<HTMLElement>('[data-alive-tab]')\n tabs.forEach(tab => {\n const cleanup = addListener(tab, 'click', () => {\n const panelId = tab.getAttribute('data-alive-tab')\n if (!panelId) return\n activateTab(container, panelId)\n })\n registerCleanup(root, cleanup)\n\n // Keyboard navigation\n const keyCleanup = addListener(tab, 'keydown', (e) => {\n const allTabs = [...container.querySelectorAll<HTMLElement>('[data-alive-tab]')]\n const idx = allTabs.indexOf(tab)\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault()\n allTabs[(idx + 1) % allTabs.length]?.focus()\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault()\n allTabs[(idx - 1 + allTabs.length) % allTabs.length]?.focus()\n }\n })\n registerCleanup(root, keyCleanup)\n })\n}\n\nfunction activateTab(container: Element, panelId: string): void {\n // Deactivate all tabs + panels within this tabs container\n container.querySelectorAll('[data-alive-tab]').forEach(t => {\n t.classList.remove('is-active')\n t.setAttribute('aria-selected', 'false')\n t.setAttribute('tabindex', '-1')\n })\n\n // Find panels — look in the container, then in the whole document\n const searchRoot = container.closest('[data-alive-tabs-panels]') ?? document\n searchRoot.querySelectorAll('[data-alive-panel]').forEach(p => {\n p.classList.remove('is-active')\n p.setAttribute('aria-hidden', 'true')\n })\n\n // Activate the selected tab\n const activeTab = container.querySelector<HTMLElement>(`[data-alive-tab=\"${panelId}\"]`)\n activeTab?.classList.add('is-active')\n activeTab?.setAttribute('aria-selected', 'true')\n activeTab?.setAttribute('tabindex', '0')\n\n // Activate the matching panel\n const activePanel = searchRoot.querySelector<HTMLElement>(`[data-alive-panel=\"${panelId}\"]`)\n activePanel?.classList.add('is-active')\n activePanel?.setAttribute('aria-hidden', 'false')\n}\n\n// ── Scroll Reveal ──────────────────────────────────────────────────────────────\n\nfunction wireScroll(el: Element, root: Element): void {\n const obs = new IntersectionObserver(\n (entries) => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n entry.target.classList.add('is-visible')\n obs.unobserve(entry.target)\n }\n })\n },\n { threshold: 0.1, rootMargin: '0px 0px -40px 0px' },\n )\n obs.observe(el)\n registerCleanup(root, () => obs.disconnect())\n}\n\n// ── Auto-Stagger ───────────────────────────────────────────────────────────────\n\nfunction wireStagger(container: Element): void {\n const children = [...container.children] as HTMLElement[]\n children.forEach((child, i) => {\n child.style.setProperty('--alive-index', String(i))\n })\n}\n\n// ── 3D Tilt ────────────────────────────────────────────────────────────────────\n\nfunction wireTilt(el: Element, root: Element): void {\n const htmlEl = el as HTMLElement\n const STRENGTH = 8\n\n const moveCleanup = addListener(htmlEl, 'mousemove', (e) => {\n const rect = htmlEl.getBoundingClientRect()\n const x = (e.clientX - rect.left) / rect.width - 0.5\n const y = (e.clientY - rect.top) / rect.height - 0.5\n htmlEl.style.transform = `perspective(800px) rotateY(${x * STRENGTH}deg) rotateX(${-y * STRENGTH}deg) scale(1.01)`\n htmlEl.style.transition = 'transform 0.1s ease-out'\n })\n\n const leaveCleanup = addListener(htmlEl, 'mouseleave', () => {\n htmlEl.style.transform = ''\n htmlEl.style.transition = 'transform 0.4s cubic-bezier(0.16, 1, 0.3, 1)'\n })\n\n registerCleanup(root, moveCleanup)\n registerCleanup(root, leaveCleanup)\n}\n\n// ── Magnetic Follow ────────────────────────────────────────────────────────────\n\nfunction wireMagnetic(el: Element, root: Element): void {\n const htmlEl = el as HTMLElement\n const PULL = 0.35\n\n const moveCleanup = addListener(htmlEl, 'mousemove', (e) => {\n const rect = htmlEl.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n const dx = (e.clientX - cx) * PULL\n const dy = (e.clientY - cy) * PULL\n htmlEl.style.transform = `translate(${dx}px, ${dy}px)`\n htmlEl.style.transition = 'transform 0.2s cubic-bezier(0.16, 1, 0.3, 1)'\n })\n\n const leaveCleanup = addListener(htmlEl, 'mouseleave', () => {\n htmlEl.style.transform = ''\n htmlEl.style.transition = 'transform 0.5s cubic-bezier(0.16, 1, 0.3, 1)'\n })\n\n registerCleanup(root, moveCleanup)\n registerCleanup(root, leaveCleanup)\n}\n\n// ── Video Scene Sequencer ──────────────────────────────────────────────────────\n\n/**\n * Force-restart CSS animations on all animated children of a scene element.\n * This ensures stagger delays are relative to scene activation, not page load.\n */\nfunction resetSceneAnimations(scene: HTMLElement): void {\n const animated = scene.querySelectorAll<HTMLElement>(\n '[class*=\"alive-enter\"], [class*=\"alive-loop\"], ' +\n '.alive-typewriter, .alive-typewriter-fast, .alive-typewriter-slow, ' +\n '.alive-word-reveal > *, .alive-kinetic-slam, ' +\n '.alive-metric-card, .alive-toast, .alive-badge-pulse, ' +\n '.alive-spotlight, .alive-code-block',\n )\n animated.forEach(el => {\n const saved = el.style.animationName\n el.style.animationName = 'none'\n void el.offsetHeight // force reflow — restarts animation from t=0\n el.style.animationName = saved\n })\n}\n\n/**\n * Wire a [data-alive-sequence] container.\n *\n * Markup:\n * <div data-alive-sequence data-alive-loop style=\"position:relative; width:800px; height:500px;\">\n * <div data-alive-scene data-alive-duration=\"3000\" data-alive-transition=\"wipe-left\">…</div>\n * <div data-alive-scene data-alive-duration=\"2500\" data-alive-transition=\"fade\">…</div>\n * </div>\n *\n * Scene attributes:\n * data-alive-duration — how long to show the scene (ms, default 3000)\n * data-alive-transition — transition type (default \"fade\"; matches alive-transition-* classes)\n * data-alive-trans-duration — transition animation duration (ms, default 600)\n *\n * Sequence attributes:\n * data-alive-loop — loop back to the first scene after the last\n */\nfunction wireVideoSequence(container: Element, root: Element): void {\n const scenes = [...container.querySelectorAll<HTMLElement>(':scope > [data-alive-scene]')]\n if (scenes.length === 0) return\n\n const loop = container.hasAttribute('data-alive-loop')\n let current = 0\n let timeoutId: ReturnType<typeof setTimeout> | null = null\n\n const containerEl = container as HTMLElement\n if (getComputedStyle(containerEl).position === 'static') {\n containerEl.style.position = 'relative'\n }\n containerEl.style.overflow = 'hidden'\n\n scenes.forEach(s => {\n s.style.position = 'absolute'\n s.style.inset = '0'\n s.classList.remove('is-active')\n })\n\n function activate(index: number): void {\n const scene = scenes[index]\n resetSceneAnimations(scene)\n scene.classList.add('is-active')\n scene.style.zIndex = '1'\n }\n\n function scheduleNext(fromIndex: number): void {\n const scene = scenes[fromIndex]\n const duration = parseInt(scene.getAttribute('data-alive-duration') ?? '3000', 10)\n\n timeoutId = setTimeout(() => {\n const nextIndex = fromIndex + 1\n const toIndex = nextIndex >= scenes.length ? (loop ? 0 : -1) : nextIndex\n if (toIndex === -1) return\n doTransition(fromIndex, toIndex)\n }, duration)\n }\n\n function doTransition(fromIndex: number, toIndex: number): void {\n const outScene = scenes[fromIndex]\n const inScene = scenes[toIndex]\n const transType = outScene.getAttribute('data-alive-transition') ?? 'fade'\n const transDur = parseInt(outScene.getAttribute('data-alive-trans-duration') ?? '600', 10)\n\n const outClass = `alive-transition-${transType}-out`\n const inClass = `alive-transition-${transType}-in`\n\n // Sync CSS animation duration with the JS timer\n outScene.style.setProperty('--alive-tr-dur', `${transDur}ms`)\n inScene.style.setProperty('--alive-tr-dur', `${transDur}ms`)\n\n // Outgoing goes on top (required for wipe/clip-path transitions)\n outScene.style.zIndex = '2'\n outScene.classList.add(outClass)\n\n // Activate incoming beneath, reset its child animations\n inScene.style.zIndex = '1'\n resetSceneAnimations(inScene)\n inScene.classList.add('is-active', inClass)\n\n timeoutId = setTimeout(() => {\n outScene.classList.remove('is-active', outClass)\n outScene.style.zIndex = ''\n outScene.style.removeProperty('--alive-tr-dur')\n inScene.classList.remove(inClass)\n inScene.style.removeProperty('--alive-tr-dur')\n current = toIndex\n scheduleNext(current)\n }, transDur)\n }\n\n activate(current)\n scheduleNext(current)\n\n registerCleanup(root, () => {\n if (timeoutId) clearTimeout(timeoutId)\n })\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\n/**\n * Wire all data-alive-* components within `root` (defaults to document.documentElement).\n * Safe to call multiple times — existing listeners are tracked and replaced on `destroy()`.\n */\nexport function init(root: Element = document.documentElement): void {\n // Accordion\n root.querySelectorAll('[data-alive-accordion]').forEach(el => wireAccordion(el, root))\n\n // Modal\n root.querySelectorAll('[data-alive-modal]').forEach(el => wireModal(el, root))\n\n // Drawer\n root.querySelectorAll('[data-alive-drawer]').forEach(el => wireDrawer(el, root))\n\n // Dropdown\n root.querySelectorAll('[data-alive-dropdown]').forEach(el => wireDropdown(el, root))\n\n // Tabs\n root.querySelectorAll('[data-alive-tabs]').forEach(el => wireTabs(el, root))\n\n // Scroll reveal\n root.querySelectorAll('[data-alive-scroll]').forEach(el => wireScroll(el, root))\n\n // Auto-stagger children\n root.querySelectorAll('[data-alive-stagger]').forEach(el => wireStagger(el))\n\n // 3D tilt\n root.querySelectorAll('[data-alive-tilt]').forEach(el => wireTilt(el, root))\n\n // Magnetic follow\n root.querySelectorAll('[data-alive-magnetic]').forEach(el => wireMagnetic(el, root))\n\n // Video scene sequencer\n root.querySelectorAll('[data-alive-sequence]').forEach(el => wireVideoSequence(el, root))\n}\n\n/**\n * Remove all event listeners registered by `init(root)`.\n */\nexport function destroy(root: Element = document.documentElement): void {\n const cleanups = cleanupRegistry.get(root) ?? []\n cleanups.forEach(fn => fn())\n cleanupRegistry.delete(root)\n}\n"],"mappings":"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","names":["cleanup"]}
package/dist/runtime.mjs CHANGED
@@ -238,6 +238,79 @@ function wireMagnetic(el, root) {
238
238
  registerCleanup(root, moveCleanup);
239
239
  registerCleanup(root, leaveCleanup);
240
240
  }
241
+ function resetSceneAnimations(scene) {
242
+ const animated = scene.querySelectorAll(
243
+ '[class*="alive-enter"], [class*="alive-loop"], .alive-typewriter, .alive-typewriter-fast, .alive-typewriter-slow, .alive-word-reveal > *, .alive-kinetic-slam, .alive-metric-card, .alive-toast, .alive-badge-pulse, .alive-spotlight, .alive-code-block'
244
+ );
245
+ animated.forEach((el) => {
246
+ const saved = el.style.animationName;
247
+ el.style.animationName = "none";
248
+ void el.offsetHeight;
249
+ el.style.animationName = saved;
250
+ });
251
+ }
252
+ function wireVideoSequence(container, root) {
253
+ const scenes = [...container.querySelectorAll(":scope > [data-alive-scene]")];
254
+ if (scenes.length === 0) return;
255
+ const loop = container.hasAttribute("data-alive-loop");
256
+ let current = 0;
257
+ let timeoutId = null;
258
+ const containerEl = container;
259
+ if (getComputedStyle(containerEl).position === "static") {
260
+ containerEl.style.position = "relative";
261
+ }
262
+ containerEl.style.overflow = "hidden";
263
+ scenes.forEach((s) => {
264
+ s.style.position = "absolute";
265
+ s.style.inset = "0";
266
+ s.classList.remove("is-active");
267
+ });
268
+ function activate(index) {
269
+ const scene = scenes[index];
270
+ resetSceneAnimations(scene);
271
+ scene.classList.add("is-active");
272
+ scene.style.zIndex = "1";
273
+ }
274
+ function scheduleNext(fromIndex) {
275
+ const scene = scenes[fromIndex];
276
+ const duration = parseInt(scene.getAttribute("data-alive-duration") ?? "3000", 10);
277
+ timeoutId = setTimeout(() => {
278
+ const nextIndex = fromIndex + 1;
279
+ const toIndex = nextIndex >= scenes.length ? loop ? 0 : -1 : nextIndex;
280
+ if (toIndex === -1) return;
281
+ doTransition(fromIndex, toIndex);
282
+ }, duration);
283
+ }
284
+ function doTransition(fromIndex, toIndex) {
285
+ const outScene = scenes[fromIndex];
286
+ const inScene = scenes[toIndex];
287
+ const transType = outScene.getAttribute("data-alive-transition") ?? "fade";
288
+ const transDur = parseInt(outScene.getAttribute("data-alive-trans-duration") ?? "600", 10);
289
+ const outClass = `alive-transition-${transType}-out`;
290
+ const inClass = `alive-transition-${transType}-in`;
291
+ outScene.style.setProperty("--alive-tr-dur", `${transDur}ms`);
292
+ inScene.style.setProperty("--alive-tr-dur", `${transDur}ms`);
293
+ outScene.style.zIndex = "2";
294
+ outScene.classList.add(outClass);
295
+ inScene.style.zIndex = "1";
296
+ resetSceneAnimations(inScene);
297
+ inScene.classList.add("is-active", inClass);
298
+ timeoutId = setTimeout(() => {
299
+ outScene.classList.remove("is-active", outClass);
300
+ outScene.style.zIndex = "";
301
+ outScene.style.removeProperty("--alive-tr-dur");
302
+ inScene.classList.remove(inClass);
303
+ inScene.style.removeProperty("--alive-tr-dur");
304
+ current = toIndex;
305
+ scheduleNext(current);
306
+ }, transDur);
307
+ }
308
+ activate(current);
309
+ scheduleNext(current);
310
+ registerCleanup(root, () => {
311
+ if (timeoutId) clearTimeout(timeoutId);
312
+ });
313
+ }
241
314
  function init(root = document.documentElement) {
242
315
  root.querySelectorAll("[data-alive-accordion]").forEach((el) => wireAccordion(el, root));
243
316
  root.querySelectorAll("[data-alive-modal]").forEach((el) => wireModal(el, root));
@@ -248,6 +321,7 @@ function init(root = document.documentElement) {
248
321
  root.querySelectorAll("[data-alive-stagger]").forEach((el) => wireStagger(el));
249
322
  root.querySelectorAll("[data-alive-tilt]").forEach((el) => wireTilt(el, root));
250
323
  root.querySelectorAll("[data-alive-magnetic]").forEach((el) => wireMagnetic(el, root));
324
+ root.querySelectorAll("[data-alive-sequence]").forEach((el) => wireVideoSequence(el, root));
251
325
  }
252
326
  function destroy(root = document.documentElement) {
253
327
  const cleanups = cleanupRegistry.get(root) ?? [];
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/runtime.ts"],"sourcesContent":["/**\n * AliveUI Runtime\n *\n * Provides data-attribute-driven interactivity for accordion, modal, drawer,\n * dropdown, and tabs components — zero dependencies, ~2 KB.\n *\n * Usage:\n * import { init } from '@alivecss/aliveui/runtime'\n * init() // wire everything in document\n * init(myRootElement) // wire a subtree\n */\n\ntype Cleanup = () => void\n\nconst cleanupRegistry = new WeakMap<Element, Cleanup[]>()\n\nfunction registerCleanup(root: Element, fn: Cleanup): void {\n const existing = cleanupRegistry.get(root) ?? []\n existing.push(fn)\n cleanupRegistry.set(root, existing)\n}\n\nfunction addListener<K extends keyof HTMLElementEventMap>(\n el: EventTarget,\n type: K,\n handler: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): Cleanup {\n el.addEventListener(type, handler as EventListener, options)\n return () => el.removeEventListener(type, handler as EventListener, options)\n}\n\n// ── Accordion ─────────────────────────────────────────────────────────────────\n\nfunction wireAccordion(container: Element, root: Element): void {\n const triggers = container.querySelectorAll<HTMLElement>('[data-alive-trigger]')\n triggers.forEach(trigger => {\n const item = trigger.closest('[data-alive-accordion-item]') ?? trigger.parentElement\n if (!item) return\n\n const cleanup = addListener(trigger, 'click', () => {\n const isOpen = item.classList.contains('is-open')\n // Close all items if not multi-open\n if (!container.hasAttribute('data-alive-multi')) {\n container.querySelectorAll('[data-alive-accordion-item]').forEach(i => {\n i.classList.remove('is-open')\n i.querySelector('[data-alive-trigger]')?.setAttribute('aria-expanded', 'false')\n })\n }\n if (!isOpen) {\n item.classList.add('is-open')\n trigger.setAttribute('aria-expanded', 'true')\n }\n })\n registerCleanup(root, cleanup)\n })\n}\n\n// ── Modal ─────────────────────────────────────────────────────────────────────\n\nfunction wireModal(modal: Element, root: Element): void {\n const id = modal.getAttribute('data-alive-modal')\n if (!id) return\n\n // Open triggers\n const openers = document.querySelectorAll<HTMLElement>(`[data-alive-open=\"${id}\"]`)\n openers.forEach(opener => {\n const cleanup = addListener(opener, 'click', () => openModal(id))\n registerCleanup(root, cleanup)\n })\n\n // Close triggers inside the modal\n modal.querySelectorAll<HTMLElement>('[data-alive-close]').forEach(closer => {\n const cleanup = addListener(closer, 'click', () => closeModal(id))\n registerCleanup(root, cleanup)\n })\n\n // Backdrop click to close (click on the modal wrapper, not the content)\n const cleanup = addListener(modal, 'click', (e) => {\n if (e.target === modal) closeModal(id)\n })\n registerCleanup(root, cleanup)\n\n // ESC key\n const escCleanup = addListener(document, 'keydown', (e) => {\n if (e.key === 'Escape' && modal.classList.contains('is-open')) closeModal(id)\n })\n registerCleanup(root, escCleanup)\n}\n\nexport function openModal(id: string): void {\n const modal = document.querySelector<HTMLElement>(`[data-alive-modal=\"${id}\"]`)\n if (!modal) return\n modal.classList.add('is-open')\n modal.setAttribute('aria-hidden', 'false')\n document.body.style.overflow = 'hidden'\n // Focus first focusable element\n const focusable = modal.querySelector<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n )\n focusable?.focus()\n}\n\nexport function closeModal(id: string): void {\n const modal = document.querySelector<HTMLElement>(`[data-alive-modal=\"${id}\"]`)\n if (!modal) return\n modal.classList.remove('is-open')\n modal.setAttribute('aria-hidden', 'true')\n document.body.style.overflow = ''\n}\n\n// ── Drawer ────────────────────────────────────────────────────────────────────\n\nfunction wireDrawer(drawer: Element, root: Element): void {\n const id = drawer.getAttribute('data-alive-drawer')\n if (!id) return\n\n const openers = document.querySelectorAll<HTMLElement>(`[data-alive-open=\"${id}\"]`)\n openers.forEach(opener => {\n const cleanup = addListener(opener, 'click', () => openDrawer(id))\n registerCleanup(root, cleanup)\n })\n\n drawer.querySelectorAll<HTMLElement>('[data-alive-close]').forEach(closer => {\n const cleanup = addListener(closer, 'click', () => closeDrawer(id))\n registerCleanup(root, cleanup)\n })\n\n const backdropCleanup = addListener(drawer, 'click', (e) => {\n if (e.target === drawer) closeDrawer(id)\n })\n registerCleanup(root, backdropCleanup)\n\n const escCleanup = addListener(document, 'keydown', (e) => {\n if (e.key === 'Escape' && drawer.classList.contains('is-open')) closeDrawer(id)\n })\n registerCleanup(root, escCleanup)\n}\n\nexport function openDrawer(id: string): void {\n const drawer = document.querySelector<HTMLElement>(`[data-alive-drawer=\"${id}\"]`)\n if (!drawer) return\n drawer.classList.add('is-open')\n drawer.setAttribute('aria-hidden', 'false')\n document.body.style.overflow = 'hidden'\n}\n\nexport function closeDrawer(id: string): void {\n const drawer = document.querySelector<HTMLElement>(`[data-alive-drawer=\"${id}\"]`)\n if (!drawer) return\n drawer.classList.remove('is-open')\n drawer.setAttribute('aria-hidden', 'true')\n document.body.style.overflow = ''\n}\n\n// ── Dropdown ──────────────────────────────────────────────────────────────────\n\nfunction wireDropdown(container: Element, root: Element): void {\n const trigger = container.querySelector<HTMLElement>('[data-alive-trigger]')\n const menu = container.querySelector<HTMLElement>('[data-alive-dropdown-menu]')\n if (!trigger || !menu) return\n\n const toggleCleanup = addListener(trigger, 'click', (e) => {\n e.stopPropagation()\n toggleDropdown(container)\n })\n registerCleanup(root, toggleCleanup)\n\n // Close on outside click\n const outsideCleanup = addListener(document, 'click', (e) => {\n if (!container.contains(e.target as Node)) {\n menu.classList.remove('is-open')\n trigger.setAttribute('aria-expanded', 'false')\n }\n })\n registerCleanup(root, outsideCleanup)\n\n // Close on ESC\n const escCleanup = addListener(document, 'keydown', (e) => {\n if (e.key === 'Escape' && menu.classList.contains('is-open')) {\n menu.classList.remove('is-open')\n trigger.setAttribute('aria-expanded', 'false')\n trigger.focus()\n }\n })\n registerCleanup(root, escCleanup)\n}\n\nexport function toggleDropdown(container: Element): void {\n const trigger = container.querySelector<HTMLElement>('[data-alive-trigger]')\n const menu = container.querySelector<HTMLElement>('[data-alive-dropdown-menu]')\n if (!menu) return\n const isOpen = menu.classList.toggle('is-open')\n trigger?.setAttribute('aria-expanded', String(isOpen))\n if (isOpen) {\n // Focus first item\n menu.querySelector<HTMLElement>('[role=\"menuitem\"], button, a')?.focus()\n }\n}\n\n// ── Tabs ──────────────────────────────────────────────────────────────────────\n\nfunction wireTabs(container: Element, root: Element): void {\n const tabs = container.querySelectorAll<HTMLElement>('[data-alive-tab]')\n tabs.forEach(tab => {\n const cleanup = addListener(tab, 'click', () => {\n const panelId = tab.getAttribute('data-alive-tab')\n if (!panelId) return\n activateTab(container, panelId)\n })\n registerCleanup(root, cleanup)\n\n // Keyboard navigation\n const keyCleanup = addListener(tab, 'keydown', (e) => {\n const allTabs = [...container.querySelectorAll<HTMLElement>('[data-alive-tab]')]\n const idx = allTabs.indexOf(tab)\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault()\n allTabs[(idx + 1) % allTabs.length]?.focus()\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault()\n allTabs[(idx - 1 + allTabs.length) % allTabs.length]?.focus()\n }\n })\n registerCleanup(root, keyCleanup)\n })\n}\n\nfunction activateTab(container: Element, panelId: string): void {\n // Deactivate all tabs + panels within this tabs container\n container.querySelectorAll('[data-alive-tab]').forEach(t => {\n t.classList.remove('is-active')\n t.setAttribute('aria-selected', 'false')\n t.setAttribute('tabindex', '-1')\n })\n\n // Find panels — look in the container, then in the whole document\n const searchRoot = container.closest('[data-alive-tabs-panels]') ?? document\n searchRoot.querySelectorAll('[data-alive-panel]').forEach(p => {\n p.classList.remove('is-active')\n p.setAttribute('aria-hidden', 'true')\n })\n\n // Activate the selected tab\n const activeTab = container.querySelector<HTMLElement>(`[data-alive-tab=\"${panelId}\"]`)\n activeTab?.classList.add('is-active')\n activeTab?.setAttribute('aria-selected', 'true')\n activeTab?.setAttribute('tabindex', '0')\n\n // Activate the matching panel\n const activePanel = searchRoot.querySelector<HTMLElement>(`[data-alive-panel=\"${panelId}\"]`)\n activePanel?.classList.add('is-active')\n activePanel?.setAttribute('aria-hidden', 'false')\n}\n\n// ── Scroll Reveal ──────────────────────────────────────────────────────────────\n\nfunction wireScroll(el: Element, root: Element): void {\n const obs = new IntersectionObserver(\n (entries) => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n entry.target.classList.add('is-visible')\n obs.unobserve(entry.target)\n }\n })\n },\n { threshold: 0.1, rootMargin: '0px 0px -40px 0px' },\n )\n obs.observe(el)\n registerCleanup(root, () => obs.disconnect())\n}\n\n// ── Auto-Stagger ───────────────────────────────────────────────────────────────\n\nfunction wireStagger(container: Element): void {\n const children = [...container.children] as HTMLElement[]\n children.forEach((child, i) => {\n child.style.setProperty('--alive-index', String(i))\n })\n}\n\n// ── 3D Tilt ────────────────────────────────────────────────────────────────────\n\nfunction wireTilt(el: Element, root: Element): void {\n const htmlEl = el as HTMLElement\n const STRENGTH = 8\n\n const moveCleanup = addListener(htmlEl, 'mousemove', (e) => {\n const rect = htmlEl.getBoundingClientRect()\n const x = (e.clientX - rect.left) / rect.width - 0.5\n const y = (e.clientY - rect.top) / rect.height - 0.5\n htmlEl.style.transform = `perspective(800px) rotateY(${x * STRENGTH}deg) rotateX(${-y * STRENGTH}deg) scale(1.01)`\n htmlEl.style.transition = 'transform 0.1s ease-out'\n })\n\n const leaveCleanup = addListener(htmlEl, 'mouseleave', () => {\n htmlEl.style.transform = ''\n htmlEl.style.transition = 'transform 0.4s cubic-bezier(0.16, 1, 0.3, 1)'\n })\n\n registerCleanup(root, moveCleanup)\n registerCleanup(root, leaveCleanup)\n}\n\n// ── Magnetic Follow ────────────────────────────────────────────────────────────\n\nfunction wireMagnetic(el: Element, root: Element): void {\n const htmlEl = el as HTMLElement\n const PULL = 0.35\n\n const moveCleanup = addListener(htmlEl, 'mousemove', (e) => {\n const rect = htmlEl.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n const dx = (e.clientX - cx) * PULL\n const dy = (e.clientY - cy) * PULL\n htmlEl.style.transform = `translate(${dx}px, ${dy}px)`\n htmlEl.style.transition = 'transform 0.2s cubic-bezier(0.16, 1, 0.3, 1)'\n })\n\n const leaveCleanup = addListener(htmlEl, 'mouseleave', () => {\n htmlEl.style.transform = ''\n htmlEl.style.transition = 'transform 0.5s cubic-bezier(0.16, 1, 0.3, 1)'\n })\n\n registerCleanup(root, moveCleanup)\n registerCleanup(root, leaveCleanup)\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\n/**\n * Wire all data-alive-* components within `root` (defaults to document.documentElement).\n * Safe to call multiple times — existing listeners are tracked and replaced on `destroy()`.\n */\nexport function init(root: Element = document.documentElement): void {\n // Accordion\n root.querySelectorAll('[data-alive-accordion]').forEach(el => wireAccordion(el, root))\n\n // Modal\n root.querySelectorAll('[data-alive-modal]').forEach(el => wireModal(el, root))\n\n // Drawer\n root.querySelectorAll('[data-alive-drawer]').forEach(el => wireDrawer(el, root))\n\n // Dropdown\n root.querySelectorAll('[data-alive-dropdown]').forEach(el => wireDropdown(el, root))\n\n // Tabs\n root.querySelectorAll('[data-alive-tabs]').forEach(el => wireTabs(el, root))\n\n // Scroll reveal\n root.querySelectorAll('[data-alive-scroll]').forEach(el => wireScroll(el, root))\n\n // Auto-stagger children\n root.querySelectorAll('[data-alive-stagger]').forEach(el => wireStagger(el))\n\n // 3D tilt\n root.querySelectorAll('[data-alive-tilt]').forEach(el => wireTilt(el, root))\n\n // Magnetic follow\n root.querySelectorAll('[data-alive-magnetic]').forEach(el => wireMagnetic(el, root))\n}\n\n/**\n * Remove all event listeners registered by `init(root)`.\n */\nexport function destroy(root: Element = document.documentElement): void {\n const cleanups = cleanupRegistry.get(root) ?? []\n cleanups.forEach(fn => fn())\n cleanupRegistry.delete(root)\n}\n"],"mappings":";AAcA,IAAM,kBAAkB,oBAAI,QAA4B;AAExD,SAAS,gBAAgB,MAAe,IAAmB;AACzD,QAAM,WAAW,gBAAgB,IAAI,IAAI,KAAK,CAAC;AAC/C,WAAS,KAAK,EAAE;AAChB,kBAAgB,IAAI,MAAM,QAAQ;AACpC;AAEA,SAAS,YACP,IACA,MACA,SACA,SACS;AACT,KAAG,iBAAiB,MAAM,SAA0B,OAAO;AAC3D,SAAO,MAAM,GAAG,oBAAoB,MAAM,SAA0B,OAAO;AAC7E;AAIA,SAAS,cAAc,WAAoB,MAAqB;AAC9D,QAAM,WAAW,UAAU,iBAA8B,sBAAsB;AAC/E,WAAS,QAAQ,aAAW;AAC1B,UAAM,OAAO,QAAQ,QAAQ,6BAA6B,KAAK,QAAQ;AACvE,QAAI,CAAC,KAAM;AAEX,UAAM,UAAU,YAAY,SAAS,SAAS,MAAM;AAClD,YAAM,SAAS,KAAK,UAAU,SAAS,SAAS;AAEhD,UAAI,CAAC,UAAU,aAAa,kBAAkB,GAAG;AAC/C,kBAAU,iBAAiB,6BAA6B,EAAE,QAAQ,OAAK;AACrE,YAAE,UAAU,OAAO,SAAS;AAC5B,YAAE,cAAc,sBAAsB,GAAG,aAAa,iBAAiB,OAAO;AAAA,QAChF,CAAC;AAAA,MACH;AACA,UAAI,CAAC,QAAQ;AACX,aAAK,UAAU,IAAI,SAAS;AAC5B,gBAAQ,aAAa,iBAAiB,MAAM;AAAA,MAC9C;AAAA,IACF,CAAC;AACD,oBAAgB,MAAM,OAAO;AAAA,EAC/B,CAAC;AACH;AAIA,SAAS,UAAU,OAAgB,MAAqB;AACtD,QAAM,KAAK,MAAM,aAAa,kBAAkB;AAChD,MAAI,CAAC,GAAI;AAGT,QAAM,UAAU,SAAS,iBAA8B,qBAAqB,EAAE,IAAI;AAClF,UAAQ,QAAQ,YAAU;AACxB,UAAMA,WAAU,YAAY,QAAQ,SAAS,MAAM,UAAU,EAAE,CAAC;AAChE,oBAAgB,MAAMA,QAAO;AAAA,EAC/B,CAAC;AAGD,QAAM,iBAA8B,oBAAoB,EAAE,QAAQ,YAAU;AAC1E,UAAMA,WAAU,YAAY,QAAQ,SAAS,MAAM,WAAW,EAAE,CAAC;AACjE,oBAAgB,MAAMA,QAAO;AAAA,EAC/B,CAAC;AAGD,QAAM,UAAU,YAAY,OAAO,SAAS,CAAC,MAAM;AACjD,QAAI,EAAE,WAAW,MAAO,YAAW,EAAE;AAAA,EACvC,CAAC;AACD,kBAAgB,MAAM,OAAO;AAG7B,QAAM,aAAa,YAAY,UAAU,WAAW,CAAC,MAAM;AACzD,QAAI,EAAE,QAAQ,YAAY,MAAM,UAAU,SAAS,SAAS,EAAG,YAAW,EAAE;AAAA,EAC9E,CAAC;AACD,kBAAgB,MAAM,UAAU;AAClC;AAEO,SAAS,UAAU,IAAkB;AAC1C,QAAM,QAAQ,SAAS,cAA2B,sBAAsB,EAAE,IAAI;AAC9E,MAAI,CAAC,MAAO;AACZ,QAAM,UAAU,IAAI,SAAS;AAC7B,QAAM,aAAa,eAAe,OAAO;AACzC,WAAS,KAAK,MAAM,WAAW;AAE/B,QAAM,YAAY,MAAM;AAAA,IACtB;AAAA,EACF;AACA,aAAW,MAAM;AACnB;AAEO,SAAS,WAAW,IAAkB;AAC3C,QAAM,QAAQ,SAAS,cAA2B,sBAAsB,EAAE,IAAI;AAC9E,MAAI,CAAC,MAAO;AACZ,QAAM,UAAU,OAAO,SAAS;AAChC,QAAM,aAAa,eAAe,MAAM;AACxC,WAAS,KAAK,MAAM,WAAW;AACjC;AAIA,SAAS,WAAW,QAAiB,MAAqB;AACxD,QAAM,KAAK,OAAO,aAAa,mBAAmB;AAClD,MAAI,CAAC,GAAI;AAET,QAAM,UAAU,SAAS,iBAA8B,qBAAqB,EAAE,IAAI;AAClF,UAAQ,QAAQ,YAAU;AACxB,UAAM,UAAU,YAAY,QAAQ,SAAS,MAAM,WAAW,EAAE,CAAC;AACjE,oBAAgB,MAAM,OAAO;AAAA,EAC/B,CAAC;AAED,SAAO,iBAA8B,oBAAoB,EAAE,QAAQ,YAAU;AAC3E,UAAM,UAAU,YAAY,QAAQ,SAAS,MAAM,YAAY,EAAE,CAAC;AAClE,oBAAgB,MAAM,OAAO;AAAA,EAC/B,CAAC;AAED,QAAM,kBAAkB,YAAY,QAAQ,SAAS,CAAC,MAAM;AAC1D,QAAI,EAAE,WAAW,OAAQ,aAAY,EAAE;AAAA,EACzC,CAAC;AACD,kBAAgB,MAAM,eAAe;AAErC,QAAM,aAAa,YAAY,UAAU,WAAW,CAAC,MAAM;AACzD,QAAI,EAAE,QAAQ,YAAY,OAAO,UAAU,SAAS,SAAS,EAAG,aAAY,EAAE;AAAA,EAChF,CAAC;AACD,kBAAgB,MAAM,UAAU;AAClC;AAEO,SAAS,WAAW,IAAkB;AAC3C,QAAM,SAAS,SAAS,cAA2B,uBAAuB,EAAE,IAAI;AAChF,MAAI,CAAC,OAAQ;AACb,SAAO,UAAU,IAAI,SAAS;AAC9B,SAAO,aAAa,eAAe,OAAO;AAC1C,WAAS,KAAK,MAAM,WAAW;AACjC;AAEO,SAAS,YAAY,IAAkB;AAC5C,QAAM,SAAS,SAAS,cAA2B,uBAAuB,EAAE,IAAI;AAChF,MAAI,CAAC,OAAQ;AACb,SAAO,UAAU,OAAO,SAAS;AACjC,SAAO,aAAa,eAAe,MAAM;AACzC,WAAS,KAAK,MAAM,WAAW;AACjC;AAIA,SAAS,aAAa,WAAoB,MAAqB;AAC7D,QAAM,UAAU,UAAU,cAA2B,sBAAsB;AAC3E,QAAM,OAAO,UAAU,cAA2B,4BAA4B;AAC9E,MAAI,CAAC,WAAW,CAAC,KAAM;AAEvB,QAAM,gBAAgB,YAAY,SAAS,SAAS,CAAC,MAAM;AACzD,MAAE,gBAAgB;AAClB,mBAAe,SAAS;AAAA,EAC1B,CAAC;AACD,kBAAgB,MAAM,aAAa;AAGnC,QAAM,iBAAiB,YAAY,UAAU,SAAS,CAAC,MAAM;AAC3D,QAAI,CAAC,UAAU,SAAS,EAAE,MAAc,GAAG;AACzC,WAAK,UAAU,OAAO,SAAS;AAC/B,cAAQ,aAAa,iBAAiB,OAAO;AAAA,IAC/C;AAAA,EACF,CAAC;AACD,kBAAgB,MAAM,cAAc;AAGpC,QAAM,aAAa,YAAY,UAAU,WAAW,CAAC,MAAM;AACzD,QAAI,EAAE,QAAQ,YAAY,KAAK,UAAU,SAAS,SAAS,GAAG;AAC5D,WAAK,UAAU,OAAO,SAAS;AAC/B,cAAQ,aAAa,iBAAiB,OAAO;AAC7C,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF,CAAC;AACD,kBAAgB,MAAM,UAAU;AAClC;AAEO,SAAS,eAAe,WAA0B;AACvD,QAAM,UAAU,UAAU,cAA2B,sBAAsB;AAC3E,QAAM,OAAO,UAAU,cAA2B,4BAA4B;AAC9E,MAAI,CAAC,KAAM;AACX,QAAM,SAAS,KAAK,UAAU,OAAO,SAAS;AAC9C,WAAS,aAAa,iBAAiB,OAAO,MAAM,CAAC;AACrD,MAAI,QAAQ;AAEV,SAAK,cAA2B,8BAA8B,GAAG,MAAM;AAAA,EACzE;AACF;AAIA,SAAS,SAAS,WAAoB,MAAqB;AACzD,QAAM,OAAO,UAAU,iBAA8B,kBAAkB;AACvE,OAAK,QAAQ,SAAO;AAClB,UAAM,UAAU,YAAY,KAAK,SAAS,MAAM;AAC9C,YAAM,UAAU,IAAI,aAAa,gBAAgB;AACjD,UAAI,CAAC,QAAS;AACd,kBAAY,WAAW,OAAO;AAAA,IAChC,CAAC;AACD,oBAAgB,MAAM,OAAO;AAG7B,UAAM,aAAa,YAAY,KAAK,WAAW,CAAC,MAAM;AACpD,YAAM,UAAU,CAAC,GAAG,UAAU,iBAA8B,kBAAkB,CAAC;AAC/E,YAAM,MAAM,QAAQ,QAAQ,GAAG;AAC/B,UAAI,EAAE,QAAQ,gBAAgB,EAAE,QAAQ,aAAa;AACnD,UAAE,eAAe;AACjB,iBAAS,MAAM,KAAK,QAAQ,MAAM,GAAG,MAAM;AAAA,MAC7C,WAAW,EAAE,QAAQ,eAAe,EAAE,QAAQ,WAAW;AACvD,UAAE,eAAe;AACjB,iBAAS,MAAM,IAAI,QAAQ,UAAU,QAAQ,MAAM,GAAG,MAAM;AAAA,MAC9D;AAAA,IACF,CAAC;AACD,oBAAgB,MAAM,UAAU;AAAA,EAClC,CAAC;AACH;AAEA,SAAS,YAAY,WAAoB,SAAuB;AAE9D,YAAU,iBAAiB,kBAAkB,EAAE,QAAQ,OAAK;AAC1D,MAAE,UAAU,OAAO,WAAW;AAC9B,MAAE,aAAa,iBAAiB,OAAO;AACvC,MAAE,aAAa,YAAY,IAAI;AAAA,EACjC,CAAC;AAGD,QAAM,aAAa,UAAU,QAAQ,0BAA0B,KAAK;AACpE,aAAW,iBAAiB,oBAAoB,EAAE,QAAQ,OAAK;AAC7D,MAAE,UAAU,OAAO,WAAW;AAC9B,MAAE,aAAa,eAAe,MAAM;AAAA,EACtC,CAAC;AAGD,QAAM,YAAY,UAAU,cAA2B,oBAAoB,OAAO,IAAI;AACtF,aAAW,UAAU,IAAI,WAAW;AACpC,aAAW,aAAa,iBAAiB,MAAM;AAC/C,aAAW,aAAa,YAAY,GAAG;AAGvC,QAAM,cAAc,WAAW,cAA2B,sBAAsB,OAAO,IAAI;AAC3F,eAAa,UAAU,IAAI,WAAW;AACtC,eAAa,aAAa,eAAe,OAAO;AAClD;AAIA,SAAS,WAAW,IAAa,MAAqB;AACpD,QAAM,MAAM,IAAI;AAAA,IACd,CAAC,YAAY;AACX,cAAQ,QAAQ,WAAS;AACvB,YAAI,MAAM,gBAAgB;AACxB,gBAAM,OAAO,UAAU,IAAI,YAAY;AACvC,cAAI,UAAU,MAAM,MAAM;AAAA,QAC5B;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,EAAE,WAAW,KAAK,YAAY,oBAAoB;AAAA,EACpD;AACA,MAAI,QAAQ,EAAE;AACd,kBAAgB,MAAM,MAAM,IAAI,WAAW,CAAC;AAC9C;AAIA,SAAS,YAAY,WAA0B;AAC7C,QAAM,WAAW,CAAC,GAAG,UAAU,QAAQ;AACvC,WAAS,QAAQ,CAAC,OAAO,MAAM;AAC7B,UAAM,MAAM,YAAY,iBAAiB,OAAO,CAAC,CAAC;AAAA,EACpD,CAAC;AACH;AAIA,SAAS,SAAS,IAAa,MAAqB;AAClD,QAAM,SAAS;AACf,QAAM,WAAW;AAEjB,QAAM,cAAc,YAAY,QAAQ,aAAa,CAAC,MAAM;AAC1D,UAAM,OAAO,OAAO,sBAAsB;AAC1C,UAAM,KAAK,EAAE,UAAU,KAAK,QAAQ,KAAK,QAAQ;AACjD,UAAM,KAAK,EAAE,UAAU,KAAK,OAAO,KAAK,SAAS;AACjD,WAAO,MAAM,YAAY,8BAA8B,IAAI,QAAQ,gBAAgB,CAAC,IAAI,QAAQ;AAChG,WAAO,MAAM,aAAa;AAAA,EAC5B,CAAC;AAED,QAAM,eAAe,YAAY,QAAQ,cAAc,MAAM;AAC3D,WAAO,MAAM,YAAY;AACzB,WAAO,MAAM,aAAa;AAAA,EAC5B,CAAC;AAED,kBAAgB,MAAM,WAAW;AACjC,kBAAgB,MAAM,YAAY;AACpC;AAIA,SAAS,aAAa,IAAa,MAAqB;AACtD,QAAM,SAAS;AACf,QAAM,OAAO;AAEb,QAAM,cAAc,YAAY,QAAQ,aAAa,CAAC,MAAM;AAC1D,UAAM,OAAO,OAAO,sBAAsB;AAC1C,UAAM,KAAK,KAAK,OAAO,KAAK,QAAQ;AACpC,UAAM,KAAK,KAAK,MAAM,KAAK,SAAS;AACpC,UAAM,MAAM,EAAE,UAAU,MAAM;AAC9B,UAAM,MAAM,EAAE,UAAU,MAAM;AAC9B,WAAO,MAAM,YAAY,aAAa,EAAE,OAAO,EAAE;AACjD,WAAO,MAAM,aAAa;AAAA,EAC5B,CAAC;AAED,QAAM,eAAe,YAAY,QAAQ,cAAc,MAAM;AAC3D,WAAO,MAAM,YAAY;AACzB,WAAO,MAAM,aAAa;AAAA,EAC5B,CAAC;AAED,kBAAgB,MAAM,WAAW;AACjC,kBAAgB,MAAM,YAAY;AACpC;AAQO,SAAS,KAAK,OAAgB,SAAS,iBAAuB;AAEnE,OAAK,iBAAiB,wBAAwB,EAAE,QAAQ,QAAM,cAAc,IAAI,IAAI,CAAC;AAGrF,OAAK,iBAAiB,oBAAoB,EAAE,QAAQ,QAAM,UAAU,IAAI,IAAI,CAAC;AAG7E,OAAK,iBAAiB,qBAAqB,EAAE,QAAQ,QAAM,WAAW,IAAI,IAAI,CAAC;AAG/E,OAAK,iBAAiB,uBAAuB,EAAE,QAAQ,QAAM,aAAa,IAAI,IAAI,CAAC;AAGnF,OAAK,iBAAiB,mBAAmB,EAAE,QAAQ,QAAM,SAAS,IAAI,IAAI,CAAC;AAG3E,OAAK,iBAAiB,qBAAqB,EAAE,QAAQ,QAAM,WAAW,IAAI,IAAI,CAAC;AAG/E,OAAK,iBAAiB,sBAAsB,EAAE,QAAQ,QAAM,YAAY,EAAE,CAAC;AAG3E,OAAK,iBAAiB,mBAAmB,EAAE,QAAQ,QAAM,SAAS,IAAI,IAAI,CAAC;AAG3E,OAAK,iBAAiB,uBAAuB,EAAE,QAAQ,QAAM,aAAa,IAAI,IAAI,CAAC;AACrF;AAKO,SAAS,QAAQ,OAAgB,SAAS,iBAAuB;AACtE,QAAM,WAAW,gBAAgB,IAAI,IAAI,KAAK,CAAC;AAC/C,WAAS,QAAQ,QAAM,GAAG,CAAC;AAC3B,kBAAgB,OAAO,IAAI;AAC7B;","names":["cleanup"]}
1
+ {"version":3,"sources":["../src/runtime.ts"],"sourcesContent":["/**\n * AliveUI Runtime\n *\n * Provides data-attribute-driven interactivity for accordion, modal, drawer,\n * dropdown, and tabs components — zero dependencies, ~2 KB.\n *\n * Usage:\n * import { init } from '@alivecss/aliveui/runtime'\n * init() // wire everything in document\n * init(myRootElement) // wire a subtree\n */\n\ntype Cleanup = () => void\n\nconst cleanupRegistry = new WeakMap<Element, Cleanup[]>()\n\nfunction registerCleanup(root: Element, fn: Cleanup): void {\n const existing = cleanupRegistry.get(root) ?? []\n existing.push(fn)\n cleanupRegistry.set(root, existing)\n}\n\nfunction addListener<K extends keyof HTMLElementEventMap>(\n el: EventTarget,\n type: K,\n handler: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n): Cleanup {\n el.addEventListener(type, handler as EventListener, options)\n return () => el.removeEventListener(type, handler as EventListener, options)\n}\n\n// ── Accordion ─────────────────────────────────────────────────────────────────\n\nfunction wireAccordion(container: Element, root: Element): void {\n const triggers = container.querySelectorAll<HTMLElement>('[data-alive-trigger]')\n triggers.forEach(trigger => {\n const item = trigger.closest('[data-alive-accordion-item]') ?? trigger.parentElement\n if (!item) return\n\n const cleanup = addListener(trigger, 'click', () => {\n const isOpen = item.classList.contains('is-open')\n // Close all items if not multi-open\n if (!container.hasAttribute('data-alive-multi')) {\n container.querySelectorAll('[data-alive-accordion-item]').forEach(i => {\n i.classList.remove('is-open')\n i.querySelector('[data-alive-trigger]')?.setAttribute('aria-expanded', 'false')\n })\n }\n if (!isOpen) {\n item.classList.add('is-open')\n trigger.setAttribute('aria-expanded', 'true')\n }\n })\n registerCleanup(root, cleanup)\n })\n}\n\n// ── Modal ─────────────────────────────────────────────────────────────────────\n\nfunction wireModal(modal: Element, root: Element): void {\n const id = modal.getAttribute('data-alive-modal')\n if (!id) return\n\n // Open triggers\n const openers = document.querySelectorAll<HTMLElement>(`[data-alive-open=\"${id}\"]`)\n openers.forEach(opener => {\n const cleanup = addListener(opener, 'click', () => openModal(id))\n registerCleanup(root, cleanup)\n })\n\n // Close triggers inside the modal\n modal.querySelectorAll<HTMLElement>('[data-alive-close]').forEach(closer => {\n const cleanup = addListener(closer, 'click', () => closeModal(id))\n registerCleanup(root, cleanup)\n })\n\n // Backdrop click to close (click on the modal wrapper, not the content)\n const cleanup = addListener(modal, 'click', (e) => {\n if (e.target === modal) closeModal(id)\n })\n registerCleanup(root, cleanup)\n\n // ESC key\n const escCleanup = addListener(document, 'keydown', (e) => {\n if (e.key === 'Escape' && modal.classList.contains('is-open')) closeModal(id)\n })\n registerCleanup(root, escCleanup)\n}\n\nexport function openModal(id: string): void {\n const modal = document.querySelector<HTMLElement>(`[data-alive-modal=\"${id}\"]`)\n if (!modal) return\n modal.classList.add('is-open')\n modal.setAttribute('aria-hidden', 'false')\n document.body.style.overflow = 'hidden'\n // Focus first focusable element\n const focusable = modal.querySelector<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n )\n focusable?.focus()\n}\n\nexport function closeModal(id: string): void {\n const modal = document.querySelector<HTMLElement>(`[data-alive-modal=\"${id}\"]`)\n if (!modal) return\n modal.classList.remove('is-open')\n modal.setAttribute('aria-hidden', 'true')\n document.body.style.overflow = ''\n}\n\n// ── Drawer ────────────────────────────────────────────────────────────────────\n\nfunction wireDrawer(drawer: Element, root: Element): void {\n const id = drawer.getAttribute('data-alive-drawer')\n if (!id) return\n\n const openers = document.querySelectorAll<HTMLElement>(`[data-alive-open=\"${id}\"]`)\n openers.forEach(opener => {\n const cleanup = addListener(opener, 'click', () => openDrawer(id))\n registerCleanup(root, cleanup)\n })\n\n drawer.querySelectorAll<HTMLElement>('[data-alive-close]').forEach(closer => {\n const cleanup = addListener(closer, 'click', () => closeDrawer(id))\n registerCleanup(root, cleanup)\n })\n\n const backdropCleanup = addListener(drawer, 'click', (e) => {\n if (e.target === drawer) closeDrawer(id)\n })\n registerCleanup(root, backdropCleanup)\n\n const escCleanup = addListener(document, 'keydown', (e) => {\n if (e.key === 'Escape' && drawer.classList.contains('is-open')) closeDrawer(id)\n })\n registerCleanup(root, escCleanup)\n}\n\nexport function openDrawer(id: string): void {\n const drawer = document.querySelector<HTMLElement>(`[data-alive-drawer=\"${id}\"]`)\n if (!drawer) return\n drawer.classList.add('is-open')\n drawer.setAttribute('aria-hidden', 'false')\n document.body.style.overflow = 'hidden'\n}\n\nexport function closeDrawer(id: string): void {\n const drawer = document.querySelector<HTMLElement>(`[data-alive-drawer=\"${id}\"]`)\n if (!drawer) return\n drawer.classList.remove('is-open')\n drawer.setAttribute('aria-hidden', 'true')\n document.body.style.overflow = ''\n}\n\n// ── Dropdown ──────────────────────────────────────────────────────────────────\n\nfunction wireDropdown(container: Element, root: Element): void {\n const trigger = container.querySelector<HTMLElement>('[data-alive-trigger]')\n const menu = container.querySelector<HTMLElement>('[data-alive-dropdown-menu]')\n if (!trigger || !menu) return\n\n const toggleCleanup = addListener(trigger, 'click', (e) => {\n e.stopPropagation()\n toggleDropdown(container)\n })\n registerCleanup(root, toggleCleanup)\n\n // Close on outside click\n const outsideCleanup = addListener(document, 'click', (e) => {\n if (!container.contains(e.target as Node)) {\n menu.classList.remove('is-open')\n trigger.setAttribute('aria-expanded', 'false')\n }\n })\n registerCleanup(root, outsideCleanup)\n\n // Close on ESC\n const escCleanup = addListener(document, 'keydown', (e) => {\n if (e.key === 'Escape' && menu.classList.contains('is-open')) {\n menu.classList.remove('is-open')\n trigger.setAttribute('aria-expanded', 'false')\n trigger.focus()\n }\n })\n registerCleanup(root, escCleanup)\n}\n\nexport function toggleDropdown(container: Element): void {\n const trigger = container.querySelector<HTMLElement>('[data-alive-trigger]')\n const menu = container.querySelector<HTMLElement>('[data-alive-dropdown-menu]')\n if (!menu) return\n const isOpen = menu.classList.toggle('is-open')\n trigger?.setAttribute('aria-expanded', String(isOpen))\n if (isOpen) {\n // Focus first item\n menu.querySelector<HTMLElement>('[role=\"menuitem\"], button, a')?.focus()\n }\n}\n\n// ── Tabs ──────────────────────────────────────────────────────────────────────\n\nfunction wireTabs(container: Element, root: Element): void {\n const tabs = container.querySelectorAll<HTMLElement>('[data-alive-tab]')\n tabs.forEach(tab => {\n const cleanup = addListener(tab, 'click', () => {\n const panelId = tab.getAttribute('data-alive-tab')\n if (!panelId) return\n activateTab(container, panelId)\n })\n registerCleanup(root, cleanup)\n\n // Keyboard navigation\n const keyCleanup = addListener(tab, 'keydown', (e) => {\n const allTabs = [...container.querySelectorAll<HTMLElement>('[data-alive-tab]')]\n const idx = allTabs.indexOf(tab)\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault()\n allTabs[(idx + 1) % allTabs.length]?.focus()\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault()\n allTabs[(idx - 1 + allTabs.length) % allTabs.length]?.focus()\n }\n })\n registerCleanup(root, keyCleanup)\n })\n}\n\nfunction activateTab(container: Element, panelId: string): void {\n // Deactivate all tabs + panels within this tabs container\n container.querySelectorAll('[data-alive-tab]').forEach(t => {\n t.classList.remove('is-active')\n t.setAttribute('aria-selected', 'false')\n t.setAttribute('tabindex', '-1')\n })\n\n // Find panels — look in the container, then in the whole document\n const searchRoot = container.closest('[data-alive-tabs-panels]') ?? document\n searchRoot.querySelectorAll('[data-alive-panel]').forEach(p => {\n p.classList.remove('is-active')\n p.setAttribute('aria-hidden', 'true')\n })\n\n // Activate the selected tab\n const activeTab = container.querySelector<HTMLElement>(`[data-alive-tab=\"${panelId}\"]`)\n activeTab?.classList.add('is-active')\n activeTab?.setAttribute('aria-selected', 'true')\n activeTab?.setAttribute('tabindex', '0')\n\n // Activate the matching panel\n const activePanel = searchRoot.querySelector<HTMLElement>(`[data-alive-panel=\"${panelId}\"]`)\n activePanel?.classList.add('is-active')\n activePanel?.setAttribute('aria-hidden', 'false')\n}\n\n// ── Scroll Reveal ──────────────────────────────────────────────────────────────\n\nfunction wireScroll(el: Element, root: Element): void {\n const obs = new IntersectionObserver(\n (entries) => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n entry.target.classList.add('is-visible')\n obs.unobserve(entry.target)\n }\n })\n },\n { threshold: 0.1, rootMargin: '0px 0px -40px 0px' },\n )\n obs.observe(el)\n registerCleanup(root, () => obs.disconnect())\n}\n\n// ── Auto-Stagger ───────────────────────────────────────────────────────────────\n\nfunction wireStagger(container: Element): void {\n const children = [...container.children] as HTMLElement[]\n children.forEach((child, i) => {\n child.style.setProperty('--alive-index', String(i))\n })\n}\n\n// ── 3D Tilt ────────────────────────────────────────────────────────────────────\n\nfunction wireTilt(el: Element, root: Element): void {\n const htmlEl = el as HTMLElement\n const STRENGTH = 8\n\n const moveCleanup = addListener(htmlEl, 'mousemove', (e) => {\n const rect = htmlEl.getBoundingClientRect()\n const x = (e.clientX - rect.left) / rect.width - 0.5\n const y = (e.clientY - rect.top) / rect.height - 0.5\n htmlEl.style.transform = `perspective(800px) rotateY(${x * STRENGTH}deg) rotateX(${-y * STRENGTH}deg) scale(1.01)`\n htmlEl.style.transition = 'transform 0.1s ease-out'\n })\n\n const leaveCleanup = addListener(htmlEl, 'mouseleave', () => {\n htmlEl.style.transform = ''\n htmlEl.style.transition = 'transform 0.4s cubic-bezier(0.16, 1, 0.3, 1)'\n })\n\n registerCleanup(root, moveCleanup)\n registerCleanup(root, leaveCleanup)\n}\n\n// ── Magnetic Follow ────────────────────────────────────────────────────────────\n\nfunction wireMagnetic(el: Element, root: Element): void {\n const htmlEl = el as HTMLElement\n const PULL = 0.35\n\n const moveCleanup = addListener(htmlEl, 'mousemove', (e) => {\n const rect = htmlEl.getBoundingClientRect()\n const cx = rect.left + rect.width / 2\n const cy = rect.top + rect.height / 2\n const dx = (e.clientX - cx) * PULL\n const dy = (e.clientY - cy) * PULL\n htmlEl.style.transform = `translate(${dx}px, ${dy}px)`\n htmlEl.style.transition = 'transform 0.2s cubic-bezier(0.16, 1, 0.3, 1)'\n })\n\n const leaveCleanup = addListener(htmlEl, 'mouseleave', () => {\n htmlEl.style.transform = ''\n htmlEl.style.transition = 'transform 0.5s cubic-bezier(0.16, 1, 0.3, 1)'\n })\n\n registerCleanup(root, moveCleanup)\n registerCleanup(root, leaveCleanup)\n}\n\n// ── Video Scene Sequencer ──────────────────────────────────────────────────────\n\n/**\n * Force-restart CSS animations on all animated children of a scene element.\n * This ensures stagger delays are relative to scene activation, not page load.\n */\nfunction resetSceneAnimations(scene: HTMLElement): void {\n const animated = scene.querySelectorAll<HTMLElement>(\n '[class*=\"alive-enter\"], [class*=\"alive-loop\"], ' +\n '.alive-typewriter, .alive-typewriter-fast, .alive-typewriter-slow, ' +\n '.alive-word-reveal > *, .alive-kinetic-slam, ' +\n '.alive-metric-card, .alive-toast, .alive-badge-pulse, ' +\n '.alive-spotlight, .alive-code-block',\n )\n animated.forEach(el => {\n const saved = el.style.animationName\n el.style.animationName = 'none'\n void el.offsetHeight // force reflow — restarts animation from t=0\n el.style.animationName = saved\n })\n}\n\n/**\n * Wire a [data-alive-sequence] container.\n *\n * Markup:\n * <div data-alive-sequence data-alive-loop style=\"position:relative; width:800px; height:500px;\">\n * <div data-alive-scene data-alive-duration=\"3000\" data-alive-transition=\"wipe-left\">…</div>\n * <div data-alive-scene data-alive-duration=\"2500\" data-alive-transition=\"fade\">…</div>\n * </div>\n *\n * Scene attributes:\n * data-alive-duration — how long to show the scene (ms, default 3000)\n * data-alive-transition — transition type (default \"fade\"; matches alive-transition-* classes)\n * data-alive-trans-duration — transition animation duration (ms, default 600)\n *\n * Sequence attributes:\n * data-alive-loop — loop back to the first scene after the last\n */\nfunction wireVideoSequence(container: Element, root: Element): void {\n const scenes = [...container.querySelectorAll<HTMLElement>(':scope > [data-alive-scene]')]\n if (scenes.length === 0) return\n\n const loop = container.hasAttribute('data-alive-loop')\n let current = 0\n let timeoutId: ReturnType<typeof setTimeout> | null = null\n\n const containerEl = container as HTMLElement\n if (getComputedStyle(containerEl).position === 'static') {\n containerEl.style.position = 'relative'\n }\n containerEl.style.overflow = 'hidden'\n\n scenes.forEach(s => {\n s.style.position = 'absolute'\n s.style.inset = '0'\n s.classList.remove('is-active')\n })\n\n function activate(index: number): void {\n const scene = scenes[index]\n resetSceneAnimations(scene)\n scene.classList.add('is-active')\n scene.style.zIndex = '1'\n }\n\n function scheduleNext(fromIndex: number): void {\n const scene = scenes[fromIndex]\n const duration = parseInt(scene.getAttribute('data-alive-duration') ?? '3000', 10)\n\n timeoutId = setTimeout(() => {\n const nextIndex = fromIndex + 1\n const toIndex = nextIndex >= scenes.length ? (loop ? 0 : -1) : nextIndex\n if (toIndex === -1) return\n doTransition(fromIndex, toIndex)\n }, duration)\n }\n\n function doTransition(fromIndex: number, toIndex: number): void {\n const outScene = scenes[fromIndex]\n const inScene = scenes[toIndex]\n const transType = outScene.getAttribute('data-alive-transition') ?? 'fade'\n const transDur = parseInt(outScene.getAttribute('data-alive-trans-duration') ?? '600', 10)\n\n const outClass = `alive-transition-${transType}-out`\n const inClass = `alive-transition-${transType}-in`\n\n // Sync CSS animation duration with the JS timer\n outScene.style.setProperty('--alive-tr-dur', `${transDur}ms`)\n inScene.style.setProperty('--alive-tr-dur', `${transDur}ms`)\n\n // Outgoing goes on top (required for wipe/clip-path transitions)\n outScene.style.zIndex = '2'\n outScene.classList.add(outClass)\n\n // Activate incoming beneath, reset its child animations\n inScene.style.zIndex = '1'\n resetSceneAnimations(inScene)\n inScene.classList.add('is-active', inClass)\n\n timeoutId = setTimeout(() => {\n outScene.classList.remove('is-active', outClass)\n outScene.style.zIndex = ''\n outScene.style.removeProperty('--alive-tr-dur')\n inScene.classList.remove(inClass)\n inScene.style.removeProperty('--alive-tr-dur')\n current = toIndex\n scheduleNext(current)\n }, transDur)\n }\n\n activate(current)\n scheduleNext(current)\n\n registerCleanup(root, () => {\n if (timeoutId) clearTimeout(timeoutId)\n })\n}\n\n// ── Public API ────────────────────────────────────────────────────────────────\n\n/**\n * Wire all data-alive-* components within `root` (defaults to document.documentElement).\n * Safe to call multiple times — existing listeners are tracked and replaced on `destroy()`.\n */\nexport function init(root: Element = document.documentElement): void {\n // Accordion\n root.querySelectorAll('[data-alive-accordion]').forEach(el => wireAccordion(el, root))\n\n // Modal\n root.querySelectorAll('[data-alive-modal]').forEach(el => wireModal(el, root))\n\n // Drawer\n root.querySelectorAll('[data-alive-drawer]').forEach(el => wireDrawer(el, root))\n\n // Dropdown\n root.querySelectorAll('[data-alive-dropdown]').forEach(el => wireDropdown(el, root))\n\n // Tabs\n root.querySelectorAll('[data-alive-tabs]').forEach(el => wireTabs(el, root))\n\n // Scroll reveal\n root.querySelectorAll('[data-alive-scroll]').forEach(el => wireScroll(el, root))\n\n // Auto-stagger children\n root.querySelectorAll('[data-alive-stagger]').forEach(el => wireStagger(el))\n\n // 3D tilt\n root.querySelectorAll('[data-alive-tilt]').forEach(el => wireTilt(el, root))\n\n // Magnetic follow\n root.querySelectorAll('[data-alive-magnetic]').forEach(el => wireMagnetic(el, root))\n\n // Video scene sequencer\n root.querySelectorAll('[data-alive-sequence]').forEach(el => wireVideoSequence(el, root))\n}\n\n/**\n * Remove all event listeners registered by `init(root)`.\n */\nexport function destroy(root: Element = document.documentElement): void {\n const cleanups = cleanupRegistry.get(root) ?? []\n cleanups.forEach(fn => fn())\n cleanupRegistry.delete(root)\n}\n"],"mappings":"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","names":["cleanup"]}
package/dist/vite.js CHANGED
@@ -2675,14 +2675,14 @@ video {
2675
2675
  gap: 10px;
2676
2676
  padding: 12px 18px;
2677
2677
  border-radius: 14px;
2678
- background: rgba(255,255,255,0.08);
2678
+ background: var(--alive-toast-bg, rgba(255,255,255,0.08));
2679
2679
  backdrop-filter: blur(16px);
2680
2680
  -webkit-backdrop-filter: blur(16px);
2681
- border: 1px solid rgba(255,255,255,0.12);
2681
+ border: 1px solid var(--alive-toast-border, rgba(255,255,255,0.12));
2682
2682
  box-shadow: 0 8px 32px rgba(0,0,0,0.24), 0 1px 0 rgba(255,255,255,0.06) inset;
2683
2683
  font-size: 0.875rem;
2684
2684
  font-weight: 500;
2685
- color: #fff;
2685
+ color: var(--alive-toast-color, #fff);
2686
2686
  animation: alive-toast-loop 5s cubic-bezier(0.22, 1, 0.36, 1) infinite both;
2687
2687
  }
2688
2688
  .alive-toast-icon {
@@ -2694,7 +2694,8 @@ video {
2694
2694
  justify-content: center;
2695
2695
  flex-shrink: 0;
2696
2696
  font-size: 14px;
2697
- background: rgba(255,255,255,0.1);
2697
+ background: var(--alive-toast-icon-bg, rgba(255,255,255,0.1));
2698
+ color: var(--alive-toast-icon-color, currentColor);
2698
2699
  }
2699
2700
  .alive-toast-title { font-weight: 600; font-size: 0.875rem; }
2700
2701
  .alive-toast-body { font-size: 0.8125rem; opacity: 0.65; margin-top: 1px; }
@@ -2728,7 +2729,7 @@ video {
2728
2729
  .alive-typewriter {
2729
2730
  display: inline-block;
2730
2731
  white-space: nowrap;
2731
- border-right: 2px solid currentColor;
2732
+ border-right: 2px solid var(--alive-typewriter-cursor, currentColor);
2732
2733
  animation:
2733
2734
  alive-type-in 2s steps(40, end) both,
2734
2735
  alive-blink 0.8s step-end infinite;
@@ -2927,7 +2928,7 @@ video {
2927
2928
  position: absolute;
2928
2929
  inset: -24px;
2929
2930
  border-radius: inherit;
2930
- background: radial-gradient(ellipse at center, rgba(99,102,241,0.25) 0%, rgba(99,102,241,0.08) 50%, transparent 70%);
2931
+ background: radial-gradient(ellipse at center, var(--alive-spotlight-color, rgba(99,102,241,0.25)) 0%, var(--alive-spotlight-color-mid, rgba(99,102,241,0.08)) 50%, transparent 70%);
2931
2932
  animation: alive-spotlight-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
2932
2933
  pointer-events: none;
2933
2934
  z-index: -1;
@@ -2937,8 +2938,8 @@ video {
2937
2938
  position: absolute;
2938
2939
  inset: -4px;
2939
2940
  border-radius: inherit;
2940
- border: 1px solid rgba(99,102,241,0.4);
2941
- box-shadow: 0 0 24px rgba(99,102,241,0.3), 0 0 48px rgba(99,102,241,0.15);
2941
+ border: 1px solid var(--alive-spotlight-ring-color, rgba(99,102,241,0.4));
2942
+ box-shadow: 0 0 24px var(--alive-spotlight-glow, rgba(99,102,241,0.3)), 0 0 48px var(--alive-spotlight-glow-far, rgba(99,102,241,0.15));
2942
2943
  animation: alive-spotlight-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
2943
2944
  pointer-events: none;
2944
2945
  }
@@ -2964,6 +2965,9 @@ video {
2964
2965
  font-size: 0.75rem;
2965
2966
  font-weight: 600;
2966
2967
  letter-spacing: 0.02em;
2968
+ background: var(--alive-badge-bg, transparent);
2969
+ color: var(--alive-badge-color, inherit);
2970
+ border: 1px solid var(--alive-badge-border, transparent);
2967
2971
  animation: alive-badge-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
2968
2972
  }
2969
2973
  .alive-badge-pulse .alive-badge-dot {
@@ -2972,6 +2976,7 @@ video {
2972
2976
  height: 8px;
2973
2977
  border-radius: 50%;
2974
2978
  flex-shrink: 0;
2979
+ background: var(--alive-badge-dot, currentColor);
2975
2980
  }
2976
2981
  .alive-badge-pulse .alive-badge-dot::before {
2977
2982
  content: '';
@@ -3188,8 +3193,8 @@ video {
3188
3193
  gap: 8px;
3189
3194
  padding: 20px 24px;
3190
3195
  border-radius: 14px;
3191
- background: rgba(255,255,255,0.04);
3192
- border: 1px solid rgba(255,255,255,0.08);
3196
+ background: var(--alive-metric-bg, rgba(255,255,255,0.04));
3197
+ border: 1px solid var(--alive-metric-border, rgba(255,255,255,0.08));
3193
3198
  animation: alive-metric-in 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
3194
3199
  min-width: 160px;
3195
3200
  }
@@ -3198,14 +3203,14 @@ video {
3198
3203
  font-weight: 500;
3199
3204
  text-transform: uppercase;
3200
3205
  letter-spacing: 0.07em;
3201
- color: rgba(255,255,255,0.4);
3206
+ color: var(--alive-metric-label-color, rgba(255,255,255,0.4));
3202
3207
  }
3203
3208
  .alive-metric-card-value {
3204
3209
  font-size: 2.25rem;
3205
3210
  font-weight: 800;
3206
3211
  letter-spacing: -0.04em;
3207
3212
  line-height: 1;
3208
- color: #fff;
3213
+ color: var(--alive-metric-value-color, #fff);
3209
3214
  }
3210
3215
  .alive-metric-card-change {
3211
3216
  display: inline-flex;
@@ -3229,7 +3234,7 @@ video {
3229
3234
  .alive-metric-card-bar-fill {
3230
3235
  height: 100%;
3231
3236
  border-radius: 2px;
3232
- background: linear-gradient(90deg, #6366f1, #8b5cf6, #6366f1);
3237
+ background: linear-gradient(90deg, var(--alive-metric-accent, #6366f1), var(--alive-metric-accent-2, #8b5cf6), var(--alive-metric-accent, #6366f1));
3233
3238
  background-size: 200% auto;
3234
3239
  transform-origin: left;
3235
3240
  animation:
@@ -4563,6 +4568,32 @@ video {
4563
4568
  .alive-meteor:nth-child(2) { top: 25%; left: 30%; animation-delay: 0.8s; animation-duration: 1.8s; width: 40px; }
4564
4569
  .alive-meteor:nth-child(3) { top: 5%; left: 60%; animation-delay: 1.5s; animation-duration: 2.5s; }
4565
4570
  .alive-meteor:nth-child(4) { top: 40%; left: 75%; animation-delay: 0.4s; animation-duration: 1.6s; width: 80px; }
4571
+
4572
+ /* \u2500\u2500 Scene Sequencer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
4573
+ Pair with [data-alive-sequence] + [data-alive-scene] attributes.
4574
+ The runtime (./runtime) drives is-active and transition classes.
4575
+ See: data-alive-duration, data-alive-transition, data-alive-loop.
4576
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
4577
+ [data-alive-sequence] {
4578
+ position: relative;
4579
+ overflow: hidden;
4580
+ }
4581
+ [data-alive-scene] {
4582
+ position: absolute;
4583
+ inset: 0;
4584
+ opacity: 0;
4585
+ pointer-events: none;
4586
+ }
4587
+ [data-alive-scene].is-active {
4588
+ opacity: 1;
4589
+ pointer-events: auto;
4590
+ z-index: 1;
4591
+ }
4592
+ /* Outgoing scene (has a -out class) must stay visible during the transition */
4593
+ [data-alive-scene][class*="-out"] {
4594
+ opacity: 1;
4595
+ z-index: 2;
4596
+ }
4566
4597
  `;
4567
4598
  }
4568
4599
  var init_base = __esm({