From 1fee99373d2a2dc019c2db210b1787becd3a3bc7 Mon Sep 17 00:00:00 2001 From: Tomi Virkki Date: Tue, 19 Dec 2023 17:08:09 +0200 Subject: [PATCH] fix: add a config option to render synchronously (#196) --- dev/pages/Grid.tsx | 39 -- package-lock.json | 545 ++++++------------- package.json | 2 + src/Grid.tsx | 2 +- src/GridColumn.tsx | 6 +- src/GridColumnGroup.tsx | 4 +- src/GridFilterColumn.tsx | 4 +- src/GridProEditColumn.tsx | 8 +- src/GridSelectionColumn.tsx | 6 +- src/GridSortColumn.tsx | 4 +- src/renderers/useModelRenderer.ts | 5 +- src/renderers/useRenderer.ts | 23 +- src/renderers/useSimpleOrChildrenRenderer.ts | 8 +- src/renderers/useSimpleRenderer.ts | 5 +- test/Dialog.spec.tsx | 25 + 15 files changed, 230 insertions(+), 456 deletions(-) delete mode 100644 dev/pages/Grid.tsx diff --git a/dev/pages/Grid.tsx b/dev/pages/Grid.tsx deleted file mode 100644 index 57a7e2fb..00000000 --- a/dev/pages/Grid.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Grid, type GridDataProvider } from '../../src/Grid.js'; -import { GridSelectionColumn } from '../../src/GridSelectionColumn.js'; -import { GridTreeColumn } from '../../src/GridTreeColumn.js'; -import { GridColumn } from '../../src/GridColumn.js'; -import { Tooltip } from '../../src/Tooltip.js'; - -type Item = { - name: string; - children: boolean; -}; - -const dataProvider: GridDataProvider = ({ parentItem, page, pageSize }, cb) => { - const levelSize = parentItem ? 5 : 100; - - const pageItems = [...Array(Math.min(levelSize, pageSize))].map((_, i) => { - const indexInLevel = page * pageSize + i; - - return { - name: `${parentItem ? parentItem.name + '-' : ''}${indexInLevel}`, - children: true, - }; - }); - - cb(pageItems, levelSize); -}; - -export default function () { - return ( - - - - - - - - - - ); -} diff --git a/package-lock.json b/package-lock.json index 3ab59fd3..78809c31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -84,6 +84,7 @@ "@types/karma-chrome-launcher": "^3.1.1", "@types/karma-mocha": "^1.3.1", "@types/mocha": "^10.0.1", + "@types/sinon": "^17.0.2", "@vitejs/plugin-react": "^4.0.0", "chai-as-promised": "^7.1.1", "chai-dom": "^1.11.0", @@ -103,6 +104,7 @@ "prettier": "^2.8.8", "rimraf": "^5.0.1", "simple-git-hooks": "^2.8.1", + "sinon": "^17.0.1", "tsx": "^3.12.7", "type-fest": "^3.11.1", "typescript": "^5.1.3", @@ -682,395 +684,6 @@ "source-map-support": "^0.5.21" } }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild-kit/core-utils/node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" - } - }, "node_modules/@esbuild-kit/esm-loader": { "version": "2.5.5", "resolved": "https://registry.npmjs.org/@esbuild-kit/esm-loader/-/esm-loader-2.5.5.tgz", @@ -1735,6 +1348,50 @@ "@webcomponents/shadycss": "^1.9.1" } }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, "node_modules/@socket.io/component-emitter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", @@ -1942,6 +1599,21 @@ "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", "devOptional": true }, + "node_modules/@types/sinon": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.2.tgz", + "integrity": "sha512-Zt6heIGsdqERkxctIpvN5Pv3edgBrhoeb3yHyxffd4InN0AX2SVNKSrhdDZKGQICVOxWP/q4DyhpfPNMSrpIiA==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true + }, "node_modules/@types/trusted-types": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz", @@ -4672,6 +4344,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, "node_modules/isbinaryfile": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", @@ -4896,6 +4574,12 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, "node_modules/karma": { "version": "6.4.2", "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.2.tgz", @@ -5332,6 +5016,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -5881,6 +5571,46 @@ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", "dev": true }, + "node_modules/nise": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", + "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/nise/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, "node_modules/node-releases": { "version": "2.0.12", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", @@ -6127,6 +5857,15 @@ "node": "14 || >=16.14" } }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -6652,6 +6391,33 @@ "simple-git-hooks": "cli.js" } }, + "node_modules/sinon": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", + "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.5", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/slice-ansi": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", @@ -7166,7 +6932,6 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, - "peer": true, "engines": { "node": ">=4" } diff --git a/package.json b/package.json index ce019b5c..adc885ab 100644 --- a/package.json +++ b/package.json @@ -132,6 +132,7 @@ "@types/karma-chrome-launcher": "^3.1.1", "@types/karma-mocha": "^1.3.1", "@types/mocha": "^10.0.1", + "@types/sinon": "^17.0.2", "@vitejs/plugin-react": "^4.0.0", "chai-as-promised": "^7.1.1", "chai-dom": "^1.11.0", @@ -151,6 +152,7 @@ "prettier": "^2.8.8", "rimraf": "^5.0.1", "simple-git-hooks": "^2.8.1", + "sinon": "^17.0.1", "tsx": "^3.12.7", "type-fest": "^3.11.1", "typescript": "^5.1.3", diff --git a/src/Grid.tsx b/src/Grid.tsx index fc16dcfa..ee7385e2 100644 --- a/src/Grid.tsx +++ b/src/Grid.tsx @@ -25,7 +25,7 @@ function Grid( props: GridProps, ref: ForwardedRef>, ): ReactElement | null { - const [portals, rowDetailsRenderer] = useModelRenderer(props.rowDetailsRenderer); + const [portals, rowDetailsRenderer] = useModelRenderer(props.rowDetailsRenderer, { renderSync: true }); return ( <_Grid {...props} ref={ref} rowDetailsRenderer={rowDetailsRenderer}> diff --git a/src/GridColumn.tsx b/src/GridColumn.tsx index ee1012b4..13aa6e54 100644 --- a/src/GridColumn.tsx +++ b/src/GridColumn.tsx @@ -25,9 +25,9 @@ function GridColumn( props: GridColumnProps, ref: ForwardedRef>, ): ReactElement | null { - const [headerPortals, headerRenderer] = useSimpleRenderer(props.headerRenderer); - const [footerPortals, footerRenderer] = useSimpleRenderer(props.footerRenderer); - const [bodyPortals, bodyRenderer] = useModelRenderer(props.renderer ?? props.children); + const [headerPortals, headerRenderer] = useSimpleRenderer(props.headerRenderer, { renderSync: true }); + const [footerPortals, footerRenderer] = useSimpleRenderer(props.footerRenderer, { renderSync: true }); + const [bodyPortals, bodyRenderer] = useModelRenderer(props.renderer ?? props.children, { renderSync: true }); return ( <_GridColumn diff --git a/src/GridColumnGroup.tsx b/src/GridColumnGroup.tsx index 5f679201..9d0f5aa1 100644 --- a/src/GridColumnGroup.tsx +++ b/src/GridColumnGroup.tsx @@ -15,8 +15,8 @@ export type GridColumnGroupProps = Partial; function GridColumnGroup(props: GridColumnGroupProps, ref: ForwardedRef): ReactElement | null { - const [headerPortals, headerRenderer] = useSimpleRenderer(props.headerRenderer); - const [footerPortals, footerRenderer] = useSimpleRenderer(props.footerRenderer); + const [headerPortals, headerRenderer] = useSimpleRenderer(props.headerRenderer, { renderSync: true }); + const [footerPortals, footerRenderer] = useSimpleRenderer(props.footerRenderer, { renderSync: true }); return ( <_GridColumnGroup {...props} footerRenderer={footerRenderer} headerRenderer={headerRenderer} ref={ref}> diff --git a/src/GridFilterColumn.tsx b/src/GridFilterColumn.tsx index 280eb096..1436c824 100644 --- a/src/GridFilterColumn.tsx +++ b/src/GridFilterColumn.tsx @@ -28,8 +28,8 @@ function GridFilterColumn( props: GridFilterColumnProps, ref: ForwardedRef>, ): ReactElement | null { - const [footerPortals, footerRenderer] = useSimpleRenderer(props.footerRenderer); - const [bodyPortals, bodyRenderer] = useModelRenderer(props.renderer ?? props.children); + const [footerPortals, footerRenderer] = useSimpleRenderer(props.footerRenderer, { renderSync: true }); + const [bodyPortals, bodyRenderer] = useModelRenderer(props.renderer ?? props.children, { renderSync: true }); return ( <_GridFilterColumn {...props} footerRenderer={footerRenderer} ref={ref} renderer={bodyRenderer}> diff --git a/src/GridProEditColumn.tsx b/src/GridProEditColumn.tsx index c5615a4b..0f7b94bf 100644 --- a/src/GridProEditColumn.tsx +++ b/src/GridProEditColumn.tsx @@ -29,10 +29,10 @@ function GridProEditColumn( props: GridProEditColumnProps, ref: ForwardedRef>, ): ReactElement | null { - const [editModePortals, editModeRenderer] = useModelRenderer(props.editModeRenderer); - const [headerPortals, headerRenderer] = useSimpleRenderer(props.headerRenderer); - const [footerPortals, footerRenderer] = useSimpleRenderer(props.footerRenderer); - const [bodyPortals, bodyRenderer] = useModelRenderer(props.renderer ?? props.children); + const [editModePortals, editModeRenderer] = useModelRenderer(props.editModeRenderer, { renderSync: true }); + const [headerPortals, headerRenderer] = useSimpleRenderer(props.headerRenderer, { renderSync: true }); + const [footerPortals, footerRenderer] = useSimpleRenderer(props.footerRenderer, { renderSync: true }); + const [bodyPortals, bodyRenderer] = useModelRenderer(props.renderer ?? props.children, { renderSync: true }); return ( <_GridProEditColumn diff --git a/src/GridSelectionColumn.tsx b/src/GridSelectionColumn.tsx index 785099fb..e543e532 100644 --- a/src/GridSelectionColumn.tsx +++ b/src/GridSelectionColumn.tsx @@ -25,9 +25,9 @@ function GridSelectionColumn( props: GridSelectionColumnProps, ref: ForwardedRef>, ): ReactElement | null { - const [headerPortals, headerRenderer] = useSimpleRenderer(props.headerRenderer); - const [footerPortals, footerRenderer] = useSimpleRenderer(props.footerRenderer); - const [bodyPortals, bodyRenderer] = useModelRenderer(props.renderer ?? props.children); + const [headerPortals, headerRenderer] = useSimpleRenderer(props.headerRenderer, { renderSync: true }); + const [footerPortals, footerRenderer] = useSimpleRenderer(props.footerRenderer, { renderSync: true }); + const [bodyPortals, bodyRenderer] = useModelRenderer(props.renderer ?? props.children, { renderSync: true }); return ( <_GridSelectionColumn diff --git a/src/GridSortColumn.tsx b/src/GridSortColumn.tsx index 30cc9db2..97e77393 100644 --- a/src/GridSortColumn.tsx +++ b/src/GridSortColumn.tsx @@ -27,8 +27,8 @@ function GridSortColumn( props: GridSortColumnProps, ref: ForwardedRef>, ): ReactElement | null { - const [footerPortals, footerRenderer] = useSimpleRenderer(props.footerRenderer); - const [bodyPortals, bodyRenderer] = useModelRenderer(props.renderer ?? props.children); + const [footerPortals, footerRenderer] = useSimpleRenderer(props.footerRenderer, { renderSync: true }); + const [bodyPortals, bodyRenderer] = useModelRenderer(props.renderer ?? props.children, { renderSync: true }); return ( <_GridSortColumn {...props} footerRenderer={footerRenderer} ref={ref} renderer={bodyRenderer}> diff --git a/src/renderers/useModelRenderer.ts b/src/renderers/useModelRenderer.ts index cc4f71fe..27476bd3 100644 --- a/src/renderers/useModelRenderer.ts +++ b/src/renderers/useModelRenderer.ts @@ -1,6 +1,6 @@ import type { ComponentType } from 'react'; import type { Slice } from './renderer.js'; -import { useRenderer, type UseRendererResult } from './useRenderer.js'; +import { useRenderer, type RendererConfig, type UseRendererResult } from './useRenderer.js'; export type Model = Readonly<{ item: I; @@ -27,6 +27,7 @@ export function convertModelRendererArgs, O extends HTMLEl export function useModelRenderer, O extends HTMLElement>( reactRenderer?: ComponentType> | null, + config?: RendererConfig, ): UseRendererResult> { - return useRenderer(reactRenderer, convertModelRendererArgs); + return useRenderer(reactRenderer, convertModelRendererArgs, config); } diff --git a/src/renderers/useRenderer.ts b/src/renderers/useRenderer.ts index 5085b85a..42c88a66 100644 --- a/src/renderers/useRenderer.ts +++ b/src/renderers/useRenderer.ts @@ -24,17 +24,36 @@ function rendererReducer( return new Map(state).set(root, args as Slice, 1>); } -export function useRenderer(node: ReactNode): UseRendererResult; +export type RendererConfig = { + renderSync?: boolean; +}; + +export function useRenderer

( + node: ReactNode, + convert?: (props: Slice, 1>) => PropsWithChildren

, + config?: RendererConfig, +): UseRendererResult; export function useRenderer

( reactRenderer: ComponentType

| null | undefined, convert: (props: Slice, 1>) => PropsWithChildren

, + config?: RendererConfig, ): UseRendererResult; export function useRenderer

( reactRendererOrNode: ReactNode | ComponentType

| null | undefined, convert?: (props: Slice, 1>) => PropsWithChildren

, + config?: RendererConfig, ): UseRendererResult { const [map, update] = useReducer>(rendererReducer, initialState); - const renderer = useCallback(((...args: Parameters) => flushSync(() => update(args))) as W, []); + const renderer = useCallback( + ((...args: Parameters) => { + if (config?.renderSync) { + flushSync(() => update(args)); + } else { + update(args); + } + }) as W, + [], + ); return reactRendererOrNode ? [ diff --git a/src/renderers/useSimpleOrChildrenRenderer.ts b/src/renderers/useSimpleOrChildrenRenderer.ts index fe29c7e4..3131987d 100644 --- a/src/renderers/useSimpleOrChildrenRenderer.ts +++ b/src/renderers/useSimpleOrChildrenRenderer.ts @@ -1,7 +1,6 @@ -import { Component, PureComponent } from 'react'; import type { ComponentType, ReactNode } from 'react'; import { useRenderer } from './useRenderer.js'; -import type { UseRendererResult } from './useRenderer.js'; +import type { RendererConfig, UseRendererResult } from './useRenderer.js'; import { type ReactSimpleRendererProps, useSimpleRenderer, @@ -11,6 +10,7 @@ import { export function useSimpleOrChildrenRenderer( fnRenderer?: ComponentType> | null, children?: ReactNode | ComponentType>, + config?: RendererConfig, ): UseRendererResult> { let _children: ReactNode | undefined; let _fnRenderer: ComponentType> | null | undefined; @@ -26,8 +26,8 @@ export function useSimpleOrChildrenRenderer( shouldUseSimpleRendererResult = !!_fnRenderer; } - const useChildrenRendererResult = useRenderer(_children); - const useSimpleRendererResult = useSimpleRenderer(_fnRenderer); + const useChildrenRendererResult = useRenderer(_children, undefined, config); + const useSimpleRendererResult = useSimpleRenderer(_fnRenderer, config); return shouldUseSimpleRendererResult ? useSimpleRendererResult : useChildrenRendererResult; } diff --git a/src/renderers/useSimpleRenderer.ts b/src/renderers/useSimpleRenderer.ts index 14f2c5e7..d854e104 100644 --- a/src/renderers/useSimpleRenderer.ts +++ b/src/renderers/useSimpleRenderer.ts @@ -1,6 +1,6 @@ import type { ComponentType, PropsWithChildren } from 'react'; import type { Slice } from './renderer.js'; -import { useRenderer, type UseRendererResult } from './useRenderer.js'; +import { useRenderer, type RendererConfig, type UseRendererResult } from './useRenderer.js'; export type ReactSimpleRendererProps = Readonly<{ original: O; @@ -16,6 +16,7 @@ function convertSimpleRendererArgs([original]: Slice< export function useSimpleRenderer( reactRenderer?: ComponentType> | null, + config?: RendererConfig, ): UseRendererResult> { - return useRenderer(reactRenderer, convertSimpleRendererArgs); + return useRenderer(reactRenderer, convertSimpleRendererArgs, config); } diff --git a/test/Dialog.spec.tsx b/test/Dialog.spec.tsx index 180913c6..25f0a65e 100644 --- a/test/Dialog.spec.tsx +++ b/test/Dialog.spec.tsx @@ -1,8 +1,10 @@ import { expect, use as useChaiPlugin } from '@esm-bundle/chai'; import { cleanup, render } from '@testing-library/react/pure.js'; import chaiDom from 'chai-dom'; +import sinon from 'sinon'; import { Dialog, type DialogElement } from '../src/Dialog.js'; import createOverlayCloseCatcher from './utils/createOverlayCloseCatcher.js'; +import { useState } from 'react'; useChaiPlugin(chaiDom); @@ -62,4 +64,27 @@ describe('Dialog', () => { ); assert(); }); + + it('should not warn on open', async () => { + function TestDialog() { + const [opened, setOpened] = useState(false); + return ( + <> + +

FooBar + + ); + } + + render(); + + const warn = sinon.stub(console, 'error'); + document.querySelector('#open-button')?.click(); + await new Promise((resolve) => requestAnimationFrame(resolve)); + warn.restore(); + + expect(warn.called).to.be.false; + }); });