From 7d6bfb5da043e3428272d4983eaad6944da9b587 Mon Sep 17 00:00:00 2001 From: Dmitry Matiouchenko Date: Thu, 15 Jun 2023 16:04:51 -0700 Subject: [PATCH] fix: table not responding to parent size change (#1516) * fix: table not responding to parent size change * chore: cleanup not used packages * chore: cleanup more not used packages --- packages/gatsby-theme-aio/package.json | 2 + .../src/components/Table/index.js | 23 ++-- packages/gatsby-theme-aio/src/utils/index.js | 114 +++++++++++++++++- yarn.lock | 18 +++ 4 files changed, 147 insertions(+), 10 deletions(-) diff --git a/packages/gatsby-theme-aio/package.json b/packages/gatsby-theme-aio/package.json index 5db79dd8e3..2a2d7846f5 100644 --- a/packages/gatsby-theme-aio/package.json +++ b/packages/gatsby-theme-aio/package.json @@ -138,6 +138,7 @@ "redoc-cli": "^0.13.20", "rehype-slug-custom-id": "^1.1.0", "request": "^2.88.2", + "resize-observer-polyfill": "^1.5.1", "sharp": "^0.31.0", "stream-http": "^3.2.0", "styled-components": "^5.3.5", @@ -145,6 +146,7 @@ "to-arraybuffer": "^1.0.1", "tty-browserify": "^0.0.1", "unist-util-select": "3.0.4", + "use-debounce": "^9.0.4", "uuid": "^9.0.0" } } diff --git a/packages/gatsby-theme-aio/src/components/Table/index.js b/packages/gatsby-theme-aio/src/components/Table/index.js index 37203c266c..ad04e53c1f 100644 --- a/packages/gatsby-theme-aio/src/components/Table/index.js +++ b/packages/gatsby-theme-aio/src/components/Table/index.js @@ -10,15 +10,26 @@ * governing permissions and limitations under the License. */ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useRef, useState } from 'react'; import { css } from '@emotion/react'; import PropTypes from 'prop-types'; import '@spectrum-css/table'; -import { MOBILE_SCREEN_WIDTH } from '../../utils'; +import { MOBILE_SCREEN_WIDTH, useParentSize } from '../../utils'; const Table = ({ children, css: cssOverrides, columnWidths, ...props }) => { - const [width, setWidth] = useState(MOBILE_SCREEN_WIDTH); const tableRef = useRef(null); + const [width, setWidth] = useState(parseInt(MOBILE_SCREEN_WIDTH, 10)); + + useParentSize(tableRef, { + debounceDelay: 500, + initialValues: { width: parseInt(MOBILE_SCREEN_WIDTH, 10) }, + callback: size => { + if (size.width) { + setWidth(size.width); + } + }, + }); + const columnWidthDistribution = columnWidths ? columnWidths .split(',') @@ -26,12 +37,6 @@ const Table = ({ children, css: cssOverrides, columnWidths, ...props }) => { .filter(width => !isNaN(width)) : []; - useEffect(() => { - if (tableRef.current.parentNode) { - setWidth(Number(tableRef.current.parentNode.offsetWidth)); - } - }, [width]); - return ( { }); }; +// Modified to actually grab the parent size https://github.com/dagda1/cuttingedge/blob/main/packages/use-get-parent-size/src/useParentSize/useParentSize.ts + +const initialContentRect = { + bottom: undefined, + height: undefined, + left: undefined, + width: undefined, + right: undefined, + top: undefined, + x: undefined, + y: undefined, +}; + +const isNil = val => typeof val === 'undefined' || val === null; + +const useParentSize = ( + ref, + { + debounceDelay = 500, + initialValues = initialContentRect, + transformFunc = o => o, + maxDifference = 10, + callback = o => o, + } +) => { + const [contentRect, setContentRect] = useState({ + ...initialContentRect, + ...initialValues, + }); + const rerenderCount = useRef(0); + const previousContentRect = useRef(initialValues); + + const transformer = useCallback(transformFunc, [transformFunc]); + + if (!ref) console.error('You must pass a valid ref to useParentSize'); + + const debouncedCallback = useDebouncedCallback( + value => { + setContentRect(value); + callback(value); + }, + debounceDelay, + { + leading: true, + } + ); + + const refElement = ref.current; + + useLayoutEffect(() => { + if (isNil(refElement)) { + if (rerenderCount.current > 10) { + throw new Error('Maximum rerender count and no refElement Found'); + } + + setContentRect({ ...contentRect }); + rerenderCount.current++; + return; + } + + if (isNil(refElement.parentNode)) { + if (rerenderCount.parentNode > 10) { + throw new Error('Maximum rerender count and no parentNode Found'); + } + + setContentRect({ ...contentRect }); + rerenderCount.parentNode++; + return; + } + + const resizeObserver = new ResizeObserver(entries => { + if (!Array.isArray(entries) || entries.length !== 1) { + return; + } + + const entry = entries[0]; + const newWidth = Math.round(entry.contentRect.width); + const newHeight = Math.round(entry.contentRect.height); + + const widthDiff = Math.abs(newWidth - (previousContentRect.current.width ?? 0)); + const heightDiff = Math.abs(newHeight - (previousContentRect.current.height ?? 0)); + + if (widthDiff > maxDifference || heightDiff > maxDifference) { + previousContentRect.current.height = newHeight; + previousContentRect.current.width = newWidth; + debouncedCallback(entry.contentRect); + } + }); + + requestAnimationFrame(() => resizeObserver?.observe(refElement.parentNode)); + + return () => { + if (!!refElement.parentNode) { + resizeObserver?.unobserve(refElement.parentNode); + } + }; + }, [maxDifference, debouncedCallback, refElement, initialValues, contentRect]); + + return useMemo(() => transformer(contentRect), [contentRect, transformer]); +}; + const DEFAULT_HOME = { title: 'Products', href: '/apis/', @@ -303,6 +414,7 @@ export { getExternalLinkProps, getElementChild, cloneChildren, + useParentSize, DEFAULT_HOME, SEARCH_PARAMS, SIDENAV_WIDTH, diff --git a/yarn.lock b/yarn.lock index 89f6fb3815..82c3007c11 100644 --- a/yarn.lock +++ b/yarn.lock @@ -118,6 +118,7 @@ __metadata: redoc-cli: ^0.13.20 rehype-slug-custom-id: ^1.1.0 request: ^2.88.2 + resize-observer-polyfill: ^1.5.1 sharp: ^0.31.0 stream-http: ^3.2.0 styled-components: ^5.3.5 @@ -125,6 +126,7 @@ __metadata: to-arraybuffer: ^1.0.1 tty-browserify: ^0.0.1 unist-util-select: 3.0.4 + use-debounce: ^9.0.4 uuid: ^9.0.0 peerDependencies: gatsby: ^4.22.0 @@ -20737,6 +20739,13 @@ __metadata: languageName: node linkType: hard +"resize-observer-polyfill@npm:^1.5.1": + version: 1.5.1 + resolution: "resize-observer-polyfill@npm:1.5.1" + checksum: 57e7f79489867b00ba43c9c051524a5c8f162a61d5547e99333549afc23e15c44fd43f2f318ea0261ea98c0eb3158cca261e6f48d66e1ed1cd1f340a43977094 + languageName: node + linkType: hard + "resolve-alpn@npm:^1.0.0": version: 1.2.1 resolution: "resolve-alpn@npm:1.2.1" @@ -23809,6 +23818,15 @@ __metadata: languageName: node linkType: hard +"use-debounce@npm:^9.0.4": + version: 9.0.4 + resolution: "use-debounce@npm:9.0.4" + peerDependencies: + react: ">=16.8.0" + checksum: 37da4ecbe4e10a6230580cac03a8cae1788ea3e417dfdd92fcf654325458cf1b4567fd57bebf888edab62701a6abe47059a585008fd04228784f223f94d66ce4 + languageName: node + linkType: hard + "utif@npm:^2.0.1": version: 2.0.1 resolution: "utif@npm:2.0.1"