diff --git a/docs/react-wordcloud.tsx b/docs/react-wordcloud.tsx index d51c1a3..e113fe5 100644 --- a/docs/react-wordcloud.tsx +++ b/docs/react-wordcloud.tsx @@ -8,7 +8,13 @@ import ReactWordcloudSrc, { Props } from '..'; export * from '..'; export default function ReactWordcloud(props: Props): JSX.Element { - const canvasAllowed = typeof document !== 'undefined' && document.createElement('canvas').getContext('2d').getImageData(0, 0, 1, 1).data.every(v => v === 0); + const canvasAllowed = + typeof document !== 'undefined' && + document + .createElement('canvas') + .getContext('2d') + .getImageData(0, 0, 1, 1) + .data.every(v => v === 0); if (!canvasAllowed) { return ( diff --git a/package.json b/package.json index 173c0a9..f9e70c8 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,8 @@ "@types/d3-selection": "^1.4.1", "@types/lodash.clonedeep": "^4.5.6", "@types/lodash.debounce": "^4.0.6", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", "@types/seedrandom": "^2.4.28", "docz": "^2.3.1", "eslint-config-xo-react": "^0.23.0", @@ -60,7 +62,7 @@ "microbundle": "^0.12.3", "react": "^16.13.1", "react-dom": "^16.13.1", - "typescript": "^3.8.3", + "typescript": "^5.0.0", "xo": "^0.32.1" }, "peerDependencies": { diff --git a/src/hooks.js b/src/hooks.js index 671bc5e..37b7a61 100644 --- a/src/hooks.js +++ b/src/hooks.js @@ -32,11 +32,13 @@ export function useResponsiveSvgSelection(minSize, initialSize, svgAttributes) { let width = 0; let height = 0; - if (initialSize === undefined) { + if (initialSize === undefined && element) { // Use parentNode size if resized has not occurred - width = element.parentElement.offsetWidth; - height = element.parentElement.offsetHeight; - } else { + // @ts-ignore - TypeScript incorrectly infers element as never + width = element.parentElement?.offsetWidth || 0; + // @ts-ignore - TypeScript incorrectly infers element as never + height = element.parentElement?.offsetHeight || 0; + } else if (initialSize) { // Use initialSize if it is provided [width, height] = initialSize; } diff --git a/src/index.js b/src/index.js index e2aafbb..8ed04da 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ import debounce from 'lodash.debounce'; -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useMemo, useRef } from 'react'; import { useResponsiveSvgSelection } from './hooks'; import { layout } from './layout'; @@ -9,8 +9,10 @@ export const defaultCallbacks = { getWordTooltip: ({ text, value }) => `${text} (${value})`, }; +const defaultColors = getDefaultColors(); + export const defaultOptions = { - colors: getDefaultColors(), + colors: defaultColors, deterministic: false, enableOptimizations: false, enableTooltip: true, @@ -26,19 +28,27 @@ export const defaultOptions = { transitionDuration: 600, }; +const DEFAULT_MIN_SIZE = [300, 300]; + function ReactWordCloud({ - callbacks, + callbacks = defaultCallbacks, maxWords = 100, - minSize, - options, + minSize: minSizeProp, + options = defaultOptions, size: initialSize, words, ...rest }) { + const minSize = useMemo(() => minSizeProp || DEFAULT_MIN_SIZE, [minSizeProp]); + + const svgAttributes = useMemo(() => options.svgAttributes, [ + options.svgAttributes, + ]); + const [ref, selection, size] = useResponsiveSvgSelection( minSize, initialSize, - options.svgAttributes, + svgAttributes, ); const render = useRef(debounce(layout, 100)); @@ -57,16 +67,13 @@ function ReactWordCloud({ words, }); } - }, [maxWords, callbacks, options, selection, size, words]); + // Note: 'size' is intentionally excluded from dependencies to prevent + // potential infinite loops, as it's updated by useResponsiveSvgSelection. + // The debounced render function will use the latest size value via closure. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [callbacks, maxWords, options, selection, words]); return
; } -ReactWordCloud.defaultProps = { - callbacks: defaultCallbacks, - maxWords: 100, - minSize: [300, 300], - options: defaultOptions, -}; - export default ReactWordCloud; diff --git a/src/layout.js b/src/layout.js index 9bd83c8..df7f754 100644 --- a/src/layout.js +++ b/src/layout.js @@ -60,7 +60,7 @@ export function render({ callbacks, options, random, selection, words }) { animation: 'scale', arrow: true, content: () => getWordTooltip(word), - onHidden: (instance) => { + onHidden: instance => { instance.destroy(); tooltipInstance = null; }, diff --git a/tsconfig.json b/tsconfig.json index e29403a..c9b32db 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,8 @@ "esModuleInterop": true, "jsx": "react", "noEmit": true, + "skipLibCheck": true, + "strict": false }, "exclude": ["**/dist", "**/node_modules"] }