Skip to content

Commit

Permalink
Merge pull request #54 from alampros/develop
Browse files Browse the repository at this point in the history
onConfettiComplete param
  • Loading branch information
alampros authored Apr 17, 2019
2 parents 4297309 + c04f0f5 commit 8449377
Show file tree
Hide file tree
Showing 9 changed files with 734 additions and 633 deletions.
2 changes: 2 additions & 0 deletions .storybook/addons.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import '@storybook/addon-notes/register'
import '@storybook/addon-knobs/register'
import '@storybook/addon-storysource/register'
import '@storybook/addon-actions/register'
1 change: 1 addition & 0 deletions .storybook/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { addParameters, configure } from '@storybook/react'
import { create } from '@storybook/theming'
addParameters({
options: {
sortStoriesByKind: true,
theme: create({
base: 'light',
brandTitle: 'React Confetti',
Expand Down
41 changes: 21 additions & 20 deletions README.md

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,11 @@
"@semantic-release/github": "^5.2.10",
"@semantic-release/npm": "^5.1.4",
"@semantic-release/release-notes-generator": "^7.1.4",
"@storybook/addon-actions": "^5.0.1",
"@storybook/addon-actions": "^5.0.9",
"@storybook/addon-info": "^5.0.1",
"@storybook/addon-knobs": "^5.0.1",
"@storybook/addon-links": "^5.0.1",
"@storybook/addon-notes": "^5.0.9",
"@storybook/addon-storysource": "^5.0.1",
"@storybook/addons": "^5.0.1",
"@storybook/react": "^5.0.1",
Expand All @@ -91,7 +92,7 @@
"react-docgen-typescript-loader": "^3.0.1",
"react-dom": "^16.2.0",
"react-fps-stats": "^0.1.1",
"react-use": "^7.3.1",
"react-use": "^8.1.2",
"semantic-release": "^15.1.7",
"typescript": "^3.3.3333",
"webpack": "^4.29.6",
Expand Down
20 changes: 20 additions & 0 deletions src/Confetti.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ export interface IConfettiOptions {
* Function to draw your own confetti shapes.
*/
drawShape?: (context: CanvasRenderingContext2D) => void
/**
* Function called when all confetti has fallen off-canvas.
*/
onConfettiComplete?: (confettiInstance?: Confetti) => void
}

export const confettiDefaults: Pick<IConfettiOptions, Exclude<keyof IConfettiOptions, 'confettiSource'>> = {
Expand Down Expand Up @@ -128,9 +132,13 @@ export class Confetti {
}
set options(opts: Partial<IConfettiOptions>) {
const lastRunState = this._options && this._options.run
const lastRecycleState = this._options && this._options.recycle
this.setOptionsWithDefaults(opts)
if(this.generator) {
Object.assign(this.generator, this.options.confettiSource)
if(typeof opts.recycle === 'boolean' && opts.recycle && lastRecycleState === false) {
this.generator.lastNumberOfPieces = this.generator.particles.length
}
}
if(typeof opts.run === 'boolean' && opts.run && lastRunState === false) {
this.update()
Expand All @@ -154,6 +162,7 @@ export class Confetti {
const {
options: {
run,
onConfettiComplete,
},
canvas,
context,
Expand All @@ -165,10 +174,21 @@ export class Confetti {
if(this.generator.animate()) {
this.rafId = requestAnimationFrame(this.update)
} else {
if(onConfettiComplete && typeof onConfettiComplete === 'function' && this.generator.particlesGenerated > 0) {
onConfettiComplete.call(this, this)
}
this._options.run = false
}
}

reset = () => {
if(this.generator && this.generator.particlesGenerated > 0) {
this.generator.particlesGenerated = 0
this.generator.particles = []
this.generator.lastNumberOfPieces = 0
}
}

stop = () => {
this.options = { run: false }
if(this.rafId) {
Expand Down
2 changes: 1 addition & 1 deletion src/ReactConfetti.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class ReactConfetti extends Component<Props> {
function extractCanvasProps(props: Partial<IConfettiOptions> | any): [Partial<IConfettiOptions>, Partial<CanvasHTMLAttributes<HTMLCanvasElement>>] {
const confettiOptions: Partial<IConfettiOptions> = {}
const rest: any = {}
const confettiOptionKeys = [...Object.keys(confettiDefaults), 'confettiSource', 'drawShape']
const confettiOptionKeys = [...Object.keys(confettiDefaults), 'confettiSource', 'drawShape', 'onConfettiComplete']
for(const prop in props) {
const val = props[prop as string]
if(confettiOptionKeys.includes(prop)) {
Expand Down
14 changes: 11 additions & 3 deletions stories/index.story.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import SizedConfetti from './SizedConfetti'
import { withKnobs, boolean, number } from '@storybook/addon-knobs'
import { storiesOf } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { action } from '@storybook/addon-actions'

import ReactConfetti from '../src/ReactConfetti'

Expand Down Expand Up @@ -54,8 +55,11 @@ storiesOf('Props|Demos', module)
max: 100,
step: 1,
}) / 100}
onConfettiComplete={action('Confetti Complete')}
/>
))
), {
notes: 'Illustrates common props usage.',
})
.add('Custom Source', () => (
<PointConfetti
friction={1}
Expand Down Expand Up @@ -86,8 +90,12 @@ storiesOf('Props|Demos', module)
step: 1,
}) / 100}
/>
))
), {
notes: 'Uses a custom `confettiSource` option to emit confetti from a small source in the center of the canvas.',
})

storiesOf('Props|Default', module)
.addDecorator(withInfo)
.add('Default', () => <ReactConfetti />)
.add('Default', () => <ReactConfetti />, {
notes: 'Bare bones basic usage with no resizing.',
})
26 changes: 19 additions & 7 deletions stories/party.story.jsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
import React, { useState } from 'react'
import { storiesOf } from '@storybook/react'
import { action } from '@storybook/addon-actions'
import SizedConfetti from './SizedConfetti'
import './party.css'

const PartyMode = ({ children }) => {
const confettiCompleteAction = action('Confetti Complete')

const PartyMode = () => {
const [party, setParty] = useState(false)
const handleClick = () => {
setParty(!party)
}
return (
<div className={'root' + (party ? ' party' : '')}>
<SizedConfetti
style={{ pointerEvents: 'none' }}
numberOfPieces={party ? 500 : 0}
recycle={false}
onConfettiComplete={confetti => {
confettiCompleteAction()
setParty(false)
confetti.reset()
}}
/>
<div className="party-container">
<button onClick={handleClick} className="party-button">
<button
onClick={() => setParty(!party)}
className="party-button"
autoFocus
>
Party
</button>
</div>
</div>
)
}

storiesOf('Props Demos', module)
storiesOf('Props|Demos', module)
.add('Party', () => (
<PartyMode />
))
), {
notes: 'Illustrates how manipulating the `numberOfPieces` can be used with a boolean state variable, as well as the `onConfettiComplete` event to reset the particle generator when `recycle` is false.',
})
Loading

0 comments on commit 8449377

Please sign in to comment.