@birdapi/velinstyle 1.2.1 → 1.3.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.
Files changed (156) hide show
  1. package/README.de.md +148 -11
  2. package/README.md +174 -16
  3. package/cli/__fixtures__/atelier-library/showcases/01-login/app.css +1 -0
  4. package/cli/__fixtures__/atelier-library/showcases/01-login/app.js +2 -0
  5. package/cli/__fixtures__/atelier-library/showcases/01-login/index.html +5 -0
  6. package/cli/__fixtures__/atelier-library/showcases/04-pricing/app.css +1 -0
  7. package/cli/__fixtures__/atelier-library/showcases/04-pricing/app.js +2 -0
  8. package/cli/__fixtures__/atelier-library/showcases/04-pricing/index.html +5 -0
  9. package/cli/__fixtures__/atelier-library/showcases/36-calendar/app.css +1 -0
  10. package/cli/__fixtures__/atelier-library/showcases/36-calendar/app.js +2 -0
  11. package/cli/__fixtures__/atelier-library/showcases/36-calendar/index.html +5 -0
  12. package/cli/atelier-catalog.json +1267 -0
  13. package/cli/atelier-formats.js +159 -0
  14. package/cli/atelier.js +382 -0
  15. package/cli/blueprints/empty-state.html +3 -5
  16. package/cli/cli-manifest.json +441 -161
  17. package/cli/docgen/extract-cli.js +2 -1
  18. package/cli/docs-generate.js +9 -0
  19. package/cli/experience.js +173 -0
  20. package/cli/index.js +1384 -361
  21. package/cli/motion.js +738 -0
  22. package/cli/production/component-graph.json +166 -0
  23. package/cli/production/explain.js +52 -0
  24. package/cli/production/extract.js +278 -0
  25. package/cli/production/graph.js +102 -0
  26. package/cli/production/report.js +168 -0
  27. package/cli/production/run.js +355 -0
  28. package/cli/production/trim-css.js +177 -0
  29. package/cli/production/trim-fonts.js +23 -0
  30. package/cli/production/trim-icons.js +38 -0
  31. package/cli/production/trim-js.js +48 -0
  32. package/cli/production/trim-motion.js +22 -0
  33. package/cli/production/trim-themes.js +50 -0
  34. package/cli/production/watch.js +38 -0
  35. package/cli/review.js +48 -1
  36. package/cli/scripts/write-atelier-fixtures.mjs +33 -0
  37. package/cli/security.js +190 -0
  38. package/cli/skills.js +53 -10
  39. package/cli/transparency.js +140 -41
  40. package/cli/workflow.js +32 -17
  41. package/components/index.js +3 -0
  42. package/components/runtime/component-loaders.js +3 -0
  43. package/components/velin-drawer.js +43 -4
  44. package/components/velin-empty-state.js +83 -0
  45. package/components/velin-modal.js +76 -15
  46. package/components/velin-otp-input.js +220 -0
  47. package/components/velin-password-strength.js +147 -0
  48. package/components/velin-sheet.js +49 -4
  49. package/components/velin-theme-toggle.js +15 -1
  50. package/core/a11y/component-contracts.json +391 -255
  51. package/core/attributes/registry.js +1 -1
  52. package/core/meta/knowledge/components.json +75 -3
  53. package/core/motion/analyze.js +38 -0
  54. package/core/motion/blueprint.js +51 -0
  55. package/core/motion/composer.js +114 -0
  56. package/core/motion/data/registry.json +352 -0
  57. package/core/motion/effects.js +17 -1
  58. package/core/motion/index.js +112 -9
  59. package/core/motion/optimize.js +44 -0
  60. package/core/motion/policy.js +77 -0
  61. package/core/motion/registry.js +131 -0
  62. package/core/motion/review.js +59 -0
  63. package/core/motion/scan.js +150 -0
  64. package/core/motion/timeline.js +68 -0
  65. package/core/motion/transitions.js +49 -0
  66. package/core/motion/triggers.js +168 -0
  67. package/core/security/checks/fs.js +92 -0
  68. package/core/security/detect.js +35 -0
  69. package/core/security/engine.js +116 -0
  70. package/core/security/index.js +18 -0
  71. package/core/security/registry.js +85 -0
  72. package/core/security/report/report.js +113 -0
  73. package/core/security/rules/ci/index.js +146 -0
  74. package/core/security/rules/consumer/index.js +174 -0
  75. package/core/security/rules/deps/index.js +182 -0
  76. package/core/security/rules/index.js +24 -0
  77. package/core/security/rules/publish/index.js +230 -0
  78. package/core/security/rules/repo/index.js +143 -0
  79. package/core/security/rules/secrets/index.js +133 -0
  80. package/core/security/score/dependency-health.js +53 -0
  81. package/core/security/score/release-health.js +66 -0
  82. package/core/security/score/score.js +102 -0
  83. package/core/security/timeline/timeline.js +76 -0
  84. package/dist/chunks/attributes-2ORR27KA.js +404 -0
  85. package/dist/chunks/attributes-HK7VIOLA.js +1080 -0
  86. package/dist/chunks/attributes-VRHHVNDO.js +1080 -0
  87. package/dist/chunks/chunk-MYKUI364.js +116 -0
  88. package/dist/chunks/chunk-NEVBPD5T.js +116 -0
  89. package/dist/chunks/chunk-Y6HN7HWX.js +116 -0
  90. package/dist/chunks/runtime-entry.js +1 -1
  91. package/dist/chunks/velin-drawer-A7Q7EBOS.js +162 -0
  92. package/dist/chunks/velin-empty-state-3NTUH2RF.js +81 -0
  93. package/dist/chunks/velin-modal-3MV4FYBK.js +231 -0
  94. package/dist/chunks/velin-otp-input-PSK42MM6.js +207 -0
  95. package/dist/chunks/velin-password-strength-TAXMLSED.js +136 -0
  96. package/dist/chunks/velin-sheet-N2VVYXFP.js +157 -0
  97. package/dist/chunks/velin-theme-toggle-J2NHC7IM.js +304 -0
  98. package/dist/llms.txt +4 -4
  99. package/dist/search-index.json +232 -5
  100. package/dist/velin-agent.json +433 -46
  101. package/dist/velinstyle-components.iife.js +3695 -2272
  102. package/dist/velinstyle-components.js +3698 -2271
  103. package/dist/velinstyle-components.min.js +262 -120
  104. package/dist/velinstyle.css +96 -13
  105. package/dist/velinstyle.d.ts +3 -0
  106. package/dist/velinstyle.min.css +1 -1
  107. package/package.json +19 -4
  108. package/packages/velinstyle-cli-core/package.json +11 -0
  109. package/packages/velinstyle-cli-core/src/config.js +84 -0
  110. package/packages/velinstyle-cli-core/src/contract.js +56 -0
  111. package/packages/velinstyle-cli-core/src/event-bus.js +50 -0
  112. package/packages/velinstyle-cli-core/src/index.js +18 -0
  113. package/packages/velinstyle-cli-core/src/lifecycle.js +33 -0
  114. package/packages/velinstyle-cli-core/src/runner.js +129 -0
  115. package/packages/velinstyle-cli-registry/data/commands.json +1216 -0
  116. package/packages/velinstyle-cli-registry/data/layouts.json +33 -0
  117. package/packages/velinstyle-cli-registry/data/widgets.json +35 -0
  118. package/packages/velinstyle-cli-registry/package.json +13 -0
  119. package/packages/velinstyle-cli-registry/src/index.js +88 -0
  120. package/packages/velinstyle-cli-renderer/package.json +8 -0
  121. package/packages/velinstyle-cli-renderer/src/index.js +286 -0
  122. package/packages/velinstyle-cli-theme/package.json +8 -0
  123. package/packages/velinstyle-cli-theme/src/index.js +84 -0
  124. package/packages/velinstyle-cli-ui/package.json +8 -0
  125. package/packages/velinstyle-cli-ui/src/index.js +34 -0
  126. package/packages/velinstyle-motion/README.md +81 -0
  127. package/packages/velinstyle-motion/package.json +37 -0
  128. package/packages/velinstyle-motion/src/ai/mini-prompt.js +119 -0
  129. package/packages/velinstyle-motion/src/ai/provider.js +59 -0
  130. package/packages/velinstyle-motion/src/ai/providers/pixverse-setup.js +402 -0
  131. package/packages/velinstyle-motion/src/ai/providers/pixverse.js +245 -0
  132. package/packages/velinstyle-motion/src/config.js +257 -0
  133. package/packages/velinstyle-motion/src/export/html-clip.js +141 -0
  134. package/packages/velinstyle-motion/src/index.js +304 -0
  135. package/packages/velinstyle-motion/src/jobs/cache.js +30 -0
  136. package/packages/velinstyle-motion/src/jobs/queue.js +69 -0
  137. package/packages/velinstyle-motion/src/jobs/usage.js +53 -0
  138. package/packages/velinstyle-motion/src/local/effects.js +139 -0
  139. package/packages/velinstyle-motion/src/local/engine.js +96 -0
  140. package/packages/velinstyle-motion/src/providers-catalog.js +44 -0
  141. package/packages/velinstyle-motion/src/registry/presets.js +25 -0
  142. package/packages/velinstyle-motion/src/registry/presets.json +85 -0
  143. package/packages/velinstyle-motion/src/ux/cost-gate.js +37 -0
  144. package/packages/velinstyle-motion/src/ux/pixverse-gate.js +153 -0
  145. package/packages/velinstyle-motion/src/ux/wizard.js +171 -0
  146. package/packages/velinstyle-motion/src/validate-image.js +91 -0
  147. package/packages/velinstyle-skills/catalog.json +1 -1
  148. package/packages/velinstyle-skills/registry.json +1 -142
  149. package/packages/velinstyle-skills/skills/velin-motion-reduced-safe/SKILL.md +1 -1
  150. package/packages/velinstyle-skills/skills/velin-motion-reveal-feedback/SKILL.md +1 -1
  151. package/src/components/data-table.css +19 -0
  152. package/src/components/empty-auth.css +33 -0
  153. package/src/components/table.css +16 -6
  154. package/src/tokens/motion.css +7 -0
  155. package/src/utilities/scroll-animation.css +66 -0
  156. package/src/velinstyle.css +1 -0
