@timbal-ai/timbal-react 1.4.0 → 1.6.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/CHANGELOG.md +30 -0
- package/README.md +43 -4
- package/dist/app.cjs +3770 -1506
- package/dist/app.d.cts +76 -31
- package/dist/app.d.ts +76 -31
- package/dist/app.esm.js +30 -8
- package/dist/{chart-artifact-C8-Py6lc.d.cts → chart-artifact-C2pZQsaP.d.ts} +247 -41
- package/dist/{chart-artifact-CMnDys2t.d.ts → chart-artifact-VAqgH-My.d.cts} +247 -41
- package/dist/{chat-ClmzWzCX.d.cts → chat-DDsp-Vzz.d.cts} +1 -1
- package/dist/{chat-ClmzWzCX.d.ts → chat-DDsp-Vzz.d.ts} +1 -1
- package/dist/chat.cjs +280 -123
- package/dist/chat.d.cts +3 -3
- package/dist/chat.d.ts +3 -3
- package/dist/chat.esm.js +4 -3
- package/dist/chunk-24B4I4XC.esm.js +232 -0
- package/dist/{chunk-VOWNCS3F.esm.js → chunk-6SQMTBPL.esm.js} +1669 -504
- package/dist/chunk-EDEKQYSU.esm.js +10 -0
- package/dist/{chunk-QIABF4KB.esm.js → chunk-ELEY66OH.esm.js} +2 -2
- package/dist/{chunk-THBA27QY.esm.js → chunk-HSL36SJ4.esm.js} +243 -124
- package/dist/chunk-JJOO4PR5.esm.js +391 -0
- package/dist/{chunk-QU7ET55D.esm.js → chunk-MBS7XHV2.esm.js} +335 -192
- package/dist/chunk-NO5AWNWT.esm.js +1066 -0
- package/dist/{chunk-VXMM2HX7.esm.js → chunk-R4RQT2XQ.esm.js} +3 -3
- package/dist/{chunk-OFWC4MIY.esm.js → chunk-TMP7RIA7.esm.js} +5 -3
- package/dist/{chunk-GQBYZRD7.esm.js → chunk-WQIQW7EM.esm.js} +40 -28
- package/dist/{chunk-OH23AX2V.esm.js → chunk-YYEI6XME.esm.js} +441 -957
- package/dist/{circular-progress-Ci8L-Hfa.d.cts → circular-progress-B9nnwzCu.d.cts} +20 -78
- package/dist/{circular-progress-Ci8L-Hfa.d.ts → circular-progress-B9nnwzCu.d.ts} +20 -78
- package/dist/index.cjs +5547 -3192
- package/dist/index.d.cts +10 -8
- package/dist/index.d.ts +10 -8
- package/dist/index.esm.js +76 -44
- package/dist/kanban-FFBeaZPS.d.cts +212 -0
- package/dist/kanban-FFBeaZPS.d.ts +212 -0
- package/dist/{layout-BTJyU8wd.d.ts → layout-CuKeSY74.d.ts} +1 -1
- package/dist/{layout-C2G-FcER.d.cts → layout-PzVwkJyL.d.cts} +1 -1
- package/dist/site.cjs +429 -0
- package/dist/site.d.cts +198 -0
- package/dist/site.d.ts +198 -0
- package/dist/site.esm.js +23 -0
- package/dist/studio.cjs +722 -363
- package/dist/studio.d.cts +2 -2
- package/dist/studio.d.ts +2 -2
- package/dist/studio.esm.js +8 -6
- package/dist/styles.css +56 -0
- package/dist/{timbal-v2-button-CNfdwGq4.d.cts → timbal-v2-button-DCAZNyUx.d.cts} +3 -3
- package/dist/{timbal-v2-button-CNfdwGq4.d.ts → timbal-v2-button-DCAZNyUx.d.ts} +3 -3
- package/dist/ui.cjs +1553 -708
- package/dist/ui.d.cts +11 -4
- package/dist/ui.d.ts +11 -4
- package/dist/ui.esm.js +45 -36
- package/dist/{welcome-DXqsGTwH.d.ts → welcome-B00oH5Io.d.cts} +5 -1
- package/dist/{welcome-BFGRoNfK.d.cts → welcome-DU-4NTjZ.d.ts} +5 -1
- package/package.json +9 -1
- package/dist/button-BoyX5pM_.d.cts +0 -18
- package/dist/button-BoyX5pM_.d.ts +0 -18
- package/dist/chunk-UCGVL7ZY.esm.js +0 -52
package/dist/site.cjs
ADDED
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/site.ts
|
|
31
|
+
var site_exports = {};
|
|
32
|
+
__export(site_exports, {
|
|
33
|
+
DURATION: () => DURATION,
|
|
34
|
+
EASE: () => EASE,
|
|
35
|
+
Magnetic: () => Magnetic,
|
|
36
|
+
Marquee: () => Marquee,
|
|
37
|
+
Parallax: () => Parallax,
|
|
38
|
+
Reveal: () => Reveal,
|
|
39
|
+
SITE_AGENT_INSTRUCTIONS: () => SITE_AGENT_INSTRUCTIONS,
|
|
40
|
+
SPRING: () => SPRING,
|
|
41
|
+
TextReveal: () => TextReveal
|
|
42
|
+
});
|
|
43
|
+
module.exports = __toCommonJS(site_exports);
|
|
44
|
+
|
|
45
|
+
// src/site/agent-instructions.ts
|
|
46
|
+
var SITE_AGENT_INSTRUCTIONS = `
|
|
47
|
+
## Site kit (@timbal-ai/timbal-react/site)
|
|
48
|
+
|
|
49
|
+
Expressive **motion & interaction primitives** for marketing, brand, landing, and editorial pages \u2014 the counterpart to \`/app\` (which is for dashboards and operations UIs). Import from \`@timbal-ai/timbal-react/site\` (or the package root).
|
|
50
|
+
|
|
51
|
+
These are **mechanics, not art direction**: they animate whatever you put inside them. Compose them under a chosen aesthetic; they do not impose colors, type, or layout.
|
|
52
|
+
|
|
53
|
+
### When to use \`/site\` (and when not to)
|
|
54
|
+
|
|
55
|
+
- **Do** use \`/site\` for landing pages, hero sections, feature walkthroughs, logo walls, pricing pages, and editorial/brand storytelling.
|
|
56
|
+
- **Do not** use \`/site\` inside dashboards, settings, tables, or in-thread chat artifacts \u2014 those stay on \`/app\` and \`/artifacts\`. Animated dashboard chrome reads as slop.
|
|
57
|
+
- Every primitive is **reduced-motion-aware** (collapses to static, no-transform output under \`prefers-reduced-motion\`) and **SSR-safe** (no layout shift \u2014 elements occupy their space from first paint). You never need to guard them yourself.
|
|
58
|
+
- Built on the \`motion\` engine the package already bundles \u2014 **no extra dependencies**.
|
|
59
|
+
|
|
60
|
+
### Dosing (anti-overuse \u2014 read this)
|
|
61
|
+
|
|
62
|
+
The failure mode is animating *everything*. Restraint is the brand signal.
|
|
63
|
+
|
|
64
|
+
- Pick **one** signature motion per section (e.g. a \`TextReveal\` headline **or** a \`Parallax\` hero image, not both stacked).
|
|
65
|
+
- Stagger entrances down the page; do not fire ten reveals at once on first paint.
|
|
66
|
+
- Reserve \`Magnetic\` for **primary** CTAs / nav, not every button.
|
|
67
|
+
- Keep \`Parallax\` \`speed\` subtle (\`0.15\`\u2013\`0.35\`); large values look gimmicky.
|
|
68
|
+
- Default durations are intentionally slow and weighted (\`DURATION.base\` = 0.7s) \u2014 that confident pacing is the point. Don't speed everything up to app-kit's 150ms.
|
|
69
|
+
|
|
70
|
+
### Component menu
|
|
71
|
+
|
|
72
|
+
| Component | Use for | Key props |
|
|
73
|
+
|-----------|---------|-----------|
|
|
74
|
+
| \`Reveal\` | Fade/slide a block in as it scrolls into view (headings, cards, images, list items). | \`variant\` (\`fade\` \\| \`fade-up\` \\| \`fade-down\` \\| \`fade-left\` \\| \`fade-right\` \\| \`blur\` \\| \`scale\` \\| \`mask-up\`, default \`fade-up\`), \`delay\`, \`duration\`, \`distance\` (px, default 28), \`amount\` (visibility fraction 0\u20131 / \`"some"\` / \`"all"\`, default 0.3), \`repeat\` (replay on re-enter), \`as\` (render element, e.g. \`"section"\`/\`"li"\`). |
|
|
75
|
+
| \`TextReveal\` | Signature editorial headline entrance \u2014 text rides up token-by-token from a clip on a stagger. | \`children\` (**plain string only**), \`splitBy\` (\`words\` default \\| \`lines\`), \`stagger\` (default 0.06), \`delay\`, \`duration\`, \`amount\` (default 0.4), \`repeat\`, \`as\` (\`span\` default \\| \`h1\`\u2013\`h4\` \\| \`p\`). |
|
|
76
|
+
| \`Parallax\` | Depth \u2014 translate a layer relative to scroll (hero images, background art). | \`speed\` (-0.6\u20260.6, positive = lags behind scroll, default 0.2), \`axis\` (\`y\` default \\| \`x\`), \`smooth\` (spring-damped, default true). |
|
|
77
|
+
| \`Marquee\` | Seamless infinite scrolling row (logo walls, testimonials, ticker). Duplicates children internally \u2014 no visible seam. | \`speed\` (px/s, default 60), \`direction\` (\`left\` default \\| \`right\`), \`pauseOnHover\` (default true), \`gap\` (CSS length, default \`"3rem"\`). |
|
|
78
|
+
| \`Magnetic\` | Pointer-following "magnetic" affordance for a **single** interactive child (primary CTA, nav link). | \`strength\` (fraction of cursor offset, default 0.35), \`max\` (px clamp, default 24), \`spring\` (\`"snappy"\` default \\| \`"smooth"\`). Wrap one button/link. |
|
|
79
|
+
|
|
80
|
+
### Motion tokens
|
|
81
|
+
|
|
82
|
+
\`EASE\` (cubic-bezier tuples: \`out\` / \`inOut\` / \`soft\`), \`DURATION\` (\`fast\` 0.4s / \`base\` 0.7s / \`slow\` 1.1s), and \`SPRING\` (\`snappy\` / \`smooth\`) are exported for custom \`motion\` work that should match the kit's feel. Prefer the component defaults; reach for tokens only when hand-rolling a bespoke animation.
|
|
83
|
+
|
|
84
|
+
### Example imports
|
|
85
|
+
|
|
86
|
+
\`\`\`tsx
|
|
87
|
+
import { Reveal, TextReveal, Parallax, Marquee, Magnetic } from "@timbal-ai/timbal-react/site";
|
|
88
|
+
\`\`\`
|
|
89
|
+
|
|
90
|
+
\`\`\`tsx
|
|
91
|
+
<Reveal variant="fade-up" delay={0.1}>
|
|
92
|
+
<TextReveal as="h1" className="text-6xl font-semibold">
|
|
93
|
+
Built for the long run
|
|
94
|
+
</TextReveal>
|
|
95
|
+
</Reveal>
|
|
96
|
+
|
|
97
|
+
<Parallax speed={0.3}>
|
|
98
|
+
<img src={hero} alt="" className="h-full w-full object-cover" />
|
|
99
|
+
</Parallax>
|
|
100
|
+
|
|
101
|
+
<Magnetic strength={0.4}>
|
|
102
|
+
<Button>Get started</Button>
|
|
103
|
+
</Magnetic>
|
|
104
|
+
\`\`\`
|
|
105
|
+
|
|
106
|
+
### Rules
|
|
107
|
+
|
|
108
|
+
- \`/site\` is for the **marketing/brand surface**, not the product app shell (\`/app\`) or in-chat widgets (\`/artifacts\`).
|
|
109
|
+
- \`TextReveal\` takes a **string** child only \u2014 it splits internally; do not pass JSX.
|
|
110
|
+
- \`Magnetic\` wraps a **single** interactive child; don't wrap whole layouts.
|
|
111
|
+
- Trust the reduced-motion / SSR handling \u2014 never add your own \`prefers-reduced-motion\` guards around these.
|
|
112
|
+
`.trim();
|
|
113
|
+
|
|
114
|
+
// src/site/Reveal.tsx
|
|
115
|
+
var React = __toESM(require("react"), 1);
|
|
116
|
+
var import_react = require("motion/react");
|
|
117
|
+
|
|
118
|
+
// src/utils.ts
|
|
119
|
+
var import_clsx = require("clsx");
|
|
120
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
121
|
+
function cn(...inputs) {
|
|
122
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/site/easing.ts
|
|
126
|
+
var EASE = {
|
|
127
|
+
/** Strong slow-out — the workhorse for entrances and reveals. */
|
|
128
|
+
out: [0.16, 1, 0.3, 1],
|
|
129
|
+
/** Symmetric in-out for loops and continuous motion. */
|
|
130
|
+
inOut: [0.65, 0, 0.35, 1],
|
|
131
|
+
/** Gentle in-out, good for parallax / large translations. */
|
|
132
|
+
soft: [0.4, 0, 0.2, 1]
|
|
133
|
+
};
|
|
134
|
+
var DURATION = {
|
|
135
|
+
fast: 0.4,
|
|
136
|
+
base: 0.7,
|
|
137
|
+
slow: 1.1
|
|
138
|
+
};
|
|
139
|
+
var SPRING = {
|
|
140
|
+
/** Tight, responsive follow. */
|
|
141
|
+
snappy: { stiffness: 350, damping: 30, mass: 0.4 },
|
|
142
|
+
/** Looser, more elastic follow. */
|
|
143
|
+
smooth: { stiffness: 150, damping: 20, mass: 0.6 }
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// src/site/Reveal.tsx
|
|
147
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
148
|
+
function hidden(variant, distance) {
|
|
149
|
+
switch (variant) {
|
|
150
|
+
case "fade":
|
|
151
|
+
return { opacity: 0 };
|
|
152
|
+
case "fade-up":
|
|
153
|
+
return { opacity: 0, y: distance };
|
|
154
|
+
case "fade-down":
|
|
155
|
+
return { opacity: 0, y: -distance };
|
|
156
|
+
case "fade-left":
|
|
157
|
+
return { opacity: 0, x: distance };
|
|
158
|
+
case "fade-right":
|
|
159
|
+
return { opacity: 0, x: -distance };
|
|
160
|
+
case "blur":
|
|
161
|
+
return { opacity: 0, filter: "blur(12px)" };
|
|
162
|
+
case "scale":
|
|
163
|
+
return { opacity: 0, scale: 0.94 };
|
|
164
|
+
case "mask-up":
|
|
165
|
+
return { y: "110%" };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function shown(variant) {
|
|
169
|
+
if (variant === "mask-up") return { y: "0%" };
|
|
170
|
+
if (variant === "blur") return { opacity: 1, filter: "blur(0px)" };
|
|
171
|
+
if (variant === "scale") return { opacity: 1, scale: 1 };
|
|
172
|
+
return { opacity: 1, x: 0, y: 0 };
|
|
173
|
+
}
|
|
174
|
+
var Reveal = React.forwardRef(function Reveal2({
|
|
175
|
+
variant = "fade-up",
|
|
176
|
+
delay = 0,
|
|
177
|
+
duration = DURATION.base,
|
|
178
|
+
distance = 28,
|
|
179
|
+
amount = 0.3,
|
|
180
|
+
repeat = false,
|
|
181
|
+
as = "div",
|
|
182
|
+
className,
|
|
183
|
+
children,
|
|
184
|
+
...rest
|
|
185
|
+
}, ref) {
|
|
186
|
+
const reduce = (0, import_react.useReducedMotion)();
|
|
187
|
+
const isMask = variant === "mask-up";
|
|
188
|
+
if (reduce) {
|
|
189
|
+
const Tag = as;
|
|
190
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tag, { ref, className: cn(isMask && "overflow-hidden", className), ...rest, children });
|
|
191
|
+
}
|
|
192
|
+
const variants = {
|
|
193
|
+
hidden: hidden(variant, distance),
|
|
194
|
+
shown: shown(variant)
|
|
195
|
+
};
|
|
196
|
+
const MotionTag = import_react.motion[as] ?? import_react.motion.div;
|
|
197
|
+
const inner = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
198
|
+
MotionTag,
|
|
199
|
+
{
|
|
200
|
+
ref,
|
|
201
|
+
className,
|
|
202
|
+
variants,
|
|
203
|
+
initial: "hidden",
|
|
204
|
+
whileInView: "shown",
|
|
205
|
+
viewport: { once: !repeat, amount },
|
|
206
|
+
transition: { duration, delay, ease: EASE.out },
|
|
207
|
+
...rest,
|
|
208
|
+
children
|
|
209
|
+
}
|
|
210
|
+
);
|
|
211
|
+
if (isMask) {
|
|
212
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "block overflow-hidden", children: inner });
|
|
213
|
+
}
|
|
214
|
+
return inner;
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// src/site/TextReveal.tsx
|
|
218
|
+
var React2 = __toESM(require("react"), 1);
|
|
219
|
+
var import_react2 = require("motion/react");
|
|
220
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
221
|
+
var tokenVariants = {
|
|
222
|
+
hidden: { y: "115%" },
|
|
223
|
+
shown: { y: "0%" }
|
|
224
|
+
};
|
|
225
|
+
function TextReveal({
|
|
226
|
+
children,
|
|
227
|
+
splitBy = "words",
|
|
228
|
+
stagger = 0.06,
|
|
229
|
+
delay = 0,
|
|
230
|
+
duration = DURATION.base,
|
|
231
|
+
repeat = false,
|
|
232
|
+
amount = 0.4,
|
|
233
|
+
as = "span",
|
|
234
|
+
className,
|
|
235
|
+
...rest
|
|
236
|
+
}) {
|
|
237
|
+
const reduce = (0, import_react2.useReducedMotion)();
|
|
238
|
+
const Tag = as;
|
|
239
|
+
const tokens = React2.useMemo(() => {
|
|
240
|
+
if (splitBy === "lines") return children.split("\n");
|
|
241
|
+
return children.split(/(\s+)/).filter((t) => t.length > 0);
|
|
242
|
+
}, [children, splitBy]);
|
|
243
|
+
if (reduce) {
|
|
244
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Tag, { className, ...rest, children });
|
|
245
|
+
}
|
|
246
|
+
const containerVariants = {
|
|
247
|
+
hidden: {},
|
|
248
|
+
shown: { transition: { staggerChildren: stagger, delayChildren: delay } }
|
|
249
|
+
};
|
|
250
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
251
|
+
import_react2.motion.span,
|
|
252
|
+
{
|
|
253
|
+
variants: containerVariants,
|
|
254
|
+
initial: "hidden",
|
|
255
|
+
whileInView: "shown",
|
|
256
|
+
viewport: { once: !repeat, amount },
|
|
257
|
+
className: cn(as === "span" ? "inline" : "block", className),
|
|
258
|
+
...rest,
|
|
259
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Tag, { className: as === "span" ? "inline" : "block", children: tokens.map(
|
|
260
|
+
(token, i) => /^\s+$/.test(token) && splitBy === "words" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: " " }, i) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
261
|
+
"span",
|
|
262
|
+
{
|
|
263
|
+
className: cn(
|
|
264
|
+
"overflow-hidden",
|
|
265
|
+
splitBy === "lines" ? "block" : "inline-block align-bottom"
|
|
266
|
+
),
|
|
267
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
268
|
+
import_react2.motion.span,
|
|
269
|
+
{
|
|
270
|
+
className: "inline-block",
|
|
271
|
+
variants: tokenVariants,
|
|
272
|
+
transition: { duration, ease: EASE.out },
|
|
273
|
+
children: token
|
|
274
|
+
}
|
|
275
|
+
)
|
|
276
|
+
},
|
|
277
|
+
i
|
|
278
|
+
)
|
|
279
|
+
) })
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// src/site/Parallax.tsx
|
|
285
|
+
var React3 = __toESM(require("react"), 1);
|
|
286
|
+
var import_react3 = require("motion/react");
|
|
287
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
288
|
+
var Parallax = React3.forwardRef(function Parallax2({ speed = 0.2, axis = "y", smooth = true, className, children, style, ...rest }, forwardedRef) {
|
|
289
|
+
const reduce = (0, import_react3.useReducedMotion)();
|
|
290
|
+
const innerRef = React3.useRef(null);
|
|
291
|
+
React3.useImperativeHandle(forwardedRef, () => innerRef.current);
|
|
292
|
+
const { scrollYProgress } = (0, import_react3.useScroll)({
|
|
293
|
+
target: innerRef,
|
|
294
|
+
offset: ["start end", "end start"]
|
|
295
|
+
});
|
|
296
|
+
const range = 100 * speed;
|
|
297
|
+
const raw = (0, import_react3.useTransform)(scrollYProgress, [0, 1], [range, -range]);
|
|
298
|
+
const smoothed = (0, import_react3.useSpring)(raw, { stiffness: 120, damping: 30, mass: 0.4 });
|
|
299
|
+
const value = smooth ? smoothed : raw;
|
|
300
|
+
if (reduce) {
|
|
301
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: innerRef, className, style, ...rest, children });
|
|
302
|
+
}
|
|
303
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
304
|
+
import_react3.motion.div,
|
|
305
|
+
{
|
|
306
|
+
ref: innerRef,
|
|
307
|
+
className: cn("will-change-transform", className),
|
|
308
|
+
style: { ...style, [axis]: value },
|
|
309
|
+
...rest,
|
|
310
|
+
children
|
|
311
|
+
}
|
|
312
|
+
);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// src/site/Marquee.tsx
|
|
316
|
+
var React4 = __toESM(require("react"), 1);
|
|
317
|
+
var import_react4 = require("motion/react");
|
|
318
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
319
|
+
var Marquee = React4.forwardRef(function Marquee2({ speed = 60, direction = "left", pauseOnHover = true, gap = "3rem", className, children, ...rest }, ref) {
|
|
320
|
+
const reduce = (0, import_react4.useReducedMotion)();
|
|
321
|
+
const x = (0, import_react4.useMotionValue)(0);
|
|
322
|
+
const setWidthRef = React4.useRef(0);
|
|
323
|
+
const groupRef = React4.useRef(null);
|
|
324
|
+
const [paused, setPaused] = React4.useState(false);
|
|
325
|
+
React4.useEffect(() => {
|
|
326
|
+
const el = groupRef.current;
|
|
327
|
+
if (!el) return;
|
|
328
|
+
const measure = () => {
|
|
329
|
+
const gapPx = parseFloat(getComputedStyle(el.parentElement).columnGap || "0") || 0;
|
|
330
|
+
setWidthRef.current = el.offsetWidth + gapPx;
|
|
331
|
+
};
|
|
332
|
+
measure();
|
|
333
|
+
const ro = new ResizeObserver(measure);
|
|
334
|
+
ro.observe(el);
|
|
335
|
+
return () => ro.disconnect();
|
|
336
|
+
}, []);
|
|
337
|
+
(0, import_react4.useAnimationFrame)((_, delta) => {
|
|
338
|
+
if (reduce || paused || setWidthRef.current === 0) return;
|
|
339
|
+
const dir = direction === "left" ? -1 : 1;
|
|
340
|
+
const moveBy = speed * delta / 1e3;
|
|
341
|
+
let next = x.get() + dir * moveBy;
|
|
342
|
+
const w = setWidthRef.current;
|
|
343
|
+
if (next <= -w) next += w;
|
|
344
|
+
else if (next >= w) next -= w;
|
|
345
|
+
x.set(next);
|
|
346
|
+
});
|
|
347
|
+
if (reduce) {
|
|
348
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
349
|
+
"div",
|
|
350
|
+
{
|
|
351
|
+
ref,
|
|
352
|
+
className: cn("flex w-full items-center overflow-x-auto", className),
|
|
353
|
+
style: { columnGap: gap },
|
|
354
|
+
...rest,
|
|
355
|
+
children
|
|
356
|
+
}
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
360
|
+
"div",
|
|
361
|
+
{
|
|
362
|
+
ref,
|
|
363
|
+
className: cn("w-full overflow-hidden", className),
|
|
364
|
+
onMouseEnter: pauseOnHover ? () => setPaused(true) : void 0,
|
|
365
|
+
onMouseLeave: pauseOnHover ? () => setPaused(false) : void 0,
|
|
366
|
+
...rest,
|
|
367
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react4.motion.div, { className: "flex w-max flex-nowrap items-center", style: { x, columnGap: gap }, children: [
|
|
368
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref: groupRef, className: "flex flex-nowrap items-center", style: { columnGap: gap }, children }),
|
|
369
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex flex-nowrap items-center", style: { columnGap: gap }, "aria-hidden": true, children })
|
|
370
|
+
] })
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// src/site/Magnetic.tsx
|
|
376
|
+
var React5 = __toESM(require("react"), 1);
|
|
377
|
+
var import_react5 = require("motion/react");
|
|
378
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
379
|
+
var Magnetic = React5.forwardRef(function Magnetic2({ strength = 0.35, max = 24, spring = "snappy", className, children, ...rest }, forwardedRef) {
|
|
380
|
+
const reduce = (0, import_react5.useReducedMotion)();
|
|
381
|
+
const innerRef = React5.useRef(null);
|
|
382
|
+
React5.useImperativeHandle(forwardedRef, () => innerRef.current);
|
|
383
|
+
const mvx = (0, import_react5.useMotionValue)(0);
|
|
384
|
+
const mvy = (0, import_react5.useMotionValue)(0);
|
|
385
|
+
const x = (0, import_react5.useSpring)(mvx, SPRING[spring]);
|
|
386
|
+
const y = (0, import_react5.useSpring)(mvy, SPRING[spring]);
|
|
387
|
+
const clamp = (v) => Math.max(-max, Math.min(max, v));
|
|
388
|
+
function handleMove(e) {
|
|
389
|
+
if (reduce) return;
|
|
390
|
+
const el = innerRef.current;
|
|
391
|
+
if (!el) return;
|
|
392
|
+
const rect = el.getBoundingClientRect();
|
|
393
|
+
const cx = rect.left + rect.width / 2;
|
|
394
|
+
const cy = rect.top + rect.height / 2;
|
|
395
|
+
mvx.set(clamp((e.clientX - cx) * strength));
|
|
396
|
+
mvy.set(clamp((e.clientY - cy) * strength));
|
|
397
|
+
}
|
|
398
|
+
function reset() {
|
|
399
|
+
mvx.set(0);
|
|
400
|
+
mvy.set(0);
|
|
401
|
+
}
|
|
402
|
+
if (reduce) {
|
|
403
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: innerRef, className: cn("inline-block", className), ...rest, children });
|
|
404
|
+
}
|
|
405
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
406
|
+
import_react5.motion.div,
|
|
407
|
+
{
|
|
408
|
+
ref: innerRef,
|
|
409
|
+
className: cn("inline-block", className),
|
|
410
|
+
style: { x, y },
|
|
411
|
+
onMouseMove: handleMove,
|
|
412
|
+
onMouseLeave: reset,
|
|
413
|
+
...rest,
|
|
414
|
+
children
|
|
415
|
+
}
|
|
416
|
+
);
|
|
417
|
+
});
|
|
418
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
419
|
+
0 && (module.exports = {
|
|
420
|
+
DURATION,
|
|
421
|
+
EASE,
|
|
422
|
+
Magnetic,
|
|
423
|
+
Marquee,
|
|
424
|
+
Parallax,
|
|
425
|
+
Reveal,
|
|
426
|
+
SITE_AGENT_INSTRUCTIONS,
|
|
427
|
+
SPRING,
|
|
428
|
+
TextReveal
|
|
429
|
+
});
|
package/dist/site.d.cts
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
/** Entrance styles. `mask-up` clips the child and slides it in from below. */
|
|
5
|
+
type RevealVariant = "fade" | "fade-up" | "fade-down" | "fade-left" | "fade-right" | "blur" | "scale" | "mask-up";
|
|
6
|
+
interface RevealProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
7
|
+
/** Entrance style. Default `fade-up`. */
|
|
8
|
+
variant?: RevealVariant;
|
|
9
|
+
/** Seconds before the animation starts. */
|
|
10
|
+
delay?: number;
|
|
11
|
+
/** Animation duration in seconds. Default {@link DURATION.base}. */
|
|
12
|
+
duration?: number;
|
|
13
|
+
/** Slide distance in px for the directional + mask variants. Default 28. */
|
|
14
|
+
distance?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Fraction of the element that must be visible before it animates (0–1), or
|
|
17
|
+
* `"some"` / `"all"`. Default 0.3.
|
|
18
|
+
*/
|
|
19
|
+
amount?: number | "some" | "all";
|
|
20
|
+
/** Replay every time the element re-enters the viewport. Default `false`. */
|
|
21
|
+
repeat?: boolean;
|
|
22
|
+
/** Render as a different intrinsic element (e.g. `"section"`, `"li"`). */
|
|
23
|
+
as?: keyof React.JSX.IntrinsicElements;
|
|
24
|
+
children?: React.ReactNode;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Reveal a block when it scrolls into view. Honours `prefers-reduced-motion`
|
|
28
|
+
* (renders immediately, no transform) and SSR (no layout shift — the element
|
|
29
|
+
* occupies its space from first paint).
|
|
30
|
+
*
|
|
31
|
+
* ```tsx
|
|
32
|
+
* <Reveal variant="fade-up" delay={0.1}>
|
|
33
|
+
* <h2>Built for the long run</h2>
|
|
34
|
+
* </Reveal>
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
declare const Reveal: React.ForwardRefExoticComponent<RevealProps & React.RefAttributes<HTMLDivElement>>;
|
|
38
|
+
|
|
39
|
+
interface TextRevealProps extends Omit<React.ComponentPropsWithoutRef<"span">, "children"> {
|
|
40
|
+
/** The text to reveal. Plain string only (split into tokens internally). */
|
|
41
|
+
children: string;
|
|
42
|
+
/** Split granularity. `words` (default) animates word-by-word; `lines` splits on `\n`. */
|
|
43
|
+
splitBy?: "words" | "lines";
|
|
44
|
+
/** Seconds between each token's entrance. Default 0.06. */
|
|
45
|
+
stagger?: number;
|
|
46
|
+
/** Seconds before the first token animates. Default 0. */
|
|
47
|
+
delay?: number;
|
|
48
|
+
/** Per-token duration in seconds. Default {@link DURATION.base}. */
|
|
49
|
+
duration?: number;
|
|
50
|
+
/** Replay every time it re-enters the viewport. Default `false`. */
|
|
51
|
+
repeat?: boolean;
|
|
52
|
+
/** Visibility fraction before animating (0–1). Default 0.4. */
|
|
53
|
+
amount?: number;
|
|
54
|
+
/** Render the wrapper as a block-level heading element instead of an inline span. */
|
|
55
|
+
as?: "span" | "h1" | "h2" | "h3" | "h4" | "p";
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Reveal text token-by-token with a masked slide-up — the signature
|
|
59
|
+
* editorial/luxury headline entrance. Each word (or line) rides up out of an
|
|
60
|
+
* `overflow-hidden` clip on a stagger. Collapses to static text under
|
|
61
|
+
* `prefers-reduced-motion`.
|
|
62
|
+
*
|
|
63
|
+
* ```tsx
|
|
64
|
+
* <TextReveal as="h1" className="text-6xl font-semibold" stagger={0.08}>
|
|
65
|
+
* Every step forward
|
|
66
|
+
* </TextReveal>
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare function TextReveal({ children, splitBy, stagger, delay, duration, repeat, amount, as, className, ...rest }: TextRevealProps): react_jsx_runtime.JSX.Element;
|
|
70
|
+
|
|
71
|
+
interface ParallaxProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
72
|
+
/**
|
|
73
|
+
* Parallax strength. Positive values drift the element *slower* than scroll
|
|
74
|
+
* (it lags behind); negative values push it ahead. Roughly the fraction of
|
|
75
|
+
* the element's travel to offset. Sensible range -0.6…0.6. Default 0.2.
|
|
76
|
+
*/
|
|
77
|
+
speed?: number;
|
|
78
|
+
/** Axis to translate along. Default `"y"`. */
|
|
79
|
+
axis?: "x" | "y";
|
|
80
|
+
/** Smooth the motion with a spring (avoids jitter on fast scroll). Default `true`. */
|
|
81
|
+
smooth?: boolean;
|
|
82
|
+
children?: React.ReactNode;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Translate a layer relative to scroll for depth. Drives off the element's own
|
|
86
|
+
* position in the viewport (no global scroll listener), so multiple parallax
|
|
87
|
+
* layers compose cheaply. No-op under `prefers-reduced-motion`.
|
|
88
|
+
*
|
|
89
|
+
* ```tsx
|
|
90
|
+
* <Parallax speed={0.3}>
|
|
91
|
+
* <img src={hero} alt="" className="h-full w-full object-cover" />
|
|
92
|
+
* </Parallax>
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
declare const Parallax: React.ForwardRefExoticComponent<ParallaxProps & React.RefAttributes<HTMLDivElement>>;
|
|
96
|
+
|
|
97
|
+
interface MarqueeProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
98
|
+
/** Scroll speed in px/second. Default 60. */
|
|
99
|
+
speed?: number;
|
|
100
|
+
/** Travel direction. Default `"left"`. */
|
|
101
|
+
direction?: "left" | "right";
|
|
102
|
+
/** Pause while hovered. Default `true`. */
|
|
103
|
+
pauseOnHover?: boolean;
|
|
104
|
+
/** Gap between the repeated content groups (any CSS length). Default `"3rem"`. */
|
|
105
|
+
gap?: string;
|
|
106
|
+
children?: React.ReactNode;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Seamless infinite marquee. Duplicates its children and advances a single
|
|
110
|
+
* motion value per frame, wrapping at the content width so there is no visible
|
|
111
|
+
* seam. Frame-rate independent (uses elapsed delta). Renders a static,
|
|
112
|
+
* horizontally-scrollable row under `prefers-reduced-motion`.
|
|
113
|
+
*
|
|
114
|
+
* ```tsx
|
|
115
|
+
* <Marquee speed={40} className="py-6">
|
|
116
|
+
* {logos.map((l) => <img key={l.id} src={l.src} alt={l.name} className="h-8" />)}
|
|
117
|
+
* </Marquee>
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
declare const Marquee: React.ForwardRefExoticComponent<MarqueeProps & React.RefAttributes<HTMLDivElement>>;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Shared motion tokens for the expressive `/site` layer.
|
|
124
|
+
*
|
|
125
|
+
* These are deliberately *opinionated but restrained* — the defaults produce
|
|
126
|
+
* the kind of confident, weighted motion seen on award-tier marketing sites
|
|
127
|
+
* (slow-out cubic-bezier, ~0.7–1s durations) rather than the snappy 150ms
|
|
128
|
+
* micro-interactions the app kit favours. Override per-component when a brief
|
|
129
|
+
* calls for it.
|
|
130
|
+
*/
|
|
131
|
+
/** Cubic-bezier easings as `[x1, y1, x2, y2]` tuples (motion's `ease` format). */
|
|
132
|
+
declare const EASE: {
|
|
133
|
+
/** Strong slow-out — the workhorse for entrances and reveals. */
|
|
134
|
+
readonly out: readonly [0.16, 1, 0.3, 1];
|
|
135
|
+
/** Symmetric in-out for loops and continuous motion. */
|
|
136
|
+
readonly inOut: readonly [0.65, 0, 0.35, 1];
|
|
137
|
+
/** Gentle in-out, good for parallax / large translations. */
|
|
138
|
+
readonly soft: readonly [0.4, 0, 0.2, 1];
|
|
139
|
+
};
|
|
140
|
+
/** Default durations (seconds) for the expressive layer. */
|
|
141
|
+
declare const DURATION: {
|
|
142
|
+
readonly fast: 0.4;
|
|
143
|
+
readonly base: 0.7;
|
|
144
|
+
readonly slow: 1.1;
|
|
145
|
+
};
|
|
146
|
+
/** Spring presets for pointer-driven motion (Magnetic, etc.). */
|
|
147
|
+
declare const SPRING: {
|
|
148
|
+
/** Tight, responsive follow. */
|
|
149
|
+
readonly snappy: {
|
|
150
|
+
readonly stiffness: 350;
|
|
151
|
+
readonly damping: 30;
|
|
152
|
+
readonly mass: 0.4;
|
|
153
|
+
};
|
|
154
|
+
/** Looser, more elastic follow. */
|
|
155
|
+
readonly smooth: {
|
|
156
|
+
readonly stiffness: 150;
|
|
157
|
+
readonly damping: 20;
|
|
158
|
+
readonly mass: 0.6;
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
interface MagneticProps extends React.ComponentPropsWithoutRef<"div"> {
|
|
163
|
+
/** How far the element follows the pointer, as a fraction of the cursor offset. Default 0.35. */
|
|
164
|
+
strength?: number;
|
|
165
|
+
/** Max travel in px in any direction (clamps `strength` on large elements). Default 24. */
|
|
166
|
+
max?: number;
|
|
167
|
+
/** Spring feel. Default `"snappy"`. */
|
|
168
|
+
spring?: keyof typeof SPRING;
|
|
169
|
+
children?: React.ReactNode;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Make a child element drift toward the cursor while hovered, springing back
|
|
173
|
+
* on leave — the classic "magnetic" CTA / nav affordance. Wrap a single
|
|
174
|
+
* interactive child (button, link). No-op under `prefers-reduced-motion`.
|
|
175
|
+
*
|
|
176
|
+
* ```tsx
|
|
177
|
+
* <Magnetic strength={0.4}>
|
|
178
|
+
* <Button>Shop the drop</Button>
|
|
179
|
+
* </Magnetic>
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
declare const Magnetic: React.ForwardRefExoticComponent<MagneticProps & React.RefAttributes<HTMLDivElement>>;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Copy-paste into a workforce agent system prompt (or codegen tool context) so
|
|
186
|
+
* the model knows which expressive `/site` motion primitives exist and how to
|
|
187
|
+
* dose them — without turning every page into a motion demo.
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```ts
|
|
191
|
+
* import { SITE_AGENT_INSTRUCTIONS } from "@timbal-ai/timbal-react/site";
|
|
192
|
+
*
|
|
193
|
+
* const systemPrompt = `${basePrompt}\n\n${SITE_AGENT_INSTRUCTIONS}`;
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
declare const SITE_AGENT_INSTRUCTIONS: string;
|
|
197
|
+
|
|
198
|
+
export { DURATION, EASE, Magnetic, type MagneticProps, Marquee, type MarqueeProps, Parallax, type ParallaxProps, Reveal, type RevealProps, type RevealVariant, SITE_AGENT_INSTRUCTIONS, SPRING, TextReveal, type TextRevealProps };
|