svelte-confetti-explosion 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ConfettiExplosion.svelte +243 -293
- package/ConfettiExplosion.svelte.d.ts +126 -126
- package/LICENSE +21 -21
- package/README.md +2 -6
- package/index.d.ts +1 -1
- package/index.js +3 -1
- package/package.json +1 -1
package/ConfettiExplosion.svelte
CHANGED
|
@@ -1,295 +1,245 @@
|
|
|
1
|
-
<script
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* @default
|
|
134
|
-
*
|
|
135
|
-
* @example
|
|
136
|
-
*
|
|
137
|
-
* ```svelte
|
|
138
|
-
* <ConfettiExplosion
|
|
139
|
-
* ```
|
|
140
|
-
*/
|
|
141
|
-
export let
|
|
142
|
-
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* @
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* ```
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
*
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
*
|
|
217
|
-
|
|
218
|
-
*
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
const rotationIndex = Math.round(Math.random() * (rotationTransforms.length - 1));
|
|
244
|
-
const durationChaos = duration - Math.round(Math.random() * 1000);
|
|
245
|
-
const shouldBeCrazy = Math.random() < CRAZY_PARTICLES_FREQUENCY;
|
|
246
|
-
const isCircle = particlesShape !== 'rectangles' &&
|
|
247
|
-
(particlesShape === 'circles' || shouldBeCircle(rotationIndex));
|
|
248
|
-
// x-axis disturbance, roughly the distance the particle will initially deviate from its target
|
|
249
|
-
const x1 = shouldBeCrazy ? round(Math.random() * CRAZY_PARTICLE_CRAZINESS, 2) : 0;
|
|
250
|
-
const x2 = x1 * -1;
|
|
251
|
-
const x3 = x1;
|
|
252
|
-
// x-axis arc of explosion, so 90deg and 270deg particles have curve of 1, 0deg and 180deg have 0
|
|
253
|
-
const x4 = round(Math.abs(mapRange(Math.abs(rotate(degree, 90) - 180), 0, 180, -1, 1)), 4);
|
|
254
|
-
// roughly how fast particle reaches end of its explosion curve
|
|
255
|
-
const y1 = round(Math.random() * BEZIER_MEDIAN, 4);
|
|
256
|
-
// roughly maps to the distance particle goes before reaching free-fall
|
|
257
|
-
const y2 = round(Math.random() * force * (coinFlip() ? 1 : -1), 4);
|
|
258
|
-
// roughly how soon the particle transitions from explosion to free-fall
|
|
259
|
-
const y3 = BEZIER_MEDIAN;
|
|
260
|
-
// roughly the ease of free-fall
|
|
261
|
-
const y4 = round(Math.max(mapRange(Math.abs(degree - 180), 0, 180, force, -force), 0), 4);
|
|
262
|
-
const setCSSVar = (key, val) => node.style.setProperty(key, val + '');
|
|
263
|
-
setCSSVar('--x-landing-point', `${landingPoint}px`);
|
|
264
|
-
setCSSVar('--duration-chaos', `${durationChaos}ms`);
|
|
265
|
-
setCSSVar('--x1', `${x1}`);
|
|
266
|
-
setCSSVar('--x2', `${x2}`);
|
|
267
|
-
setCSSVar('--x3', `${x3}`);
|
|
268
|
-
setCSSVar('--x4', `${x4}`);
|
|
269
|
-
setCSSVar('--y1', `${y1}`);
|
|
270
|
-
setCSSVar('--y2', `${y2}`);
|
|
271
|
-
setCSSVar('--y3', `${y3}`);
|
|
272
|
-
setCSSVar('--y4', `${y4}`);
|
|
273
|
-
// set --width and --height here
|
|
274
|
-
setCSSVar('--width', `${isCircle ? particleSize : Math.round(Math.random() * 4) + particleSize / 2}px`);
|
|
275
|
-
setCSSVar('--height', (isCircle ? particleSize : Math.round(Math.random() * 2) + particleSize) + 'px');
|
|
276
|
-
setCSSVar('--rotation', `${rotationTransforms[rotationIndex].join()}`);
|
|
277
|
-
setCSSVar('--rotation-duration', `${rotation}ms`);
|
|
278
|
-
setCSSVar('--border-radius', `${isCircle ? '50%' : '0'}`);
|
|
279
|
-
}
|
|
280
|
-
</script>
|
|
281
|
-
|
|
282
|
-
{#if isVisible && isValid}
|
|
283
|
-
<div class="container" style="--floor-height: {stageHeight}px;">
|
|
284
|
-
{#each particles as { color, degree }}
|
|
285
|
-
<div class="particle" use:confettiStyles={{ degree }}>
|
|
286
|
-
<div style="--bgcolor: {color};" />
|
|
287
|
-
</div>
|
|
288
|
-
{/each}
|
|
289
|
-
</div>
|
|
290
|
-
{/if}
|
|
291
|
-
|
|
292
|
-
<style >@keyframes y-axis {
|
|
1
|
+
<script context="module">"use strict";
|
|
2
|
+
const ROTATION_SPEED_MIN = 200; // minimum possible duration of single particle full rotation
|
|
3
|
+
const ROTATION_SPEED_MAX = 800; // maximum possible duration of single particle full rotation
|
|
4
|
+
const CRAZY_PARTICLES_FREQUENCY = 0.1; // 0-1 frequency of crazy curvy unpredictable particles
|
|
5
|
+
const CRAZY_PARTICLE_CRAZINESS = 0.3; // 0-1 how crazy these crazy particles are
|
|
6
|
+
const BEZIER_MEDIAN = 0.5; // utility for mid-point bezier curves, to ensure smooth motion paths
|
|
7
|
+
const FORCE = 0.5; // 0-1 roughly the vertical force at which particles initially explode
|
|
8
|
+
const SIZE = 12; // max height for particle rectangles, diameter for particle circles
|
|
9
|
+
const FLOOR_HEIGHT = 800; // pixels the particles will fall from initial explosion point
|
|
10
|
+
const FLOOR_WIDTH = 1600; // horizontal spread of particles in pixels
|
|
11
|
+
const PARTICLE_COUNT = 150;
|
|
12
|
+
const DURATION = 3500;
|
|
13
|
+
const COLORS = ['#FFC700', '#F00', '#2E3191', '#41BBC7'];
|
|
14
|
+
const abs = Math.abs, random = Math.random, mathRound = Math.round, max = Math.max;
|
|
15
|
+
const createParticles = (count, colors) => {
|
|
16
|
+
const increment = 360 / count;
|
|
17
|
+
return Array.from({ length: count }, (_, i) => ({
|
|
18
|
+
color: colors[i % colors.length],
|
|
19
|
+
degree: i * increment,
|
|
20
|
+
}));
|
|
21
|
+
};
|
|
22
|
+
const waitFor = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
23
|
+
// From here: https://stackoverflow.com/a/11832950
|
|
24
|
+
const round = (num, precision = 2) => mathRound((num + Number.EPSILON) * 10 ** precision) / 10 ** precision;
|
|
25
|
+
const mapRange = (value, x1, y1, x2, y2) => ((value - x1) * (y2 - x2)) / (y1 - x1) + x2;
|
|
26
|
+
const rotate = (degree, amount) => degree + amount > 360 ? degree + amount - 360 : degree + amount;
|
|
27
|
+
const coinFlip = () => random() > 0.5;
|
|
28
|
+
// We can use the first three bits to flag which axis to rotate on.
|
|
29
|
+
// x = binary 100 = decimal 4
|
|
30
|
+
// y = binary 010 = decimal 2
|
|
31
|
+
// z = binary 001 = decimal 1
|
|
32
|
+
// We can use dual axis rotations (a bit more realistic) by combining the above bits.
|
|
33
|
+
// x & y = binary 110 = decimal 6
|
|
34
|
+
// x & z = binary 101 = decimal 5
|
|
35
|
+
// y & z = binary 011 = decimal 3
|
|
36
|
+
const POSSIBLE_ROTATION_TRANSFORMS = 6;
|
|
37
|
+
// avoid rotation on z axis (001 = 1) for circles as it has no visual effect.
|
|
38
|
+
const shouldBeCircle = (rotationTransform) => rotationTransform !== 1 && coinFlip();
|
|
39
|
+
const isUndefined = (value) => typeof value === 'undefined';
|
|
40
|
+
const error = (message) => {
|
|
41
|
+
console.error(message);
|
|
42
|
+
return false;
|
|
43
|
+
};
|
|
44
|
+
const assertPositiveInteger = (val, name) => !isUndefined(val) && Number.isSafeInteger(val) && val < 0
|
|
45
|
+
? error(name + ' must be a positive integer')
|
|
46
|
+
: true;
|
|
47
|
+
const validate = (particleCount, duration, colors, particleSize, force, stageHeight, stageWidth, particlesShape) => {
|
|
48
|
+
if (!assertPositiveInteger(particleCount, 'particleCount') ||
|
|
49
|
+
!assertPositiveInteger(duration, 'duration') ||
|
|
50
|
+
!assertPositiveInteger(particleSize, 'particleSize') ||
|
|
51
|
+
!assertPositiveInteger(force, 'force') ||
|
|
52
|
+
!assertPositiveInteger(stageHeight, 'floorHeight') ||
|
|
53
|
+
!assertPositiveInteger(stageWidth, 'floorWidth')) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (!isUndefined(particlesShape) &&
|
|
57
|
+
!['mix', 'circles', 'rectangles'].includes(particlesShape)) {
|
|
58
|
+
return error('particlesShape should be either "mix" or "circles" or "rectangle"');
|
|
59
|
+
}
|
|
60
|
+
if (!isUndefined(colors) && !Array.isArray(colors)) {
|
|
61
|
+
return error('colors must be an array of strings');
|
|
62
|
+
}
|
|
63
|
+
if (force > 1) {
|
|
64
|
+
return error('force must be within 0 and 1');
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
};
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<script>import { onMount } from 'svelte';
|
|
71
|
+
/**
|
|
72
|
+
* Number of confetti particles to create
|
|
73
|
+
*
|
|
74
|
+
* @default 150
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
*
|
|
78
|
+
* ```svelte
|
|
79
|
+
* <ConfettiExplosion particleCount={200} />
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export let particleCount = PARTICLE_COUNT;
|
|
83
|
+
/**
|
|
84
|
+
* Size of the confetti particles in pixels
|
|
85
|
+
*
|
|
86
|
+
* @default 12
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
*
|
|
90
|
+
* ```svelte
|
|
91
|
+
* <ConfettiExplosion particleSize={20} />
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export let particleSize = SIZE;
|
|
95
|
+
/**
|
|
96
|
+
* Duration of the animation in milliseconds
|
|
97
|
+
*
|
|
98
|
+
* @default 3500
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
*
|
|
102
|
+
* ```svelte
|
|
103
|
+
* <ConfettiExplosion duration={5000} />
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export let duration = DURATION;
|
|
107
|
+
/**
|
|
108
|
+
* Shape of particles to use. Can be `mix`, `circles` or `rectangles`
|
|
109
|
+
*
|
|
110
|
+
* `mix` will use both circles and rectangles
|
|
111
|
+
* `circles` will use only circles
|
|
112
|
+
* `rectangles` will use only rectangles
|
|
113
|
+
*
|
|
114
|
+
* @default 'mix'
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
*
|
|
118
|
+
* ```svelte
|
|
119
|
+
* <ConfettiExplosion particlesShape='circles' />
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
*
|
|
124
|
+
* ```svelte
|
|
125
|
+
* <ConfettiExplosion particlesShape='rectangles' />
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export let particlesShape = 'mix';
|
|
129
|
+
/**
|
|
130
|
+
* Colors to use for the confetti particles. Pass string array of colors. Can use hex colors, named colors,
|
|
131
|
+
* CSS Variables, literally anything valid in plain CSS.
|
|
132
|
+
*
|
|
133
|
+
* @default ['#FFC700', '#FF0000', '#2E3191', '#41BBC7']
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
*
|
|
137
|
+
* ```svelte
|
|
138
|
+
* <ConfettiExplosion colors={['var(--yellow)', 'var(--red)', '#2E3191', '#41BBC7']} />
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export let colors = COLORS;
|
|
142
|
+
/**
|
|
143
|
+
* Force of the confetti particles. Between 0 and 1. 0 is no force, 1 is maximum force.
|
|
144
|
+
*
|
|
145
|
+
* @default 0.5
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
*
|
|
149
|
+
* ```svelte
|
|
150
|
+
* <ConfettiExplosion force={0.8} />
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
export let force = FORCE;
|
|
154
|
+
/**
|
|
155
|
+
* Height of the stage in pixels. Confetti will only fall within this height.
|
|
156
|
+
*
|
|
157
|
+
* @default 800
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
*
|
|
161
|
+
* ```svelte
|
|
162
|
+
* <ConfettiExplosion floorHeight={500} />
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export let stageHeight = FLOOR_HEIGHT;
|
|
166
|
+
/**
|
|
167
|
+
* Width of the stage in pixels. Confetti will only fall within this width.
|
|
168
|
+
*
|
|
169
|
+
* @default 1600
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
*
|
|
173
|
+
* ```svelte
|
|
174
|
+
* <ConfettiExplosion floorWidth={1000} />
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
export let stageWidth = FLOOR_WIDTH;
|
|
178
|
+
/**
|
|
179
|
+
* Whether or not destroy all confetti nodes after the `duration` period has passed. By default it destroys all nodes, to preserve memory.
|
|
180
|
+
*
|
|
181
|
+
* @default true
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
*
|
|
185
|
+
* ```svelte
|
|
186
|
+
* <ConfettiExplosion shouldDestroyAfterDone={false} />
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export let shouldDestroyAfterDone = true;
|
|
190
|
+
let isVisible = true;
|
|
191
|
+
$: particles = createParticles(particleCount, colors);
|
|
192
|
+
$: isValid = validate(particleCount, duration, colors, particleSize, force, stageHeight, stageWidth, particlesShape);
|
|
193
|
+
onMount(async () => {
|
|
194
|
+
await waitFor(duration);
|
|
195
|
+
if (shouldDestroyAfterDone) {
|
|
196
|
+
isVisible = false;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
function confettiStyles(node, degree) {
|
|
200
|
+
// Crazy calculations for generating styles
|
|
201
|
+
const rotationTransform = mathRound(random() * (POSSIBLE_ROTATION_TRANSFORMS - 1));
|
|
202
|
+
const isCircle = particlesShape !== 'rectangles' &&
|
|
203
|
+
(particlesShape === 'circles' || shouldBeCircle(rotationTransform));
|
|
204
|
+
const setCSSVar = (key, val) => node.style.setProperty(key, val + '');
|
|
205
|
+
// Get x landing point for it
|
|
206
|
+
setCSSVar('--x-landing-point', mapRange(abs(rotate(degree, 90) - 180), 0, 180, -stageWidth / 2, stageWidth / 2) + 'px');
|
|
207
|
+
setCSSVar('--duration-chaos', duration - mathRound(random() * 1e3) + 'ms');
|
|
208
|
+
// x-axis disturbance, roughly the distance the particle will initially deviate from its target
|
|
209
|
+
const x1 = random() < CRAZY_PARTICLES_FREQUENCY ? round(random() * CRAZY_PARTICLE_CRAZINESS, 2) : 0;
|
|
210
|
+
setCSSVar('--x1', x1);
|
|
211
|
+
setCSSVar('--x2', x1 * -1);
|
|
212
|
+
setCSSVar('--x3', x1);
|
|
213
|
+
// x-axis arc of explosion, so 90deg and 270deg particles have curve of 1, 0deg and 180deg have 0
|
|
214
|
+
setCSSVar('--x4', round(abs(mapRange(abs(rotate(degree, 90) - 180), 0, 180, -1, 1)), 4));
|
|
215
|
+
// roughly how fast particle reaches end of its explosion curve
|
|
216
|
+
setCSSVar('--y1', round(random() * BEZIER_MEDIAN, 4));
|
|
217
|
+
// roughly maps to the distance particle goes before reaching free-fall
|
|
218
|
+
setCSSVar('--y2', round(random() * force * (coinFlip() ? 1 : -1), 4));
|
|
219
|
+
// roughly how soon the particle transitions from explosion to free-fall
|
|
220
|
+
setCSSVar('--y3', BEZIER_MEDIAN);
|
|
221
|
+
// roughly the ease of free-fall
|
|
222
|
+
setCSSVar('--y4', round(max(mapRange(abs(degree - 180), 0, 180, force, -force), 0), 4));
|
|
223
|
+
// set --width and --height here
|
|
224
|
+
setCSSVar('--width', (isCircle ? particleSize : mathRound(random() * 4) + particleSize / 2) + 'px');
|
|
225
|
+
setCSSVar('--height', (isCircle ? particleSize : mathRound(random() * 2) + particleSize) + 'px');
|
|
226
|
+
setCSSVar('--rotation', rotationTransform.toString(2).padStart(3, '0').split(''));
|
|
227
|
+
setCSSVar('--rotation-duration', random() * (ROTATION_SPEED_MAX - ROTATION_SPEED_MIN) + ROTATION_SPEED_MIN + 'ms');
|
|
228
|
+
setCSSVar('--border-radius', isCircle ? '50%' : 0);
|
|
229
|
+
}
|
|
230
|
+
</script>
|
|
231
|
+
|
|
232
|
+
{#if isVisible && isValid}
|
|
233
|
+
<div class="container" style:--floor-height="{stageHeight}px">
|
|
234
|
+
{#each particles as { color, degree }}
|
|
235
|
+
<div class="particle" use:confettiStyles={degree}>
|
|
236
|
+
<div style:--bgcolor={color} />
|
|
237
|
+
</div>
|
|
238
|
+
{/each}
|
|
239
|
+
</div>
|
|
240
|
+
{/if}
|
|
241
|
+
|
|
242
|
+
<style>@keyframes y-axis {
|
|
293
243
|
to {
|
|
294
244
|
transform: translate3d(0, var(--floor-height), 0);
|
|
295
245
|
}
|
|
@@ -332,4 +282,4 @@ function confettiStyles(node, { degree }) {
|
|
|
332
282
|
background-color: var(--bgcolor);
|
|
333
283
|
animation: rotation var(--rotation-duration) infinite linear;
|
|
334
284
|
border-radius: var(--border-radius);
|
|
335
|
-
}</style>
|
|
285
|
+
}</style>
|
|
@@ -1,126 +1,126 @@
|
|
|
1
|
-
import { SvelteComponentTyped } from "svelte";
|
|
2
|
-
declare type ParticleShape = 'mix' | 'circles' | 'rectangles';
|
|
3
|
-
declare const __propDef: {
|
|
4
|
-
props: {
|
|
5
|
-
/**
|
|
6
|
-
* Number of confetti particles to create
|
|
7
|
-
*
|
|
8
|
-
* @default 150
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
*
|
|
12
|
-
* ```svelte
|
|
13
|
-
* <ConfettiExplosion particleCount={200} />
|
|
14
|
-
* ```
|
|
15
|
-
*/ particleCount?: number;
|
|
16
|
-
/**
|
|
17
|
-
* Size of the confetti particles in pixels
|
|
18
|
-
*
|
|
19
|
-
* @default 12
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
*
|
|
23
|
-
* ```svelte
|
|
24
|
-
* <ConfettiExplosion particleSize={20} />
|
|
25
|
-
* ```
|
|
26
|
-
*/ particleSize?: number;
|
|
27
|
-
/**
|
|
28
|
-
* Duration of the animation in milliseconds
|
|
29
|
-
*
|
|
30
|
-
* @default 3500
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
*
|
|
34
|
-
* ```svelte
|
|
35
|
-
* <ConfettiExplosion duration={5000} />
|
|
36
|
-
* ```
|
|
37
|
-
*/ duration?: number;
|
|
38
|
-
/**
|
|
39
|
-
* Shape of particles to use. Can be `mix`, `circles` or `rectangles`
|
|
40
|
-
*
|
|
41
|
-
* `mix` will use both circles and rectangles
|
|
42
|
-
* `circles` will use only circles
|
|
43
|
-
* `rectangles` will use only rectangles
|
|
44
|
-
*
|
|
45
|
-
* @default 'mix'
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
*
|
|
49
|
-
* ```svelte
|
|
50
|
-
* <ConfettiExplosion particlesShape='circles' />
|
|
51
|
-
* ```
|
|
52
|
-
*
|
|
53
|
-
* @example
|
|
54
|
-
*
|
|
55
|
-
* ```svelte
|
|
56
|
-
* <ConfettiExplosion particlesShape='rectangles' />
|
|
57
|
-
* ```
|
|
58
|
-
*/ particlesShape?: ParticleShape;
|
|
59
|
-
/**
|
|
60
|
-
* Colors to use for the confetti particles. Pass string array of colors. Can use hex colors, named colors,
|
|
61
|
-
* CSS Variables, literally anything valid in plain CSS.
|
|
62
|
-
*
|
|
63
|
-
* @default ['#FFC700', '#FF0000', '#2E3191', '#41BBC7']
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
*
|
|
67
|
-
* ```svelte
|
|
68
|
-
* <ConfettiExplosion colors={['var(--yellow)', 'var(--red)', '#2E3191', '#41BBC7']} />
|
|
69
|
-
* ```
|
|
70
|
-
*/ colors?: string[];
|
|
71
|
-
/**
|
|
72
|
-
* Force of the confetti particles. Between 0 and 1. 0 is no force, 1 is maximum force.
|
|
73
|
-
*
|
|
74
|
-
* @default 0.5
|
|
75
|
-
*
|
|
76
|
-
* @example
|
|
77
|
-
*
|
|
78
|
-
* ```svelte
|
|
79
|
-
* <ConfettiExplosion force={0.8} />
|
|
80
|
-
* ```
|
|
81
|
-
*/ force?: number;
|
|
82
|
-
/**
|
|
83
|
-
* Height of the stage in pixels. Confetti will only fall within this height.
|
|
84
|
-
*
|
|
85
|
-
* @default 800
|
|
86
|
-
*
|
|
87
|
-
* @example
|
|
88
|
-
*
|
|
89
|
-
* ```svelte
|
|
90
|
-
* <ConfettiExplosion floorHeight={500} />
|
|
91
|
-
* ```
|
|
92
|
-
*/ stageHeight?: number;
|
|
93
|
-
/**
|
|
94
|
-
* Width of the stage in pixels. Confetti will only fall within this width.
|
|
95
|
-
*
|
|
96
|
-
* @default 1600
|
|
97
|
-
*
|
|
98
|
-
* @example
|
|
99
|
-
*
|
|
100
|
-
* ```svelte
|
|
101
|
-
* <ConfettiExplosion floorWidth={1000} />
|
|
102
|
-
* ```
|
|
103
|
-
*/ stageWidth?: number;
|
|
104
|
-
/**
|
|
105
|
-
* Whether or not destroy all confetti nodes after the `duration` period has passed. By default it destroys all nodes, to preserve memory.
|
|
106
|
-
*
|
|
107
|
-
* @default true
|
|
108
|
-
*
|
|
109
|
-
* @example
|
|
110
|
-
*
|
|
111
|
-
* ```svelte
|
|
112
|
-
* <ConfettiExplosion shouldDestroyAfterDone={false} />
|
|
113
|
-
* ```
|
|
114
|
-
*/ shouldDestroyAfterDone?: boolean;
|
|
115
|
-
};
|
|
116
|
-
events: {
|
|
117
|
-
[evt: string]: CustomEvent<any>;
|
|
118
|
-
};
|
|
119
|
-
slots: {};
|
|
120
|
-
};
|
|
121
|
-
export declare type ConfettiExplosionProps = typeof __propDef.props;
|
|
122
|
-
export declare type ConfettiExplosionEvents = typeof __propDef.events;
|
|
123
|
-
export declare type ConfettiExplosionSlots = typeof __propDef.slots;
|
|
124
|
-
export default class ConfettiExplosion extends SvelteComponentTyped<ConfettiExplosionProps, ConfettiExplosionEvents, ConfettiExplosionSlots> {
|
|
125
|
-
}
|
|
126
|
-
export {};
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
declare type ParticleShape = 'mix' | 'circles' | 'rectangles';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
/**
|
|
6
|
+
* Number of confetti particles to create
|
|
7
|
+
*
|
|
8
|
+
* @default 150
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
*
|
|
12
|
+
* ```svelte
|
|
13
|
+
* <ConfettiExplosion particleCount={200} />
|
|
14
|
+
* ```
|
|
15
|
+
*/ particleCount?: number | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Size of the confetti particles in pixels
|
|
18
|
+
*
|
|
19
|
+
* @default 12
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
*
|
|
23
|
+
* ```svelte
|
|
24
|
+
* <ConfettiExplosion particleSize={20} />
|
|
25
|
+
* ```
|
|
26
|
+
*/ particleSize?: number | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Duration of the animation in milliseconds
|
|
29
|
+
*
|
|
30
|
+
* @default 3500
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
*
|
|
34
|
+
* ```svelte
|
|
35
|
+
* <ConfettiExplosion duration={5000} />
|
|
36
|
+
* ```
|
|
37
|
+
*/ duration?: number | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Shape of particles to use. Can be `mix`, `circles` or `rectangles`
|
|
40
|
+
*
|
|
41
|
+
* `mix` will use both circles and rectangles
|
|
42
|
+
* `circles` will use only circles
|
|
43
|
+
* `rectangles` will use only rectangles
|
|
44
|
+
*
|
|
45
|
+
* @default 'mix'
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
*
|
|
49
|
+
* ```svelte
|
|
50
|
+
* <ConfettiExplosion particlesShape='circles' />
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
*
|
|
55
|
+
* ```svelte
|
|
56
|
+
* <ConfettiExplosion particlesShape='rectangles' />
|
|
57
|
+
* ```
|
|
58
|
+
*/ particlesShape?: ParticleShape | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Colors to use for the confetti particles. Pass string array of colors. Can use hex colors, named colors,
|
|
61
|
+
* CSS Variables, literally anything valid in plain CSS.
|
|
62
|
+
*
|
|
63
|
+
* @default ['#FFC700', '#FF0000', '#2E3191', '#41BBC7']
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
*
|
|
67
|
+
* ```svelte
|
|
68
|
+
* <ConfettiExplosion colors={['var(--yellow)', 'var(--red)', '#2E3191', '#41BBC7']} />
|
|
69
|
+
* ```
|
|
70
|
+
*/ colors?: string[] | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Force of the confetti particles. Between 0 and 1. 0 is no force, 1 is maximum force.
|
|
73
|
+
*
|
|
74
|
+
* @default 0.5
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
*
|
|
78
|
+
* ```svelte
|
|
79
|
+
* <ConfettiExplosion force={0.8} />
|
|
80
|
+
* ```
|
|
81
|
+
*/ force?: number | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Height of the stage in pixels. Confetti will only fall within this height.
|
|
84
|
+
*
|
|
85
|
+
* @default 800
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
*
|
|
89
|
+
* ```svelte
|
|
90
|
+
* <ConfettiExplosion floorHeight={500} />
|
|
91
|
+
* ```
|
|
92
|
+
*/ stageHeight?: number | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* Width of the stage in pixels. Confetti will only fall within this width.
|
|
95
|
+
*
|
|
96
|
+
* @default 1600
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
*
|
|
100
|
+
* ```svelte
|
|
101
|
+
* <ConfettiExplosion floorWidth={1000} />
|
|
102
|
+
* ```
|
|
103
|
+
*/ stageWidth?: number | undefined;
|
|
104
|
+
/**
|
|
105
|
+
* Whether or not destroy all confetti nodes after the `duration` period has passed. By default it destroys all nodes, to preserve memory.
|
|
106
|
+
*
|
|
107
|
+
* @default true
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
*
|
|
111
|
+
* ```svelte
|
|
112
|
+
* <ConfettiExplosion shouldDestroyAfterDone={false} />
|
|
113
|
+
* ```
|
|
114
|
+
*/ shouldDestroyAfterDone?: boolean | undefined;
|
|
115
|
+
};
|
|
116
|
+
events: {
|
|
117
|
+
[evt: string]: CustomEvent<any>;
|
|
118
|
+
};
|
|
119
|
+
slots: {};
|
|
120
|
+
};
|
|
121
|
+
export declare type ConfettiExplosionProps = typeof __propDef.props;
|
|
122
|
+
export declare type ConfettiExplosionEvents = typeof __propDef.events;
|
|
123
|
+
export declare type ConfettiExplosionSlots = typeof __propDef.slots;
|
|
124
|
+
export default class ConfettiExplosion extends SvelteComponentTyped<ConfettiExplosionProps, ConfettiExplosionEvents, ConfettiExplosionSlots> {
|
|
125
|
+
}
|
|
126
|
+
export {};
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c)
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Puru Vijay
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Let's party 🎊🎊 with Svelte! svelte-confetti-explosion allows you to show an awesome confetti explosion on your page, with Svelte!
|
|
4
4
|
|
|
5
|
-
> This library is the svelte port of the amazing [
|
|
5
|
+
> This library is the svelte port of the amazing [react-confetti-explosion](https://www.npmjs.com/package//react-confetti-explosion) package. All the logic is from that package only, optimisation and Svelte code are mine 😉
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- 🤏 Tiny -
|
|
9
|
+
- 🤏 Tiny - 2KB min+br.
|
|
10
10
|
- 🐇 Simple - Quite simple to use, and effectively no-config required!
|
|
11
11
|
- 🧙♀️ Elegant - Use a Svelte component rather than setting things up in `onMount` hook.
|
|
12
12
|
- 🗃️ Highly customizable - Offers tons of options that you can modify to get different behaviors.
|
|
@@ -205,7 +205,3 @@ Also, after the specified `duration`, all the confetti DOM nodes will be destroy
|
|
|
205
205
|
|
|
206
206
|
MIT License
|
|
207
207
|
© [Puru Vijay](https://twitter.com/puruvjdev)
|
|
208
|
-
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
```
|
package/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default as ConfettiExplosion } from './ConfettiExplosion.svelte';
|
|
1
|
+
export { default as ConfettiExplosion } from './ConfettiExplosion.svelte';
|
package/index.js
CHANGED