@orangecheck/design 0.25.0 → 0.27.0

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/index.js CHANGED
@@ -58,7 +58,381 @@ var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
58
58
  var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
59
59
  var Link6__default = /*#__PURE__*/_interopDefault(Link6);
60
60
 
61
- // src/tokens/cn.ts
61
+ var __defProp = Object.defineProperty;
62
+ var __getOwnPropNames = Object.getOwnPropertyNames;
63
+ var __esm = (fn, res) => function __init() {
64
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
65
+ };
66
+ var __export = (target, all) => {
67
+ for (var name in all)
68
+ __defProp(target, name, { get: all[name], enumerable: true });
69
+ };
70
+
71
+ // src/tokens/scene-tokens.ts
72
+ function parseColor(value) {
73
+ let m = value.match(/color\(srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)/);
74
+ if (m?.[1] != null && m[2] != null && m[3] != null) {
75
+ return { r: +m[1], g: +m[2], b: +m[3] };
76
+ }
77
+ m = value.match(/rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)/);
78
+ if (m?.[1] != null && m[2] != null && m[3] != null) {
79
+ return { r: +m[1] / 255, g: +m[2] / 255, b: +m[3] / 255 };
80
+ }
81
+ return null;
82
+ }
83
+ function srgbToOklab({ r, g, b }) {
84
+ const lin = (c) => c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
85
+ const lr = lin(r);
86
+ const lg = lin(g);
87
+ const lb = lin(b);
88
+ const l = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);
89
+ const m = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);
90
+ const s = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);
91
+ return {
92
+ L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
93
+ a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
94
+ b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s
95
+ };
96
+ }
97
+ function oklabToSrgb(L, a, bb) {
98
+ const l = Math.pow(L + 0.3963377774 * a + 0.2158037573 * bb, 3);
99
+ const m = Math.pow(L - 0.1055613458 * a - 0.0638541728 * bb, 3);
100
+ const s = Math.pow(L - 0.0894841775 * a - 1.291485548 * bb, 3);
101
+ const lr = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
102
+ const lg = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
103
+ const lb = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;
104
+ const un = (c) => Math.min(1, Math.max(0, c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055));
105
+ return { r: un(lr), g: un(lg), b: un(lb) };
106
+ }
107
+ function normalizeHue(c, isDark) {
108
+ const { L, a, b } = srgbToOklab(c);
109
+ const C = Math.hypot(a, b);
110
+ const targetL = isDark ? Math.min(0.75, Math.max(0.55, L)) : Math.min(0.95, Math.max(0.82, L + 0.25));
111
+ const scale = C > 1e-6 ? Math.min(C, 0.14) / C : 0;
112
+ return oklabToSrgb(targetL, a * scale, b * scale);
113
+ }
114
+ function readOcSceneTokens(host) {
115
+ if (typeof document === "undefined") return null;
116
+ const probe = document.createElement("div");
117
+ probe.setAttribute("aria-hidden", "true");
118
+ probe.style.cssText = "position:absolute;width:0;height:0;overflow:hidden;pointer-events:none;";
119
+ const cells = SLOTS.map((slot) => {
120
+ const cell = document.createElement("span");
121
+ cell.style.color = `color-mix(in srgb, var(${slot}), var(${slot}))`;
122
+ probe.appendChild(cell);
123
+ return cell;
124
+ });
125
+ host.appendChild(probe);
126
+ try {
127
+ const parsed = cells.map((cell) => parseColor(getComputedStyle(cell).color));
128
+ const [orange, green, blue, violet, background] = parsed;
129
+ if (!orange || !green || !blue || !violet || !background) return null;
130
+ const root = document.documentElement;
131
+ return {
132
+ palette: [orange, green, blue, violet],
133
+ background,
134
+ isDark: root.classList.contains("dark"),
135
+ motionOff: root.getAttribute("data-oc-motion") === "off"
136
+ };
137
+ } finally {
138
+ host.removeChild(probe);
139
+ }
140
+ }
141
+ function subscribeOcTheme(cb) {
142
+ if (typeof document === "undefined") return () => {
143
+ };
144
+ let raf1 = 0;
145
+ let raf2 = 0;
146
+ const schedule = () => {
147
+ cancelAnimationFrame(raf1);
148
+ cancelAnimationFrame(raf2);
149
+ raf1 = requestAnimationFrame(() => {
150
+ raf2 = requestAnimationFrame(cb);
151
+ });
152
+ };
153
+ const mo = new MutationObserver(schedule);
154
+ mo.observe(document.documentElement, {
155
+ attributes: true,
156
+ attributeFilter: ["class", "data-oc-theme", "data-oc-motion"]
157
+ });
158
+ return () => {
159
+ mo.disconnect();
160
+ cancelAnimationFrame(raf1);
161
+ cancelAnimationFrame(raf2);
162
+ };
163
+ }
164
+ var SLOTS;
165
+ var init_scene_tokens = __esm({
166
+ "src/tokens/scene-tokens.ts"() {
167
+ SLOTS = ["--au-orange", "--au-green", "--au-blue", "--au-violet", "--background"];
168
+ }
169
+ });
170
+
171
+ // src/tokens/aurora-gl.ts
172
+ var aurora_gl_exports = {};
173
+ __export(aurora_gl_exports, {
174
+ mountAuroraGL: () => mountAuroraGL
175
+ });
176
+ function killFlagged() {
177
+ try {
178
+ const raw = localStorage.getItem(KILL_KEY);
179
+ if (!raw) return false;
180
+ if (Date.now() - Number(raw) > KILL_TTL_MS) {
181
+ localStorage.removeItem(KILL_KEY);
182
+ return false;
183
+ }
184
+ return true;
185
+ } catch {
186
+ return false;
187
+ }
188
+ }
189
+ function setKillFlag() {
190
+ try {
191
+ localStorage.setItem(KILL_KEY, String(Date.now()));
192
+ } catch {
193
+ }
194
+ }
195
+ function cypherFinish() {
196
+ const skin = document.documentElement.getAttribute("data-oc-theme");
197
+ return skin !== null && skin !== "ember";
198
+ }
199
+ function samplePalette(host) {
200
+ const tokens = readOcSceneTokens(host);
201
+ if (!tokens) return null;
202
+ return {
203
+ hues: tokens.palette.map((h) => normalizeHue(h, tokens.isDark)),
204
+ bg: tokens.background,
205
+ isDark: tokens.isDark,
206
+ finish: cypherFinish() ? 1 : 0
207
+ };
208
+ }
209
+ function mountAuroraGL(container) {
210
+ if (killFlagged()) return null;
211
+ if (getComputedStyle(container).getPropertyValue("--oc-aurora-gl").trim() === "off") {
212
+ return null;
213
+ }
214
+ const canvas = document.createElement("canvas");
215
+ canvas.className = "oc-aurora__gl";
216
+ const glMaybe = canvas.getContext("webgl2", {
217
+ antialias: false,
218
+ depth: false,
219
+ stencil: false,
220
+ alpha: false,
221
+ powerPreference: "low-power",
222
+ failIfMajorPerformanceCaveat: true
223
+ // SwiftShader/blocklist → CSS floor, free
224
+ });
225
+ if (!glMaybe) return null;
226
+ const gl = glMaybe;
227
+ const first = samplePalette(container);
228
+ if (!first) return null;
229
+ let prog;
230
+ const uni = {};
231
+ try {
232
+ const compile = (type, src) => {
233
+ const s = gl.createShader(type);
234
+ gl.shaderSource(s, src);
235
+ gl.compileShader(s);
236
+ if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error("compile");
237
+ return s;
238
+ };
239
+ prog = gl.createProgram();
240
+ gl.attachShader(prog, compile(gl.VERTEX_SHADER, VS));
241
+ gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, FS));
242
+ gl.linkProgram(prog);
243
+ if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) throw new Error("link");
244
+ gl.useProgram(prog);
245
+ const buf = gl.createBuffer();
246
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
247
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
248
+ const loc = gl.getAttribLocation(prog, "p");
249
+ gl.enableVertexAttribArray(loc);
250
+ gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
251
+ for (const k of ["uRes", "uT", "uIsDark", "uFinish", "uMix", "uA0", "uA1", "uA2", "uA3", "uB0", "uB1", "uB2", "uB3", "uBg"]) {
252
+ uni[k] = gl.getUniformLocation(prog, k);
253
+ }
254
+ } catch {
255
+ return null;
256
+ }
257
+ container.appendChild(canvas);
258
+ let palFrom = first;
259
+ let palTo = first;
260
+ let mixStart = 0;
261
+ let raf = 0;
262
+ let lastFrame = 0;
263
+ let clock = 0;
264
+ let lastTick = 0;
265
+ let lastInput = performance.now();
266
+ let live = false;
267
+ let disposed = false;
268
+ let slowStreak = 0;
269
+ const setVec = (k, c) => gl.uniform3f(uni[k] ?? null, c.r, c.g, c.b);
270
+ function resize() {
271
+ const coarse = matchMedia("(pointer: coarse)").matches;
272
+ const dpr = Math.min(devicePixelRatio || 1, coarse ? 1.5 : 2) * 0.75;
273
+ const w = Math.max(1, Math.round(container.clientWidth * dpr));
274
+ const hgt = Math.max(1, Math.round(container.clientHeight * dpr));
275
+ if (canvas.width !== w || canvas.height !== hgt) {
276
+ canvas.width = w;
277
+ canvas.height = hgt;
278
+ gl.viewport(0, 0, w, hgt);
279
+ }
280
+ }
281
+ function draw(now) {
282
+ raf = requestAnimationFrame(draw);
283
+ if (now - lastFrame < FRAME_MS) return;
284
+ const frameGap = now - lastFrame;
285
+ lastFrame = now;
286
+ if (frameGap > FRAME_MS * 2.5) {
287
+ if (++slowStreak > 90) {
288
+ setKillFlag();
289
+ dispose();
290
+ return;
291
+ }
292
+ } else if (slowStreak > 0) slowStreak--;
293
+ const settled = now - lastInput > SETTLE_MS;
294
+ if (!settled) {
295
+ clock += Math.min(now - lastTick, 100) / 1e3;
296
+ }
297
+ lastTick = now;
298
+ if (settled && live && mixDone(now)) return;
299
+ resize();
300
+ const mix = Math.min(1, (now - mixStart) / CROSSFADE_MS);
301
+ gl.uniform2f(uni.uRes ?? null, canvas.width, canvas.height);
302
+ gl.uniform1f(uni.uT ?? null, clock);
303
+ gl.uniform1f(uni.uIsDark ?? null, palTo.isDark ? 1 : 0);
304
+ gl.uniform1f(uni.uFinish ?? null, palTo.finish);
305
+ gl.uniform1f(uni.uMix ?? null, mix);
306
+ setVec("uA0", palFrom.hues[0]);
307
+ setVec("uA1", palFrom.hues[1]);
308
+ setVec("uA2", palFrom.hues[2]);
309
+ setVec("uA3", palFrom.hues[3]);
310
+ setVec("uB0", palTo.hues[0]);
311
+ setVec("uB1", palTo.hues[1]);
312
+ setVec("uB2", palTo.hues[2]);
313
+ setVec("uB3", palTo.hues[3]);
314
+ setVec("uBg", palTo.bg);
315
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
316
+ if (!live) {
317
+ live = true;
318
+ container.classList.add("oc-aurora--gl-live");
319
+ }
320
+ }
321
+ function mixDone(now) {
322
+ return now - mixStart >= CROSSFADE_MS;
323
+ }
324
+ const onInput = () => {
325
+ lastInput = performance.now();
326
+ };
327
+ const onVisibility = () => {
328
+ if (document.hidden) {
329
+ cancelAnimationFrame(raf);
330
+ raf = 0;
331
+ } else if (!raf && !disposed) {
332
+ lastFrame = 0;
333
+ lastTick = performance.now();
334
+ raf = requestAnimationFrame(draw);
335
+ }
336
+ };
337
+ const onContextLost = (e) => {
338
+ e.preventDefault();
339
+ cancelAnimationFrame(raf);
340
+ raf = 0;
341
+ };
342
+ const onContextRestored = () => {
343
+ dispose();
344
+ };
345
+ const unsubscribeTheme = subscribeOcTheme(() => {
346
+ if (disposed) return;
347
+ const root = document.documentElement;
348
+ if (root.getAttribute("data-oc-motion") === "off") {
349
+ dispose();
350
+ return;
351
+ }
352
+ const next = samplePalette(container);
353
+ if (!next) return;
354
+ palFrom = { ...palTo, hues: [...palTo.hues] };
355
+ palTo = next;
356
+ mixStart = performance.now();
357
+ lastInput = performance.now();
358
+ });
359
+ window.addEventListener("pointermove", onInput, { passive: true });
360
+ window.addEventListener("scroll", onInput, { passive: true });
361
+ window.addEventListener("keydown", onInput, { passive: true });
362
+ document.addEventListener("visibilitychange", onVisibility);
363
+ canvas.addEventListener("webglcontextlost", onContextLost);
364
+ canvas.addEventListener("webglcontextrestored", onContextRestored);
365
+ function dispose() {
366
+ if (disposed) return;
367
+ disposed = true;
368
+ cancelAnimationFrame(raf);
369
+ unsubscribeTheme();
370
+ window.removeEventListener("pointermove", onInput);
371
+ window.removeEventListener("scroll", onInput);
372
+ window.removeEventListener("keydown", onInput);
373
+ document.removeEventListener("visibilitychange", onVisibility);
374
+ canvas.removeEventListener("webglcontextlost", onContextLost);
375
+ canvas.removeEventListener("webglcontextrestored", onContextRestored);
376
+ container.classList.remove("oc-aurora--gl-live");
377
+ canvas.remove();
378
+ const ext = gl.getExtension("WEBGL_lose_context");
379
+ if (ext) ext.loseContext();
380
+ }
381
+ resize();
382
+ mixStart = performance.now();
383
+ lastTick = performance.now();
384
+ raf = requestAnimationFrame(draw);
385
+ return dispose;
386
+ }
387
+ var KILL_KEY, KILL_TTL_MS, SETTLE_MS, FRAME_MS, CROSSFADE_MS, VS, FS;
388
+ var init_aurora_gl = __esm({
389
+ "src/tokens/aurora-gl.ts"() {
390
+ init_scene_tokens();
391
+ KILL_KEY = "oc-aurora-gl-kill:1";
392
+ KILL_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
393
+ SETTLE_MS = 9e4;
394
+ FRAME_MS = 33;
395
+ CROSSFADE_MS = 250;
396
+ VS = `#version 300 es
397
+ in vec2 p;void main(){gl_Position=vec4(p,0.,1.);}`;
398
+ FS = `#version 300 es
399
+ precision highp float;
400
+ out vec4 o;
401
+ uniform vec2 uRes;uniform float uT,uIsDark,uFinish,uMix;
402
+ uniform vec3 uA0,uA1,uA2,uA3,uB0,uB1,uB2,uB3,uBg;
403
+ float h(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}
404
+ float n2(vec2 p){vec2 i=floor(p),f=fract(p);f=f*f*(3.-2.*f);
405
+ return mix(mix(h(i),h(i+vec2(1,0)),f.x),mix(h(i+vec2(0,1)),h(i+vec2(1,1)),f.x),f.y);}
406
+ float fbm(vec2 p){float v=0.,a=.55;for(int i=0;i<3;i++){v+=a*n2(p);p=p*2.03+vec2(1.7,9.2);a*=.5;}return v;}
407
+ float B2(vec2 a){a=floor(a);return fract(a.x/2.+a.y*a.y*.75);}
408
+ // OKLab mix (Ottosson) so skin crossfades never transit gray-brown.
409
+ vec3 l2s(vec3 c){return mix(12.92*c,1.055*pow(c,vec3(1./2.4))-.055,step(.0031308,c));}
410
+ vec3 s2l(vec3 c){return mix(c/12.92,pow((c+.055)/1.055,vec3(2.4)),step(.04045,c));}
411
+ vec3 okmix(vec3 a,vec3 b,float t){
412
+ vec3 la=s2l(a),lb=s2l(b);
413
+ mat3 M1=mat3(.4122214708,.2119034982,.0883024619,.5363325363,.6806995451,.2817188376,.0514459929,.1073969566,.6299787005);
414
+ mat3 M2=mat3(4.0767416621,-1.2684380046,-.0041960863,-3.3077115913,2.6097574011,-.7034186147,.2309699292,-.3413193965,1.707614701);
415
+ vec3 ka=pow(M1*la,vec3(1./3.)),kb=pow(M1*lb,vec3(1./3.));
416
+ vec3 k=mix(ka,kb,t);return clamp(l2s(M2*(k*k*k)),0.,1.);}
417
+ void main(){
418
+ vec2 uv=gl_FragCoord.xy/uRes;
419
+ vec2 p=(uv-.5)*vec2(uRes.x/uRes.y,1.)*1.9;
420
+ float t=uT*.018;
421
+ vec2 w=vec2(fbm(p+vec2(0.,t)),fbm(p+vec2(5.2,1.3)-t*.7));
422
+ float f=fbm(p+1.9*w+vec2(t*.5,-t*.3));
423
+ float g=fbm(p*.6+w*1.2+vec2(9.1,3.7));
424
+ vec3 c0=okmix(uA0,uB0,uMix),c1=okmix(uA1,uB1,uMix),c2=okmix(uA2,uB2,uMix),c3=okmix(uA3,uB3,uMix);
425
+ vec3 c=mix(mix(c0,c1,smoothstep(.25,.55,g)),mix(c2,c3,smoothstep(.45,.8,g)),smoothstep(.4,.7,g));
426
+ float e=smoothstep(.32,.9,f);
427
+ if(uFinish>.5){
428
+ float b=B2(.125*gl_FragCoord.xy)*.0625+B2(.25*gl_FragCoord.xy)*.25+B2(.5*gl_FragCoord.xy);
429
+ e=floor(e*5.+b*.8-.4)/5.;}
430
+ // container CSS already applies the mode-op \xD7 intensity opacity + radial mask
431
+ vec3 col=(uIsDark>.5)?clamp(uBg+c*e*1.15,0.,1.):mix(uBg,c,e);
432
+ col+=(fract(52.9829189*fract(dot(gl_FragCoord.xy,vec2(0.06711056,0.00583715))))-.5)/255.;
433
+ o=vec4(col,1.);}`;
434
+ }
435
+ });
62
436
  function cn(...inputs) {
63
437
  return tailwindMerge.twMerge(clsx.clsx(inputs));
64
438
  }
