blocks-dusted 0.1.10 → 0.1.12

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 (249) hide show
  1. package/README.md +35 -0
  2. package/package.json +5 -2
  3. package/src/cli.js +39 -3
  4. package/src/commands/shop.js +59 -0
  5. package/src/commands/warehouse.js +73 -0
  6. package/src/utils/paths.js +13 -13
  7. package/templates/blocks/DD-Accordion/Component.tsx +229 -0
  8. package/templates/blocks/DD-Accordion/README.md +3 -0
  9. package/templates/blocks/DD-Accordion/config.ts +73 -0
  10. package/templates/blocks/DD-Accordion/manifest.json +75 -0
  11. package/templates/blocks/DD-AnimText/Component.tsx +788 -0
  12. package/templates/blocks/DD-AnimText/README.md +3 -0
  13. package/templates/blocks/DD-AnimText/config.ts +295 -0
  14. package/templates/blocks/DD-AnimText/manifest.json +85 -0
  15. package/templates/blocks/DD-AsideNav/Component.tsx +321 -0
  16. package/templates/blocks/DD-AsideNav/config.ts +204 -0
  17. package/templates/blocks/DD-AsideNav/manifest.json +80 -0
  18. package/templates/blocks/DD-Banner/Component.tsx +51 -0
  19. package/templates/blocks/DD-Banner/config.ts +57 -0
  20. package/templates/blocks/DD-Banner/manifest.json +72 -0
  21. package/templates/blocks/DD-BgLightning/Component.tsx +44 -0
  22. package/templates/blocks/DD-BgLightning/README.md +3 -0
  23. package/templates/blocks/DD-BgLightning/config.ts +97 -0
  24. package/templates/blocks/DD-BgLightning/manifest.json +79 -0
  25. package/templates/blocks/DD-BookCall/Component.tsx +535 -535
  26. package/templates/blocks/DD-BookCall/config.ts +238 -238
  27. package/templates/blocks/DD-ButtonPop/Component.tsx +117 -0
  28. package/templates/blocks/DD-ButtonPop/config.ts +105 -0
  29. package/templates/blocks/DD-ButtonPop/manifest.json +88 -0
  30. package/templates/blocks/DD-ButtonPop/svg-icons/Dust2.tsx +167 -0
  31. package/templates/blocks/DD-Card/Component.tsx +251 -0
  32. package/templates/blocks/DD-Card/README.md +4 -0
  33. package/templates/blocks/DD-Card/config.ts +154 -0
  34. package/templates/blocks/DD-Card/manifest.json +82 -0
  35. package/templates/blocks/DD-CardTemplate01/Component.tsx +140 -140
  36. package/templates/blocks/DD-CardTemplate01/config.ts +106 -106
  37. package/templates/blocks/DD-Carousel-A/Component.tsx +249 -249
  38. package/templates/blocks/DD-Carousel-B/Component.tsx +403 -403
  39. package/templates/blocks/DD-Chip/Component.tsx +250 -0
  40. package/templates/blocks/DD-Chip/EXAMPLES.md +313 -0
  41. package/templates/blocks/DD-Chip/README.md +202 -0
  42. package/templates/blocks/DD-Chip/config.ts +369 -0
  43. package/templates/blocks/DD-Chip/manifest.json +74 -0
  44. package/templates/blocks/DD-ComparisonTable/Component.tsx +256 -256
  45. package/templates/blocks/DD-Contact/Component.tsx +435 -434
  46. package/templates/blocks/DD-Contact/config.ts +22 -22
  47. package/templates/blocks/DD-Counter/Component.tsx +190 -0
  48. package/templates/blocks/DD-Counter/README.md +4 -0
  49. package/templates/blocks/DD-Counter/config.ts +291 -0
  50. package/templates/blocks/DD-Counter/manifest.json +74 -0
  51. package/templates/blocks/DD-CustomCSS/Component.tsx +8 -0
  52. package/templates/blocks/DD-CustomCSS/README.md +4 -0
  53. package/templates/blocks/DD-CustomCSS/addToLayout.md +5 -0
  54. package/templates/blocks/DD-CustomCSS/config.ts +22 -0
  55. package/templates/blocks/DD-CustomCSS/manifest.json +72 -0
  56. package/templates/blocks/DD-CustomCSS/renderCustomCSS.md +7 -0
  57. package/templates/blocks/DD-FeatCat/Component.tsx +302 -302
  58. package/templates/blocks/DD-FeatCat/config.ts +201 -201
  59. package/templates/blocks/DD-FeatStrip/Component.tsx +585 -585
  60. package/templates/blocks/DD-FeatStrip/config.ts +134 -134
  61. package/templates/blocks/DD-FluidBtn/ButtonsEyeCatching.tsx +628 -0
  62. package/templates/blocks/DD-FluidBtn/Component.tsx +43 -0
  63. package/templates/blocks/DD-FluidBtn/README.md +6 -0
  64. package/templates/blocks/DD-FluidBtn/config.ts +102 -0
  65. package/templates/blocks/DD-FluidBtn/manifest.json +86 -0
  66. package/templates/blocks/DD-GooeyInfo/Component.tsx +149 -0
  67. package/templates/blocks/DD-GooeyInfo/config.ts +135 -0
  68. package/templates/blocks/DD-GooeyInfo/manifest.json +72 -0
  69. package/templates/blocks/DD-Hero/Component.tsx +297 -297
  70. package/templates/blocks/DD-Hero/config.ts +267 -267
  71. package/templates/blocks/DD-HorizontalScroll/Component.tsx +936 -936
  72. package/templates/blocks/DD-HorizontalScroll/config.ts +231 -231
  73. package/templates/blocks/DD-Icon/Component.tsx +287 -0
  74. package/templates/blocks/DD-Icon/README.md +4 -0
  75. package/templates/blocks/DD-Icon/config.ts +258 -0
  76. package/templates/blocks/DD-Icon/hooks/revalidateBlockIds.ts +66 -0
  77. package/templates/blocks/DD-Icon/manifest.json +82 -0
  78. package/templates/blocks/DD-IconButton/Component.tsx +455 -0
  79. package/templates/blocks/DD-IconButton/README.md +326 -0
  80. package/templates/blocks/DD-IconButton/config.ts +239 -0
  81. package/templates/blocks/DD-IconButton/manifest.json +85 -0
  82. package/templates/blocks/DD-IdTag/Component.tsx +21 -0
  83. package/templates/blocks/DD-IdTag/README.md +4 -0
  84. package/templates/blocks/DD-IdTag/config.ts +41 -0
  85. package/templates/blocks/DD-IdTag/manifest.json +72 -0
  86. package/templates/blocks/DD-Iframe/Component.tsx +45 -0
  87. package/templates/blocks/DD-Iframe/README.md +4 -0
  88. package/templates/blocks/DD-Iframe/config.ts +47 -0
  89. package/templates/blocks/DD-Iframe/manifest.json +72 -0
  90. package/templates/blocks/DD-IframeMedia/Component.tsx +133 -0
  91. package/templates/blocks/DD-IframeMedia/README.md +4 -0
  92. package/templates/blocks/DD-IframeMedia/config.ts +79 -0
  93. package/templates/blocks/DD-IframeMedia/manifest.json +72 -0
  94. package/templates/blocks/DD-LineAnim/Component.tsx +36 -0
  95. package/templates/blocks/DD-LineAnim/README.md +4 -0
  96. package/templates/blocks/DD-LineAnim/config.ts +90 -0
  97. package/templates/blocks/DD-LineAnim/manifest.json +80 -0
  98. package/templates/blocks/DD-LinkGrid/Component.tsx +119 -0
  99. package/templates/blocks/DD-LinkGrid/README.md +4 -0
  100. package/templates/blocks/DD-LinkGrid/config.ts +51 -0
  101. package/templates/blocks/DD-LinkGrid/manifest.json +74 -0
  102. package/templates/blocks/DD-LogoMarq/Component.tsx +132 -0
  103. package/templates/blocks/DD-LogoMarq/README.md +4 -0
  104. package/templates/blocks/DD-LogoMarq/config.ts +264 -0
  105. package/templates/blocks/DD-LogoMarq/manifest.json +82 -0
  106. package/templates/blocks/DD-Lottie/Component.tsx +459 -0
  107. package/templates/blocks/DD-Lottie/README.md +4 -0
  108. package/templates/blocks/DD-Lottie/config.ts +379 -0
  109. package/templates/blocks/DD-Lottie/index.tsx +28 -0
  110. package/templates/blocks/DD-Lottie/manifest.json +83 -0
  111. package/templates/blocks/DD-MagicBento/Component.tsx +777 -0
  112. package/templates/blocks/DD-MagicBento/README.md +4 -0
  113. package/templates/blocks/DD-MagicBento/config.ts +264 -0
  114. package/templates/blocks/DD-MagicBento/manifest.json +74 -0
  115. package/templates/blocks/DD-MasonaryMedia/Component.tsx +545 -545
  116. package/templates/blocks/DD-MasonaryMedia/config.ts +2 -2
  117. package/templates/blocks/DD-MasonaryMedia/vendor.d.ts +2 -2
  118. package/templates/blocks/DD-Masonry/Component.tsx +645 -0
  119. package/templates/blocks/DD-Masonry/README.md +4 -0
  120. package/templates/blocks/DD-Masonry/config.ts +475 -0
  121. package/templates/blocks/DD-Masonry/manifest.json +82 -0
  122. package/templates/blocks/DD-Pricing/Component.tsx +2 -5
  123. package/templates/blocks/DD-Process/Component.tsx +2 -4
  124. package/templates/blocks/DD-Process/config.ts +150 -150
  125. package/templates/blocks/DD-Progress/Component.tsx +156 -0
  126. package/templates/blocks/DD-Progress/README.md +4 -0
  127. package/templates/blocks/DD-Progress/config.ts +175 -0
  128. package/templates/blocks/DD-Progress/manifest.json +74 -0
  129. package/templates/blocks/DD-ProjHeader/Component.tsx +91 -0
  130. package/templates/blocks/DD-ProjHeader/README.md +4 -0
  131. package/templates/blocks/DD-ProjHeader/config.ts +96 -0
  132. package/templates/blocks/DD-ProjHeader/manifest.json +72 -0
  133. package/templates/blocks/DD-ProjSlider/Component.tsx +123 -0
  134. package/templates/blocks/DD-ProjSlider/README.md +4 -0
  135. package/templates/blocks/DD-ProjSlider/config.ts +64 -0
  136. package/templates/blocks/DD-ProjSlider/manifest.json +72 -0
  137. package/templates/blocks/DD-ScrollText/Component.tsx +114 -0
  138. package/templates/blocks/DD-ScrollText/README.md +4 -0
  139. package/templates/blocks/DD-ScrollText/config.ts +58 -0
  140. package/templates/blocks/DD-ScrollText/manifest.json +72 -0
  141. package/templates/blocks/DD-Section/Component.tsx +266 -266
  142. package/templates/blocks/DD-Separator/Component.tsx +66 -0
  143. package/templates/blocks/DD-Separator/README.md +4 -0
  144. package/templates/blocks/DD-Separator/config.ts +58 -0
  145. package/templates/blocks/DD-Separator/manifest.json +72 -0
  146. package/templates/blocks/DD-Services/Component.tsx +176 -176
  147. package/templates/blocks/DD-Services/config.ts +149 -149
  148. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +307 -307
  149. package/templates/blocks/DD-Slider-A/Component.tsx +1 -1
  150. package/templates/blocks/DD-StackCards/Component.tsx +1 -1
  151. package/templates/blocks/DD-StackCards/config.ts +399 -399
  152. package/templates/blocks/DD-Team/Component.tsx +247 -247
  153. package/templates/blocks/DD-Team/config.ts +173 -173
  154. package/templates/blocks/DD-TeamCards/Component.tsx +251 -0
  155. package/templates/blocks/DD-TeamCards/README.md +4 -0
  156. package/templates/blocks/DD-TeamCards/config.ts +302 -0
  157. package/templates/blocks/DD-TeamCards/manifest.json +74 -0
  158. package/templates/blocks/DD-TechStack/Component.tsx +174 -174
  159. package/templates/blocks/DD-TechStack/config.ts +153 -153
  160. package/templates/blocks/DD-TestMarq/Component.tsx +132 -0
  161. package/templates/blocks/DD-TestMarq/README.md +4 -0
  162. package/templates/blocks/DD-TestMarq/RowLabel.tsx +9 -0
  163. package/templates/blocks/DD-TestMarq/config.ts +88 -0
  164. package/templates/blocks/DD-TestMarq/manifest.json +72 -0
  165. package/templates/blocks/DD-Testim/Component.tsx +247 -0
  166. package/templates/blocks/DD-Testim/README.md +4 -0
  167. package/templates/blocks/DD-Testim/config.ts +101 -0
  168. package/templates/blocks/DD-Testim/manifest.json +75 -0
  169. package/templates/blocks/DD-Testim2/Component.tsx +256 -0
  170. package/templates/blocks/DD-Testim2/README.md +4 -0
  171. package/templates/blocks/DD-Testim2/config.ts +100 -0
  172. package/templates/blocks/DD-Testim2/manifest.json +74 -0
  173. package/templates/blocks/DD-Testimonials/Component.tsx +139 -147
  174. package/templates/blocks/DD-Testimonials/config.ts +120 -120
  175. package/templates/blocks/DD-TextMarq/Component.tsx +157 -0
  176. package/templates/blocks/DD-TextMarq/README.md +4 -0
  177. package/templates/blocks/DD-TextMarq/config.ts +237 -0
  178. package/templates/blocks/DD-TextMarq/manifest.json +82 -0
  179. package/templates/blocks/DD-Thanks/Component.tsx +501 -0
  180. package/templates/blocks/DD-Thanks/README.md +4 -0
  181. package/templates/blocks/DD-Thanks/config.ts +224 -0
  182. package/templates/blocks/DD-Thanks/manifest.json +72 -0
  183. package/templates/blocks/DD-VertMarq/Component.tsx +154 -0
  184. package/templates/blocks/DD-VertMarq/README.md +4 -0
  185. package/templates/blocks/DD-VertMarq/config.ts +236 -0
  186. package/templates/blocks/DD-VertMarq/dist/index.css +6 -0
  187. package/templates/blocks/DD-VertMarq/dist/index.min.css +1 -0
  188. package/templates/blocks/DD-VertMarq/manifest.json +74 -0
  189. package/templates/blocks/DD-Work/Component.tsx +318 -315
  190. package/templates/blocks/DD-Work/config.ts +165 -165
  191. package/templates/blocks/DD-Work-B/Component.tsx +294 -294
  192. package/templates/blocks/DDHG-CTASection2/Component.tsx +185 -0
  193. package/templates/blocks/DDHG-CTASection2/config.ts +140 -0
  194. package/templates/blocks/DDHG-CTASection2/manifest.json +45 -0
  195. package/templates/blocks/DDHG-HighlightArc/Component.tsx +243 -0
  196. package/templates/blocks/DDHG-HighlightArc/config.ts +85 -0
  197. package/templates/blocks/DDHG-HighlightArc/manifest.json +46 -0
  198. package/templates/blocks/DDHG-LogoMarquee/Component.tsx +143 -0
  199. package/templates/blocks/DDHG-LogoMarquee/config.ts +154 -0
  200. package/templates/blocks/DDHG-LogoMarquee/manifest.json +39 -0
  201. package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +227 -0
  202. package/templates/blocks/DDHG-NavCodeGrid/config.ts +64 -0
  203. package/templates/blocks/DDHG-NavCodeGrid/manifest.json +45 -0
  204. package/templates/blocks/DDHG-ProcessSec/Component.tsx +574 -0
  205. package/templates/blocks/DDHG-ProcessSec/config.ts +170 -0
  206. package/templates/blocks/DDHG-ProcessSec/manifest.json +56 -0
  207. package/templates/blocks/DDHG-ServiceDetails/Component.tsx +164 -0
  208. package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +390 -0
  209. package/templates/blocks/DDHG-ServiceDetails/config.ts +77 -0
  210. package/templates/blocks/DDHG-ServiceDetails/manifest.json +50 -0
  211. package/templates/blocks/DDHG-ServiceHero/Component.tsx +234 -0
  212. package/templates/blocks/DDHG-ServiceHero/config.ts +49 -0
  213. package/templates/blocks/DDHG-ServiceHero/manifest.json +26 -0
  214. package/templates/blocks/DDHG-ServiceOverview/Component.tsx +277 -0
  215. package/templates/blocks/DDHG-ServiceOverview/config.ts +64 -0
  216. package/templates/blocks/DDHG-ServiceOverview/manifest.json +44 -0
  217. package/templates/blocks/DDHG-StatsFAQ/Component.tsx +389 -0
  218. package/templates/blocks/DDHG-StatsFAQ/config.ts +204 -0
  219. package/templates/blocks/DDHG-StatsFAQ/manifest.json +45 -0
  220. package/templates/blocks/DDHG-TeamCards/Component.tsx +169 -0
  221. package/templates/blocks/DDHG-TeamCards/config.ts +48 -0
  222. package/templates/blocks/DDHG-TeamCards/manifest.json +29 -0
  223. package/templates/shared/src/components/BgLightning/index.tsx +242 -0
  224. package/templates/shared/src/components/ui/ShareButton/index.tsx +80 -0
  225. package/templates/shared/src/components/ui/anims/FadeOnScroll.tsx +48 -0
  226. package/templates/shared/src/components/ui/anims/FadeUpOnInView.tsx +63 -0
  227. package/templates/shared/src/components/ui/anims/GlareHover.tsx +111 -0
  228. package/templates/shared/src/components/ui/anims/LineAnims.tsx +81 -0
  229. package/templates/shared/src/components/ui/anims/TitleAnims01.tsx +54 -0
  230. package/templates/shared/src/components/ui/anims/animation-container.tsx +29 -0
  231. package/templates/shared/src/components/ui/anims/blur-in.tsx +26 -0
  232. package/templates/shared/src/components/ui/anims/counter.tsx +53 -0
  233. package/templates/shared/src/components/ui/anims/fade.tsx +83 -0
  234. package/templates/shared/src/components/ui/anims/gradual-spacing.tsx +39 -0
  235. package/templates/shared/src/components/ui/anims/pull-up.tsx +93 -0
  236. package/templates/shared/src/components/ui/anims/reveal-text.tsx +76 -0
  237. package/templates/shared/src/components/ui/anims/rotate-words.tsx +43 -0
  238. package/templates/shared/src/components/ui/anims/shiny-text.tsx +58 -0
  239. package/templates/shared/src/components/ui/anims/shuffle-text.tsx +85 -0
  240. package/templates/shared/src/components/ui/anims/split-text.tsx +211 -0
  241. package/templates/shared/src/components/ui/anims/staggered-fade.tsx +133 -0
  242. package/templates/shared/src/components/ui/anims/text-scroll.tsx +111 -0
  243. package/templates/shared/src/components/ui/anims/typing-effect.tsx +112 -0
  244. package/templates/shared/src/components/ui/button-dusted-fluid/index.tsx +1521 -0
  245. package/templates/shared/src/components/ui/separator.tsx +85 -0
  246. package/templates/shared/src/hooks/useBodyScrollLock.ts +97 -0
  247. package/templates/shared/src/hooks/useClickOutside.ts +28 -0
  248. package/templates/shared/src/utilities/renderCustomCSS.ts +5 -0
  249. package/templates/shared/src/utilities/smoothScroll.ts +65 -0