@@ -240,7 +240,7 @@ function registerBuiltins() {
240
240
  },
241
241
  });
242
242
 
243
- for (const motion of ['velin-reveal', 'velin-fade', 'velin-slide', 'velin-scale', 'velin-parallax', 'velin-hover', 'velin-stagger', 'velin-scroll']) {
243
+ for (const motion of ['velin-motion', 'velin-trigger', 'velin-duration', 'velin-delay', 'velin-ease', 'velin-timeline', 'velin-motion-sequence', 'velin-reveal', 'velin-fade', 'velin-slide', 'velin-scale', 'velin-parallax', 'velin-hover', 'velin-stagger', 'velin-scroll']) {
244
244
  registerAttribute(motion, { enhance() {} });
245
245
  }
246
246
  }
@@ -201,7 +201,7 @@
201
201
  "density": ["default"],
202
202
  "themeSupport": ["light", "dark"],
203
203
  "motion": { "reducedMotionSafe": true },
204
- "examples": ["<velin-modal><h2 slot=\"title\">…</h2></velin-modal>"],
204
+ "examples": ["<velin-modal title=\"Confirm\"></velin-modal>", "<velin-modal><h2 slot=\"title\">…</h2></velin-modal>"],
205
205
  "promptKeywords": ["modal", "dialog overlay", "popup"],