@@ -108,13 +482,85 @@ function resolveTheme(id) {
108
482
  return isKnownTheme(id) ? id : DEFAULT_OC_THEME;
109
483
  }
110
484
  var OC_SKIN_COOKIE = "oc_skin";
485
+ var OC_MOTION_COOKIE = "oc_motion";
111
486
  var BLOBS = [1, 2, 3, 4, 5];
112
- function OcAurora({ intensity, className }) {
487
+ function onIdle(cb, timeout) {
488
+ if (typeof requestIdleCallback === "function") {
489
+ const id2 = requestIdleCallback(cb, { timeout });
490
+ return () => cancelIdleCallback(id2);
491
+ }
492
+ const id = setTimeout(cb, timeout);
493
+ return () => clearTimeout(id);
494
+ }
495
+ function OcAurora({ intensity, gl = false, className }) {
496
+ const hostRef = React2.useRef(null);
497
+ React2.useEffect(() => {
498
+ if (!gl) return;
499
+ const host = hostRef.current;
500
+ if (!host) return;
501
+ let disposed = false;
502
+ let disposeScene = null;
503
+ let cancelIdle = null;
504
+ const prm = matchMedia("(prefers-reduced-motion: reduce)");
505
+ const forced = matchMedia("(forced-colors: active)");
506
+ function gatesPass() {
507
+ if (prm.matches || forced.matches) return false;
508
+ if (document.documentElement.getAttribute("data-oc-motion") === "off") return false;
509
+ const nav = navigator;
510
+ if (nav.connection?.saveData === true) return false;
511
+ if (typeof nav.deviceMemory === "number" && nav.deviceMemory <= 4) return false;
512
+ return true;
513
+ }
514
+ function boot() {
515
+ cancelIdle = onIdle(async () => {
516
+ if (disposed || disposeScene || !gatesPass()) return;
517
+ try {
518
+ const mod = await Promise.resolve().then(() => (init_aurora_gl(), aurora_gl_exports));
519
+ if (disposed || disposeScene || !gatesPass()) return;
520
+ disposeScene = mod.mountAuroraGL(host);
521
+ } catch {
522
+ }
523
+ }, 2e3);
524
+ }
525
+ function teardownScene() {
526
+ disposeScene?.();
527
+ disposeScene = null;
528
+ }
529
+ const onPrmChange = () => {
530
+ if (prm.matches) teardownScene();
531
+ else if (!disposeScene) boot();
532
+ };
533
+ prm.addEventListener?.("change", onPrmChange);
534
+ const mo = new MutationObserver(() => {
535
+ const off = document.documentElement.getAttribute("data-oc-motion") === "off";
536
+ if (!off && !disposeScene && !disposed) boot();
537
+ });
538
+ mo.observe(document.documentElement, {
539
+ attributes: true,
540
+ attributeFilter: ["data-oc-motion"]
541
+ });
542
+ if (document.readyState === "complete") boot();
543
+ else {
544
+ const onLoad = () => boot();
545
+ window.addEventListener("load", onLoad, { once: true });
546
+ }
547
+ return () => {
548
+ disposed = true;
549
+ cancelIdle?.();
550
+ prm.removeEventListener?.("change", onPrmChange);
551
+ mo.disconnect();
552
+ teardownScene();
553
+ };
554
+ }, [gl]);
113
555
  const style = intensity == null ? void 0 : { "--oc-aurora-intensity": String(intensity) };
114
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("oc-aurora", className), style, "aria-hidden": "true", children: BLOBS.map((n) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: `oc-aurora__blob oc-aurora__blob-${n}` }, n)) });
556
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: hostRef, className: cn("oc-aurora", className), style, "aria-hidden": "true", children: [
557
+ BLOBS.map((n) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: `oc-aurora__blob oc-aurora__blob-${n}` }, n)),
558
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oc-aurora__grain" })
559
+ ] });
115
560
  }
