From 8a9f7ad4c20e5f596aa78021f9014d52e3f1e4dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Wed, 22 Jan 2025 03:42:21 +0100 Subject: [PATCH] 0.1.1 (#3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Julien Valverdé Reviewed-on: https://gitea:3000/Thilawyn/reffuse/pulls/3 --- bun.lockb | Bin 152424 -> 153528 bytes package.json | 2 +- packages/example/package.json | 31 ++--- packages/example/src/main.tsx | 2 +- packages/example/src/routeTree.gen.ts | 52 +++++++- packages/example/src/routes/__root.tsx | 5 +- packages/example/src/routes/blank.tsx | 9 ++ packages/example/src/routes/index.tsx | 7 +- packages/example/src/routes/tests.tsx | 23 ++++ packages/example/src/routes/time.tsx | 18 +-- packages/reffuse/package.json | 7 +- packages/reffuse/src/Reffuse.ts | 154 ++++++++++++++++++++---- packages/reffuse/src/ReffuseContext.tsx | 1 + 13 files changed, 239 insertions(+), 72 deletions(-) create mode 100644 packages/example/src/routes/blank.tsx create mode 100644 packages/example/src/routes/tests.tsx diff --git a/bun.lockb b/bun.lockb index ea854204c0c64f0ae4a18816aaeeca67a4f65389..fa0518b996a55f809b137efb772d51e4a8a05f45 100755 GIT binary patch delta 34974 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 K`>M9e!~YNcdqjx< delta 34750 zcmeIbcR&=$);BygFv<`F1SJcI2@oVBB0(|Xh*>c!ASwtV!GLMTj2UgU%{k$kQ8DM7 zG3U7E?5;U|ztaKG#l3s)^Stl-{c%TsbLyO`I(6z)?CxTE%UboLW$J8C*R+T~&8wVn zY<2K?zYaSB&%9haRFUX9*2!h_i4|_G8cZm4xw%q7pYD^R9hI86$^FB%3zMInM3WZkp6asq)cqzd{BauG@>J0fBP;1aRprt_vO7a{Ng`zz8 z2T)`I>Mbc=s!}Mdz{en+Eogs9Z+lP&@D{KZ1?vuiS}3#%oyJ_DKw4c!dQw6xYIqEM zDe%FdRI^H;Wk4UHbgJbav;wFjD0Q;W=rF|J0HyeCpe~>@K#@e32}+%?okVLo!~c}f2?8pRNfGyh9?URtyRngN!Y|1vE)H&;blBawm zc{zzU&>}!>`L?Q<@HQxQj#Hr27q)>?#wDPXE?eR=L8+I=N%E$kR8UPR-VK!Umz8)0 zDCK|dE~dK-O66z|AV3AI0i^`9Bt8q26vUtnsWZl7bo9zVZ3D#`CxcR(C&l;erNAdn zk~fuTJ5U-eUE||>dnBYQJ_jfirr_UzlDuP(z_-)wMSxtG3rd~i0TLL4?ggy~nvm|% zJt-wt;TtTb+YGr8$-DPTNkcdKP2#&H^y=z?PLxAln9QEDdAk-tla zi`9vVOGzU?BtuTt2h|ef?z*-Rkbk?z$M)$?3DWU}Ph-fb8a--@1@5fPH7`*q=zE0d zg&r~K9XDPq#P_l`+RkB@s%(csmr57n~Z2-EI+h8ptC+$w1kidf=VFKk*ae_cay=v=Jx`+?Aj- zv)qjm3;wY;VKT4NL^Oak6Khf*l)77NT1;F#T)#__>o*tu+!~bPljGC6$NLoarq@kH z4>W8cdf<-4F9J_B_h>0LTeq0>j8wElT6~}M1TMtDNb3d@sR}P(BF$xIQ57=z3V13> zc1;Kd7ELV`K*<$mpyZ+&ZKO5=rM9WoRvhV1z*EUjz|&lI8kF+efR+W-6RB4BPEw!% ztwIT-#V%yqQCv_Dfs)TRf>Hr1KuNJ)XHijndR$CWOxO5#okT;4JO2hljjl$Xe{jqH3uCXD`w0EPrb_}POSMNP^!r| zP%BVli7v*3S_XV#I!uC(r%C!`4?X}-@#jIQBBMb|aR=2Fb*msmqv9&6UI|p8CzkjW z{hM+m^$;ydi%*X43Tw|pP9@Jv5Zi17s4eGUXs4~-Q>^p|P_kK`;N|((z(aJJJU`3x zu{__()2ck*$_s(K0Lb&ZJg>|1w={2Sb@Kcy&&%?PA}<*7#4k_m^2#HxH1a|sF9`Cy z9*-*0i0ad;cT%733B52_#Ra8DO3#F@F=>t&G(e0LI&&eQ&~4&s8CgX(L^f(GA5d%1 z?eLrp=u%MXg`fM1ZT%9II?ElGs;tQGyKQjfQ(1L`RjE$Q0((DweNuk~46=lc==5iuk7YnG>VE<2!A zw~~`Pn~$GYDk(p!;r1yH$J%vZohy~eePz6WaXQl#Tz08fxmC<`N&}k`(G~2f^qrc! zqVyJ}S(fFP!)IzAu;|z|^3rm}M>no_nb%hDH~WRYsXe-&2J}=WJD(bFyxr4q^(0FY08$t&a*+CxP<^r^lr>4rIS^ zkFCR$uNmiN6RLKHb83hQtpZs*mtzyiIoUQ)?$+ZHZ9~mop?B6sG`hIr60~qmR#mtz zRtBsc_t-X!P2^nd!qg40uMUyUDFDnghsMO##R!8H#U8@?oln7E;C4A(+gtUQrsGKsK7oaS2n`K;IPe!IP>CaE-a=E?U+= zs7;%)3I$e9l(F71kgerhD~7RBTmrtMxSWb%sSd{7%sD1`cv=1B$;2u{FQ_sR|Cb|RmvCD$2D#jtzoN-8} z8Un5{mBKx$V#aN;@lxB`!|Ou4w_TvRTLDL@H-Kx%t#%AneGx*>D+jCUIS6(-1*@`! z5XD|as2-(LJCzeH(4)@II&lf^VJ5R6!+NSizg76554v*;da8{ftR)E}1tE3iI-G0O zFs9=Ys)nggW8U#XiV|EZx=<}Ag`zq*CHLAn&?E~SjUs)hEGOqSF?3NV+W$ow4{6)K zNOwWn>Mv4@3dL#Y1t}JEU6ImK)y5EFi7P6!GB7DuQK7(`_mgxqq%l88Z?{q#7n`&h z7NWnZT>~k$g+Hk+QyG^Me~}J=6l?TPX|EJ3t&Wxducb|c^sgR!0qI}$M!Ei+_I3re zF@#uCe>6e))sQHZI{t#%1k9YLt3Fc?a^qthTY zI#l^UWixlq%`;Rr7|UrL&cicUwHKj!La3ytLeW47H9<&>R2ShR%f=xjs=I`c zn8N|ff@nZ@gv7jS5famVE|5jQ0fIjDXoNK6J1(_hph*)90U8Brc+nhQbQhKbOD>^C zn0hc=+yHS(&bw}P7RWuR5vqI}$hifFs=P6dYLc7P$p}gFS=B)Ga&Q62qM(^VeFI!Q zaG1}71Jy1;VoEdv=C&j*r)HS?IAk@2^fZf>-;dx_x0f-pC#SAZk;7zp`3fkRf(36lbljLJh@L#eI_wZhcP zA*0-o*$1lbBZ&FVCRptrCZ@%-6cWf{xP;naY$2CZJ4}58G1NGQ-1^#q%#L%7zyb@` z)ZkW!1}hJRb1Nf4)gK`scNuWr5rOL3m=LKsU`Fjg^&oIfMGpIh6X4Ks5J%1N4O~@l zSZYuiH*5>YxRTuZpg?s$aMW;!L%w6+@Sh9^XB;6q2)hqdv=cbei9P~1XBTjka-YP( z7RNxfNgeb+p#-wC8G__yu?fb2qtXSdRp-HB3}bP3sw+BGSa?_m&b2|9dMjid#1gT9 zmVuc~x#u;4)$s_?C`Y%c5y)n8u90EN{CZqsWT?ujJ{AfgQ5%G4$`)7c)tqa?Fy){1 zxx|K{YEQH!T!LQY9T})f0f+HYHCUP3fOFG?nmmKxF9SvG94R^<{R5TKfolvEqHC^$ zqdow4!_d-LXsZjAYKRau7~F{_S}bv*BkqACR}1#3JuyzHF@@g8dT=>WVJ7n-BgZN5 zQOnDg>Jp@pTyn!;wLcbOD50TIHIQk!gvMd&Bak(ROmvMu_ZYI_QQ}TOmfvG~aTBMEkMeG9xab zS(vJ6GwQz{k-_S*2vLLSQNLFo0Y~Gfq|mKO!(8+N8inX&oxzbFbWU`uncyfNqlQ+W z1V>#5DKV>{j22<)jx7`l^b*kr>NVgnkjTcSf$Hbr$YRV%5rL|js2FyG4#DbS2w}D) zIkav9M{S38unJUuXvw*?3RPD{&uI;zSoLAxXl#kxS#X7Ju|_g7Se*EpgQF%h<<>_8 znvVrXYarTBp%0kJYnS>lV%i}_MI8p)Mc3#snhx;2gv-HqJ?=5Sr*W=r!k96a&?Zck zhU9Iy?p1-D$;VI9@9m1he~MM{on!wwKRcz1V^ojc^bpcBL;hZ?s?l_RSrV!1OxSA(PDyu z5!~aBVd`w~l{kYc06BX?KO97wJ^*LZ~)USO^oPqK86}1df)h>c(KOTIuu^xSu1h!RmF8(u9M7 zjCJ}xIE+}q@10?guuhv?O%QiZ%L_ z6xgKD%oG=>t^+Py;8L9f)ler7XwIj10h_IAXK>*^a`Prf>53idfu(3eu1cdikxgxLFiIJ$g#H&iwp>0 z+>#vyp+5>jL8)@A79m_GBHjLiP{}k|rYQ(bDhQoJs0+22(l?!3*)vonqo zZ4+$b)wgh%iEZfQs5XWW^ZZYJz__2dZi&t99U=4#brhu3sF)-}0#y^h)#08y2P^aY zaf!V{Rbl;Uib(DqtR9FE<{fdWQs(#P+)_hX2`(YEy;ct$$N-=ZQ7S<#QA1Gr5GA=0 zG58R*23&~2hbYBYkZ48FN&xDiPy*=F!iOl8*AyUmbKK(6n_Sw4^iUJ1LTPdfC+FHAVVJkrGR$;eTb5tk0@UVd;ukk7;;mD zJ}6mUg0xALf+g`q29}cI%|NL+>?C=4P-?EKprp@R;)6lSlTn~#SUXVqXemIJ^^hX^ zfRe=nL5)F2gPMWzpcbGjL8-t^pr)V)Ky5&8fRbzPgHpcNp!6w9sbYUZPV~JPuayG= zC50uZ+7c}TYA5mkXDIytzoD3FR8BIqI7%K0l;VG&)c!vR{x9=X{(ocub*`GIkqc;N zQ0g=BQVoexusgn}nR`g`Vkq@VF##n^pp2YHUq`NHUjwdDUjt`~O_H(~rIb2ZNIjvi zm6o_va75Fj)I^C-r&OSQBso!%_m%kKD8=`a;)zo84v=`F6hBbnLE8xh43;8>ND)LS zp;qFFlA>Xfe7GbpN-6yaNlsMB4elpaFH6cbMv5g$GtLBwFG@+vL`nX4l#*mi>55Vk zO~DuG;gkwD5FsGUv2&yhL@B{si6^S${QEl!U21_8yAYHry+le?l#*zfBqvJK#s*ND z-?oC%jJ^*P{}l)5OQKZjLGVNmN%Sx%b;%P-OzD*N6n#mQ5}uY4o{?z26kn85y0ef| z6g|TsdXc^)O7WK@o+$B`CBBfN{v^AKFB%lLCHg>0Sd@~2hmaF}B&B;Hr6Wo;`a_EU z6O^Lf(brFu^1qkjKTQ*3ZA<(z(nYS zL6V#(r3(fn!)r=>s1#3>(r~|$zUq>mPC~b@S=+U-94E#T$ zV)(T`mArt@ulJ_^uQ#t< zU?Gj{|6`li+@P!qEPVEb6^mmtJGP#kA8odD+|!5#skbU*U5uHXm67>==A1{{-hOFr z8`bmWr;(veT8)i-n?JVwSfjU@VGBBP(-$O+OQmXmRMtXqQ!s=j5-d^J@B`I}du_n%hHn_Nni< zNAJ0%V~>Pie_=LuUqtNAUQrP?_9ioO4YK2HcZJ;2`_R2rnXDy^pSD?F^INSMWwZ4j zhHZQO?s^ZGg;uWn?@qtx*5-Aqo9Dl_<5rJL;ZK;dT3pBRR@{m4jiTrlqx{j&by>gX zL+7VGoUROCb$aLMdfH*-`863GwmmC3c5a11<+Qh)hW6jOB`Vo`$WoJGJ!akisBN4( z{P-U`-kD^SzwY13m@}DR%?+NQVW!;C3DMk<2_~G!L=7|NGABlJ{U@4mH^5nNu9Kp< zDw9mO36nIe40i?GWpE+c8fL|f$&Ti-vQ4<>;B2^=Q=+-*ljAwnR1NoNvI*C5s)jjm zlP5=WGp3kuZzpS*BUcM)8gM4uYEHwPxkxUW`vC6i6b*CXa;8ReE2f%oCet*mBG-0W zG}mUD3AYnmWllXknlqSg!X;1FFjsCXxGmrucnyw^CGgQ)58i}33C@GFnGwxd&oJQz z&(N@H+);2xz?g%)KC7P&aa@PRW|GkC&1pA5e-+x_{-y$Nw_1e6=BNvlg z%AT?O=HguITJLEky~dc&p>VM%t63K9^rTQp+VTv2N6( zLrKr``}-su%dcA^ciEs?TQ2A=-Rm~r`-G;y-IZ?lPpTDLrmnFqJMi$%Au}y~9xk@( zv+-l}aNpj_&(RB}r)KZRwIx%0GyMkIf^%I8cQ1vzmulL!Dr#z-;6ZD@Jvn@ z@4E`ebLU!D=sB$PEce(=6DH*MP?@i)Yd8DMi;J-XFQ+V?ZddO{QkA~_{)pQ@xz_Z( ziSO#ry?rW$E^J$K-piu3^xQ-K=+A22e^{%H*Xp0%vSoXzh_I=*2F@I6W7B>v_x-0+j(%4&qc7*}mtZySL1=Wwf zP}9O=>dLNFRblHJJsf}H%PZ5G{H)$pf=6rTb}Rka>55maL(|W@R=W`!eRJj0xa zP7m>Hmp*RRQJ+u89#3Al-fT*fZnNXhBsy8~?Uzn6evmY*((+OMBTlAueUn%@M6+(x^%=dl=+Y{0$awI2c6Yn-Cyipl zIwVAw`@P?Qzzg?Q41HaGtz@tc8u4tr;G=K4a`F1qIlC+Zd#w2iP|I8DqGc9Bq^o_q(@cq zNB{6{miWf2!H`usf4n<**MH=VdP~y2R35om)vt{2w}xF-Dois^uK%#Qw%tXIDOdKq zg~$BHvziUD)Yh(SHfT++r+ur7ij~xMcxGSl(YJ|7dcU#Pp^3Hf9#(7RSE2em&c(sI zg4g$?J*7Ivc6seJrBUr2^-?K;{zTivpfx?~G_b;1K2 zJb^6u=v!~QvU+7H?JZS{yLX~TuQ@P%j#*szkz>XkcZWx{&;NaPpZE8Sc9m%OTdA$~ z>qh0UNfR#XAL#XNNq$Di@UqDUx}f@^!Ghw>1!~dR@?*#KP+8h9NS@x&Ysce-PpkCP zG%DTV)`rB>eXmbZj{MR%VL`h!-M&vPJ;|z3nD&$3g~i_8gVH+H={6|fkM+Bn+)FQ_ zxJyyRgY-LC%?Nn^TjkCTjcn_th9<2VaNUwidf;%__T$UONl&V&9Cy9tPK{dF(sy;s zW^+fxPP$0XY44*IuUoZV-*KeY=Ql+U z?*5ffrM0zn)o1H24eowdYu)?In4sq&*4v6Gjw`A-WU;xQb`? zy)Kr`Ha@_`cIjd@B+j6U=e-SAdftk6Zmitar17cEONQ(n(|Yzj?J1*z1V5Q^9^xkqs<354?XeL z_xs7tB^;B3I=Jm_9kk(LMQz>n)f!$96zdC~h%c&loX+m*$CsL>`scq)bV}?yIrHw* z%a)hDEL&@Dj*RS=l@mV6+2P7`tMTmzm|mXgnH~7z`sZ>7N3^d|zGvLCY5uMu3yLW2 zR#fq*rD0z6H%E8!-s`gHkY(WC{= zz1M`#AAF$Ws_w>H$Mi8+k~SpDLTo#I;g)9iqKX|x+;3`dEx5y%TSF1xkHahJ(~4@o_snx^PaX>{H%R_zV~Q6(0$?+laN{+{kGZ~?rqvICAh{$%L!$^ z*7FUY;gE9h{>T>f|9Jl@`b5MeNij{E2}KouITMgGsLu7Uz4d&@_?|H9)mFFKa8sIG9VAXG%pB%_P`li7?hx>gmqK)tmPkJgWFRVR_>SbfDUCiK)<<)DOR8(BOVv{+;XXg&@`>s)o zNj|rl@0d8{U7g>abbjM^@NAo!7TZTOzCT*;>E}uP!Vb(_v~t>qhf#yiZ|xTU)^PHm zu8ntWpHrl`WbV$gXx57hS{}_(xXJkL%{|6f(aFU3Xf7Y$S)A*-Xf}o$x(?f@JQHoz z#pi4Db-Y{5b8A0(+|ju&b{M6NJUrUy;_^X5*3C5Dw)(bhN?O9OrS0Lb#LSY zzLd3-E%({p^=r4C+4m!gRDWDiw+{Fm?|&?E_(L0yqZizbY{wlwaA?3{>ko6>w^VL^ zC2D){uCm|TyVM(Jv*gUjCKJne81?XqJo0eEqYf{lm9?$*Wi?#Ib=+djo!p{f6F8f# z*w$^uwr;D2P2!G%I|9yQn}$v1GPhydx((Y_a2)5l9s8*5*hg*G;6U3IaF@Y_?9ect z8?yu3)*aZkf}6<&?ZmcqC$_CSHEcHb7~CUpQM)v3E;n-*yu1tBR&evV$lchs?#8xt zw+82DKZ5%JuHzmJTg>I`!M1e|wyk?LY$?}vFSf0Fv26vnoKx?^wsjx2t@||i3y!Ve zwt#ckufd^x zLj4Y*eup${6L$sNWpE*fH7t)Ca~SnIjQWAw$^{)k{f?l1M>K3Z_ZZwGa8XA!ILS8i zDC&0<^#iw?i#&$<9Yg(&Y1m%wBe)OXIv&@s{ans*)bBXzcS3_RUTsgHekV{raECed zN!0Ho>UUDZj&fVUZ2{+SO2dwG38zrMQ>Y)flbp?I)bBLvcUr?vb4S4)Ic?HNV^w|B z@~Ri>yf|B4?`C})ljNi2R?m95{?wn}m0`>D^bmnoOEH5~^G zA8fqbOxf?O`?ieF)}4C~GS%k$^r>b(v9d#pj4x-C%)0x9e|A4R>yJuDH>A3bN&kKG zm=>Nz2GgCQgX!rOyCL7*^-8RpFuvblo%_D%7U3(c2R}R6EL87-TiF3uzaMaW-P!KG z&439nwmJ85eZP3@>?fbHf@jrypHgdca)+r#-17_8+KElhb=MzXsY86gfQ83vRq5B_ zWa(E+mQEbs;r@ZIvG;qm9x!I}`>P()2aX$hY}lmT(HYf4)@QDJdAIDd8y`1aaPgvJ zHS)xIuc&p}pv5irjCMcOFZ$iunCxm>+poSc_12!7Z8jcSG4B4?xO0kk^=Gxo-)D2n z+w6Vto6g@3PkIrVeSPf3PUnIg77lp5_c1s3qIGzMGWET-d@k91)9#Kz7p9N*QC_@b zdT;fMMC;Z1`zf~qr@zXbs_k4WDfjKg z4<*8%*8W;$+=TDemDUYUUz9$_%WvqL`2nME#w@TpTjIit;H>-gTMn+)q4|{fwr+|^ zt=_FI)#~o3a*8^aFO72OVw<+_Ip=ZHT3c`4@9)|~RIxCx;P}w@?5gD*p55C$U~h}G zvF1C!`iInCG^~Pe*IIc2W_K5_veU#mynnx}TBzBeLi>mL(!$A#ff@Rj~7Mr{<-&W!BHMHjx9}AtQa?X zUqUPY&U41MwwODx(Vwe7SMQN9uwH{pb>@UrO>E`%rfZt@jf8y~u6fM5#wM0mj#)O+ z^vJYiZhD-m2uub zqe26ZZ`UK+EuKBbvYfL^?ZFSf&imN(?7Iuka{D}NV-TL+KJ>ZI$R2*p4()7l@UTJW zp4->IT8=+Tp4?%mb9lg1x3m?`Lu%{1B3=z0zWJH=h2CKuH`>>Fd#_K^fj+A`#_SZ`4IsbAf$j`8bTO+TM# z9zXNZjoKwGG%ZIr9dKo8)`;eM&URIseQ>L8zBzl>?d$Qc@4Ou5KEH8Tk%sq1SpMjj zOS#i#UVhJZna{6j*?F1om>!@IYxmW!4K1#2pL-Z|Ro*1NE$jas(+ zw#=@yP3n^6*ZQqiy7dbw_qp*1`}|cmhu4T7oOI3mb-mode;BBzEoBCFwJa_jcZI%Zc%)xfQNK;+l$8*1p^))}@} zmFw0vrG>98XL6t2Kk|8T?f5RAYL5&Y!VV>MpYOJ@qg}}1yic{JO<>kqOV^}kkM@3h z`p48$ch}msA7^ak5O>!9Q;F!bp5CX&-tJm@j+tluCdUmmFB)6j2uk_=ZLi-wCZ9a- zZRpTx|DPelbBlPkb5Y~Us%*DTx&0|4Eon$ccPHybk$i6BEvx$Zt>ns|Sk+>HKIhf{ z`{^zNY?^F~GfSS?Z+Wc&C1?0I|N7iw!E?8#Z;ub%#)mLw&39D7DKUJGl11|$@b|mC zi5>)Td|N#TRwyCZNrHG@tq(yPJ!X=Ztj`{nz#(~kKFNp~C=WRDFN~P2Ab4iN3{;s; zIH8l5YQfGi{tQys=(~%5=1g~?Qwt~N7 z!z`E{|JH_as;4b+UX&tl3Fh{;gSp>u)hLuSP>_8g*)Cj|8B)6ALh1Nbi;Rqf__R&@ z9eZY>`ig4`V~VA7%lamNsnSCwf5w!Z;h#CP19|w0X7ruK@*q8;{Qtu@+4syaJ5KCS zx~_bqZY)gu?YsD)xuuTK?{LBvPY;Un)Q0sWSzRd&v2=KnKJ_FSU3!H}GWqrj9hIpq z$r?!M=rLP_DAOt;B_W-qk&i7klw@>UZL^eF0~rPBNF5zxqV#kWn2syaap4_Ox_BwC z5o9|dBOTo&*}AR>;L|8kq=q&5*ko3YU(uaeswjgozqLCHjIl$|9&iB40giwZ;0%-p zrlNd0|1%kw0&oDG3mOkJ1R?{qg3NymQ=b6O zB$LUvAwVb)29RILkL0&H{MH`Kku~Bk^kDV18srXwv^o$7d_vvmXz~Z(BS6QM-vX78 zt};*?2nK2bZh#*U0(b$T00t@j-3$GZ8T}1`A_DLRsse$4KM(|j0r>kCt-=EVPoN4= z4R8g*0Uw|)P!FgBR0Mp18K^RymNEcJ0EU1XPy!`^@2JFA;2Yo$zA8Ycuju&TTc8!f z)KdlmnR>VbHUt4WNHqwc^IrV{>Lzq@a|SRIm<>z@CIRDtaR41a9RZ94bih!6jvfvH z=xppDpg%z8aOtFOFQ6wt=P0@WU4hOO@D&Th0Be9%z-nMQumZ>hHuL5^nWMHMf|Y>E zKo!6ha0BSq5UK(mfG1E5@B+L6AHWyz1N?yizz(nn9Dq`Q8ZZFL0!Dx}U<#N4#()V> znogBkB47cO0c-$Uzz{G8tbp6-CPRRsz%ZZ!5DL&nBpj#((7>jFOuz0B3n$YUECZZD zI3J*+lBEDszyvS`Y=COiQeFtqnaOs*aNraQr4x8_LFWN;fC<28U=%P67!G6r=|BpQ z03-rCfDtHgFR%}I1Uv>_0@hHlmlg0g|DehT+ zSc#8e%|3iwGP7Yu{Lo}(;Y{O$=3$zjX)2{@lI9_5#!kr6k>8oj?6l*+eh0n*Uja%^ z_laq$9}CdKrRD%V52F*h^miEajE^H)CR(VFu)3+nTsYLn$;=*E&weJmH_?H2c6QFmb&k9 zCCnkCum!)j7qj4>r7$yQ#^)ofqB>d$;<{vZd13)F&k3M~fffi_D99?g1Y3mZtQnR1 zLurDlNK!#beuyd}BV(vIN++wO_2=jGlEEi>F$1-1RvE!?EgAlo(jk-8QVq!RiU1W+ zoL_!bV_G#Z;|uw{L8MQI^RwM(QDJ$Zm4cQYT8=0U)!P*yxy=6@ zrsYSDqb2I+c+qI>kL^S?l^t1JO)0Lp2BG!OA1H7x!qmo;mexyJ#(V%Wh(1&S^1Lne zds*Pa-$`M1&Lj^6|jNsXeboz7)3h;jdrr@SN$OZaYc1GftNd!>~7K0 z0$a7e%s@_}!f5UFiSPtX> zt5LpUJp$_hvX;WRz-kGbLAL|jfGxmQU>ve0Dgc2Kw8y6bHEnR=T8oRO+E-xPoW=v3j|v8Y#{6I;f^5X zpf+s@`V^EZPJgM}7I=klG-zuAKVcwqZ%&u!bm^`_lo>#K&{)6)hyl6)bT3Sfrz?57 zl_B#)F*X%WnGoVr`VwDy5UZqzARjo0HD%;OpX!y`u4J8jJ$-yVy%mr6kipD1fG!>>L0MH>hsF-Wk5*xwf;_zgJ-rl5 z5mOd159^$;^S7K`4Kd!HLH?e;itS2%&tPULgy|~53aJ`yS{Za;&)6n~sh%RH3}Qyz zE1T%LHe()Qyga=<{jmGxO@=Tl2ZT@uctn@Aec4&-e)&}?bC9Q(r;oynuQh~uH}S>| zHu0xux3<&`Tx+)C1CmJg$-kx9I^#uV+wW!eBgP+jy~G<2c2N6i%Aa%En?0y2lra;y=18?KeZiJXVU5lqRdrAA>L^_P$>J*d31;=xpZX&v0Gj=A zsls>GvNA#BKl*DbYpUM27egO?zErO~RnOlCG4iiumzv*Y)bE>gQHVhX&j1W$ezlg_ z*vdbveL(TJ#hVG;-G!`vf!?0p{3k7|YT%;ZLr@4?JAK>nfS8BNw14x73u08QxQ ziAKaQMmlnz--^~}>YV6u3^Bf<2OjA2Lv+mAPWs_(-N3=uPItFFyb>u;3i-%{U$4U@ zlQVxD#7_PdX|s=O2bnyGbdl1bj41v)68Ou%25s7MVwDDKW>pZ3@FpYV--|v~B_j9K zm2_7jE4e{2iH{n}Yy#xp=$3!GQPPbB@=s5%|Kr;5wGSTkDlGM!ik~wS_RBxNePFiN z!4Ja>DhkE=k}Da18p{3YXRWCft|gB=IC1%h;gSkeQ2vQ<`KKcbV;b@f!%%1Wm$7fv zJ3RNvjjvw|OCQWPLjpE~?+Icr|I&8TdwE;Dwr_JNOn15jzhD@%_LqOvyng#Tijl`h zO)V@+{?%^%iQDr|SY2y@7#~mk!{FzilM(XId?(y{sjKi}JEk?cf!g!V!(l{!J{ZJa z{=xLt-R`rI$sa!m=>#utF3I;E4kP5>Ubo$Jw8X$8&E)F96Y{UKv$ts_M}G*vR#=7y zzi<8`tz&Wy!KdF_xQQ(FjtH^Tr z{H*_=1^-$1_{o%?T0*kqKkW>~w!%N~)6Wi(`i0aHEcn&bqb1v<4)9}3|MN2bSr<&^ zulh z-SZa{aUgDn@XsePUlz#RtX7& z&#}d9L8-^%8bKlX;6GgpiZ8EVkuP?JEpBQpm{TQxDgSm(4gJ@nUw&1KomqMJdmbNE9PWS~g{10RG-x%ZnMp^RWB6k>Z%OlS*!XWt{7hKRTf3wIHKdSyg zkClc&aWmC_+;M+uj{hsZ`Pch^zjW6B-5pUuD-}C>{;uidjmbY6ME`lC{4{U=O;7#b z7^r`{m-}hIC@;~{1w*l;=l{4(|4#e;IQm3bdb=!HCqHb(y!pg+%wDSWMS!){7V63-Z4e z#yBB{@?7-U{(ZumXjT|g6ES#HtSgamwrkRZHFNHDBC2d)0vn$`oiZm&Vkzah)xrt+i^80wN z^>{plE5H;tKKleV=<<8g+%GIn%kR0NgKz~W+@q4;Lv!=y?zzAD>++?)DDm%L`K+aOd|RMS%QLoq2X%+s-|XYgd>;ejAQg?OC1kN|>U5 z$l4WE`BEE@SAH?tKE;drl^!d@3scB%%1PK-bA?}tA&D;x zDx!U5?QvE4Y|<{j9w>jInZto9kDC;xkYDuUR=SEW8+UJEVa$@M{7uR$zY-|6>=(7E zqvgB86!N=#9!}4AvoP%4_QIIkRr#v9uuOg{P?r9x9-Yl=^e;?d;K6r6iU9e=LtOAP zm&6IPvIE05~;3uE;7W}BIXJ|*M5_TdSJ z3qN=>vr+qD$}EK(Bl!7X6XchO-O0L^vA*#!19UFj(Wl-ezi#ZNvrTEkkWxxv#-+yy z1urC%UkN0{P=rE$=UM!a$NkdU-dTR4`J|z$LrRA5d{dv`;%)*>|VL}2Jj7OT75-4kE zC*_XwFAZ)X1~=sCmUc~kXC8}Ujd`OjxWCbs58Hwp#PU1lX3wm!D~enGCz9h41zDHL z=kLIDKYk0I0FCFbAu*fHzoo3d@vd8On|5;m-)SrJvEK{b6;Wbq+XnfLuXB$|CBl{m z0sN}1xGVG~fUmj-^m71z8$2`QKSBX(%6n`BX~)NGgYr0jAaTk3TH=H_+(gItr^iRt zr+Z9w-d`HJhj@AVk$GZ*0O{3#y0*JtsOH>!UPUO}+Y{O3cK}8=J0I2Y&CxrOS;)FK zh;OtVX87{)+nKLj=bGZW*Sgv9#xZ6a4=dhiP&QtqtH@7T$Flz&F>uXe(x-y?X# zUEmMb;X`+!Qf2w*U2x-ge%vlJ@3^|cnI_$ptV-WP+h?g!0{IWd&gXX{oqe$#NigAI zeZJIg6mZ&~f3X=y-@|t^TPE}&Uw-0l)&rZ;_q)*zq{ciLi;{H9GOfxfJb@19>%1$enVr(AA8mxGxP6(Y=Po^ zPWhdU`fYq#o-DDFW>|WIX6C8}iqn!ER9tvD1z&={hfJ@dld7>An%}3f|#O z524d~@UDlLuit;-N?x}QLrQE5pI`Uaf70|JawGiO4*B(%={s8ewnl0C8a43~r&6(3 z|9c&6?_uVvj))dcl|p0wfZk76$)zu>as!DTHf+a>B3n)akE-;`4P+6qaB@?9H#9#WFd zH7C*Is_^+Jf}Q4@oxwV(e~fi89MC~re37KrF+5)`z5-ZX6r=ft$B=m%f9E6!?r0Fn zw;86}q+q zmh606=H{BhthRjWajZ@93pZaK7~Ff#r4#3nz+W5@EBM{epq1a`dC1=4+uX;dw0NNr z18_RwP)G6F;puPjOXr=Pzgdi-=9S;(={qHEz}~qF1}oXoPNF03f?A>~PlID(j`}pF z^~c-OAD5*H`Hi4?)(5YjIrHsz#86eRQB&yg?N49ji8E@6sqWU7LoD@tzLUpAb-LTWLgsjM9Q z6~AgMA2e~bQ+Tv4zt%Z@OoMM5msS`gxIkF;B=h(|rNprBy|T3Xp0OS6!m4dU49Y6+6%EipPj-D z6goS_?>)yHa8m2mIqdA@x6GFFtrzoXz_jvG9kCJ1a_2qIAvI z;0GbEeX$p5LW<|^{5sNJ?1in6qSy;dA*PK7|Bdp>FQ`3IvMFEhQSv_F5>QAXzrxn~ z(_4O4ewUZd-~PAg(b9P`$k;La+WJCSsx0%lywLN0R*HX)H@kDbyHcj$-c;4i-xdgI4( zSF?5Vwjco(4c}ib;dI1Gm~qQEQljFgWlHp8jwbn{o zKL0AK%)h(Jh8db&7NhDl%NuqL7k$RQo*CT-glA;-j!&<~ue*hdBcmIv0Up)0yutSK z-ftlYyvgkHCf{V)Ob=Vryb8BjL`i<~LtHT(eux8j-5)YHUU#4A^UogQ?~{AqN43^H zW(NG(ib}fzwt0~x{*PD_{?!wfO$yBOrafX-j9>5s*W@PmSV_M96IPd3K4H!CbWd43 zQ$6$?{>CTPKo8xKukx84VS)Uc&uj?4tAsK{4}0poZzYsVmGIKu^2+kO)<|i|UsWs1 z%K}G3rH>qLVv5KtLuCb7aN1DmC5MHaO^lRkKFmnzP()g?O;;s^P7k*(CWx2c==F0vSEHKZ!qB2LxpQ@lVWBW;e%5rwGF|qMU9$n*O zx_ZQ=bdC3jPfAEm=oOQZkkX5PML8VmDvkL)bx|ktdP)a=L|tVa-madqsD7Z%H@pj z-b~q<&kj_YP#Qx%qq#CcR`k8OV4`aar4AzVaHVtJ@fOOP%rL8&QW*a;n(?z*D=XRK zPGI8-_fux9>Ae5x2aC1$@91tzDZ-ocS6id8O!vFvP diff --git a/package.json b/package.json index 6d4beab..6c1b407 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "clean:node": "rm -rf node_modules" }, "devDependencies": { - "npm-check-updates": "^17.1.13", + "npm-check-updates": "^17.1.14", "npm-sort": "^0.0.4", "typescript": "^5.7.3" } diff --git a/packages/example/package.json b/packages/example/package.json index d73afec..ee4ebd4 100644 --- a/packages/example/package.json +++ b/packages/example/package.json @@ -11,31 +11,32 @@ "preview": "vite preview" }, "devDependencies": { - "@eslint/js": "^9.17.0", - "@tanstack/react-router": "^1.95.3", - "@tanstack/router-devtools": "^1.95.3", - "@tanstack/router-plugin": "^1.95.3", + "@eslint/js": "^9.18.0", + "@tanstack/react-router": "^1.97.3", + "@tanstack/router-devtools": "^1.97.3", + "@tanstack/router-plugin": "^1.97.3", "@thilawyn/thilaschema": "^0.1.4", - "@types/react": "^19.0.4", - "@types/react-dom": "^19.0.2", + "@types/react": "^19.0.7", + "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", - "effect": "^3.12.1", - "eslint": "^9.17.0", - "eslint-plugin-react-hooks": "^5.0.0", - "eslint-plugin-react-refresh": "^0.4.16", + "effect": "^3.12.5", + "eslint": "^9.18.0", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.18", "globals": "^15.14.0", "react": "^19.0.0", "react-dom": "^19.0.0", "reffuse": "workspace:*", - "typescript-eslint": "^8.18.2", - "vite": "^6.0.5" + "typescript-eslint": "^8.21.0", + "vite": "^6.0.11" }, "dependencies": { - "@effect/platform": "^0.73.1", - "@effect/platform-browser": "^0.52.1", + "@effect/platform": "^0.74.0", + "@effect/platform-browser": "^0.53.0", "@radix-ui/themes": "^3.1.6", "@typed/id": "^0.17.1", - "lucide-react": "^0.471.1", + "@typed/lazy-ref": "^0.3.3", + "lucide-react": "^0.473.0", "mobx": "^6.13.5" } } diff --git a/packages/example/src/main.tsx b/packages/example/src/main.tsx index f3e3987..8fe1e6d 100644 --- a/packages/example/src/main.tsx +++ b/packages/example/src/main.tsx @@ -1,10 +1,10 @@ import { FetchHttpClient } from "@effect/platform" import { Clipboard, Geolocation, Permissions } from "@effect/platform-browser" import { createRouter, RouterProvider } from "@tanstack/react-router" -import { ReffuseRuntime } from "@thilawyn/reffuse" import { Layer } from "effect" import { StrictMode } from "react" import { createRoot } from "react-dom/client" +import { ReffuseRuntime } from "reffuse" import { GlobalContext } from "./reffuse" import { routeTree } from "./routeTree.gen" diff --git a/packages/example/src/routeTree.gen.ts b/packages/example/src/routeTree.gen.ts index 2cec328..92e0a99 100644 --- a/packages/example/src/routeTree.gen.ts +++ b/packages/example/src/routeTree.gen.ts @@ -12,7 +12,9 @@ import { Route as rootRoute } from './routes/__root' import { Route as TimeImport } from './routes/time' +import { Route as TestsImport } from './routes/tests' import { Route as CountImport } from './routes/count' +import { Route as BlankImport } from './routes/blank' import { Route as IndexImport } from './routes/index' // Create/Update Routes @@ -23,12 +25,24 @@ const TimeRoute = TimeImport.update({ getParentRoute: () => rootRoute, } as any) +const TestsRoute = TestsImport.update({ + id: '/tests', + path: '/tests', + getParentRoute: () => rootRoute, +} as any) + const CountRoute = CountImport.update({ id: '/count', path: '/count', getParentRoute: () => rootRoute, } as any) +const BlankRoute = BlankImport.update({ + id: '/blank', + path: '/blank', + getParentRoute: () => rootRoute, +} as any) + const IndexRoute = IndexImport.update({ id: '/', path: '/', @@ -46,6 +60,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof IndexImport parentRoute: typeof rootRoute } + '/blank': { + id: '/blank' + path: '/blank' + fullPath: '/blank' + preLoaderRoute: typeof BlankImport + parentRoute: typeof rootRoute + } '/count': { id: '/count' path: '/count' @@ -53,6 +74,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof CountImport parentRoute: typeof rootRoute } + '/tests': { + id: '/tests' + path: '/tests' + fullPath: '/tests' + preLoaderRoute: typeof TestsImport + parentRoute: typeof rootRoute + } '/time': { id: '/time' path: '/time' @@ -67,41 +95,51 @@ declare module '@tanstack/react-router' { export interface FileRoutesByFullPath { '/': typeof IndexRoute + '/blank': typeof BlankRoute '/count': typeof CountRoute + '/tests': typeof TestsRoute '/time': typeof TimeRoute } export interface FileRoutesByTo { '/': typeof IndexRoute + '/blank': typeof BlankRoute '/count': typeof CountRoute + '/tests': typeof TestsRoute '/time': typeof TimeRoute } export interface FileRoutesById { __root__: typeof rootRoute '/': typeof IndexRoute + '/blank': typeof BlankRoute '/count': typeof CountRoute + '/tests': typeof TestsRoute '/time': typeof TimeRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/count' | '/time' + fullPaths: '/' | '/blank' | '/count' | '/tests' | '/time' fileRoutesByTo: FileRoutesByTo - to: '/' | '/count' | '/time' - id: '__root__' | '/' | '/count' | '/time' + to: '/' | '/blank' | '/count' | '/tests' | '/time' + id: '__root__' | '/' | '/blank' | '/count' | '/tests' | '/time' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute + BlankRoute: typeof BlankRoute CountRoute: typeof CountRoute + TestsRoute: typeof TestsRoute TimeRoute: typeof TimeRoute } const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, + BlankRoute: BlankRoute, CountRoute: CountRoute, + TestsRoute: TestsRoute, TimeRoute: TimeRoute, } @@ -116,16 +154,24 @@ export const routeTree = rootRoute "filePath": "__root.tsx", "children": [ "/", + "/blank", "/count", + "/tests", "/time" ] }, "/": { "filePath": "index.tsx" }, + "/blank": { + "filePath": "blank.tsx" + }, "/count": { "filePath": "count.tsx" }, + "/tests": { + "filePath": "tests.tsx" + }, "/time": { "filePath": "time.tsx" } diff --git a/packages/example/src/routes/__root.tsx b/packages/example/src/routes/__root.tsx index beef033..b9e5fa0 100644 --- a/packages/example/src/routes/__root.tsx +++ b/packages/example/src/routes/__root.tsx @@ -1,7 +1,8 @@ import { Container, Flex, Theme } from "@radix-ui/themes" -import "@radix-ui/themes/styles.css" import { createRootRoute, Link, Outlet } from "@tanstack/react-router" import { TanStackRouterDevtools } from "@tanstack/router-devtools" + +import "@radix-ui/themes/styles.css" import "../index.css" @@ -17,6 +18,8 @@ function Root() { Index Time Count + Tests + Blank diff --git a/packages/example/src/routes/blank.tsx b/packages/example/src/routes/blank.tsx new file mode 100644 index 0000000..3d1cd68 --- /dev/null +++ b/packages/example/src/routes/blank.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/blank')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/blank"!
+} diff --git a/packages/example/src/routes/index.tsx b/packages/example/src/routes/index.tsx index c4caacd..6de5c78 100644 --- a/packages/example/src/routes/index.tsx +++ b/packages/example/src/routes/index.tsx @@ -1,10 +1,9 @@ -import { R } from "@/reffuse" import { TodosContext } from "@/todos/reffuse" import { TodosState } from "@/todos/services" import { VTodos } from "@/todos/views/VTodos" import { Container } from "@radix-ui/themes" import { createFileRoute } from "@tanstack/react-router" -import { Console, Effect, Layer } from "effect" +import { Layer } from "effect" import { useMemo } from "react" @@ -18,10 +17,6 @@ function Index() { Layer.provideMerge(TodosState.make("todos")) ), []) - R.useEffect(Effect.addFinalizer(() => Console.log("Effect cleanup")).pipe( - Effect.flatMap(() => Console.log("Effect recalculated")) - )) - return ( diff --git a/packages/example/src/routes/tests.tsx b/packages/example/src/routes/tests.tsx new file mode 100644 index 0000000..a019c4b --- /dev/null +++ b/packages/example/src/routes/tests.tsx @@ -0,0 +1,23 @@ +import { R } from "@/reffuse" +import { createFileRoute } from "@tanstack/react-router" +import { GetRandomValues, makeUuid4 } from "@typed/id" +import { Console, Effect } from "effect" + + +export const Route = createFileRoute("/tests")({ + component: RouteComponent +}) + +function RouteComponent() { + // R.useMemo(Effect.addFinalizer(() => Console.log("Cleanup!")).pipe( + // Effect.map(() => "test") + // )) + + const value = R.useMemoScoped(Effect.addFinalizer(() => Console.log("cleanup")).pipe( + Effect.andThen(makeUuid4), + Effect.provide(GetRandomValues.CryptoRandom), + ), []) + console.log(value) + + return
Hello "/tests"!
+} diff --git a/packages/example/src/routes/time.tsx b/packages/example/src/routes/time.tsx index e2ba3d8..702a5ad 100644 --- a/packages/example/src/routes/time.tsx +++ b/packages/example/src/routes/time.tsx @@ -1,6 +1,6 @@ import { R } from "@/reffuse" import { createFileRoute } from "@tanstack/react-router" -import { Console, DateTime, Effect, Ref, Schedule, Stream } from "effect" +import { DateTime, Ref, Schedule, Stream } from "effect" const timeEverySecond = Stream.repeatEffectWithSchedule( @@ -16,21 +16,7 @@ export const Route = createFileRoute("/time")({ function Time() { const timeRef = R.useRefFromEffect(DateTime.now) - - R.useFork(Effect.addFinalizer(() => Console.log("Cleanup")).pipe( - Effect.flatMap(() => - Stream.runForEach(timeEverySecond, v => Ref.set(timeRef, v)) - ) - ), [timeRef]) - // Reffuse.useFork(Effect.addFinalizer(() => Console.log("Cleanup")).pipe( - // Effect.flatMap(() => DateTime.now), - // Effect.flatMap(v => Ref.set(timeRef, v)), - // Effect.repeat(Schedule.intersect( - // Schedule.forever, - // Schedule.spaced("1 second"), - // )), - // ), [timeRef]) - + R.useFork(Stream.runForEach(timeEverySecond, v => Ref.set(timeRef, v)), [timeRef]) const [time] = R.useRefState(timeRef) diff --git a/packages/reffuse/package.json b/packages/reffuse/package.json index e07c985..d729b00 100644 --- a/packages/reffuse/package.json +++ b/packages/reffuse/package.json @@ -1,6 +1,6 @@ { "name": "reffuse", - "version": "0.1.0", + "version": "0.1.1", "type": "module", "files": [ "./README.md", @@ -29,8 +29,9 @@ "clean:node": "rm -rf node_modules" }, "devDependencies": { - "@types/react": "^19.0.4", - "effect": "^3.12.1", + "@typed/lazy-ref": "^0.3.3", + "@types/react": "^19.0.7", + "effect": "^3.12.5", "react": "^19.0.0" } } diff --git a/packages/reffuse/src/Reffuse.ts b/packages/reffuse/src/Reffuse.ts index fd42420..9b1f114 100644 --- a/packages/reffuse/src/Reffuse.ts +++ b/packages/reffuse/src/Reffuse.ts @@ -1,4 +1,5 @@ -import { Context, Effect, ExecutionStrategy, Exit, Fiber, Option, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" +import * as LazyRef from "@typed/lazy-ref" +import { Context, Effect, ExecutionStrategy, Exit, Fiber, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect" import React from "react" import * as ReffuseContext from "./ReffuseContext.js" import * as ReffuseRuntime from "./ReffuseRuntime.js" @@ -55,6 +56,19 @@ export class Reffuse { ), [runtime, context]) } + useRunCallback() { + const runtime = ReffuseRuntime.useRuntime() + const context = this.useContext() + + return React.useCallback(( + effect: Effect.Effect, + options?: Runtime.RunCallbackOptions, + ): Runtime.Cancel => effect.pipe( + Effect.provide(context), + effect => Runtime.runCallback(runtime)(effect, options), + ), [runtime, context]) + } + /** * Reffuse equivalent to `React.useMemo`. @@ -78,6 +92,55 @@ export class Reffuse { ]) } + useMemoScoped( + effect: Effect.Effect, + deps?: React.DependencyList, + options?: RenderOptions & ScopeOptions, + ): A { + const runSync = this.useRunSync() + + // Calculate an initial version of the value so that it can be accessed during the first render + const [initialScope, initialValue] = React.useMemo(() => Scope.make(options?.finalizerExecutionStrategy).pipe( + Effect.flatMap(scope => effect.pipe( + Effect.provideService(Scope.Scope, scope), + Effect.map(value => [scope, value] as const), + )), + + runSync, + ), []) + + // Keep track of the state of the initial scope + const initialScopeClosed = React.useRef(false) + + const [value, setValue] = React.useState(initialValue) + + React.useEffect(() => { + const closeInitialScope = Scope.close(initialScope, Exit.void).pipe( + Effect.andThen(Effect.sync(() => { initialScopeClosed.current = true })), + Effect.when(() => !initialScopeClosed.current), + ) + + const [scope, value] = closeInitialScope.pipe( + Effect.andThen(Scope.make(options?.finalizerExecutionStrategy).pipe( + Effect.flatMap(scope => effect.pipe( + Effect.provideService(Scope.Scope, scope), + Effect.map(value => [scope, value] as const), + )) + )), + + runSync, + ) + + setValue(value) + return () => { runSync(Scope.close(scope, Exit.void)) } + }, [ + ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync], + ...(deps ?? []), + ]) + + return value + } + /** * Reffuse equivalent to `React.useEffect`. * @@ -171,20 +234,6 @@ export class Reffuse { ]) } - useSuspense( - effect: Effect.Effect, - deps?: React.DependencyList, - options?: { readonly signal?: AbortSignal } & RenderOptions, - ): A { - const runPromise = this.useRunPromise() - - const promise = React.useMemo(() => runPromise(effect, options), [ - ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runPromise], - ...(deps ?? []), - ]) - return React.use(promise) - } - /** * An asynchronous and non-blocking alternative to `React.useEffect`. * @@ -226,7 +275,7 @@ export class Reffuse { return () => { Fiber.interrupt(fiber).pipe( - Effect.flatMap(() => Scope.close(scope, Exit.void)), + Effect.andThen(Scope.close(scope, Exit.void)), runFork, ) } @@ -236,6 +285,44 @@ export class Reffuse { ]) } + // useSuspense( + // effect: Effect.Effect, + // deps?: React.DependencyList, + // options?: { readonly signal?: AbortSignal } & RenderOptions, + // ): A { + // const runPromise = this.useRunPromise() + + // const promise = React.useMemo(() => runPromise(effect, options), [ + // ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runPromise], + // ...(deps ?? []), + // ]) + // return React.use(promise) + // } + + // useSuspenseScoped( + // effect: Effect.Effect, + // deps?: React.DependencyList, + // options?: { readonly signal?: AbortSignal } & RenderOptions & ScopeOptions, + // ): A { + // const runSync = this.useRunSync() + // const runPromise = this.useRunPromise() + + // const initialPromise = React.useMemo(() => runPromise(Effect.scoped(effect)), []) + // const [promise, setPromise] = React.useState(initialPromise) + + // React.useEffect(() => { + // const scope = runSync(Scope.make()) + // setPromise(runPromise(Effect.provideService(effect, Scope.Scope, scope), options)) + + // return () => { runPromise(Scope.close(scope, Exit.void)) } + // }, [ + // ...options?.doNotReExecuteOnRuntimeOrContextChange ? [] : [runSync, runPromise], + // ...(deps ?? []), + // ]) + + // return React.use(promise) + // } + useRef(value: A): SubscriptionRef.SubscriptionRef { return this.useMemo( @@ -256,14 +343,14 @@ export class Reffuse { /** * Binds the state of a `SubscriptionRef` to the state of the React component. * - * Returns a [value, setter] tuple just like `React.useState` and triggers a re-render everytime the value of the ref changes. + * Returns a [value, setter] tuple just like `React.useState` and triggers a re-render everytime the value held by the ref changes. * * Note that the rules of React's immutable state still apply: updating a ref with the same value will not trigger a re-render. */ useRefState(ref: SubscriptionRef.SubscriptionRef): [A, React.Dispatch>] { const runSync = this.useRunSync() - const initialState = React.useMemo(() => runSync(ref), [ref]) + const initialState = React.useMemo(() => runSync(ref), []) const [reactStateValue, setReactStateValue] = React.useState(initialState) this.useFork(Stream.runForEach(ref.changes, v => Effect.sync(() => @@ -271,23 +358,38 @@ export class Reffuse { )), [ref]) const setValue = React.useCallback((setStateAction: React.SetStateAction) => - runSync(Ref.update(ref, previousState => - SetStateAction.value(setStateAction, previousState) + runSync(Ref.update(ref, prevState => + SetStateAction.value(setStateAction, prevState) )), [ref]) return [reactStateValue, setValue] } + /** + * Binds the state of a `LazyRef` from the `@typed/lazy-ref` package to the state of the React component. + * + * Returns a [value, setter] tuple just like `React.useState` and triggers a re-render everytime the value held by the ref changes. + * + * Note that the rules of React's immutable state still apply: updating a ref with the same value will not trigger a re-render. + */ + useLazyRefState(ref: LazyRef.LazyRef): [A, React.Dispatch>] { + const runSync = this.useRunSync() - useStreamState(stream: Stream.Stream): Option.Option { - const [reactStateValue, setReactStateValue] = React.useState(Option.none()) + const initialState = React.useMemo(() => runSync(ref), []) + const [reactStateValue, setReactStateValue] = React.useState(initialState) - this.useFork(Stream.runForEach(stream, v => Effect.sync(() => - setReactStateValue(Option.some(v)) - )), [stream]) + this.useFork(Stream.runForEach(ref.changes, v => Effect.sync(() => + setReactStateValue(v) + )), [ref]) - return reactStateValue + const setValue = React.useCallback((setStateAction: React.SetStateAction) => + runSync(LazyRef.update(ref, prevState => + SetStateAction.value(setStateAction, prevState) + )), + [ref]) + + return [reactStateValue, setValue] } } diff --git a/packages/reffuse/src/ReffuseContext.tsx b/packages/reffuse/src/ReffuseContext.tsx index 7d4a17c..dbca682 100644 --- a/packages/reffuse/src/ReffuseContext.tsx +++ b/packages/reffuse/src/ReffuseContext.tsx @@ -9,6 +9,7 @@ export class ReffuseContext { readonly Provider: ReffuseContextReactProvider constructor() { + // TODO: scope the layer creation this.Provider = (props) => { const runtime = ReffuseRuntime.useRuntime()