@alfadocs/ui-kit 0.0.15 → 0.0.17

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.
@@ -145,10 +145,10 @@ const ae = 'ヲァィゥェォャュョッーアイウエオカキクケコサ
145
145
  const t = typeof window < "u" && typeof window.matchMedia == "function" ? window.matchMedia("(prefers-reduced-motion: reduce)") : null;
146
146
  if (t != null && t.matches) return;
147
147
  const A = v || (typeof window > "u" ? "" : getComputedStyle(document.documentElement).getPropertyValue(le[P]).trim() || getComputedStyle(o).color), Q = typeof window > "u" ? "monospace" : getComputedStyle(document.documentElement).getPropertyValue("--font-mono").trim() || "monospace", h = window.devicePixelRatio || 1;
148
- let c = 0, g = [], d = [], E = [];
148
+ let c = 0, b = [], d = [], E = [];
149
149
  const R = () => {
150
150
  const n = o.getBoundingClientRect();
151
- if (o.width = Math.max(1, Math.floor(n.width * h)), o.height = Math.max(1, Math.floor(n.height * h)), e.setTransform(h, 0, 0, h, 0, 0), c = Math.max(1, Math.floor(n.width / l)), g = new Array(c).fill(0).map(
151
+ if (o.width = Math.max(1, Math.floor(n.width * h)), o.height = Math.max(1, Math.floor(n.height * h)), e.setTransform(h, 0, 0, h, 0, 0), c = Math.max(1, Math.floor(n.width / l)), b = new Array(c).fill(0).map(
152
152
  () => (
153
153
  // Random initial offset so columns never start in sync.
154
154
  Math.floor(Math.random() * (n.height / l))
@@ -174,34 +174,34 @@ const ae = 'ヲァィゥェォャュョッーアイウエオカキクケコサ
174
174
  for (let a = 0; a < c; a += 1) {
175
175
  const w = x.charAt(
176
176
  Math.floor(Math.random() * x.length)
177
- ), N = u ? (Math.random() - 0.5) * 2 : 0, U = a * l + N, T = g[a] * l;
178
- i === "synthwave" && d[a] && (e.fillStyle = d[a], L && (e.shadowColor = d[a])), e.fillText(w, U, T), T > r.height && Math.random() > 0.97 && (g[a] = 0), g[a] += u && E[a] || 1;
177
+ ), N = u ? (Math.random() - 0.5) * 2 : 0, U = a * l + N, T = b[a] * l;
178
+ i === "synthwave" && d[a] && (e.fillStyle = d[a], L && (e.shadowColor = d[a])), e.fillText(w, U, T), T > r.height && Math.random() > 0.97 && (b[a] = 0), b[a] += u && E[a] || 1;
179
179
  }
180
180
  }
181
181
  f = window.requestAnimationFrame(B);
182
- }, b = () => {
182
+ }, g = () => {
183
183
  f || !S || !k || (C = window.performance ? window.performance.now() : 0, f = window.requestAnimationFrame(B));
184
184
  }, _ = () => {
185
185
  f && (window.cancelAnimationFrame(f), f = 0);
186
186
  };
187
- R(), b();
187
+ R(), g();
188
188
  const s = typeof ResizeObserver < "u" ? new ResizeObserver(R) : null;
189
189
  s == null || s.observe(o);
190
190
  const Y = () => R();
191
191
  s || window.addEventListener("resize", Y);
192
192
  const j = () => {
193
- S = !document.hidden, S ? b() : _();
193
+ S = !document.hidden, S ? g() : _();
194
194
  };
195
195
  document.addEventListener("visibilitychange", j);
196
196
  const m = typeof IntersectionObserver < "u" ? new IntersectionObserver(
197
197
  (n) => {
198
- k = n.some((r) => r.isIntersecting), k ? b() : _();
198
+ k = n.some((r) => r.isIntersecting), k ? g() : _();
199
199
  },
200
200
  { threshold: 0 }
201
201
  ) : null;
202
202
  m == null || m.observe(o);
203
203
  const F = () => {
204
- t != null && t.matches ? _() : b();
204
+ t != null && t.matches ? _() : g();
205
205
  };
206
206
  return (H = t == null ? void 0 : t.addEventListener) == null || H.call(t, "change", F), () => {
207
207
  var n;
@@ -225,7 +225,7 @@ const ae = 'ヲァィゥェォャュョッーアイウエオカキクケコサ
225
225
  se({ background: X, vibe: i, mask: D, maskRadius: K }),
226
226
  W
227
227
  ].filter(Boolean).join(" "),
228
- children: /* @__PURE__ */ G("canvas", { ref: V, className: "block size-full" })
228
+ children: /* @__PURE__ */ G("canvas", { ref: V, className: "absolute inset-0 block size-full" })
229
229
  }
230
230
  );
231
231
  }
@@ -234,4 +234,4 @@ de.displayName = "MatrixRain";
234
234
  export {
235
235
  de as M
236
236
  };