116
561
  var ONE_YEAR = 60 * 60 * 24 * 365;
117
562
  var ATTR = "data-oc-theme";
563
+ var MOTION_ATTR = "data-oc-motion";
118
564
  function readSkinCookie() {
119
565
  if (typeof document === "undefined") return null;
120
566
  const prefix = `${OC_SKIN_COOKIE}=`;
@@ -146,6 +592,38 @@ function applyAttr(skin) {
146
592
  if (typeof document === "undefined") return;
147
593
  document.documentElement.setAttribute(ATTR, skin);
148
594
  }
595
+ function readMotionCookie() {
596
+ if (typeof document === "undefined") return null;
597
+ const prefix = `${OC_MOTION_COOKIE}=`;
598
+ for (const part of document.cookie.split(";")) {
599
+ const trimmed = part.trim();
600
+ if (trimmed.startsWith(prefix)) {
601
+ const v = decodeURIComponent(trimmed.slice(prefix.length));
602
+ return v === "off" ? "off" : v === "on" ? "on" : null;
603
+ }
604
+ }
605
+ return null;
606
+ }
607
+ function writeMotionCookie(value) {
608
+ if (typeof document === "undefined") return;
609
+ const isLocal = location.hostname === "localhost" || location.hostname === "127.0.0.1";
610
+ const parts = [
611
+ `${OC_MOTION_COOKIE}=${encodeURIComponent(value)}`,
612
+ "Path=/",
613
+ `Max-Age=${ONE_YEAR}`,
614
+ "SameSite=Lax"
615
+ ];
616
+ if (!isLocal) {
617
+ parts.push("Domain=.ochk.io");
618
+ parts.push("Secure");
619
+ }
620
+ document.cookie = parts.join("; ");
621
+ }
622
+ function applyMotionAttr(motion) {
623
+ if (typeof document === "undefined") return;
624
+ if (motion === "off") document.documentElement.setAttribute(MOTION_ATTR, "off");
625
+ else document.documentElement.removeAttribute(MOTION_ATTR);
626
+ }
149
627
  function applySkinChrome(skin) {
150
628
  if (typeof window === "undefined") return;
151
629
  if (typeof window.__ocApplySkinChrome === "function") {
@@ -162,6 +640,7 @@ function OcThemeProvider({
162
640
  aurora = true
163
641
  }) {
164
642
  const [skin, setSkinState] = React2.useState(() => resolveTheme(defaultSkin));
643
+ const [motion, setMotionState] = React2.useState("on");
165
644
  const hydratedRef = React2.useRef(false);
166
645
  React2.useEffect(() => {
167
646
  if (hydratedRef.current) return;
@@ -170,6 +649,9 @@ function OcThemeProvider({
170
649
  applyAttr(fromCookie);
171
650
  applySkinChrome(fromCookie);
172
651
  setSkinState(fromCookie);
652
+ const motionCookie = readMotionCookie() ?? "on";
653
+ applyMotionAttr(motionCookie);
654
+ setMotionState(motionCookie);
173
655
  }, [defaultSkin]);
174
656
  React2.useEffect(() => {
175
657
  function sync() {
@@ -179,6 +661,11 @@ function OcThemeProvider({
179
661
  applySkinChrome(fromCookie);
180
662
  setSkinState(fromCookie);
181
663
  }
664
+ const motionCookie = readMotionCookie() ?? "on";
665
+ if (motionCookie !== motion) {
666
+ applyMotionAttr(motionCookie);
667
+ setMotionState(motionCookie);
668
+ }
182
669
  }
183
670
  window.addEventListener("focus", sync);
184
671
  document.addEventListener("visibilitychange", sync);
@@ -186,7 +673,7 @@ function OcThemeProvider({
186
673
  window.removeEventListener("focus", sync);
187
674
  document.removeEventListener("visibilitychange", sync);
188
675
  };
189
- }, [skin]);
676
+ }, [skin, motion]);
190
677
  const setSkin = React2.useCallback((id) => {
191
678
  const next = resolveTheme(id);
192
679
  applyAttr(next);
@@ -194,12 +681,24 @@ function OcThemeProvider({
194
681
  writeSkinCookie(next);
195
682
  setSkinState(next);
196
683
  }, []);
684
+ const setMotion = React2.useCallback((value2) => {
685
+ const next = value2 === "off" ? "off" : "on";
686
+ applyMotionAttr(next);
687
+ writeMotionCookie(next);
688
+ setMotionState(next);
689
+ }, []);
197
690
  const value = React2.useMemo(
198
- () => ({ skin, setSkin, themes: OC_THEMES }),
199
- [skin, setSkin]
691
+ () => ({ skin, setSkin, themes: OC_THEMES, motion, setMotion }),
692
+ [skin, setSkin, motion, setMotion]
200
693
  );
201
694
  return /* @__PURE__ */ jsxRuntime.jsxs(OcSkinContext.Provider, { value, children: [
202
- aurora !== false && /* @__PURE__ */ jsxRuntime.jsx(OcAurora, { intensity: typeof aurora === "object" ? aurora.intensity : void 0 }),
695
+ aurora !== false && /* @__PURE__ */ jsxRuntime.jsx(
696
+ OcAurora,
697
+ {
698
+ intensity: typeof aurora === "object" ? aurora.intensity : void 0,
699
+ gl: typeof aurora === "object" ? aurora.gl : void 0
700
+ }
701
+ ),
203
702
  children
204
703
  ] });
205
704
  }
@@ -210,9 +709,13 @@ function useOcSkin() {
210
709
  }
211
710
  return ctx;
212
711
  }
712
+ function useOcMotion() {
713
+ const { motion, setMotion } = useOcSkin();
714
+ return { motion, setMotion };
715
+ }
213
716
  function getOcThemeInitScript(defaultSkin = DEFAULT_OC_THEME) {
214
717
  const accents = Object.fromEntries(OC_THEMES.map((t) => [t.id, t.accent]));
215
- return `(function(){var ACC=${JSON.stringify(accents)},DEF=${JSON.stringify(defaultSkin)},ORIG=${JSON.stringify(OC_DEFAULT_ACCENT)},fav=null;function acc(s){return ACC[s]||ACC[DEF]||ORIG;}window.__ocApplySkinChrome=function(s){try{var a=acc(s);var meta=document.querySelector('meta[name="theme-color"]');if(meta){meta.setAttribute('content',a);}var link=document.querySelector('link[rel~="icon"][type="image/svg+xml"]');if(!link){return;}var paint=function(svg){link.setAttribute('href','data:image/svg+xml,'+encodeURIComponent(svg.split(ORIG).join(a)));};if(fav!=null){paint(fav);return;}var h=link.getAttribute('href');if(!h||h.indexOf('data:')===0){return;}fetch(h).then(function(r){return r.text();}).then(function(svg){fav=svg;paint(svg);}).catch(function(){});}catch(e){}};try{var m=document.cookie.match(/(?:^|; )${OC_SKIN_COOKIE}=([^;]*)/);var s=m?decodeURIComponent(m[1]):DEF;if(!s){s=DEF;}document.documentElement.setAttribute('${ATTR}',s);window.__ocApplySkinChrome(s);}catch(e){document.documentElement.setAttribute('${ATTR}',DEF);}})();`;
718
+ return `(function(){var ACC=${JSON.stringify(accents)},DEF=${JSON.stringify(defaultSkin)},ORIG=${JSON.stringify(OC_DEFAULT_ACCENT)},fav=null;function acc(s){return ACC[s]||ACC[DEF]||ORIG;}window.__ocApplySkinChrome=function(s){try{var a=acc(s);var meta=document.querySelector('meta[name="theme-color"]');if(meta){meta.setAttribute('content',a);}var link=document.querySelector('link[rel~="icon"][type="image/svg+xml"]');if(!link){return;}var paint=function(svg){link.setAttribute('href','data:image/svg+xml,'+encodeURIComponent(svg.split(ORIG).join(a)));};if(fav!=null){paint(fav);return;}var h=link.getAttribute('href');if(!h||h.indexOf('data:')===0){return;}fetch(h).then(function(r){return r.text();}).then(function(svg){fav=svg;paint(svg);}).catch(function(){});}catch(e){}};try{var m=document.cookie.match(/(?:^|; )${OC_SKIN_COOKIE}=([^;]*)/);var s=m?decodeURIComponent(m[1]):DEF;if(!s){s=DEF;}document.documentElement.setAttribute('${ATTR}',s);window.__ocApplySkinChrome(s);}catch(e){document.documentElement.setAttribute('${ATTR}',DEF);}try{var mm=document.cookie.match(/(?:^|; )${OC_MOTION_COOKIE}=([^;]*)/);if(mm&&decodeURIComponent(mm[1])==='off'){document.documentElement.setAttribute('${MOTION_ATTR}','off');}}catch(e){}})();`;
216
719
  }
217
720
  var COOKIE = "oc_theme";
218
721
  var ALLOWED = /* @__PURE__ */ new Set(["light", "dark", "system"]);
@@ -347,10 +850,12 @@ var MODES = [
347
850
  ];
348
851
  function AppearanceControls({ className }) {
349
852
  const { skin, setSkin, themes } = useOcSkin();
853
+ const { motion, setMotion } = useOcMotion();
350
854
  const { theme, setTheme } = nextThemes.useTheme();
351
855
  const [mounted, setMounted] = React2.useState(false);
352
856
  React2.useEffect(() => setMounted(true), []);
353
857
  const activeMode = mounted ? theme ?? "system" : null;
858
+ const activeMotion = mounted ? motion : null;
354
859
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
355
860
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "label-mono text-muted-foreground px-3 pt-3 pb-2", children: "mode" }),
356
861
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-1 px-2 pb-2", children: MODES.map(({ id, label, Icon: Icon2 }) => {
@@ -397,6 +902,32 @@ function AppearanceControls({ className }) {
397
902
  ]
398
903
  }
399
904
  ) }, t.id);
905
+ }) }),
906
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "label-mono text-muted-foreground border-t px-3 pt-3 pb-2", children: "ambient motion" }),
907
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-1 px-2 pb-3", children: [
908
+ { id: "on", label: "on", Icon: lucideReact.Waves },
909
+ { id: "off", label: "off", Icon: lucideReact.Pause }
910
+ ].map(({ id, label, Icon: Icon2 }) => {
911
+ const active = activeMotion === id;
912
+ return /* @__PURE__ */ jsxRuntime.jsxs(
913
+ "button",
914
+ {
915
+ type: "button",
916
+ role: "menuitemradio",
917
+ "aria-checked": active,
918
+ "aria-label": id === "off" ? "pause ambient motion" : "ambient motion on",
919
+ onClick: () => setMotion(id),
920
+ className: cn(
921
+ "flex flex-col items-center gap-1 rounded-md border py-2 text-[11px] transition-colors",
922
+ active ? "border-primary text-foreground bg-accent" : "border-transparent text-muted-foreground hover:bg-accent hover:text-accent-foreground"
923
+ ),
924
+ children: [
925
+ /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "size-4", "aria-hidden": true }),
926
+ label
927
+ ]
928
+ },
929
+ id
930
+ );
400
931
  }) })
