From 453c7ac5f8e2fefca61c002018fb26ec48085409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sat, 18 Oct 2025 18:26:11 +0200 Subject: [PATCH 01/27] feat: setup nextjs example --- examples/nextjs/.gitignore | 41 + examples/nextjs/eslint.config.mjs | 25 + examples/nextjs/next.config.ts | 9 + examples/nextjs/package.json | 26 + examples/nextjs/public/file.svg | 1 + examples/nextjs/public/globe.svg | 1 + examples/nextjs/public/next.svg | 1 + examples/nextjs/public/vercel.svg | 1 + examples/nextjs/public/window.svg | 1 + .../nextjs/src/app/examples/nested/page.tsx | 80 + examples/nextjs/src/app/favicon.ico | Bin 0 -> 25931 bytes examples/nextjs/src/app/globals.css | 91 + examples/nextjs/src/app/layout.tsx | 33 + examples/nextjs/src/app/page.module.css | 167 ++ examples/nextjs/src/app/page.tsx | 60 + .../nextjs/src/components/Icon.module.css | 6 + examples/nextjs/src/components/Icon.tsx | 120 + .../src/components/ResizeHandle.module.css | 30 + .../nextjs/src/components/ResizeHandle.tsx | 33 + .../nextjs/src/components/shared.module.css | 99 + examples/nextjs/tsconfig.json | 27 + package.json | 1 + pnpm-lock.yaml | 2550 ++++++++++++++++- pnpm-workspace.yaml | 3 +- 24 files changed, 3320 insertions(+), 86 deletions(-) create mode 100644 examples/nextjs/.gitignore create mode 100644 examples/nextjs/eslint.config.mjs create mode 100644 examples/nextjs/next.config.ts create mode 100644 examples/nextjs/package.json create mode 100644 examples/nextjs/public/file.svg create mode 100644 examples/nextjs/public/globe.svg create mode 100644 examples/nextjs/public/next.svg create mode 100644 examples/nextjs/public/vercel.svg create mode 100644 examples/nextjs/public/window.svg create mode 100644 examples/nextjs/src/app/examples/nested/page.tsx create mode 100644 examples/nextjs/src/app/favicon.ico create mode 100644 examples/nextjs/src/app/globals.css create mode 100644 examples/nextjs/src/app/layout.tsx create mode 100644 examples/nextjs/src/app/page.module.css create mode 100644 examples/nextjs/src/app/page.tsx create mode 100644 examples/nextjs/src/components/Icon.module.css create mode 100644 examples/nextjs/src/components/Icon.tsx create mode 100644 examples/nextjs/src/components/ResizeHandle.module.css create mode 100644 examples/nextjs/src/components/ResizeHandle.tsx create mode 100644 examples/nextjs/src/components/shared.module.css create mode 100644 examples/nextjs/tsconfig.json diff --git a/examples/nextjs/.gitignore b/examples/nextjs/.gitignore new file mode 100644 index 000000000..5ef6a5207 --- /dev/null +++ b/examples/nextjs/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/examples/nextjs/eslint.config.mjs b/examples/nextjs/eslint.config.mjs new file mode 100644 index 000000000..719cea2b5 --- /dev/null +++ b/examples/nextjs/eslint.config.mjs @@ -0,0 +1,25 @@ +import { dirname } from "path"; +import { fileURLToPath } from "url"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, +}); + +const eslintConfig = [ + ...compat.extends("next/core-web-vitals", "next/typescript"), + { + ignores: [ + "node_modules/**", + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ], + }, +]; + +export default eslintConfig; diff --git a/examples/nextjs/next.config.ts b/examples/nextjs/next.config.ts new file mode 100644 index 000000000..eec2aea61 --- /dev/null +++ b/examples/nextjs/next.config.ts @@ -0,0 +1,9 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ + ignoreBuildErrors: true, + optimizePackageImports: ["react-resizable-panels"], +}; + +export default nextConfig; diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json new file mode 100644 index 000000000..e6e68d8ba --- /dev/null +++ b/examples/nextjs/package.json @@ -0,0 +1,26 @@ +{ + "name": "react-resizable-panels-nextjs", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbopack", + "build": "next build --turbopack", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "react": "19.1.0", + "react-dom": "19.1.0", + "next": "15.5.6", + "react-resizable-panels": "workspace:*" + }, + "devDependencies": { + "typescript": "^5", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "15.5.6", + "@eslint/eslintrc": "^3" + } +} diff --git a/examples/nextjs/public/file.svg b/examples/nextjs/public/file.svg new file mode 100644 index 000000000..004145cdd --- /dev/null +++ b/examples/nextjs/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/nextjs/public/globe.svg b/examples/nextjs/public/globe.svg new file mode 100644 index 000000000..567f17b0d --- /dev/null +++ b/examples/nextjs/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/nextjs/public/next.svg b/examples/nextjs/public/next.svg new file mode 100644 index 000000000..5174b28c5 --- /dev/null +++ b/examples/nextjs/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/nextjs/public/vercel.svg b/examples/nextjs/public/vercel.svg new file mode 100644 index 000000000..770539603 --- /dev/null +++ b/examples/nextjs/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/nextjs/public/window.svg b/examples/nextjs/public/window.svg new file mode 100644 index 000000000..b2b2a44f6 --- /dev/null +++ b/examples/nextjs/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/nextjs/src/app/examples/nested/page.tsx b/examples/nextjs/src/app/examples/nested/page.tsx new file mode 100644 index 000000000..3ef78fa6f --- /dev/null +++ b/examples/nextjs/src/app/examples/nested/page.tsx @@ -0,0 +1,80 @@ +"use client"; + +import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; +import styles from "@/components/shared.module.css"; + +export default function NestedExample() { + return ( +
+

Nested Resizable Panels

+

+ This example shows nested groups. Click near the intersection of two + groups to resize in multiple directions at once. +

+ +
+ + +
left
+
+ + + + +
top
+
+ + + + +
inner left
+
+ + +
inner right
+
+
+
+
+
+ + +
right
+
+
+
+ +
+

Features:

+
    +
  • Three levels of nested panel groups
  • +
  • Horizontal and vertical resize handles
  • +
  • Persistent layout state using localStorage
  • +
  • Minimum size constraints on panels
  • +
  • Responsive design with proper CSS variables
  • +
+ +
+ + ← Back to simple example + +
+
+
+ ); +} diff --git a/examples/nextjs/src/app/favicon.ico b/examples/nextjs/src/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 zcmeHv30#a{`}aL_*G&7qml|y<+KVaDM2m#dVr!KsA!#An?kSQM(q<_dDNCpjEux83 zLb9Z^XxbDl(w>%i@8hT6>)&Gu{h#Oeyszu?xtw#Zb1mO{pgX9699l+Qppw7jXaYf~-84xW z)w4x8?=youko|}Vr~(D$UXIbiXABHh`p1?nn8Po~fxRJv}|0e(BPs|G`(TT%kKVJAdg5*Z|x0leQq0 zkdUBvb#>9F()jo|T~kx@OM8$9wzs~t2l;K=woNssA3l6|sx2r3+kdfVW@e^8e*E}v zA1y5{bRi+3Z`uD3{F7LgFJDdvm;nJilkzDku>BwXH(8ItVCXk*-lSJnR?-2UN%hJ){&rlvg`CDTj z)Bzo!3v7Ou#83zEDEFcKt(f1E0~=rqeEbTnMvWR#{+9pg%7G8y>u1OVRUSoox-ovF z2Ydma(;=YuBY(eI|04{hXzZD6_f(v~H;C~y5=DhAC{MMS>2fm~1H_t2$56pc$NH8( z5bH|<)71dV-_oCHIrzrT`2s-5w_+2CM0$95I6X8p^r!gHp+j_gd;9O<1~CEQQGS8) zS9Qh3#p&JM-G8rHekNmKVewU;pJRcTAog68KYo^dRo}(M>36U4Us zfgYWSiHZL3;lpWT=zNAW>Dh#mB!_@Lg%$ms8N-;aPqMn+C2HqZgz&9~Eu z4|Kp<`$q)Uw1R?y(~S>ePdonHxpV1#eSP1B;Ogo+-Pk}6#0GsZZ5!||ev2MGdh}_m z{DeR7?0-1^zVs&`AV6Vt;r3`I`OI_wgs*w=eO%_#7Kepl{B@xiyCANc(l zzIyd4y|c6PXWq9-|KM8(zIk8LPk(>a)zyFWjhT!$HJ$qX1vo@d25W<fvZQ2zUz5WRc(UnFMKHwe1| zWmlB1qdbiA(C0jmnV<}GfbKtmcu^2*P^O?MBLZKt|As~ge8&AAO~2K@zbXelK|4T<{|y4`raF{=72kC2Kn(L4YyenWgrPiv z@^mr$t{#X5VuIMeL!7Ab6_kG$&#&5p*Z{+?5U|TZ`B!7llpVmp@skYz&n^8QfPJzL z0G6K_OJM9x+Wu2gfN45phANGt{7=C>i34CV{Xqlx(fWpeAoj^N0Biu`w+MVcCUyU* zDZuzO0>4Z6fbu^T_arWW5n!E45vX8N=bxTVeFoep_G#VmNlQzAI_KTIc{6>c+04vr zx@W}zE5JNSU>!THJ{J=cqjz+4{L4A{Ob9$ZJ*S1?Ggg3klFp!+Y1@K+pK1DqI|_gq z5ZDXVpge8-cs!o|;K73#YXZ3AShj50wBvuq3NTOZ`M&qtjj#GOFfgExjg8Gn8>Vq5 z`85n+9|!iLCZF5$HJ$Iu($dm?8~-ofu}tEc+-pyke=3!im#6pk_Wo8IA|fJwD&~~F zc16osQ)EBo58U7XDuMexaPRjU@h8tXe%S{fA0NH3vGJFhuyyO!Uyl2^&EOpX{9As0 zWj+P>{@}jxH)8|r;2HdupP!vie{sJ28b&bo!8`D^x}TE$%zXNb^X1p@0PJ86`dZyj z%ce7*{^oo+6%&~I!8hQy-vQ7E)0t0ybH4l%KltWOo~8cO`T=157JqL(oq_rC%ea&4 z2NcTJe-HgFjNg-gZ$6!Y`SMHrlj}Etf7?r!zQTPPSv}{so2e>Fjs1{gzk~LGeesX%r(Lh6rbhSo_n)@@G-FTQy93;l#E)hgP@d_SGvyCp0~o(Y;Ee8{ zdVUDbHm5`2taPUOY^MAGOw*>=s7=Gst=D+p+2yON!0%Hk` zz5mAhyT4lS*T3LS^WSxUy86q&GnoHxzQ6vm8)VS}_zuqG?+3td68_x;etQAdu@sc6 zQJ&5|4(I?~3d-QOAODHpZ=hlSg(lBZ!JZWCtHHSj`0Wh93-Uk)_S%zsJ~aD>{`A0~ z9{AG(e|q3g5B%wYKRxiL2Y$8(4w6bzchKuloQW#e&S3n+P- z8!ds-%f;TJ1>)v)##>gd{PdS2Oc3VaR`fr=`O8QIO(6(N!A?pr5C#6fc~Ge@N%Vvu zaoAX2&(a6eWy_q&UwOhU)|P3J0Qc%OdhzW=F4D|pt0E4osw;%<%Dn58hAWD^XnZD= z>9~H(3bmLtxpF?a7su6J7M*x1By7YSUbxGi)Ot0P77`}P3{)&5Un{KD?`-e?r21!4vTTnN(4Y6Lin?UkSM z`MXCTC1@4A4~mvz%Rh2&EwY))LeoT=*`tMoqcEXI>TZU9WTP#l?uFv+@Dn~b(>xh2 z;>B?;Tz2SR&KVb>vGiBSB`@U7VIWFSo=LDSb9F{GF^DbmWAfpms8Sx9OX4CnBJca3 zlj9(x!dIjN?OG1X4l*imJNvRCk}F%!?SOfiOq5y^mZW)jFL@a|r-@d#f7 z2gmU8L3IZq0ynIws=}~m^#@&C%J6QFo~Mo4V`>v7MI-_!EBMMtb%_M&kvAaN)@ZVw z+`toz&WG#HkWDjnZE!6nk{e-oFdL^$YnbOCN}JC&{$#$O27@|Tn-skXr)2ml2~O!5 zX+gYoxhoc7qoU?C^3~&!U?kRFtnSEecWuH0B0OvLodgUAi}8p1 zrO6RSXHH}DMc$&|?D004DiOVMHV8kXCP@7NKB zgaZq^^O<7PoKEp72kby@W0Z!Y*Ay{&vfg#C&gG@YVR9g?FEocMUi1gSN$+V+ayF45{a zuDZDTN}mS|;BO%gEf}pjBfN2-gIrU#G5~cucA;dokXW89%>AyXJJI z9X4UlIWA|ZYHgbI z5?oFk@A=Ik7lrEQPDH!H+b`7_Y~aDb_qa=B2^Y&Ow41cU=4WDd40dp5(QS-WMN-=Y z9g;6_-JdNU;|6cPwf$ak*aJIcwL@1n$#l~zi{c{EW?T;DaW*E8DYq?Umtz{nJ&w-M zEMyTDrC&9K$d|kZe2#ws6)L=7K+{ zQw{XnV6UC$6-rW0emqm8wJoeZK)wJIcV?dST}Z;G0Arq{dVDu0&4kd%N!3F1*;*pW zR&qUiFzK=@44#QGw7k1`3t_d8&*kBV->O##t|tonFc2YWrL7_eqg+=+k;!F-`^b8> z#KWCE8%u4k@EprxqiV$VmmtiWxDLgnGu$Vs<8rppV5EajBXL4nyyZM$SWVm!wnCj-B!Wjqj5-5dNXukI2$$|Bu3Lrw}z65Lc=1G z^-#WuQOj$hwNGG?*CM_TO8Bg-1+qc>J7k5c51U8g?ZU5n?HYor;~JIjoWH-G>AoUP ztrWWLbRNqIjW#RT*WqZgPJXU7C)VaW5}MiijYbABmzoru6EmQ*N8cVK7a3|aOB#O& zBl8JY2WKfmj;h#Q!pN%9o@VNLv{OUL?rixHwOZuvX7{IJ{(EdPpuVFoQqIOa7giLVkBOKL@^smUA!tZ1CKRK}#SSM)iQHk)*R~?M!qkCruaS!#oIL1c z?J;U~&FfH#*98^G?i}pA{ z9Jg36t4=%6mhY(quYq*vSxptes9qy|7xSlH?G=S@>u>Ebe;|LVhs~@+06N<4CViBk zUiY$thvX;>Tby6z9Y1edAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJwb z_^v8bbg`SAn{I*4bH$u(RZ6*xUhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=pC^S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk($?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvhCL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397*_cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111aH}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*IcmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU&68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-=A=yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v#ix45EVrcEhr>!NMhprl$InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~&^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7<4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}scZlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2`1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M=hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S(O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/examples/nextjs/src/app/globals.css b/examples/nextjs/src/app/globals.css new file mode 100644 index 000000000..352e78bf8 --- /dev/null +++ b/examples/nextjs/src/app/globals.css @@ -0,0 +1,91 @@ +:root { + --color-background-code: #050a15; + --color-background-default: #081120; + --color-brand: #dcadff; + --color-button-background: #2a3343; + --color-button-background-hover: #39414d; + --color-button-border: #18181a; + --color-code: #dcadff; + --color-default: #ffffff; + --color-dim: #91a0ba; + --color-horizontal-rule: #39414d; + --color-input: #ffffff; + --color-input-background: #18181a; + --color-input-border: #39414d; + --color-input-border-focused: #dcadff; + --color-link: #dcadff; + --color-panel-background: #192230; + --color-panel-background-alternate: #202124; + --color-resize-bar: #515b6a; + --color-resize-bar-active: #b1bdd0; + --color-resize-bar-hover: #515b6a; + --color-warning-background: #7400cc; + + --color-scroll-thumb: #515b6a; +} + +:root, +html, +body { + padding: 0; + margin: 0; + max-width: 100vw; + overflow-x: hidden; + + background-color: var(--color-background-default); + color: var(--color-default); + + font-family: Arial, Helvetica, sans-serif; + font-size: 12px; +} + +* { + box-sizing: border-box; + line-height: 1.5em; +} + +p { + margin: 0.5rem 0; +} + +code { + color: var(--color-code); + background-color: var(--color-background-code); + font-family: monospace; + padding: 0 0.25em; + border-radius: 0.25em; +} + +h1, +h2 { + font-weight: normal; + margin: 0.5rem 0; +} + +a { + color: var(--color-link); +} + +::-webkit-scrollbar { + width: 0.75rem; + height: 0.75rem; + background: transparent; +} + +::-webkit-scrollbar-corner { + background: transparent; +} + +::-webkit-scrollbar-track { + border-radius: 0.75rem; + background: transparent; +} + +::-webkit-scrollbar-thumb { + border-radius: 0.75rem; + background: var(--color-scroll-thumb); +} + +::-webkit-scrollbar-thumb:hover { + background: var(--color-resize-bar-hover); +} diff --git a/examples/nextjs/src/app/layout.tsx b/examples/nextjs/src/app/layout.tsx new file mode 100644 index 000000000..c64d72725 --- /dev/null +++ b/examples/nextjs/src/app/layout.tsx @@ -0,0 +1,33 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "React Resizable Panels - Next.js Example", + description: + "Nested resizable panels example using react-resizable-panels in Next.js", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/examples/nextjs/src/app/page.module.css b/examples/nextjs/src/app/page.module.css new file mode 100644 index 000000000..58c71af9e --- /dev/null +++ b/examples/nextjs/src/app/page.module.css @@ -0,0 +1,167 @@ +.page { + --gray-rgb: 0, 0, 0; + --gray-alpha-200: rgba(var(--gray-rgb), 0.08); + --gray-alpha-100: rgba(var(--gray-rgb), 0.05); + + --button-primary-hover: #383838; + --button-secondary-hover: #f2f2f2; + + display: grid; + grid-template-rows: 20px 1fr 20px; + align-items: center; + justify-items: center; + min-height: 100svh; + padding: 80px; + gap: 64px; + font-family: var(--font-geist-sans); +} + +@media (prefers-color-scheme: dark) { + .page { + --gray-rgb: 255, 255, 255; + --gray-alpha-200: rgba(var(--gray-rgb), 0.145); + --gray-alpha-100: rgba(var(--gray-rgb), 0.06); + + --button-primary-hover: #ccc; + --button-secondary-hover: #1a1a1a; + } +} + +.main { + display: flex; + flex-direction: column; + gap: 32px; + grid-row-start: 2; +} + +.main ol { + font-family: var(--font-geist-mono); + padding-left: 0; + margin: 0; + font-size: 14px; + line-height: 24px; + letter-spacing: -0.01em; + list-style-position: inside; +} + +.main li:not(:last-of-type) { + margin-bottom: 8px; +} + +.main code { + font-family: inherit; + background: var(--gray-alpha-100); + padding: 2px 4px; + border-radius: 4px; + font-weight: 600; +} + +.ctas { + display: flex; + gap: 16px; +} + +.ctas a { + appearance: none; + border-radius: 128px; + height: 48px; + padding: 0 20px; + border: 1px solid transparent; + transition: + background 0.2s, + color 0.2s, + border-color 0.2s; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + line-height: 20px; + font-weight: 500; +} + +a.primary { + background: var(--foreground); + color: var(--background); + gap: 8px; +} + +a.secondary { + border-color: var(--gray-alpha-200); + min-width: 158px; +} + +.footer { + grid-row-start: 3; + display: flex; + gap: 24px; +} + +.footer a { + display: flex; + align-items: center; + gap: 8px; +} + +.footer img { + flex-shrink: 0; +} + +/* Enable hover only on non-touch devices */ +@media (hover: hover) and (pointer: fine) { + a.primary:hover { + background: var(--button-primary-hover); + border-color: transparent; + } + + a.secondary:hover { + background: var(--button-secondary-hover); + border-color: transparent; + } + + .footer a:hover { + text-decoration: underline; + text-underline-offset: 4px; + } +} + +@media (max-width: 600px) { + .page { + padding: 32px; + padding-bottom: 80px; + } + + .main { + align-items: center; + } + + .main ol { + text-align: center; + } + + .ctas { + flex-direction: column; + } + + .ctas a { + font-size: 14px; + height: 40px; + padding: 0 16px; + } + + a.secondary { + min-width: auto; + } + + .footer { + flex-wrap: wrap; + align-items: center; + justify-content: center; + } +} + +@media (prefers-color-scheme: dark) { + .logo { + filter: invert(); + } +} diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx new file mode 100644 index 000000000..830d7de75 --- /dev/null +++ b/examples/nextjs/src/app/page.tsx @@ -0,0 +1,60 @@ +"use client"; + +import { Panel, PanelGroup } from "react-resizable-panels"; +import { ResizeHandle } from "@/components/ResizeHandle"; +import styles from "@/components/shared.module.css"; + +export default function Home() { + return ( +
+
+
+ + +
left
+
+ + + + +
top
+
+ + + + +
left
+
+ + +
right
+
+
+
+
+
+ + +
right
+
+
+
+
+
+ ); +} diff --git a/examples/nextjs/src/components/Icon.module.css b/examples/nextjs/src/components/Icon.module.css new file mode 100644 index 000000000..22063649a --- /dev/null +++ b/examples/nextjs/src/components/Icon.module.css @@ -0,0 +1,6 @@ +.Icon { + flex: 0 0 1rem; + width: 1rem; + height: 1rem; + fill: currentColor; +} diff --git a/examples/nextjs/src/components/Icon.tsx b/examples/nextjs/src/components/Icon.tsx new file mode 100644 index 000000000..6eb0bbabb --- /dev/null +++ b/examples/nextjs/src/components/Icon.tsx @@ -0,0 +1,120 @@ +import { SVGProps } from "react"; +import styles from "./Icon.module.css"; + +export type IconType = + | "chevron-down" + | "close" + | "collapse" + | "css" + | "dialog" + | "drag" + | "expand" + | "files" + | "horizontal-collapse" + | "horizontal-expand" + | "html" + | "loading" + | "markdown" + | "resize" + | "resize-horizontal" + | "resize-vertical" + | "search" + | "typescript" + | "warning"; + +export default function Icon({ + className = "", + type, + ...rest +}: SVGProps & { + className?: string; + type: IconType; +}) { + let path = ""; + switch (type) { + case "chevron-down": + path = "M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z"; + break; + case "close": + path = + "M20 6.91L17.09 4L12 9.09L6.91 4L4 6.91L9.09 12L4 17.09L6.91 20L12 14.91L17.09 20L20 17.09L14.91 12L20 6.91Z"; + break; + case "collapse": + path = + "M19.5,3.09L15,7.59V4H13V11H20V9H16.41L20.91,4.5L19.5,3.09M4,13V15H7.59L3.09,19.5L4.5,20.91L9,16.41V20H11V13H4Z"; + break; + case "css": + path = + "M5,3L4.35,6.34H17.94L17.5,8.5H3.92L3.26,11.83H16.85L16.09,15.64L10.61,17.45L5.86,15.64L6.19,14H2.85L2.06,18L9.91,21L18.96,18L20.16,11.97L20.4,10.76L21.94,3H5Z"; + break; + case "dialog": + path = + "M18 18V20H4A2 2 0 0 1 2 18V8H4V18M22 6V14A2 2 0 0 1 20 16H8A2 2 0 0 1 6 14V6A2 2 0 0 1 8 4H20A2 2 0 0 1 22 6M20 6H8V14H20Z"; + break; + case "drag": + path = + "M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2m-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2m0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2m6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2m0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2m0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2"; + break; + case "expand": + path = + "M10,21V19H6.41L10.91,14.5L9.5,13.09L5,17.59V14H3V21H10M14.5,10.91L19,6.41V10H21V3H14V5H17.59L13.09,9.5L14.5,10.91Z"; + break; + case "files": + path = + "M15,7H20.5L15,1.5V7M8,0H16L22,6V18A2,2 0 0,1 20,20H8C6.89,20 6,19.1 6,18V2A2,2 0 0,1 8,0M4,4V22H20V24H4A2,2 0 0,1 2,22V4H4Z"; + break; + case "horizontal-collapse": + path = + "M13,20V4H15.03V20H13M10,20V4H12.03V20H10M5,8L9.03,12L5,16V13H2V11H5V8M20,16L16,12L20,8V11H23V13H20V16Z"; + break; + case "horizontal-expand": + path = + "M13,4V20H11V4H13M8,20V4H10V20H8M19,8V11H22V13H19V16L15,12L19,8M5,16L9,12L5,8V11H2V13H5V16Z"; + break; + case "html": + path = + "M12,17.56L16.07,16.43L16.62,10.33H9.38L9.2,8.3H16.8L17,6.31H7L7.56,12.32H14.45L14.22,14.9L12,15.5L9.78,14.9L9.64,13.24H7.64L7.93,16.43L12,17.56M4.07,3H19.93L18.5,19.2L12,21L5.5,19.2L4.07,3Z"; + break; + case "loading": + path = "M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z"; + break; + case "markdown": + path = + "M22.269,19.385H1.731a1.73,1.73,0,0,1-1.73-1.73V6.345a1.73,1.73,0,0,1,1.73-1.73H22.269a1.731,1.731,0,0,1,1.731,1.73V17.654A1.73,1.73,0,0,1,22.269,19.385ZM12,6.923v9.231H9.462V9.077l-2.308,3.846L4.846,9.077v7.077H2.308V6.923H5.769L7.154,9.308,8.538,6.923Zm7.385,2.769V6.923h2.308v9.231H19.385V10.615L16.154,16.154,12.923,10.615v5.539H10.615V6.923h2.308l3.231,5.539Z"; + break; + case "resize": + path = + "M22,3H2C0.91,3.04 0.04,3.91 0,5V19C0.04,20.09 0.91,20.96 2,21H22C23.09,20.96 23.96,20.09 24,19V5C23.96,3.91 23.09,3.04 22,3M22,19H2V5H22V19Z"; + break; + case "resize-horizontal": + path = + "M18,16V13H22V11H18V8L15,12L18,16M6,16L9,12L6,8V11H2V13H6V16M11,18H13V6H11V18Z"; + break; + case "resize-vertical": + path = + "M8,18H11V22H13V18H16L12,15L8,18M8,6L12,9L16,6H13V2H11V6H8M18,11V13H6V11H18Z"; + break; + case "search": + path = + "M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z"; + break; + case "typescript": + path = + "M3,3H21V21H3V3M13.71,17.86C14.21,18.84 15.22,19.59 16.8,19.59C18.4,19.59 19.6,18.76 19.6,17.23C19.6,15.82 18.79,15.19 17.35,14.57L16.93,14.39C16.2,14.08 15.89,13.87 15.89,13.37C15.89,12.96 16.2,12.64 16.7,12.64C17.18,12.64 17.5,12.85 17.79,13.37L19.1,12.5C18.55,11.54 17.77,11.17 16.7,11.17C15.19,11.17 14.22,12.13 14.22,13.4C14.22,14.78 15.03,15.43 16.25,15.95L16.67,16.13C17.45,16.47 17.91,16.68 17.91,17.26C17.91,17.74 17.46,18.09 16.76,18.09C15.93,18.09 15.45,17.66 15.09,17.06L13.71,17.86M13,11.25H8V12.75H9.5V20H11.25V12.75H13V11.25Z"; + break; + case "warning": + path = + "M5,3H19A2,2 0 0,1 21,5V19A2,2 0 0,1 19,21H5A2,2 0 0,1 3,19V5A2,2 0 0,1 5,3M13,13V7H11V13H13M13,17V15H11V17H13Z"; + break; + } + + return ( + + + + ); +} diff --git a/examples/nextjs/src/components/ResizeHandle.module.css b/examples/nextjs/src/components/ResizeHandle.module.css new file mode 100644 index 000000000..ee3193b22 --- /dev/null +++ b/examples/nextjs/src/components/ResizeHandle.module.css @@ -0,0 +1,30 @@ +.ResizeHandle { + flex: 0 0 0.5rem; + display: flex; + justify-content: center; + align-items: center; + outline: none; + color: var(--color-resize-bar); +} +.ResizeHandle:hover { + color: var(--color-resize-bar-hover); +} +.ResizeHandle[data-resize-handle-active] { + color: var(--color-resize-bar-active); +} + +.ResizeHandle .ResizeHandleThumb[data-direction="vertical"] { + rotate: 90deg; +} + +@media (pointer: coarse) { + .ResizeHandle { + flex: 0 0 2rem; + } + + .ResizeHandle .ResizeHandleThumb { + flex: 0 0 1.25rem; + height: 1.25rem; + width: 1.25rem; + } +} diff --git a/examples/nextjs/src/components/ResizeHandle.tsx b/examples/nextjs/src/components/ResizeHandle.tsx new file mode 100644 index 000000000..ce6fc9cce --- /dev/null +++ b/examples/nextjs/src/components/ResizeHandle.tsx @@ -0,0 +1,33 @@ +import { + PanelResizeHandle, + PanelResizeHandleProps, + usePanelGroupContext, +} from "react-resizable-panels"; + +import styles from "./ResizeHandle.module.css"; +import Icon from "./Icon"; + +export function ResizeHandle({ + className = "", + id, + ...rest +}: PanelResizeHandleProps & { + className?: string; + id?: string; +}) { + const { direction } = usePanelGroupContext(); + + return ( + + + + ); +} diff --git a/examples/nextjs/src/components/shared.module.css b/examples/nextjs/src/components/shared.module.css new file mode 100644 index 000000000..2b6e0c2c7 --- /dev/null +++ b/examples/nextjs/src/components/shared.module.css @@ -0,0 +1,99 @@ +.PanelGroupWrapper { + height: 20rem; +} +.PanelGroupWrapper[data-short] { + height: 10rem; +} +.PanelGroupWrapper[data-tall] { + height: 30rem; +} + +.PanelGroup { + font-size: 2rem; +} + +.Panel { + display: flex; + flex-direction: row; + font-size: 2rem; +} + +.PanelColumn, +.PanelRow { + display: flex; +} +.PanelColumn { + flex-direction: column; +} +.PanelRow { + flex-direction: row; +} + +.Centered { + flex: 1 1 auto; + display: flex; + align-items: center; + justify-content: center; + background-color: var(--color-panel-background); + border-radius: 0.5rem; + overflow: hidden; + font-size: 1rem; + padding: 0.5rem; + word-break: break-all; +} + +/* ResizeHandle styles are defined in ResizeHandle.module.css */ + +.Overflow { + width: 100%; + height: 100%; + overflow: auto; + padding: 1rem; + + /* Firefox fixes */ + scrollbar-width: thin; + scrollbar-color: var(--color-scroll-thumb) transparent; +} + +.Button, +.ButtonDisabled { + background-color: var(--color-button-background); + color: var(--color-default); + border: none; + border-radius: 0.5rem; + padding: 0.25rem 0.5rem; +} +.Button:hover { + background-color: var(--color-button-background-hover); +} +.ButtonDisabled { + opacity: 0.5; +} + +.Buttons { + display: flex; + flex-direction: row; + align-items: center; + gap: 1ch; + margin-bottom: 1rem; +} + +.Capitalize { + text-transform: capitalize; +} + +.WarningBlock { + display: inline-flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + gap: 1ch; + background: var(--color-warning-background); + padding: 0.5em; + border-radius: 0.5rem; +} +.WarningIcon { + flex: 0 0 2rem; + width: 2rem; + height: 2rem; +} diff --git a/examples/nextjs/tsconfig.json b/examples/nextjs/tsconfig.json new file mode 100644 index 000000000..c1334095f --- /dev/null +++ b/examples/nextjs/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/package.json b/package.json index 0124d990b..af87dfb92 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dev": "pnpm run /^dev:.*/", "dev:core": "cd packages/react-resizable-panels && pnpm watch", "dev:website": "cd packages/react-resizable-panels-website && pnpm watch", + "next:dev": "pnpm --filter react-resizable-panels-nextjs dev", "docs": "cd packages/react-resizable-panels-website && pnpm build", "lint": "cd packages/react-resizable-panels && pnpm lint", "prerelease": "preconstruct build", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cd3be483d..9251b6aea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -70,6 +70,43 @@ importers: specifier: ^5.8.3 version: 5.8.3 + examples/nextjs: + dependencies: + next: + specifier: 15.5.6 + version: 15.5.6(@playwright/test@1.37.0)(react-dom@19.1.0)(react@19.1.0) + react: + specifier: 19.1.0 + version: 19.1.0 + react-dom: + specifier: 19.1.0 + version: 19.1.0(react@19.1.0) + react-resizable-panels: + specifier: workspace:* + version: link:../../packages/react-resizable-panels + devDependencies: + '@eslint/eslintrc': + specifier: ^3 + version: 3.3.1 + '@types/node': + specifier: ^20 + version: 20.19.22 + '@types/react': + specifier: ^19 + version: 19.2.2 + '@types/react-dom': + specifier: ^19 + version: 19.2.2(@types/react@19.2.2) + eslint: + specifier: ^9 + version: 9.38.0 + eslint-config-next: + specifier: 15.5.6 + version: 15.5.6(eslint@9.38.0)(typescript@5.8.3) + typescript: + specifier: ^5 + version: 5.8.3 + packages/react-resizable-panels: devDependencies: '@babel/plugin-proposal-nullish-coalescing-operator': @@ -652,6 +689,30 @@ packages: engines: {node: '>=18'} dev: true + /@emnapi/core@1.5.0: + resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} + requiresBuild: true + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + dev: true + optional: true + + /@emnapi/runtime@1.5.0: + resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} + requiresBuild: true + dependencies: + tslib: 2.8.1 + optional: true + + /@emnapi/wasi-threads@1.1.0: + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + requiresBuild: true + dependencies: + tslib: 2.8.1 + dev: true + optional: true + /@esbuild/aix-ppc64@0.21.5: resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} @@ -869,11 +930,61 @@ packages: eslint-visitor-keys: 3.4.3 dev: true + /@eslint-community/eslint-utils@4.4.0(eslint@9.38.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 9.38.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/eslint-utils@4.9.0(eslint@9.38.0): + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 9.38.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.12.1: + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + /@eslint-community/regexpp@4.8.0: resolution: {integrity: sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true + /@eslint/config-array@0.21.1: + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@eslint/config-helpers@0.4.1: + resolution: {integrity: sha512-csZAzkNhsgwb0I/UAV6/RGFTbiakPCf0ZrGmrIxQpYvGZ00PhTkSnyKNolphgIvmnJeGw6rcGVEXfTzUnFuEvw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/core': 0.16.0 + dev: true + + /@eslint/core@0.16.0: + resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@types/json-schema': 7.0.15 + dev: true + /@eslint/eslintrc@2.1.2: resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -891,11 +1002,59 @@ packages: - supports-color dev: true + /@eslint/eslintrc@3.3.1: + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + ajv: 6.12.6 + debug: 4.4.0 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.2.4 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + /@eslint/js@8.48.0: resolution: {integrity: sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@eslint/js@9.38.0: + resolution: {integrity: sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@eslint/object-schema@2.1.7: + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@eslint/plugin-kit@0.4.0: + resolution: {integrity: sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/core': 0.16.0 + levn: 0.4.1 + dev: true + + /@humanfs/core@0.19.1: + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + dev: true + + /@humanfs/node@0.16.7: + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + dev: true + /@humanwhocodes/config-array@0.11.11: resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} engines: {node: '>=10.10.0'} @@ -916,6 +1075,226 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@humanwhocodes/retry@0.4.3: + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + dev: true + + /@img/colour@1.0.0: + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + requiresBuild: true + dev: false + optional: true + + /@img/sharp-darwin-arm64@0.34.4: + resolution: {integrity: sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.3 + dev: false + optional: true + + /@img/sharp-darwin-x64@0.34.4: + resolution: {integrity: sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.3 + dev: false + optional: true + + /@img/sharp-libvips-darwin-arm64@1.2.3: + resolution: {integrity: sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-darwin-x64@1.2.3: + resolution: {integrity: sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linux-arm64@1.2.3: + resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linux-arm@1.2.3: + resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linux-ppc64@1.2.3: + resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linux-s390x@1.2.3: + resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linux-x64@1.2.3: + resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linuxmusl-arm64@1.2.3: + resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linuxmusl-x64@1.2.3: + resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-linux-arm64@0.34.4: + resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.3 + dev: false + optional: true + + /@img/sharp-linux-arm@0.34.4: + resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.3 + dev: false + optional: true + + /@img/sharp-linux-ppc64@0.34.4: + resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.3 + dev: false + optional: true + + /@img/sharp-linux-s390x@0.34.4: + resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.3 + dev: false + optional: true + + /@img/sharp-linux-x64@0.34.4: + resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.3 + dev: false + optional: true + + /@img/sharp-linuxmusl-arm64@0.34.4: + resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.3 + dev: false + optional: true + + /@img/sharp-linuxmusl-x64@0.34.4: + resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.3 + dev: false + optional: true + + /@img/sharp-wasm32@0.34.4: + resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + requiresBuild: true + dependencies: + '@emnapi/runtime': 1.5.0 + dev: false + optional: true + + /@img/sharp-win32-arm64@0.34.4: + resolution: {integrity: sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-win32-ia32@0.34.4: + resolution: {integrity: sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-win32-x64@0.34.4: + resolution: {integrity: sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} engines: {node: '>=6.0.0'} @@ -1097,32 +1476,129 @@ packages: requiresBuild: true optional: true - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + /@napi-rs/wasm-runtime@0.2.12: + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + requiresBuild: true dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 + '@emnapi/core': 1.5.0 + '@emnapi/runtime': 1.5.0 + '@tybys/wasm-util': 0.10.1 + dev: true + optional: true - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} + /@next/env@15.5.6: + resolution: {integrity: sha512-3qBGRW+sCGzgbpc5TS1a0p7eNxnOarGVQhZxfvTdnV0gFI61lX7QNtQ4V1TSREctXzYn5NetbUsLvyqwLFJM6Q==} + dev: false - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + /@next/eslint-plugin-next@15.5.6: + resolution: {integrity: sha512-YxDvsT2fwy1j5gMqk3ppXlsgDopHnkM4BoxSVASbvvgh5zgsK8lvWerDzPip8k3WVzsTZ1O7A7si1KNfN4OZfQ==} dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 + fast-glob: 3.3.1 + dev: true - /@parcel/bundler-default@2.9.3(@parcel/core@2.9.3): - resolution: {integrity: sha512-JjJK8dq39/UO/MWI/4SCbB1t/qgpQRFnFDetAAAezQ8oN++b24u1fkMDa/xqQGjbuPmGeTds5zxGgYs7id7PYg==} - engines: {node: '>= 12.0.0', parcel: ^2.9.3} - dependencies: - '@parcel/diagnostic': 2.9.3 - '@parcel/graph': 2.9.3 - '@parcel/hash': 2.9.3 - '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + /@next/swc-darwin-arm64@15.5.6: + resolution: {integrity: sha512-ES3nRz7N+L5Umz4KoGfZ4XX6gwHplwPhioVRc25+QNsDa7RtUF/z8wJcbuQ2Tffm5RZwuN2A063eapoJ1u4nPg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@next/swc-darwin-x64@15.5.6: + resolution: {integrity: sha512-JIGcytAyk9LQp2/nuVZPAtj8uaJ/zZhsKOASTjxDug0SPU9LAM3wy6nPU735M1OqacR4U20LHVF5v5Wnl9ptTA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-arm64-gnu@15.5.6: + resolution: {integrity: sha512-qvz4SVKQ0P3/Im9zcS2RmfFL/UCQnsJKJwQSkissbngnB/12c6bZTCB0gHTexz1s6d/mD0+egPKXAIRFVS7hQg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-arm64-musl@15.5.6: + resolution: {integrity: sha512-FsbGVw3SJz1hZlvnWD+T6GFgV9/NYDeLTNQB2MXoPN5u9VA9OEDy6fJEfePfsUKAhJufFbZLgp0cPxMuV6SV0w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-x64-gnu@15.5.6: + resolution: {integrity: sha512-3QnHGFWlnvAgyxFxt2Ny8PTpXtQD7kVEeaFat5oPAHHI192WKYB+VIKZijtHLGdBBvc16tiAkPTDmQNOQ0dyrA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-x64-musl@15.5.6: + resolution: {integrity: sha512-OsGX148sL+TqMK9YFaPFPoIaJKbFJJxFzkXZljIgA9hjMjdruKht6xDCEv1HLtlLNfkx3c5w2GLKhj7veBQizQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@next/swc-win32-arm64-msvc@15.5.6: + resolution: {integrity: sha512-ONOMrqWxdzXDJNh2n60H6gGyKed42Ieu6UTVPZteXpuKbLZTH4G4eBMsr5qWgOBA+s7F+uB4OJbZnrkEDnZ5Fg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@next/swc-win32-x64-msvc@15.5.6: + resolution: {integrity: sha512-pxK4VIjFRx1MY92UycLOOw7dTdvccWsNETQ0kDHkBlcFH1GrTLUjSiHU1ohrznnux6TqRHgv5oflhfIWZwVROQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + + /@nolyfill/is-core-module@1.0.39: + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + dev: true + + /@parcel/bundler-default@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-JjJK8dq39/UO/MWI/4SCbB1t/qgpQRFnFDetAAAezQ8oN++b24u1fkMDa/xqQGjbuPmGeTds5zxGgYs7id7PYg==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/graph': 2.9.3 + '@parcel/hash': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) '@parcel/utils': 2.9.3 nullthrows: 1.1.1 transitivePeerDependencies: @@ -1886,7 +2362,6 @@ packages: playwright-core: 1.37.0 optionalDependencies: fsevents: 2.3.2 - dev: true /@polka/url@1.0.0-next.25: resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} @@ -2152,6 +2627,14 @@ packages: dev: true optional: true + /@rtsao/scc@1.1.0: + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + dev: true + + /@rushstack/eslint-patch@1.14.0: + resolution: {integrity: sha512-WJFej426qe4RWOm9MMtP4V3CV4AucXolQty+GRgAWLgQXmpCuwzs7hEpxxhSc/znXUSxum9d/P/32MW0FlAAlA==} + dev: true + /@swc/core-darwin-arm64@1.3.76: resolution: {integrity: sha512-ovviEhZ/1E81Z9OGrO0ivLWk4VCa3I3ZzM+cd3gugglRRwVwtlIaoIYqY5S3KiCAupDd1+UCl5X7Vbio7a/V8g==} engines: {node: '>=10'} @@ -2258,10 +2741,24 @@ packages: dependencies: tslib: 2.6.2 + /@swc/helpers@0.5.15: + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + dependencies: + tslib: 2.8.1 + dev: false + /@trysound/sax@0.2.0: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} + /@tybys/wasm-util@0.10.1: + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + requiresBuild: true + dependencies: + tslib: 2.8.1 + dev: true + optional: true + /@types/estree@0.0.39: resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} dev: false @@ -2273,10 +2770,28 @@ packages: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} dev: true + /@types/estree@1.0.8: + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + dev: true + /@types/json-schema@7.0.12: resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} dev: true + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: true + + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: true + + /@types/node@20.19.22: + resolution: {integrity: sha512-hRnu+5qggKDSyWHlnmThnUqg62l29Aj/6vcYgUaSFL9oc7DVjeWEQN3PRgdSc6F8d9QRMWkf36CLMch1Do/+RQ==} + dependencies: + undici-types: 6.21.0 + dev: true + /@types/node@22.15.3: resolution: {integrity: sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==} dependencies: @@ -2289,7 +2804,15 @@ packages: /@types/react-dom@18.2.18: resolution: {integrity: sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==} dependencies: - '@types/react': 18.2.48 + '@types/react': 19.2.2 + dev: true + + /@types/react-dom@19.2.2(@types/react@19.2.2): + resolution: {integrity: sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==} + peerDependencies: + '@types/react': ^19.2.0 + dependencies: + '@types/react': 19.2.2 dev: true /@types/react@18.2.48: @@ -2300,6 +2823,12 @@ packages: csstype: 3.1.2 dev: true + /@types/react@19.2.2: + resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==} + dependencies: + csstype: 3.1.2 + dev: true + /@types/resolve@1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} dependencies: @@ -2342,6 +2871,34 @@ packages: - supports-color dev: true + /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@9.38.0)(typescript@5.8.3): + resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.8.0 + '@typescript-eslint/parser': 5.62.0(eslint@9.38.0)(typescript@5.8.3) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/type-utils': 5.62.0(eslint@9.38.0)(typescript@5.8.3) + '@typescript-eslint/utils': 5.62.0(eslint@9.38.0)(typescript@5.8.3) + debug: 4.3.4 + eslint: 9.38.0 + graphemer: 1.4.0 + ignore: 5.2.4 + natural-compare-lite: 1.4.0 + semver: 7.5.4 + tsutils: 3.21.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/parser@5.62.0(eslint@8.47.0)(typescript@5.8.3): resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2362,6 +2919,26 @@ packages: - supports-color dev: true + /@typescript-eslint/parser@5.62.0(eslint@9.38.0)(typescript@5.8.3): + resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) + debug: 4.3.4 + eslint: 9.38.0 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/scope-manager@5.62.0: resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2390,6 +2967,26 @@ packages: - supports-color dev: true + /@typescript-eslint/type-utils@5.62.0(eslint@9.38.0)(typescript@5.8.3): + resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) + '@typescript-eslint/utils': 5.62.0(eslint@9.38.0)(typescript@5.8.3) + debug: 4.3.4 + eslint: 9.38.0 + tsutils: 3.21.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/types@5.62.0: resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2436,6 +3033,26 @@ packages: - typescript dev: true + /@typescript-eslint/utils@5.62.0(eslint@9.38.0)(typescript@5.8.3): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.38.0) + '@types/json-schema': 7.0.12 + '@types/semver': 7.5.0 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) + eslint: 9.38.0 + eslint-scope: 5.1.1 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/visitor-keys@5.62.0: resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2444,60 +3061,214 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@vitest/expect@3.1.2: - resolution: {integrity: sha512-O8hJgr+zREopCAqWl3uCVaOdqJwZ9qaDwUP7vy3Xigad0phZe9APxKhPcDNqYYi0rX5oMvwJMSCAXY2afqeTSA==} - dependencies: - '@vitest/spy': 3.1.2 - '@vitest/utils': 3.1.2 - chai: 5.2.0 - tinyrainbow: 2.0.0 + /@unrs/resolver-binding-android-arm-eabi@1.11.1: + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + requiresBuild: true dev: true + optional: true - /@vitest/mocker@3.1.2(vite@5.3.5): - resolution: {integrity: sha512-kOtd6K2lc7SQ0mBqYv/wdGedlqPdM/B38paPY+OwJ1XiNi44w3Fpog82UfOibmHaV9Wod18A09I9SCKLyDMqgw==} - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - dependencies: - '@vitest/spy': 3.1.2 - estree-walker: 3.0.3 - magic-string: 0.30.17 - vite: 5.3.5(@types/node@22.15.3) + /@unrs/resolver-binding-android-arm64@1.11.1: + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + requiresBuild: true dev: true + optional: true - /@vitest/pretty-format@3.1.2: - resolution: {integrity: sha512-R0xAiHuWeDjTSB3kQ3OQpT8Rx3yhdOAIm/JM4axXxnG7Q/fS8XUwggv/A4xzbQA+drYRjzkMnpYnOGAc4oeq8w==} - dependencies: - tinyrainbow: 2.0.0 + /@unrs/resolver-binding-darwin-arm64@1.11.1: + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + requiresBuild: true dev: true + optional: true - /@vitest/runner@3.1.2: - resolution: {integrity: sha512-bhLib9l4xb4sUMPXnThbnhX2Yi8OutBMA8Yahxa7yavQsFDtwY/jrUZwpKp2XH9DhRFJIeytlyGpXCqZ65nR+g==} - dependencies: - '@vitest/utils': 3.1.2 - pathe: 2.0.3 + /@unrs/resolver-binding-darwin-x64@1.11.1: + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + requiresBuild: true dev: true + optional: true - /@vitest/snapshot@3.1.2: - resolution: {integrity: sha512-Q1qkpazSF/p4ApZg1vfZSQ5Yw6OCQxVMVrLjslbLFA1hMDrT2uxtqMaw8Tc/jy5DLka1sNs1Y7rBcftMiaSH/Q==} - dependencies: - '@vitest/pretty-format': 3.1.2 - magic-string: 0.30.17 - pathe: 2.0.3 + /@unrs/resolver-binding-freebsd-x64@1.11.1: + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + requiresBuild: true dev: true + optional: true - /@vitest/spy@3.1.2: - resolution: {integrity: sha512-OEc5fSXMws6sHVe4kOFyDSj/+4MSwst0ib4un0DlcYgQvRuYQ0+M2HyqGaauUMnjq87tmUaMNDxKQx7wNfVqPA==} - dependencies: - tinyspy: 3.0.2 + /@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1: + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + requiresBuild: true dev: true + optional: true - /@vitest/ui@3.1.2(vitest@3.1.2): + /@unrs/resolver-binding-linux-arm-musleabihf@1.11.1: + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@unrs/resolver-binding-linux-arm64-gnu@1.11.1: + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@unrs/resolver-binding-linux-arm64-musl@1.11.1: + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@unrs/resolver-binding-linux-ppc64-gnu@1.11.1: + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@unrs/resolver-binding-linux-riscv64-gnu@1.11.1: + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@unrs/resolver-binding-linux-riscv64-musl@1.11.1: + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@unrs/resolver-binding-linux-s390x-gnu@1.11.1: + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@unrs/resolver-binding-linux-x64-gnu@1.11.1: + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@unrs/resolver-binding-linux-x64-musl@1.11.1: + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@unrs/resolver-binding-wasm32-wasi@1.11.1: + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + requiresBuild: true + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + dev: true + optional: true + + /@unrs/resolver-binding-win32-arm64-msvc@1.11.1: + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@unrs/resolver-binding-win32-ia32-msvc@1.11.1: + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@unrs/resolver-binding-win32-x64-msvc@1.11.1: + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@vitest/expect@3.1.2: + resolution: {integrity: sha512-O8hJgr+zREopCAqWl3uCVaOdqJwZ9qaDwUP7vy3Xigad0phZe9APxKhPcDNqYYi0rX5oMvwJMSCAXY2afqeTSA==} + dependencies: + '@vitest/spy': 3.1.2 + '@vitest/utils': 3.1.2 + chai: 5.2.0 + tinyrainbow: 2.0.0 + dev: true + + /@vitest/mocker@3.1.2(vite@5.3.5): + resolution: {integrity: sha512-kOtd6K2lc7SQ0mBqYv/wdGedlqPdM/B38paPY+OwJ1XiNi44w3Fpog82UfOibmHaV9Wod18A09I9SCKLyDMqgw==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + dependencies: + '@vitest/spy': 3.1.2 + estree-walker: 3.0.3 + magic-string: 0.30.17 + vite: 5.3.5(@types/node@22.15.3) + dev: true + + /@vitest/pretty-format@3.1.2: + resolution: {integrity: sha512-R0xAiHuWeDjTSB3kQ3OQpT8Rx3yhdOAIm/JM4axXxnG7Q/fS8XUwggv/A4xzbQA+drYRjzkMnpYnOGAc4oeq8w==} + dependencies: + tinyrainbow: 2.0.0 + dev: true + + /@vitest/runner@3.1.2: + resolution: {integrity: sha512-bhLib9l4xb4sUMPXnThbnhX2Yi8OutBMA8Yahxa7yavQsFDtwY/jrUZwpKp2XH9DhRFJIeytlyGpXCqZ65nR+g==} + dependencies: + '@vitest/utils': 3.1.2 + pathe: 2.0.3 + dev: true + + /@vitest/snapshot@3.1.2: + resolution: {integrity: sha512-Q1qkpazSF/p4ApZg1vfZSQ5Yw6OCQxVMVrLjslbLFA1hMDrT2uxtqMaw8Tc/jy5DLka1sNs1Y7rBcftMiaSH/Q==} + dependencies: + '@vitest/pretty-format': 3.1.2 + magic-string: 0.30.17 + pathe: 2.0.3 + dev: true + + /@vitest/spy@3.1.2: + resolution: {integrity: sha512-OEc5fSXMws6sHVe4kOFyDSj/+4MSwst0ib4un0DlcYgQvRuYQ0+M2HyqGaauUMnjq87tmUaMNDxKQx7wNfVqPA==} + dependencies: + tinyspy: 3.0.2 + dev: true + + /@vitest/ui@3.1.2(vitest@3.1.2): resolution: {integrity: sha512-+YPgKiLpFEyBVJNHDkRcSDcLrrnr20lyU4HQoI9Jtq1MdvoX8usql9h38mQw82MBU1Zo5BPC6sw+sXZ6NS18CQ==} peerDependencies: vitest: 3.1.2 @@ -2531,11 +3302,25 @@ packages: acorn: 8.10.0 dev: true + /acorn-jsx@5.3.2(acorn@8.15.0): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.15.0 + dev: true + /acorn@8.10.0: resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} engines: {node: '>=0.4.0'} hasBin: true + /acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /agent-base@7.1.3: resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} @@ -2574,6 +3359,33 @@ packages: /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + /aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + dev: true + + /array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + dev: true + + /array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + dev: true + /array-sorting-utilities@0.0.1: resolution: {integrity: sha512-h/idT7IGFYQoUk+/ilm5uFAbG1mZ/vW5wYDJG+OD0w15AvTEBv3Yu9WGcV0dTTdKitcufHtLYQjHd42m9u7RZw==} dev: false @@ -2583,16 +3395,111 @@ packages: engines: {node: '>=8'} dev: true + /array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + dev: true + + /array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + dev: true + + /array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + dev: true + + /array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + dev: true + + /array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + dev: true + + /arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + dev: true + /assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} dev: true + /ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + dev: true + + /async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + dev: true + /at-least-node@1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} dev: false + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.1.0 + dev: true + + /axe-core@4.11.0: + resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} + engines: {node: '>=4'} + dev: true + + /axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + dev: true + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2640,6 +3547,32 @@ packages: engines: {node: '>=8'} dev: true + /call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + dev: true + + /call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + dev: true + + /call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + dev: true + /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -2647,6 +3580,10 @@ packages: /caniuse-lite@1.0.30001522: resolution: {integrity: sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg==} + /caniuse-lite@1.0.30001751: + resolution: {integrity: sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==} + dev: false + /chai@5.2.0: resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} engines: {node: '>=12'} @@ -2687,6 +3624,10 @@ packages: engines: {node: '>=8'} dev: false + /client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + dev: false + /clone@2.1.2: resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} engines: {node: '>=0.8'} @@ -2748,6 +3689,15 @@ packages: which: 2.0.2 dev: true + /cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + /css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} dependencies: @@ -2786,6 +3736,10 @@ packages: resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} dev: true + /damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + dev: true + /data-urls@5.0.0: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} @@ -2794,10 +3748,48 @@ packages: whatwg-url: 14.2.0 dev: true + /data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dev: true + + /data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dev: true + + /data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dev: true + /dataloader@2.2.2: resolution: {integrity: sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==} dev: false + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -2839,6 +3831,24 @@ packages: engines: {node: '>=0.10.0'} dev: false + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + dev: true + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + dev: true + /detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -2849,6 +3859,13 @@ packages: engines: {node: '>=0.10'} hasBin: true + /detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + requiresBuild: true + dev: false + optional: true + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2856,6 +3873,13 @@ packages: path-type: 4.0.0 dev: true + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: true + /doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} @@ -2893,9 +3917,22 @@ packages: resolution: {integrity: sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==} engines: {node: '>=6'} + /dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + dev: true + /electron-to-chromium@1.4.496: resolution: {integrity: sha512-qeXC3Zbykq44RCrBa4kr8v/dWzYJA8rAwpyh9Qd+NKWoJfjG5vvJqy9XOJ9H4P/lqulZBCgUWAYi+FeK5AuJ8g==} + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + /enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} @@ -2921,10 +3958,135 @@ packages: dependencies: is-arrayish: 0.2.1 + /es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + dev: true + + /es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + dev: true + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + dev: true + + /es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 + dev: true + /es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} dev: true + /es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + dev: true + + /es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + dev: true + + /es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.2 + dev: true + + /es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + dev: true + /esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} @@ -2956,17 +4118,171 @@ packages: '@esbuild/win32-x64': 0.21.5 dev: true - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /eslint-config-next@15.5.6(eslint@9.38.0)(typescript@5.8.3): + resolution: {integrity: sha512-cGr3VQlPsZBEv8rtYp4BpG1KNXDqGvPo9VC1iaCgIA11OfziC/vczng+TnAS3WpRIR3Q5ye/6yl+CRUuZ1fPGg==} + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@next/eslint-plugin-next': 15.5.6 + '@rushstack/eslint-patch': 1.14.0 + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@9.38.0)(typescript@5.8.3) + '@typescript-eslint/parser': 5.62.0(eslint@9.38.0)(typescript@5.8.3) + eslint: 9.38.0 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.38.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.38.0) + eslint-plugin-react: 7.37.5(eslint@9.38.0) + eslint-plugin-react-hooks: 5.2.0(eslint@9.38.0) + typescript: 5.8.3 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + dev: true + + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.4 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.38.0): + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.0 + eslint: 9.38.0 + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0) + get-tsconfig: 4.12.0 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.13 + unrs-resolver: 1.11.1 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-module-utils@2.12.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0): + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.62.0(eslint@9.38.0)(typescript@5.8.3) + debug: 3.2.7 + eslint: 9.38.0 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.38.0) + transitivePeerDependencies: + - supports-color + dev: true - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} + /eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0): + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@rtsao/scc': 1.1.0 + '@typescript-eslint/parser': 5.62.0(eslint@9.38.0)(typescript@5.8.3) + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.38.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} + /eslint-plugin-jsx-a11y@6.10.2(eslint@9.38.0): + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.11.0 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.38.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 dev: true /eslint-plugin-react-hooks@4.6.0(eslint@8.47.0): @@ -2978,6 +4294,42 @@ packages: eslint: 8.47.0 dev: true + /eslint-plugin-react-hooks@5.2.0(eslint@9.38.0): + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + dependencies: + eslint: 9.38.0 + dev: true + + /eslint-plugin-react@7.37.5(eslint@9.38.0): + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 9.38.0 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + dev: true + /eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} @@ -2994,11 +4346,24 @@ packages: estraverse: 5.3.0 dev: true + /eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + /eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + /eslint@8.47.0: resolution: {integrity: sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3045,6 +4410,63 @@ packages: - supports-color dev: true + /eslint@9.38.0: + resolution: {integrity: sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.1 + '@eslint/core': 0.16.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.38.0 + '@eslint/plugin-kit': 0.4.0 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.5.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.2.4 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.3 + transitivePeerDependencies: + - supports-color + dev: true + + /espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + dev: true + /espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3155,6 +4577,13 @@ packages: flat-cache: 3.1.0 dev: true + /file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + dependencies: + flat-cache: 4.0.1 + dev: true + /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -3178,6 +4607,14 @@ packages: rimraf: 3.0.2 dev: true + /flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + dev: true + /flatted@3.2.7: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true @@ -3186,6 +4623,13 @@ packages: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} dev: true + /for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + dev: true + /fs-extra@9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -3204,7 +4648,6 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true - dev: true optional: true /fsevents@2.3.3: @@ -3216,21 +4659,80 @@ packages: /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: false + + /function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + dev: true + + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true + + /generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + dev: true /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + /get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + dev: true + /get-port@4.2.0: resolution: {integrity: sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==} engines: {node: '>=6'} dev: true + /get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + dev: true + + /get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + dev: true + /get-them-args@1.3.2: resolution: {integrity: sha512-LRn8Jlk+DwZE4GTlDbT3Hikd1wSHgLMme/+7ddlqKd7ldwR6LjJgTVWzBnR01wnYGe4KgrXjg287RaI22UHmAw==} dev: false + /get-tsconfig@4.12.0: + resolution: {integrity: sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + /glob-base@0.3.0: resolution: {integrity: sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==} engines: {node: '>=0.10.0'} @@ -3278,6 +4780,19 @@ packages: dependencies: type-fest: 0.20.2 + /globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + dev: true + + /globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + dev: true + /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -3290,6 +4805,11 @@ packages: slash: 3.0.0 dev: true + /gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + dev: true + /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} dev: false @@ -3298,6 +4818,11 @@ packages: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true + /has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + dev: true + /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -3306,12 +4831,43 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + dependencies: + es-define-property: 1.0.1 + dev: true + + /has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + dev: true + + /has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + dev: true + + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.1.0 + dev: true + /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} dependencies: function-bind: 1.1.2 - dev: false + + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true /html-encoding-sniffer@4.0.0: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} @@ -3425,20 +4981,98 @@ packages: /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + /internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + dev: true + /interval-utilities@0.0.1: resolution: {integrity: sha512-Qo1IAx3noFPA0ssKfNe0eQmLmGmquWlEiwPn9Oeb16L1PqWnNe0YGfeRlU/hF7dtjjYRdNfVMVl+0o0cMLvjOQ==} dependencies: - point-utilities: 0.0.2 + point-utilities: 0.1.0 dev: false + /is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + dev: true + /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + /is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + dev: true + + /is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + dependencies: + has-bigints: 1.1.0 + dev: true + + /is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + dev: true + + /is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + dependencies: + semver: 7.7.3 + dev: true + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: true + /is-core-module@2.13.0: resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} dependencies: has: 1.0.3 - dev: false + + /is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.2 + dev: true + + /is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + dev: true + + /is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + dev: true /is-dotfile@1.0.3: resolution: {integrity: sha512-9YclgOGtN/f8zx0Pr4FQYMdibBiTaH3sn52vjYip4ZSf6C4/6RfTEZ+MR4GvKhCxdPh21Bg42/WL55f6KSnKpg==} @@ -3454,6 +5088,24 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + /is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + dev: true + + /is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + dev: true + /is-glob@2.0.1: resolution: {integrity: sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==} engines: {node: '>=0.10.0'} @@ -3470,10 +5122,28 @@ packages: /is-json@2.0.1: resolution: {integrity: sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==} + /is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + dev: true + /is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} dev: false + /is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + dev: true + + /is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + dev: true + /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -3493,10 +5163,92 @@ packages: '@types/estree': 1.0.1 dev: false + /is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + dev: true + + /is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + dev: true + + /is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + dev: true + + /is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + dev: true + + /is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + dev: true + + /is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.19 + dev: true + + /is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + dev: true + + /is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + dev: true + + /is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + dev: true + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true + /iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + dev: true + /jest-worker@26.6.2: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} @@ -3570,6 +5322,13 @@ packages: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true + /json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + dependencies: + minimist: 1.2.8 + dev: true + /json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -3583,6 +5342,16 @@ packages: graceful-fs: 4.2.11 dev: false + /jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + dev: true + /keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} dependencies: @@ -3597,6 +5366,17 @@ packages: shell-exec: 1.0.2 dev: false + /language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + dev: true + + /language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + dependencies: + language-subtag-registry: 0.3.23 + dev: true + /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -3779,6 +5559,11 @@ packages: remove-accents: 0.5.0 dev: false + /math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + dev: true + /mdn-data@2.0.14: resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} @@ -3802,6 +5587,10 @@ packages: dependencies: brace-expansion: 1.1.11 + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + /mrmime@2.0.0: resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} engines: {node: '>=10'} @@ -3843,6 +5632,11 @@ packages: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + + /napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true dev: true /natural-compare-lite@1.4.0: @@ -3853,6 +5647,50 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /next@15.5.6(@playwright/test@1.37.0)(react-dom@19.1.0)(react@19.1.0): + resolution: {integrity: sha512-zTxsnI3LQo3c9HSdSf91O1jMNsEzIXDShXd4wVdg9y5shwLqBXi4ZtUUJyB86KGVSJLZx0PFONvO54aheGX8QQ==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + dependencies: + '@next/env': 15.5.6 + '@playwright/test': 1.37.0 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001751 + postcss: 8.4.31 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + styled-jsx: 5.1.6(react@19.1.0) + optionalDependencies: + '@next/swc-darwin-arm64': 15.5.6 + '@next/swc-darwin-x64': 15.5.6 + '@next/swc-linux-arm64-gnu': 15.5.6 + '@next/swc-linux-arm64-musl': 15.5.6 + '@next/swc-linux-x64-gnu': 15.5.6 + '@next/swc-linux-x64-musl': 15.5.6 + '@next/swc-win32-arm64-msvc': 15.5.6 + '@next/swc-win32-x64-msvc': 15.5.6 + sharp: 0.34.4 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + dev: false + /node-addon-api@4.3.0: resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} @@ -3917,11 +5755,77 @@ packages: resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==} dev: true + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true + + /object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + dev: true + + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: true + /object-path@0.6.0: resolution: {integrity: sha512-fxrwsCFi3/p+LeLOAwo/wyRMODZxdGBtUlWRzsEpsUVrisZbEfZ21arxLGfaWfcnqb8oHPNihIb4XPE8CQPN5A==} engines: {node: '>=0.8.0'} dev: false + /object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + dev: true + + /object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + dev: true + + /object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + dev: true + + /object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + dev: true + + /object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + dev: true + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -3942,6 +5846,15 @@ packages: /ordered-binary@1.4.1: resolution: {integrity: sha512-9LtiGlPy982CsgxZvJGNNp2/NnrgEr6EAyN3iIEP3/8vd3YLgAZQHbQ75ZrkfBRGrNg37Dk3U6tuVb+B4Xfslg==} + /own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + dev: true + /p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -4032,7 +5945,6 @@ packages: /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: false /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} @@ -4052,7 +5964,6 @@ packages: /picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - dev: true /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -4072,15 +5983,32 @@ packages: resolution: {integrity: sha512-1c46jhTH/myQw6sesrcuHVtLoSNfJv8Pfy9t3rs6subY7kARv0HRw5PpyfPYPpPtQvBOmgbE6K+qgYUpj81LAA==} engines: {node: '>=16'} hasBin: true - dev: true /point-utilities@0.0.2: resolution: {integrity: sha512-jNUr+ijPk0cWw39gtJG0O8HNPL2EVC7e2ilC1NUlJw1QVTgC8NIMS/8AmG9IJfvfmJx+IlT8KNJzf/Jb035STQ==} dev: false + /point-utilities@0.1.0: + resolution: {integrity: sha512-vLuthhYO+b6trGuN4UeAfTWTJ/mq87/HthpG6jYIMU3a7kS6ZhOY2Oc/F9neUIa6NuCKz/qjJhoQkPwksOaUVw==} + dev: false + + /possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + dev: true + /postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.1.1 + source-map-js: 1.2.0 + dev: false + /postcss@8.4.40: resolution: {integrity: sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==} engines: {node: ^10 || ^12 || >=14} @@ -4131,6 +6059,14 @@ packages: engines: {node: '>= 0.6.0'} dev: true + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + dev: true + /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} @@ -4158,9 +6094,22 @@ packages: react: 0.0.0-experimental-247738465-20240130 scheduler: 0.0.0-experimental-247738465-20240130 + /react-dom@19.1.0(react@19.1.0): + resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} + peerDependencies: + react: ^19.1.0 + dependencies: + react: 19.1.0 + scheduler: 0.26.0 + dev: false + /react-error-overlay@6.0.9: resolution: {integrity: sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==} + /react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: true + /react-refresh@0.9.0: resolution: {integrity: sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==} engines: {node: '>=0.10.0'} @@ -4204,6 +6153,25 @@ packages: dependencies: loose-envify: 1.4.0 + /react@19.1.0: + resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} + engines: {node: '>=0.10.0'} + dev: false + + /reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + dev: true + /regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} @@ -4211,6 +6179,18 @@ packages: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} dev: false + /regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + dev: true + /remove-accents@0.5.0: resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==} dev: false @@ -4224,6 +6204,10 @@ packages: engines: {node: '>=8'} dev: false + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true + /resolve@1.22.4: resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} hasBin: true @@ -4231,7 +6215,15 @@ packages: is-core-module: 2.13.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: false + + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} @@ -4287,9 +6279,37 @@ packages: dependencies: queue-microtask: 1.2.3 + /safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + dev: true + /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + /safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + dev: true + + /safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + dev: true + /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} dev: true @@ -4306,6 +6326,10 @@ packages: dependencies: loose-envify: 1.4.0 + /scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + dev: false + /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -4317,10 +6341,80 @@ packages: dependencies: lru-cache: 6.0.0 + /semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + dev: true + + /set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + dev: true + + /set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + dev: true + /shallowequal@1.1.0: resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} dev: false + /sharp@0.34.4: + resolution: {integrity: sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + requiresBuild: true + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.4 + '@img/sharp-darwin-x64': 0.34.4 + '@img/sharp-libvips-darwin-arm64': 1.2.3 + '@img/sharp-libvips-darwin-x64': 1.2.3 + '@img/sharp-libvips-linux-arm': 1.2.3 + '@img/sharp-libvips-linux-arm64': 1.2.3 + '@img/sharp-libvips-linux-ppc64': 1.2.3 + '@img/sharp-libvips-linux-s390x': 1.2.3 + '@img/sharp-libvips-linux-x64': 1.2.3 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.3 + '@img/sharp-libvips-linuxmusl-x64': 1.2.3 + '@img/sharp-linux-arm': 0.34.4 + '@img/sharp-linux-arm64': 0.34.4 + '@img/sharp-linux-ppc64': 0.34.4 + '@img/sharp-linux-s390x': 0.34.4 + '@img/sharp-linux-x64': 0.34.4 + '@img/sharp-linuxmusl-arm64': 0.34.4 + '@img/sharp-linuxmusl-x64': 0.34.4 + '@img/sharp-wasm32': 0.34.4 + '@img/sharp-win32-arm64': 0.34.4 + '@img/sharp-win32-ia32': 0.34.4 + '@img/sharp-win32-x64': 0.34.4 + dev: false + optional: true + /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -4337,6 +6431,46 @@ packages: resolution: {integrity: sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==} dev: false + /side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + dev: true + + /side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + dev: true + + /side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + dev: true + + /side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + dev: true + /siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} dev: true @@ -4363,7 +6497,6 @@ packages: /source-map-js@1.2.0: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} - dev: true /source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} @@ -4385,6 +6518,10 @@ packages: resolution: {integrity: sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==} engines: {node: '>=12'} + /stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + dev: true + /stable@0.1.8: resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' @@ -4397,12 +6534,92 @@ packages: resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} dev: true + /stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + dev: true + + /string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + dev: true + + /string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + dev: true + + /string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.0 + dev: true + + /string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + dev: true + + /string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + dev: true + + /string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + dev: true + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: true + /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -4412,6 +6629,23 @@ packages: resolution: {integrity: sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA==} dev: false + /styled-jsx@5.1.6(react@19.1.0): + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + dependencies: + client-only: 0.0.1 + react: 19.1.0 + dev: false + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -4427,7 +6661,6 @@ packages: /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - dev: false /suspense@0.0.38(react-dom@0.0.0-experimental-247738465-20240130)(react@0.0.0-experimental-247738465-20240130): resolution: {integrity: sha512-0u82Snn5MUjMRULeio/OJDcR8DoI032aGw+x2WHFgs3d5zPxMqGOlkEXrsFuYpN3fL4fukaNmOspZVUcJJ5Kmg==} @@ -4554,6 +6787,15 @@ packages: punycode: 2.3.1 dev: true + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + dev: true + /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true @@ -4561,6 +6803,9 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + /tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + /tsutils@3.21.0(typescript@5.8.3): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -4582,11 +6827,66 @@ packages: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} + /typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + dev: true + + /typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + dev: true + + /typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + dev: true + + /typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + dev: true + /typescript@5.8.3: resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} hasBin: true + /unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + dev: true + /undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -4595,6 +6895,33 @@ packages: engines: {node: '>= 10.0.0'} dev: false + /unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + requiresBuild: true + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + dev: true + /update-browserslist-db@1.0.11(browserslist@4.21.10): resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==} hasBin: true @@ -4778,6 +7105,59 @@ packages: webidl-conversions: 7.0.0 dev: true + /which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + dev: true + + /which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + dev: true + + /which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + dev: true + + /which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + dev: true + /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index eccc335f9..2937eb6b8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,2 +1,3 @@ packages: - - 'packages/**' \ No newline at end of file + - 'packages/**' + - 'examples/**' \ No newline at end of file From 66e84b9137caa40a4b01eca96f45cd243d57029a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sun, 19 Oct 2025 19:50:30 +0200 Subject: [PATCH 02/27] feat: init persistence support for resizable panels for ssr --- .../nextjs/src/app/examples/nested/page.tsx | 80 ----------- examples/nextjs/src/app/page.tsx | 3 +- packages/react-resizable-panels/src/Panel.ts | 19 ++- .../react-resizable-panels/src/PanelGroup.ts | 3 + .../src/PanelGroupContext.ts | 1 + .../src/PersistScript.tsx | 130 ++++++++++++++++++ .../react-resizable-panels/src/constants.ts | 1 + packages/react-resizable-panels/src/index.ts | 2 + .../src/utils/computePanelFlexBoxStyle.ts | 7 +- .../src/utils/serialization.ts | 9 +- 10 files changed, 168 insertions(+), 87 deletions(-) delete mode 100644 examples/nextjs/src/app/examples/nested/page.tsx create mode 100644 packages/react-resizable-panels/src/PersistScript.tsx diff --git a/examples/nextjs/src/app/examples/nested/page.tsx b/examples/nextjs/src/app/examples/nested/page.tsx deleted file mode 100644 index 3ef78fa6f..000000000 --- a/examples/nextjs/src/app/examples/nested/page.tsx +++ /dev/null @@ -1,80 +0,0 @@ -"use client"; - -import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; -import styles from "@/components/shared.module.css"; - -export default function NestedExample() { - return ( -
-

