well-petal 0.0.23 → 0.0.25
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/dist/petal.js +228 -0
- package/package.json +5 -2
- package/.gitattributes +0 -2
- package/.prettierrc +0 -5
- package/demo/index.html +0 -124
- package/demo/styles.css +0 -244
- package/src/animation.ts +0 -108
- package/src/banner.ts +0 -41
- package/src/lib/animations.ts +0 -76
- package/src/lib/attributes.ts +0 -48
- package/src/lib/breakpoints.ts +0 -4
- package/src/lib/console.ts +0 -51
- package/src/lib/elements.ts +0 -0
- package/src/lib/helpers.ts +0 -5
- package/src/lib/memory.ts +0 -54
- package/src/petal.css +0 -11
- package/src/petal.ts +0 -5
- package/src/popup.ts +0 -132
- package/src/video.ts +0 -6
- package/tsconfig.json +0 -24
- package/webpack.config.js +0 -58
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "well-petal",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.25",
|
|
4
4
|
"description": "Webflow Popups powered by attributes",
|
|
5
|
-
"main": "petal.js",
|
|
5
|
+
"main": "dist/petal.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
6
9
|
"scripts": {
|
|
7
10
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
11
|
"build": "webpack --config webpack.config.js",
|
package/.gitattributes
DELETED
package/.prettierrc
DELETED
package/demo/index.html
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Petal Popup Demo</title>
|
|
7
|
-
<link rel="stylesheet" href="styles.css" />
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<!-- Banner at top of page -->
|
|
11
|
-
<div petal-el="banner" petal="demo-banner" petal-session-ttl="5" class="banner">
|
|
12
|
-
<div class="banner-content">
|
|
13
|
-
<p>🎉 Welcome to Petal! This banner remembers you closed it for 5 minutes (set via petal-session-ttl).</p>
|
|
14
|
-
<button petal-el="banner-close" class="banner-close" aria-label="Close banner">×</button>
|
|
15
|
-
</div>
|
|
16
|
-
</div>
|
|
17
|
-
|
|
18
|
-
<div class="container">
|
|
19
|
-
<h1>Petal Popup Demo</h1>
|
|
20
|
-
<p>Click the buttons below to test different popup animations and configurations.</p>
|
|
21
|
-
|
|
22
|
-
<div class="buttons">
|
|
23
|
-
<!-- Scale Up Popup Trigger -->
|
|
24
|
-
<button petal-el="open" petal="scale-popup" class="btn">Open Scale Popup</button>
|
|
25
|
-
|
|
26
|
-
<!-- Slide Down Popup Trigger -->
|
|
27
|
-
<button petal-el="open" petal="slide-down-popup" class="btn">Open Slide Down Popup</button>
|
|
28
|
-
|
|
29
|
-
<!-- Slide Left Popup Trigger -->
|
|
30
|
-
<button petal-el="open" petal="slide-left-popup" class="btn">Open Slide Left Popup</button>
|
|
31
|
-
|
|
32
|
-
<!-- Mobile Responsive Popup Trigger -->
|
|
33
|
-
<button petal-el="open" petal="responsive-popup" class="btn">Open Responsive Popup</button>
|
|
34
|
-
|
|
35
|
-
<!-- Different Open/Close Animation Trigger -->
|
|
36
|
-
<button petal-el="open" petal="custom-mask-popup" class="btn">Open Different Animations Popup</button>
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
|
|
40
|
-
<!-- Scale Up Popup -->
|
|
41
|
-
<div petal-el="popup" petal="scale-popup" petal-anim-open="scale" petal-duration="0.5" petal-slot-opacity="0.5" class="popup">
|
|
42
|
-
<div petal-el="mask" petal-mask-opacity="0.15" class="mask"></div>
|
|
43
|
-
<div petal-el="slot" class="slot">
|
|
44
|
-
<div class="popup-content">
|
|
45
|
-
<h2>Scale Popup</h2>
|
|
46
|
-
<p>This popup uses a scale animation (auto-reverses on close).</p>
|
|
47
|
-
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
|
48
|
-
<button petal-el="close" petal="scale-popup" class="btn btn-close">Close</button>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
|
|
53
|
-
<!-- Slide Down Popup -->
|
|
54
|
-
<div petal-el="popup" petal="slide-down-popup" petal-anim-open="slide-down" petal-duration="0.6" petal-mask-close="true" class="popup">
|
|
55
|
-
<div petal-el="mask" petal-mask-opacity="0.2" class="mask"></div>
|
|
56
|
-
<div petal-el="slot" class="slot">
|
|
57
|
-
<div class="popup-content">
|
|
58
|
-
<h2>Slide Down Popup</h2>
|
|
59
|
-
<p>This popup slides down from the top when opening, slides up to the top when closing.</p>
|
|
60
|
-
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
|
|
61
|
-
<button petal-el="close" petal="slide-down-popup" class="btn btn-close">Close</button>
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
|
|
66
|
-
<!-- Slide Left Popup -->
|
|
67
|
-
<div petal-el="popup" petal="slide-left-popup" petal-anim-open="slide-left" petal-duration="0.6" class="popup">
|
|
68
|
-
<div petal-el="mask" petal-mask-opacity="0.2" class="mask"></div>
|
|
69
|
-
<div petal-el="slot" class="slot">
|
|
70
|
-
<div class="popup-content">
|
|
71
|
-
<h2>Slide Left Popup</h2>
|
|
72
|
-
<p>This popup slides in from the left when opening, slides up to the top when closing.</p>
|
|
73
|
-
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
|
|
74
|
-
<button petal-el="close" petal="slide-left-popup" class="btn btn-close">Close</button>
|
|
75
|
-
</div>
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
|
|
79
|
-
<!-- Responsive Popup (Different animations for mobile/desktop) -->
|
|
80
|
-
<div petal-el="popup" petal="responsive-popup" petal-anim-open="scale" petal-anim-open-mobile="slide-up" petal-duration="0.5" class="popup">
|
|
81
|
-
<div petal-el="mask" petal-mask-opacity="0.3" class="mask"></div>
|
|
82
|
-
<div petal-el="slot" class="slot">
|
|
83
|
-
<div class="popup-content">
|
|
84
|
-
<h2>Responsive Popup</h2>
|
|
85
|
-
<p>This popup uses scale on desktop and slide-up (from bottom) on mobile.</p>
|
|
86
|
-
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
|
|
87
|
-
<button petal-el="close" petal="responsive-popup" class="btn btn-close">Close</button>
|
|
88
|
-
</div>
|
|
89
|
-
</div>
|
|
90
|
-
</div>
|
|
91
|
-
|
|
92
|
-
<!-- Different Open/Close Animations -->
|
|
93
|
-
<div petal-el="popup" petal="custom-mask-popup" petal-anim-open="scale" petal-anim-close="slide-up" petal-duration="0.5" class="popup">
|
|
94
|
-
<div petal-el="mask" petal-mask-opacity="0.6" class="mask"></div>
|
|
95
|
-
<div petal-el="slot" class="slot">
|
|
96
|
-
<div class="popup-content">
|
|
97
|
-
<h2>Different Open/Close Animations</h2>
|
|
98
|
-
<p>This popup scales when opening and slides down (to the bottom) when closing!</p>
|
|
99
|
-
<p>Darker background mask (opacity: 0.6).</p>
|
|
100
|
-
<button petal-el="close" petal="custom-mask-popup" class="btn btn-close">Close</button>
|
|
101
|
-
</div>
|
|
102
|
-
</div>
|
|
103
|
-
</div>
|
|
104
|
-
|
|
105
|
-
<!-- Load GSAP -->
|
|
106
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
|
|
107
|
-
|
|
108
|
-
<!-- Load Petal -->
|
|
109
|
-
<script src="../dist/petal.js"></script>
|
|
110
|
-
|
|
111
|
-
<!-- Initialize Petal -->
|
|
112
|
-
<script>
|
|
113
|
-
// Initialize all popups and banners when page loads
|
|
114
|
-
if (window.petal) {
|
|
115
|
-
if (window.petal.initializeAllPopups) {
|
|
116
|
-
window.petal.initializeAllPopups();
|
|
117
|
-
}
|
|
118
|
-
if (window.petal.initializeBanner) {
|
|
119
|
-
window.petal.initializeBanner();
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
</script>
|
|
123
|
-
</body>
|
|
124
|
-
</html>
|
package/demo/styles.css
DELETED
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
/* Reset and Base Styles */
|
|
2
|
-
* {
|
|
3
|
-
margin: 0;
|
|
4
|
-
padding: 0;
|
|
5
|
-
box-sizing: border-box;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
body {
|
|
9
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
10
|
-
line-height: 1.6;
|
|
11
|
-
color: #333;
|
|
12
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
13
|
-
min-height: 100vh;
|
|
14
|
-
padding: 20px;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/* Banner Styles */
|
|
18
|
-
.banner {
|
|
19
|
-
position: fixed;
|
|
20
|
-
top: 0;
|
|
21
|
-
left: 0;
|
|
22
|
-
right: 0;
|
|
23
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
24
|
-
color: white;
|
|
25
|
-
z-index: 10000;
|
|
26
|
-
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.banner-content {
|
|
30
|
-
max-width: 1200px;
|
|
31
|
-
margin: 0 auto;
|
|
32
|
-
padding: 12px 20px;
|
|
33
|
-
display: flex;
|
|
34
|
-
align-items: center;
|
|
35
|
-
justify-content: space-between;
|
|
36
|
-
gap: 20px;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.banner-content p {
|
|
40
|
-
margin: 0;
|
|
41
|
-
color: white;
|
|
42
|
-
font-size: 14px;
|
|
43
|
-
font-weight: 500;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.banner-close {
|
|
47
|
-
background: rgba(255, 255, 255, 0.2);
|
|
48
|
-
border: none;
|
|
49
|
-
color: white;
|
|
50
|
-
font-size: 24px;
|
|
51
|
-
width: 32px;
|
|
52
|
-
height: 32px;
|
|
53
|
-
border-radius: 50%;
|
|
54
|
-
cursor: pointer;
|
|
55
|
-
display: flex;
|
|
56
|
-
align-items: center;
|
|
57
|
-
justify-content: center;
|
|
58
|
-
transition: all 0.2s ease;
|
|
59
|
-
flex-shrink: 0;
|
|
60
|
-
line-height: 1;
|
|
61
|
-
padding: 0;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.banner-close:hover {
|
|
65
|
-
background: rgba(255, 255, 255, 0.3);
|
|
66
|
-
transform: scale(1.1);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.banner-close:active {
|
|
70
|
-
transform: scale(0.95);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/* Adjust body padding when banner is visible */
|
|
74
|
-
body {
|
|
75
|
-
padding-top: 70px;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/* Container */
|
|
79
|
-
.container {
|
|
80
|
-
max-width: 800px;
|
|
81
|
-
margin: 0 auto;
|
|
82
|
-
background: white;
|
|
83
|
-
padding: 40px;
|
|
84
|
-
border-radius: 12px;
|
|
85
|
-
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
h1 {
|
|
89
|
-
color: #667eea;
|
|
90
|
-
margin-bottom: 10px;
|
|
91
|
-
font-size: 2.5rem;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
p {
|
|
95
|
-
color: #666;
|
|
96
|
-
margin-bottom: 20px;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/* Buttons */
|
|
100
|
-
.buttons {
|
|
101
|
-
display: flex;
|
|
102
|
-
flex-wrap: wrap;
|
|
103
|
-
gap: 15px;
|
|
104
|
-
margin-top: 30px;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.btn {
|
|
108
|
-
padding: 12px 24px;
|
|
109
|
-
background: #667eea;
|
|
110
|
-
color: white;
|
|
111
|
-
border: none;
|
|
112
|
-
border-radius: 8px;
|
|
113
|
-
font-size: 16px;
|
|
114
|
-
font-weight: 600;
|
|
115
|
-
cursor: pointer;
|
|
116
|
-
transition: all 0.3s ease;
|
|
117
|
-
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.btn:hover {
|
|
121
|
-
background: #5568d3;
|
|
122
|
-
transform: translateY(-2px);
|
|
123
|
-
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.4);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.btn:active {
|
|
127
|
-
transform: translateY(0);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/* Popup Structure */
|
|
131
|
-
.popup {
|
|
132
|
-
position: fixed;
|
|
133
|
-
top: 0;
|
|
134
|
-
left: 0;
|
|
135
|
-
width: 100%;
|
|
136
|
-
height: 100%;
|
|
137
|
-
display: none;
|
|
138
|
-
align-items: center;
|
|
139
|
-
justify-content: center;
|
|
140
|
-
z-index: 9999;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/* Mask (Background Overlay) */
|
|
144
|
-
.mask {
|
|
145
|
-
position: absolute;
|
|
146
|
-
top: 0;
|
|
147
|
-
left: 0;
|
|
148
|
-
width: 100%;
|
|
149
|
-
height: 100%;
|
|
150
|
-
background: black;
|
|
151
|
-
opacity: 0;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/* Slot (Popup Content Container) */
|
|
155
|
-
.slot {
|
|
156
|
-
position: relative;
|
|
157
|
-
z-index: 10000;
|
|
158
|
-
max-width: 90%;
|
|
159
|
-
max-height: 90vh;
|
|
160
|
-
overflow: auto;
|
|
161
|
-
opacity: 0;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/* Popup Content */
|
|
165
|
-
.popup-content {
|
|
166
|
-
background: white;
|
|
167
|
-
padding: 40px;
|
|
168
|
-
border-radius: 16px;
|
|
169
|
-
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
170
|
-
max-width: 500px;
|
|
171
|
-
width: 100%;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
.popup-content h2 {
|
|
175
|
-
color: #667eea;
|
|
176
|
-
margin-bottom: 15px;
|
|
177
|
-
font-size: 2rem;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
.popup-content p {
|
|
181
|
-
margin-bottom: 15px;
|
|
182
|
-
line-height: 1.8;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
.popup-content p:last-of-type {
|
|
186
|
-
margin-bottom: 25px;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/* Close Button */
|
|
190
|
-
.btn-close {
|
|
191
|
-
background: #dc3545;
|
|
192
|
-
width: 100%;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
.btn-close:hover {
|
|
196
|
-
background: #c82333;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/* Mobile Responsive */
|
|
200
|
-
@media (max-width: 768px) {
|
|
201
|
-
.container {
|
|
202
|
-
padding: 20px;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
h1 {
|
|
206
|
-
font-size: 2rem;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
.buttons {
|
|
210
|
-
flex-direction: column;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.btn {
|
|
214
|
-
width: 100%;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
.popup-content {
|
|
218
|
-
padding: 30px 20px;
|
|
219
|
-
max-width: 95%;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.popup-content h2 {
|
|
223
|
-
font-size: 1.5rem;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/* Scrollbar Styling for Popup Slot */
|
|
228
|
-
.slot::-webkit-scrollbar {
|
|
229
|
-
width: 8px;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
.slot::-webkit-scrollbar-track {
|
|
233
|
-
background: #f1f1f1;
|
|
234
|
-
border-radius: 10px;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
.slot::-webkit-scrollbar-thumb {
|
|
238
|
-
background: #667eea;
|
|
239
|
-
border-radius: 10px;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
.slot::-webkit-scrollbar-thumb:hover {
|
|
243
|
-
background: #5568d3;
|
|
244
|
-
}
|
package/src/animation.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
animateScaleUp,
|
|
3
|
-
animateOpenSlideUp,
|
|
4
|
-
animateOpenSlideDown,
|
|
5
|
-
animateOpenSlideLeft,
|
|
6
|
-
animateOpenSlideRight,
|
|
7
|
-
animateScaleDown,
|
|
8
|
-
animateCloseSlideUp,
|
|
9
|
-
animateCloseSlideDown,
|
|
10
|
-
animateCloseSlideLeft,
|
|
11
|
-
animateCloseSlideRight,
|
|
12
|
-
} from "./lib/animations";
|
|
13
|
-
import { ATTR_PETAL_ANIM_OPEN, ATTR_PETAL_ANIM_CLOSE, ATTR_PETAL_ANIM_OPEN_MOBILE, ATTR_PETAL_ANIM_CLOSE_MOBILE, ATTR_PETAL_DURATION } from "./lib/attributes";
|
|
14
|
-
import { isMobile } from "./lib/breakpoints";
|
|
15
|
-
|
|
16
|
-
// Popup animation types
|
|
17
|
-
export type PopupAnimation = "scale" | "slide-up" | "slide-down" | "slide-left" | "slide-right";
|
|
18
|
-
const validAnimations: PopupAnimation[] = ["scale", "slide-up", "slide-down", "slide-left", "slide-right"];
|
|
19
|
-
|
|
20
|
-
const animationOpenMap: Record<PopupAnimation, () => GSAPTweenVars> = {
|
|
21
|
-
scale: animateScaleUp,
|
|
22
|
-
"slide-up": animateOpenSlideUp,
|
|
23
|
-
"slide-down": animateOpenSlideDown,
|
|
24
|
-
"slide-left": animateOpenSlideLeft,
|
|
25
|
-
"slide-right": animateOpenSlideRight,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const animationCloseMap: Record<PopupAnimation, () => GSAPTweenVars> = {
|
|
29
|
-
scale: animateScaleDown,
|
|
30
|
-
"slide-up": animateCloseSlideUp,
|
|
31
|
-
"slide-down": animateCloseSlideDown,
|
|
32
|
-
"slide-left": animateCloseSlideLeft,
|
|
33
|
-
"slide-right": animateCloseSlideRight,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
// Map open animations to their corresponding close animations
|
|
37
|
-
const reverseAnimationMap: Record<PopupAnimation, PopupAnimation> = {
|
|
38
|
-
scale: "scale",
|
|
39
|
-
"slide-up": "slide-down",
|
|
40
|
-
"slide-down": "slide-up",
|
|
41
|
-
"slide-left": "slide-right",
|
|
42
|
-
"slide-right": "slide-left",
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Creates GSAP animation based on the popup's attributes
|
|
47
|
-
* @param popup The Popup element
|
|
48
|
-
* @param direction Open or Close
|
|
49
|
-
* @returns GSAP animation vars for the popup
|
|
50
|
-
*/
|
|
51
|
-
export function getPopupGSAPAnimation(popup: HTMLElement, direction: "open" | "close"): GSAPTweenVars {
|
|
52
|
-
// Determine the name of the animation to perform
|
|
53
|
-
let animationName = getAnimationName(popup, direction);
|
|
54
|
-
|
|
55
|
-
// Get the animation function
|
|
56
|
-
let anim;
|
|
57
|
-
if (direction === "open") anim = animationOpenMap[animationName]();
|
|
58
|
-
else anim = animationCloseMap[animationName]();
|
|
59
|
-
|
|
60
|
-
// Set the animation duration
|
|
61
|
-
const duration = parseFloat(popup.getAttribute(ATTR_PETAL_DURATION) || "0.5");
|
|
62
|
-
anim.to.duration = duration;
|
|
63
|
-
|
|
64
|
-
return anim;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
*
|
|
69
|
-
* @param popup The Popup element
|
|
70
|
-
* @param direction Open or Close
|
|
71
|
-
* @returns The name of the animation to perform
|
|
72
|
-
*/
|
|
73
|
-
function getAnimationName(popup: HTMLElement, direction: "open" | "close"): PopupAnimation {
|
|
74
|
-
const openDesktop = getPopupAnimation(popup, ATTR_PETAL_ANIM_OPEN);
|
|
75
|
-
const openMobile = getPopupAnimation(popup, ATTR_PETAL_ANIM_OPEN_MOBILE);
|
|
76
|
-
|
|
77
|
-
const closeDesktop = getPopupAnimation(popup, ATTR_PETAL_ANIM_CLOSE);
|
|
78
|
-
const closeMobile = getPopupAnimation(popup, ATTR_PETAL_ANIM_CLOSE_MOBILE);
|
|
79
|
-
|
|
80
|
-
if (direction === "open") {
|
|
81
|
-
if (isMobile()) return openMobile;
|
|
82
|
-
else return openDesktop;
|
|
83
|
-
}
|
|
84
|
-
// If closing
|
|
85
|
-
else {
|
|
86
|
-
const hasCloseDesktop = popup.hasAttribute(ATTR_PETAL_ANIM_CLOSE);
|
|
87
|
-
const hasCloseMobile = popup.hasAttribute(ATTR_PETAL_ANIM_CLOSE_MOBILE);
|
|
88
|
-
|
|
89
|
-
if (isMobile()) {
|
|
90
|
-
// If no mobile close animation is set, use the reverse of the open animation
|
|
91
|
-
return hasCloseMobile ? closeMobile : reverseAnimationMap[openMobile];
|
|
92
|
-
} else {
|
|
93
|
-
// If no desktop close animation is set, use the reverse of the open animation
|
|
94
|
-
return hasCloseDesktop ? closeDesktop : reverseAnimationMap[openDesktop];
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Validate popup animation string
|
|
100
|
-
export function isPopupAnimation(value: string): value is PopupAnimation {
|
|
101
|
-
return validAnimations.includes(value as PopupAnimation);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Safe parser with fallback
|
|
105
|
-
function getPopupAnimation(popup: HTMLElement, attr: string): PopupAnimation {
|
|
106
|
-
const raw = popup.getAttribute(attr);
|
|
107
|
-
return isPopupAnimation(raw ?? "") ? (raw as PopupAnimation) : "slide-up";
|
|
108
|
-
}
|
package/src/banner.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { ATTR_PETAL_BANNER, ATTR_PETAL_BANNER_CLOSE, ATTR_PETAL_NAME, ATTR_PETAL_ELEMENT, ATTR_PETAL_SESSION_TTL, PetalElements } from "./lib/attributes";
|
|
2
|
-
import { getAllPetalElementsOfType } from "./lib/helpers";
|
|
3
|
-
import { storeClosedState, checkClosedState } from "./lib/memory";
|
|
4
|
-
|
|
5
|
-
export function initializeBanner() {
|
|
6
|
-
const banners = getAllPetalElementsOfType(ATTR_PETAL_BANNER);
|
|
7
|
-
banners.forEach((banner) => {
|
|
8
|
-
const name = banner.getAttribute(ATTR_PETAL_NAME);
|
|
9
|
-
if (!name) return;
|
|
10
|
-
|
|
11
|
-
const closeButtons = banner.querySelectorAll(`[${ATTR_PETAL_ELEMENT}="${ATTR_PETAL_BANNER_CLOSE}"]`);
|
|
12
|
-
|
|
13
|
-
// Get session TTL in minutes (default: 1440 minutes = 24 hours)
|
|
14
|
-
const sessionTTLMinutes = parseFloat(banner.getAttribute(ATTR_PETAL_SESSION_TTL) || "1440");
|
|
15
|
-
|
|
16
|
-
// Create PetalElements object for memory functions
|
|
17
|
-
const petal: PetalElements = {
|
|
18
|
-
name,
|
|
19
|
-
trigger: banner,
|
|
20
|
-
popup: banner as HTMLElement,
|
|
21
|
-
mask: banner,
|
|
22
|
-
slot: banner
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
// Check if banner was closed and session is still valid
|
|
26
|
-
if (checkClosedState("banner", petal, sessionTTLMinutes)) {
|
|
27
|
-
// If closed and session valid, hide the banner
|
|
28
|
-
(banner as HTMLElement).style.display = "none";
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Add click event listeners to close buttons
|
|
32
|
-
closeButtons.forEach((closeButton) => {
|
|
33
|
-
closeButton.addEventListener("click", () => {
|
|
34
|
-
// Hide the banner
|
|
35
|
-
(banner as HTMLElement).style.display = "none";
|
|
36
|
-
// Store closed state in sessionStorage with timestamp
|
|
37
|
-
storeClosedState("banner", petal);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
}
|
package/src/lib/animations.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
export function animateScaleUp(): GSAPTweenVars {
|
|
2
|
-
return {
|
|
3
|
-
from: { scale: 0, opacity: 0 },
|
|
4
|
-
to: { scale: 1, opacity: 1, ease: "power3.inOut" },
|
|
5
|
-
};
|
|
6
|
-
}
|
|
7
|
-
export function animateScaleDown(): GSAPTweenVars {
|
|
8
|
-
return {
|
|
9
|
-
from: { scale: 1, opacity: 0 },
|
|
10
|
-
to: { scale: 0, opacity: 1, ease: "power3.inOut" },
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
export function animateOpenSlideUp(): GSAPTweenVars {
|
|
14
|
-
return {
|
|
15
|
-
from: { y: "100%", x: "0%", opacity: 0 }, // From bottom
|
|
16
|
-
to: { y: "0%", x: "0%", opacity: 1, ease: "power3.inOut" }, // To top
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
export function animateOpenSlideDown(): GSAPTweenVars {
|
|
20
|
-
return {
|
|
21
|
-
from: { y: "-100%", x: "0%", opacity: 0 }, // From top
|
|
22
|
-
to: { y: "0%", x: "0%", opacity: 1, ease: "power3.inOut" }, // To bottom
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
export function animateOpenSlideRight(): GSAPTweenVars {
|
|
26
|
-
return {
|
|
27
|
-
from: { x: "-100%", y: "0%", opacity: 0 }, // From left
|
|
28
|
-
to: { x: "0%", y: "0%", opacity: 1, ease: "power3.inOut" }, // To center
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
export function animateOpenSlideLeft(): GSAPTweenVars {
|
|
32
|
-
return {
|
|
33
|
-
from: { x: "100%", y: "0%", opacity: 0 }, // From right
|
|
34
|
-
to: { x: "0%", y: "0%", opacity: 1, ease: "power3.inOut" }, // To center
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
export function animateCloseSlideUp(): GSAPTweenVars {
|
|
38
|
-
return {
|
|
39
|
-
from: { y: "0%", x: "0%", opacity: 1 }, // From bottom
|
|
40
|
-
to: { y: "-100%", x: "0%", opacity: 0, ease: "power3.inOut" }, // To top
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
export function animateCloseSlideDown(): GSAPTweenVars {
|
|
44
|
-
return {
|
|
45
|
-
from: { y: "0%", x: "0%", opacity: 1 }, // From top
|
|
46
|
-
to: { y: "100%", x: "0%", opacity: 0, ease: "power3.inOut" }, // To bottom
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
export function animateCloseSlideRight(): GSAPTweenVars {
|
|
50
|
-
return {
|
|
51
|
-
from: { x: "0%", y: "0%", opacity: 1 }, // From left
|
|
52
|
-
to: { x: "100%", y: "0%", opacity: 0, ease: "power3.inOut" }, // To center
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
export function animateCloseSlideLeft(): GSAPTweenVars {
|
|
56
|
-
return {
|
|
57
|
-
from: { x: "0%", y: "0%", opacity: 1 }, // From right
|
|
58
|
-
to: { x: "-100%", y: "0%", opacity: 0, ease: "power3.inOut" }, // To center
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Mask animations
|
|
63
|
-
|
|
64
|
-
export function animateMaskOpen(opacity: number): GSAPTweenVars {
|
|
65
|
-
return {
|
|
66
|
-
from: { opacity: 0 },
|
|
67
|
-
to: { opacity: opacity, duration: 0.5 },
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function animateMaskClosed(opacity: number): GSAPTweenVars {
|
|
72
|
-
return {
|
|
73
|
-
from: { opacity: opacity },
|
|
74
|
-
to: { opacity: 0, duration: 0.5 },
|
|
75
|
-
};
|
|
76
|
-
}
|
package/src/lib/attributes.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
export interface PetalElements {
|
|
2
|
-
name: string;
|
|
3
|
-
trigger: Element;
|
|
4
|
-
popup: HTMLElement;
|
|
5
|
-
mask: Element;
|
|
6
|
-
slot: Element;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
// BASE
|
|
10
|
-
export const ATTR_PETAL_NAME = "petal";
|
|
11
|
-
export const ATTR_PETAL_ELEMENT = "petal-el";
|
|
12
|
-
|
|
13
|
-
// BEHAVIOR
|
|
14
|
-
export const ATTR_PETAL_SHOW_ONCE = "petal-show-once"; // Regardless of other settings, only show the popup once per user session
|
|
15
|
-
export const ATTR_PETAL_SHOW_DELAY = "petal-show-delay"; // Time to wait before showing popup (in seconds)
|
|
16
|
-
export const ATTR_PETAL_SESSION_TTL = "petal-session-ttl"; // Time to keep user session (in hours)
|
|
17
|
-
|
|
18
|
-
/**-------------------------*
|
|
19
|
-
* POPUP
|
|
20
|
-
*--------------------------*/
|
|
21
|
-
|
|
22
|
-
// ELEMENTS
|
|
23
|
-
export const ATTR_PETAL_POPUP = "popup";
|
|
24
|
-
export const ATTR_PETAL_OPEN = "open";
|
|
25
|
-
export const ATTR_PETAL_CLOSE = "close";
|
|
26
|
-
export const ATTR_PETAL_MASK = "mask";
|
|
27
|
-
export const ATTR_PETAL_SLOT = "slot";
|
|
28
|
-
|
|
29
|
-
// MASK
|
|
30
|
-
export const ATTR_PETAL_MASK_OPACITY = "petal-mask-opacity";
|
|
31
|
-
export const ATTR_PETAL_MASK_CLOSE = "petal-mask-close";
|
|
32
|
-
|
|
33
|
-
// ANIMATIONS
|
|
34
|
-
export const ATTR_PETAL_ANIM_OPEN = "petal-anim-open";
|
|
35
|
-
export const ATTR_PETAL_ANIM_CLOSE = "petal-anim-close";
|
|
36
|
-
export const ATTR_PETAL_ANIM_OPEN_MOBILE = "petal-anim-open-mobile";
|
|
37
|
-
export const ATTR_PETAL_ANIM_CLOSE_MOBILE = "petal-anim-close-mobile";
|
|
38
|
-
export const ATTR_PETAL_DURATION = "petal-duration";
|
|
39
|
-
|
|
40
|
-
/**-------------------------*
|
|
41
|
-
* BANNER
|
|
42
|
-
*--------------------------*/
|
|
43
|
-
|
|
44
|
-
// ELEMENTS
|
|
45
|
-
export const ATTR_PETAL_BANNER = "banner";
|
|
46
|
-
export const ATTR_PETAL_BANNER_CLOSE = "banner-close";
|
|
47
|
-
|
|
48
|
-
export const ATTR_PETAL_BANNER_CLOSED_CLASS = "petal-hide-nav-banner";
|
package/src/lib/breakpoints.ts
DELETED