From b38fb0ffd9de5a85e60f350ad072d2b2e9d3806c Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 10 Mar 2026 20:02:14 -0400 Subject: [PATCH] Site search --- .github/workflows/pending-changes.yml | 14 +- package.json | 10 +- pnpm-lock.yaml | 594 +++++++++++++++++++++++++- public/generated/search-index.json | 506 ++++++++++++++++++++++ public/generated/search-records.json | 171 ++++++++ scripts/compile-search-index.ts | 6 + src/App.tsx | 3 +- src/components/NavLink.tsx | 6 +- 8 files changed, 1291 insertions(+), 19 deletions(-) create mode 100644 public/generated/search-index.json create mode 100644 public/generated/search-records.json create mode 100644 scripts/compile-search-index.ts diff --git a/.github/workflows/pending-changes.yml b/.github/workflows/pending-changes.yml index 6fb2d40b4..592943d37 100644 --- a/.github/workflows/pending-changes.yml +++ b/.github/workflows/pending-changes.yml @@ -9,8 +9,20 @@ jobs: - uses: pnpm/action-setup@v2 with: version: 10 + - name: Install dependencies run: pnpm install --frozen-lockfile --recursive + env: + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 'true' + + - name: Setup Google Chrome + uses: browser-actions/setup-chrome@v2 + id: setup-chrome + with: + install-dependencies: true + - uses: nickcharlton/diff-check@main with: - command: pnpm run compile + command: pnpm dev & pnpm run compile + env: + CHROME_PATH: ${{ steps.setup-chrome.outputs.chrome-path }} \ No newline at end of file diff --git a/package.json b/package.json index 2c3e0ba30..0568b1fee 100644 --- a/package.json +++ b/package.json @@ -20,16 +20,17 @@ ], "scripts": { "dev": "vite", - "dev:integrations": "concurrently -k \"pnpm run dev:integrations:next\" \"pnpm run dev:integrations:vike\" \"pnpm run dev:integrations:vite\"", + "dev:integrations": "pnpm run /^dev:integrations:.*/", "dev:integrations:next": "pnpm -C integrations/next/ run dev", "dev:integrations:vike": "pnpm -C integrations/vike/ run dev", "dev:integrations:vite": "pnpm -C integrations/vite/ run dev", - "build": "pnpm run build:lib && pnpm run build:docs", + "build": "pnpm run /^build:.*/", "build:docs": "cross-env TARGET=docs vite build", "build:lib": "cross-env TARGET=lib vite build", - "compile": "pnpm run compile:docs && pnpm run compile:examples", + "compile": "pnpm run --sequential /^compile:.*/", "compile:docs": "tsx ./scripts/compile-docs", "compile:examples": "tsx ./scripts/compile-examples", + "compile:search-index": "tsx ./scripts/compile-search-index", "compress:og-image": "tsx ./scripts/compress-og-image", "e2e:install": "pnpm -C integrations/tests exec playwright install --with-deps", "e2e:test": "pnpm -C integrations/tests run test", @@ -91,11 +92,12 @@ "postcss": "^8.5.6", "prettier": "3.6.2", "prettier-plugin-tailwindcss": "^0.7.1", + "puppeteer": "^24.38.0", "react": "^19.2.3", "react-docgen-typescript": "^2.4.0", "react-dom": "^19.2.3", "react-error-boundary": "^6.0.0", - "react-lib-tools": "0.0.35", + "react-lib-tools": "^0.0.44", "react-router-dom": "^7.6.3", "rimraf": "^6.1.2", "rollup-plugin-terser": "^7.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4f15db6f..589f37cbb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -122,6 +122,9 @@ importers: prettier-plugin-tailwindcss: specifier: ^0.7.1 version: 0.7.1(prettier@3.6.2) + puppeteer: + specifier: ^24.38.0 + version: 24.38.0(typescript@5.8.3) react: specifier: ^19.2.3 version: 19.2.3 @@ -135,8 +138,8 @@ importers: specifier: ^6.0.0 version: 6.0.0(react@19.2.3) react-lib-tools: - specifier: 0.0.35 - version: 0.0.35(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.8.3) + specifier: ^0.0.44 + version: 0.0.44(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.8.3) react-router-dom: specifier: ^7.6.3 version: 7.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -1316,6 +1319,11 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@puppeteer/browsers@2.13.0': + resolution: {integrity: sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==} + engines: {node: '>=18'} + hasBin: true + '@react-aria/focus@3.21.2': resolution: {integrity: sha512-JWaCR7wJVggj+ldmM/cb/DXFg47CXR55lznJhZBh4XVqJjMKwaOOqpT5vNN7kpC1wUpXicGNuDnJDN1S/+6dhQ==} peerDependencies: @@ -1777,6 +1785,9 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@ts-ast-parser/comment@0.2.0': resolution: {integrity: sha512-W/nxZGgoK0HS90Zuy5tg4I2TF6izsW3U8jIHk+M9dEvpBjvVMLOZCmZbaewsOsu8xA11vAiLAD4IMBjLMuUwcQ==} engines: {node: 18.x || 20.x || 21.x} @@ -1900,6 +1911,9 @@ packages: '@types/serve-static@1.15.10': resolution: {integrity: sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==} + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + '@typescript-eslint/eslint-plugin@8.48.0': resolution: {integrity: sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2258,6 +2272,10 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} @@ -2274,9 +2292,59 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + b4a@1.7.3: + resolution: {integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bare-events@2.8.2: + resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + + bare-fs@4.5.5: + resolution: {integrity: sha512-XvwYM6VZqKoqDll8BmSww5luA5eflDzY0uEFfBJtFKe4PAAtxBjU3YIxzIBzhyaEQBy1VXEQBto4cpN5RZJw+w==} + engines: {bare: '>=1.16.0'} + peerDependencies: + bare-buffer: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + + bare-os@3.7.1: + resolution: {integrity: sha512-ebvMaS5BgZKmJlvuWh14dg9rbUI84QeV3WlWn6Ph6lFI8jJoh7ADtVTyD2c93euwbe+zgi0DVrl4YmqXeM9aIA==} + engines: {bare: '>=1.14.0'} + + bare-path@3.0.0: + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + + bare-stream@2.8.0: + resolution: {integrity: sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==} + peerDependencies: + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + bare-events: + optional: true + + bare-url@2.3.2: + resolution: {integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==} + + basic-ftp@5.2.0: + resolution: {integrity: sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==} + engines: {node: '>=10.0.0'} + body-parser@2.2.0: resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} engines: {node: '>=18'} @@ -2296,6 +2364,9 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -2350,6 +2421,11 @@ packages: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} + chromium-bidi@14.0.0: + resolution: {integrity: sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==} + peerDependencies: + devtools-protocol: '*' + cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} @@ -2443,6 +2519,15 @@ packages: typescript: optional: true + cosmiconfig@9.0.0: + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -2471,6 +2556,10 @@ packages: damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + data-urls@5.0.0: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} @@ -2515,6 +2604,15 @@ packages: supports-color: optional: true + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} @@ -2537,6 +2635,10 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -2549,6 +2651,9 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + devtools-protocol@0.0.1581282: + resolution: {integrity: sha512-nv7iKtNZQshSW2hKzYNr46nM/Cfh5SEvE2oV0/SEGgc9XupIY5ggf84Cz8eJIkBce7S3bmTAauFD6aysMpnqsQ==} + diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -2589,6 +2694,9 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + enhanced-resolve@5.18.3: resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} engines: {node: '>=10.13.0'} @@ -2601,6 +2709,10 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} @@ -2664,6 +2776,11 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + eslint-config-next@16.0.6: resolution: {integrity: sha512-nx0Z2S50TlcSQ2RtyULCff5tlKTwqF/ICh3U9s8C/e2aRXAm1Ootdb7BEHGZmejtJSgsFq8PVFdlWy8BHiz2pg==} peerDependencies: @@ -2780,6 +2897,11 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} @@ -2809,6 +2931,9 @@ packages: eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} + expect-type@1.2.2: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} @@ -2820,9 +2945,17 @@ packages: exsolve@1.0.7: resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + fast-glob@3.3.1: resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} engines: {node: '>=8.6.0'} @@ -2840,6 +2973,9 @@ packages: fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -2914,6 +3050,10 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + fuse.js@7.1.0: + resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} + engines: {node: '>=10'} + generator-function@2.0.1: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} @@ -2938,6 +3078,10 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + get-symbol-description@1.1.0: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} @@ -2945,6 +3089,10 @@ packages: get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-uri@6.0.5: + resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} + engines: {node: '>= 14'} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -3084,6 +3232,10 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -3453,6 +3605,10 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -3539,6 +3695,9 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} @@ -3580,6 +3739,10 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} + netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + next@16.0.10: resolution: {integrity: sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==} engines: {node: '>=20.9.0'} @@ -3677,6 +3840,14 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + pac-proxy-agent@7.2.0: + resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==} + engines: {node: '>= 14'} + + pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -3739,6 +3910,9 @@ packages: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -3854,6 +4028,10 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -3861,6 +4039,16 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + proxy-agent@6.5.0: + resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} + engines: {node: '>= 14'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -3869,6 +4057,15 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + puppeteer-core@24.38.0: + resolution: {integrity: sha512-zB3S/tksIhgi2gZRndUe07AudBz5SXOB7hqG0kEa9/YXWrGwlVlYm3tZtwKgfRftBzbmLQl5iwHkQQl04n/mWw==} + engines: {node: '>=18'} + + puppeteer@24.38.0: + resolution: {integrity: sha512-abnJOBVoL9PQTLKSbYGm9mjNFyIPaTVj77J/6cS370dIQtcZMpx8wyZoAuBzR71Aoon6yvI71NEVFUsl3JU82g==} + engines: {node: '>=18'} + hasBin: true + qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} @@ -3911,8 +4108,8 @@ packages: react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - react-lib-tools@0.0.35: - resolution: {integrity: sha512-erQsHCfLYWqKMR+MvySERZ59FjGuTGFYXnEhcablSj80gVro3cKWbGP30iyGo9vxZqjBEg/TSNNcPhLe8xsjeg==} + react-lib-tools@0.0.44: + resolution: {integrity: sha512-RMGtXSI0FOCwTeuZ4Hn1FlYBpgl5VVwSEVyhzCe/BJKKHbuMtgMmk5GKC03MMd5+1A8gnN1FEivuF+d+VXHrtQ==} peerDependencies: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 @@ -4106,6 +4303,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + send@1.2.0: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} @@ -4190,9 +4392,21 @@ packages: resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} engines: {node: '>=18'} + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + socks-proxy-agent@8.0.5: + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} + + socks@2.8.7: + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -4232,6 +4446,9 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} + streamx@2.23.0: + resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -4337,11 +4554,23 @@ packages: resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==} engines: {node: '>=6'} + tar-fs@3.1.1: + resolution: {integrity: sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==} + + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + + teex@1.0.1: + resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} + terser@5.43.1: resolution: {integrity: sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==} engines: {node: '>=10'} hasBin: true + text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -4458,6 +4687,9 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} + typed-query-selector@2.12.1: + resolution: {integrity: sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA==} + typescript-eslint@8.48.0: resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4708,6 +4940,9 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} + webdriver-bidi-protocol@0.4.1: + resolution: {integrity: sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==} + webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} @@ -4778,6 +5013,18 @@ packages: utf-8-validate: optional: true + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} @@ -4808,6 +5055,9 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} @@ -4822,6 +5072,9 @@ packages: peerDependencies: zod: ^3.25.0 || ^4.0.0 + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.1.5: resolution: {integrity: sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg==} @@ -4976,7 +5229,7 @@ snapshots: '@babel/parser': 7.28.5 '@babel/template': 7.27.2 '@babel/types': 7.28.5 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -5661,6 +5914,21 @@ snapshots: '@polka/url@1.0.0-next.29': {} + '@puppeteer/browsers@2.13.0': + dependencies: + debug: 4.4.3 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.5.0 + semver: 7.7.4 + tar-fs: 3.1.1 + yargs: 17.7.2 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + - supports-color + '@react-aria/focus@3.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@react-aria/interactions': 3.25.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -6073,6 +6341,8 @@ snapshots: dependencies: '@testing-library/dom': 10.4.1 + '@tootallnate/quickjs-emscripten@0.23.0': {} + '@ts-ast-parser/comment@0.2.0': dependencies: tslib: 2.8.1 @@ -6215,6 +6485,11 @@ snapshots: '@types/node': 24.2.0 '@types/send': 0.17.6 + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 24.2.0 + optional: true + '@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -6277,7 +6552,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.8.3) '@typescript-eslint/types': 8.48.0 - debug: 4.4.1 + debug: 4.4.3 typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -6286,7 +6561,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) '@typescript-eslint/types': 8.48.0 - debug: 4.4.1 + debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -6309,7 +6584,7 @@ snapshots: '@typescript-eslint/types': 8.48.0 '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.8.3) '@typescript-eslint/utils': 8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3) - debug: 4.4.1 + debug: 4.4.3 eslint: 9.30.1(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 @@ -6321,7 +6596,7 @@ snapshots: '@typescript-eslint/types': 8.48.0 '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) '@typescript-eslint/utils': 8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.9.3) - debug: 4.4.1 + debug: 4.4.3 eslint: 9.30.1(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 @@ -6714,6 +6989,10 @@ snapshots: ast-types-flow@0.0.8: {} + ast-types@0.13.4: + dependencies: + tslib: 2.8.1 + async-function@1.0.0: {} available-typed-arrays@1.0.7: @@ -6724,8 +7003,50 @@ snapshots: axobject-query@4.1.0: {} + b4a@1.7.3: {} + balanced-match@1.0.2: {} + bare-events@2.8.2: {} + + bare-fs@4.5.5: + dependencies: + bare-events: 2.8.2 + bare-path: 3.0.0 + bare-stream: 2.8.0(bare-events@2.8.2) + bare-url: 2.3.2 + fast-fifo: 1.3.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + optional: true + + bare-os@3.7.1: + optional: true + + bare-path@3.0.0: + dependencies: + bare-os: 3.7.1 + optional: true + + bare-stream@2.8.0(bare-events@2.8.2): + dependencies: + streamx: 2.23.0 + teex: 1.0.1 + optionalDependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + optional: true + + bare-url@2.3.2: + dependencies: + bare-path: 3.0.0 + optional: true + + basic-ftp@5.2.0: {} + body-parser@2.2.0: dependencies: bytes: 3.1.2 @@ -6760,6 +7081,8 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.1) + buffer-crc32@0.2.13: {} + buffer-from@1.1.2: {} builtin-modules@3.3.0: {} @@ -6808,6 +7131,12 @@ snapshots: check-error@2.1.1: {} + chromium-bidi@14.0.0(devtools-protocol@0.0.1581282): + dependencies: + devtools-protocol: 0.0.1581282 + mitt: 3.0.1 + zod: 3.25.76 + cli-cursor@5.0.0: dependencies: restore-cursor: 5.1.0 @@ -6895,6 +7224,15 @@ snapshots: optionalDependencies: typescript: 5.8.3 + cosmiconfig@9.0.0(typescript@5.8.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.8.3 + create-require@1.1.1: {} crelt@1.0.6: {} @@ -6921,6 +7259,8 @@ snapshots: damerau-levenshtein@1.0.8: {} + data-uri-to-buffer@6.0.2: {} + data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 @@ -6958,6 +7298,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.3: + dependencies: + ms: 2.1.3 + decimal.js@10.6.0: {} deep-eql@5.0.2: {} @@ -6978,12 +7322,20 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + degenerator@5.0.1: + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + depd@2.0.0: {} dequal@2.0.3: {} detect-libc@2.1.2: {} + devtools-protocol@0.0.1581282: {} + diff@4.0.2: {} doctrine@2.1.0: @@ -7017,6 +7369,10 @@ snapshots: encodeurl@2.0.0: {} + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + enhanced-resolve@5.18.3: dependencies: graceful-fs: 4.2.11 @@ -7026,6 +7382,8 @@ snapshots: entities@6.0.1: {} + env-paths@2.2.1: {} + environment@1.1.0: {} error-ex@1.3.2: @@ -7198,6 +7556,14 @@ snapshots: escape-string-regexp@4.0.0: {} + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + eslint-config-next@16.0.6(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 16.0.6 @@ -7412,6 +7778,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.1 + esprima@4.0.1: {} + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -7434,6 +7802,12 @@ snapshots: eventemitter3@5.0.1: {} + events-universal@1.0.1: + dependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + expect-type@1.2.2: {} express@5.1.0: @@ -7470,8 +7844,20 @@ snapshots: exsolve@1.0.7: {} + extract-zip@2.0.1: + dependencies: + debug: 4.4.3 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + fast-deep-equal@3.1.3: {} + fast-fifo@1.3.2: {} + fast-glob@3.3.1: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -7496,6 +7882,10 @@ snapshots: dependencies: reusify: 1.1.0 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -7568,6 +7958,8 @@ snapshots: functions-have-names@1.2.3: {} + fuse.js@7.1.0: {} + generator-function@2.0.1: {} gensync@1.0.0-beta.2: {} @@ -7594,6 +7986,10 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-stream@5.2.0: + dependencies: + pump: 3.0.3 + get-symbol-description@1.1.0: dependencies: call-bound: 1.0.4 @@ -7604,6 +8000,14 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + get-uri@6.0.5: + dependencies: + basic-ftp: 5.2.0 + data-uri-to-buffer: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -7741,6 +8145,8 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + ip-address@10.1.0: {} + ipaddr.js@1.9.1: {} is-array-buffer@3.0.5: @@ -7770,7 +8176,7 @@ snapshots: is-bun-module@2.0.0: dependencies: - semver: 7.7.3 + semver: 7.7.4 is-callable@1.2.7: {} @@ -8110,6 +8516,8 @@ snapshots: dependencies: yallist: 4.0.0 + lru-cache@7.18.3: {} + lz-string@1.5.0: {} magic-string@0.30.17: @@ -8180,6 +8588,8 @@ snapshots: minipass@7.1.2: {} + mitt@3.0.1: {} + mlly@1.8.0: dependencies: acorn: 8.15.0 @@ -8207,6 +8617,8 @@ snapshots: negotiator@1.0.0: {} + netmask@2.0.2: {} + next@16.0.10(@babel/core@7.28.5)(@playwright/test@1.57.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: '@next/env': 16.0.10 @@ -8325,6 +8737,24 @@ snapshots: dependencies: p-limit: 3.1.0 + pac-proxy-agent@7.2.0: + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.4 + debug: 4.4.3 + get-uri: 6.0.5 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + pac-resolver@7.0.1: + dependencies: + degenerator: 5.0.1 + netmask: 2.0.2 + package-json-from-dist@1.0.1: {} parent-module@1.0.1: @@ -8333,7 +8763,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.28.6 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -8371,6 +8801,8 @@ snapshots: pathval@2.0.1: {} + pend@1.2.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -8429,6 +8861,8 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 + progress@2.0.3: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -8440,10 +8874,64 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + proxy-agent@6.5.0: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 7.18.3 + pac-proxy-agent: 7.2.0 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + proxy-from-env@1.1.0: {} + + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + punycode.js@2.3.1: {} punycode@2.3.1: {} + puppeteer-core@24.38.0: + dependencies: + '@puppeteer/browsers': 2.13.0 + chromium-bidi: 14.0.0(devtools-protocol@0.0.1581282) + debug: 4.4.3 + devtools-protocol: 0.0.1581282 + typed-query-selector: 2.12.1 + webdriver-bidi-protocol: 0.4.1 + ws: 8.19.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - bufferutil + - react-native-b4a + - supports-color + - utf-8-validate + + puppeteer@24.38.0(typescript@5.8.3): + dependencies: + '@puppeteer/browsers': 2.13.0 + chromium-bidi: 14.0.0(devtools-protocol@0.0.1581282) + cosmiconfig: 9.0.0(typescript@5.8.3) + devtools-protocol: 0.0.1581282 + puppeteer-core: 24.38.0 + typed-query-selector: 2.12.1 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - bufferutil + - react-native-b4a + - supports-color + - typescript + - utf-8-validate + qs@6.14.0: dependencies: side-channel: 1.1.0 @@ -8483,7 +8971,7 @@ snapshots: react-is@17.0.2: {} - react-lib-tools@0.0.35(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.8.3): + react-lib-tools@0.0.44(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.8.3): dependencies: '@codemirror/lang-css': 6.3.1 '@codemirror/lang-html': 6.4.11 @@ -8494,10 +8982,18 @@ snapshots: '@codemirror/state': 6.5.3 '@lezer/highlight': 1.2.3 '@ts-ast-parser/core': 0.8.0(typescript@5.8.3) + fuse.js: 7.1.0 + puppeteer: 24.38.0(typescript@5.8.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - bufferutil + - react-native-b4a + - supports-color - typescript + - utf-8-validate react-refresh@0.17.0: {} @@ -8711,6 +9207,8 @@ snapshots: semver@7.7.3: {} + semver@7.7.4: {} + send@1.2.0: dependencies: debug: 4.4.1 @@ -8855,11 +9353,26 @@ snapshots: ansi-styles: 6.2.1 is-fullwidth-code-point: 5.1.0 + smart-buffer@4.2.0: {} + snake-case@3.0.4: dependencies: dot-case: 3.0.4 tslib: 2.8.1 + socks-proxy-agent@8.0.5: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + socks: 2.8.7 + transitivePeerDependencies: + - supports-color + + socks@2.8.7: + dependencies: + ip-address: 10.1.0 + smart-buffer: 4.2.0 + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -8888,6 +9401,15 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 + streamx@2.23.0: + dependencies: + events-universal: 1.0.1 + fast-fifo: 1.3.2 + text-decoder: 1.2.3 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + string-argv@0.3.2: {} string-width@4.2.3: @@ -9003,6 +9525,35 @@ snapshots: tapable@2.2.2: {} + tar-fs@3.1.1: + dependencies: + pump: 3.0.3 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 4.5.5 + bare-path: 3.0.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + tar-stream@3.1.7: + dependencies: + b4a: 1.7.3 + fast-fifo: 1.3.2 + streamx: 2.23.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + teex@1.0.1: + dependencies: + streamx: 2.23.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + optional: true + terser@5.43.1: dependencies: '@jridgewell/source-map': 0.3.11 @@ -9010,6 +9561,12 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 + text-decoder@1.2.3: + dependencies: + b4a: 1.7.3 + transitivePeerDependencies: + - react-native-b4a + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -9165,6 +9722,8 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typed-query-selector@2.12.1: {} + typescript-eslint@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3): dependencies: '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.6.1))(typescript@5.8.3) @@ -9445,6 +10004,8 @@ snapshots: dependencies: xml-name-validator: 5.0.0 + webdriver-bidi-protocol@0.4.1: {} + webidl-conversions@7.0.0: {} whatwg-encoding@3.1.1: @@ -9526,6 +10087,8 @@ snapshots: ws@8.18.3: {} + ws@8.19.0: {} + xml-name-validator@5.0.0: {} xmlchars@2.2.0: {} @@ -9550,6 +10113,11 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + yn@3.1.1: {} yocto-queue@0.1.0: {} @@ -9558,6 +10126,8 @@ snapshots: dependencies: zod: 4.1.5 + zod@3.25.76: {} + zod@4.1.5: {} zustand@5.0.9(@types/react@19.2.7)(react@19.2.3)(use-sync-external-store@1.5.0(react@19.2.3)): diff --git a/public/generated/search-index.json b/public/generated/search-index.json new file mode 100644 index 000000000..5c531a2c5 --- /dev/null +++ b/public/generated/search-index.json @@ -0,0 +1,506 @@ +{ + "keys": [ + { + "path": [ + "title" + ], + "id": "title", + "weight": 1, + "src": "title", + "getFn": null + }, + { + "path": [ + "section" + ], + "id": "section", + "weight": 1, + "src": "section", + "getFn": null + }, + { + "path": [ + "text" + ], + "id": "text", + "weight": 1, + "src": "text", + "getFn": null + } + ], + "records": [ + { + "i": 0, + "$": { + "0": { + "v": "Getting started with react-resizable-panels", + "n": 0.5 + }, + "2": { + "v": "This library is a set of React components that can be used to build resizable layouts like the one below: This panel is resizableThis one is too There are many types of layouts, covered in the examples section of the docs. Check out the support page if you have questions. Installation Begin by installing the library from NPM: npm install react-resizable-panels TypeScript definitions are included within the published dist folder. Support Here are some ways to support this project: Become a GitHub sponsorBuy me a coffee", + "n": 0.108 + } + } + }, + { + "i": 1, + "$": { + "0": { + "v": "Previous releases", + "n": 0.707 + }, + "2": { + "v": "Click below to view documentation for past releases. 4.x documentation source code3.x documentation source code2.x documentation source code1.x source code", + "n": 0.224 + } + } + }, + { + "i": 2, + "$": { + "0": { + "v": "The basics", + "n": 0.707 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "The simplest resizable panel configuration is two panels within a group. import { Group, Panel } from \"react-resizable-panels\";\n \n\n left\n right\n leftright Panel groups use a flexbox layout with a default orientation of horizontal but the orientation prop can be used to specify a vertical layout. \n top\n bottom\n Vertical groups may benefit from an explicit height or min-height (read more). topbottom Panels can be resized by clicking on their borders but explicit separators can be rendered to improve UX. Separators provide another benefit: double-clicking on one resets a panel to its default size. leftright \n left\n \n right\n Separators improve keyboard accessibility by providing a tab-focusable window splitter element.", + "n": 0.094 + } + } + }, + { + "i": 3, + "$": { + "0": { + "v": "Min/max sizes", + "n": 0.707 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "Panels can be configured with minimum/maximum allowed sizes. Size can be specified using the following CSS units: PixelsPercentagesFont sizes (em, rem)Viewport sizes (vh, vw) For example, the left panel below only allows itself to be resized between 10v0-200 pixels. \n left\n \n right\n left200pxright As another example, this panel group will not allow any individual panel to be smaller than 10% of the group's width. \n left\n \n middle\n \n right\n left33%middle33%right33% When specifying sizes, remember:Numbers are evaluated as pixels.Strings are evaluated as percentages (0..100%) unless otherwise specified.You can always include the unit, even for pixels (e.g. minSize=\"100px\") or percentages (e.g. minSize=\"10%\")", + "n": 0.095 + } + } + }, + { + "i": 4, + "$": { + "0": { + "v": "Collapsible panels", + "n": 0.707 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "Panels can be configured to be collapsible using the collapsible and minSize properties. \n \n \n \n 284pxThe panel on the left has a minimum size of 100 pixels. It will collapse entirely if resized smaller than 50 pixels. Although it isn't required, it's recommended that you also render a Separator for panels that can be collapsed fully. This separator gives users something to click to re-open a panel after it's been collapsed. The collapsedSize property can also be provided to prevent a panel from disappearing fully when collapsed. \n \n \n \n 284pxThe panel on the left collapses to a width of 35 pixels. This enables building UIs like VS Code's \"Folders\" side panel. A panel's collapse threshold is half its minimum size. Collapsible panels can also be collapsed by default by setting their defaultSize to 0 (pixels or percent). \n \n \n \n 0%The panel on the left is collapsed by default but can be expanded by dragging the separator.", + "n": 0.075 + } + } + }, + { + "i": 5, + "$": { + "0": { + "v": "Persistent layouts", + "n": 0.707 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "Panel groups can be configured to save and restore layouts between page visits with the useDefaultLayout hook. Resize the panels below and then reload the page to see an example. const { defaultLayout, onLayoutChanged } = useDefaultLayout({\n id: \"unique-layout-id\",\n storage: localStorage\n});\n \n\n left\n \n center\n \n right\n left33%center33%right33% Panels require unique id props to restore saved layouts. The example above works well with client rendered application. Click below for more guidance about server rendering. Persistent layouts with conditional panelsPersistent layouts with server renderingPersistent layouts with server components", + "n": 0.102 + } + } + }, + { + "i": 6, + "$": { + "0": { + "v": "Persistent layouts with conditional panels", + "n": 0.447 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "For Groups that contain conditionally rendered Panels, it can be useful to save multiple layouts (one for each set of Panels). To enable this, pass the additional panelIds prop as shown below. const { defaultLayout, onLayoutChanged } = useDefaultLayout({\n id: \"unique-layout-id\",\n // This set of ids must match the Panels rendered during mount,\n // or the default layout will not be restored\n panelIds: showLeftPanel ? [\"left\", \"right\"] : [\"right\"],\n storage: localStorage\n});\n \n\n {showLeftPanel && (\n <>\n left\n \n \n )}\n right\n", + "n": 0.108 + } + } + }, + { + "i": 7, + "$": { + "0": { + "v": "Persistent layouts with server rendering", + "n": 0.447 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "Because localStorage is unavailable on the server, a custom storage configuration is needed to avoid layout shift when server rendering. Building on the previous example, a Cookie based storage might look like this: import { type LayoutStorage } from \"react-resizable-panels\";\n \nconst cookieStorage: LayoutStorage = {\n getItem(key: string) {\n const cookies = document.cookie.split(\";\");\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split(\"=\");\n if (name === key) {\n return value;\n }\n }\n return null;\n },\n setItem(key: string, value: string) {\n document.cookie = `${key}=${value}; path=/;`;\n }\n};\n \nuseDefaultLayout({\n id: \"unique-layout-id\",\n storage: cookieStorage\n}); If an async storage API is required, saved layouts should be loaded using suspense. The example above includes path=/ so that saved layouts can be shared between paths; see Using HTTP cookies for more.", + "n": 0.091 + } + } + }, + { + "i": 8, + "$": { + "0": { + "v": "Persistent layouts with server components", + "n": 0.447 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "When using server components with a framework like Next.js, a slightly different approach is required: export default async function Page() {\n const api = await cookies();\n const defaultLayoutString = api.get(groupId)?.value;\n const defaultLayout = defaultLayoutString\n ? (JSON.parse(defaultLayoutString) as Layout)\n : undefined;\n \n return ;\n} (\"use client\");\n \nexport default function ClientComponent({\n defaultLayout,\n groupId\n}: {\n defaultLayout: Layout | undefined;\n groupId: string;\n}) {\n return (\n {\n document.cookie = `${groupId}=${JSON.stringify(layout)}; path=/;`;\n }}\n >\n \n left\n \n \n right\n \n \n );\n} The example above includes path=/ so that saved layouts can be shared between paths; see Using HTTP cookies for more.", + "n": 0.097 + } + } + }, + { + "i": 9, + "$": { + "0": { + "v": "Nested groups", + "n": 0.707 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "Panel groups can be nested. In this configuration, multiple groups can be resized at the same time by clicking near panel intersections. \n left\n \n \n top\n \n \n left\n right\n \n \n \n \n right\n", + "n": 0.16 + } + } + }, + { + "i": 10, + "$": { + "0": { + "v": "Conditional Panels", + "n": 0.707 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "Panel can be conditionally rendered. hide left panelhide right panel leftcenterright \n {hideLeftPanel || (\n <>\n left panel\n \n \n )}\n center panel\n {hideRightPanel || (\n <>\n \n right panel\n \n )}\n Conditional panels should also specify ids to help match previous, saved layouts.", + "n": 0.143 + } + } + }, + { + "i": 11, + "$": { + "0": { + "v": "Fixed size panels", + "n": 0.577 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "You can also render non-interactive elements inside of a group if you need fixed-size content. \n left\n \n right\n
Fixed sized element
\n
leftrightFixed sized element Non-interactive elements can also be rendered between panels. \n left\n \n
Fixed sized element
\n \n right\n
leftFixed sized elementright As with other types of groups, separators are optional (but recommended). \n left\n
Fixed sized element
\n right\n
leftFixed sized elementright", + "n": 0.122 + } + } + }, + { + "i": 12, + "$": { + "0": { + "v": "Disabling interactions", + "n": 0.707 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "Panel and Separator components can be disabled to disable or limit resize behavior. Below are a few examples of how this can be used to implement different types of UIs. In groups with only two panels, disabling a separator is sufficient to completely prevent resizing. \n left\n \n right\n leftright The same applies to disabling one or both panels when there is no explicit separator element. Note this is functionally the same as disabling the entire Group component. \n left\n right\n leftright In groups with three or more panels, disabling a separator does not completely prevent a panel from being resized. In the example below, resizing the center panel can indirectly cause the left panel to be resized as well. leftcenterright Disabling a panel prevents it from being resized, though its separator can still be used to resize other panels. \n left\n \n center (disabled)\n \n right\n leftcenter (disabled)right When there is no separator, a disabled panel's edges can also be used to resize other panels. leftcenter (disabled)right You can also disable both a panel and its separator to completely prevent them from being resized or interacted with in any way. \n left (disabled\n \n center\n \n right\n left (disabled)centerright Note that a disabled Panel can still be resized using the imperative API.", + "n": 0.067 + } + } + }, + { + "i": 13, + "$": { + "0": { + "v": "Group resize behavior", + "n": 0.577 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "Resizing a group typically affects the size of panels within the group. The groupResizeBehavior prop can be used override this behavior and freeze specific panels (in terms of their pixels sizes) while the group is resized. For an example of this, resize the browser window while keeping an eye on the left panel below. \n \n left\n \n \n main\n left (frozen)44%250pxright56%318px Minor pixel changes in the panel above are due to precision/rounding. Groups are required to contain at least one panel without groupResizeBehavior=\"preserve-pixel-size\".", + "n": 0.108 + } + } + }, + { + "i": 14, + "$": { + "0": { + "v": "Overflow", + "n": 1 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "Groups and Panels set the overflow styles shown below: \n
\n \n \n
\n
\n \n \n
\n
\n
This combination of styles ensures overflow content is scrollable without unexpectedly stretching the size of the group. To enable Panels to have overflowing visual styles (like shadows or outlines) you need to change the group overflow style to \"visible\": // Option 1: Override with className (must be !important)\n // Option 2: Override with inline style\n If you change the overflow style, it is recommended that you also specify an explicit width/height on the group. For example, this group of panels demonstrate drop-shadow style. \n left\n leftright And this group demonstrate a focus outline style. \n \n The panel sets a higher z-index on focus-within to avoid clipping issues. Styles that affect the outer panel element (e.g. shadows, outlines) work without any customizations. Things like tooltips or popovers that are rendered inside of the panel will be clipped by the overflow:auto style. Because of this it's recommended to use portals for these. However you can override the default style as shown below. \n \n left\n \n leftright All of the above styles also apply to the separator component. leftright", + "n": 0.064 + } + } + }, + { + "i": 15, + "$": { + "0": { + "v": "Custom CSS styles", + "n": 0.577 + }, + "1": { + "v": "Examples", + "n": 1 + }, + "2": { + "v": "className and style props can be used to customize styles, but there are a few limitations to remember: Certain style properties cannot be overridden; (refer to component documentation for a list of specific styles)Panel styles are applied to a nested HTMLDivElement to prevent interfering with the Flex layout When styling a Separator, use the data-separator attribute rather than :hover or :active pseudo-classes. This attribute is updated when the pointer is near enough to a separator element to be interactive, even if it is not directly on top of the element.
\n
\n
\n
An example using Tailwind CSS might look something like this. leftright", + "n": 0.093 + } + } + }, + { + "i": 16, + "$": { + "0": { + "v": "Group component", + "n": 0.707 + }, + "1": { + "v": "Props", + "n": 1 + }, + "2": { + "v": "A Group wraps a set of resizable Panel components.\nGroup content can be resized horizontally or vertically.\nGroup elements always include the following attributes:\n
Test id can be used to narrow selection when unit testing.\n Optional propschildren?: ReactNodePanel and Separator components that comprise this group.\nclassName?: stringCSS class name.\ndefaultLayout?: LayoutDefault layout for the Group.\nThis value allows layouts to be remembered between page reloads.\nRefer to the documentation for how to avoid layout shift when using server components.\ndisableCursor?: booleanThis library sets custom mouse cursor styles to indicate drag state.\nUse this prop to disable that behavior for Panels and Separators in this group.\ndisabled?: booleanDisable resize functionality.\nelementRef?: RefRef attached to the root HTMLDivElement.\ngroupRef?: RefExposes the following imperative API:\n\ngetLayout(): Layout\nsetLayout(layout: Layout): void\n\nThe useGroupRef and useGroupCallbackRef hooks are exported for convenience use in TypeScript projects.\nid?: string | numberUniquely identifies this group within an application.\nFalls back to useId when not provided.\nThis value will also be assigned to the data-group attribute.\nonLayoutChange?: (layout: Layout) => voidCalled when the Group's layout is changing.\nFor layout changes caused by pointer events, this method is called each time the pointer is moved.\nFor most cases, it is recommended to use the onLayoutChanged callback instead.\nonLayoutChanged?: (layout: Layout) => voidCalled after the Group's layout has been changed.\nFor layout changes caused by pointer events, this method is not called until the pointer has been released.\nThis method is recommended when saving layouts to some storage api.\norientation?: \"horizontal\" | \"vertical\" = \"horizontal\"Specifies the resizable orientation (\"horizontal\" or \"vertical\"); defaults to \"horizontal\"\nresizeTargetMinimumSize?: { coarse: number; fine: number; } = {\n coarse: 20,\n fine: 10\n }Minimum size of the resizable hit target area (either Separator or Panel edge)\nThis threshold ensures are large enough to avoid mis-clicks.\n\nCoarse inputs (typically a finger on a touchscreen) have reduced accuracy;\nto ensure accessibility and ease of use, hit targets should be larger to prevent mis-clicks.\nFine inputs (typically a mouse) can be smaller\n\nApple interface guidelines suggest 20pt (27px) on desktops and 28pt (37px) for touch devices\nIn practice this seems to be much larger than many of their own applications use though.\nstyle?: CSSPropertiesCSS properties.\nThe following styles cannot be overridden: display, flex-direction, flex-wrap, and overflow.\n", + "n": 0.054 + } + } + }, + { + "i": 17, + "$": { + "0": { + "v": "Panel component", + "n": 0.707 + }, + "1": { + "v": "Props", + "n": 1 + }, + "2": { + "v": "A Panel wraps resizable content and can be configured with min/max size constraints and collapsible behavior.\nPanel size props can be in the following formats:\n\nPercentage of the parent Group (0..100)\nPixels\nRelative font units (em, rem)\nViewport relative units (vh, vw)\n\nNumeric values are assumed to be pixels.\nStrings without explicit units are assumed to be percentages (0%..100%).\nPercentages may also be specified as strings ending with \"%\" (e.g. \"33%\")\nPixels may also be specified as strings ending with the unit \"px\".\nOther units should be specified as strings ending with their CSS property units (e.g. 1rem, 50vh)\nPanel elements always include the following attributes:\n
Test id can be used to narrow selection when unit testing.\nPanel elements must be direct DOM children of their parent Group elements.\n Optional propsclassName?: stringCSS class name.\nClass is applied to nested HTMLDivElement to avoid styles that interfere with Flex layout.\ncollapsedSize?: string | number = \"0%\"Panel size when collapsed; defaults to 0%.\ncollapsible?: boolean = falseThis panel can be collapsed.\nA collapsible panel will collapse when it's size is less than of the specified minSize\ndefaultSize?: string | numberDefault size of Panel within its parent group; default is auto-assigned based on the total number of Panels.\ndisabled?: booleanWhen disabled, a panel cannot be resized either directly or indirectly (by resizing another panel).\nelementRef?: RefRef attached to the root HTMLDivElement.\ngroupResizeBehavior?: \"preserve-relative-size\" | \"preserve-pixel-size\" = \"preserve-relative-size\"How should this Panel behave if the parent Group is resized?\nDefaults to preserve-relative-size.\n\npreserve-relative-size: Retain the current relative size (as a percentage of the Group)\npreserve-pixel-size: Retain its current size (in pixels)\n\nPanel min/max size constraints may impact this behavior.\nA Group must contain at least one Panel with preserve-relative-size resize behavior.\nid?: string | numberUniquely identifies this panel within the parent group.\nFalls back to useId when not provided.\nThis prop is used to associate persisted group layouts with the original panel.\nThis value will also be assigned to the data-panel attribute.\nmaxSize?: string | number = \"100%\"Maximum size of Panel within its parent group; defaults to 100%.\nminSize?: string | number = \"0%\"Minimum size of Panel within its parent group; defaults to 0%.\nonResize?: ((panelSize: PanelSize, id: string | number, prevPanelSize: PanelSize | undefined) => void) | undefinedCalled when panel sizes change.\n\npanelSize Panel size (both as a percentage of the parent Group and in pixels)\nid Panel id (if one was provided as a prop)\nprevPanelSize Previous panel size (will be undefined on mount)\n\npanelRef?: RefExposes the following imperative API:\n\ncollapse(): void\nexpand(): void\ngetSize(): number\nisCollapsed(): boolean\nresize(size: number): void\n\nThe usePanelRef and usePanelCallbackRef hooks are exported for convenience use in TypeScript projects.\nstyle?: CSSPropertiesCSS properties.\nStyle is applied to nested HTMLDivElement to avoid styles that interfere with Flex layout.\n", + "n": 0.049 + } + } + }, + { + "i": 18, + "$": { + "0": { + "v": "Separator component", + "n": 0.707 + }, + "1": { + "v": "Props", + "n": 1 + }, + "2": { + "v": "Separators are not required but they are recommended as they improve keyboard accessibility.\nSeparator elements must be direct DOM children of their parent Group elements.\nSeparator elements always include the following attributes:\n
Test id can be used to narrow selection when unit testing.\nIn addition to the attributes shown above, separator also renders all required WAI-ARIA properties.\n Optional propsclassName?: stringCSS class name.\nUse the data-separator attribute for custom hover and active styles\nThe following properties cannot be overridden: flex-grow, flex-shrink\ndisabled?: booleanWhen disabled, the separator cannot be used to resize its neighboring panels.\nThe panels may still be resized indirectly (while other panels are being resized).\nTo prevent a panel from being resized at all, it needs to also be disabled.\nelementRef?: RefRef attached to the root HTMLDivElement.\nid?: string | numberUniquely identifies the separator within the parent group.\nFalls back to useId when not provided.\nThis value will also be assigned to the data-separator attribute.\nstyle?: CSSPropertiesCSS properties.\nUse the data-separator attribute for custom hover and active styles\nThe following properties cannot be overridden: flex-grow, flex-shrink\n", + "n": 0.078 + } + } + }, + { + "i": 19, + "$": { + "0": { + "v": "GroupImperativeHandle", + "n": 1 + }, + "1": { + "v": "Imperative API", + "n": 0.707 + }, + "2": { + "v": "Imperative Group API.\nThe useGroupRef and useGroupCallbackRef hooks are exported for convenience use in TypeScript projects.\n getLayoutGet the Group's current layout as a map of Panel id to percentage (0..100)\ngetLayout: () => { [panelId: string]: number };setLayoutSet a new layout for the Group\nsetLayout: (layout: { [panelId: string]: number }) => Layout;", + "n": 0.141 + } + } + }, + { + "i": 20, + "$": { + "0": { + "v": "PanelImperativeHandle", + "n": 1 + }, + "1": { + "v": "Imperative API", + "n": 0.707 + }, + "2": { + "v": "Imperative Panel API\nThe usePanelRef and usePanelCallbackRef hooks are exported for convenience use in TypeScript projects.\n collapseCollapse the Panel to it's collapsedSize.\nThis method will do nothing if the Panel is not collapsible or if it is already collapsed.\ncollapse: () => void;expandExpand a collapsed Panel to its most recent size.\nThis method will do nothing if the Panel is not currently collapsed.\nexpand: () => void;getSizeGet the current size of the Panel in pixels as well as a percentage of the parent group (0..100).\ngetSize: () => {\n asPercentage: number;\n inPixels: number;\n };isCollapsedThe Panel is currently collapsed.\nisCollapsed: () => boolean;resizeUpdate the Panel's size.\nSize can be in the following formats:\n\nPercentage of the parent Group (0..100)\nPixels\nRelative font units (em, rem)\nViewport relative units (vh, vw)\n\nNumeric values are assumed to be pixels.\nStrings without explicit units are assumed to be percentages (0%..100%).\nPercentages may also be specified as strings ending with \"%\" (e.g. \"33%\")\nPixels may also be specified as strings ending with the unit \"px\".\nOther units should be specified as strings ending with their CSS property units (e.g. 1rem, 50vh)\nresize: (size: number | string) => void;", + "n": 0.076 + } + } + }, + { + "i": 21, + "$": { + "0": { + "v": "useDefaultLayout", + "n": 1 + }, + "1": { + "v": "Hooks", + "n": 1 + }, + "2": { + "v": "The useDefaultLayout hook saves and restores group layouts between page loads. It can be configured to store values using localStorage, sessionStorage, cookies, or any other persistence layer that makes sense for your application. import { useDefaultLayout } from \"react-resizable-panels\";\n \nconst { defaultLayout, onLayoutChanged } = useDefaultLayout({\n id: \"unique-layout-id\"\n});\n \n Refer to the persistent layouts section for more examples of how to best use the hook in your client or server-rendered application. Parameters debounceSaveMs?: number = 100Debounce save operation by the specified number of milliseconds; defaults to 100msThis parameter corresponds to the deprecated onLayoutChange callback. Code using the new onLayoutChanged callback (shown above) does not need to be debounced.id: stringUniquely identifies a specific group/layout.panelIds?: string[] | undefinedGroups that contain conditionally-rendered Panels should use this parameter to determine which layout is retrieved on mount.This prevents layout shift for server-rendered apps. Ids must match during mount to avoid layout shift.storage?: LayoutStorage = localStorageStorage API; responsible for reading and writing saved layouts.", + "n": 0.079 + } + } + }, + { + "i": 22, + "$": { + "0": { + "v": "useGroupRef", + "n": 1 + }, + "1": { + "v": "Hooks", + "n": 1 + }, + "2": { + "v": "The useGroupRef hook returns a mutable ref object. import { Group, useGroupRef } from \"react-resizable-panels\";\n \nfunction ExampleComponent() {\n const ref = useGroupRef();\n \n return ;\n} This component is useful for situations where you only need a local (to your component) reference to the imperative Group API. If you need to share the ref with another component or hook, use the callback ref hook instead.", + "n": 0.124 + } + } + }, + { + "i": 23, + "$": { + "0": { + "v": "useGroupCallbackRef", + "n": 1 + }, + "1": { + "v": "Hooks", + "n": 1 + }, + "2": { + "v": "And the useGroupCallbackRef hook returns a ref callback function and value tuple. import { Group, useGroupCallbackRef } from \"react-resizable-panels\";\n \nfunction ExampleComponent() {\n // groupRef can safely be shared with other components, context, and hooks\n // It can also be used as a dependency to effects\n const [groupRef, setGroupRef] = useGroupCallbackRef();\n \n return ;\n}", + "n": 0.136 + } + } + }, + { + "i": 24, + "$": { + "0": { + "v": "usePanelRef", + "n": 1 + }, + "1": { + "v": "Hooks", + "n": 1 + }, + "2": { + "v": "The usePanelRef hook returns a mutable ref object. import { Group, Panel, usePanelRef } from \"react-resizable-panels\";\n \nfunction ExampleComponent() {\n const ref = usePanelRef();\n \n return (\n \n \n {/* Other panels... */}\n \n );\n} This component is useful for situations where you only need a local (to your component) reference to the imperative Panel API. If you need to share the ref with another component or hook, use the callback ref hook instead.", + "n": 0.116 + } + } + }, + { + "i": 25, + "$": { + "0": { + "v": "usePanelCallbackRef", + "n": 1 + }, + "1": { + "v": "Hooks", + "n": 1 + }, + "2": { + "v": "And the usePanelCallbackRef hook returns a ref callback function and value tuple. . import { Group, Panel, usePanelCallbackRef } from \"react-resizable-panels\";\n \nfunction ExampleComponent() {\n // panelRef can safely be shared with other components, context, and hooks\n // It can also be used as a dependency to effects\n const [panelRef, setPanelRef] = usePanelCallbackRef();\n \n return (\n \n \n {/* Other panels... */}\n \n );\n}", + "n": 0.125 + } + } + }, + { + "i": 26, + "$": { + "0": { + "v": "Requirements", + "n": 1 + }, + "2": { + "v": "This library requires React version 18 or newer. It also uses the ResizeObserver (or polyfill) to convert layout constraints into relative percentages.", + "n": 0.213 + } + } + }, + { + "i": 27, + "$": { + "0": { + "v": "Common questions", + "n": 0.707 + }, + "2": { + "v": "Why do I see an \"invalid panel layout\" error?This error means that a Group layout (or the sum total of Panel default sizes) does not add up to 100%.If the layout you've specified does add up to 100, the most likely remaining cause is that you've specified sizes as pixels rather than percentages as per this note from the Panel docs:Numeric values are assumed to be pixels. Strings without explicit units are assumed to be percentages (0%..100%).Why is a vertical group not visible?By default, Group elements specify a default style height:100%. However according to the w3 spec:The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to \"auto\".Put another way, fixing this requires setting an explicit height either on the Group itself or on its parent HTMLElement.// an inline style will override the default\nrender();\n \n// an !important CSS rule will also override it\nrender();\n \n// a min-height CSS rule will accomplish the same result\nrender();Note that because the default height is an inline style, it can only be overridden by another inline style or an !important CSS rule.ReferenceError: localStorage is not definedThe useDefaultLayout hook saves layouts to localStorage by default. This does not work for server-rendered applications though, since localStorage is only defined on the client.Refer to the server rendering or server components docs for examples of how to save layouts on the server.How can I conditionally render a Panel based on screen size?The recommended way is to use the ResizeObserver API, either through a hook like useResizeObserver or a component like react-virtualized-auto-sizer.const { ref, width = 0 } = useResizeObserver();\n \n
\n \n ...\n {width >= 500 && (\n <>\n \n ...\n \n )}\n \n
Putting the defaultSize on the conditional Panel is the easiest way to avoid invalid layout constraints in this type of scenario.", + "n": 0.054 + } + } + }, + { + "i": 28, + "$": { + "0": { + "v": "Support", + "n": 1 + }, + "2": { + "v": "GitHub is the easiest place to look for help, but it's probably not the fastest. This project is maintained by a single developer so there is limited bandwidth for answering questions. I recommend asking questions on Stack Overflow or Reddit to start with. Both sites have active communities who often respond quickly. If you don't find an answer there you can try opening a GitHub issue- but please take a moment first to see if your question has has already been answered before opening a new one.", + "n": 0.107 + } + } + } + ] +} \ No newline at end of file diff --git a/public/generated/search-records.json b/public/generated/search-records.json new file mode 100644 index 000000000..8697c7252 --- /dev/null +++ b/public/generated/search-records.json @@ -0,0 +1,171 @@ +[ + { + "path": "/", + "text": "This library is a set of React components that can be used to build resizable layouts like the one below: This panel is resizableThis one is too There are many types of layouts, covered in the examples section of the docs. Check out the support page if you have questions. Installation Begin by installing the library from NPM: npm install react-resizable-panels TypeScript definitions are included within the published dist folder. Support Here are some ways to support this project: Become a GitHub sponsorBuy me a coffee", + "title": "Getting started with react-resizable-panels" + }, + { + "path": "/versions", + "text": "Click below to view documentation for past releases. 4.x documentation source code3.x documentation source code2.x documentation source code1.x source code", + "title": "Previous releases" + }, + { + "path": "/examples/the-basics", + "section": "Examples", + "text": "The simplest resizable panel configuration is two panels within a group. import { Group, Panel } from \"react-resizable-panels\";\n \n\n left\n right\n leftright Panel groups use a flexbox layout with a default orientation of horizontal but the orientation prop can be used to specify a vertical layout. \n top\n bottom\n Vertical groups may benefit from an explicit height or min-height (read more). topbottom Panels can be resized by clicking on their borders but explicit separators can be rendered to improve UX. Separators provide another benefit: double-clicking on one resets a panel to its default size. leftright \n left\n \n right\n Separators improve keyboard accessibility by providing a tab-focusable window splitter element.", + "title": "The basics" + }, + { + "path": "/examples/min-max-sizes", + "section": "Examples", + "text": "Panels can be configured with minimum/maximum allowed sizes. Size can be specified using the following CSS units: PixelsPercentagesFont sizes (em, rem)Viewport sizes (vh, vw) For example, the left panel below only allows itself to be resized between 10v0-200 pixels. \n left\n \n right\n left200pxright As another example, this panel group will not allow any individual panel to be smaller than 10% of the group's width. \n left\n \n middle\n \n right\n left33%middle33%right33% When specifying sizes, remember:Numbers are evaluated as pixels.Strings are evaluated as percentages (0..100%) unless otherwise specified.You can always include the unit, even for pixels (e.g. minSize=\"100px\") or percentages (e.g. minSize=\"10%\")", + "title": "Min/max sizes" + }, + { + "path": "/examples/collapsible-panels", + "section": "Examples", + "text": "Panels can be configured to be collapsible using the collapsible and minSize properties. \n \n \n \n 284pxThe panel on the left has a minimum size of 100 pixels. It will collapse entirely if resized smaller than 50 pixels. Although it isn't required, it's recommended that you also render a Separator for panels that can be collapsed fully. This separator gives users something to click to re-open a panel after it's been collapsed. The collapsedSize property can also be provided to prevent a panel from disappearing fully when collapsed. \n \n \n \n 284pxThe panel on the left collapses to a width of 35 pixels. This enables building UIs like VS Code's \"Folders\" side panel. A panel's collapse threshold is half its minimum size. Collapsible panels can also be collapsed by default by setting their defaultSize to 0 (pixels or percent). \n \n \n \n 0%The panel on the left is collapsed by default but can be expanded by dragging the separator.", + "title": "Collapsible panels" + }, + { + "path": "/examples/persistent-layout", + "section": "Examples", + "text": "Panel groups can be configured to save and restore layouts between page visits with the useDefaultLayout hook. Resize the panels below and then reload the page to see an example. const { defaultLayout, onLayoutChanged } = useDefaultLayout({\n id: \"unique-layout-id\",\n storage: localStorage\n});\n \n\n left\n \n center\n \n right\n left33%center33%right33% Panels require unique id props to restore saved layouts. The example above works well with client rendered application. Click below for more guidance about server rendering. Persistent layouts with conditional panelsPersistent layouts with server renderingPersistent layouts with server components", + "title": "Persistent layouts" + }, + { + "path": "/examples/persistent-layout/conditional-panels", + "section": "Examples", + "text": "For Groups that contain conditionally rendered Panels, it can be useful to save multiple layouts (one for each set of Panels). To enable this, pass the additional panelIds prop as shown below. const { defaultLayout, onLayoutChanged } = useDefaultLayout({\n id: \"unique-layout-id\",\n // This set of ids must match the Panels rendered during mount,\n // or the default layout will not be restored\n panelIds: showLeftPanel ? [\"left\", \"right\"] : [\"right\"],\n storage: localStorage\n});\n \n\n {showLeftPanel && (\n <>\n left\n \n \n )}\n right\n", + "title": "Persistent layouts with conditional panels" + }, + { + "path": "/examples/persistent-layout/server-rendering", + "section": "Examples", + "text": "Because localStorage is unavailable on the server, a custom storage configuration is needed to avoid layout shift when server rendering. Building on the previous example, a Cookie based storage might look like this: import { type LayoutStorage } from \"react-resizable-panels\";\n \nconst cookieStorage: LayoutStorage = {\n getItem(key: string) {\n const cookies = document.cookie.split(\";\");\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split(\"=\");\n if (name === key) {\n return value;\n }\n }\n return null;\n },\n setItem(key: string, value: string) {\n document.cookie = `${key}=${value}; path=/;`;\n }\n};\n \nuseDefaultLayout({\n id: \"unique-layout-id\",\n storage: cookieStorage\n}); If an async storage API is required, saved layouts should be loaded using suspense. The example above includes path=/ so that saved layouts can be shared between paths; see Using HTTP cookies for more.", + "title": "Persistent layouts with server rendering" + }, + { + "path": "/examples/persistent-layout/server-components", + "section": "Examples", + "text": "When using server components with a framework like Next.js, a slightly different approach is required: export default async function Page() {\n const api = await cookies();\n const defaultLayoutString = api.get(groupId)?.value;\n const defaultLayout = defaultLayoutString\n ? (JSON.parse(defaultLayoutString) as Layout)\n : undefined;\n \n return ;\n} (\"use client\");\n \nexport default function ClientComponent({\n defaultLayout,\n groupId\n}: {\n defaultLayout: Layout | undefined;\n groupId: string;\n}) {\n return (\n {\n document.cookie = `${groupId}=${JSON.stringify(layout)}; path=/;`;\n }}\n >\n \n left\n \n \n right\n \n
\n );\n} The example above includes path=/ so that saved layouts can be shared between paths; see Using HTTP cookies for more.", + "title": "Persistent layouts with server components" + }, + { + "path": "/examples/nested-groups", + "section": "Examples", + "text": "Panel groups can be nested. In this configuration, multiple groups can be resized at the same time by clicking near panel intersections. \n left\n \n \n top\n \n \n left\n right\n \n \n \n \n right\n", + "title": "Nested groups" + }, + { + "path": "/examples/conditional-panels", + "section": "Examples", + "text": "Panel can be conditionally rendered. hide left panelhide right panel leftcenterright \n {hideLeftPanel || (\n <>\n left panel\n \n \n )}\n center panel\n {hideRightPanel || (\n <>\n \n right panel\n \n )}\n Conditional panels should also specify ids to help match previous, saved layouts.", + "title": "Conditional Panels" + }, + { + "path": "/examples/fixed-size-panels", + "section": "Examples", + "text": "You can also render non-interactive elements inside of a group if you need fixed-size content. \n left\n \n right\n
Fixed sized element
\n
leftrightFixed sized element Non-interactive elements can also be rendered between panels. \n left\n \n
Fixed sized element
\n \n right\n
leftFixed sized elementright As with other types of groups, separators are optional (but recommended). \n left\n
Fixed sized element
\n right\n
leftFixed sized elementright", + "title": "Fixed size panels" + }, + { + "path": "/examples/disabled-panels", + "section": "Examples", + "text": "Panel and Separator components can be disabled to disable or limit resize behavior. Below are a few examples of how this can be used to implement different types of UIs. In groups with only two panels, disabling a separator is sufficient to completely prevent resizing. \n left\n \n right\n leftright The same applies to disabling one or both panels when there is no explicit separator element. Note this is functionally the same as disabling the entire Group component. \n left\n right\n leftright In groups with three or more panels, disabling a separator does not completely prevent a panel from being resized. In the example below, resizing the center panel can indirectly cause the left panel to be resized as well. leftcenterright Disabling a panel prevents it from being resized, though its separator can still be used to resize other panels. \n left\n \n center (disabled)\n \n right\n leftcenter (disabled)right When there is no separator, a disabled panel's edges can also be used to resize other panels. leftcenter (disabled)right You can also disable both a panel and its separator to completely prevent them from being resized or interacted with in any way. \n left (disabled\n \n center\n \n right\n left (disabled)centerright Note that a disabled Panel can still be resized using the imperative API.", + "title": "Disabling interactions" + }, + { + "path": "/examples/group-resize-behavior", + "section": "Examples", + "text": "Resizing a group typically affects the size of panels within the group. The groupResizeBehavior prop can be used override this behavior and freeze specific panels (in terms of their pixels sizes) while the group is resized. For an example of this, resize the browser window while keeping an eye on the left panel below. \n \n left\n \n \n main\n left (frozen)44%250pxright56%318px Minor pixel changes in the panel above are due to precision/rounding. Groups are required to contain at least one panel without groupResizeBehavior=\"preserve-pixel-size\".", + "title": "Group resize behavior" + }, + { + "path": "/examples/overflow", + "section": "Examples", + "text": "Groups and Panels set the overflow styles shown below: \n
\n \n \n
\n
\n \n \n
\n
\n
This combination of styles ensures overflow content is scrollable without unexpectedly stretching the size of the group. To enable Panels to have overflowing visual styles (like shadows or outlines) you need to change the group overflow style to \"visible\": // Option 1: Override with className (must be !important)\n // Option 2: Override with inline style\n If you change the overflow style, it is recommended that you also specify an explicit width/height on the group. For example, this group of panels demonstrate drop-shadow style. \n left\n leftright And this group demonstrate a focus outline style. \n \n The panel sets a higher z-index on focus-within to avoid clipping issues. Styles that affect the outer panel element (e.g. shadows, outlines) work without any customizations. Things like tooltips or popovers that are rendered inside of the panel will be clipped by the overflow:auto style. Because of this it's recommended to use portals for these. However you can override the default style as shown below. \n \n left\n \n leftright All of the above styles also apply to the separator component. leftright", + "title": "Overflow" + }, + { + "path": "/examples/custom-css-styles", + "section": "Examples", + "text": "className and style props can be used to customize styles, but there are a few limitations to remember: Certain style properties cannot be overridden; (refer to component documentation for a list of specific styles)Panel styles are applied to a nested HTMLDivElement to prevent interfering with the Flex layout When styling a Separator, use the data-separator attribute rather than :hover or :active pseudo-classes. This attribute is updated when the pointer is near enough to a separator element to be interactive, even if it is not directly on top of the element.
\n
\n
\n
An example using Tailwind CSS might look something like this. leftright", + "title": "Custom CSS styles" + }, + { + "path": "/props/group", + "section": "Props", + "text": "A Group wraps a set of resizable Panel components.\nGroup content can be resized horizontally or vertically.\nGroup elements always include the following attributes:\n
Test id can be used to narrow selection when unit testing.\n Optional propschildren?: ReactNodePanel and Separator components that comprise this group.\nclassName?: stringCSS class name.\ndefaultLayout?: LayoutDefault layout for the Group.\nThis value allows layouts to be remembered between page reloads.\nRefer to the documentation for how to avoid layout shift when using server components.\ndisableCursor?: booleanThis library sets custom mouse cursor styles to indicate drag state.\nUse this prop to disable that behavior for Panels and Separators in this group.\ndisabled?: booleanDisable resize functionality.\nelementRef?: RefRef attached to the root HTMLDivElement.\ngroupRef?: RefExposes the following imperative API:\n\ngetLayout(): Layout\nsetLayout(layout: Layout): void\n\nThe useGroupRef and useGroupCallbackRef hooks are exported for convenience use in TypeScript projects.\nid?: string | numberUniquely identifies this group within an application.\nFalls back to useId when not provided.\nThis value will also be assigned to the data-group attribute.\nonLayoutChange?: (layout: Layout) => voidCalled when the Group's layout is changing.\nFor layout changes caused by pointer events, this method is called each time the pointer is moved.\nFor most cases, it is recommended to use the onLayoutChanged callback instead.\nonLayoutChanged?: (layout: Layout) => voidCalled after the Group's layout has been changed.\nFor layout changes caused by pointer events, this method is not called until the pointer has been released.\nThis method is recommended when saving layouts to some storage api.\norientation?: \"horizontal\" | \"vertical\" = \"horizontal\"Specifies the resizable orientation (\"horizontal\" or \"vertical\"); defaults to \"horizontal\"\nresizeTargetMinimumSize?: { coarse: number; fine: number; } = {\n coarse: 20,\n fine: 10\n }Minimum size of the resizable hit target area (either Separator or Panel edge)\nThis threshold ensures are large enough to avoid mis-clicks.\n\nCoarse inputs (typically a finger on a touchscreen) have reduced accuracy;\nto ensure accessibility and ease of use, hit targets should be larger to prevent mis-clicks.\nFine inputs (typically a mouse) can be smaller\n\nApple interface guidelines suggest 20pt (27px) on desktops and 28pt (37px) for touch devices\nIn practice this seems to be much larger than many of their own applications use though.\nstyle?: CSSPropertiesCSS properties.\nThe following styles cannot be overridden: display, flex-direction, flex-wrap, and overflow.\n", + "title": "Group component" + }, + { + "path": "/props/panel", + "section": "Props", + "text": "A Panel wraps resizable content and can be configured with min/max size constraints and collapsible behavior.\nPanel size props can be in the following formats:\n\nPercentage of the parent Group (0..100)\nPixels\nRelative font units (em, rem)\nViewport relative units (vh, vw)\n\nNumeric values are assumed to be pixels.\nStrings without explicit units are assumed to be percentages (0%..100%).\nPercentages may also be specified as strings ending with \"%\" (e.g. \"33%\")\nPixels may also be specified as strings ending with the unit \"px\".\nOther units should be specified as strings ending with their CSS property units (e.g. 1rem, 50vh)\nPanel elements always include the following attributes:\n
Test id can be used to narrow selection when unit testing.\nPanel elements must be direct DOM children of their parent Group elements.\n Optional propsclassName?: stringCSS class name.\nClass is applied to nested HTMLDivElement to avoid styles that interfere with Flex layout.\ncollapsedSize?: string | number = \"0%\"Panel size when collapsed; defaults to 0%.\ncollapsible?: boolean = falseThis panel can be collapsed.\nA collapsible panel will collapse when it's size is less than of the specified minSize\ndefaultSize?: string | numberDefault size of Panel within its parent group; default is auto-assigned based on the total number of Panels.\ndisabled?: booleanWhen disabled, a panel cannot be resized either directly or indirectly (by resizing another panel).\nelementRef?: RefRef attached to the root HTMLDivElement.\ngroupResizeBehavior?: \"preserve-relative-size\" | \"preserve-pixel-size\" = \"preserve-relative-size\"How should this Panel behave if the parent Group is resized?\nDefaults to preserve-relative-size.\n\npreserve-relative-size: Retain the current relative size (as a percentage of the Group)\npreserve-pixel-size: Retain its current size (in pixels)\n\nPanel min/max size constraints may impact this behavior.\nA Group must contain at least one Panel with preserve-relative-size resize behavior.\nid?: string | numberUniquely identifies this panel within the parent group.\nFalls back to useId when not provided.\nThis prop is used to associate persisted group layouts with the original panel.\nThis value will also be assigned to the data-panel attribute.\nmaxSize?: string | number = \"100%\"Maximum size of Panel within its parent group; defaults to 100%.\nminSize?: string | number = \"0%\"Minimum size of Panel within its parent group; defaults to 0%.\nonResize?: ((panelSize: PanelSize, id: string | number, prevPanelSize: PanelSize | undefined) => void) | undefinedCalled when panel sizes change.\n\npanelSize Panel size (both as a percentage of the parent Group and in pixels)\nid Panel id (if one was provided as a prop)\nprevPanelSize Previous panel size (will be undefined on mount)\n\npanelRef?: RefExposes the following imperative API:\n\ncollapse(): void\nexpand(): void\ngetSize(): number\nisCollapsed(): boolean\nresize(size: number): void\n\nThe usePanelRef and usePanelCallbackRef hooks are exported for convenience use in TypeScript projects.\nstyle?: CSSPropertiesCSS properties.\nStyle is applied to nested HTMLDivElement to avoid styles that interfere with Flex layout.\n", + "title": "Panel component" + }, + { + "path": "/props/separator", + "section": "Props", + "text": "Separators are not required but they are recommended as they improve keyboard accessibility.\nSeparator elements must be direct DOM children of their parent Group elements.\nSeparator elements always include the following attributes:\n
Test id can be used to narrow selection when unit testing.\nIn addition to the attributes shown above, separator also renders all required WAI-ARIA properties.\n Optional propsclassName?: stringCSS class name.\nUse the data-separator attribute for custom hover and active styles\nThe following properties cannot be overridden: flex-grow, flex-shrink\ndisabled?: booleanWhen disabled, the separator cannot be used to resize its neighboring panels.\nThe panels may still be resized indirectly (while other panels are being resized).\nTo prevent a panel from being resized at all, it needs to also be disabled.\nelementRef?: RefRef attached to the root HTMLDivElement.\nid?: string | numberUniquely identifies the separator within the parent group.\nFalls back to useId when not provided.\nThis value will also be assigned to the data-separator attribute.\nstyle?: CSSPropertiesCSS properties.\nUse the data-separator attribute for custom hover and active styles\nThe following properties cannot be overridden: flex-grow, flex-shrink\n", + "title": "Separator component" + }, + { + "path": "/imperative-api/group", + "section": "Imperative API", + "text": "Imperative Group API.\nThe useGroupRef and useGroupCallbackRef hooks are exported for convenience use in TypeScript projects.\n getLayoutGet the Group's current layout as a map of Panel id to percentage (0..100)\ngetLayout: () => { [panelId: string]: number };setLayoutSet a new layout for the Group\nsetLayout: (layout: { [panelId: string]: number }) => Layout;", + "title": "GroupImperativeHandle" + }, + { + "path": "/imperative-api/panel", + "section": "Imperative API", + "text": "Imperative Panel API\nThe usePanelRef and usePanelCallbackRef hooks are exported for convenience use in TypeScript projects.\n collapseCollapse the Panel to it's collapsedSize.\nThis method will do nothing if the Panel is not collapsible or if it is already collapsed.\ncollapse: () => void;expandExpand a collapsed Panel to its most recent size.\nThis method will do nothing if the Panel is not currently collapsed.\nexpand: () => void;getSizeGet the current size of the Panel in pixels as well as a percentage of the parent group (0..100).\ngetSize: () => {\n asPercentage: number;\n inPixels: number;\n };isCollapsedThe Panel is currently collapsed.\nisCollapsed: () => boolean;resizeUpdate the Panel's size.\nSize can be in the following formats:\n\nPercentage of the parent Group (0..100)\nPixels\nRelative font units (em, rem)\nViewport relative units (vh, vw)\n\nNumeric values are assumed to be pixels.\nStrings without explicit units are assumed to be percentages (0%..100%).\nPercentages may also be specified as strings ending with \"%\" (e.g. \"33%\")\nPixels may also be specified as strings ending with the unit \"px\".\nOther units should be specified as strings ending with their CSS property units (e.g. 1rem, 50vh)\nresize: (size: number | string) => void;", + "title": "PanelImperativeHandle" + }, + { + "path": "/hooks/use-default-layout", + "section": "Hooks", + "text": "The useDefaultLayout hook saves and restores group layouts between page loads. It can be configured to store values using localStorage, sessionStorage, cookies, or any other persistence layer that makes sense for your application. import { useDefaultLayout } from \"react-resizable-panels\";\n \nconst { defaultLayout, onLayoutChanged } = useDefaultLayout({\n id: \"unique-layout-id\"\n});\n \n Refer to the persistent layouts section for more examples of how to best use the hook in your client or server-rendered application. Parameters debounceSaveMs?: number = 100Debounce save operation by the specified number of milliseconds; defaults to 100msThis parameter corresponds to the deprecated onLayoutChange callback. Code using the new onLayoutChanged callback (shown above) does not need to be debounced.id: stringUniquely identifies a specific group/layout.panelIds?: string[] | undefinedGroups that contain conditionally-rendered Panels should use this parameter to determine which layout is retrieved on mount.This prevents layout shift for server-rendered apps. Ids must match during mount to avoid layout shift.storage?: LayoutStorage = localStorageStorage API; responsible for reading and writing saved layouts.", + "title": "useDefaultLayout" + }, + { + "path": "/hooks/use-group-ref", + "section": "Hooks", + "text": "The useGroupRef hook returns a mutable ref object. import { Group, useGroupRef } from \"react-resizable-panels\";\n \nfunction ExampleComponent() {\n const ref = useGroupRef();\n \n return ;\n} This component is useful for situations where you only need a local (to your component) reference to the imperative Group API. If you need to share the ref with another component or hook, use the callback ref hook instead.", + "title": "useGroupRef" + }, + { + "path": "/hooks/use-group-callback-ref", + "section": "Hooks", + "text": "And the useGroupCallbackRef hook returns a ref callback function and value tuple. import { Group, useGroupCallbackRef } from \"react-resizable-panels\";\n \nfunction ExampleComponent() {\n // groupRef can safely be shared with other components, context, and hooks\n // It can also be used as a dependency to effects\n const [groupRef, setGroupRef] = useGroupCallbackRef();\n \n return ;\n}", + "title": "useGroupCallbackRef" + }, + { + "path": "/hooks/use-panel-ref", + "section": "Hooks", + "text": "The usePanelRef hook returns a mutable ref object. import { Group, Panel, usePanelRef } from \"react-resizable-panels\";\n \nfunction ExampleComponent() {\n const ref = usePanelRef();\n \n return (\n \n \n {/* Other panels... */}\n \n );\n} This component is useful for situations where you only need a local (to your component) reference to the imperative Panel API. If you need to share the ref with another component or hook, use the callback ref hook instead.", + "title": "usePanelRef" + }, + { + "path": "/hooks/use-panel-callback-ref", + "section": "Hooks", + "text": "And the usePanelCallbackRef hook returns a ref callback function and value tuple. . import { Group, Panel, usePanelCallbackRef } from \"react-resizable-panels\";\n \nfunction ExampleComponent() {\n // panelRef can safely be shared with other components, context, and hooks\n // It can also be used as a dependency to effects\n const [panelRef, setPanelRef] = usePanelCallbackRef();\n \n return (\n \n \n {/* Other panels... */}\n \n );\n}", + "title": "usePanelCallbackRef" + }, + { + "path": "/platform-requirements", + "text": "This library requires React version 18 or newer. It also uses the ResizeObserver (or polyfill) to convert layout constraints into relative percentages.", + "title": "Requirements" + }, + { + "path": "/common-questions", + "text": "Why do I see an \"invalid panel layout\" error?This error means that a Group layout (or the sum total of Panel default sizes) does not add up to 100%.If the layout you've specified does add up to 100, the most likely remaining cause is that you've specified sizes as pixels rather than percentages as per this note from the Panel docs:Numeric values are assumed to be pixels. Strings without explicit units are assumed to be percentages (0%..100%).Why is a vertical group not visible?By default, Group elements specify a default style height:100%. However according to the w3 spec:The percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to \"auto\".Put another way, fixing this requires setting an explicit height either on the Group itself or on its parent HTMLElement.// an inline style will override the default\nrender();\n \n// an !important CSS rule will also override it\nrender();\n \n// a min-height CSS rule will accomplish the same result\nrender();Note that because the default height is an inline style, it can only be overridden by another inline style or an !important CSS rule.ReferenceError: localStorage is not definedThe useDefaultLayout hook saves layouts to localStorage by default. This does not work for server-rendered applications though, since localStorage is only defined on the client.Refer to the server rendering or server components docs for examples of how to save layouts on the server.How can I conditionally render a Panel based on screen size?The recommended way is to use the ResizeObserver API, either through a hook like useResizeObserver or a component like react-virtualized-auto-sizer.const { ref, width = 0 } = useResizeObserver();\n \n
\n \n ...\n {width >= 500 && (\n <>\n \n ...\n \n )}\n \n
Putting the defaultSize on the conditional Panel is the easiest way to avoid invalid layout constraints in this type of scenario.", + "title": "Common questions" + }, + { + "path": "/support", + "text": "GitHub is the easiest place to look for help, but it's probably not the fastest. This project is maintained by a single developer so there is limited bandwidth for answering questions. I recommend asking questions on Stack Overflow or Reddit to start with. Both sites have active communities who often respond quickly. If you don't find an answer there you can try opening a GitHub issue- but please take a moment first to see if your question has has already been answered before opening a new one.", + "title": "Support" + } +] \ No newline at end of file diff --git a/scripts/compile-search-index.ts b/scripts/compile-search-index.ts new file mode 100644 index 000000000..8ef9736b2 --- /dev/null +++ b/scripts/compile-search-index.ts @@ -0,0 +1,6 @@ +import { compileSearchIndex } from "react-lib-tools/scripts/compile-search-index.ts"; + +await compileSearchIndex({ + chromeExecutablePath: process.env.CHROME_PATH, + filterSelector: "[data-group]" +}); diff --git a/src/App.tsx b/src/App.tsx index 190d388f7..c7eb52cd1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,8 +8,8 @@ import { type CommonQuestion } from "react-lib-tools"; import { repository } from "../package.json"; -import { html as GroupExplicitHeightHTML } from "../public/generated/examples/GroupExplicitHeight.json"; import { html as ConditionallyRenderPanel } from "../public/generated/examples/ConditionallyRenderPanel.json"; +import { html as GroupExplicitHeightHTML } from "../public/generated/examples/GroupExplicitHeight.json"; import { Link } from "./components/Link"; import { NavLink } from "./components/NavLink"; import { Group } from "./components/styled-panels/Group"; @@ -21,6 +21,7 @@ export default function App() { return ( Getting started diff --git a/src/components/NavLink.tsx b/src/components/NavLink.tsx index 2ed70f9af..6e4222887 100644 --- a/src/components/NavLink.tsx +++ b/src/components/NavLink.tsx @@ -11,6 +11,10 @@ export function NavLink({ path: Path | DefaultPath; }>) { return ( - + + children={children} + className={className} + path={path} + /> ); }