motion-presets-kit 0.1.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.
@@ -0,0 +1,537 @@
1
+ import { warn, shouldReduceMotion, parentVariants, fade } from './chunk-PFZKSPJW.js';
2
+ import { z } from 'zod';
3
+ import { motion, useMotionValue, useMotionValueEvent, animate } from 'motion/react';
4
+ import { memo, useId, useRef, useEffect, useMemo, useState, useCallback } from 'react';
5
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
+
7
+ var counterOptionsSchema = z.object({
8
+ from: z.number().default(0),
9
+ to: z.number().default(100),
10
+ decimals: z.number().int().min(0).default(0),
11
+ prefix: z.string().default(""),
12
+ suffix: z.string().default(""),
13
+ separator: z.string().default(","),
14
+ format: z.custom(
15
+ (value) => typeof value === "function"
16
+ ).optional(),
17
+ duration: z.number().default(1),
18
+ reducedMotion: z.boolean().default(true)
19
+ });
20
+ var dragConstraintsSchema = z.object({
21
+ top: z.number().optional(),
22
+ right: z.number().optional(),
23
+ bottom: z.number().optional(),
24
+ left: z.number().optional()
25
+ });
26
+ var draggableOptionsSchema = z.object({
27
+ axis: z.enum(["x", "y", "both"]).default("both"),
28
+ bounds: z.union([z.literal("parent"), z.literal("document"), dragConstraintsSchema]).optional(),
29
+ snapToGrid: z.tuple([z.number(), z.number()]).optional(),
30
+ dragElastic: z.union([z.number(), z.boolean()]).optional(),
31
+ dragMomentum: z.boolean().optional()
32
+ });
33
+ var marqueeOptionsSchema = z.object({
34
+ speed: z.number().positive().default(20),
35
+ direction: z.enum(["left", "right"]).default("left"),
36
+ pauseOnHover: z.boolean().default(true),
37
+ gap: z.string().default("2rem"),
38
+ reducedMotion: z.boolean().default(true)
39
+ });
40
+ var textAnimateOptionsSchema = z.object({
41
+ by: z.enum(["word", "letter"]).default("word"),
42
+ type: z.enum([
43
+ "blurIn",
44
+ "slideUp",
45
+ "slideDown",
46
+ "slideLeft",
47
+ "slideRight",
48
+ "typeWriter"
49
+ ]).default("slideUp"),
50
+ duration: z.number().default(0.4),
51
+ startDelay: z.number().default(0),
52
+ highlight: z.array(z.string()).default([]),
53
+ highlightClassName: z.string().default(""),
54
+ reducedMotion: z.boolean().default(true)
55
+ });
56
+
57
+ // src/components/counter-utils.ts
58
+ function formatCounterValue(value, options = {}) {
59
+ const {
60
+ decimals = 0,
61
+ prefix = "",
62
+ suffix = "",
63
+ separator = ",",
64
+ format
65
+ } = options;
66
+ if (format) return `${prefix}${format(value)}${suffix}`;
67
+ const fixed = Math.abs(value).toFixed(decimals);
68
+ const [integer = "", fraction] = fixed.split(".");
69
+ const requestGrouped = separator !== "" && separator !== "none";
70
+ const grouped = requestGrouped ? integer.replace(/\B(?=(\d{3})+(?!\d))/g, separator) : integer;
71
+ const sign = value < 0 ? "-" : "";
72
+ const decimalPart = fraction ? `.${fraction}` : "";
73
+ return `${prefix}${sign}${grouped}${decimalPart}${suffix}`;
74
+ }
75
+
76
+ // src/components/draggable-utils.ts
77
+ function hasInvalidBounds(bounds) {
78
+ if (bounds.top !== void 0 && bounds.bottom !== void 0 && bounds.top > bounds.bottom) {
79
+ return true;
80
+ }
81
+ if (bounds.left !== void 0 && bounds.right !== void 0 && bounds.left > bounds.right) {
82
+ return true;
83
+ }
84
+ return false;
85
+ }
86
+ function resolveDragConstraints(bounds) {
87
+ if (bounds === void 0) return null;
88
+ if (bounds === "parent" || bounds === "document") return bounds;
89
+ return hasInvalidBounds(bounds) ? null : bounds;
90
+ }
91
+ function getDragConstraintsProp(resolved, containerRef) {
92
+ if (resolved === "parent" || resolved === "document") return containerRef;
93
+ return resolved ?? void 0;
94
+ }
95
+ function buildSnapModifier(snapToGrid) {
96
+ if (!snapToGrid) return void 0;
97
+ const [gridX, gridY] = snapToGrid;
98
+ const grid = gridX === 0 ? gridY : gridY === 0 ? gridX : gridX;
99
+ if (grid === 0) return void 0;
100
+ return (value) => Math.round(value / grid) * grid;
101
+ }
102
+ function Draggable({
103
+ children,
104
+ axis = "both",
105
+ bounds,
106
+ snapToGrid,
107
+ dragElastic,
108
+ dragMomentum,
109
+ dragControls,
110
+ onDragStart,
111
+ onDrag,
112
+ onDragEnd,
113
+ className
114
+ }) {
115
+ const parsed = draggableOptionsSchema.safeParse({
116
+ axis,
117
+ bounds,
118
+ snapToGrid,
119
+ dragElastic,
120
+ dragMomentum
121
+ });
122
+ if (!parsed.success) {
123
+ warn(`Opciones inv\xE1lidas en Draggable: ${parsed.error.message}`);
124
+ }
125
+ const data = parsed.success ? parsed.data : draggableOptionsSchema.parse({});
126
+ if (typeof data.bounds === "object" && data.bounds !== null && hasInvalidBounds(data.bounds)) {
127
+ warn(
128
+ "bounds inv\xE1lidos en Draggable (top > bottom o left > right). Se ignoran los l\xEDmites (CL-007)."
129
+ );
130
+ }
131
+ const resolved = resolveDragConstraints(data.bounds);
132
+ const containerMode = resolved === "parent" || resolved === "document" ? resolved : null;
133
+ const elementRef = useRef(null);
134
+ const containerRef = useRef(null);
135
+ useEffect(() => {
136
+ const element = elementRef.current;
137
+ if (!element || containerMode === null) return;
138
+ containerRef.current = containerMode === "parent" ? element.parentElement : element.ownerDocument?.documentElement ?? null;
139
+ }, [containerMode]);
140
+ const drag = data.axis === "both" ? true : data.axis;
141
+ const dragConstraints = getDragConstraintsProp(resolved, containerRef);
142
+ const modifyTarget = buildSnapModifier(data.snapToGrid);
143
+ return /* @__PURE__ */ jsx(
144
+ motion.div,
145
+ {
146
+ ref: elementRef,
147
+ drag,
148
+ dragConstraints,
149
+ dragElastic: data.dragElastic,
150
+ dragMomentum: data.dragMomentum,
151
+ dragTransition: modifyTarget ? { modifyTarget } : void 0,
152
+ dragControls,
153
+ onDragStart,
154
+ onDrag,
155
+ onDragEnd,
156
+ className,
157
+ children
158
+ }
159
+ );
160
+ }
161
+ function useCounter(ref, options = {}) {
162
+ const parsed = counterOptionsSchema.safeParse(options);
163
+ if (!parsed.success) {
164
+ warn(`Opciones inv\xE1lidas en useCounter: ${parsed.error.message}`);
165
+ }
166
+ const config = parsed.success ? parsed.data : counterOptionsSchema.parse({});
167
+ const { from, to, duration, reducedMotion } = config;
168
+ const formatOptions = useMemo(
169
+ () => ({
170
+ decimals: config.decimals,
171
+ prefix: config.prefix,
172
+ suffix: config.suffix,
173
+ separator: config.separator,
174
+ format: config.format
175
+ }),
176
+ [
177
+ config.decimals,
178
+ config.prefix,
179
+ config.suffix,
180
+ config.separator,
181
+ config.format
182
+ ]
183
+ );
184
+ const motionValue = useMotionValue(from);
185
+ const [value, setValue] = useState(from);
186
+ const writeValue = useCallback(
187
+ (next) => {
188
+ const element = ref.current;
189
+ if (element) {
190
+ element.textContent = formatCounterValue(next, formatOptions);
191
+ }
192
+ },
193
+ [ref, formatOptions]
194
+ );
195
+ useMotionValueEvent(motionValue, "change", (latest) => {
196
+ setValue(latest);
197
+ writeValue(latest);
198
+ });
199
+ useEffect(() => {
200
+ if (shouldReduceMotion(reducedMotion)) {
201
+ motionValue.set(to);
202
+ setValue(to);
203
+ writeValue(to);
204
+ }
205
+ }, [motionValue, to, reducedMotion, writeValue]);
206
+ const start = useCallback(() => {
207
+ if (shouldReduceMotion(reducedMotion)) {
208
+ motionValue.set(to);
209
+ setValue(to);
210
+ writeValue(to);
211
+ return;
212
+ }
213
+ motionValue.set(from);
214
+ setValue(from);
215
+ animate(motionValue, to, {
216
+ duration,
217
+ ease: [0.16, 1, 0.3, 1]
218
+ });
219
+ }, [motionValue, from, to, duration, reducedMotion, writeValue]);
220
+ const reset = useCallback(() => {
221
+ motionValue.set(from);
222
+ setValue(from);
223
+ writeValue(from);
224
+ }, [motionValue, from, writeValue]);
225
+ return { value, start, reset };
226
+ }
227
+
228
+ // src/components/marquee-utils.ts
229
+ function buildMarqueeKeyframes(options) {
230
+ const { id, direction, gap, speed, pauseOnHover } = options;
231
+ const animationName = `motion-marquee-${id}`;
232
+ const listClassName = `motion-marquee-list-${id}`;
233
+ const trackClassName = `motion-marquee-track-${id}`;
234
+ const from = direction === "left" ? "0" : `calc(-100% - ${gap})`;
235
+ const to = direction === "left" ? `calc(-100% - ${gap})` : "0";
236
+ const css = [
237
+ `@keyframes ${animationName}{from{transform:translateX(${from})}to{transform:translateX(${to})}}`,
238
+ `.${listClassName}{display:flex;align-items:center;flex-shrink:0;min-width:100%;gap:${gap};animation:${animationName} ${speed}s linear infinite;will-change:transform;backface-visibility:hidden}`,
239
+ `.${trackClassName}{display:flex;gap:${gap}}`,
240
+ pauseOnHover ? `.${trackClassName}:hover .${listClassName}{animation-play-state:paused}` : ""
241
+ ].filter(Boolean).join("");
242
+ return { animationName, listClassName, trackClassName, css };
243
+ }
244
+ var MASK_STYLE = {
245
+ maskImage: "linear-gradient(to right, transparent, black 15%, black 85%, transparent)",
246
+ WebkitMaskImage: "linear-gradient(to right, transparent, black 15%, black 85%, transparent)"
247
+ };
248
+ var BASE_STYLE = {
249
+ display: "flex",
250
+ overflow: "hidden",
251
+ width: "100%"
252
+ };
253
+ var Marquee = memo(function Marquee2({
254
+ children,
255
+ speed = 20,
256
+ direction = "left",
257
+ pauseOnHover = true,
258
+ gap = "2rem",
259
+ className,
260
+ reducedMotion = true
261
+ }) {
262
+ const rawId = useId();
263
+ const id = rawId.replace(/[^a-zA-Z0-9_-]/g, "");
264
+ const duplicateRef = useRef(null);
265
+ useEffect(() => {
266
+ const element = duplicateRef.current;
267
+ if (element) element.inert = true;
268
+ }, []);
269
+ const parsed = marqueeOptionsSchema.safeParse({
270
+ speed,
271
+ direction,
272
+ pauseOnHover,
273
+ gap,
274
+ reducedMotion
275
+ });
276
+ if (!parsed.success) {
277
+ warn(`Opciones inv\xE1lidas en Marquee: ${parsed.error.message}`);
278
+ }
279
+ const config = parsed.success ? parsed.data : marqueeOptionsSchema.parse({});
280
+ const keyframes = useMemo(
281
+ () => buildMarqueeKeyframes({
282
+ id,
283
+ direction: config.direction,
284
+ gap: config.gap,
285
+ speed: config.speed,
286
+ pauseOnHover: config.pauseOnHover
287
+ }),
288
+ [id, config.direction, config.gap, config.speed, config.pauseOnHover]
289
+ );
290
+ const paused = shouldReduceMotion(config.reducedMotion);
291
+ const listStyle = {
292
+ display: "flex",
293
+ alignItems: "center",
294
+ flexShrink: 0,
295
+ minWidth: "100%",
296
+ gap: config.gap,
297
+ ...paused ? {} : {
298
+ animation: `${keyframes.animationName} ${config.speed}s linear infinite`,
299
+ willChange: "transform",
300
+ backfaceVisibility: "hidden"
301
+ }
302
+ };
303
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
304
+ /* @__PURE__ */ jsx("style", { children: keyframes.css }),
305
+ /* @__PURE__ */ jsxs(
306
+ "section",
307
+ {
308
+ "aria-label": "Contenido en desplazamiento continuo",
309
+ className: className ? `${keyframes.trackClassName} ${className}` : keyframes.trackClassName,
310
+ style: { ...BASE_STYLE, ...MASK_STYLE },
311
+ children: [
312
+ /* @__PURE__ */ jsx("div", { className: keyframes.listClassName, style: listStyle, children }),
313
+ /* @__PURE__ */ jsx(
314
+ "div",
315
+ {
316
+ ref: duplicateRef,
317
+ className: keyframes.listClassName,
318
+ style: listStyle,
319
+ "aria-hidden": "true",
320
+ children
321
+ }
322
+ )
323
+ ]
324
+ }
325
+ )
326
+ ] });
327
+ });
328
+
329
+ // src/components/text-animate-utils.ts
330
+ var TAG_RE = /<[^>]*>/g;
331
+ var TOKEN_SOURCE = "<[^>]*>|\\s+|[^<\\s]+";
332
+ function tokenize(text) {
333
+ const tokens = [];
334
+ const regex = new RegExp(TOKEN_SOURCE, "g");
335
+ let match = regex.exec(text);
336
+ while (match !== null) {
337
+ const value = match[0];
338
+ if (value.startsWith("<")) tokens.push({ kind: "tag", value });
339
+ else if (/^\s+$/.test(value)) tokens.push({ kind: "space", value });
340
+ else tokens.push({ kind: "text", value });
341
+ match = regex.exec(text);
342
+ }
343
+ return tokens;
344
+ }
345
+ function groupWords(tokens) {
346
+ const units = [];
347
+ let pending = "";
348
+ let current = null;
349
+ const flush = () => {
350
+ if (current !== null) {
351
+ units.push(current);
352
+ current = null;
353
+ }
354
+ };
355
+ for (const token of tokens) {
356
+ if (token.kind === "space") {
357
+ flush();
358
+ continue;
359
+ }
360
+ if (token.kind === "tag") {
361
+ if (current !== null) current += token.value;
362
+ else pending += token.value;
363
+ continue;
364
+ }
365
+ flush();
366
+ current = pending + token.value;
367
+ pending = "";
368
+ }
369
+ flush();
370
+ if (pending) units.push(pending);
371
+ return units;
372
+ }
373
+ function groupLetters(tokens) {
374
+ const units = [];
375
+ let pending = "";
376
+ for (const token of tokens) {
377
+ if (token.kind === "space") {
378
+ for (const char of token.value) units.push(char);
379
+ continue;
380
+ }
381
+ if (token.kind === "tag") {
382
+ if (token.value.startsWith("</") && units.length > 0) {
383
+ const last = units.length - 1;
384
+ units[last] = `${units[last] ?? ""}${token.value}`;
385
+ } else {
386
+ pending += token.value;
387
+ }
388
+ continue;
389
+ }
390
+ const chars = [...token.value];
391
+ chars.forEach((char, index) => {
392
+ units.push((index === 0 ? pending : "") + char);
393
+ pending = "";
394
+ });
395
+ }
396
+ if (pending) units.push(pending);
397
+ return units;
398
+ }
399
+ function splitText(text, by = "word") {
400
+ const tokens = tokenize(text);
401
+ return by === "letter" ? groupLetters(tokens) : groupWords(tokens);
402
+ }
403
+ function getHighlightRanges(text, highlights) {
404
+ const plain = text.replace(TAG_RE, "");
405
+ const lower = plain.toLowerCase();
406
+ const ranges = [];
407
+ for (const highlight of highlights) {
408
+ if (!highlight) continue;
409
+ const needle = highlight.toLowerCase();
410
+ let from = 0;
411
+ while (from <= lower.length - needle.length) {
412
+ const index = lower.indexOf(needle, from);
413
+ if (index === -1) break;
414
+ ranges.push([index, index + needle.length]);
415
+ from = index + needle.length;
416
+ }
417
+ }
418
+ return ranges;
419
+ }
420
+ function isWordHighlighted(word, highlights) {
421
+ const plain = word.replace(TAG_RE, "").toLowerCase();
422
+ return highlights.some(
423
+ (highlight) => highlight !== "" && plain.includes(highlight.toLowerCase())
424
+ );
425
+ }
426
+ function getAnimationParams(type = "slideUp") {
427
+ switch (type) {
428
+ case "blurIn":
429
+ return { direction: "none", distance: 0, blur: 8 };
430
+ case "slideDown":
431
+ return { direction: "down", distance: 20, blur: 4 };
432
+ case "slideLeft":
433
+ return { direction: "left", distance: 20, blur: 4 };
434
+ case "slideRight":
435
+ return { direction: "right", distance: 20, blur: 4 };
436
+ case "typeWriter":
437
+ return { direction: "none", distance: 0, blur: 0 };
438
+ default:
439
+ return { direction: "up", distance: 20, blur: 4 };
440
+ }
441
+ }
442
+ var componentCache = /* @__PURE__ */ new Map();
443
+ function getMotionComponent(tag) {
444
+ const key = String(tag);
445
+ let component = componentCache.get(key);
446
+ if (!component) {
447
+ component = motion.create(tag);
448
+ componentCache.set(key, component);
449
+ }
450
+ return component;
451
+ }
452
+ var SPAN_STYLE = { display: "inline-block", whiteSpace: "pre-wrap" };
453
+ var WORD_STYLE = { ...SPAN_STYLE, marginRight: "0.25em" };
454
+ function TextAnimate({
455
+ text,
456
+ as = "p",
457
+ by = "word",
458
+ type = "slideUp",
459
+ duration = 0.4,
460
+ startDelay = 0,
461
+ highlight = [],
462
+ highlightClassName = "",
463
+ reducedMotion = true,
464
+ ...props
465
+ }) {
466
+ const parsed = textAnimateOptionsSchema.safeParse({
467
+ by,
468
+ type,
469
+ duration,
470
+ startDelay,
471
+ highlight,
472
+ highlightClassName,
473
+ reducedMotion
474
+ });
475
+ if (!parsed.success) {
476
+ warn(`Opciones inv\xE1lidas en TextAnimate: ${parsed.error.message}`);
477
+ }
478
+ const config = parsed.success ? parsed.data : textAnimateOptionsSchema.parse({});
479
+ const MotionWrapper = useMemo(() => getMotionComponent(as), [as]);
480
+ const units = useMemo(() => splitText(text, config.by), [text, config.by]);
481
+ const ranges = useMemo(
482
+ () => config.by === "letter" ? getHighlightRanges(text, config.highlight) : [],
483
+ [text, config.by, config.highlight]
484
+ );
485
+ const animationParams = useMemo(
486
+ () => getAnimationParams(config.type),
487
+ [config.type]
488
+ );
489
+ const parent = useMemo(
490
+ () => parentVariants({
491
+ delayChildren: config.type === "typeWriter" && config.by === "letter" ? 0.05 : 0.08,
492
+ startDelay: config.startDelay,
493
+ reducedMotion: config.reducedMotion
494
+ }),
495
+ [config.type, config.by, config.startDelay, config.reducedMotion]
496
+ );
497
+ const child = useMemo(
498
+ () => fade({
499
+ ...animationParams,
500
+ excludeDelay: true,
501
+ duration: config.type === "typeWriter" ? 0.05 : config.duration,
502
+ reducedMotion: config.reducedMotion
503
+ }),
504
+ [animationParams, config.type, config.duration, config.reducedMotion]
505
+ );
506
+ const isWord = config.by === "word";
507
+ const itemStyle = isWord ? WORD_STYLE : SPAN_STYLE;
508
+ return /* @__PURE__ */ jsx(
509
+ MotionWrapper,
510
+ {
511
+ variants: parent,
512
+ initial: "initial",
513
+ whileInView: "animate",
514
+ viewport: { once: true },
515
+ ...props,
516
+ children: units.map((unit, index) => {
517
+ const highlighted = isWord ? isWordHighlighted(unit, config.highlight) : ranges.some(([start, end]) => index >= start && index < end);
518
+ const hasHtml = /<[^>]*>/.test(unit);
519
+ const key = `${index}-${unit}`;
520
+ return /* @__PURE__ */ jsx(
521
+ motion.span,
522
+ {
523
+ variants: child,
524
+ className: highlighted ? config.highlightClassName : void 0,
525
+ style: itemStyle,
526
+ ...hasHtml ? { dangerouslySetInnerHTML: { __html: unit } } : { children: unit === "" ? "\xA0" : unit }
527
+ },
528
+ key
529
+ );
530
+ })
531
+ }
532
+ );
533
+ }
534
+
535
+ export { Draggable, Marquee, TextAnimate, buildMarqueeKeyframes, buildSnapModifier, counterOptionsSchema, dragConstraintsSchema, draggableOptionsSchema, formatCounterValue, getAnimationParams, getDragConstraintsProp, getHighlightRanges, hasInvalidBounds, isWordHighlighted, marqueeOptionsSchema, resolveDragConstraints, splitText, textAnimateOptionsSchema, useCounter };
536
+ //# sourceMappingURL=chunk-GU3ZCMLK.js.map
537
+ //# sourceMappingURL=chunk-GU3ZCMLK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/schemas/counter.ts","../src/schemas/draggable.ts","../src/schemas/marquee.ts","../src/schemas/text-animate.ts","../src/components/counter-utils.ts","../src/components/draggable-utils.ts","../src/components/Draggable.tsx","../src/components/hooks/useCounter.ts","../src/components/marquee-utils.ts","../src/components/Marquee.tsx","../src/components/text-animate-utils.ts","../src/components/TextAnimate.tsx"],"names":["z","useEffect","Marquee","useRef","useMemo","jsx","motion"],"mappings":"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","file":"chunk-GU3ZCMLK.js","sourcesContent":["import { z } from \"zod\";\n\nexport const counterOptionsSchema = z.object({\n\tfrom: z.number().default(0),\n\tto: z.number().default(100),\n\tdecimals: z.number().int().min(0).default(0),\n\tprefix: z.string().default(\"\"),\n\tsuffix: z.string().default(\"\"),\n\tseparator: z.string().default(\",\"),\n\tformat: z\n\t\t.custom<(value: number) => string>(\n\t\t\t(value): value is (value: number) => string =>\n\t\t\t\ttypeof value === \"function\",\n\t\t)\n\t\t.optional(),\n\tduration: z.number().default(1),\n\treducedMotion: z.boolean().default(true),\n});\n\nexport type CounterOptions = z.input<typeof counterOptionsSchema>;\nexport type ResolvedCounterOptions = z.output<typeof counterOptionsSchema>;\n","import { z } from \"zod\";\n\nexport const dragConstraintsSchema = z.object({\n\ttop: z.number().optional(),\n\tright: z.number().optional(),\n\tbottom: z.number().optional(),\n\tleft: z.number().optional(),\n});\n\nexport const draggableOptionsSchema = z.object({\n\taxis: z.enum([\"x\", \"y\", \"both\"]).default(\"both\"),\n\tbounds: z\n\t\t.union([z.literal(\"parent\"), z.literal(\"document\"), dragConstraintsSchema])\n\t\t.optional(),\n\tsnapToGrid: z.tuple([z.number(), z.number()]).optional(),\n\tdragElastic: z.union([z.number(), z.boolean()]).optional(),\n\tdragMomentum: z.boolean().optional(),\n});\n\nexport type DraggableOptions = z.input<typeof draggableOptionsSchema>;\nexport type ResolvedDraggableOptions = z.output<typeof draggableOptionsSchema>;\nexport type DragConstraints = z.infer<typeof dragConstraintsSchema>;\n","import { z } from \"zod\";\n\nexport const marqueeOptionsSchema = z.object({\n\tspeed: z.number().positive().default(20),\n\tdirection: z.enum([\"left\", \"right\"]).default(\"left\"),\n\tpauseOnHover: z.boolean().default(true),\n\tgap: z.string().default(\"2rem\"),\n\treducedMotion: z.boolean().default(true),\n});\n\nexport type MarqueeOptions = z.input<typeof marqueeOptionsSchema>;\nexport type ResolvedMarqueeOptions = z.output<typeof marqueeOptionsSchema>;\n","import { z } from \"zod\";\n\nexport const textAnimateOptionsSchema = z.object({\n\tby: z.enum([\"word\", \"letter\"]).default(\"word\"),\n\ttype: z\n\t\t.enum([\n\t\t\t\"blurIn\",\n\t\t\t\"slideUp\",\n\t\t\t\"slideDown\",\n\t\t\t\"slideLeft\",\n\t\t\t\"slideRight\",\n\t\t\t\"typeWriter\",\n\t\t])\n\t\t.default(\"slideUp\"),\n\tduration: z.number().default(0.4),\n\tstartDelay: z.number().default(0),\n\thighlight: z.array(z.string()).default([]),\n\thighlightClassName: z.string().default(\"\"),\n\treducedMotion: z.boolean().default(true),\n});\n\nexport type TextAnimateOptions = z.input<typeof textAnimateOptionsSchema>;\nexport type ResolvedTextAnimateOptions = z.output<\n\ttypeof textAnimateOptionsSchema\n>;\n","import type { CounterOptions } from \"../schemas/counter\";\n\n/** Formatea un número con decimales, separador de miles, prefijo/sufijo y `format` custom (CL-005). */\nexport function formatCounterValue(\n\tvalue: number,\n\toptions: CounterOptions = {},\n): string {\n\tconst {\n\t\tdecimals = 0,\n\t\tprefix = \"\",\n\t\tsuffix = \"\",\n\t\tseparator = \",\",\n\t\tformat,\n\t} = options;\n\n\tif (format) return `${prefix}${format(value)}${suffix}`;\n\n\tconst fixed = Math.abs(value).toFixed(decimals);\n\tconst [integer = \"\", fraction] = fixed.split(\".\");\n\tconst requestGrouped = separator !== \"\" && separator !== \"none\";\n\tconst grouped = requestGrouped\n\t\t? integer.replace(/\\B(?=(\\d{3})+(?!\\d))/g, separator)\n\t\t: integer;\n\tconst sign = value < 0 ? \"-\" : \"\";\n\tconst decimalPart = fraction ? `.${fraction}` : \"\";\n\n\treturn `${prefix}${sign}${grouped}${decimalPart}${suffix}`;\n}\n","import type { RefObject } from \"react\";\nimport type { DragConstraints } from \"../schemas/draggable\";\n\n/** `true` si los límites tienen `top > bottom` o `left > right` (CL-007). */\nexport function hasInvalidBounds(bounds: DragConstraints): boolean {\n\tif (\n\t\tbounds.top !== undefined &&\n\t\tbounds.bottom !== undefined &&\n\t\tbounds.top > bounds.bottom\n\t) {\n\t\treturn true;\n\t}\n\tif (\n\t\tbounds.left !== undefined &&\n\t\tbounds.right !== undefined &&\n\t\tbounds.left > bounds.right\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nexport type ResolvedDragBounds = \"parent\" | \"document\" | DragConstraints | null;\n\n/** Normaliza `bounds` a un valor usable por motion, descartando límites inválidos (CL-007). */\nexport function resolveDragConstraints(\n\tbounds: \"parent\" | \"document\" | DragConstraints | undefined,\n): ResolvedDragBounds {\n\tif (bounds === undefined) return null;\n\tif (bounds === \"parent\" || bounds === \"document\") return bounds;\n\treturn hasInvalidBounds(bounds) ? null : bounds;\n}\n\n/**\n * Traduce `bounds` al prop `dragConstraints` de motion.\n * `\"parent\"`/`\"document\"` no son strings válidos en motion: se resuelven a un\n * ref al elemento contenedor (`containerRef`) que motion mide al iniciar el drag.\n */\nexport function getDragConstraintsProp(\n\tresolved: ResolvedDragBounds,\n\tcontainerRef: RefObject<Element | null>,\n): Partial<DragConstraints> | { current: Element | null } | undefined {\n\tif (resolved === \"parent\" || resolved === \"document\") return containerRef;\n\treturn resolved ?? undefined;\n}\n\n/** Construye el `modifyTarget` de `dragTransition` que ajusta el destino a la grilla. */\nexport function buildSnapModifier(\n\tsnapToGrid: [number, number] | undefined,\n): ((value: number) => number) | undefined {\n\tif (!snapToGrid) return undefined;\n\tconst [gridX, gridY] = snapToGrid;\n\tconst grid = gridX === 0 ? gridY : gridY === 0 ? gridX : gridX;\n\tif (grid === 0) return undefined;\n\treturn (value: number) => Math.round(value / grid) * grid;\n}\n","import { motion, type PanInfo } from \"motion/react\";\nimport { type ReactElement, type ReactNode, useEffect, useRef } from \"react\";\nimport {\n\ttype DragConstraints,\n\tdraggableOptionsSchema,\n} from \"../schemas/draggable\";\nimport { warn } from \"../utils/warn\";\nimport {\n\tbuildSnapModifier,\n\tgetDragConstraintsProp,\n\thasInvalidBounds,\n\tresolveDragConstraints,\n} from \"./draggable-utils\";\n\nexport interface DraggableProps {\n\tchildren?: ReactNode;\n\taxis?: \"x\" | \"y\" | \"both\";\n\tbounds?: \"parent\" | \"document\" | DragConstraints;\n\tsnapToGrid?: [number, number];\n\tdragElastic?: number | boolean;\n\tdragMomentum?: boolean;\n\tdragControls?: unknown;\n\tonDragStart?: (event: unknown, info: PanInfo) => void;\n\tonDrag?: (event: unknown, info: PanInfo) => void;\n\tonDragEnd?: (event: unknown, info: PanInfo) => void;\n\tclassName?: string;\n}\n\n/**\n * Wrapper de `motion.div` con drag configurable por eje, límites, snap y callbacks.\n * `bounds` inválidos se descartan con un `warn()` (CL-007).\n */\nexport function Draggable({\n\tchildren,\n\taxis = \"both\",\n\tbounds,\n\tsnapToGrid,\n\tdragElastic,\n\tdragMomentum,\n\tdragControls,\n\tonDragStart,\n\tonDrag,\n\tonDragEnd,\n\tclassName,\n}: DraggableProps): ReactElement {\n\tconst parsed = draggableOptionsSchema.safeParse({\n\t\taxis,\n\t\tbounds,\n\t\tsnapToGrid,\n\t\tdragElastic,\n\t\tdragMomentum,\n\t});\n\tif (!parsed.success) {\n\t\twarn(`Opciones inválidas en Draggable: ${parsed.error.message}`);\n\t}\n\n\tconst data = parsed.success ? parsed.data : draggableOptionsSchema.parse({});\n\n\tif (\n\t\ttypeof data.bounds === \"object\" &&\n\t\tdata.bounds !== null &&\n\t\thasInvalidBounds(data.bounds)\n\t) {\n\t\twarn(\n\t\t\t\"bounds inválidos en Draggable (top > bottom o left > right). Se ignoran los límites (CL-007).\",\n\t\t);\n\t}\n\n\tconst resolved = resolveDragConstraints(data.bounds);\n\tconst containerMode =\n\t\tresolved === \"parent\" || resolved === \"document\" ? resolved : null;\n\n\tconst elementRef = useRef<HTMLDivElement>(null);\n\tconst containerRef = useRef<Element | null>(null);\n\n\tuseEffect(() => {\n\t\tconst element = elementRef.current;\n\t\tif (!element || containerMode === null) return;\n\t\tcontainerRef.current =\n\t\t\tcontainerMode === \"parent\"\n\t\t\t\t? element.parentElement\n\t\t\t\t: (element.ownerDocument?.documentElement ?? null);\n\t}, [containerMode]);\n\n\tconst drag = data.axis === \"both\" ? true : (data.axis as \"x\" | \"y\");\n\tconst dragConstraints = getDragConstraintsProp(resolved, containerRef);\n\tconst modifyTarget = buildSnapModifier(data.snapToGrid);\n\n\treturn (\n\t\t<motion.div\n\t\t\tref={elementRef}\n\t\t\tdrag={drag}\n\t\t\tdragConstraints={dragConstraints}\n\t\t\tdragElastic={data.dragElastic}\n\t\t\tdragMomentum={data.dragMomentum}\n\t\t\tdragTransition={modifyTarget ? { modifyTarget } : undefined}\n\t\t\tdragControls={dragControls as never}\n\t\t\tonDragStart={onDragStart}\n\t\t\tonDrag={onDrag}\n\t\t\tonDragEnd={onDragEnd}\n\t\t\tclassName={className}\n\t\t>\n\t\t\t{children}\n\t\t</motion.div>\n\t);\n}\n","import { animate, useMotionValue, useMotionValueEvent } from \"motion/react\";\nimport {\n\ttype RefObject,\n\tuseCallback,\n\tuseEffect,\n\tuseMemo,\n\tuseState,\n} from \"react\";\nimport {\n\ttype CounterOptions,\n\tcounterOptionsSchema,\n} from \"../../schemas/counter\";\nimport { shouldReduceMotion } from \"../../utils/reduced-motion\";\nimport { warn } from \"../../utils/warn\";\nimport { formatCounterValue } from \"../counter-utils\";\n\nexport interface UseCounterResult {\n\tvalue: number;\n\tstart: () => void;\n\treset: () => void;\n}\n\n/**\n * Contador animado que escribe el valor formateado en `ref.current.textContent`\n * y expone el valor actual de forma reactiva.\n * Con `reducedMotion` activo muestra el valor final directamente (RF-095).\n */\nexport function useCounter(\n\tref: RefObject<HTMLElement | null>,\n\toptions: CounterOptions = {},\n): UseCounterResult {\n\tconst parsed = counterOptionsSchema.safeParse(options);\n\tif (!parsed.success) {\n\t\twarn(`Opciones inválidas en useCounter: ${parsed.error.message}`);\n\t}\n\tconst config = parsed.success ? parsed.data : counterOptionsSchema.parse({});\n\tconst { from, to, duration, reducedMotion } = config;\n\n\tconst formatOptions = useMemo(\n\t\t() => ({\n\t\t\tdecimals: config.decimals,\n\t\t\tprefix: config.prefix,\n\t\t\tsuffix: config.suffix,\n\t\t\tseparator: config.separator,\n\t\t\tformat: config.format,\n\t\t}),\n\t\t[\n\t\t\tconfig.decimals,\n\t\t\tconfig.prefix,\n\t\t\tconfig.suffix,\n\t\t\tconfig.separator,\n\t\t\tconfig.format,\n\t\t],\n\t);\n\n\tconst motionValue = useMotionValue(from);\n\tconst [value, setValue] = useState(from);\n\n\tconst writeValue = useCallback(\n\t\t(next: number) => {\n\t\t\tconst element = ref.current;\n\t\t\tif (element) {\n\t\t\t\telement.textContent = formatCounterValue(next, formatOptions);\n\t\t\t}\n\t\t},\n\t\t[ref, formatOptions],\n\t);\n\n\tuseMotionValueEvent(motionValue, \"change\", (latest) => {\n\t\tsetValue(latest);\n\t\twriteValue(latest);\n\t});\n\n\tuseEffect(() => {\n\t\tif (shouldReduceMotion(reducedMotion)) {\n\t\t\tmotionValue.set(to);\n\t\t\tsetValue(to);\n\t\t\twriteValue(to);\n\t\t}\n\t}, [motionValue, to, reducedMotion, writeValue]);\n\n\tconst start = useCallback(() => {\n\t\tif (shouldReduceMotion(reducedMotion)) {\n\t\t\tmotionValue.set(to);\n\t\t\tsetValue(to);\n\t\t\twriteValue(to);\n\t\t\treturn;\n\t\t}\n\t\tmotionValue.set(from);\n\t\tsetValue(from);\n\t\tanimate(motionValue, to, {\n\t\t\tduration,\n\t\t\tease: [0.16, 1, 0.3, 1],\n\t\t});\n\t}, [motionValue, from, to, duration, reducedMotion, writeValue]);\n\n\tconst reset = useCallback(() => {\n\t\tmotionValue.set(from);\n\t\tsetValue(from);\n\t\twriteValue(from);\n\t}, [motionValue, from, writeValue]);\n\n\treturn { value, start, reset };\n}\n","export interface MarqueeKeyframesOptions {\n\tid: string;\n\tdirection: \"left\" | \"right\";\n\tgap: string;\n\tspeed: number;\n\tpauseOnHover: boolean;\n}\n\nexport interface MarqueeKeyframes {\n\tanimationName: string;\n\tlistClassName: string;\n\ttrackClassName: string;\n\tcss: string;\n}\n\n/** Genera los `@keyframes` y clases CSS del marquee (una función pura, sin React). */\nexport function buildMarqueeKeyframes(\n\toptions: MarqueeKeyframesOptions,\n): MarqueeKeyframes {\n\tconst { id, direction, gap, speed, pauseOnHover } = options;\n\tconst animationName = `motion-marquee-${id}`;\n\tconst listClassName = `motion-marquee-list-${id}`;\n\tconst trackClassName = `motion-marquee-track-${id}`;\n\n\tconst from = direction === \"left\" ? \"0\" : `calc(-100% - ${gap})`;\n\tconst to = direction === \"left\" ? `calc(-100% - ${gap})` : \"0\";\n\n\tconst css = [\n\t\t`@keyframes ${animationName}{from{transform:translateX(${from})}to{transform:translateX(${to})}}`,\n\t\t`.${listClassName}{display:flex;align-items:center;flex-shrink:0;min-width:100%;gap:${gap};animation:${animationName} ${speed}s linear infinite;will-change:transform;backface-visibility:hidden}`,\n\t\t`.${trackClassName}{display:flex;gap:${gap}}`,\n\t\tpauseOnHover\n\t\t\t? `.${trackClassName}:hover .${listClassName}{animation-play-state:paused}`\n\t\t\t: \"\",\n\t]\n\t\t.filter(Boolean)\n\t\t.join(\"\");\n\n\treturn { animationName, listClassName, trackClassName, css };\n}\n","import {\n\ttype CSSProperties,\n\tmemo,\n\ttype ReactNode,\n\tuseEffect,\n\tuseId,\n\tuseMemo,\n\tuseRef,\n} from \"react\";\nimport {\n\tmarqueeOptionsSchema,\n\ttype ResolvedMarqueeOptions,\n} from \"../schemas/marquee\";\nimport { shouldReduceMotion } from \"../utils/reduced-motion\";\nimport { warn } from \"../utils/warn\";\nimport { buildMarqueeKeyframes } from \"./marquee-utils\";\n\nexport interface MarqueeProps {\n\tchildren: ReactNode;\n\tspeed?: number;\n\tdirection?: \"left\" | \"right\";\n\tpauseOnHover?: boolean;\n\tgap?: string;\n\tclassName?: string;\n\treducedMotion?: boolean;\n}\n\nconst MASK_STYLE: CSSProperties = {\n\tmaskImage:\n\t\t\"linear-gradient(to right, transparent, black 15%, black 85%, transparent)\",\n\tWebkitMaskImage:\n\t\t\"linear-gradient(to right, transparent, black 15%, black 85%, transparent)\",\n};\n\nconst BASE_STYLE: CSSProperties = {\n\tdisplay: \"flex\",\n\toverflow: \"hidden\",\n\twidth: \"100%\",\n};\n\n/** Marquee con CSS puro (`@keyframes`) y children duplicados para un loop sin costuras. */\nexport const Marquee = memo(function Marquee({\n\tchildren,\n\tspeed = 20,\n\tdirection = \"left\",\n\tpauseOnHover = true,\n\tgap = \"2rem\",\n\tclassName,\n\treducedMotion = true,\n}: MarqueeProps) {\n\tconst rawId = useId();\n\tconst id = rawId.replace(/[^a-zA-Z0-9_-]/g, \"\");\n\tconst duplicateRef = useRef<HTMLDivElement>(null);\n\n\tuseEffect(() => {\n\t\tconst element = duplicateRef.current;\n\t\tif (element) element.inert = true;\n\t}, []);\n\n\tconst parsed = marqueeOptionsSchema.safeParse({\n\t\tspeed,\n\t\tdirection,\n\t\tpauseOnHover,\n\t\tgap,\n\t\treducedMotion,\n\t});\n\tif (!parsed.success) {\n\t\twarn(`Opciones inválidas en Marquee: ${parsed.error.message}`);\n\t}\n\tconst config: ResolvedMarqueeOptions = parsed.success\n\t\t? parsed.data\n\t\t: marqueeOptionsSchema.parse({});\n\n\tconst keyframes = useMemo(\n\t\t() =>\n\t\t\tbuildMarqueeKeyframes({\n\t\t\t\tid,\n\t\t\t\tdirection: config.direction,\n\t\t\t\tgap: config.gap,\n\t\t\t\tspeed: config.speed,\n\t\t\t\tpauseOnHover: config.pauseOnHover,\n\t\t\t}),\n\t\t[id, config.direction, config.gap, config.speed, config.pauseOnHover],\n\t);\n\n\tconst paused = shouldReduceMotion(config.reducedMotion);\n\tconst listStyle: CSSProperties = {\n\t\tdisplay: \"flex\",\n\t\talignItems: \"center\",\n\t\tflexShrink: 0,\n\t\tminWidth: \"100%\",\n\t\tgap: config.gap,\n\t\t...(paused\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tanimation: `${keyframes.animationName} ${config.speed}s linear infinite`,\n\t\t\t\t\twillChange: \"transform\",\n\t\t\t\t\tbackfaceVisibility: \"hidden\",\n\t\t\t\t}),\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<style>{keyframes.css}</style>\n\t\t\t<section\n\t\t\t\taria-label=\"Contenido en desplazamiento continuo\"\n\t\t\t\tclassName={\n\t\t\t\t\tclassName\n\t\t\t\t\t\t? `${keyframes.trackClassName} ${className}`\n\t\t\t\t\t\t: keyframes.trackClassName\n\t\t\t\t}\n\t\t\t\tstyle={{ ...BASE_STYLE, ...MASK_STYLE }}\n\t\t\t>\n\t\t\t\t<div className={keyframes.listClassName} style={listStyle}>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t\t<div\n\t\t\t\t\tref={duplicateRef}\n\t\t\t\t\tclassName={keyframes.listClassName}\n\t\t\t\t\tstyle={listStyle}\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</section>\n\t\t</>\n\t);\n});\n","export type TextAnimateBy = \"word\" | \"letter\";\n\nexport type TextAnimateType =\n\t| \"blurIn\"\n\t| \"slideUp\"\n\t| \"slideDown\"\n\t| \"slideLeft\"\n\t| \"slideRight\"\n\t| \"typeWriter\";\n\nexport interface TextAnimationParams {\n\tdirection: \"up\" | \"down\" | \"left\" | \"right\" | \"none\";\n\tdistance: number;\n\tblur: number;\n}\n\ntype TokenKind = \"tag\" | \"text\" | \"space\";\n\ninterface Token {\n\tkind: TokenKind;\n\tvalue: string;\n}\n\nconst TAG_RE = /<[^>]*>/g;\nconst TOKEN_SOURCE = \"<[^>]*>|\\\\s+|[^<\\\\s]+\";\n\nfunction tokenize(text: string): Token[] {\n\tconst tokens: Token[] = [];\n\tconst regex = new RegExp(TOKEN_SOURCE, \"g\");\n\tlet match = regex.exec(text);\n\twhile (match !== null) {\n\t\tconst value = match[0];\n\t\tif (value.startsWith(\"<\")) tokens.push({ kind: \"tag\", value });\n\t\telse if (/^\\s+$/.test(value)) tokens.push({ kind: \"space\", value });\n\t\telse tokens.push({ kind: \"text\", value });\n\t\tmatch = regex.exec(text);\n\t}\n\treturn tokens;\n}\n\n/**\n * Agrupa palabras manteniendo las etiquetas HTML pegadas a la palabra contigua\n * (CL-004). `\"<strong>Hello</strong> World\"` → `[\"<strong>Hello</strong>\", \"World\"]`.\n */\nfunction groupWords(tokens: Token[]): string[] {\n\tconst units: string[] = [];\n\tlet pending = \"\";\n\tlet current: string | null = null;\n\tconst flush = () => {\n\t\tif (current !== null) {\n\t\t\tunits.push(current);\n\t\t\tcurrent = null;\n\t\t}\n\t};\n\n\tfor (const token of tokens) {\n\t\tif (token.kind === \"space\") {\n\t\t\tflush();\n\t\t\tcontinue;\n\t\t}\n\t\tif (token.kind === \"tag\") {\n\t\t\tif (current !== null) current += token.value;\n\t\t\telse pending += token.value;\n\t\t\tcontinue;\n\t\t}\n\t\tflush();\n\t\tcurrent = pending + token.value;\n\t\tpending = \"\";\n\t}\n\tflush();\n\tif (pending) units.push(pending);\n\treturn units;\n}\n\n/** Agrupa letras manteniendo las etiquetas pegadas a la primera/última letra. */\nfunction groupLetters(tokens: Token[]): string[] {\n\tconst units: string[] = [];\n\tlet pending = \"\";\n\n\tfor (const token of tokens) {\n\t\tif (token.kind === \"space\") {\n\t\t\tfor (const char of token.value) units.push(char);\n\t\t\tcontinue;\n\t\t}\n\t\tif (token.kind === \"tag\") {\n\t\t\tif (token.value.startsWith(\"</\") && units.length > 0) {\n\t\t\t\tconst last = units.length - 1;\n\t\t\t\tunits[last] = `${units[last] ?? \"\"}${token.value}`;\n\t\t\t} else {\n\t\t\t\tpending += token.value;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tconst chars = [...token.value];\n\t\tchars.forEach((char, index) => {\n\t\t\tunits.push((index === 0 ? pending : \"\") + char);\n\t\t\tpending = \"\";\n\t\t});\n\t}\n\tif (pending) units.push(pending);\n\treturn units;\n}\n\n/** Divide el texto en palabras o letras, preservando las etiquetas HTML (CL-004). */\nexport function splitText(text: string, by: TextAnimateBy = \"word\"): string[] {\n\tconst tokens = tokenize(text);\n\treturn by === \"letter\" ? groupLetters(tokens) : groupWords(tokens);\n}\n\n/**\n * Rangos `[inicio, fin)` de coincidencias (case-insensitive) sobre el texto sin\n * etiquetas. Los índices alinean 1:1 con las unidades de `splitText(..., \"letter\")`.\n */\nexport function getHighlightRanges(\n\ttext: string,\n\thighlights: string[],\n): Array<[number, number]> {\n\tconst plain = text.replace(TAG_RE, \"\");\n\tconst lower = plain.toLowerCase();\n\tconst ranges: Array<[number, number]> = [];\n\n\tfor (const highlight of highlights) {\n\t\tif (!highlight) continue;\n\t\tconst needle = highlight.toLowerCase();\n\t\tlet from = 0;\n\t\twhile (from <= lower.length - needle.length) {\n\t\t\tconst index = lower.indexOf(needle, from);\n\t\t\tif (index === -1) break;\n\t\t\tranges.push([index, index + needle.length]);\n\t\t\tfrom = index + needle.length;\n\t\t}\n\t}\n\treturn ranges;\n}\n\n/** `true` si una palabra (sin etiquetas) contiene alguno de los resaltados. */\nexport function isWordHighlighted(word: string, highlights: string[]): boolean {\n\tconst plain = word.replace(TAG_RE, \"\").toLowerCase();\n\treturn highlights.some(\n\t\t(highlight) => highlight !== \"\" && plain.includes(highlight.toLowerCase()),\n\t);\n}\n\n/** Parámetros de `fade()` asociados a cada tipo de animación de texto. */\nexport function getAnimationParams(\n\ttype: TextAnimateType = \"slideUp\",\n): TextAnimationParams {\n\tswitch (type) {\n\t\tcase \"blurIn\":\n\t\t\treturn { direction: \"none\", distance: 0, blur: 8 };\n\t\tcase \"slideDown\":\n\t\t\treturn { direction: \"down\", distance: 20, blur: 4 };\n\t\tcase \"slideLeft\":\n\t\t\treturn { direction: \"left\", distance: 20, blur: 4 };\n\t\tcase \"slideRight\":\n\t\t\treturn { direction: \"right\", distance: 20, blur: 4 };\n\t\tcase \"typeWriter\":\n\t\t\treturn { direction: \"none\", distance: 0, blur: 0 };\n\t\tdefault:\n\t\t\treturn { direction: \"up\", distance: 20, blur: 4 };\n\t}\n}\n","import { type HTMLMotionProps, motion } from \"motion/react\";\nimport type * as React from \"react\";\nimport { type ElementType, type ReactElement, useMemo } from \"react\";\nimport { fade } from \"../presets/fade\";\nimport { parentVariants } from \"../presets/parent-variants\";\nimport {\n\ttype ResolvedTextAnimateOptions,\n\ttextAnimateOptionsSchema,\n} from \"../schemas/text-animate\";\nimport { warn } from \"../utils/warn\";\nimport {\n\tgetAnimationParams,\n\tgetHighlightRanges,\n\tisWordHighlighted,\n\tsplitText,\n\ttype TextAnimateBy,\n\ttype TextAnimateType,\n} from \"./text-animate-utils\";\n\ntype IntrinsicTag = keyof React.JSX.IntrinsicElements;\n\nconst componentCache = new Map<string, ElementType>();\n\nfunction getMotionComponent(tag: IntrinsicTag): ElementType {\n\tconst key = String(tag);\n\tlet component = componentCache.get(key);\n\tif (!component) {\n\t\tcomponent = motion.create(tag) as ElementType;\n\t\tcomponentCache.set(key, component);\n\t}\n\treturn component;\n}\n\nconst SPAN_STYLE = { display: \"inline-block\", whiteSpace: \"pre-wrap\" } as const;\nconst WORD_STYLE = { ...SPAN_STYLE, marginRight: \"0.25em\" } as const;\n\nexport interface TextAnimateProps extends HTMLMotionProps<\"p\"> {\n\ttext: string;\n\tas?: IntrinsicTag;\n\tby?: TextAnimateBy;\n\ttype?: TextAnimateType;\n\tduration?: number;\n\tstartDelay?: number;\n\thighlight?: string[];\n\thighlightClassName?: string;\n\treducedMotion?: boolean;\n}\n\n/**\n * Anima texto dividiéndolo en palabras o letras. Preserva el HTML inline (CL-004),\n * resalta coincidencias (case-insensitive) y anima al entrar en viewport.\n *\n * ADVERTENCIA: el HTML inline se inyecta con `dangerouslySetInnerHTML`. No pases\n * como `text` contenido no confiable sin sanitizarlo antes (riesgo de XSS).\n */\nexport function TextAnimate({\n\ttext,\n\tas = \"p\",\n\tby = \"word\",\n\ttype = \"slideUp\",\n\tduration = 0.4,\n\tstartDelay = 0,\n\thighlight = [],\n\thighlightClassName = \"\",\n\treducedMotion = true,\n\t...props\n}: TextAnimateProps): ReactElement {\n\tconst parsed = textAnimateOptionsSchema.safeParse({\n\t\tby,\n\t\ttype,\n\t\tduration,\n\t\tstartDelay,\n\t\thighlight,\n\t\thighlightClassName,\n\t\treducedMotion,\n\t});\n\tif (!parsed.success) {\n\t\twarn(`Opciones inválidas en TextAnimate: ${parsed.error.message}`);\n\t}\n\tconst config: ResolvedTextAnimateOptions = parsed.success\n\t\t? parsed.data\n\t\t: textAnimateOptionsSchema.parse({});\n\n\tconst MotionWrapper = useMemo(() => getMotionComponent(as), [as]);\n\tconst units = useMemo(() => splitText(text, config.by), [text, config.by]);\n\tconst ranges = useMemo(\n\t\t() =>\n\t\t\tconfig.by === \"letter\" ? getHighlightRanges(text, config.highlight) : [],\n\t\t[text, config.by, config.highlight],\n\t);\n\tconst animationParams = useMemo(\n\t\t() => getAnimationParams(config.type),\n\t\t[config.type],\n\t);\n\n\tconst parent = useMemo(\n\t\t() =>\n\t\t\tparentVariants({\n\t\t\t\tdelayChildren:\n\t\t\t\t\tconfig.type === \"typeWriter\" && config.by === \"letter\" ? 0.05 : 0.08,\n\t\t\t\tstartDelay: config.startDelay,\n\t\t\t\treducedMotion: config.reducedMotion,\n\t\t\t}),\n\t\t[config.type, config.by, config.startDelay, config.reducedMotion],\n\t);\n\n\tconst child = useMemo(\n\t\t() =>\n\t\t\tfade({\n\t\t\t\t...animationParams,\n\t\t\t\texcludeDelay: true,\n\t\t\t\tduration: config.type === \"typeWriter\" ? 0.05 : config.duration,\n\t\t\t\treducedMotion: config.reducedMotion,\n\t\t\t}),\n\t\t[animationParams, config.type, config.duration, config.reducedMotion],\n\t);\n\n\tconst isWord = config.by === \"word\";\n\tconst itemStyle = isWord ? WORD_STYLE : SPAN_STYLE;\n\n\treturn (\n\t\t<MotionWrapper\n\t\t\tvariants={parent}\n\t\t\tinitial=\"initial\"\n\t\t\twhileInView=\"animate\"\n\t\t\tviewport={{ once: true }}\n\t\t\t{...props}\n\t\t>\n\t\t\t{units.map((unit, index) => {\n\t\t\t\tconst highlighted = isWord\n\t\t\t\t\t? isWordHighlighted(unit, config.highlight)\n\t\t\t\t\t: ranges.some(([start, end]) => index >= start && index < end);\n\t\t\t\tconst hasHtml = /<[^>]*>/.test(unit);\n\t\t\t\tconst key = `${index}-${unit}`;\n\t\t\t\treturn (\n\t\t\t\t\t<motion.span\n\t\t\t\t\t\tkey={key}\n\t\t\t\t\t\tvariants={child}\n\t\t\t\t\t\tclassName={highlighted ? config.highlightClassName : undefined}\n\t\t\t\t\t\tstyle={itemStyle}\n\t\t\t\t\t\t{...(hasHtml\n\t\t\t\t\t\t\t? { dangerouslySetInnerHTML: { __html: unit } }\n\t\t\t\t\t\t\t: { children: unit === \"\" ? \"\\u00A0\" : unit })}\n\t\t\t\t\t/>\n\t\t\t\t);\n\t\t\t})}\n\t\t</MotionWrapper>\n\t);\n}\n"]}