@@ -0,0 +1,459 @@
1
+ 'use client'
2
+
3
+ import React, { useEffect, useRef, useState, Suspense } from 'react'
4
+ import { cn } from '@/utilities/ui'
5
+ import { motion, useInView } from 'framer-motion'
6
+ import type { Media } from '@/payload-types'
7
+ import dynamic from 'next/dynamic'
8
+
9
+ const DotLottieReact = dynamic(
10
+ () => import('@lottiefiles/dotlottie-react').then((m) => m.DotLottieReact),
11
+ { ssr: false, loading: () => null }
12
+ )
13
+
14
+ type DotLottieInstance = any
15
+
16
+ export interface LottieBlockProps {
17
+ blockName?: string
18
+ lottieFile: Media | string
19
+ format?: 'json' | 'lottie'
20
+ autoplay?: boolean
21
+ loop?: boolean
22
+ controls?: boolean
23
+ hover?: boolean
24
+ speed?: number
25
+ direction?: '1' | '-1'
26
+ width?: string
27
+ height?: string
28
+ objectFit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'
29
+ playOnScroll?: boolean
30
+ scrollBehavior?: 'once' | 'always' | 'sync'
31
+ scrollStart?: number
32
+ scrollEnd?: number
33
+ containerClass?: string
34
+ customStyle?: React.CSSProperties
35
+ customCSS?: string
36
+ alt?: string
37
+ title?: string
38
+ reducedMotion?: boolean
39
+ }
40
+
41
+ const lottieBaseClass = cn(
42
+ 'lottie-block group relative inline-block overflow-hidden',
43
+ '[&_.lottie-animation]:block [&_.lottie-animation]:h-full [&_.lottie-animation]:w-full',
44
+ '[&_.lottie-loading]:flex [&_.lottie-loading]:min-h-[100px] [&_.lottie-loading]:min-w-[100px] [&_.lottie-loading]:items-center [&_.lottie-loading]:justify-center [&_.lottie-loading]:rounded [&_.lottie-loading]:!bg-transparent [&_.lottie-loading]:text-sm [&_.lottie-loading]:text-[#6c757d]',
45
+ '[&_.lottie-placeholder]:flex [&_.lottie-placeholder]:min-h-[100px] [&_.lottie-placeholder]:min-w-[100px] [&_.lottie-placeholder]:items-center [&_.lottie-placeholder]:justify-center [&_.lottie-placeholder]:rounded [&_.lottie-placeholder]:!bg-transparent [&_.lottie-placeholder]:text-sm [&_.lottie-placeholder]:text-[#6c757d] dark:[&_.lottie-placeholder]:text-[#adb5bd]',
46
+ '[&_.lottie-controls]:absolute [&_.lottie-controls]:bottom-2.5 [&_.lottie-controls]:left-1/2 [&_.lottie-controls]:flex [&_.lottie-controls]:-translate-x-1/2 [&_.lottie-controls]:gap-2 [&_.lottie-controls]:rounded-[20px] [&_.lottie-controls]:bg-black/70 [&_.lottie-controls]:px-3 [&_.lottie-controls]:py-2 [&_.lottie-controls]:opacity-0 [&_.lottie-controls]:backdrop-blur-sm [&_.lottie-controls]:transition-opacity [&_.lottie-controls]:duration-300 group-hover:[&_.lottie-controls]:opacity-100 max-md:[&_.lottie-controls]:opacity-100',
47
+ '[&_.lottie-control-btn]:cursor-pointer [&_.lottie-control-btn]:rounded [&_.lottie-control-btn]:border-0 [&_.lottie-control-btn]:bg-transparent [&_.lottie-control-btn]:px-2 [&_.lottie-control-btn]:py-1 [&_.lottie-control-btn]:text-base [&_.lottie-control-btn]:text-white [&_.lottie-control-btn]:transition-colors [&_.lottie-control-btn]:duration-200 hover:[&_.lottie-control-btn]:bg-white/20 focus:[&_.lottie-control-btn]:outline focus:[&_.lottie-control-btn]:outline-2 focus:[&_.lottie-control-btn]:outline-offset-2 focus:[&_.lottie-control-btn]:outline-[#007bff]',
48
+ '[&_.lottie-reduced-motion-notice]:absolute [&_.lottie-reduced-motion-notice]:right-2.5 [&_.lottie-reduced-motion-notice]:top-2.5 [&_.lottie-reduced-motion-notice]:rounded [&_.lottie-reduced-motion-notice]:bg-black/80 [&_.lottie-reduced-motion-notice]:px-2 [&_.lottie-reduced-motion-notice]:py-1 [&_.lottie-reduced-motion-notice]:text-xs [&_.lottie-reduced-motion-notice]:text-white',
49
+ '[&_.sr-only]:absolute [&_.sr-only]:m-[-1px] [&_.sr-only]:h-px [&_.sr-only]:w-px [&_.sr-only]:overflow-hidden [&_.sr-only]:whitespace-nowrap [&_.sr-only]:border-0 [&_.sr-only]:p-0 [&_.sr-only]:[clip:rect(0,0,0,0)]',
50
+ 'motion-reduce:[&_.lottie-animation]:![animation-play-state:paused]'
51
+ )
52
+
53
+ const getPresetClass = (containerClass?: string) =>
54
+ cn(
55
+ containerClass?.includes('lottie-block--small') && 'h-[100px] w-[100px]',
56
+ containerClass?.includes('lottie-block--medium') && 'h-[200px] w-[200px]',
57
+ containerClass?.includes('lottie-block--large') && 'h-[400px] w-[400px]',
58
+ containerClass?.includes('lottie-block--full-width') && 'h-auto w-full',
59
+ containerClass?.includes('lottie-block--square') && 'aspect-square',
60
+ containerClass?.includes('lottie-block--rounded') && 'rounded-lg',
61
+ containerClass?.includes('lottie-block--circular') && 'overflow-hidden rounded-full',
62
+ containerClass?.includes('lottie-block--shadow') &&
63
+ 'shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-1px_rgba(0,0,0,0.06)]',
64
+ containerClass?.includes('lottie-block--border') && 'border-2 border-[#e5e7eb]'
65
+ )
66
+
67
+ const LottieBlockComponent: React.FC<LottieBlockProps> = ({
68
+ blockName,
69
+ lottieFile,
70
+ format,
71
+ autoplay = true,
72
+ loop = true,
73
+ controls = false,
74
+ hover = false,
75
+ speed = 1,
76
+ direction = '1',
77
+ width,
78
+ height,
79
+ objectFit = 'contain',
80
+ playOnScroll = false,
81
+ scrollBehavior = 'once',
82
+ scrollStart = 0,
83
+ scrollEnd = 100,
84
+ containerClass,
85
+ customStyle,
86
+ customCSS,
87
+ alt,
88
+ title,
89
+ reducedMotion = true
90
+ }) => {
91
+ const containerRef = useRef<HTMLDivElement>(null)
92
+ const lottieRef = useRef<HTMLDivElement>(null)
93
+
94
+ const lottieInstanceRef = useRef<any>(null)
95
+ const dotLottieRef = useRef<DotLottieInstance | null>(null)
96
+
97
+ const isLoadingRef = useRef(false)
98
+ const loadedFileRef = useRef<string | null>(null)
99
+
100
+ const [hasPlayed, setHasPlayed] = useState(false)
101
+ const [isClient, setIsClient] = useState(false)
102
+ const [animationLoaded, setAnimationLoaded] = useState(false)
103
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState(false)
104
+
105
+ const inView = useInView(containerRef, { once: scrollBehavior === 'once' })
106
+
107
+ const scrollHeight = 6000
108
+
109
+ useEffect(() => {
110
+ setIsClient(true)
111
+
112
+ if (typeof window === 'undefined') return
113
+
114
+ const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)')
115
+
116
+ const updateReducedMotion = () => {
117
+ setPrefersReducedMotion(mediaQuery.matches)
118
+ }
119
+
120
+ updateReducedMotion()
121
+ mediaQuery.addEventListener?.('change', updateReducedMotion)
122
+
123
+ return () => {
124
+ mediaQuery.removeEventListener?.('change', updateReducedMotion)
125
+ }
126
+ }, [])
127
+
128
+ const fileUrl = React.useMemo(() => {
129
+ if (typeof lottieFile === 'string') return lottieFile
130
+
131
+ if (lottieFile && typeof lottieFile === 'object') {
132
+ if ('url' in lottieFile && lottieFile.url) {
133
+ return lottieFile.url as string
134
+ }
135
+
136
+ if ('filename' in lottieFile && lottieFile.filename) {
137
+ return `/media/${lottieFile.filename}`
138
+ }
139
+ }
140
+
141
+ return null
142
+ }, [lottieFile])
143
+
144
+ const resolvedFormat = React.useMemo<'json' | 'lottie'>(() => {
145
+ if (format === 'lottie') return 'lottie'
146
+ if (format === 'json') return 'json'
147
+
148
+ const lowerUrl = fileUrl?.toLowerCase() || ''
149
+
150
+ if (lowerUrl.endsWith('.lottie')) return 'lottie'
151
+ if (lowerUrl.includes('.lottie?')) return 'lottie'
152
+
153
+ return 'json'
154
+ }, [format, fileUrl])
155
+
156
+ useEffect(() => {
157
+ if (resolvedFormat !== 'json') return
158
+ if (!isClient || !lottieRef.current || !fileUrl || isLoadingRef.current) return
159
+
160
+ if (loadedFileRef.current === fileUrl && lottieInstanceRef.current) return
161
+
162
+ isLoadingRef.current = true
163
+
164
+ const loadLottie = async () => {
165
+ try {
166
+ const lottie = await import('lottie-web')
167
+
168
+ if (lottieInstanceRef.current) {
169
+ lottieInstanceRef.current.destroy()
170
+ lottieInstanceRef.current = null
171
+ }
172
+
173
+ dotLottieRef.current = null
174
+
175
+ const instance = lottie.default.loadAnimation({
176
+ container: lottieRef.current!,
177
+ renderer: 'svg',
178
+ loop: loop && !prefersReducedMotion,
179
+ autoplay: autoplay && !playOnScroll && !hover && !prefersReducedMotion,
180
+ path: fileUrl,
181
+ rendererSettings: {
182
+ preserveAspectRatio: `xMidYMid ${objectFit === 'contain' ? 'meet' : 'slice'}`
183
+ }
184
+ })
185
+
186
+ instance.setSpeed(speed)
187
+ instance.setDirection(parseInt(direction) as 1 | -1)
188
+
189
+ lottieInstanceRef.current = instance
190
+ loadedFileRef.current = fileUrl
191
+ isLoadingRef.current = false
192
+ setAnimationLoaded(true)
193
+
194
+ if (reducedMotion && prefersReducedMotion) {
195
+ instance.pause()
196
+ instance.goToAndStop(0, true)
197
+ }
198
+ } catch (error) {
199
+ console.error('LottieBlock: Failed to load Lottie animation:', error)
200
+ isLoadingRef.current = false
201
+ setAnimationLoaded(false)
202
+ }
203
+ }
204
+
205
+ void loadLottie()
206
+
207
+ return () => {
208
+ if (lottieInstanceRef.current) {
209
+ lottieInstanceRef.current.destroy()
210
+ lottieInstanceRef.current = null
211
+ }
212
+
213
+ loadedFileRef.current = null
214
+ isLoadingRef.current = false
215
+ setAnimationLoaded(false)
216
+ }
217
+ }, [
218
+ isClient,
219
+ fileUrl,
220
+ resolvedFormat,
221
+ loop,
222
+ autoplay,
223
+ playOnScroll,
224
+ hover,
225
+ prefersReducedMotion,
226
+ objectFit,
227
+ speed,
228
+ direction,
229
+ reducedMotion
230
+ ])
231
+
232
+ useEffect(() => {
233
+ if (!playOnScroll || prefersReducedMotion) return
234
+
235
+ if (scrollBehavior === 'sync') {
236
+ const handleScroll = () => {
237
+ const el = containerRef.current
238
+ if (!el) return
239
+
240
+ const elementTopOffset = el.offsetTop
241
+ const scrolled = window.pageYOffset - elementTopOffset
242
+ const scrollProgress = Math.max(0, Math.min(1, scrolled / scrollHeight))
243
+
244
+ const startT = Math.min(scrollStart, scrollEnd) / 100
245
+ const endT = Math.max(scrollStart, scrollEnd) / 100
246
+ const t = startT + scrollProgress * (endT - startT)
247
+
248
+ if (resolvedFormat === 'json') {
249
+ const inst = lottieInstanceRef.current
250
+ if (!inst) return
251
+
252
+ const totalFrames = typeof inst.totalFrames === 'number' ? inst.totalFrames : 0
253
+ if (totalFrames <= 0) return
254
+
255
+ const currentFrame = Math.round(t * (totalFrames - 1))
256
+ inst.goToAndStop(currentFrame, true)
257
+ } else {
258
+ const dot = dotLottieRef.current
259
+ if (!dot) return
260
+
261
+ const totalFrames =
262
+ (typeof dot.totalFrames === 'number' && dot.totalFrames) ||
263
+ (typeof dot.totalFrames === 'function' && dot.totalFrames()) ||
264
+ (typeof dot.getTotalFrames === 'function' && dot.getTotalFrames()) ||
265
+ 100
266
+
267
+ const currentFrame = Math.round(t * (totalFrames - 1))
268
+ dot.setFrame?.(currentFrame)
269
+ }
270
+ }
271
+
272
+ window.addEventListener('scroll', handleScroll, { passive: true })
273
+ handleScroll()
274
+
275
+ return () => window.removeEventListener('scroll', handleScroll)
276
+ }
277
+
278
+ if (inView && (!hasPlayed || scrollBehavior === 'always')) {
279
+ if (resolvedFormat === 'json') {
280
+ lottieInstanceRef.current?.play?.()
281
+ } else {
282
+ dotLottieRef.current?.play?.()
283
+ }
284
+
285
+ setHasPlayed(true)
286
+ }
287
+ }, [
288
+ playOnScroll,
289
+ inView,
290
+ hasPlayed,
291
+ scrollBehavior,
292
+ scrollStart,
293
+ scrollEnd,
294
+ prefersReducedMotion,
295
+ animationLoaded,
296
+ resolvedFormat
297
+ ])
298
+
299
+ const handleMouseEnter = () => {
300
+ if (!hover || prefersReducedMotion) return
301
+
302
+ if (resolvedFormat === 'json') {
303
+ lottieInstanceRef.current?.play?.()
304
+ } else {
305
+ dotLottieRef.current?.play?.()
306
+ }
307
+ }
308
+
309
+ const handleMouseLeave = () => {
310
+ if (!hover || prefersReducedMotion) return
311
+
312
+ if (resolvedFormat === 'json') {
313
+ lottieInstanceRef.current?.pause?.()
314
+ } else {
315
+ dotLottieRef.current?.pause?.()
316
+ }
317
+ }
318
+
319
+ const handlePlay = () => {
320
+ if (prefersReducedMotion) return
321
+
322
+ if (resolvedFormat === 'json') {
323
+ lottieInstanceRef.current?.play?.()
324
+ } else {
325
+ dotLottieRef.current?.play?.()
326
+ }
327
+ }
328
+
329
+ const handlePause = () => {
330
+ if (resolvedFormat === 'json') {
331
+ lottieInstanceRef.current?.pause?.()
332
+ } else {
333
+ dotLottieRef.current?.pause?.()
334
+ }
335
+ }
336
+
337
+ const handleStop = () => {
338
+ if (resolvedFormat === 'json') {
339
+ lottieInstanceRef.current?.stop?.()
340
+ } else {
341
+ dotLottieRef.current?.pause?.()
342
+ dotLottieRef.current?.setFrame?.(0)
343
+ }
344
+ }
345
+
346
+ const containerStyles: React.CSSProperties = {
347
+ width: width || 'auto',
348
+ height: height || 'auto',
349
+ display: 'inline-block',
350
+ paddingBottom: playOnScroll && scrollBehavior === 'sync' ? `${scrollHeight}px` : undefined,
351
+ ...customStyle
352
+ }
353
+
354
+ const finalContainerClassName = cn(
355
+ lottieBaseClass,
356
+ getPresetClass(containerClass),
357
+ containerClass
358
+ )
359
+
360
+ if (!isClient) {
361
+ return (
362
+ <Suspense fallback={'Loading animation...'}>
363
+ <div
364
+ className={cn(finalContainerClassName, 'lottie-loading')}
365
+ style={containerStyles}
366
+ title={title}
367
+ >
368
+ <div className="lottie-placeholder">Loading animation...</div>
369
+ </div>
370
+ </Suspense>
371
+ )
372
+ }
373
+
374
+ return (
375
+ <Suspense fallback={'Loading animation...'}>
376
+ <motion.div
377
+ ref={containerRef}
378
+ initial={{ filter: 'blur(4px)', opacity: 0 }}
379
+ animate={{ filter: 'none', opacity: 1 }}
380
+ transition={{ duration: 0.3, delay: 0, ease: 'easeInOut' }}
381
+ className={finalContainerClassName}
382
+ style={containerStyles}
383
+ onMouseEnter={handleMouseEnter}
384
+ onMouseLeave={handleMouseLeave}
385
+ role="img"
386
+ aria-label={alt || 'Lottie animation'}
387
+ title={title}
388
+ data-block-name={blockName}
389
+ data-lottie-format={resolvedFormat}
390
+ >
391
+ {customCSS ? <style dangerouslySetInnerHTML={{ __html: customCSS }} /> : null}
392
+
393
+ {resolvedFormat === 'json' ? (
394
+ <div
395
+ ref={lottieRef}
396
+ className="lottie-animation"
397
+ style={{ width: '100%', height: '100%', objectFit }}
398
+ />
399
+ ) : inView ? (
400
+ <DotLottieReact
401
+ src={fileUrl || ''}
402
+ autoplay={
403
+ autoplay && !playOnScroll && !hover && !(reducedMotion && prefersReducedMotion)
404
+ }
405
+ loop={loop && !(reducedMotion && prefersReducedMotion)}
406
+ speed={speed}
407
+ dotLottieRefCallback={(inst) => {
408
+ dotLottieRef.current = inst
409
+ }}
410
+ onLoad={() => {
411
+ setAnimationLoaded(true)
412
+ }}
413
+ style={{ width: '100%', height: '100%' }}
414
+ />
415
+ ) : (
416
+ <div style={{ width: '100%', height: '100%' }} aria-hidden="true" />
417
+ )}
418
+
419
+ {controls && !prefersReducedMotion && (
420
+ <div className="lottie-controls">
421
+ <button
422
+ onClick={handlePlay}
423
+ className="lottie-control-btn lottie-play"
424
+ aria-label="Play animation"
425
+ type="button"
426
+ >
427
+ ▶️
428
+ </button>
429
+ <button
430
+ onClick={handlePause}
431
+ className="lottie-control-btn lottie-pause"
432
+ aria-label="Pause animation"
433
+ type="button"
434
+ >
435
+ ⏸️
436
+ </button>
437
+ <button
438
+ onClick={handleStop}
439
+ className="lottie-control-btn lottie-stop"
440
+ aria-label="Stop animation"
441
+ type="button"
442
+ >
443
+ ⏹️
444
+ </button>
445
+ </div>
446
+ )}
447
+
448
+ {reducedMotion && prefersReducedMotion && (
449
+ <div className="lottie-reduced-motion-notice sr-only">
450
+ Animation paused due to reduced motion preference
451
+ </div>
452
+ )}
453
+ </motion.div>
454
+ </Suspense>
455
+ )
456
+ }
457
+
458
+ export const DDLottie = LottieBlockComponent
459
+ export default LottieBlockComponent
@@ -0,0 +1,4 @@
1
+ # DD-Lottie
2
+
3
+ Portable first-pass conversion of `LottieBlock` from ROUND-TWO-CONVERSION. Project-specific roots and nested unconverted block dependencies were intentionally replaced with local rendering so the template can install into a clean Payload project.
4
+