Nested Resizable Panels

-

- This example shows nested groups. Click near the intersection of two - groups to resize in multiple directions at once. -

- -
- - -
left
-
- - - - -
top
-
- - - - -
inner left
-
- - -
inner right
-
-
-
-
-
- - -
right
-
-
-
- -
-

Features:

-
    -
  • Three levels of nested panel groups
  • -
  • Horizontal and vertical resize handles
  • -
  • Persistent layout state using localStorage
  • -
  • Minimum size constraints on panels
  • -
  • Responsive design with proper CSS variables
  • -
- - -
-
- ); -} diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index 830d7de75..fb9eaaaf2 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { Panel, PanelGroup } from "react-resizable-panels"; +import { Panel, PanelGroup, PersistScript } from "react-resizable-panels"; import { ResizeHandle } from "@/components/ResizeHandle"; import styles from "@/components/shared.module.css"; @@ -35,6 +35,7 @@ export default function Home() { diff --git a/packages/react-resizable-panels/src/Panel.ts b/packages/react-resizable-panels/src/Panel.ts index 639ce3bb7..be4ae4b36 100644 --- a/packages/react-resizable-panels/src/Panel.ts +++ b/packages/react-resizable-panels/src/Panel.ts @@ -2,6 +2,7 @@ import { isBrowser } from "#is-browser"; import { isDevelopment } from "#is-development"; import { ForwardedRef, + Fragment, HTMLAttributes, PropsWithChildren, ReactElement, @@ -15,6 +16,8 @@ import { PanelGroupContext } from "./PanelGroupContext"; import { DATA_ATTRIBUTES } from "./constants"; import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect"; import useUniqueId from "./hooks/useUniqueId"; +import { panelSizeCssVar } from "./utils/computePanelFlexBoxStyle"; +import { PersistScript } from "./PersistScript"; export type PanelOnCollapse = () => void; export type PanelOnExpand = () => void; @@ -102,6 +105,7 @@ export function PanelWithForwardedRef({ } const { + autoSaveId, collapsePanel, expandPanel, getPanelSize, @@ -234,7 +238,15 @@ export function PanelWithForwardedRef({ return createElement(Type, { ...rest, - children, + children: createElement( + Fragment, + null, + createElement(PersistScript, { + autoSaveId, + panelId, + }), + children + ), className: classNameFromProps, id: panelId, style: { @@ -247,7 +259,10 @@ export function PanelWithForwardedRef({ [DATA_ATTRIBUTES.panel]: "", [DATA_ATTRIBUTES.panelCollapsible]: collapsible || undefined, [DATA_ATTRIBUTES.panelId]: panelId, - [DATA_ATTRIBUTES.panelSize]: parseFloat("" + style.flexGrow).toFixed(1), + [DATA_ATTRIBUTES.panelSize]: parseFloat( + "" + (style as any)[panelSizeCssVar] + ).toFixed(1), + suppressHydrationWarning: true, }); } diff --git a/packages/react-resizable-panels/src/PanelGroup.ts b/packages/react-resizable-panels/src/PanelGroup.ts index 23c627985..a89af601e 100644 --- a/packages/react-resizable-panels/src/PanelGroup.ts +++ b/packages/react-resizable-panels/src/PanelGroup.ts @@ -909,6 +909,7 @@ function PanelGroupWithForwardedRef({ stopDragging, unregisterPanel, panelGroupElement: panelGroupElementRef.current, + autoSaveId, }) satisfies TPanelGroupContext, [ collapsePanel, @@ -927,6 +928,7 @@ function PanelGroupWithForwardedRef({ startDragging, stopDragging, unregisterPanel, + autoSaveId, ] ); @@ -957,6 +959,7 @@ function PanelGroupWithForwardedRef({ [DATA_ATTRIBUTES.group]: "", [DATA_ATTRIBUTES.groupDirection]: direction, [DATA_ATTRIBUTES.groupId]: groupId, + [DATA_ATTRIBUTES.autoSaveId]: autoSaveId || undefined, }) ); } diff --git a/packages/react-resizable-panels/src/PanelGroupContext.ts b/packages/react-resizable-panels/src/PanelGroupContext.ts index 6c51b70ff..2fcdcaae9 100644 --- a/packages/react-resizable-panels/src/PanelGroupContext.ts +++ b/packages/react-resizable-panels/src/PanelGroupContext.ts @@ -36,6 +36,7 @@ export type TPanelGroupContext = { stopDragging: () => void; unregisterPanel: (panelData: PanelData) => void; panelGroupElement: ParentNode | null; + autoSaveId?: string | null; }; export const PanelGroupContext = createContext(null); diff --git a/packages/react-resizable-panels/src/PersistScript.tsx b/packages/react-resizable-panels/src/PersistScript.tsx new file mode 100644 index 000000000..f8a59d263 --- /dev/null +++ b/packages/react-resizable-panels/src/PersistScript.tsx @@ -0,0 +1,130 @@ +import { createElement } from "react"; +import { + DEFAULT_STORAGE_KEY_PREFIX, + SerializedPanelGroupState, +} from "./utils/serialization"; +import { DATA_ATTRIBUTES } from "./constants"; + +function persist( + /** + * autoSaveId + */ + i: string | null, + /** + * storageKeyPrefix + */ + k?: string, + /** + * autoSaveId data attribute + */ + v?: string, + /** + * panel data attribute + */ + w?: string, + /** + * panelId + */ + x?: string +) { + let p: SerializedPanelGroupState | null = null; + try { + const r = i && localStorage.getItem(`${k}:${i}`); + if (r) { + const d = JSON.parse(r); + if (typeof d === "object" && d != null) { + p = d as SerializedPanelGroupState; + } + } + } catch (error) {} + + console.log("PersistScript loaded", p); + + let layout = null; + if (p && typeof p === "object") { + const keys = Object.keys(p); + if (keys.length > 0) { + const firstKey = keys[0]; + const stateData = p[firstKey]; + if (stateData && typeof stateData === "object" && "layout" in stateData) { + layout = stateData.layout; + } + } + } + + console.log("Extracted layout:", layout); + + // // find element with data attribute + // const panelGroupElement = document.querySelector( + // `[${v}="${i}"]` + // ) as HTMLElement | null; + + // console.log("Found panel group element:", panelGroupElement); + + // // find immediate children with data-panel attributes + // const panelElements = panelGroupElement?.querySelectorAll( + // `:scope > [${w}=""]` + // ) as NodeListOf; + + // console.log("Found panel elements:", panelElements); + + // // go through panelElements and add css variable --panel-size + // if (panelElements && layout && Array.isArray(layout)) { + // panelElements.forEach((el, index) => { + // const size = layout ? layout[index] : null; + // if (size != null) { + // el.style.setProperty("--panel-size", `${size}%`); + // console.log( + // `Set --panel-size for panel ${index} to ${size}%`, + // el, + // size + // ); + // } + // }); + // } + + // find the panel with the panelId + const panel = document.querySelector( + `[data-panel-id="${x}"]` + ) as HTMLElement | null; + + console.log("Found panel element:", panel); + + // set the --panel-size css variable on the panel + if (panel && layout) { + panel.style.setProperty("--panel-size-x", `${layout}%`); + console.log(`Set --panel-size for panel ${x} to ${layout}%`, panel); + } +} + +const PERSIST_STR = persist.toString(); + +export interface PersistScriptProps { + nonce?: string; + autoSaveId?: string | null; + storageKeyPrefix?: string; + panelId?: string; +} + +export const PersistScript = ({ + nonce, + autoSaveId, + storageKeyPrefix = DEFAULT_STORAGE_KEY_PREFIX, + panelId, +}: PersistScriptProps) => { + const scriptArgs = JSON.stringify([ + autoSaveId, + storageKeyPrefix, + DATA_ATTRIBUTES.autoSaveId, + DATA_ATTRIBUTES.panel, + panelId, + ]).slice(1, -1); + + return createElement("script", { + suppressHydrationWarning: true, + dangerouslySetInnerHTML: { + __html: `(${PERSIST_STR})(${scriptArgs})`, + }, + nonce, + }); +}; diff --git a/packages/react-resizable-panels/src/constants.ts b/packages/react-resizable-panels/src/constants.ts index eec9d6dad..7a396435a 100644 --- a/packages/react-resizable-panels/src/constants.ts +++ b/packages/react-resizable-panels/src/constants.ts @@ -11,6 +11,7 @@ export const DATA_ATTRIBUTES = { resizeHandleEnabled: "data-panel-resize-handle-enabled", resizeHandleId: "data-panel-resize-handle-id", resizeHandleState: "data-resize-handle-state", + autoSaveId: "data-panel-auto-save-id", } as const; export const PRECISION = 10; diff --git a/packages/react-resizable-panels/src/index.ts b/packages/react-resizable-panels/src/index.ts index 7357a828e..2511c809b 100644 --- a/packages/react-resizable-panels/src/index.ts +++ b/packages/react-resizable-panels/src/index.ts @@ -1,6 +1,7 @@ import { Panel } from "./Panel"; import { PanelGroup } from "./PanelGroup"; import { PanelResizeHandle } from "./PanelResizeHandle"; +import { PersistScript } from "./PersistScript"; import { DATA_ATTRIBUTES } from "./constants"; import { usePanelGroupContext } from "./hooks/usePanelGroupContext"; import { assert } from "./utils/assert"; @@ -59,6 +60,7 @@ export { Panel, PanelGroup, PanelResizeHandle, + PersistScript, // Hooks usePanelGroupContext, diff --git a/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.ts b/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.ts index f89ec1cb1..7735f7781 100644 --- a/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.ts +++ b/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.ts @@ -4,6 +4,8 @@ import { PanelData } from "../Panel"; import { DragState } from "../PanelGroupContext"; import { CSSProperties } from "react"; +export const panelSizeCssVar = "--panel-size"; + // the % of the group's overall space this panel should occupy. export function computePanelFlexBoxStyle({ defaultSize, @@ -35,8 +37,9 @@ export function computePanelFlexBoxStyle({ } return { + [panelSizeCssVar]: flexGrow, flexBasis: 0, - flexGrow, + flexGrow: `var(${panelSizeCssVar})`, flexShrink: 1, // Without this, Panel sizes may be unintentionally overridden by their content @@ -45,5 +48,5 @@ export function computePanelFlexBoxStyle({ // Disable pointer events inside of a panel during resize // This avoid edge cases like nested iframes pointerEvents: dragState !== null ? "none" : undefined, - }; + } as CSSProperties; } diff --git a/packages/react-resizable-panels/src/utils/serialization.ts b/packages/react-resizable-panels/src/utils/serialization.ts index bbb3b8def..f8a611e69 100644 --- a/packages/react-resizable-panels/src/utils/serialization.ts +++ b/packages/react-resizable-panels/src/utils/serialization.ts @@ -12,8 +12,13 @@ export type SerializedPanelGroupState = { [panelIds: string]: PanelConfigurationState; }; -function getPanelGroupKey(autoSaveId: string): string { - return `react-resizable-panels:${autoSaveId}`; +export const DEFAULT_STORAGE_KEY_PREFIX = "react-resizable-panels"; + +export function getPanelGroupKey( + autoSaveId: string, + prefix = DEFAULT_STORAGE_KEY_PREFIX +): string { + return `${prefix}:${autoSaveId}`; } // Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic) From 95f2e5b812fd0eb2def52b58dbd098b8c70466f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sun, 19 Oct 2025 20:13:29 +0200 Subject: [PATCH 03/27] feat: update panel layout handling to support new format with panel IDs --- .../src/PersistScript.tsx | 48 +++----------- .../src/utils/serialization.ts | 65 +++++++++++++++++-- 2 files changed, 70 insertions(+), 43 deletions(-) diff --git a/packages/react-resizable-panels/src/PersistScript.tsx b/packages/react-resizable-panels/src/PersistScript.tsx index f8a59d263..e7833b96e 100644 --- a/packages/react-resizable-panels/src/PersistScript.tsx +++ b/packages/react-resizable-panels/src/PersistScript.tsx @@ -1,6 +1,7 @@ import { createElement } from "react"; import { DEFAULT_STORAGE_KEY_PREFIX, + PanelLayoutItem, SerializedPanelGroupState, } from "./utils/serialization"; import { DATA_ATTRIBUTES } from "./constants"; @@ -38,62 +39,31 @@ function persist( } } catch (error) {} - console.log("PersistScript loaded", p); - - let layout = null; + let layout: PanelLayoutItem[] | null = null; if (p && typeof p === "object") { const keys = Object.keys(p); if (keys.length > 0) { const firstKey = keys[0]; - const stateData = p[firstKey]; + const stateData = firstKey ? p[firstKey] : null; if (stateData && typeof stateData === "object" && "layout" in stateData) { layout = stateData.layout; } } } - console.log("Extracted layout:", layout); - - // // find element with data attribute - // const panelGroupElement = document.querySelector( - // `[${v}="${i}"]` - // ) as HTMLElement | null; - - // console.log("Found panel group element:", panelGroupElement); - - // // find immediate children with data-panel attributes - // const panelElements = panelGroupElement?.querySelectorAll( - // `:scope > [${w}=""]` - // ) as NodeListOf; - - // console.log("Found panel elements:", panelElements); - - // // go through panelElements and add css variable --panel-size - // if (panelElements && layout && Array.isArray(layout)) { - // panelElements.forEach((el, index) => { - // const size = layout ? layout[index] : null; - // if (size != null) { - // el.style.setProperty("--panel-size", `${size}%`); - // console.log( - // `Set --panel-size for panel ${index} to ${size}%`, - // el, - // size - // ); - // } - // }); - // } - // find the panel with the panelId const panel = document.querySelector( `[data-panel-id="${x}"]` ) as HTMLElement | null; - console.log("Found panel element:", panel); - // set the --panel-size css variable on the panel if (panel && layout) { - panel.style.setProperty("--panel-size-x", `${layout}%`); - console.log(`Set --panel-size for panel ${x} to ${layout}%`, panel); + // find element in layout by panelId + const item = layout.find((item) => item.panelId === x); + if (item) { + panel.style.setProperty("--panel-size", `${item.size}%`); + console.log(`Set --panel-size for panel ${x} to ${item.size}%`, panel); + } } } diff --git a/packages/react-resizable-panels/src/utils/serialization.ts b/packages/react-resizable-panels/src/utils/serialization.ts index f8a611e69..f767d2fd0 100644 --- a/packages/react-resizable-panels/src/utils/serialization.ts +++ b/packages/react-resizable-panels/src/utils/serialization.ts @@ -1,11 +1,16 @@ import { PanelData } from "../Panel"; import { PanelGroupStorage } from "../PanelGroup"; +export type PanelLayoutItem = { + panelId: string; + size: number; +}; + export type PanelConfigurationState = { expandToSizes: { [panelId: string]: number; }; - layout: number[]; + layout: PanelLayoutItem[]; }; export type SerializedPanelGroupState = { @@ -63,10 +68,55 @@ export function loadPanelGroupState( autoSaveId: string, panels: PanelData[], storage: PanelGroupStorage -): PanelConfigurationState | null { +): { layout: number[]; expandToSizes: Record } | null { const state = loadSerializedPanelGroupState(autoSaveId, storage) ?? {}; const panelKey = getPanelKey(panels); - return state[panelKey] ?? null; + const savedState = state[panelKey]; + + if (!savedState) { + return null; + } + + // Handle both old format (number[]) and new format (PanelLayoutItem[]) + let layout: number[]; + if (Array.isArray(savedState.layout)) { + if ( + savedState.layout.length > 0 && + typeof savedState.layout[0] === "object" && + savedState.layout[0] !== null && + "panelId" in savedState.layout[0] + ) { + // New format: PanelLayoutItem[] + const layoutWithIds = savedState.layout as PanelLayoutItem[]; + + // Create a map of panelId to value for quick lookup + const panelIdToValue = new Map(); + layoutWithIds.forEach((item) => { + panelIdToValue.set(item.panelId, item.size); + }); + + // Map the layout to match current panel order + layout = panels.map((panel) => panelIdToValue.get(panel.id) || 0); + + // If we don't have values for all panels, fall back to null + if ( + layout.some((size) => size === 0) && + layoutWithIds.length !== panels.length + ) { + return null; + } + } else { + // Old format: number[] - need to cast through unknown to handle type mismatch + layout = savedState.layout as unknown as number[]; + } + } else { + return null; + } + + return { + layout, + expandToSizes: savedState.expandToSizes || {}, + }; } export function savePanelGroupState( @@ -79,9 +129,16 @@ export function savePanelGroupState( const panelGroupKey = getPanelGroupKey(autoSaveId); const panelKey = getPanelKey(panels); const state = loadSerializedPanelGroupState(autoSaveId, storage) ?? {}; + + // Convert number[] layout to PanelLayoutItem[] with panel IDs + const layoutWithIds: PanelLayoutItem[] = sizes.map((size, index) => ({ + panelId: panels[index]?.id || `panel-${index}`, + size, + })); + state[panelKey] = { expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()), - layout: sizes, + layout: layoutWithIds, }; try { From 907947e49f21c7016fce1063d25c1d7ef16777e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sun, 19 Oct 2025 20:44:17 +0200 Subject: [PATCH 04/27] feat: add panel order attribute for improved layout management --- examples/nextjs/src/app/page.tsx | 23 ++++++++++++++----- packages/react-resizable-panels/src/Panel.ts | 2 ++ .../src/PersistScript.tsx | 14 +++++------ .../react-resizable-panels/src/constants.ts | 1 + .../src/utils/serialization.ts | 15 ++++++------ 5 files changed, 34 insertions(+), 21 deletions(-) diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index fb9eaaaf2..00bbb5d9e 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -14,11 +14,16 @@ export default function Home() { autoSaveId="persistence1" direction="horizontal" > - +
left
- +
top
- + - +
left
- +
right
@@ -50,7 +56,12 @@ export default function Home() {
- +
right
diff --git a/packages/react-resizable-panels/src/Panel.ts b/packages/react-resizable-panels/src/Panel.ts index be4ae4b36..d2e94126b 100644 --- a/packages/react-resizable-panels/src/Panel.ts +++ b/packages/react-resizable-panels/src/Panel.ts @@ -259,6 +259,8 @@ export function PanelWithForwardedRef({ [DATA_ATTRIBUTES.panel]: "", [DATA_ATTRIBUTES.panelCollapsible]: collapsible || undefined, [DATA_ATTRIBUTES.panelId]: panelId, + [DATA_ATTRIBUTES.panelOrder]: + order !== undefined ? order.toString() : undefined, [DATA_ATTRIBUTES.panelSize]: parseFloat( "" + (style as any)[panelSizeCssVar] ).toFixed(1), diff --git a/packages/react-resizable-panels/src/PersistScript.tsx b/packages/react-resizable-panels/src/PersistScript.tsx index e7833b96e..35fc62535 100644 --- a/packages/react-resizable-panels/src/PersistScript.tsx +++ b/packages/react-resizable-panels/src/PersistScript.tsx @@ -51,18 +51,18 @@ function persist( } } - // find the panel with the panelId const panel = document.querySelector( `[data-panel-id="${x}"]` ) as HTMLElement | null; - // set the --panel-size css variable on the panel if (panel && layout) { - // find element in layout by panelId - const item = layout.find((item) => item.panelId === x); - if (item) { - panel.style.setProperty("--panel-size", `${item.size}%`); - console.log(`Set --panel-size for panel ${x} to ${item.size}%`, panel); + const panelOrderAttr = panel.getAttribute("data-panel-order"); + if (panelOrderAttr) { + const panelOrder = parseInt(panelOrderAttr, 10); + const item = layout.find((item) => item.order === panelOrder); + if (item) { + panel.style.setProperty("--panel-size", `${item.size}`); + } } } } diff --git a/packages/react-resizable-panels/src/constants.ts b/packages/react-resizable-panels/src/constants.ts index 7a396435a..9d1b9e122 100644 --- a/packages/react-resizable-panels/src/constants.ts +++ b/packages/react-resizable-panels/src/constants.ts @@ -5,6 +5,7 @@ export const DATA_ATTRIBUTES = { panel: "data-panel", panelCollapsible: "data-panel-collapsible", panelId: "data-panel-id", + panelOrder: "data-panel-order", panelSize: "data-panel-size", resizeHandle: "data-resize-handle", resizeHandleActive: "data-resize-handle-active", diff --git a/packages/react-resizable-panels/src/utils/serialization.ts b/packages/react-resizable-panels/src/utils/serialization.ts index f767d2fd0..85bf2c2a8 100644 --- a/packages/react-resizable-panels/src/utils/serialization.ts +++ b/packages/react-resizable-panels/src/utils/serialization.ts @@ -2,7 +2,7 @@ import { PanelData } from "../Panel"; import { PanelGroupStorage } from "../PanelGroup"; export type PanelLayoutItem = { - panelId: string; + order: number; size: number; }; @@ -84,19 +84,19 @@ export function loadPanelGroupState( savedState.layout.length > 0 && typeof savedState.layout[0] === "object" && savedState.layout[0] !== null && - "panelId" in savedState.layout[0] + "order" in savedState.layout[0] ) { // New format: PanelLayoutItem[] const layoutWithIds = savedState.layout as PanelLayoutItem[]; - // Create a map of panelId to value for quick lookup - const panelIdToValue = new Map(); + // Create a map of order to size for quick lookup + const orderToValue = new Map(); layoutWithIds.forEach((item) => { - panelIdToValue.set(item.panelId, item.size); + orderToValue.set(item.order, item.size); }); // Map the layout to match current panel order - layout = panels.map((panel) => panelIdToValue.get(panel.id) || 0); + layout = panels.map((panel) => orderToValue.get(panel.order ?? 0) || 0); // If we don't have values for all panels, fall back to null if ( @@ -130,9 +130,8 @@ export function savePanelGroupState( const panelKey = getPanelKey(panels); const state = loadSerializedPanelGroupState(autoSaveId, storage) ?? {}; - // Convert number[] layout to PanelLayoutItem[] with panel IDs const layoutWithIds: PanelLayoutItem[] = sizes.map((size, index) => ({ - panelId: panels[index]?.id || `panel-${index}`, + order: panels[index]?.order ?? index, size, })); From 67e15a27e11f97f4ec130e5ca0bcc17cc0b47917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sun, 19 Oct 2025 21:09:31 +0200 Subject: [PATCH 05/27] feat: enhance persistence logic for panel layout with new data attributes and improved state handling --- packages/react-resizable-panels/src/Panel.ts | 12 ++-- .../src/PersistScript.tsx | 65 ++++++++----------- .../src/utils/serialization.ts | 5 -- 3 files changed, 36 insertions(+), 46 deletions(-) diff --git a/packages/react-resizable-panels/src/Panel.ts b/packages/react-resizable-panels/src/Panel.ts index d2e94126b..e1dcf5e71 100644 --- a/packages/react-resizable-panels/src/Panel.ts +++ b/packages/react-resizable-panels/src/Panel.ts @@ -241,10 +241,12 @@ export function PanelWithForwardedRef({ children: createElement( Fragment, null, - createElement(PersistScript, { - autoSaveId, - panelId, - }), + autoSaveId + ? createElement(PersistScript, { + autoSaveId, + panelId, + }) + : null, children ), className: classNameFromProps, @@ -264,6 +266,8 @@ export function PanelWithForwardedRef({ [DATA_ATTRIBUTES.panelSize]: parseFloat( "" + (style as any)[panelSizeCssVar] ).toFixed(1), + + // TODO: find a way to avoid suppressHydrationWarning globally, maybe add CSS variable to the body, but then variable should contain groupId and order, e.g --panel-size-- suppressHydrationWarning: true, }); } diff --git a/packages/react-resizable-panels/src/PersistScript.tsx b/packages/react-resizable-panels/src/PersistScript.tsx index 35fc62535..8152ce27e 100644 --- a/packages/react-resizable-panels/src/PersistScript.tsx +++ b/packages/react-resizable-panels/src/PersistScript.tsx @@ -5,46 +5,34 @@ import { SerializedPanelGroupState, } from "./utils/serialization"; import { DATA_ATTRIBUTES } from "./constants"; +import { panelSizeCssVar } from "./utils/computePanelFlexBoxStyle"; function persist( - /** - * autoSaveId - */ - i: string | null, - /** - * storageKeyPrefix - */ - k?: string, - /** - * autoSaveId data attribute - */ - v?: string, - /** - * panel data attribute - */ - w?: string, - /** - * panelId - */ - x?: string + autoSaveId: string | null, + storageKeyPrefix: string, + panelIdDataAttributeName: string, + panelOrderDataAttributeName: string, + panelId: string, + panelSizeCssVar: string ) { - let p: SerializedPanelGroupState | null = null; + let state: SerializedPanelGroupState | null = null; try { - const r = i && localStorage.getItem(`${k}:${i}`); - if (r) { - const d = JSON.parse(r); - if (typeof d === "object" && d != null) { - p = d as SerializedPanelGroupState; + const rawState = + autoSaveId && localStorage.getItem(`${storageKeyPrefix}:${autoSaveId}`); + if (rawState) { + const parsedState = JSON.parse(rawState); + if (typeof parsedState === "object" && parsedState != null) { + state = parsedState as SerializedPanelGroupState; } } } catch (error) {} let layout: PanelLayoutItem[] | null = null; - if (p && typeof p === "object") { - const keys = Object.keys(p); + if (state && typeof state === "object") { + const keys = Object.keys(state); if (keys.length > 0) { const firstKey = keys[0]; - const stateData = firstKey ? p[firstKey] : null; + const stateData = firstKey ? state[firstKey] : null; if (stateData && typeof stateData === "object" && "layout" in stateData) { layout = stateData.layout; } @@ -52,16 +40,18 @@ function persist( } const panel = document.querySelector( - `[data-panel-id="${x}"]` + `[${panelIdDataAttributeName}="${panelId}"]` ) as HTMLElement | null; if (panel && layout) { - const panelOrderAttr = panel.getAttribute("data-panel-order"); + const panelOrderAttr = panel.getAttribute( + panelOrderDataAttributeName || "" + ); if (panelOrderAttr) { const panelOrder = parseInt(panelOrderAttr, 10); const item = layout.find((item) => item.order === panelOrder); if (item) { - panel.style.setProperty("--panel-size", `${item.size}`); + panel.style.setProperty(panelSizeCssVar, `${item.size}`); } } } @@ -70,10 +60,10 @@ function persist( const PERSIST_STR = persist.toString(); export interface PersistScriptProps { - nonce?: string; - autoSaveId?: string | null; + panelId: string; + autoSaveId: string | null; storageKeyPrefix?: string; - panelId?: string; + nonce?: string; } export const PersistScript = ({ @@ -85,9 +75,10 @@ export const PersistScript = ({ const scriptArgs = JSON.stringify([ autoSaveId, storageKeyPrefix, - DATA_ATTRIBUTES.autoSaveId, - DATA_ATTRIBUTES.panel, + DATA_ATTRIBUTES.panelId, + DATA_ATTRIBUTES.panelOrder, panelId, + panelSizeCssVar, ]).slice(1, -1); return createElement("script", { diff --git a/packages/react-resizable-panels/src/utils/serialization.ts b/packages/react-resizable-panels/src/utils/serialization.ts index 85bf2c2a8..7422cc8a5 100644 --- a/packages/react-resizable-panels/src/utils/serialization.ts +++ b/packages/react-resizable-panels/src/utils/serialization.ts @@ -86,19 +86,15 @@ export function loadPanelGroupState( savedState.layout[0] !== null && "order" in savedState.layout[0] ) { - // New format: PanelLayoutItem[] const layoutWithIds = savedState.layout as PanelLayoutItem[]; - // Create a map of order to size for quick lookup const orderToValue = new Map(); layoutWithIds.forEach((item) => { orderToValue.set(item.order, item.size); }); - // Map the layout to match current panel order layout = panels.map((panel) => orderToValue.get(panel.order ?? 0) || 0); - // If we don't have values for all panels, fall back to null if ( layout.some((size) => size === 0) && layoutWithIds.length !== panels.length @@ -106,7 +102,6 @@ export function loadPanelGroupState( return null; } } else { - // Old format: number[] - need to cast through unknown to handle type mismatch layout = savedState.layout as unknown as number[]; } } else { From 8d5120d97ba2afbc74473280e872d740ebe8d4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sun, 19 Oct 2025 21:46:44 +0200 Subject: [PATCH 06/27] feat: improve persistence logic by adding early return for null state --- packages/react-resizable-panels/src/PersistScript.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/react-resizable-panels/src/PersistScript.tsx b/packages/react-resizable-panels/src/PersistScript.tsx index 8152ce27e..26075b41a 100644 --- a/packages/react-resizable-panels/src/PersistScript.tsx +++ b/packages/react-resizable-panels/src/PersistScript.tsx @@ -27,6 +27,10 @@ function persist( } } catch (error) {} + if (!state) { + return; + } + let layout: PanelLayoutItem[] | null = null; if (state && typeof state === "object") { const keys = Object.keys(state); From 7907c0a0c3c52311d08f6736aebd4495555966f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sun, 19 Oct 2025 21:46:52 +0200 Subject: [PATCH 07/27] feat: update panel default sizes for improved layout consistency --- examples/nextjs/src/app/page.tsx | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index 00bbb5d9e..9309af5a1 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -23,7 +23,12 @@ export default function Home() {
left
- + top - + - +
left
- +
right
From d52f7f0d2c73a3b5e865e9783539304a65b4ff86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Wed, 22 Oct 2025 21:59:26 +0200 Subject: [PATCH 08/27] feat: rename PersistScript with PanelPersistScript and make it opt-in --- examples/nextjs/src/app/page.tsx | 22 +++++++++++++++---- packages/react-resizable-panels/src/Panel.ts | 14 +----------- ...rsistScript.tsx => PanelPersistScript.tsx} | 2 +- packages/react-resizable-panels/src/index.ts | 4 ++-- 4 files changed, 22 insertions(+), 20 deletions(-) rename packages/react-resizable-panels/src/{PersistScript.tsx => PanelPersistScript.tsx} (98%) diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index 9309af5a1..7fa619747 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { Panel, PanelGroup, PersistScript } from "react-resizable-panels"; +import { Panel, PanelGroup, PanelPersistScript } from "react-resizable-panels"; import { ResizeHandle } from "@/components/ResizeHandle"; import styles from "@/components/shared.module.css"; @@ -11,7 +11,7 @@ export default function Home() {
+
left
@@ -28,10 +30,12 @@ export default function Home() { minSize={35} defaultSize={60} order={2} + id="l1:middle" > + +
top
@@ -48,10 +54,12 @@ export default function Home() { defaultSize={65} minSize={10} order={2} + id="l2:bottom" > + +
left
@@ -68,7 +78,9 @@ export default function Home() { defaultSize={50} minSize={10} order={2} + id="l3:right" > +
right
@@ -81,7 +93,9 @@ export default function Home() { defaultSize={20} minSize={10} order={3} + id="l1:right" > +
right
diff --git a/packages/react-resizable-panels/src/Panel.ts b/packages/react-resizable-panels/src/Panel.ts index e1dcf5e71..f9869b5b7 100644 --- a/packages/react-resizable-panels/src/Panel.ts +++ b/packages/react-resizable-panels/src/Panel.ts @@ -2,7 +2,6 @@ import { isBrowser } from "#is-browser"; import { isDevelopment } from "#is-development"; import { ForwardedRef, - Fragment, HTMLAttributes, PropsWithChildren, ReactElement, @@ -17,7 +16,6 @@ import { DATA_ATTRIBUTES } from "./constants"; import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect"; import useUniqueId from "./hooks/useUniqueId"; import { panelSizeCssVar } from "./utils/computePanelFlexBoxStyle"; -import { PersistScript } from "./PersistScript"; export type PanelOnCollapse = () => void; export type PanelOnExpand = () => void; @@ -238,17 +236,7 @@ export function PanelWithForwardedRef({ return createElement(Type, { ...rest, - children: createElement( - Fragment, - null, - autoSaveId - ? createElement(PersistScript, { - autoSaveId, - panelId, - }) - : null, - children - ), + children, className: classNameFromProps, id: panelId, style: { diff --git a/packages/react-resizable-panels/src/PersistScript.tsx b/packages/react-resizable-panels/src/PanelPersistScript.tsx similarity index 98% rename from packages/react-resizable-panels/src/PersistScript.tsx rename to packages/react-resizable-panels/src/PanelPersistScript.tsx index 26075b41a..ee7f83390 100644 --- a/packages/react-resizable-panels/src/PersistScript.tsx +++ b/packages/react-resizable-panels/src/PanelPersistScript.tsx @@ -70,7 +70,7 @@ export interface PersistScriptProps { nonce?: string; } -export const PersistScript = ({ +export const PanelPersistScript = ({ nonce, autoSaveId, storageKeyPrefix = DEFAULT_STORAGE_KEY_PREFIX, diff --git a/packages/react-resizable-panels/src/index.ts b/packages/react-resizable-panels/src/index.ts index 2511c809b..b8da5c01a 100644 --- a/packages/react-resizable-panels/src/index.ts +++ b/packages/react-resizable-panels/src/index.ts @@ -1,7 +1,7 @@ import { Panel } from "./Panel"; import { PanelGroup } from "./PanelGroup"; import { PanelResizeHandle } from "./PanelResizeHandle"; -import { PersistScript } from "./PersistScript"; +import { PanelPersistScript } from "./PanelPersistScript"; import { DATA_ATTRIBUTES } from "./constants"; import { usePanelGroupContext } from "./hooks/usePanelGroupContext"; import { assert } from "./utils/assert"; @@ -60,7 +60,7 @@ export { Panel, PanelGroup, PanelResizeHandle, - PersistScript, + PanelPersistScript, // Hooks usePanelGroupContext, From ea6270a8a95e754b088c19e07f9cdd940bd5ab7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Wed, 22 Oct 2025 22:47:17 +0200 Subject: [PATCH 09/27] feat: refactor panel order handling and improve serialization tests --- examples/nextjs/src/app/page.tsx | 4 +- packages/react-resizable-panels/src/Panel.ts | 1 - .../utils/computePanelFlexBoxStyle.test.ts | 15 +- .../src/utils/serialization.test.ts | 370 ++++++++++++++++++ .../src/utils/serialization.ts | 10 +- 5 files changed, 387 insertions(+), 13 deletions(-) create mode 100644 packages/react-resizable-panels/src/utils/serialization.test.ts diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index 7fa619747..327b56d7a 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -18,7 +18,7 @@ export default function Home() { className={styles.PanelRow} defaultSize={20} minSize={10} - order={1} + // order={1} id="l1:left" > @@ -29,7 +29,7 @@ export default function Home() { className={styles.PanelRow} minSize={35} defaultSize={60} - order={2} + // order={2} id="l1:middle" > diff --git a/packages/react-resizable-panels/src/Panel.ts b/packages/react-resizable-panels/src/Panel.ts index f9869b5b7..a9dfb1ad9 100644 --- a/packages/react-resizable-panels/src/Panel.ts +++ b/packages/react-resizable-panels/src/Panel.ts @@ -103,7 +103,6 @@ export function PanelWithForwardedRef({ } const { - autoSaveId, collapsePanel, expandPanel, getPanelSize, diff --git a/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.test.ts b/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.test.ts index bbbd04bcb..ff0372294 100644 --- a/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.test.ts +++ b/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.test.ts @@ -30,8 +30,9 @@ describe("computePanelFlexBoxStyle", () => { }) ).toMatchInlineSnapshot(` { + "--panel-size": "0.12", "flexBasis": 0, - "flexGrow": "0.12", + "flexGrow": "var(--panel-size)", "flexShrink": 1, "overflow": "hidden", "pointerEvents": undefined, @@ -51,8 +52,9 @@ describe("computePanelFlexBoxStyle", () => { }) ).toMatchInlineSnapshot(` { + "--panel-size": "1", "flexBasis": 0, - "flexGrow": "1", + "flexGrow": "var(--panel-size)", "flexShrink": 1, "overflow": "hidden", "pointerEvents": undefined, @@ -75,8 +77,9 @@ describe("computePanelFlexBoxStyle", () => { }) ).toMatchInlineSnapshot(` { + "--panel-size": "0.25", "flexBasis": 0, - "flexGrow": "0.25", + "flexGrow": "var(--panel-size)", "flexShrink": 1, "overflow": "hidden", "pointerEvents": undefined, @@ -94,8 +97,9 @@ describe("computePanelFlexBoxStyle", () => { }) ).toMatchInlineSnapshot(` { + "--panel-size": "0.58", "flexBasis": 0, - "flexGrow": "0.58", + "flexGrow": "var(--panel-size)", "flexShrink": 1, "overflow": "hidden", "pointerEvents": undefined, @@ -113,8 +117,9 @@ describe("computePanelFlexBoxStyle", () => { }) ).toMatchInlineSnapshot(` { + "--panel-size": "0.17", "flexBasis": 0, - "flexGrow": "0.17", + "flexGrow": "var(--panel-size)", "flexShrink": 1, "overflow": "hidden", "pointerEvents": undefined, diff --git a/packages/react-resizable-panels/src/utils/serialization.test.ts b/packages/react-resizable-panels/src/utils/serialization.test.ts new file mode 100644 index 000000000..918284c26 --- /dev/null +++ b/packages/react-resizable-panels/src/utils/serialization.test.ts @@ -0,0 +1,370 @@ +import { describe, expect, test, beforeEach } from "vitest"; +import { + loadPanelGroupState, + savePanelGroupState, + getPanelGroupKey, +} from "./serialization"; +import { PanelData } from "../Panel"; + +class MockStorage { + private data: Map = new Map(); + + getItem(key: string): string | null { + return this.data.get(key) ?? null; + } + + setItem(key: string, value: string): void { + this.data.set(key, value); + } + + removeItem(key: string): void { + this.data.delete(key); + } + + clear(): void { + this.data.clear(); + } +} + +describe("serialization", () => { + let storage: MockStorage; + + beforeEach(() => { + storage = new MockStorage(); + }); + + describe("getPanelGroupKey", () => { + test("should generate correct storage key with default prefix", () => { + expect(getPanelGroupKey("my-group")).toBe( + "react-resizable-panels:my-group" + ); + }); + + test("should generate correct storage key with custom prefix", () => { + expect(getPanelGroupKey("my-group", "custom-prefix")).toBe( + "custom-prefix:my-group" + ); + }); + }); + + describe("savePanelGroupState and loadPanelGroupState", () => { + const createPanelData = ( + id: string, + idIsFromProps: boolean, + order?: number, + minSize?: number + ): PanelData => ({ + callbacks: {}, + constraints: { minSize }, + id, + idIsFromProps, + order, + }); + + test("should save and load panel state with new format (with order)", () => { + const panels: PanelData[] = [ + createPanelData("left", true, 1, 10), + createPanelData("right", true, 2, 10), + ]; + + const sizes = [42.7459658713, 57.2540341287]; + const panelSizesBeforeCollapse = new Map(); + + savePanelGroupState( + "test-group", + panels, + panelSizesBeforeCollapse, + sizes, + storage + ); + + const loaded = loadPanelGroupState("test-group", panels, storage); + + expect(loaded).not.toBeNull(); + if (loaded) { + expect(loaded.layout).toEqual(sizes); + expect(loaded.expandToSizes).toEqual({}); + } + }); + + test("should save and load panel state with expandToSizes", () => { + const panels: PanelData[] = [ + createPanelData("panel1", true, 1, 10), + createPanelData("panel2", true, 2, 10), + ]; + + const sizes = [50, 50]; + const panelSizesBeforeCollapse = new Map([ + ["panel1", 60], + ["panel2", 40], + ]); + + savePanelGroupState( + "test-group", + panels, + panelSizesBeforeCollapse, + sizes, + storage + ); + + const loaded = loadPanelGroupState("test-group", panels, storage); + + expect(loaded).not.toBeNull(); + if (loaded) { + expect(loaded.layout).toEqual(sizes); + expect(loaded.expandToSizes).toEqual({ + panel1: 60, + panel2: 40, + }); + } + }); + + test("should handle old format from localStorage (number array)", () => { + const panels: PanelData[] = [ + createPanelData("p1", false, undefined, 10), + createPanelData("p2", false, undefined, 10), + createPanelData("p3", false, undefined, 10), + ]; + + // Simulate old format in localStorage + const oldFormatData = { + '{"minSize":10},{"minSize":10},{"minSize":10}': { + expandToSizes: {}, + layout: [20.6563247098, 35.1228707735, 44.2208045167], + }, + }; + + const storageKey = getPanelGroupKey("test-group"); + storage.setItem(storageKey, JSON.stringify(oldFormatData)); + + const loaded = loadPanelGroupState("test-group", panels, storage); + + expect(loaded).not.toBeNull(); + if (loaded) { + expect(loaded.layout).toEqual([ + 20.6563247098, 35.1228707735, 44.2208045167, + ]); + expect(loaded.expandToSizes).toEqual({}); + } + }); + + test("should handle new format from localStorage (with order)", () => { + const panels: PanelData[] = [ + createPanelData("left", true, 1, 10), + createPanelData("right", true, 2, 10), + ]; + + // Simulate new format in localStorage + const newFormatData = { + "left,right": { + expandToSizes: {}, + layout: [ + { order: 1, size: 42.7459658713 }, + { order: 2, size: 57.2540341287 }, + ], + }, + }; + + const storageKey = getPanelGroupKey("test-group"); + storage.setItem(storageKey, JSON.stringify(newFormatData)); + + const loaded = loadPanelGroupState("test-group", panels, storage); + + expect(loaded).not.toBeNull(); + if (loaded) { + expect(loaded.layout).toEqual([42.7459658713, 57.2540341287]); + expect(loaded.expandToSizes).toEqual({}); + } + }); + + test("should work with panels without order (backwards compatibility)", () => { + const panels: PanelData[] = [ + createPanelData("panel1", true, undefined, 10), + createPanelData("panel2", true, undefined, 10), + ]; + + const sizes = [30, 70]; + const panelSizesBeforeCollapse = new Map(); + + savePanelGroupState( + "test-group", + panels, + panelSizesBeforeCollapse, + sizes, + storage + ); + + const loaded = loadPanelGroupState("test-group", panels, storage); + + expect(loaded).not.toBeNull(); + if (loaded) { + expect(loaded.layout).toEqual(sizes); + } + }); + + test("should handle mixed panels (some with order, some without)", () => { + const panels: PanelData[] = [ + createPanelData("panel1", true, 1, 10), + createPanelData("panel2", true, undefined, 10), + createPanelData("panel3", true, 3, 10), + ]; + + const sizes = [25, 35, 40]; + const panelSizesBeforeCollapse = new Map(); + + savePanelGroupState( + "test-group", + panels, + panelSizesBeforeCollapse, + sizes, + storage + ); + + const loaded = loadPanelGroupState("test-group", panels, storage); + + expect(loaded).not.toBeNull(); + if (loaded) { + expect(loaded.layout).toEqual(sizes); + } + }); + + test("should return null for non-existent autoSaveId", () => { + const panels: PanelData[] = [createPanelData("panel1", true, 1, 10)]; + + const loaded = loadPanelGroupState("non-existent", panels, storage); + + expect(loaded).toBeNull(); + }); + + test("should return null for mismatched panel configuration", () => { + const panels1: PanelData[] = [ + createPanelData("panel1", true, 1, 10), + createPanelData("panel2", true, 2, 10), + ]; + + savePanelGroupState("test-group", panels1, new Map(), [50, 50], storage); + + // Different panel configuration + const panels2: PanelData[] = [ + createPanelData("panel1", true, 1, 10), + createPanelData("panel3", true, 2, 10), // Different panel + ]; + + const loaded = loadPanelGroupState("test-group", panels2, storage); + + expect(loaded).toBeNull(); + }); + + test("should handle panel order changes correctly with new format", () => { + const panels: PanelData[] = [ + createPanelData("left", true, 1, 10), + createPanelData("middle", true, 2, 10), + createPanelData("right", true, 3, 10), + ]; + + const sizes = [20, 30, 50]; + savePanelGroupState("test-group", panels, new Map(), sizes, storage); + + // Reorder panels + const reorderedPanels: PanelData[] = [ + createPanelData("right", true, 3, 10), + createPanelData("left", true, 1, 10), + createPanelData("middle", true, 2, 10), + ]; + + const loaded = loadPanelGroupState( + "test-group", + reorderedPanels, + storage + ); + + expect(loaded).not.toBeNull(); + if (loaded) { + // Should map to the correct order based on order property + expect(loaded.layout).toEqual([50, 20, 30]); + } + }); + + test("should handle auto-generated IDs with order", () => { + const panels: PanelData[] = [ + createPanelData("auto-id-1", false, 1, 15), + createPanelData("auto-id-2", false, 2, 15), + ]; + + const sizes = [45, 55]; + savePanelGroupState("test-group", panels, new Map(), sizes, storage); + + const loaded = loadPanelGroupState("test-group", panels, storage); + + expect(loaded).not.toBeNull(); + if (loaded) { + expect(loaded.layout).toEqual(sizes); + } + }); + + test("should handle auto-generated IDs without order (old behavior)", () => { + const panels: PanelData[] = [ + createPanelData("auto-id-1", false, undefined, 15), + createPanelData("auto-id-2", false, undefined, 15), + ]; + + const sizes = [45, 55]; + savePanelGroupState("test-group", panels, new Map(), sizes, storage); + + const loaded = loadPanelGroupState("test-group", panels, storage); + + expect(loaded).not.toBeNull(); + if (loaded) { + expect(loaded.layout).toEqual(sizes); + } + }); + + test("should handle invalid JSON gracefully", () => { + const storageKey = getPanelGroupKey("test-group"); + storage.setItem(storageKey, "invalid json{"); + + const panels: PanelData[] = [createPanelData("panel1", true, 1, 10)]; + const loaded = loadPanelGroupState("test-group", panels, storage); + + expect(loaded).toBeNull(); + }); + + test("should handle non-object JSON gracefully", () => { + const storageKey = getPanelGroupKey("test-group"); + storage.setItem(storageKey, JSON.stringify("string value")); + + const panels: PanelData[] = [createPanelData("panel1", true, 1, 10)]; + const loaded = loadPanelGroupState("test-group", panels, storage); + + expect(loaded).toBeNull(); + }); + + test("should preserve multiple panel group states", () => { + const panels1: PanelData[] = [ + createPanelData("group1-panel1", true, 1, 10), + createPanelData("group1-panel2", true, 2, 10), + ]; + + const panels2: PanelData[] = [ + createPanelData("group2-panel1", true, 1, 10), + createPanelData("group2-panel2", true, 2, 10), + ]; + + savePanelGroupState("group1", panels1, new Map(), [30, 70], storage); + savePanelGroupState("group2", panels2, new Map(), [60, 40], storage); + + const loaded1 = loadPanelGroupState("group1", panels1, storage); + const loaded2 = loadPanelGroupState("group2", panels2, storage); + + expect(loaded1).not.toBeNull(); + if (loaded1) { + expect(loaded1.layout).toEqual([30, 70]); + } + + expect(loaded2).not.toBeNull(); + if (loaded2) { + expect(loaded2.layout).toEqual([60, 40]); + } + }); + }); +}); diff --git a/packages/react-resizable-panels/src/utils/serialization.ts b/packages/react-resizable-panels/src/utils/serialization.ts index 7422cc8a5..cc5e9d1af 100644 --- a/packages/react-resizable-panels/src/utils/serialization.ts +++ b/packages/react-resizable-panels/src/utils/serialization.ts @@ -86,10 +86,10 @@ export function loadPanelGroupState( savedState.layout[0] !== null && "order" in savedState.layout[0] ) { - const layoutWithIds = savedState.layout as PanelLayoutItem[]; + const panelLayoutItems = savedState.layout as PanelLayoutItem[]; const orderToValue = new Map(); - layoutWithIds.forEach((item) => { + panelLayoutItems.forEach((item) => { orderToValue.set(item.order, item.size); }); @@ -97,7 +97,7 @@ export function loadPanelGroupState( if ( layout.some((size) => size === 0) && - layoutWithIds.length !== panels.length + panelLayoutItems.length !== panels.length ) { return null; } @@ -125,14 +125,14 @@ export function savePanelGroupState( const panelKey = getPanelKey(panels); const state = loadSerializedPanelGroupState(autoSaveId, storage) ?? {}; - const layoutWithIds: PanelLayoutItem[] = sizes.map((size, index) => ({ + const layout: PanelLayoutItem[] = sizes.map((size, index) => ({ order: panels[index]?.order ?? index, size, })); state[panelKey] = { expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()), - layout: layoutWithIds, + layout, }; try { From 650b30906608f826e8aaf369df75cc9956924c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Wed, 22 Oct 2025 23:03:54 +0200 Subject: [PATCH 10/27] feat: enhance panel order handling in load and save functions for better layout consistency --- .../src/utils/serialization.ts | 52 +++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/packages/react-resizable-panels/src/utils/serialization.ts b/packages/react-resizable-panels/src/utils/serialization.ts index cc5e9d1af..1387ebf2b 100644 --- a/packages/react-resizable-panels/src/utils/serialization.ts +++ b/packages/react-resizable-panels/src/utils/serialization.ts @@ -93,7 +93,29 @@ export function loadPanelGroupState( orderToValue.set(item.order, item.size); }); - layout = panels.map((panel) => orderToValue.get(panel.order ?? 0) || 0); + const explicitOrders = new Set(); + panels.forEach((panel) => { + if (panel.order !== undefined) { + explicitOrders.add(panel.order); + } + }); + + let nextAvailableOrder = 0; + layout = panels.map((panel) => { + let order: number; + + if (panel.order !== undefined) { + order = panel.order; + } else { + while (explicitOrders.has(nextAvailableOrder)) { + nextAvailableOrder++; + } + order = nextAvailableOrder; + nextAvailableOrder++; + } + + return orderToValue.get(order) || 0; + }); if ( layout.some((size) => size === 0) && @@ -125,10 +147,30 @@ export function savePanelGroupState( const panelKey = getPanelKey(panels); const state = loadSerializedPanelGroupState(autoSaveId, storage) ?? {}; - const layout: PanelLayoutItem[] = sizes.map((size, index) => ({ - order: panels[index]?.order ?? index, - size, - })); + const explicitOrders = new Set(); + panels.forEach((panel) => { + if (panel.order !== undefined) { + explicitOrders.add(panel.order); + } + }); + + let nextAvailableOrder = 0; + const layout: PanelLayoutItem[] = sizes.map((size, index) => { + const panel = panels[index]; + let order: number; + + if (panel?.order !== undefined) { + order = panel.order; + } else { + while (explicitOrders.has(nextAvailableOrder)) { + nextAvailableOrder++; + } + order = nextAvailableOrder; + nextAvailableOrder++; + } + + return { order, size }; + }); state[panelKey] = { expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()), From fabff8f6dbf2c818d9f2af7d186ece2f7c002f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Thu, 23 Oct 2025 22:20:39 +0200 Subject: [PATCH 11/27] feat: add playwright test for panel persist script --- examples/nextjs/src/app/page.tsx | 4 +- .../nextjs/tests/PanelPersistScript.spec.ts | 34 +++++++++++++ .../package.json | 1 + .../playwright.config.ts | 50 +++++++++++++++++-- 4 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 examples/nextjs/tests/PanelPersistScript.spec.ts diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index 327b56d7a..7fa619747 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -18,7 +18,7 @@ export default function Home() { className={styles.PanelRow} defaultSize={20} minSize={10} - // order={1} + order={1} id="l1:left" > @@ -29,7 +29,7 @@ export default function Home() { className={styles.PanelRow} minSize={35} defaultSize={60} - // order={2} + order={2} id="l1:middle" > diff --git a/examples/nextjs/tests/PanelPersistScript.spec.ts b/examples/nextjs/tests/PanelPersistScript.spec.ts new file mode 100644 index 000000000..1640dc12c --- /dev/null +++ b/examples/nextjs/tests/PanelPersistScript.spec.ts @@ -0,0 +1,34 @@ +import { expect, test } from "@playwright/test"; + +test.describe("Panel Persist Script", () => { + test("should load and persist panel layouts using localStorage on the initial server side render", async ({ + page, + }) => { + await page.goto("http://localhost:3000"); + + await page.evaluate(() => { + localStorage.setItem( + "react-resizable-panels:l1", + `{"l1:left,l1:middle,l1:right":{"expandToSizes":{},"layout":[{"order":1,"size":29.5488424113},{"order":2,"size":58.984252547},{"order":3,"size":11.4669050417}]}}` + ); + }); + + await page.goto("http://localhost:3000"); + + const leftPanelSize = await page.$eval("#l1\\:left", (el) => + getComputedStyle(el).getPropertyValue("--panel-size").trim() + ); + const middlePanelSize = await page.$eval("#l1\\:middle", (el) => + getComputedStyle(el).getPropertyValue("--panel-size").trim() + ); + const rightPanelSize = await page.$eval("#l1\\:right", (el) => + getComputedStyle(el).getPropertyValue("--panel-size").trim() + ); + + expect(middlePanelSize).toBe("58.984"); + expect(rightPanelSize).toBe("11.467"); + expect(leftPanelSize).toBe("29.549"); + + await page.close(); + }); +}); diff --git a/packages/react-resizable-panels-website/package.json b/packages/react-resizable-panels-website/package.json index 3c6f6ba71..d2c04401d 100644 --- a/packages/react-resizable-panels-website/package.json +++ b/packages/react-resizable-panels-website/package.json @@ -10,6 +10,7 @@ "kill-port": "kill-port ${PORT:-1234}", "test:e2e": "playwright test", "test:e2e:debug": "DEBUG=true playwright test", + "test:e2e:nextjs": "PROJECT=nextjs playwright test", "watch": "parcel \"index.html\"" }, "dependencies": { diff --git a/packages/react-resizable-panels-website/playwright.config.ts b/packages/react-resizable-panels-website/playwright.config.ts index 486245298..2fab75957 100644 --- a/packages/react-resizable-panels-website/playwright.config.ts +++ b/packages/react-resizable-panels-website/playwright.config.ts @@ -1,8 +1,52 @@ import type { PlaywrightTestConfig } from "@playwright/test"; +declare global { + namespace NodeJS { + interface ProcessEnv { + PROJECT: Projects; + } + } +} + +const CI = !!process.env.CI; const { DEBUG } = process.env; +const project = process.env.PROJECT || "website"; + +type InferServer = Exclude ? U : T, undefined>; +type WebServer = InferServer; +type TestDir = InferServer; +type Projects = "website" | "nextjs"; + +function getProjectServer(): WebServer { + const projects: Record = { + website: { + cwd: "./", + command: "npm run watch", + url: "http://localhost:1234", + reuseExistingServer: !CI, + }, + nextjs: { + cwd: "../../examples/nextjs", + command: "pnpm run dev", + url: "http://localhost:3000", + reuseExistingServer: !CI, + }, + }; + + return projects[project]; +} + +function getTestDir(): TestDir { + const projects: Record = { + website: "./", + nextjs: "../../examples/nextjs/tests", + }; + + return projects[project]; +} const config: PlaywrightTestConfig = { + testDir: getTestDir(), use: { browserName: "chromium", headless: true, @@ -10,11 +54,7 @@ const config: PlaywrightTestConfig = { ignoreHTTPSErrors: true, video: "on-first-retry", }, - webServer: { - command: "npm run watch", - reuseExistingServer: true, - url: "http://localhost:1234", - }, + webServer: getProjectServer(), timeout: 60_000, }; From 11e1f42569c30b5efa5e818f6cc6ab000c02ff02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Thu, 23 Oct 2025 22:37:43 +0200 Subject: [PATCH 12/27] feat: add PanelPersistScript readme --- packages/react-resizable-panels/README.md | 54 +++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/packages/react-resizable-panels/README.md b/packages/react-resizable-panels/README.md index d63429df0..004accb02 100644 --- a/packages/react-resizable-panels/README.md +++ b/packages/react-resizable-panels/README.md @@ -95,6 +95,14 @@ import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; | `style` | `?CSSProperties` | CSS style to attach to root element | | `tagName` | `?string = "div"` | HTML element tag name for root element | + +### `PanelPersistScript` + +| prop | type | description | +| :----------- | :------------ | :-------------------------------------------------------------------------------------------- | +| `autoSaveId` | `string` | Must match the parent `PanelGroup`'s `autoSaveId` prop | +| `panelId` | `string` | Must match the parent `Panel`'s `id` prop | + --- ## FAQ @@ -180,9 +188,49 @@ Yes. Panel groups with an `autoSaveId` prop will automatically save and restore ### How can I use persistent layouts with SSR? -By default, this library uses `localStorage` to persist layouts. With server rendering, this can cause a flicker when the default layout (rendered on the server) is replaced with the persisted layout (in `localStorage`). The way to avoid this flicker is to also persist the layout with a cookie like so: +By default, this library uses `localStorage` to persist layouts. With server rendering, this can cause a flicker when the default layout (rendered on the server) is replaced with the persisted layout (in `localStorage`). There are two ways to avoid this flicker: + +#### Option 1: Using `PanelPersistScript` + +The `PanelPersistScript` component synchronously applies the persisted layout before React hydration, eliminating layout flicker. + +**Requirements:** + +- `id` and `order` props are **required** on each `Panel` component +- `PanelPersistScript` must be placed as the **first child** of each `Panel` +- `panelId` prop must match the `Panel`'s `id` +- `autoSaveId` prop must match the `PanelGroup`'s `autoSaveId` + +```tsx +"use client"; + +import { Panel, PanelGroup, PanelResizeHandle, PanelPersistScript } from "react-resizable-panels"; + +export function ClientComponent() { + return ( + + + + {/* Panel content */} + + + + + {/* Panel content */} + + + ); +} +``` + +> [!NOTE] +> A working example is available in [`examples/nextjs`](https://github.com/bvaughn/react-resizable-panels/tree/main/examples/nextjs). + +#### Option 2: Cookie-based persistence + +Alternatively, you can persist the layout with cookies and pass it from the server to the client. -#### Server component +**Server component:** ```tsx import ResizablePanels from "@/app/ResizablePanels"; @@ -200,7 +248,7 @@ export function ServerComponent() { } ``` -#### Client component +**Client component:** ```tsx "use client"; From 599ff388f8ce3c9c6cab317cab6e1d715e3b5dc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Fri, 24 Oct 2025 09:28:47 +0200 Subject: [PATCH 13/27] feat: add suppressHydrationWarning prop to Panel components and remove it form the Panel internals --- examples/nextjs/src/app/page.tsx | 7 +++++++ packages/react-resizable-panels/README.md | 7 ++++--- packages/react-resizable-panels/src/Panel.ts | 3 --- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index 7fa619747..9810ad09b 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -20,6 +20,7 @@ export default function Home() { minSize={10} order={1} id="l1:left" + suppressHydrationWarning >
left
@@ -31,6 +32,7 @@ export default function Home() { defaultSize={60} order={2} id="l1:middle" + suppressHydrationWarning >
top
@@ -55,6 +58,7 @@ export default function Home() { minSize={10} order={2} id="l2:bottom" + suppressHydrationWarning >
left
@@ -79,6 +84,7 @@ export default function Home() { minSize={10} order={2} id="l3:right" + suppressHydrationWarning >
right
@@ -94,6 +100,7 @@ export default function Home() { minSize={10} order={3} id="l1:right" + suppressHydrationWarning >
right
diff --git a/packages/react-resizable-panels/README.md b/packages/react-resizable-panels/README.md index 004accb02..58ae7cd07 100644 --- a/packages/react-resizable-panels/README.md +++ b/packages/react-resizable-panels/README.md @@ -200,6 +200,7 @@ The `PanelPersistScript` component synchronously applies the persisted layout be - `PanelPersistScript` must be placed as the **first child** of each `Panel` - `panelId` prop must match the `Panel`'s `id` - `autoSaveId` prop must match the `PanelGroup`'s `autoSaveId` +- `suppressHydrationWarning` prop should be added to `Panel` components that may have different sizes between server and client renders ```tsx "use client"; @@ -208,13 +209,13 @@ import { Panel, PanelGroup, PanelResizeHandle, PanelPersistScript } from "react- export function ClientComponent() { return ( - - + + {/* Panel content */} - + {/* Panel content */} diff --git a/packages/react-resizable-panels/src/Panel.ts b/packages/react-resizable-panels/src/Panel.ts index a9dfb1ad9..9f07e3334 100644 --- a/packages/react-resizable-panels/src/Panel.ts +++ b/packages/react-resizable-panels/src/Panel.ts @@ -253,9 +253,6 @@ export function PanelWithForwardedRef({ [DATA_ATTRIBUTES.panelSize]: parseFloat( "" + (style as any)[panelSizeCssVar] ).toFixed(1), - - // TODO: find a way to avoid suppressHydrationWarning globally, maybe add CSS variable to the body, but then variable should contain groupId and order, e.g --panel-size-- - suppressHydrationWarning: true, }); } From 2ad53d406b629d1cad0ca95aaf5ec4a40e67faff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Fri, 24 Oct 2025 23:47:07 +0200 Subject: [PATCH 14/27] feat: minify the script --- packages/react-resizable-panels/package.json | 7 + .../react-resizable-panels/scripts/README.md | 21 + .../react-resizable-panels/scripts/minify.ts | 199 ++ .../src/PanelPersistScript.tsx | 66 +- .../src/scripts/persist.minified.ts | 9 + .../src/scripts/persist.ts | 74 + pnpm-lock.yaml | 1764 +++++++++++++++-- 7 files changed, 1957 insertions(+), 183 deletions(-) create mode 100644 packages/react-resizable-panels/scripts/README.md create mode 100644 packages/react-resizable-panels/scripts/minify.ts create mode 100644 packages/react-resizable-panels/src/scripts/persist.minified.ts create mode 100644 packages/react-resizable-panels/src/scripts/persist.ts diff --git a/packages/react-resizable-panels/package.json b/packages/react-resizable-panels/package.json index 2b21be798..a075d5739 100644 --- a/packages/react-resizable-panels/package.json +++ b/packages/react-resizable-panels/package.json @@ -56,19 +56,26 @@ "clear:builds": "rm -rf ./packages/*/dist", "clear:node_modules": "rm -rf ./node_modules", "lint": "eslint \"src/**/*.{ts,tsx}\"", + "minify:persist": "tsx scripts/minify.ts src/scripts/persist.ts src/scripts/persist.minified.ts", + "prebuild": "pnpm run minify:persist", "test:browser": "vitest", "test:node": "vitest -c vitest.node.config.ts", "watch": "parcel watch --port=2345" }, "devDependencies": { + "@babel/core": "^7.22.0", "@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6", "@babel/plugin-proposal-optional-chaining": "7.21.0", + "@babel/preset-env": "^7.22.0", + "@types/babel__core": "^7.20.0", "@vitest/ui": "^3.1.2", "eslint": "^8.37.0", "eslint-plugin-react-hooks": "^4.6.0", "jsdom": "^26.1.0", "react": "experimental", "react-dom": "experimental", + "terser": "^5.19.0", + "tsx": "^4.7.0", "vitest": "^3.1.2" }, "peerDependencies": { diff --git a/packages/react-resizable-panels/scripts/README.md b/packages/react-resizable-panels/scripts/README.md new file mode 100644 index 000000000..a9e25812d --- /dev/null +++ b/packages/react-resizable-panels/scripts/README.md @@ -0,0 +1,21 @@ +# Build Scripts + +## Files + +### minify.ts +Generic TypeScript minification script that: +1. Accepts input and output file paths as arguments +2. Strips TypeScript types with `@babel/preset-typescript` +3. Transforms with Babel using browser compatibility settings +4. Minifies with Terser +5. Generates output file with minified code + +**Usage:** +```bash +tsx scripts/minify.ts +``` + +**Example:** +```bash +tsx scripts/minify.ts src/scripts/persist.ts src/scripts/persist.minified.ts +``` \ No newline at end of file diff --git a/packages/react-resizable-panels/scripts/minify.ts b/packages/react-resizable-panels/scripts/minify.ts new file mode 100644 index 000000000..78028daa3 --- /dev/null +++ b/packages/react-resizable-panels/scripts/minify.ts @@ -0,0 +1,199 @@ +#!/usr/bin/env node + +/** + * Generic script to minify TypeScript/JavaScript files. + * Strips TypeScript types, transforms with Babel, and minifies with Terser. + * + * Usage: + * tsx scripts/minify.ts + * + * Example: + * tsx scripts/minify.ts src/scripts/persist.ts src/scripts/persist.minified.ts + */ + +import { transformSync, BabelFileResult } from "@babel/core"; +import { + minify, + MinifyOptions as TerserMinifyOptions, + MinifyOutput, +} from "terser"; +import { writeFileSync, readFileSync } from "fs"; +import { fileURLToPath } from "url"; +import { dirname, join, relative, basename } from "path"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +interface MinifyFileOptions { + inputPath: string; + outputPath: string; + removeComments?: boolean; + removeExports?: boolean; +} + +async function minifyFile(options: MinifyFileOptions): Promise { + const { + inputPath, + outputPath, + removeComments = true, + removeExports = true, + } = options; + + const packageRoot = join(__dirname, ".."); + const absoluteInputPath = join(packageRoot, inputPath); + const absoluteOutputPath = join(packageRoot, outputPath); + + console.log("🔨 Minifying:", relative(packageRoot, absoluteInputPath)); + + const sourceContent = readFileSync(absoluteInputPath, "utf-8"); + const isTypeScript = inputPath.endsWith(".ts") || inputPath.endsWith(".tsx"); + + let processedCode = sourceContent; + + if (isTypeScript) { + const typeStripResult: BabelFileResult | null = transformSync( + sourceContent, + { + filename: basename(inputPath), + presets: [ + ["@babel/preset-typescript", { onlyRemoveTypeImports: true }], + ], + } + ); + + if (!typeStripResult || !typeStripResult.code) { + throw new Error("TypeScript stripping failed"); + } + + processedCode = typeStripResult.code; + } + + if (removeComments) { + processedCode = processedCode.replace(/^\/\*\*[\s\S]*?\*\/\s*/gm, ""); // JSDoc + processedCode = processedCode.replace(/\/\/.*$/gm, ""); // Single-line comments + } + + if (removeExports) { + processedCode = processedCode + .replace(/export\s+default\s+/g, "") + .replace(/export\s*{\s*[^}]*\s*};?\s*$/gm, "") + .replace(/export\s+(const|let|var|function|class)\s+/g, "$1 "); + } + + processedCode = processedCode.trim(); + + const babelResult: BabelFileResult | null = transformSync(processedCode, { + presets: [ + [ + "@babel/preset-env", + { + targets: { + chrome: "79", // Match browserslist in package.json + }, + modules: false, + }, + ], + ], + plugins: [ + "@babel/plugin-proposal-nullish-coalescing-operator", + "@babel/plugin-proposal-optional-chaining", + ], + }); + + if (!babelResult || !babelResult.code) { + throw new Error("Babel transformation failed"); + } + + const terserOptions: TerserMinifyOptions = { + compress: { + dead_code: true, + drop_debugger: true, + conditionals: true, + evaluate: true, + booleans: true, + loops: true, + unused: true, + hoist_funs: true, + keep_fargs: false, + hoist_vars: false, + if_return: true, + join_vars: true, + side_effects: true, + }, + mangle: { + toplevel: false, + }, + format: { + comments: false, + preamble: "", + }, + }; + + const minifyResult: MinifyOutput = await minify( + babelResult.code, + terserOptions + ); + + if (!minifyResult || !minifyResult.code) { + throw new Error("Minification failed"); + } + + const outputContent = `// Auto-generated by scripts/minify.ts +// DO NOT EDIT MANUALLY +// Source: ${inputPath} + +/** + * Minified version of ${basename(inputPath)} + * Pre-minified to match browser bundle transformations. + */ +export const MINIFIED_PERSIST = ${JSON.stringify(minifyResult.code)}; +`; + + writeFileSync(absoluteOutputPath, outputContent, "utf-8"); + + console.log("✅ Generated:", relative(packageRoot, absoluteOutputPath)); + console.log("📦 Original size:", sourceContent.length, "bytes"); + console.log("📦 Minified size:", minifyResult.code.length, "bytes"); + console.log( + "📈 Reduction:", + ((1 - minifyResult.code.length / sourceContent.length) * 100).toFixed(1) + + "%" + ); + console.log("\n💡 Preview:"); + console.log(minifyResult.code.substring(0, 200) + "..."); +} + +async function main() { + const args = process.argv.slice(2); + + if (args.length < 2) { + console.error("❌ Usage: tsx scripts/minify.ts "); + console.error("\nExample:"); + console.error( + " tsx scripts/minify.ts src/scripts/persist.ts src/scripts/persist.minified.ts" + ); + process.exit(1); + } + + const inputPath = args[0]; + const outputPath = args[1]; + + if (!inputPath || !outputPath) { + console.error("❌ Both input and output paths are required"); + process.exit(1); + } + + try { + await minifyFile({ + inputPath, + outputPath, + removeComments: true, + removeExports: true, + }); + } catch (err) { + console.error("❌ Error:", err); + process.exit(1); + } +} + +main(); diff --git a/packages/react-resizable-panels/src/PanelPersistScript.tsx b/packages/react-resizable-panels/src/PanelPersistScript.tsx index ee7f83390..5e22940b3 100644 --- a/packages/react-resizable-panels/src/PanelPersistScript.tsx +++ b/packages/react-resizable-panels/src/PanelPersistScript.tsx @@ -1,67 +1,8 @@ import { createElement } from "react"; -import { - DEFAULT_STORAGE_KEY_PREFIX, - PanelLayoutItem, - SerializedPanelGroupState, -} from "./utils/serialization"; +import { DEFAULT_STORAGE_KEY_PREFIX } from "./utils/serialization"; import { DATA_ATTRIBUTES } from "./constants"; import { panelSizeCssVar } from "./utils/computePanelFlexBoxStyle"; - -function persist( - autoSaveId: string | null, - storageKeyPrefix: string, - panelIdDataAttributeName: string, - panelOrderDataAttributeName: string, - panelId: string, - panelSizeCssVar: string -) { - let state: SerializedPanelGroupState | null = null; - try { - const rawState = - autoSaveId && localStorage.getItem(`${storageKeyPrefix}:${autoSaveId}`); - if (rawState) { - const parsedState = JSON.parse(rawState); - if (typeof parsedState === "object" && parsedState != null) { - state = parsedState as SerializedPanelGroupState; - } - } - } catch (error) {} - - if (!state) { - return; - } - - let layout: PanelLayoutItem[] | null = null; - if (state && typeof state === "object") { - const keys = Object.keys(state); - if (keys.length > 0) { - const firstKey = keys[0]; - const stateData = firstKey ? state[firstKey] : null; - if (stateData && typeof stateData === "object" && "layout" in stateData) { - layout = stateData.layout; - } - } - } - - const panel = document.querySelector( - `[${panelIdDataAttributeName}="${panelId}"]` - ) as HTMLElement | null; - - if (panel && layout) { - const panelOrderAttr = panel.getAttribute( - panelOrderDataAttributeName || "" - ); - if (panelOrderAttr) { - const panelOrder = parseInt(panelOrderAttr, 10); - const item = layout.find((item) => item.order === panelOrder); - if (item) { - panel.style.setProperty(panelSizeCssVar, `${item.size}`); - } - } - } -} - -const PERSIST_STR = persist.toString(); +import { MINIFIED_PERSIST } from "./scripts/persist.minified"; export interface PersistScriptProps { panelId: string; @@ -86,9 +27,8 @@ export const PanelPersistScript = ({ ]).slice(1, -1); return createElement("script", { - suppressHydrationWarning: true, dangerouslySetInnerHTML: { - __html: `(${PERSIST_STR})(${scriptArgs})`, + __html: `(${MINIFIED_PERSIST})(${scriptArgs})`, }, nonce, }); diff --git a/packages/react-resizable-panels/src/scripts/persist.minified.ts b/packages/react-resizable-panels/src/scripts/persist.minified.ts new file mode 100644 index 000000000..68d76235e --- /dev/null +++ b/packages/react-resizable-panels/src/scripts/persist.minified.ts @@ -0,0 +1,9 @@ +// Auto-generated by scripts/minify.ts +// DO NOT EDIT MANUALLY +// Source: src/scripts/persist.ts + +/** + * Minified version of persist.ts + * Pre-minified to match browser bundle transformations. + */ +export const MINIFIED_PERSIST = "function persist(t,e,o,n,l,r){let i=null;try{const o=t&&localStorage.getItem(e+\":\"+t);if(o){const t=JSON.parse(o);\"object\"==typeof t&&null!=t&&(i=t)}}catch(t){}if(!i)return;let c=null;if(i&&\"object\"==typeof i){const t=Object.keys(i);if(t.length>0){const e=t[0],o=e?i[e]:null;o&&\"object\"==typeof o&&\"layout\"in o&&(c=o.layout)}}const s=document.querySelector(\"[\"+o+'=\"'+l+'\"]');if(s&&c){const t=s.getAttribute(n||\"\");if(t){const e=parseInt(t,10),o=c.find((function(t){return t.order===e}));o&&s.style.setProperty(r,String(o.size))}}}import{PanelLayoutItem,SerializedPanelGroupState}from\"../utils/serialization\";"; diff --git a/packages/react-resizable-panels/src/scripts/persist.ts b/packages/react-resizable-panels/src/scripts/persist.ts new file mode 100644 index 000000000..8bed24cdb --- /dev/null +++ b/packages/react-resizable-panels/src/scripts/persist.ts @@ -0,0 +1,74 @@ +/** + * The persist function that gets inlined in server-rendered HTML. + * This function restores panel sizes from localStorage before React hydration. + * + * This file is the source of truth for the persist logic. + * It gets minified and transformed by minify-persist.ts during the build. + */ + +import { + PanelLayoutItem, + SerializedPanelGroupState, +} from "../utils/serialization"; + +/** + * Persist function that runs in the browser before React hydration. + * Restores panel sizes from localStorage to prevent layout shift. + */ +function persist( + autoSaveId: string | null, + storageKeyPrefix: string, + panelIdDataAttributeName: string, + panelOrderDataAttributeName: string, + panelId: string, + panelSizeCssVar: string +): void { + let state: SerializedPanelGroupState | null = null; + try { + const rawState = + autoSaveId && localStorage.getItem(storageKeyPrefix + ":" + autoSaveId); + if (rawState) { + const parsedState = JSON.parse(rawState); + if (typeof parsedState === "object" && parsedState != null) { + state = parsedState as SerializedPanelGroupState; + } + } + } catch (error) {} + + if (!state) { + return; + } + + let layout: PanelLayoutItem[] | null = null; + if (state && typeof state === "object") { + const keys = Object.keys(state); + if (keys.length > 0) { + const firstKey = keys[0]; + const stateData = firstKey ? state[firstKey] : null; + if (stateData && typeof stateData === "object" && "layout" in stateData) { + layout = stateData.layout; + } + } + } + + const panel = document.querySelector( + "[" + panelIdDataAttributeName + '="' + panelId + '"]' + ) as HTMLElement | null; + + if (panel && layout) { + const panelOrderAttr = panel.getAttribute( + panelOrderDataAttributeName || "" + ); + if (panelOrderAttr) { + const panelOrder = parseInt(panelOrderAttr, 10); + const item = layout.find(function (item) { + return item.order === panelOrder; + }); + if (item) { + panel.style.setProperty(panelSizeCssVar, String(item.size)); + } + } + } +} + +export { persist }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9251b6aea..fab0fb08c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -109,12 +109,21 @@ importers: packages/react-resizable-panels: devDependencies: + '@babel/core': + specifier: ^7.22.0 + version: 7.22.11 '@babel/plugin-proposal-nullish-coalescing-operator': specifier: 7.18.6 - version: 7.18.6 + version: 7.18.6(@babel/core@7.22.11) '@babel/plugin-proposal-optional-chaining': specifier: 7.21.0 - version: 7.21.0 + version: 7.21.0(@babel/core@7.22.11) + '@babel/preset-env': + specifier: ^7.22.0 + version: 7.28.5(@babel/core@7.22.11) + '@types/babel__core': + specifier: ^7.20.0 + version: 7.20.5 '@vitest/ui': specifier: ^3.1.2 version: 3.1.2(vitest@3.1.2) @@ -133,9 +142,15 @@ importers: react-dom: specifier: experimental version: 0.0.0-experimental-247738465-20240130(react@0.0.0-experimental-247738465-20240130) + terser: + specifier: ^5.19.0 + version: 5.19.2 + tsx: + specifier: ^4.7.0 + version: 4.20.6 vitest: specifier: ^3.1.2 - version: 3.1.2(@types/node@22.15.3)(@vitest/ui@3.1.2)(jsdom@26.1.0) + version: 3.1.2(@types/node@22.15.3)(@vitest/ui@3.1.2)(jsdom@26.1.0)(terser@5.19.2) packages/react-resizable-panels-website: dependencies: @@ -222,10 +237,24 @@ packages: '@babel/highlight': 7.22.20 chalk: 2.4.2 + /@babel/code-frame@7.27.1: + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + dev: true + /@babel/compat-data@7.22.9: resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==} engines: {node: '>=6.9.0'} + /@babel/compat-data@7.28.5: + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/core@7.22.11: resolution: {integrity: sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ==} engines: {node: '>=6.9.0'} @@ -257,11 +286,29 @@ packages: '@jridgewell/trace-mapping': 0.3.19 jsesc: 2.5.2 + /@babel/generator@7.28.5: + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + dev: true + /@babel/helper-annotate-as-pure@7.22.5: resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.0 + '@babel/types': 7.28.5 + dev: true + + /@babel/helper-annotate-as-pure@7.27.3: + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.28.5 dev: true /@babel/helper-compilation-targets@7.22.10: @@ -274,6 +321,17 @@ packages: lru-cache: 5.1.1 semver: 6.3.1 + /@babel/helper-compilation-targets@7.27.2: + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.27.0 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + /@babel/helper-create-class-features-plugin@7.22.10: resolution: {integrity: sha512-5IBb77txKYQPpOEdUdIhBx8VrZyDCQ+H82H0+5dX1TmuscP5vJKEE3cKurjtIw/vFwzbVH48VweE78kVDBrqjA==} engines: {node: '>=6.9.0'} @@ -291,12 +349,53 @@ packages: semver: 6.3.1 dev: true - /@babel/helper-environment-visitor@7.22.20: - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + /@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.22.11): + resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.22.11) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.28.5 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.22.11): + resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-annotate-as-pure': 7.27.3 + regexpu-core: 6.4.0 + semver: 6.3.1 + dev: true + + /@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.22.11): + resolution: {integrity: sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + debug: 4.4.3 + lodash.debounce: 4.0.8 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + dev: true - /@babel/helper-environment-visitor@7.22.5: - resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==} + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} /@babel/helper-function-name@7.22.5: @@ -304,7 +403,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.22.15 - '@babel/types': 7.23.0 + '@babel/types': 7.28.5 dev: true /@babel/helper-function-name@7.23.0: @@ -312,194 +411,1099 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.22.15 - '@babel/types': 7.23.0 + '@babel/types': 7.28.5 + + /@babel/helper-globals@7.28.0: + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + dev: true /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.28.5 + + /@babel/helper-member-expression-to-functions@7.22.5: + resolution: {integrity: sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.28.5 + dev: true + + /@babel/helper-member-expression-to-functions@7.28.5: + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-module-imports@7.22.5: + resolution: {integrity: sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.28.5 + + /@babel/helper-module-imports@7.27.1: + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-module-transforms@7.22.9(@babel/core@7.22.11): + resolution: {integrity: sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.5 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + + /@babel/helper-module-transforms@7.28.3(@babel/core@7.22.11): + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-optimise-call-expression@7.22.5: + resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.28.5 + dev: true + + /@babel/helper-optimise-call-expression@7.27.1: + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.28.5 + dev: true + + /@babel/helper-plugin-utils@7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + engines: {node: '>=6.9.0'} + + /@babel/helper-plugin-utils@7.27.1: + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-wrap-function': 7.28.3 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-replace-supers@7.22.9: + resolution: {integrity: sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.22.5 + '@babel/helper-optimise-call-expression': 7.22.5 + dev: true + + /@babel/helper-replace-supers@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.28.5 + + /@babel/helper-skip-transparent-expression-wrappers@7.22.5: + resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.0 + dev: true + + /@babel/helper-skip-transparent-expression-wrappers@7.27.1: + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.28.5 + + /@babel/helper-string-parser@7.22.5: + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + engines: {node: '>=6.9.0'} + + /@babel/helper-string-parser@7.27.1: + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier@7.28.5: + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-option@7.22.5: + resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-option@7.27.1: + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-wrap-function@7.28.3: + resolution: {integrity: sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helpers@7.23.2: + resolution: {integrity: sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.2 + '@babel/types': 7.23.0 + transitivePeerDependencies: + - supports-color + + /@babel/highlight@7.22.20: + resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + chalk: 2.4.2 + js-tokens: 4.0.0 + + /@babel/parser@7.23.0: + resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==} + engines: {node: '>=6.0.0'} + hasBin: true dependencies: '@babel/types': 7.23.0 - /@babel/helper-member-expression-to-functions@7.22.5: - resolution: {integrity: sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==} + /@babel/parser@7.28.5: + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.28.5 + dev: true + + /@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.22.11): + resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.22.11) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.22.11): + resolution: {integrity: sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.22.11): + resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.11) + dev: true + + /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.22.11): + resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.11) + dev: true + + /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.22.11): + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + dev: true + + /@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-syntax-jsx@7.22.5: + resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.22.11): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.11): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-typescript@7.22.5: + resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.22.11): + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.22.11): + resolution: {integrity: sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.22.11) + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.22.11) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.22.11): + resolution: {integrity: sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.22.11): + resolution: {integrity: sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-classes@7.28.4(@babel/core@7.22.11): + resolution: {integrity: sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-globals': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.22.11) + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/template': 7.27.2 + dev: true + + /@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.22.11): + resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.22.11): + resolution: {integrity: sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.22.11) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.22.11): + resolution: {integrity: sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-for-of@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-function-name@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-literals@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.22.11): + resolution: {integrity: sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-commonjs@7.22.5(@babel/core@7.22.11): + resolution: {integrity: sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-simple-access': 7.22.5 + + /@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.22.11): + resolution: {integrity: sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-new-target@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-object-rest-spread@7.28.4(@babel/core@7.22.11): + resolution: {integrity: sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.22.11) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.22.11) + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-object-super@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/types': 7.23.0 + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.22.11) + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-module-imports@7.22.5: - resolution: {integrity: sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==} + /@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/types': 7.23.0 + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true - /@babel/helper-module-transforms@7.22.9(@babel/core@7.22.11): - resolution: {integrity: sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==} + /@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.22.11): + resolution: {integrity: sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.22.11 - '@babel/helper-environment-visitor': 7.22.5 - '@babel/helper-module-imports': 7.22.5 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + dev: true - /@babel/helper-optimise-call-expression@7.22.5: - resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} + /@babel/plugin-transform-parameters@7.27.7(@babel/core@7.22.11): + resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/types': 7.23.0 + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/helper-plugin-utils@7.22.5: - resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} - engines: {node: '>=6.9.0'} - - /@babel/helper-replace-supers@7.22.9: - resolution: {integrity: sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==} + /@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-member-expression-to-functions': 7.22.5 - '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/core': 7.22.11 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + /@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/types': 7.23.0 + '@babel/core': 7.22.11 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + dev: true - /@babel/helper-skip-transparent-expression-wrappers@7.22.5: - resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} + /@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/types': 7.23.0 + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/helper-split-export-declaration@7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + /@babel/plugin-transform-regenerator@7.28.4(@babel/core@7.22.11): + resolution: {integrity: sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/types': 7.23.0 + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true - /@babel/helper-string-parser@7.22.5: - resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} + /@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + dev: true - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + /@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true - /@babel/helper-validator-option@7.22.5: - resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==} + /@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true - /@babel/helpers@7.23.2: - resolution: {integrity: sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==} + /@babel/plugin-transform-spread@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.2 - '@babel/types': 7.23.0 + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color + dev: true - /@babel/highlight@7.22.20: - resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} + /@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 - - /@babel/parser@7.23.0: - resolution: {integrity: sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.23.0 + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + dev: true - /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6: - resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} + /@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3 + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-proposal-optional-chaining@7.21.0: - resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} + /@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3 + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-syntax-jsx@7.22.5: - resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} + /@babel/plugin-transform-typescript@7.22.10: + resolution: {integrity: sha512-7++c8I/ymsDo4QQBAgbraXLzIM6jmfao11KgIBEYZRReWzNWH9NtNgJcyrZiXsOPh523FQm6LfpLyy/U5fn46A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.22.10 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-typescript': 7.22.5 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3: - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + /@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3: - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + /@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==} + engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.22.11 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-syntax-typescript@7.22.5: - resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} + /@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.22.11 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-modules-commonjs@7.22.5(@babel/core@7.22.11): - resolution: {integrity: sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==} + /@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.22.11): + resolution: {integrity: sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/core': ^7.0.0 dependencies: '@babel/core': 7.22.11 - '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.11) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-simple-access': 7.22.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.22.11) + '@babel/helper-plugin-utils': 7.27.1 + dev: true - /@babel/plugin-transform-typescript@7.22.10: - resolution: {integrity: sha512-7++c8I/ymsDo4QQBAgbraXLzIM6jmfao11KgIBEYZRReWzNWH9NtNgJcyrZiXsOPh523FQm6LfpLyy/U5fn46A==} + /@babel/preset-env@7.28.5(@babel/core@7.22.11): + resolution: {integrity: sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.22.10 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-typescript': 7.22.5 + '@babel/compat-data': 7.28.5 + '@babel/core': 7.22.11 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.22.11) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.22.11) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.22.11) + '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.22.11) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.22.11) + '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.22.11) + '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.22.11) + '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.22.11) + '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.22.11) + '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.22.11) + '@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.22.11) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.22.11) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.22.11) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.22.11) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.22.11) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.22.11) + '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-regenerator': 7.28.4(@babel/core@7.22.11) + '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.22.11) + '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.22.11) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.22.11) + babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.22.11) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.22.11) + babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.22.11) + core-js-compat: 3.46.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.22.11): + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/types': 7.23.0 + esutils: 2.0.3 dev: true /@babel/preset-typescript@7.22.5: @@ -530,6 +1534,15 @@ packages: '@babel/parser': 7.23.0 '@babel/types': 7.23.0 + /@babel/template@7.27.2: + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + dev: true + /@babel/traverse@7.23.2: resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} engines: {node: '>=6.9.0'} @@ -547,6 +1560,21 @@ packages: transitivePeerDependencies: - supports-color + /@babel/traverse@7.28.5: + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/types@7.23.0: resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==} engines: {node: '>=6.9.0'} @@ -555,6 +1583,13 @@ packages: '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 + /@babel/types@7.28.5: + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + /@codemirror/autocomplete@6.9.0(@codemirror/language@6.10.0)(@codemirror/state@6.4.0): resolution: {integrity: sha512-Fbwm0V/Wn3BkEJZRhr0hi5BhCo5a7eBL6LYaliPjOSwCyfOpnjXY59HruSxOUNV+1OYer0Tgx1zRNQttjXyDog==} peerDependencies: @@ -722,6 +1757,15 @@ packages: dev: true optional: true + /@esbuild/aix-ppc64@0.25.11: + resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm64@0.21.5: resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} @@ -731,6 +1775,15 @@ packages: dev: true optional: true + /@esbuild/android-arm64@0.25.11: + resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm@0.21.5: resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} @@ -740,6 +1793,15 @@ packages: dev: true optional: true + /@esbuild/android-arm@0.25.11: + resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-x64@0.21.5: resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} @@ -749,6 +1811,15 @@ packages: dev: true optional: true + /@esbuild/android-x64@0.25.11: + resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-arm64@0.21.5: resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} @@ -758,6 +1829,15 @@ packages: dev: true optional: true + /@esbuild/darwin-arm64@0.25.11: + resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-x64@0.21.5: resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} @@ -767,6 +1847,15 @@ packages: dev: true optional: true + /@esbuild/darwin-x64@0.25.11: + resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-arm64@0.21.5: resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} @@ -776,6 +1865,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-arm64@0.25.11: + resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-x64@0.21.5: resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} @@ -785,6 +1883,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-x64@0.25.11: + resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm64@0.21.5: resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} @@ -794,6 +1901,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm64@0.25.11: + resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm@0.21.5: resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} @@ -803,6 +1919,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm@0.25.11: + resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ia32@0.21.5: resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} @@ -812,6 +1937,15 @@ packages: dev: true optional: true + /@esbuild/linux-ia32@0.25.11: + resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-loong64@0.21.5: resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} @@ -821,6 +1955,15 @@ packages: dev: true optional: true + /@esbuild/linux-loong64@0.25.11: + resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-mips64el@0.21.5: resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} @@ -830,6 +1973,15 @@ packages: dev: true optional: true + /@esbuild/linux-mips64el@0.25.11: + resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ppc64@0.21.5: resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} @@ -839,6 +1991,15 @@ packages: dev: true optional: true + /@esbuild/linux-ppc64@0.25.11: + resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-riscv64@0.21.5: resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} @@ -848,6 +2009,15 @@ packages: dev: true optional: true + /@esbuild/linux-riscv64@0.25.11: + resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-s390x@0.21.5: resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} @@ -857,6 +2027,15 @@ packages: dev: true optional: true + /@esbuild/linux-s390x@0.25.11: + resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-x64@0.21.5: resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} @@ -866,6 +2045,24 @@ packages: dev: true optional: true + /@esbuild/linux-x64@0.25.11: + resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-arm64@0.25.11: + resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/netbsd-x64@0.21.5: resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} @@ -875,6 +2072,24 @@ packages: dev: true optional: true + /@esbuild/netbsd-x64@0.25.11: + resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-arm64@0.25.11: + resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/openbsd-x64@0.21.5: resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} @@ -884,6 +2099,24 @@ packages: dev: true optional: true + /@esbuild/openbsd-x64@0.25.11: + resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openharmony-arm64@0.25.11: + resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + requiresBuild: true + dev: true + optional: true + /@esbuild/sunos-x64@0.21.5: resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} @@ -893,6 +2126,15 @@ packages: dev: true optional: true + /@esbuild/sunos-x64@0.25.11: + resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-arm64@0.21.5: resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} @@ -902,6 +2144,15 @@ packages: dev: true optional: true + /@esbuild/win32-arm64@0.25.11: + resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-ia32@0.21.5: resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} @@ -911,6 +2162,15 @@ packages: dev: true optional: true + /@esbuild/win32-ia32@0.25.11: + resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-x64@0.21.5: resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} @@ -920,6 +2180,15 @@ packages: dev: true optional: true + /@esbuild/win32-x64@0.25.11: + resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.47.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1295,12 +2564,19 @@ packages: dev: false optional: true + /@jridgewell/gen-mapping@0.3.13: + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.31 + dev: true + /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} engines: {node: '>=6.0.0'} dependencies: '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.19 /@jridgewell/resolve-uri@3.1.1: @@ -1316,20 +2592,26 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.19 - dev: false /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: false /@jridgewell/sourcemap-codec@1.5.0: resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - dev: true /@jridgewell/trace-mapping@0.3.19: resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} dependencies: '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 + + /@jridgewell/trace-mapping@0.3.31: + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.5.0 + dev: true /@lezer/common@0.15.12: resolution: {integrity: sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==} @@ -2759,6 +4041,35 @@ packages: dev: true optional: true + /@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + dev: true + + /@types/babel__generator@7.27.0: + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + dependencies: + '@babel/types': 7.28.5 + dev: true + + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + dev: true + + /@types/babel__traverse@7.28.0: + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + dependencies: + '@babel/types': 7.28.5 + dev: true + /@types/estree@0.0.39: resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} dev: false @@ -3238,7 +4549,7 @@ packages: '@vitest/spy': 3.1.2 estree-walker: 3.0.3 magic-string: 0.30.17 - vite: 5.3.5(@types/node@22.15.3) + vite: 5.3.5(@types/node@22.15.3)(terser@5.19.2) dev: true /@vitest/pretty-format@3.1.2: @@ -3280,7 +4591,7 @@ packages: sirv: 3.0.1 tinyglobby: 0.2.13 tinyrainbow: 2.0.0 - vitest: 3.1.2(@types/node@22.15.3)(@vitest/ui@3.1.2)(jsdom@26.1.0) + vitest: 3.1.2(@types/node@22.15.3)(@vitest/ui@3.1.2)(jsdom@26.1.0)(terser@5.19.2) dev: true /@vitest/utils@3.1.2: @@ -3314,12 +4625,12 @@ packages: resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} engines: {node: '>=0.4.0'} hasBin: true + dev: true /acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true - dev: true /agent-base@7.1.3: resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} @@ -3500,6 +4811,42 @@ packages: engines: {node: '>= 0.4'} dev: true + /babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.22.11): + resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/core': 7.22.11 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.22.11) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.22.11): + resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.22.11) + core-js-compat: 3.46.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.22.11): + resolution: {integrity: sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.22.11) + transitivePeerDependencies: + - supports-color + dev: true + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -3508,6 +4855,11 @@ packages: dependencies: safe-buffer: 5.2.1 + /baseline-browser-mapping@2.8.20: + resolution: {integrity: sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==} + hasBin: true + dev: true + /boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -3533,9 +4885,20 @@ packages: node-releases: 2.0.13 update-browserslist-db: 1.0.11(browserslist@4.21.10) + /browserslist@4.27.0: + resolution: {integrity: sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + baseline-browser-mapping: 2.8.20 + caniuse-lite: 1.0.30001751 + electron-to-chromium: 1.5.240 + node-releases: 2.0.26 + update-browserslist-db: 1.1.4(browserslist@4.27.0) + dev: true + /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: false /builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} @@ -3582,7 +4945,6 @@ packages: /caniuse-lite@1.0.30001751: resolution: {integrity: sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==} - dev: false /chai@5.2.0: resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} @@ -3651,7 +5013,6 @@ packages: /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - dev: false /commander@7.2.0: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} @@ -3667,6 +5028,12 @@ packages: /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + /core-js-compat@3.46.0: + resolution: {integrity: sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==} + dependencies: + browserslist: 4.27.0 + dev: true + /cosmiconfig@8.2.0: resolution: {integrity: sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==} engines: {node: '>=14'} @@ -3813,6 +5180,18 @@ packages: dependencies: ms: 2.1.3 + /debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + /decimal.js@10.5.0: resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==} dev: true @@ -3929,6 +5308,10 @@ packages: /electron-to-chromium@1.4.496: resolution: {integrity: sha512-qeXC3Zbykq44RCrBa4kr8v/dWzYJA8rAwpyh9Qd+NKWoJfjG5vvJqy9XOJ9H4P/lqulZBCgUWAYi+FeK5AuJ8g==} + /electron-to-chromium@1.5.240: + resolution: {integrity: sha512-OBwbZjWgrCOH+g6uJsA2/7Twpas2OlepS9uvByJjR2datRDuKGYeD+nP8lBBks2qnB7bGJNHDUx7c/YLaT3QMQ==} + dev: true + /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} dev: true @@ -4118,10 +5501,49 @@ packages: '@esbuild/win32-x64': 0.21.5 dev: true + /esbuild@0.25.11: + resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.11 + '@esbuild/android-arm': 0.25.11 + '@esbuild/android-arm64': 0.25.11 + '@esbuild/android-x64': 0.25.11 + '@esbuild/darwin-arm64': 0.25.11 + '@esbuild/darwin-x64': 0.25.11 + '@esbuild/freebsd-arm64': 0.25.11 + '@esbuild/freebsd-x64': 0.25.11 + '@esbuild/linux-arm': 0.25.11 + '@esbuild/linux-arm64': 0.25.11 + '@esbuild/linux-ia32': 0.25.11 + '@esbuild/linux-loong64': 0.25.11 + '@esbuild/linux-mips64el': 0.25.11 + '@esbuild/linux-ppc64': 0.25.11 + '@esbuild/linux-riscv64': 0.25.11 + '@esbuild/linux-s390x': 0.25.11 + '@esbuild/linux-x64': 0.25.11 + '@esbuild/netbsd-arm64': 0.25.11 + '@esbuild/netbsd-x64': 0.25.11 + '@esbuild/openbsd-arm64': 0.25.11 + '@esbuild/openbsd-x64': 0.25.11 + '@esbuild/openharmony-arm64': 0.25.11 + '@esbuild/sunos-x64': 0.25.11 + '@esbuild/win32-arm64': 0.25.11 + '@esbuild/win32-ia32': 0.25.11 + '@esbuild/win32-x64': 0.25.11 + dev: true + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} + /escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + dev: true + /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -5307,6 +6729,12 @@ packages: engines: {node: '>=4'} hasBin: true + /jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + dev: true + /json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} dev: true @@ -5504,6 +6932,10 @@ packages: p-locate: 5.0.0 dev: true + /lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + dev: true + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -5717,6 +7149,10 @@ packages: /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + /node-releases@2.0.26: + resolution: {integrity: sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==} + dev: true + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -6172,6 +7608,17 @@ packages: which-builtin-type: 1.2.1 dev: true + /regenerate-unicode-properties@10.2.2: + resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} + engines: {node: '>=4'} + dependencies: + regenerate: 1.4.2 + dev: true + + /regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + dev: true + /regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} @@ -6191,6 +7638,29 @@ packages: set-function-name: 2.0.2 dev: true + /regexpu-core@6.4.0: + resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} + engines: {node: '>=4'} + dependencies: + regenerate: 1.4.2 + regenerate-unicode-properties: 10.2.2 + regjsgen: 0.8.0 + regjsparser: 0.13.0 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.2.1 + dev: true + + /regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + dev: true + + /regjsparser@0.13.0: + resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} + hasBin: true + dependencies: + jsesc: 3.1.0 + dev: true + /remove-accents@0.5.0: resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==} dev: false @@ -6208,6 +7678,16 @@ packages: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} dev: true + /resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + /resolve@1.22.4: resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} hasBin: true @@ -6503,7 +7983,6 @@ packages: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - dev: false /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} @@ -6704,10 +8183,9 @@ packages: hasBin: true dependencies: '@jridgewell/source-map': 0.3.5 - acorn: 8.10.0 + acorn: 8.15.0 commander: 2.20.3 source-map-support: 0.5.21 - dev: false /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -6816,6 +8294,17 @@ packages: typescript: 5.8.3 dev: true + /tsx@4.20.6: + resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + engines: {node: '>=18.0.0'} + hasBin: true + dependencies: + esbuild: 0.25.11 + get-tsconfig: 4.12.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -6890,6 +8379,29 @@ packages: /undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + /unicode-canonical-property-names-ecmascript@2.0.1: + resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} + engines: {node: '>=4'} + dev: true + + /unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-property-aliases-ecmascript: 2.2.0 + dev: true + + /unicode-match-property-value-ecmascript@2.2.1: + resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} + engines: {node: '>=4'} + dev: true + + /unicode-property-aliases-ecmascript@2.2.0: + resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} + engines: {node: '>=4'} + dev: true + /universalify@2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} @@ -6932,6 +8444,17 @@ packages: escalade: 3.1.1 picocolors: 1.0.0 + /update-browserslist-db@1.1.4(browserslist@4.27.0): + resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.27.0 + escalade: 3.2.0 + picocolors: 1.1.1 + dev: true + /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: @@ -6946,7 +8469,7 @@ packages: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} dev: false - /vite-node@3.1.2(@types/node@22.15.3): + /vite-node@3.1.2(@types/node@22.15.3)(terser@5.19.2): resolution: {integrity: sha512-/8iMryv46J3aK13iUXsei5G/A3CUlW4665THCPS+K8xAaqrVWiGB4RfXMQXCLjpK9P2eK//BczrVkn5JLAk6DA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true @@ -6955,7 +8478,7 @@ packages: debug: 4.4.0 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 5.3.5(@types/node@22.15.3) + vite: 5.3.5(@types/node@22.15.3)(terser@5.19.2) transitivePeerDependencies: - '@types/node' - less @@ -6967,7 +8490,7 @@ packages: - terser dev: true - /vite@5.3.5(@types/node@22.15.3): + /vite@5.3.5(@types/node@22.15.3)(terser@5.19.2): resolution: {integrity: sha512-MdjglKR6AQXQb9JGiS7Rc2wC6uMjcm7Go/NHNO63EwiJXfuk9PgqiP/n5IDJCziMkfw9n4Ubp7lttNwz+8ZVKA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -6999,11 +8522,12 @@ packages: esbuild: 0.21.5 postcss: 8.4.40 rollup: 4.19.0 + terser: 5.19.2 optionalDependencies: fsevents: 2.3.3 dev: true - /vitest@3.1.2(@types/node@22.15.3)(@vitest/ui@3.1.2)(jsdom@26.1.0): + /vitest@3.1.2(@types/node@22.15.3)(@vitest/ui@3.1.2)(jsdom@26.1.0)(terser@5.19.2): resolution: {integrity: sha512-WaxpJe092ID1C0mr+LH9MmNrhfzi8I65EX/NRU/Ld016KqQNRgxSOlGNP1hHN+a/F8L15Mh8klwaF77zR3GeDQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true @@ -7052,8 +8576,8 @@ packages: tinyglobby: 0.2.13 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 5.3.5(@types/node@22.15.3) - vite-node: 3.1.2(@types/node@22.15.3) + vite: 5.3.5(@types/node@22.15.3)(terser@5.19.2) + vite-node: 3.1.2(@types/node@22.15.3)(terser@5.19.2) why-is-node-running: 2.3.0 transitivePeerDependencies: - less From 2e1769f028072c36a3fef6602507b1c0387afeb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Fri, 24 Oct 2025 23:49:34 +0200 Subject: [PATCH 15/27] feat: change import to type for PanelLayoutItem and SerializedPanelGroupState in persist.ts --- packages/react-resizable-panels/src/scripts/persist.minified.ts | 2 +- packages/react-resizable-panels/src/scripts/persist.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-resizable-panels/src/scripts/persist.minified.ts b/packages/react-resizable-panels/src/scripts/persist.minified.ts index 68d76235e..d084f1194 100644 --- a/packages/react-resizable-panels/src/scripts/persist.minified.ts +++ b/packages/react-resizable-panels/src/scripts/persist.minified.ts @@ -6,4 +6,4 @@ * Minified version of persist.ts * Pre-minified to match browser bundle transformations. */ -export const MINIFIED_PERSIST = "function persist(t,e,o,n,l,r){let i=null;try{const o=t&&localStorage.getItem(e+\":\"+t);if(o){const t=JSON.parse(o);\"object\"==typeof t&&null!=t&&(i=t)}}catch(t){}if(!i)return;let c=null;if(i&&\"object\"==typeof i){const t=Object.keys(i);if(t.length>0){const e=t[0],o=e?i[e]:null;o&&\"object\"==typeof o&&\"layout\"in o&&(c=o.layout)}}const s=document.querySelector(\"[\"+o+'=\"'+l+'\"]');if(s&&c){const t=s.getAttribute(n||\"\");if(t){const e=parseInt(t,10),o=c.find((function(t){return t.order===e}));o&&s.style.setProperty(r,String(o.size))}}}import{PanelLayoutItem,SerializedPanelGroupState}from\"../utils/serialization\";"; +export const MINIFIED_PERSIST = "function persist(t,e,n,o,c,l){let r=null;try{const n=t&&localStorage.getItem(e+\":\"+t);if(n){const t=JSON.parse(n);\"object\"==typeof t&&null!=t&&(r=t)}}catch(t){}if(!r)return;let s=null;if(r&&\"object\"==typeof r){const t=Object.keys(r);if(t.length>0){const e=t[0],n=e?r[e]:null;n&&\"object\"==typeof n&&\"layout\"in n&&(s=n.layout)}}const i=document.querySelector(\"[\"+n+'=\"'+c+'\"]');if(i&&s){const t=i.getAttribute(o||\"\");if(t){const e=parseInt(t,10),n=s.find((function(t){return t.order===e}));n&&i.style.setProperty(l,String(n.size))}}}"; diff --git a/packages/react-resizable-panels/src/scripts/persist.ts b/packages/react-resizable-panels/src/scripts/persist.ts index 8bed24cdb..f12bad85a 100644 --- a/packages/react-resizable-panels/src/scripts/persist.ts +++ b/packages/react-resizable-panels/src/scripts/persist.ts @@ -6,7 +6,7 @@ * It gets minified and transformed by minify-persist.ts during the build. */ -import { +import type { PanelLayoutItem, SerializedPanelGroupState, } from "../utils/serialization"; From 29613a85575909c794fbd3f103fb992d9a874c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sat, 25 Oct 2025 19:32:30 +0200 Subject: [PATCH 16/27] feat: implement useIsSSR hook for server-side rendering detection --- .../src/PanelPersistScript.tsx | 7 +++++++ .../react-resizable-panels/src/hooks/useIsSSR.ts | 14 ++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 packages/react-resizable-panels/src/hooks/useIsSSR.ts diff --git a/packages/react-resizable-panels/src/PanelPersistScript.tsx b/packages/react-resizable-panels/src/PanelPersistScript.tsx index 5e22940b3..ff65ed711 100644 --- a/packages/react-resizable-panels/src/PanelPersistScript.tsx +++ b/packages/react-resizable-panels/src/PanelPersistScript.tsx @@ -3,6 +3,7 @@ import { DEFAULT_STORAGE_KEY_PREFIX } from "./utils/serialization"; import { DATA_ATTRIBUTES } from "./constants"; import { panelSizeCssVar } from "./utils/computePanelFlexBoxStyle"; import { MINIFIED_PERSIST } from "./scripts/persist.minified"; +import { useIsSSR } from "./hooks/useIsSSR"; export interface PersistScriptProps { panelId: string; @@ -17,6 +18,12 @@ export const PanelPersistScript = ({ storageKeyPrefix = DEFAULT_STORAGE_KEY_PREFIX, panelId, }: PersistScriptProps) => { + const isSSR = useIsSSR(); + + if (!isSSR) { + return null; + } + const scriptArgs = JSON.stringify([ autoSaveId, storageKeyPrefix, diff --git a/packages/react-resizable-panels/src/hooks/useIsSSR.ts b/packages/react-resizable-panels/src/hooks/useIsSSR.ts new file mode 100644 index 000000000..dd7f911f6 --- /dev/null +++ b/packages/react-resizable-panels/src/hooks/useIsSSR.ts @@ -0,0 +1,14 @@ +import { useDeferredValue, useSyncExternalStore } from "react"; + +const emptySubscribe = () => () => {}; +const returnFalse = () => false; +const trueOnServerOrHydration = () => true; + +export function useIsSSR() { + const isSSRSync = useSyncExternalStore( + emptySubscribe, + returnFalse, + trueOnServerOrHydration + ); + return useDeferredValue(isSSRSync); +} From 6020a9bd49206330798620f810498a847eafcd04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sat, 25 Oct 2025 19:46:25 +0200 Subject: [PATCH 17/27] chore: update next --- examples/nextjs/package.json | 8 +- examples/nextjs/tsconfig.json | 24 +- pnpm-lock.yaml | 489 ++++++++++++++++++++++++---------- 3 files changed, 373 insertions(+), 148 deletions(-) diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json index e6e68d8ba..18f80d789 100644 --- a/examples/nextjs/package.json +++ b/examples/nextjs/package.json @@ -9,9 +9,9 @@ "lint": "eslint" }, "dependencies": { - "react": "19.1.0", - "react-dom": "19.1.0", - "next": "15.5.6", + "react": "19.2.0", + "react-dom": "19.2.0", + "next": "16.0.0", "react-resizable-panels": "workspace:*" }, "devDependencies": { @@ -20,7 +20,7 @@ "@types/react": "^19", "@types/react-dom": "^19", "eslint": "^9", - "eslint-config-next": "15.5.6", + "eslint-config-next": "16.0.0", "@eslint/eslintrc": "^3" } } diff --git a/examples/nextjs/tsconfig.json b/examples/nextjs/tsconfig.json index c1334095f..b575f7dac 100644 --- a/examples/nextjs/tsconfig.json +++ b/examples/nextjs/tsconfig.json @@ -1,7 +1,11 @@ { "compilerOptions": { "target": "ES2017", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -11,7 +15,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -19,9 +23,19 @@ } ], "paths": { - "@/*": ["./src/*"] + "@/*": [ + "./src/*" + ] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": [ + "node_modules" + ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fab0fb08c..a55fdb85c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -73,14 +73,14 @@ importers: examples/nextjs: dependencies: next: - specifier: 15.5.6 - version: 15.5.6(@playwright/test@1.37.0)(react-dom@19.1.0)(react@19.1.0) + specifier: 16.0.0 + version: 16.0.0(@playwright/test@1.37.0)(react-dom@19.2.0)(react@19.2.0) react: - specifier: 19.1.0 - version: 19.1.0 + specifier: 19.2.0 + version: 19.2.0 react-dom: - specifier: 19.1.0 - version: 19.1.0(react@19.1.0) + specifier: 19.2.0 + version: 19.2.0(react@19.2.0) react-resizable-panels: specifier: workspace:* version: link:../../packages/react-resizable-panels @@ -101,8 +101,8 @@ importers: specifier: ^9 version: 9.38.0 eslint-config-next: - specifier: 15.5.6 - version: 15.5.6(eslint@9.38.0)(typescript@5.8.3) + specifier: 16.0.0 + version: 16.0.0(@typescript-eslint/parser@5.62.0)(eslint@9.38.0)(typescript@5.8.3) typescript: specifier: ^5 version: 5.8.3 @@ -277,6 +277,29 @@ packages: transitivePeerDependencies: - supports-color + /@babel/core@7.28.5: + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/generator@7.23.0: resolution: {integrity: sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==} engines: {node: '>=6.9.0'} @@ -484,6 +507,20 @@ packages: - supports-color dev: true + /@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5): + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/helper-optimise-call-expression@7.22.5: resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} engines: {node: '>=6.9.0'} @@ -621,6 +658,14 @@ packages: transitivePeerDependencies: - supports-color + /@babel/helpers@7.28.4: + resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + dev: true + /@babel/highlight@7.22.20: resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==} engines: {node: '>=6.9.0'} @@ -2199,16 +2244,6 @@ packages: eslint-visitor-keys: 3.4.3 dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@9.38.0): - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - dependencies: - eslint: 9.38.0 - eslint-visitor-keys: 3.4.3 - dev: true - /@eslint-community/eslint-utils@4.9.0(eslint@9.38.0): resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2579,6 +2614,13 @@ packages: '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.19 + /@jridgewell/remapping@2.3.5: + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + dev: true + /@jridgewell/resolve-uri@3.1.1: resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} @@ -2768,18 +2810,18 @@ packages: dev: true optional: true - /@next/env@15.5.6: - resolution: {integrity: sha512-3qBGRW+sCGzgbpc5TS1a0p7eNxnOarGVQhZxfvTdnV0gFI61lX7QNtQ4V1TSREctXzYn5NetbUsLvyqwLFJM6Q==} + /@next/env@16.0.0: + resolution: {integrity: sha512-s5j2iFGp38QsG1LWRQaE2iUY3h1jc014/melHFfLdrsMJPqxqDQwWNwyQTcNoUSGZlCVZuM7t7JDMmSyRilsnA==} dev: false - /@next/eslint-plugin-next@15.5.6: - resolution: {integrity: sha512-YxDvsT2fwy1j5gMqk3ppXlsgDopHnkM4BoxSVASbvvgh5zgsK8lvWerDzPip8k3WVzsTZ1O7A7si1KNfN4OZfQ==} + /@next/eslint-plugin-next@16.0.0: + resolution: {integrity: sha512-IB7RzmmtrPOrpAgEBR1PIQPD0yea5lggh5cq54m51jHjjljU80Ia+czfxJYMlSDl1DPvpzb8S9TalCc0VMo9Hw==} dependencies: fast-glob: 3.3.1 dev: true - /@next/swc-darwin-arm64@15.5.6: - resolution: {integrity: sha512-ES3nRz7N+L5Umz4KoGfZ4XX6gwHplwPhioVRc25+QNsDa7RtUF/z8wJcbuQ2Tffm5RZwuN2A063eapoJ1u4nPg==} + /@next/swc-darwin-arm64@16.0.0: + resolution: {integrity: sha512-/CntqDCnk5w2qIwMiF0a9r6+9qunZzFmU0cBX4T82LOflE72zzH6gnOjCwUXYKOBlQi8OpP/rMj8cBIr18x4TA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -2787,8 +2829,8 @@ packages: dev: false optional: true - /@next/swc-darwin-x64@15.5.6: - resolution: {integrity: sha512-JIGcytAyk9LQp2/nuVZPAtj8uaJ/zZhsKOASTjxDug0SPU9LAM3wy6nPU735M1OqacR4U20LHVF5v5Wnl9ptTA==} + /@next/swc-darwin-x64@16.0.0: + resolution: {integrity: sha512-hB4GZnJGKa8m4efvTGNyii6qs76vTNl+3dKHTCAUaksN6KjYy4iEO3Q5ira405NW2PKb3EcqWiRaL9DrYJfMHg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -2796,8 +2838,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-gnu@15.5.6: - resolution: {integrity: sha512-qvz4SVKQ0P3/Im9zcS2RmfFL/UCQnsJKJwQSkissbngnB/12c6bZTCB0gHTexz1s6d/mD0+egPKXAIRFVS7hQg==} + /@next/swc-linux-arm64-gnu@16.0.0: + resolution: {integrity: sha512-E2IHMdE+C1k+nUgndM13/BY/iJY9KGCphCftMh7SXWcaQqExq/pJU/1Hgn8n/tFwSoLoYC/yUghOv97tAsIxqg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -2805,8 +2847,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-musl@15.5.6: - resolution: {integrity: sha512-FsbGVw3SJz1hZlvnWD+T6GFgV9/NYDeLTNQB2MXoPN5u9VA9OEDy6fJEfePfsUKAhJufFbZLgp0cPxMuV6SV0w==} + /@next/swc-linux-arm64-musl@16.0.0: + resolution: {integrity: sha512-xzgl7c7BVk4+7PDWldU+On2nlwnGgFqJ1siWp3/8S0KBBLCjonB6zwJYPtl4MUY7YZJrzzumdUpUoquu5zk8vg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -2814,8 +2856,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-gnu@15.5.6: - resolution: {integrity: sha512-3QnHGFWlnvAgyxFxt2Ny8PTpXtQD7kVEeaFat5oPAHHI192WKYB+VIKZijtHLGdBBvc16tiAkPTDmQNOQ0dyrA==} + /@next/swc-linux-x64-gnu@16.0.0: + resolution: {integrity: sha512-sdyOg4cbiCw7YUr0F/7ya42oiVBXLD21EYkSwN+PhE4csJH4MSXUsYyslliiiBwkM+KsuQH/y9wuxVz6s7Nstg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -2823,8 +2865,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-musl@15.5.6: - resolution: {integrity: sha512-OsGX148sL+TqMK9YFaPFPoIaJKbFJJxFzkXZljIgA9hjMjdruKht6xDCEv1HLtlLNfkx3c5w2GLKhj7veBQizQ==} + /@next/swc-linux-x64-musl@16.0.0: + resolution: {integrity: sha512-IAXv3OBYqVaNOgyd3kxR4L3msuhmSy1bcchPHxDOjypG33i2yDWvGBwFD94OuuTjjTt/7cuIKtAmoOOml6kfbg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -2832,8 +2874,8 @@ packages: dev: false optional: true - /@next/swc-win32-arm64-msvc@15.5.6: - resolution: {integrity: sha512-ONOMrqWxdzXDJNh2n60H6gGyKed42Ieu6UTVPZteXpuKbLZTH4G4eBMsr5qWgOBA+s7F+uB4OJbZnrkEDnZ5Fg==} + /@next/swc-win32-arm64-msvc@16.0.0: + resolution: {integrity: sha512-bmo3ncIJKUS9PWK1JD9pEVv0yuvp1KPuOsyJTHXTv8KDrEmgV/K+U0C75rl9rhIaODcS7JEb6/7eJhdwXI0XmA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -2841,8 +2883,8 @@ packages: dev: false optional: true - /@next/swc-win32-x64-msvc@15.5.6: - resolution: {integrity: sha512-pxK4VIjFRx1MY92UycLOOw7dTdvccWsNETQ0kDHkBlcFH1GrTLUjSiHU1ohrznnux6TqRHgv5oflhfIWZwVROQ==} + /@next/swc-win32-x64-msvc@16.0.0: + resolution: {integrity: sha512-O1cJbT+lZp+cTjYyZGiDwsOjO3UHHzSqobkPNipdlnnuPb1swfcuY6r3p8dsKU4hAIEO4cO67ZCfVVH/M1ETXA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -3913,10 +3955,6 @@ packages: resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} dev: true - /@rushstack/eslint-patch@1.14.0: - resolution: {integrity: sha512-WJFej426qe4RWOm9MMtP4V3CV4AucXolQty+GRgAWLgQXmpCuwzs7hEpxxhSc/znXUSxum9d/P/32MW0FlAAlA==} - dev: true - /@swc/core-darwin-arm64@1.3.76: resolution: {integrity: sha512-ovviEhZ/1E81Z9OGrO0ivLWk4VCa3I3ZzM+cd3gugglRRwVwtlIaoIYqY5S3KiCAupDd1+UCl5X7Vbio7a/V8g==} engines: {node: '>=10'} @@ -4182,29 +4220,25 @@ packages: - supports-color dev: true - /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@9.38.0)(typescript@5.8.3): - resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2)(eslint@9.38.0)(typescript@5.8.3): + resolution: {integrity: sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser': ^8.46.2 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' dependencies: - '@eslint-community/regexpp': 4.8.0 - '@typescript-eslint/parser': 5.62.0(eslint@9.38.0)(typescript@5.8.3) - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/type-utils': 5.62.0(eslint@9.38.0)(typescript@5.8.3) - '@typescript-eslint/utils': 5.62.0(eslint@9.38.0)(typescript@5.8.3) - debug: 4.3.4 + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.46.2(eslint@9.38.0)(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.46.2 + '@typescript-eslint/type-utils': 8.46.2(eslint@9.38.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.38.0)(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.46.2 eslint: 9.38.0 graphemer: 1.4.0 - ignore: 5.2.4 - natural-compare-lite: 1.4.0 - semver: 7.5.4 - tsutils: 3.21.0(typescript@5.8.3) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -4230,26 +4264,38 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@5.62.0(eslint@9.38.0)(typescript@5.8.3): - resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/parser@8.46.2(eslint@9.38.0)(typescript@5.8.3): + resolution: {integrity: sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' dependencies: - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) - debug: 4.3.4 + '@typescript-eslint/scope-manager': 8.46.2 + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.46.2 + debug: 4.4.3 eslint: 9.38.0 typescript: 5.8.3 transitivePeerDependencies: - supports-color dev: true + /@typescript-eslint/project-service@8.46.2(typescript@5.8.3): + resolution: {integrity: sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.8.3) + '@typescript-eslint/types': 8.46.2 + debug: 4.4.3 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/scope-manager@5.62.0: resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4258,6 +4304,23 @@ packages: '@typescript-eslint/visitor-keys': 5.62.0 dev: true + /@typescript-eslint/scope-manager@8.46.2: + resolution: {integrity: sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/visitor-keys': 8.46.2 + dev: true + + /@typescript-eslint/tsconfig-utils@8.46.2(typescript@5.8.3): + resolution: {integrity: sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + typescript: 5.8.3 + dev: true + /@typescript-eslint/type-utils@5.62.0(eslint@8.47.0)(typescript@5.8.3): resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4278,21 +4341,19 @@ packages: - supports-color dev: true - /@typescript-eslint/type-utils@5.62.0(eslint@9.38.0)(typescript@5.8.3): - resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/type-utils@8.46.2(eslint@9.38.0)(typescript@5.8.3): + resolution: {integrity: sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: '*' - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' dependencies: - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) - '@typescript-eslint/utils': 5.62.0(eslint@9.38.0)(typescript@5.8.3) - debug: 4.3.4 + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.8.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.38.0)(typescript@5.8.3) + debug: 4.4.3 eslint: 9.38.0 - tsutils: 3.21.0(typescript@5.8.3) + ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -4303,6 +4364,11 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@typescript-eslint/types@8.46.2: + resolution: {integrity: sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + /@typescript-eslint/typescript-estree@5.62.0(typescript@5.8.3): resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4324,6 +4390,27 @@ packages: - supports-color dev: true + /@typescript-eslint/typescript-estree@8.46.2(typescript@5.8.3): + resolution: {integrity: sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/project-service': 8.46.2(typescript@5.8.3) + '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.8.3) + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/visitor-keys': 8.46.2 + debug: 4.4.3 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.3 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/utils@5.62.0(eslint@8.47.0)(typescript@5.8.3): resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4344,24 +4431,21 @@ packages: - typescript dev: true - /@typescript-eslint/utils@5.62.0(eslint@9.38.0)(typescript@5.8.3): - resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@typescript-eslint/utils@8.46.2(eslint@9.38.0)(typescript@5.8.3): + resolution: {integrity: sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.38.0) - '@types/json-schema': 7.0.12 - '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.3) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0) + '@typescript-eslint/scope-manager': 8.46.2 + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.8.3) eslint: 9.38.0 - eslint-scope: 5.1.1 - semver: 7.5.4 + typescript: 5.8.3 transitivePeerDependencies: - supports-color - - typescript dev: true /@typescript-eslint/visitor-keys@5.62.0: @@ -4372,6 +4456,14 @@ packages: eslint-visitor-keys: 3.4.3 dev: true + /@typescript-eslint/visitor-keys@8.46.2: + resolution: {integrity: sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.46.2 + eslint-visitor-keys: 4.2.1 + dev: true + /@unrs/resolver-binding-android-arm-eabi@1.11.1: resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} cpu: [arm] @@ -4869,12 +4961,25 @@ packages: balanced-match: 1.0.2 concat-map: 0.0.1 + /brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + dependencies: + balanced-match: 1.0.2 + dev: true + /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} dependencies: fill-range: 7.0.1 + /braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.1.1 + dev: true + /browserslist@4.21.10: resolution: {integrity: sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -5028,6 +5133,10 @@ packages: /convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + /core-js-compat@3.46.0: resolution: {integrity: sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==} dependencies: @@ -5553,28 +5662,28 @@ packages: engines: {node: '>=10'} dev: true - /eslint-config-next@15.5.6(eslint@9.38.0)(typescript@5.8.3): - resolution: {integrity: sha512-cGr3VQlPsZBEv8rtYp4BpG1KNXDqGvPo9VC1iaCgIA11OfziC/vczng+TnAS3WpRIR3Q5ye/6yl+CRUuZ1fPGg==} + /eslint-config-next@16.0.0(@typescript-eslint/parser@5.62.0)(eslint@9.38.0)(typescript@5.8.3): + resolution: {integrity: sha512-DWKT1YAO9ex2rK0/EeiPpKU++ghTiG59z6m08/ReLRECOYIaEv17maSCYT8zmFQLwIrY5lhJ+iaJPQdT4sJd4g==} peerDependencies: - eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 + eslint: '>=9.0.0' typescript: '>=3.3.1' peerDependenciesMeta: typescript: optional: true dependencies: - '@next/eslint-plugin-next': 15.5.6 - '@rushstack/eslint-patch': 1.14.0 - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@9.38.0)(typescript@5.8.3) - '@typescript-eslint/parser': 5.62.0(eslint@9.38.0)(typescript@5.8.3) + '@next/eslint-plugin-next': 16.0.0 eslint: 9.38.0 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.38.0) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.38.0) eslint-plugin-react: 7.37.5(eslint@9.38.0) - eslint-plugin-react-hooks: 5.2.0(eslint@9.38.0) + eslint-plugin-react-hooks: 7.0.1(eslint@9.38.0) + globals: 16.4.0 typescript: 5.8.3 + typescript-eslint: 8.46.2(eslint@9.38.0)(typescript@5.8.3) transitivePeerDependencies: + - '@typescript-eslint/parser' - eslint-import-resolver-webpack - eslint-plugin-import-x - supports-color @@ -5585,7 +5694,7 @@ packages: dependencies: debug: 3.2.7 is-core-module: 2.16.1 - resolve: 1.22.4 + resolve: 1.22.11 transitivePeerDependencies: - supports-color dev: true @@ -5604,7 +5713,7 @@ packages: optional: true dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.0 + debug: 4.4.3 eslint: 9.38.0 eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0) get-tsconfig: 4.12.0 @@ -5637,7 +5746,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.62.0(eslint@9.38.0)(typescript@5.8.3) + '@typescript-eslint/parser': 5.62.0(eslint@8.47.0)(typescript@5.8.3) debug: 3.2.7 eslint: 9.38.0 eslint-import-resolver-node: 0.3.9 @@ -5657,7 +5766,7 @@ packages: optional: true dependencies: '@rtsao/scc': 1.1.0 - '@typescript-eslint/parser': 5.62.0(eslint@9.38.0)(typescript@5.8.3) + '@typescript-eslint/parser': 5.62.0(eslint@8.47.0)(typescript@5.8.3) array-includes: 3.1.9 array.prototype.findlastindex: 1.2.6 array.prototype.flat: 1.3.3 @@ -5716,13 +5825,20 @@ packages: eslint: 8.47.0 dev: true - /eslint-plugin-react-hooks@5.2.0(eslint@9.38.0): - resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} - engines: {node: '>=10'} + /eslint-plugin-react-hooks@7.0.1(eslint@9.38.0): + resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} + engines: {node: '>=18'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 dependencies: + '@babel/core': 7.28.5 + '@babel/parser': 7.28.5 eslint: 9.38.0 + hermes-parser: 0.25.1 + zod: 4.1.12 + zod-validation-error: 4.0.2(zod@4.1.12) + transitivePeerDependencies: + - supports-color dev: true /eslint-plugin-react@7.37.5(eslint@9.38.0): @@ -5964,6 +6080,17 @@ packages: merge2: 1.4.1 micromatch: 4.0.5 + /fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + dev: true + /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} dev: true @@ -6012,6 +6139,13 @@ packages: dependencies: to-regex-range: 5.0.1 + /fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -6207,6 +6341,11 @@ packages: engines: {node: '>=18'} dev: true + /globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + engines: {node: '>=18'} + dev: true + /globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -6283,6 +6422,7 @@ packages: engines: {node: '>= 0.4.0'} dependencies: function-bind: 1.1.2 + dev: false /hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} @@ -6291,6 +6431,16 @@ packages: function-bind: 1.1.2 dev: true + /hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + dev: true + + /hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + dependencies: + hermes-estree: 0.25.1 + dev: true + /html-encoding-sniffer@4.0.0: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} @@ -6378,6 +6528,11 @@ packages: engines: {node: '>= 4'} dev: true + /ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + dev: true + /immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} dev: false @@ -6471,6 +6626,7 @@ packages: resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} dependencies: has: 1.0.3 + dev: false /is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} @@ -7014,11 +7170,26 @@ packages: braces: 3.0.2 picomatch: 2.3.1 + /micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + dev: true + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.2 + dev: true + /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} dev: true @@ -7079,9 +7250,9 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /next@15.5.6(@playwright/test@1.37.0)(react-dom@19.1.0)(react@19.1.0): - resolution: {integrity: sha512-zTxsnI3LQo3c9HSdSf91O1jMNsEzIXDShXd4wVdg9y5shwLqBXi4ZtUUJyB86KGVSJLZx0PFONvO54aheGX8QQ==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + /next@16.0.0(@playwright/test@1.37.0)(react-dom@19.2.0)(react@19.2.0): + resolution: {integrity: sha512-nYohiNdxGu4OmBzggxy9rczmjIGI+TpR5vbKTsE1HqYwNm1B+YSiugSrFguX6omMOKnDHAmBPY4+8TNJk0Idyg==} + engines: {node: '>=20.9.0'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -7100,23 +7271,23 @@ packages: sass: optional: true dependencies: - '@next/env': 15.5.6 + '@next/env': 16.0.0 '@playwright/test': 1.37.0 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001751 postcss: 8.4.31 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - styled-jsx: 5.1.6(react@19.1.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + styled-jsx: 5.1.6(react@19.2.0) optionalDependencies: - '@next/swc-darwin-arm64': 15.5.6 - '@next/swc-darwin-x64': 15.5.6 - '@next/swc-linux-arm64-gnu': 15.5.6 - '@next/swc-linux-arm64-musl': 15.5.6 - '@next/swc-linux-x64-gnu': 15.5.6 - '@next/swc-linux-x64-musl': 15.5.6 - '@next/swc-win32-arm64-msvc': 15.5.6 - '@next/swc-win32-x64-msvc': 15.5.6 + '@next/swc-darwin-arm64': 16.0.0 + '@next/swc-darwin-x64': 16.0.0 + '@next/swc-linux-arm64-gnu': 16.0.0 + '@next/swc-linux-arm64-musl': 16.0.0 + '@next/swc-linux-x64-gnu': 16.0.0 + '@next/swc-linux-x64-musl': 16.0.0 + '@next/swc-win32-arm64-msvc': 16.0.0 + '@next/swc-win32-x64-msvc': 16.0.0 sharp: 0.34.4 transitivePeerDependencies: - '@babel/core' @@ -7530,13 +7701,13 @@ packages: react: 0.0.0-experimental-247738465-20240130 scheduler: 0.0.0-experimental-247738465-20240130 - /react-dom@19.1.0(react@19.1.0): - resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} + /react-dom@19.2.0(react@19.2.0): + resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} peerDependencies: - react: ^19.1.0 + react: ^19.2.0 dependencies: - react: 19.1.0 - scheduler: 0.26.0 + react: 19.2.0 + scheduler: 0.27.0 dev: false /react-error-overlay@6.0.9: @@ -7589,8 +7760,8 @@ packages: dependencies: loose-envify: 1.4.0 - /react@19.1.0: - resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} + /react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} engines: {node: '>=0.10.0'} dev: false @@ -7695,6 +7866,7 @@ packages: is-core-module: 2.13.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + dev: false /resolve@2.0.0-next.5: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} @@ -7806,8 +7978,8 @@ packages: dependencies: loose-envify: 1.4.0 - /scheduler@0.26.0: - resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + /scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} dev: false /semver@6.3.1: @@ -8108,7 +8280,7 @@ packages: resolution: {integrity: sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA==} dev: false - /styled-jsx@5.1.6(react@19.1.0): + /styled-jsx@5.1.6(react@19.2.0): resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} engines: {node: '>= 12.0.0'} peerDependencies: @@ -8122,7 +8294,7 @@ packages: optional: true dependencies: client-only: 0.0.1 - react: 19.1.0 + react: 19.2.0 dev: false /supports-color@5.5.0: @@ -8265,6 +8437,15 @@ packages: punycode: 2.3.1 dev: true + /ts-api-utils@2.1.0(typescript@5.8.3): + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + dependencies: + typescript: 5.8.3 + dev: true + /tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} dependencies: @@ -8361,6 +8542,23 @@ packages: reflect.getprototypeof: 1.0.10 dev: true + /typescript-eslint@8.46.2(eslint@9.38.0)(typescript@5.8.3): + resolution: {integrity: sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + dependencies: + '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2)(eslint@9.38.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.46.2(eslint@9.38.0)(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.8.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.38.0)(typescript@5.8.3) + eslint: 9.38.0 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + dev: true + /typescript@5.8.3: resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} @@ -8737,6 +8935,19 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + /zod-validation-error@4.0.2(zod@4.1.12): + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + dependencies: + zod: 4.1.12 + dev: true + /zod@3.21.4: resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} dev: false + + /zod@4.1.12: + resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} + dev: true From b1922f9dc70e2d2d67d35f9e9851d28307a77377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sun, 26 Oct 2025 21:54:21 +0100 Subject: [PATCH 18/27] chore: serialization refactor --- .../src/utils/serialization.test.ts | 34 ---- .../src/utils/serialization.ts | 151 +++++++++--------- 2 files changed, 78 insertions(+), 107 deletions(-) diff --git a/packages/react-resizable-panels/src/utils/serialization.test.ts b/packages/react-resizable-panels/src/utils/serialization.test.ts index 918284c26..61e2e261f 100644 --- a/packages/react-resizable-panels/src/utils/serialization.test.ts +++ b/packages/react-resizable-panels/src/utils/serialization.test.ts @@ -285,40 +285,6 @@ describe("serialization", () => { } }); - test("should handle auto-generated IDs with order", () => { - const panels: PanelData[] = [ - createPanelData("auto-id-1", false, 1, 15), - createPanelData("auto-id-2", false, 2, 15), - ]; - - const sizes = [45, 55]; - savePanelGroupState("test-group", panels, new Map(), sizes, storage); - - const loaded = loadPanelGroupState("test-group", panels, storage); - - expect(loaded).not.toBeNull(); - if (loaded) { - expect(loaded.layout).toEqual(sizes); - } - }); - - test("should handle auto-generated IDs without order (old behavior)", () => { - const panels: PanelData[] = [ - createPanelData("auto-id-1", false, undefined, 15), - createPanelData("auto-id-2", false, undefined, 15), - ]; - - const sizes = [45, 55]; - savePanelGroupState("test-group", panels, new Map(), sizes, storage); - - const loaded = loadPanelGroupState("test-group", panels, storage); - - expect(loaded).not.toBeNull(); - if (loaded) { - expect(loaded.layout).toEqual(sizes); - } - }); - test("should handle invalid JSON gracefully", () => { const storageKey = getPanelGroupKey("test-group"); storage.setItem(storageKey, "invalid json{"); diff --git a/packages/react-resizable-panels/src/utils/serialization.ts b/packages/react-resizable-panels/src/utils/serialization.ts index 1387ebf2b..70ea16da9 100644 --- a/packages/react-resizable-panels/src/utils/serialization.ts +++ b/packages/react-resizable-panels/src/utils/serialization.ts @@ -10,11 +10,18 @@ export type PanelConfigurationState = { expandToSizes: { [panelId: string]: number; }; - layout: PanelLayoutItem[]; + layout: number[]; +}; + +export type PanelSerializedConfigurationState = { + expandToSizes: { + [panelId: string]: number; + }; + layout: PanelLayoutItem[] | number[]; }; export type SerializedPanelGroupState = { - [panelIds: string]: PanelConfigurationState; + [panelIds: string]: PanelSerializedConfigurationState; }; export const DEFAULT_STORAGE_KEY_PREFIX = "react-resizable-panels"; @@ -64,11 +71,73 @@ function loadSerializedPanelGroupState( return null; } +function getExplicitOrders(panels: PanelData[]): Set { + const explicitOrders = new Set(); + panels.forEach((panel) => { + if (panel.order !== undefined) { + explicitOrders.add(panel.order); + } + }); + return explicitOrders; +} + +function assignOrdersToPanels(panels: PanelData[]): number[] { + const explicitOrders = getExplicitOrders(panels); + let nextAvailableOrder = 0; + + return panels.map((panel) => { + if (panel.order !== undefined) { + return panel.order; + } else { + while (explicitOrders.has(nextAvailableOrder)) { + nextAvailableOrder++; + } + const order = nextAvailableOrder; + nextAvailableOrder++; + return order; + } + }); +} + +function isOldFormat( + savedLayout: PanelSerializedConfigurationState["layout"] +): savedLayout is number[] { + return savedLayout.every((item) => typeof item === "number"); +} + +function parseLayoutFromSavedState( + savedLayout: PanelSerializedConfigurationState["layout"], + panels: PanelData[] +): number[] | null { + if (isOldFormat(savedLayout)) { + return savedLayout; + } + + const orderToValue = new Map(); + savedLayout.forEach((item) => { + orderToValue.set(item.order, item.size); + }); + + const panelOrders = assignOrdersToPanels(panels); + const layout = panelOrders.map((order) => { + return orderToValue.get(order) || 0; + }); + + if ( + layout.some((size) => size === 0) && + savedLayout.length !== panels.length + ) { + return null; + } + + return layout; +} + export function loadPanelGroupState( autoSaveId: string, panels: PanelData[], storage: PanelGroupStorage -): { layout: number[]; expandToSizes: Record } | null { +): PanelConfigurationState | null { const state = loadSerializedPanelGroupState(autoSaveId, storage) ?? {}; const panelKey = getPanelKey(panels); const savedState = state[panelKey]; @@ -77,56 +146,8 @@ export function loadPanelGroupState( return null; } - // Handle both old format (number[]) and new format (PanelLayoutItem[]) - let layout: number[]; - if (Array.isArray(savedState.layout)) { - if ( - savedState.layout.length > 0 && - typeof savedState.layout[0] === "object" && - savedState.layout[0] !== null && - "order" in savedState.layout[0] - ) { - const panelLayoutItems = savedState.layout as PanelLayoutItem[]; - - const orderToValue = new Map(); - panelLayoutItems.forEach((item) => { - orderToValue.set(item.order, item.size); - }); - - const explicitOrders = new Set(); - panels.forEach((panel) => { - if (panel.order !== undefined) { - explicitOrders.add(panel.order); - } - }); - - let nextAvailableOrder = 0; - layout = panels.map((panel) => { - let order: number; - - if (panel.order !== undefined) { - order = panel.order; - } else { - while (explicitOrders.has(nextAvailableOrder)) { - nextAvailableOrder++; - } - order = nextAvailableOrder; - nextAvailableOrder++; - } - - return orderToValue.get(order) || 0; - }); - - if ( - layout.some((size) => size === 0) && - panelLayoutItems.length !== panels.length - ) { - return null; - } - } else { - layout = savedState.layout as unknown as number[]; - } - } else { + const layout = parseLayoutFromSavedState(savedState.layout, panels); + if (!layout) { return null; } @@ -147,28 +168,12 @@ export function savePanelGroupState( const panelKey = getPanelKey(panels); const state = loadSerializedPanelGroupState(autoSaveId, storage) ?? {}; - const explicitOrders = new Set(); - panels.forEach((panel) => { - if (panel.order !== undefined) { - explicitOrders.add(panel.order); - } - }); - - let nextAvailableOrder = 0; + const panelOrders = assignOrdersToPanels(panels); const layout: PanelLayoutItem[] = sizes.map((size, index) => { - const panel = panels[index]; - let order: number; - - if (panel?.order !== undefined) { - order = panel.order; - } else { - while (explicitOrders.has(nextAvailableOrder)) { - nextAvailableOrder++; - } - order = nextAvailableOrder; - nextAvailableOrder++; + const order = panelOrders[index]; + if (order === undefined) { + throw new Error(`Order for panel at index ${index} is undefined`); } - return { order, size }; }); From 3b2a438e9f69e7710dfd0061252df8eecd05e91d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sun, 26 Oct 2025 23:22:57 +0100 Subject: [PATCH 19/27] feat: order prop auto increment --- examples/nextjs/src/app/page.tsx | 14 +++--- packages/react-resizable-panels/src/Panel.ts | 21 ++++++--- .../react-resizable-panels/src/PanelGroup.ts | 31 ++++++++----- .../src/PanelGroupContext.ts | 3 +- .../src/utils/serialization.ts | 46 ++++--------------- 5 files changed, 52 insertions(+), 63 deletions(-) diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index 9810ad09b..fbdb11494 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -18,7 +18,7 @@ export default function Home() { className={styles.PanelRow} defaultSize={20} minSize={10} - order={1} + // order={1} id="l1:left" suppressHydrationWarning > @@ -30,7 +30,7 @@ export default function Home() { className={styles.PanelRow} minSize={35} defaultSize={60} - order={2} + // order={2} id="l1:middle" suppressHydrationWarning > @@ -44,7 +44,7 @@ export default function Home() { className={styles.PanelColumn} defaultSize={35} minSize={10} - order={1} + // order={1} id="l2:top" suppressHydrationWarning > @@ -56,7 +56,7 @@ export default function Home() { className={styles.PanelColumn} defaultSize={65} minSize={10} - order={2} + // order={2} id="l2:bottom" suppressHydrationWarning > @@ -70,7 +70,7 @@ export default function Home() { className={styles.PanelRow} defaultSize={50} minSize={10} - order={1} + // order={1} id="l3:left" suppressHydrationWarning > @@ -82,7 +82,7 @@ export default function Home() { className={styles.PanelRow} defaultSize={50} minSize={10} - order={2} + // order={2} id="l3:right" suppressHydrationWarning > @@ -98,7 +98,7 @@ export default function Home() { className={styles.PanelRow} defaultSize={20} minSize={10} - order={3} + // order={3} id="l1:right" suppressHydrationWarning > diff --git a/packages/react-resizable-panels/src/Panel.ts b/packages/react-resizable-panels/src/Panel.ts index 9f07e3334..ab0f46f3c 100644 --- a/packages/react-resizable-panels/src/Panel.ts +++ b/packages/react-resizable-panels/src/Panel.ts @@ -10,6 +10,7 @@ import { useContext, useImperativeHandle, useRef, + useState, } from "react"; import { PanelGroupContext } from "./PanelGroupContext"; import { DATA_ATTRIBUTES } from "./constants"; @@ -43,7 +44,7 @@ export type PanelData = { constraints: PanelConstraints; id: string; idIsFromProps: boolean; - order: number | undefined; + order: number; }; export type ImperativePanelHandle = { @@ -88,7 +89,7 @@ export function PanelWithForwardedRef({ onCollapse, onExpand, onResize, - order, + order: orderFromProps, style: styleFromProps, tagName: Type = "div", ...rest @@ -109,6 +110,7 @@ export function PanelWithForwardedRef({ getPanelStyle, groupId, isPanelCollapsed, + assignPanelOrder, reevaluatePanelConstraints, registerPanel, resizePanel, @@ -117,6 +119,12 @@ export function PanelWithForwardedRef({ const panelId = useUniqueId(idFromProps); + const assignedOrderRef = useRef(null); + + if (assignedOrderRef.current === null) { + assignedOrderRef.current = assignPanelOrder(orderFromProps); + } + const panelDataRef = useRef({ callbacks: { onCollapse, @@ -132,7 +140,7 @@ export function PanelWithForwardedRef({ }, id: panelId, idIsFromProps: idFromProps !== undefined, - order, + order: assignedOrderRef.current, }); const devWarningsRef = useRef<{ @@ -161,7 +169,7 @@ export function PanelWithForwardedRef({ panelDataRef.current.id = panelId; panelDataRef.current.idIsFromProps = idFromProps !== undefined; - panelDataRef.current.order = order; + panelDataRef.current.order = assignedOrderRef.current as number; callbacks.onCollapse = onCollapse; callbacks.onExpand = onExpand; @@ -193,7 +201,7 @@ export function PanelWithForwardedRef({ return () => { unregisterPanel(panelData); }; - }, [order, panelId, registerPanel, unregisterPanel]); + }, [orderFromProps, panelId, registerPanel, unregisterPanel]); useImperativeHandle( forwardedRef, @@ -248,8 +256,7 @@ export function PanelWithForwardedRef({ [DATA_ATTRIBUTES.panel]: "", [DATA_ATTRIBUTES.panelCollapsible]: collapsible || undefined, [DATA_ATTRIBUTES.panelId]: panelId, - [DATA_ATTRIBUTES.panelOrder]: - order !== undefined ? order.toString() : undefined, + [DATA_ATTRIBUTES.panelOrder]: assignedOrderRef.current.toString(), [DATA_ATTRIBUTES.panelSize]: parseFloat( "" + (style as any)[panelSizeCssVar] ).toFixed(1), diff --git a/packages/react-resizable-panels/src/PanelGroup.ts b/packages/react-resizable-panels/src/PanelGroup.ts index a89af601e..160e48385 100644 --- a/packages/react-resizable-panels/src/PanelGroup.ts +++ b/packages/react-resizable-panels/src/PanelGroup.ts @@ -133,6 +133,7 @@ function PanelGroupWithForwardedRef({ const panelIdToLastNotifiedSizeMapRef = useRef>({}); const panelSizeBeforeCollapseRef = useRef>(new Map()); const prevDeltaRef = useRef(0); + const nextAvailableOrderRef = useRef(1); const committedValuesRef = useRef<{ autoSaveId: string | null; @@ -527,23 +528,29 @@ function PanelGroupWithForwardedRef({ return !collapsible || fuzzyCompareNumbers(panelSize, collapsedSize) > 0; }, []); + const assignPanelOrder = useCallback((explicitOrder?: number) => { + if (explicitOrder !== undefined) { + // Update next available order to avoid conflicts + nextAvailableOrderRef.current = Math.max( + nextAvailableOrderRef.current, + explicitOrder + 1 + ); + return explicitOrder; + } else { + // Assign auto-increment order + const currentOrder = nextAvailableOrderRef.current; + nextAvailableOrderRef.current++; + return currentOrder; + } + }, []); + const registerPanel = useCallback( (panelData: PanelData) => { const { panelDataArray } = eagerValuesRef.current; panelDataArray.push(panelData); panelDataArray.sort((panelA, panelB) => { - const orderA = panelA.order; - const orderB = panelB.order; - if (orderA == null && orderB == null) { - return 0; - } else if (orderA == null) { - return -1; - } else if (orderB == null) { - return 1; - } else { - return orderA - orderB; - } + return panelA.order - panelB.order; }); eagerValuesRef.current.panelDataArrayChanged = true; @@ -901,6 +908,7 @@ function PanelGroupWithForwardedRef({ groupId, isPanelCollapsed, isPanelExpanded, + assignPanelOrder, reevaluatePanelConstraints, registerPanel, registerResizeHandle, @@ -921,6 +929,7 @@ function PanelGroupWithForwardedRef({ groupId, isPanelCollapsed, isPanelExpanded, + assignPanelOrder, reevaluatePanelConstraints, registerPanel, registerResizeHandle, diff --git a/packages/react-resizable-panels/src/PanelGroupContext.ts b/packages/react-resizable-panels/src/PanelGroupContext.ts index 2fcdcaae9..774901529 100644 --- a/packages/react-resizable-panels/src/PanelGroupContext.ts +++ b/packages/react-resizable-panels/src/PanelGroupContext.ts @@ -1,5 +1,5 @@ import { PanelConstraints, PanelData } from "./Panel"; -import { CSSProperties, createContext } from "react"; +import { CSSProperties, createContext, MutableRefObject } from "react"; // The "contextmenu" event is not supported as a PointerEvent in all browsers yet, so MouseEvent still need to be handled export type ResizeEvent = KeyboardEvent | PointerEvent | MouseEvent; @@ -25,6 +25,7 @@ export type TPanelGroupContext = { groupId: string; isPanelCollapsed: (panelData: PanelData) => boolean; isPanelExpanded: (panelData: PanelData) => boolean; + assignPanelOrder: (explicitOrder?: number) => number; reevaluatePanelConstraints: ( panelData: PanelData, prevConstraints: PanelConstraints diff --git a/packages/react-resizable-panels/src/utils/serialization.ts b/packages/react-resizable-panels/src/utils/serialization.ts index 70ea16da9..bffc3d095 100644 --- a/packages/react-resizable-panels/src/utils/serialization.ts +++ b/packages/react-resizable-panels/src/utils/serialization.ts @@ -44,9 +44,7 @@ function getPanelKey(panels: PanelData[]): string { if (idIsFromProps) { return id; } else { - return order - ? `${order}:${JSON.stringify(constraints)}` - : JSON.stringify(constraints); + return `${order}:${JSON.stringify(constraints)}`; } }) .sort((a, b) => a.localeCompare(b)) @@ -71,34 +69,6 @@ function loadSerializedPanelGroupState( return null; } -function getExplicitOrders(panels: PanelData[]): Set { - const explicitOrders = new Set(); - panels.forEach((panel) => { - if (panel.order !== undefined) { - explicitOrders.add(panel.order); - } - }); - return explicitOrders; -} - -function assignOrdersToPanels(panels: PanelData[]): number[] { - const explicitOrders = getExplicitOrders(panels); - let nextAvailableOrder = 0; - - return panels.map((panel) => { - if (panel.order !== undefined) { - return panel.order; - } else { - while (explicitOrders.has(nextAvailableOrder)) { - nextAvailableOrder++; - } - const order = nextAvailableOrder; - nextAvailableOrder++; - return order; - } - }); -} - function isOldFormat( savedLayout: PanelSerializedConfigurationState["layout"] ): savedLayout is number[] { @@ -118,8 +88,8 @@ function parseLayoutFromSavedState( orderToValue.set(item.order, item.size); }); - const panelOrders = assignOrdersToPanels(panels); - const layout = panelOrders.map((order) => { + const layout = panels.map((panel) => { + const order = panel.order; return orderToValue.get(order) || 0; }); @@ -168,12 +138,14 @@ export function savePanelGroupState( const panelKey = getPanelKey(panels); const state = loadSerializedPanelGroupState(autoSaveId, storage) ?? {}; - const panelOrders = assignOrdersToPanels(panels); const layout: PanelLayoutItem[] = sizes.map((size, index) => { - const order = panelOrders[index]; - if (order === undefined) { - throw new Error(`Order for panel at index ${index} is undefined`); + const panel = panels[index]; + if (!panel) { + throw new Error( + `No panel found at index ${index} while saving panel group state` + ); } + const order = panel.order; return { order, size }; }); From a8a5bb75689d48fa6888a252bb900dda3aff2a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sun, 26 Oct 2025 23:25:25 +0100 Subject: [PATCH 20/27] chore: update test --- .../src/utils/serialization.test.ts | 82 +------------------ 1 file changed, 1 insertion(+), 81 deletions(-) diff --git a/packages/react-resizable-panels/src/utils/serialization.test.ts b/packages/react-resizable-panels/src/utils/serialization.test.ts index 61e2e261f..5ede32757 100644 --- a/packages/react-resizable-panels/src/utils/serialization.test.ts +++ b/packages/react-resizable-panels/src/utils/serialization.test.ts @@ -51,7 +51,7 @@ describe("serialization", () => { const createPanelData = ( id: string, idIsFromProps: boolean, - order?: number, + order: number, minSize?: number ): PanelData => ({ callbacks: {}, @@ -119,35 +119,6 @@ describe("serialization", () => { } }); - test("should handle old format from localStorage (number array)", () => { - const panels: PanelData[] = [ - createPanelData("p1", false, undefined, 10), - createPanelData("p2", false, undefined, 10), - createPanelData("p3", false, undefined, 10), - ]; - - // Simulate old format in localStorage - const oldFormatData = { - '{"minSize":10},{"minSize":10},{"minSize":10}': { - expandToSizes: {}, - layout: [20.6563247098, 35.1228707735, 44.2208045167], - }, - }; - - const storageKey = getPanelGroupKey("test-group"); - storage.setItem(storageKey, JSON.stringify(oldFormatData)); - - const loaded = loadPanelGroupState("test-group", panels, storage); - - expect(loaded).not.toBeNull(); - if (loaded) { - expect(loaded.layout).toEqual([ - 20.6563247098, 35.1228707735, 44.2208045167, - ]); - expect(loaded.expandToSizes).toEqual({}); - } - }); - test("should handle new format from localStorage (with order)", () => { const panels: PanelData[] = [ createPanelData("left", true, 1, 10), @@ -177,57 +148,6 @@ describe("serialization", () => { } }); - test("should work with panels without order (backwards compatibility)", () => { - const panels: PanelData[] = [ - createPanelData("panel1", true, undefined, 10), - createPanelData("panel2", true, undefined, 10), - ]; - - const sizes = [30, 70]; - const panelSizesBeforeCollapse = new Map(); - - savePanelGroupState( - "test-group", - panels, - panelSizesBeforeCollapse, - sizes, - storage - ); - - const loaded = loadPanelGroupState("test-group", panels, storage); - - expect(loaded).not.toBeNull(); - if (loaded) { - expect(loaded.layout).toEqual(sizes); - } - }); - - test("should handle mixed panels (some with order, some without)", () => { - const panels: PanelData[] = [ - createPanelData("panel1", true, 1, 10), - createPanelData("panel2", true, undefined, 10), - createPanelData("panel3", true, 3, 10), - ]; - - const sizes = [25, 35, 40]; - const panelSizesBeforeCollapse = new Map(); - - savePanelGroupState( - "test-group", - panels, - panelSizesBeforeCollapse, - sizes, - storage - ); - - const loaded = loadPanelGroupState("test-group", panels, storage); - - expect(loaded).not.toBeNull(); - if (loaded) { - expect(loaded.layout).toEqual(sizes); - } - }); - test("should return null for non-existent autoSaveId", () => { const panels: PanelData[] = [createPanelData("panel1", true, 1, 10)]; From 2261a44c6d7695f0d021d880b7b05dabfaffcd4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Mon, 27 Oct 2025 00:05:48 +0100 Subject: [PATCH 21/27] feat: move css vars to panelGroup for better performance --- examples/nextjs/src/app/page.tsx | 17 +-- packages/react-resizable-panels/src/Panel.ts | 3 - .../react-resizable-panels/src/PanelGroup.ts | 44 ++++++-- .../src/PanelPersistScript.tsx | 7 +- .../react-resizable-panels/src/constants.ts | 1 - .../src/scripts/persist.minified.ts | 2 +- .../src/scripts/persist.ts | 30 ++---- .../utils/computePanelFlexBoxStyle.test.ts | 101 +++--------------- .../src/utils/computePanelFlexBoxStyle.ts | 34 +----- 9 files changed, 71 insertions(+), 168 deletions(-) diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index fbdb11494..3b68e4cb5 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -14,15 +14,14 @@ export default function Home() { autoSaveId="l1" direction="horizontal" > + -
left
@@ -30,25 +29,22 @@ export default function Home() { className={styles.PanelRow} minSize={35} defaultSize={60} - // order={2} id="l1:middle" suppressHydrationWarning > - + -
top
@@ -56,25 +52,22 @@ export default function Home() { className={styles.PanelColumn} defaultSize={65} minSize={10} - // order={2} id="l2:bottom" suppressHydrationWarning > - + -
left
@@ -82,11 +75,9 @@ export default function Home() { className={styles.PanelRow} defaultSize={50} minSize={10} - // order={2} id="l3:right" suppressHydrationWarning > -
right
@@ -98,11 +89,9 @@ export default function Home() { className={styles.PanelRow} defaultSize={20} minSize={10} - // order={3} id="l1:right" suppressHydrationWarning > -
right
diff --git a/packages/react-resizable-panels/src/Panel.ts b/packages/react-resizable-panels/src/Panel.ts index ab0f46f3c..e118728ec 100644 --- a/packages/react-resizable-panels/src/Panel.ts +++ b/packages/react-resizable-panels/src/Panel.ts @@ -257,9 +257,6 @@ export function PanelWithForwardedRef({ [DATA_ATTRIBUTES.panelCollapsible]: collapsible || undefined, [DATA_ATTRIBUTES.panelId]: panelId, [DATA_ATTRIBUTES.panelOrder]: assignedOrderRef.current.toString(), - [DATA_ATTRIBUTES.panelSize]: parseFloat( - "" + (style as any)[panelSizeCssVar] - ).toFixed(1), }); } diff --git a/packages/react-resizable-panels/src/PanelGroup.ts b/packages/react-resizable-panels/src/PanelGroup.ts index 160e48385..50b953ea0 100644 --- a/packages/react-resizable-panels/src/PanelGroup.ts +++ b/packages/react-resizable-panels/src/PanelGroup.ts @@ -477,19 +477,12 @@ function PanelGroupWithForwardedRef({ // This API should never read from committedValuesRef const getPanelStyle = useCallback( (panelData: PanelData, defaultSize: number | undefined) => { - const { panelDataArray } = eagerValuesRef.current; - - const panelIndex = findPanelDataIndex(panelDataArray, panelData); - return computePanelFlexBoxStyle({ - defaultSize, dragState, - layout, - panelData: panelDataArray, - panelIndex, + order: panelData.order, }); }, - [dragState, layout] + [dragState] ); // External APIs are safe to memoize via committed values ref @@ -941,12 +934,43 @@ function PanelGroupWithForwardedRef({ ] ); + const generatePanelSizeCssVars = useCallback( + (precision: number = 3) => { + const { panelDataArray } = eagerValuesRef.current; + const cssVars: Record = {}; + + for (let i = 0; i < panelDataArray.length; i++) { + const panelData = panelDataArray[i]; + if (!panelData) continue; + + const size = layout[i]; + + let flexGrow: string; + if (size == null) { + const defaultSize = panelData.constraints.defaultSize; + flexGrow = + defaultSize != undefined ? defaultSize.toFixed(precision) : "1"; + } else if (panelDataArray.length === 1) { + flexGrow = "1"; + } else { + flexGrow = size.toFixed(precision); + } + + cssVars[`--panel-${panelData.order}-size`] = flexGrow; + } + + return cssVars; + }, + [layout] + ); + const style: CSSProperties = { display: "flex", flexDirection: direction === "horizontal" ? "row" : "column", height: "100%", overflow: "hidden", width: "100%", + ...generatePanelSizeCssVars(), }; return createElement( @@ -969,6 +993,8 @@ function PanelGroupWithForwardedRef({ [DATA_ATTRIBUTES.groupDirection]: direction, [DATA_ATTRIBUTES.groupId]: groupId, [DATA_ATTRIBUTES.autoSaveId]: autoSaveId || undefined, + + suppressHydrationWarning: true, }) ); } diff --git a/packages/react-resizable-panels/src/PanelPersistScript.tsx b/packages/react-resizable-panels/src/PanelPersistScript.tsx index ff65ed711..04ed8e9e1 100644 --- a/packages/react-resizable-panels/src/PanelPersistScript.tsx +++ b/packages/react-resizable-panels/src/PanelPersistScript.tsx @@ -6,7 +6,6 @@ import { MINIFIED_PERSIST } from "./scripts/persist.minified"; import { useIsSSR } from "./hooks/useIsSSR"; export interface PersistScriptProps { - panelId: string; autoSaveId: string | null; storageKeyPrefix?: string; nonce?: string; @@ -16,7 +15,6 @@ export const PanelPersistScript = ({ nonce, autoSaveId, storageKeyPrefix = DEFAULT_STORAGE_KEY_PREFIX, - panelId, }: PersistScriptProps) => { const isSSR = useIsSSR(); @@ -27,10 +25,7 @@ export const PanelPersistScript = ({ const scriptArgs = JSON.stringify([ autoSaveId, storageKeyPrefix, - DATA_ATTRIBUTES.panelId, - DATA_ATTRIBUTES.panelOrder, - panelId, - panelSizeCssVar, + DATA_ATTRIBUTES.autoSaveId, ]).slice(1, -1); return createElement("script", { diff --git a/packages/react-resizable-panels/src/constants.ts b/packages/react-resizable-panels/src/constants.ts index 9d1b9e122..0c91a764e 100644 --- a/packages/react-resizable-panels/src/constants.ts +++ b/packages/react-resizable-panels/src/constants.ts @@ -6,7 +6,6 @@ export const DATA_ATTRIBUTES = { panelCollapsible: "data-panel-collapsible", panelId: "data-panel-id", panelOrder: "data-panel-order", - panelSize: "data-panel-size", resizeHandle: "data-resize-handle", resizeHandleActive: "data-resize-handle-active", resizeHandleEnabled: "data-panel-resize-handle-enabled", diff --git a/packages/react-resizable-panels/src/scripts/persist.minified.ts b/packages/react-resizable-panels/src/scripts/persist.minified.ts index d084f1194..8a692747c 100644 --- a/packages/react-resizable-panels/src/scripts/persist.minified.ts +++ b/packages/react-resizable-panels/src/scripts/persist.minified.ts @@ -6,4 +6,4 @@ * Minified version of persist.ts * Pre-minified to match browser bundle transformations. */ -export const MINIFIED_PERSIST = "function persist(t,e,n,o,c,l){let r=null;try{const n=t&&localStorage.getItem(e+\":\"+t);if(n){const t=JSON.parse(n);\"object\"==typeof t&&null!=t&&(r=t)}}catch(t){}if(!r)return;let s=null;if(r&&\"object\"==typeof r){const t=Object.keys(r);if(t.length>0){const e=t[0],n=e?r[e]:null;n&&\"object\"==typeof n&&\"layout\"in n&&(s=n.layout)}}const i=document.querySelector(\"[\"+n+'=\"'+c+'\"]');if(i&&s){const t=i.getAttribute(o||\"\");if(t){const e=parseInt(t,10),n=s.find((function(t){return t.order===e}));n&&i.style.setProperty(l,String(n.size))}}}"; +export const MINIFIED_PERSIST = "function persist(t,e,o,l=3){let c=null;try{const o=t&&localStorage.getItem(e+\":\"+t);if(o){const t=JSON.parse(o);\"object\"==typeof t&&null!=t&&(c=t)}}catch(t){}if(!c)return;let n=null;if(c&&\"object\"==typeof c){const t=Object.keys(c);if(t.length>0){const e=t[0],o=e?c[e]:null;o&&\"object\"==typeof o&&\"layout\"in o&&(n=o.layout)}}const s=document.querySelector(\"[\"+o+'=\"'+t+'\"]');s&&n&&n.forEach((t=>{const e=`--panel-${t.order}-size`;s.style.setProperty(e,t.size.toFixed(l))}))}"; diff --git a/packages/react-resizable-panels/src/scripts/persist.ts b/packages/react-resizable-panels/src/scripts/persist.ts index f12bad85a..0ee7e7fab 100644 --- a/packages/react-resizable-panels/src/scripts/persist.ts +++ b/packages/react-resizable-panels/src/scripts/persist.ts @@ -18,10 +18,8 @@ import type { function persist( autoSaveId: string | null, storageKeyPrefix: string, - panelIdDataAttributeName: string, - panelOrderDataAttributeName: string, - panelId: string, - panelSizeCssVar: string + panelAutoSaveIdDataAttributeName: string, + precision = 3 ): void { let state: SerializedPanelGroupState | null = null; try { @@ -46,28 +44,20 @@ function persist( const firstKey = keys[0]; const stateData = firstKey ? state[firstKey] : null; if (stateData && typeof stateData === "object" && "layout" in stateData) { - layout = stateData.layout; + layout = stateData.layout as PanelLayoutItem[]; } } } - const panel = document.querySelector( - "[" + panelIdDataAttributeName + '="' + panelId + '"]' + const panelGroup = document.querySelector( + "[" + panelAutoSaveIdDataAttributeName + '="' + autoSaveId + '"]' ) as HTMLElement | null; - if (panel && layout) { - const panelOrderAttr = panel.getAttribute( - panelOrderDataAttributeName || "" - ); - if (panelOrderAttr) { - const panelOrder = parseInt(panelOrderAttr, 10); - const item = layout.find(function (item) { - return item.order === panelOrder; - }); - if (item) { - panel.style.setProperty(panelSizeCssVar, String(item.size)); - } - } + if (panelGroup && layout) { + layout.forEach((item) => { + const cssVarName = `--panel-${item.order}-size`; + panelGroup.style.setProperty(cssVarName, item.size.toFixed(precision)); + }); } } diff --git a/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.test.ts b/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.test.ts index ff0372294..2bb023e1e 100644 --- a/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.test.ts +++ b/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.test.ts @@ -1,38 +1,17 @@ import { describe, expect, test } from "vitest"; -import { PanelConstraints, PanelData } from "../Panel"; import { computePanelFlexBoxStyle } from "./computePanelFlexBoxStyle"; describe("computePanelFlexBoxStyle", () => { - function createPanelData(constraints: PanelConstraints = {}): PanelData { - return { - callbacks: {}, - constraints, - id: "fake", - idIsFromProps: false, - order: undefined, - }; - } - - test("should observe a panel's default size if group layout has not yet been computed", () => { + test("should return flex styles with CSS variable for panel order", () => { expect( computePanelFlexBoxStyle({ - defaultSize: 0.1233456789, dragState: null, - layout: [], - panelData: [ - createPanelData({ - defaultSize: 0.1233456789, - }), - createPanelData(), - ], - panelIndex: 0, - precision: 2, + order: 1, }) ).toMatchInlineSnapshot(` { - "--panel-size": "0.12", "flexBasis": 0, - "flexGrow": "var(--panel-size)", + "flexGrow": "var(--panel-1-size)", "flexShrink": 1, "overflow": "hidden", "pointerEvents": undefined, @@ -40,21 +19,16 @@ describe("computePanelFlexBoxStyle", () => { `); }); - test("should always fill the full width for single-panel groups", () => { + test("should use correct order in CSS variable", () => { expect( computePanelFlexBoxStyle({ - defaultSize: undefined, dragState: null, - layout: [], - panelData: [createPanelData()], - panelIndex: 0, - precision: 2, + order: 3, }) ).toMatchInlineSnapshot(` { - "--panel-size": "1", "flexBasis": 0, - "flexGrow": "var(--panel-size)", + "flexGrow": "var(--panel-3-size)", "flexShrink": 1, "overflow": "hidden", "pointerEvents": undefined, @@ -62,67 +36,24 @@ describe("computePanelFlexBoxStyle", () => { `); }); - test("should round sizes to avoid floating point precision errors", () => { - const layout = [0.25435, 0.5758, 0.1698]; - const panelData = [createPanelData(), createPanelData(), createPanelData()]; - - expect( - computePanelFlexBoxStyle({ - defaultSize: undefined, - dragState: null, - layout, - panelData, - panelIndex: 0, - precision: 2, - }) - ).toMatchInlineSnapshot(` -{ - "--panel-size": "0.25", - "flexBasis": 0, - "flexGrow": "var(--panel-size)", - "flexShrink": 1, - "overflow": "hidden", - "pointerEvents": undefined, -} -`); - + test("should disable pointer events during drag", () => { expect( computePanelFlexBoxStyle({ - defaultSize: undefined, - dragState: null, - layout, - panelData, - panelIndex: 1, - precision: 2, + dragState: { + dragHandleId: "handle", + dragHandleRect: { x: 0, y: 0, width: 10, height: 10 } as DOMRect, + initialCursorPosition: 100, + initialLayout: [0.5, 0.5], + }, + order: 2, }) ).toMatchInlineSnapshot(` { - "--panel-size": "0.58", "flexBasis": 0, - "flexGrow": "var(--panel-size)", + "flexGrow": "var(--panel-2-size)", "flexShrink": 1, "overflow": "hidden", - "pointerEvents": undefined, -} -`); - - expect( - computePanelFlexBoxStyle({ - defaultSize: undefined, - dragState: null, - layout, - panelData, - panelIndex: 2, - precision: 2, - }) - ).toMatchInlineSnapshot(` -{ - "--panel-size": "0.17", - "flexBasis": 0, - "flexGrow": "var(--panel-size)", - "flexShrink": 1, - "overflow": "hidden", - "pointerEvents": undefined, + "pointerEvents": "none", } `); }); diff --git a/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.ts b/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.ts index 7735f7781..018f6f276 100644 --- a/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.ts +++ b/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.ts @@ -1,45 +1,21 @@ -// This method returns a number between 1 and 100 representing +// This method returns flex styles using CSS variables for panel sizes -import { PanelData } from "../Panel"; import { DragState } from "../PanelGroupContext"; import { CSSProperties } from "react"; export const panelSizeCssVar = "--panel-size"; -// the % of the group's overall space this panel should occupy. +// Returns flex styles that use CSS variables for panel sizes export function computePanelFlexBoxStyle({ - defaultSize, dragState, - layout, - panelData, - panelIndex, - precision = 3, + order, }: { - defaultSize: number | undefined; - layout: number[]; dragState: DragState | null; - panelData: PanelData[]; - panelIndex: number; - precision?: number; + order: number; }): CSSProperties { - const size = layout[panelIndex]; - - let flexGrow; - if (size == null) { - // Initial render (before panels have registered themselves) - // In order to support server rendering, fall back to default size if provided - flexGrow = defaultSize != undefined ? defaultSize.toFixed(precision) : "1"; - } else if (panelData.length === 1) { - // Special case: Single panel group should always fill full width/height - flexGrow = "1"; - } else { - flexGrow = size.toFixed(precision); - } - return { - [panelSizeCssVar]: flexGrow, flexBasis: 0, - flexGrow: `var(${panelSizeCssVar})`, + flexGrow: `var(--panel-${order}-size)`, flexShrink: 1, // Without this, Panel sizes may be unintentionally overridden by their content From 4bcae4cd2333dd85553a5057d895d2562ae1eed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sun, 2 Nov 2025 22:20:11 +0100 Subject: [PATCH 22/27] feat: add orderIsFromProps to panel data structure and update related tests --- .../react-resizable-panels/src/Panel.test.tsx | 295 +++++++++++++----- packages/react-resizable-panels/src/Panel.ts | 3 + .../src/PanelGroup.test.tsx | 38 ++- .../react-resizable-panels/src/PanelGroup.ts | 3 +- .../src/utils/calculateAriaValues.test.ts | 1 + .../calculateUnsafeDefaultLayout.test.ts | 1 + .../src/utils/serialization.test.ts | 1 + 7 files changed, 258 insertions(+), 84 deletions(-) diff --git a/packages/react-resizable-panels/src/Panel.test.tsx b/packages/react-resizable-panels/src/Panel.test.tsx index ed3f24b64..44c78c4cd 100644 --- a/packages/react-resizable-panels/src/Panel.test.tsx +++ b/packages/react-resizable-panels/src/Panel.test.tsx @@ -11,6 +11,7 @@ import { } from "."; import { assert } from "./utils/assert"; import { getPanelElement } from "./utils/dom/getPanelElement"; +import { getPanelGroupElement } from "./utils/dom/getPanelGroupElement"; import { mockPanelGroupOffsetWidthAndHeight, verifyAttribute, @@ -430,9 +431,11 @@ describe("PanelGroup", () => { describe("constraints", () => { test("should resize a collapsed panel if the collapsedSize prop changes", () => { + const panelGroupId = "test-panel-group-collapsed"; + act(() => { root.render( - + { ); }); - let leftElement = getPanelElement("left", container); - let middleElement = getPanelElement("middle", container); - let rightElement = getPanelElement("right", container); - assert(leftElement, ""); - assert(middleElement, ""); - assert(rightElement, ""); - expect(leftElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("10.0"); - expect(middleElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe( - "80.0" + const leftPanelElement = getPanelElement("left", container); + const leftElementOrder = leftPanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder + ); + const middlePanelElement = getPanelElement("middle", container); + const middleElementOrder = middlePanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder ); - expect(rightElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("10.0"); + const rightPanelElement = getPanelElement("right", container); + const rightElementOrder = rightPanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder + ); + + expect(leftElementOrder).toBe("1"); + expect(middleElementOrder).toBe("2"); + expect(rightElementOrder).toBe("3"); + + // get panel group element and select css variable with order + const panelGroupElement = getPanelGroupElement(panelGroupId, container); + const leftPanelSize = panelGroupElement?.style.getPropertyValue( + `--panel-${leftElementOrder}-size` + ); + const middlePanelSize = panelGroupElement?.style.getPropertyValue( + `--panel-${middleElementOrder}-size` + ); + const rightPanelSize = panelGroupElement?.style.getPropertyValue( + `--panel-${rightElementOrder}-size` + ); + + expect(leftPanelSize).toBe("10.000"); + expect(middlePanelSize).toBe("80.000"); + expect(rightPanelSize).toBe("10.000"); act(() => { root.render( - + @@ -478,17 +502,27 @@ describe("PanelGroup", () => { ); }); - expect(leftElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("5.0"); - expect(middleElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe( - "90.0" + const leftPanelSizeAfter = panelGroupElement?.style.getPropertyValue( + `--panel-${leftElementOrder}-size` + ); + const middlePanelSizeAfter = panelGroupElement?.style.getPropertyValue( + `--panel-${middleElementOrder}-size` + ); + const rightPanelSizeAfter = panelGroupElement?.style.getPropertyValue( + `--panel-${rightElementOrder}-size` ); - expect(rightElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("5.0"); + + expect(leftPanelSizeAfter).toBe("5.000"); + expect(middlePanelSizeAfter).toBe("90.000"); + expect(rightPanelSizeAfter).toBe("5.000"); }); test("it should not expand a collapsed panel if other constraints change", () => { + const panelGroupId = "test-panel-group-expand"; + act(() => { root.render( - + { ); }); - let leftElement = getPanelElement("left", container); - let middleElement = getPanelElement("middle", container); - let rightElement = getPanelElement("right", container); - assert(leftElement, ""); - assert(middleElement, ""); - assert(rightElement, ""); - expect(leftElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("10.0"); - expect(middleElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe( - "80.0" + const leftPanelElement = getPanelElement("left", container); + const leftElementOrder = leftPanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder + ); + const middlePanelElement = getPanelElement("middle", container); + const middleElementOrder = middlePanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder + ); + const rightPanelElement = getPanelElement("right", container); + const rightElementOrder = rightPanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder + ); + + expect(leftElementOrder).toBe("1"); + expect(middleElementOrder).toBe("2"); + expect(rightElementOrder).toBe("3"); + + // get panel group element and select css variable with order + const panelGroupElement = getPanelGroupElement(panelGroupId, container); + const leftPanelSize = panelGroupElement?.style.getPropertyValue( + `--panel-${leftElementOrder}-size` + ); + const middlePanelSize = panelGroupElement?.style.getPropertyValue( + `--panel-${middleElementOrder}-size` + ); + const rightPanelSize = panelGroupElement?.style.getPropertyValue( + `--panel-${rightElementOrder}-size` ); - expect(rightElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("10.0"); + + expect(leftPanelSize).toBe("10.000"); + expect(middlePanelSize).toBe("80.000"); + expect(rightPanelSize).toBe("10.000"); act(() => { root.render( - + @@ -534,17 +589,27 @@ describe("PanelGroup", () => { ); }); - expect(leftElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("10.0"); - expect(middleElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe( - "80.0" + const leftPanelSizeAfter = panelGroupElement?.style.getPropertyValue( + `--panel-${leftElementOrder}-size` ); - expect(rightElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("10.0"); + const middlePanelSizeAfter = panelGroupElement?.style.getPropertyValue( + `--panel-${middleElementOrder}-size` + ); + const rightPanelSizeAfter = panelGroupElement?.style.getPropertyValue( + `--panel-${rightElementOrder}-size` + ); + + expect(leftPanelSizeAfter).toBe("10.000"); + expect(middlePanelSizeAfter).toBe("80.000"); + expect(rightPanelSizeAfter).toBe("10.000"); }); test("should resize a panel if the minSize prop changes", () => { + const panelGroupId = "test-panel-group-minsize"; + act(() => { root.render( - + @@ -554,21 +619,42 @@ describe("PanelGroup", () => { ); }); - let leftElement = getPanelElement("left", container); - let middleElement = getPanelElement("middle", container); - let rightElement = getPanelElement("right", container); - assert(leftElement, ""); - assert(middleElement, ""); - assert(rightElement, ""); - expect(leftElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("15.0"); - expect(middleElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe( - "70.0" + const leftPanelElement = getPanelElement("left", container); + const leftElementOrder = leftPanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder + ); + const middlePanelElement = getPanelElement("middle", container); + const middleElementOrder = middlePanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder + ); + const rightPanelElement = getPanelElement("right", container); + const rightElementOrder = rightPanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder ); - expect(rightElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("15.0"); + + expect(leftElementOrder).toBe("1"); + expect(middleElementOrder).toBe("2"); + expect(rightElementOrder).toBe("3"); + + // get panel group element and select css variable with order + const panelGroupElement = getPanelGroupElement(panelGroupId, container); + const leftPanelSize = panelGroupElement?.style.getPropertyValue( + `--panel-${leftElementOrder}-size` + ); + const middlePanelSize = panelGroupElement?.style.getPropertyValue( + `--panel-${middleElementOrder}-size` + ); + const rightPanelSize = panelGroupElement?.style.getPropertyValue( + `--panel-${rightElementOrder}-size` + ); + + expect(leftPanelSize).toBe("15.000"); + expect(middlePanelSize).toBe("70.000"); + expect(rightPanelSize).toBe("15.000"); act(() => { root.render( - + @@ -578,17 +664,27 @@ describe("PanelGroup", () => { ); }); - expect(leftElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("20.0"); - expect(middleElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe( - "60.0" + const leftPanelSizeAfter = panelGroupElement?.style.getPropertyValue( + `--panel-${leftElementOrder}-size` + ); + const middlePanelSizeAfter = panelGroupElement?.style.getPropertyValue( + `--panel-${middleElementOrder}-size` ); - expect(rightElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("20.0"); + const rightPanelSizeAfter = panelGroupElement?.style.getPropertyValue( + `--panel-${rightElementOrder}-size` + ); + + expect(leftPanelSizeAfter).toBe("20.000"); + expect(middlePanelSizeAfter).toBe("60.000"); + expect(rightPanelSizeAfter).toBe("20.000"); }); test("should resize a panel if the maxSize prop changes", () => { + const panelGroupId = "test-panel-group"; + act(() => { root.render( - + @@ -598,21 +694,42 @@ describe("PanelGroup", () => { ); }); - let leftElement = getPanelElement("left", container); - let middleElement = getPanelElement("middle", container); - let rightElement = getPanelElement("right", container); - assert(leftElement, ""); - assert(middleElement, ""); - assert(rightElement, ""); - expect(leftElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("25.0"); - expect(middleElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe( - "50.0" + const leftPanelElement = getPanelElement("left", container); + const leftElementOrder = leftPanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder + ); + const middlePanelElement = getPanelElement("middle", container); + const middleElementOrder = middlePanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder ); - expect(rightElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("25.0"); + const rightPanelElement = getPanelElement("right", container); + const rightElementOrder = rightPanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder + ); + + expect(leftElementOrder).toBe("1"); + expect(middleElementOrder).toBe("2"); + expect(rightElementOrder).toBe("3"); + + // get panel group element and select css variable with order + const panelGroupElement = getPanelGroupElement(panelGroupId, container); + const leftPanelSize = panelGroupElement?.style.getPropertyValue( + `--panel-${leftElementOrder}-size` + ); + const middlePanelSize = panelGroupElement?.style.getPropertyValue( + `--panel-${middleElementOrder}-size` + ); + const rightPanelSize = panelGroupElement?.style.getPropertyValue( + `--panel-${rightElementOrder}-size` + ); + + expect(leftPanelSize).toBe("25.000"); + expect(middlePanelSize).toBe("50.000"); + expect(rightPanelSize).toBe("25.000"); act(() => { root.render( - + @@ -622,11 +739,19 @@ describe("PanelGroup", () => { ); }); - expect(leftElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("20.0"); - expect(middleElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe( - "60.0" + const leftPanelSizeAfter = panelGroupElement?.style.getPropertyValue( + `--panel-${leftElementOrder}-size` + ); + const middlePanelSizeAfter = panelGroupElement?.style.getPropertyValue( + `--panel-${middleElementOrder}-size` ); - expect(rightElement.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe("20.0"); + const rightPanelSizeAfter = panelGroupElement?.style.getPropertyValue( + `--panel-${rightElementOrder}-size` + ); + + expect(leftPanelSizeAfter).toBe("20.000"); + expect(middlePanelSizeAfter).toBe("60.000"); + expect(rightPanelSizeAfter).toBe("20.000"); }); }); @@ -978,22 +1103,21 @@ describe("PanelGroup", () => { verifyAttribute(leftElement, DATA_ATTRIBUTES.panel, ""); verifyAttribute(leftElement, DATA_ATTRIBUTES.panelId, "left-panel"); verifyAttribute(leftElement, DATA_ATTRIBUTES.groupId, "test-group"); - verifyAttribute(leftElement, DATA_ATTRIBUTES.panelSize, "75.0"); verifyAttribute(leftElement, DATA_ATTRIBUTES.panelCollapsible, null); verifyAttribute(rightElement, DATA_ATTRIBUTES.panel, ""); verifyAttribute(rightElement, DATA_ATTRIBUTES.panelId, "right-panel"); verifyAttribute(rightElement, DATA_ATTRIBUTES.groupId, "test-group"); - verifyAttribute(rightElement, DATA_ATTRIBUTES.panelSize, "25.0"); verifyAttribute(rightElement, DATA_ATTRIBUTES.panelCollapsible, "true"); }); - test("should update the data-panel-size attribute when the panel resizes", () => { + test("should update the CSS variables when the panel resizes", () => { const leftPanelRef = createRef(); + const panelGroupId = "test-group-resize"; act(() => { root.render( - + @@ -1007,15 +1131,42 @@ describe("PanelGroup", () => { assert(leftElement, ""); assert(rightElement, ""); - verifyAttribute(leftElement, DATA_ATTRIBUTES.panelSize, "75.0"); - verifyAttribute(rightElement, DATA_ATTRIBUTES.panelSize, "25.0"); + const leftElementOrder = leftElement.getAttribute( + DATA_ATTRIBUTES.panelOrder + ); + const rightElementOrder = rightElement.getAttribute( + DATA_ATTRIBUTES.panelOrder + ); + const panelGroupElement = getPanelGroupElement(panelGroupId, container); + + expect(leftElementOrder).toBe("1"); + expect(rightElementOrder).toBe("2"); + + // Check initial CSS variable values + const leftInitialSize = panelGroupElement?.style.getPropertyValue( + `--panel-${leftElementOrder}-size` + ); + const rightInitialSize = panelGroupElement?.style.getPropertyValue( + `--panel-${rightElementOrder}-size` + ); + + expect(leftInitialSize).toBe("75.000"); + expect(rightInitialSize).toBe("25.000"); act(() => { leftPanelRef.current?.resize(30); }); - verifyAttribute(leftElement, DATA_ATTRIBUTES.panelSize, "30.0"); - verifyAttribute(rightElement, DATA_ATTRIBUTES.panelSize, "70.0"); + // Check CSS variable values after resize + const leftResizedSize = panelGroupElement?.style.getPropertyValue( + `--panel-${leftElementOrder}-size` + ); + const rightResizedSize = panelGroupElement?.style.getPropertyValue( + `--panel-${rightElementOrder}-size` + ); + + expect(leftResizedSize).toBe("30.000"); + expect(rightResizedSize).toBe("70.000"); }); }); diff --git a/packages/react-resizable-panels/src/Panel.ts b/packages/react-resizable-panels/src/Panel.ts index e118728ec..56c3f39cd 100644 --- a/packages/react-resizable-panels/src/Panel.ts +++ b/packages/react-resizable-panels/src/Panel.ts @@ -45,6 +45,7 @@ export type PanelData = { id: string; idIsFromProps: boolean; order: number; + orderIsFromProps: boolean; }; export type ImperativePanelHandle = { @@ -141,6 +142,7 @@ export function PanelWithForwardedRef({ id: panelId, idIsFromProps: idFromProps !== undefined, order: assignedOrderRef.current, + orderIsFromProps: orderFromProps !== undefined, }); const devWarningsRef = useRef<{ @@ -170,6 +172,7 @@ export function PanelWithForwardedRef({ panelDataRef.current.id = panelId; panelDataRef.current.idIsFromProps = idFromProps !== undefined; panelDataRef.current.order = assignedOrderRef.current as number; + panelDataRef.current.orderIsFromProps = orderFromProps !== undefined; callbacks.onCollapse = onCollapse; callbacks.onExpand = onExpand; diff --git a/packages/react-resizable-panels/src/PanelGroup.test.tsx b/packages/react-resizable-panels/src/PanelGroup.test.tsx index 7c7d8b0c7..e945d270e 100644 --- a/packages/react-resizable-panels/src/PanelGroup.test.tsx +++ b/packages/react-resizable-panels/src/PanelGroup.test.tsx @@ -71,6 +71,7 @@ describe("PanelGroup", () => { }); test("should recalculate layout after being hidden by Activity", () => { + const panelGroupId = "test-panel-group"; const panelRef = createRef(); let mostRecentLayout: number[] | null = null; @@ -82,7 +83,11 @@ describe("PanelGroup", () => { act(() => { root.render( - + @@ -95,14 +100,29 @@ describe("PanelGroup", () => { expect(panelRef.current?.getSize()).toEqual(60); const leftPanelElement = getPanelElement("left"); + const leftElementOrder = leftPanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder + ); const rightPanelElement = getPanelElement("right"); - expect(leftPanelElement?.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe( - "60.0" + const rightElementOrder = rightPanelElement?.getAttribute( + DATA_ATTRIBUTES.panelOrder ); - expect(rightPanelElement?.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe( - "40.0" + + expect(leftElementOrder).toBe("1"); + expect(rightElementOrder).toBe("2"); + + // get panel group element and select css variable with order + const panelGroupElement = getPanelGroupElement(panelGroupId, container); + const leftPanelOrder = panelGroupElement?.style.getPropertyValue( + `--panel-${leftElementOrder}-size` + ); + const rightPanelOrder = panelGroupElement?.style.getPropertyValue( + `--panel-${rightElementOrder}-size` ); + expect(leftPanelOrder).toBe("60.000"); + expect(rightPanelOrder).toBe("40.000"); + act(() => { root.render( @@ -131,12 +151,8 @@ describe("PanelGroup", () => { expect(panelRef.current?.getSize()).toEqual(60); // This bug is only observable in the DOM; callbacks will not re-fire - expect(leftPanelElement?.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe( - "60.0" - ); - expect(rightPanelElement?.getAttribute(DATA_ATTRIBUTES.panelSize)).toBe( - "40.0" - ); + expect(leftPanelOrder).toBe("60.000"); + expect(rightPanelOrder).toBe("40.000"); }); // github.com/bvaughn/react-resizable-panels/issues/303 diff --git a/packages/react-resizable-panels/src/PanelGroup.ts b/packages/react-resizable-panels/src/PanelGroup.ts index 50b953ea0..0470a04cf 100644 --- a/packages/react-resizable-panels/src/PanelGroup.ts +++ b/packages/react-resizable-panels/src/PanelGroup.ts @@ -290,7 +290,8 @@ function PanelGroupWithForwardedRef({ if (panelsHaveChanged) { if ( panelDataArray.find( - ({ idIsFromProps, order }) => !idIsFromProps || order == null + ({ idIsFromProps, orderIsFromProps }) => + !idIsFromProps || !orderIsFromProps ) ) { devWarningsRef.current.didLogIdAndOrderWarning = true; diff --git a/packages/react-resizable-panels/src/utils/calculateAriaValues.test.ts b/packages/react-resizable-panels/src/utils/calculateAriaValues.test.ts index 9644ce746..07cf00cb8 100644 --- a/packages/react-resizable-panels/src/utils/calculateAriaValues.test.ts +++ b/packages/react-resizable-panels/src/utils/calculateAriaValues.test.ts @@ -17,6 +17,7 @@ describe("calculateAriaValues", () => { id: `${idCounter++}`, idIsFromProps: false, order: orderCounter++, + orderIsFromProps: false, }; } diff --git a/packages/react-resizable-panels/src/utils/calculateUnsafeDefaultLayout.test.ts b/packages/react-resizable-panels/src/utils/calculateUnsafeDefaultLayout.test.ts index ac29d8b50..e68c6f7f4 100644 --- a/packages/react-resizable-panels/src/utils/calculateUnsafeDefaultLayout.test.ts +++ b/packages/react-resizable-panels/src/utils/calculateUnsafeDefaultLayout.test.ts @@ -18,6 +18,7 @@ describe("calculateUnsafeDefaultLayout", () => { id: `${idCounter++}`, idIsFromProps: false, order: orderCounter++, + orderIsFromProps: false, }; } diff --git a/packages/react-resizable-panels/src/utils/serialization.test.ts b/packages/react-resizable-panels/src/utils/serialization.test.ts index 5ede32757..9739d9f07 100644 --- a/packages/react-resizable-panels/src/utils/serialization.test.ts +++ b/packages/react-resizable-panels/src/utils/serialization.test.ts @@ -59,6 +59,7 @@ describe("serialization", () => { id, idIsFromProps, order, + orderIsFromProps: false, }); test("should save and load panel state with new format (with order)", () => { From 86d27639d60c7257fc79b9cfa780c7aada2f0cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sun, 2 Nov 2025 22:33:38 +0100 Subject: [PATCH 23/27] feat: replace PanelPersistScript with PersistScript and update documentation --- examples/nextjs/src/app/page.tsx | 8 +++---- packages/react-resizable-panels/README.md | 24 ++++++++----------- ...nelPersistScript.tsx => PersistScript.tsx} | 3 +-- packages/react-resizable-panels/src/index.ts | 4 ++-- 4 files changed, 17 insertions(+), 22 deletions(-) rename packages/react-resizable-panels/src/{PanelPersistScript.tsx => PersistScript.tsx} (88%) diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index 3b68e4cb5..731e910ef 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { Panel, PanelGroup, PanelPersistScript } from "react-resizable-panels"; +import { Panel, PanelGroup, PersistScript } from "react-resizable-panels"; import { ResizeHandle } from "@/components/ResizeHandle"; import styles from "@/components/shared.module.css"; @@ -14,7 +14,7 @@ export default function Home() { autoSaveId="l1" direction="horizontal" > - + - + - + - - + + + {/* Panel content */} - - + {/* Panel content */} diff --git a/packages/react-resizable-panels/src/PanelPersistScript.tsx b/packages/react-resizable-panels/src/PersistScript.tsx similarity index 88% rename from packages/react-resizable-panels/src/PanelPersistScript.tsx rename to packages/react-resizable-panels/src/PersistScript.tsx index 04ed8e9e1..e4fe9f25f 100644 --- a/packages/react-resizable-panels/src/PanelPersistScript.tsx +++ b/packages/react-resizable-panels/src/PersistScript.tsx @@ -1,7 +1,6 @@ import { createElement } from "react"; import { DEFAULT_STORAGE_KEY_PREFIX } from "./utils/serialization"; import { DATA_ATTRIBUTES } from "./constants"; -import { panelSizeCssVar } from "./utils/computePanelFlexBoxStyle"; import { MINIFIED_PERSIST } from "./scripts/persist.minified"; import { useIsSSR } from "./hooks/useIsSSR"; @@ -11,7 +10,7 @@ export interface PersistScriptProps { nonce?: string; } -export const PanelPersistScript = ({ +export const PersistScript = ({ nonce, autoSaveId, storageKeyPrefix = DEFAULT_STORAGE_KEY_PREFIX, diff --git a/packages/react-resizable-panels/src/index.ts b/packages/react-resizable-panels/src/index.ts index b8da5c01a..2511c809b 100644 --- a/packages/react-resizable-panels/src/index.ts +++ b/packages/react-resizable-panels/src/index.ts @@ -1,7 +1,7 @@ import { Panel } from "./Panel"; import { PanelGroup } from "./PanelGroup"; import { PanelResizeHandle } from "./PanelResizeHandle"; -import { PanelPersistScript } from "./PanelPersistScript"; +import { PersistScript } from "./PersistScript"; import { DATA_ATTRIBUTES } from "./constants"; import { usePanelGroupContext } from "./hooks/usePanelGroupContext"; import { assert } from "./utils/assert"; @@ -60,7 +60,7 @@ export { Panel, PanelGroup, PanelResizeHandle, - PanelPersistScript, + PersistScript, // Hooks usePanelGroupContext, From 3a21cd0412a5a76b442909866b7aca0699fa10c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Sun, 2 Nov 2025 23:42:06 +0100 Subject: [PATCH 24/27] feat: refactor panel size handling with CSS variable template and update persist logic --- examples/nextjs/src/app/page.tsx | 7 ------- packages/react-resizable-panels/src/PanelGroup.ts | 9 +++++++-- packages/react-resizable-panels/src/PersistScript.tsx | 3 ++- packages/react-resizable-panels/src/constants.ts | 2 ++ .../src/scripts/persist.minified.ts | 2 +- packages/react-resizable-panels/src/scripts/persist.ts | 6 +++++- 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index 731e910ef..a5d79506d 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -19,7 +19,6 @@ export default function Home() { className={styles.PanelRow} defaultSize={20} minSize={10} - id="l1:left" suppressHydrationWarning >
left
@@ -29,7 +28,6 @@ export default function Home() { className={styles.PanelRow} minSize={35} defaultSize={60} - id="l1:middle" suppressHydrationWarning >
top
@@ -52,7 +49,6 @@ export default function Home() { className={styles.PanelColumn} defaultSize={65} minSize={10} - id="l2:bottom" suppressHydrationWarning >
left
@@ -75,7 +70,6 @@ export default function Home() { className={styles.PanelRow} defaultSize={50} minSize={10} - id="l3:right" suppressHydrationWarning >
right
@@ -89,7 +83,6 @@ export default function Home() { className={styles.PanelRow} defaultSize={20} minSize={10} - id="l1:right" suppressHydrationWarning >
right
diff --git a/packages/react-resizable-panels/src/PanelGroup.ts b/packages/react-resizable-panels/src/PanelGroup.ts index 0470a04cf..9075a459a 100644 --- a/packages/react-resizable-panels/src/PanelGroup.ts +++ b/packages/react-resizable-panels/src/PanelGroup.ts @@ -28,7 +28,7 @@ import { EXCEEDED_VERTICAL_MIN, reportConstraintsViolation, } from "./PanelResizeHandleRegistry"; -import { DATA_ATTRIBUTES } from "./constants"; +import { DATA_ATTRIBUTES, PANEL_SIZE_CSS_VARIABLE_TEMPLATE } from "./constants"; import { useForceUpdate } from "./hooks/useForceUpdate"; import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect"; import useUniqueId from "./hooks/useUniqueId"; @@ -957,7 +957,12 @@ function PanelGroupWithForwardedRef({ flexGrow = size.toFixed(precision); } - cssVars[`--panel-${panelData.order}-size`] = flexGrow; + cssVars[ + PANEL_SIZE_CSS_VARIABLE_TEMPLATE.replace( + "%s", + panelData.order.toString() + ) + ] = flexGrow; } return cssVars; diff --git a/packages/react-resizable-panels/src/PersistScript.tsx b/packages/react-resizable-panels/src/PersistScript.tsx index e4fe9f25f..a73dd1cbb 100644 --- a/packages/react-resizable-panels/src/PersistScript.tsx +++ b/packages/react-resizable-panels/src/PersistScript.tsx @@ -1,6 +1,6 @@ import { createElement } from "react"; import { DEFAULT_STORAGE_KEY_PREFIX } from "./utils/serialization"; -import { DATA_ATTRIBUTES } from "./constants"; +import { DATA_ATTRIBUTES, PANEL_SIZE_CSS_VARIABLE_TEMPLATE } from "./constants"; import { MINIFIED_PERSIST } from "./scripts/persist.minified"; import { useIsSSR } from "./hooks/useIsSSR"; @@ -25,6 +25,7 @@ export const PersistScript = ({ autoSaveId, storageKeyPrefix, DATA_ATTRIBUTES.autoSaveId, + PANEL_SIZE_CSS_VARIABLE_TEMPLATE, ]).slice(1, -1); return createElement("script", { diff --git a/packages/react-resizable-panels/src/constants.ts b/packages/react-resizable-panels/src/constants.ts index 0c91a764e..331debd7f 100644 --- a/packages/react-resizable-panels/src/constants.ts +++ b/packages/react-resizable-panels/src/constants.ts @@ -15,3 +15,5 @@ export const DATA_ATTRIBUTES = { } as const; export const PRECISION = 10; + +export const PANEL_SIZE_CSS_VARIABLE_TEMPLATE = "--panel-%s-size"; diff --git a/packages/react-resizable-panels/src/scripts/persist.minified.ts b/packages/react-resizable-panels/src/scripts/persist.minified.ts index 8a692747c..a8bf3f0e9 100644 --- a/packages/react-resizable-panels/src/scripts/persist.minified.ts +++ b/packages/react-resizable-panels/src/scripts/persist.minified.ts @@ -6,4 +6,4 @@ * Minified version of persist.ts * Pre-minified to match browser bundle transformations. */ -export const MINIFIED_PERSIST = "function persist(t,e,o,l=3){let c=null;try{const o=t&&localStorage.getItem(e+\":\"+t);if(o){const t=JSON.parse(o);\"object\"==typeof t&&null!=t&&(c=t)}}catch(t){}if(!c)return;let n=null;if(c&&\"object\"==typeof c){const t=Object.keys(c);if(t.length>0){const e=t[0],o=e?c[e]:null;o&&\"object\"==typeof o&&\"layout\"in o&&(n=o.layout)}}const s=document.querySelector(\"[\"+o+'=\"'+t+'\"]');s&&n&&n.forEach((t=>{const e=`--panel-${t.order}-size`;s.style.setProperty(e,t.size.toFixed(l))}))}"; +export const MINIFIED_PERSIST = "function persist(t,e,o,c,l=3){let n=null;try{const o=t&&localStorage.getItem(e+\":\"+t);if(o){const t=JSON.parse(o);\"object\"==typeof t&&null!=t&&(n=t)}}catch(t){}if(!n)return;let r=null;if(n&&\"object\"==typeof n){const t=Object.keys(n);if(t.length>0){const e=t[0],o=e?n[e]:null;o&&\"object\"==typeof o&&\"layout\"in o&&(r=o.layout)}}const s=document.querySelector(\"[\"+o+'=\"'+t+'\"]');s&&r&&r.forEach((t=>{const e=c.replace(\"%s\",t.order.toString());s.style.setProperty(e,t.size.toFixed(l))}))}"; diff --git a/packages/react-resizable-panels/src/scripts/persist.ts b/packages/react-resizable-panels/src/scripts/persist.ts index 0ee7e7fab..fcc4d512d 100644 --- a/packages/react-resizable-panels/src/scripts/persist.ts +++ b/packages/react-resizable-panels/src/scripts/persist.ts @@ -19,6 +19,7 @@ function persist( autoSaveId: string | null, storageKeyPrefix: string, panelAutoSaveIdDataAttributeName: string, + panelSizeCssVariableTemplate: string, precision = 3 ): void { let state: SerializedPanelGroupState | null = null; @@ -55,7 +56,10 @@ function persist( if (panelGroup && layout) { layout.forEach((item) => { - const cssVarName = `--panel-${item.order}-size`; + const cssVarName = panelSizeCssVariableTemplate.replace( + "%s", + item.order.toString() + ); panelGroup.style.setProperty(cssVarName, item.size.toFixed(precision)); }); } From 170b78253ac5c424b7d9f1605e677cff98647b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Mon, 3 Nov 2025 00:26:38 +0100 Subject: [PATCH 25/27] feat: streamline panel persistence logic and enhance CSS variable handling --- examples/nextjs/src/app/page.tsx | 29 +------ packages/react-resizable-panels/src/Panel.ts | 1 - .../react-resizable-panels/src/PanelGroup.ts | 3 +- .../src/PersistScript.tsx | 2 - .../react-resizable-panels/src/constants.ts | 1 + .../src/scripts/persist.minified.ts | 2 +- .../src/scripts/persist.ts | 87 +++++++++++-------- .../src/utils/computePanelFlexBoxStyle.ts | 19 +++- 8 files changed, 77 insertions(+), 67 deletions(-) diff --git a/examples/nextjs/src/app/page.tsx b/examples/nextjs/src/app/page.tsx index a5d79506d..c138390ef 100644 --- a/examples/nextjs/src/app/page.tsx +++ b/examples/nextjs/src/app/page.tsx @@ -9,38 +9,26 @@ export default function Home() {
+ - - +
left
- + -
top
@@ -49,19 +37,16 @@ export default function Home() { className={styles.PanelColumn} defaultSize={65} minSize={10} - suppressHydrationWarning > -
left
@@ -70,7 +55,6 @@ export default function Home() { className={styles.PanelRow} defaultSize={50} minSize={10} - suppressHydrationWarning >
right
@@ -79,12 +63,7 @@ export default function Home() {
- +
right
diff --git a/packages/react-resizable-panels/src/Panel.ts b/packages/react-resizable-panels/src/Panel.ts index 56c3f39cd..73be23f81 100644 --- a/packages/react-resizable-panels/src/Panel.ts +++ b/packages/react-resizable-panels/src/Panel.ts @@ -16,7 +16,6 @@ import { PanelGroupContext } from "./PanelGroupContext"; import { DATA_ATTRIBUTES } from "./constants"; import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect"; import useUniqueId from "./hooks/useUniqueId"; -import { panelSizeCssVar } from "./utils/computePanelFlexBoxStyle"; export type PanelOnCollapse = () => void; export type PanelOnExpand = () => void; diff --git a/packages/react-resizable-panels/src/PanelGroup.ts b/packages/react-resizable-panels/src/PanelGroup.ts index 9075a459a..87793d6b9 100644 --- a/packages/react-resizable-panels/src/PanelGroup.ts +++ b/packages/react-resizable-panels/src/PanelGroup.ts @@ -481,9 +481,10 @@ function PanelGroupWithForwardedRef({ return computePanelFlexBoxStyle({ dragState, order: panelData.order, + autoSaveId, }); }, - [dragState] + [dragState, autoSaveId] ); // External APIs are safe to memoize via committed values ref diff --git a/packages/react-resizable-panels/src/PersistScript.tsx b/packages/react-resizable-panels/src/PersistScript.tsx index a73dd1cbb..c8e86efc3 100644 --- a/packages/react-resizable-panels/src/PersistScript.tsx +++ b/packages/react-resizable-panels/src/PersistScript.tsx @@ -22,9 +22,7 @@ export const PersistScript = ({ } const scriptArgs = JSON.stringify([ - autoSaveId, storageKeyPrefix, - DATA_ATTRIBUTES.autoSaveId, PANEL_SIZE_CSS_VARIABLE_TEMPLATE, ]).slice(1, -1); diff --git a/packages/react-resizable-panels/src/constants.ts b/packages/react-resizable-panels/src/constants.ts index 331debd7f..19c376b8e 100644 --- a/packages/react-resizable-panels/src/constants.ts +++ b/packages/react-resizable-panels/src/constants.ts @@ -16,4 +16,5 @@ export const DATA_ATTRIBUTES = { export const PRECISION = 10; +// %s will be replaced with `order` or `autoSaveId-order` export const PANEL_SIZE_CSS_VARIABLE_TEMPLATE = "--panel-%s-size"; diff --git a/packages/react-resizable-panels/src/scripts/persist.minified.ts b/packages/react-resizable-panels/src/scripts/persist.minified.ts index a8bf3f0e9..ec0e3c589 100644 --- a/packages/react-resizable-panels/src/scripts/persist.minified.ts +++ b/packages/react-resizable-panels/src/scripts/persist.minified.ts @@ -6,4 +6,4 @@ * Minified version of persist.ts * Pre-minified to match browser bundle transformations. */ -export const MINIFIED_PERSIST = "function persist(t,e,o,c,l=3){let n=null;try{const o=t&&localStorage.getItem(e+\":\"+t);if(o){const t=JSON.parse(o);\"object\"==typeof t&&null!=t&&(n=t)}}catch(t){}if(!n)return;let r=null;if(n&&\"object\"==typeof n){const t=Object.keys(n);if(t.length>0){const e=t[0],o=e?n[e]:null;o&&\"object\"==typeof o&&\"layout\"in o&&(r=o.layout)}}const s=document.querySelector(\"[\"+o+'=\"'+t+'\"]');s&&r&&r.forEach((t=>{const e=c.replace(\"%s\",t.order.toString());s.style.setProperty(e,t.size.toFixed(l))}))}"; +export const MINIFIED_PERSIST = "function persist(t,e,o=3){const n=[];for(let c=0;c0){const e=t[0],o=e?i[e]:null;o&&\"object\"==typeof o&&\"layout\"in o&&(a=o.layout)}}a&&a.forEach((t=>{const c=e.replace(\"%s\",`${s}-${t.order.toString()}`);n.push(`${c}: ${t.size.toFixed(o)};`)}))}if(n.length>0){const t=new CSSStyleSheet;t.replaceSync(`:root { ${n.join(\" \")} }`),document.adoptedStyleSheets=[...document.adoptedStyleSheets,t]}}"; diff --git a/packages/react-resizable-panels/src/scripts/persist.ts b/packages/react-resizable-panels/src/scripts/persist.ts index fcc4d512d..d6d264258 100644 --- a/packages/react-resizable-panels/src/scripts/persist.ts +++ b/packages/react-resizable-panels/src/scripts/persist.ts @@ -16,52 +16,71 @@ import type { * Restores panel sizes from localStorage to prevent layout shift. */ function persist( - autoSaveId: string | null, storageKeyPrefix: string, - panelAutoSaveIdDataAttributeName: string, panelSizeCssVariableTemplate: string, precision = 3 ): void { - let state: SerializedPanelGroupState | null = null; - try { - const rawState = - autoSaveId && localStorage.getItem(storageKeyPrefix + ":" + autoSaveId); - if (rawState) { - const parsedState = JSON.parse(rawState); - if (typeof parsedState === "object" && parsedState != null) { - state = parsedState as SerializedPanelGroupState; + const cssRules: string[] = []; + + for (let i = 0; i < localStorage.length; i++) { + const key = localStorage.key(i); + if (!key || !key.startsWith(storageKeyPrefix + ":")) { + continue; + } + + const autoSaveId = key.substring(storageKeyPrefix.length + 1); + if (!autoSaveId) { + continue; + } + + let state: SerializedPanelGroupState | null = null; + try { + const rawState = localStorage.getItem(key); + if (rawState) { + const parsedState = JSON.parse(rawState); + if (typeof parsedState === "object" && parsedState != null) { + state = parsedState as SerializedPanelGroupState; + } } + } catch (error) { + continue; } - } catch (error) {} - if (!state) { - return; - } + if (!state) { + continue; + } - let layout: PanelLayoutItem[] | null = null; - if (state && typeof state === "object") { - const keys = Object.keys(state); - if (keys.length > 0) { - const firstKey = keys[0]; - const stateData = firstKey ? state[firstKey] : null; - if (stateData && typeof stateData === "object" && "layout" in stateData) { - layout = stateData.layout as PanelLayoutItem[]; + let layout: PanelLayoutItem[] | null = null; + if (state && typeof state === "object") { + const keys = Object.keys(state); + if (keys.length > 0) { + const firstKey = keys[0]; + const stateData = firstKey ? state[firstKey] : null; + if ( + stateData && + typeof stateData === "object" && + "layout" in stateData + ) { + layout = stateData.layout as PanelLayoutItem[]; + } } } - } - const panelGroup = document.querySelector( - "[" + panelAutoSaveIdDataAttributeName + '="' + autoSaveId + '"]' - ) as HTMLElement | null; + if (layout) { + layout.forEach((item) => { + const cssVarName = panelSizeCssVariableTemplate.replace( + "%s", + `${autoSaveId}-${item.order.toString()}` + ); + cssRules.push(`${cssVarName}: ${item.size.toFixed(precision)};`); + }); + } + } - if (panelGroup && layout) { - layout.forEach((item) => { - const cssVarName = panelSizeCssVariableTemplate.replace( - "%s", - item.order.toString() - ); - panelGroup.style.setProperty(cssVarName, item.size.toFixed(precision)); - }); + if (cssRules.length > 0) { + const sheet = new CSSStyleSheet(); + sheet.replaceSync(`:root { ${cssRules.join(" ")} }`); + document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet]; } } diff --git a/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.ts b/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.ts index 018f6f276..7763b2584 100644 --- a/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.ts +++ b/packages/react-resizable-panels/src/utils/computePanelFlexBoxStyle.ts @@ -1,21 +1,34 @@ // This method returns flex styles using CSS variables for panel sizes +import { PANEL_SIZE_CSS_VARIABLE_TEMPLATE } from "../constants"; import { DragState } from "../PanelGroupContext"; import { CSSProperties } from "react"; -export const panelSizeCssVar = "--panel-size"; - // Returns flex styles that use CSS variables for panel sizes export function computePanelFlexBoxStyle({ dragState, order, + autoSaveId = null, }: { dragState: DragState | null; order: number; + autoSaveId?: string | null; }): CSSProperties { + const panelSizeCssVar = PANEL_SIZE_CSS_VARIABLE_TEMPLATE.replace( + "%s", + order.toString() + ); + const panelRootSizeCssVar = PANEL_SIZE_CSS_VARIABLE_TEMPLATE.replace( + "%s", + `${autoSaveId}-${order.toString()}` + ); + const flexGrow = autoSaveId + ? `var(${panelSizeCssVar}, var(${panelRootSizeCssVar}))` + : `var(${panelSizeCssVar})`; + return { flexBasis: 0, - flexGrow: `var(--panel-${order}-size)`, + flexGrow, flexShrink: 1, // Without this, Panel sizes may be unintentionally overridden by their content From d28f085849bbddce839df904e06c9e2880d8ae9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Mon, 3 Nov 2025 00:43:04 +0100 Subject: [PATCH 26/27] feat: remove suppressHydrationWarning from PanelGroupWithForwardedRef --- packages/react-resizable-panels/src/PanelGroup.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/react-resizable-panels/src/PanelGroup.ts b/packages/react-resizable-panels/src/PanelGroup.ts index 87793d6b9..2b391587c 100644 --- a/packages/react-resizable-panels/src/PanelGroup.ts +++ b/packages/react-resizable-panels/src/PanelGroup.ts @@ -1000,8 +1000,6 @@ function PanelGroupWithForwardedRef({ [DATA_ATTRIBUTES.groupDirection]: direction, [DATA_ATTRIBUTES.groupId]: groupId, [DATA_ATTRIBUTES.autoSaveId]: autoSaveId || undefined, - - suppressHydrationWarning: true, }) ); } From 6c2e55f98aee8d218f7f4b40079ab016e3861c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivica=20Batini=C4=87?= Date: Mon, 3 Nov 2025 00:52:41 +0100 Subject: [PATCH 27/27] chore: update readme --- packages/react-resizable-panels/README.md | 39 +++++++++++++---------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/packages/react-resizable-panels/README.md b/packages/react-resizable-panels/README.md index 76b9cd7ad..2fc93581f 100644 --- a/packages/react-resizable-panels/README.md +++ b/packages/react-resizable-panels/README.md @@ -100,7 +100,6 @@ import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels"; | prop | type | description | | :----------- | :------------ | :-------------------------------------------------------------------------------------------- | -| `autoSaveId` | `string` | Must match the parent `PanelGroup`'s `autoSaveId` prop | --- @@ -192,12 +191,7 @@ By default, this library uses `localStorage` to persist layouts. With server ren #### Option 1: Using `PersistScript` The `PersistScript` component synchronously applies the persisted layout before React hydration, eliminating layout flicker. - -**Requirements:** - -- `PersistScript` must be placed as the **first child** of each `PanelGroup` -- `autoSaveId` prop must match the `PanelGroup`'s `autoSaveId` -- `suppressHydrationWarning` prop should be added to `PanelGroup` components to avoid hydration warnings +It injects CSS variable rules into an adopted stylesheet based on the saved layout in `localStorage`. ```tsx "use client"; @@ -206,20 +200,31 @@ import { Panel, PanelGroup, PanelResizeHandle, PersistScript } from "react-resiz export function ClientComponent() { return ( - - - - {/* Panel content */} - - - - {/* Panel content */} - - + <> + + + + {/* Panel content */} + + + + {/* Panel content */} + + + ); } ``` +Here's the example of injected CSS variables: + +```css +:root { + --panel-my-layout-1-size: 60.000; + --panel-my-layout-2-size: 40.000; +} +``` + > [!NOTE] > A working example is available in [`examples/nextjs`](https://github.com/bvaughn/react-resizable-panels/tree/main/examples/nextjs).