206
206
  "designIntelligence": {
207
207
  "visualWeight": 5,
@@ -491,7 +491,7 @@
491
491
  "density": ["default", "compact"],
492
492
  "themeSupport": ["light", "dark"],
493
493
  "motion": { "reducedMotionSafe": true },
494
- "examples": ["<velin-drawer></velin-drawer>"],
494
+ "examples": ["<velin-drawer title=\"Filters\"></velin-drawer>", "<velin-drawer><span slot=\"title\">Filters</span></velin-drawer>"],
495
495
  "promptKeywords": ["drawer", "side panel", "sidebar overlay"],
496
496
  "designIntelligence": {
497
497
  "visualWeight": 4,
@@ -528,7 +528,7 @@
528
528
  "density": ["default", "compact"],
529
529
  "themeSupport": ["light", "dark"],
530
530
  "motion": { "reducedMotionSafe": true },
531
- "examples": ["<velin-sheet></velin-sheet>"],
531
+ "examples": ["<velin-sheet title=\"Actions\"></velin-sheet>", "<velin-sheet><span slot=\"title\">Actions</span></velin-sheet>"],
532
532
  "promptKeywords": ["sheet", "bottom sheet", "action sheet"],
533
533
  "designIntelligence": {
534
534
  "visualWeight": 4,
@@ -617,6 +617,78 @@
617
617
  "commonMistakes": ["toasts for persistent form errors"],
618
618
  "bestPractices": ["auto-dismiss with pause on focus/hover"]
619
619
  }
620
+ },
621
+ {
622
+ "id": "velin-otp-input",
623
+ "kind": "web-component",
624
+ "tag": "velin-otp-input",
625
+ "category": "forms",
626
+ "subcategory": "otp",
627
+ "purpose": "Segmented one-time-password / PIN digit entry with paste and keyboard support.",
628
+ "family": "forms",
629
+ "maturity": "core",
630
+ "recommendedPages": ["auth", "saas"],
631
+ "recommendedSections": [],
632
+ "compatibleWith": ["css-button", "velin-form-summary", "velin-secure-field"],
633
+ "incompatibleWith": [],
634
+ "accessibility": { "role": "group", "notes": "Per-digit labels; autocomplete one-time-code" },
635
+ "seo": { "impact": "none" },
636
+ "performance": { "cost": "lazy-ok" },
637
+ "variants": [],
638
+ "density": ["default"],
639
+ "themeSupport": ["light", "dark"],
640
+ "motion": { "reducedMotionSafe": true },
641
+ "examples": ["<velin-otp-input length=\"6\"></velin-otp-input>"],
642
+ "promptKeywords": ["otp", "2fa", "pin", "one-time password"],
643
+ "api": { "events": ["velin-change", "velin-complete"], "attributes": ["length", "value", "disabled", "name"] }
644
+ },
645
+ {
646
+ "id": "velin-password-strength",
647
+ "kind": "web-component",
648
+ "tag": "velin-password-strength",
649
+ "category": "forms",
650
+ "subcategory": "password",
651
+ "purpose": "Heuristic password strength meter linked to an input via for= or value.",
652
+ "family": "forms",
653
+ "maturity": "core",
654
+ "recommendedPages": ["auth", "saas"],
655
+ "recommendedSections": [],
656
+ "compatibleWith": ["css-input", "velin-secure-field", "velin-form-summary"],
657
+ "incompatibleWith": [],
658
+ "accessibility": { "role": "progressbar", "notes": "aria-live polite label" },
659
+ "seo": { "impact": "none" },
660
+ "performance": { "cost": "lazy-ok" },
661
+ "variants": [],
662
+ "density": ["default"],
663
+ "themeSupport": ["light", "dark"],
664
+ "motion": { "reducedMotionSafe": true },
665
+ "examples": ["<input id=\"pw\" type=\"password\"><velin-password-strength for=\"pw\"></velin-password-strength>"],
666
+ "promptKeywords": ["password strength", "meter", "signup"],
667
+ "api": { "events": ["velin-strength"], "attributes": ["for", "value", "label"] }
668
+ },
669
+ {
670
+ "id": "velin-empty-state",
671
+ "kind": "web-component",
672
+ "tag": "velin-empty-state",
673
+ "category": "feedback",
674
+ "subcategory": "empty",
675
+ "purpose": "Consistent empty / zero-data surface with illustration, title, description, and actions slots.",
676
+ "family": "feedback",
677
+ "maturity": "core",
678
+ "recommendedPages": ["dashboard", "saas", "shop", "docs"],
679
+ "recommendedSections": [],
680
+ "compatibleWith": ["css-button", "velin-icon"],
681
+ "incompatibleWith": [],
682
+ "accessibility": { "role": "status" },
683
+ "seo": { "impact": "none" },
684
+ "performance": { "cost": "lazy-ok" },
685
+ "variants": [],
686
+ "density": ["default"],
687
+ "themeSupport": ["light", "dark"],
688
+ "motion": { "reducedMotionSafe": true },
689
+ "examples": ["<velin-empty-state heading=\"No items yet\" description=\"Create your first entry.\"><button slot=\"actions\" class=\"velin-btn velin-btn--primary\">Create</button></velin-empty-state>"],
690
+ "promptKeywords": ["empty state", "no results", "zero data"],
691
+ "api": { "attributes": ["heading", "description"], "slots": ["illustration", "title", "description", "actions"] }
620
692
  }
621
693
  ]
