blocks-dusted 0.1.12 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/installers/patchRenderBlocks.js +1 -1
- package/src/registry/validateTemplateManifest.js +2 -1
- package/templates/blocks/BannerDD790432/Component.tsx +63 -0
- package/templates/blocks/BannerDD790432/config.ts +54 -0
- package/templates/blocks/BannerDD790432/manifest.json +80 -0
- package/templates/blocks/Button47/Component.tsx +124 -0
- package/templates/blocks/Button47/config.ts +75 -0
- package/templates/blocks/Button47/link.ts +22 -0
- package/templates/blocks/Button47/manifest.json +105 -0
- package/templates/blocks/Button47/styles.module.scss +75 -0
- package/templates/blocks/DD-Accordion/Component.tsx +55 -36
- package/templates/blocks/DD-Accordion/config.ts +71 -59
- package/templates/blocks/DD-AnimText/Component.tsx +50 -32
- package/templates/blocks/DD-AnimText/config.ts +296 -295
- package/templates/blocks/DD-AsideNav/Component.tsx +323 -319
- package/templates/blocks/DD-Banner/Component.tsx +54 -51
- package/templates/blocks/DD-BookCall/Component.tsx +535 -535
- package/templates/blocks/DD-ButtonPop/Component.tsx +118 -117
- package/templates/blocks/DD-Card/Component.tsx +4 -4
- package/templates/blocks/DD-CardTemplate01/Component.tsx +139 -140
- package/templates/blocks/DD-CardsWithVariantV3/Component.tsx +472 -0
- package/templates/blocks/DD-CardsWithVariantV3/ElectricBorder/index.tsx +203 -0
- package/templates/blocks/DD-CardsWithVariantV3/ElectricBorder/styles.ts +87 -0
- package/templates/blocks/DD-CardsWithVariantV3/ElectricBorder/useInjectStyle.ts +39 -0
- package/templates/blocks/DD-CardsWithVariantV3/config.ts +326 -0
- package/templates/blocks/DD-CardsWithVariantV3/manifest.json +110 -0
- package/templates/blocks/DD-Carousel-A/Component.tsx +251 -249
- package/templates/blocks/DD-Carousel-B/Component.tsx +405 -403
- package/templates/blocks/DD-ComparisonTable/Component.tsx +255 -256
- package/templates/blocks/DD-Contact/Component.tsx +433 -435
- package/templates/blocks/DD-Counter/Component.tsx +11 -6
- package/templates/blocks/DD-DeliCard/Component.tsx +303 -0
- package/templates/blocks/DD-DeliCard/config.ts +186 -0
- package/templates/blocks/DD-DeliCard/manifest.json +94 -0
- package/templates/blocks/DD-FeatCat/Component.tsx +302 -302
- package/templates/blocks/DD-FeatProd/CircularGallery.tsx +1179 -0
- package/templates/blocks/DD-FeatProd/Component.tsx +484 -0
- package/templates/blocks/DD-FeatProd/config.ts +173 -0
- package/templates/blocks/DD-FeatProd/manifest.json +93 -0
- package/templates/blocks/DD-FeatServ/Component.tsx +607 -0
- package/templates/blocks/DD-FeatServ/config.ts +213 -0
- package/templates/blocks/DD-FeatServ/manifest.json +113 -0
- package/templates/blocks/DD-FeatStrip/Component.tsx +584 -585
- package/templates/blocks/DD-FluidBtn/ButtonsEyeCatching.tsx +627 -628
- package/templates/blocks/DD-FluidBtn/Component.tsx +46 -43
- package/templates/blocks/DD-GooeyInfo/Component.tsx +150 -149
- package/templates/blocks/DD-GooeyInfo/config.ts +136 -135
- package/templates/blocks/DD-Hero/Component.tsx +296 -297
- package/templates/blocks/DD-HeroPlas/Component.tsx +50 -0
- package/templates/blocks/DD-HeroPlas/ThreeScene.tsx +109 -0
- package/templates/blocks/DD-HeroPlas/config.ts +33 -0
- package/templates/blocks/DD-HeroPlas/manifest.json +88 -0
- package/templates/blocks/DD-HorizontalScroll/Component.tsx +937 -936
- package/templates/blocks/DD-Icon/Component.tsx +46 -81
- package/templates/blocks/DD-IconButton/Component.tsx +13 -20
- package/templates/blocks/DD-IdTag/Component.tsx +22 -21
- package/templates/blocks/DD-LineAnim/Component.tsx +42 -36
- package/templates/blocks/DD-LogoMarq/Component.tsx +38 -48
- package/templates/blocks/DD-Lottie/Component.tsx +11 -3
- package/templates/blocks/DD-MasonaryMedia/Component.tsx +544 -545
- package/templates/blocks/DD-MasonaryMedia/config.ts +389 -389
- package/templates/blocks/DD-Masonry/Component.tsx +654 -644
- package/templates/blocks/DD-Masonry/config.ts +475 -475
- package/templates/blocks/DD-MaterialSwatches/Component.tsx +85 -0
- package/templates/blocks/DD-MaterialSwatches/config.ts +232 -0
- package/templates/blocks/DD-MaterialSwatches/manifest.json +84 -0
- package/templates/blocks/DD-MaterialSwatches/material.ts +107 -0
- package/templates/blocks/DD-NineCanvas/Component.tsx +129 -0
- package/templates/blocks/DD-NineCanvas/RenderBlocks.tsx +244 -0
- package/templates/blocks/DD-NineCanvas/allowedCanvasBlocks.ts +6 -0
- package/templates/blocks/DD-NineCanvas/blockComponents.tsx +8 -0
- package/templates/blocks/DD-NineCanvas/canvas/CanvasGrid.tsx +316 -0
- package/templates/blocks/DD-NineCanvas/canvas/RadialNav.tsx +432 -0
- package/templates/blocks/DD-NineCanvas/canvas/canvas-panels.css +889 -0
- package/templates/blocks/DD-NineCanvas/canvas/icons/custom-icons.tsx +364 -0
- package/templates/blocks/DD-NineCanvas/config.ts +61 -0
- package/templates/blocks/DD-NineCanvas/manifest.json +165 -0
- package/templates/blocks/DD-NineCanvas/styles.scss +152 -0
- package/templates/blocks/DD-NineCanvas/tooltip/get-strict-context.tsx +26 -0
- package/templates/blocks/DD-NineCanvas/tooltip/primitives.tsx +178 -0
- package/templates/blocks/DD-NineCanvas/tooltip/tooltip.tsx +71 -0
- package/templates/blocks/DD-NineCanvas/tooltip/use-controlled-state.tsx +33 -0
- package/templates/blocks/DD-NineCanvas/utilities/FadeOnScroll.tsx +68 -0
- package/templates/blocks/DD-NineCanvas/utilities/ParallaxWrapper.tsx +157 -0
- package/templates/blocks/DD-NineCanvas/utilities/renderCustomCSS.ts +5 -0
- package/templates/blocks/DD-NineCanvas/utilities/webglCleanup.ts +27 -0
- package/templates/blocks/DD-PayloadAIAssistant/Component.tsx +78 -0
- package/templates/blocks/DD-PayloadAIAssistant/DustedBot.tsx +590 -0
- package/templates/blocks/DD-PayloadAIAssistant/config.ts +37 -0
- package/templates/blocks/DD-PayloadAIAssistant/demo.css +125 -0
- package/templates/blocks/DD-PayloadAIAssistant/manifest.json +93 -0
- package/templates/blocks/DD-PayloadAIAssistant/source-defaults.ts +17 -0
- package/templates/blocks/DD-PayloadAIAssistant/styles.ts +306 -0
- package/templates/blocks/DD-Pricing/Component.tsx +2 -3
- package/templates/blocks/DD-Pricing/config.ts +215 -215
- package/templates/blocks/DD-Process/Component.tsx +2 -2
- package/templates/blocks/DD-ProjHeader/Component.tsx +93 -91
- package/templates/blocks/DD-ProjSlider/Component.tsx +1 -1
- package/templates/blocks/DD-Section/Component.tsx +265 -266
- package/templates/blocks/DD-Separator/Component.tsx +66 -66
- package/templates/blocks/DD-Services/Component.tsx +176 -176
- package/templates/blocks/DD-ShowcaseGrid/Component.tsx +306 -307
- package/templates/blocks/DD-Slider-A/Component.tsx +2 -2
- package/templates/blocks/DD-StackCards/Component.tsx +172 -171
- package/templates/blocks/DD-Team/Component.tsx +247 -247
- package/templates/blocks/DD-TeamCards/Component.tsx +251 -251
- package/templates/blocks/DD-TechStack/Component.tsx +173 -174
- package/templates/blocks/DD-TestMarq/Component.tsx +158 -132
- package/templates/blocks/DD-Testim/Component.tsx +247 -247
- package/templates/blocks/DD-Testim2/Component.tsx +265 -256
- package/templates/blocks/DD-Testimonials/Component.tsx +139 -139
- package/templates/blocks/DD-Thanks/Component.tsx +1 -1
- package/templates/blocks/DD-Work/Component.tsx +318 -318
- package/templates/blocks/DD-Work-B/Component.tsx +294 -294
- package/templates/blocks/DDHG-CTASection2/Component.tsx +183 -184
- package/templates/blocks/DDHG-HighlightArc/Component.tsx +6 -3
- package/templates/blocks/DDHG-LogoMarquee/Component.tsx +45 -8
- package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +1 -3
- package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +9 -22
- package/templates/blocks/DDHG-ServiceHero/Component.tsx +10 -10
- package/templates/blocks/DDHG-TeamCards/Component.tsx +6 -35
- package/templates/blocks/Form/Checkbox/index.tsx +45 -0
- package/templates/blocks/Form/Component.tsx +163 -0
- package/templates/blocks/Form/Country/index.tsx +65 -0
- package/templates/blocks/Form/Country/options.ts +982 -0
- package/templates/blocks/Form/Email/index.tsx +38 -0
- package/templates/blocks/Form/Error/index.tsx +15 -0
- package/templates/blocks/Form/Message/index.tsx +13 -0
- package/templates/blocks/Form/Number/index.tsx +36 -0
- package/templates/blocks/Form/Select/index.tsx +63 -0
- package/templates/blocks/Form/State/index.tsx +64 -0
- package/templates/blocks/Form/State/options.ts +52 -0
- package/templates/blocks/Form/Text/index.tsx +32 -0
- package/templates/blocks/Form/Textarea/index.tsx +40 -0
- package/templates/blocks/Form/Width/index.tsx +13 -0
- package/templates/blocks/Form/config.ts +51 -0
- package/templates/blocks/Form/fields.tsx +21 -0
- package/templates/blocks/Form/manifest.json +168 -0
- package/templates/blocks/MediaBlock/Component.tsx +67 -0
- package/templates/blocks/MediaBlock/config.ts +14 -0
- package/templates/blocks/MediaBlock/manifest.json +92 -0
- package/templates/blocks/TransitionsDustedShowcase/Component.tsx +9 -0
- package/templates/blocks/TransitionsDustedShowcase/config.ts +13 -0
- package/templates/blocks/TransitionsDustedShowcase/manifest.json +80 -0
- package/templates/blocks/rawHtml/Component.tsx +25 -0
- package/templates/blocks/rawHtml/config.ts +56 -0
- package/templates/blocks/rawHtml/manifest.json +80 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
.topLogoBgWrapper {
|
|
2
|
+
position: fixed;
|
|
3
|
+
left: 0;
|
|
4
|
+
right: 0;
|
|
5
|
+
top: 0;
|
|
6
|
+
margin: auto;
|
|
7
|
+
width: fit-content;
|
|
8
|
+
max-width: fit-content;
|
|
9
|
+
height: fit-content;
|
|
10
|
+
max-height: 2.5rem;
|
|
11
|
+
z-index: 99999;
|
|
12
|
+
pointer-events: auto;
|
|
13
|
+
|
|
14
|
+
filter: drop-shadow(0px 1px 2px var(--border)) drop-shadow(rgba(0, 0, 0, 0.8) 2px 4px 6px);
|
|
15
|
+
|
|
16
|
+
animation: topLogoEnter 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@keyframes topLogoEnter {
|
|
20
|
+
from {
|
|
21
|
+
opacity: 0;
|
|
22
|
+
transform: translateY(-1.25rem) scale(0.94);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
to {
|
|
26
|
+
opacity: 1;
|
|
27
|
+
transform: translateY(0) scale(1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
@media (max-width: 768px) {
|
|
31
|
+
.topLogoBgWrapper {
|
|
32
|
+
scale: 0.7;
|
|
33
|
+
transform-origin: top;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.svglogolink {
|
|
38
|
+
position: relative;
|
|
39
|
+
top: -2.6rem;
|
|
40
|
+
max-width: fit-content;
|
|
41
|
+
margin: auto;
|
|
42
|
+
padding-top: 0.6rem;
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: flex-start;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
z-index: 99999;
|
|
48
|
+
filter: brightness(0.8) drop-shadow(2px 4px 6px rgba(0, 0, 0, 0.5));
|
|
49
|
+
transition: all 0.3s;
|
|
50
|
+
}
|
|
51
|
+
.svglogolink::before {
|
|
52
|
+
content: '';
|
|
53
|
+
position: absolute;
|
|
54
|
+
top: 0;
|
|
55
|
+
width: 3.5rem;
|
|
56
|
+
height: 5px;
|
|
57
|
+
border-radius: 999px;
|
|
58
|
+
background: #e5e5e5;
|
|
59
|
+
box-shadow: 0 0 12px rgba(255, 255, 255, 0.65);
|
|
60
|
+
opacity: 0;
|
|
61
|
+
filter: blur(0.25px);
|
|
62
|
+
transform: translateY(-2px);
|
|
63
|
+
transition: all 0.3s;
|
|
64
|
+
}
|
|
65
|
+
.svglogolink::after {
|
|
66
|
+
content: '';
|
|
67
|
+
position: absolute;
|
|
68
|
+
top: 5px;
|
|
69
|
+
width: 5.25rem;
|
|
70
|
+
height: 3rem;
|
|
71
|
+
background: linear-gradient(
|
|
72
|
+
to bottom,
|
|
73
|
+
rgba(255, 255, 255, 0.28),
|
|
74
|
+
rgba(255, 255, 255, 0.08) 45%,
|
|
75
|
+
rgba(255, 255, 255, 0)
|
|
76
|
+
);
|
|
77
|
+
clip-path: polygon(28% 0, 72% 0, 100% 100%, 0 100%);
|
|
78
|
+
filter: blur(1.5px);
|
|
79
|
+
opacity: 0;
|
|
80
|
+
pointer-events: none;
|
|
81
|
+
transition: all 0.3s;
|
|
82
|
+
mix-blend-mode: lighten;
|
|
83
|
+
}
|
|
84
|
+
.svglogolink:hover {
|
|
85
|
+
filter: brightness(1.5) drop-shadow(2px 4px 6px rgba(0, 0, 0, 0.8));
|
|
86
|
+
}
|
|
87
|
+
.svglogolink:hover::before,
|
|
88
|
+
.svglogolink:hover::after {
|
|
89
|
+
opacity: 1;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.bottomLogoBgWrapper {
|
|
93
|
+
position: fixed;
|
|
94
|
+
left: 0;
|
|
95
|
+
right: 0;
|
|
96
|
+
bottom: 0;
|
|
97
|
+
margin: auto;
|
|
98
|
+
width: fit-content;
|
|
99
|
+
height: fit-content;
|
|
100
|
+
z-index: 100;
|
|
101
|
+
pointer-events: auto;
|
|
102
|
+
|
|
103
|
+
filter: drop-shadow(0px 1px 2px var(--border)) drop-shadow(rgba(0, 0, 0, 0.8) 2px 4px 6px);
|
|
104
|
+
|
|
105
|
+
animation: bottomLogoEnter 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@keyframes bottomLogoEnter {
|
|
109
|
+
from {
|
|
110
|
+
opacity: 0;
|
|
111
|
+
transform: translateY(1.25rem) scale(0.94);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
to {
|
|
115
|
+
opacity: 1;
|
|
116
|
+
transform: translateY(0) scale(1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
@media (max-width: 768px) {
|
|
120
|
+
.bottomLogoBgWrapper {
|
|
121
|
+
scale: 0.7;
|
|
122
|
+
transform-origin: bottom;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.ninecanvas {
|
|
127
|
+
position: relative;
|
|
128
|
+
min-height: 100vh;
|
|
129
|
+
max-height: 100vh;
|
|
130
|
+
overflow: auto hidden;
|
|
131
|
+
z-index: 20;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
body.has-ninecanvas-footer-reveal article.page-article {
|
|
135
|
+
overflow: auto hidden;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.hzNineCanvasBlock {
|
|
139
|
+
isolation: isolate;
|
|
140
|
+
margin: 0;
|
|
141
|
+
position: sticky;
|
|
142
|
+
top: 0;
|
|
143
|
+
height: 100dvh;
|
|
144
|
+
// background: var(--card-foreground);
|
|
145
|
+
background: radial-gradient(circle at center, #353535, transparent);
|
|
146
|
+
overflow: hidden;
|
|
147
|
+
z-index: 20;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.hzNineCanvasBlock .renderblock-container {
|
|
151
|
+
min-height: initial;
|
|
152
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
|
|
3
|
+
function getStrictContext<T>(
|
|
4
|
+
name?: string,
|
|
5
|
+
): readonly [
|
|
6
|
+
({ value, children }: { value: T; children?: React.ReactNode }) => React.JSX.Element,
|
|
7
|
+
() => T,
|
|
8
|
+
] {
|
|
9
|
+
const Context = React.createContext<T | undefined>(undefined)
|
|
10
|
+
|
|
11
|
+
const Provider = ({ value, children }: { value: T; children?: React.ReactNode }) => (
|
|
12
|
+
<Context.Provider value={value}>{children}</Context.Provider>
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
const useSafeContext = () => {
|
|
16
|
+
const ctx = React.useContext(Context)
|
|
17
|
+
if (ctx === undefined) {
|
|
18
|
+
throw new Error(`useContext must be used within ${name ?? 'a Provider'}`)
|
|
19
|
+
}
|
|
20
|
+
return ctx
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return [Provider, useSafeContext] as const
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { getStrictContext }
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { Tooltip as TooltipPrimitive } from '@base-ui/react/tooltip'
|
|
5
|
+
import {
|
|
6
|
+
AnimatePresence,
|
|
7
|
+
motion,
|
|
8
|
+
useMotionValue,
|
|
9
|
+
useSpring,
|
|
10
|
+
type HTMLMotionProps,
|
|
11
|
+
type MotionValue,
|
|
12
|
+
type SpringOptions,
|
|
13
|
+
} from 'motion/react'
|
|
14
|
+
|
|
15
|
+
import { getStrictContext } from './get-strict-context'
|
|
16
|
+
import { useControlledState } from './use-controlled-state'
|
|
17
|
+
|
|
18
|
+
type TooltipContextType = {
|
|
19
|
+
isOpen: boolean
|
|
20
|
+
setIsOpen: TooltipProps['onOpenChange']
|
|
21
|
+
x: MotionValue<number>
|
|
22
|
+
y: MotionValue<number>
|
|
23
|
+
followCursor?: boolean | 'x' | 'y'
|
|
24
|
+
followCursorSpringOptions?: SpringOptions
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const [LocalTooltipProvider, useTooltip] = getStrictContext<TooltipContextType>('TooltipContext')
|
|
28
|
+
|
|
29
|
+
type TooltipProviderProps = React.ComponentProps<typeof TooltipPrimitive.Provider>
|
|
30
|
+
|
|
31
|
+
function TooltipProvider(props: TooltipProviderProps) {
|
|
32
|
+
return <TooltipPrimitive.Provider data-slot="tooltip-provider" {...props} />
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type TooltipProps = React.ComponentProps<typeof TooltipPrimitive.Root> & {
|
|
36
|
+
followCursor?: boolean | 'x' | 'y'
|
|
37
|
+
followCursorSpringOptions?: SpringOptions
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function Tooltip({
|
|
41
|
+
followCursor = false,
|
|
42
|
+
followCursorSpringOptions = { stiffness: 200, damping: 17 },
|
|
43
|
+
...props
|
|
44
|
+
}: TooltipProps) {
|
|
45
|
+
const [isOpen, setIsOpen] = useControlledState({
|
|
46
|
+
value: props?.open,
|
|
47
|
+
defaultValue: props?.defaultOpen,
|
|
48
|
+
onChange: props?.onOpenChange,
|
|
49
|
+
})
|
|
50
|
+
const x = useMotionValue(0)
|
|
51
|
+
const y = useMotionValue(0)
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<LocalTooltipProvider
|
|
55
|
+
value={{
|
|
56
|
+
isOpen,
|
|
57
|
+
setIsOpen,
|
|
58
|
+
x,
|
|
59
|
+
y,
|
|
60
|
+
followCursor,
|
|
61
|
+
followCursorSpringOptions,
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
<TooltipPrimitive.Root data-slot="tooltip" {...props} onOpenChange={setIsOpen} />
|
|
65
|
+
</LocalTooltipProvider>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
type TooltipTriggerProps = React.ComponentProps<typeof TooltipPrimitive.Trigger>
|
|
70
|
+
|
|
71
|
+
function TooltipTrigger({ onMouseMove, ...props }: TooltipTriggerProps) {
|
|
72
|
+
const { x, y, followCursor } = useTooltip()
|
|
73
|
+
|
|
74
|
+
const handleMouseMove = (
|
|
75
|
+
event: Parameters<NonNullable<TooltipTriggerProps['onMouseMove']>>[0],
|
|
76
|
+
) => {
|
|
77
|
+
onMouseMove?.(event)
|
|
78
|
+
|
|
79
|
+
const target = event.currentTarget.getBoundingClientRect()
|
|
80
|
+
|
|
81
|
+
if (followCursor === 'x' || followCursor === true) {
|
|
82
|
+
const eventOffsetX = event.clientX - target.left
|
|
83
|
+
const offsetXFromCenter = (eventOffsetX - target.width / 2) / 2
|
|
84
|
+
x.set(offsetXFromCenter)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (followCursor === 'y' || followCursor === true) {
|
|
88
|
+
const eventOffsetY = event.clientY - target.top
|
|
89
|
+
const offsetYFromCenter = (eventOffsetY - target.height / 2) / 2
|
|
90
|
+
y.set(offsetYFromCenter)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<TooltipPrimitive.Trigger
|
|
96
|
+
data-slot="tooltip-trigger"
|
|
97
|
+
onMouseMove={handleMouseMove}
|
|
98
|
+
{...props}
|
|
99
|
+
/>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type TooltipPortalProps = Omit<React.ComponentProps<typeof TooltipPrimitive.Portal>, 'keepMounted'>
|
|
104
|
+
|
|
105
|
+
function TooltipPortal(props: TooltipPortalProps) {
|
|
106
|
+
const { isOpen } = useTooltip()
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<AnimatePresence>
|
|
110
|
+
{isOpen && <TooltipPrimitive.Portal keepMounted data-slot="tooltip-portal" {...props} />}
|
|
111
|
+
</AnimatePresence>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
type TooltipPositionerProps = React.ComponentProps<typeof TooltipPrimitive.Positioner>
|
|
116
|
+
|
|
117
|
+
function TooltipPositioner(props: TooltipPositionerProps) {
|
|
118
|
+
return <TooltipPrimitive.Positioner data-slot="tooltip-positioner" {...props} />
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
type TooltipPopupProps = Omit<React.ComponentProps<typeof TooltipPrimitive.Popup>, 'render'> &
|
|
122
|
+
HTMLMotionProps<'div'>
|
|
123
|
+
|
|
124
|
+
function TooltipPopup({
|
|
125
|
+
transition = { type: 'spring', stiffness: 300, damping: 25 },
|
|
126
|
+
style,
|
|
127
|
+
...props
|
|
128
|
+
}: TooltipPopupProps) {
|
|
129
|
+
const { x, y, followCursor, followCursorSpringOptions } = useTooltip()
|
|
130
|
+
const translateX = useSpring(x, followCursorSpringOptions)
|
|
131
|
+
const translateY = useSpring(y, followCursorSpringOptions)
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<TooltipPrimitive.Popup
|
|
135
|
+
render={
|
|
136
|
+
<motion.div
|
|
137
|
+
key="tooltip-popup"
|
|
138
|
+
data-slot="tooltip-popup"
|
|
139
|
+
initial={{ opacity: 0, scale: 0.5 }}
|
|
140
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
141
|
+
exit={{ opacity: 0, scale: 0.5 }}
|
|
142
|
+
transition={transition}
|
|
143
|
+
style={{
|
|
144
|
+
x: followCursor === 'x' || followCursor === true ? translateX : undefined,
|
|
145
|
+
y: followCursor === 'y' || followCursor === true ? translateY : undefined,
|
|
146
|
+
...style,
|
|
147
|
+
}}
|
|
148
|
+
{...props}
|
|
149
|
+
/>
|
|
150
|
+
}
|
|
151
|
+
/>
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
type TooltipArrowProps = React.ComponentProps<typeof TooltipPrimitive.Arrow>
|
|
156
|
+
|
|
157
|
+
function TooltipArrow(props: TooltipArrowProps) {
|
|
158
|
+
return <TooltipPrimitive.Arrow data-slot="tooltip-arrow" {...props} />
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export {
|
|
162
|
+
TooltipProvider,
|
|
163
|
+
Tooltip,
|
|
164
|
+
TooltipTrigger,
|
|
165
|
+
TooltipPortal,
|
|
166
|
+
TooltipPositioner,
|
|
167
|
+
TooltipPopup,
|
|
168
|
+
TooltipArrow,
|
|
169
|
+
useTooltip,
|
|
170
|
+
type TooltipProviderProps,
|
|
171
|
+
type TooltipProps,
|
|
172
|
+
type TooltipTriggerProps,
|
|
173
|
+
type TooltipPortalProps,
|
|
174
|
+
type TooltipPositionerProps,
|
|
175
|
+
type TooltipPopupProps,
|
|
176
|
+
type TooltipArrowProps,
|
|
177
|
+
type TooltipContextType,
|
|
178
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
TooltipProvider as TooltipProviderPrimitive,
|
|
5
|
+
Tooltip as TooltipPrimitive,
|
|
6
|
+
TooltipTrigger as TooltipTriggerPrimitive,
|
|
7
|
+
TooltipPositioner as TooltipPositionerPrimitive,
|
|
8
|
+
TooltipPopup as TooltipPopupPrimitive,
|
|
9
|
+
TooltipArrow as TooltipArrowPrimitive,
|
|
10
|
+
TooltipPortal as TooltipPortalPrimitive,
|
|
11
|
+
type TooltipProviderProps as TooltipProviderPrimitiveProps,
|
|
12
|
+
type TooltipProps as TooltipPrimitiveProps,
|
|
13
|
+
type TooltipTriggerProps as TooltipTriggerPrimitiveProps,
|
|
14
|
+
type TooltipPositionerProps as TooltipPositionerPrimitiveProps,
|
|
15
|
+
type TooltipPopupProps as TooltipPopupPrimitiveProps,
|
|
16
|
+
} from './primitives'
|
|
17
|
+
import { cn } from '@/utilities/ui'
|
|
18
|
+
|
|
19
|
+
type TooltipProviderProps = TooltipProviderPrimitiveProps
|
|
20
|
+
|
|
21
|
+
function TooltipProvider({ delay = 0, ...props }: TooltipProviderProps) {
|
|
22
|
+
return <TooltipProviderPrimitive delay={delay} {...props} />
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type TooltipProps = TooltipPrimitiveProps & {
|
|
26
|
+
delay?: TooltipProviderProps['delay']
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function Tooltip({ delay = 0, ...props }: TooltipProps) {
|
|
30
|
+
return (
|
|
31
|
+
<TooltipProvider delay={delay}>
|
|
32
|
+
<TooltipPrimitive {...props} />
|
|
33
|
+
</TooltipProvider>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type TooltipTriggerProps = TooltipTriggerPrimitiveProps
|
|
38
|
+
|
|
39
|
+
function TooltipTrigger({ ...props }: TooltipTriggerProps) {
|
|
40
|
+
return <TooltipTriggerPrimitive {...props} />
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type TooltipPanelProps = TooltipPositionerPrimitiveProps & TooltipPopupPrimitiveProps
|
|
44
|
+
|
|
45
|
+
function TooltipPanel({ className, sideOffset = 4, children, style, ...props }: TooltipPanelProps) {
|
|
46
|
+
return (
|
|
47
|
+
<TooltipPortalPrimitive>
|
|
48
|
+
<TooltipPositionerPrimitive sideOffset={sideOffset} className="z-100 hzToolTip" {...props}>
|
|
49
|
+
<TooltipPopupPrimitive
|
|
50
|
+
className={cn(
|
|
51
|
+
'bg-primary/75 text-primary-foreground w-fit origin-(--transform-origin) rounded-md px-3 py-1.5 text-xs text-balance',
|
|
52
|
+
className,
|
|
53
|
+
)}
|
|
54
|
+
style={style}
|
|
55
|
+
>
|
|
56
|
+
{children}
|
|
57
|
+
<TooltipArrowPrimitive className="bg-primary fill-primary z-50 size-2.5 data-[side='bottom']:-top-1 data-[side='right']:-left-1 data-[side='left']:-right-1 data-[side='inline-start']:-right-1 data-[side='inline-end']:-left-1 rotate-45 rounded-[2px]" />
|
|
58
|
+
</TooltipPopupPrimitive>
|
|
59
|
+
</TooltipPositionerPrimitive>
|
|
60
|
+
</TooltipPortalPrimitive>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export {
|
|
65
|
+
Tooltip,
|
|
66
|
+
TooltipTrigger,
|
|
67
|
+
TooltipPanel,
|
|
68
|
+
type TooltipProps,
|
|
69
|
+
type TooltipTriggerProps,
|
|
70
|
+
type TooltipPanelProps,
|
|
71
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
|
|
3
|
+
interface CommonControlledStateProps<T> {
|
|
4
|
+
value?: T
|
|
5
|
+
defaultValue?: T
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
+
export function useControlledState<T, Rest extends any[] = []>(
|
|
10
|
+
props: CommonControlledStateProps<T> & {
|
|
11
|
+
onChange?: (value: T, ...args: Rest) => void
|
|
12
|
+
},
|
|
13
|
+
): readonly [T, (next: T, ...args: Rest) => void] {
|
|
14
|
+
const { value, defaultValue, onChange } = props
|
|
15
|
+
|
|
16
|
+
const [state, setInternalState] = React.useState<T>(
|
|
17
|
+
value !== undefined ? value : (defaultValue as T),
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
React.useEffect(() => {
|
|
21
|
+
if (value !== undefined) setInternalState(value)
|
|
22
|
+
}, [value])
|
|
23
|
+
|
|
24
|
+
const setState = React.useCallback(
|
|
25
|
+
(next: T, ...args: Rest) => {
|
|
26
|
+
setInternalState(next)
|
|
27
|
+
onChange?.(next, ...args)
|
|
28
|
+
},
|
|
29
|
+
[onChange],
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
return [state, setState] as const
|
|
33
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { useEffect, useRef, useState } from 'react'
|
|
4
|
+
import { motion, useScroll, useTransform } from 'framer-motion'
|
|
5
|
+
|
|
6
|
+
type FadeOffset = 'start start' | 'start center' | 'start end' | `start ${number}%`
|
|
7
|
+
|
|
8
|
+
interface FadeOnScrollProps {
|
|
9
|
+
children: React.ReactNode
|
|
10
|
+
startFade?: number
|
|
11
|
+
endFade?: number
|
|
12
|
+
finalOpacity?: number
|
|
13
|
+
offsetStart?: FadeOffset
|
|
14
|
+
offsetEnd?: FadeOffset
|
|
15
|
+
useAbsoluteScroll?: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const FadeOnScroll: React.FC<FadeOnScrollProps> = ({
|
|
19
|
+
children,
|
|
20
|
+
startFade = 0,
|
|
21
|
+
endFade = 1,
|
|
22
|
+
finalOpacity = 0,
|
|
23
|
+
offsetStart = 'start 50%',
|
|
24
|
+
offsetEnd = 'start 0%',
|
|
25
|
+
useAbsoluteScroll = false,
|
|
26
|
+
}) => {
|
|
27
|
+
const containerRef = useRef<HTMLDivElement>(null)
|
|
28
|
+
const [targetRef, setTargetRef] = useState<HTMLElement | null>(null)
|
|
29
|
+
|
|
30
|
+
// Bind scroll tracking only when ready
|
|
31
|
+
const scrollSetupRef = useRef(false)
|
|
32
|
+
const { scrollY, scrollYProgress } = useScroll({
|
|
33
|
+
target: targetRef ? { current: targetRef } : undefined,
|
|
34
|
+
offset: [offsetStart, offsetEnd],
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const opacity = useTransform(
|
|
38
|
+
useAbsoluteScroll ? scrollY : scrollYProgress,
|
|
39
|
+
[startFade, endFade],
|
|
40
|
+
[1, finalOpacity],
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (typeof window === 'undefined') return
|
|
45
|
+
|
|
46
|
+
const container = containerRef.current
|
|
47
|
+
if (!container) return
|
|
48
|
+
|
|
49
|
+
const parent = container.closest('.renderblock-container')
|
|
50
|
+
if (!parent) return
|
|
51
|
+
|
|
52
|
+
let sibling = parent.nextElementSibling as HTMLElement | null
|
|
53
|
+
while (sibling && !sibling.classList.contains('renderblock-container')) {
|
|
54
|
+
sibling = sibling.nextElementSibling as HTMLElement | null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (sibling && !scrollSetupRef.current) {
|
|
58
|
+
setTargetRef(sibling)
|
|
59
|
+
scrollSetupRef.current = true
|
|
60
|
+
}
|
|
61
|
+
}, [])
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<motion.div ref={containerRef} style={{ opacity }}>
|
|
65
|
+
{children}
|
|
66
|
+
</motion.div>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { useEffect, useId, useRef } from 'react'
|
|
4
|
+
import { motion, useScroll, useTransform } from 'framer-motion'
|
|
5
|
+
import { gsap } from 'gsap'
|
|
6
|
+
import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
|
7
|
+
import { ScrollToPlugin } from 'gsap/ScrollToPlugin'
|
|
8
|
+
|
|
9
|
+
type ParallaxWrapperProps = {
|
|
10
|
+
children: React.ReactNode
|
|
11
|
+
enabled?: boolean
|
|
12
|
+
sectionId?: string
|
|
13
|
+
animationConfig?: {
|
|
14
|
+
smooth?: number
|
|
15
|
+
effects?: boolean
|
|
16
|
+
scrollToSelector?: string
|
|
17
|
+
scrollDuration?: number
|
|
18
|
+
ease?: string
|
|
19
|
+
triggerSelector?: string
|
|
20
|
+
pinSpacing?: number | string
|
|
21
|
+
pinTargetSelector?: string
|
|
22
|
+
markers?: boolean
|
|
23
|
+
makers?: boolean
|
|
24
|
+
parallaxDistance?: number
|
|
25
|
+
parallaxDirection?: 'up' | 'down'
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const toNumber = (value: number | string | undefined, fallback: number): number => {
|
|
30
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value
|
|
31
|
+
|
|
32
|
+
if (typeof value === 'string') {
|
|
33
|
+
const parsed = Number(value)
|
|
34
|
+
if (Number.isFinite(parsed)) return parsed
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return fallback
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const ParallaxWrapper: React.FC<ParallaxWrapperProps> = ({
|
|
41
|
+
children,
|
|
42
|
+
enabled = true,
|
|
43
|
+
sectionId,
|
|
44
|
+
animationConfig = {},
|
|
45
|
+
}) => {
|
|
46
|
+
const reactId = useId()
|
|
47
|
+
const safeId = sectionId || `parallax-${reactId.replace(/:/g, '')}`
|
|
48
|
+
|
|
49
|
+
const sectionRef = useRef<HTMLElement>(null)
|
|
50
|
+
const innerRef = useRef<HTMLDivElement>(null)
|
|
51
|
+
|
|
52
|
+
const {
|
|
53
|
+
scrollToSelector,
|
|
54
|
+
scrollDuration = 1.3,
|
|
55
|
+
triggerSelector,
|
|
56
|
+
pinTargetSelector,
|
|
57
|
+
pinSpacing,
|
|
58
|
+
markers,
|
|
59
|
+
makers,
|
|
60
|
+
parallaxDistance = 120,
|
|
61
|
+
parallaxDirection = 'up',
|
|
62
|
+
} = animationConfig
|
|
63
|
+
|
|
64
|
+
const showMarkers = markers === true || makers === true
|
|
65
|
+
const distance = Math.abs(toNumber(parallaxDistance, 120))
|
|
66
|
+
const yStart = parallaxDirection === 'down' ? -distance : distance
|
|
67
|
+
const yEnd = parallaxDirection === 'down' ? distance : -distance
|
|
68
|
+
|
|
69
|
+
const { scrollYProgress } = useScroll({
|
|
70
|
+
target: sectionRef,
|
|
71
|
+
offset: ['start end', 'end start'],
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const y = useTransform(scrollYProgress, [0, 1], [yStart, yEnd])
|
|
75
|
+
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
if (!enabled || typeof window === 'undefined') return
|
|
78
|
+
|
|
79
|
+
gsap.registerPlugin(ScrollTrigger, ScrollToPlugin)
|
|
80
|
+
|
|
81
|
+
const sectionEl = sectionRef.current
|
|
82
|
+
const innerEl = innerRef.current
|
|
83
|
+
|
|
84
|
+
if (!sectionEl || !innerEl) return
|
|
85
|
+
|
|
86
|
+
const scrollTo = (selector: string = scrollToSelector || `#${safeId}`) => {
|
|
87
|
+
if (!selector) return
|
|
88
|
+
|
|
89
|
+
if ((window as any).lenis) {
|
|
90
|
+
;(window as any).lenis.scrollTo(selector, {
|
|
91
|
+
offset: 0,
|
|
92
|
+
duration: scrollDuration,
|
|
93
|
+
easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
|
|
94
|
+
})
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const target = document.querySelector(selector)
|
|
99
|
+
if (target) {
|
|
100
|
+
target.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
;(window as any).gsapScrollTo = scrollTo
|
|
105
|
+
|
|
106
|
+
const triggerEl = triggerSelector ? document.querySelector(triggerSelector) : sectionEl
|
|
107
|
+
const pinEl = pinTargetSelector ? document.querySelector(pinTargetSelector) : null
|
|
108
|
+
|
|
109
|
+
if (!triggerEl) return
|
|
110
|
+
|
|
111
|
+
let pinTrigger: ScrollTrigger | undefined
|
|
112
|
+
|
|
113
|
+
if (pinEl) {
|
|
114
|
+
const pinDistance = toNumber(pinSpacing, window.innerHeight)
|
|
115
|
+
|
|
116
|
+
pinTrigger = ScrollTrigger.create({
|
|
117
|
+
trigger: triggerEl,
|
|
118
|
+
pin: pinEl,
|
|
119
|
+
start: 'top top',
|
|
120
|
+
end: `+=${pinDistance}`,
|
|
121
|
+
scrub: true,
|
|
122
|
+
markers: showMarkers,
|
|
123
|
+
invalidateOnRefresh: true,
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return () => {
|
|
128
|
+
pinTrigger?.kill()
|
|
129
|
+
}
|
|
130
|
+
}, [
|
|
131
|
+
enabled,
|
|
132
|
+
safeId,
|
|
133
|
+
scrollToSelector,
|
|
134
|
+
scrollDuration,
|
|
135
|
+
triggerSelector,
|
|
136
|
+
pinTargetSelector,
|
|
137
|
+
pinSpacing,
|
|
138
|
+
showMarkers,
|
|
139
|
+
])
|
|
140
|
+
|
|
141
|
+
if (!enabled) return <>{children}</>
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<section
|
|
145
|
+
id={safeId}
|
|
146
|
+
ref={sectionRef}
|
|
147
|
+
className="relative overflow-hidden"
|
|
148
|
+
data-parallax-wrapper="true"
|
|
149
|
+
>
|
|
150
|
+
<motion.div ref={innerRef} style={{ y }} className="relative will-change-transform">
|
|
151
|
+
{children}
|
|
152
|
+
</motion.div>
|
|
153
|
+
</section>
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export default ParallaxWrapper
|