Skip to content

Commit 5eccb59

Browse files
authored
Merge pull request #74 from AdamTyler/feature/ts
Typescript support
2 parents 53253b4 + e706168 commit 5eccb59

19 files changed

Lines changed: 5411 additions & 10069 deletions

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,32 @@ npm install react-dice-complete
1414

1515
- [React](https://facebook.github.io/react/)
1616

17-
## Example Usage (ES6)
17+
## Usage
1818

1919
```javascript
2020
import React, { useRef } from 'react'
21-
import ReactDice from 'react-dice-complete'
21+
import ReactDice, { ReactDiceRef } from 'react-dice-complete'
2222

2323
const MyDiceApp = () => {
2424

25-
const reactDice = useRef()
25+
const reactDice = useRef<ReactDiceRef>(null)
2626

27-
const rollDone = (totalValue, values) => {
27+
const rollDone = (totalValue: number, values: number[]) => {
2828
console.log('individual die values array:', values)
2929
console.log('total dice value:', totalValue)
3030
}
3131

3232
const rollAll = () => {
33-
reactDice.current.rollAll()
33+
reactDice.current?.rollAll()
3434
}
3535

3636
render() {
3737
return (
3838
<div>
3939
<ReactDice
4040
numDice={2}
41-
rollDone={rollDone}
4241
ref={reactDice}
42+
rollDone={rollDone}
4343
/>
4444
</div>
4545
)

babel.config.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

config/webpack.config.dev.js

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,25 @@ const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'
44

55
module.exports = {
66
mode: 'development',
7-
devtool: 'inline-source-map',
7+
devtool: 'source-map',
88
entry: [
99
'webpack-dev-server/client?http://localhost:8080',
1010
'webpack/hot/only-dev-server',
11-
'./src/App.js',
11+
'./index.js',
1212
],
1313
output: {
1414
filename: 'bundle.js',
1515
path: resolve(__dirname, 'demo'),
1616
publicPath: '/',
1717
},
1818
resolve: {
19-
extensions: ['.js', '.jsx'],
19+
extensions: ['.ts', '.tsx', '.js', '.jsx'],
2020
modules: [resolve(__dirname, 'src'), 'node_modules'],
2121
},
2222
module: {
2323
rules: [
24-
{
25-
test: /\.(js|jsx)$/,
26-
use: {
27-
loader: 'babel-loader',
28-
options: {
29-
presets: ['@babel/preset-env', '@babel/preset-react'],
30-
plugins: ['react-refresh/babel'],
31-
},
32-
},
33-
exclude: /node_modules/,
34-
},
24+
{ test: /\.(t|j)sx?$/, use: { loader: 'ts-loader' }, exclude: /node_modules/ },
25+
{ enforce: 'pre', test: /\.js$/, exclude: /node_modules/, loader: 'source-map-loader' },
3526
{
3627
test: /\.(css|scss)$/,
3728
use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],

config/webpack.config.docs.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,21 @@ const HtmlWebpackPlugin = require('html-webpack-plugin')
33

44
module.exports = {
55
mode: 'production',
6-
devtool: 'inline-source-map',
6+
devtool: 'source-map',
77
entry: './index.js',
88
output: {
99
filename: 'bundle.js',
1010
path: resolve(__dirname, '../docs'),
1111
publicPath: './',
1212
},
1313
resolve: {
14-
extensions: ['.js', '.jsx'],
14+
extensions: ['.ts', '.tsx', '.js', '.jsx'],
1515
modules: [resolve(__dirname, 'src'), 'node_modules'],
1616
},
1717
module: {
1818
rules: [
19-
{
20-
test: /\.(js|jsx)$/,
21-
use: {
22-
loader: 'babel-loader',
23-
options: {
24-
presets: ['@babel/preset-env', '@babel/preset-react'],
25-
},
26-
},
27-
exclude: /node_modules/,
28-
},
19+
{ test: /\.(t|j)sx?$/, use: { loader: 'ts-loader' }, exclude: /node_modules/ },
20+
{ enforce: 'pre', test: /\.js$/, exclude: /node_modules/, loader: 'source-map-loader' },
2921
{
3022
test: /\.(css|scss)$/,
3123
use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],

config/webpack.config.prod.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const { resolve } = require('path')
22

33
module.exports = {
44
mode: 'production',
5-
entry: './src/ReactDice.js',
5+
entry: './lib/ReactDice.tsx',
66
output: {
77
filename: 'react-dice-complete.js',
88
path: resolve(__dirname, '../dist'),
@@ -18,21 +18,22 @@ module.exports = {
1818
},
1919
},
2020
resolve: {
21-
extensions: ['.js', '.jsx'],
21+
extensions: ['.ts', '.tsx', '.js', '.jsx'],
2222
modules: [resolve(__dirname, 'src'), 'node_modules'],
2323
},
2424
module: {
2525
rules: [
2626
{
27-
test: /\.(js|jsx)$/,
27+
test: /\.(t|j)sx?$/,
2828
use: {
29-
loader: 'babel-loader',
29+
loader: 'ts-loader',
3030
options: {
31-
presets: ['@babel/preset-env', '@babel/preset-react'],
31+
transpileOnly: false,
3232
},
3333
},
3434
exclude: /node_modules/,
3535
},
36+
{ enforce: 'pre', test: /\.js$/, exclude: /node_modules/, loader: 'source-map-loader' },
3637
{
3738
test: /\.(css|scss)$/,
3839
use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],

docs/bundle.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/bundle.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// This file used for docs page
1+
// This file used for dev and docs page
22
import React from 'react'
33
import { createRoot } from 'react-dom/client'
44

lib/DiceContainer.tsx

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import React, {
2+
forwardRef,
3+
useRef,
4+
useState,
5+
useEffect,
6+
useImperativeHandle,
7+
memo,
8+
useMemo,
9+
} from 'react'
10+
import Die, { DieRef, DieProps } from './Die'
11+
import './styles.scss'
12+
13+
export type DieContainerRef = {
14+
rollAll: (values?: number[]) => void
15+
}
16+
17+
export interface DiceContainerProps extends Omit<DieProps, 'onRollDone'> {
18+
numDice: number
19+
totalCb: (newTotalValue: number, newDiceValues: number[]) => void
20+
}
21+
22+
const DiceContainer = forwardRef<DieContainerRef, DiceContainerProps>(
23+
({ numDice, totalCb, ...rest }, ref): JSX.Element => {
24+
const diceRefs = useRef<Array<DieRef | null>>([])
25+
const [totalValue, setTotalValue] = useState(numDice * 6)
26+
const [diceValues, setDiceValues] = useState<number[]>([])
27+
const [rollCount, setRollCount] = useState(0)
28+
29+
useImperativeHandle(ref, () => ({
30+
rollAll,
31+
}))
32+
33+
const rollAll = (values = []) => {
34+
setRollCount(diceRefs.current.length)
35+
let index = 0
36+
for (let die of diceRefs.current) {
37+
if (die !== null) {
38+
die.rollDie(values[index])
39+
index += 1
40+
}
41+
}
42+
}
43+
44+
const onRollDone = () => {
45+
setRollCount((count) => count - 1)
46+
}
47+
48+
useEffect(() => {
49+
if (rollCount <= 0) {
50+
setTimeout(getRollResults, 100)
51+
}
52+
}, [rollCount])
53+
54+
const getRollResults = () => {
55+
let newTotalValue = 0
56+
let newDiceValues: number[] = []
57+
for (let die of diceRefs.current) {
58+
if (die !== null) {
59+
const value = die.getValue()
60+
newDiceValues.push(value)
61+
newTotalValue += value
62+
}
63+
}
64+
setTotalValue(newTotalValue)
65+
setDiceValues(newDiceValues)
66+
totalCb(newTotalValue, newDiceValues)
67+
}
68+
69+
useEffect(() => {
70+
getRollResults()
71+
}, [numDice])
72+
73+
const getDice = useMemo(() => {
74+
let dice: JSX.Element[] = []
75+
for (let i = 0; i < numDice; i++) {
76+
dice.push(
77+
<Die
78+
{...rest}
79+
key={i}
80+
onRollDone={onRollDone}
81+
ref={(die) => (diceRefs.current[i] = die)}
82+
/>
83+
)
84+
}
85+
return dice
86+
}, [rest, numDice, onRollDone])
87+
88+
return <div className='dice'>{getDice}</div>
89+
}
90+
)
91+
92+
export default memo(DiceContainer)

src/Die.js renamed to lib/Die.tsx

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,46 @@
11
import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react'
22

3-
const Die = forwardRef(
3+
export type DieRef = {
4+
getValue: () => number
5+
rollDie: (value?: number) => void
6+
}
7+
8+
export interface DieProps {
9+
defaultRoll?: number
10+
dieCornerRadius?: number
11+
dieSize?: number
12+
disableIndividual?: boolean
13+
disableRandom?: boolean
14+
dotColor?: string
15+
faceColor?: string
16+
margin?: number
17+
onRollDone: (value: number) => void
18+
outline?: boolean
19+
outlineColor?: string
20+
rollTime?: number
21+
sides?: number
22+
}
23+
24+
const Die = forwardRef<DieRef, DieProps>(
425
(
526
{
6-
defaultRoll,
7-
dieCornerRadius,
8-
dieSize,
9-
disableIndividual,
10-
disableRandom,
11-
dotColor,
12-
faceColor,
13-
margin,
27+
defaultRoll = 4,
28+
dieCornerRadius = 5,
29+
dieSize = 60,
30+
disableIndividual = false,
31+
disableRandom = false,
32+
dotColor = '#1dff00',
33+
faceColor = '#ff00ac',
34+
margin = 15,
1435
onRollDone,
15-
outline,
16-
outlineColor,
17-
rollTime,
18-
sides,
19-
},
36+
outline = false,
37+
outlineColor = '#000000',
38+
rollTime = 2,
39+
sides = 6,
40+
}: DieProps,
2041
ref
21-
) => {
22-
const dieRef = useRef()
42+
): JSX.Element => {
43+
const dieRef = useRef<HTMLDivElement>(null)
2344

2445
useImperativeHandle(ref, () => ({
2546
getValue: () => {
@@ -36,19 +57,19 @@ const Die = forwardRef(
3657
return Math.floor(Math.random() * max) + min
3758
}
3859

39-
const rollDie = (value) => {
40-
dieRef.current.className = `die`
41-
void dieRef.current.offsetWidth
60+
const rollDie = (value?: number) => {
61+
dieRef.current && (dieRef.current.className = `die`)
62+
void dieRef.current?.offsetWidth
4263
let roll = disableRandom ? dieValue : value || getRandomInt()
43-
dieRef.current.classList.add(`roll${roll}`)
64+
dieRef.current?.classList.add(`roll${roll}`)
4465
setTimeout(() => {
4566
setDieValue(roll)
4667
onRollDone(roll)
4768
}, rollTime * 1000)
4869
}
4970

5071
// face styles
51-
let faceStyle = {
72+
let faceStyle: React.CSSProperties = {
5273
background: faceColor,
5374
borderRadius: `${dieCornerRadius}px`,
5475
height: `${dieSize}px`,
@@ -78,7 +99,7 @@ const Die = forwardRef(
7899
}
79100
// dot styles
80101
const dotSize = dieSize / 6 - 2
81-
const dotStyle = {
102+
const dotStyle: React.CSSProperties = {
82103
background: dotColor,
83104
height: `${dotSize}px`,
84105
width: `${dotSize}px`,
@@ -125,7 +146,7 @@ const Die = forwardRef(
125146
return (
126147
<div
127148
className='die-container'
128-
onClick={disableIndividual ? null : () => rollDie()}
149+
onClick={disableIndividual ? undefined : () => rollDie()}
129150
style={containerStyle}
130151
>
131152
<div className={`die roll${dieValue}`} ref={dieRef} style={rollStyle}>

0 commit comments

Comments
 (0)