401
932
  ] });
402
933
  }
@@ -452,6 +983,9 @@ function OcAppearanceMenu({
452
983
  )
453
984
  ] });
454
985
  }
986
+
987
+ // src/tokens/index.ts
988
+ init_scene_tokens();
455
989
  var buttonVariants = classVarianceAuthority.cva(
456
990
  "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
457
991
  {
@@ -5042,6 +5576,7 @@ exports.MarketingHeading = MarketingHeading;
5042
5576
  exports.Modal = Modal;
5043
5577
  exports.NumberedStep = NumberedStep;
5044
5578
  exports.OC_DEFAULT_ACCENT = OC_DEFAULT_ACCENT;
5579
+ exports.OC_MOTION_COOKIE = OC_MOTION_COOKIE;
5045
5580
  exports.OC_SKIN_COOKIE = OC_SKIN_COOKIE;
5046
5581
  exports.OC_THEMES = OC_THEMES;
5047
5582
  exports.OcAccountMenu = OcAccountMenu;
@@ -5130,14 +5665,18 @@ exports.getOcThemeInitScript = getOcThemeInitScript;
5130
5665
  exports.iconBadgeVariants = iconBadgeVariants;
5131
5666
  exports.isKnownTheme = isKnownTheme;
5132
5667
  exports.makeStatusPill = makeStatusPill;
5668
+ exports.normalizeHue = normalizeHue;
5133
5669
  exports.priceBoth = priceBoth;
5134
5670
  exports.prompt = prompt;
5671
+ exports.readOcSceneTokens = readOcSceneTokens;
5135
5672
  exports.relativeTime = relativeTime;
5136
5673
  exports.resolveTheme = resolveTheme;
5137
5674
  exports.satsToUsd = satsToUsd;
5138
5675
  exports.shortenAddress = shortenAddress;
5676
+ exports.subscribeOcTheme = subscribeOcTheme;
5139
5677
  exports.surfaceVariants = surfaceVariants;
5140
5678
  exports.usdToSats = usdToSats;
5679
+ exports.useOcMotion = useOcMotion;
5141
5680
  exports.useOcSkin = useOcSkin;
5142
5681
  exports.useSpotPrice = useSpotPrice;
5143
5682
  //# sourceMappingURL=index.js.map