237
- //# sourceMappingURL=matrix-rain-C2kqBVxr.js.map
237
+ //# sourceMappingURL=matrix-rain-Q7xTEpKu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"matrix-rain-C2kqBVxr.js","sources":["../../src/components/matrix-rain/matrix-rain.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* MatrixRain — decorative canvas overlay. */\n/* */\n/* Falling-glyph \"digital rain\" with a CRT terminal vibe. Designed for */\n/* easter-egg / dev-flavoured surfaces: place inside a relatively- */\n/* positioned container with an `inset-0` className. */\n/* */\n/* Behaviour: */\n/* - Honours `prefers-reduced-motion` (renders nothing, animation off). */\n/* - Pauses while the tab is hidden (visibility API). */\n/* - Pauses when scrolled off-screen (IntersectionObserver). */\n/* - DPR-aware so glyphs stay sharp on HiDPI. */\n/* - Resizes with the container (ResizeObserver). */\n/* - \"Density-by-use\" trail: the per-frame decay alpha is small, so */\n/* columns that fire often accumulate a denser background residue */\n/* than rarely-firing ones — well-trodden paths stay luminous. */\n/* */\n/* The canvas is purely decorative — `aria-hidden=\"true\"`, no focus, no */\n/* visible text. Consumers must own the parent's positioning + stacking. */\n/* -------------------------------------------------------------------- */\n\nimport { forwardRef, useEffect, useMemo, useRef } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\n/* ------------------------------------------------------------------ */\n/* Glyph presets */\n/* ------------------------------------------------------------------ */\n\n/**\n * Half-width katakana + Latin digits + a few symbols. The canonical\n * Matrix used reverse-mirrored half-width katakana from a custom font;\n * plain half-width katakana is the closest open approximation.\n */\nconst KATAKANA_GLYPHS =\n 'ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワ' +\n '0123456789:・.\"=*+-<>¦|';\n\nconst HEX_GLYPHS = '0123456789ABCDEF{}[]<>/\\\\;:=$#@!*+-';\nconst BINARY_GLYPHS = '01';\nconst SYMBOL_GLYPHS = '!@#$%^&*()_+-=[]{}|;:,.<>?/';\n\nconst GLYPH_PRESETS = {\n katakana: KATAKANA_GLYPHS,\n hex: HEX_GLYPHS,\n binary: BINARY_GLYPHS,\n symbols: SYMBOL_GLYPHS,\n} as const;\n\ntype GlyphPreset = keyof typeof GLYPH_PRESETS;\n\n/* ------------------------------------------------------------------ */\n/* CVA variants */\n/* ------------------------------------------------------------------ */\n\nconst wrapperVariants = cva(\n // Wrapper holds the canvas plus optional overlay pseudo-elements.\n // pointer-events-none so the overlay never blocks underlying UI.\n 'pointer-events-none relative overflow-hidden',\n {\n variants: {\n // Built-in surface so the rain has somewhere to read against\n // without the consumer wrapping it themselves.\n // `transparent` (default) lets the parent provide the background.\n // `solid` paints a near-black surface using the brand `blue-900`\n // step from the palette — the rain's brightest glyphs read clean\n // against it in either light or dark theme.\n background: {\n transparent: '',\n solid: 'bg-[var(--color-blue-900)]',\n },\n vibe: {\n // No overlay, no canvas filter — just the rain.\n clean: '',\n // Fallout-CRT stack: vignette + dense scanlines + bloom +\n // per-glyph phosphor glow (canvas-side shadowBlur, applied in\n // the draw loop).\n terminal: [\n \"before:pointer-events-none before:absolute before:inset-0 before:z-[2] before:content-['']\",\n 'before:bg-[radial-gradient(closest-side,transparent_55%,rgb(0_0_0/0.55)_100%)]',\n \"after:pointer-events-none after:absolute after:inset-0 after:z-[1] after:content-['']\",\n 'after:bg-[repeating-linear-gradient(to_bottom,transparent_0,transparent_2px,rgb(0_0_0/0.32)_2px,rgb(0_0_0/0.32)_3px)]',\n 'after:mix-blend-multiply',\n '[&>canvas]:[filter:blur(0.55px)_brightness(1.25)_contrast(1.1)_saturate(1.3)]',\n ].join(' '),\n // Sci-fi HUD: light scanlines, soft bloom, slow opacity pulse,\n // per-glyph glow. No vignette.\n hologram: [\n \"after:pointer-events-none after:absolute after:inset-0 after:z-[1] after:content-['']\",\n 'after:bg-[repeating-linear-gradient(to_bottom,transparent_0,transparent_3px,rgb(0_0_0/0.18)_3px,rgb(0_0_0/0.18)_4px)]',\n 'after:mix-blend-multiply',\n '[&>canvas]:[filter:blur(0.4px)_brightness(1.15)_contrast(1.05)]',\n '[&>canvas]:[animation:matrix-rain-hologram-pulse_3s_ease-in-out_infinite]',\n ].join(' '),\n // Synthwave neon: heavy bloom, no scanlines, indigo horizon\n // glow at the bottom. Glyph colour is computed per-column in\n // the draw loop (accent → info gradient).\n synthwave: [\n \"after:pointer-events-none after:absolute after:inset-x-0 after:bottom-0 after:h-[30%] after:z-[1] after:content-['']\",\n 'after:bg-[linear-gradient(to_top,var(--color-indigo-800),transparent)]',\n 'after:opacity-50',\n '[&>canvas]:[filter:blur(0.7px)_brightness(1.3)_contrast(1.15)_saturate(1.5)]',\n ].join(' '),\n // Vintage scope monitor: dense thin scanlines, sharp edges\n // (no canvas filter), animated horizontal sweep beam.\n oscilloscope: [\n // Scanlines (denser, alpha-heavier than terminal)\n \"after:pointer-events-none after:absolute after:inset-0 after:z-[1] after:content-['']\",\n 'after:bg-[repeating-linear-gradient(to_bottom,transparent_0,transparent_1px,rgb(0_0_0/0.4)_1px,rgb(0_0_0/0.4)_2px)]',\n 'after:mix-blend-multiply',\n // Sweep beam — thin highlight bar scrolling top → bottom\n \"before:pointer-events-none before:absolute before:inset-x-0 before:top-0 before:z-[2] before:h-[4px] before:content-['']\",\n 'before:bg-[linear-gradient(to_bottom,transparent,var(--foreground),transparent)]',\n 'before:opacity-50',\n 'before:[animation:matrix-rain-osc-sweep_4s_linear_infinite]',\n 'before:mix-blend-screen',\n ].join(' '),\n // Production-friendly: low opacity, no overlay. Pairs with\n // `decay=\"slow\"` (the default) for a faint background-noise\n // feel that doesn't dominate foreground content.\n ghost: '[&>canvas]:opacity-30',\n },\n // Radial mask that fades the canvas to transparent in the middle\n // so foreground content stays readable. `closest-side` adapts to\n // non-square containers. The `--mr` custom property comes from\n // the `maskRadius` variant below.\n mask: {\n none: '',\n center: [\n '[&>canvas]:[mask-image:radial-gradient(closest-side,transparent_0%,transparent_var(--mr,30%),black_calc(var(--mr,30%)+45%))]',\n '[&>canvas]:[-webkit-mask-image:radial-gradient(closest-side,transparent_0%,transparent_var(--mr,30%),black_calc(var(--mr,30%)+45%))]',\n ].join(' '),\n },\n // Mask radius — t-shirt sizes drive the inner clear-zone radius.\n // Only applied when mask=\"center\". md (30%) is the default.\n maskRadius: {\n xs: '[--mr:15%]',\n sm: '[--mr:22%]',\n md: '[--mr:30%]',\n lg: '[--mr:42%]',\n xl: '[--mr:55%]',\n },\n },\n defaultVariants: {\n background: 'transparent',\n vibe: 'clean',\n mask: 'none',\n maskRadius: 'md',\n },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Tone → semantic token resolution */\n/* ------------------------------------------------------------------ */\n\ntype Tone = 'primary' | 'accent' | 'success' | 'error' | 'info';\ntype Density = 'low' | 'medium' | 'high';\ntype Pace = 'gentle' | 'normal' | 'fast';\ntype Decay = 'none' | 'slow' | 'normal' | 'fast';\n\nconst TONE_VAR: Record<Tone, string> = {\n primary: '--primary',\n accent: '--accent',\n success: '--success',\n error: '--error',\n info: '--info',\n};\n\nconst DENSITY_FONT_PX: Record<Density, number> = {\n low: 18,\n medium: 14,\n high: 11,\n};\n\nconst PACE_FRAME_MS: Record<Pace, number> = {\n gentle: 100,\n normal: 60,\n fast: 33,\n};\n\n// Per-frame trail decay alpha. Smaller = trails persist longer = more\n// \"density by use\". `none` skips the decay step entirely; over long\n// uptimes the canvas approaches a saturated noise field. `slow` is the\n// new default that produces the \"well-trodden paths stay bright\" feel.\nconst DECAY_ALPHA: Record<Decay, number | null> = {\n none: null,\n slow: 0.003,\n normal: 0.02,\n fast: 0.08,\n};\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\nexport interface MatrixRainProps extends VariantProps<typeof wrapperVariants> {\n /** Glyph preset name or a literal string of glyphs. Default `katakana`. */\n glyphs?: GlyphPreset | string;\n /** Brand tone for the rain. Resolved against the active theme. */\n tone?: Tone;\n /** Optional explicit colour — any CSS colour value. Overrides `tone` when set. */\n color?: string;\n /** Glyph density — controls font-size. */\n density?: Density;\n /** Animation pace — controls frame interval. */\n pace?: Pace;\n /** Trail persistence — smaller decay = denser cumulative background. */\n decay?: Decay;\n /**\n * Built-in surface beneath the rain. `transparent` (default) lets the\n * parent provide its own background; `solid` paints a near-black\n * surface so the rain reads cleanly without the consumer wrapping it\n * themselves — useful for standalone demos or full-bleed easter eggs.\n */\n background?: 'transparent' | 'solid';\n /**\n * Visual treatment.\n * - `clean` — just the rain.\n * - `terminal` — Fallout-CRT: vignette + scanlines + bloom + glow.\n * - `hologram` — sci-fi HUD: soft scanlines + slow opacity pulse.\n * - `synthwave` — 80s neon: heavy bloom + indigo horizon + accent→\n * info gradient across columns (overrides `tone`).\n * - `oscilloscope` — vintage scope: sharp edges + dense scanlines +\n * animated horizontal beam sweep.\n * - `ghost` — production-friendly faint background variant.\n */\n vibe?: 'clean' | 'terminal' | 'hologram' | 'synthwave' | 'oscilloscope' | 'ghost';\n /**\n * When `true`, gives each column a stable random speed multiplier\n * (0.6×–1.4× of the base pace) and adds a small horizontal jitter to\n * each glyph. Pairs with any vibe — makes the rain feel alive vs.\n * metronomic.\n */\n storm?: boolean;\n /**\n * Radial mask. `center` fades the canvas to fully transparent in the\n * middle so foreground content sitting over the rain stays readable\n * (e.g. code-block easter egg with copy in the middle).\n */\n mask?: 'none' | 'center';\n /**\n * Inner clear-zone radius for `mask=\"center\"`. Ignored when `mask`\n * is `none`. T-shirt sizes map to: xs 15%, sm 22%, md 30% (default),\n * lg 42%, xl 55%.\n */\n maskRadius?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** Class merged onto the wrapper. */\n className?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const MatrixRain = forwardRef<HTMLDivElement, MatrixRainProps>(\n function MatrixRain(\n {\n glyphs = 'katakana',\n tone = 'primary',\n color,\n density = 'medium',\n pace = 'normal',\n decay = 'slow',\n vibe = 'clean',\n storm = false,\n mask = 'none',\n maskRadius = 'md',\n background = 'transparent',\n className,\n },\n ref,\n ) {\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n\n // Resolve the glyph string from a preset key or literal pass-through.\n const glyphString = useMemo<string>(() => {\n if (glyphs in GLYPH_PRESETS) {\n return GLYPH_PRESETS[glyphs as GlyphPreset];\n }\n return glyphs;\n }, [glyphs]);\n\n const fontSize = DENSITY_FONT_PX[density];\n const frameInterval = PACE_FRAME_MS[pace];\n const decayAlpha = DECAY_ALPHA[decay];\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n // Bail entirely under reduced-motion. The CSS overlay is also\n // suppressed by media-query in the consumer's stylesheet if needed\n // — defence in depth, but the JS is the authoritative gate here.\n const reduceMotionMql =\n typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia('(prefers-reduced-motion: reduce)')\n : null;\n if (reduceMotionMql?.matches) return;\n\n // Resolve colour: explicit prop wins; otherwise read the theme\n // token. Final fallback is the canvas's inherited `color` (cascade\n // of the host `<div>`), which the browser always resolves to a\n // usable value — keeps a literal hex out of component code.\n const resolvedColor = (() => {\n if (color) return color;\n if (typeof window === 'undefined') return '';\n const fromVar = getComputedStyle(document.documentElement)\n .getPropertyValue(TONE_VAR[tone])\n .trim();\n return fromVar || getComputedStyle(canvas).color;\n })();\n\n // Resolve --font-mono at runtime so the kit's font fallback chain\n // (incl. Noto Sans JP for katakana) flows through to canvas.\n const fontFamily = (() => {\n if (typeof window === 'undefined') return 'monospace';\n const fromVar = getComputedStyle(document.documentElement)\n .getPropertyValue('--font-mono')\n .trim();\n return fromVar || 'monospace';\n })();\n\n const dpr = window.devicePixelRatio || 1;\n let columns = 0;\n let drops: number[] = [];\n // Synthwave: per-column accent → info gradient. Resolved through\n // a temporary probe element so we get back fully-resolved rgb()\n // strings the canvas API accepts. Empty when not in synthwave.\n let columnColors: string[] = [];\n // Storm: per-column random speed factor (0.6×–1.4× base pace) +\n // glyph horizontal jitter. Stable across frames, recomputed on\n // each fit() so columns stay coherent.\n let columnSpeeds: number[] = [];\n\n const fit = () => {\n const rect = canvas.getBoundingClientRect();\n canvas.width = Math.max(1, Math.floor(rect.width * dpr));\n canvas.height = Math.max(1, Math.floor(rect.height * dpr));\n // Render in CSS pixels so font metrics stay sharp on HiDPI.\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n columns = Math.max(1, Math.floor(rect.width / fontSize));\n drops = new Array(columns).fill(0).map(() =>\n // Random initial offset so columns never start in sync.\n Math.floor(Math.random() * (rect.height / fontSize)),\n );\n\n if (vibe === 'synthwave') {\n // Build the per-column gradient by resolving color-mix()\n // through a probe span. Browser handles the OKLCH math; we\n // just store the resulting rgb() string per column.\n const probe = document.createElement('span');\n probe.style.display = 'none';\n document.documentElement.appendChild(probe);\n columnColors = new Array(columns).fill('').map((_, i) => {\n const t = (i / Math.max(1, columns - 1)) * 100;\n probe.style.color = `color-mix(in oklch, var(--accent) ${\n 100 - t\n }%, var(--info) ${t}%)`;\n const computed = getComputedStyle(probe).color;\n return computed || resolvedColor;\n });\n document.documentElement.removeChild(probe);\n } else {\n columnColors = [];\n }\n\n if (storm) {\n columnSpeeds = new Array(columns)\n .fill(0)\n .map(() => 0.6 + Math.random() * 0.8);\n } else {\n columnSpeeds = [];\n }\n };\n\n let lastFrame = 0;\n let rafHandle = 0;\n let isVisible = true;\n let isOnscreen = true;\n\n const draw = (now: number) => {\n if (now - lastFrame >= frameInterval) {\n lastFrame = now;\n const rect = canvas.getBoundingClientRect();\n\n // Trail decay — `destination-out` fades existing pixels by\n // `decayAlpha` each frame. Skip when `decay === 'none'` so\n // trails are permanent (eventually saturate; intended).\n // Under `destination-out` only the alpha channel matters, so\n // we drive the fade via `globalAlpha` and any opaque CSS-keyword\n // fillStyle — no rgba literal needed.\n if (decayAlpha !== null) {\n ctx.globalCompositeOperation = 'destination-out';\n ctx.globalAlpha = decayAlpha;\n ctx.fillStyle = 'black';\n ctx.fillRect(0, 0, rect.width, rect.height);\n ctx.globalAlpha = 1;\n }\n\n ctx.globalCompositeOperation = 'source-over';\n ctx.font = `${fontSize}px ${fontFamily}`;\n ctx.textBaseline = 'top';\n // Per-glyph phosphor glow (canvas shadowBlur). On for vibes\n // that need an emission envelope; off for sharp variants.\n const wantsGlow =\n vibe === 'terminal' || vibe === 'hologram' || vibe === 'synthwave';\n if (wantsGlow) {\n ctx.shadowColor = resolvedColor;\n ctx.shadowBlur = Math.max(4, fontSize * 0.6);\n } else {\n ctx.shadowBlur = 0;\n }\n\n // Default fill (overridden per-column for synthwave).\n if (vibe !== 'synthwave') ctx.fillStyle = resolvedColor;\n\n for (let i = 0; i < columns; i += 1) {\n const ch = glyphString.charAt(\n Math.floor(Math.random() * glyphString.length),\n );\n // Storm: small horizontal jitter so rows feel alive.\n const jitter = storm ? (Math.random() - 0.5) * 2 : 0;\n const x = i * fontSize + jitter;\n const y = drops[i] * fontSize;\n\n // Synthwave: gradient colour per column.\n if (vibe === 'synthwave' && columnColors[i]) {\n ctx.fillStyle = columnColors[i];\n if (wantsGlow) ctx.shadowColor = columnColors[i];\n }\n\n ctx.fillText(ch, x, y);\n\n // Reset randomly once past the bottom so columns restart\n // staggered rather than all at once.\n if (y > rect.height && Math.random() > 0.97) {\n drops[i] = 0;\n }\n // Storm: per-column variable advance speed.\n drops[i] += storm ? columnSpeeds[i] || 1 : 1;\n }\n }\n rafHandle = window.requestAnimationFrame(draw);\n };\n\n const start = () => {\n if (rafHandle) return;\n if (!isVisible || !isOnscreen) return;\n lastFrame = window.performance ? window.performance.now() : 0;\n rafHandle = window.requestAnimationFrame(draw);\n };\n const stop = () => {\n if (rafHandle) {\n window.cancelAnimationFrame(rafHandle);\n rafHandle = 0;\n }\n };\n\n fit();\n start();\n\n // Resize with the container.\n const resizeObserver =\n typeof ResizeObserver !== 'undefined' ? new ResizeObserver(fit) : null;\n resizeObserver?.observe(canvas);\n const onWindowResize = () => fit();\n if (!resizeObserver) window.addEventListener('resize', onWindowResize);\n\n // Pause when tab is hidden.\n const onVisibility = () => {\n isVisible = !document.hidden;\n if (isVisible) start();\n else stop();\n };\n document.addEventListener('visibilitychange', onVisibility);\n\n // Pause when scrolled off-screen.\n const intersectionObserver =\n typeof IntersectionObserver !== 'undefined'\n ? new IntersectionObserver(\n (entries) => {\n isOnscreen = entries.some((e) => e.isIntersecting);\n if (isOnscreen) start();\n else stop();\n },\n { threshold: 0 },\n )\n : null;\n intersectionObserver?.observe(canvas);\n\n // Pause if reduced-motion gets toggled at runtime.\n const onReduceMotionChange = () => {\n if (reduceMotionMql?.matches) stop();\n else start();\n };\n reduceMotionMql?.addEventListener?.('change', onReduceMotionChange);\n\n return () => {\n stop();\n resizeObserver?.disconnect();\n intersectionObserver?.disconnect();\n if (!resizeObserver) window.removeEventListener('resize', onWindowResize);\n document.removeEventListener('visibilitychange', onVisibility);\n reduceMotionMql?.removeEventListener?.('change', onReduceMotionChange);\n };\n }, [\n glyphString,\n tone,\n color,\n fontSize,\n frameInterval,\n decayAlpha,\n vibe,\n storm,\n ]);\n\n return (\n <div\n ref={ref}\n aria-hidden=\"true\"\n className={[\n wrapperVariants({ background, vibe, mask, maskRadius }),\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n >\n <canvas ref={canvasRef} className=\"block size-full\" />\n </div>\n );\n },\n);\n\nMatrixRain.displayName = 'MatrixRain';\n"],"names":["KATAKANA_GLYPHS","HEX_GLYPHS","BINARY_GLYPHS","SYMBOL_GLYPHS","GLYPH_PRESETS","wrapperVariants","cva","TONE_VAR","DENSITY_FONT_PX","PACE_FRAME_MS","DECAY_ALPHA","MatrixRain","forwardRef","glyphs","tone","color","density","pace","decay","vibe","storm","mask","maskRadius","background","className","ref","canvasRef","useRef","glyphString","useMemo","fontSize","frameInterval","decayAlpha","useEffect","canvas","ctx","reduceMotionMql","resolvedColor","fontFamily","dpr","columns","drops","columnColors","columnSpeeds","fit","rect","probe","_","i","t","lastFrame","rafHandle","isVisible","isOnscreen","draw","now","wantsGlow","ch","jitter","x","y","start","stop","resizeObserver","onWindowResize","onVisibility","intersectionObserver","entries","e","onReduceMotionChange","_a","jsx"],"mappings":"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"}
1
+ {"version":3,"file":"matrix-rain-Q7xTEpKu.js","sources":["../../src/components/matrix-rain/matrix-rain.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* MatrixRain — decorative canvas overlay. */\n/* */\n/* Falling-glyph \"digital rain\" with a CRT terminal vibe. Designed for */\n/* easter-egg / dev-flavoured surfaces: place inside a relatively- */\n/* positioned container with an `inset-0` className. */\n/* */\n/* Behaviour: */\n/* - Honours `prefers-reduced-motion` (renders nothing, animation off). */\n/* - Pauses while the tab is hidden (visibility API). */\n/* - Pauses when scrolled off-screen (IntersectionObserver). */\n/* - DPR-aware so glyphs stay sharp on HiDPI. */\n/* - Resizes with the container (ResizeObserver). */\n/* - \"Density-by-use\" trail: the per-frame decay alpha is small, so */\n/* columns that fire often accumulate a denser background residue */\n/* than rarely-firing ones — well-trodden paths stay luminous. */\n/* */\n/* The canvas is purely decorative — `aria-hidden=\"true\"`, no focus, no */\n/* visible text. Consumers must own the parent's positioning + stacking. */\n/* -------------------------------------------------------------------- */\n\nimport { forwardRef, useEffect, useMemo, useRef } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\n\n/* ------------------------------------------------------------------ */\n/* Glyph presets */\n/* ------------------------------------------------------------------ */\n\n/**\n * Half-width katakana + Latin digits + a few symbols. The canonical\n * Matrix used reverse-mirrored half-width katakana from a custom font;\n * plain half-width katakana is the closest open approximation.\n */\nconst KATAKANA_GLYPHS =\n 'ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワ' +\n '0123456789:・.\"=*+-<>¦|';\n\nconst HEX_GLYPHS = '0123456789ABCDEF{}[]<>/\\\\;:=$#@!*+-';\nconst BINARY_GLYPHS = '01';\nconst SYMBOL_GLYPHS = '!@#$%^&*()_+-=[]{}|;:,.<>?/';\n\nconst GLYPH_PRESETS = {\n katakana: KATAKANA_GLYPHS,\n hex: HEX_GLYPHS,\n binary: BINARY_GLYPHS,\n symbols: SYMBOL_GLYPHS,\n} as const;\n\ntype GlyphPreset = keyof typeof GLYPH_PRESETS;\n\n/* ------------------------------------------------------------------ */\n/* CVA variants */\n/* ------------------------------------------------------------------ */\n\nconst wrapperVariants = cva(\n // Wrapper holds the canvas plus optional overlay pseudo-elements.\n // pointer-events-none so the overlay never blocks underlying UI.\n 'pointer-events-none relative overflow-hidden',\n {\n variants: {\n // Built-in surface so the rain has somewhere to read against\n // without the consumer wrapping it themselves.\n // `transparent` (default) lets the parent provide the background.\n // `solid` paints a near-black surface using the brand `blue-900`\n // step from the palette — the rain's brightest glyphs read clean\n // against it in either light or dark theme.\n background: {\n transparent: '',\n solid: 'bg-[var(--color-blue-900)]',\n },\n vibe: {\n // No overlay, no canvas filter — just the rain.\n clean: '',\n // Fallout-CRT stack: vignette + dense scanlines + bloom +\n // per-glyph phosphor glow (canvas-side shadowBlur, applied in\n // the draw loop).\n terminal: [\n \"before:pointer-events-none before:absolute before:inset-0 before:z-[2] before:content-['']\",\n 'before:bg-[radial-gradient(closest-side,transparent_55%,rgb(0_0_0/0.55)_100%)]',\n \"after:pointer-events-none after:absolute after:inset-0 after:z-[1] after:content-['']\",\n 'after:bg-[repeating-linear-gradient(to_bottom,transparent_0,transparent_2px,rgb(0_0_0/0.32)_2px,rgb(0_0_0/0.32)_3px)]',\n 'after:mix-blend-multiply',\n '[&>canvas]:[filter:blur(0.55px)_brightness(1.25)_contrast(1.1)_saturate(1.3)]',\n ].join(' '),\n // Sci-fi HUD: light scanlines, soft bloom, slow opacity pulse,\n // per-glyph glow. No vignette.\n hologram: [\n \"after:pointer-events-none after:absolute after:inset-0 after:z-[1] after:content-['']\",\n 'after:bg-[repeating-linear-gradient(to_bottom,transparent_0,transparent_3px,rgb(0_0_0/0.18)_3px,rgb(0_0_0/0.18)_4px)]',\n 'after:mix-blend-multiply',\n '[&>canvas]:[filter:blur(0.4px)_brightness(1.15)_contrast(1.05)]',\n '[&>canvas]:[animation:matrix-rain-hologram-pulse_3s_ease-in-out_infinite]',\n ].join(' '),\n // Synthwave neon: heavy bloom, no scanlines, indigo horizon\n // glow at the bottom. Glyph colour is computed per-column in\n // the draw loop (accent → info gradient).\n synthwave: [\n \"after:pointer-events-none after:absolute after:inset-x-0 after:bottom-0 after:h-[30%] after:z-[1] after:content-['']\",\n 'after:bg-[linear-gradient(to_top,var(--color-indigo-800),transparent)]',\n 'after:opacity-50',\n '[&>canvas]:[filter:blur(0.7px)_brightness(1.3)_contrast(1.15)_saturate(1.5)]',\n ].join(' '),\n // Vintage scope monitor: dense thin scanlines, sharp edges\n // (no canvas filter), animated horizontal sweep beam.\n oscilloscope: [\n // Scanlines (denser, alpha-heavier than terminal)\n \"after:pointer-events-none after:absolute after:inset-0 after:z-[1] after:content-['']\",\n 'after:bg-[repeating-linear-gradient(to_bottom,transparent_0,transparent_1px,rgb(0_0_0/0.4)_1px,rgb(0_0_0/0.4)_2px)]',\n 'after:mix-blend-multiply',\n // Sweep beam — thin highlight bar scrolling top → bottom\n \"before:pointer-events-none before:absolute before:inset-x-0 before:top-0 before:z-[2] before:h-[4px] before:content-['']\",\n 'before:bg-[linear-gradient(to_bottom,transparent,var(--foreground),transparent)]',\n 'before:opacity-50',\n 'before:[animation:matrix-rain-osc-sweep_4s_linear_infinite]',\n 'before:mix-blend-screen',\n ].join(' '),\n // Production-friendly: low opacity, no overlay. Pairs with\n // `decay=\"slow\"` (the default) for a faint background-noise\n // feel that doesn't dominate foreground content.\n ghost: '[&>canvas]:opacity-30',\n },\n // Radial mask that fades the canvas to transparent in the middle\n // so foreground content stays readable. `closest-side` adapts to\n // non-square containers. The `--mr` custom property comes from\n // the `maskRadius` variant below.\n mask: {\n none: '',\n center: [\n '[&>canvas]:[mask-image:radial-gradient(closest-side,transparent_0%,transparent_var(--mr,30%),black_calc(var(--mr,30%)+45%))]',\n '[&>canvas]:[-webkit-mask-image:radial-gradient(closest-side,transparent_0%,transparent_var(--mr,30%),black_calc(var(--mr,30%)+45%))]',\n ].join(' '),\n },\n // Mask radius — t-shirt sizes drive the inner clear-zone radius.\n // Only applied when mask=\"center\". md (30%) is the default.\n maskRadius: {\n xs: '[--mr:15%]',\n sm: '[--mr:22%]',\n md: '[--mr:30%]',\n lg: '[--mr:42%]',\n xl: '[--mr:55%]',\n },\n },\n defaultVariants: {\n background: 'transparent',\n vibe: 'clean',\n mask: 'none',\n maskRadius: 'md',\n },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Tone → semantic token resolution */\n/* ------------------------------------------------------------------ */\n\ntype Tone = 'primary' | 'accent' | 'success' | 'error' | 'info';\ntype Density = 'low' | 'medium' | 'high';\ntype Pace = 'gentle' | 'normal' | 'fast';\ntype Decay = 'none' | 'slow' | 'normal' | 'fast';\n\nconst TONE_VAR: Record<Tone, string> = {\n primary: '--primary',\n accent: '--accent',\n success: '--success',\n error: '--error',\n info: '--info',\n};\n\nconst DENSITY_FONT_PX: Record<Density, number> = {\n low: 18,\n medium: 14,\n high: 11,\n};\n\nconst PACE_FRAME_MS: Record<Pace, number> = {\n gentle: 100,\n normal: 60,\n fast: 33,\n};\n\n// Per-frame trail decay alpha. Smaller = trails persist longer = more\n// \"density by use\". `none` skips the decay step entirely; over long\n// uptimes the canvas approaches a saturated noise field. `slow` is the\n// new default that produces the \"well-trodden paths stay bright\" feel.\nconst DECAY_ALPHA: Record<Decay, number | null> = {\n none: null,\n slow: 0.003,\n normal: 0.02,\n fast: 0.08,\n};\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\nexport interface MatrixRainProps extends VariantProps<typeof wrapperVariants> {\n /** Glyph preset name or a literal string of glyphs. Default `katakana`. */\n glyphs?: GlyphPreset | string;\n /** Brand tone for the rain. Resolved against the active theme. */\n tone?: Tone;\n /** Optional explicit colour — any CSS colour value. Overrides `tone` when set. */\n color?: string;\n /** Glyph density — controls font-size. */\n density?: Density;\n /** Animation pace — controls frame interval. */\n pace?: Pace;\n /** Trail persistence — smaller decay = denser cumulative background. */\n decay?: Decay;\n /**\n * Built-in surface beneath the rain. `transparent` (default) lets the\n * parent provide its own background; `solid` paints a near-black\n * surface so the rain reads cleanly without the consumer wrapping it\n * themselves — useful for standalone demos or full-bleed easter eggs.\n */\n background?: 'transparent' | 'solid';\n /**\n * Visual treatment.\n * - `clean` — just the rain.\n * - `terminal` — Fallout-CRT: vignette + scanlines + bloom + glow.\n * - `hologram` — sci-fi HUD: soft scanlines + slow opacity pulse.\n * - `synthwave` — 80s neon: heavy bloom + indigo horizon + accent→\n * info gradient across columns (overrides `tone`).\n * - `oscilloscope` — vintage scope: sharp edges + dense scanlines +\n * animated horizontal beam sweep.\n * - `ghost` — production-friendly faint background variant.\n */\n vibe?: 'clean' | 'terminal' | 'hologram' | 'synthwave' | 'oscilloscope' | 'ghost';\n /**\n * When `true`, gives each column a stable random speed multiplier\n * (0.6×–1.4× of the base pace) and adds a small horizontal jitter to\n * each glyph. Pairs with any vibe — makes the rain feel alive vs.\n * metronomic.\n */\n storm?: boolean;\n /**\n * Radial mask. `center` fades the canvas to fully transparent in the\n * middle so foreground content sitting over the rain stays readable\n * (e.g. code-block easter egg with copy in the middle).\n */\n mask?: 'none' | 'center';\n /**\n * Inner clear-zone radius for `mask=\"center\"`. Ignored when `mask`\n * is `none`. T-shirt sizes map to: xs 15%, sm 22%, md 30% (default),\n * lg 42%, xl 55%.\n */\n maskRadius?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** Class merged onto the wrapper. */\n className?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const MatrixRain = forwardRef<HTMLDivElement, MatrixRainProps>(\n function MatrixRain(\n {\n glyphs = 'katakana',\n tone = 'primary',\n color,\n density = 'medium',\n pace = 'normal',\n decay = 'slow',\n vibe = 'clean',\n storm = false,\n mask = 'none',\n maskRadius = 'md',\n background = 'transparent',\n className,\n },\n ref,\n ) {\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n\n // Resolve the glyph string from a preset key or literal pass-through.\n const glyphString = useMemo<string>(() => {\n if (glyphs in GLYPH_PRESETS) {\n return GLYPH_PRESETS[glyphs as GlyphPreset];\n }\n return glyphs;\n }, [glyphs]);\n\n const fontSize = DENSITY_FONT_PX[density];\n const frameInterval = PACE_FRAME_MS[pace];\n const decayAlpha = DECAY_ALPHA[decay];\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n // Bail entirely under reduced-motion. The CSS overlay is also\n // suppressed by media-query in the consumer's stylesheet if needed\n // — defence in depth, but the JS is the authoritative gate here.\n const reduceMotionMql =\n typeof window !== 'undefined' && typeof window.matchMedia === 'function'\n ? window.matchMedia('(prefers-reduced-motion: reduce)')\n : null;\n if (reduceMotionMql?.matches) return;\n\n // Resolve colour: explicit prop wins; otherwise read the theme\n // token. Final fallback is the canvas's inherited `color` (cascade\n // of the host `<div>`), which the browser always resolves to a\n // usable value — keeps a literal hex out of component code.\n const resolvedColor = (() => {\n if (color) return color;\n if (typeof window === 'undefined') return '';\n const fromVar = getComputedStyle(document.documentElement)\n .getPropertyValue(TONE_VAR[tone])\n .trim();\n return fromVar || getComputedStyle(canvas).color;\n })();\n\n // Resolve --font-mono at runtime so the kit's font fallback chain\n // (incl. Noto Sans JP for katakana) flows through to canvas.\n const fontFamily = (() => {\n if (typeof window === 'undefined') return 'monospace';\n const fromVar = getComputedStyle(document.documentElement)\n .getPropertyValue('--font-mono')\n .trim();\n return fromVar || 'monospace';\n })();\n\n const dpr = window.devicePixelRatio || 1;\n let columns = 0;\n let drops: number[] = [];\n // Synthwave: per-column accent → info gradient. Resolved through\n // a temporary probe element so we get back fully-resolved rgb()\n // strings the canvas API accepts. Empty when not in synthwave.\n let columnColors: string[] = [];\n // Storm: per-column random speed factor (0.6×–1.4× base pace) +\n // glyph horizontal jitter. Stable across frames, recomputed on\n // each fit() so columns stay coherent.\n let columnSpeeds: number[] = [];\n\n const fit = () => {\n const rect = canvas.getBoundingClientRect();\n canvas.width = Math.max(1, Math.floor(rect.width * dpr));\n canvas.height = Math.max(1, Math.floor(rect.height * dpr));\n // Render in CSS pixels so font metrics stay sharp on HiDPI.\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n columns = Math.max(1, Math.floor(rect.width / fontSize));\n drops = new Array(columns).fill(0).map(() =>\n // Random initial offset so columns never start in sync.\n Math.floor(Math.random() * (rect.height / fontSize)),\n );\n\n if (vibe === 'synthwave') {\n // Build the per-column gradient by resolving color-mix()\n // through a probe span. Browser handles the OKLCH math; we\n // just store the resulting rgb() string per column.\n const probe = document.createElement('span');\n probe.style.display = 'none';\n document.documentElement.appendChild(probe);\n columnColors = new Array(columns).fill('').map((_, i) => {\n const t = (i / Math.max(1, columns - 1)) * 100;\n probe.style.color = `color-mix(in oklch, var(--accent) ${\n 100 - t\n }%, var(--info) ${t}%)`;\n const computed = getComputedStyle(probe).color;\n return computed || resolvedColor;\n });\n document.documentElement.removeChild(probe);\n } else {\n columnColors = [];\n }\n\n if (storm) {\n columnSpeeds = new Array(columns)\n .fill(0)\n .map(() => 0.6 + Math.random() * 0.8);\n } else {\n columnSpeeds = [];\n }\n };\n\n let lastFrame = 0;\n let rafHandle = 0;\n let isVisible = true;\n let isOnscreen = true;\n\n const draw = (now: number) => {\n if (now - lastFrame >= frameInterval) {\n lastFrame = now;\n const rect = canvas.getBoundingClientRect();\n\n // Trail decay — `destination-out` fades existing pixels by\n // `decayAlpha` each frame. Skip when `decay === 'none'` so\n // trails are permanent (eventually saturate; intended).\n // Under `destination-out` only the alpha channel matters, so\n // we drive the fade via `globalAlpha` and any opaque CSS-keyword\n // fillStyle — no rgba literal needed.\n if (decayAlpha !== null) {\n ctx.globalCompositeOperation = 'destination-out';\n ctx.globalAlpha = decayAlpha;\n ctx.fillStyle = 'black';\n ctx.fillRect(0, 0, rect.width, rect.height);\n ctx.globalAlpha = 1;\n }\n\n ctx.globalCompositeOperation = 'source-over';\n ctx.font = `${fontSize}px ${fontFamily}`;\n ctx.textBaseline = 'top';\n // Per-glyph phosphor glow (canvas shadowBlur). On for vibes\n // that need an emission envelope; off for sharp variants.\n const wantsGlow =\n vibe === 'terminal' || vibe === 'hologram' || vibe === 'synthwave';\n if (wantsGlow) {\n ctx.shadowColor = resolvedColor;\n ctx.shadowBlur = Math.max(4, fontSize * 0.6);\n } else {\n ctx.shadowBlur = 0;\n }\n\n // Default fill (overridden per-column for synthwave).\n if (vibe !== 'synthwave') ctx.fillStyle = resolvedColor;\n\n for (let i = 0; i < columns; i += 1) {\n const ch = glyphString.charAt(\n Math.floor(Math.random() * glyphString.length),\n );\n // Storm: small horizontal jitter so rows feel alive.\n const jitter = storm ? (Math.random() - 0.5) * 2 : 0;\n const x = i * fontSize + jitter;\n const y = drops[i] * fontSize;\n\n // Synthwave: gradient colour per column.\n if (vibe === 'synthwave' && columnColors[i]) {\n ctx.fillStyle = columnColors[i];\n if (wantsGlow) ctx.shadowColor = columnColors[i];\n }\n\n ctx.fillText(ch, x, y);\n\n // Reset randomly once past the bottom so columns restart\n // staggered rather than all at once.\n if (y > rect.height && Math.random() > 0.97) {\n drops[i] = 0;\n }\n // Storm: per-column variable advance speed.\n drops[i] += storm ? columnSpeeds[i] || 1 : 1;\n }\n }\n rafHandle = window.requestAnimationFrame(draw);\n };\n\n const start = () => {\n if (rafHandle) return;\n if (!isVisible || !isOnscreen) return;\n lastFrame = window.performance ? window.performance.now() : 0;\n rafHandle = window.requestAnimationFrame(draw);\n };\n const stop = () => {\n if (rafHandle) {\n window.cancelAnimationFrame(rafHandle);\n rafHandle = 0;\n }\n };\n\n fit();\n start();\n\n // Resize with the container.\n const resizeObserver =\n typeof ResizeObserver !== 'undefined' ? new ResizeObserver(fit) : null;\n resizeObserver?.observe(canvas);\n const onWindowResize = () => fit();\n if (!resizeObserver) window.addEventListener('resize', onWindowResize);\n\n // Pause when tab is hidden.\n const onVisibility = () => {\n isVisible = !document.hidden;\n if (isVisible) start();\n else stop();\n };\n document.addEventListener('visibilitychange', onVisibility);\n\n // Pause when scrolled off-screen.\n const intersectionObserver =\n typeof IntersectionObserver !== 'undefined'\n ? new IntersectionObserver(\n (entries) => {\n isOnscreen = entries.some((e) => e.isIntersecting);\n if (isOnscreen) start();\n else stop();\n },\n { threshold: 0 },\n )\n : null;\n intersectionObserver?.observe(canvas);\n\n // Pause if reduced-motion gets toggled at runtime.\n const onReduceMotionChange = () => {\n if (reduceMotionMql?.matches) stop();\n else start();\n };\n reduceMotionMql?.addEventListener?.('change', onReduceMotionChange);\n\n return () => {\n stop();\n resizeObserver?.disconnect();\n intersectionObserver?.disconnect();\n if (!resizeObserver) window.removeEventListener('resize', onWindowResize);\n document.removeEventListener('visibilitychange', onVisibility);\n reduceMotionMql?.removeEventListener?.('change', onReduceMotionChange);\n };\n }, [\n glyphString,\n tone,\n color,\n fontSize,\n frameInterval,\n decayAlpha,\n vibe,\n storm,\n ]);\n\n return (\n <div\n ref={ref}\n aria-hidden=\"true\"\n className={[\n wrapperVariants({ background, vibe, mask, maskRadius }),\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n >\n <canvas ref={canvasRef} className=\"absolute inset-0 block size-full\" />\n </div>\n );\n },\n);\n\nMatrixRain.displayName = 'MatrixRain';\n"],"names":["KATAKANA_GLYPHS","HEX_GLYPHS","BINARY_GLYPHS","SYMBOL_GLYPHS","GLYPH_PRESETS","wrapperVariants","cva","TONE_VAR","DENSITY_FONT_PX","PACE_FRAME_MS","DECAY_ALPHA","MatrixRain","forwardRef","glyphs","tone","color","density","pace","decay","vibe","storm","mask","maskRadius","background","className","ref","canvasRef","useRef","glyphString","useMemo","fontSize","frameInterval","decayAlpha","useEffect","canvas","ctx","reduceMotionMql","resolvedColor","fontFamily","dpr","columns","drops","columnColors","columnSpeeds","fit","rect","probe","_","i","t","lastFrame","rafHandle","isVisible","isOnscreen","draw","now","wantsGlow","ch","jitter","x","y","start","stop","resizeObserver","onWindowResize","onVisibility","intersectionObserver","entries","e","onReduceMotionChange","_a","jsx"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { jsx as t } from "react/jsx-runtime";
2
+ import { forwardRef as e } from "react";
3
+ import { useTranslation as m } from "react-i18next";
4
+ import { B as c } from "./button-CXL8bA8G.js";
5
+ import { L as f } from "./logo-BlIdYz3n.js";
6
+ const u = e(({ label: o, type: r = "button", ...n }, i) => {
7
+ const { t: a } = m(), s = o ?? a("ui.auth.continueWithAlfadocs", "Continue with AlfaDocs");
8
+ return /* @__PURE__ */ t(
9
+ c,
10
+ {
11
+ ref: i,
12
+ type: r,
13
+ startIcon: /* @__PURE__ */ t(f, { variant: "mark", size: "sm", decorative: !0 }),
14
+ ...n,
15
+ children: s
16
+ }
17
+ );
18
+ });
19
+ u.displayName = "SignInWithAlfadocsButton";
20
+ export {
21
+ u as S
22
+ };
23
+ //# sourceMappingURL=sign-in-with-alfadocs-button-CprizH2U.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign-in-with-alfadocs-button-CprizH2U.js","sources":["../../src/components/sign-in-with-alfadocs-button/sign-in-with-alfadocs-button.tsx"],"sourcesContent":["import { forwardRef, type ReactNode } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Button, type ButtonProps } from '../button';\nimport { Logo } from '../logo';\n\n// A provider-style button (\"Sign in with AlfaDocs\"). Wraps the Button\n// primitive so it inherits the full intent / size / loading / asChild /\n// startIcon / endIcon / forced-colors / focus-ring contract for free.\n// The only additions are: a sensible default label resolved from the\n// `ui.auth.continueWithAlfadocs` translation key, and the AlfaDocs\n// brand mark rendered as a leading icon.\n\nexport interface SignInWithAlfadocsButtonProps\n extends Omit<ButtonProps, 'startIcon' | 'children'> {\n /**\n * Override the visible label. When omitted, the component reads\n * `ui.auth.continueWithAlfadocs` (English fallback: \"Continue with\n * AlfaDocs\"). Pass a node to render e.g. \"Sign in with AlfaDocs\" or a\n * fully-translated string.\n */\n label?: ReactNode;\n}\n\nexport const SignInWithAlfadocsButton = forwardRef<\n HTMLButtonElement,\n SignInWithAlfadocsButtonProps\n>(({ label, type = 'button', ...props }, ref) => {\n const { t } = useTranslation();\n const resolvedLabel =\n label ?? t('ui.auth.continueWithAlfadocs', 'Continue with AlfaDocs');\n\n return (\n <Button\n ref={ref}\n type={type}\n startIcon={<Logo variant=\"mark\" size=\"sm\" decorative />}\n {...props}\n >\n {resolvedLabel}\n </Button>\n );\n});\n\nSignInWithAlfadocsButton.displayName = 'SignInWithAlfadocsButton';\n"],"names":["SignInWithAlfadocsButton","forwardRef","label","type","props","ref","t","useTranslation","resolvedLabel","jsx","Button","Logo"],"mappings":";;;;;AAuBO,MAAMA,IAA2BC,EAGtC,CAAC,EAAE,OAAAC,GAAO,MAAAC,IAAO,UAAU,GAAGC,EAAA,GAASC,MAAQ;AAC/C,QAAM,EAAE,GAAAC,EAAA,IAAMC,EAAA,GACRC,IACJN,KAASI,EAAE,gCAAgC,wBAAwB;AAErE,SACE,gBAAAG;AAAA,IAACC;AAAA,IAAA;AAAA,MACC,KAAAL;AAAA,MACA,MAAAF;AAAA,MACA,6BAAYQ,GAAA,EAAK,SAAQ,QAAO,MAAK,MAAK,YAAU,IAAC;AAAA,MACpD,GAAGP;AAAA,MAEH,UAAAI;AAAA,IAAA;AAAA,EAAA;AAGP,CAAC;AAEDR,EAAyB,cAAc;"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "packageVersion": "0.0.15",
3
+ "packageVersion": "0.0.17",
4
4
  "components": [
5
5
  {
6
6
  "kind": "component",
@@ -1,4 +1,4 @@
1
- import { M as i } from "../../_chunks/matrix-rain-C2kqBVxr.js";
1
+ import { M as i } from "../../_chunks/matrix-rain-Q7xTEpKu.js";
2
2
  export {
3
3
  i as MatrixRain
4
4
  };
@@ -1,4 +1,4 @@
1
- import { S as n } from "../../_chunks/sign-in-with-alfadocs-button-Gu7Qk2gq.js";
1
+ import { S as n } from "../../_chunks/sign-in-with-alfadocs-button-CprizH2U.js";
2
2
  export {
3
3
  n as SignInWithAlfadocsButton
4
4
  };
@@ -1,15 +1,6 @@
1
- import { type ButtonHTMLAttributes, type ReactNode } from 'react';
2
- import { type VariantProps } from 'class-variance-authority';
3
- declare const signInVariants: (props?: ({
4
- surface?: "light" | "dark" | "auto" | null | undefined;
5
- size?: "sm" | "md" | "lg" | null | undefined;
6
- } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
- export interface SignInWithAlfadocsButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof signInVariants> {
8
- /**
9
- * Show the loading spinner and disable the button. Mirrors Button's
10
- * loading contract so the two can be swapped without surprise.
11
- */
12
- loading?: boolean;
1
+ import { type ReactNode } from 'react';
2
+ import { type ButtonProps } from '../button';
3
+ export interface SignInWithAlfadocsButtonProps extends Omit<ButtonProps, 'startIcon' | 'children'> {
13
4
  /**
14
5
  * Override the visible label. When omitted, the component reads
15
6
  * `ui.auth.continueWithAlfadocs` (English fallback: "Continue with
@@ -19,5 +10,4 @@ export interface SignInWithAlfadocsButtonProps extends ButtonHTMLAttributes<HTML
19
10
  label?: ReactNode;
20
11
  }
21
12
  export declare const SignInWithAlfadocsButton: import("react").ForwardRefExoticComponent<SignInWithAlfadocsButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
22
- export {};
23
13
  //# sourceMappingURL=sign-in-with-alfadocs-button.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sign-in-with-alfadocs-button.d.ts","sourceRoot":"","sources":["../../../src/components/sign-in-with-alfadocs-button/sign-in-with-alfadocs-button.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,oBAAoB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC9E,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AASlE,QAAA,MAAM,cAAc;;;8EAgDnB,CAAC;AAEF,MAAM,WAAW,6BACf,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC,EAC7C,YAAY,CAAC,OAAO,cAAc,CAAC;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED,eAAO,MAAM,wBAAwB,6HAyCpC,CAAC"}
1
+ {"version":3,"file":"sign-in-with-alfadocs-button.d.ts","sourceRoot":"","sources":["../../../src/components/sign-in-with-alfadocs-button/sign-in-with-alfadocs-button.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEnD,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAUrD,MAAM,WAAW,6BACf,SAAQ,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,UAAU,CAAC;IACnD;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED,eAAO,MAAM,wBAAwB,6HAkBnC,CAAC"}
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { b as S } from "./_chunks/button.agent-BuGZBktn.js";
6
6
  import { B as g } from "./_chunks/button-group-CI7LFxt3.js";
7
7
  import { F as C } from "./_chunks/floating-action-button-BM9ib-Wf.js";
8
8
  import { I as A } from "./_chunks/icon-button-group-tERESY-n.js";
9
- import { S as I } from "./_chunks/sign-in-with-alfadocs-button-Gu7Qk2gq.js";
9
+ import { S as I } from "./_chunks/sign-in-with-alfadocs-button-CprizH2U.js";
10
10
  import { SafeHtml as R, sanitiseHtml as E } from "./safe-html/index.js";
11
11
  import { A as N, a as F, b as k } from "./_chunks/autocomplete.agent-kb0nmr6F.js";
12
12
  import { C as M, a as D, u as V } from "./_chunks/checkbox-CfiZ0FZc.js";
@@ -69,7 +69,7 @@ import { A as Yo } from "./_chunks/alert-C5ud6CfE.js";
69
69
  import { D as zo, d as qo } from "./_chunks/dialog.agent-B276rAQF.js";
70
70
  import { D as Qo } from "./_chunks/dropdown-menu-CJKvK7VG.js";
71
71
  import { d as Zo } from "./_chunks/dropdown-menu.agent-Cry4Nmes.js";
72
- import { M as at } from "./_chunks/matrix-rain-C2kqBVxr.js";
72
+ import { M as at } from "./_chunks/matrix-rain-Q7xTEpKu.js";
73
73
  import { M as rt, i as ot } from "./_chunks/message-card-g5VS5Q80.js";
74
74
  import { M as st } from "./_chunks/message-tray-CAk-iibU.js";
75
75
  import { N as nt, i as mt } from "./_chunks/notification-card-CQxJporb.js";