solid-drift 0.7.1 → 0.8.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/README.md +199 -1
- package/dist/ai.d.ts +207 -0
- package/dist/ai.js +570 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +3 -1
- package/dist/motion.d.ts +78 -1
- package/dist/motion.js +81 -49
- package/dist/text.d.ts +27 -0
- package/dist/text.js +84 -0
- package/dist/web3.d.ts +213 -0
- package/dist/web3.js +640 -0
- package/package.json +1 -1
package/dist/motion.js
CHANGED
|
@@ -16,53 +16,7 @@ import { parseColorStops, sampleColorStops, } from "./color.js";
|
|
|
16
16
|
import { resolveEasing } from "./easing.js";
|
|
17
17
|
import { now, schedule } from "./engine.js";
|
|
18
18
|
import { prefersReducedMotion } from "./reduced-motion.js";
|
|
19
|
-
|
|
20
|
-
const od = el
|
|
21
|
-
.ownerDocument;
|
|
22
|
-
if (od)
|
|
23
|
-
return od ?? undefined;
|
|
24
|
-
return typeof document !== "undefined" ? document : undefined;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Split an element's text into per-unit inline-block spans so each
|
|
28
|
-
* letter (or word) can be transformed independently. The original text
|
|
29
|
-
* is preserved as an aria-label for screen readers.
|
|
30
|
-
*/
|
|
31
|
-
function splitUnits(el, unit) {
|
|
32
|
-
const doc = ownerDoc(el);
|
|
33
|
-
if (!doc)
|
|
34
|
-
return [];
|
|
35
|
-
const text = el.textContent ?? "";
|
|
36
|
-
el.textContent = "";
|
|
37
|
-
el.setAttribute("aria-label", text);
|
|
38
|
-
const spans = [];
|
|
39
|
-
const push = (content) => {
|
|
40
|
-
const s = doc.createElement("span");
|
|
41
|
-
s.textContent = content;
|
|
42
|
-
s.setAttribute("aria-hidden", "true");
|
|
43
|
-
s.style.display = "inline-block";
|
|
44
|
-
s.style.willChange = "transform, opacity, filter";
|
|
45
|
-
el.appendChild(s);
|
|
46
|
-
spans.push(s);
|
|
47
|
-
};
|
|
48
|
-
if (unit === "words") {
|
|
49
|
-
for (const word of text.split(/(\s+)/)) {
|
|
50
|
-
if (word.length === 0)
|
|
51
|
-
continue;
|
|
52
|
-
if (/^\s+$/.test(word)) {
|
|
53
|
-
el.appendChild(doc.createTextNode(word));
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
push(word);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
for (const ch of text)
|
|
62
|
-
push(ch === " " ? " " : ch);
|
|
63
|
-
}
|
|
64
|
-
return spans;
|
|
65
|
-
}
|
|
19
|
+
import { mulberry32, splitUnits } from "./text.js";
|
|
66
20
|
function clamp01(v) {
|
|
67
21
|
return v < 0 ? 0 : v > 1 ? 1 : v;
|
|
68
22
|
}
|
|
@@ -88,7 +42,8 @@ function applyKineticStyle(el, e, from) {
|
|
|
88
42
|
*
|
|
89
43
|
* One master clock drives every unit, so a headline with 40 characters
|
|
90
44
|
* costs a single rAF task, not 40 timers. Units animate through the
|
|
91
|
-
* same `from` state with per-unit easing.
|
|
45
|
+
* same `from` state with per-unit easing; set `from.variance` above 0
|
|
46
|
+
* for seeded per-unit jitter around those values.
|
|
92
47
|
*
|
|
93
48
|
* SSR-safe: no-op on the server. Under reduced motion every unit jumps
|
|
94
49
|
* to its final state when `play()` runs, so the text is fully readable.
|
|
@@ -113,10 +68,13 @@ export function createKineticType(ref, options = {}) {
|
|
|
113
68
|
scale: options.from?.scale ?? 0.85,
|
|
114
69
|
opacity: options.from?.opacity ?? 0,
|
|
115
70
|
rotate: options.from?.rotate ?? 0,
|
|
71
|
+
variance: options.from?.variance ?? 0,
|
|
72
|
+
seed: options.from?.seed ?? 0,
|
|
116
73
|
};
|
|
117
74
|
const easing = resolveEasing(easingOpt);
|
|
118
75
|
const [status, setStatus] = createSignal("idle");
|
|
119
76
|
let units = [];
|
|
77
|
+
let unitFrom = [];
|
|
120
78
|
let controls = null;
|
|
121
79
|
let runToken = 0;
|
|
122
80
|
const play = () => {
|
|
@@ -124,6 +82,7 @@ export function createKineticType(ref, options = {}) {
|
|
|
124
82
|
controls?.stop();
|
|
125
83
|
controls = null;
|
|
126
84
|
units = [];
|
|
85
|
+
unitFrom = [];
|
|
127
86
|
if (typeof window !== "undefined") {
|
|
128
87
|
const el = ref();
|
|
129
88
|
if (el)
|
|
@@ -133,6 +92,29 @@ export function createKineticType(ref, options = {}) {
|
|
|
133
92
|
setStatus("done");
|
|
134
93
|
return Promise.resolve();
|
|
135
94
|
}
|
|
95
|
+
// Seeded per-unit jitter around the `from` values. Deterministic
|
|
96
|
+
// for a given seed, so the same headline renders the same way on
|
|
97
|
+
// every run. Variance 0 keeps the exact legacy behavior.
|
|
98
|
+
const variance = clamp01(from.variance);
|
|
99
|
+
if (variance > 0) {
|
|
100
|
+
const rand = mulberry32(from.seed);
|
|
101
|
+
unitFrom = units.map(() => ({
|
|
102
|
+
y: from.y + variance * (rand() * 2 - 1) * 20,
|
|
103
|
+
blur: Math.max(0, from.blur + variance * (rand() * 2 - 1) * 8),
|
|
104
|
+
scale: from.scale + variance * (rand() * 2 - 1) * 0.15,
|
|
105
|
+
opacity: from.opacity,
|
|
106
|
+
rotate: from.rotate + variance * (rand() * 2 - 1) * 12,
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
unitFrom = units.map(() => ({
|
|
111
|
+
y: from.y,
|
|
112
|
+
blur: from.blur,
|
|
113
|
+
scale: from.scale,
|
|
114
|
+
opacity: from.opacity,
|
|
115
|
+
rotate: from.rotate,
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
136
118
|
setStatus("running");
|
|
137
119
|
const total = duration + stagger * (units.length - 1);
|
|
138
120
|
return new Promise((resolve) => {
|
|
@@ -146,7 +128,7 @@ export function createKineticType(ref, options = {}) {
|
|
|
146
128
|
onUpdate: (elapsed) => {
|
|
147
129
|
for (let i = 0; i < units.length; i++) {
|
|
148
130
|
const local = clamp01((elapsed - i * stagger) / duration);
|
|
149
|
-
applyKineticStyle(units[i], easing(local),
|
|
131
|
+
applyKineticStyle(units[i], easing(local), unitFrom[i]);
|
|
150
132
|
}
|
|
151
133
|
},
|
|
152
134
|
onComplete: () => {
|
|
@@ -716,6 +698,7 @@ export function createBeat(options = {}) {
|
|
|
716
698
|
beat,
|
|
717
699
|
bar,
|
|
718
700
|
phase,
|
|
701
|
+
beatsPerBar: perBar,
|
|
719
702
|
onBeat: (cb) => {
|
|
720
703
|
listeners.add(cb);
|
|
721
704
|
return () => {
|
|
@@ -727,3 +710,52 @@ export function createBeat(options = {}) {
|
|
|
727
710
|
status,
|
|
728
711
|
};
|
|
729
712
|
}
|
|
713
|
+
/**
|
|
714
|
+
* Guided showreel recipe: a thin typed wrapper over
|
|
715
|
+
* `createScenePlayer` for showreels and launch films. Scenes carry a
|
|
716
|
+
* named `kind` so the reel reads like a shot list, and each scene's
|
|
717
|
+
* `onEnter` wires one of the motion-graphics primitives
|
|
718
|
+
* (`createKineticType`, `createCamera`, `createColorShift`,
|
|
719
|
+
* `createTransition`, `createBeat`).
|
|
720
|
+
*
|
|
721
|
+
* Same controls, status values, and reduced-motion behavior as
|
|
722
|
+
* `createScenePlayer`: `play()` jumps to the final frame under reduced
|
|
723
|
+
* motion or on the server.
|
|
724
|
+
*
|
|
725
|
+
* ```ts
|
|
726
|
+
* const reel = createShowreel([
|
|
727
|
+
* { kind: "title", duration: 1200, onEnter: () => titleCard.play() },
|
|
728
|
+
* { kind: "camera", duration: 2000, onEnter: () => dolly.play() },
|
|
729
|
+
* { kind: "color", duration: 1500, onEnter: () => finale.play() },
|
|
730
|
+
* ])
|
|
731
|
+
* beatCuts = createBeatCuts(beat, reel, { every: 8 })
|
|
732
|
+
* await reel.play()
|
|
733
|
+
* ```
|
|
734
|
+
*/
|
|
735
|
+
export function createShowreel(scenes) {
|
|
736
|
+
return createScenePlayer(scenes);
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Beat-synced scene cuts: advance the player every N beats through
|
|
740
|
+
* the beat clock's `onBeat`. Returns a cleanup function that
|
|
741
|
+
* unsubscribes the cut listener.
|
|
742
|
+
*
|
|
743
|
+
* Cuts only fire while the player is running, so pausing the reel
|
|
744
|
+
* pauses the cuts too.
|
|
745
|
+
*
|
|
746
|
+
* ```ts
|
|
747
|
+
* const beat = createBeat({ bpm: 128, beatsPerBar: 4 })
|
|
748
|
+
* const stopCuts = createBeatCuts(beat, player) // cut every bar
|
|
749
|
+
* beat.start()
|
|
750
|
+
* await player.play()
|
|
751
|
+
* stopCuts()
|
|
752
|
+
* ```
|
|
753
|
+
*/
|
|
754
|
+
export function createBeatCuts(beat, player, options = {}) {
|
|
755
|
+
const every = Math.max(1, Math.floor(options.every ?? beat.beatsPerBar));
|
|
756
|
+
return beat.onBeat((b) => {
|
|
757
|
+
if (b % every === 0 && player.status() === "running") {
|
|
758
|
+
player.next();
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
}
|
package/dist/text.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal text utilities shared by the motion-graphics primitives.
|
|
3
|
+
*
|
|
4
|
+
* Not part of the public API: family modules import from here, but
|
|
5
|
+
* nothing in this file is re-exported from the package index.
|
|
6
|
+
*/
|
|
7
|
+
/** Document owning the element, with an SSR-safe fallback. */
|
|
8
|
+
export declare function ownerDoc(el: Element): Document | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Split an element's text into per-unit inline-block spans so each
|
|
11
|
+
* letter (or word) can be transformed independently. The original text
|
|
12
|
+
* is preserved as an aria-label for screen readers. Any previous
|
|
13
|
+
* content is replaced.
|
|
14
|
+
*/
|
|
15
|
+
export declare function splitUnits(el: Element, unit: "chars" | "words"): HTMLElement[];
|
|
16
|
+
/**
|
|
17
|
+
* Append per-unit inline-block spans for `text` to the element's
|
|
18
|
+
* existing content, without clearing it. Used by streaming text, where
|
|
19
|
+
* each flushed batch adds new units while earlier units keep playing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function appendUnits(el: Element, text: string, unit: "chars" | "words"): HTMLElement[];
|
|
22
|
+
/**
|
|
23
|
+
* Deterministic pseudo-random generator (mulberry32). Used for
|
|
24
|
+
* per-unit variance so seeded jitter renders identically on every
|
|
25
|
+
* run, which keeps tests stable and output reproducible.
|
|
26
|
+
*/
|
|
27
|
+
export declare function mulberry32(seed: number): () => number;
|
package/dist/text.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal text utilities shared by the motion-graphics primitives.
|
|
3
|
+
*
|
|
4
|
+
* Not part of the public API: family modules import from here, but
|
|
5
|
+
* nothing in this file is re-exported from the package index.
|
|
6
|
+
*/
|
|
7
|
+
/** Document owning the element, with an SSR-safe fallback. */
|
|
8
|
+
export function ownerDoc(el) {
|
|
9
|
+
const od = el
|
|
10
|
+
.ownerDocument;
|
|
11
|
+
if (od)
|
|
12
|
+
return od ?? undefined;
|
|
13
|
+
return typeof document !== "undefined" ? document : undefined;
|
|
14
|
+
}
|
|
15
|
+
function pushUnit(doc, parent, content) {
|
|
16
|
+
const s = doc.createElement("span");
|
|
17
|
+
s.textContent = content;
|
|
18
|
+
s.setAttribute("aria-hidden", "true");
|
|
19
|
+
s.style.display = "inline-block";
|
|
20
|
+
s.style.willChange = "transform, opacity, filter";
|
|
21
|
+
parent.appendChild(s);
|
|
22
|
+
return s;
|
|
23
|
+
}
|
|
24
|
+
function appendTokens(doc, parent, text, unit) {
|
|
25
|
+
const spans = [];
|
|
26
|
+
if (unit === "words") {
|
|
27
|
+
for (const word of text.split(/(\s+)/)) {
|
|
28
|
+
if (word.length === 0)
|
|
29
|
+
continue;
|
|
30
|
+
if (/^\s+$/.test(word)) {
|
|
31
|
+
parent.appendChild(doc.createTextNode(word));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
spans.push(pushUnit(doc, parent, word));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
for (const ch of text)
|
|
40
|
+
spans.push(pushUnit(doc, parent, ch === " " ? " " : ch));
|
|
41
|
+
}
|
|
42
|
+
return spans;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Split an element's text into per-unit inline-block spans so each
|
|
46
|
+
* letter (or word) can be transformed independently. The original text
|
|
47
|
+
* is preserved as an aria-label for screen readers. Any previous
|
|
48
|
+
* content is replaced.
|
|
49
|
+
*/
|
|
50
|
+
export function splitUnits(el, unit) {
|
|
51
|
+
const doc = ownerDoc(el);
|
|
52
|
+
if (!doc)
|
|
53
|
+
return [];
|
|
54
|
+
const text = el.textContent ?? "";
|
|
55
|
+
el.textContent = "";
|
|
56
|
+
el.setAttribute("aria-label", text);
|
|
57
|
+
return appendTokens(doc, el, text, unit);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Append per-unit inline-block spans for `text` to the element's
|
|
61
|
+
* existing content, without clearing it. Used by streaming text, where
|
|
62
|
+
* each flushed batch adds new units while earlier units keep playing.
|
|
63
|
+
*/
|
|
64
|
+
export function appendUnits(el, text, unit) {
|
|
65
|
+
const doc = ownerDoc(el);
|
|
66
|
+
if (!doc)
|
|
67
|
+
return [];
|
|
68
|
+
return appendTokens(doc, el, text, unit);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Deterministic pseudo-random generator (mulberry32). Used for
|
|
72
|
+
* per-unit variance so seeded jitter renders identically on every
|
|
73
|
+
* run, which keeps tests stable and output reproducible.
|
|
74
|
+
*/
|
|
75
|
+
export function mulberry32(seed) {
|
|
76
|
+
let a = seed >>> 0;
|
|
77
|
+
return () => {
|
|
78
|
+
a |= 0;
|
|
79
|
+
a = (a + 0x6d2b79f5) | 0;
|
|
80
|
+
let t = Math.imul(a ^ (a >>> 15), 1 | a);
|
|
81
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
82
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
83
|
+
};
|
|
84
|
+
}
|
package/dist/web3.d.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* web3 family: motion primitives for onchain product UI.
|
|
3
|
+
*
|
|
4
|
+
* Transaction lifecycle, price tickers, mint reveals, and wallet
|
|
5
|
+
* button micro-interactions, without depending on any wallet or chain
|
|
6
|
+
* library. State arrives through accessors in a wagmi/viem-style
|
|
7
|
+
* shape (the adapter pattern), so the primitives stay zero-dependency
|
|
8
|
+
* while your app keeps its own stack.
|
|
9
|
+
*
|
|
10
|
+
* All primitives are signal-native, SSR-safe, dependency-free, and
|
|
11
|
+
* define sensible static behavior under `prefers-reduced-motion`.
|
|
12
|
+
*/
|
|
13
|
+
import { type Accessor } from "solid-js";
|
|
14
|
+
import { type Easing, type EasingName } from "./easing.js";
|
|
15
|
+
type MaybeElement = () => Element | null | undefined;
|
|
16
|
+
/** Stages of a transaction's life, from wallet prompt to finality. */
|
|
17
|
+
export type TxState = "idle" | "signing" | "pending" | "confirming" | "success" | "failed";
|
|
18
|
+
/** wagmi/viem-style transaction status fed through `source`. */
|
|
19
|
+
export interface TxStatusInput {
|
|
20
|
+
/** Transaction status from the wallet/chain adapter. */
|
|
21
|
+
status?: "pending" | "success" | "error" | "idle";
|
|
22
|
+
/** Confirmations seen so far, once a hash exists. */
|
|
23
|
+
confirmations?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface TxLifecycleOptions {
|
|
26
|
+
/**
|
|
27
|
+
* wagmi/viem-style state accessor. Omit for fully manual control
|
|
28
|
+
* through `set()`.
|
|
29
|
+
*/
|
|
30
|
+
source?: Accessor<TxStatusInput>;
|
|
31
|
+
/** Confirmations that promote "pending" to "confirming". Default 1. */
|
|
32
|
+
requiredConfirmations?: number;
|
|
33
|
+
/** Spring stiffness for the progress ring. Default 170. */
|
|
34
|
+
stiffness?: number;
|
|
35
|
+
/** Spring damping for the progress ring. Default 26. */
|
|
36
|
+
damping?: number;
|
|
37
|
+
/** Called after entering a state, with the previous state. */
|
|
38
|
+
onEnter?: (state: TxState, prev: TxState) => void;
|
|
39
|
+
}
|
|
40
|
+
export interface TxLifecycleControls {
|
|
41
|
+
/** Current lifecycle state. */
|
|
42
|
+
state: Accessor<TxState>;
|
|
43
|
+
/**
|
|
44
|
+
* Set the state manually, for stages the chain never reports
|
|
45
|
+
* (for example "signing" when the wallet prompt opens).
|
|
46
|
+
*/
|
|
47
|
+
set: (next: TxState) => void;
|
|
48
|
+
/** Return to "idle". */
|
|
49
|
+
reset: () => void;
|
|
50
|
+
/**
|
|
51
|
+
* 0 to 1 across the lifecycle, spring-smoothed for progress rings
|
|
52
|
+
* and bars: idle 0, signing 0.25, pending 0.5, confirming 0.75,
|
|
53
|
+
* success/failed 1.
|
|
54
|
+
*/
|
|
55
|
+
progress: Accessor<number>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Signal-native transaction lifecycle.
|
|
59
|
+
*
|
|
60
|
+
* Feed it wagmi/viem-style state through `source` and it derives the
|
|
61
|
+
* stage: a reported hash with too few confirmations is "pending",
|
|
62
|
+
* enough confirmations is "confirming", success/error map to
|
|
63
|
+
* "success"/"failed". Stages the chain never reports, like "signing"
|
|
64
|
+
* while the wallet prompt is open, are set manually.
|
|
65
|
+
*
|
|
66
|
+
* ```ts
|
|
67
|
+
* const tx = createTxLifecycle({
|
|
68
|
+
* source: () => ({
|
|
69
|
+
* status: receiptQuery.status, // "pending" | "success" | "error" | "idle"
|
|
70
|
+
* confirmations: receiptQuery.confirmations,
|
|
71
|
+
* }),
|
|
72
|
+
* requiredConfirmations: 2,
|
|
73
|
+
* })
|
|
74
|
+
* const openWallet = () => {
|
|
75
|
+
* tx.set("signing")
|
|
76
|
+
* sendTransaction()
|
|
77
|
+
* }
|
|
78
|
+
* // <ProgressRing value={tx.progress()} state={tx.state()} />
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* SSR-safe: "idle" with `progress()` 0. Under reduced motion state
|
|
82
|
+
* changes apply instantly and `progress()` jumps to its target.
|
|
83
|
+
*/
|
|
84
|
+
export declare function createTxLifecycle(options?: TxLifecycleOptions): TxLifecycleControls;
|
|
85
|
+
export interface TickerOptions {
|
|
86
|
+
/** Decimals in the formatted output. Default 2. */
|
|
87
|
+
decimals?: number;
|
|
88
|
+
/** Roll duration per digit, in ms. Default 400. */
|
|
89
|
+
duration?: number;
|
|
90
|
+
/** Flash color when the value rises. Default "#16a34a". */
|
|
91
|
+
upColor?: string;
|
|
92
|
+
/** Flash color when the value falls. Default "#dc2626". */
|
|
93
|
+
downColor?: string;
|
|
94
|
+
/** How long the flash color holds, in ms. Default 600. */
|
|
95
|
+
flashMs?: number;
|
|
96
|
+
/** Locale for grouping separators. Default "en-US". */
|
|
97
|
+
locale?: string;
|
|
98
|
+
}
|
|
99
|
+
export interface TickerControls {
|
|
100
|
+
/** Formatted value, SSR-safe. */
|
|
101
|
+
display: Accessor<string>;
|
|
102
|
+
/** Direction of the last update: "up" | "down" | "flat". */
|
|
103
|
+
direction: Accessor<"up" | "down" | "flat">;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Animated price/balance ticker: per-digit roll, direction flash.
|
|
107
|
+
*
|
|
108
|
+
* Each digit is a 0-9 strip in an overflow-hidden column, driven by a
|
|
109
|
+
* single rAF task for the whole ticker. Rapid source updates batch to
|
|
110
|
+
* one render per frame, keeping only the latest value, so a hot price
|
|
111
|
+
* feed never queues animation debt. Non-digit characters (decimal
|
|
112
|
+
* point, grouping separators, minus sign) render statically.
|
|
113
|
+
*
|
|
114
|
+
* ```tsx
|
|
115
|
+
* let el!: HTMLSpanElement
|
|
116
|
+
* const [price, setPrice] = createSignal(48210.5)
|
|
117
|
+
* const ticker = createTicker(price, () => el, { decimals: 2 })
|
|
118
|
+
* <span ref={el} style={{ color: ticker.direction() === "up" ? "green" : "red" }}>
|
|
119
|
+
* {ticker.display()}
|
|
120
|
+
* </span>
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* SSR-safe: `display()` returns the formatted string with no DOM.
|
|
124
|
+
* Under reduced motion the text swaps instantly: no roll, no flash.
|
|
125
|
+
*/
|
|
126
|
+
export declare function createTicker(source: Accessor<number>, ref: MaybeElement, options?: TickerOptions): TickerControls;
|
|
127
|
+
export type MintRevealStatus = "idle" | "anticipating" | "flipping" | "revealed";
|
|
128
|
+
export interface MintRevealOptions {
|
|
129
|
+
/** Anticipation shake duration, in ms. Default 500. */
|
|
130
|
+
shakeDuration?: number;
|
|
131
|
+
/** rotateY flip duration, in ms. Default 700. */
|
|
132
|
+
flipDuration?: number;
|
|
133
|
+
/** Squash and stretch on landing. Default true. */
|
|
134
|
+
squash?: boolean;
|
|
135
|
+
/** Easing for the flip. Default "easeOutCubic". */
|
|
136
|
+
easing?: Easing | EasingName;
|
|
137
|
+
/** Called at the flip midpoint: swap the card faces here. */
|
|
138
|
+
onFlip?: () => void;
|
|
139
|
+
}
|
|
140
|
+
export interface MintRevealControls {
|
|
141
|
+
/** Play the full reveal choreography. Resolves when revealed. */
|
|
142
|
+
play: () => Promise<void>;
|
|
143
|
+
/** Return to "idle". */
|
|
144
|
+
reset: () => void;
|
|
145
|
+
/** Reactive status. */
|
|
146
|
+
status: Accessor<MintRevealStatus>;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Pack-open / card-reveal choreography, built on the cartoon family:
|
|
150
|
+
* an anticipation shake, a rotateY flip with a face swap at the
|
|
151
|
+
* midpoint, and squash and stretch driven by the flip's own velocity
|
|
152
|
+
* as the card lands. Everything stays on compositor-friendly
|
|
153
|
+
* properties (transform, and the CSS `scale` property for the deform).
|
|
154
|
+
*
|
|
155
|
+
* ```tsx
|
|
156
|
+
* let card!: HTMLDivElement
|
|
157
|
+
* const [face, setFace] = createSignal<"back" | "front">("back")
|
|
158
|
+
* const reveal = createMintReveal(() => card, {
|
|
159
|
+
* onFlip: () => setFace("front"), // swap faces mid-flip
|
|
160
|
+
* })
|
|
161
|
+
* <button onClick={() => reveal.play()}>Reveal</button>
|
|
162
|
+
* <div ref={card} style={{ "backface-visibility": "hidden" }}>
|
|
163
|
+
* {face() === "back" ? <CardBack /> : <NftFront />}
|
|
164
|
+
* </div>
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* SSR-safe: no-op on the server, `status()` is "revealed" so the face
|
|
168
|
+
* renders statically. Under reduced motion the shake and flip are
|
|
169
|
+
* skipped and the final face shows at once.
|
|
170
|
+
*/
|
|
171
|
+
export declare function createMintReveal(ref: MaybeElement, options?: MintRevealOptions): MintRevealControls;
|
|
172
|
+
export interface ConnectButtonOptions {
|
|
173
|
+
/** Magnetic pull strength, 0 to 1. Default 0.35. */
|
|
174
|
+
strength?: number;
|
|
175
|
+
/** Scale while pressed. Default 0.96. */
|
|
176
|
+
pressScale?: number;
|
|
177
|
+
}
|
|
178
|
+
export type ConnectButtonStatus = "idle" | "ticking" | "pulsing";
|
|
179
|
+
export interface ConnectButtonControls {
|
|
180
|
+
/** Checkmark tick for copy-address feedback. */
|
|
181
|
+
copyTick: () => void;
|
|
182
|
+
/** Expanding ring pulse for chain switches. */
|
|
183
|
+
chainPulse: () => void;
|
|
184
|
+
/** Reactive status: "idle" | "ticking" | "pulsing". */
|
|
185
|
+
status: Accessor<ConnectButtonStatus>;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Wallet connect-button micro-interactions: magnetic hover pull,
|
|
189
|
+
* press scale, a checkmark tick for copy-address feedback, and an
|
|
190
|
+
* expanding ring pulse for chain switches.
|
|
191
|
+
*
|
|
192
|
+
* The button's transform is owned by the primitive (magnetic pull
|
|
193
|
+
* plus press scale); the tick and pulse animate overlay spans so
|
|
194
|
+
* they never fight the hover motion. The button is given
|
|
195
|
+
* `position: relative` the first time a tick or pulse runs, to stage
|
|
196
|
+
* the overlays.
|
|
197
|
+
*
|
|
198
|
+
* ```tsx
|
|
199
|
+
* let btn!: HTMLButtonElement
|
|
200
|
+
* const connect = createConnectButton(() => btn)
|
|
201
|
+
* const copy = async () => {
|
|
202
|
+
* await navigator.clipboard.writeText(address())
|
|
203
|
+
* connect.copyTick()
|
|
204
|
+
* }
|
|
205
|
+
* <button ref={btn} onClick={copy}>0x7a…f3c2</button>
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* SSR-safe: no-op on the server. Under reduced motion the magnetic
|
|
209
|
+
* pull is off and the tick/pulse become instant state changes (the
|
|
210
|
+
* check shows statically, then hides).
|
|
211
|
+
*/
|
|
212
|
+
export declare function createConnectButton(ref: MaybeElement, options?: ConnectButtonOptions): ConnectButtonControls;
|
|
213
|
+
export {};
|