622
694
  }
@@ -0,0 +1,38 @@
1
+ import { scanMotionHtml, doctorMotionHtml, collectMotionElements } from './scan.js';
2
+
3
+ /**
4
+ * Aggregate metrics for `velinstyle motion analyze`.
5
+ * @param {string} html
6
+ */
7
+ export function analyzeMotionHtml(html) {
8
+ const { elements } = collectMotionElements(html);
9
+ const scan = scanMotionHtml(html);
10
+ const durations = elements.map((e) => e.duration).filter((d) => d > 0);
11
+ const sum = durations.reduce((a, b) => a + b, 0);
12
+ const avg = durations.length ? Math.round(sum / durations.length) : 0;
13
+ const longest = durations.length ? Math.max(...durations) : 0;
14
+ const doctor = doctorMotionHtml(html);
15
+ const reducedPass = !doctor.findings.some((f) => f.code === 'motion.missing-reduced' || f.code === 'motion.excessive-duration');
16
+
17
+ let layoutShiftRisk = 'LOW';
18
+ if (elements.some((e) => e.preset === 'parallax') || scan.summary.infinite > 2) layoutShiftRisk = 'MEDIUM';
19
+ if (scan.summary.infinite > 5 || longest > 2000) layoutShiftRisk = 'HIGH';
20
+
21
+ return {
22
+ ok: doctor.ok,
23
+ metrics: {
24
+ animations: elements.length || scan.summary.classHits,
25
+ durationMs: sum,
26
+ durationLabel: `${(sum / 1000).toFixed(1)} s`,
27
+ averageMs: avg,
28
+ longestMs: longest,
29
+ reducedMotion: reducedPass ? 'PASS' : 'FAIL',
30
+ infinite: scan.summary.infinite,
31
+ layoutShiftRisk,
32
+ },
33
+ summary: scan.summary,
34
+ findings: doctor.findings,
35
+ };
36
+ }
37
+
38
+ export { doctorMotionHtml, scanMotionHtml };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Emit motion blueprint HTML snippets from registry.
3
+ */
4
+ import { getBlueprint, getPreset, getTimeline, getPolicy } from './registry.js';
5
+
6
+ /**
7
+ * @param {string} kind
8
+ * @returns {{ ok: boolean, html?: string, error?: string, blueprint?: object }}
9
+ */
10
+ export function emitMotionBlueprint(kind) {
11
+ const bp = getBlueprint(kind);
12
+ if (!bp) {
13
+ return {
14
+ ok: false,
15
+ error: `Unknown motion blueprint "${kind}". Use: landing|dashboard|pricing|portfolio|shop|forum|docs|blog|crm|login`,
16
+ };
17
+ }
18
+ const policy = getPolicy(bp.policy || 'safe');
19
+ const timeline = bp.timeline ? getTimeline(bp.timeline) : null;
20
+ const presetBlocks = (bp.presets || [])
21
+ .map((id) => {
22
+ const p = getPreset(id);
23
+ return ` <!-- preset: ${id}${p ? ` — ${p.title}` : ''} -->
24
+ <div velin-motion="${id === 'heroReveal' ? 'fade' : id}" velin-trigger="visible" class="velin-mb-4">
25
+ <p class="velin-text-muted">${p?.title || id}</p>
26
+ </div>`;
27
+ })
28
+ .join('\n');
29
+
30
+ const timelineBlock = timeline
31
+ ? `
32
+ <section velin-timeline="${timeline.id}" class="velin-stack velin-gap-3" aria-label="${timeline.title}">
33
+ ${(timeline.steps || [])
34
+ .map(
35
+ (step, i) =>
36
+ ` <div data-velin-step="${step}" velin-motion="fade" velin-trigger="load" velin-delay="${i * 100}">${step}</div>`,
37
+ )
38
+ .join('\n')}
39
+ </section>`
40
+ : '';
41
+
42
+ const html = `<!-- Velin Motion blueprint: ${bp.id} · policy ${policy?.id || 'safe'} -->
43
+ <!-- ${bp.description} -->
44
+ <div data-velin-motion-policy="${policy?.id || 'safe'}" data-velin-reveal-auto>
45
+ ${presetBlocks}
46
+ ${timelineBlock}
47
+ </div>
48
+ `;
49
+
50
+ return { ok: true, html, blueprint: bp };
51
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Motion Composer — sequence API (Studio-ready).
3
+ */
4
+ import { prefersReducedMotion, markVisible } from './effects.js';
5
+ import { resolvePresetId } from './registry.js';
6
+ import { applyEffects } from './effects.js';
7
+
8
+ /**
9
+ * @typedef {{ type: 'fade'|'slide'|'wait'|'rotate'|'blur'|'preset', preset?: string, ms?: number, value?: string }} MotionStep
10
+ */
11
+
12
+ export function fade(ms = 400) {
13
+ return { type: 'fade', ms };
14
+ }
15
+
16
+ export function slide(ms = 500, value = 'up') {
17
+ return { type: 'slide', ms, value };
18
+ }
19
+
20
+ export function wait(ms = 200) {
21
+ return { type: 'wait', ms };
22
+ }
23
+
24
+ export function rotate(ms = 400) {
25
+ return { type: 'rotate', ms };
26
+ }
27
+
28
+ export function blur(ms = 400) {
29
+ return { type: 'blur', ms };
30
+ }
31
+
32
+ export function preset(id, ms) {
33
+ return { type: 'preset', preset: id, ms };
34
+ }
35
+
36
+ /**
37
+ * @param {MotionStep[]} steps
38
+ * @param {{ root?: HTMLElement, target?: HTMLElement }} [ctx]
39
+ */
40
+ export async function sequence(steps = [], ctx = {}) {
41
+ const target = ctx.target || ctx.root;
42
+ const reduced = prefersReducedMotion();
43
+ const ran = [];
44
+
45
+ for (const step of steps) {
46
+ if (step.type === 'wait') {
47
+ if (!reduced && step.ms) await delay(step.ms);
48
+ ran.push(step);
49
+ continue;
50
+ }
51
+ if (target && typeof target.classList?.add === 'function') {
52
+ if (step.type === 'preset' && step.preset) {
53
+ const p = resolvePresetId(step.preset);
54
+ if (p?.cssClass) target.classList.add(...String(p.cssClass).split(/\s+/));
55
+ applyEffects(target, { [step.preset]: 'true' });
56
+ } else if (step.type === 'fade') {
57
+ applyEffects(target, { fade: 'true' });
58
+ } else if (step.type === 'slide') {
59
+ applyEffects(target, { slide: step.value || 'up' });
60
+ } else if (step.type === 'blur') {
61
+ applyEffects(target, { blur: 'true' });
62
+ } else if (step.type === 'rotate') {
63
+ applyEffects(target, { flip: 'true' });
64
+ }
65
+ markVisible(target);
66
+ }
67
+ if (!reduced && step.ms) await delay(step.ms);
68
+ ran.push(step);
69
+ }
70
+ return { ok: true, ran };
71
+ }
72
+
73
+ function delay(ms) {
74
+ return new Promise((resolve) => {
75
+ if (typeof setTimeout === 'undefined') return resolve();
76
+ setTimeout(resolve, ms);
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Declarative `<section velin-motion-sequence>` — children play in order.
82
+ */
83
+ export function enhanceSequences(root) {
84
+ if (!root?.querySelectorAll) return () => {};
85
+ const nodes = [...root.querySelectorAll('[velin-motion-sequence]')];
86
+ for (const section of nodes) {
87
+ const children = [...section.children];
88
+ let i = 0;
89
+ const stepMs = Number(section.getAttribute('velin-sequence-gap') || 120);
90
+ for (const child of children) {
91
+ child.classList.add('velin-animate-on-scroll', 'velin-animate-on-scroll--fade');
92
+ if (prefersReducedMotion()) {
93
+ markVisible(child);
94
+ } else if (typeof setTimeout !== 'undefined') {
95
+ const delayMs = i * stepMs;
96
+ setTimeout(() => markVisible(child), delayMs);
97
+ } else {
98
+ markVisible(child);
99
+ }
100
+ i += 1;
101
+ }
102
+ }
103
+ return () => {};
104
+ }
105
+
106
+ export const Motion = {
107
+ sequence,
108
+ fade,
109
+ slide,
110
+ wait,
111
+ rotate,
112
+ blur,
113
+ preset,
114
+ };