Skip to content

Commit

Permalink
React (#18)
Browse files Browse the repository at this point in the history
* Basic working logic

* Update docs

* Update docs

* Update sizes

* Add changeset
  • Loading branch information
PuruVJ committed Dec 19, 2023
1 parent bd1eac5 commit 4eb52f1
Show file tree
Hide file tree
Showing 31 changed files with 1,248 additions and 129 deletions.
8 changes: 8 additions & 0 deletions .changeset/brown-pianos-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@neoconfetti/vanilla': minor
'@neoconfetti/svelte': minor
'@neoconfetti/core': minor
'@neoconfetti/vue': minor
---

Add particleClass property, optimize code
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"scripts": {
"changeset": "changeset",
"ci:version": "changeset version",
"ci:release": "changeset publish"
"ci:release": "changeset publish",
"sizes": "tsx scripts/sizes.ts"
},
"repository": {
"type": "git",
Expand All @@ -22,14 +23,19 @@
"devDependencies": {
"@rollup/pluginutils": "^5.1.0",
"@types/node": "^20.10.5",
"@types/react": "^18.2.45",
"@types/react-dom": "^18.2.18",
"brotli-size": "^4.0.0",
"brotli-size-cli": "^1.0.0",
"bun-types": "^1.0.18",
"esbuild": "^0.19.9",
"fast-glob": "^3.3.2",
"lightningcss": "^1.22.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"svelte": "^4.2.8",
"terser": "^5.26.0",
"tsup": "^8.0.1",
"tsx": "^4.7.0",
"typescript": "^5.3.3",
"vue": "^3.2.47"
},
Expand Down
20 changes: 16 additions & 4 deletions packages/core/demo/src/lib/Counter.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
let particleShape: ConfettiParticleShape = 'mix';
let force = 0.5;
let particleClass = 'particlesss';
let showConfetti = false;
onMount(() => {
Expand All @@ -15,16 +17,26 @@
setTimeout(() => {
// render = {};
// colors = ['#eee', 'black'];
// particleShape = 'circles';
colors = ['#eee', 'black'];
particleShape = 'circles';
force = 1;
// force = 1;
}, 2000);
});
</script>

<input bind:value={particleClass} />

{#if showConfetti}
<div use:confetti={{ destroyAfterDone: false, colors, particleShape, force }} />
<div
use:confetti={{
destroyAfterDone: false,
colors,
particleShape,
force,
particleClass,
}}
/>
{/if}

<!-- <ConfettiExplosion destroyAfterDone={false} particleCount={4} /> -->
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"compile": "tsup",
"size": "brotli-size dist/min/index.js"
},
"description": "Let's party 🎊🎊 with Svelte! @neodrag/core allows you to show an awesome confetti explosion on your page, with Svelte!",
"description": "Let's party 🎊🎊 with Svelte! @neoconfetti/core allows you to show an awesome confetti explosion on your page, with Svelte!",
"keywords": [],
"author": "Puru Vijay",
"license": "MIT"
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
declare module '*.module.css?map' {
const container: string;
const particle: string;
export { container, particle };
export { container as c, particle as p };
}

declare module '*?inline' {
Expand Down
60 changes: 40 additions & 20 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import styles from './style.module.css?inline';
import { container as c_container, particle as c_particle } from './style.module.css?map';
import { c as c_container, p as c_particle } from './style.module.css?map';

type ParticleShape = 'mix' | 'circles' | 'rectangles';
type Particle = {
Expand Down Expand Up @@ -32,6 +32,13 @@ type ConfettiOptions = {
*/
particleSize?: number;

/**
* Class to apply to each confetti particle
*
* @default undefined
*/
particleClass?: string;

/**
* Duration of the animation in milliseconds
*
Expand Down Expand Up @@ -79,11 +86,12 @@ type ConfettiOptions = {

// Take DEFAULT.COLORS, etc anf convert to DEFAULT_COLORS, etc
const DEFAULT_COLORS = ['#FFC700', '#FF0000', '#2E3191', '#41BBC7'];
const DEFAULT_DURATION = 3500;
export const DEFAULT_DURATION = 3500;
const DEFAULT_FORCE = 0.5;
const DEFAULT_PARTICLE_COUNT = 150;
const DEFAULT_PARTICLE_SHAPE = 'mix' as ParticleShape;
const DEFAULT_PARTICLE_SIZE = 12;
const DEFAULT_PARTICLE_CLASS = '';
const DEFAULT_DESTROY_AFTER_DONE = true;
const DEFAULT_STAGE_HEIGHT = 800;
const DEFAULT_STAGE_WIDTH = 1600;
Expand All @@ -96,6 +104,7 @@ export function confetti(container: HTMLElement, options: ConfettiOptions = {})
particleCount = DEFAULT_PARTICLE_COUNT,
particleShape = DEFAULT_PARTICLE_SHAPE,
particleSize = DEFAULT_PARTICLE_SIZE,
particleClass = DEFAULT_PARTICLE_CLASS,
destroyAfterDone = DEFAULT_DESTROY_AFTER_DONE,
stageHeight = DEFAULT_STAGE_HEIGHT,
stageWidth = DEFAULT_STAGE_WIDTH,
Expand All @@ -106,13 +115,12 @@ export function confetti(container: HTMLElement, options: ConfettiOptions = {})
// stage-height
container.style.setProperty('--sh', stageHeight + 'px');

let particles = create_particles(particleCount, colors);
let nodes = create_particle_nodes(container, particles);
let particles: Particle[] = [];
let nodes: HTMLElement[] = [];

const calc_rotation_transform = () => math_round(random() * (POSSIBLE_ROTATION_TRANSFORMS - 1));
const get_is_circle = (particle_shape: ParticleShape, rotation_transform: number) =>
particle_shape !== 'rectangles' &&
(particle_shape === 'circles' || should_be_circle(rotation_transform));
particle_shape === 'circles' || should_be_circle(rotation_transform);

function confetti_styles(node: HTMLElement, degree: number) {
// Crazy calculations for generating styles
Expand Down Expand Up @@ -193,10 +201,10 @@ export function confetti(container: HTMLElement, options: ConfettiOptions = {})
container.innerHTML = '';
clearTimeout(timer);

let particles = create_particles(particleCount, colors);
let nodes = create_particle_nodes(container, particles);
particles = create_particles(particleCount, colors);
nodes = create_particle_nodes(container, particles, particleClass);

for (const [i, node] of Object.entries(nodes)) confetti_styles(node, particles[+i].degree);
for (const [i, node] of object_entries(nodes)) confetti_styles(node, particles[+i].degree);

timer = setTimeout(() => {
if (destroyAfterDone) container.innerHTML = '';
Expand All @@ -210,6 +218,7 @@ export function confetti(container: HTMLElement, options: ConfettiOptions = {})
const new_particle_count = new_options.particleCount ?? DEFAULT_PARTICLE_COUNT;
const new_particle_shape = new_options.particleShape ?? DEFAULT_PARTICLE_SHAPE;
const new_particle_size = new_options.particleSize ?? DEFAULT_PARTICLE_SIZE;
const new_particle_class = new_options.particleClass ?? DEFAULT_PARTICLE_CLASS;
const new_colors = new_options.colors ?? DEFAULT_COLORS;
const new_stage_height = new_options.stageHeight ?? DEFAULT_STAGE_HEIGHT;
const new_duration = new_options.duration ?? DEFAULT_DURATION;
Expand All @@ -222,21 +231,28 @@ export function confetti(container: HTMLElement, options: ConfettiOptions = {})
let start_from_scratch = false;
// Other might have changed. First, check the diff for colors, as only that matters
if (new_particle_count === particleCount) {
//! Why the hell this works but directly setting the CSS variables on nodes doesn't??
// Why the hell this works but directly setting the CSS variables on nodes doesn't??
nodes = Array.from(container.querySelectorAll(`.${c_particle}`));

for (const [i, { color }] of Object.entries(particles)) {
for (const [i, { color }] of object_entries(particles)) {
const node = nodes[+i];
if (JSON.stringify(colors) !== JSON.stringify(new_colors)) {
nodes[+i].style.setProperty('--bgc', color);
node.style.setProperty('--bgc', color);
}

if (new_particle_shape !== particleShape) {
nodes[+i].style.setProperty(
node.style.setProperty(
// --border-radius
'--br',
get_is_circle(new_particle_shape, calc_rotation_transform()) ? '50%' : '0'
);
}

if (new_particle_class !== particleClass) {
// Surgically remove the old particleClass from all particles, and replace with new_particle_class
if (particleClass) node.classList.remove(particleClass);
if (new_particle_class) node.classList.add(new_particle_class);
}
}
} else {
start_from_scratch = true;
Expand All @@ -256,18 +272,16 @@ export function confetti(container: HTMLElement, options: ConfettiOptions = {})
particleCount = new_particle_count;
particleShape = new_particle_shape;
particleSize = new_particle_size;
particleClass = new_particle_class;
destroyAfterDone = new_destroy_after_done;
stageHeight = new_stage_height;
stageWidth = new_stage_width;

console.log(1, start_from_scratch);

if (start_from_scratch) {
scratch();
}
if (start_from_scratch) scratch();
},

destroy() {
container.innerHTML = '';
clearTimeout(timer);
},
};
Expand All @@ -282,12 +296,16 @@ function append_styles(styles: string) {
append_child(document.head, style);
}

function create_particle_nodes(container: HTMLElement, particles: Particle[] = []) {
function create_particle_nodes(
container: HTMLElement,
particles: Particle[] = [],
particleClass: ConfettiOptions['particleClass']
) {
const particle_nodes: HTMLElement[] = [];

for (const { color } of particles) {
const particle_node = element('div');
particle_node.className = c_particle;
particle_node.className = `${c_particle} ${particleClass}`;
particle_node.style.setProperty('--bgc', color);

const inner_particle = element('div');
Expand Down Expand Up @@ -333,6 +351,8 @@ const rotate = (degree: number, amount: number) =>

const coin_flip = () => random() > 0.5;

const object_entries = Object.entries;

// We can use the first three bits to flag which axis to rotate on.
// x = binary 100 = decimal 4
// y = binary 010 = decimal 2
Expand Down
31 changes: 18 additions & 13 deletions packages/core/src/style.module.css
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
@keyframes y-axis {
/* y-axis */
@keyframes ya {
to {
translate: 0 var(--sh);
}
}

@keyframes x-axis {
/* x-axis */
@keyframes xa {
to {
translate: var(--xlp) 0;
}
}

@keyframes rotation {
/* rotation */
@keyframes r {
50% {
rotate: var(--hr) 180deg;
}
Expand All @@ -19,7 +22,8 @@
}
}

.container {
/* Container */
.c {
width: 0;
height: 0;

Expand All @@ -30,24 +34,25 @@
z-index: 1200;
}

.particle {
animation: x-axis var(--dc) forwards cubic-bezier(var(--x1), var(--x2), var(--x3), var(--x4));
animation-name: x-axis;
/* Particle */
.p {
animation: xa var(--dc) forwards cubic-bezier(var(--x1), var(--x2), var(--x3), var(--x4));
animation-name: xa;
}

.particle > div {
.p > div {
position: absolute;
top: 0;
left: 0;

animation: y-axis var(--dc) forwards cubic-bezier(var(--y1), var(--y2), var(--y3), var(--y4));
animation-name: y-axis;
animation: ya var(--dc) forwards cubic-bezier(var(--y1), var(--y2), var(--y3), var(--y4));
animation-name: ya;

width: var(--w);
height: var(--h);
}

.particle > div::before {
.p > div::before {
display: block;

height: 100%;
Expand All @@ -56,8 +61,8 @@
content: '';
background-color: var(--bgc);

animation: rotation var(--rd) infinite linear;
animation-name: rotation;
animation: r var(--rd) infinite linear;
animation-name: r;

border-radius: var(--br);
}

0 comments on commit 4eb52f1

Please sign in to comment.