react-marketing-ui 0.0.3 → 0.0.5
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/accordion.js +1 -1
- package/dist/accordion.js.map +1 -1
- package/dist/accordion.mjs +222 -2
- package/dist/accordion.mjs.map +1 -1
- package/dist/action-swap.js +1 -0
- package/dist/action-swap.mjs +77 -3
- package/dist/action-swap.mjs.map +1 -1
- package/dist/animated-beam.js +1 -0
- package/dist/animated-beam.mjs +127 -2
- package/dist/animated-beam.mjs.map +1 -1
- package/dist/button.js +1 -1
- package/dist/button.js.map +1 -1
- package/dist/button.mjs +115 -2
- package/dist/button.mjs.map +1 -1
- package/dist/card.js +1 -2
- package/dist/card.js.map +1 -1
- package/dist/card.mjs +135 -3
- package/dist/card.mjs.map +1 -1
- package/dist/dia-text-reveal.js +1 -0
- package/dist/dia-text-reveal.mjs +331 -2
- package/dist/dia-text-reveal.mjs.map +1 -1
- package/dist/elevated-input.js +1 -1
- package/dist/elevated-input.js.map +1 -1
- package/dist/elevated-input.mjs +48 -2
- package/dist/elevated-input.mjs.map +1 -1
- package/dist/fade-in.js +1 -0
- package/dist/fade-in.mjs +84 -2
- package/dist/fade-in.mjs.map +1 -1
- package/dist/feature-card.js +1 -1
- package/dist/feature-card.js.map +1 -1
- package/dist/feature-card.mjs +34 -2
- package/dist/feature-card.mjs.map +1 -1
- package/dist/flowchart-parts.js +1 -1
- package/dist/flowchart-parts.js.map +1 -1
- package/dist/flowchart-parts.mjs +91 -2
- package/dist/flowchart-parts.mjs.map +1 -1
- package/dist/footer-glow.d.cts +2 -0
- package/dist/footer-glow.d.ts +2 -0
- package/dist/footer-glow.d.ts.map +1 -0
- package/dist/footer-glow.js +110 -0
- package/dist/footer-glow.js.map +1 -0
- package/dist/footer-glow.mjs +108 -0
- package/dist/footer-glow.mjs.map +1 -0
- package/dist/glossy-button.js +1 -1
- package/dist/glossy-button.js.map +1 -1
- package/dist/glossy-button.mjs +82 -2
- package/dist/glossy-button.mjs.map +1 -1
- package/dist/grainient.js +1 -0
- package/dist/grainient.mjs +327 -2
- package/dist/grainient.mjs.map +1 -1
- package/dist/highlighter.js +1 -0
- package/dist/highlighter.mjs +122 -3
- package/dist/highlighter.mjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +101 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2741 -32
- package/dist/index.mjs.map +1 -1
- package/dist/input.js +1 -0
- package/dist/input.mjs +107 -2
- package/dist/input.mjs.map +1 -1
- package/dist/lib/breakpoints.js +1 -1
- package/dist/lib/breakpoints.js.map +1 -1
- package/dist/lib/breakpoints.mjs +34 -1
- package/dist/lib/breakpoints.mjs.map +1 -1
- package/dist/lib/cn.js +1 -1
- package/dist/lib/cn.js.map +1 -1
- package/dist/lib/cn.mjs +17 -1
- package/dist/lib/cn.mjs.map +1 -1
- package/dist/lib/ease.js +1 -0
- package/dist/lib/ease.mjs +9 -1
- package/dist/lib/ease.mjs.map +1 -1
- package/dist/lib/surface.js +1 -0
- package/dist/lib/surface.mjs +37 -1
- package/dist/lib/surface.mjs.map +1 -1
- package/dist/lib/use-media-query.js +1 -0
- package/dist/lib/use-media-query.mjs +16 -1
- package/dist/lib/use-media-query.mjs.map +1 -1
- package/dist/liquid-metal.js +1 -0
- package/dist/liquid-metal.mjs +40 -2
- package/dist/liquid-metal.mjs.map +1 -1
- package/dist/navigation-menu-icons.js +1 -1
- package/dist/navigation-menu-icons.js.map +1 -1
- package/dist/navigation-menu-icons.mjs +36 -1
- package/dist/navigation-menu-icons.mjs.map +1 -1
- package/dist/navigation-menu-styles.js +1 -1
- package/dist/navigation-menu-styles.js.map +1 -1
- package/dist/navigation-menu-styles.mjs +11 -1
- package/dist/navigation-menu-styles.mjs.map +1 -1
- package/dist/navigation-menu.js +1 -2
- package/dist/navigation-menu.js.map +1 -1
- package/dist/navigation-menu.mjs +350 -5
- package/dist/navigation-menu.mjs.map +1 -1
- package/dist/password-input.js +1 -0
- package/dist/password-input.mjs +171 -3
- package/dist/password-input.mjs.map +1 -1
- package/dist/rainbow-button.js +1 -0
- package/dist/rainbow-button.mjs +45 -2
- package/dist/rainbow-button.mjs.map +1 -1
- package/dist/range-slider.js +1 -0
- package/dist/range-slider.mjs +82 -1
- package/dist/range-slider.mjs.map +1 -1
- package/dist/rolling-badge.js +1 -0
- package/dist/rolling-badge.mjs +68 -2
- package/dist/rolling-badge.mjs.map +1 -1
- package/dist/savings-badge.js +1 -1
- package/dist/savings-badge.js.map +1 -1
- package/dist/savings-badge.mjs +22 -2
- package/dist/savings-badge.mjs.map +1 -1
- package/dist/shine-border.js +1 -0
- package/dist/shine-border.mjs +44 -2
- package/dist/shine-border.mjs.map +1 -1
- package/dist/sparkles-text.js +1 -0
- package/dist/sparkles-text.mjs +84 -3
- package/dist/sparkles-text.mjs.map +1 -1
- package/dist/tabs.js +1 -0
- package/dist/tabs.mjs +118 -2
- package/dist/tabs.mjs.map +1 -1
- package/dist/theme-toggle.js +1 -0
- package/dist/theme-toggle.mjs +248 -5
- package/dist/theme-toggle.mjs.map +1 -1
- package/package.json +12 -2
- package/dist/chunk-3SB6HUBA.mjs +0 -31
- package/dist/chunk-3SB6HUBA.mjs.map +0 -1
- package/dist/chunk-4PBVBXGY.mjs +0 -84
- package/dist/chunk-4PBVBXGY.mjs.map +0 -1
- package/dist/chunk-4VCFWVSJ.mjs +0 -42
- package/dist/chunk-4VCFWVSJ.mjs.map +0 -1
- package/dist/chunk-5QQAPGR2.mjs +0 -109
- package/dist/chunk-5QQAPGR2.mjs.map +0 -1
- package/dist/chunk-6MB4UKRX.mjs +0 -19
- package/dist/chunk-6MB4UKRX.mjs.map +0 -1
- package/dist/chunk-6T5LR34O.mjs +0 -45
- package/dist/chunk-6T5LR34O.mjs.map +0 -1
- package/dist/chunk-AYLCYDUM.mjs +0 -275
- package/dist/chunk-AYLCYDUM.mjs.map +0 -1
- package/dist/chunk-AYY7D2RJ.mjs +0 -112
- package/dist/chunk-AYY7D2RJ.mjs.map +0 -1
- package/dist/chunk-CTZEI2YS.mjs +0 -324
- package/dist/chunk-CTZEI2YS.mjs.map +0 -1
- package/dist/chunk-DA3I3Y5O.mjs +0 -71
- package/dist/chunk-DA3I3Y5O.mjs.map +0 -1
- package/dist/chunk-EYHT2EWJ.mjs +0 -18
- package/dist/chunk-EYHT2EWJ.mjs.map +0 -1
- package/dist/chunk-IHLGCS63.mjs +0 -36
- package/dist/chunk-IHLGCS63.mjs.map +0 -1
- package/dist/chunk-JVXJ6SFX.mjs +0 -38
- package/dist/chunk-JVXJ6SFX.mjs.map +0 -1
- package/dist/chunk-KBHYXLRG.mjs +0 -13
- package/dist/chunk-KBHYXLRG.mjs.map +0 -1
- package/dist/chunk-KMXUQYR3.mjs +0 -74
- package/dist/chunk-KMXUQYR3.mjs.map +0 -1
- package/dist/chunk-KNPOZ34H.mjs +0 -88
- package/dist/chunk-KNPOZ34H.mjs.map +0 -1
- package/dist/chunk-KRNWCJ4D.mjs +0 -219
- package/dist/chunk-KRNWCJ4D.mjs.map +0 -1
- package/dist/chunk-M5MESV26.mjs +0 -124
- package/dist/chunk-M5MESV26.mjs.map +0 -1
- package/dist/chunk-MJYBPJBA.mjs +0 -115
- package/dist/chunk-MJYBPJBA.mjs.map +0 -1
- package/dist/chunk-NNHPQ67J.mjs +0 -10
- package/dist/chunk-NNHPQ67J.mjs.map +0 -1
- package/dist/chunk-OCZFHVVD.mjs +0 -71
- package/dist/chunk-OCZFHVVD.mjs.map +0 -1
- package/dist/chunk-QAWSH567.mjs +0 -19
- package/dist/chunk-QAWSH567.mjs.map +0 -1
- package/dist/chunk-R2E2J42H.mjs +0 -38
- package/dist/chunk-R2E2J42H.mjs.map +0 -1
- package/dist/chunk-TPGLLSYV.mjs +0 -65
- package/dist/chunk-TPGLLSYV.mjs.map +0 -1
- package/dist/chunk-VJENJHXJ.mjs +0 -72
- package/dist/chunk-VJENJHXJ.mjs.map +0 -1
- package/dist/chunk-W22G7XHR.mjs +0 -104
- package/dist/chunk-W22G7XHR.mjs.map +0 -1
- package/dist/chunk-WDR5VPZJ.mjs +0 -79
- package/dist/chunk-WDR5VPZJ.mjs.map +0 -1
- package/dist/chunk-WLUGKBH7.mjs +0 -37
- package/dist/chunk-WLUGKBH7.mjs.map +0 -1
- package/dist/chunk-WYJYLDUA.mjs +0 -84
- package/dist/chunk-WYJYLDUA.mjs.map +0 -1
- package/dist/chunk-XZEDZVXT.mjs +0 -38
- package/dist/chunk-XZEDZVXT.mjs.map +0 -1
- package/dist/chunk-YKGP5JIL.mjs +0 -328
- package/dist/chunk-YKGP5JIL.mjs.map +0 -1
- package/dist/chunk-YM3U2OBE.mjs +0 -99
- package/dist/chunk-YM3U2OBE.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/components/glossy-button.tsx"],"names":["twMerge","clsx","cva","jsxs","Fragment","jsx"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/glossy-button.tsx"],"names":["twMerge","clsx","cva","jsxs","Fragment","jsx"],"mappings":";;;;;;;AAIO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAOA,qBAAA,CAAQC,SAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;AC6BA,IAAM,UAAA,GAAa,EAAA;AAAA,EACjB,+DAAA;AAAA,EACA,sEAAA;AAAA,EACA,gCAAA;AAAA;AAAA,EAEA,+DAAA;AAAA,EACA,iEAAA;AAAA;AAAA,EAEA,8HAAA;AAAA;AAAA;AAAA,EAGA,yFAAA;AAAA,EACA,wHAAA;AAAA,EACA,sCAAA;AAAA,EACA,qEAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,oBAAA,GAAuBC,0BAAA;AAAA,EAC3B,EAAA;AAAA,IACE,0JAAA;AAAA;AAAA;AAAA,IAGA,uBAAA;AAAA,IACA,6CAAA;AAAA;AAAA,IAEA;AAAA,GACF;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,EAAA,EAAI,oBAAA;AAAA,QACJ,EAAA,EAAI,sBAAA;AAAA,QACJ,EAAA,EAAI;AAAA,OACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,OAAA,EAAS;AAAA,QACP,OAAA,EAAS,EAAA;AAAA,QACT,MAAA,EAAQ,eAAA;AAAA,QACR,WAAA,EAAa,oBAAA;AAAA,QACb,OAAA,EAAS,gBAAA;AAAA,QACT,QAAA,EAAU,iBAAA;AAAA,QACV,SAAA,EAAW,kBAAA;AAAA,QACX,SAAA,EAAW,kBAAA;AAAA,QACX,OAAA,EAAS;AAAA;AACX,KACF;AAAA,IACA,eAAA,EAAiB,EAAE,IAAA,EAAM,IAAA,EAAM,SAAS,SAAA;AAAU;AAEtD;AAeO,SAAS,YAAA,CAAa;AAAA,EAC3B,IAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA,EAAc;AAChB,CAAA,EAAsB;AACpB,EAAA,MAAM,0BACJC,eAAA,CAAAC,mBAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAC,cAAA,CAAC,UAAK,eAAA,EAAc,OAAA,EAAQ,aAAA,EAAa,IAAA,EAAM,WAAW,UAAA,EAAY,CAAA;AAAA,oBACtEA,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EAAU,QAAA,EAAS;AAAA,GAAA,EACrC,CAAA;AAGF,EAAA,MAAM,eAAA,GAAkB,GAAG,oBAAA,CAAqB,EAAE,MAAM,OAAA,EAAS,GAAG,SAAS,CAAA;AAE7E,EAAA,IAAI,OAAO,YAAA,KAAiB,QAAA;AAC1B,IAAA,uBACEA,cAAA,CAAC,GAAA,EAAA,EAAE,IAAA,EAAM,YAAA,EAAc,SAAA,EAAW,EAAA,CAAG,eAAA,EAAiB,cAAc,CAAA,EAAG,YAAA,EAAY,SAAA,EAChF,QAAA,EAAA,OAAA,EACH,CAAA;AAGJ,EAAA,uBACEA,cAAA,CAAC,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,SAAA,EAAW,eAAA,EAAiB,OAAA,EAAS,YAAA,EAAc,QAAA,EAAoB,YAAA,EAAY,SAAA,EACtG,QAAA,EAAA,OAAA,EACH,CAAA;AAEJ","file":"glossy-button.js","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport type { CSSProperties } from 'react';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * A style object that may carry CSS custom properties (CSS variables)\n * such as `--duration`. React's `CSSProperties` intentionally drops\n * its index signature, so custom properties are not accepted without help.\n */\nexport type CSSPropertiesWithVars = CSSProperties & Record<`--${string}`, string | number>;\n\n/**\n * Builds a {@link CSSProperties} value that also allows CSS custom properties,\n * so `style` props can be written without an `as React.CSSProperties` cast while\n * still type-checking both the known style keys and the custom-property values.\n *\n * @example\n * <div style={validCssVars({ '--duration': '0.35s', color: 'red' })} />\n */\nexport function validCssVars(style: CSSPropertiesWithVars): CSSProperties {\n return style;\n}\n\n/**\n * Narrows a union to the member(s) that declare `key` — a type-guard\n * replacement for the `in` operator's discriminated-union narrowing.\n */\nexport function hasKey<K extends PropertyKey>(key: K, obj: unknown): obj is Record<K, unknown> {\n return obj !== null && typeof obj === 'object' && Object.hasOwn(obj, key);\n}\n\nexport function noop(): void {\n // intentional no-op\n}\n","import { cva, type VariantProps } from 'class-variance-authority';\nimport type { ReactNode } from 'react';\nimport { cn } from '../lib/utils.js';\n\n/**\n * Physically-lit button: a domed, back-lit key built from one effect layer.\n *\n * The geometry lives in a single `box-shadow` list that gets swapped wholesale on\n * press, so the bevel and cast can drop out while the rim survives without any\n * of them being separate elements:\n *\n * • the gloss span — face fill + the shadow list (bevel, rim, cast).\n * • its `before:` — the dome gradient, painted over the face.\n * • its `after:` — the hover/press tint, the only thing that cross-fades.\n *\n * The recipe lives in `global.css`. Every colour is a `--btn-*` primitive, and\n * the two shadow composites are declared on `.glossy` — on the key itself, not\n * on `:root` — because a var() inside a custom property is substituted where the\n * property is *declared*. That's what lets one `.glossy-<variant>` class restyle\n * the whole recipe by setting primitives, and it's why there are no `dark:`\n * variants here: `.dark` overrides the same primitives.\n *\n * The span is a sibling of the label rather than its parent so the label never\n * inherits the effect layers' stacking or transitions; `isolate` on the root\n * contains the span's negative z-index.\n *\n * Server-renderable: every state is pure CSS. Passing a function as\n * `actionOrLink` requires a client-component parent, as with any onClick prop.\n */\n\n/**\n * The whole visual treatment. Absolutely positioned behind the label, with the\n * dome (`before:`) and the interaction tint (`after:`) stacked over the face.\n * Only the tint animates opacity; the shadow list animates by being replaced.\n */\nconst glossLayer = cn(\n 'pointer-events-none absolute inset-0 z-[-1] rounded-[inherit]',\n '[background-color:var(--btn-face)] [box-shadow:var(--shadow-button)]',\n 'transition-shadow duration-150',\n // Pressed (and disabled): bevel + cast go transparent, the rim stays.\n 'group-active/glossy:[box-shadow:var(--shadow-button-pressed)]',\n 'group-disabled/glossy:[box-shadow:var(--shadow-button-pressed)]',\n // Dome — fixed direction, per-variant stops. Above the face, below the tint.\n \"before:absolute before:inset-0 before:rounded-[inherit] before:content-[''] before:[background-image:var(--gradient-button)]\",\n // Interaction tint. Hidden outright when disabled, and on touch (no hover\n // state to speak of) so the root's active:opacity can carry the press instead.\n \"after:absolute after:inset-0 after:rounded-[inherit] after:content-[''] after:opacity-0\",\n 'after:[background-color:var(--btn-tint-hover)] after:transition-opacity after:duration-150 after:[will-change:opacity]',\n 'group-hover/glossy:after:opacity-100',\n 'group-active/glossy:after:[background-color:var(--btn-tint-active)]',\n 'group-disabled/glossy:after:hidden [@media(hover:none)]:after:hidden',\n);\n\nconst glossyButtonVariants = cva(\n cn(\n 'glossy group/glossy relative isolate inline-flex cursor-pointer select-none items-center justify-center gap-1 whitespace-nowrap rounded-full font-normal',\n // Label colour rides the variant. Kept as a utility rather than a plain\n // declaration on `.glossy` so a caller's own text-* class still wins.\n '[color:var(--btn-fg)]',\n 'disabled:cursor-default disabled:opacity-50',\n // Touch devices get no hover layer, so the whole key dims on press instead.\n '[@media(hover:none)]:active:opacity-80',\n ),\n {\n variants: {\n size: {\n sm: 'h-8 px-2.5 text-sm',\n md: 'h-9 px-5 text-[17px]',\n lg: 'h-11 px-6 text-[17px]',\n },\n /**\n * Written out as literal class names — Tailwind's scanner is static, so a\n * `glossy-${variant}` template would never make it into the stylesheet.\n * `neutral` is the bare recipe, so it needs no class of its own.\n */\n variant: {\n neutral: '',\n accent: 'glossy-accent',\n destructive: 'glossy-destructive',\n special: 'glossy-special',\n positive: 'glossy-positive',\n attention: 'glossy-attention',\n highlight: 'glossy-highlight',\n inverse: 'glossy-inverse',\n },\n },\n defaultVariants: { size: 'md', variant: 'neutral' },\n },\n);\n\nexport type GlossyButtonProps = VariantProps<typeof glossyButtonVariants> & {\n /**\n * String → renders as a plain <a href={...}>.\n * Function → renders as a <button type=\"button\" onClick={...}>.\n */\n actionOrLink: string | (() => void);\n children: ReactNode;\n /** Button-only — an anchor can't be disabled. */\n disabled?: boolean;\n className?: string;\n 'aria-label'?: string;\n};\n\nexport function GlossyButton({\n size,\n variant,\n actionOrLink,\n children,\n disabled,\n className,\n 'aria-label': ariaLabel,\n}: GlossyButtonProps) {\n const content = (\n <>\n <span data-fx-layer=\"gloss\" aria-hidden={true} className={glossLayer} />\n <span className=\"px-0.5\">{children}</span>\n </>\n );\n\n const buttonClassName = cn(glossyButtonVariants({ size, variant }), className);\n\n if (typeof actionOrLink === 'string')\n return (\n <a href={actionOrLink} className={cn(buttonClassName, 'no-underline')} aria-label={ariaLabel}>\n {content}\n </a>\n );\n\n return (\n <button type=\"button\" className={buttonClassName} onClick={actionOrLink} disabled={disabled} aria-label={ariaLabel}>\n {content}\n </button>\n );\n}\n\nexport { glossyButtonVariants };\n"]}
|
package/dist/glossy-button.mjs
CHANGED
|
@@ -1,4 +1,84 @@
|
|
|
1
|
-
|
|
2
|
-
import '
|
|
1
|
+
"use client";
|
|
2
|
+
import { cva } from 'class-variance-authority';
|
|
3
|
+
import { clsx } from 'clsx';
|
|
4
|
+
import { twMerge } from 'tailwind-merge';
|
|
5
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function cn(...inputs) {
|
|
8
|
+
return twMerge(clsx(inputs));
|
|
9
|
+
}
|
|
10
|
+
var glossLayer = cn(
|
|
11
|
+
"pointer-events-none absolute inset-0 z-[-1] rounded-[inherit]",
|
|
12
|
+
"[background-color:var(--btn-face)] [box-shadow:var(--shadow-button)]",
|
|
13
|
+
"transition-shadow duration-150",
|
|
14
|
+
// Pressed (and disabled): bevel + cast go transparent, the rim stays.
|
|
15
|
+
"group-active/glossy:[box-shadow:var(--shadow-button-pressed)]",
|
|
16
|
+
"group-disabled/glossy:[box-shadow:var(--shadow-button-pressed)]",
|
|
17
|
+
// Dome — fixed direction, per-variant stops. Above the face, below the tint.
|
|
18
|
+
"before:absolute before:inset-0 before:rounded-[inherit] before:content-[''] before:[background-image:var(--gradient-button)]",
|
|
19
|
+
// Interaction tint. Hidden outright when disabled, and on touch (no hover
|
|
20
|
+
// state to speak of) so the root's active:opacity can carry the press instead.
|
|
21
|
+
"after:absolute after:inset-0 after:rounded-[inherit] after:content-[''] after:opacity-0",
|
|
22
|
+
"after:[background-color:var(--btn-tint-hover)] after:transition-opacity after:duration-150 after:[will-change:opacity]",
|
|
23
|
+
"group-hover/glossy:after:opacity-100",
|
|
24
|
+
"group-active/glossy:after:[background-color:var(--btn-tint-active)]",
|
|
25
|
+
"group-disabled/glossy:after:hidden [@media(hover:none)]:after:hidden"
|
|
26
|
+
);
|
|
27
|
+
var glossyButtonVariants = cva(
|
|
28
|
+
cn(
|
|
29
|
+
"glossy group/glossy relative isolate inline-flex cursor-pointer select-none items-center justify-center gap-1 whitespace-nowrap rounded-full font-normal",
|
|
30
|
+
// Label colour rides the variant. Kept as a utility rather than a plain
|
|
31
|
+
// declaration on `.glossy` so a caller's own text-* class still wins.
|
|
32
|
+
"[color:var(--btn-fg)]",
|
|
33
|
+
"disabled:cursor-default disabled:opacity-50",
|
|
34
|
+
// Touch devices get no hover layer, so the whole key dims on press instead.
|
|
35
|
+
"[@media(hover:none)]:active:opacity-80"
|
|
36
|
+
),
|
|
37
|
+
{
|
|
38
|
+
variants: {
|
|
39
|
+
size: {
|
|
40
|
+
sm: "h-8 px-2.5 text-sm",
|
|
41
|
+
md: "h-9 px-5 text-[17px]",
|
|
42
|
+
lg: "h-11 px-6 text-[17px]"
|
|
43
|
+
},
|
|
44
|
+
/**
|
|
45
|
+
* Written out as literal class names — Tailwind's scanner is static, so a
|
|
46
|
+
* `glossy-${variant}` template would never make it into the stylesheet.
|
|
47
|
+
* `neutral` is the bare recipe, so it needs no class of its own.
|
|
48
|
+
*/
|
|
49
|
+
variant: {
|
|
50
|
+
neutral: "",
|
|
51
|
+
accent: "glossy-accent",
|
|
52
|
+
destructive: "glossy-destructive",
|
|
53
|
+
special: "glossy-special",
|
|
54
|
+
positive: "glossy-positive",
|
|
55
|
+
attention: "glossy-attention",
|
|
56
|
+
highlight: "glossy-highlight",
|
|
57
|
+
inverse: "glossy-inverse"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
defaultVariants: { size: "md", variant: "neutral" }
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
function GlossyButton({
|
|
64
|
+
size,
|
|
65
|
+
variant,
|
|
66
|
+
actionOrLink,
|
|
67
|
+
children,
|
|
68
|
+
disabled,
|
|
69
|
+
className,
|
|
70
|
+
"aria-label": ariaLabel
|
|
71
|
+
}) {
|
|
72
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
73
|
+
/* @__PURE__ */ jsx("span", { "data-fx-layer": "gloss", "aria-hidden": true, className: glossLayer }),
|
|
74
|
+
/* @__PURE__ */ jsx("span", { className: "px-0.5", children })
|
|
75
|
+
] });
|
|
76
|
+
const buttonClassName = cn(glossyButtonVariants({ size, variant }), className);
|
|
77
|
+
if (typeof actionOrLink === "string")
|
|
78
|
+
return /* @__PURE__ */ jsx("a", { href: actionOrLink, className: cn(buttonClassName, "no-underline"), "aria-label": ariaLabel, children: content });
|
|
79
|
+
return /* @__PURE__ */ jsx("button", { type: "button", className: buttonClassName, onClick: actionOrLink, disabled, "aria-label": ariaLabel, children: content });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { GlossyButton, glossyButtonVariants };
|
|
3
83
|
//# sourceMappingURL=glossy-button.mjs.map
|
|
4
84
|
//# sourceMappingURL=glossy-button.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"glossy-button.mjs"}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/glossy-button.tsx"],"names":[],"mappings":";;;;;AAIO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;AC6BA,IAAM,UAAA,GAAa,EAAA;AAAA,EACjB,+DAAA;AAAA,EACA,sEAAA;AAAA,EACA,gCAAA;AAAA;AAAA,EAEA,+DAAA;AAAA,EACA,iEAAA;AAAA;AAAA,EAEA,8HAAA;AAAA;AAAA;AAAA,EAGA,yFAAA;AAAA,EACA,wHAAA;AAAA,EACA,sCAAA;AAAA,EACA,qEAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,oBAAA,GAAuB,GAAA;AAAA,EAC3B,EAAA;AAAA,IACE,0JAAA;AAAA;AAAA;AAAA,IAGA,uBAAA;AAAA,IACA,6CAAA;AAAA;AAAA,IAEA;AAAA,GACF;AAAA,EACA;AAAA,IACE,QAAA,EAAU;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,EAAA,EAAI,oBAAA;AAAA,QACJ,EAAA,EAAI,sBAAA;AAAA,QACJ,EAAA,EAAI;AAAA,OACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,OAAA,EAAS;AAAA,QACP,OAAA,EAAS,EAAA;AAAA,QACT,MAAA,EAAQ,eAAA;AAAA,QACR,WAAA,EAAa,oBAAA;AAAA,QACb,OAAA,EAAS,gBAAA;AAAA,QACT,QAAA,EAAU,iBAAA;AAAA,QACV,SAAA,EAAW,kBAAA;AAAA,QACX,SAAA,EAAW,kBAAA;AAAA,QACX,OAAA,EAAS;AAAA;AACX,KACF;AAAA,IACA,eAAA,EAAiB,EAAE,IAAA,EAAM,IAAA,EAAM,SAAS,SAAA;AAAU;AAEtD;AAeO,SAAS,YAAA,CAAa;AAAA,EAC3B,IAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA,EAAc;AAChB,CAAA,EAAsB;AACpB,EAAA,MAAM,0BACJ,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,UAAK,eAAA,EAAc,OAAA,EAAQ,aAAA,EAAa,IAAA,EAAM,WAAW,UAAA,EAAY,CAAA;AAAA,oBACtE,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EAAU,QAAA,EAAS;AAAA,GAAA,EACrC,CAAA;AAGF,EAAA,MAAM,eAAA,GAAkB,GAAG,oBAAA,CAAqB,EAAE,MAAM,OAAA,EAAS,GAAG,SAAS,CAAA;AAE7E,EAAA,IAAI,OAAO,YAAA,KAAiB,QAAA;AAC1B,IAAA,uBACE,GAAA,CAAC,GAAA,EAAA,EAAE,IAAA,EAAM,YAAA,EAAc,SAAA,EAAW,EAAA,CAAG,eAAA,EAAiB,cAAc,CAAA,EAAG,YAAA,EAAY,SAAA,EAChF,QAAA,EAAA,OAAA,EACH,CAAA;AAGJ,EAAA,uBACE,GAAA,CAAC,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,SAAA,EAAW,eAAA,EAAiB,OAAA,EAAS,YAAA,EAAc,QAAA,EAAoB,YAAA,EAAY,SAAA,EACtG,QAAA,EAAA,OAAA,EACH,CAAA;AAEJ","file":"glossy-button.mjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport type { CSSProperties } from 'react';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * A style object that may carry CSS custom properties (CSS variables)\n * such as `--duration`. React's `CSSProperties` intentionally drops\n * its index signature, so custom properties are not accepted without help.\n */\nexport type CSSPropertiesWithVars = CSSProperties & Record<`--${string}`, string | number>;\n\n/**\n * Builds a {@link CSSProperties} value that also allows CSS custom properties,\n * so `style` props can be written without an `as React.CSSProperties` cast while\n * still type-checking both the known style keys and the custom-property values.\n *\n * @example\n * <div style={validCssVars({ '--duration': '0.35s', color: 'red' })} />\n */\nexport function validCssVars(style: CSSPropertiesWithVars): CSSProperties {\n return style;\n}\n\n/**\n * Narrows a union to the member(s) that declare `key` — a type-guard\n * replacement for the `in` operator's discriminated-union narrowing.\n */\nexport function hasKey<K extends PropertyKey>(key: K, obj: unknown): obj is Record<K, unknown> {\n return obj !== null && typeof obj === 'object' && Object.hasOwn(obj, key);\n}\n\nexport function noop(): void {\n // intentional no-op\n}\n","import { cva, type VariantProps } from 'class-variance-authority';\nimport type { ReactNode } from 'react';\nimport { cn } from '../lib/utils.js';\n\n/**\n * Physically-lit button: a domed, back-lit key built from one effect layer.\n *\n * The geometry lives in a single `box-shadow` list that gets swapped wholesale on\n * press, so the bevel and cast can drop out while the rim survives without any\n * of them being separate elements:\n *\n * • the gloss span — face fill + the shadow list (bevel, rim, cast).\n * • its `before:` — the dome gradient, painted over the face.\n * • its `after:` — the hover/press tint, the only thing that cross-fades.\n *\n * The recipe lives in `global.css`. Every colour is a `--btn-*` primitive, and\n * the two shadow composites are declared on `.glossy` — on the key itself, not\n * on `:root` — because a var() inside a custom property is substituted where the\n * property is *declared*. That's what lets one `.glossy-<variant>` class restyle\n * the whole recipe by setting primitives, and it's why there are no `dark:`\n * variants here: `.dark` overrides the same primitives.\n *\n * The span is a sibling of the label rather than its parent so the label never\n * inherits the effect layers' stacking or transitions; `isolate` on the root\n * contains the span's negative z-index.\n *\n * Server-renderable: every state is pure CSS. Passing a function as\n * `actionOrLink` requires a client-component parent, as with any onClick prop.\n */\n\n/**\n * The whole visual treatment. Absolutely positioned behind the label, with the\n * dome (`before:`) and the interaction tint (`after:`) stacked over the face.\n * Only the tint animates opacity; the shadow list animates by being replaced.\n */\nconst glossLayer = cn(\n 'pointer-events-none absolute inset-0 z-[-1] rounded-[inherit]',\n '[background-color:var(--btn-face)] [box-shadow:var(--shadow-button)]',\n 'transition-shadow duration-150',\n // Pressed (and disabled): bevel + cast go transparent, the rim stays.\n 'group-active/glossy:[box-shadow:var(--shadow-button-pressed)]',\n 'group-disabled/glossy:[box-shadow:var(--shadow-button-pressed)]',\n // Dome — fixed direction, per-variant stops. Above the face, below the tint.\n \"before:absolute before:inset-0 before:rounded-[inherit] before:content-[''] before:[background-image:var(--gradient-button)]\",\n // Interaction tint. Hidden outright when disabled, and on touch (no hover\n // state to speak of) so the root's active:opacity can carry the press instead.\n \"after:absolute after:inset-0 after:rounded-[inherit] after:content-[''] after:opacity-0\",\n 'after:[background-color:var(--btn-tint-hover)] after:transition-opacity after:duration-150 after:[will-change:opacity]',\n 'group-hover/glossy:after:opacity-100',\n 'group-active/glossy:after:[background-color:var(--btn-tint-active)]',\n 'group-disabled/glossy:after:hidden [@media(hover:none)]:after:hidden',\n);\n\nconst glossyButtonVariants = cva(\n cn(\n 'glossy group/glossy relative isolate inline-flex cursor-pointer select-none items-center justify-center gap-1 whitespace-nowrap rounded-full font-normal',\n // Label colour rides the variant. Kept as a utility rather than a plain\n // declaration on `.glossy` so a caller's own text-* class still wins.\n '[color:var(--btn-fg)]',\n 'disabled:cursor-default disabled:opacity-50',\n // Touch devices get no hover layer, so the whole key dims on press instead.\n '[@media(hover:none)]:active:opacity-80',\n ),\n {\n variants: {\n size: {\n sm: 'h-8 px-2.5 text-sm',\n md: 'h-9 px-5 text-[17px]',\n lg: 'h-11 px-6 text-[17px]',\n },\n /**\n * Written out as literal class names — Tailwind's scanner is static, so a\n * `glossy-${variant}` template would never make it into the stylesheet.\n * `neutral` is the bare recipe, so it needs no class of its own.\n */\n variant: {\n neutral: '',\n accent: 'glossy-accent',\n destructive: 'glossy-destructive',\n special: 'glossy-special',\n positive: 'glossy-positive',\n attention: 'glossy-attention',\n highlight: 'glossy-highlight',\n inverse: 'glossy-inverse',\n },\n },\n defaultVariants: { size: 'md', variant: 'neutral' },\n },\n);\n\nexport type GlossyButtonProps = VariantProps<typeof glossyButtonVariants> & {\n /**\n * String → renders as a plain <a href={...}>.\n * Function → renders as a <button type=\"button\" onClick={...}>.\n */\n actionOrLink: string | (() => void);\n children: ReactNode;\n /** Button-only — an anchor can't be disabled. */\n disabled?: boolean;\n className?: string;\n 'aria-label'?: string;\n};\n\nexport function GlossyButton({\n size,\n variant,\n actionOrLink,\n children,\n disabled,\n className,\n 'aria-label': ariaLabel,\n}: GlossyButtonProps) {\n const content = (\n <>\n <span data-fx-layer=\"gloss\" aria-hidden={true} className={glossLayer} />\n <span className=\"px-0.5\">{children}</span>\n </>\n );\n\n const buttonClassName = cn(glossyButtonVariants({ size, variant }), className);\n\n if (typeof actionOrLink === 'string')\n return (\n <a href={actionOrLink} className={cn(buttonClassName, 'no-underline')} aria-label={ariaLabel}>\n {content}\n </a>\n );\n\n return (\n <button type=\"button\" className={buttonClassName} onClick={actionOrLink} disabled={disabled} aria-label={ariaLabel}>\n {content}\n </button>\n );\n}\n\nexport { glossyButtonVariants };\n"]}
|
package/dist/grainient.js
CHANGED
package/dist/grainient.mjs
CHANGED
|
@@ -1,4 +1,329 @@
|
|
|
1
|
-
|
|
2
|
-
import '
|
|
1
|
+
"use client";
|
|
2
|
+
import { Renderer, Triangle, Mesh, Program } from 'ogl';
|
|
3
|
+
import { useRef, useEffect } from 'react';
|
|
4
|
+
import { clsx } from 'clsx';
|
|
5
|
+
import { twMerge } from 'tailwind-merge';
|
|
6
|
+
import { jsx } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
function cn(...inputs) {
|
|
9
|
+
return twMerge(clsx(inputs));
|
|
10
|
+
}
|
|
11
|
+
var vertex = `#version 300 es
|
|
12
|
+
in vec2 position;
|
|
13
|
+
void main() {
|
|
14
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
17
|
+
var fragment = `#version 300 es
|
|
18
|
+
precision highp float;
|
|
19
|
+
uniform vec2 iResolution;
|
|
20
|
+
uniform float iTime;
|
|
21
|
+
uniform float uTimeSpeed;
|
|
22
|
+
uniform float uColorBalance;
|
|
23
|
+
uniform float uWarpStrength;
|
|
24
|
+
uniform float uWarpFrequency;
|
|
25
|
+
uniform float uWarpSpeed;
|
|
26
|
+
uniform float uWarpAmplitude;
|
|
27
|
+
uniform float uBlendAngle;
|
|
28
|
+
uniform float uBlendSoftness;
|
|
29
|
+
uniform float uRotationAmount;
|
|
30
|
+
uniform float uNoiseScale;
|
|
31
|
+
uniform float uGrainAmount;
|
|
32
|
+
uniform float uGrainScale;
|
|
33
|
+
uniform float uGrainAnimated;
|
|
34
|
+
uniform float uContrast;
|
|
35
|
+
uniform float uGamma;
|
|
36
|
+
uniform float uSaturation;
|
|
37
|
+
uniform vec2 uCenterOffset;
|
|
38
|
+
uniform float uZoom;
|
|
39
|
+
uniform vec3 uColor1;
|
|
40
|
+
uniform vec3 uColor2;
|
|
41
|
+
uniform vec3 uColor3;
|
|
42
|
+
out vec4 fragColor;
|
|
43
|
+
#define S(a,b,t) smoothstep(a,b,t)
|
|
44
|
+
mat2 Rot(float a){float s=sin(a),c=cos(a);return mat2(c,-s,s,c);}
|
|
45
|
+
vec2 hash(vec2 p){p=vec2(dot(p,vec2(2127.1,81.17)),dot(p,vec2(1269.5,283.37)));return fract(sin(p)*43758.5453);}
|
|
46
|
+
float noise(vec2 p){vec2 i=floor(p),f=fract(p),u=f*f*(3.0-2.0*f);float n=mix(mix(dot(-1.0+2.0*hash(i+vec2(0.0,0.0)),f-vec2(0.0,0.0)),dot(-1.0+2.0*hash(i+vec2(1.0,0.0)),f-vec2(1.0,0.0)),u.x),mix(dot(-1.0+2.0*hash(i+vec2(0.0,1.0)),f-vec2(0.0,1.0)),dot(-1.0+2.0*hash(i+vec2(1.0,1.0)),f-vec2(1.0,1.0)),u.x),u.y);return 0.5+0.5*n;}
|
|
47
|
+
void mainImage(out vec4 o, vec2 C){
|
|
48
|
+
float t=iTime*uTimeSpeed;
|
|
49
|
+
vec2 uv=C/iResolution.xy;
|
|
50
|
+
float ratio=iResolution.x/iResolution.y;
|
|
51
|
+
vec2 tuv=uv-0.5+uCenterOffset;
|
|
52
|
+
tuv/=max(uZoom,0.001);
|
|
53
|
+
float degree=noise(vec2(t*0.1,tuv.x*tuv.y)*uNoiseScale);
|
|
54
|
+
tuv.y*=1.0/ratio;
|
|
55
|
+
tuv*=Rot(radians((degree-0.5)*uRotationAmount+180.0));
|
|
56
|
+
tuv.y*=ratio;
|
|
57
|
+
float frequency=uWarpFrequency;
|
|
58
|
+
float ws=max(uWarpStrength,0.001);
|
|
59
|
+
float amplitude=uWarpAmplitude/ws;
|
|
60
|
+
float warpTime=t*uWarpSpeed;
|
|
61
|
+
tuv.x+=sin(tuv.y*frequency+warpTime)/amplitude;
|
|
62
|
+
tuv.y+=sin(tuv.x*(frequency*1.5)+warpTime)/(amplitude*0.5);
|
|
63
|
+
vec3 colLav=uColor1;
|
|
64
|
+
vec3 colOrg=uColor2;
|
|
65
|
+
vec3 colDark=uColor3;
|
|
66
|
+
float b=uColorBalance;
|
|
67
|
+
float s=max(uBlendSoftness,0.0);
|
|
68
|
+
mat2 blendRot=Rot(radians(uBlendAngle));
|
|
69
|
+
float blendX=(tuv*blendRot).x;
|
|
70
|
+
float edge0=-0.3-b-s;
|
|
71
|
+
float edge1=0.2-b+s;
|
|
72
|
+
float v0=0.5-b+s;
|
|
73
|
+
float v1=-0.3-b-s;
|
|
74
|
+
vec3 layer1=mix(colDark,colOrg,S(edge0,edge1,blendX));
|
|
75
|
+
vec3 layer2=mix(colOrg,colLav,S(edge0,edge1,blendX));
|
|
76
|
+
vec3 col=mix(layer1,layer2,S(v0,v1,tuv.y));
|
|
77
|
+
vec2 grainUv=uv*max(uGrainScale,0.001);
|
|
78
|
+
if(uGrainAnimated>0.5){grainUv+=vec2(iTime*0.05);}
|
|
79
|
+
float grain=fract(sin(dot(grainUv,vec2(12.9898,78.233)))*43758.5453);
|
|
80
|
+
col+=(grain-0.5)*uGrainAmount;
|
|
81
|
+
col=(col-0.5)*uContrast+0.5;
|
|
82
|
+
float luma=dot(col,vec3(0.2126,0.7152,0.0722));
|
|
83
|
+
col=mix(vec3(luma),col,uSaturation);
|
|
84
|
+
col=pow(max(col,0.0),vec3(1.0/max(uGamma,0.001)));
|
|
85
|
+
col=clamp(col,0.0,1.0);
|
|
86
|
+
o=vec4(col,1.0);
|
|
87
|
+
}
|
|
88
|
+
void main(){
|
|
89
|
+
vec4 o=vec4(0.0);
|
|
90
|
+
mainImage(o,gl_FragCoord.xy);
|
|
91
|
+
fragColor=o;
|
|
92
|
+
}
|
|
93
|
+
`;
|
|
94
|
+
function createGrainientProgram(gl) {
|
|
95
|
+
return new Program(gl, {
|
|
96
|
+
vertex,
|
|
97
|
+
fragment,
|
|
98
|
+
uniforms: {
|
|
99
|
+
iTime: { value: 0 },
|
|
100
|
+
iResolution: { value: new Float32Array([1, 1]) },
|
|
101
|
+
uTimeSpeed: { value: 0.25 },
|
|
102
|
+
uColorBalance: { value: 0 },
|
|
103
|
+
uWarpStrength: { value: 1 },
|
|
104
|
+
uWarpFrequency: { value: 5 },
|
|
105
|
+
uWarpSpeed: { value: 2 },
|
|
106
|
+
uWarpAmplitude: { value: 50 },
|
|
107
|
+
uBlendAngle: { value: 0 },
|
|
108
|
+
uBlendSoftness: { value: 0.05 },
|
|
109
|
+
uRotationAmount: { value: 500 },
|
|
110
|
+
uNoiseScale: { value: 2 },
|
|
111
|
+
uGrainAmount: { value: 0.1 },
|
|
112
|
+
uGrainScale: { value: 2 },
|
|
113
|
+
uGrainAnimated: { value: 0 },
|
|
114
|
+
uContrast: { value: 1.5 },
|
|
115
|
+
uGamma: { value: 1 },
|
|
116
|
+
uSaturation: { value: 1 },
|
|
117
|
+
uCenterOffset: { value: new Float32Array([0, 0]) },
|
|
118
|
+
uZoom: { value: 0.9 },
|
|
119
|
+
uColor1: { value: new Float32Array([1, 1, 1]) },
|
|
120
|
+
uColor2: { value: new Float32Array([1, 1, 1]) },
|
|
121
|
+
uColor3: { value: new Float32Array([1, 1, 1]) }
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
var ctxMap = /* @__PURE__ */ new WeakMap();
|
|
126
|
+
var HEX_COLOR_RE = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
|
|
127
|
+
var hexToRgb = (hex) => {
|
|
128
|
+
const result = HEX_COLOR_RE.exec(hex);
|
|
129
|
+
if (!result) return [1, 1, 1];
|
|
130
|
+
const [, r = "ff", g = "ff", b = "ff"] = result;
|
|
131
|
+
return [Number.parseInt(r, 16) / 255, Number.parseInt(g, 16) / 255, Number.parseInt(b, 16) / 255];
|
|
132
|
+
};
|
|
133
|
+
var prefersReducedMotion = () => typeof globalThis !== "undefined" && globalThis.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true;
|
|
134
|
+
var isLowPowerClient = () => {
|
|
135
|
+
if (typeof globalThis === "undefined") return false;
|
|
136
|
+
const narrow = globalThis.matchMedia?.("(max-width: 1023px)").matches === true;
|
|
137
|
+
const fewCores = typeof navigator !== "undefined" && typeof navigator.hardwareConcurrency === "number" && navigator.hardwareConcurrency <= 4;
|
|
138
|
+
return narrow || fewCores;
|
|
139
|
+
};
|
|
140
|
+
var GRAIN_LAYER = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.12'/%3E%3C/svg%3E")`;
|
|
141
|
+
var fallbackGradient = (c1, c2, c3) => `${GRAIN_LAYER}, linear-gradient(135deg, ${c1} 0%, ${c2} 55%, ${c3} 100%)`;
|
|
142
|
+
var applyStaticBg = (el, src) => {
|
|
143
|
+
el.style.backgroundImage = `url(${src})`;
|
|
144
|
+
el.style.backgroundSize = "cover";
|
|
145
|
+
el.style.backgroundPosition = "center";
|
|
146
|
+
};
|
|
147
|
+
function initGrainient(container) {
|
|
148
|
+
const renderer = new Renderer({
|
|
149
|
+
webgl: 2,
|
|
150
|
+
alpha: true,
|
|
151
|
+
antialias: false,
|
|
152
|
+
dpr: Math.min(globalThis.devicePixelRatio || 1, 2)
|
|
153
|
+
});
|
|
154
|
+
const gl = renderer.gl;
|
|
155
|
+
const canvas = gl.canvas;
|
|
156
|
+
canvas.style.width = "100%";
|
|
157
|
+
canvas.style.height = "100%";
|
|
158
|
+
canvas.style.display = "block";
|
|
159
|
+
container.appendChild(canvas);
|
|
160
|
+
const geometry = new Triangle(gl);
|
|
161
|
+
const program = createGrainientProgram(gl);
|
|
162
|
+
const mesh = new Mesh(gl, { geometry, program });
|
|
163
|
+
ctxMap.set(container, { renderer, program, mesh });
|
|
164
|
+
const setSize = () => {
|
|
165
|
+
const rect = container.getBoundingClientRect();
|
|
166
|
+
renderer.setSize(Math.max(1, Math.floor(rect.width)), Math.max(1, Math.floor(rect.height)));
|
|
167
|
+
const res = program.uniforms.iResolution.value;
|
|
168
|
+
res[0] = gl.drawingBufferWidth;
|
|
169
|
+
res[1] = gl.drawingBufferHeight;
|
|
170
|
+
renderer.render({ scene: mesh });
|
|
171
|
+
};
|
|
172
|
+
const ro = new ResizeObserver(setSize);
|
|
173
|
+
ro.observe(container);
|
|
174
|
+
setSize();
|
|
175
|
+
let raf = 0;
|
|
176
|
+
let isVisible = true;
|
|
177
|
+
let isPageVisible = !document.hidden;
|
|
178
|
+
const t0 = performance.now();
|
|
179
|
+
const loop = (t) => {
|
|
180
|
+
program.uniforms.iTime.value = (t - t0) * 1e-3;
|
|
181
|
+
renderer.render({ scene: mesh });
|
|
182
|
+
raf = requestAnimationFrame(loop);
|
|
183
|
+
};
|
|
184
|
+
const tryStart = () => {
|
|
185
|
+
if (isVisible && isPageVisible && raf === 0) raf = requestAnimationFrame(loop);
|
|
186
|
+
};
|
|
187
|
+
const tryStop = () => {
|
|
188
|
+
if (raf !== 0) {
|
|
189
|
+
cancelAnimationFrame(raf);
|
|
190
|
+
raf = 0;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
const reduce = prefersReducedMotion();
|
|
194
|
+
const io = new IntersectionObserver(
|
|
195
|
+
([entry]) => {
|
|
196
|
+
if (!entry) return;
|
|
197
|
+
isVisible = entry.isIntersecting;
|
|
198
|
+
if (isVisible) tryStart();
|
|
199
|
+
else tryStop();
|
|
200
|
+
},
|
|
201
|
+
{ threshold: 0 }
|
|
202
|
+
);
|
|
203
|
+
if (!reduce) io.observe(container);
|
|
204
|
+
const onVisibility = () => {
|
|
205
|
+
isPageVisible = !document.hidden;
|
|
206
|
+
if (isPageVisible) tryStart();
|
|
207
|
+
else tryStop();
|
|
208
|
+
};
|
|
209
|
+
if (!reduce) document.addEventListener("visibilitychange", onVisibility);
|
|
210
|
+
if (!reduce) tryStart();
|
|
211
|
+
return () => {
|
|
212
|
+
tryStop();
|
|
213
|
+
ro.disconnect();
|
|
214
|
+
io.disconnect();
|
|
215
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
216
|
+
ctxMap.delete(container);
|
|
217
|
+
try {
|
|
218
|
+
container.removeChild(canvas);
|
|
219
|
+
} catch {
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
var Grainient = (props) => {
|
|
224
|
+
const {
|
|
225
|
+
timeSpeed = 0.25,
|
|
226
|
+
colorBalance = 0,
|
|
227
|
+
warpStrength = 1,
|
|
228
|
+
warpFrequency = 5,
|
|
229
|
+
warpSpeed = 2,
|
|
230
|
+
warpAmplitude = 50,
|
|
231
|
+
blendAngle = 0,
|
|
232
|
+
blendSoftness = 0.05,
|
|
233
|
+
rotationAmount = 500,
|
|
234
|
+
noiseScale = 2,
|
|
235
|
+
grainAmount = 0.1,
|
|
236
|
+
grainScale = 2,
|
|
237
|
+
grainAnimated = false,
|
|
238
|
+
contrast = 1.5,
|
|
239
|
+
gamma = 1,
|
|
240
|
+
saturation = 1,
|
|
241
|
+
centerX = 0,
|
|
242
|
+
centerY = 0,
|
|
243
|
+
zoom = 0.9,
|
|
244
|
+
color1 = "#FF9FFC",
|
|
245
|
+
color2 = "#5227FF",
|
|
246
|
+
color3 = "#B497CF",
|
|
247
|
+
staticSrc = "",
|
|
248
|
+
className = ""
|
|
249
|
+
} = props;
|
|
250
|
+
const containerRef = useRef(null);
|
|
251
|
+
const fallbackRef = useRef(false);
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
const container = containerRef.current;
|
|
254
|
+
if (!container) return;
|
|
255
|
+
if (isLowPowerClient() || prefersReducedMotion()) {
|
|
256
|
+
fallbackRef.current = true;
|
|
257
|
+
container.dataset.fallback = "true";
|
|
258
|
+
if (staticSrc) applyStaticBg(container, staticSrc);
|
|
259
|
+
else container.style.background = fallbackGradient(color1, color2, color3);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
return initGrainient(container);
|
|
263
|
+
}, []);
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
const container = containerRef.current;
|
|
266
|
+
if (!container) return;
|
|
267
|
+
if (fallbackRef.current) {
|
|
268
|
+
if (staticSrc) applyStaticBg(container, staticSrc);
|
|
269
|
+
else container.style.background = fallbackGradient(color1, color2, color3);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const ctx = ctxMap.get(container);
|
|
273
|
+
if (!ctx) return;
|
|
274
|
+
const { program, renderer, mesh } = ctx;
|
|
275
|
+
const u = program.uniforms;
|
|
276
|
+
u.uTimeSpeed.value = timeSpeed;
|
|
277
|
+
u.uColorBalance.value = colorBalance;
|
|
278
|
+
u.uWarpStrength.value = warpStrength;
|
|
279
|
+
u.uWarpFrequency.value = warpFrequency;
|
|
280
|
+
u.uWarpSpeed.value = warpSpeed;
|
|
281
|
+
u.uWarpAmplitude.value = warpAmplitude;
|
|
282
|
+
u.uBlendAngle.value = blendAngle;
|
|
283
|
+
u.uBlendSoftness.value = blendSoftness;
|
|
284
|
+
u.uRotationAmount.value = rotationAmount;
|
|
285
|
+
u.uNoiseScale.value = noiseScale;
|
|
286
|
+
u.uGrainAmount.value = grainAmount;
|
|
287
|
+
u.uGrainScale.value = grainScale;
|
|
288
|
+
u.uGrainAnimated.value = grainAnimated ? 1 : 0;
|
|
289
|
+
u.uContrast.value = contrast;
|
|
290
|
+
u.uGamma.value = gamma;
|
|
291
|
+
u.uSaturation.value = saturation;
|
|
292
|
+
u.uCenterOffset.value = new Float32Array([centerX, centerY]);
|
|
293
|
+
u.uZoom.value = zoom;
|
|
294
|
+
u.uColor1.value = new Float32Array(hexToRgb(color1));
|
|
295
|
+
u.uColor2.value = new Float32Array(hexToRgb(color2));
|
|
296
|
+
u.uColor3.value = new Float32Array(hexToRgb(color3));
|
|
297
|
+
if (prefersReducedMotion()) renderer.render({ scene: mesh });
|
|
298
|
+
}, [
|
|
299
|
+
timeSpeed,
|
|
300
|
+
colorBalance,
|
|
301
|
+
warpStrength,
|
|
302
|
+
warpFrequency,
|
|
303
|
+
warpSpeed,
|
|
304
|
+
warpAmplitude,
|
|
305
|
+
blendAngle,
|
|
306
|
+
blendSoftness,
|
|
307
|
+
rotationAmount,
|
|
308
|
+
noiseScale,
|
|
309
|
+
grainAmount,
|
|
310
|
+
grainScale,
|
|
311
|
+
grainAnimated,
|
|
312
|
+
contrast,
|
|
313
|
+
gamma,
|
|
314
|
+
saturation,
|
|
315
|
+
centerX,
|
|
316
|
+
centerY,
|
|
317
|
+
zoom,
|
|
318
|
+
color1,
|
|
319
|
+
color2,
|
|
320
|
+
color3,
|
|
321
|
+
staticSrc
|
|
322
|
+
]);
|
|
323
|
+
return /* @__PURE__ */ jsx("div", { ref: containerRef, className: cn("grainient-container", className) });
|
|
324
|
+
};
|
|
325
|
+
var grainient_default = Grainient;
|
|
326
|
+
|
|
327
|
+
export { grainient_default as default };
|
|
3
328
|
//# sourceMappingURL=grainient.mjs.map
|
|
4
329
|
//# sourceMappingURL=grainient.mjs.map
|
package/dist/grainient.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"grainient.mjs"}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/grainient.shader.ts","../src/components/grainient.tsx"],"names":[],"mappings":"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","file":"grainient.mjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport type { CSSProperties } from 'react';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n/**\n * A style object that may carry CSS custom properties (CSS variables)\n * such as `--duration`. React's `CSSProperties` intentionally drops\n * its index signature, so custom properties are not accepted without help.\n */\nexport type CSSPropertiesWithVars = CSSProperties & Record<`--${string}`, string | number>;\n\n/**\n * Builds a {@link CSSProperties} value that also allows CSS custom properties,\n * so `style` props can be written without an `as React.CSSProperties` cast while\n * still type-checking both the known style keys and the custom-property values.\n *\n * @example\n * <div style={validCssVars({ '--duration': '0.35s', color: 'red' })} />\n */\nexport function validCssVars(style: CSSPropertiesWithVars): CSSProperties {\n return style;\n}\n\n/**\n * Narrows a union to the member(s) that declare `key` — a type-guard\n * replacement for the `in` operator's discriminated-union narrowing.\n */\nexport function hasKey<K extends PropertyKey>(key: K, obj: unknown): obj is Record<K, unknown> {\n return obj !== null && typeof obj === 'object' && Object.hasOwn(obj, key);\n}\n\nexport function noop(): void {\n // intentional no-op\n}\n","import { type Mesh, Program, type Renderer } from 'ogl';\n\n// Keep renderer/program alive across re-renders so the uniform-sync effect can\n// update uniforms without ever rebuilding the WebGL context.\nconst vertex = `#version 300 es\nin vec2 position;\nvoid main() {\n gl_Position = vec4(position, 0.0, 1.0);\n}\n`;\n\nconst fragment = `#version 300 es\nprecision highp float;\nuniform vec2 iResolution;\nuniform float iTime;\nuniform float uTimeSpeed;\nuniform float uColorBalance;\nuniform float uWarpStrength;\nuniform float uWarpFrequency;\nuniform float uWarpSpeed;\nuniform float uWarpAmplitude;\nuniform float uBlendAngle;\nuniform float uBlendSoftness;\nuniform float uRotationAmount;\nuniform float uNoiseScale;\nuniform float uGrainAmount;\nuniform float uGrainScale;\nuniform float uGrainAnimated;\nuniform float uContrast;\nuniform float uGamma;\nuniform float uSaturation;\nuniform vec2 uCenterOffset;\nuniform float uZoom;\nuniform vec3 uColor1;\nuniform vec3 uColor2;\nuniform vec3 uColor3;\nout vec4 fragColor;\n#define S(a,b,t) smoothstep(a,b,t)\nmat2 Rot(float a){float s=sin(a),c=cos(a);return mat2(c,-s,s,c);}\nvec2 hash(vec2 p){p=vec2(dot(p,vec2(2127.1,81.17)),dot(p,vec2(1269.5,283.37)));return fract(sin(p)*43758.5453);}\nfloat noise(vec2 p){vec2 i=floor(p),f=fract(p),u=f*f*(3.0-2.0*f);float n=mix(mix(dot(-1.0+2.0*hash(i+vec2(0.0,0.0)),f-vec2(0.0,0.0)),dot(-1.0+2.0*hash(i+vec2(1.0,0.0)),f-vec2(1.0,0.0)),u.x),mix(dot(-1.0+2.0*hash(i+vec2(0.0,1.0)),f-vec2(0.0,1.0)),dot(-1.0+2.0*hash(i+vec2(1.0,1.0)),f-vec2(1.0,1.0)),u.x),u.y);return 0.5+0.5*n;}\nvoid mainImage(out vec4 o, vec2 C){\n float t=iTime*uTimeSpeed;\n vec2 uv=C/iResolution.xy;\n float ratio=iResolution.x/iResolution.y;\n vec2 tuv=uv-0.5+uCenterOffset;\n tuv/=max(uZoom,0.001);\n float degree=noise(vec2(t*0.1,tuv.x*tuv.y)*uNoiseScale);\n tuv.y*=1.0/ratio;\n tuv*=Rot(radians((degree-0.5)*uRotationAmount+180.0));\n tuv.y*=ratio;\n float frequency=uWarpFrequency;\n float ws=max(uWarpStrength,0.001);\n float amplitude=uWarpAmplitude/ws;\n float warpTime=t*uWarpSpeed;\n tuv.x+=sin(tuv.y*frequency+warpTime)/amplitude;\n tuv.y+=sin(tuv.x*(frequency*1.5)+warpTime)/(amplitude*0.5);\n vec3 colLav=uColor1;\n vec3 colOrg=uColor2;\n vec3 colDark=uColor3;\n float b=uColorBalance;\n float s=max(uBlendSoftness,0.0);\n mat2 blendRot=Rot(radians(uBlendAngle));\n float blendX=(tuv*blendRot).x;\n float edge0=-0.3-b-s;\n float edge1=0.2-b+s;\n float v0=0.5-b+s;\n float v1=-0.3-b-s;\n vec3 layer1=mix(colDark,colOrg,S(edge0,edge1,blendX));\n vec3 layer2=mix(colOrg,colLav,S(edge0,edge1,blendX));\n vec3 col=mix(layer1,layer2,S(v0,v1,tuv.y));\n vec2 grainUv=uv*max(uGrainScale,0.001);\n if(uGrainAnimated>0.5){grainUv+=vec2(iTime*0.05);}\n float grain=fract(sin(dot(grainUv,vec2(12.9898,78.233)))*43758.5453);\n col+=(grain-0.5)*uGrainAmount;\n col=(col-0.5)*uContrast+0.5;\n float luma=dot(col,vec3(0.2126,0.7152,0.0722));\n col=mix(vec3(luma),col,uSaturation);\n col=pow(max(col,0.0),vec3(1.0/max(uGamma,0.001)));\n col=clamp(col,0.0,1.0);\n o=vec4(col,1.0);\n}\nvoid main(){\n vec4 o=vec4(0.0);\n mainImage(o,gl_FragCoord.xy);\n fragColor=o;\n}\n`;\n\nexport type GrainientContext = { renderer: Renderer; program: Program; mesh: Mesh };\n\nexport function createGrainientProgram(gl: Renderer['gl']): Program {\n return new Program(gl, {\n vertex,\n fragment,\n uniforms: {\n iTime: { value: 0 },\n iResolution: { value: new Float32Array([1, 1]) },\n uTimeSpeed: { value: 0.25 },\n uColorBalance: { value: 0.0 },\n uWarpStrength: { value: 1.0 },\n uWarpFrequency: { value: 5.0 },\n uWarpSpeed: { value: 2.0 },\n uWarpAmplitude: { value: 50.0 },\n uBlendAngle: { value: 0.0 },\n uBlendSoftness: { value: 0.05 },\n uRotationAmount: { value: 500.0 },\n uNoiseScale: { value: 2.0 },\n uGrainAmount: { value: 0.1 },\n uGrainScale: { value: 2.0 },\n uGrainAnimated: { value: 0.0 },\n uContrast: { value: 1.5 },\n uGamma: { value: 1.0 },\n uSaturation: { value: 1.0 },\n uCenterOffset: { value: new Float32Array([0, 0]) },\n uZoom: { value: 0.9 },\n uColor1: { value: new Float32Array([1, 1, 1]) },\n uColor2: { value: new Float32Array([1, 1, 1]) },\n uColor3: { value: new Float32Array([1, 1, 1]) },\n },\n });\n}\n\nexport const ctxMap = new WeakMap<HTMLElement, GrainientContext>();\n","'use client';\n\nimport { Mesh, Renderer, Triangle } from 'ogl';\nimport { useEffect, useRef } from 'react';\nimport { cn } from '../lib/utils.js';\nimport { createGrainientProgram, ctxMap } from './grainient.shader.js';\nimport type { GrainientProps } from './grainient.types.js';\nimport './grainient.css';\n\nconst HEX_COLOR_RE = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i;\n\nconst hexToRgb = (hex: string): [number, number, number] => {\n const result = HEX_COLOR_RE.exec(hex);\n if (!result) return [1, 1, 1];\n // The regex guarantees all three capture groups when it matches; the defaults\n // only silence noUncheckedIndexedAccess.\n const [, r = 'ff', g = 'ff', b = 'ff'] = result;\n return [Number.parseInt(r, 16) / 255, Number.parseInt(g, 16) / 255, Number.parseInt(b, 16) / 255];\n};\n\n// framer-motion's MotionConfig only governs declarative motion.* components, so\n// this raw-WebGL canvas carries its own prefers-reduced-motion check.\nconst prefersReducedMotion = () =>\n typeof globalThis !== 'undefined' && globalThis.matchMedia?.('(prefers-reduced-motion: reduce)').matches === true;\n\n// The home page mounts four Grainient canvases at once; browsers cap live WebGL\n// contexts (~8-16) and each costs GPU/CPU. On low-power clients — narrow viewports\n// or few CPU cores — skip WebGL and let the static background stand in.\nconst isLowPowerClient = () => {\n if (typeof globalThis === 'undefined') return false;\n const narrow = globalThis.matchMedia?.('(max-width: 1023px)').matches === true;\n const fewCores =\n typeof navigator !== 'undefined' && typeof navigator.hardwareConcurrency === 'number' && navigator.hardwareConcurrency <= 4;\n return narrow || fewCores;\n};\n\n// A tiling SVG feTurbulence tile that stands in for the shader's film grain,\n// inlined so it needs no network request.\nconst GRAIN_LAYER = `url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.12'/%3E%3C/svg%3E\")`;\n\n// CSS gradient fallback when no pre-rendered image is available.\nconst fallbackGradient = (c1: string, c2: string, c3: string) =>\n `${GRAIN_LAYER}, linear-gradient(135deg, ${c1} 0%, ${c2} 55%, ${c3} 100%)`;\n\n// Apply a pre-rendered static image as a cover background.\nconst applyStaticBg = (el: HTMLDivElement, src: string) => {\n el.style.backgroundImage = `url(${src})`;\n el.style.backgroundSize = 'cover';\n el.style.backgroundPosition = 'center';\n};\n\n// Build the WebGL context, wire up resize/visibility observers, and run the\n// render loop. Returns a cleanup that tears everything back down.\nfunction initGrainient(container: HTMLDivElement): () => void {\n const renderer = new Renderer({\n webgl: 2,\n alpha: true,\n antialias: false,\n dpr: Math.min(globalThis.devicePixelRatio || 1, 2),\n });\n\n const gl = renderer.gl;\n const canvas = gl.canvas;\n canvas.style.width = '100%';\n canvas.style.height = '100%';\n canvas.style.display = 'block';\n container.appendChild(canvas);\n\n const geometry = new Triangle(gl);\n const program = createGrainientProgram(gl);\n const mesh = new Mesh(gl, { geometry, program });\n ctxMap.set(container, { renderer, program, mesh });\n\n const setSize = () => {\n const rect = container.getBoundingClientRect();\n renderer.setSize(Math.max(1, Math.floor(rect.width)), Math.max(1, Math.floor(rect.height)));\n const res: Float32Array = program.uniforms.iResolution.value;\n res[0] = gl.drawingBufferWidth;\n res[1] = gl.drawingBufferHeight;\n renderer.render({ scene: mesh });\n };\n\n const ro = new ResizeObserver(setSize);\n ro.observe(container);\n setSize();\n\n let raf = 0;\n let isVisible = true;\n let isPageVisible = !document.hidden;\n const t0 = performance.now();\n\n const loop = (t: number) => {\n program.uniforms.iTime.value = (t - t0) * 0.001;\n renderer.render({ scene: mesh });\n raf = requestAnimationFrame(loop);\n };\n\n const tryStart = () => {\n if (isVisible && isPageVisible && raf === 0) raf = requestAnimationFrame(loop);\n };\n const tryStop = () => {\n if (raf !== 0) {\n cancelAnimationFrame(raf);\n raf = 0;\n }\n };\n\n // Reduced motion: render a single static frame and never start the RAF loop.\n const reduce = prefersReducedMotion();\n\n const io = new IntersectionObserver(\n ([entry]) => {\n if (!entry) return;\n isVisible = entry.isIntersecting;\n if (isVisible) tryStart();\n else tryStop();\n },\n { threshold: 0 },\n );\n if (!reduce) io.observe(container);\n\n const onVisibility = () => {\n isPageVisible = !document.hidden;\n if (isPageVisible) tryStart();\n else tryStop();\n };\n if (!reduce) document.addEventListener('visibilitychange', onVisibility);\n if (!reduce) tryStart();\n\n return () => {\n tryStop();\n ro.disconnect();\n io.disconnect();\n document.removeEventListener('visibilitychange', onVisibility);\n ctxMap.delete(container);\n try {\n container.removeChild(canvas);\n } catch {\n /* ignore */\n }\n };\n}\n\nconst Grainient = (props: GrainientProps) => {\n const {\n timeSpeed = 0.25,\n colorBalance = 0.0,\n warpStrength = 1.0,\n warpFrequency = 5.0,\n warpSpeed = 2.0,\n warpAmplitude = 50.0,\n blendAngle = 0.0,\n blendSoftness = 0.05,\n rotationAmount = 500.0,\n noiseScale = 2.0,\n grainAmount = 0.1,\n grainScale = 2.0,\n grainAnimated = false,\n contrast = 1.5,\n gamma = 1.0,\n saturation = 1.0,\n centerX = 0.0,\n centerY = 0.0,\n zoom = 0.9,\n color1 = '#FF9FFC',\n color2 = '#5227FF',\n color3 = '#B497CF',\n staticSrc = '',\n className = '',\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n // Set once on mount: when true, WebGL is skipped and a static background stands in.\n const fallbackRef = useRef(false);\n\n // Effect 1: build WebGL context once, pause when offscreen / tab hidden.\n // When a pre-rendered image is available, low-power clients and\n // prefers-reduced-motion users get it as a zero-GPU-cost background.\n // The renderer is created once on mount; color changes are handled in Effect 2.\n // biome-ignore lint/plugin: creates the WebGL renderer once on mount and tears it down on unmount — imperative GPU setup with no derived-state form.\n // biome-ignore lint/correctness/useExhaustiveDependencies: mount-only WebGL setup; color/staticSrc changes are handled in Effect 2.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n if (isLowPowerClient() || prefersReducedMotion()) {\n fallbackRef.current = true;\n container.dataset.fallback = 'true';\n if (staticSrc) applyStaticBg(container, staticSrc);\n else container.style.background = fallbackGradient(color1, color2, color3);\n return;\n }\n return initGrainient(container);\n }, []); // renderer created once\n\n // Effect 2: sync props to uniforms — zero GPU cost, no teardown.\n // biome-ignore lint/plugin: imperatively writes props into mutable WebGL uniform objects (an external system); there is no render-time equivalent.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n // Fallback clients have no WebGL context; re-apply the background so a\n // later color/src change still reaches the static background.\n if (fallbackRef.current) {\n if (staticSrc) applyStaticBg(container, staticSrc);\n else container.style.background = fallbackGradient(color1, color2, color3);\n return;\n }\n\n const ctx = ctxMap.get(container);\n if (!ctx) return;\n\n const { program, renderer, mesh } = ctx;\n const u = program.uniforms;\n\n u.uTimeSpeed.value = timeSpeed;\n u.uColorBalance.value = colorBalance;\n u.uWarpStrength.value = warpStrength;\n u.uWarpFrequency.value = warpFrequency;\n u.uWarpSpeed.value = warpSpeed;\n u.uWarpAmplitude.value = warpAmplitude;\n u.uBlendAngle.value = blendAngle;\n u.uBlendSoftness.value = blendSoftness;\n u.uRotationAmount.value = rotationAmount;\n u.uNoiseScale.value = noiseScale;\n u.uGrainAmount.value = grainAmount;\n u.uGrainScale.value = grainScale;\n u.uGrainAnimated.value = grainAnimated ? 1.0 : 0.0;\n u.uContrast.value = contrast;\n u.uGamma.value = gamma;\n u.uSaturation.value = saturation;\n u.uCenterOffset.value = new Float32Array([centerX, centerY]);\n u.uZoom.value = zoom;\n u.uColor1.value = new Float32Array(hexToRgb(color1));\n u.uColor2.value = new Float32Array(hexToRgb(color2));\n u.uColor3.value = new Float32Array(hexToRgb(color3));\n\n // Under reduced motion the RAF loop never starts; draw one frame here so\n // the real colors appear (the first frame from setSize() is all-white).\n if (prefersReducedMotion()) renderer.render({ scene: mesh });\n }, [\n timeSpeed,\n colorBalance,\n warpStrength,\n warpFrequency,\n warpSpeed,\n warpAmplitude,\n blendAngle,\n blendSoftness,\n rotationAmount,\n noiseScale,\n grainAmount,\n grainScale,\n grainAnimated,\n contrast,\n gamma,\n saturation,\n centerX,\n centerY,\n zoom,\n color1,\n color2,\n color3,\n staticSrc,\n ]);\n\n return <div ref={containerRef} className={cn('grainient-container', className)} />;\n};\n\nexport default Grainient;\n"]}
|
package/dist/highlighter.js
CHANGED