From e2204eab98ba2a1e9067991cb212a3ca1acbf7e8 Mon Sep 17 00:00:00 2001 From: Birgit Pauli-Haack Date: Mon, 13 Nov 2023 17:02:46 +0100 Subject: [PATCH 001/116] corrected + updated links (#56084) changed two links in create block scaffolding tool documentation props to @juanmaguitar for review --- packages/create-block/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/create-block/README.md b/packages/create-block/README.md index 88ac97c34c2cf..51c36ca91b014 100644 --- a/packages/create-block/README.md +++ b/packages/create-block/README.md @@ -15,7 +15,7 @@ _It is largely inspired by [create-react-app](https://create-react-app.dev/docs/ - [Interactive Mode](#interactive-mode) - [`slug`](#slug) - [`options`](#options) -- [Available Commands](#available-commands) +- [Available Commands](#available-commands-in-the-scaffolded-project) - [External Project Templates](#external-project-templates) - [Contributing to this package](#contributing-to-this-package) @@ -141,7 +141,7 @@ For example, running the `start` script from inside the generated folder (`npm s ## External Project Templates -[Click here](https://github.com/WordPress/gutenberg/tree/HEAD/packages/create-block/docs/external-template.md) for information on External Project Templates +[Click here](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block-tutorial-template/) for information on External Project Templates ## Contributing to this package From 8ecddc93c5ec438c8cf18419a5f4ec0d5b68474f Mon Sep 17 00:00:00 2001 From: Nick Diego Date: Mon, 13 Nov 2023 10:16:53 -0600 Subject: [PATCH 002/116] Add new block development "Quick Start Guide" and update the `create-block-tutorial-template` (#56056) * Add the new quick start guide. * Update the create-block tutorial template to work with the new quick start guide. * Remove the quick start guide from the create block tutorial. * Add back ABSPATH check. * Revert change to package version number. * Update readme. * Remove @wordpress/icons dependency and add custom icon. * Fix title in manifest. * Fix heading in Quick Start Guide. --- docs/getting-started/create-block/README.md | 18 ---- docs/getting-started/quick-start-guide.md | 44 ++++++++ docs/manifest.json | 6 ++ docs/toc.json | 1 + .../CHANGELOG.md | 4 + .../create-block-tutorial-template/README.md | 4 +- .../assets/gilbert-color.otf | Bin 626352 -> 0 bytes .../block-templates/edit.js.mustache | 95 +++++++++++++++--- .../block-templates/editor.scss.mustache | 13 --- .../block-templates/index.js.mustache | 40 +++----- .../block-templates/render.php.mustache | 35 +++++-- .../block-templates/save.js.mustache | 24 ++++- .../block-templates/style.scss.mustache | 17 ---- .../create-block-tutorial-template/index.js | 40 ++++---- .../package.json | 7 +- .../plugin-templates/$slug.php.mustache | 6 +- .../plugin-templates/readme.txt.mustache | 2 +- 17 files changed, 233 insertions(+), 123 deletions(-) create mode 100644 docs/getting-started/quick-start-guide.md delete mode 100644 packages/create-block-tutorial-template/assets/gilbert-color.otf delete mode 100644 packages/create-block-tutorial-template/block-templates/editor.scss.mustache delete mode 100644 packages/create-block-tutorial-template/block-templates/style.scss.mustache diff --git a/docs/getting-started/create-block/README.md b/docs/getting-started/create-block/README.md index 2b87f09f1f903..22a28560c76a8 100644 --- a/docs/getting-started/create-block/README.md +++ b/docs/getting-started/create-block/README.md @@ -8,24 +8,6 @@ The tutorial includes setting up your development environment, tools, and gettin The first thing you need is a development environment and tools. This includes setting up your WordPress environment, Node, NPM, and your code editor. If you need help, see the [setting up your development environment documentation](/docs/getting-started/devenv/README.md). -## Quick Start - -The `@wordpress/create-block` package exists to create the necessary block scaffolding to get you started. See [create-block package documentation](https://www.npmjs.com/package/@wordpress/create-block) for additional features. This quick start assumes you have a development environment with node installed, and a WordPress site. - -From your plugins directory, to create your block run: - -```sh -npx @wordpress/create-block gutenpride --template @wordpress/create-block-tutorial-template -``` - -> Remember that you should use Node.js v14. Other versions may result in an error in the terminal. See [Node Development Tools](https://developer.wordpress.org/block-editor/getting-started/devenv/#node-development-tools) for more info. - -The [npx command](https://docs.npmjs.com/cli/v8/commands/npx) runs a command from a remote package, in this case our create-block package that will create a new directory called `gutenpride`, installs the necessary files, and builds the block plugin. If you want an interactive mode that prompts you for details, run the command without the `gutenpride` name. - -You now need to activate the plugin from inside wp-admin plugins page. - -After activation, go to the block editor and use the inserter to search and add your new block. - ## Table of Contents The create a block tutorials breaks down to the following sections. diff --git a/docs/getting-started/quick-start-guide.md b/docs/getting-started/quick-start-guide.md new file mode 100644 index 0000000000000..4ad3998e7c27d --- /dev/null +++ b/docs/getting-started/quick-start-guide.md @@ -0,0 +1,44 @@ +# Quick Start Guide + +This guide is designed to demonstrate the basic principles of block development in WordPress using a hands-on approach. Following the steps below, you will create a custom block plugin that uses modern JavaScript (ESNext and JSX) in a matter of minutes. The example block displays the copyright symbol (©) and the current year, the perfect addition to any website's footer. + +## Scaffold the block plugin + +Start by ensuring you have Node.js and `npm` installed on your computer. Review the [Node.js development environment](https://developer.wordpress.org/block-editor/getting-started/devenv/nodejs-development-environment/) guide if not. + +Next, use the [`@wordpress/create-block`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/) package and the [`@wordpress/create-block-tutorial-template`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block-tutorial-template/) template to scaffold the complete “Copyright Date Block” plugin. + +
+

You can use create-block to scaffold a block just about anywhere and then use wp-env inside the generated plugin folder. This will create a local WordPress development environment with your new block plugin installed and activated.

+

If you already have your own local WordPress development environment, navigate to the plugins/ folder using the terminal.

+
+ +Choose the folder where you want to create the plugin, and then execute the following command in the terminal from within that folder: + +```sh +npx @wordpress/create-block copyright-date-block --template create-block-tutorial-template +``` + +The `slug` provided (`copyright-date-block`) defines the folder name for the scaffolded plugin and the internal block name. + +Navigate to the Plugins page of your local WordPress installation and activate the “Copyright Date Block” plugin. The example block will then be available in the Editor. + +## Basic usage + +With the plugin activated, you can explore how the block works. Use the following command to move into the newly created plugin folder and start the development process. + +```sh +cd copyright-date-block && npm start +``` + +When `create-block` scaffolds the block, it installs `wp-scripts` and adds the most common scripts to the block’s `package.json` file. Refer to the [Get started with wp-scripts](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-scripts/) article for an introduction to this package. + +The `npm start` command will start a development server and watch for changes in the block’s code, rebuilding the block whenever modifications are made. + +When you are finished making changes, run the `npm run build` command. This optimizes the block code and makes it production-ready. + +## Additional resources + +- [Get started with create-block](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-create-block/) +- [Get started with wp-scripts](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-scripts/) +- [Get started with wp-env](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-env/) \ No newline at end of file diff --git a/docs/manifest.json b/docs/manifest.json index bc4d8bd7c3b28..ba345e7716ee3 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -41,6 +41,12 @@ "markdown_source": "../docs/getting-started/devenv/get-started-with-wp-scripts.md", "parent": "devenv" }, + { + "title": "Quick Start Guide", + "slug": "quick-start-guide", + "markdown_source": "../docs/getting-started/quick-start-guide.md", + "parent": "getting-started" + }, { "title": "Create a Block Tutorial", "slug": "create-block", diff --git a/docs/toc.json b/docs/toc.json index cbabf3d3b737c..8a29d2d4f10af 100644 --- a/docs/toc.json +++ b/docs/toc.json @@ -20,6 +20,7 @@ } ] }, + { "docs/getting-started/quick-start-guide.md": [] }, { "docs/getting-started/create-block/README.md": [ { diff --git a/packages/create-block-tutorial-template/CHANGELOG.md b/packages/create-block-tutorial-template/CHANGELOG.md index d395b408d86c5..20f2a56d36643 100644 --- a/packages/create-block-tutorial-template/CHANGELOG.md +++ b/packages/create-block-tutorial-template/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Breaking Change + +- Update the block example scaffolded by the template. + ## 2.33.0 (2023-11-02) ## 2.32.0 (2023-10-18) diff --git a/packages/create-block-tutorial-template/README.md b/packages/create-block-tutorial-template/README.md index a4143312948e5..f883ff5fb79d4 100644 --- a/packages/create-block-tutorial-template/README.md +++ b/packages/create-block-tutorial-template/README.md @@ -1,6 +1,6 @@ # Create Block Tutorial Template -This is a template for [`@wordpress/create-block`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/create-block/README.md) that is the finished version of the block in the official [WordPress Tutorial](https://github.com/WordPress/gutenberg/tree/HEAD/docs/getting-started/create-block/README.md) for the block editor. +This is a template for [`@wordpress/create-block`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/create-block/README.md) that creates an example "Copyright Date" block. This block is used in the official WordPress block development [Quick Start Guide](https://developer.wordpress.org/block-editor/getting-started/quick-start-guide). ## Usage @@ -10,6 +10,8 @@ This block template can be used by running the following command: npx @wordpress/create-block --template @wordpress/create-block-tutorial-template ``` +Use the default options when prompted in the terminal. + ## Contributing to this package This is an individual package that's part of the Gutenberg project. The project is organized as a monorepo. It's made up of multiple self-contained software packages, each with a specific purpose. The packages in this monorepo are published to [npm](https://www.npmjs.com/) and used by [WordPress](https://make.wordpress.org/core/) as well as other software projects. diff --git a/packages/create-block-tutorial-template/assets/gilbert-color.otf b/packages/create-block-tutorial-template/assets/gilbert-color.otf deleted file mode 100644 index f21f9a173f2fe0b53a02723ce7fae62fca7cb897..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 626352 zcmeEvcYIYeZTA6dkK~|@4e4^zu)hVA>Mt~*>&x;SKDjv zd+pV)UoR;q6U8UJJKcI~(j9L+|D8znkHm4dcJAHl_N3y~pNW$+9eGCDxqA;j zBF>E&BEChvZf}-+|3CI^7cn=B$bGlp(K+eiAAi^-&Mkh4>^3oNWNPmHMRzn8iAoZQ zAC!@vI<(UAdX-UkCqCC@AR{_9yffM-;Jr@9$bvD2BW{`~QhByWWYWmgF}dc8-Y7C{ zkVK43FGy_>^+vQf9jl5sm9kSurmt!p-T~!*L-B*TIr#;c2mV$56Otq`Nbxxuk-X>L z@;96opYI?`w?&P*Iry|^N>_$W_nnj|v~;wEw(-4Jx>6+UBYQ?9{GLEQ8|gpug-CB< zDq-el^R$EmpU0gK@&1JOG`pp_alG1IIuTR4A{=7`{@sax1l=XxSiY0yM!YKiW*PcQ z!XIlVnMXt8*N~h5Y_MvIDN+Y;xj?>8YRHoTI83gVs{(MiTq8XLaD-HqRslFlu8@TR zI9mMjVE~SmN^&Fsmy-@4BmTp`cxh@n1mG*AoC)Gn0q~y!`IP`a7Jw@Qejc+jVbN%P zgEK7v8@bNR3&4)Vn{5HuhdS#6a2Vh^>s<0qF6#y>`u=4;F33;M8kW>Ebwqkz zQj4a^P5qs6a>wRn4$mk^O7=Hzo78J~X4V5^lj@;LK}LF>*Df&dZ+ag+dUVrafj*n2 z<&5l`Gh}QwJI~C{&&h6_)ID`vVRlYlX435$nVH$Cjgz{hj!iAdNg9|sGBqEy*uG$F zZu;oVf{fg}%%SP*q*GpcYC+}$=^((!kvZAXDh2o}HhbQBaWEu359RKtJe`-89X~8{RC-tC8Pq$k-g^ovA{VK_-E*hlhH?WX^S?!kVk4ffEr0sFVIT?>XABS$NR71J{nXT z4Gf0;3eTpJhMbY0XAah2tj^2BJQHxf)@}?ux??uuK<{ki5cedx9av@JFB>JS(FM=3 z_!OWnkMS;!^zlcc56JxRKvP62ZA6ysp4RMbq89;ls$GWMUY zt5N{W+DS9~rTq#Yk6uA+nqurctXeZ2@lqf8$RRzOCf*S4UF7d`hcl! zmwwV;?vMd;Cs^VxxmyOwJ#sIWcL)f}Wgn(ukSX_Lxw5dxWUyQr1)}C-xeCDoqh$;T zIZnpQpJamkP3FqqWuCkuugUB325jJ)vPc%oJF-OHmk(q)Ea4~eseC3YWtIF>R?FwI zM!t|QWv#4}uVlS!kd3lQzLCwcMZT5qWUG8H+hn`!fOqqQ?3O)JBtObt*(X2AemNiq z<&YePO+6~dArmwl(j7h4Pl#o;@scKTSq^pw> zld31xNJ>h&23Fu7e&cuibNzq!&-2gszv6$@|C)b+|8@Tx{)PU3_}}y|^1tO@?0?(; zj(>^&UH?-5d;a(R%lsesm-|2Tf8<}`|JeVD|5N{G{+0e!{(t&c`#<-u@qgj}(!bWf z&i|Evy?=v$qyKCFCjU47&HgR^Z~fo-xB9>LZ}V^W@9^*R|KQ){-|gSyFY^EB-|OG! z|H;4Kf53mxf5?B>f5d;(f6RZv|BL^m|CIlN|Kg#@Ls71A9oOfEx#4bv8|g;5(Qb?z z>&Cg|+<3RVdxcxUz0$4dCb*T{%5D|6s$0#y%Dvi6bgR2H+?sBZTg$!1t?kxv>$>&a z`fdZap?j^{$ZhO4ahtl$T)*4gO?F$jE!|e`b#807joa33=U(sL;I?;fbZ>HRc00Ho z-A?W;Zi;)W+u7~nc6GbC-Q6B;Pxm&rm)qOzo=+)Vd=cZ8eej&!r#95>e;<>tBhZh>3qKH!da$GBtN zaqf8cPwoWw&+dcnME4>0VfPXDFYYAwQFpTYSNAdZad(RQg!`oXlsnaZ+MVV;<38(7 zcb{{gcW1aSxHH{Z?u+hh_a%3Z`?C8tcdq+)cb+@neZ_s%ea&6qzV5!^E_DClzUeM< z-*OkbZ@cffORR-F{#zpdEs_70$p3#N(%52q#_s!n__x>o_}~8f)OvrP*pKZB{rkv% zWIwda@%O%cPyd$KfA#l{{iDCP?Z5h4Y%l%2WiS0LvV-u~X3re`o4sfDo)-guv-Zr~ z^ZcF)U$4Ml&Hr!zYJ8ojf0e(kTs5w0T!n;x|NZY%AP|pGGx_i2-xT;a1^%B?Kx3VM zjD^zy!HzQjOijG}APvkT(!gnj=Xq)1iw4{kyUs80-Y@X!j^|Y5ZIT#$eu?+>_#D8; zhtJ_MALbpw=NrvS09*xoyaxC<=0W74AAN4aIAich!l$PsIJNNfOM)puIX?Q1Jd=#i z36#g;xexf=3OE^`a#F*b#nX?vv1oS=CC~J)mamLfBgl8#Y zq@{SiBGC%}jQ#jIv~P;{?-XCm*Pby;J=ocax|{Jih4?Gmu|4VYtW+~m7$0ShPhzy* zvOwL{cs_&nq$QpqdVc^IbRvFc3!e4x1YMkYsEdE*O}ux;r;7Jc`mF?flUK)lk0%y;D0-#`3^Nc?f*u>yJ+lg#3-Q4e1Q%2kMA`ynFhA`hYs(*LvbG@`4}M;fH!7s5`Lk zC{NH2bVwOJqPm3oB*g#JA3+^b3wT41l+`7_)+r%gPsSMhK)(ca4E0Re4|PsZ?}T(u zK>q}F5a{UXp@1$5>7#&73hAY5(KmEcP(PK`QJ3i|>MKt_c{(bnr-HhQWzbjrP-g}8 zR#10^^cVFmbXZW21$9|)eS%NwtdM>S>bOgK?h-CRdqABR)O!Kl7t((L9T?Js%P<%A z$q)I3pR)Ro_MnRQL1fU=aets={@3&ibqn_wF_-ZLmbcz#w#nrfx__^3S6O5H0=sm{aRE6rLSf7V7&HbuH2;5tZB5mL=T$n-&ZRHn)- z1WVtPr3j6FjBw~$1V1+;=($aHA;`HOq0QrRQqIan6K1`$#e>wan2*oUvXsnjPrss$9dg($64ll?0o5b z<9zSza`rhVoYPLJFTxk+yV6(HSKHUvm+ZU2*U{I-ce`((Z-{TWFVi>5H`+JB_gCLE z-wfYNz6HLweee5L_*VHg__p|d@a^>-@}2OV5A%gZhg}(#5LP*?W?0>@MqzEjI)rr( z8x)oiRv7kB*yOM$!=4M98TNYE@~|($HihjDI~aB*%!Zc>uN+<{yh%8Yxx>4M_Yc1} zJTp8$d_wr-@M+;MhQAX2R`>_utHRfZZw)UBKN5aA+(tx4RE($|(KzC|h?^t2Mf8gp z9FY-`7xAZvM+I`Xk##-V%9R za(b|QJbT7M*S3ZEb4TWjgF447+pQOUUakQ zw$YuU`$XRxogO_RdQ|l2=n2t}L_ZciHTt>e7o+D!zZU&w^pfZgqCbgV9lb7kQ}ov8 zAENh0ABsK^eLDI=jERYiDHl^QrdmwRn7T2IVw%Uaj%gp$DW+>oubBQZcgLj0438NZ zlOHoS=E0arF;ilu#mtC#DP~^G>oIS|ERFdv=ChbJG3#SC$83w)9rIJnk(i%j&c>9) z`eLJF%g0uVy*jp5Z2j0Ku`OcT#@-a065BntPwar$dt%dKGh=gN3uDK}J`_7S_Q}|1 zV`s*`9Q#V_!q~TC-;Z4pyDIj}*p0E@#_otMiaii}EcRsV#klCW3URgKn#XmDyFG4b zTu$7$xX0t3i<=ksX58|))p1|P?TI@ccdlGmxrB1plxtG1O}S3xZZ9{uTvoZ!uw$E^XNQ{VjD z)U@>UF=<(;BS#hH6r>Lwl9gRJ5=Y(nnZvV(=47E|Zh9V0a0^mL0?1Fz9;)^7GqZ@$V*QjmQ$EF3@6L^nPc+PA4tzm=dpKoW_EfSj@of>JTg;(tn~c+^ihSWS;KjP zoSrwTFg;&Sm~u@Yt)07c?bf|V&)a(S?$h`7e*NzlaOc3ghUBHDjYuybf`qrj(Y09*3k2O&>NqBlG?dStGM^a!2Lm7Zg4)dd%2yte?&v9>DQ`W?E|2 zkkmZQ(;l*OvWK8Gj@E~lq2$n<(b*&!Ns)!3u{;1zBerS5bN!sWp~EmW&U1KSW>!}E z$Q;EpKWA8hN3p#0;hF3pedy41%$fAcFH|z-DcyoE9%VTk>w>Vs0t|rz{j@@0aA^$1 zI!HU>*I3N=Qqu|x(mSMO=A{*m9F~J?|P}cYq0z_?Y)=Q>ZP@MU8>c~D-6~hS(sIjnVU7X zmo8s_ZPQ=d^uN@mf3WsIEg7DkHxisWBr88v>!)gN>ZSU)oPg=223w_ada3DYf$4$X zph>zmO25lgSb4}evv7F@te@@)GYA!` z2KZ7S5=nyE7bhOUO%mqiJ6z1jNZU`rtn~|BOqF(0Rd>UmrUBBeZP4GlpBp`M3^ zpn}V(RuCF!Xb36@4Ky?a6@&&F8iKMz17(N0&kpsH9cr5$YLO9YF(d@#hMUm_Smyw|sV=rgav7rve zUQXSyp1xL34;8t%AZKvz}HBIiMu%^kkD6DC6io%*E->R^t$(HOEpdIsj#NWw<)Y?axaB7P42C*rpbL2 z)-<`V!kQ-EuCS)b{S?+Txxd1iCf}j3rpW^o)-?G}g*8ncsIaEVcPXrCa;n0bCJ#|q z)8sUTHBDB&YVL8Dw{V&!57RoDCJ$Fw)8q_=HBHV`SkvVD71lI)gu>0az(s%^<6wL=ze%_bf6Rp`cV4fIZ_^Ysn;?tl~;6GSDtgF1)hiHfxp5e zZj?+lthZl;(g%#-FRGu1qexWzN(Su@={XP!4R%nN3wnT1HkZ1a+tV_r6YGjq+~ z%{(*TykcH8ubBnrb@K+|9RDzHnnmU?bLDVI`y3TP6MZ*bFI?|(VQkuQ>U5ZcbYrNP79}{ z)5^IH5uP?qTc@3Ky>o-p-nr4a$+_9-;B-XX=N2c$xz*|HbaA>m-JI@D52vSdo72nb zjfhZR=XR%`)8Dzn8Q|RM40P^t?sf(tPBhrL*SXJ0b%r2fG}K9VhB?EX48)G^cSbl_ z&PXTQ$#HU>QBIzdk9bm{^MEtj8RLvaWNEzfCuf55XXim@qVtgRFd|KVaV9yBI+GD` zdJHkADb5qllg?AlROe}D8X{27I@6u!oadbxh(*nGW;ri9vz?a^m3rCvn={w>yED(3 z@4Vu?>b&MGK&0voXQA^C=S^pk^Om#Nc^i?dCC-F#<*au$I2)a>olS^%ZFaUe-#XtpTM_%(=4^L% zI6Ivm5Cz-q>~V^mADz93hyCR2cMdoQokPxH=ZJIEIp!QkjLda@c7AbAI;RjVJL8;n zik)-LdFO(2(J66C9qSXH@i{)9FU%K?SX!hn$`|d6@x>ylR?ZjiEAP9)R{`<0ioOJ2 zC0}J<6-3&q`L6O^?Mw7k_to&#^dBMmyz8@0)o%~(t>xBi>HNBMSu0&1mTqrJ_tw&Vm-MJ7 zJx9oGbEMZR()$(ZTPS^BkbVWyZ?yDVE_bYu0o!F@BN?14_x)W`XULGpWyljU^e#!S zFT-w<;ZMl$Gm?=anT_QBmNMdL$@)-6?w6cY8P!tqjXV$|qj$*Imu1|$GJds8xK{rB zgFLuPChnJqZsiVAXPw&7v;P4@_mAQ|EX*nC)t%nU9Ox_u4#~m8a=5D;SuRHh$}ztjzfn&7Ros{4 z=e_dFQ*v^YoSiKfK9Gx9Qj#mBS4!!dVka7@YfJ@WdKbLCSsV0 zY-FMyG0``em?kE6nTe}q;yyR=2+qG}%D-$X)HhdFG!+|~N>`f7ZA|5}rplM5>P1s+ ziMgtixoWey`U#VmVycfZHLf!?c9@!XnWTy)DbLhOG__tg*Sv0OH!!u&nmVbb&RA(-CLU;v8Kmv({rD>?U3oU-t>Ok^!eKKJz;L|W^RAQ^h-4To;CfGO#e5{9bcFM zd(EAt=B{ey?w026baVIfX3*DWaE!S(+}tPTzT+l!ry26BN$X~YUNFP{VTPBQ%--hy zFHF|WCTqOOde4lUYO*s-_F|J=Y;r4`Q7uj0OQs;g6f84^_nQZ9H=}PbW15<=NoJhi zjKA6ZskxbOjrntec`(8}9Bn4WnMu>lqlxCPkD15Mm?`tk6MfAS)65fJn^rMtTWG!HPh>x=LVbSpEEPQHZx<*tj6ZWo@REq znZ3fiblALH#k>qRp}zUs1~a$N%w1vr9&YA!GxMjKS5}%=Pn*{+n%8~i4WC))GjB$i zMYYXa1!i%kdHW&r&IYrjx_Q@Umew)vrI`2MGao!?KD^Om7cv_UKB*kyFAi+;-v1@CP5LbfL?I&%&n^9}7R* z|H8MG&i1_UMfk;tDdA@ap8cWH*{)|-hEKWpb9np|{X4rP{_H3#ORLSY_H3^~m8Mvk zx@}gtwR!u8p?7O@>kSLH@+8V-O@0fMJDrXvTq-a5sKU|k_~I&7{^riN=9^`GQN^@f zJRemimmkC~NrGueUuX5! z;AQCcE@vuQ*~5>wN52DN06r7bzD)T5?bZI&1DL;@iz!LZrK?bXQcZwK^R`;(-u3`{ z44lP&{-EC6F2Q=aeU7sCz}#LrUqqZMjp>Vi7o0%{&lh!3L@HrI^R{Z?xS~Lz^cWB` z1!Q^(l&rDLn#T^FA(@u<8;?G!CXBcC)asg6;yN#~_Sob_RwCLJS$pD%^-)$vRf(~3 zZ4n82dd@N{SEpi}?-x$8(g!8>`EWF>RAX5b`b!~U?DU607%ct=lNaIb)kyStc+*j9 zKVERg+V}bZy0CwkwexCqiNca{@D*Dz#8tWTt$l6dAS;viZngIFHhs~hO<6bzog6rL z#!77aQP!SZjyYXf2tuA)In~M)`7O}NQ%5FQ`)v)bN(`~vM?C9uq(y9)c^;EFymu@6 zTRw-iMobu`w7j(t>n{U~LBvXatbT_9K&0!U1S?_W*+DxSf&k8OymxE>8Rm8_Unt3aPLENwj3xAHdhQTbD`Qf}iQ4n8hzD<-p*Wz}b3 zBy%&$5`nSE!0}xV zg!uiK0sKl=fI@p`;?+(7bSmRaRQ$P@tb7iFnhESu2FzK8hMiNeXh;AegIx`n4RKgT z;&vtzEJ*D#1#{!W%eKpw^#!;fO{s`{uM@8cJ7p)|RGWn%65AC4t_-5uL*W?0?p<9I zrFJhC%pM{;Xo6f0!G~7VCTN)0eiZw{136eZ?MXY0vSxgK3tM`un8f*yapNR_vQ7-c z1m}%xP7wWHHg8tEG;iS3WdAS>0gQwI4j$ z!a6mf(X3qvPL-5YNLa}>tYyi)YpECdK^@uUP-OANKUfnpuE?5yo?eCOKMcka+Px4d zNo+I;LtZnFiz3&|#iAewNmFnvaybqkUbfx4Wjq@GFo;Y&##LP=>6DT;$=7|e6Re#D z6^BLP!^^gBPCE*4)}jPXWy@FV!P_O^t?#)!)u3|i9&)W+KT)jxj$Q0tf#T0};Xjz$ zg{>Z;u%weMXMs!QPetS{eR$cDJ|hM={s|HaNg%Z|A14J`=6W~+SBOntc2Ip%O(-tA z8fwCR{VK#k6TA}Z)nBbg+1Cp&Ml&c?EA2cn!2>xIZDb?2MGKCPF`yF9V&E zjLX@BR=#i3*E*h%S60!+*iwV@iW>tCNWyfv1W#6>9a!G2J@ELLN^0Luh}8xdASOW3 z18E1eJL75UK!SjC_bwuS}AioD2%rs73-MMJ_^P1BFY=g15kYQ0i4?i>P=~ zV9yilt+Ty7`BhO+WH?8;nrdk|gbH2Ryo0bs>k|3g8XxCe_qZuQJi+BrqQ@;T*j>ob#oTQ3C=Ik!=GFS@>zIrAmx~uad60s9az5NIr z$;JF=D!dmhms-pE0%R+)FNoA`80f}U!4BZbSg8fWKu!)+&}Qst+EL_m@_Q1|DH~o? znGUoS8Jm60#+uiHj}%{A+sZl6(mY*n7|s1iMfSy3s}!|oh=hG+lX?{vx#)3Z(*&<< z6Gt1mR{a^~UMgcQ#3miWv=;Onqdu7(u#1-8LS5TmIKxwfG|^XhZdkovw!#U)T;STF zzj6)K>*`Gwl`0U<4mDu4J0u2QQGk_^1+}OFYg;oMi)I=PYRH)o2V45-Hh50xkGRL5 zy+;Lk3X8{=^$_h})I&_Q<`t*_XXh|#_OTV9JsYOL6|>PG_{Hsm=@vW+OK-nhUW5V1 zTR8~@?0g7?W9?KZNURlX@cg1Kfy5F*0U3A4P8Hp$wBmQuKbQ{%CAsi2z;}Fj*(?Ky z4Dwu^+Vlq4jpXLC4WYY11RYL<{*m;B`%rpC?X5t zmc7{@J5GgA%)n|ukOPETHF;5)C2o6U65mQzjDQmtG&xR64doTkS~^gk*HP`XJdII4 zeid>l3FD*Ui~np59YQ%qlP5#yDD~u;r9ce{ewYL}=C7Pe1{u{ErhY!n-rZZ^OFjiZ z1r*@}*$sd!$^aq*lTovWF-D+zQ!JF!#mY)u8ndRJS>OXX(?H?va9Bh*-%XzXwqZI3 zIL@^yT7yAf08#9s!c`b+!9YUQt}xxbu)Rdms-{l~&dD89&f9%c2?cA(r5?U)sh z04pE|vSE`m`D6={i%5dI&-YkQCq52bCpE|#HMqPr$yh1qM6T->pwmjcnd4yV%ZafS zeDD;s;U!{#Mx@B)#6Y8KxVQ;0;8J5TNK&&9Y*7xD0U+Ehf?%swSfAprP_ZhR@4#^y zB;7dxv=Z3@CT<55g8hZc8^!{|dLW5X)C=-+WCG~%1LlaL%}~A+T~8G>&d0=9zaf$g5h;baHECqO{r;Ei{y3l?xf;Vdv={6G# z?P5@TiQCGJ9pR-e0;kJBF5-bAN}&hBvFFhw|Yn>LlxOy4!(^NO{cW8&C{W*f1l8v-}1;ZFiF7+dv$S{Qz*(_0K*@~mAr$qx*NP= zOPQCA)dp3XXK*`CYw;VsJ`IDYUbk;T&42*%0JL*_@q<=Q*TBAfRy%AX?T_RQVr=(v z;m!dy`_mJEPN};l!@1vA#UxF*ymcsnb>M?g<%2-_@Ura=R!|-G%}jVumnp!mn3&y0 z8g*I(`T6uK5ULLRJ%Ag*U;wRsM;&>-+a2nHu@*tErTwT6rv!Cs-vf1N3K;+*&Bz6! zN(gc(gQy_p6VXvrV*(xvf>SZp-4Fn|TbCTGDWfW&7z&jjIb=Td|J__t-Ri^7;844k zlUkGvFc|TutAZU62|P4MB}D~=q-i>in^ROolU{?+5Y0Ih7|Ct|H`wh1pf@$qS8yOi zbl4JzXTR|jPt{n)p{jS1K-A^P%ju0X+~bT9Xn?$jYymx(DKq4#z<}>tCu4`4oTGb z1Q#oTO4?u@B%u|krn{&Fs26n1{?(wa#0Y9AP+lHw260tCTY+KwUa~mk+!FQiKPKkXb>@=KEV{8 z4h^bLk5_tO@|V;nR-Yq+GlKjA?(kkAgc!Cd7Z7Rz#S6jc+rj+!4Hk&OrpYjpb^zqW z)aty58qs4q@Pe`!UzO=pnf!|BJl+f7cbSd{8+!ed4W%wri#K}HLh|B+)~p0?m=jyZ z(<$VV-v!HLS1kiu^dcKBSOQe5VN-btwD#|u#Lit<(hZPDyJVuEI0(XkR{*JIbG+-Z z_Vz>UoB^hx-wz?Vl1lY+m}B+b2?xEd`sVh9K1WrF_dwxxN`WTdz;Qv}e0VuhH;!Aa zCb|O-+9=OgM&EWmG)l-91srlgHfD;S5X6+l0L&)1{%2N?WmIQL%FVG!y zS1>T$4$q09S0Z(o&{JW8Nma#6y@WoEdM@hcupNr&@_1cnzZe1IU^H~>DT&E6XVib1 zfCY4Q;0fP@4G7c%*&wh1!L&&qZa|=UPqwh8{c6T9Wc*@o5+?`CdkymTFZI`A<^O0$ z1s=7hn0PxXs6c>-=x_v8N>UDvE(YqY{7Iqmc2p2!Z-a#b>I3emfb#_K{67Qe{LX%< zB4z__G535b#Mo>j(}VrR%s|hEgg5H^ybC4~B>lTiz^H3o7J*b>T) z>D0?IbPZhSOIyM=*le4dpnl}#X-9v*JifT1HO&v6v1VB~H+kN$sU*%DAPy7YRR%?e zb1F&gf{9#MfeHXM!9uXDH(i|wDZ#cO(n#}_-pqk%Z?LM}&>rM(zGe|7G7`a+HQ=JN zJ=PP^sn|xi$$KtI^)N%hS zAt2;1}cCe`$1CrafQ1EJyB>`gOa1`G|RrMLo){Wrh z_;YdAT$nn@;%>=QEXF!w+ybI&aYlswDsZ*SaGnF~N{2CIR7%~X0f!)jqWfo}S_zHL zqp(T#FE~R&CbTpj!{>od$Dd|)3{ZSw;4G@OGKC z4XmsQaye=>C}QM*%(vh!vA3ToA`A3V=lzYA={c zTiPO`gWfRJh2R9trF7SM?yhA4BlPk-Gl9&ANyw^8=H0G`Dx0Q{Cq*~G#4#t3AeUUS z6kGy2$~eRzLHt1gbw|5_xHhL^vBxpP_Ve^K<}i#pmvZ4G6qbxyp`b3~!bwwB48$la z`%xw3@AvM=rIbq!pO{) zjCzz= z5#j47E5ihn!88G9YXMM|3p`}@w!^GyUxY1_p&em%;1_92P+>S&rL@k}K_D!NXxEg7 z3~t(m70^UqQGi*@^c1%Favlt$41)mU(S~i5`c2W1w!znG!6IuQ_VLBju)R)fh_D4* z0V}(CFb~8)c_5ZF0Ll{kN+|R|gqM1c8&2=_DQv;WJ}UG=U4R^Tr{qH2mX3lhWL3=K zcYEeG(qk0eIMjVLC^&TIfyS_#p(Nz0e30f87DN(Bq;p$gE2~2ixRYbg(7nIGxoj}# zvYqcZC{^w@0-F#>bASjSPLK$^B5;WagBmIkFth)N2o+{>Zy(fdEe6qV^AN{!1rUdQ z4Kw)v z2a7-**M!4fO#~XK(p(NISKuy78bXCjh0aj4ek!jsSWBr%i@t|(40^;t*LDS$rXx7Q zzKC+ENK5oO8FdF0uYEm%0faTgaABiK-ne$|LB{cIrA0i25iF~n7>S{VljmQ+Y~?`+ zB8GXem|{Pi{SHs<;#FlPr|~wVMaeTU7l#_lk0*dUrMs)~u1*s6#Gs2w+Rt+WRT2>K zThxIKE_E#(dpEYRs9Cx@kqbWtmKJZ$^5r-$Is3Ua(coF<=7p1}W>JXF*1=mr6)~y; z0$tlu1{UqQfW@3#fdmd5^_I5gK))(0+M=7B%lkB6U}55mAHfL$s2!M5V8QS6W>oq- zJZTVa?Ggyo7Vwmp;FSx`hnFLbTG6n!;vr#h{&q4}MpB{U?Ht%e83UIJB<91*W*O%R z?+>*5F@YxdWo!0kCsb+a+bMRJNQDWnxl zK%Ek-lSUp15#JZ#M`1Q5Nn^WzuuR=}Y>u4}b)o|TYwGobUqz=LQg5|o8Y~P(1Se00 zp4~#{Ou*g5jI7p459orH=_B=UR0M8-klOtuO*`mQyP4i$!$l0uG){r80tnX&PM5T! zqEzSZhE3GKW3Zb9zsi__v%nrsN4P8?4O}`*$>TLMJ?)Z4ia)pAI^B0Iv(87@6hR`$ z=5(*^mv9s9AqvR%lkvKB1;yrl=q>3w9hpy3GGeF@7VgCy|A{ySsuQg$=*@DUCFP#L zBzE_K&;dad|LV+&)B{oHUmsiXA+1~vG&$Cq5dXg z+$(b#Me;y!y3}VdS>NrkY1E7?vd6%KQnB8!O!Pvpa>qE0?q0(ULWp{SQFhY*0?u|e z*EEfMFi9n)(IiZLt~C)eXJP6H3BWl5=sE5T3aL*YTU&g)esV#?a9WW<4^IGpFw3oMQ;ZBm6-5&x^^=0EZp)sYN(j`77%2ABe7 zi#w0Dv=nz`E?&X2h!7DGq{Lf4FHD4UQ_P2FrgHaIsx@SAhIqiUq4l|R zo=OL3gc~`d_^$^6sh=<|J<1ukCdg1Cy2EE1y=jzop zJ_3u5GJwcHBU?$eGEb)LKcEPtF>JSehpoH7HrwwQybpoc!*F;Zvvr1flWXZoOEn^T z#E&*L$&05bL`k!eXJM)};7;O`>XH2YY=+K-3p$yx{Ca=*tqy$XTv^>1k|b&Z<)dr$o)#kMLm33C}$T(lV+6Sbu&u z7?iuwxqXVHfp5&Mqvs<8*$~H-%7*zo8VqW}T0HF*3%!Vho(dwiU2T^|;fOdMU`%bAw8B zy;^W?YL~8qt9c<6OrWv9h2E}07DTFqcze<&P!=NL=%B9ZB@jmh@?yV%wgI>aYyS-? zu|o%C*WZ9CY^hou9$R`A+=I}MEv2UxU;HH8RIIU?J9!bf0s%ju2<{0^JwHrwRiTh zP>Cep&(<}G($By~YGDPqjX`Ui2Zq#BeDOYO)_`dP?!tW-t~7QpgZTu_DZ2XhA-KJu z)~=bjoO+8!#s7RzFK_LdK3*dQ;qm9*vCahO5$y-&qB2$yQ{Dg%#eUxc%<(-X1Fs~< zhP|+;nl1G=QvRD)qeV7{lwSkB?d4stwe}P20zC!0_==}Xf7k`6O=`Ze4OD264@{Pj zmu};JVD}Q584m<&%Uu&dq$}wsUk}cd8`QHUXjg#=wb*jIp-lvP(?Dy2=sXt&p$Au; z14@5vSOas4FP`JEkFg1QSh0e~6G8T|9eH#ifz?9Y=k?S+&2(cc=33Afz`E}p%T0V zuVh0$yc}taYmio2V>eHl@x1QR>MWt{!mSN!U!s!LgYMT!;=!Pd-G>W8;P>y;AqrZ! zhOhE_FD#d`8ZYApXIaMO$U~KGZv@%%7i(iUxkz$>%!t9fV4I)iL{r0SB1EtbUpN7)InS;{lwBN5$VX(J zkqE2;y16wFHt=p!e~_05jwC%(0BI4&7cM9Ot}xk zmMq5Inko0;OCpqDwv-wpAXsRLL26`xpll=!vcVT@DUCcglrp0v+~u| zV^dyH)yt?>&H(L;+i^0fMBJ0M)jDU@bx{0uQaU|M^gc4Sk_^=HE@SI-fP!jT4sS0K z8{%L~)Jam@bwWC|3)qRnd4xp`5>em0=~`y~rh#`YAqng`zs4+n2aoqa3=&)y zMHhjK5?BxK{R*-b>YyeTqzn=9<}JRrWaI$001;oe<{12aNPOTNxE)y;lR(r2fthD; zjNJzJpqJtMDabsSM*B98>bfaOKNZYv55TXoA8*B6-l7q;A8(@^4dA`nC)PsPJAlvm z4pcid0Oe2%UJxA&wv<8K#5VPAb87!V1!}v*ae+w&mJV}v#pB_I&9R{bcTWoujCebGePvF%1rL``n0DAg=3;a5-{&_l$K6~ z&}Z$-^8#cis{i(2SgDM@L`|eqJZ@K#sa-*f6NDS14ytnxF3ENy?WU>4a_u zDSwY1R6I%)Q0c!%sAKnNAh^sWhBsihq(Azw1vv15|H1l5Kn@S&#)oBrT3X~a zV7W{Ie?hK*Vt<+uBy2ejEaF|TpdVt74Fr?!C+D7i0!I6%C0GW*7$KH-KE$RCl*SSM z|2>xHpaGUIS&`c1f0pH8cs*`czW~V0vwKRywX|%&ABreGl z4TXW5{uI~NbmHX-+JFeCX*l;MQ6YI4EC8sUU@4g;tQS0;5@v?^A>1V!nOBQ< z2`x$jw_p^~Nh1-1kPYlS+ye2@Hz=hs_EA%nR>7=%aI4Xp>|`dwGTQR&N1;fdVGw9T zO^UHYN_h~~c`3D!Lzd>`=!vYV0V4FD33i*Bi0xL5dD#B_tp!+ci!$cli18M3`?~Yc zs5780s5!84qlFZq`Y2`OMZ(aLJ_rYn zn^Q}HXB6=~O}ssq6lxGP8&Pe4Nj2P&nrF{8wBgry@IM&ko!1U?sAXHu#h3|{rM841 zznIf zuWH6@p##7*#;paAFdqyRi#)ohz@(DSt{80+NStC~a|OlsWH>K+3aM(xpjg01`1&-8 zJ&4N3E>*v$7B46*10UEQ)s9_YPo@6(a1NfdatQq6fC@B)@J6|ElX)EAefyR?Y1e@Z z>^hYXF4)I#tD%YV8I-X*xv#^U7e%bieINC-3QEwqy(t^~FKvs;xQ_Po8ftIlF>D>< zi&t8+c~Z@w^}!beF%8nRXcuOsU+g-x6VyGlocvcpBuYRDTN(~Zl(0@IYnOb*4bE#d zz<4)tSthaKsYOWMrEYv10UUs2*S8yCTIaAbcG5H~N+$}y>)Lt?d)r33{oD?Gxe~1< z0n%u{Lp6+wM#O3$^9)AnJqSztKI$c>|MZxLK=A2 z68Nv$P`g0!c2ZrtIIs=UixDtR13j&RL4%J(acVpeMU63}_X>{&mhOHlM=%xh{v=-F z+y6M!BK94C)*!jyVCfGQLZ_U;<^`_Kl`1}g5W}xrol{5jkf#CZRtxOnC3u|@^)9es zmff|Q&f8Y?OKog!2(%7bO2A$B4HD&E)bb~d~aiOhiC! znST9n1H3iQfPFmzT8p6@yOYHH0p2^56V#uy#46giNPzNWybmB2DoU7axlehoEXX;X zd37-~pRia1NufySxJLq*h*D)vu#lvB$ps51%I6z&bQhQ(+G{%KCeG4G5i!_22 zUv_g++F67CAxv?o9>VlLJz4s~m*}P4d)O`qojq(H#)3RYt;ti3_~O4}`v4_qmcg4% z2HChQc5NE8;16WBH);DrAhr&h;MvTjvbvGQpV8Hj8^JjQ5f`FXJk|(n)0bN28r?z# zL0m+b4aM5KJy&WV1GX?==xHpK*h|yUd1fn6v@``ukACah!&?n2q`@9sjS%51vLzpI+f)v9T|U8n;l8d3!)|7I5o5(Rdl zM?l>Bx?!l@T*Q8gY?)nX+SXNmZwLDOq*Ho%q*E&XigW>bk#qqn28gQUElaup6$4B1 zACZncarp-Rp7!{<&NBU`-ETt{kR5w~T zA{@O&=!vigQao^}0o}p_mAIRs)9`~dpl^Tbxc>ar3R}b(*8pnvyB^T;6^Qbd$H9v5 z44_KtTZ3OGvT|bad#Bj1_Yt#0m#67H+Or%piopbl zS**YRf`{fHA)DfrN`B!~y$Qh8MB9G3xWNg}@?i#9KJ!x@AvmWQSa|ym33ns0{fs)e z=LEGAT~Gx&G6qp-^bK_F*}?qLk<-u@-a~T&33BPR>PRRBmC^Q14ckf^bp$>Ib&{dB zYM;KR$I-2~P!oFJOes)krF*u^I>Io?&lRWJ|Isxw%2r`m%ci0uqj zYq63Cyv?sJaSeVhYsH8d(41k-1F2ntGBE}0S^5)yDZvsnSCI;K0(WXw-UBBDjOoMN z$$2?u8SabFS#hohUzD9L$cH}cPjJ)iFN6+kfqQajBA{PXyB?YVQx6c^=N7zK$08|5 z2i~%Xpx08WHUO_mM>0M%$RAPWGUBHF*9Z&oq4Id=Q=rg<7%#5}19&U*ipG)cJa7!y zux}q&)cA#y5bS}0msYT-0OKHmYqvp;S!{o%R$vpUfely?qyc8meSRkbPd%5KGXH8ahIEK1oZU z`L5F8nP7Bar4L0&Q6uuYmHM47u&mIz(wHXV#A+y(YiC2AeKPjS{%Vq42JT4jv^C#eGDAXy8iQe+dqL~P~kkZR%P0YD;|azSK(UX z>L3=l)!Z)FyrX-$39g|uf&fU>5m@gOa;0|+R*{ClM`|Q+0hIk)lww06i&JQ_roS$I{_2^KO6E{Pj@%#`pQ>|^2 z5f;PSIZReh_pEpPH2{tE>@0Bn#rHDDUpOm7zoFx={oHT{kKu5}>CMDDEi8Kshv|6d zioZFA^YFM21pky6ViutTOpvwAStiKJv&{D>xS?}Qjc*3dQ85$DhqwmLF@ZX12z+^x z=N$`{J;%gtARxRR8+JUBRzTMvlmeqgQXO-#idT){_hzpw51arZ!cHxMVy`-^I12a^ zTlT4X{EZUd%W8)L3i0B7Fi`QuSn}FvYv${9-+zfCncBmVUzsC^D2|1zh~pm}6JnvK z!-G;{Z6&0%@2u4($m(y_iUjl4Y8bDh0B?#JW zG=8E1;jIqnQWy|>hFS>4UiC7K{}sdagMj}r! zzxg6~ERc}nOQ`QI_JVAe=!u9s0c?7T`tKP0A$x8)^@i2}pV9T6=0b z^{8(#Ck8N{i23#m$75Z4tPLo!uLP7tCz$`%V!Y#mJ1h;MwX|V&%`pA8Djt|Rj6bu% zZ5$9)fs2mKUZhqGc>P!_U{Qy~7$}Ov$_PaOs7M`jK*YSdimY7ifFkGw?g1wGEgT5b zfZq_7<%q;m+|eAk<0p~yZSdSK%&asHQ{=Id_j4Hh`k<8elQ!jBfcBas5aNLnYg1qH z;We;lxzj@f@W)q-DVCuquHfNFm~&ZAL&g&&yS9~HDB=Uz0 zv8g>m=Mqg(6ZI+bb5nVw^Ucj%2VD=4qRFS;TW=MGbv(mCnfd@`1|4=_>TU2Uu}m*M z;ae!y;0LB?G*@)yaZW(V2CqTwo{R-@;VIg^oZ11dUyZMtBECl5gAep!6k}EG=U|JXE%Tx3owDrNscfr8NXHNy-cuz&jT&Au`Ojdis;Q zp)v&0aje8kkRAq7oq|cMq_1vxQ*r1TUz~v*6L{JDvWAy*OOIo%1^V8WLM?~@eOrp9 zCj?4RU5k%Y<2`I~pfznV^@YO-o4vRQ#RhJcy+~7Fz+Lv@S5ORQIVEe;MyQ9X2jR^4 zvQe>GE%2>b34CJJYr>ayFpkD7!snu>Hr7e#AxZ=tpcr7upPmJqI+Qc%M{NLijwjWC zu$M4W*kra%VwZlN~0hx4zS&y(r{U|YG7E4m76BlV7hEtb#Y4~g1y zIA6k~$ij9uW?#%Q%VF)(qAmypEC)Az!Qu^69H%fn`(Xo(62il?HjVr9^UF}AnkbxW zzh^0ADW1gIhd2$Kt_DEw5Uc;lA-*TJ#qFVizV4`jP|VbpF6B1%7gkz`aitZRa(M+z zVK}C1cc~xBn`jU$6q{PW&4X${v*9ckGmcnY6AQ2c#EKxoCDa6wEG~JK`#;|PtPH_bo!_CA^L)jVA!31DxbVEP_2iEK5nw)7(Acyb13(3gC1HqobWzUAq&DV$U%- z-3lY(mwi#QgbI@v3G78}!-^O2T?`Z*oWYw%`?xaE9OM)TCyCTx_V3wfu${3cUYkbX zhMaH%5#7c`Pf63?eT{&1#iYp90*RMMs2!0t{4!~`M95wg5SG?l?&jp5Sd!qDt-Rjk zu^WS85>5xF7RNgeI!Vn2nAy*rp`@=?Gt`Kiq{<+*RA**=(mRq=#g7-UBlc;!5z%tQ ztREL;Z4cm)as*R)0n?RQ# zjs^=z*c@0*Mc(0rVm)S$EKg0uDO*e7i6GmRw&3E0_W`$+faVfD3@lVaAq~$58S$+> z;tYxh?sh0d6l5ya#V({ZSBVnUJU&=%%U@j9uh?@%0XP%r$7aAC?HQHi=q5H zK@=eao#QGPIP9LFi35t+^CY0dl{-&va=asjugDGH11t#e*6%gjKpwG!X0w*t7JD(0 zeHMaeFJKB{Qo8^mGhks+b34R9;wWQVKv<~~jzx&TG^7D6M11jbYbv6J(^Y@L^3Q4? zpU(g;&#S}y=QjHDhsek8@y>v9Wtlt#&jJ*D2zzBOn`HozPs@V*K*db(pG6-U${$&c zry%p_G}(8zf!(^}fE1TI=;z=8NtEvOz%iO2mqQ>IWz1m{G@LhAza)fSyiV-9J3%Al zvNpa^X=StizCtVyK_r$9FJOKWl?K+vl@Zjc+XyU!1hhLwHdFg}0IMc3U`4yXng&bx zfa*ZDJ(sn2|hl(eTvRLYy)jp3Bh0ULO;zW@?QtkN9R zA4ZNa14Idr}Ctl*4d^%+hdRD@!Y|sV32aX zAcj9d8YGfP?CnM_u?xcKo*-_i3BU#3ktXu-RS@zN%VfZLb@3AMy%%g#$-j|AtV%a< zf4M#yQPrXN^ZIle_}f8P!TUx`!u_dn{GGWidK+UWdX(B4*KLHo96IBvvDD@mnlyqt zh8ZFkWz4ZVr}IPx&AEUYieV?r#%m!Q$M|!ttuuZQexRW8UjEQ)nOlB|iCBt6{c*=r z3(%J)=jLK*+}S*a2K>w%;JofGdW1<(R(=tBntvgZcgW9yni}zzy zKB&Qqss9(p#s5B{xPz7Nz#)NOUBS;ZVIpr+)xM4U-}uH6YzQA9liWrHjcgq1f%KTx zee|E@wp=(uCi-yrxan#Q6t!_zOth#YhB$7)V49u_qG^HP$HqXkdiqg zDbit3CxPReSbQ%6lc++KeiV`=6=`Y?#^JkEKyHd*8X;cmm8 zpiR4i#zYceSiJ{wzyr)iuICXXFzlt-_5@=__6S^G@8NaAY~*eNv&5fWXyp~)XK)z} zE=f(8ZK=v08&w0XYbnFEhkZkjt)agx?i0f+giP5lcJUkG_6sbpm(4PO$iO@Ux7|c*`uJk-SdCg zJM(}or@W7!`>C`)6)hqqE!sp9Nm-&PiHb;Snjw-cOCk)VnM9T*GEJnBFi{eTq-aV~ z5-HN6RA?jZJuT0D-p}`UuKRxOXKS&%@65dZxvq1a>$=YJJHP$>&N*uQT1MAz9rFFv zv|ulk<+no)K2zAW6?}#{1fS;O@d|*LF~jzKh|Uuk4Pzwpu==#DkYSVndsta;spv^G zv@oiz!R1F7N?Pxcwq4O_mFV)qS`1{p#f;B~Ys^si5UCTg^-i6)Eqs!lN9Kk3O6D>H zlB)BPa+=+w^Bu%5vrRP$4|a*EMN^I62HW4i+LaCF+)+);HGODBsH9M+8bjUu4%{fw zh?Y)7y|VtDW>VYHVZKynbsXoWaaRjAN^At9Q+ zYayHJfg(|HEJdQQxt%~jE+n-!iQ9x?<^_GX6iQPg#@s$}=WNsN8}6LV;G<>hLXr&i zw(Smc;qq1Vz5PiU`l%*j+c(DlN9h}c)tiLyo6t73_E%sbmv_o`^oR0r>7*1}4$h|+ z(S=798{9t1)}NtllgY7ORhdkUHb5+03_d8y>q-d}62y|TR9dMbOaVEIFb(?#8YGdf z-v4feHb9iL)dl!!E0}0=z%?2m`_1IFD=z$y3|9p-y|m&_oUM+nqtN4DtR8SRs;8Tf zQT2pdqJP~PtYrVvGj8;;0q~stId3loPvUh)OL_SbZV@i)MG8mOZJA_6C743h2PXOQhG zY=R+wAVFVO0+8>iu&xB6e$}x+;aArTvB@jlLbgd^`&1XSU3Q+ksWDRXqE%WZaVI$A z9u%VZi5OeDfHP#+t3r39%f6`73;OPmpK%z1UKf&N(7Jd%bAm-Ku~=bqdsS5*exQr4 z#>N3KP=txA6?7Hd$fh^0SbKn~Pu<}-zbI;V^TAZz2Wkb1wvip5_Cxvh!vy~xAcXHL zTISm^CXZ)`jy+ow;89p7hT5#FMHDyF(2&E02DoNHf{I+~9(%8MuJFz$KOuz=e#oQA+_A`e5jw;F1$u zf>bteiL<%}YEl-s1hp(s0eAs10#!-0(*kE{HqFIGz*y{(26rbp67j&MnPBGWg~0j` z_K5QfbP+(w;1zMCAT$W>Flm^~)QBrcDwr_XF_6j!(mlB7e-#xF_6%|FNo>It`W#@8 zz*IbFS(qB3SA?m;u7Ifq`UwC!4@^A(==+=C3YZFkT8)5VY8L2$ zxu`cUOcm%Q(}eEflEhLsWpEc?fXHisejX-Enz`zZ5Z+VCbhH` zCs}X{-&`<*fk;>CM6tr(jn}%fBh>4P7WVrRW8luFo2J8J5m%6}TWf%{eH6*>!ArkN zAlxKYUrd#V7rT;`3mv;~9rHtHsS19tzN`QI)RHNDqQuDI(U zdOwONtnAbjm`}DLjY!~NsflJr)FjXxURf+7zPkl}v4m?s_SwMs?hg8xeEWR$aHWA+aD=~ zEoPG*7pBhIS(Ja=etzHXM!h*qVJrwe_ znIiPJ%C%<|9*R(f`j6LYbST1{uiq>QjkaIZ@{amjZLwBa`;HmTHx!}5*HQO<6UCwm ziSHK_b2{u^7)zQ`=0~tEUEv`B&>*DOJ`>(zzxchS@E^K@V)as`?36^m8zKmO%CK2I zYh{M|oT-7(Yrj`)eh-#t_%S^19zf6R8~ZvyNXbx|m8)|Y^`q6w-zq4yML$~e!{`(a zqf;1FP0bGnI9l)2TvtdSa7R=CLdTk;CRIPk#?kU31ob1QI@QMZrKuJ4gG1nGS^7bJ zx|Sq@Afy5jAYUZ*gLHyKB#sh9uo3W}WSNjk;b=)BVBmmOs-RNi10n2Q=hNDN5Za0l zELcfxQdz>3^06|4@eP?vZVu{$|8^P$E$vAw32FxRpYMPR)y}xMJyJ<^Oh?@&TU|(K zTG?1izM7T@M;fT#f!s-odjJ~r)m)mEpT#^Vbv*VR^0N!L>qiUwIHXiyNN$s=rKbK^ zfWnR4eEDJN*-X6FU{)RBhp&)Z*m$+#L@?M^eQUe)u%i1I*|{lum&$?Xk3|p2Dy{jAou2Vm9~;zvurF{CyG$L>9AwuQVHT>O2pA;L@I(Y0a1|l}0Hf)T zsD$KW>$LhVuFZ_~ltn}8@~toqVLjfkl#)8y_Q(r{3$THPl2}i55e-4R5e;cl)OJP4 zNkg_6AzvB_6j>j16jenRqn`kj*3B^d7HDBVCPuFz=+nMCRSy)R@z}>m#2=F7qx8It=Dr8Dx@gYW7VM>jJ-xu+A8O*s@SB zF90Vvw_)9ZIk#vj0!w#Ao8`v3d-LPmd0-u^C{Y@mo6-W;o*uFzt}U!{(^0n)TE85F zrgraNB}d(dxk&jB#z0eq>*_ z`b2??*n|4O+|&I*;^3_B?A*k_HlwW)elQJcQ%&TOrrG>vU3N{A#;T+%0z!Jdb_K<2 z^f|BWXP^kDr>CdfVy>W^8(Q1DXs!0)=6fhZD{OlbSBk<^HYlN_YQ$NfM(*u^q|xWR zvY$be(Bh8rH9K!W{dU?#3@58>salHAN32;IAFhenMW{w+5{~w`-o`> zNs`d#L+Y0Va_AS@ZSH=Bf~{WwGgKP&`9PzTzH1xH&oB;tSq3TnVt@XxECzW7%CR5A z9vlg{?jK)JE>iF%z;&=K;maScLY4jCi?DS6_|n#pw6`7RBR4ODc|f>kR7VTL#82=< z*w?`@ESRBqBCIhmrTsIk$P@DG^TcN*9Q)h$M1iXJkNt{6IRvT(y^TA#QnG7uQMF-z z{-YFzKY{&$l|=jB=Qm2Q2xFr(Az#UtN%lc0i6sMz@ zj7ti_tV}7k*-*sbL71NC2nLZS=~RJ-ZD#F&vao>gF**L)g8AWIizGtqklFoYxRNh4a3M+Np(P`EcGqfc3`9C78l_;dKel zD<^zz&btWt5OLmyaFB@e_C`}l;k>KhC>GBJ&oz@^hpp{CrfgOuVs8H$Q~zK^Msr7pR>h$xWtuzMTkyY_e2?_8E>(&6nP3MUOqS$p zsR=Cq3d)TxN{90q8jm>dP7ZgGlFdMJ(9XX)!{H5R@XvAD@tG3 zDRu8?b!QJu%N=8L08#}&a;Xe*_L9W;YeGEukL_5=AJA4^11Wp9H1>EopW{nZ<}HX| z{>fX^7e~EAH$}B1+Gqg!sx+W|O!sjZDv~Y!wry&_E($QUQLPjvmQ&9_mFDB^*ppmW zNCLva{0;%OfLY#ur8}_}jCy*;XFk>$HKo8sJ+%z~0I@mVF-?sI!ES2FWp{C6`lLgB zxR}9O2xf%~k7~q+OXN~jwyU>7aT%x8vaQhw?PFBUUyKeI74bkV9D&^s8-9dZeU}yC zPORFB|LO`uw1~=8TgO)wQ6332oC0vy(j-@T8|+@w0q(eg78;eqgFt5J?4N6PM_t;a z&K^)*T00tid)roA#lB1R%PY)~lERG*il1Q&ai?NCGNN#jgUa?x8mS z`XhGaNCY7Lk`q7-HE8ev^N9c{+M{ z+)ofGe5M@^1i=It$>0@xHLxwDIL&dWFMc*UV{oy5B{bv$v_9*q|81Q|Q+*Tw{zMs) z6K(D$+8Z$iBc)shjEn%DA4X;YTusl8k-}CL;*L?PeyvRbe2hHJ^d3q>%e+o7oa?`XYr! z=F3|09!L?i5ma83lQobcXi<)P3yz*vvpcRZSE+~otx#CY3JNQZg$yyVN;eDuAd}; zopFD|7fFT`#%I#{@;A3Q4Xth^+HghD-C5EQED)G&NPSJ)gs zW|IuUTFDqcCoz06ove~pMNxY0L|fWXQ<9YnU_P<;Obs9TAitQL-uX`{7uf0+vh|K6 z85+J%jVPJq2)~>t{||-Spm}Upe4Q|)C~(lm9elmLg7!-D9L;7qT%Z%>stVmgwtnHq z;x?17QbHkCk`+qVyQz$Nn{7o^s@yW_YcIi`N`3!E!)J0U8opd?bU%W9H%d=S@xgmA zzhFo5RrntT{(`b-x3(r#WU+R^cmThLJIzA(2kHIkjl=>|js=OAMa&cwd@=>wg5r6Z zNGMmZgQll^b69RnXy6-zYhu{mqjR~Kal<&;l}lR=`0db=G;zc@qRyqwQh;tasY4hM zPVcZ(no5M=sYgsLYyu_JD=?}Rc~W=TfP&YH+ra5gNAva5qzhG}DgG@B)H6;Rls3Oh zo}JZjTfaHrh#mElROWLjdIv35P0^c7&!yw!&|?lPR^5?O3tSa7f3pB4zU+5Zqa!sj z9~qkHJP%;v%5Fk&JYDR+0Xi?szJY}6V(ff5m3uoHEaf~8n;(o%)v#nL0zAR#QEzgv z3gh&AmtBcW(UAhH$X`eDZZ)#d-Bw7pnReKqQ`$tvRY7i=+s##07piL9aNp3e;=)Xu zmMyLi(@G)#*aAp>u4o!=c?5@cnL*?(K`YzI0y&BnhY6>K7@8nCoU_y|QlKUo9Bi%s zWHAbz8j_yT*~k8&E}mUe6Eb1tzqu24gROpdBlOvfPE@f+!?5cU{@V+$qMrIZdoe{X z%<(kd`&u~eydmaR1}y9mw3#0GeTH4u1Hajr^5#u+%rJLrcdFOUef+Co)-E*!?g0!3 zbw_y!L#h|86jYrVf=Ho>RBYQU6}DjZ9}J$tH;W-Ya*g!Zqk?^Ulo*9AZaeZjsyloV zkB4Id*)_WG1K$7|ZC@x@^Dianhft#a^3=kslsy!_05Y!jU?B71bQ;ap4TOX?vVFj2 zHBqd?htr_1^_8GueX0w6`9gfap4V4q*!Yz%`Cc4-7NB?KSG5Yiy4upb>@QbYL$OL| zUW1F@sBYBS1E_a3WI0teFzdv^I^{)6AZa>_Z-9_QlV)>NbXcj4wd9Tn48+=k6x)BQrStPIznlj;dM{x$$g4=to0=;Xom< z=q1_!C>-KsKHt((fOLox-x8!lY2hp<*$t^oJDj=H1jwAYF^tytaaf*nBUM0;Rf`M%p(+bdb{Dy#Yen3Pw8Koxjr-p)SQc($+MQ zZrGeCrqS|XL)anAmwaJYSC}lM#E=-^tSAiMIWkl$4p+O zy+~I;Zn}DsxIa{5yC%xK(VvB?@Fj8~9HQaHR1$f-j?Ha0kn2WN=zV2qPMSX7M=UpA zRRo8^PDfcOYqvG2hM48s!rTkMIRB}-)hVn#KWCKa;uLVum8E2Nx&R$X9XN18>IlxO zMgWK)b%e6ZOzN=n7(KmNt5+jA05gx|fc~!v`sX7Dgb~^0fNI$R+jYej1N}%2FfiT= z;hd#F%1AaCw&Zhql$y#`XAn-b^_H{@XC5V2jKfVtx7ueZt(OHy&+b&98{Mku|2`R}y_R_aJ zQGpG9UB)^kr2%3y6}>k6Dg~R?VkGClhh!eF19{)T-$9Gh_-8_;t{}5kd`Y!o_bV@? zKzAdrG2@6nr@#AoVfyX2 zX?rzD5AqhI1Ni}X`6(bjmUi+brEyxgc!{MJB$-7Zzm|L%$PcXXpNi>pDq|~5Qk6at zeo*>KX%nm0a*`j7_uo_kn!A)r9O5>KmgXWq4Ruh%=wgEWpovHg6OHGghN+pk)UYh_ zqdlAhmV^8>W~-{o<24x)$$5Ai05QU24wa+`KJgq#P%HFuJKHL1epP?LZfpWsVIJ)OBx$x*Rs&y5WuR>zj16FKN0k6L3~-Mao2mFforJ6M2=i z5-M1C-DJ~!C$TT46RbNH7x5)cbuqmT90CX@Q~H}XE)CM~amL!Et%Jt3L!?vz{e2P$ z9P22#DPY7pi70A8rLnfcXPt=W3J4gP%fZ9~aGppNkO;Hxh?yn%f|@Z+*j-Kkyfxf5 zn9J>k4}4+UP%u7-eH9+WzO+aR7TG35aaKxXI~i8A7h;N30Am?^E#aP|YK?zT0S00A z1^Q;`m{fpi>ZJy9FYF;w0nExy2yMPMZersDAw=9Hr~&lf70~GJ>aElSDFi5<{8LP* z18^e_WP=~&@j5meaO|U87t;Xjt028gh3~7S)xDvuYEWqFykz_5YD1611kCMlNT;29 z{C4%Bh{kLOx>*vjYgYsK^E9+)kD-p04MDZm5HSTr3d1mJ4Q8sCNp3T>4I0?0k>F1X z$NISngSajV1Hj2tFhFEHszWJCgB%T!svt48AEiOIYjotKoVI@N2mq3$G~~&#+?0E7 z&Ee!^Wb$%y?qE=}IXTf=8C6NY{W>{&mJTx>IQl88vinmLMp z3aA^I13+NR3tk6H0%7Q<>2KR|N!3Uz{zd8o3EqL|;Yx;czt|Mb)rYKuhCS^Z3!M(e zx&k((4kUDfFgt9@f8#RWvw1G$p*cu%y(K~^TCTy>WW~Yc(t5Eoc__m%bxLumbE&3n zm>b}n!s98f`QZGDo95l)J&9iCo8>u^U?>tTQ z=GohCn2Cof|0||<{Ey@5?2-|+t+O`&o*dfmbl}vp?8pyu%snYt7#`q?i>nkC2P;?s z+%Fs$b`kV>Bq`5U{{O@Sfxbq8 z53rrYgn{B8Lbl$KWPTpK%iYxhy~bu1t`cNaDB1Z=+?v*_7>CG{Z*dQanZFcwezqC- zj;MJy=@(}H6slq&58WC0v|bi8BVL$COh^`^C@y??y)CCE{}*&THP%C8^iyL!AnQZs zxFye1%fT+8xC63Fn3*d-!gkcH#&Qhw4r7&ecSR=l*bxwu zU(y{pQXJjGe=*xaI`TtGUh|z@CD z5R|qQgdl+vs03`B!@I-ic$mUEOtL;cSdOScDt3?sKEx5@&R&_ziqH9}usrPUgC?sU zrg#O&18atJ#)_iAO5+hbvXhYP z@+Cf0x=JqZRt};?9AHG>j$dP2|LjE1rHE>#Y5Ay#Ck4aHuuig z*=Go-;!p{IBYQPud!q8#vaTp$PZT~866m{CBUxBqb7_$ zYLeln3(4z8C|*A8=*H~!>qo(O+!R~vmTCy8Qv5|Q^ki^+dItP(1UCJ@Ew&1zhLL$; zYhf67z*dW?^?Q-Veh7{+{@MRvGv+^eu!GOzrww+ldc$B7#2^gGIoP2l##Vz3w&fn| z^xf-y+J)d++PPB0^WH#era2Sl3`WcO7Ly>_Dw3EQR;kJ?sUxbN^&O~ilv3~6dYi;f z3)tp~y(gG9r;*VHfUH&x3rTH{K-Ujf3nXwhJ@KxIOeB@%>LAZmKCfzkX8wyN^x{BycWNv@BZ4S{SIw35djNO2@wz* zJzxZ^QT{qne&aBUp)n{Znh$fNlC)tK1Fe*fo2J(X6*3Vqkw{7V^YMErC?x_`8ghu8 zm|h(FVQuX}SDPb1m=i$3L6Kn%YYS~e3=|`=~r0Ud_ zwp?2*`g6T$B31ocRoNWDz^l{kpU^Fc<&wx@$3GIk_q|1d`XnOioV*Y__v zrMR(UwO`ck1A6a{k}9P2r0!C2E0yzC+tr?;|+b5YDGD3K)m9ncp$D|Er^Rp6WhrX)$2+t-@TqbHa z0Ww4q9aq?5QQYj3He*aJb0vq;>Eb1@Z|uUO$h~CUa6GL)GQGCP7j2&SQsAh1@_O(8`zh6ZX1 z%LDe}ZSl#oQ6d4Ypp!D7R_IS0P^(}2Hnh(``?*Iuxrc=tfvNh-YjziMgD;6L3;B;|yE%74NosO7MAVQS7#NfUc>bwrs?f^xjGEr<9nDE%F~Z7tHz-pcou>(( zS8=`52J(7Vmz2Ki&z$~)&KaGn zRnNlNt09G4HQW8W9>HVO$c@=M>563Ix1tC}cj2m5)URy6+yc)RnrFmw<3ouuviZ3( zU#Dk$=iRg0*u0hE?wMe&rpToFOIwg5){N<;ly{K^9=${H&ih?@27KruF$<8BVO?Ec z^O9@e)ULSHp$%$ExeAi9A*qf8H5IPMdR3NGa4T#c#?K-=?%CT0WY!Otc3w=!_qc{A@mwZoOHJ3}dGf+*0J)^d1H9<4< zHa&f99^Aa&Wz4FgPbdYOTFp?+t}eP)sMOUJ)hv=G+N3*L;##yCcP0o$ht32A$nJs0 zpEDh&U>noi%2rz&~JDA#jHGCiB83Y#V!-Zqy*UUb%8||c88YLHn4z0E% z3cBAaO~?Pp{)*iAfnI_l>ZPn4p3tZ4=@Qv1Q`^I~&qZ7EU7CLLeJ6@?YvEOO*zqpT>Yq9qO;Ok{f`7h>LzVOg$M?gs}4Op(Z|-zIvO&9 zt6UAi)$cUW#{A>2A3<-u9@yE1M+*0==A;E!-SIcDWni&0?Asm-n+gY341bddydU;O z7aldM9Lja&POV9^%3gjRdg{34gz~Ka7H9aYH`C&V55B~6<9E>UKl>rN*ds4^T`*Q1 zGP-0BD(eS-B=yZ5-o+-?#Y5b*K27p77@qifXOQ}8IH@y6k$MyCkDq@He;+&NeM$D) zzgtQ5U8mk{7m~NH8z$iQ**t=dq*tEp;|rdjE->twyN3d14IuUT1*9Iko79?gigGv4 zN3B1)38|)FYoS{ED4Z*M_Z5Dw9iEX zT&b(=qZSL63vhXT%UbfA)9oW07kA!Yx2hilo_vc+Z@d6ihYLwE)Q^H6Y|ZiZ{5g6% z?B--IGZ&A0M&b@1;bmQRG3+y50EhkV%7E(Yf6*%6hvZvV#0j%F`$DMWAx8h5%XWh> zWh(&aolWQRWx-(tKz^sxj%!H$v!>9Z$0zernmX*HQ`FRAjqA~ZVx^w}ULzjB&G!9$ z4BU}jg%fpNEY24IU%$m-_h|W5t4$f+o%Cr5E=BnKlFEblz3UZVNPrhm_OZoR&GuqJh5$1_L|KC;4LL+lfIm81#8=xlgOU_u2f~Q|rQiS!ey=J5$;-urESCcIs_) ztUYh+d`YnDyXZOZ|6Y-iv};ZD z&D^~$fa#OgoIBm-$yI8WkyZTiNnfRuGpufLdonQj9*cHly#u<{^c0a}j|D-iU--h| zh1BD;c9(SXvAHelB#REXOb0>}7f;O4@A2_t1~DGB+7!tuI<3|v-BOCK)xLqAV(mNL z5e;sqfd@6Xp`uAw6}6)Mu4}2t??Dtjy{I6AI%gY~kH+!%*##+F@4PZE)2lP*e~qiT z-!=G|9)yF{*x5idAoR_m0r;+-cHNh3to8heCBM%a>%ep)-eJGTAFXhfH7GQ1_wMEP z^v3or`H$|VBP*r+QfBQp`x)K%$jlp38ab|{7CAx#*&EqnS4AHifAi(AlOI0JgrPsM z1+h`LGrWA!3viP=I~sonvwkSs4X*!MEiB}hddp)`4beVlsgUlzoztz;hLO&Ty zQ)=za8%#eS`y}uUOgDB*1=ADHWP#}tM0eRvXau|44KbN79GKlA$b7%}gd>8u&q9$T zxdTP;DgOGPw+t&Hz8fhVf$xs2@Ur1Z=x*;`>ot~T{!$g(yBj%w^q$6evWFj!4)FPW zoMZ+m!WBtlI1i`loayRJHXdAbCm_`x}rRxfCSbeGTD=7Y{@37Z}nJ>9_MS zq*r_i-og!1$96ZoL_|DtR}1xh$1H2*l||lB-wUt9`{OTeNox12NXn_t5v*BM@r?UE zeFK0reHVRu4*)4UdMhQD7zI|jMbva>yu6iT?9-n%whyiIo4)yoFWX;5>a4MRd43tR zw=CQ{^&y=Yk3AJ!2pc_WH++0Pduu;T@ZmzY?+h>z7i;zESJaPx>|<$T)G?w5d@ zzV+YdQ?js8?VWV($tl^96jP z5(fAkkEQ~?Sg#y_--XeT3-D*&ap-_=`%(h%t;R=2v~* z!;?4;R9Zdq0?fYj9gIn36!i|>fqP~q=P5V#Zi9gZ-3(%H50r#s_=CjOm^K1^yZ-@KiUZIS2cQ~+dq?NfPpollcYm_ith!*OYs&pKVTJx zq}Xiii#|)~U?I75Zmghp+@y+jJ{x|4j&HL363s?=T}7m$9b+ zmdZ_!w1{hqT+)EzJ~870RMgj5UwLZOoRGyr8@-twM(^qyA5dYER;io zuo2Lsz?g(~0ZmpI@}xq0AI@ztTq_*NmKngMFwQnt0V7Q07? zX6;a}kTj^zNfhH3SEiwo?{HlKq3s82#c}ZM=Iry(nCy=7k%G>gY8E9kAQ+Oi5R*!AP9n`BDbf zz`(8nHAklm$ZhM)nUzp*mlhugyIoX^Nu-7-=07eeik|uh9jE(!|M~<;EV>uvwRIZ$ z@An|~vQfP;>|TAJ*UR6=F52+>`!EUrf){REKaA~#LzjvCd)L{VRiPX7d1;BZ3!BNi z+OivZ>yaymFiTPS0(8)_s9=`#pKt6LUi-Dj-W)y`ZU)p-!Bo^A^|!>mq?W%k2z~as z{*jX)U!o6A0;7sEd_4djK$3+7J7%RI0q%EZM#r|bY1lx-u_UO3m}uKob>*8|tzhUNjT=g$DvHQO`*U3$aY0=iVWDMFW|0ufPj#KiIw z^nunNEjLgjoh6xU+=KMunt}ze6niS#^)111!$(hqc?-YspHpq#!kjcT@bJ?LL>?~l zb(u>;6B=@J==H{D;FIzZmA#B|%x|Qr5DdgqZ|P-?2~9Hv$XqIXrb!fc^byl&YSpWU z2(NaIIv=Do|6X8ydAhwMQ`}cQHX>7YXNX>tQs9^B=v}2Er`~}&D$mc)>?nXh;Y-Y- zdw$jNZpDDl&zsh}9Xe!?Q}*%!%vs z&ErsZgoAEM<2zF5{M=LC7Y@Gr&M-{siaoubyA|{JoaPgPlA6u2GqCtJ{!FM1eYTfO zDJQ56xET!@eqEta=J6Une#z$1`FHWucT<{{=;E}tbg{xDb&+YKbI!X?U6i-v%@cfL z+DC#KaO~Gxa%StB8TQ7GS@NUSL9jKaw1j&v>kfJB6#1@JH;W` zW$Sod=AqVjT~Fx?>Bb*Ic(jR;w`rDAX}m5s@lD9{!G5^c_TrKI=ATSPmR#I|0O#Yh zONg{URR8g$3e_gHZAT(+n|5Jb`5wyXrmg5s%Ua=V-r4$50?c>X;+Z_>TrkspozWhSAl*s&P7}K5%Kx6rX~nrzB<3N?lQmfIR85wSo*3jQie9xtCD=v>QtM2}CtMZt8CQpA?qV9sXz04(J zA(y94=dy&(7MzL?*}0wq%k|H5xkDp;l>i^*iC0I~f+2tmFjIS7(JSjR2YTlF4CVKY zNKNWRs?C|Ww3>CG&_ndLq^YLsR_$m3!yM%p532Rm2*fPF^ANdr$Gau zM$~lE{v$fs$6AbF9c<|bn9ARD7s|@fUy%A3H|7r$aP?IjB)l^u{_#8fuJSq_q^%y|zatuq6aJU3I3?d@D`VQndKmg6-rhl^UGJepgu>SvJZ z(-3XJ%2$yx_LBY`sp*^adcu<=<6;Z{1P9Z~ol5EnrU27UsmJSB{VA08_$i5$NHJFT zeDa=TJ3v?Xqh`?f>iVRfg*XbEgk=JhJQ(RtF zTh^4|@}kTe(35z9X&wy5tGYx2Do(Xr_p`y{(oYu2FosL-p- zDKqntWh$v@uNvee{RnxOkZV6YFQu7@AcFn&`uzsKRIks#vz4vaNiT<4FBXB*_~?HU znfAvK`ReldPpcEEht@Lb=6U?FPcsL;CNFy)?*am)`jq}n%!4_PexC3t z<$bQb=hx#fU{ z3N^`m`jm^nlhH-;hK!h0!y6OU^shm zc7Y>`CMY>hrDl$N=(Yqkfua_1m+XXiu7T>2xu56b20xIk?tS&M5yMSyUx7%A$Rcy( z!*x>YJf;XBUV78xKww4BH!K3ItR6ixaB$@$PqfZUH%t`_a1&P0LXD6&;64CF+9@-iE)=XqNI;_oW3#g^4Cn zF9h}ZC;~I$PcMJ=H7&Lt`#BSU+3I880cKAUrSV0#MIhy{IK9m5xsA(~v0Qo(;gjic z^kiQCH$-{K2E0aogS77hujP%dB-Upw_`akfVHkVqy-+ zm(*Fdv;70l6M2?|WN+V;r&H@Q)wcaGY=ByWza$`G`Yn|BL8HtRkaw#5ATK`IfUkTR z6S|Ynn!z;Wj%WDd{QlptB>5FI?)o?3O7A+AWeM)Or|DMUm^@v;9CUidMjxB>$@@5h zZaWpo`zY+Z#cTCR@9Gj=cvQC{S6Uc?pyhd&d31LQ`?%gKT3IiNW3t1saplj%mC){)#yIfS&p2dARG*RPusRVzbamR#D901Sdo_E(G(BFBxa7X& zESG3^C95c2S*x`cHit9r{^|gB>cti9LUP>w)x>w^5BeO}!Sst+f>Lgoch%p5d3|%k zxx9+s{DdU%K@3I~Xl{FfDLL1|y@z$5)`BR;9}ybOV(Vzu`Nt_br^lk5p`ip7zJ5O0 zB_CRWd348dRP^J8iqzN5a-s{5LRZ~Fj(*`se&=i5LLpX?6&gIE&oU_<8&|qx){+Ag z0~$EfLri&2@}>ACTf3;U2S1Nd|Dz~KGw*qf6!-pZ8*BnKs@|qp@|nj7Y7zEK+R`f( z%k3lSo(MzCBVe}rnM;Mo?#!hd6KKWIU9w}I^=1xE2CXJZos}tnG<@TrW@QwT8fIk< zr8kEcq&Y+kYjn1s`3f=h(UOk?D}@&zhP{WBDhilyzY1OQ;KaN?`K zE<#xKzk#{T=7Vu9U)6?ayC*Aw7uAMO$*cd{%jM|5qNy#en$Y3w{bxx{2(-;LD`ov> zL5|;N{XgX<5HWVZ(ahHWvoV#D{qH;!!RxBO{RZC5q4;Ggyo)=f?z$TRMuR)P5xg$B zw|XE_ckZjt8jVt=&Do1jm&;BxcP<4oKVIMkpg=UYBmJNy9^2lsU!r*fzpyCJm3)vW zR8gXchV`{q-gS=fF4zr;r8<4WTxkdwv3dLouh_J{>d4bCpHE0w&UyTR1QtVxxigj9m(fbTc!UD9!^hpE=bRD8K9^A!h&OfMsgCKjvVcJ6^a6 z2U@YG(O%YcBDI$h*m=g`#5H~J(4Z`}A@=H(rR*v49p}^Lyfh7(NDD_6dtR56Hoq{X zi;xL^9U&7uJb_HT>oPDt-U@{3_hbU0vV?)O290sI90>KxbK%%i8}7pH?s7Uv6>DgA z#vi8)m$LV8C7Bze&iuVyNRq)&^B1Ry~K zixjii9~p})8i3yq%w9#LTI~1uD5|ijEI>3DmYf?@C&z|se>%Yj?&=e73ZC(>I3X{6 zBJg1#=6%sFUQ%}F=oqzK@z!_7ee%*i?%USZI$D{v6Mj_F=k217Ru*gAUq_#LI?>Vc za=c`9v_(eFj-Jfa#ldv+v{~wCgPPXS*i-BN<e4wl6w_|cZdo`z7*o0s{gbB=%^(E(AiKKP|6oTVbw%Fm~hDv z0Tc28&m{65fs&pYYCL{sGpuTyckFl8L7p4wzTI0E;--v}-+t`v_EvV`5g#GxH zCw8_j3^Z*z5xQ2it&E3+QMS89bEFz7^=r)kuDbv|yCevSvdn13Z#-``$l10jWv!aI zB&DolKYc-jAtgEw&D^QbNDcC_Q+tDYAhR$$uh57{+lY*YW&f(FdQ5jpwo>LZ)h!$~ zO79HPL9H<_TQ;>Ons&-TJn}B80_%c#3;a*3Hakc6{=&LLef-J#bq^8R=fTngw2P1Z zC82G)Pr!h|mmWf!%;>Z6q+Q=V&Y1qJcAa;f2qGI6yn1zC9~)Em4jPr8Lbjs=u7TLm z1W)Z4HkO&IBVQ!7{ZYiu$Ra1Ej9jg@EYX3cO`&j$Cp@U9JP{^ZqUa(eDTiF!P=iJ` zK(28MO43Cy1>WSx{bi`Qm5WXJ1!Yjn({M(7 zh!GZh{9aO@W|DgLY*H(xn>iA#%MIFBR z0qZKRLrE*f7}V`ii{k(#wHOv6swg70H}btcg2{Nr2P zd)*YzP@w8Vw5eGcQb)`tbpoT9w)b^XN6g{%F=NN!eA)LcF24pXm@d8kdbIAbxQM>k zeHX6_#mU_8!*2d=c_oF?b*AaAwi*67d)Af&QVU?RasDJ@$r#*ljFW7y0c zSkS9?y@NoheIi92Q{+5LVmY11{5h|~=SJyaE%v$xUr6Ffj$^iNa@f^{M{%Y+%l+xwyU1%5c7xGw0NNo&@Hn+5jL1zcu687eCT2Td$cN+Oul~Mz z=$#CTSi9%g_<)mTuehJj>)d)f^F5C}LJvNAp|2R=n(HtE;_Ze6)y-^>*sDDkSOIIU zeMo)fOZzFh@JL_tuI0|knxOdO<4jm^A$jMqwja;yr8}y%cOH8Rvo1G}3!nH0SI&#P zPqA@_YsM(jh@x4c4X=H`jN zx&6mIU(uXhUJ|`=FH9qj*_Q55bgoT8qLm%DopeU9P~bP$FZf)VPOyVywisKCExxi; z!lB~lw!(H_H;QR8=95tIzTFK<&RI!!VpCdQll6Br$6U9-OVnL!bq`{yiq~Zdw-}G5 z8z`Xj`dOuzT>2+-Ppw(d=dSc;Ph;J_=+y+41SQez zFSEj@nSzsfL;o9J;{BxGGgJL~?H?%amj$Yz@)TY34OYr%%#LCe&?nQ*VcNOa*|T_Es0RV1M-C*kIc?o+ z9YJ|21szrM5265d5&9`pNmTtNz8q!&1F-o9%_@+SZS=HmP}d~EOQXpm+t{mrxXd^K z?~~MSt0oWG4W6z}h6Q>#-Qc&pNAU--<;32tpQ&kDEty3i9z}?!eD*ZDAEPFTKfmCf zMmzru9i)a%+SYG-GA{D5n@+nHULjeSB^ybS!LXRfOlmSgvtb~sUX3Zqf}W|S<&Z>w z;A`C|I)&LIv$I7w^SeT}YC_ z262xmXlJsIJ+#iwKbg{jiEei!+YkEfvj~qZ(Q-WgRd&{MhiSvdA33ZR#9_y#;SX_UT zs<`8B?F1idG!yu+rJ+k7&856{Xf4lXny%z0wrk(r-4@fC#d>$lFlvfv>&!~D*t!06 zrnq*Bc9Q{Ze9GjD!OJ-N-&$wkR(Gzb<|FplLg$CLV__@+FEMe zLbjhg`C^h|x-HhIkRJ*Ozo<|Z@>xYTN^q6zB$V<1)vqr^6@CqSPwU2j`Sn5vyO1j` ztDAiYsMubZ-Z<{(nldWS^ljt|u>R`@(>%**m z)1DK)({VGjSZ$-pd9_W=3T5^C+L*G% zl~7pb62>y~4|AJ=l^xg+(oY%H3XAtEA1ikEDmHE2p_3B7>dFxMHIS66#Lk)ctT@I@ zw^0lVIb7<4vE-^A-9olsBTf*`Vnktl-YDQ2QOPU9>x+Aq_5LaLvSd(n3)%h^_zD^0 zbufot#2%zBJrmseQo~b`olyPPw!itu+F|nx6|r&}um5EO|2D@_^4Fh5EY}Dvp8`wW zpH|s^p}K`^cg-+qcYlIHp#(wuxs;kxsaLb!%*$j*cMGhRVbv{U>m5ll_$gMMEww3?V%#ma=pUsz13;@zd*So*#qiL0>1vBwBJW$oJ{WCdJU?<0bpRUv-acX@~QK|H8+9M~C zWO`AAZ_j>92?;^HQj$O675*DltJ3^x_7qS54Nw6(2L#lvVTvKUIDt{w_xL@1;{dUw z%xO0u@)Hayt%bxoalCM}bD%K)k@&+YJE-to=wF8|a6t2~Q*6e4J|?Zi{UE;Uu9CFA z5Ug`89sv=~vK@eX8IO0jB3S(M;=P^Gx%^`YOE6M5vTK1Xydy~lFf!gt({JGO`Vfk% zA^uxK9JPMnO}ddY1Pot_)O1exwjd}G^M_KwCeg~O*;M*>kkXIuJ(KE2RfI!M8U#LKCRmm~MOzdL)BU z0;+eFMVggGUR6ZcEhxmD+5zzY2B(9E(+r>%+r(jZfH(zd7Q?R|n=~^8X}~36PIjc> zr{lzg$|7xD;hsb~VP!DN;Xd^Zv0(rGzqdvRTL4m)=k54$4&%cD)B{bxoj2zqAqDIhn-3 z9MuX96J6Pzg)DTHIKK(?X`U?Iq}Y3>7keCuvHqtt^&VUg^gXS4x5eUZL45QW)k?x7 zKFm%a_((^Np^}Mb7)jL-aV-UGtWO5;pFy8Md;T!n5biT1jbAPTUjj9T;|}6IwcAa6 z58}&91&9me26s{#uMH)Dyk%^FNw^}D_-M0$TxtM^clgbBBeO`dC!s9ha(o@mTqL zCLdQ`Pk0MZX~2p16eDSxQ`;RvC8q8AR}lV^z;~dtO11nAuD=Fc`+B#dGOn?rNk z;_y0s%dZjb?qTuapdbhI1^WJo-1m zS{YtCM@G0P>T;$^AYEM-iTUT%&|9UnIUN%hB?nViXLz9NY@`I0xLfT|5pPLR-t*FS zJBw7zyM{%qs#Z+VYI8A12p2x-YM6MAxFR>pF=lDJQlP2Ni5VeVjFcbwonDy~UjUW) zr5(|J>|&2lHiGuI@%i^2pYHgq-|29VB&g|yu{0SDC{-h2)>F2DdS8u4&zsrdo@>Ei z96>Ay1f~3oqvhO%CHtq)cfG%BfuvtBJ`&OoXT6=d)4dt^R8JV(7SqO^C?0tU&O~Cz z1)MhM(ykt+k-JDNzNGl@Rh7(TD`F}uRX7HnxU!8vaC0n`MTr9$RX*pi{^xfA1z`q2 zGK+#PmZIBT#5n#n4al_zNd85Hr#n(m@h@K4iX=?WkCG|)C4lt{kcj@(32fGpOae*Z z<)7*e(9V%o^e#RQCbMy9`B!0#&eeoV-G^j$?Zhc2r13hLB;IS9Ts`e7;9O~&DV17Z zDH;CM`%s!|S6_xn{u*~P{uXw@cW_<@&Jp-d(9{x2T3|3o)w27^(JFrNfVLhT5T z@Oi4OFC0Xo^Li}2bSeDRxe{>N1$JO&M_6&<^t-^R|{ltEb*NG%1dl?jx5kj0ZAY%Uxj%||NDEA$tyt`7W z$_CYS@p9bGHO%Ae|K9$4^hp0%8(uCIN45)((v)=zIj)A8@+WW(RhEA^cyTG)Kacj2 z^x~S&OU_-_87+!pdfxazuS z3Q`w3C67h8$ctgV3iE8}KVHkp5sI*KseyW^je>(hF;FIjbS1k$%SL9VQ2aJ9|BeG= zlMv_*vKpf~3h+^gt2qkP=WPvrtl2Eh`{Z$`V3@=BdA}b&7uKBL{0~CJZ`UQv|DXnw zWFk!sG{q+zTZ)u30V1gv=6{g0(fkieJZ;zf54dKvX zxs4op4{F|jLmzM&PoKi&-i-s8iKyKZRpd<{j}uB$MdjlK@w3 zal<#HcB2sy1{ud5%fjAM23l-&<}|rzVx`tBmJ!(n6Ei z!R<~}TVaq+q!C?F!TkiaslJhin}vP*zD{v;9fDC>S*+a2?5$L&3XHlK<&~ls3GH;z`Nh9{L10J5%Nkq=vQx>=BCk1Ml7)p<7Vk4k6 z_|aEKY+AN1B*_;Jl;d<-Jq@C2`+nFG)c<~golq1tE8F$3bKuFRtb})vMtZg0&o6;u zrPhZ>^bhdp|3@$1_p#%Ld>_e$`1iM1phhGQPa$Fi;AT$iSr#gUGDVC?c4OUQL{P{q#{`Yc!hCELXwdBIo> zNB^V^u{om&FL2$ZP_Tor{xKY@PeJw%E3siUv+;eUXZ$zzX$W4l$)yn!zoTmoe{tHcEgysu#n(9a3_YH1N9@qd^^ml#s(lC2P`vkI@`xY}Dq| zX_;&e$h&h|`(o|C0U-hcSf9WIqQX+3+NHK(0>isMOeiy4e&&P<*RTsG#zdnB9Y&+K z2tzK6o+fkM%Dn1XB@D9YnKfegrA)BT0|AbzrG2$G&joFcGRAwXXup({2c9XeR71E3 zUr`%$Yk#`R!dgoEf6__}bq9oc{V0w^msB1viQy(t zY`?-(b*&io-|4OEixi=nz7`>Rt;)Uj%2wf1WvUym!Rmwf{S7?(15dwOi0GTLNymJ} zS5}0g{js>+BrK2pPC;^}<|q>V?o|v%g4(Ov(5%Ge$(Qk!l|=h}HkH*=+LS4)0_1auode4VwWB!F_-X1xj(4kq zDWAQ}*oTlr`u|b28Gk0=4DyP`C{n8a7{)06w-97GcOs&45sWficoc=}7IIwOMly*T zwNYqK0yYC7MR%n%*O6F*u1^JpP1-GF>z%;MR5sYKx~z=nf2+p)!^hV2WYK+Qu=b|P zWKH(&+!A<;=sk?(Bf#eu>#~T?{YN9{@;;m2%2T|+r8&D0%>130A{CI~gcM+c*#E|O=~!CTcbF}iata5$nZ zH`N>^#(+72Hxq(#9TB@TK zIyALZ* zKJ)b7AeSHT4+Oakl+3!oF~Ye8Eg5DD2lz~m#Vt6k{L+SK6yI31^!g#l_KF$2St+DQ z-#CD&HQ6l(k5pgXB8P_W0oSfR0CYN{+TvHRsRmN-;kRgdHza$4y~ise%%1%ZLu790 zmHz?N!W~hw`*oBefBmw%Ekx_M!P;vvfp<|Y%jI{a&3=Tap_?dZfGI$A2cSIsKkoV{ zA3JRLQ;hmhORRVZjek zhnk_IxCY9%3y;ztbPG9tepz|wX51jRoG(X*xMg7Du`HD-%M2+$aS+6i=MZclrN*HFl4{)37(#iq8!f>63q<#2GL&{ zqHG&k8a5XjHE=wmIaumZO%!OCCdPPDF--_ggjtpXkHEG~@ZY+#G_GQeRg`M5L?@`a zriCSZE69vn-JH3Fq7>rSme5-4Uf`IkYkuDCW#G_N#NR&_EAK9ze^c;QA1cli(^h2-DJt5%Fv7dM;99TyvS#^qAuMn`f|xYIA$i&%YP!A^3a0c z+z27zH&FQ3l3w$ft&%MX@**oLLzu^a`FhTew>!J=a35(Nf z|MdX+dUAV;8ZK;poH$0RzP*{PlJ5X8E~yC47Zm(@T9kAFTIE_+LKv-rINcvd(X`Gj zD5No~Dbh23gZuvt+}r&F{c=QYsqJC1;n67;U6okH9!-&$kHkI7dT>)9n7~NS_!+;x z>tm}nLIroR97i6QAxv{59O3b*!LURL@^i|9bqhOz?h8d4JPJ*93)!w7$Om%5=uh1! zts_RbUhbmAP+u8_XgL9V^lyOn?tEe5k{u94l+1w0FK>iKQV2|U=R&UTL<`U>D4OjYx{T3x5QT@#1T=^@WnL?V3;X_cI{_ ze^@b`Jz#7fD0kmF0yfAQdXI(LfHc2QIlEu?Y4@TYM%zxs%fp$#iTSvc{Fe=3cwb6> z@+f?nzXog8vfc5YNK0r?QPyy5z472^rX+h2`rFD$6hTReBIaq~c)mq|jzYJWmw+Y> zd(o1K;*S?;s%zy$Sq~uzyZ#^c&I7=T>iYlZzOqX(APQE*6{4c-uCEs&_8y77MPq_1 zh>A+2*kWR0)I?2e*jFR=5_N5npjg+~6OAT_v0+065!-?a%>VPf^V-5fG*SP*Bs$LQ z<<8u8`aS2&Jp2CfP|-??x_k#|Ya9DGiHgC42v&bPP$bPaF>(n?tyQG+vDo=LiY+vt z?LmS;X-&PpfzI-vv*6ND`naI4UjMRb1$?Dt=@V@6unac?!odrD<{V8v$qn%TE7E!I zdQDg^B0fkC32)g-((L{z6?s(I2nvB~)Bz1K?Qb;Wiva1QdM)VK^S)(ZU@4MhB z3!Zs`-u_NU!J8thhvtEFy|o+Agf4?E+StpL4Pu)nSB;ry26;$FSL0%pjMP7+p!FxL z_7c@UDtWrht{BQTzK?yFhPR>G$ZATq!40xpHPKQ~PY({2Y2m4nCMfl901f=VCO{uN z!WwIQnr~xSo&*^Yr`}emvcYZIXz@ZfKh!7t z)xSu0ooIP~NHBPvFIC_(`n&fMm3_4vTuuIkzi(^GhTI$hZF@2a`3QNnk!VM098Vhm zVKY7lMu4Xxca#1L08ty{oAEtq@l=fQ1*>Ap2m4%fBG*s(_k4UD40GwHWU;u5*74sVD0yyP zCvXFxS3=p@M(ho2(@~VZO9z(NAGjC2rr1Rm%?MQvXJp%NJ)T)%bjNG3trI%xB_Qnl z9;}P4?>R!vi1^y5=>M68o*lR!6m|{V6h8Y0sNZUlJ#&TBYO^qM2Cxifv8M~}nGSAl zmNgjMgI*7ACi4`l^D($#bHJ*91J%v7gXbxBVA|ZMrR}E}M|1dnBHw>mRJ$ok^$!Mp z$oBy6dua-L%}2M^r#haw6a+RZ-QRK{zvP&UHICS>bm5;~kWbT2iwAuZ8q%EU`FF@3 zl~Mf64JUCCHTr)lt+>~M|H&1{P{{jJSltt}@Y;)eCs$9cAt>K%p}v{l5IKT_W> zOaJcvraqDo7B%WkqedYku9CY7IeOm<8;An7(3bxhh^H$G5NCTbfG++m3it*dH5^e4 z>{FpDe5vCZ#l3>(WQ`A42Oj>Y1wlE)Gk&><+?9#egyC)L$;e;jaQ_l`smRWN?t)KF zMK-L>Gr=o9{gl+wa(?Oc*ig2I?8))G3Bpc6&vSu1!lE3Rx>tJ2-wGS(zMUpxP{9e? zL&hK%wLBIfK@uy}s~tn|uC&XWl3gF4jsf|`ZIC6e3Lpah=N4R&d6B#DI>TzO`{c{7 zNy=-`l9XRGZNzq8u9U|Z3kAFv^^fYGouvH#(2C)e#fNe^ZWmq?3Fad3gFr^sT$!#h zX~KEpfbOFe20K|gIWL!!t$04>QQZuMI*<8~2U4SyLHw44dV!o7dXYM|@bg$=duvt- zZg7)|(-fofuj7y!S$UTHR%&N68G?l>%J?!LPNQzIg&rNzm*eQ*Fk*yBPZ${GFf=MK06|MF#N zq|CEk_FSeJKP!RuxD40x(U4M>c!u?1ATw#q#RLOc5gi3{)qmYC2)(&HZr%82@ScA+ z-n5KBpt3p;7ksoj;`~cTTS(cyGJ`f-%Ve?{ z`gqaim&%mNOlHi!5|>4l5Yepe78UnfT^ZyrsOiizz`^T`8O(2Gqx5JY3OK^t(GSk0;Jq0=lUiHT6XXnn3lHJ3P_e(4Xk0S_!$GwV>%(@3h7WURSg_468 z6+P2^fnIO2OhdcNXcH#d>8pj3oyEEpQ4XKA)gVs0+eBzNU0RL&(iFjz3jY zp3ZyJbTOP9D!x3R;ki&8zKg!zrFyzMx4%-vzgy7u08mPu=^=UMrW5YvPfz)MD^8)0ypHiX?T1do&b_t`vu!U) zlSxQBpUTv0!GF|jYkpI~-RT_)CBQA-PCxCVl?RccfBn*aRvSPKP9O$b`;!d+QuC3x zv|rfZGyMYEpAbG(3GUnt zw7u{l1pB*(qo_VXrbFN-9$gc`T(qU%&z8&;JL5uaaQxP@?*ouz4}ooEX`VhR_3)|s zVNn~FRmdFjY{;(<%B^h+cml z%dYVM(j%XY4cv$QNfw#HuLqEnfnPG*$3Jx_7NY{@!3*Mm7l~A07-D)_20jmN7S;Ba z9R4FFiPtPp=(q0E2e`_jY1_AIvfyn#xtBb$zGQj>orf3xDf>)+!kXaaNy;O7E|lxt zB*`muJRd1v>0&f)8Q+iZ;x;v>>Yp_SFR$S}K16EaI{YrSr<^b6Zc$bX-@v0YJQnb4 zgl}Utm*``b>|(FfXN|&o{j9L-coh0gK98bTZJ1{9wmyBgEbr#?8g&J8pBwpd3RjWu zyAQE96}k(t_X`O0Tv_nSPww>}Hrrnj=3x8arr?B5LG)s(;IS6=4=+l--}sP%hvgz6 zj;C?YO_rIziEiI7f0=E9uvU=}zxEUF4uP|FmB}>FhrY^1-r8?vOS1DY@!3Agkz?ye zPshk2yW}jIA0X9r@+qhwzQl|ET72IOes?XH&gL7poAxuSY3n%eTKJAn?9;(K2IMDH zG4r||%YYlobJt(fw-ViTZ_>7)b7u@!r>G!?)ei?yr7)>+7eh34kK2*A7 zy!2P!fK5pFqF^KB5`#`WwUvXeLPwWDS6j7JF7qzUbGN3qw!@%n1j%{8s$hDlpevMB z3cAjQCV#X8L%l3c-QDB3Cg|ES{lP>SaP6AnJeh?Q=ZS9#iYt+sD6T|&C0g`USxa#x z;`go zv3y?x_wFy0XLEl-mQ6yhU{V1`2e%60n+VGH%lI6Ayx%Zv$0HbrJ;?NAf}-(Npq z`Z1__4*)Ir-D$N3Ms7W_8;KCqg?0hr& zG>stD$MMBD@7M0RG%mVHZ+o}M^@29n|mXo<&Wpd)oVcwZV6*>x^hwb zO?7TtPiJM`-#FaAL*WU#*Ec}?5`eg1$H1M5aZ(C7mqcuE@wFWiH!tsmYJEd==P&$I zWTHRRi2T-&Vz!1*p&z(k&9*SO*c)4(OrDX4U_}hs;BPJ1PHT-~2laAaC1<~SAr3-{ zBora+!rT638JbAsTN~39K6>2oFS=MN0@S~bgN+(Ges?%j@)v7u@H;cI1^DLy-butSNdDtft z9P${SfA`h4CzdSrk4XYY)|7Ga6=}==I56xJxIricH>J5RyNKR+_k@Me^8WK^y?`3b z-Vc_X%N{Iv2RH}sNdvsC()&KQ`!R`(e+c;Z(oyg%KE_~{xOl2}5`2P_GnjJ*!fPR1 z9n3ymk&D&g;@OA#+@bJ?rw=A4gMmw1jl`$^v+;eUh5CGojkJok6f6D$ExIbAOJCeV zG-M}lN0J5I+om`oZ3v>%Ry!0)v9;ux)jf@}TUmRBsEDGk7QkkR()kK@mVO5Ae|`PK z1Gh0&mRoDAc99Da=cNlU3l<5r3#E7#`Fz=VQa>LF)$d}#1)oe6YDf4l^AKf)Zd7e` zAR?G2bqC4q>40ExqtPcndI@pvOU(N$Lt9gZCt06zE z`vk~f6{ybo452+2up8YGI-&zE%*S_XQFY2d-0oc(9`C@Vgie(aYb#IIOl{>$mDH+g zzX0nESp^?W63Il{v}mkwi;7^id_P985Uq+k;Up+5{Lc03qRKVnEc7K2=}He{x&K3T z-AC|l-#u{6Bz`R`e%juYR3CI`JUtt{TL2QTF9MQu!uqFUR_Wt`FqKM=NooZTkCJa+ ze^@#iQq|S(3^Er#wtBI3dLU!p%`%H`Yd#FrO~cxuegaIzzAY8Y#KLF&WNl5PwK_qE zvdF)oW!>P2@^q(?uOUvPIdkWC-u=J!pS+za`yI;?m2@2bs-k|n#d;?Mo8D<)?=O8- zQo6C87QpoO*dG8uvuN7X45lH}mS620}89t5vl4kz}@8DV`qEzl(t2bH8o>|+= zzsY(4JSoWRwU=JIyM!zU{cAma@!cx-NMIq;QQP@&2DX+MQ?s&Nz58bbDfzt?3<}&T z@KIz2KT070_;BG{cYyqFX~l1VMynUIytczI!Rgw#;KY{CU$m4ke&eaq)5hC>-XGtJ&@x}M%v_z@B*=yR-o*Y;VTsrUjt+91Dk zAHx2J&XkH_gEWS}3<)z8spXz(f)^&q15R@homYSAMAiIr0u4JEcJ@)>{;L` z_~5KL2Qq`tUIHZ_iNqHDg3AXO`jBV%n(g$P6aaqU0skR+O$xwX0V1fZg8?iqGp}CM zP$!An9e%KSneT$jd#_CoA`>q4zw?#v&yt@R45%9s_rW8tP4|oUpN~+r?rHJq}Leg&5tkEg?b7* z)nvdV&4C*|dX{@cmWN-JUtfN8|Dhum%#*6tMd;_n6aK8Cxh=Q?D(K54_)xH0QT^Ep zBAXSj1w{2?b#Ci%46$DG_k;O}CkUh|&`>~|op)E)0))7fMDKo(pm>g8&Ndt97ABg_gI|#}8^;o+>@>ThfObttV+-z#O65cSLJ*MTT=FW8XQ+i%x2} zr)pz8bcBYf>9!wMif)uH{8QbAT1eGu8TO4hY7N{za6x2?9flzT&Q_m?dFl8dR2pyr zTvTvN>3p`sefWTGoxGhU7ryfRs;Ig5>cHitUBFT|&G>~8-X=O(YYr}v(7$9`zGxMk ze1kW6`Ged<9!LOK?dmw5ZxzjhP8{XCtoTLzDMj65Sj z)ri0$wHR8_A5joBT#m+fL#-g8KVfz748n}&`}qw%y})5~5?<742|z3{GOmXJ^k5q0 zzVTn=%LE{0sQ3@php;-1(Sln~f3gNZYO*AN;0l=IWHCxt01|zN0Fs$^3~!7x@6Q3C zxn84{Uk`_n7T>pg07-U)01}kS0P;*FkO>k3P#CQU0VG27Py%cv0J%FJBzf{_{mPPF zHZupxEy4>B;lG2$cRa}ao21qLDx*XYEQ65>Zh4vc;t=R!;M17b4~zd501I9e8FB$y zf8Ag0y@cYk|7GGlrw_&3-W*i}@G3)X%M+p!kF@ zPK6MH%L@Ldu1lgt)9Ae_r0~*CK)##g;0q;0O1F379FldYfuqWt;}MDKt8z{ovkDQ( zsLMd4kM0bbhu{4^{~N}V0wKLGAzHddq}P06sIEAtibyfEWUt-1HKyQtiWpn}(bAf$ z)*}(QP^3aatpB0t@V78Z{Jr3{^Cb*|*SyiCYTaXsR0sgvER9#j1-Q%{2`b(L!g8C#NZu@n3Xj{SLiEgh8n@QwUp7xJ~wYE^a)O%OYos+(Wvqq zL!F^!2+@a(0vE`vCD7+J0}`&J8IX7klnc=(a_vGhh-yQ@S4N-H*AOCWpJ2dtBbm>( z9x_fBiW^OMQ0Su`;+K%qz2GTtKKnmmweB%R>V>|iJX5y9bH2$&sCRX8D8Ky!$G#;B z=`QoNV;4TY6MRI(MStKt)o_7NR4er9Pgt!cH0=4NSBmr!cH(>TowD>6_0c%bTOCVr zA6<9mzW+n$^LndGc^nLM=7(??A*5K;ZmX7h*0LjB(D($K3t^YbsdqF|FqbQ496VJgiS{&GW=KZ!Q+B z_q2R4is5n7sZ&~+NmvGmO*2W5unr->@K|6L)0hi-BMIZT(W$pq ztHx#VcOYXMoB?DW!7Q{@=p}e4bXhz!R6hps$TT$g+oCKzstc3-JIW#a_uB(t2%7RF z&x?{D0`#_uRF<0B2GTgbl?@OoW=guR%O#ktWef%a!TdBoDl`b~w-G{z zTu;L8c>%T0RBw9wlpPx^dg{jX^&|8s(=3x5FbLT4JrLym<$>F2(DVg=@5<2D>;85a zmV0Pu2OWKn3l>jYM_+xIjRyz+$gv^;6nF4}G+VbB%3Te=M&JWeD@yR|YXm%toJ^wAR zD4b-bCs-#;2gAS~CAFRa5F%I!!QxT0jywzG7GvI7}q_>lRT`;aw!gsB-quyhqWm}uuS2wh)upfni_+ahrF85gP+ahombFi~Gu?c$_#y)hT3>p$q5xg`9Kxjla6fN6g`Y!c1rXuq5Ja;7m?E)K z`Wynk|ISiwLUyc;_2bjUZGhUZ1NmDo$wTX@LE?bSdg{T5D59sAqPDu<;jJQUevH_) z9@Bw-hlt4x!~}r|E-XQmpW`zKn(E@_zA#Ss?vYTT?>vS74*B+A<`Wq=7=wH1EueP; zYDZJrF0X)GSUlm1>0({wu?O#IT`|Go17^J()`e$3X7Z_!XT?LM4~a-VD~ST5OeMgk zXD>ijdI}8rpcMHFCisLc!wEAOohRv>(DR!bcowvpRT$l_`1lK51=Aec%swynelC z5e+R$!(b5&ElR@@qi-#}rdd*-~Y|e3i;yBe{c_9hAuddy&erPz=8@D}|N>?fR+zCr?vEcq1@0OA?1haAiL%v$B&Aq&P3 zc1t@MR%d(W{S93>83fwUS0mR!*~!q1JXzAoKwTG329Q)@=_JIv_^1K;(q2g$cgfPH zGwCJ14J3KKls5L9J=lNt$8)h*F63-sKjiF?0X&rnk0F&oiJ~%3JK~SItOX{g2>V)r6Kb1;`Y^niMcU5*f(X9(<%VbQ8`#4pW{(!rovIz<)xh-RxS%csUJu?f?_h zLCIh^pHce?qqPRZ*x2pTzJ+T@7x*f z{YPJH2uAM8xg!b+{YP{P!`%*dFW!ANPKf2ozcWx1OUS=2Od2ovLaXBhG{Pd$Y;44K zlq9fY1nIzP^8R# z4QUse8i%r)s0N%TDOxfsm`ZI4mSW4P-(>QiT>C%_5|aq5F*QOf-wT3e3MD59d?qRH z5Fo+AdPH(WxP#F(wjXCYorgP=YUx>Jd#nr327iWlwE+*KV)}rE%z?5^5Jttk@n7gOCs_0;>>(Fqr}qQ4_1|<-cL=%2IFcyB zK8%nN-POjBgiFFpOm1`VxaiX@&RAA=)A-4h!~1q&49Vjce(vw{MqJP-%QJ?=m8FP_ zpPml~j$!OYpYb7zWvupfevb*R{I76p2k+g)VrTf@I4OCTOUW;bw|!GD9b8885W;ck zU`#zSzpi zSa}tt*lsD<;p4r8#sv-i39FX~SnY+G*HtWh6qt{U^T`5|gY~p->Hpsi-t?$@+Ac0QjzWj2)>fId<^;2g}9Wg>RMbLj#LZ9 zWq&&P7sREHi|?gf*k#^w_|HfFe@(nQxDBoD<{e~>4`C}cl97ieGS0?g4i<&2Cu8CxZJ#zM_{b!>54M)xE9=C){M!uN z=0Tpe^`x_XW4htDKwnX3XW+W0U8n?QErm*ufH9(?ez11Vbu2s#Vbw|3FFr$#s8iML zss5eJ#i()fxBTXm$7xjWlkxvFbmnPvA3WNH*2KE0(g$ zJ-t#F=L&{RuP`yjvvEC5aYyxY5J(eI&`H;o15b2L(pH!= z1;|UOQ!?AS$j<5kG1hq3Y&^T=#k&%hVMDzf8irVxNyGmiQ86kgeI3AmIJ^96|8uxR zw87$nyb9Q4c^RXfudlHN(vtmdOfsg+uLGP5-P)d0k;;Atb_mgD7-;oLQUI%sOP`6U z$6nUDle$l*XRM<)bb^|3HF)Q7sVR>;TanSy=MJ^6>tZA}e~hG!pDq*+X;q$ZWKI9e z3zHE%HkHqVmK{1_Qm_VPM~FbLBn9_cfIMtvPyc_GS_M*1kzG-%$hsz%F!&5@9Grz? zj5g&@L3E95aQ-hNJM?+{Ysg+|+z{C$F^EEzM0Pk5xD~RYwxyBX>yuZ4$Trw7rJo3y z?L8jvNqNMszz_-(a(p!BWYn$>z}SjU5w| zB4|frbOcx)p-~W)WG@8#t~nmw7f|2+=Ndu}xKwH60spDI-ptXpayyK%`%)aDcW23| zzDQe@DDItLku0j{WR0yJqdu`M^m}X5GL2Q0GHA|{iVp6VCpLH(rSCtq6HI>--^|~X zr{as@S6Fr1)?lgracZ{GxC3@B-4Yhdlz-~p62^!C*TqOZT{ z&QKY5Z!o%Tfha*7lswf`FCAi1gHle)4v5?^#030HLGdXvC>KvtR2q1|$4lq>*1Ar# zx>~C-jjm&YLy=E2kmwdip$30W3rzt!Jy;0GV+CL$Ej(TCjw}So;U7#qdFB_2K=}0+ zO6LprpF&~5pQX3|_R!j4r@<35{ChGpp$I!NuEd$pbB(YAZP-b+_O_7WO3z}1)p*v! z92(GHn?obw=ovz7b+0d0*_vU(9GV$GrQ}%$YNekN@#KS+HS;B(?{SBRa9Hb#~Y;C_U==vW1RW(>kFz6|q)2kn^G^mCy{oCKsoQyF=J~X0f zf5|vMp?;d$J8vmC8YVja;tXc-Ea3e41>w^FMd>gnfDevw6-3hm(nyevJJuF4+pg& zA2PRRh3cW0;lV6u$~GaNkp*osKxxTCN5gztfnSiCGS%xvU*Ru+v3L&w5GeCSPzhcg zLKb;1GiSt1EMc2iWUFm<+}(PO88QBFTf<`1!$tmnZP^_<^2o!j8#mR`@mz$z5$myv z{&j$F*J$^+10%V}3(;5O7XNGAm36n)|FYY$-4E=3UiVkJ&+WdjM~@z>^|+_U>plO_ z^Q{$ryTa|?n%Zl{-mCN;v*IQzj_tEWpVRwX)aTljj$NsJ<*9uK_gkso_U1S$qtJ}nF>V~`Txjo#T?gwsvH^Lp@ z4sxU25pJv-=f=CE+|lk#cb2=rUFh1}E$&u#o4egMuq}gGwk_u_oM&;K&3O*zB+hd= z&*Qw1^CHfRIa@g|=e&aRO3te|ujafanB@-T9K$(|b3Es%oTqVK&v^sq?>TSeyovK> z&RaNd<-CpacFw7scX8g$IgRrk&U@)Q(`lA_QS)!k)UKtE>o}R2X=clsIjeW)bN-tv zaQD&2{hSYQKFFAYdpmG%2kz~xrX9Gq1NU~|-VWT`fqOe}ZwKz}z`Y%~w*&Wf;NA}0 z+ktyKaBm0h?aaO%xVHoMcHrI)+}nYBJF{*F?(M+69k{mx_jcgk4&2*;dpmG%2kz~_ zy&br>1NU~|-VWT`fqT1c-f5P*Q?o}f)%N1=zMTK&tieG$IA{k4?cku@n5Ai!%UaEu z++$34b}-eQ!wH1IO}o34^LL#8=4!!FJ2+|wNA2LK-L-Q*#GJOZb-~z{K`Z!b1z)Wu zNR*)ftsAs%6F4Vw9>sYy=UF^=Hs?8obw9KD><*?yqfbG z&SgO-0|jL{4-Hzuc`GQsLopX{N|I}R9jvc|^>whmj?(%%SYHS0>tKBy ztgnOhb+En;*4M%MI#^!^>+4{B9jvc|^>whm4%XMf`Z`!&2kYx#eI2Z?gY|W=z7E#c z!TLH_Uq{XQI#^!^>+4{B9jvc|^>whm4%XMf`Z`!&2kYx#eI2Z?gY|W=z7E#c!TLH_ zUkB^!Kqsyk{MlCG+>&!^&TTli<=mcg7tY-{&*D6r^Bm4eoab_$$9Vzgg`5|0Ud-9b zc{%45oL6#Q#d$U7HNl_VYMiTcuEDt`=b@ZqIFH~Q%lTu@BRR)$j^{jz^JvafIZxyK zE$11W*K^*$`FqYAId9^;nX`@a7S3BaZ{xh3b1LUuoOg3hhkURyF7gkC9vYpr_+~Saj4^ufSSf~{+RPf&a%!&{;}eJuKU|~=JV?R6_%7S|4b&> zO3UKmFUo&Q@J?q=THe3@Gc2p_z^P*Y0h=!ExBo)>OB7XEH(KkTT7dr{7Mt){u`9u6 zmv-SdcAdBD`qje9mauM@1-puUwG1m1*e=gn{9myO`z;R&?q9TFy&U@QvNgZBX8Z56 zPQM;q{oiNx3T|E6@yM<(WP|^Y+Rtm&*w4${HGEkX|NoG+zFG}jyWE#_0n;zEr}#f$ z-AAmy_xg^CE@X!wZ*b|q;5q!YgX}(gz}oFk_J}=hPugGXX?w>0X47qk{li|gmu;rK zYOmXy_LjY8^Xvor&_1>fTVS8qXSUEqT+G$E73s;`BjujI`TPF~0-?{p?E4S@%KQIC zPW4gSqPmnwsXn~B-R-8id)&S5 zK6k%+z&+@QB)LDihv|O<#_Y~a53m+H&#n<2=>2a4Wgh+yM7&x1me8oZHxK z;kF|#yu16p`;i;v#<(Mi1pn0i(w#~?_&nFj`fhT!Gwb`9;S=t!?m738d)>X`=D7~H zFcOJ$i}Z^0jjR!Ah^!ZBjHDuk$R?4kB0EI(jO-UVATl~~cw~I!*vJWylOv}`&W>CV zxioSmGugsc#7^sL{cIIm)mF3BiLbAT)wGrku(fSnThG?F!9Zg}8$x`$$(n5=u$Q!y zrP=3aEoXV+-9_x?@7TudP&TnGZ7X8m+Ypc2j`;Tu_Fdc2hTHdSC)?R}v0ZI9V&Z$) zp0*db+sD3d``UgM0T!!sUBj)(wZB`7>j1Yl*9Nx^*MV*j*KfOZxvuBd=Q`MJz;#16 zglnT~;@a#s;+k+tt|^!1nsHgKIhW^Ja7C^|-FLWd?1phA63=xrw>j4>+?HIoa$9rV z#%*hHaIwAH!F|{5NDc9Nt~&vjp?wGh|m`a}04 zuEh7bwzvbij&!5A67A=Dusek7p>7P$24BFX|mNZpxjRUveYT(c$ zQ=xq>(W!kZk#0<7cs8TISx(w!3Yz`#7`x$-EOXG@^=UGn-_K zedklgore^ok74gn-p%@O*rvni=MH4sN|ZmK{IspiVVgZj`9&mNU$f0Gqt6-0zJ6v~ z9Yfo7kb)!&ZGDkhbQbb(RkQ7X&RClw8CNs=-hDj(0y1)Svt3%5^NvW%HO%&Si|0>6 zZZgMxm|OG`I0PQ~0duMwfh=8%kL~@K`pc231I!L$9&Q!n>)K|cH=sP(8aV9W$0+~O z*5R;2zem|@Acu`n`FreF2bmqlxRDF(+Z;AF%Xc^=rPnn(YIpiyA9=l=*|Enl?k|zt z>zkdR9KKVK;e*XiJegZlydA`QL1I-sO~!M-yyhb|Gu1+Y_CTF#FvE=6MS!1c{TGNBkc21pQsDvF<@* zq|L5Z+ux%*GG;fju4oHdgmtvtLO;?cIkP{!$-4GMv*gY0*_>x~LB|x#?mwIUr=V?$ zW)JQ_y`rl_%^n6fZZ;a|J7$lfWn%?&(Z*&^^6%K0XeDUj>Bo7#8U3`0*|VQeKhrkl zuo=%Yp9!`ZhrO_qnLSTzfH7YLMv-yo$1TiW2IkPxmK^rVF0}o*ZN*`)|CMqNwB6Qb zZ@s|tlhAwHn9UwbeHIP4t=W55nRP!2UAUduC%`(gD_U`Tv(J9Q8t*|r?qDv;8X`}l zDZgv34jw>b?a1Nk8QYzR_8e}m+e5(f4D{&t%=H4-_GdKePUd(1u-s-Gv( zvb&gD72b<{ioV^|P^-*mV>It><^}+ZSQ;I?ySahPljrx~aO+YZIS0MGr@8f?qC6Z8 zy_dNSq20)z(A9gJYkZCQyoJ`@$6Pb;jQtq>{e5$3U>*AyO}?+W0=S3H_v3Kid4~Ge z?FSrgvpbpR9NVA6ZF7Z(=MU|N=C<9N`nfiO!wm;^t~)l@0gyYmsGp7X)naZ>))kw8 z9d@9(@89fcW2B8VcR&xbm5#7c9Bw@P8($eq?I3f~IeE+ZCD5&e(lNm^Yj^l8ThPv zmijmBmmKbcajbEcoy6fj{yycIb~1-s0Dnct+bJCGGw>37*M7wjG594m)_%%9wwSC`C=ZLI?tckvDzu}0i($CNHxAt3$tZ^1|_zC%w*e?y} zfLNWK$r1VX%G3|Hvp6CffQ#4&tn#xh(sV!N?_-~1aY^5XCFzY#*m9|>s*kAC>Q|tn;o=)5qIvL1*;8KhHay;b*b_Uo}CrzS!m0iXW zIi(0pE@8JY*&@IGJ9BuNeZ%FXT39V3FIz zcUkr(zvnl6e#0~GvP-$qB6lB4{o!^KN92C=TK&)1yWDJ%M-O7Xhg%y*i(eC7k zyu$q5`!rfKPlQdx9f6s3&wa3=i~^7HvdN^mr5L{%4Ekn|Y=U zzw}=$y75ckVu3xy5#35O^CT9{(-z$UTCF?I{>l;EWdQ4a6d(387Tpb50lz=X5#76m zXLiK1{WsLVN=r-B|fA@5Y9*oS4U2o5EL=Q&?#~;TFJ_GhfR@B{Y&vQhN zy@O{?z&HL6i~cOjGbww4Bl=5dBk~be)r-8_0UXe|FL6Xq19!bQ!H@p3MK4C5_UUD> za72Hf=a~_B*Jtu^u?y&b5`OkqEqbTqKu>#(BRZ95nA__d(P^9W{MGgbNA!Ny6`h1n z{!NQMbR2U?+ANOfW51_<5T5$CEc)bMC_im)b3~uMjPgnL4oCEF>oU)@&E|+shyLq^ z*c^`Nizfn;zu3DR(Kp~&)|Lq68mWbRo~zO|_3WV$oITX9BTIY-@Nk zdZdfGD8oQ|(G!Sp#4vMjqWnh}cX5mD46dV35cjCF*zRfCPIL9H-eP;tqy9SA&2{55 zmdMFy+;vBn$9~8hB5kgR>tV42zDNDKuBYp1v60A)=+b=qKX(y1o`W5m^!cE`FkZ7W*~!Qjfjy7_DNlbC7khbMPIlYOxE@FYzdTh}A51 ziS+&^ZgqSTu}hgVa8w~obrFCKi!4Mb{yVw#-TD@5zu%V!yTKNFl=(*|x($%Cu_sRU zOW%9Gp>H^gGkoaxJr$luuXZ$l4zyC!6G?8Tq>a_cdq za?a%}*0CRBo#XP@yRn7PE#-nMfCgX^InovJ*~H@?`SMUV)Z*Pn(RL5_9lSX4o_G23 z#%^Pa_tttxx?%Wr;ww$?O%R9IoEWTOFm%r=2Yw>N)_vIb&FvWKSZahES4Y&Ai zz#0GL_t@{n_vr4+JGq@Kz9;jK-|u$D9*yq@-YM^b{)-=wX8w1$UEQu0ANiIq@8)*1 z_`#PjpY!o2?r!lh8DHMR?SX24oM*nz+b4Tk{7B>><-Ocq7N77l=FsT&#+wyC?gn4p z$L)jJ1n<-zf>-kU7XS6;zPzv7*WzdLOmuIzA0Dsxq^K|d!2JMmhWy9lx<5X!_=WH? zR>lsqh-*gWbUvpEiwWUU!GM zLoEKlWM4ki9g6rqiSp6-S;wI27WwjF?l6l#1^vXFJKP;^@n5R4b^BunYWA|f=zo_RM@zx$`@tNws5%1kNi@yQhyZ?kYdd6G)J@$K)C%6d~U+@rZ zw|5iWM2mmc%a@OGM_GK)UcmMae7;9poor^x$GBsxZiV}K<`H)+{=d53zxL(h+;LX7 z(k{Siu=@!f!Mc@?@#W*)@%-c$b70h;x}RE|Y-!3rb3e1XRcRYP+nwM}u)4L@^yQzs zpW~Xj(aipc7x5QXHwgZsd?I_!x^J)T%fG}QQTOfVeEB4IlGUwymM@>|PDX|7KtF4` zQ`{-2Qt(3gSMFC`x7jq)4rG<=hFg?D}Vba%Sdedn*h zE$x1Tx3X@txG(?K{nqNXDp20goq_+dZo30~`Al~vrp)QS&$IAo*6p;jFQ4tswz^&W zQvRts$DLz!yPxgLliVb$+e>`Cl{?p+YjykV?#t)7^Q>-P=p-`Do$t=Ky8ZX?STF!!Dyd$6bQ=wC+ge zM)^{Asns2IG<0~O`yKw&y5suz@@4KatNZEoJTuEpc9X5{MBqvJa(B7a{fg(i^&pOM zh1H#j42(@8qH(3wox2M3a2BzRtE{f|8v1#PD96=ScNsK^&b`K6V|7OQ-d@-0MW zrdZvgvCR2qVl;oWdiluWZxi>JYW3_**`N@&xy$OiwNq9E=WeU-iR_AQMl5HV)%T*G z*eyhL?y>rn=_j@o@tu3Ee%0HNX^QmRXY~UlD;_82bHCLOls-&bw2jA2JgDL5 z!^RvwZrH%lWaEPxMjbq6%&>unA946d{j=u(u_MNhZs6JB$wIO@QOsr2jZMjP zwmF&2XEURll9^KN#AGJjT*&5&#nII|ZkH+tmPQzq$hM5kw+!59lZ`7q1NcZ+yRM%y4i@?E_Jf@O};!31mZTsQ`u~DB3~dd(UdL}nzO|O z(5UH_wz*s(-AHe_TsoT@UAd=j{jH|*z2U@Fn$y_~(UzucA>W+JC9|0^O&T_x&Jm0# zk6P174!mWOG|;@W`9yAvx(g@Xf5%%81aDDTpVROihINbE#amI2vJ)NTv$;F{xB@ zs+cBb)l|MWJe{Qz$S&8ZlRT>d_u#71q}*b30A44e%cM0220I?mKrFTDXkwWOd{Ec>q!q(pi*6kfS4~9y6As+T8|^u3!ORXS9?w5a`sKh$xjyce!>?bID>h_c@W6W&lKVr~Wl4svzIhY&#*b;FV?> zF3W>$8V1QFyhyEqZKbm=XuEQ6X|QxLkk^x6u7>cMu(SD4(Gb`Opg?Fz=CaKhgdwsw ziDE>&=ZlS*RCA$#2ycOm(l9hpXVGvmlWl;;5WJ~kV=_@drWbRWh9qhMu}|zenJPAC z3yE}oB1#gHfg+17O{om#NtysNBQ&Sd>0-X2Db3wnQSyc+`9vmJXlP-+vkj=B<}A^FJ(kT# zP$n6^rf~`poXn(#CyPZSa6!^4p8#WYlWA$H%%w6F+GZuQnM-*pHQo8CfGBW+cu3`w zjeaJW0u7o-GDnU*+Q|H19Bw{U@JBk(P65RrI03z zqDe@|V^p-1aL^49oX+Vxx16j0GmF7fp zg*;gl6^io&my(48Aenxy0dmV0^T0sVmdU0HV>|;C=n4vi12FcI&`X&G{A@iBG*y^@ zyW)aWF(s^(*}%`!^Ffu<69=S6E@6yRs5{$SL_OpgOY~mUlu&)ibQ<7c&%-deMo|p( z)X*d)3)N-IHM9b(2(n^hg6H#aGu#9{H5XEB1i}Uhpbl(d?^HfF5j?=m$-?L)Q^>&S zg^5rV>&WLawUm~I(jc@1RGX$-LOd-nzSy>(f&_C`M#Ga%%g`tW5X6=xBHVLIB!EQ2}5Qo4D>|o#; zC@+yfYQcjU)>~xIrhFP{kS5tiFe_lp2zTTo<9IjJTbf z%FJO@z@EvaF?4w=@twA7Gmg<8wRS|Ob> zsY+&~3)xz$-f!}1cd0dM0^_e4xt|j5GfW(n-H70Z9E;#t6avdPmN8VrOyw%DoDyW% zJBgc+^+h&)q8~(%I;qSs1R?ZZBX+JR&L9(=oJb)`vKeyO8dw)g zK;;*jiwVfRGx6X!Xc2s}MNE2xCS9iB#(Mq$1)m5Ry4t7U~Okc5K*uW(d> zGaMFv3&-uuZz9_kj~YL;OoVXkrpn;r**x+c#;-7mXL3|~p_W(kG|r{+g#y^Gf>pLg z2-h-LtGrqUt5+;QwWUHeO=YsFP)$WV)u5$9HZ@dJA(}GHR7l1%m?#Fp1W$(6k!S{f zmxWv+8V?{(HD!riOLir~snIN{QR!60+wkSukj3SA8Az7IN-SuDmc|2>N1DTS+Mr>u zq{TkTY~=|y-fTyT$xfA(`z`pH$_*RJkIE#XJ*qK_eNgGCQrV&w*m7Bhs#G?rH5O~C zrmAw2VJf3El^?|5DfL~Nn+B{_9t)#Y#?BTcs8BM9i2}x=vL{(*mNB&lfe29EQby$( z{l%(CF><+q7|}n~SbC_T_F=kdDL+ZqKUBlUK6IT!_;WpsP5+5G{kcwz3x3opCCxEQM1K>}q?D(-Qeqdip## z)$|Y#r5T0j^ORHVyIOhd@S0Vo;7T?PIcT>G$1+ZZxh0V5tIDt~V^yFpBgkV_PkG#R ze*E(zR_(rQ%*sB^v%M$P7%`2OWH(>PAh5mg@irlPXiOFhJeTpd4~i7R&Sl3`9xFdp zC7}aHq(>a!4co6^3!6+VNB*SPyJXM+-ZGRUHxJBknKhHajeRQlBl|Uz&?XE=E>@AY zBQ=$kqCj14*ie2HS}nK7GhgYcQp9>LRZgsw=%~_9WlSvN(u1|5S1N~N*5hGkv%xeI zI4FyFr&&m%Ih)9`CBl!NWygZ;TF`T8?P?Ozuh|0Pv|5+P;K7eqWDaDeBbw8NJQJsN zF_#h@3taerA=Of;T8FJ!Y60A;_klpEd2MCo{um@g8k3<0QlqmnpAv<_Xtqmed}fIN z5loT=cIrY3{02(UckKQcHp#*ijKDjuopEVvQls9M+Bnr99;mT90P|>kfi9_ijt0T| zg3GND=wL3&;ZUwA{RK#jnMyEzgLHl&O^Q8F3+OuW zL^{{N-W%(>ppA?WlmOP1Rg`K*v(EtL><>rhu$h@`24k@tbHE5F6+6KSo1X0y?g*BV z!>+@x3}GNTl6ef2+B)6EnVlB(mRmKH9|V-8#tr2{wW>vr<6{<=RPL5rR%^<)s)3Rg zuN06ALOJl}g#^TI8Ol_KaIb>9TvNg4s8LIK<)IO=8A0XFp%-UB(eCqxK&nGeIJs#OKrclU;CXOIF0ZwBTvNOI9+fv zWDtm@0{Xsm(=#gGChcddb>%)LaszQFHckldc$eV%@?edMnc{X}JMEk18Nm;aGpx|U zShxg}IX`Ft$6teFf*;CHEsex(@Q-JZ6O}3`ryPD|bHf%WRY1Il9Gy((V-Ap%Bfv$W$*?+9veR| z1^gTu{BUv*l-suW!5E`7ETx9>Sk>7z_zB}Ss#evk_bb|oB-6{MGli-v1V+fa6#QTaYqdcSBI{Sh)feZ!+*8> zU#a}6=qgh~S4#%c6&%5_EjG*odXg-X=`nIvWQ+KSyxzf;oSc}$HHH^zG=Ke@juV?o zH8l^*O^YRxNqWx>iV~+TauE9^ftwC}S8nT@<};}=ON~>lsdQEviN`A%stXOvP8AV@ zi->jLLMh;r%+yS+JhO>-HF0nk(qk~#h`3-{GY159I$JYz*}xqmvo3r}An}h4r}q#x z#5mY)6p-;X1F0!8icLnjWw~KZ|9&<^FrYT3gM%Tt>XNTC&z5s9;G6z|bwe z(sVXkGmG+at7DdH!XX8L;l#qR3JVy{O^95aii8S0eEftesHq^LrvI>x7BzD$8x55R z98QHyBB7j}8jLIlECQYOHC516fL@*TQj-w5p<4;N;J#xeRh%p}R2PdYW1@>OYe&-5 zz*A+lr97NY7^yVpOL%eGSHmSK&oUDruoI zw+b*i*NFWqgj&nml|H%v?B}JLvS+VCH8lbW!?zhj9M;qva|v7qp+FMrR5+*eEhbxq zPGu6+`PVGBD>;+T~fp8rbg3c+;YD&wtg_KR6U3&+0|AP`M%_BL#NEW%1)>2{Kg!5 zAeGZr+waE;XuH~74;cb7jM-MOZAZVLn5Bi-HeyI%2a=_PdBu)bZec|Xb9{=xSMZmP z(uAr~DaH89`|)yB3#lRGu_<;<*EqYi$!D{QFqK|l-;lto;p?(FV)9Io+r9_|YFg=Z zjcrY@ZOG^{V=f}w6PD%<}sE; zuFA+H2Z5+G7C13>Sx|}Om?Tab5ph8tKmyfdUsWGtuTy>w0xmz;RDQCu*e@4bsak(* zmBhNl7T>_Yx6FpU#IV=fkeE`?6JL9Go!SJuta*& zL}V=6C?XTM0!Y*$e+_mcnS+E9cHl5&CZjC~#t!+TnL-1gNWzJ9Auo1;4Sow5g@g#% zSiz>GT;vHE@HlA?in&&*aA740;*zXTZBV&Muh`Cf+C$kR^hqSYJWhF-iJc~@MdGs1 zvT;GM17wYP(roaVv1(i$6xi*tR9|4FC(bu%S|_*0od`u*0n0Zz{L0t*hK# z0$F~#K)Aeu2DSF{1%u@^)K0y+iV7irwOmWeW;NITpNS!qx%cJPpr`7ttkEJ$fg)H~ zoTz9MPED+qs<2}71pG<;3e{FV@3({GZbAR}b%+_0;G&#SB|;;R$+YoB6uR=SeXSBR zzAgaOy7`v(G6H!IEQ{bq2pyP{G(x6}K~3rr4rlHbvz~b6b{8u_3^2m1%&PiX<{o1=9kqLP{>3B%2+0r(D(IA6GtgqCxIyJp9E* zt{%7CP0j+8bm5FP_OX~`_+M?@!`X<<8wbuJ-FRx=qZ2^^I;5=hzbNuC5WP&yby zHI?KrA}R@-N}hV8sKXMTJd1j)h($}7szp#0S2YIX(l3x`-)l^ zY)qj6@u!^&Hnaj-N|GS9fcL8?vdB?|am-sN#l~_-U}Cv|s~-Cf_@W*vtW}v$SNl+M zmq-GXLFbW+BKy2mv4!ad)YPxIZeaJd5gdDs#XsQxX!; zK7OO5lHxH`Nb5&s;7(w32_1`m5=iax0xPX1CMv4{)4AjUUl*I#dRhM|o5QI-WTzNh zNk@r%iUjw(j;e6EUK#ORPMTva5p~7oG7NYD1&YC}Nx)16R16%4rwJy&$<3gOtrI3f zcK8=Sa6RQ)ptKB*D({8F=7)P4U;y&H_#PK1BNvKL6_X$-9-{!E%7?nhVT1X&feQ5n zf_^@s5oZ|*me2~RmSmsk;UejazPZF1(i#6izR?fLSHwt3M6&S7E;7BCS}rXKpm$Sp zP)en$Md2$F(3m5OM0nFRF_8iptc%1S}UDLpJt)EdVFUC^;S5G4K5EzhwqiH z?J-Y;9>K5_Rn}}z{O**PQnC>{mZUf0-iUM}(2D1yHn@X5iW{AUVD%$`pgPilipn_8 z;nE~^8T_IF$+$<$DFxnRA5I{fPwz9~;UzJ@sR;c@X-V;sS||%#`&hIB3GvW{GGW0n z_6O=$n`E467#P~VvLQxBfximotN9(3jigucA@3upy0x2I!ZDS`HSDD(2_|~Q#H#8}KLu}rd2%KHq@ai?!$Yn_KvKm7l0+NM zFzH>djS;0KVyfK_A|=~`gi`8jP9_#6hcfZxtSyMnVHL6t@|YpeC{)X557}8EYsp-O zrHta;M(*hjN=Jo!jwy<`CGlmA8NBZrX$#gv@}C<5#y za)h!Il|~GSWvUh@S{%P#CR0pS$f*l&TUT?c;d_FErG>R9IKp;c^sJqKA_3hq5xp=X zLm#1xQ#y|ZsLT#7El;nCugYYW@X&q5Tcj>Lv|Z9RAv}_1{2MX?A2~TG!dvotU^MZn zL1lHLt94a`R2R4O8xu7fW4^peW+j=Xynw0=v^)gWj;q~GOpLDVN?ZIcT&@?1p?rfH zqQE?*N|2D#qc9ooJ^8&jbXJ(?w*m=#i*TegF5W;N#l@^9MG|IW|LwC5U=r30-LW@; z`cb^zGUW{?4Td(y?!jn)ZB&uP_@y82Ujlu#A&1L$3fg5pc0KNDht5quS|9eFE)2KihKnTGr>YsGKV zSysV&2+$<@<|uYCD<*3~+jV$ZJ2W{O@bB%3rU)t4_grTAlJp6CE>~81#xgDzmk3+I3H~K^?TcXwteJ{;{0sDa z;E1nNPj>SDFY(@fC{&iPHqbI)Tkz19t)%aWetA-ZnNgI|Y`|916@nrcs9dLvo=_{| zWx$I75b^(qDw8hcMSzfH%6a9OAnC&wyy4_K&5;Ns1*-woo(*I8h&~n^YT07CTH{-z zpFK}O}r(9r*ft&|;I;!A*l8b|9jt9MsL^fzrNhj=Il;KH| z2XAwcZG~$COz1WDBy~hKB}Z{+kai&bj(<>Y5uekG7Qul+B_S1(e3G*H@Ln*O{7ftY zAA)?T^oGr$PY`$q8p&jOmrQ~R%pt?IVNntUqMTW=M*|zg-3s)K=;xKPB&e4<@u)A= zNNr%}BHQsF@j^Vhjl2j}L2_%TGW2-4ebssp_G>+#_>Gw&+Y6{qE1)k0g#TeNQA$ni}-vb5&tXy*eudV*TOsle>hRPN^{LLOHyk zFz+>$JjIoj6=K=Or3*?D!p39|s#GV82faLqwI<&_ibnP>Rwj0*2oaSD7ouG;1oOP+ zmTF{ogoDJ>4)0>JJHorCZ!Q8lyc2t=dn@h+qDH^xrcb-aR#1s+(dQ|JMS4AL=VJfj=073H%Xw9Dp(mEPN8Ojd&vr zM25^x6g4__Fh^l_Fllzg{o;2wPuwpJPPB1ywfDg62LX8GX4wbux{3Ue37+yi@+V|| zME<7KZ+5?f?oPBk`D5?|&mf zr4bo%HeTB5LogQs8Wv6szA^~;d5MRtvuo(MS{m)TzNa5Ic!XSMW?;9%1uJr2@8SF( zFWOY~AdGSoVLPh079-MZH3Sv*YM}O643MV#Vl2^rN+N3dh(r@Rhal2=V93$KZh~mt z_U+ZltI+Me5#0L-R!&B9UZ~~B-yW`fqR!v`y8daeAEQ+s#&y~td4fW(Z4gRQtGbgk zMILwHK2rv!4e9RC{Sh#yT*m4;%NrHkM1@cj{yhu&D3ngSV|38@;p zc7*SH(hw_d9mKL-$R1@<|cgF!1KzL)6E>3HagPVcQ*w zjeq%WdzlXB?c;m?Y9?$gI(n)kPfQ&wk<|U8zB3Rg;w_9Xrj;-%OIOZV?FY+e%#+c#Bx z{4F)1JSXwUSHkz>E`3twG$F6@lio;n=`f*!Z`>nr65o8KwF@6- zklEkZhQ~E@UT3VY*&&zfIr2liHVCP6pMK~$zrZkl^8~N+{Qy#5^Fh|BRk7nF*pBI; zx^E1b1Ex7H#)glok;q&Y#AU8fmBUq~6Z{f^I1FwBpJ(jpM*oTpy5of|K-DI( ziV{vN9uq=6^IO&E#ga&)aNheTp~9SCr{;>DzeEZ4*dOIR89JYS%W?Mr!Ev46_Wid< zeXaP@)(O^}Kh`TN2tDrbi-M}=FOb0TFEWtpm8JO|7>ECo4RQ_yMrFw=45~&WSyF;q)AxJ^6dHk#Fu`jti~1_uvMM2Ls~xiA1% zk%%j(>C5A)35lHc9thAOQWQN_-1X|+qOzxieNp4{H+9{n-y)|{QqX~m=BEYUjNECz z8>Eijzx!#_^rQK|ED+Vapq*JW@B%M<0<;vzDrES! zE`b`A4s2H7KKGfREtafkQCLGz#766;#knGmWvd`E!=N!3d;#a-lZYLEi>38(Haz+s zIA*$0hC62(Q;38>A!QGLJUsD+V4c~(o}qR>1yqYaqKp8kn-)Pu$P`2&R=)n5zzyUg z;dlP{0^BCn$$|GT=ZESLg#5%OEMD#VKZ%8_VzJkT0PbWeO>$clEU?{wG|kePEgIFjM9lZCmESsmS1Y>sUuBBOnf| z`LCMs&D9j-a_@eHs<|hV&LG((<9uUXA*>=4qU99rmuI!nwqZKvSt4s&q?30?5uuTS z(C66tMZ)j9esduJbx@o6Gu^W;+ap28SsDy-S<&^h{enGm-tXyMAEeC6_VjjOU3Ht! z8v4vuUElRq#)hr;UW$l2Ac-SFS9^qvos|FY0t$SJPf^_-n_onqH+K`{5K!HD9p~e` z^@c>)W4TlBWsmvC`Co8p2bwZm#*tL#_?5YZ`baQNRvS_(Zt~oZST278(uM3b#wih# zA0K0naV^kZC7>Z(2UmwOfljbPd@8R(=X*+8Yszy;T5O6g&lMfn+sF<%JcvENkuI;b zxs6ogV?r1*?GNsv^wk=Q>SL0L#7JKYUtw;Op3p$~?ItC@ZuWu^wMq-H^V)up56q0B zX)d(VsZA`!p_aQ}?9D@)6nlf@)Bg@O{0q?$JefUH`TGdhE&{NDUE z@jR@g{Hdz5(t!5N>kLfxzm~1FV_gGZ^0H03wJjCG61UEX;@ztWs_;PpBLEaa&KLWt z?aI-B&kt|_*g=@NPuyX6Qr?W&4T|mpRuW!hgnSeO?*%b_JEc8$`Sy?_@Jl>k=OD? z!9`@Ae?OV&9b(bkrtGl6iIOv4~rqc#n6&CU+^J-S||d{cVcYh-T$7Am@;GM$(umWaio?By$AlZ@?c9wrs!`SkAgO$*iWGpyhrP4J4( zO9Nm;pWaTsdHnd|>@~~5JWL?X$6F+; z-HPDkV{KxLV{De;MkFs9VF5*yP%9^o`_b)tXLF!iH6|6U-og>r*tJ&s$&czJX!gk? z+#kGG`S##z?0WF$p(GVD7~nRq>(c$}zF2#3&r6Ep-r4f!!W)l+L!P!ve;5WAsh~k} z@d;wGO;nX^6CeG^QTUMRB0uW^IVghHY=Z#bmfK z7y6V@FYm#a0_`EQg!^-FutOM25)_$N6Ol9H$x5*`PUP@O#AnPg9`NQs{3$xZFiwj~ znMQ;laVUc@wJ^y@kcdkNK0@PlJp@w1*pn%Tj{+3?J0^4oXY_=Mgv<NI%3OnX%pA0m3rMu2%#A`{@MI8`bIw(Y5j*cz@RSa^ z@51r8zXbZd=or#@6%zL$MUHQpvuNyxk7G12jOu{c?lB|TY?1_ASjMe=;=a90(isAb zlj!f4fYqCCEG^&(N420JFl29K^zj{$ch(=({+s*(+bj342Ir_Xn+0KTfVjZg{r{mY zI7fd{-b`Kw!%>oZjJSQ;E(?fw36J@NtUkNGI*QuKO|v%QFstpwdoFfi^upBCd%*{5 z-lcmN_fC~v4WC8r`&=THsaWb0W>x_2)0bR!{qKETb|fp8N?>4dn#kO`$JIz3@U@u$ zr?Xxdp!GP!;rR+a&8^IG{nIm40_?M45oiv*=(>`gi9(8hCB|peI$y0|9=Rc=z_^}( zZjlFWRCVn!F5lr^P_Z`&(P||WUdPu{!Yms$5Sz!GMIfM)v*EU|DXWpRnPifr)+j(? z%v%X6dKS*Vhgqlh?4&%!y><=G;%%zGprYH&7JQ=QGuSTDEdS)c?zrq>CUG;4-AQ*7 zbQj#{&VzuVc%oN+mgS2~qZ1R_w0r!Fc=wDhP|lvwjStIKu0D90c)W=DfK z9%cqNu^fg!&#!Ni_qm;XT5f5Nf%2mQkO6Kk0Ww!c-}~1!rgHVXgZjGuK2$Wf-v{^K zZ=&2wshIbC7F*3oE5IhbnLAsos_j32UW39N=Ph1(yI|k{WN<%#(R%yT{ftb*r>K2=-fO2!GFEG24y$i=>%K>0AI>KIA~Jk? zPdR=UbygJ*czp&!s52B*w@xyVRrE29L=j+ZG75{Mrg&J^N0DS6Yb9_M9P^Yo1N}g9 zAJa&3&O*3C6$&Ms;}FyraI?+_r*4y)m8__uNHB%X!Z0y}3JKl$CA#CR2)t9ihoj_6Z_{p%cyc5fZyAvKu zY&k=uAh9?!YA%lL6o?>k`)9%H0=Yo22bCQD!lZ2L{X2K3k>-KyG$iuiF_++ad757$ zQH5T88!K+mk>JCVOekB$u88ej1gq#`4elpD&|vdqrHhH|By2sGZ`^%bxotz;%&E_5 zk2J+eMo*WGg>&9@k2WUgXUSmhC8=&bic-F5R#cn$7?VY(230v_U;DibjpRCKi z_e;P=q0AO0A6Ctj#^;P)3?&R_2`cn5_0T$vSQ95W&gTpJ4k#jhDsp}pW$+DGU$LL-*6WLTHFo(&+-4>0<(=Ek z->=`@MdB2SzGqBF<4W-H$$n!1!qQ&ns=0A4Ey+h>m zUp7)iuA#~hdBy)jhRY@R#& z-LL&64}!Bp;nJW_OoT*DZyf5TJLioEd;<08wu705zUf55XXsn9fL@NifuB27&UO6T zPX~SH?+ty|P-b9sF5?zO-@*V{y3sdzx#-&}p7cGj-Jx&FBzFFc3WuP2T)Tc=gU9-H%jI;qEUCeLaR2?T>j9_Jajt+BoZJ((P;RtpL+F7yB-e_Mb1)@Al`-XQyqTiNg=Q{=rl4 zLVf>vKmV+*-_QRExtX_jgwpr4Q!6TzUa$5HKoQPo$r*{Ljg97sVcHLtr z480fb9I>ywugD&}R^(-+89Tb95z}Kp;f2a-@I=7FwES`Jsd?B>T1>_Kb85#X3jAx?XYlhFpvUch^I{&RZBeurU+gx+Md{`p~482_v4;CxT=mvVk0lVucypBz+k|F%8&nf^KNez@esy~OdN zgw{%`dWLSR@*-4UzC%vIlv>2_K&B)yFoU<%-a{98eXjKLBM+41eRgw)-#oi{hOV3U zoE{|Jt`EIEcJJ}|+$(B%e5%tk<^{V#m% zub}q_V6(?*LTD;IsizcO;)ZQdlmF}El<)}=0iLl!;0h??S^-QBgy8(W6Ylx#43qV1 z4*^n~*Jpz4Kks|*W9zTCH&1+*JjIK8fU19&D^|hDq~J9x+1bCYF~-+fn`yh;f$=Cke-g`Y| z|GK^7!IMuTVKqno$bzM6C&@Pk6;^_*mUu zjXA`0#pPw-?Kk@7Js&IQubwS+S) zVQTZLJ9;o(i&B~vvWv|3h}scU!Y^$q9>iu>aQ$>`9Qb@pl-vA-m}mC+(pGQ|W2!(~ zUX#Zg)>VYMAY1KiN`cyk2a7-vA~iwdWweM>Cg&DmeS1i14ub(R&{4pAm7^6=(=$=G zpr=GLl-8Lka|NHP;I2!xoEYMZ8lRBb(C6NaN9wgtP{ZDCm)Zryg!nw^`2{(@pymb; z^Zomh6FRyAB<*jGnVx;&vkyFJ<-;WvusCS8B>xa?FxQI;rh;o2tVl=~nL7#XoA&};0Gn+lj0q~)WXZGtrELafFcwC}M&e|`&v#1NgNJQ= z-2RZud!{C~Pg}I_!9B6Riil0s!xNF##41YLWVQy-)X2E~%ygtV>oH0o6gTsMkC# zX~>bOQ#;SQ);yxp;gYhU20~Kn0-%|icq_L^p?6jE^m%$q6Y43wmhUCT=^wgW#0tYr z5>JyBrlbT-;Z>Y95?A`6d=|5TWFtc)hT+QBk85ZS+|!SDaB$~k0kr4N>-u%$H%{9C zex3a?)G!Xw9voXDv`=y1%o++rIz$kyw3=v~)X*Pt*f$eCs$$|w!3i4u2izF&-r$h8#fwCxrCocM%See|P z^qFL)j-V#qh-hsmLeEJR12+5Z-V<5XspbEwznF>;vX&| zKtd-KjIATrotCqafX{`OL&-rm6`5wg$jldOjOq}X3m4h#J$N7#NLC3_OW|_aiEuB$ zw4TxF(RAicsEs_Q)J-uD$>_)vJo|iv^78wyXI~3&`-atGZ)>2ZnQ!JRU9qNjlb3Sv zD(b+dB0Cjc)5R`h$EOR`>V!R=eU%&4|FC|m3>zq8m)DklBF1K`j}QLG<{~X2Gg%n5 zw6h)6%>jeCu$3$|D)$3gfm5BwpCpY{SG?sMJ+ z3jhW&KvFTC+W7z5o@bD?ndU!WY>Du!9Sr*+>($A;P17$jX+rP?B_kw;kUUxyIGcZJ zhCB>(`>I zPS68Af_Nld9HvclDUdE|{Em}?QfjQ~)~eH-n_y|}Xx+kxmmM)Zm}3(DKt|$k&CEYt z3BdujCJZ9c|>_e!; z$Rv>FK`KhQdpz%6YFGnk9iv$?Bbccy#BuKzTL9_c*BLR z`A*WbFCYxg*-n0RzTiIZ{SZNdy%L#AwM<4+e=Ay*Mw?tRaIx^|&NZIE(!J zihW^zp2ZTgJMlRcvJL7fmXH~K|JctO?_V$b6=S|!Bo6Nrw~4L7$bQq67m{zkW;667 zdmGm)Jvbd1*tGXK>f+C$>Pn1}R}IY;()28T2>5p(O)H7q08_+zK~34OqGAgwb9DLT z=1dXJfu3Rf98L7sMbrH$5D2?F)W{V5uB-MR59~~r?IEqoPe{&fZP$>7M(Q8TIL~LW zdSp8-6sAv!+^754{&SZ9zK=vcuSIIYNR?rbBm3uVbT9RTfcy>1sfb}}d{5YLvS8nKd|B3 zC;dCs_lv-s?;gN!9_s>d{VHqO2d#^E>ZeN0Ne_iCARVc4r{vf!@`BAJbU*Th${=S) zo)mJQA3Vl4BbU>h2LzV7)_}4=4ESXwElN?sJ6d=Lf-?*%hh>4_W1qidEZI?}N}27-@ffwJppRW!MiI5P6z_6=4+G{On{z zqW-XN4hk5BKqk1?mcnZ0!I%f~;ysvA`% z&$af$t}zRd?>kesd|AId7aj!=RTJfE4JwbHUL~bO)=AK{r1)Cdyh6rOZGKIS|6cb8 zZu*q0nwF}at7816IPH6`}1_{CcUd-K&Y+`hR3_(rFr${=*`gS)jB}< zR{-!68m$CW5Ub_o{4b$!$b>JpS*6I7KwA)3zW)uZ;sa5HI+%k?Xq;~3%iW7 zaF}HpGN0+a@(hzC;pCP~AM&2TgV4u7^JpUU445B(BzqG^rMH-8M8_Y2!544rwR+^! zBNMz4I9|ae))VR(YiCMIzj+s5?~kj-RLcmwpP9vngh<3?zb)DkYn+Y}At&4jP?q~w zhB9E3k*8;;tPu?e_8i9Y5Uwck!bVgdq#}WhD7YOvkJB~gL=6DOLZlRFzbP^7ShxMF zVkEJX*VoiF?~|lHW4!*N(K{tZ1Um>~u%>e|gnA-J!4ziDZ-S4DL6wtsZ=KOdjsTJ} z+39Qn--d_+?zER9PJx6!B(!my4XK!qEbDME9)@l)!8KCd97egpq9o+}?yo-wFfoZR z2k)KHtWcFG`5-b)ZrG$ArV3E7n#LK95eF<`P67*T$afd>BcDBXG?NopvMbVr6t57{ zxTgtJQJgiZ72*{id|<&-Ia6>=n$fT+<0quN$?RJjI@EHJ-a&=RAYQ+JZeI$EUPAkB zn_d(gZdkPDsd5jT;x;F+m?du!=yTHdT!ky+aG4TR{Y4+l@_uxpds zHIbm#DwB!P@9?!d5569Tz4&@D>ah38{qgn5{zUqrJ8mamzJ#0RoJ=+TlL-y+B*T!- zGof~l>cCVH+6D-=H7te+4=O_V`=eU zRYCpk4o7{^^0HGm-phg@Xxv$a+Q$M>vV(jbOaf4+@;@P)-;N|1n2d`|C6VyT91tK` z-l4frHZtOGe-~CKGk6SO{7e^#RQVGdI2Esgq+Z92tXLECz126%!vx;V0ZS{7kUQ;E zEc78DCFvp#%>=6<7b7ztfl(<=?9QA7fCE8TpnY`<^vGCLyq?+`ibE%6Ry2MM2|0Q? z9LJO_Bs9Q*5PRpVFzLgMNaLYz1nmoS+cXO- zSM7URVNLZrdTo|iH9MKS*4UtB$jIal9?r+ank^S;nka0Uoh`K%IY8yC@?PY+Udf@+ z@N13NNX@p%32}-!WBOR(78rprd)N9B!C*0OUw^%pcZzCeeNFIO;M6cET)VlKSgywB z0aq0c*o%CP?tsVN+e7xnFY3Y`2Bt)vSU!{ODPttOqM=W^y0bWcXSIQj24rBd zcA$i!uGm4zkg=c?TDBQ0rHYpwW`uGff<)k9FEz=OJ!4LhGQ3L<6)aLtM;w%>ZUC)( zeC&z4ZvYdFzXE2=%d3+1!5$5ehYf(`+asR%G*MaJi!@Y%=~F#WJPo=s^PC~?FzL*4 zp#|-2(w!YqJ(x$SRK=7ar$RT5HfB%~E6gqu#r-wM5D&ugWMokWmU>5@1wY`Mk|!2S zi@c;ZAG!|KM3jlaw%}`qG>be#n?cUOE`(ypbw_w+P#}G}m(@V6S$D9OfObbx)ycL~ z%w)R-LL~iaBc3>Hsg&sHFLjPd-E~8_($M1VT}PP}QvlT!7`ffkpXWiPkI&@-+)XT% z=X<=c!WH7PcVubz>Kp_SHhJjtL7NXA_>VUtZ1W0|J&8HrpZH`+LNzw7F=oeNl8QQY9cbW~NVfr>>-%@vI$tLP4wH~TImSa9?f5k8D8Q@Ud zALC}B#B7%G_$}lhzLLV?X&lHmUr{BzlorGRi;82(@P5@k@h$Lob+aL^BB<{Al7%n7} z_Fo!b%TC#AP+k@TnXOOP88ZzLH16nu4JwSFejA5g!-6~iBI`{nK`%)a#q}zq~oKCW`7|f@{<|pGjSD>LGD;*2?p0O7fJErEyfNM*dVop6>EL4C%!lT z0f^ig)w}_{7H=#6`0LLt$izREkyx6rwa|?z%qn(h%ldI{f$R4c^yhu=?UsG>ZPHJ- zpO)%%;q`>q(>a9{*k}XTz#oC<_bP&p4U*>oEGtaGN?Sl?1d(cGEZwXNM&ZxE}M4;?$~<-$ME@uXB9mXCTW-OlL!bF$MO z^Za@S%zV7o2j|E0fG)7&_3cAElf^*wrpK!r+JW#tX-7B1>&EYsjyS>lKmOwv8GP@5 z6jmm+NI*D(%|_YRccRJ?089yKW=4@c7Y8FBm<(kFnJw2CR1Q^mdJ!c53f00~)T8_bXtYo^QvR3de`k6_O3k;J@B-`<;S6{{B-u| z$BybNGH!7uFA;v0H7&~EXn2u;Bu?dl#;l=i>l{2cI_LPnC;aw+-R_@vWaK9AKt_po z)M-L$91uH%m)Xgt@@1}fZP9-FtY3(Xcz*}VeXmI2sK6itzQ+)lsNHFPeS3#e&Q1`BSfwVhhbt8aTWO-7@63jD-R9`^?)mRr18<`ZfZ>7uqv`)UiCcyX`&Y1lDqypSyb`w~gTyk!R>}3zC7;H2*&pb5@q*KYjcKzk8s=AlfvF*hNlf$ zn4vF)CuDT9?ZW_&$Lv+|Ubk2M+fY-5ba4pBm-OlQKkmtN@(1-@b^@S^G1-$#}^%*S0GJjH0)w@dc>bn!}*zUcWS();mTH)DKT&xpXpN+_`4 z;M3jPj2RixmxZj(bj@&0(6o?O>9~Jwksp1)QeT%X6{WSTmWmt$Yb!xjMPjGA5MoJT zNmv;jEn69IsCvv?yDOY95N3a>Lauq+@7MFuHMz1s;{yEgmLy$a#P6-<9L9+ko=#?n z9IZ`Ck+x>gp*5NO7{w1xX{4sWfYLDl0f0wdOlHsE*x4pXAM)rU3gI@y4y%`NET(8% z_B`=E$(J_q3!~mULA=#@X$UkO1g`Aj4p&c8wgGRE*@C z7_n!OJq1vbJW9-{*W*=#u|!|08M{+1hc@ipOxil9&x@`%p6{7ib+N$mdGQ|lbA2N! z6O%O2ck(7{Q0|V{1h(wE>0Oo!i$o-vyg<&u2MGuyPzbxYiHy2}m^p^okIJ~hoG7_Y zx+oZndG|=S%i1v&?jOBg36T>LAz^#G7&VFh4N~5Xw&egN?za`#_L5GinF)0*fXZ>{ z9(nY^+eiL;lUMKWK&z`*V~Y;}Zz8?+gTnJ9gUsvK$*9es-EjEpn~z^16iRA{nbMMM zLH5>HQs=yNU&gdt*Ku3U3xC#^{ewJrUdV7x-qH(p`gT#;Cba0R2FXEN%ZosoE;8Fx zcJBW`QQLL2rg#e4@}!G%^Y?$Ry???}Cqc8Y4=T=_jI0m3jJ(!u7crki9m?+@uk(#J z4md|H)_L@ii=TaELPY#yvdO0y8RleI)BcOQFP=W+Nn&LE4b_}tyFF69|;2bN*Q*ch3YrU?#wI&D6&C^g#Gjdxd;eo0cqO zvx*`ng_m`}E+zpWEk3}0v%p#2H|y+tFy!Osj_f<%#x~_jf}`CdDC_Po1e7ukutl&Q z4lbX!mx-bw+_v7kSnH1_aJ_BYEDyXt2)^RsRqgJHXv<0u0mc|C$R^0=8(Gi%;R&dU z>m6N(H5H_NM4Eg9`<==x_RDSMn=)>pAi7ohKun+0z*6T4zn2nb=t?AkF@|2$5gt0z z_jUG%oB#}33YP%wAdKHFLDsNj-mHDc_vVtwf#%|_1ut4Bin zZv7(DB99}7Ye|9yPS}0!z~1XI9hWjM!`qkjzM1!$#NV@ z-emO1gBKf=9gK>|x5{osdDqtPM)vQ6pr?8FP;{>8LD6$W_DRz1|K_P{kBbTP*#X86 zj!Y;HRZKQvII^CyH;%mSzRmwvI`%)Bxh;TGCmVZh-ylVvo>D%8Yix6t($_F z6N|zP7w-2#YQMl~G3D`!`a~g%!6cMp8nbqhX(EU~5ndmh!a>7@Zs%8XjQG2&0;jof zBD?eFi|VgC*5$PQddhIgykd{69|vvaFf1NJTPIJ&O2cKhnXUU2x9%@YhLS$wb`{&5h7nAM|q4L6-mRMA4df1EJpSWg@(7w>c-h ziPNH$tg%9((Zh)OYK`R82{0hWoP!yq3O9p2h>Bd)y#>ULXcGm`Y4#z>jvP5Dc8Ko@ z!9JqbeTR00YjO8PuY-(!g$I03?6aS~d$`Y}UqTU4TjH>Jm(eu`If!9SsqGg8i&ul| zJCX{@p&ZeKy~%KnDZ~SahSIU}Rv=iMK+H>>3n&rOv?a9E9Ox$YUAw$sGZhX9Z1>WS zUqWgLkG-3-$89kxlyh(kuTWY_jgO|4Vh&8afraE0Rd?~V_@S0$eZl&5DojNH9mfTM zlH<+}62BK^AH}KK!AGSe#qo}w4p5L0W=c{9KMHoM-={8TZxRa}2o)ZL+i1=iOLeNh zK6>L=Fc}l?ybTk%}x!~<*Mkuk9iksw|8iGaMaBagJ#|2g*YsI}3aThDF_@qt?Vg*y6guxE=K zjy-!EXgBt31s!Qtc!e16I|l8`$atMPf1N>_i+NhKPkcEr^t+c=I`btWy(Ms6j1o|=_}b&aTpya zc=ukoZVmV`BW~;YbqR7?85Izw`)!I7&EkGrBXgUYsPagPEkuMg8SS>}iFzAc@VmKf z26|f~a~oV!6;d(|RV}}5l5%5i>d?XW-PC{jXa4(hK6i4bbo1DYGAVL!mc@e6G9Jw) zPm@<#UI%G;SrsWAIC%(PSp@YYo|0Y7FfP@?x?vKa^2&)}V%ML6E^K&e9Z217fD6h0R*ArUS{JmD_kr(Vb8P)%)`!G zlt`O$HJvf?|1FDP0*k@2HZ%!GiDdSOJf(vM=|GQCs+c_~UaUxtbz_-yB=$niiz4$@ zQd&gZzS20grf;Gp7;d?FkYDl6Iasu6JlFI+UPp;oH7|yPX=}?uvQTmxJqw84bx8&= zf=`H$fk1N`LqoMW)Z^D~u-V^!@m=gCyDY0E!8z7MWrAsPxq1gI$+k%3c)7hs`AYnp z*&z-qUer;de3u$LgrNo9WD~Fi#PFF+NW3_tgn}c4L(sQ_(T`-3+$q}u>BHh9#>^Np zL8^mk)fPkW2z>~-mm2Y8pmG^Y$x>@lHi5HLUMxU_RbyqmA6~<^Q`4%3g0nOF|O6i=?GT9!+H}5T0+JV1b!hfO;HR5Y1DD*cSz8p6tBNp zXBklZ=Cg&lOQ4h!S9R$F@Q^H-^$H*qm{E5KW?;ql47}IBGj7L{m9q3bp)gHbO})&T zu(0q?>m#@!H9|nJyMvfu)=39QUri>)(y1-`_?3xWQ!YD=0a<~VybYUvYSul_Jliif zkIr%IrbfMq{go;?&& z=^R_Pnatcb&ju2h;6b%-KJdd=S0Sk>J=PIP`;Il>2T}Cu<4C^h=S(w!=~Lg#ZEH?y zUF^pFZH>%r;XqMe0uw@V#4|YCEO-4i=C)(N{WIdWwnCw_+wc@1@uxQ?iN~z@2-x0r z{HGrT?xwE?W?gW!E;6lY#R07Z z<>)qX3TfkjADff|hYc-%rpX9NH6)gfV^@hpX)ez@q`(#e+<*L<|JM!mZxCPLKjJt{ zsH{bag^`0c7im6H-9JWnvtgsmt;5#l2iX}JDtmg(Qr!pLw|a}n4mI6#mY#k}KRxHJ zgy*?KJI5bbyH@w(AV%b+*l>6 z4+6!glzK;6u`wzm6`vdfGlPWSlQ8EVyiY5~kSF~LkSRQz|74IbY!tyV{D}f*g$Xc> zeItIRtG?X?MxT%tbyxpJ`mSHh4#~nE0ug(Uuc|DFD)h4W-e*1vcU_-(TfV)#x23WKDaUF57)6c!%D^~CV{%sj^EfF+;F84dF3DSt5Nk{SkW3vhpMVOtGW9 zrNC{7i-@dWT&1@(OXf&J@VkFP6w93a?-_$0u&VxC;n~d4Or5CL7a~(&ZJEBz(Q4jm zjp^73$|EyZ$ril;)fTW$ybs-q?FC7%0#2-$jtM6xU73ZQVaVjQMV4BG&2^2{+kG?d zgJdD12BHpIQh1m(GO!%a@bYYX#vtnjs}wqBr3cXmjP)M#fq^DXbXg#x#cyhP&05KF zH-Z;`lVGe>IS?a%fe+zh*?Gxdurou1?VpiU7r)7_rZT;l3sY=9oC<9y1n#~yuzuts zo!483<0^sA<2I}C{CcTa;s6BViIm)9UuL1}VC&_Orp%JakQ<=wzxvkO*#24iV%^3| zIxnTm*Zroke%?mSWPh^AXi?dWvSZFQShE)fD+=!`j*<1NcdmPWJ1#SDUN)=r^!kf6 zBoWxX_RtPa_7~Ujb*2=lasWN3ybxvvBb7rC;}w#A$0#)0mcx6{fv9p2(TEI#SK6;v z7$c>~oTB2&Yh5L-7!<3%>oKU#C*8{IlJ6rfD!xVU5xx>6{dvi8WSrkcC@{lhhUeD2 zvvuodxpFhsN9UAM^4GUUF*t-Ce?{DkyplB~b_9cYW|RluxaNYTZoSKvl2(jF%Hee% zlg~Ale?B}bA;DKW>j-=L<&ZOkmX2ll#KOS7hWYOnJjRODos0)v$iU~1pYuU=+YCj| z_Ls8?DLWueu4z?V-_<`4)GTiq6PC!~*P8GYE6{a<*NnMr7>uU8WAz^h&5;RzH`xM(9 ze#u3{!t&O_LKh4#Kf-M(iJ z>V}uEPym98O^8-BNtt5ZoQswz>_OfOVueQ_>m3(~()r)j?So3-1|UO)TqF_)H9i7$okVa!KM<&@18a|T7&6HhTP=2@e|=x z)Jcs}1vzag5)hUvwd9wflI-&nO>ceo$V*I^Wey`1?oQ`1-$6Q^AcnG}=Byc{3yBo( z>hcW1jpvDjUSu65yVBjux;8iqC#x%o?kg#}x7SP_@bjckkC_NN5GQacbNsYt5-bH; zqKgPpJFV-bPmZ;Fz?TyT-<(0&e{<0DDIwqzdA1&Lv!i+Nf)^ZeBh@M5jyJ1I>WNkrjGgFi=d? zJT5YS#tw&T{4vnFck1qF0enMxUVHE|5ks~Xy(UhM^P~hLUTgt}@7{jm*n$T4gRkZU zzd{uMDCUr2mlCL96f>QcDH2XUh7gBp&!mPk3*w{}#zv841d{sF>T@c~ahaG=V~6+4 zrUCVyzp*_MsT-?Y`1y z@EtY_L)3}H$MJii(yLDJ>Cz5$G2sf+)`kK=C>bg-@`-ZbFI#H6mQ5(8$m|pMrb>8d zra%cXS#`00uuR`}fMxU30~J;MDz=`!3k*!A(`&B%zxI)}dMM2|nspX8d;M75y||mW z2g@`hy@~rv5nO}1eYyS{8vZFgZ(CbgeE0; z(y1@+y{*nN{5Cm_D*0=4pVX+`VvCI_AyZ;UxDUiLtXm9$M-Z;f5&Xu*TM`>wYX#tx z&7%~snY^c}sO-s;a&_ZDyf{=rZ+I)}mZ|kl-aQ=anY+>XW-t1NC zKPE6IvVlvPI2=)yH<5>1ijDD630lhhNt+N~3tA@y$o(R!J42BpEJ*F!L>a0`H-s=&vzpy1=9^{`7ITC{Ir!%bG^*_B3T^FnTcU^i zdwm7j@QlDG|M;B3uP0B$bXI?V!!JeGe*94+9HoQ!mHy zBN&Ac4#7C(w})heb9f;cH6I}vPmy(7m^c6aA5WXYjAV=y_M8s6$h|)UWx?J@F5)c> zV3Uja0ZA%xSwYkP2EiyL{(=cWD^#KWEllvB4aP`X~7=(}03;We=uL1_u5 zxUPTx5%FNZo$_;S9+njY`v#$-}V z4+KI$l(>Q<|z-cRs>db)$)y0cP2aB)HE(#@^kk)7tzwsJ0TI`b+0= z>4t`aqa+enGv_gHDyW|!L7XYdbM?V(dR5II?AB3jRHe>wx6Pir>Di%QZsOzz-Co#89kPDK)?1ql{}2rW%DUaqq-)RF|N|qtyF&+31@W zWOGWP|9Yu6Y~Z!;d1^%Rg>yKhGY=Dm_}j+ z@Bk3glc_JkKlDx_X|>RIGULvm6%O(7@k$}eBCrdH`ye}U-#@crlYjCi)dSKqMHNM- zrUlLH1+Eld0$N}|o;Jd%G57WWl$MkF^u+&VCIgf}Xx(P=3p3^)?-_Gm<7Az0QEu+z zB@%MT`hbIU)IQX#1p-Kbo1bE7lF?9@gEfod8OCpORTNc}{@6qNmzdkSse@sbG4*Z4xAmu@o9hm^ zzPZZC@y8bIxc~g|=iXJSW*L9K%ANaRGy;CQLNE<1TA5+#v?`+VHtSd4&YOh3ACVV?RVkWUwo!t?>r6xCb3<$IO zuh-I>M1nZYlVw<~^<;(UmJ+NVJd-aeE_c~># z?x{~^YcQk}@$FEdHcy}?u->G$k^@WH8CthKnwE_Ee>%y;?)?IEkUl9tM#bX$D1z1W zl!7vf#0cMf6|ms@1EgxFA=JXxeEqe02?43`+FA9lI>@CPa^n8nzrM=01{28)ZP6#) zu{Y^~LM2DD`P3AUbCh0ln{oV&wo70x)_u1#MPo<_k zq>r2@&)9tB^=b3hmS7?+^V-`Rex+;iqltR)WcKK^ZQUGz*f-%XJ{6UN5W=3!{?6rM zvlZW5zxL3{sV-lf+Jy(Jy7hL)zW2ryk7ZOo!5cOWD~D|?0pLUiK_O;xM`v^h6+;a< zeiRu{Rpl~u5K4qg0PuU1epkBSPBHETSCI4U_jisn9P~9yZ;A`58PN9LH?V7nyyjiz zmq04dOY(6qWIutgTaKOkJq%Jy8KSl+J&`*PYFRj0^VDREEJ2-8k1_=oh$9Bfl?fcC{2H=*vH=xZ-0r}$>lV-T_UUC1 z9u0Ql_O49LUUvKBr-Z|h>2Lx|F7Gm791ft9R?7YdQjq(&t>GBvE#VhvBvTiS=}zr@ znD6$3CyTEt4RN;|P}RG0wieta!>!S(?^YROcWqx9+DpFBgGd?C- z(K)%$=Zk%N6!EnU4)!R*yt(DCY4+*ohtYWU^_zgMkAFdV4+wAH_I#NsF3u;`QsY;vMx9M{nvHpHM0Kn58qEl0P97ZIA{7) zp>-{{!dcg?OSIF{&UeX!V2bm@wvu`f?-w~_3CxZ~^SJM6x6olMD1{uu^*Mq*>+{## z383})>jyb|u2#FZMs41C?|p3jl?mA{7bdtf-X5F)QlDPX6NEU`pfZL-=S1CB0N^+M zaoboCrPp6j36HsM5|LmC`g-)*{6e3@a3zi|3fyCXJ;Tv-X4cF?Vn(MS zmG-C_>l8a5uOVL;OVd%aWsf@HmF0iV@YD6bT@OT5Tm>FFNw5s?s>BaAAzX<( zy0k+Sa8qPkPO*xtif0;oI$z%2u`o|qbJpbvXFk1cSnS4^$ErMK%j=FCSGEU|-z|+j z05mtFd6_N+$0o4yib(8P9=l+gw-xz?ZRJ1RkrLm7Lynb2H{IRnr^@nIc|&)m*(z_m zKvbI-C<>vBDlf3o*X0GiKD@v>@SI-Yn|G%dNS_NNz%gZCjn4z?e|muca)%eF7W4E1 zKhm`az{T;Td)pq^NRNE8Cu5Y-#nej%dI>I{%JS#w%Xo=?UbYop>+l=)Glzx!0;R$#8k=?|VdAGBMRf3I=me%d;lo>pcT-@FzyNRH(#g?IFhwFV0fMv@)3Ppt=L?0(A5t76 z;fW%vSiVilL5$y>BD&e(wYCv$L!(T8)&N@vW|{TPrsh);+k(3i3_>nNz}dbG6TVgs zNXLkH6Qt_VEXxFslO?6&JRfxGAb6~)Or@?cVoZNji^K6ngva_Pvl;T>kExrH2nKswfi~*v~OJsp4DTbLkEt{{ndGgR z&{Zbfay!u{_n>v80hdbF|C zl;%MK1v@fG_w3g7c6QO#zq-zk=D+mijvcB@FU&n@LhA?w_KK|~KFxB7tis}w=k<8C z%Zic_waMm4&hgYzh;x~!~cW<%G%0Z-plg66=k7w3G3?M`aPqI(53vunAD3k zA&z2}j5jDSG$Ca7ky4u>-BZ<`y`0dV#kIqBCoe(<&By3W)&VEEeR!(E{)p%J;=QIf zD*mO&6Gh)IVtRWsB|_yzL*_g>isQ#lwkelJv(Di)RA6Rf-4oW2QM+6oQbfe%cCt+) zVSlWb*l!??Y7Eo4=vQzoBC$(#Q}{2R!Xfn{U;q>;B=UunTgUaVABF44$87&j>)8|9 zXW)DhK$ufwigEA(S?#W^SWA$oE<{q$=&H64^~%OZ-piV8BzQ_KnY<( zX;`t6Jp!xd%hhoVl4UJI$kthfwFo3UsX6B+{e+Wl1YW+Iq=q(?(iRCzH_(78!l)r) zG;k-0*-=)QNbHt~Eg67?xx$9-i=z!=NXVBoa+1a-B=;@S*kkFBRwQ%hSc)g7z&zPw zif>LD^6!tG0&}OoMIiZxLl$$g5<0n#SJ|_>4q@r5<|vdW--5~?5Y?k|hOX0Le&ArG z`PexuDT;<+I6k)@^S$d&RPsT-yyb)Z2}$Cz`=8MphtpAtMdC7WMiq+Tm4mU1FNk#u z8j&iMsjX2l<}W-;de z#Lbx@l%BC>U?e&v@>^6ZiT#{xd*O4sojZrCFT$N)v)O-n?oCq7_cvKIu$Rl(C12i5 zHg57cfA5)6Jl#vyU*&{b+)v&Q$}Vwlv6yF1JDl;K#e?K?Z}yFrs^{QNLjBE?zC%M! zH~E_JMM?lQf@ch(?-J6#C?paV`)H`eGK*t2!`y|$W|z2y`BQZLV3x%zORnqGC{9#v z;H0-LB`zF3+ABQ2dlXdkN7$jSY}jHf<)B0Xjy z)}Q_f>9M%i3zpEF+QFpe<^r;3N%cbu#6sqF>H{9N4-|$swixHG2=?HOn_kp$mUt5c z4%v1os;!TgI^F_ptK&Vgw(S?1B;Tj#wX{DZ7|EJTC0#4KmeY=&M%Xp7_vD#E__+qi zW8-pD&&z#B?x0_%F}8lV?5yoYTM2!jeq+n#*xa-!=7G8zBbZ#dX{+0YNPgWmVA1qt zFP(RfXAYo=39ybu#xDedptw=CAV%OVcO}64KFWyW{3z%BJT;=vq;z z-;_uIuvV-E4kl~_&*1HHbJ1$J+ytz^NpRJVqAc?!ro&X}$w?=}$4Uq4 z<;WGgAK-(GY6S<(QG7dX7Yjel*x8YTQIh5=3?qitL1)U(i-YYu)(!T4y_Wqrd2ZIQ zmh|T*YJecwuB@O#U5-!ux4w~#_Ro;d0ed()iG)(;EID+Urc+X7BEx;<3vnE%C$ zgYy@t6+zSI(hZiizLNf`1Syp1kzwz0PksM|S)f%Lj6grsJ31m>1Q8ZMREH`S-vP;A zJ8*7*i1zu7HgUeO208Ye&aO+dnB$g+cE#k6;D&@#t(S-3J9yQKiN9o!_6s)4M^c3$ zq00xFhlzXGH73{(58ybg0v!VXB8n=-O239OO_IPhD#zLn**BcznaP1v(B(;{$W@8> z#QdI3kKlezF)s;b@BT$E#39g)NYks|UQo-vd=X1c@@MJR%2~Ml`B3JwZgI~n+qr7b zPR$W7su$hb#Q8P5ScHeOUkjGKk3(ipSZNED2O+^5M>(-Dz>NdQakH?hY~1T_waL+o z@O3?kYDPi;V`)XZ3t+F(6bexg4Z2L`dWA3o_PUovG{$20d+}n|ZKc4~?E0I#M zQj6($aAIsNX8kV!5CSBv)x0LXhW4sl_|i*kU!t*StSITLx9e52Z{9@aaIyEBdXc33 zO}d>Uf3cbv|Jb=_GxLm1Cx2d~^Fy0?qd%Y&I}wjUzD8!^*b!f>vo}CmgIU8kNz8>&Q_GbYdi=^3{ zSGP*gydu;sj%ZXfY;g#@wYYoWqOq5Cj{*I_Zc-gUZ|Z~J5d5@=Q1LtX`K1B=+(VaE z_#E=aSJ$lecJmy&r!oWK?7OeA>-IgX%gB91lJ_THBzZk~k3D!YOY&^Vxu5J)*{qO~ zwr_5QW0yQC+o;9c>u(Z~r7p_>NUk_OFshRz)!CsU3Xm98m!(zL&uj2c0u~(rt0J>C zt^Jh`+`b#*-R81yRe^DC&Mk$waziypnCYRWYc6}L_p$xwZ%noMx;?3%>S)2$+=78G z;%dI+s2jV)#uKTd=>%hq+4`#UHDGF>|3$c1s{{$MlTwpY1DOrhxTDE z!Wgv=U8f8`ZNiG=f($AE-$@ph#iS{irKd#+hh@L7F>jHa{iDKwrX#ca_Oq~Z(d)Qy z%e%jtxDXu~IAwB-Jc(cZERs8Bcf6)@g-+Tz-ZHbLA@&D+3Czp1361C?cA0?N{@@`( zM>W=_;2PY^a89~4+#CJ?#{#g3?<*w^I_#5PJ*nt1#!1sxbkpUxuA8yXw|gUI2!bb? zgOt*>@6D4kz%{m~^Z?m@d+b~B1ridBH*>U$!z7yi+JXATi=m1Va5xdk2KvkMSJE04<~dA+L${eBQeh$e#x=#k>A#w?$bPH zzCZqvK=XQ4kwFq~Gg;io|9Lu*=kr(>?rAWT&KZ3M804W&E$o9we>*Sp3W_phz*<1> zK!D?}&id_ltS8^TM@!7<-@KK@jSl5$>hAM#wuyNefZwSp!2s)tL1esxHc{+vM3wK2 zrp^&WXimEJO&KEtphhEYE8@+xxoGgb;o5{d=bgl|XMIWVN3*^!)u!XMR(*vQL9DRz zD_(rWp40k<+b8q|Tu!vQK4D+Y>z_r)&^=#vn=fd~G`HOIt$OjKnlUvi$@;U-I|qY2 zVwsZ`@1*}v-nu9BfQ)b3etYV*3wuV_P$F>{dq4Nun4e(J>uK;E)vBR7`%US#y$LJB z%N01l{=iSQ;ZfTDsqo7fyB&l#e?Y`+R~AplxG9hmv|)@^e<7J(DL7M{^sLU!Q+P=* zSe=r{bJ{eoE=fL!?2G|fYg{%g_x!ip23QZ{=l^mFo|_rUT6-hsa13A zv5Ba1V$4j`p?ZAtaXd;uBN10oglfuFP-Ib;lLZ7R_U4Vhp=J;-RoMhGN&EI|c+B%a zG>EcymV{33v>4`lTFSRX)EpGxY*UfP=BTj2w1GtD#o*u9*SQa2LDt4X1ZsG_D4JGu zDUV53$5|TvtbticddrSj5vtl!Ca&2Yx&&BN#vHjj9g3N!Iukomj$36re9^S5VeEYI zu@qcqXV^MiGNq4Bc~Dt~AiPpEgeBl>gih_p8k3P!d87!KsVGG#!iq9Xo*AMwC#h5~ z4fe1IrBkiWQ-f=9AOPAqji8gD@#;#7%Z4lIl#VG0ArQM!3@-TLb>y6k}OX# zEkQ^k3N&H%Tr&&%>JR)Z|eB~K+z~Zd4SSx1g)x69`ibD2kI-p}d zjp+W_p`NI24x{X1n0EEnSP&9zY9{JMW+6PPe1js`1I8b|qZS(03}rMAtj8~GCQ#24 z5N1WaefzaHV=sP;^`NaVDw?)+ zwi@aJAc?Y4=deY_7*I7$?+gZH>9JDQ*&rPeZre)-bVOuPWBVG4^Z3(jj<${UD#w?h zdcNWmt(s2DR34(|Xt2>D@}(=!3O8ECpDo5y8WAAIjC^XzC!wmEfHD#5cJ41eGBS|l zappvReym?dEl;XTPsLvqIUrHT;F1@-&)J_jFYgO%3xJ9_BbvUKWWtI3h$fIQtJKyH z3Y~Z;0NLSMAHR^93SV4==4FTHxKK(ivkvD>^o^%rPqdU;BT!$EUC0~L`jnDV5f@{y znm~e*n1~nHMD@2iC8hFo;BZ81_cq?^H626CFaA)g25jaU<8`Sa7;To9`TKjBD*vti zaC#-Zwi1L{%$s!c!`3-n(~rp0WVS>(b$cV7So_{wGP>(J109I9-@QpDQ-|-0ikF8; zj?ywB^66A2*VH2^Jy6-krj`Fnj&e8-Bf6^k!wb<2uSDG`maUDwn%k_~-1nJtOKR3= zpsvRs)#1M<#R*_Mh1_L#Gy`;#q8cwJsgvroUh~bIBE-K|Ko?qZs-tKd`qvevL%$I^ z&ckFaFg6g>_}UeDSOwD5MoSgh$CLjz`)}@#`8|TY;UjVqHs@Qvx&ElBbO(O;Pd4a8_{F4lCUJuXT1VtF4(u_TOeKIj}_dXB`*i}TZs zxa!c?2k+kq4)@36jwhzd6x?oe3CBw=cP27n9M2WN)!#9{8OaD@ig#)EICx~O2xZ88 zCB3~oi zv`+eN)Q&yw+YwKCM{#p@|6uHm8bdSeS`;p#B&pryyM(xBQ7cSmnCf`hUFG3w zxfbn@(p@8EGbjuOq--4uA}myx(7P1zoZ*c+O7P3h*L9P8VgA!(=25pF>LcqZEwgk$ za87o--S94JX#qM744Wq+dw^E$zpeQ0?=&bm$z{b4lm@#v!z}yA+iVw3*E@Z@gOR3LbPk;xb<_p(->s+86kMYg z)-FhPmgp~~t0%ALS4LyO4)Z4qaQ>F> zhe>czimy$g&T7PG29purzGaEJ@i#kr{IKs%i=6GLbJTRw@VTrJoN>6ZDDw1UvxRJd z&9G3~s8vdeP5D`aA&I!B=l+&?M+=vP9<5Gz&3SOtjxDh}Sci(H)(BnzA-lK*Y+B)v zuzdsLY($W7ZQ$Mg~r=D6*&Lw@U@n!wLC4?r53(!Go$Lo z!_M%rOqLYQXlTB*4X}T#5d#+F@!JC9=Too+qb!tQZM>+jm zq<yN)P0EnRU5_8#fX?1E#bf){u!i?d!g*XJf3v-5ty>$JLeOAK!G$ z!qAu7H}!NrTaM82Mf>vgy04EGGb(BOyvMJ0bnHaYq2z0`G0;Y?jWMvP_`Y6SwFm>8|bU_O)g(ASbrrZ*EH9U&$mw#3CYx|j+}}4iEIqp!g|f^ z59?XOR0nM^?ys@^%d6L2zpV>}9nX8kvDZ`fuMW{DfmTe6CM=8V!x5C}-QXUImcLMPPyUnGZJ8s{*$1ZYu37+9MP*Uu7(^zXUhdIB0%|}zd zaXj{m`g4&-8xOoWr-qK7+%@I?-?WC;2qnX;1jw>Lp3h#ar?n^n>B?eYiKS}rU1CG1;=sipR{D0hYxY!r(rB!GnB#J|@d>6&XChgm4!{6DF|!f5Qs= zWKHp)&F_``<{YRkC|n|X%*_&T7MIH5DQ=iJjepsdyjP&gP-+=<*WmscMRg+@{Sd5r zE{!nVFAGtr-hR>^?2O{M!>g{pue)zU*B$IHZ(wbq5sf?&q+ZtXF@)3khWiZn;AaNX z`q+U^ktB2n%&8FM(IJhGc&rA2^i~dH*lCU7jN`AqbZ+9HC->(<>F4vWnCImk>-s)( z|2g$`yyZ5we@@q-KJ=JjFFS6Kx3aA3DKYnY-}Q6Lu}9n`$j5-4*n^mdJQxjS^B74r zPV_*j>-tuV@~5=QbWzju>ly<(E88ME4#0R;K`2lX-Vv2}_vaqUYs~h7-xZJyhbtk) zdmU|UNU+?i_^;Djz$1%D7U*UR{PF1JkM7jjJaK|dl)DHRdPtudSAlM^WpV$*+URuA|mhJ{4Y_CX#*@7 z07T#$^xc9>I~T!6(Ws2-e8D;e@Xx$Rl0z114fLZFeH3(DZcoQlW}lxAGUMCj=K`-k zUSjjYt^E}9@?NF(KTZMlq=7PG8DN+Q53|jh^Tz~;1apU#1P=serlCrUQ`@1DXTfAN_kwK8FD)Rj;uN5ony9#=7$Ho^IC2}Ac;3)DsrdHvOD`L z;yRzPhdMa=4QTK5cIdBMipXreV=g?#u6vdwocYbWx`91fsAFGt&hOdHKdF{ol=C~G znwsvz0+ut}2CHmDp%!e?>Ppld7f1xvP?+S|L+i&jE~6g)F=P4_1C}-bPB+3Ll%LJXehzi6|Z;Y*XGp0r>R4imm%_M6J^_3KdKQXN6Zd7 z%sbd9mbl=g{B|ScBDYOtBR5&33$=JXO(wQVAt2Z2hlEp|@ZlOs8`A9)5ZWv6V=T8| ziCbz%2%J$;Y%Tb0aO;)JX1Qz$Sv?W&3DPXD6Ob-JYPZjN8o=cgb&0jI-pOgnIjM%$ zP9Fa@QYK40{?oVh<4@~X!tOml^s@N(gdVsRDI>erLToqKgwEw|LOl*hBY>H8WB7`L z7q}Hr7OLWq*ugcjW^qkt%|XY$bE-p;EE+hf(A!i2*3T$#MP=7zJq4R{1 z0BqM^u_ZVHn8dn#{jkLG{5)MiXs(Li=Ajt%#q~H=v~->>ix)HEPc$I&{xQeV!8$_f zdk1kkF%k@jx{wg;44~qz;8zo8i&#fmoI`v}3BXd3TO23QTDgO*h_-CFbG;6(nkH~- zXp`{6)S3x0mf~e{Luv#3Fy3df%dp4sQqQPV?T7536yW-h@z0-s+qrN*XQ4+Hw=W6u zy$@@T?nCR3SFpma?o~T!tdkap#5$JiDXo23*Lu_bFg)k$x8Igv$Ywo8Ue(I@1sRG< zJ*UGh8jf9-BFvb5xy}2!+dl8HJ^5#+Jpau?<&S%T&2^^HRtTvQW?m2`J+as~V!|@^ zJc+QFQ3>3~aeH45=2rWMPbgBQ_J z!wN;NL@2QI_0wA$D=;(HTh{q=gT&){-ED0D ze7dk}z7wCBIog%=BFoUvrxDh7lO;?&7Il`|6>MDbOgX3XueTuP732JR{q%7z zWloBBu6u5GU*XgFRrIt3)e*g2Kd!hd#c_mgQOgm{U4hu_pB1-dn@-?17l2qS(eeE9 zD`4;-5(JP@G`JAT|Iwd*IV(RSRw8R~HJy7N%x{TdMM7fz%^iJU0Ht*x`O!mZGI$P= zik!i+1estsO!wR>8;U4&(3U~iFD6Roxqu!peuAhM+>`Su2z>sc_Rhbe>yTmZq=}vk zuIFT1^;UsB-s$hjFpek zz&WRP#~GW8y=c#hZ`L2{lFMx!@ASNW4u)CrMq4}OoZoR>_u4i*8&X4JG)$**Y^}4SNUvXA?ydU~Y99wLX9G$(xv#+&J zI(Pac4kpH%J$8wY%Q^WeJoLRDi0UH3@P_jIPYuM` zRIuT=@cNcZ9&Fp9!^)AXScS%)DhJQsub*^+1e9b@L7aeDi36$VM6mWx)$G&LyAh%} z0F1_Q0+4iP5zbf_l;> zWUC0lafS435rm4M_SpJy-_Z7xd=q*IVtqvSHeu|QSTpom3*_YYn><|WnQUDfa;?fW z_@ylrWiETSudFVSu#(qU_g*{Lo6gO!GGC(XIZy5ghR|pmz**wHO)$qsh%rrQ`mf~68&TwgyXT#Eay;Y< zukVF`8A){!X zzxT`LA&IFcgPY1XW#g#FVg^=_6>v(38+)vw5i?@L#Vh_fG2@kgUJLY>VrI&iUdS2D zbIF-5c_C;T9F}t4M2WPmJ6@`ei*T-uy_8Y>|3cD`6-&?%+_!Z(1&zTGG_to7x7}jp zuLO-7deKelkD%EkJ}UH@=yOr?Oo2AvEs$;fGbz)OEP*`hyBF$4us>DK-1Da|d;)?{ zT(9yIIUV|va{XGaMx}1n`uauZl+EjOkn;zgA)$_9ruhr!nh{hI{MGFV>j9_m3Y&U} zv0$U?kLP>XI~Qm#`~N`Wm1?0w$_X@PUSz&or|jg_^^kd*XZ(=p`wQc0%$8@i)g}9G zw$-ZQJT!5qaIb1a{!0uA#^%(HJ2!jKpBT?r_%A;3k zAKHW{R=CAsYe@+{b#h;chk>XVQ4<5<^2gW8bjBs!(>_vO&09cGmjPu1W#x`}?`e}Y z`CZL>rVZp|zh>S*a)p48X-~eY@_n4mJL-UEqN}M-mHy0KjVbxx>>Y8hTzV!?Rp`6g z=N*&(uL$Nt=>0ubDGEMh^JSHeI=EXdBb&FEba#6nS*566ueBw*|0&`8SB`ISr)^RG zkaRwU!6`Q~T$fq9r1OkznZBiS9Q{x_|FZ@u;}_}vmEW85{KTu=a^Ob{(wlVt3xo6@ zNaqP=jK+QHYwT^i1v4&BGDC4&q~8_KPZ#&EEz zzO2i+E^92`YVN#7)}Op!-C$+b3)Wu+Y0t+_ReGap`K|AB zlbob~8HF(T*D^m3>AA>v!*@mgKO2QO0#aCj_?qA_tv?aro8Zq;J5)f{!TPoJu-0h* z`R4V{N`1e+V|1PeA_BCF@h8=Fwh>u?K>m}FIVh9-jp+#zLVfDu8JarY_*eiF82Pta zIH-x8<{Q#(^3Q+h?!$yCKHf=FznJ@v=Ry-Zj$->oVVRehSO}_?F%Uvno*CY)o*V zyH0?GvRmJBehM*H!bE~;eM%PpJbzE@T&iiF(ECus`GTB@d8MINz#Fa=I9E$V=KP|y zTFKV)oAw0v{Rj3(!{?6|3TRM0^Q9F8YA}+c1VN~%BAoIE#SPk{c_vWe$KMNDE0<6z z%jMGlN!f*9vpgs6D~SZ?_Inr0sLIKl7tctycUC(*N_hWs=jIKPvhl<5(&H{&+n5sP zTYK5O!&T>NXGXoGc!~EqAYiTz&p3fAO}^*2;e#Icr|s8RxjxRTp=s9FU3cym%`1-& zJl@n7&K>iKa|fAc9_uL*$>&1eHg&CJ4UJ}Pk7~ba?$6wBDnmTWdzP`pQsI->v8Lq{{uLGek36@e{9o#D&4xaZ%{Q_5IH91a;E>6gs-<%_ zVqke*r+J^oz(0SHv3#P#0R_r~mXDYK%G`Af?g!8tTW^i$29--(+*6hhT(@}$~%}O{_1Pi?e{M{zO1`$PW_W8OGmbp+kL>QK^%4_@IV(R3bBNLmG+x? zzCah0X+%&@ffRWb*RtQg^BUcv??Ge+U<+_zAPG?Hylu_#sHR#l)`lSG`RD;C;;5mu ze2~gc7^YfqG<|@k-_;MmR0s#@7N;M|>m2;>R64ZO2{AxRE%-X)6PM_z(Jy6|;ormVb~{&)nVEhEv@QJm-04=~>Qk z@6Q7?&EJF=87_R9$bIBPHQUQAJ_Q-N%e8qzd(YAue;XU$xeE*rf|UA%J)OL3Swh|V zQmFn`|GeR#NU++sp}`4_YqD0Po=py#VsjUv?h>urke#ltkD_0^g|=k{z@%7KbxkZt zuGXN_>!;UV$IvvPdb(f_#D#8jL8+F)oRp*0fUH|IF&tmL-#n6Qx$el0Z+Qe(GW zUw+!gQ1KT~?{WGVq@5mbuRfjJP^E(!18p46vQdtJ{yzX6QV4qcbhv`KNr%+c=zP}~ z)5Ll(dCgZTU0r{ut(qyAtoCn881{&%>OA6{n^FM!aN-DF8UKXI18b@>UJo?5{(ArL zPCq!G@3%Nl6JgnqbL3#?H*%Y!883G317c<{%t1WuJBOXQK_cbX*!tD(th?&IXP0VN z+@E9k>-~G^*#zRbz2pySZ;*@?sm72i+7X@_oxJ*&*3DG0hqDBeE98rUNwt>>^~uDl z;J2uOhomo1&zCYWiqqw7LC?St|L6>RwVaTpD3KYW3(~%A2`DSu2Gyy0coTsst|#2` z7*rvkQ#mT6fh70l4k5O?do3z4JI>AClBBdff0LsFGG25ZpkiEu(}W(ksRdx?tWfPL}j&W zBx;9;>S@60KvX}`fG9zeNRm)Db<7H{DdQ|9h@Ynw2XzXgt-Z6l`iVK@Q46vP zR});fL4DAaLh|50r+_+2)4UEW(N5i1Dlo7Uvv^!mhzex$Xcf2aD=;;GRyX9&Dki6C z9ATpV&{jqQdBz}~FiCesHc$rP0G>j7)CU#Q08 zctpVq-efJ5wE&*ZmzLPi4|Ot?#wMXKu_-`#pCb&WG4-b7M1@-=z6;JFHLLH2Dn~J4 zQKb&vdGk$iiujT=&!0>T@HSYN0>a|lSRclFD*kzfegiJe;;UmTl#4s=p#ZE15~yiA$VG&@e?xP8+S(irku zeCvFV_cxVeYkyu3tk>Tw%F;H4;2X;>D6UfgUTcE2ko@-Y#Pt6#Po#w%1lXdu72MECs!x-Fm|OK8ooyPkepZuMeb=GhZ)um5!Dk|P+PUd)PKn=#_8${<9Aq-HI2Og4rN^o!n(G?0R&Otu4_<4xe6i&aKeLAW zu4mS8LkAr_Tf41L{^!5b{jYvns_1)lY;0W4%p6BC*!cHvzfQ~>RTj7gnmRf11#ixu zuUPh@o%?Y{R8eyTBmOo1Jh=g$M4Ey*#qTLi3nVOpBFg>_|edu8z1fC!uuUxjdH8 zVblv#Xs*kW(BLbMB(!%N3+OiZY?e@$e+ozVG>^}usO-CZW{%LL@Bx#I8);}P)A88m z2$N*~C`TxtQ&+qej!RAYm}fuP^u;gA5KdLB#n#qy zE=8}u+qAt6wh&BV_;^96{73riigbLg!7{PKPcT?EB010Hhr?o#BNW(^Xv-5n1oXH! z*!AXdte&!0p5TXHXs(Qt{S-fZNmJ#c3~?ALn<`TN`ZPm4ZK*t^BK`gH!&8-Y>N*xo zfEX!I`7iGuhp*tsGC8zdx(TxyD;tqMMq|Kc6CmQOln}PNd0&wp|BTOOu?gSvvG5Kl z8q-^oH}z6rXbknU@IDcu+*eJnMDzl-$ByD%icz9jK{chT`@-zvOiI79%7fk?h2RthnRVo^2Y4CbsZ=a(iM>6(<;2}hgB-h?wW9qNDv?%50RT;B?IC8Tq_qUATM z4~*45)}}Abc-2@M-mbPXV`0XJ*od|)VvYow2j(uPFPE&QloxYgy;B1=pF`u?H3V{L-mjK*?@`R(93&T1b{-Pt0OC1Na#QUY*^u6E&#roK3qyi zKitFG8Hc-!oeeX*jLzhs2)R|F)na8HnBnmo48FCIVJ^i>Zceg9N&xJy=w}Ilecf+- zM^wM`>RlZSr!~J40CA=!6EtGfHa!Yv5 z%7Z5}Lc4EwBy)!|lC>EHP4z5ink-w1=Ad9JHH@z<{w1C!2$(EgnVod{0DA}hRF)3q zu8#>;(!F+Rq|<_x(#-jnk~%AG&g&9n-11wbXE&i8dM-Rfopgq;_4%59IjNi8kf1X+D7rHI_<%G|A`2l3*<1F|fxrY)Ma+q~=~k z1s@rB@vRHhcHg08sbW^|O4hN(=wpMaZG2_|ZrU+f{+3&nfCVD7@sbc*hnT<$%Lz^< z=+5a&HkwV;<43uTlxSH~s`QeTSY5__FL%LCE}g?E*X-&|Bzkf-*AWW=Eb9E;lKDK@ zDe;Zg>iF!ar{Fqy#AL0={7l;dvkRuNR7X(M75c}cQzNfrH%Azq$;9zRk<*fjVw_$YOfiW)sGn)IK8=nQ-@qeQ4(9qV*)^ch8JV_mbDDRV}`whbxD_C+m2Qm4kP z?Go2!+mvUf?gggoHpaRp?59X|I|BHG8pJsXri<<$!)p^_xmR93jc zkz)3kSIerma#*4>C3SHm(_7en!9h;@cnZ2(?wc+Kr9PfJerm{`C_{Vm7%gbf_TF`D z{Mygv@Aqe$`%A~A^R&mHwuftJK`16Q8Ax$TuqSSowEH!~ei|Ep-J43ke@*Eh*KMWe zZzuF8ZTc{ye|_`8f{!QpYY>~)Gl6+I|4zzQIA zer90dmB7cTdL{4_&wMiiKb2c7vdT`nQik#mlGZqJ)K{S*YxPyAyogXanM%x=qAN`* zq7MyZ1zKfgmHihBnPsBtkJX{L=_w0YGDsD{Hv6wEWcZyj(-)KQ>srV$1cx=;Eadd< zUdNh+ycmPY>zpj)7=uK7a13G%4r8!c$gu`v3^ogyg&J_$eFHfQl((lZwdVHA0(G?5 zk6OrSUtAXQHJ}12h!x7vM=fM+CRz@O;KI$rOIgU}H8`-42N|QnK$3J}6`}rvqc@buJGEJIaiTfl0^51Q6XhXG!5~I05ApHN4zWSBlyz-lG zz;8~aAz#udAn2u+$CbKK2qV1hRXWILfBz=sLizCsKH-ip^Wsha@mPQ2ePapri{APp zY?3&s`(^Lqs{qxJ>uv&JoU-=i1sNRoj$8Yk?FFsH(fooojq!rv-P_@0k{*eX!Z1-aw1oUgKNS$Mr8bSgXVJJXon|QO1gnkK2geU8FC8UV`3z z&6R#GX2Ye}zhGV16C>m5>Ao>Gy<6AupI)kzSBmx1Zqxf9CZI|5#I1WHWbv3-lu$;x z2;A~!-dsNhLIJoAzr5Cm`b=Fu(o+}MPPsX*39M3L5g;azCbvIdf4c4@W}!wsE2!J@ zosz9`iNp9RG*9K!#%|xqa3-9pL)DEYIPgNQlB*wQ{AC~>Iq|)ZtMfwwP4H`yt{!*a zC6FD_?zD@(PVx4&2wuQR(28&d92((eh^3E;`a~4GDph$wwh?@33G6aSE4zhgbIR9IiPix04N|C!fZA%0I_xy#pVx+Wkw- zniHL}2v)rI*Px>AU_J>nHK;x`eusl!F0!-`UJ6#=?xLE7c1QXe0>~xhRG)!$GT7$g z*Pj2|OcFR$tSD@F0fnP(-r1qcxWwBD4Glx|y1sr)Im`8Z*^9zK!kiarXXs2?gk1wd zSrBhlhq|p=T-uXIeH~2y;iNSuj3J@&{3?&vJw*KZGAB&eTInE2SR>K9$84g8L0PZt zVlcQw8yU*bUTn6rB&6PAjS$D25X7(S1zg5k5DI`pb5$Q3biBINNBww#QdE%_L)}@1 zdWMYq=L4&0Ump^3K5^>i(oKxmvYGSU8`l7mK|_ui@XjC|FKnkiqiC^xMiFBn$6Q^d z_yw;Ky9{{K;3yRa3(E35HrNc7vaqLjK+9EKCr%H&!rTDtG}^CaTUQN>gJ_lP0e2#? z%d^32M#OE54CVvoEe@NT`v}%{q%CJSjWa#(M3zGxj_FztVb>H1Sr8%Iga#MB6E0nh zXY9le-(UW4`Emm3Wd5=*B5jiik+LmZ|32*R^W%6M@l+e_XzR4bb3?GJ3{ysR{su#r zMRCs|q`3L=E;OLfSR7yPc&mjmz=jF3fU%@jJS1=})+UQ0u8(u%eN&D!NQUlH>f}W8 zkN6s4?`7cWynFQ`IxQrLfS2iVg*Vywfc02R=q794071crE&~8|jqkgYGjS2}cLL4i zGWi8^4n)`cuXQZlmEd^=$NP+K0RKAm#E8=&PkIMItgfjF(v}Y*1V~w#tzrBq>W}YvHi}g^pLjN?A#-(Pq%{=l&5;TJ&tfEmy8P$^75uJi!*cr{ zlL(XBrjg}O$rWfz@^0Gu&9zIy7FN0@WC)jwv+5HYSfKHo>8Ko+xUb}u^f_M&$a_lb zm>&pVeSClFw}Eq!0=^oO+x;7YFaWNg1^aULm3zP)qy)wJ7|Kc`sIx(#rKQ*|++-T- zWZOQ1x^;gwzT*5v1NYabvUKGL5pdD1kc;oW-{J6aDjLXto((3maZaYqK0N4?yS#$Y}$si}5PF&{pOQ%VN4 z>02oor?La12QtKBkNs}L9~&%4&N!o)&i@bf)hD#Re?0Rp?DlVA-o2FC$K&?2efPgn z?>ohMzs$h2`2Z!Fr;ECrzH{aBjLUi+C-23tBFfL2>VZRG;54zo4c{@bJkAYbflBFO)k$ z{DXhAKCXJ^#p@D%XddfdyiAh?)u$<8e+bpB>ODRmL4&|qSYzwQSseUz-Wkg*5UJwj zHZ=|vvPtX&e6=kI%FQSYTSiPg-lC;(g?<^(hY3+T0PM(g$Mw)S>JcBtD<>DqI*&2$ zjdh)x3oOy_PqQ+sMY6X3z((OaY{0oSsSI8Z+rbrY<-svKBn?U>j*e z60{O4VvJL1+>vjrr>wM<#&qI+_Ny;e0y%qYHE!=qRV#&Ty)FxNg&xzap;Qog@`f>#}V?wkO_kbCI4J5$ zTlIcALxf*dW21iEoBmfpl3d5HKZZa;#S1yOlT6*YG*K&vkrlAjGGZH$hc+Y0(1lckPs+PQv!)&+P! zk;Jkk#7WW>Yd!i zwb(=0e+5(IiCz|jcths9a9W{+i*yrH)lX~M#&8@?-f8DT5j*vIcFz9mg+ab_+E_yd}4>>#H7@7>_XMTWoxS3mLigFPpCm~JhbZ&TQR*Hs*76= zN2YHl>cEV_l~zU*o)=-JrxLdHy)G0vI+b8deqQjJ3j#>f@cF)~|9o_8bkXpk%a6zL zCv0K4el7giupxDnDW+vd;>nSlQP~&jg#*+_MH39R=EC>Uye`C$$>+h{<$Oz+AgXoy zB!SgZ-puU1o|tlD9+UAJ_5F528=*B}oTGOvp1JZecK5 ztL=7=#X_jSIAoYfel6UD%=HdPRTknCJ6&%a<~i^QO9-Vk}wFCmBmO5Xd41;$ih$JZ=aw)MJwtIF1I~{ z!97=fdM=A|G>%x@^VFwr!s3>f42IU3FI_?@)I- zl~Rv`q&;^m2zBgI1@-U4i+HcV!`O}F2uj$JM9+7ih!UHjq<{@Mzkj%rtjcnZT^G18 zNp&UL`5~ip`6HbyzGfwCFv0PsO3}Ll0UReS7qYDRbQW=#8Sl$V-! zoaIcQSkrypnKsvyRMjzWCMyTB|6%jxEy*m#)aBi^x%a6P0f3RhF1W?+C+LDFE!bu_ zeWHT7T96wGravAim~q|Ub zlh*709UnJd`H5EM)0x$lg1NAP{hf;@yd;q%9jJ< zwNh2kHODk9((E#$Qh=nv&S*$JKd^eEEm@?B+OJxx1#g=~cb&c+r+vu=db8TDg1d z_wE5W<)3^edw+5N!Pcl{j&{JJ;t1$>ht;i=ObF8sd} z_I`7+V8Agh4|+CRh!e?CBq@k$2Fu?RND>8TG$3l}?y_Q#>sbAgh8$v9ZaT|#Vn;OL zeqHKzmWT9TNm`XRA;c#@*Z(@+Fh=?h&+m^P^LSH#^m6gJ{)9dRTW|d^A?k!0Z=xX! zz$Lm`nj5VgOwX-KNv)TX2oXKKM*5GOYRq4K()HPL)tmmev;Jd@r0lOhef&}VUVHjF z(tl;q`YnjtbsRFyTF5M>`HY#Jlv&SW-d`)Y^i1ac(z9KOY>HPgD?>=_^PQH~(IvgH8& zJJQZ?PL+WOB_)y;U+*RNs%EWs_m4PwT28+KGtOex1CIugLTD_UulH7XUM?5XuC791 zZ_-}Qt zseHz;Z?BR{z!`Cu_FZR+WkoNI#Bm^rQPzv%$Z%u1HF6ctOpl4IG96Lg1!~xh2+F_J zWk0@6O{oUrH*d=2A+yL(-+1xO1jH{Nxv?qk96@eYDS7vR3RB)g)~6bHrANw-Q+(|2mu_h3auvgKp)BoRhmlt1-`G`$t~C)XTujio1OUXI8iyL1e zixi}D{w;fb4GY^CTDiFvuJkzB9;q&tb{0fz!3PVbrZwgw@0Cndi7nhq1ZXTr}llIeVNCGNkJXRS`N#=_uSK2e*R8~fy%X&JWIpuYrFjZ{I zSpbiiObffd%U)WSON4b4UvKWug=4gDcVcrKOpr6WeY|dtfj&xlww4HSg2@5Bb)vHA z>5_T6(tTRz7RrZkKncZ`ZLPGlEctyBGb}j-i$J4KugF@F8HF{EcZKKilgss#vhn-y*o%e;1}OjS)EkQipFFOR+C^x7!2r5mKplBmac+xW*p5W*dHb#+cuviwABy64z zB-ad|4-kvP42DS~2Fx1yYiJX3N%p61!l}8Vff0ig9FRq%L%1>?KvX+W(bH0}5TWb? z1UPcS1IiWgCMRAm2P~En#g}jkhsI;l1tDThPC{g_<0Mnixg>tTW|&t_uUyg0D^kog zN$uB@59*W8kq(}PNVP)P6?QCB%fu)wcy>A+cpE`&CP`YB{aGKh3|Sd+>Fy2&3rnGG z*+!;UOxdp8l}9)N#XGVfk#;M`_1>^t+tXO*DpYg{NsS7vG2c04%F5wOs6-mAJS1As zkNX+Mfz1%jvOTb^C}}cheKny#{@$)aVSVh73hU6AV;Kk7932I%(PK=q_VZqol>In7rk|Ii}HK!RTM3NMmV(G%1bD>!QRr0$`gxX2f=o_?_}=< zibSNLibX1_;pUHTgzS7n4Mf-;QMzZ2Pd_~oy%=?Lo5ulEL$TZM=uJW=cy5h8WJ+{4Qu|X({yqD!%G3b-JGh31#uL`Bwf=k ztOjf~9$_b3O%`(T-{755=`eV8IfXTh-_$9#DzsFA<)to1I=MZvK$j0u6|X7BIpPk{ zU9i|}YN0X5Y_DD{_UD>fVBu1bB%X4d%CykQA2QlY}muPz)42Nq-+g_R9p zlTixej*xU@HC!=9&o@aGWJw?s_@TX`0y(wd*7Bp2*ZeW{L>#N2eUg6CM{+;LRBfm8 zu0m&Co=(Ha3u(t^b-C|lLbdk=ff>vKShM;OROy7hnYlN?sf!XHql)POAxo4Tt#L_Q z5g<5U3X-roBvt8na_GY|lXIB_ddlTa>XL0j@ad8h{ZvsxCE5qR#QDaTOqMkgwz>Rr z-F>j36e(2kQ$YIWF=_GV;C(8IpQItiz0NzFy~u^os;mJFU_52q(O)sWjF>aaWEA%6 z&-&%-&_mvHD;2@^)mgCkF|}oI(Z9y^{R!zwbwCxaz=7= z%#z&6#DA0MUpBnlOeh^DjC(5uB1Q(=j#k}9++{>hv6fkm&}rI{uwp+9E?X3nNF9gT0S-i8hEk-d86a0)u-*$W2erYw~5PkcjgRzc^ zLl=`FwWxngX=I&Gq98N}g;k4+NZvR1#6ma^5dbMUlxUNdz~DSWH$*xLE_#e=-zan$ zNIP<1_BP}EEZlHs3PsRqgqZeR?EpAxbtcRxkhNr{DXE}}OD$zWMc?!`Xhi*>xgsa6 zbIlSt<6JwxRFoH!rKc*KFM0XMv2ed+%gf*@_|jfp6QW!yZPwKIs0DKhead#mWoyi2 z(`{1KhE=E(Esp+t{a7X^$&rFpYtH#Zo<#J*+>ABa{uC#ftf`B;cPiC5Et+u=NK@4B zkRw>+jW!_SQSWUCmQfs!aJcjDrYqWp&{-(4-QY*NBYQ{+l@USdi51gt@}ur*f_<&9 znIqVHL6BZxb2>p(PB0~lZ79%Js(?8yF%VKAs=%7k^dc@yY7Q3ogbOo1%mWu@I^ES_ z@6cnB^}OJ*YOoiqAXXU>Pa%862$U+vF{}jf;wsymedD{!Hmi<wL@FY>`sm+~4jLd72iFT+kL& z%TqSt7+WtI8($dOxxRexJvr-EH17TgjMV+-p|OU`Y@-NAUfdAqSLKAK(!|h+avd!- zd8TyicmkYJMpr2{`Z&jDVG0qt)+?@ehpRl7$iGOq0G%tKK)uelFPuy{HtGu}^UmnB z3(*eZU1)axH+)zGQgj}24y!7LStGB_E;fhm8bu&W z7>446Qr6;efu|f#(6T?+2Xc^e9HTYe>Jv*zGfy^)`v`YFs5p!UCFl{Inh3!lS%i~VB?4VMbukQ?f{g=Y$-4OvXAR2fY`&SqNl)2 zAkbE21a&NW%GOTTxt7@zfe|eo#{w6lCI44S> zp#Vp?4+v5~0a9)rm$^)as3<%7x!<&9W33ZO6p8#7C)4+t%gWFcP z=5l6RfR4h}t~lSKV{yY?Ts&5W0)ChBno3YuT*}B1F+a384l{=HE zl%5iWvZCLo-!qvyst~?xV^7S6;qjb$~V%bL{biwDIT2A zNmr})m8lzR9eMYJGSv=ylqt5IY#qv!6f!Z!I0TeAM495{;pg2~rY!cBh<%cXsy%#Y z=rWp&A0<=$5LXM8AJWjim@UDaUGMt*6LR*WL=!^uoJMJRU?Vk0fMyqaiPt5)U>rr> zKTa5&j5A%7D=xb*JURh#>l|;Qw-;5wP9eAOlwrR(>0$A+u#1^uVkv_zP5y<7pVt@p zRmIOqG!D^OIlrD${G4ahT>W^44#?WKGY7sZe63<58@{Ug)4s2Yh)l{}IH(dAm6GV9 zM-LOQERGcZj9RJUr5OtBg@Xl8g-Jg1qq-v_ea%$ zw^D5K>f&s!POhR?cV^DNo`1!$nitDaXe#ItBdi;|g@W6BWbK~3H#apEbWJOnePo}4 zLc@i|z!e(dBxAHc6Q`=O{9|P4rEg zrvg1%XgU;$u}q_bqd%pEdLBVhjFohwBN@7BeXY zEF4M!c+mBthNgRImM&K8s697X@s6g3a%|!aje~`0-b$0hyRb?DOp;#KZt0;F z$Kgxnb3RZ*xn3TdJ7!fwjfK+|U(6iaWAme)>qmRAAF>I`3a>|(7Ai3#=RDSatbjro z?ACq-hCDd&&ahTDXSNAbWVX?5i^UHGvu^O3c1PaFu596mx+zo1UB%)PlP01Hn?x4E zr%4yROX}4ldFn{IG>MeStkT6@gL+NL-PGYQk^_V}qGt=umSLYTryR@Dvw7a4 zGkym)i4Ug}tY;VP+Kgr|!2{Gwo zhwlr-r0M!k#iXC7Y!8R8%8{bjH6-0+p!mIP!sy!asF|R2?R&9lGBF{A)Wfj(THTxQ zlf0y)QH!U_kHx6Pq$R8Hk(9Sr>lbpEYQmdRsp0YW$|9(UU>_Yk{V7d*3Q0dt)9#gT zCmg;#B>m+MU)l4|4@h@Sdw2(y0Ae|O6QPX5S1w?I9`~qa)3j+CW2H9ObA^bX>(yLB z#HX~nIyo=m*35$Kg^1-eB~nl!;-S?E7RNB(ixC@h-M(7)T(_n=2>~){om|z52unDm z=*6w6)57&rZq0pmzGajoMl4xF+H#Ca!FdH+EyY0WIfTw7py(jl-Z(f(FcmtP(zSp1 z{zdhfQ?QB2(O$5flVYaAEzOii!kCZx>=d&Nj9l>2pq;sx>4{3JRCP2+D}l2K9c7HI zF2EH~`6VE0Z%)FlN&KvYy7*R8$4j+-90Bdr-l^CZ)|0$CB3KI%zFhi*h}Y~!SVmF{6TpR5>O*#8=g~E) z@G#*$H;TDiL5cC6ey@6|;0riKjd6;qp={At-YY}pNaFujz>o>X%{j)(4;?KzA&cCdg zt%6(mkfl))WX64MvNVb+`E#=p+*FmSvbb3Kkc^MMI9}4$rZ3G{nOd0h%ZITnwJM6a z&gA#iqGU~E32Qpvm!yxRxVSIKSdSErw*?vN@pdf8SdXMDwFRk?bKzU3Tf9C?a#A@? z+ZWzJ`!c}+5ZhHOuY@64P>RmihC#BQ`FAz%SdYw%AAlZ+JmoJ{M0ti(uf2#Mv3QnFUDC!`a%lE-Kkk|ax2C~i$oT^~F3 znRcBwTpzLNGYexOncE@1TjW=YD(fzpLD5rHj#(NJ(Ef&p#8R##;uMtACBH8?XUV)R zS7s;2a~kn=vO;A_;y6@VAEG*DUK^gfRGu=N{MUPwUuSL{A@0^apT(eV7*k3@!%%*-NW>%_3wedt>Th(X#A?Md7B>Y zzg)P4$jxG&Tf4{L9)er(CK-1!4>|}!4tI?8>fyqKs166yQ2(2E_ghxng!&`0J^=kT zvWc1yqdXy$-Fkg{cW#jLK3-543jaHF{r%IF#@MWYJg7){sXD9O$vP`?ODRK3pONST z#p!X_bnK{9pd^;orYI`|$IRfBpY{`L92G zcXsZ73QODneRuZr4}bXX-yi?`Ki(^d`R?ET_218a`uXwk58wUymp}jLp96cR!pVwn zf0qXL>zR2yGk^W(zh3?GFQ0s7PUc4n{nM_3305}dJ$Tp0zpareDT(U&l#v;8D)mx- z3nNp^C2b_W+{%mv9)qIA@nd8f`3g2>l*=+uqzzy18<`n7VPwk3Iomff889sBZgd|S znQLbaM*PsNUzyY^lln|1bvn63eTpb4$^MU(T=M&GF!0JTUOC2Ra*R{q+Zk?yvrJ)K zJT2+1tk_cV+VVqjePAE%g1-fiRThVOtY8juDcwpqP@%sJaB|$;%B7us1*<7PoCU*v zAE1fx#>)>W9N)OfMR&u;7FZa54G+GPUKtN{y?bk#d|i@EdETM1g*w?6Geshmlx{wphk-#D2o*efmb2rxIcBB?YQ04#*+lG+M@!< z(w>!O5ba?JG_|LVNlw!hLsK54(#U7sAm`xTwROvKr43cBTj0Dw52$?`3zGE!40WAr z0&TlLStUoijir4&m_sfbySgD2p+X>M-P}Vhd`GvO-;aapCyuskQ*nXJGcL{Aq&GFs zc+8I%bCW!m6_mf$7PTUEwSWk5S=43cLr3F--l;VSNJ;7qfLa9MP4l~rxz-*fL!!T+ zZ%`n7YR~qkT1&Y#)og_*A12y&hmF`jyXZChb2!(7CBOXP@~0Pbv!2SNxwHu-38>N! zj*7681TFjo1i$!Gf;6`fBCZ|;5`@A4LCTUB?7cmMEx|BXrRaVkG&Q24Lg3p$boG(< zi7Z~iX9@%(p$Bj8`hE6BA?@AnL*iZMJm_ns`^NOsQAz@4Km=Mcl+?!-fvnLA9+CAx z`&8kj_&YdTX&w_;QR$oY$=49i@}qJy`%sWH)!hZC?My&0vK6~cM6f_O6A*-{6J!_P z6U=Z4o-BBQ@ObhQ#Z62waVPZy$ukfD1MDN9H;utp6c|Zs4ERAwXbjGu@LnLyBU!}& zxrA|K4>kjij{a*5;mFJN6}rs)3hT7r+iq!N{pJ<`taUlXVJ6x*T3mazE-pN{%s<|X z%)g2qRdW)qX{CAlMi@@)8J`)e(Lembst7Qp7krh!;)#;1 zXney8zy1=*Z@W{;T{bz2SSmA;{02wo?z)9Wo;aTCc`iu0ToqdO-)Edx$1q&~@8-NJ z7W|a+ig-58>mErx=e$bE94GiI9@o^V9Uj*<)~WWyaaEghInL&E_WIE~KCU^}sDC-? z(+MAEy_5PrgwfUaf2<(jh<3E&TBPx;=3n{7 zzy0e=i22)78JKb(B&ShAe#egI4ep`jRGwlXm;P@3?HivxDZu}GndY`}^!K7{ePi3` zD>Kcqo1dj@{myNp+f!MNVB?at+}n)Nux{^|j7q@*Rd!xBT`+_5 zE2*&2t81u~=$-;wf6j$XiPmYW-O+~nEzzNu*UcHqV{oxI)Wqu6Gtyvl>e>6{9!T}w z^6!AV+{h6piupPCVXFuaQl2cnmVuku#<>qib;r67BLReez1AkKby|D+JMh>P?}eml znWni;`MdM1DYEj|7w~HKCkKmmd3-hnpF484rP70qzmwekp`7Krs{l>M*HG(tu z+F$md=fu;nx9TagEz4yrdX3b6-Sg$t+gpc=N;2M9T)j#(y=cqamNz30BPZDs*I$#0 z%%LN!g1N%lx7CDoq<7fC1~6mWGOqdpKua%THA) z@Vxe5nKV97`MZv-YrIn1>YO;g{ORg)uk8ibtI&jvZcYOba%ltAvnZotd}co7D$8C( zLpqfrsxgFuqJpS^&0Bc&GH@+m5YlsE;t13COb)3+PXVN~OBh4_2h!}fRBNbQRv47I zF|AA56Z(&besNBuKL$(NuJz}yL*oV+xcwf1r{%)3`s>MUO6@WIo@polc=hAH?R_OZ zNijoG4Zr4Bb1;7Ft7Y+|W~NW_;Hzt$$MRa$XMFYkJtx1q7(0yig=0Zh(7fY|8G9Te zDZ>ccf11ODzkda;9(MCB_`2eUX_fx|`1K-x8dwhF7!9x>@UJ? zPh~i3niROjgj8`z5=n}JUD1U}rzENqStl`1)lJ$~sCi1RBYv~XMB_JUq6OQUm{Vs4q7nE)A9@eqEd3a+)2Xuy!S{k7%cz?plE?!r{+R)CE`|i5R5rA-n?9`mT1{B(mo1wbJ~?3d{jo;N2PsQ|EjwE;Jeyb z|FZEtt5_aNAAm6n9m)6>s;0@@B?wk)*j`5mXf=5jF=!!LoJn|yKAC8mvFwXtHlgu+ zf~F!5ux)*2n(X-@3Z-3|EpHLKG-razs=4AA>Qu09fK{vp=e2)QCaP^O^_2p)tk=45 zV`y{b)=wWrR^!tzF?e{``g*ia2W64I&%`ptD%i{s%>9x$UStHMH}g8!ex2Xne+Wby z=)0@L&&Cr}3@kTMHS!==(kA*N$Jm1v2-rflH0MMTNAeb|aUeI+j4S@n(RjR|UTlBX4}tzbYT>%}^eUCEAF$3((Bkl0!mI!9HcP)iQq6;q<=?;%)_8mT+X z&l~!Td9JR%i^i- ztj0Unp>fChnVp`p7IfZ(Ta$}X4fGJC#v&TAY%G++W;Y~}M08d(xG;0v5&$T4)3?JX zAMeqiy^WNZD;vZz^N1(7$XKk2x!A4aFG#zygAW)Ry`IGSkZ}}?`w9R$i@HEor^3dO z>obZaSBU90ZDZt%B@d+xW!v;7gyor@!htgOM;8-d(*TFlq#%P{-X-{Vu2T*R9 z95zWT7SfZ`uQWYpZ4y*oz2J}OdV{Rjk3D~LC)Up#I|G&CxCAmE$0ai~7a6=1r(LFo z!FEk5tS6-E+reW^r^+f&67t)^0zTvP47D9^1bB!dsS7FCYI z#wjyzj6G-|#@3L5kORr^EoKzKAis;t!rCg64+N=GLUK!0j7Ng6AYc!E0US*SdUud( z5zP!I!Vw+WdBj z-Jz{b7FOpbDMQ>1yX3}ruMD~X`pdx9)yX>WHR!6F2B(rZs4aR-CTTC7bkcm0NH-}E zC}}=yh`%5Wzb?nn6J@DMQ)+diYwBqGbyzssFXW3@YFZCVP2pA~Vk`f~Sv)_BmxXJs z`k?{FHPO9ENi?~B0E^H5!&XwCO078aS z&v0twuheag`W%;^Jx^R*?`9W-U?Xkt zGRo6BkcVT;S`rbxOA$I{40J_dfCeo;ccHgv0^>RTws%gYG@-QGULj`3lj2YS#_%!B z>d`mlc`$l_6{uTw;GR}TJKFi;K2Vs|^q?s0DEQXaeFR1ikbYqm2gf&^-Kqs6f&(P1 z+pa_|#GlS?w^xtVAx&G()*(&WVut+bxI>!c(zJ(5|B-h$+809rYanMH`RQz6`{E=jUjg<&YfU0o4g&m2pXd%+oW3Fs1bro)=x`z3hFWJtyyG&H(U2i| zQQ9Ehf)+08s)in3q%q=2#CLgj@@ugtRO&?09C%iNv(YInR<%V7OVz<4aJBS28BGlk zJYR9Hg&guhz~Q`s%f5z_=y9~d5R@!F9c~}9Xn0TVtHvpXPAxB6rk#soeF6swn0CcuLjnd| zKD!9H#e}kVX{Q|~&on4;AuLv>IY-tE(Wex@=;0Kl^Z;_Z?@A^-X^{u!EAUh{v=Js* zB?O{1uIM~j51vTdhH}R~?&B@Yt z?!Gejg(Kpi%%p&lH-;E~DCRN#y~k@;F6cS<@&Oa}wW#0!p*{kl7G1*ix%0+2ntFI;+2w{_M=$#LR zG=MHC2U&+!-V`a74@YXwy_43s8c4-LY_dN5M>&sf7AdL&5LW1;=8Dd4N4$u$>txj* zgNgjgF(mcEe69;h!(w4165F{Bd{*fjXaTKWrcr$TAcvP%=!z~KaYE-TgG3fl+WXU6=)-LRj54wNS~e5?j_b%p0T)x zCg1Z1C$@~4gfU}E#|K7;<7cppC=fUrBnfOd55mL)Y>LEb6nuNzEW=c zITYR~|IVVy6i37HiZw$!qYSaI_Q$YeN(`@Mn+KJLIu~yRQys%MAsqJU8GAW4SIssE zBI*(m611O$3`4F*h=_d zaEcWMI6jV6;9Db7bo0;)&eR3?YMzXH^-9rf7~#b^3M{OTlwzTIZ^IZ$DOb^PT669e zVbiXUt(Hf8NUIPA$o2gc@2>tKH8|$If$2BRyGnPkL1_l&O-^}j18YVGrb+(MCagKN zr`0Qj=e3#iAydz}BjBPF=}AK~rtOm9EYSGt#vM_f>M0-Aead2~cY;^9ES5dpU#oHZ z^5qYn(pM@ArI$-~U|Feg^;oDu!pLG;mL6n&5$-%!SpL(ZcFcGyTnNriR6Ft=gxYm{ z*{RPl_@TLgcqiVEq2{sT`+7O|&0J^mPYcydQ>JB=W=kiV=B(dx8(k(H(7SbPnYFW|2b_{d)}6FGunIgIEbgPv`E1Q=lT;xDS#FdA!HO z8Ae5Pda?I{V$`GYEI*1>_mTH~G9Hqn_>xo!q;T-Pe+^XLeMI9H-Lu~w-9-e0VY zJhfVD#6q|m&F!D!%};oO$6)t6ZK&Ka9z|U&q#2zvJy?DV6u>@OH@+%!oe0c6*Jjw~vW! z57^OoA6n;nm}SfJc4COg5$X>bRc zMw3te$8@BchVnOF;l#so3x9(!kjrR$SLx{rq?W(u^=(G&DShn4j?kV3xM7$ut(Q!S;+^OBcMJ2RALA7G=^ea}rVVDO z@z{**@hoUJPNPhO&V<(og<&2(sm7jolwfzF_}ZH+{QQ$2^&*rx8>NR(t4U=SpDC9G zSBH?<{mrtB^`+uL+-kw|alFwTXAwRvb&-E9+!%;_f^xCw;2>0LB3<4MX$H&-CpFOz z(N^hLx?@490CADaX?86`t1cfy$&RSkpxE*JGXLtG{9~e5c>x<|dCKG43ddGbP5;FS zL?060q5b3se-K}g2sW2EFFgm5H~?RvFr|r3%#IrT}`Fyk??}Q; zJ!N^9SD5GWR)=T#s{`e==qrA=G1lKJUC07o-o2al0XRN_7&T5A8c<+pCSlnCMFy!)pg!B%wzFSdIZMcC;n|C23pNmNR=dwr;H9Szkhtvc3`h zJ!q#tKS7*&<$8TxE)d#jMN}ez0$EGT_lKv}N`!uC*7e;YtBvGB=LT!>eE2$eN`%P= zQ!$cYB||pR#pGji9B1qUcqLdG_m}Vcz}r6Z4q6MBib&tyjcR2icj#Tb-ntHro5y@M zWc@^L(}ae4wLW(pI)3ho127D|^*cFu5#Je{`oI|`0o90zx~Jm`ImqB>t9cS z;XMh9eZS|8J3oK;@%EwZo5PW4gA>u_4cnn|M1&; z^BDt=KmYm1hwuO658wUqKY#meZ}k8E^0S%$>F3{m{B?}izaD?~AI~@+!#{lgm-pZQ z`s?@q{fF=N#(w$fr@#E@Qdj=;%b$OH`_uP-`uWjCC1cvqUw{1h-`~4r8v4u6|1+lj z+mHYC+uQH|{P6ylU;8zG`R%{+oqziIzux}w@y9>^@b*u?{P5%dIs5Z3zy9g_$9Ugn z&j@vI2}6i`hziSfMsCaCWG(ce2Qh_&_C<2bjyaQ>q+esgPW*Aw?rzqR{7HWB?T3Ez z%-hD;5}FN{lSO$gh$~%yowI`j6*YjWFH61*^!{@i9lDdR`WMjY|Msu`@9ZV$YR_@` z!`;;%fshpX`YT;+(3Q}KJeFpc(=t_0kf)&?iAM$G(22udcEZsFy%7w7wEPNH^t*zp zR1~)Uxo9mUwho0rWekh!pRa%IcdjGT3;GR2Qh!1JD}|#^ssDH<^|29T-btRLQVAxV zbiH*Y*cdm zYsackUdG?&sjaj8cBg9gaxW}SLxa~N)sEEA3b5F;kP4kgpTQ%$p9@qyTdfm|?Jf{9 zNv@(Ga;Y4Jg4Zf0KSgdk`(0UlA=zDc66z9#y+LVt9Rf~ac)#9ploKU4>@xYaqHM|E zO6CB}yNlFLF$NQ(r=y8G-6T>#Zw7!!V{Jd>bUlO*(4p(jdv=e^z~!mlnEWm1tkQPuWE&Ub%L1BxK%m!E`UGmEt!@tTRhRi;?z57cD86 zWGtF9dFa;|dS7a?q`{;=kxt2(VCm?xA^Jhbyh`2xABCfqgr+{y8OMioa*Mn0;(Z@_ z;4h*yCzCXY^YurQwP13hwA&d&{g)|}Dh-Hb^0KcvG;$jBo*Sq4Mdjffb9p_vhf3Bs zxmWgBhG$WsTr0Saypm;2R*H{g9(it3-+~1Jd-C>PPPXJkE~?}_mWQA&#Hc&zu7gxH zxqk9VR=R$_j6ATx(2>j>#O0YxiImSdzDe_OxaYy~cU0BqbLwQtM`|&UvGt z2!JJDYK=~_Nj?g#@Gj|UpZt02b3XfP`kIZe`Ibjyj#9lIktdHxgqv*CDlOqL-SIqL zC4DJ*p8-CTMS~wE6BxUV6G=sb14Ew)Bb8CT{M)gLScuxWQqKD^23n))WO5$-B4P-j zr2Hl+qCZK#^R2|zN|WQ*OFicOy9g3l%<4xLNdoD6I>QyziCi*M?EL)Z1Nc-iB8{yc zRC=b#y@R(jYH9Ugk=o8;vW8r>6p6J#S;{6S1$rXc-5<}-_g$_@vL~=S*DgT8NycQA~vraMOw>mUO5#Lw$%H*~i8s%ix z;PUX6G3|CJnl0G(bEc#9&@}I!YTIr=E+IPmUcZK^u^yw{qSupxH;bbDx{tiQj?UC+W`cXfiJl`t?HCbO9jk^x|Kex!Dj|E(-jK>d1TfORa()t}evQiK*m4JajkfvHNADlf^*OV$v zN^(#>^22+DG!=^PZf1d+F@=p+54skl7Z5etu>)L|G{fXmr9h5Grv=G6IDST0WKO2u z@nS9|4h=fqI(alv$t_6}n2g5tvvcy&gMD6!J~p1ab@JBdPW!Vyw|>=5tYho;Oi%uH zCvQ&7cs+Sfo;-bBC`B@_y4$nmX^n%@U34?W^s#AQD+D;}UCo7``rV=kwViRv#C8OE zF!>0Z?O0>004-~f&n|)M!`l<5n$KAGQf_hjEq!qP-ucPndk6i_A3O%9FYY?qfzD8K zPDdZv@>jyja;Z{&St&Y;{NMcK>2>36?ZW!tb#10891Fr@uKPKih<2$!#dP87N?dOl#I<#DA_G`Dl^(*u zsnD-0#ie~IDT`xdcQcW)P|7kmp1fsAtxujl?lZ{t=uA$_1}K1UMy|)U6E(U<)@NOd z=`+Su-ZzybE52ShecJJfTt97^zkyuBIp#(c{ z);@*Nq)e+CNjyzTT(jk1u~8pm%aOYh5&Z&IBldS-%hljY91j8xft3)G=0t_61>GYB zq=H}&V^%Y;SyAzDl!@iXM8qwwC4@+sTxR#K9ET%O~Z zUDXoQ*h==z8O+BSm+o|XWY&TGU8knT*4wA^c%+uhAAIoSPctFE_le&^LZY45^LQfD zYE{43aY1TvGRhqnu(SCGpc@Ug|)#@2hNr=bh{6bEoI7GIji#S8EK84?aKtcIWyv zE$37QouEs{7@RlTuJpJ_!7c_q_n@ZxWOUazdZU zyJ_;xAH$h7pTYu2l9@15WgiLzwwE2-8 z3A+rH7P}1LZm~;n8fxgijWza~Z}u#$P2P}Wnr6@mK`vhfyDWH}7tm_uiphwqqZdd;WsmM)jX_YOi1Y!L zeK49YKY;s!7A)aK2kD!1mwK=3012;3|84(U4pq##O52jF2H!ffhSvy+vyecQh!!T= z^38~3@1^>~O2FA{Gov2o zv=&Hu#o`GXPAR9A-bBv}5VJy7CH}!^wIj}AKD{{K&Xyz@TLO3WKTj2>^aJ&&((Yt7 zBrTQ5+tJ6>`UAPFY`ey{WtfpKeZ|wLqb+&oca6_VZ0CvUV}o66FmQQ@L6Qvvw}pP5 zb25v#E~BdqD(o+RMk?8m^8~hRrIfY1G+GI2#HKo%E>?9P%ys-HQu9i`zh9a6m zX;bN9DdbJmUS>xuaZ4bUCz92XRKZUpX+4N)mo!on-b?EpmQwW6JanV?@=q3;2z7Sym}*j52k`T=d4V?c14%ckM7~;}>*%^l?q)=NkD0~%H!+r=0P~RSK zyAp_iHN+`!s2ZFIJX1(hH>eD034a${W2**+SAj<;Js^LM|6m|t33eT)t)rGyz04U0 zah1=Oo`95dx|N9++mjv??A9?9W=b{DhbOyoV<%^lou-@GRTwD@$bKQ#iXnmLyFj-& zDgm>$KGe7~>_JM=O|od~@eemXR*ie+D<4DIz0&O4;PTrYM@JG=Xd5_WTG=P<&uLHf z4N!?Ks@?Eit$b>lb!mUai}q$6o_`5^SSdjq^(F^0K_=|7P-E5z%r3Yh-3#@gLfhKI z5n6V@9|FkTH=s{@<@ebz7HVqi(5?dNU`Wer_VO@d$~xmVIVk>Qo@%v*siX5ue=CoFbnN6(_S_ z6eq%?D^78tJf%5t4(;|eCuxs>XQDZ!B(5|ksrx|qqB&VupbC!ZtU6InKUa5BUC>k~ zpd{EXXV#|bbR+P0q&k(!`%%@2xr`k@M|CQcJ?p zLqGU34m>_via9D^i-x$mYK|N*g8R8jru!@Q6+lH&G=Zj@>~669Cl$c^l*4~R z{g3J<_q!A%4MW^ps^pnma`;~Z; zY?%(nDo8rLts^I%`tn-tYmLpbT!a&)jM(Uh^A){w>?Ud7kL?E{9`m@lg5)2cpEAfY zq0pz3$JND!5f~dLd(!5s99j?BQYr5^I&R<48&nshv6|Q+kD5+|u7yrX8Aw(ZjJZ_E z@FL_?@QLuXBr3?~6mK{{uq%*Yd6hS%RZj{cnYOyn#61|1n{rV7%sfdcWvXkvjC~*6 zhl@9?J8Gf(C{;7{^@dOu3HI zrq63RRPbpGO5E}O?tzEH_m+!L)o3N3nWg}3x{~s;sA0zu;%DIci`y{hQ}NI~2=_LS zFLpjPhmRxmwt+H_&d1RT{^5*6QH^T=Bz>;{>;1(pMZugaLBn&WM-Yzqj1P_XVrL^2 zw5rcF)BvRE;ox6vMZ|{rSGMI+uhDsUpsr7_>mn|_^&?DuJxq>i6wEK^niJ-zLyRCxPs<5tel_O$i2OQ;FGO)s5Zal``)UNle{N~+{J zApK~;buKIg;#Z9bCL;z_J~CA&Z+e{>?2Qg{(SNKnc?d)YM5uuI^u+$!^wiT#BmHk< zk{hwib&}Jfk4diYwCL+-5+?e0Ob@?a>aky*U%%F9J&RvAQ&JJ)6Bb_Q(UU1zX{ZtN zC#}hi0AZ8(0yiIf*PxtEL{8L1L`RP6>7fvjEOg4IPTuS%$sE4seVIcHksns% zl+fY3{+Q6wN9MDHjyAYywu^_Sp1pZL%sGIy1h)%j4JMakPJk!uIv*9Ms_CHs<2 z$@wi=fL#!G6$41urQr(D9-$f>$P#VR7FEpd(CKZ*YHQd~fw^_TKN|!aIRukN(aHnv zZ>157s|gn57wi+5>lZgw1rE^I*L-rF0N5|kNw<3mw0-PrRSIlq-P5N{OSbW8Ls@#? zzxI8GHgVzi{)d`SXM!~)WUp&lfv?pGZ1e_+Mm?U-e;ds*9Ql*-0sfwN~N zNr1tYRTLPcR&tyYS|yO&1CnZzx5;;W!GeV{Sm;M-0B%n5DFDOeQ)GA~heHIK=?lhf z40U1`xDnCTh;!e-95ZZED*)Pe3F5;_eb4rlN`1@9><<~ze=DPSeg4=~+%pz*Jq5)s z4<4_=QG;CYDOj1t*bodCz!c&n=t6i%(W@lXXaI|?tldDLp8Vo*T-;S9tE4J}zZS9!5Pc!pt9bCV|11T*2HgH-Y){}2Uc z(N3&9`+msEt8`*!<*AT8VC5NFHNq3D9JDQr*C$yy!5u|-X60xufV#!XxrvK!NAfgI zE`w(s={)$ud1K|}TH`jWWVxfX^L%ULMco>dO9Wjt3o#C5VNTOPre zKKaG{hk6hkw%c5A<6a@Q41 z#veaW4zGoKouPiOjAu7I3+#8icx6%3WInUTWu1}OjCevIgOm8Qzy!)^pyZ2vip z{?9k5ZIFkv67nnZ!_&wQEAV4c@uhHow2y^iHwmXx;t>^xDF2?QSeiY#xj};pCdRpX zD-6rxx=kff($v|_q^=rp2^c!pvgS4OysPM24;xX+L?Gpi$Rm+_58j^gAZL~_6GMZA zsBEEJ=FHB(TL_QdR>48{mW`pwY|;mMAA0aeFnv~;-iAF^MmF?_A(svw9Q-z!>z7Hu z*S823zs^FEv9%o&{bcJhcA2O0Ue5YLyjj*E`b2`b0iWq|bNa>(H$Q}LIb;%m6|YT} zIy?C8Lw{C(xNJ18ZQ0l{ZPTGy&5PY)+QE>symsi?P;~iaUyQYVncnT$Gx|q~O$468qsiCf`3Jxa3Fx!eU^SDI-hjV!NKARrf`RgtAE{(@ZJhf4H!HDFFozF5z*+ckXC z7vpg_7i*fb4z62Gr))ciqoNRs#cpcu`D;0G{%ne6AV? zXd|*2NY|wsR0HeSUGLhe6}Wjn|J$#wEm)bv*1O-;3uFg$$CS+H`+7lbWj8UlpI?_e z@6)y-NLb&UrX%=yxvb>lE}ynf5Sc^5EuA3NMIGz?I3`hxnt8n|Od&?Bb*{(X+U~Y; z`;QN_wWJsoR@pSGn&%fyE-~E@rA6#lb=rQ%Ze6ZZ9)(t~&YzrqsAHb~(c}9%kLeGZ z*pMxCs1?mQNA+a^PT2giex~Zn7IHj#^;pDu_W?aB6#C=7M>q7SYw_}GEds7zf>MsUFXZuU73=isQbqXKl5<(=WQL~FJil-$ntpo-`j^3;~C86ab>8V z!FEL%1_Qcj8&hI-ef(gk3q^!7j#%IL#7?P$A~wQiMG>;Xk$-XBqyp8t9lUwWVdlC` z2^fFclEl-yk6f<}f#))%A+(TWNnbX$Tcp6Il8^^*jFQf4A?v+lR12vah#Out2= z!lNE5lO%Nsb(-?NX=jcT#B!Q|mbtpk<#N}uQi|U#PhUSP6jy)gJ2XAJLx~N;t#-ZD zl^2iDmE(Y^hQl2s*klbJ+Zu%HZBX_T?-{iu^vpw#*;U2tYf(yty1~r9VM?d)XzEzA9Do8l)?qq z#N<*il4jVIh%J?N!=V3|W3XHFjjdzhOQJ+xRcbDmX>`~&pFvU^Z<>x^xeoO76af9? zBlwKN4QWGl!Pj{5gv;63MgVUrp{HkiR%&Mraia$>P=O9rO!VfH^RIfljfokpNz0#k z*!z5zj@@=`-M_I}>-itD{xH+DkbXLiwMcI#wyeO$LpNYTCR*EH&04zt^ogwc(3t7^ z(3j^_uXS+G;#88{1Tz&NMXlEEh0k8nzf236l#ql}n(5A=6eqp?0&1l|O}qezRMPns zbAf)jf1@S{V!_3A<$!UO`bTo`_;h7tD+E(6mkjn@LZbH?Q|u&GfC;&VL^OsLE)-Yh zL(1AJeQzk7^)e;D6|TADGrDbU4o&_R_Br)G6E(r9j&|!@M89sO!$rbkCbV`*C~b5) zx)Y|b+OL*>pZqp?M)w?aA{VmLOyc&9;xh%niDjs+0|=I$uIGN;vN&X@#L*Yk8IFvl z%8lH6@=DbH30cYSORe8nNo`keB*G{V_f`Nj!CDGL7R{Lj3@X@`Aor_XIt!IFxdRVC`p>42A zr2$9Hy*dsgGHFlWcv2z*{7d2eu|$43;UY=>auzs8(xs-ne(=fVOCn-Ba;2!WMa9Om~k+*@tflKYXG8#!KxW=^9YW1o|u zxlZU|q*7wEQ^wjztDFbN-zOtyqROj3{_$!rEWX#kXgE^WqplY&n?S0XZy-Ke1B2kl zf|g3r8v`W}mNMdY%9}<;$;0Sfkk$o-#XUL~Q1Dvgg0*kK_?7z_40mr@FhIEbJ62fn zKGO15p;YYwTTrtTVrf;Ry-h>2F(A51njm_xw#smL+dDi=L;a5yvhEIQ`REGVk~CW5 zr{AXGNutjs4irQ>OixsC3)b|J3YBKKpu|bvKc>y&?yOW@4?-W91q^eD*Kqt*q`y-2fsMS zyqpVZUh5B@tUvf21WY$LUbVDpX|$V~Lz-$~N`-Z`E6W|kPO|R7nt}AiptRJ4B9#@6h2qH=eon*qa_XM0&Lw{3`q?j=y;c ziysLWU5yW3h5O6%qt`l|XYnI3Mv=x!Ta}>+FGF({MzrQ12~-B1nAu;Au^8?GJ%Wg0 zha`_un>Z+BHOss1V|=jvFm4`DVPW);@)#}!Z%Y%7a)>MT(Y`||Y?3AeN1YIw_9f=x zy&&H-f+>Krl>NkKEN1vd)#>F`x_+?k1HlhWS@hLxmC*>L>P4rOkful`%p;HqOHkF; z&>KZ5)dzBvdyTY(1QvxK6P5Py9_!=Nkpd>mUBab-#7?re<1q~qJf4~!G-o%QO4WCaT2=Crb2a< zXmI~Vgx9|75f^_Frj9<`sHE`r?o0;*3RS>y__^c-Utc0zha-(j5lG-&cc2ab=7_Q_ zt6+5~Of2^(+&p0)4LTLJ9ufiZNOJx>3|9X4%j8z%fIFvX5);W0NmFHO2gg@xZeWVQ zGv_?9 zG4}fMGnv4SA7-VZLS0=N%}5goLrAHwSGEh~rZ{#+t4burtLes*Q#lrK!;d#DA~fWG zzSd#s{zHGq`{k`7B4{}9PFRRSG0ufdNW{V0P&_wt4P=HzbTz~2wMRi0Y%esL%O$p0 zmNZLC$_30Xt+X^^xT|~;piy{}14-?%oZ)w-c!A4kJe1Z+acl?oKOWKqL9M8K42;=X z(1!<41xDovXxDY+C6;Zu!JX7m2dLkXN5RYiNwVDGS?v}%Ko>BgeVKr#lHxNi^s3p# zz*IQmb$wdlu$dPKlXM`3YmEOkQHqVHdBbyEs@^ z9n(0^2~UX^5k?Z8JQ*v$ySl##$OHLi*2EtcB27k-g4NcoE}7~n-0@#k%vWpqsN@#M zBmV}SDu65{>6)BK->zx|j4vsl)|AO2OBAwTcX-~7{FyMlaDF64Mv?4SVNW(Yc{k1^ z(1z=)GbbEdyOYh5=1izZyfI=fZ3^GUAMW_V3HSb-qdHsp(F$l&z>z=Y6xB!-zh)$5 z4X9quRcarKrqzWc0fdo2V5a&8a5sGN=oDfq-19-Y*)eueKm&<|{+ux@YSDv8E6GG% zP;rPLqv`ck+s*l(&JEH{2-z?aYjJ00PDUCiB=&5VVW4Mqyns>ea0rd-43tkgseMQ5{N!#ZbCR>Vh3 zPm8YdX-$+!#}Cn`z?3!IL+&TFs|kLTiwwf4WHb41kvYuXYHsLwU|tBv0WUoxiFk{m zL4|NCkrL8_ryrW8N80e}Q$*qj?ct@-K4>f6;jDx+&@&cbDLx!@UUCya{O0M?{2XB!PQn&~S4f;UzXLf25w=FHZ|=FC+jg zTT|cLv{8W~Nfw3u-C@Ctk`OJm6 z(Zmi=TZY@Pd-F!$2h?>J{P88)xaZ8DvGzDSL1;|@$_31yzsL-k^+hWzDP70Ow^Bj3c_xMi|4xB{oazrdXw ziyh!&gj#%D*mW%SHZgoZ2XuE=eh`MsXp zFZY9_O+B)WKO|Pip&x`hVOM^TVAC;oKHCq%t*EW&$NV68b-ByF+z-Nmg9<oxs-}`hw2#50%evoYT z(9)tIMoIf3KZrn3)YXJ{q7G38g|09hyojSGj*za0#t~AA=qCRV5Q%4QgMSpu!9U>7 z75mVTAX@Qh{!yGQffi8BVX}THj=W4{1v`pkBI^8((iPRE={G6KYzmG&7hw7vM+i4; zQ`E82SO{^1h}+MujY@oiBLw5fyY?I* z@nJPj$i7(H_Jpkc=^EqxhK`VkvB~Z6aZkts_&qF)CmbQohUi*A{5ehfFGsul{7v@r zl=@R|Q?!r0zU>Yq#*saTvWntyMX)Tc9T1kVS*& z&ZobWdTLe*Dc(!ko?WRXrV)E35G%w|^$> zD^GYo#y&TPxlifcH1~3Vp5Lo6TTP8_FRebp1?Yflcu2)Hy=9m=6Hs_de{QvF$tMmd z`1C0&?DG2BIi+B_eVx|$HP34dP7^zVk(<9)kmCHXDr`LDV^8kLy5o}zDMPnd{*h*J zwZi!5J)w>1ldFD)Eifg*Pj6dikj1C;0bCwq!Fn+gepEsI6o@gVK-nT17GBq)aaF|SN^#ds|{H(y=p#^aXGZ z3ijSs_nl=bweTstnvU~uIZf-{vy%t!D0V3`gIyPt5oAn(*+I|s7sGQ+|${gK4mj}uU~_o^+8Z;uY3Vu#dU^Hi6*cBrN8zv_;^rVVqVOh>p|rP`DEttB z(9B`3@%UKb$C%ItRSmX1p%oU}KK!ait;(^dqfWWQ3a$-KPd;_jzvRhl#O~!!!YdZV zvrfXx4Vq$75>OI6_w^WnoPRM)YEO+i4Mp1jSbq%?oogTE!0 zdPS^w7MGeFWpPGaaR1M0T&#VSNUJ?~?2AzN^ekUQvcYF(XZ#a2*8H|2p2-0l*f#XS z-coQL9Dk2q80SdyNMw$Kem7FurW0JoJ45xo24Vzsa$1^&9R%e=pF+mgvr@nIhZ^HF zHr~F$Kc+=q-~P#ul?Y#E-_T0R+Mcq@G)Lkpx!(7(X1eRp@pM;D$BSzYSFe}|&pMOO z)*Si~=)$6r)DtewjRK}g25o8%vEgDDPDfxvQP_C!MDQ&NB>cR^RysEkYy2irpc4%t zJEt4x_!(TJftDYzk@#Vc_(%;NocM#Wwz3%Xxr^VmhJEmUGxCw%0un~yFimGBEC1clIh}oTc7TxG1(1%d}^{0 z7tNXHah)M2EPoJ{ciqz4H#3~(vgPNv{0Uyjzx><3zWfn+#dvtu5&4)-F`NX`#ts+n zL|Wb9x^n4{RHc0OgAWdM?BkjH531|@|L9nkeEs5c-R$ypRTeMZ)q$&z>BLJt9c$2& zc6z zDG%v1$U6cqiR5%q^L171Pc_&>Y>sY^V&&)ew@6&^eU{sE8JeeZ){^-dD2Pv*L?8}qPYyR4^NG6zb zkSDI>Hvz!`?V*3oL$Get4ak>FEs6$7ff^7N-`xZli3)Y0&M^7(@}aM9pgxW<#c?Tr zfkiY?TOWGRR3|=G$@V;}sR!8U3nTWgI1#Xc_VYRm3CL$M7Z*W70A2z*NjlOc3?BJu z>I`-qz$8a%WK^RF0La#s3}80cIbutF5@dcQQ+Jx5rc6-XB#q}5Lc*nTtjX`g%Azg8 z$+(yu!Ry#!pb=Tt<2pzNQp2IXD5wa8R_+VBfvN$JF2J95$tMkV2cRnntB<_A(q8IqKD0!}RZ` zAz5V>L22CZI1D*3PTYp22v$HP6NI1?j6#yQ0Mt?VRAe9AG;0ig3{-I{+2~~INz`Ph z_Xv`Nt%s8Wl>!9Porl1f@p4WP9iR#f?fU+Vzn6bPKM+7wfS0nZePnFv>cN}J0qqd* zEGRXpmcD^fQ=hGtC8#q2fB}GHz1pl*T3x>bwWeg&wuUrPDtmP?(cOcc5r2nqaegLw zEg&Nd#q`QeZ8*dog>%)S#CP69W_vJC)wY3p%LML#Bb@<I-hwp3MlQ@7q6Wyj zRBu}&#fJg>aZG}5=jc?TnN~|q>~aXE)#xG0mlqYUX=Tq671xTU@VAgTXd2u(I8GYH zVZW;79S>V>QxO<8j75fGwUDd&Lg{E=s8qr#H*GB4iGaN15USD*5i7PiPro2!eO29U z0?!iKK)J~3o{vhI**(E?0d@~32#ZoS<}V7m3Ra5=P+SZ1k&g_-{Vu>qcra$_z82P;5nF!)H8&RJrFCq^i0Ds;3VCDfRc2jRP5pd9-@Wx-R;V}KD@0l z#fyAtYT54bg@>56cc3H#^#Jhwszy=*&Q8!2J725b31aUf-+_Of z9iq}n_b^=L{$a=2YtMCCz}}D@T(Mx5fw+n^P-{txQO*`Bb)R|56U6kf%9NNH@g(9q zMcf)kUidbejn@e|J7Ublx=97Lx<@wyXbY-Hkf4Hqx{T0dPIhJWNVNwI*i_(*k`(8z zc7Y_sc$N{m$4#mb99%f1BGF^Rx&oAjm6*7y^vH+{M4PWIHFlKCXfv)E)d*3Wk|_{M{(Bj z<}ApNiUf`L9-7JB8Sz;RC;L+z2f_HxfUFR#I}mbbWBmfraVw!6vfaYnqA@h~7V1ug z5?BuIF(vq@9zfBfOQ zKmO-$zwM3w-(PMwu(?d?zB|LNyP7cDIsGW6FUfByIPE}4e@^7H?UY5(@)fBp9M`#(Rt z|K-fs9#yTl@ z&=@gSDC3R)qoCp+L~;MQ4o;XZD?d+2Gj%u*jxDvAy@{(ZA~DUR+#qAD88+qBJUIT2 zP4zi_n|RJ^cImSyiR>arv?yLE38&qY@>RfUuSGUH0Tk=FD}?smMdBe@4^*F!L^LBp zGyE^69X>t})n6g?e_*AeQCNQ`qoXY~DX>XR^*Neee@NWZ%N$w*jKGWcmrWDsLx&A8 z4gu%KcMnduDrPUw315>ApGCZf!N`Dp@3FxWt&EzA1f=YD)z*8gY_8s1-JHYYUWp$6 zKYRDK3rp-$Xs zD5lmVh4i!(*jL(%C}l=7v*_BZA6pj zm@RtacvqXAHDRMFpK=nZD4T}!D>0da!{zX#`~jN#xWD6-!}Z+&R_r_-jeX8Mqf~?|HXX+Jy-Fl&kDJpo zp$CDX_rtK2wsdN9HTg8iqHY`Z={O@8hUX3w-KTeO9WQNXQ4Wp8^ZHx(1`7RxEzGH! zElivXWv0{$ujeUE)6#ZkW-o2wEctm0Pb@CW`cUYJlAd_^Gvhb`MX_9cFr&kA5`@hu%0mx$WVuHGbBX?}m1N+&L5e zl0GV>Rnlo?CtWt-U-{(g%bgo`^;L4GPLyGlV*@=RIGF*hkL`eeK{_bSU93Xo;ii%b z=?Q!v9q?k5BF|!!DsUt&Cf2kIZ*VUSepC>=ONXs(_F3r=JJE73e-&wGtDYS2j_4N; z_%D$TqaYaG+278oLOj4>jmfCbpoME2QZ<~=$xfm`%^39veL|Fw;WQs)K5wmXm%}ADFBYuChI>Dns?T_A zh6OZy!!i*4>WjtMm>`y;fni5OYv$&!F@h_y*eue~=$Xyo7{SfbZa))IpY814(k>jF z?FPfwtnBvJ&lM>De9mR`;AKmms}aY%uDfjEfOi(F~Z1;8l|gDjeZ z$dXbN&e1&wXo^%SP^2o`Qq3z>5ui5)^SQtwFn?oHO=wJN?=Hhvkv2B^Y^=ZD?mg!z zUMd?5YpM4+WgBqVh)U=)=^`rZ+_qgvhqhG9M4y&#YYHT>xn|;-LH8b$x4C9wOxG4E zA4p&isuRwG(@)!_l)?2+t`YG4`xzN`i{bvSyMOs@SD|2vRLPj=3*G%1Y?3 z#c^iUHm!ZTo$26-M6Bz^ZErwEY76p)JqhE8Z+&baTUi zz7_*I;R{xgYNP$YaD>Sh6}ET)@a2JJ>B{g(Qq%rjAmW()hL-lHPiqn+^@EO>)_Y?N zX32XJ82DMDJ!RKIO3w!9607Y^AJ%|?!19R4@w!V_Q)kozk`||SQI&P)dI*YIl7|34 z!=DAOuykBsGV``v03iI(2CJp5X@{1(FKpDpwL6<$%CL`NExc}bE{*-tBLaq(oW|uA z*aV0+7`=~M*>rD1H?q0GQ(vWieAZ-X^Lyl=YmI{hd*;3z9CYWS0^LGsXUM0vLO#)D zxMAS%nyAc@IxPipCIT9Qcqya_bq~V73baCyWIVZjlI^MI@_Ub(wZtz#^*)m$n1nN`s+*mo2Ksz9^hT-qe zXy!=ios%oAP4plg%9-`Y-|=m|8I{TA1_yqXuz04t!WGe>n5e2&A5sW0+e<=Kfza9> z`i4j1#qFiH52^sxk(gjcj>I?HUTs6rnNvA>m2@!hm_7G=@;#G2mDpI&{c1iYYgw{2 zOCkA*O(1s3duAIBAi8NAnkI9zL@hd=k4oL*7DHS57xZE@l6KeY@qyPg@g{uWU@ZgV z{6c)-tIg#$_RHx+ITJq-9661#JrA)p?X5%Zo&pA(ZTrD?Y__F>kuxqZR@jnbbP`HA zlmS^kNHq&0z5RB+Ev!W3*M{7M@2tJ&967UKUKAU5s2+f zlyAc!K+mx-%QBJ~8)hisa;Z!cQO}f((S+2e0vXDAKjL{y{iT(9-3i`QB`oM9IP2s~ zVYFaYwKOGLXGy1Ojl<4)rq)&onPmPQb+CIThVFEUT27t0*Yk(`l6`%p&93KnVGjuf7I{25Cw#Bb<%&gV1qIHt~uy5P%N*Z?D z>>~MkM?qhjgj~egu{7+rw|SfV$gyKbyw~_hK7^8*%Om?-pMg;hOK`%s6v($fZxG!} z+nFc7rG&h}w_hb8iz_wB>F(Z-JIMk zXYbQbC)iNZrBcJf%SSVQH9B;gw3RgYMab4A=lEV)Z1+r+nHnwT46ya*pIZ&&tK)?pZz&nC(j`t| zW~Y7^0pKuKeGc6ka08C7EdsFnceW8?wutaez^&mha~|MvTW1r2sUTOw+DGF6b=^P7 z2EcEo$}B?!k158zP`pX-z(0rulgsAuF2tXljGm-e8GnxYU-y!W)9SgA%OTSAN!;?+As4#sLt_Z5*Tk;HXqoxF0Hv3v4;y(1lr@rZ(TNFtu~?fs$?VNR-nZNt zg$MgcRH@qci6HGmeY8Be>)qbgp4%QelqB745UPoBsC@z|EC%8bl(|TeyO=G|MG?6VjuNF`1$7MnE8eZe3>8qRq?A)=` zcNO~X)mVBtp5;MDTrbW0?3HuxhsU2;gNvP78EwVPk!|&e>wk15GK&!4oCLP!HlsQb^jhVkFnN)JaxA~BO=-+!3CHyNY9&@ueXpFR~*DJXB5UMd#Is937D z)}TXLcaHwEl^FZrozd#1)KYxkFM*vc;=}&bkzQIX5&insHo2G+JsZMfWjg5cA_PHjh*LaZ9(A z*9-Z;GLN`%GgM66X036^5n7g8)3l$G*+kJt!IW~z(c9EIC=cuXqm6jSmSQLD!o86v zqUyYl+=HSx6#j>Pjx$U}hTw!Kda3@Q00HGXF58q1*aN7$nE;CU_TFJjjSqQN=^6}* z@Ygi)G?CUOLBTm4?(pp@x^%STe3Tl?DQprpvNCH9?{=~PP$~xDj>AXSY2r)?9NeKL z#aF+3$Ax!~$ME4!nSxLfPW1-Unds3ow#k4P&^U$MkLA0pj3nz~-X7Zy3w z7&e!WTT>X@{bXg8i_z4Z->ksRhK}gVfaaV}sd>@Yul00hRd;E7P6y2{k*#gjCITig zBhdP`3C`?+Gh3kTfaL?9f8X=Z>v#19o?$sz;Te{bCEhn20N=dcQmJQHaI93Hb7sZ$ zTlQ(!c!k-)4O6&1Snu{!K1Txg541BTG>nn$;*q@nYDWl2>OxbllJ( zD7H2PAO(>)ebbYt!e22ZKEf~X=%Mz=VXau%M{bAB|ydKs4S!F?Y3 zlizUvZEslzuiAg1uiJ*J(^4BGwqwZ#ydNF<@cvWV(?Gjhi-+)j$2ZDCXW;jib|JBH z-cm=4qcz4jC*3D5V$P3=j5xtKE3Gn`<1i3^i4$eE=WWfIuQ0p>6C-gTPO0<_VtmKL zqeL4mJjZ{0EhFvD(l&^)MR^$RPEcNM(vcW!P0PJQub#zgpkaWCs#NRn+`cnkyK&zT zce1^q{9mHd8ksOj#JX3{_6?1!~s@?q^sFK8yqK6ycM zea}kBGkRYY4nbinGhwmb;rph>VaS%YMQ|DOXd%#R8$x!uKgF#8OTePKFhP+qwJmpd z`En*SG_3FCvHf934_;cAM}JDqNnoZTp?EW9rtJ*?`#Rx8IZ*vJQPToG>}k{!+O=A1 z(G)JJ%9%`UHMi9`%V(tJ3+&s3K>02n4mV5{vDd?vPw=v=1#?3iqyHD5SXdAPj|(j@}&IMd9ggSxAs9l zTj(zXm#fAanP+ilbv^zl_2wPw~*E9bTabmCQ-_N?I1!{{y>ikj0J z0BGO`1F{88lwRSW7olh0O2P=mm@sS55y>9`v|ZXbuNv9%aESCa)vHrz8;?btY3{aL zqYF9C0dH}o@h-Edt>>Iej17wZO3DjZM$p>ng98l}Q=g90W^?2tQ`@1ISU3 z_Neoha@}YAUBf0A{AlMwOiSBxUiD3|DDhYKH*aq+$JcFwlS0x9{#PCq+}KK@g>v`z zso?p=OvrG5aQW*auUTvRr6l9MLw!}9iP}uqJN-X8DHmO8oje6#_M`GQy>WPQJA<#k zUT+AwSFP7mVxZIYT1Wy}K!ePFlJ-IxO3;u;LV`jhaT3K!GvgyrHgri8DUy^xSDG=X zZs{W84hO$$4%*09m^5fNnTbmycvhS~k0TT#+L5TA#36|~sZo+VRL2ELE#nAAt{Y_u zlYsS#pKfSTMD;?tea5#saJ&rScv;>x2vg1OhQ=DyxDM$LVEuf}?!e;Nuf2|UL&cvj z+TF~q>u-`9Kw9Wz~l#gqvT8(X45L3O5ZNa9n488+~bF~us_5rE2kPyHW-w>W}8Nl zO0NXq<1sA)=_G{@jddwF@FKOqFtpVH%+S8FJ2Q2q#_puY8Q`VA)1c=o`gkr$;@96q zBlhK1q2;gt{+EkDyVJ?GcqA^#_e@6UI(}*qDLe%aoiOMFxU2-n4aFh|yWr|R)sN%> zP^NOHbuiR!uy)!VR^@!loIDYdu~EL~ECGPcdh7RaP(^zONgbp)Go*>`tof4WLtB^T zJX@lQkDIlgab&VBV$in--R0im-)T1tM?!1zoq8oS`LKL?`UIW+Fp-EMHnaJr9u;CG zkCi?)Hnpc^aOaL>aOd829OEfd+FAOIdPjTUo8VTrH*CwRj-^ew?pl)J=;eGC5}$Hm znsU{k9v3rYo{`|4+N)DAaFM_>Fm}MSws)`@21(uT7$C7x)$F(=DO@y&gx;d?$ql51 z&1ILgeb($hJ*{#YJv*(Y#_6=$CL3Yy&~%tjX4_Bm7xn|@jAv_-ZU%Ljl{O3+>gD67 ztBb?mN_k%W=-S;tEU(*WT+nN&LS`1{Nr3;3A$29HWCyPO5q+_7R5-6zN>4l`_4OgF zNo*BA+dYOs1acz};&GBzfs=n}l6fGn!nr1YUZMr^?=xAwXRPzey_>q%#leNn^$Nn1 zH%UU?u%e%#JA}Duc#3oS0-fW?R&l_c(&D%BHl*rH>XFDHo=YV63SaH6GrU4h(y==_B0U&Fk#i;+3fEq71C1@ zo#z#dTjP#5Gd5(rgOlPs2H|VWPbA{0%rnqU6vPYE^xNTQ?a80|++)D#*ZsxGSxvYN z=)ce0%MQlAV#f|VdmHI1SqPVYXz|070mhL~#7c-Ge%Q8d`x?F1_jw&y=|s4MuZ$_8 z1Y5<35pM_nqIgyXKn_bwf5e&3>)*6M`4)qy(lk$T`HL)lrF?xu(_nYQ8of%sqBY~o zQBr$8Ij7CEpjwxiUD_rA7N6>{X1-W)>E6$-eSC>IotVRAQS`;i2j#@}ZVux9S&PH! z`U=4fQ1iM4ONLd9cv`ShQ>TM5lq-!P=m2>(CgiL_SRGl z#;#`f4bjuUocFB2hs_)tz}+-Di)K}JYE9_aQ8*q4%k!G@JN7(nRV;DP+7soHXS?tF z<`7o;*Vjt@+S{h0ZtIpWGks|D2KPZ4hW?qP7{CC-&<_I>(5+OsXO5?89G*;1`0Ek9 zzzJWnT-vHcmgm)CnVjA<#qRa^)FyiQg6O}7l27wuZ-X0}N}3M6U7pgqyR0kf)_y7GL|MSP+-QD{i&(ZXc-`)M|U;g;JzkU3_|M`JHJI%V6gg^XWw`bzM zgLC8L&#SigtzZx3(zC)>*2ZTT};Z*@w?8Jzx`5utv z01CXr?kj@igcuw9pO-yG)#<}F9Vw6)F)cIn;Ok zYG^$Dj(H&JGui;C(KL@rvP$PsdDpMT&-n87_v|yqc`3LiogZq{NZ#KI`Z_L?LnfhR zbJwqi#?udK1ClRV24EhYv8n%Y{2u>!*N=;1UX?Xgu9iYL;)I3CBm1- z5_jiazZx1(zN3#szGM0BJ}hHn|MT)C_rE~iJ^PYzW*CRzfx_j)UCL#8pK{Zvoy1bD zZ+xcn)zEnQMQu#-Mau~E0U8_opNB8{C1=InHpjHX=`)>z*)mDLKx4(2#IYLc+jwuW zpV~bf+;{zIXgv9nJ{I*Q{mc8n_>$h(ua+&P?{n42r9K6Gw7+AVE#dZyT^-p#vE+5?~=}c4vy*f(-@)KA`n&_>;^Kar?M>KV|Pl z01KYjdCWPKdZu)xtTK}I%7;~=D{nn)aUx6G;Yh&6g-Dt)4O0>jy=X{Eb?aD_xscF1 zWd%WufDXd439%3Dw z`~{_y;pZgr_CEfZ!$7*pPi7;KdO>!$b&5{{*!aWgtJ}@E-a@Qyxh3P?Nk@@& z2!)!OwP9ZouPCtZL-4I zjI-_kuFcc1rCO7@P8yX@u02KWSHXkkE+6+)TjPTWGTW9;N*`Fx$wg8kGnOXmW`Y%_E= z2}&0|zQ1F#=k0i$`j*9CONi6HTw;7ASZAcrZJf7vf=kvqihjeoV=wKF*J`%fd^*(O zoV7K*)ObyA&2S1dMC)kpJ>GR$ypy-DULAE|dUt9LO)t;RMR-Y}JK5@v`Te+KQH;h# zyiXzVk0YV;b@4(%AnVoxa^zMQp;6N;>DK4oZNSlbh1` zlso7aapm@3zRQbfu`&nR&9t2PF<#T(QdF$@;q>Qx$K2sOdujZCHeCOT$1uz*x?!P( z&Qy-rCf^A_ia5q@p=qTg(9)8>#8v0b?S`Qk&~#f0N!0E0zn|JKJ-YoV+i7}qZ)v}d zIh4Kt)Hv(rpEb`!M<%>W+#>shue&K_=C)^^khn%Wy9qW+}U%xqQzVKMh;nfPZjn>qe}?}x8UQ6=WY)(UQ;*=9EL zcQUor)JC|?Z6=_PfBR$2;PKC2KfUwH={@>-^BetDoDTAainDcc?mveA7&CMPQfZ6M zrjL&_bWFa{iX5(1>Gtts|5^LhxSY!O(wEa!MA9?V?;w&eD${N$Z&4i+IAs7maa4o` zo&p<@6a^O@QPh40307yjW@zk}5lQXFyY^F$ZTIu)_b2sB>h;|Csb6_ee@=fVMS1?= z`1aoTK4oj9LKPpD_$R$P=1Cmcn6Rtn&?Cc!#EMG?Bqk<$j$YoKv5mJ=%|?o4K(nk> zsKGE_aGro`Wl?9i;7P38`D$sSjLvr$x8?6fV7`59?0^4AT!88YKHI+V1AG`AKLxv; z(VYGp3G6kt4|@iECdKA6B~~6I(Q8W-OCQ@kBxS7GF8$=Ys1Od*Z|oQm=ATNC0epyc zl2^rT&SWrd+_zKN%c*7li=j%rCgs}{oHBg-0NeeV^F!)bl=w8zqZw3azMf(PuV6JD zg4rNSW5vg-4p!`)c&YAk8UMcq3JJq2sE1oMaZb-z3sF*+ryi|@i`B$4u-C$D5b zk8+B1Ep54y_?+a?=oEF=9kEkCG@$d%ckNsQD|ve0M-z-v9ze{fd_>v zYNoRxI2;`C3<~T=-reS5o`z_?N*&UbO&wYHc!!&t--pAeExKjyT8q%#yojTe&*+Td zD^`D5{d`@mY(L_$e?Pm42PueQniEQ4D8rr(?suDD;9Fm1##jpWO3j&IpXJOUq)-OG z98DTMKjI3T-?_m1kc$;6migZv1P4oc%n+hrQ)GTkO;4EG*Fe84P#cBnm$h&9*bo** zg8bNpq@ZX6Eh;I|E)8b71?L-Z*%fu#{fM?q;5<>B+vvSAY`q_$e@1UU@cU*x%H68n z^>BnRi=hraESqXskCx`#c;%Tt!sc{&^JDb=2<|Zl-G@~x{7HLrNX>hmIiR+!&9&Xp zfoeOdA2BHm#y`~3Tn6;Hs(e9-kb`R1Mx9WJQAPnbXR@txfb!CA`A3~KT%qb9(b*m7 zo48JSenI7d;X^QKOM680L;^4SQ0$~npjbjShjtNDWJ1M{ivOW#i;SM`=B zrNN;=Y2b?6(3bRztmN<}2*DOr7o$h80`)4cw6uv?h}rh5p+mH;Jcc`Ucjq4Y<3^+Z z@UCAiZTPh38ysQF-&3Ty?jGCvpHC*Mx@#GpHm+`DHen`wLor{v3SW-nkrvP z#>Pm@qHu%?x0^6_rr;b~%U@G*ogj|InFEi=7Nui@YI8I5H3f<1t3`K`qn)T#!d+b2 z=uM=qSy*Aua+nKg$w8E5B^t5YCEnGVp6cgfwvL%tW{g`^bE}Xuz)Syq|2d;LVQP^z z3k@KH%VGNtTb6KO6|)kP2GR)2N`O8)yw*<%kK?|gY4AdDOl;$5@mjRN80C}0D~qm} zwONz0!HiCYp4ly_(&%P6`wt0;xi!T6VCCZcysMOfgS`G&6pnSFUsi^n8J?6v3x<(P z0}n92EsSwg9V9WzSKo6A1Lz576c~anFSNnv85)yT!veX7WSA!<51i+z4$_*H9HjG1 zjT5xYRksJbrgj<&PEx3^2n|{Zg`ff0vW5>-BG`pY2CXdCt5SsV>m-c8xE5tf3L?ai z4)JVIFFL$=DL^LRpE||+u@G$URhL_*y<$8YGeOd$UM;hcR8Gr)#VFVz^h=?n3$pdu z&<5;KusLQPC31D9Q(gQm^)~DSh!NC38B+#31Mp7hXdkpyls(pb3TIEB*{%K~F3zgd zcwL+EMW^F!cmGy*clREg?xSzIyD!R|A9HvAd~J`=Vf3e+Mmg*3cKntjIzHvuJj|JJ z;Ib}VwIAKeXii5rbkBG)oIAS9W2ziu`Dn4l>>*9#;0J$mvdO;l(u9vVJcE98h5<0C z(&^wp4H)a&!Gv)V7A^(m)V%a4ND?Tc$C#VD^@cr8D^wX2bi;}253JX^;KVK*j}&&e zB0?X+NSHN0K0xi%?a@)Z0TONZu3n1K1`>z5fWj5DLDytAI@Z&*Es@`wp5lmwxX{Nq z%vDMibr9AEr1JiBZ3~7IHz2(SSf@F2pF~QOsf<43YRfIKx(ggdr=r%<9>Vttm>3ky zp>TOzM{DIlLDY1Sj{yxpm8_&6n3cRW@dgh}=$#f-35ZQk1l#CZ<{)lbHmu%n+Q z-8tkXZU-;Tbn%0z>>(lp6y!l3?}DENKCnosfUkG?D8rp0JM*FZ>^0@_vzuzDZ{g$I zK%II%oX@AhJoD0;x|;d8C!WpS^9j%KDOSt>VytM5;MnmEoGg?K{~DWn0K)EclKfLQ2@KyelU7^YPeeKa~PL`_^^aYIx1U_z~qz`#sDi;89) zAGbh_pjf=m{Mu9w^VjG9qU;>xK*$iIxU0rsA&N;ntOvucHO+g#BFz>M7n*l~1ynmg z^ln)fU9o9PDgnw`Q!sdKO$lY>cTu!6-+lM=n}@F`a+tn~uMvnnjDGZ+)cj3L&5QQL zO=|u&q~?^W(&bG*HGeFrxmo>O#gMNUeMI>Vw~Lu(F%mh4|0(^Mu1&qhn>hb!=;Y6-ww%rXgb78|zdD zLD?rj?)6S}0N@lTb%N7rCV0I34IyU-F~9+L0<|%UU4XIMIGH$Ig3k+2+dk?5jRNFg z#}VTwcevwM7XhM}LN`;4grQ_D^|P(V9G}@-NhgSUb7}aZi|#=9-cb*dJmg>vum|>^ z--=Jwcovy_^U>0s`Hg^u9zO-S?lX!cR822aveWXubI=Rf<(536c5e{Qm^;8kKE$LS*>5EF|xrK8i z5w5+YFFQEC*^);2b$yS(7;QgY(n&mCPg!B{=7W~4u#bz?2pB`%45q-+w#d@HH9KzS zRE`Y+=}inaE_HkbEnYo5et9UC!5$5MVizP_KiM6-yWGfbEy)|p0YFU)ilKGIz)8&g zr*iJ!Lj*ZtVs69mIAQ`3-GKl*9K^j7?vBUbmy@8P4Wv1%yS&VD`(orU*V# z2tBmt_zRzQYXGo~PeYn^S{VD~QgE^6@vV$(IINieXmR5dX8Q58aL7X)Jj!K>)$WRg znD~40hY;wJmyEv(PgIkHyK*78VK-9hP3Ko!6%`)$S<3Mw)V388s3G*l@?#SwcQz&F zGUF;F^hqA#(NL@m&L6sdee40eAC#k}3<5M1v?@trUnGVIPE(j=!l+hVCZW~!>r zN{W)EBm)%lU^oo<`1j}#`ds8`2@Cn&3gsL4GS}%;k~9hXoE34G*X4vlST2`!HYMFY z*Ubi~P645Jn@;vrJfs{7C|M4z#^S_7+8X=gFG`5v@xwNmA^`RLcFfMvtm*l!u|MA; z+CKbw31oKFa(I4i6K;);a{H3!zlAs%fe%*_Cl}SCn>e|NlZf`OB~C7xdc%JF72@Qg z4m~{n*NBt9{OMRB{_5i7Eo{gm3`$oX`=?AsHw(@@xyDMyX><<~t)YR-eI) zwc&6&$h4i?90kte*pn~_#RDG%@MKPgU8PLOL_ek@@8*xWF~PxmTZ#Cd9%gw(Ut=UvXl2*?Y!CUq+wAG#PI<&d9xY* z!uXXfNhgpj@$f_s5C};E1Qtoz(2{=vA85Zo8!#BjU_|7|4;&L#1?H$q1)8Xo7kVjp zg+`!iDOV417{fMrSx_iG0=6J{NKa#rOWvd|QPduQEFrO@^q4vNU}7Fgou(G*m0*wA zkl(TQWNM^@W<%MS=?V9X!oNVT80`v){j$*6jGO&#o~ zF4E7ezTlc__GoGZdY`JPwVc4bL9`NHrL3CZ;cauJfhf}oRYzt5#fc^j4uw73=4ckyw`gO zy*M~i;>DrC-VeJ4Ct(2atim{3xi~pJBk74v#~f3bOGL>rqFw}((Ne-WbyYM5#+6jc zIVjy4v1&L02=4{Abq*pWjqBl_CzY^;fG6Z7GZKdhY2w5dbmk;woQ5z){Uv#dq!`t+wRrczDe&l!5Lj%ExS{aYw8__NqJVAC-X zSZ0YZ1?~-Cw1A}!09Zj#@yRB8yRcRwk?&%gY${K5%7|u6rhpi(xB_Xh8Te2OqlIDY zi9~=!E6$VPr4j~oEV>Bdi&TWxjujP4>5$~+CMbU>>s40xWWC0?EaTPpm8EJRl7Yu& zJu+T@9a>Ipx*07O&dnlk!m{SPWI^+cQ&wmU4t1b=^dLdY1!OhNU>xi$i$RP6emI^z>l7{rHa@}SaJ@r z7x<3}my2fwn;o^SydB6ZV_xrU)PzFJ8k7BDa*`yjUrlh9Q8g)G^v zEc`+1%#UFd_#>94>DSUqmfz>;(+wUWkJspL*do;rqUr2WeJsgd4Ou^2#s4_>Efj^?i+0+1t7Dop?omQ|HR1pylmcc?F>G zcCNg1u3U^*-_DhP{rK^Zzf-m5>IfTokHfigCXYIEAy*@i_nh%m5+u+eGiq5Al_67U z6LC^i-o%oJGNmi9Rmz_?Ww1O{|+NJ}O4^qijPETsu{MR2klq6v0Iu=Kx<@QflT z?A3>9ihJ$1LVa;gh8;Lhm1q;~5X&^G&lGE9ZzXe68!d+^E!3A}Tx?WfPtB((t0`$W zF}ec71YwXyd)KiHbBG7|4Y@O0uUnQi74&;s&cw5w;FSQ==$p7e#JTzb|xa`*Xi{ zxTW7bU@pC{LQIu19Rv_pX)tn&|%Uf0d?z?oX0q6p|f% zf%BFZk47-LKt{Sh@UZaKKd1XUnq0W&V0}-QdjFu)Z|Z8Z$t$$K#>3BHzaP)M$T;8L4yn=A_fa}jQNam(N= zZOh>G=U)sWE(hQ6`2Nu0@k`tC`1iG{@Es+*vGi{FX}=l=t~U<7dxOZ}OVRqDs)*d1>W-*|W_ZoY9iB;6@82-ZqLFScr@_N$EVyw zp|e)(`;c9TaKY-rIf7>pr*JngzFqwMQ;*}me`=*MQDQs&?Ld)xD1Nc3sr}t zUIlMwc*5fDJ6+ZR(}@pGyyk!ka;cDP^sgy(7EJm`s8S;}y$@0?6@cc0n#*Mm>D6xy z3B9skE2VOB!`@IndrCE$H+?`69~^W$p?lA}Z{&rZ8^)Z=kIj(c>KSKbdT83tJ^y6M zca0cQ&T+U4Ca)kIGWraR8SGqZS@5hSsR+ucBGf-Q)L+|Z5L#uNvA+cs1Mmq>0bQgQa6E379kX0W28{I zc)6NOTO{7Rl>noZO6t$UjMf&;BmUt&f@!QF?EBy^fAXCJ%&@Q1d_7f-%vhFbkC^xU z^r1G{7Ai#481|>j<@xOE@w=~KU_QJQa=#r(*Ey0d+X>(Mk#tc<9G3jAI+FN^4nswY zzNKzQ(!=9F!jW`bv#C$-k9H&pIv$~H`-gnvBk6L+=^|Nv)saLITK#Ep?O)|cI*QhJ zCAbf9+++$Jh3}El$g8FN1MOB+`Tib(K^#RPEs9GB3lJr?bc3+uD zR$QOR+lu?DnTEv85O92!K@ny$6f5zMB!i;NZ|;)Nm@4+pVqx{NU6^8Q7@{ghimY`k zxojAASL|HaN- zP;u*&G_1R0e%AxJsmPyp@9>z#CcA_cjRFj04WF$}5eqgP#ebeOuA(@MQT*Gcn&N%q8u?x~)y0I^ zue7PU4teSc`_VVm_498b2VXd;WE)54<|pQUcPh!G<_Ax5jrfE_W8ymH%<2>(&#BdL zjC&P^lDZuJ5GmOZjmaWM8=@^&T#1A~2`!&oe0&jXC8Vo$O3}lvIl)eO7^e^gFKNYa zlX@N=v;wgv<%uIx;gwD5lT>ay?si2_h`LAToq$XDFL}JlFv3$EPi+(br3A#Ov4ZDX zi=|UJ+%DO=y7+8yaYZVON1Hzyo&JQUq`j$xm*Me41gCcjCG(jl`CpJ5r#SwSx#MXu zGP}bxG)guV)+*)?6hUIu1}v@9&~S=Us?E+aG}gMNO8Jt;KMhTWWEz}!)cYr0^iK(w zq%J`6{D)&?csG(cX?QWhVq|6L96XT9ULCKm{`0l3oY>O*^WjdEl*~(s^8lVhVrL;C zniCRYC-9ofBMo*qU&+(2j(v##Y8EsP{Nh)8QqI^@18|LzSFGXnnN-1v3 zi1tNsc1VZ8ICe>0<>VS+KBp(wZIdNS;Lq#7UWOF@h@0%9ruW<2WXJxrt8B8DkXzYg zBnt^So@Dd&>Ty)si=KHaww3cktq^BWogcC^+WB!`v?oQNEJSwZ0C7?-0_H_r#7^~# z<4#TT&J*eYVXeholmkRjw>m<E3JPEMYl6DvRUz{Lrh%=SM4~*CaSu2h-_6mQE)H z8Lz3N=}z6ZB|D^F_3yc;&DFwIBKF9v&AFBL*2%%%tM@uQg73=NL5)x#+u6a6bI8}( zAucAcoU=pnxe#y84gu)Hbao^lTW3c~+g09)pNUxJ>=3h$>n~>qy`-HT#&SM8aGcI( z2P0@YJmiZ^Mq){B0;Wqt7o`VB7Y zlPKLami6i-tW<>nR*)u(D49Hzdx)b+f)uNCY4cSHfKTU}|YTxgq|Q1P};v>TuyX04y+KjyLg#&rkaF6OWtdN6G?q1L>1C z31tU;shEQPIFZUf55((`NFc#KjX}Fy8mIBgElW(n&vNwe@4J7zYk9yNQ@@P{X1g_7F{5ixCL>BAn#NbN@yZRmm5%8($Yf`!GR>k16^`Y zZ%!;kV&frRL_4WTdj;-9b@@*?$bu0g2;7&cii>|bZKmX#sKNq3!s_pB^b?(|y zNB{o1oS49oFZlm5lu{DZdniU7(AblNmpy5ZpYX_jQUhXYl-SU3SAH?hGU1WoJnO$4 z2c$PH^6ZiUB?6Ij9FC?E*FjgN>@kyLBNlcT27GB-Uf-X8(V!XnpW|SD{xqQr&M*GC zrR~h~PpyP58w(g8&)3D_RU%`r{>Ab5%#H7d+pjXb_53NF^YrWWc^KVgiNE6OucAzj z0sd3}+AxdpTz{iQe9;~Bl@{?ub8PthU$clWBah++|K^MM;_!Z*MSS}8S6Rd_Vg|%s z!|tBwGb@0@@jWYOzWc18V03KQBBPXEcq8B`hC%Un>}nyF21eC2~X!c$*U8#=P3EmNt&B`Gz>Y z+AlF3&3BJ&{m*K2wom-LfVa8YXw|W{mc&K?%xxf9gTlnnT zm$~X!N5^WL%HjFf4?nM73_ma5aa(gOsq~^c`6g@bqDpiA?R}*UD}HHP#7AFqr#j75 z{h9Izrz*=&1vO592U}_FYDHk3MuQ#lY;$Gso zl5tbjDVVC~oi;Q{0Y=W}Sg`*Iw#Hz8;A3^r z2g;chtcCpzAUOUL!(QpNX5-9IP`fNR=-dP^;>!SK%fZ@~*ZBpvQ_*u;a3-ME*Zsj; zPnS-uH(y)J%NQncH&||kWBQsrT5z>W`;=TfU{?7MC8jg;Ngh_M3?1XVwx2ESXDd4m z7WVj+5ekoJ;{y^OHrB~^8lLep=jY7JH(5DZzxRo_PwO{n%}r`pv^I9S1eK9aaXuBof0P*CE7wWwW<~c0ntStExj7 zCnwr;``LY;XYO|o+asQU-q^c$@xYk6r*Q1Cs7v>_)|Q3W8i=TpeZ!N*7SE+j4o|K% zjn%Xv(qH#v)U1#9e_2v*PKLDloRt?Oc;g?)lZR#0d)?c5zfYfjl|$wwY{c!5`DTaA z1z*waka@1voCsgr|490l#zKtW4w<((WR78qClc{nA2Jv1g5f9__30*^yE@$(o*goT z^-mcI%F>Dz&A^VAwMX_ zzuiOTJo(FTeEnie=JUtb_kGBm!PE6a_-4u6ESa0TY^o=7Q3t*qGUFk0>f-ORWRkVt z+LE~#TOW>sUuenj$m7`SB~DI0{I_k%yoB|<9WvkOkhv()ZkEi=k`dBO?CHcS_?^UL ze#?i<&yQC*WYjqM{PFdDTQVu2b3o+`00%|jrY8-5 zUQFyu83UzWghM-tg(AiiWGKO_LosU?wbLF+@*FJmOR0F_drD(}{zXs6@ccYV7{^~XPZub%hv)yQdAi^H`PvN5 z>z6RH=x{`*@sLkknXA-u1@!|4$CwuMf#TIk>2wQ{T#HS|Fzw@w6s5cf+!Eg!C^bb?|WnMPKJd&>Hh%+0bgL4k!>2*B5A9j zk&ngtmND4urQufVT49A%-*1<3rK0~H8Wx>!kahp=$NxW4E)Q}#kNLFZ)q!HgqEk&?|qX^^L9xUatS|m5CSE&Vm(fSjp z#18hU%Jj6syUtkO7a82zmw;seTEU#`;WYIgb&oN=HySt*cFR(*kmj{eXd&c$L5P^n zm9H``+!iP_5c(8NJ}SYa=4S0#YJS)jU!RG~ZheD@WKQ|@pDf|xf(@1a$(k+P$kC!r z%fyV=d-|CrHBm*J41z`Td=!>vFT*f=$+2wchUhU>A4nK%MeF2nz@ZM@?N>2a#r$ncNbm~6d76m77~DvvPpifQbEWi!`H9OXe5G-FFhnxH6V4syi!vH zAQ*ftIrbUP&}Ui3cp>ebpujT5U{d{iUO4kAExpM0MZ>o0Vc_hre3S!FLxDVzvcAb4 zfuvD0B80t3N71!vn|j+j``Ov~6zq_Vyvu;BbWvwrkyVw$o{YdOE%>y9!nI^w_E_zx zpW2q{AN3Zrh3l6P-!}nHhT{DEl>+>t*a%YVCcvMIt|oAd`&Sm=msD>cvL8)=A0D=U zU6k-2U4UQoGo=Dmhe0I`0ho`DTX+z4m?Wf?yqg`r>pUNOUR)0~`c(Zdi$1X@VHIMco6X+cj zIRLJ=k-2&R75#3r!U7|0=m|o5OF2l|5RD9s9f=p>8OtuEG&i^f(n3Q3h&L?I?Dtam zal3@@g{~LfxeC!M*n}0$$?k~^mykd10&E5%zN1Ei`WuU=K~(hh6H1-1VP_mM`FoxE zPJWF>(g*aWya%PI{@yQl^uLA<8B5JRkbmk0oO63md(EdllSgJspWd8ubA3x66dEIg z#z?|-nTazbKB&qXm`)X=bl3OPRiCC8Hn3?brf+p}op;-ZC}8wQ0&J7YTFApIE6fAY z@T9D$xuAhfGdC@%zM{^53OY~vloaHwRFMAkI^)T%G28V0vUIZW4l9MZVDsBt{?sOO z_>k3KRs*E@Dx3DD{F8r-O=~gdBTsp0Z<}`7<=@Aqy{MVWbNQh*Er{sP>jV(z^>&p_ zJL35lQrNC}$s3xAx{%xvnFong6R{ch7Q;Bge>#2;pgkV$V=PBfvvS#*owLi`jUeqz z&6J{51g&IMkzQ{Vg`Pe1U^|?rjmb)fbHY z?hldB)JGzYsmJ7>edQ`S`~^jFr?8&f;?AEm7rZ&Du`^f62~}yUl9RtX7toXD_Ti?1 zPR(U2%~R*2^6c)(v0}#Jx6JLFVx%mDuyGdFc-s_i_xYY$y5wSCM_X5*T5k(mufgX z)-p*OKXR2xmTQ}!L!(UQ;#A6&%e}X>3sH@fN)9D`9HI5Al${^!J1`h84=`L{$~dqB97`?LDxpkuH9^yjmT z>Rj@o7Zb-NnjaQHOB)P})9?X(7KadP6`Gms-C9=&J57D_CXF{Qt05(>&Bat`#_?Qk zf5qHF(-|dAvT+@$QiO*>Gbt}KjX~8n>L2F5BNXv9^pMSqK&kI+XI*l*-FDV>cGksU z;ZSWx(dHj;XT3qWnaxY+kkCG>T@o^}2p4>d2N~~C2+>sH0gex4Uo7#oK`t+30Hq?b z0*I1Q5ySgX7s9RUQnll(n2KESknG+S)MO=g28p7|c51PZUXPqksj7zNfUg80!##n! zSE1!8T~ZPSae)~X2i@Iquh6$c9>I~e<-y{&5{TO%=Ao!^wg|6rWs;D2LUhEs7jvobRykwt_aA@S)9N>?cz;|W*4b`6DD*zznMMf2$L32D|I<%Q z&hfhC+f|gi7t}LwLd<(y1ZuY_KeML+R2baAg}i|;Zlg$x$A=9_c^-X8+g716uS^9O z#c?K^2!VlObdI6=+<*pR)nI-osmz5ZfLHcSE+VL>rWizAoORN+wyGhSJD19E>8eK9uXaX#Mok{xfqS zII((TqOWmP?cT3BTN|w$t`oiL~c;*WeBA8rZTe!u^ z!xgTh;-?dU4zpzGKGisBLFE+lXj=A+7oYw}J&(Q`>Mc$X+T}y47&gVJAE6iR$QbU_ zr&M@cg(hnUK35(l)K)vN0YQ#6VlRhtH9S3pS55^+-X$-FYjxEW3y4mCzDE*Q(Gd*! zaaD#%O*I_KfVqjj+J4?z-Vc2!KMz84(o}Tl&aM< zI0ja`N{wn5ht<+`m1I!r%}82**+g$c6Gxw+>v*#UpUEbB=eSc$<`MNN`Z51|mwVR? zZM{#`7QA~g?!ao(L~G;N@^Y(DsQ&@|9)-}fq;@5B_rP|cqdzju01{&32^L{53yy(7 z@UCgRPvYrV2BW6B;;20AqHXSY&|>WI5_;H%ZG`B~L^Fg^Y9RD}lyuMo10OUc72adZ zgi$q){#C_rSZJUg6`G394QCNUDy>^%(HF`^Y0pAIVi+Js{0*_)j+S*_a-TA-wPu!O zIIT#vJXhOOpB~uhqTQdk^ybx^l15M!$1Xh!VshwZ{(VTMJ!>KnthN@G%i;4L#c&q! z(8DSW;eWDz9xT+gBHus@aR3#es?Jova&JQ*-o4g%x-bd_bULC&Z*2uXRR-M3;19+enVm%~S9>D1 zqIos}s2P7suecuK<7A#Ff^pbQ`)gHj^voT^#%le!J?_qFkJsj1_ITU0wbf@ykUc(& zg1))$`;cEe!Q#R)CXp6Hw`w6pwmlbibIb5#8}!^{`qqGM0@kU;x+_wvCYwCwSTt!k zmP~WQFh=QBt=~nQc$}nz^P@CBV37lc?NksHmg+Ei1*_W?RR z4Et(78T#zz;mBD&wogXw+@zE=B`|n07@$rUOcZ6qBNtD)g|rXG-qYRA?%#ctwIv zabp9Fr}U{c$bPtYmqao-zngc^=ahAk9i=_FmF0{|45KG8rtavdY$5+-Faf8-m#<(O zc%At@9-~DonJP^**{0MmSTNaSfZE*S4>Hz;0TRpM_6MYPXM#DXA>or1^4y9Ig(jM} zTXc$n#g(3>4q9(b(0-nd;#--CPl=(3jE z@ETp6iyhd8_oo`)2WDlBFHm{HTQ$Jaa$`jX{=b#=R~FO5`XMD%`xt993<&`6w@l%o zf?*qG228Av4D*8k*F4BoE;Xav2l=NADIiM1J#%8f-11aIENp58^%2ehTOdLbZG2fh zavBY0WnYcZ@ZWdq`nIob z`|7r@{?{M=@b|y}{h$86{-^)=KY#m!w4?h!s5tt&yHEf6*T4Vo|M;Ij{_gJH|I`nd z{_(rJfBnlJfA_bK|Mx#X$nmvr|2CIUIjzFzoC#V~MGToKIOUbT=I|(Ec46MwZ8vHY zl&7?utA$NWW4CboDR`=(<4sA`ig-2SumscQv7JalG|pZu5B(sHsc^;MldZ=7&i?lK zhwvHAdFzM09~a}r!*?$I=nozH(OyU;G*N; zmOK_WCQ=@#e-&!(!HMpun&3k6DF7WnYJiDC6%guyG}zJm^B|EV%!Lla9txt1TYKLZ z`NaT8v9s_u(s;6mKt*<4Rs^Cd#gSfic%VdjrW!N}4hSRMAMO$qfPHz#J&=?h%C=e)wFL8%WLzUA0n zyoT!e_!6-Ahup*$SHNu(|0tXIvQG6QZsKDX=T$cGOBiN2)i_#`qaVRnj8V~Z!88S( z*B_lF_^dXBuuys6kutVFZbjXcw{rxO+Nn)eRX?|!8#2-<#Pik1q=biw&hfL2_)oC1 z%dd+%j?9zkNzb}e&!3(O#JhjjA3F62V|n}Vp6jDY9$!Kpe!CgIXmq^I3}2KJUwMY#0$cj{5?)AN zJ&lepa@a8RpODUN(M_O02%?>Sw&A~`NbiG*DU5Z9w+fFiky-_Iou;RNv+MU!+*&Jt z-hA)a*8WOGY42-xa_PRUan^mIeFC_mB_XAtwktr$%SxL?%pf%m4F|OsPMqQiqyPi| zM59xg5o#owF6KY(S*hq0KN-|A)ffdq!Snag`jXK=sg2_}nFs+&a2Hp{AKc2_%2yZ- z&F_NZ1}&$BYMUt6id+Z)c?|&7zh>FVmvRDk0o`z6pUTh~dj5PO;&z?}la@G5#BQr2 zHI}Y=(>xJ=-zOq}?)MJ2^qYsSA1?x?LtYo6JfQp-0zsB=aumM?k+-!x`dEZ#sfHpN zD_=DrioYcx#56%oL2%LQ15tO?CIFhhhJPn=H_scPSQEEJxR~knE%y=ATxQUB55f>Lvzni#t3vqGL(EH)U#r5-t ziyQosYgO7JHR3?s=8kiEf+I^P;{TBi&XX1VECHI+Bzb4>qeGi)ZI(hDT!6iC`|u)F zY9dHv60dTQOGH$OI%f>RK4EpD#J)8ut2v@GQ3tZppV(JS~y=0>>2$vZW9o8q48 z-l^_YN(3P1O=6YaRi37l2yWh~SSRJ2>b|MvhW7i<_anYJnuU&IJ1xJOVdBE$^jCpqiA-vI3&-y7&98lu?)$mxV2Ptu2UtQquzP*j_Mb4NsN}= zR=IaHBjH@RUh8{lRg@)QM2U60s{Eq?M5mvdJZosmpwJT%&0g-v3+7v_k9!%7zL##d z-i1+@CON$-iEZ_+Y3{1Gqo%lgLLJle!6+PHK`#e&xC?={u`x@=zlE~zFx~~dW&0IuohBn*zqSOV;9^S-Igkg-*W`>|-qqE>;p47Pr}Q`mx=#agH!)PJaJ701 zF?3OPxrw3gUJPBdll~FJ&|m%}CNiK1ui`I#2^Uadf)LNVbP$W;Y#qcV$dW298Du`71VIn)CGzm*6vnKS2l`l&qbi^uU8+vr{BrWqgwKIC zAc&dsyC_nni_~FEp_n^RFKh2=J$_=pOWO`T4!juWN>F$?w;aWBj&j$~4=HHNcNe@b zA6^O__wnw~&zy@6JdscFH7Ob1V|bm`hjm6PL1Ib)ErF&{3YdsM((!4Ny{UiqyZcYx z7v_b{7((>Oxv_WTqBtBn!fC{twZ-C*j+koa`1YM)NYvFiZqDHpjpNcZ_M{Ktvu}9* z3FCdkdKtQVeKf}QB{W8+mzH$fB-xQy-Xs^}7{l6plTC8*+!;FZ9c_|m*VjHtwl88} zfNQ~AVy;Nt!?}X!r3A1rKMyd2hx5Le0+3e=Jc&vr4VFZPKMpOK#7*|yp>PWP;4Fy3 zdq~nF0;P|Vxyha-c!~>yvmCy68&m?Jo~%^CyozUm;GoV4?{NriU^)nY4)kC;7<4wX zxBDX&=!e`37Rzqnqi2<{%aOT=g~?6bGUUTha{w<2z5$}e_d(voZ;zqH0ietN_=s4C zCm6gpiF*M##LPTAC47qyHNN?w2~v-x=5)KKjkja; z1LF|`5L*nb4=jz|1(U8*cc6YD7x%4UKVkc8fzvjGOIPZf!>%*~3Ue@L7}6B2pj~$< ze{sK^?{V*Ee`*#R01DGG9NgH3va)uZ09k7W6%^&C*3UL#I%laRh5VNd`18-WnD)S_ zGYxUpP0?E=!!Whiuu)YCfP-3It&D-K9V2g5ur_9~K^F5Zc3OW*v8nXl3Ru;ra{_J6 zl>nDS=ncK2P2lH8HkAiNkFv^!F4f|<1|isN95cQT^_6t(Y#|V5p$t>l;WvMR1GKZyj zlX2f%#$8lnhiUr0WZV}@(5=h6khGWc^Djw`?Vl~fr$16 zi(50W1CWj)49Fa(LmPHSEzMNUTkzorkT(4@g6JoK9FjtZjZjF0mg&9gsK{6&A5FC3 z#kZ0{^)>7pQ7smq_*McgTsG@ctR^h=Om4~juNqt`j-aBB2fkhL<7AOcKx{)2Hj#p9 z)Ey4}_L!&kGBLUN{e`A6y@@}immySay_}nLFEKCV9wELLsiAh?iEb&z!S#FK8(eW$s5;3=vxgU`|KdRjnQoP*5H?v6Zi-Lvgx->0M zt!MGeRUT6yki}83oNPHULsl@JcI~g}Y0lc*74Gi(VL=M&NL>!uep1%aJinwpr4HqK zMQ>>r(;?;rPgYhP=?<~^2oId54)vjD?LMV=`WHrJqwK7MmBsXhfKHS~lkgQ?hk8Ou zf=`_r+7sftV9jsVpZuLy(7?uZ$CV_`5>1WF+yR?K3ImlbpMpBZc(4dB)CZG-aB^y+uR~%B?ynC z{$6HukQd2PaPBxL!VUW|VX;SNl(u#?TjVH8-<3g*SCuXAJOcuJsKN!j9r5YM3KyQ5 zD#N0RnOHuB{J|pE-T7v)GK8J48b%VB$(NOAn29aFrCa zXxBUi92yVuCCqH>ZH)nQT)D8~c0>Z6t6<0cyDdLau`m_gmR~4e{^g(j4{^f93>$$j_oEP zBZ9uUd7pb|FDgWD>nTb6WOmUW1yGzvXCf$zhj%fR-au2@y#$2&O~{Ii2(+85cmt2o zx0V$bVMsrktat-F;O=ESAaD_HBAJJ)6k(LSx{rl3lDW>}$T81T{5n1ZC$ z`d*AT@yB@5WLZg>$M5-(dXhQ{3^Ju)w}+2$?p1?}YH?d01(u%Mf>)E^J>I68hhB`g zrKN6DI3QR(^r*75R)>e&mf9kD8!D^Ex~&@WwzSl3vhaj_-4-$dus^rKAG!&R|8AR` z@}K@y|NTBfB&tc^?y-}Yb_|z{0DmBp$D=uh6D3W#zXKN^L^uvvg)e6P3?d5ytXmU6 z=a&tHjbnpD(h-;vZ3vv&pJfI!p;ExNH$6?(BeWq3LGVVrT7^7h7^ch~M<)(1yjv_L z#v(YI0sKkwJ7isS#Lx@~rpCp}#`R+nd2_Zuzy*dl1ZS!OfXOgdzBkcs!yG7(ZgLUERL))Lw=xdHg8 zq#Y;-z~YT}aY9mh9X->id9nPzOl^>!%;khfJq!Dq7e;N6#&EC*S*y&*$-Y$>WG8Lk zY;YNGo_rVM-7G^30+E(!o9ZetD`hvVk-gqADg%Qs*UVjYFgE)qs7e?K2DtB1i36=K zi(kHa!8%#+ckFjdJiKx83-$m5)jy9oK9wPB=_8S|7-LgY6=Ybj^E1UV7X|va z>r_KA1g1zXf*H-201m+D`A_p89B$N@yxZDq_FvLpjT-KP09EZYUni#^OvBPR;!6lk znIVBJMCz603FA7UFDz@=z_=q))<@S9Zjux^d8<|N4At&Lg8(iNZ*^$Dk`}q50tDu>2uSRv(Qvl&M|k-UKYslxYddJ^V&J}=AUlpbbomZ_8R#6fx$U{a+C|`{q zVuC9ui7vM6$B^nmC<7t?6#oKF=>11tA8v-wquGWW6SjJ$O)w)8q1fJxT4ELST0hEG zCweM=56+NECboY$l_rVEdE;S`h_z_#JbZ$Y8WzX?@R2C62I!fxG0}?b4Nq@MhUVPX zZqtXlubvH#U2&{%R{Ox+N58VLs$$Rjkn*Ul!3BYIzc2Y0-fP{A*z~FEx~=sIBHe6^ zZ%a$v7Oo6yFk%y-Pzh)Cr~LwRa<8HQ`Q+FXIZOu zWYBF?8Ai64%qjWaku!uCI`1^K1)bE`TG8*FY6K<(40M!MCbxRB#Jp5 z$7F6uWlW(ij!pY6-b*1eA8ZNM3T+GY+%f*Td)x4 zr8XVeTKbuNyo&Oi@j$NU)(V>bz$`Yp`$Fi4m7V;yLpgTkoJSPpq#`(SK+hsEkR>OS z1j>0U4DUYGr1H{I)|dsQ6mE9hPqp$UP*+;p#- z?iGuvl(Mg*dtIM_cK1^L1lv#WJDPax9?1_P2w(2@#G(*ZOtPnW2CP5dp-rd7QTX{+|EM*oll{T zH)!+WrH{SnrXN0b7|P}O{p#qQ?e%>y-y)%U_Yxrf8!n`aior0p|1b;bGG21oHNR>h zy@fUS62iG$&U}KCOsW(sjCVY(sAfq7o0dRe(FPvI^CHiQb3l!WLM_MM_W`_vaWiup zBvm<-v{fbyZaJAxsdAQt@MI|=ER%@EbI20s&hZ#fD5%h>J@nDC|YO!E(L-$?ck-vGQAi3b}7Z(P+Zpo_VJLLVTjE>7|Ia(Ssuk)Z~W@w>F~ zx~~U$_4L=>x$2TuG1fQU&w>?mAi_zR0Ptd&WBS62%i&1W26D{39%ey|I^L#N=-M35 z>IU=##tf{UlY&Bhb*l8cpZm0|CSev zJp|KjiNIrnsG)1?4ecVajrsRRWBL{N+;p3G=1{29Y$#Rc#Kh(XEqJsH@qg>U!r^K2iy3 zghmRzl#`p>!005+(7ag$2ApW%GnK$twPw14? zlH5o5fD{U;P(CnDt))*`%id*5$t)gS%Ec-llVC|X>l1wA(u?@BTHj@1S7mt8hUj{b zXnzEjg9-w0nhvK#nQwllti~7q&WlgZl zR!kazu#|2WyCRJV5R(5jZbu$|UrCPaEhQZ!MU8eQqluO#Sw3;;i;m!vXla69o?)Tp zcO*ihQ^A|ck&H~zWc?Bn7TqBT*NlH0_m)_f;j;*TGK69)_Bw4avh6{ttazFjV=Y1W z7h%V?EZeHgI&x$PZzKefWL7dlR}u`gigK(7kqPA_Ylr_e%SeEa9Oku7!l)LgR3i}H zFH~I{j^yklv7e-6mV`}StKTJ+L;P)&rq`#_*}asNa67cGmTL4J9oiRtBez3)I>>K_ z_U+IXVgFtZ?TfbJ?a-c7$!~gSzeVMm-Iz&qO6t6#@Nkg?-@_b^sgt@b3||U%;`LEu zLSzv@0F@HC1<1kUV?xY;Eve^-cZ1HVxCjUD7$bZF*7Ht&FsZSrb|XnBfs8T6fTW+ORU|f0D6`9P$*_L-gzeGbB@if-($=sDL?OPe8LmAu4zQY(oQ-5H47yt-QJO*|>k}qk*>~tjiN^+;M@5k2+Gb07i>%y7 zA$)2R-wQMcfW79gn4Bo7>OA4FLzKl$oOl^uOSMhmvMF)~)Tc}b?~9X=*W%*h>12HA zEa*37p^nxS^xm_zDQI`Z6<%vIjs5Ybp`fdb`Ab-~?{Umu5C~sm%-=*FycEOcyOgfL z51V)d7g|vIoPT_1JfhsHIO@5XdHQf6+YJ;!dXvgO;b#slv!9I>UgEah^Qu-ReX`Um z+_0^XG38hVrYMkhOc<0`@7l%WvRokcUb;6^@MLEP4d5zFuU-{M`}r@kO(Vn_x-{@ZKXTSTw< zENS#d$476B&Po)dr(#;O3q83N3XPZVJ=JpJi3VwhXZ5?p#rZ;4OHtX=-Pboa6g!;% zHem3aS9Ige(aDqfn1b_qks(hBgqj0h;(5qxpfd?)#vU{|$s|1EWwj*u!-tv_%L3nX zgu{Oi_a(sx9fBz%byC>dCkpf7kcOPkkVuS3QE-|xgGW>N0#HULbpx~AR(Q~Wo4dHZ zA(wf!Ve)Cx!cvKKAyc`H_$i@BGG5`*OVy?u;M3IF=iDrMj@A(ligGsm(EC}c1WPR;p zF~1X)0iG}Vq;~oWP0zFSnO$2JS^MoUSm-tX1aW;ulA`@fV33lGQWkke!_u&P&>B zvKWGQOcFFdT3E0XjZ<*MF#vkM2|*-~PFZ@%#WIKKjpo zq>dk6>(FBOK^tw49e>rh-ACIC`IF6KDEP!tolWAi z-=*kEvNRP7?h0eybF+Br3n4&nahu8s*9j1xBq%4=fEaBuwxEsZ^Iix_9WW-tmsTr8 z#3+~Dng~%czc-%(I${K@i*$`~c7Pw3Q|@OEdlp~2AsD^7u{Auk-zG#f|E=BC8|FWV z4;dcWmFqrM`H#Xnf{D@od92`h1VtEB^zQ%-L46o=+y+NQ16UQnfkkC)GUk(^&Em~G za#JMWmLk9y@8`xT{8K|)bKAdv^x?u&dbaWgLywO04*G;kxMek`Uh$L?Fim)77hm2q z;fP#)E{k6BJ--PX6&oMxIz{xR0mz{E{wLNR1Rls72(AQu)qV9HgeFD4+jmIhr8OtF8hqwbCf-XctkdJlAoiha$=gU62 zU7()MHRQGtIu(Rjk}d=rh6y76^HHNvILXzVcam)1zz*i2eu;xWo?k^RxOkL2lXds^Xl0`Y%Dj=3L=D^@im|BFK#uB34djG3h|63}YG9^nQVmYN z=eZhq>chFp@%~ciZv66QU%dGm#=sSO_*7Y|1OB##OUvy${-XRIXR^$Vw_3yKYkpo| znGyRi20MP=J&j#8m}v4+{?u+1CX<{YZ7l{mH(TX5$p<0aX#Y5o*j6lPVlN3PRV8d| zmrv~EXt+f9s+d`VzjE4=tH%lnx45t!vCXuXN`hD&k`GIp5ad*ujEG2BQph{`h;L7<4+6~|n~%kzwVOtrkoU#CK9EaHj$T&7#mknQ0(mzL@?{70G9Vv=(e z6!k_bKFm9zqsazB*~B+cCS@;awmm$~w1PEWbwEHJN!O8p$5xN=W#p1UL$--+sV6LS z$fm@H9xx*VOielFq?*c1bA?Zml9=N{rccTp>zO-MdjF%vx|Eht4X3-(q zx@R_8pX(?Q;*W)y33R-Od=_aU5_vxq-NhP~e7NF3R2D`fvG3r_BAkWPRRr~s|G3+* zw?%I7Z;RaK`iEHLW31sBkeD|Lb6WRy?x5I9wAgz|OU*7+Q;9H6!ZZOCL=Mm4AmX4% z!s_@qluL9M8SeI!isIRw3Q`sBAd>MuQ1Hp?mLFA<`1w?jil->IQ|Ia@9H~>ONGZTY zpc+@^Hlh~VWHZTQIE+ai=T(905ReqcdM@c%ziq-8LwEH`?fCjS%iK}pCnWd8`O1Re z3Faws*)p*>`GR(Q)-P)x5`iPCgQM6`6+eay(m8A7y?y(%DU1N zoS}hI23WoBz>crD zxoo-F^)LkhQs^>XVvn35`%|4Mz@@9>(xs=0 zyw+}Y+iIh4=(PaDXmj?FVRBX-IfGP4m;A?xAN%^;h1}+sxeKdc)lFplmPAI^j7|;4 z--5_^jl1?c7a4CrH7^_EvdE~i6!54q(%JztSyH2boGO+dOUU8$Sma{Wph0S~8PBG6 zUQHFtrQ0iXvQrfFH0(ZMbP3CH)BuIb5}Hh^or9`MmW!EU?qRn@Evu5{ zP(Wa`DOoN6d6;UJCxBT+%Mrb!*``KF6AW*<)76CtW}$;Ot!R0vJ@?;l4I6>?B4y{^ zor{dqvgm@?bHu8TbinZA&*yB8RwD|t&S;Jjl@c}rxD;N9<`C3dvK9;~5^en{&ozsS zeqmSw_Pp4+`JctaqA5G#`?8+a4_DK|hnd(RW zMXfll&(xver>-M^3I?*&H`ubKV4%zqE`~zP7k3}zJgtWF0-%V3pgzR(vQIGfAfh{3=B$;v?b0l^+&u z%phu?m?B?rZLhBbT! zW>2Q1zDF{dOX{L+j5E*vRc;4CN*EeRi6nB`!*Ta<4{s8HQvD}caJ{Kt0YtW&?&jZ3 zFu>d?U$H%-Uwt5o05C~-LXnu-OWF$;BdIF925y)rB=P_&$7Cq0P*B63->%^&B;j$%VSay~pu8A$A{E zLV6A-&v3rR?GC#ue>aDdt|)AkJUUG@o#5zOU&Pp zZ{YC|C;Tm~p^JE_Z@7jo`do&6^UK%J8{n~I8ojWF0&}#tduoRA5mO;Un4ZGCvOC$9 z$(2g!$_ewz{_H1s(Icmr;!5^CwM97kr)yR zDiQu*1w})J4QilwkYaQsI8R2XZ~>rL9!g!>A$^WhTD8!3qz_UOoXXQTAUk=7#6lia z%43GGE#wB3spDHDc6OjBeTULCWn#r_o>H-BPszYqa=7LOR`2}dXj5}zncH>W&@}&T z#vLaGs}I)29Wl(?+11xaD}LfiW-~)iLCJ=!o%tS^EJ~{y1n>$G0JS6RF-MK)C{ zAiucKj^$lEWDu3>kAN`HB#6!5QSzWUN3KOh;1zwBgC3cgmUh*fW^KXGo3@Z2PU?bNhdcVc z!;ySmPm0@r%>%?I#PJOTzoGerwu>6~|F?H<%aJ6Y!l-Wz5V(K1$)G>u?!) z@2f6 z;VEYlin#*Hp9V1)@JTU0hyOhrCClRZ!@t~C+et_of`d62#I#Pq3o1N9gyXTV(ct@w zxL4==JU{r%yYrcoC*}`6^DE#pCpEHP8J~G~Xg0~?j2%doEe@Q-#}$5_QKXfG;%2(ORi`SB|8d9S?j`c{e;k^F)n@N*u_W zoTAB#b8~h3DVPKW0LTwSmOJV92r=MwQp^PCpvhYt#XL)QymKmH=}fZtZ!Ax}F>Wd^ zgv(FyLK!Zd^$z8jwI$dQF|k~%O^^L{-5ej?=ba;2^)PcrHjoQ6 zAc-h>$)wuGB{ainy9{hPOi$=+fG(8CTDKgg4)^<>rwnd%Up-^Qx{a@{4+?msPeLC7 z`KC`ozaY#lbCxyit(I_kc5dsxvXy16O#9=0Ot3 z2&vQZLZ<8<(F!M~%7hUxr9>6JBAf&X1Y=nzc_La?Ivj0D!x#kLqJrk#jST37KU4Z6y?*wiZw(C}<%+TDPNufw2RM5V)n(CCtF_g<*9hP`11Db z6j2JCyt_4~^`ylzw=SO1VW-&4T+V5A6zX|gSppEQLCnx7Py%uzVJX{$3$0CJ4> zJHE_!o&IUgeTht=2sq%@1z}63T8SdcZFZ{+7r2(7)LgA?@Nmlm5ue8I5n1c$xo!Lm z>>OknDSs`pbDE_end7O?&ttio=TcR)#d9gFdGTBVMmO^mX@tVC&h~lV<%bxM&w)37 zY|O80%#)s?9~<+VZOoI$_OUtsn2q@X1@Z*bojEbtNhqM47jzux2dUTYZ*ojYr=uhV zbxni;Z5_9StPv*&t6N2AXluePln^X42q@i+2}=~AI0+#Mo`mR)PeIBYg~=#RA~vY? zF|SB5%#*-Bz~4z?0`3(R0mu>rG&??92=7r`D!WSR6O^BFXV*MRASSnk&Gj;MxD&`J zEQMA65?&9iMJBY})nkqzYGg1TkUSv9^7~Mr)y|2lCVjk+Y}E&o>Mr?fasEQg+==PH zU*pOUV}$3X_nvo~PXiV6@rZAvPba&r@hXzFPsj%+0p|xBKT`%`x^i1A6&Y=CF;d@F zZlz_$hLZSvIjMVBXeDjn+))(;-Mbma_dcf6l3^bFS|ARvaY$6ib0d%){w4vrl9TP)UwxHfTi_8 zj``hC_XjwZ&SIxldi=rW{()@nv~0XC(8Msl6E=6!wt1X6ue+!3tnY-)ZM`nv3!6JR zyT3v=J|)!OgiVVz&+gmF(h` z2vm5_!^AF;8ify!L2$(5BKcTyPcg|?MX^@cEe9MK??UP&F|A2(2)RxugJkn{SeiJ& za>W3!`y3TeTySEF2_%VK-IHGGOEQ&JW=rUmIEkDtx*<15gf#)cQF&o6lB$Fsh9GlG zU|ZXkvUkir@!dqcA)#{55y1A5GRG7BCC=LZ*`$NW7=dH16VqEmRNMwQM=BCn#AS#- zXN;1IeX0@i{p6r$W9ObX=F`-}Ky ze3NB@-(N8BePZ|;7ALoR>)oRwyO&@mfRPb9;=;pKf*m3!C4v}idtHHL0a$L9FiAuFqW1O`Nm|Jg<2pS+#yGvzCzX z6j4Oy{feO27qPBt6(c7B2Bps7SjQr>%~qO(!4po=X(FqG77nYF9n+dmCcGuGKm=LRdGNYO-`USX~tka1%m&J74 zz1$qK>z^APKgr%XCw*0!MKnmAxeL?@$*teZ&ZNCEgY^%td%1sc?BvG}p@zP#aI9>r zOzBOMl>gkPG$mo63j${BbGmlAH%)W1bqihL2gRkAjq&fAzH+jx}Rjy>q z-oq9S_prRlHT|k!Zpa(n1z-w$$LoA3|=`_>7#O5;Pm_yQYK?CHx^o3 zY&@TmwNd$`q>Ga5;#z2Xbm6+Nyndu~-hSEx&$0{UeC|zo9CT*4e|9`4uw0N8PDQVN z#vk?|FPmVi-eylOccpA?Jy)j>DFSfwL98|`XLM!8tHgUdc9k(!ayWd)reQY;^AIDN zXY7xXPtl{#azn&PCjdiu&-d}KVG(&1S4~@_9 zJ{x;tr>2Lm0$ULrAEeE4ynI>P*2mYrok{{Rk>~vWkkW$W8Sfu$N8f+1K=Y@$h?=I)DVNJ5$*^%PSnL_kRz)Wvle`Qq8#PY#d?x<0ocw# zMb_l&%$nprd4hA~2$7_}l+($?TuJZRXA++oOLqH8_0};m2Jo230kTlAiEe^?S9y92 zxCn9=c>UZsreW!H=5Q?gNtZ7WBd(APhClnJfn9DQ;kDgMadbb~f^%QBeV(2TVKeb> zP8Xa^UG3{lTA|)HI(E_)G`$=~Oin>MPRS40FN0~k<;;(gFPl&uVlkFXniS4nfOqyy zGn!CAWcN4(oLf8rrZndJ8gtSyk0;``sJGaIh^UsO@9>4Nv`qup{b~1aN4O6Mh80h; zZQ%t8SmTBM5~faObGn&DPWj90FR~KsO&>g+G)-8+je0!M*PSS-1QEeqPGcQR?Z&tl zO1})?Eb$qaRbrm=+41lhAT;@?qZc3fWL}yKj)I0E5mWs!;tK`P=}o(0fUbAe4vL*1 zuYB%(n!CC5d`!V<;oi6QCRLl&Woa4tvvY9GxL$E&cioN=WUkoLfg;{k+`f z6OPwtVSO5X14)(+OiO3PURZ`6wh>RG+D1!`V`ZXDzNr-3*w>PgP!mgZM=9i(Pcm-| z1+#Uk2RJCF*hFPZ3$oNRbulad4B;Vp(zC?KIbzXDmCFO`f{asRC7h}6TN~7|zR%M( z=)2Eb#-eTqIc^!ti=m93^^r^i$vEh=sJ9Pf+|8^|QxS>z<&1C3(vMyzGsr?mC9)=3 z{Y#2sw2gCYD=joSZ;3ZPI!)#YuiQik)4SJo8U0$D!aQr+PjBBY)q5xjyK~_-tX|3K zmlHs`e4bs@$gqWur%G)Rh+qm-S{?tXkQC#5itW&tZWn87wPPTQ_B=)$RHg(uI4<6RR*6zn}F@Hja<3e6T zEWyUW^Ub$Y)gmMUAcueKjN^%EyrXRp)#+1JPh}BH^zxVyhm!MkCwbs=_HerM$f=EJ zEkBzTrGd@0-xI0jIy1SpBtO?3Nf~C~llSv5C;cxOhHN<@#V9k_K#+& z>-lE1JTeMG*UMqFr!w@luh-O_Kdth>yX@z4VJ*ph=9G`tHkO#yPPa`Gju5>K-)>-3 zO3XQX?r7>4V>z;|9g>Lf(vqWTYO0o)$uEP1ST5G4N-3A{*UBhYcO|17`G*YK@9r1g zjsPSl&tXTRlR`R{f=JpjL6x8;07feG#CTGMMd*;`F_s{y80ewi34jL20k4j5_=6%J zvBGD0^_0*~yuJJKz)F72wg9EUIYGaR$vfrRN;yu zk~RdECd$|6K~k8?B>}&!mP*HTEpB48B$$PFU0kur>oadKru!D&FcZq`n?U7h=GVrR zmQHHUbl7w{_V>=S9f}fzxa|; zDKQpMf%+a9-8!8gD5f9KpZO@!t!3)dt-O?Ai6`K}g%#yU5O2+#%w%dKTg~3m`?7Yb z_XMbQ>2OhJ!qSyMi$A3-?)(ZUC7zW&;&J~5j<7YmzRN~E7n4yNHTL`$8Jw!rm2#hrmYHiC4YPB|^=WD|SLm$X^mTGBAV0gc zdE|=1GqIwwqbnRoN)IO>-dh#6Ah@zt->8ODC*9!)m+5<-=`J3f)$#guHTp`;O?|1> zW8d12xmzeL<)DhbQVXCiM$2Qr*O$hR#oI!mYfHb%7R6ARWm1gPOwogpJXY~QYmXkA zbyh>zEH8^XmgeNaKkc16bgBCK73%=w9*2N>h&RujReTvOmkDuvL6R}`?zc2Km_=J_ zF?&%LUoQ5zZ(8lqHVwf!@Xo2fcXK$zk(9G0qsVe%G>pKV=Z~p!sKA0p>*riT-)l3J9zo=jl7uOG1j>(!aCZzVuME=F;$a8s{Vcg4wG1Azxj_7=myptuAEUo+v_1CweQq?`;Qez`+qm3LZ0|4Wu77du%H z-GR|R|IXxf4nfUgot(y`UO}x^NSyfH6P{d%P|LkuJ~4&xG2wvA#nXD%xccwGK292L znFkXNTp}qETI`8Jd(>3I5L^g99P9{PGx$#*qIQ-iBidFO->Z;H%x^Y3Hxt=;bu_Ek?%VkmXD1=pEf8O z3Rp-%wtH`IX}d$J8`vYX-QJd4*oW?w1Y+A=+s3yd&*U-K6wnlRM#%+3Ub;dB=wBLb zk8BQP4oU@)Ch`vRLSQnt%(=U@X3nT~!&uzw(dC4dY=D{F4#r4rM7Dh=q?w5~qF;?B z3fppj#x#DeXA5pMwe??f(DtWNLy`v~IWGIpQxAJnYDh||gAdeEUY)5bKn>BgbZ>NO z9#H%e_YW-bNShPcQ6B4Ntkxxqb+VZI-rL49pSM!5t2%d61&9ZT9x^7A>2N6o6#88W zFG!I?%EKI9klwm1G!k=mWXljjkL;QC!7&8l-=FsX`p%5!9HyBlYQysdHO2#Ib%*hU zwQv?t5Bt@^WgddOYi!14@uIq~-}Xwz!xxiNvbM$>7!QS%&R{_kj(Es;{7A~kwo`ke z_|Ec`7knpoc4AtW|6uj&TieB7KOerga0N_mTFn!d-m2mleuy9s_|A1R-48BNY$wd5 zvzQwLnfpckey9?*2ia{~B(4bL&Z3(sM_W78b$pl|(YWA>)Tb8`Pno)dmG zJu;X|=Q;J2!Pv&nr+7{n;UUkdPxQXLk>?=ABH;j!*aBtcKGe)p~qtyrV9>;+1Ugdy}`|0g3%DPrW0D-gwAN& zRYZ5l`U=l;gzQ$4=~p6aor6=R<|yn@v=4wYKms*l@F+fl%PLY1%A7P#yC+Kom=yLy zoB`4o97;I{2#HfBxPQsV+xgGM9wE(-WH|Z}j2Cke2;ay;;s*gfozDIMnB7_H1&Pq-iT1fO-QC{;besIO(v)WXk6E80JeevfX4v|7JM zw`0tZYl0Rzx*fkeGrN9!1K@w4ilg7@HotM0fA4oJlOTw)a>gadWLtQ=-u22Kk-qn? zJ1n?9!#aSr9l@|B8B6QHrJUa|-vB_4bXV1AFSznqEqMFH*Og!vG%K-8M`vQk1kz(%IS+RR_<;iHtOTbE zTdq8Jst+i~%vK2oN)Zlms04F-E;8vlFWQDY_w8iTU&5F}_Qyoh*p0p`CHVR*rZiwM z*rC#QT?%=N43LVEaS&ex>&==SPg^p;N$L%rogNv#uI%rmD4=Bq#($+{{G(d-=C*}$!04ON35i6 z4opFOuQ<5K@^Y%(3tGN|Q-VYoE&al0Jt2ROQ7?BTvuZsSd`x@3Up!84?`?_tZf{>( z`c)>aKZ4NR$Gn5~`v=C=+P0o(e;-r-R<5mAGWCy<=vNc-%+!yXm}k#c`1}i={?f!e zSz5MFd|jq*C+vYt|H~~c-;AfzZfDn9PJuKv$5yjs_mkm3rq77_?OmpilCqWQk2|(j znSPy@Z!6PhYGY^qB{IEdegIT-6TQv%0o<#^!Az7vrS{F$6a4k~#a?v?O}<$){! zHU^8va-u+axm|Gils#wks8At+JPaf%|H3sF2rEiFt4&bC6Mqfs6bL$dpky-4}z;+ z)a}L#qu##vXf|atlYXHt=tmc^-aydbrYy`Iv~?RfF@OkY;3>LwP0%1$CPqqR3!*A- zcLfB4kaGM5H^QBF7wm29JaD`Ln#K(bd!Q*{Y@#zATRIDP8?AD=avuQi4&v9ri?fho z2_S2m>MWN`V2J|^tSj+!d@2Q6O0ohcqO9vqwIfgTPfQ=n7eEkwtKWaoKd?4E<~ssj zbEN0}PFz&vlK_U`y-SBa^*09tm73>6%DPe>_iB?X~={p!4E)g zLDVN*`i=Z}z?@l;_(ixrY!=4BP?&K_o2~&OBH%>8%HX9nNb#2xD*+aOr--V$OfY24 z`8|4<#Kf~@&*K+iw1gI2T0Esi-R%akK<@5@CHIE7?1?lr2cw$#+rOJ%0G`$u!t(Vz+uj zT}WwyRNQ{Y^ctXH-4rGuC?Hu_Ufd1?w|wO}xzuFxxLv;sw2J+dFEn;-IQf7na3V+t zSnsKAT!vEVCeZAGzo8|M#3~De9zca@0+86V@0vIO@M~sc21e_0C46s09~`-N`xi`wNpSSTFA1+gbA0O?#fICL9b&WX&e$8HB?CvgCFWN z(3^?~m`*^=a5sG99-PNm>?~rR4`=L+2s{E{er?}RRM6IZA_A7;aEnd^yo3Vm5kY4- zQc#L~WsO5Y8PbJklL)}yN+Tfl{^&wJk2wrLA!0jD4kG~YP>%q9bX-&!SWN3;CsTBt zL^DCagfrghLXkC-`(3IYv~7T@YiH<@fXOHZx+J9@i@mc3>^u#iDiE%HvNdGCbq-p` z&sbx2=hx@3=OU*eas@z!k&3dGY%^61PvO;$Vo7empT-lf66<+B1SQ8h zY##}ahCnH^g%c&AhUQ;nw{s>(@;#>oJ)-@T@Fz}ztNmx;1xYU&NG`4%dtJ6Y;zjD{ zB1wX7E-VfvQasS1vG=#gst0R~Qqf!?SnC0c)Sk$CI-RV&b*yLdQ$6IOo?7&=;S4<~ zp?B=rd0%J+zsBj8bVd;o3}O+`ofZ)hMpM9)L=;g@0aHqCg{I@lSt6${5_|{>iAg5x zh4^>9drI70$^yGjScql1N|p&&Avg0Gn@-{nridefvO1b*uJ>j@lRg=^ebAf8#CD=@ z7I-vZe6Yi~9wLfVaxFc<7MyQ53pvN<@$vZIZ4c7Hb(T5nmh4lOQZ>D+Z~MUu=7`&2Q} zK&`Ly29qIL7(6M-swZcNApgix7NIhpL~C{;BzljjFm5_&Y-EPG*+)xG>=523GFL(sErHeMw>{1fxS3mSpdXs?`w5O04ASwB-y|fQZu^+rG4V#-78hw@&=+ z1dz(nX)PU75xPQ1vKFA#BsW5=p-T(3yVGP~Wk|)s15ZU#W|UhZ(d&_Pq6=UXazezu z4*emYm`TGo_6bpxc$g?E$iS?{3Tg+5W|jZS?!hC>Yj#YI5XrEBLXzt)8ncs;n4A+t zSm^cjQ&n}jt&sYN-jQMBOeKLQhSE+IX;i`v$a?}#bRoyES+hHYj+q{UwoOokoUCbW zPZGW}_JyCdDE{y>-;Bh&knSMig>vV=B|eH45NZ!mU*w_%!nklSJHj_DZXfG&()2>A zB=!JyS|7Avdnb|Ky4%ck+iZjz8)jF<6e+>95Qj5{t~5ZHfwLj$mfNqiIlHD4kMg-LdnLlt1dx~D; zIfuT=^>=CO^pK#mB8bmOCyXf^r*gVjS>%_ar){UPn}}R8B7`q{fa0W1lJ$~JnZuGL z@Jaw`S_u41jjZmqzAw%&=i5^hq^PrDUgpt8ue4rP>*b+T=a{KDaVXVMHdZ|s+f_e8 z86g{lTY0lgmkrOh97T=@OkHf;81IVUh&?C?WmYTFLqPDLpoCssKfW*U^?D9#`S-v6 zdvLaEP5`NL9EKs3NH8cPoTTGe?K0(KZ#-@xllh#a)Hd>$Suwj=g7Ou zE&3HH8uw7~&$fyVO(c$R;{a9TI*R>9Zppx#+~VZ2o1=$GuCN2SFs;%HSrGT^X67ZW zO_-Y)P(p4N$AUf8F^KC0TP6o_&fU?}PDX8Ec@{BnWA9~UFS%yra5`x7^;f&7cUS+o z{3DWu+X5utL&PT!7&XPe(ap2X@~^*39mwC=ZTUOOU~$`ez-!wRxrjiX&ai$wG_k85 zN=u#^lyqLmYRShAg{)!>gD*tLlBysY*D7PFMX;5zios0$<%47_p`wRE7K=})<+zX~ zJ6PuJl#taneuOOgpWtdj7VigaV~hq6JrS~)q1lMHLY65%cHEvMr4Xp4isn&^w^CBk zsGk~p^{vbjYJ6sclFna#<`F(Wz)VjI>CbN-e0p z6n?rfLs&%OR6Z$FRp)+#>OMp;n@7#)xl*B=rcuztu@MF+%p9?~;^ zu3i%zkaxT(Iv}!P@x2ms-L#DElPik2H~kNU4X+FPDFz6q|0o%@ThQX z6h~Yyi4oE`JT0M#EjoK}sCoiT4#lGEVj(=zMEnuUQ`lv4G_ZL#c6rYq01>h9I(HYV zOBWh@XQ9`TGRo$|kc~|=9Utzju^#Xhf^T$;{!G4`hni^0tx#H8-hT?p)QxJh+j|W# za77j7Vqqen-k&n7(baJOA+VNRjgurvuKsSjn(RzvR(q>(x-qMza$juCxIN1_h2oc* z)f^I$vrm}Sl2#Un&sU_-e|ogD#Bc5zIvl3~TbOg3ful4FHzniWV@224IkeXKvy zDO*&s(N3)scRwecdaI+O3~O(aPQQ^|jU5siO$Zgy$nX@!J0@icjzBA$jXg>|xKhjn6@9HGu^M!Awt%M-)` z9bt6HqTNXILZ)E2De<)48ZK9_%|*S}MSHOe*o4y2>($jgd9SnEBb`P&h{?C9_PSZF zCI7~68V2j(^fu0o^foeY$t6R2s0VzeJ(2IxI*Z}9hticiRg69!ZU@zM0{Qr?-*(1G zLRz1$Ln&W;amKWBDL<`ejHd<-pO=eCKNhm&;ur*DVCkm*jas$n=&fy1je~A2jE)@x57m*S80gL?I#RG6cIw|nu-{as( zMq*%$p^C2DoHB-PS^F`?CCEWA5J2gupIrTly*1bZPj-l&@c?EjvLHnWm@fF6>>^OD zIb+TTxPi~*KT1VC=HX=GiW~Tn9v7!B5{N0+n+$7=)FevL zM9Ph{h;XQ=DSU9Wt#3Sx;d~d^-?`i^ft@aip)y-IVqkyWRUVmX<1~MLwy2YHWhdAt z!3}?pb9FY`1Jw3CjBZg@?D9NEPs4s~FHqusy?Jg z)p$;>mkK*@P6;{rJr17n3~nzV#E|Q)4CV_jWsdTY5{mQ*f}0HuTir!hYp>t%3$j_*Ar8n|uoq}f2Rv?Ovzve5X6 z-0s}R_#>x?YiPj=9^~sck0f?)e`tyJnK;tF2zxMMj3GdEg;TA-PCk8~G7KgQk6pJDU$XcK*3ID z3C)yD;x!ye4*ov`A2*@oa^Oo#8^2!UktKbrW1e&U;YO%MkXYc&U#f_K3enG1e1i{i z+CFoYGww~tqF|kh%eo6<6$<1c2w*Ctt}()~LZ==vF-hs=kXbSk(_hq4$kO>j2rc7E zm|gj~5Kt9A{qg7VnTgMBzYQ^nbg-BTFIVCx z2|;sS04*fKr(K%msddcq$uKl|^@Zg~NMM$I09>2%H54f{$37cQ_LMVg>z@9^rqvp%8-0#Sm9P=grXOtb-aCGcHeqI{xOWE#l(*Lk23{jdM|=Zk;) z%hS^ze>wz208E3Ma8766riz;tep>YslfO|>UY{HKrS;F_+qrIuP^RdVO_kV~Z;#;1m>eT9{-P2;Lu_w5;H!_uS0P0!dE zb9?_xyVAHxk5D`d8W8%SG8!MIFr|c4#^s7_5uvt(e&@os`y*@4TdbpOX6{_wZI{q3LrcKuI({Xc*HgHnH&fB4VmKmT;` z{Fi_I+yDOS|NY}n7nlAc$h80a>EbVc`r}W3e)@m^@r5Po4C$78TTpT1y1y~?{m1_K zv48&ak3W6+umAdwzi0oP#c={8ki!JnHU0EKW+h@vSHc|fAFiN+O+{Kdp`b<;`$s9L z>`ux1+9&6iYpA5 z1xbD&q!CX}hRgnT5?sC*p!{dn)yjy_47PLh#|u+cw+p?r2F2zixn}?P_;!6-Aj?I* z3?|I%+lTtp7m^`nS=%HYXln`<(H6DOtRDAeU7ND7ng5M}ryGJM`%X9XtWCTWePOu} z+Pd~-?QaFpX^YysH+M9viZJ4=>C0OAGLr9$y}U1Mn`d}HWYZgmJa%YV8gcdPr{uPT zCyU+D2{}NXVz+9Ixex<)^(3HJ1Uoo-zj*3DWi8uH{6PA`F%=gQJJS9(X}EYAP;zL) zeM|Z2dWjHH^s>D7vqA>kTlWEWs6;DHf`{PAkm4x=-?f&@72#M41w9casm!bhM0soY zCj|X+waCu_EZyI__I5n3YvWCvWbIW+L(|@sT&?Y8ab&f(jZRM8<)ahiBsSErQm`;t z0NcD}x{`ac<}HP!C0P*7Hzp+WAsNq2?vYVXp1FBy1y0=^ncAm=KIFEswkOX?Sul|H zZ3RAuF7FxCpT-WDxZAQ=#Szlmm_}=jHh2QitlyG!U^?8K0Yg1ePz?w$ux=by{ zOds;N`YdiHsaX;=A&E!w-KlGFq_6dbpfvgi`Z6VbQLWszt2Lp=c2yRHFR|#Ytr2aq z54)%~t901cgNeWSm&-sD7B}3xm}}4Bd(^(QPR&Co#m5e)(Vi*y!VxUb5l=(z8uy>J zLl15t2sIJ<6|u_AWBW;uboq&2FoBHxczBhN2U!Uc#=*G-PKLuM`OV7}C(yl&7}qI_ z%HbvpmM|3|iuV^n->CCqFg?#vCk~d^=@Rlxj-aLGOT3uMLW5t$jfuJ3-h9bA2^QWf zTh38-$tpi5y}8@0&KN{e!vl~ebwUGe0c|#)XSJ4#iX^day~1Sodl6J z@Ef_{a#7gQ-jsZ!vUMee-38}kPF~D7-p5K+8t0?jLdk7oR5v_ysVU)C?m_pJi6!|! zdACGF1m(cZCczQs;nYU*=W@B-8M2ureIySeSE3wVl`Mz9k#7X2_F_F?BPF_s0bz7%czPyYg_K%E$&yRnSkRnn}nxp$q zTz)*?_|KS=KKw^>LkURH$nrtr#c@G5Qv2D`=!3ebYttaVJ`$*>X(S)8mCwP?EO&-T<@%Q2X{o8mulK0=nx932KJ5dJW`zo6>F*dmcBNqmzwWcY+zANw9cU&#; zR6c|gN9sf6yW@Dt&ungruMYTbB=c%2F}wqL>*w6q#PGc+zNx7{5-EK7+>Ev! zjf=)2T3E7amWKxB4If}hD8oZy5tqM{6z3M|-J#8n!v0$!iE<7y$u}G^`vOHTH4o%L z6EaZ=p;dVu>hH;T&D<(gUjiD(WKBJuu*h@Y3BmCBOR8`>Ei=xQu1T0x;S0<+g+do1 zAYuO=T>ZIB^>^1v>m6H0&E~=E3rRhgd@V2MK4HkUY-8%HB{T10>3gd)Qh@0rQ+&e) zv7O|!JPv%diLR*+teT~BS)RGA{p_J_}get}r~Bdz9W{CEAwBPB%p&Dp7m84)C51^fHgrv3`=AAPF0-0Dc#6RK~mOYJrN znQ2w8|M_1s2Zuo-*C18GHUgFWmSbnw{My(dj}jx)yLvG8n(Z;kuN(XJnOBUxm_Kyr z!q4QT*nI=$AG1pWP8yRr#eZ@vd;`uOX7q8qzv`bC@6TL)f4u*7Q@^tQgg>FJuk-$O znm>~JpPcRw$a9DMZiLU;!13l0o2R6rO1`b&I+m<%OPHqzL3$Kc6t5TDYS91{YTmzTX5gb59 zPfILECn-p&k~oYU{lr;PY6TtzF2V{4z*&V}WD6p)7+zu=foq==MazXpisFzH*XK85 zlY=ioI9xF*i{+KZ-8z=~Qi-+{5hk3FVKd`NrJX#V%-xPq!??{-y2<%k34)2QDvH*3 zK@F18S>{CLKJ<=oq>yRq;_+(9kf$hFFb*lMP~};r1;70yMx9GA@u-$R^H0S>*~^0&T=5y>bffv`2HNk~|!!(O0Z|90CuLvW4uG!qDqrD|X2$yEN1z zmVJ%@l<`g^aV2|8rtLh1>H;o$@z`fH3ZNcRTyqJc?p`aS@=AU!QRzsc|GMl*l_CYW zhkkRs{!fb1pctCoy#@SAb|g8JD>Y@(Hm3ZKg`zcKA*$h}{0~-8<$vz4fkE&cL2s>q z4tz(N0KHxo(1FECQKl5o`K-1JiIzCOVYB!jeX+%fiq3Yx zTny0@LUpB=w=H0VQmzOuQhEX|J%vGG_R<*{x#K8SE9+hk$*a-yKGn0%ruhX*07t^4 zP^le7>!Pn?lq5ovRk_^5Sf%hzUc#jLr4xsbW*-UguCz=DIQ%!+QEzUw;B+=*ct~Jb z)Gm{T18oyI0%~ znG_Ee=Z_pANvyLxbTRgz@=KdDwZ8AUCbIyY)31zv;fvNkC+gsW;fl;QWd^a1fg_146BP%DX*9Pkg9neF!sFBq4_CUGJR?vAW0L; z2pT1og`r_Mg*-$Tk_{`U+qqE)L?#SK+O=urP#vH7f=7do)E_3r|JnBd+1 z^Ry1KV%Wt9YF-Db1%kbrla58*sJ7428QMxV9Vy8%nS)ta#59wInyaPyG-i@=@M7{S zPrTxWc7I>BG0n8*W&M!!GWE-PtKd|GvfEEK;bmkIxcijSvP>hUUQBvVvL!r?dFpc# zgkW2`Hl10!v2N<;H8!l%F~bIIwBnt9 zoftK4Cwa-+Mduo8@(g@!9OuYMAzbQ5Ce<8~H)MEcT5Qs)F{G`^68m@er8oSXLd9wM z3_zJ=ugW{l4>BxMOe9EOA6=Wq!=qOxPq&Hmrfv=U@%r|)>Db%1jBK2p>zHX6QDGH) oe&d*@2iF1i$@#K29qZKzaMLvA>Fw(P$J^JYV{hM%c^FUrKi326 { + if ( currentYear !== fallbackCurrentYear ) { + setAttributes( { fallbackCurrentYear: currentYear } ); + } + }, [ currentYear, fallbackCurrentYear, setAttributes ] ); + + let displayDate; + + // Display the starting year as well if supplied by the user. + if ( showStartingYear && startingYear ) { + displayDate = startingYear + '–' + currentYear; + } else { + displayDate = currentYear; + } + return ( -
- setAttributes( { message: val } ) } - /> -
+ <> + + + + setAttributes( { + showStartingYear: ! showStartingYear, + } ) + } + /> + { showStartingYear && ( + + setAttributes( { startingYear: value } ) + } + /> + ) } + + +

© { displayDate }

+ ); } diff --git a/packages/create-block-tutorial-template/block-templates/editor.scss.mustache b/packages/create-block-tutorial-template/block-templates/editor.scss.mustache deleted file mode 100644 index 5d0b2deea6c10..0000000000000 --- a/packages/create-block-tutorial-template/block-templates/editor.scss.mustache +++ /dev/null @@ -1,13 +0,0 @@ -/** - * The following styles get applied inside the editor only. - * - * Replace them with your own styles or remove the file completely. - */ - -.wp-block-{{namespace}}-{{slug}} input[type="text"] { - font-family: Gilbert, sans-serif; - font-size: 64px; - color: inherit; - background: inherit; - border: 0; -} diff --git a/packages/create-block-tutorial-template/block-templates/index.js.mustache b/packages/create-block-tutorial-template/block-templates/index.js.mustache index fa35fbf272922..117d08b866980 100644 --- a/packages/create-block-tutorial-template/block-templates/index.js.mustache +++ b/packages/create-block-tutorial-template/block-templates/index.js.mustache @@ -5,49 +5,41 @@ */ import { registerBlockType } from '@wordpress/blocks'; -/** - * Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files. - * All files containing `style` keyword are bundled together. The code used - * gets applied both to the front of your site and to the editor. All other files - * get applied to the editor only. - * - * @see https://www.npmjs.com/package/@wordpress/scripts#using-css - */ -import './style.scss'; -import './editor.scss'; - /** * Internal dependencies */ import Edit from './edit'; -{{#isStaticVariant}} import save from './save'; -{{/isStaticVariant}} import metadata from './block.json'; +/** + * Define a custom SVG icon for the block. This icon will appear in + * the Inserter and when the user selects the block in the Editor. + */ +const calendarIcon = ( + +); + /** * Every block starts by registering a new block type definition. * * @see https://developer.wordpress.org/block-editor/developers/block-api/#registering-a-block */ registerBlockType( metadata.name, { - /** - * Used to construct a preview for the block to be shown in the block inserter. - */ - example: { - attributes: { - message: '{{title}}', - }, - }, + icon: calendarIcon, /** * @see ./edit.js */ edit: Edit, - {{#isStaticVariant}} - /** * @see ./save.js */ save, - {{/isStaticVariant}} } ); diff --git a/packages/create-block-tutorial-template/block-templates/render.php.mustache b/packages/create-block-tutorial-template/block-templates/render.php.mustache index b971a023985e5..1d31cdbed2836 100644 --- a/packages/create-block-tutorial-template/block-templates/render.php.mustache +++ b/packages/create-block-tutorial-template/block-templates/render.php.mustache @@ -1,10 +1,33 @@ -{{#isDynamicVariant}} -

> - -

-{{/isDynamicVariant}} + +// Get the current year. +$current_year = date( "Y" ); + +// Determine which content to display. +if ( isset( $attributes['fallbackCurrentYear'] ) && $attributes['fallbackCurrentYear'] === $current_year ) { + + // The current year is the same as the fallback, so use the block content saved in the database (by the save.js function). + $block_content = $content; +} else { + + // The current year is different from the fallback, so render the updated block content. + if ( ! empty( $attributes['startingYear'] ) && ! empty( $attributes['showStartingYear'] ) ) { + $display_date = $attributes['startingYear'] . '–' . $current_year; + } else { + $display_date = $current_year; + } + + $block_content = '

© ' . esc_html( $display_date ) . '

'; +} + +echo wp_kses_post( $block_content ); diff --git a/packages/create-block-tutorial-template/block-templates/save.js.mustache b/packages/create-block-tutorial-template/block-templates/save.js.mustache index a11ee432a4d44..944ae4c29254c 100644 --- a/packages/create-block-tutorial-template/block-templates/save.js.mustache +++ b/packages/create-block-tutorial-template/block-templates/save.js.mustache @@ -1,4 +1,3 @@ -{{#isStaticVariant}} /** * React hook that is used to mark the block wrapper element. * It provides all the necessary props like the class name. @@ -16,10 +15,27 @@ import { useBlockProps } from '@wordpress/block-editor'; * * @param {Object} props Properties passed to the function. * @param {Object} props.attributes Available block attributes. + * * @return {Element} Element to render. */ export default function save( { attributes } ) { - const blockProps = useBlockProps.save(); - return
{ attributes.message }
; + const { fallbackCurrentYear, showStartingYear, startingYear } = attributes; + + // If there is no fallbackCurrentYear, which could happen if the block + // is loaded from a template/pattern, return null. In this case, block + // rendering will be handled by the render.php file. + if ( ! fallbackCurrentYear ) { + return null; + } + + let displayDate; + + // Display the starting year as well if supplied by the user. + if ( showStartingYear && startingYear ) { + displayDate = startingYear + '–' + fallbackCurrentYear; + } else { + displayDate = fallbackCurrentYear; + } + + return

© { displayDate }

; } -{{/isStaticVariant}} diff --git a/packages/create-block-tutorial-template/block-templates/style.scss.mustache b/packages/create-block-tutorial-template/block-templates/style.scss.mustache deleted file mode 100644 index b1f1241345cbb..0000000000000 --- a/packages/create-block-tutorial-template/block-templates/style.scss.mustache +++ /dev/null @@ -1,17 +0,0 @@ -/** - * The following styles get applied both on the front of your site - * and in the editor. - * - * Replace them with your own styles or remove the file completely. - */ - -@font-face { - font-family: Gilbert; - src: url(../assets/gilbert-color.otf); - font-weight: 700; -} - -.wp-block-{{namespace}}-{{slug}} { - font-family: Gilbert, sans-serif; - font-size: 64px; -} diff --git a/packages/create-block-tutorial-template/index.js b/packages/create-block-tutorial-template/index.js index 514918e70ad8b..12c073d841fe5 100644 --- a/packages/create-block-tutorial-template/index.js +++ b/packages/create-block-tutorial-template/index.js @@ -5,35 +5,35 @@ const { join } = require( 'path' ); module.exports = { defaultValues: { - slug: 'gutenpride', - category: 'text', - title: 'Gutenpride', - description: - 'A Gutenberg block to show your pride! This block enables you to type text and style it with the color font Gilbert from Type with Pride.', - dashicon: 'flag', + slug: 'copyright-date-block', + title: 'Copyright Date', + description: "Display your site's copyright date.", attributes: { - message: { + fallbackCurrentYear: { + type: 'string', + }, + showStartingYear: { + type: 'boolean', + }, + startingYear: { type: 'string', - source: 'text', - selector: 'div', }, }, supports: { + color: { + background: false, + text: true, + }, html: false, - }, - }, - variants: { - static: {}, - dynamic: { - attributes: { - message: { - type: 'string', - }, + typography: { + fontSize: true, }, - render: 'file:./render.php', }, + editorScript: 'file:./index.js', + render: 'file:./render.php', + example: {}, + wpEnv: true, }, pluginTemplatesPath: join( __dirname, 'plugin-templates' ), blockTemplatesPath: join( __dirname, 'block-templates' ), - assetsPath: join( __dirname, 'assets' ), }; diff --git a/packages/create-block-tutorial-template/package.json b/packages/create-block-tutorial-template/package.json index 5fd4d71fd4cd8..33eb73835bfae 100644 --- a/packages/create-block-tutorial-template/package.json +++ b/packages/create-block-tutorial-template/package.json @@ -1,15 +1,16 @@ { "name": "@wordpress/create-block-tutorial-template", "version": "2.33.0", - "description": "Template for @wordpress/create-block used in the official WordPress tutorial.", + "description": "This is a template for @wordpress/create-block that creates an example 'Copyright Date' block. This block is used in the official WordPress block development Quick Start Guide.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ "wordpress", "create block", - "block template" + "block template", + "quick start" ], - "homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/docs/getting-started/create-block", + "homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/docs/getting-started/quick-start-guide", "repository": { "type": "git", "url": "https://github.com/WordPress/gutenberg.git", diff --git a/packages/create-block-tutorial-template/plugin-templates/$slug.php.mustache b/packages/create-block-tutorial-template/plugin-templates/$slug.php.mustache index 52c9c4966646f..6de24df94c8d8 100644 --- a/packages/create-block-tutorial-template/plugin-templates/$slug.php.mustache +++ b/packages/create-block-tutorial-template/plugin-templates/$slug.php.mustache @@ -8,7 +8,7 @@ * Description: {{description}} {{/description}} * Version: {{version}} - * Requires at least: 6.1 + * Requires at least: 6.2 * Requires PHP: 7.0 {{#author}} * Author: {{author}} @@ -41,7 +41,7 @@ if ( ! defined( 'ABSPATH' ) ) { * * @see https://developer.wordpress.org/reference/functions/register_block_type/ */ -function {{namespaceSnakeCase}}_{{slugSnakeCase}}_block_init() { +function {{namespaceSnakeCase}}_{{slugSnakeCase}}_init() { register_block_type( __DIR__ . '/build' ); } -add_action( 'init', '{{namespaceSnakeCase}}_{{slugSnakeCase}}_block_init' ); +add_action( 'init', '{{namespaceSnakeCase}}_{{slugSnakeCase}}_init' ); diff --git a/packages/create-block-tutorial-template/plugin-templates/readme.txt.mustache b/packages/create-block-tutorial-template/plugin-templates/readme.txt.mustache index f069906fb19fa..d2b31bed6c0e6 100644 --- a/packages/create-block-tutorial-template/plugin-templates/readme.txt.mustache +++ b/packages/create-block-tutorial-template/plugin-templates/readme.txt.mustache @@ -3,7 +3,7 @@ Contributors: {{author}} {{/author}} Tags: block -Tested up to: 6.1 +Tested up to: 6.4 Stable tag: {{version}} {{#license}} License: {{license}} From 901dc7de57974179aa95382e52aab0a736eded5a Mon Sep 17 00:00:00 2001 From: Artemio Morales Date: Mon, 13 Nov 2023 18:12:43 +0100 Subject: [PATCH 003/116] Add check for lightbox values during image block migration (#56057) --- packages/block-library/src/image/deprecated.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/block-library/src/image/deprecated.js b/packages/block-library/src/image/deprecated.js index 4205da8e117b9..0365ddcfff5d1 100644 --- a/packages/block-library/src/image/deprecated.js +++ b/packages/block-library/src/image/deprecated.js @@ -1047,6 +1047,14 @@ const v8 = { }, }, migrate( { width, height, ...attributes } ) { + // We need to perform a check here because in cases + // where attributes are added dynamically to blocks, + // block invalidation overrides the isEligible() method + // and forces the migration to run, so it's not guaranteed + // that `behaviors` or `behaviors.lightbox` will be defined. + if ( ! attributes.behaviors?.lightbox ) { + return attributes; + } const { behaviors: { lightbox: { enabled }, From f803a8f718e3c3ba8e11820b0d1a9dc515609cce Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Tue, 14 Nov 2023 01:27:18 +0800 Subject: [PATCH 004/116] Remove extraneous template part title in replace control (#55603) --- .../block-library/src/template-part/edit/index.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/packages/block-library/src/template-part/edit/index.js b/packages/block-library/src/template-part/edit/index.js index 64c8db5e3bc15..4152280bf7336 100644 --- a/packages/block-library/src/template-part/edit/index.js +++ b/packages/block-library/src/template-part/edit/index.js @@ -4,7 +4,6 @@ import { useSelect } from '@wordpress/data'; import { BlockSettingsMenuControls, - BlockTitle, useBlockProps, Warning, store as blockEditorStore, @@ -14,7 +13,7 @@ import { import { Spinner, Modal, MenuItem } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import { store as coreStore } from '@wordpress/core-data'; -import { useState, createInterpolateElement } from '@wordpress/element'; +import { useState } from '@wordpress/element'; /** * Internal dependencies @@ -174,17 +173,7 @@ export default function TemplatePartEdit( { } aria-haspopup="dialog" > - { createInterpolateElement( - __( 'Replace ' ), - { - BlockTitle: ( - - ), - } - ) } + { __( 'Replace' ) } ); } } From 3c17bb21753e72fab52021e7926a9d440e95f942 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:33:39 -0500 Subject: [PATCH 005/116] Bump shivammathur/setup-php from 2.26.0 to 2.27.1 (#55930) Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) from 2.26.0 to 2.27.1. - [Release notes](https://github.com/shivammathur/setup-php/releases) - [Commits](https://github.com/shivammathur/setup-php/compare/7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067...a36e1e52ff4a1c9e9c9be31551ee4712a6cb6bd0) --- updated-dependencies: - dependency-name: shivammathur/setup-php dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/unit-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 39f7caf6f806e..65ba01d0b70e8 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -126,7 +126,7 @@ jobs: # dependency versions are installed and cached. ## - name: Set up PHP - uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2.26.0 + uses: shivammathur/setup-php@a36e1e52ff4a1c9e9c9be31551ee4712a6cb6bd0 # v2.27.1 with: php-version: '${{ matrix.php }}' ini-file: development @@ -226,7 +226,7 @@ jobs: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Set up PHP - uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2.26.0 + uses: shivammathur/setup-php@a36e1e52ff4a1c9e9c9be31551ee4712a6cb6bd0 # v2.27.1 with: php-version: '7.4' coverage: none From ec688be162096eb059038b8333ab21e696318e75 Mon Sep 17 00:00:00 2001 From: Rich Tabor Date: Mon, 13 Nov 2023 14:26:43 -0500 Subject: [PATCH 006/116] Another round of __next40pxDefaultSize controls (#56022) * ReusableBlockEdit * __next40pxDefaultSize for block-library * __next40pxDefaultSize for PageAttributesOrder --- packages/block-editor/src/hooks/anchor.js | 1 + packages/block-editor/src/hooks/block-rename-ui.js | 2 ++ packages/block-editor/src/hooks/custom-class-name.js | 1 + packages/block-library/src/block/edit.js | 3 ++- .../src/comments/edit/comments-inspector-controls.js | 1 + packages/block-library/src/cover/edit/inspector-controls.js | 1 + packages/block-library/src/group/edit.js | 1 + packages/block-library/src/query/edit/query-content.js | 1 + .../block-library/src/template-part/edit/advanced-controls.js | 1 + packages/editor/src/components/page-attributes/order.js | 1 + 10 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/anchor.js b/packages/block-editor/src/hooks/anchor.js index 7a8f507d9674e..3d404c4a86811 100644 --- a/packages/block-editor/src/hooks/anchor.js +++ b/packages/block-editor/src/hooks/anchor.js @@ -59,6 +59,7 @@ function BlockEditAnchorControl( { blockName, attributes, setAttributes } ) { const textControl = ( diff --git a/packages/block-library/src/comments/edit/comments-inspector-controls.js b/packages/block-library/src/comments/edit/comments-inspector-controls.js index 5dd7afab431ce..1a33cb68ea38a 100644 --- a/packages/block-library/src/comments/edit/comments-inspector-controls.js +++ b/packages/block-library/src/comments/edit/comments-inspector-controls.js @@ -22,6 +22,7 @@ export default function CommentsInspectorControls( { )' ), value: 'div' }, diff --git a/packages/block-library/src/cover/edit/inspector-controls.js b/packages/block-library/src/cover/edit/inspector-controls.js index 3ed0ae872f933..38757f90c2dee 100644 --- a/packages/block-library/src/cover/edit/inspector-controls.js +++ b/packages/block-library/src/cover/edit/inspector-controls.js @@ -319,6 +319,7 @@ export default function CoverInspectorControls( { )' ), value: 'div' }, diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index 4d5354eff0180..277fa6872fa82 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -52,6 +52,7 @@ function GroupEditControls( { tagName, onSelectTagName } ) { )' ), value: 'div' }, diff --git a/packages/block-library/src/query/edit/query-content.js b/packages/block-library/src/query/edit/query-content.js index 6fef2c43b4aff..4d9b8885cb15e 100644 --- a/packages/block-library/src/query/edit/query-content.js +++ b/packages/block-library/src/query/edit/query-content.js @@ -131,6 +131,7 @@ export default function QueryContent( { )' ), value: 'div' }, diff --git a/packages/block-library/src/template-part/edit/advanced-controls.js b/packages/block-library/src/template-part/edit/advanced-controls.js index b879b46638fac..8ad4b4bdbeb1d 100644 --- a/packages/block-library/src/template-part/edit/advanced-controls.js +++ b/packages/block-library/src/template-part/edit/advanced-controls.js @@ -95,6 +95,7 @@ export function TemplatePartAdvancedControls( { ) } Date: Tue, 14 Nov 2023 04:47:30 +0900 Subject: [PATCH 007/116] Light box: Fix button misalignment in gallery image (#56060) --- packages/block-library/src/image/view.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/block-library/src/image/view.js b/packages/block-library/src/image/view.js index 30967a2de92c3..ef46e932d2490 100644 --- a/packages/block-library/src/image/view.js +++ b/packages/block-library/src/image/view.js @@ -313,11 +313,21 @@ store( if ( caption ) { const captionComputedStyle = window.getComputedStyle( caption ); - figureHeight = - figureHeight - - caption.offsetHeight - - parseFloat( captionComputedStyle.marginTop ) - - parseFloat( captionComputedStyle.marginBottom ); + if ( + ! [ 'absolute', 'fixed' ].includes( + captionComputedStyle.position + ) + ) { + figureHeight = + figureHeight - + caption.offsetHeight - + parseFloat( + captionComputedStyle.marginTop + ) - + parseFloat( + captionComputedStyle.marginBottom + ); + } } const buttonOffsetTop = figureHeight - offsetHeight; From 4d3b14823b8f4751badfdca432a57113b0d2c0fb Mon Sep 17 00:00:00 2001 From: Dean Sas Date: Mon, 13 Nov 2023 22:49:53 +0000 Subject: [PATCH 008/116] Process embeds inside patterns (#55979) Embed blocks inside patterns were not being processed when viewing a site. This focused change addresses that issue. --- packages/block-library/src/pattern/index.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/pattern/index.php b/packages/block-library/src/pattern/index.php index f05bb333bd186..436452f685300 100644 --- a/packages/block-library/src/pattern/index.php +++ b/packages/block-library/src/pattern/index.php @@ -48,7 +48,12 @@ function render_block_core_pattern( $attributes ) { $content = gutenberg_serialize_blocks( $blocks ); } - return do_blocks( $content ); + $content = do_blocks( $content ); + + global $wp_embed; + $content = $wp_embed->autoembed( $content ); + + return $content; } add_action( 'init', 'register_block_core_pattern' ); From f927f2d348be9e23739496ff69c49b1fae2cfa7b Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 14 Nov 2023 09:53:07 +1100 Subject: [PATCH 009/116] List View: Add keyboard shortcut to select all blocks (#54899) * List View: Try adding keyboard shortcut to select all blocks * Move up each leve of the hierarchy incrementally * Fix bug if focused on a different part of the list view from the block selection * Add e2e tests * Simplify e2e tests * Clarify the group block state a little more in the e2e test --- .../list-view/block-select-button.js | 45 ++++++- .../src/components/list-view/index.js | 2 + .../specs/editor/various/list-view.spec.js | 112 +++++++++++++++++- 3 files changed, 157 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/list-view/block-select-button.js b/packages/block-editor/src/components/list-view/block-select-button.js index cec5d4699c7a2..25de5483f5192 100644 --- a/packages/block-editor/src/components/list-view/block-select-button.js +++ b/packages/block-editor/src/components/list-view/block-select-button.js @@ -19,6 +19,7 @@ import { SPACE, ENTER, BACKSPACE, DELETE } from '@wordpress/keycodes'; import { useSelect, useDispatch } from '@wordpress/data'; import { __unstableUseShortcutEventMatch as useShortcutEventMatch } from '@wordpress/keyboard-shortcuts'; import { __, sprintf } from '@wordpress/i18n'; +import isShallowEqual from '@wordpress/is-shallow-equal'; /** * Internal dependencies @@ -30,6 +31,7 @@ import ListViewExpander from './expander'; import { useBlockLock } from '../block-lock'; import { store as blockEditorStore } from '../../store'; import useListViewImages from './use-list-view-images'; +import { useListViewContext } from './context'; function ListViewBlockSelectButton( { @@ -64,10 +66,12 @@ function ListViewBlockSelectButton( getBlocksByClientId, canRemoveBlocks, } = useSelect( blockEditorStore ); - const { duplicateBlocks, removeBlocks } = useDispatch( blockEditorStore ); + const { duplicateBlocks, multiSelect, removeBlocks } = + useDispatch( blockEditorStore ); const isMatch = useShortcutEventMatch(); const isSticky = blockInformation?.positionType === 'sticky'; const images = useListViewImages( { clientId, isExpanded } ); + const { rootClientId } = useListViewContext(); const positionLabel = blockInformation?.positionLabel ? sprintf( @@ -183,6 +187,45 @@ function ListViewBlockSelectButton( updateFocusAndSelection( updatedBlocks[ 0 ], false ); } } + } else if ( isMatch( 'core/block-editor/select-all', event ) ) { + if ( event.defaultPrevented ) { + return; + } + event.preventDefault(); + + const { firstBlockRootClientId, selectedBlockClientIds } = + getBlocksToUpdate(); + const blockClientIds = getBlockOrder( firstBlockRootClientId ); + if ( ! blockClientIds.length ) { + return; + } + + // If we have selected all sibling nested blocks, try selecting up a level. + // This is a similar implementation to that used by `useSelectAll`. + // `isShallowEqual` is used for the list view instead of a length check, + // as the array of siblings of the currently focused block may be a different + // set of blocks from the current block selection if the user is focused + // on a different part of the list view from the block selection. + if ( isShallowEqual( selectedBlockClientIds, blockClientIds ) ) { + // Only select up a level if the first block is not the root block. + // This ensures that the block selection can't break out of the root block + // used by the list view, if the list view is only showing a partial hierarchy. + if ( + firstBlockRootClientId && + firstBlockRootClientId !== rootClientId + ) { + updateFocusAndSelection( firstBlockRootClientId, true ); + return; + } + } + + // Select all while passing `null` to skip focusing to the editor canvas, + // and retain focus within the list view. + multiSelect( + blockClientIds[ 0 ], + blockClientIds[ blockClientIds.length - 1 ], + null + ); } } diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js index 1d21c28643a73..315a6153839d1 100644 --- a/packages/block-editor/src/components/list-view/index.js +++ b/packages/block-editor/src/components/list-view/index.js @@ -222,6 +222,7 @@ function ListViewComponent( insertedBlock, setInsertedBlock, treeGridElementRef: elementRef, + rootClientId, } ), [ draggedClientIds, @@ -233,6 +234,7 @@ function ListViewComponent( AdditionalBlockContent, insertedBlock, setInsertedBlock, + rootClientId, ] ); diff --git a/test/e2e/specs/editor/various/list-view.spec.js b/test/e2e/specs/editor/various/list-view.spec.js index 222d743acdf39..f05b7760c4cc7 100644 --- a/test/e2e/specs/editor/various/list-view.spec.js +++ b/test/e2e/specs/editor/various/list-view.spec.js @@ -421,7 +421,7 @@ test.describe( 'List View', () => { ).toBeFocused(); } ); - test( 'should duplicate, delete, and deselect blocks using keyboard', async ( { + test( 'should select, duplicate, delete, and deselect blocks using keyboard', async ( { editor, page, pageUtils, @@ -464,6 +464,116 @@ test.describe( 'List View', () => { { name: 'core/file', selected: true, focused: true }, ] ); + // Move up to columns block, expand, and then move to the first column block. + await page.keyboard.press( 'ArrowUp' ); + await page.keyboard.press( 'ArrowRight' ); + await page.keyboard.press( 'ArrowDown' ); + + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'The last inserted block should be selected, while the first column block should be focused.' + ) + .toMatchObject( [ + { name: 'core/group' }, + { + name: 'core/columns', + innerBlocks: [ + { name: 'core/column', selected: false, focused: true }, + { name: 'core/column' }, + ], + }, + { name: 'core/file', selected: true, focused: false }, + ] ); + + // Select all sibling column blocks at current level. + await pageUtils.pressKeys( 'primary+a' ); + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'All column blocks should be selected, with the first one focused.' + ) + .toMatchObject( [ + { name: 'core/group', selected: false, focused: false }, + { + name: 'core/columns', + innerBlocks: [ + { name: 'core/column', selected: true, focused: true }, + { name: 'core/column', selected: true, focused: false }, + ], + selected: false, + }, + { name: 'core/file', selected: false, focused: false }, + ] ); + + // Select next parent (the columns block). + await pageUtils.pressKeys( 'primary+a' ); + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'The columns block should be selected and focused.' + ) + .toMatchObject( [ + { name: 'core/group', selected: false, focused: false }, + { + name: 'core/columns', + innerBlocks: [ + { name: 'core/column' }, + { name: 'core/column' }, + ], + selected: true, + focused: true, + }, + { name: 'core/file', selected: false, focused: false }, + ] ); + + // Select all siblings at root level. + await pageUtils.pressKeys( 'primary+a' ); + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'All blocks should be selected.' + ) + .toMatchObject( [ + { name: 'core/group', selected: true, focused: false }, + { + name: 'core/columns', + innerBlocks: [ + { name: 'core/column' }, + { name: 'core/column' }, + ], + selected: true, + focused: true, + }, + { name: 'core/file', selected: true, focused: false }, + ] ); + + // Deselect blocks via Escape key. + await page.keyboard.press( 'Escape' ); + // Collapse the columns block. + await page.keyboard.press( 'ArrowLeft' ); + + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'All blocks should be deselected, with focus on the Columns block.' + ) + .toMatchObject( [ + { name: 'core/group', selected: false, focused: false }, + { + name: 'core/columns', + selected: false, + focused: true, + }, + { name: 'core/file', selected: false, focused: false }, + ] ); + + // Move focus and selection to the file block to set up for testing duplication. + await listView + .getByRole( 'gridcell', { name: 'File', exact: true } ) + .dblclick(); + + // Test duplication behaviour. await pageUtils.pressKeys( 'primaryShift+d' ); await expect From d27ffba8c58f0f975e80c48b1dcba1e5816663a5 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Tue, 14 Nov 2023 09:43:52 +0400 Subject: [PATCH 010/116] Fix flaky 'Meta boxes' e2e tests (#56083) * Fix flaky 'Meta boxes' e2e tests * Just swap the expected text order --- test/e2e/specs/editor/plugins/meta-boxes.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/specs/editor/plugins/meta-boxes.spec.js b/test/e2e/specs/editor/plugins/meta-boxes.spec.js index b901201ff6c1d..5999dc07aeafe 100644 --- a/test/e2e/specs/editor/plugins/meta-boxes.spec.js +++ b/test/e2e/specs/editor/plugins/meta-boxes.spec.js @@ -62,8 +62,8 @@ test.describe( 'Meta boxes', () => { await page.goto( `/?p=${ postId }` ); await expect( - page.locator( '.wp-block-latest-posts > li' ) - ).toContainText( [ 'A published post', 'Dynamic block test' ] ); + page.locator( '.entry-content .wp-block-latest-posts__post-title' ) + ).toContainText( [ 'Dynamic block test', 'A published post' ] ); } ); test( 'Should render the excerpt in meta based on post content if no explicit excerpt exists', async ( { From b09e9bd32c4bd8740833d7b15ca814ce3c7c1608 Mon Sep 17 00:00:00 2001 From: Ramon Date: Tue, 14 Nov 2023 17:51:25 +1100 Subject: [PATCH 011/116] Site editor template preview: add E2E test and aria-pressed attribute to template preview toggle (#56096) * This PR adds a follow up E2E test for https://github.com/WordPress/gutenberg/pull/52674 It also adds an aria label to the edit template button to indicate its state (pressed or not pressed). * Refactor test to account for order of page content blocks * remove saving from tests. unnecessary to the test --- .../page-panels/edit-template.js | 1 + .../sidebar-edit-mode/page-panels/style.scss | 6 + test/e2e/specs/site-editor/pages.spec.js | 123 ++++++++++++++++++ 3 files changed, 130 insertions(+) diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js index 8067453a51821..fde2b63d6e833 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js @@ -114,6 +114,7 @@ export default function EditTemplate() { icon={ ! isTemplateHidden ? check : undefined } + isPressed={ ! isTemplateHidden } onClick={ () => { setPageContentFocusType( isTemplateHidden diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss index e1a8e4acb7227..64d72db4e15fd 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss @@ -84,6 +84,11 @@ .components-popover__content { min-width: 240px; } + .components-button.is-pressed, + .components-button.is-pressed:hover { + background: inherit; + color: inherit; + } } .edit-site-page-panels-edit-slug__dropdown { @@ -92,3 +97,4 @@ padding: $grid-unit-20; } } + diff --git a/test/e2e/specs/site-editor/pages.spec.js b/test/e2e/specs/site-editor/pages.spec.js index d1f32b9f209d7..8008109be15ee 100644 --- a/test/e2e/specs/site-editor/pages.spec.js +++ b/test/e2e/specs/site-editor/pages.spec.js @@ -136,6 +136,128 @@ test.describe( 'Pages', () => { ) ).toBeVisible(); } ); + + test( 'toggle template preview', async ( { page, editor } ) => { + await draftNewPage( page ); + await editor.openDocumentSettingsSidebar(); + + await editor.canvas + .getByRole( 'document', { + name: 'Block: Content', + } ) + .getByRole( 'document', { + name: 'Empty block; start writing or type forward slash to choose a block', + } ) + .click(); + + // Add some content to the page. + await page.keyboard.type( 'Sweet paragraph 1' ); + await page.keyboard.press( 'Enter' ); + await page.keyboard.type( 'Sweet paragraph 2' ); + + // Header template area and page content are visible. + await expect( + editor.canvas.getByRole( 'document', { + name: 'Block: header', + } ) + ).toBeVisible(); + + const paragraphs = editor.canvas + .getByRole( 'document', { + name: 'Block: Content', + } ) + .getByText( 'Sweet paragraph ' ); + + await expect( paragraphs.nth( 0 ) ).toBeVisible(); + await expect( paragraphs.nth( 1 ) ).toBeVisible(); + await expect( + editor.canvas.getByRole( 'document', { + name: 'Block: Title', + } ) + ).toBeVisible(); + + // Toggle template preview to "off". + const templateOptionsButton = page + .getByRole( 'region', { name: 'Editor settings' } ) + .getByRole( 'button', { name: 'Template options' } ); + await templateOptionsButton.click(); + const templatePreviewButton = page + .getByRole( 'menu', { name: 'Template options' } ) + .getByRole( 'menuitem', { name: 'Template preview' } ); + + await expect( templatePreviewButton ).toHaveAttribute( + 'aria-pressed', + 'true' + ); + await templatePreviewButton.click(); + await expect( templatePreviewButton ).toHaveAttribute( + 'aria-pressed', + 'false' + ); + + // Header template area should be hidden. + await expect( + editor.canvas.getByRole( 'document', { + name: 'Block: header', + } ) + ).toBeHidden(); + + // Content block is still visible and wrapped in a container. + const paragraphsInGroup = editor.canvas + .getByRole( 'document', { + name: 'Block: Group', + } ) + .getByRole( 'document', { + name: 'Block: Content', + } ) + .getByText( 'Sweet paragraph ' ); + + await expect( paragraphsInGroup.nth( 0 ) ).toBeVisible(); + await expect( paragraphsInGroup.nth( 1 ) ).toBeVisible(); + // Check order of paragraphs. + // Important to ensure the blocks are rendered as they are in the template. + await expect( paragraphsInGroup.nth( 0 ) ).toHaveText( + 'Sweet paragraph 1' + ); + await expect( paragraphsInGroup.nth( 1 ) ).toHaveText( + 'Sweet paragraph 2' + ); + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Block: Group', + } ) + .getByRole( 'document', { + name: 'Block: Title', + } ) + ).toBeVisible(); + + // Remove focus from templateOptionsButton button. + await editor.canvas.locator( 'body' ).click(); + + // Toggle template preview to "on". + await templateOptionsButton.click(); + await templatePreviewButton.click(); + await expect( templatePreviewButton ).toHaveAttribute( + 'aria-pressed', + 'true' + ); + + // Header template area and page content are once again visible. + await expect( + editor.canvas.getByRole( 'document', { + name: 'Block: header', + } ) + ).toBeVisible(); + await expect( paragraphs.nth( 0 ) ).toBeVisible(); + await expect( paragraphs.nth( 1 ) ).toBeVisible(); + await expect( + editor.canvas.getByRole( 'document', { + name: 'Block: Title', + } ) + ).toBeVisible(); + } ); + test( 'swap template and reset to default', async ( { admin, page, @@ -195,6 +317,7 @@ test.describe( 'Pages', () => { await resetButton.click(); await expect( templateOptionsButton ).toHaveText( 'Single Entries' ); } ); + test( 'swap template options should respect the declared `postTypes`', async ( { page, editor, From 0ee99bb1af39d9a6585d23a6db842ec42339c7d6 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Tue, 14 Nov 2023 10:09:51 +0000 Subject: [PATCH 012/116] Update: DataViews add rename functionality to custom views. (#55997) --- .../custom-dataviews-list.js | 165 +++++++++++++----- 1 file changed, 122 insertions(+), 43 deletions(-) diff --git a/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js b/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js index f11c63653205f..12659a36bbf9b 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js +++ b/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js @@ -9,8 +9,13 @@ import { DropdownMenu, MenuGroup, MenuItem, + TextControl, + __experimentalHStack as HStack, + __experimentalVStack as VStack, + Button, + Modal, } from '@wordpress/components'; -import { useMemo } from '@wordpress/element'; +import { useMemo, useState } from '@wordpress/element'; import { moreVertical } from '@wordpress/icons'; import { __ } from '@wordpress/i18n'; import { privateApis as routerPrivateApis } from '@wordpress/router'; @@ -26,6 +31,55 @@ const { useHistory, useLocation } = unlock( routerPrivateApis ); const EMPTY_ARRAY = []; +function RenameItemModalContent( { dataviewId, currentTitle, setIsRenaming } ) { + const { editEntityRecord } = useDispatch( coreStore ); + const [ title, setTitle ] = useState( currentTitle ); + return ( +
{ + event.preventDefault(); + await editEntityRecord( + 'postType', + 'wp_dataviews', + dataviewId, + { + title, + } + ); + setIsRenaming( false ); + } } + > + + + + + + + +
+ ); +} + function CustomDataViewItem( { dataviewId, isActive } ) { const { params: { path }, @@ -49,51 +103,76 @@ function CustomDataViewItem( { dataviewId, isActive } ) { const viewContent = JSON.parse( dataview.content ); return viewContent.type; }, [ dataview.content ] ); + const [ isRenaming, setIsRenaming ] = useState( false ); return ( - + + { ( { onClose } ) => ( + + { + setIsRenaming( true ); + onClose(); + } } + > + { __( 'Rename' ) } + + { + await deleteEntityRecord( + 'postType', + 'wp_dataviews', + dataview.id, + { + force: true, + } + ); + if ( isActive ) { + history.replace( { + path, + } ); + } + onClose(); + } } + isDestructive + > + { __( 'Delete' ) } + + + ) } + + } + /> + { isRenaming && ( + { + setIsRenaming( false ); } } > - { ( { onClose } ) => ( - - { - await deleteEntityRecord( - 'postType', - 'wp_dataviews', - dataview.id, - { - force: true, - } - ); - if ( isActive ) { - history.replace( { - path, - } ); - } - onClose(); - } } - isDestructive - > - { __( 'Delete' ) } - - - ) } - - } - /> + + + ) } + ); } From 8c29767d60f450d581f6f31ab17a525b57114a53 Mon Sep 17 00:00:00 2001 From: Birgit Pauli-Haack Date: Tue, 14 Nov 2023 11:22:03 +0100 Subject: [PATCH 013/116] fixes wrong link in #56084 (#56106) props to @gziolo for review --- packages/create-block/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-block/README.md b/packages/create-block/README.md index 51c36ca91b014..20bb6c62ccf66 100644 --- a/packages/create-block/README.md +++ b/packages/create-block/README.md @@ -141,7 +141,7 @@ For example, running the `start` script from inside the generated folder (`npm s ## External Project Templates -[Click here](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block-tutorial-template/) for information on External Project Templates +[Click here](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/packages-create-block-external-template/) for information on External Project Templates ## Contributing to this package From 560c38df911672b5802d60dab0fc099096fc80a0 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 14 Nov 2023 11:25:41 +0100 Subject: [PATCH 014/116] SiteEditor: Optimize BackToPageNotification component (#56102) --- .../back-to-page-notification.js | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/packages/edit-site/src/components/page-content-focus-manager/back-to-page-notification.js b/packages/edit-site/src/components/page-content-focus-manager/back-to-page-notification.js index a2990c56a673c..9bf9ac33b1d19 100644 --- a/packages/edit-site/src/components/page-content-focus-manager/back-to-page-notification.js +++ b/packages/edit-site/src/components/page-content-focus-manager/back-to-page-notification.js @@ -25,27 +25,19 @@ export default function BackToPageNotification() { * switches from focusing on editing page content to editing a template. */ export function useBackToPageNotification() { - const { isPage, hasPageContentFocus } = useSelect( - ( select ) => ( { - isPage: select( editSiteStore ).isPage(), - hasPageContentFocus: select( editSiteStore ).hasPageContentFocus(), - } ), + const hasPageContentFocus = useSelect( + ( select ) => select( editSiteStore ).hasPageContentFocus(), [] ); + const { isPage } = useSelect( editSiteStore ); const alreadySeen = useRef( false ); - const prevHasPageContentFocus = useRef( false ); const { createInfoNotice } = useDispatch( noticesStore ); const { setHasPageContentFocus } = useDispatch( editSiteStore ); useEffect( () => { - if ( - ! alreadySeen.current && - isPage && - prevHasPageContentFocus.current && - ! hasPageContentFocus - ) { + if ( isPage() && ! alreadySeen.current && ! hasPageContentFocus ) { createInfoNotice( __( 'You are editing a template.' ), { isDismissible: true, type: 'snackbar', @@ -58,11 +50,8 @@ export function useBackToPageNotification() { } ); alreadySeen.current = true; } - prevHasPageContentFocus.current = hasPageContentFocus; }, [ - alreadySeen, isPage, - prevHasPageContentFocus, hasPageContentFocus, createInfoNotice, setHasPageContentFocus, From 71a6fb60994e252a5675bdc8d32c3dcda5287da6 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Tue, 14 Nov 2023 12:59:25 +0200 Subject: [PATCH 015/116] Rich text: highlight format: gracefully handle old span format (#56071) --- .../format-library/src/text-color/index.js | 18 --------- .../src/text-color/index.native.js | 22 ----------- packages/rich-text/src/component/index.js | 38 ------------------- packages/rich-text/src/create.js | 8 ---- 4 files changed, 86 deletions(-) diff --git a/packages/format-library/src/text-color/index.js b/packages/format-library/src/text-color/index.js index 630431dc50fa0..8a28cb69549cd 100644 --- a/packages/format-library/src/text-color/index.js +++ b/packages/format-library/src/text-color/index.js @@ -135,23 +135,5 @@ export const textColor = { style: 'style', class: 'class', }, - /* - * Since this format relies on the tag, it's important to - * prevent the default yellow background color applied by most - * browsers. The solution is to detect when this format is used with a - * text color but no background color, and in such cases to override - * the default styling with a transparent background. - * - * @see https://github.com/WordPress/gutenberg/pull/35516 - */ - __unstableFilterAttributeValue( key, value ) { - if ( key !== 'style' ) return value; - // We should not add a background-color if it's already set. - if ( value && value.includes( 'background-color' ) ) return value; - const addedCSS = [ 'background-color', transparentValue ].join( ':' ); - // Prepend `addedCSS` to avoid a double `;;` as any the existing CSS - // rules will already include a `;`. - return value ? [ addedCSS, value ].join( ';' ) : addedCSS; - }, edit: TextColorEdit, }; diff --git a/packages/format-library/src/text-color/index.native.js b/packages/format-library/src/text-color/index.native.js index 21db4c2a444f3..7c44e4efc001a 100644 --- a/packages/format-library/src/text-color/index.native.js +++ b/packages/format-library/src/text-color/index.native.js @@ -26,7 +26,6 @@ import { usePreferredColorSchemeStyle } from '@wordpress/compose'; * Internal dependencies */ import { getActiveColors } from './inline.js'; -import { transparentValue } from './index.js'; import { default as InlineColorUI } from './inline'; import styles from './style.scss'; @@ -183,26 +182,5 @@ export const textColor = { style: 'style', class: 'class', }, - /* - * Since this format relies on the tag, it's important to - * prevent the default yellow background color applied by most - * browsers. The solution is to detect when this format is used with a - * text color but no background color, and in such cases to override - * the default styling with a transparent background. - * - * @see https://github.com/WordPress/gutenberg/pull/35516 - */ - __unstableFilterAttributeValue( key, value ) { - if ( key !== 'style' ) return value; - // We need to remove the extra spaces within the styles on mobile - const newValue = value?.replace( / /g, '' ); - // We should not add a background-color if it's already set - if ( newValue && newValue.includes( 'background-color' ) ) - return newValue; - const addedCSS = [ 'background-color', transparentValue ].join( ':' ); - // Prepend `addedCSS` to avoid a double `;;` as any the existing CSS - // rules will already include a `;`. - return newValue ? [ addedCSS, newValue ].join( ';' ) : addedCSS; - }, edit: TextColorEdit, }; diff --git a/packages/rich-text/src/component/index.js b/packages/rich-text/src/component/index.js index 17cf17e2e3154..87e57e49e4333 100644 --- a/packages/rich-text/src/component/index.js +++ b/packages/rich-text/src/component/index.js @@ -89,21 +89,6 @@ export function useRichText( { if ( ! record.current ) { hadSelectionUpdate.current = isSelected; setRecordFromProps(); - // Sometimes formats are added programmatically and we need to make - // sure it's persisted to the block store / markup. If these formats - // are not applied, they could cause inconsistencies between the data - // in the visual editor and the frontend. Right now, it's only relevant - // to the `core/text-color` format, which is applied at runtime in - // certain circunstances. See the `__unstableFilterAttributeValue` - // function in `packages/format-library/src/text-color/index.js`. - // @todo find a less-hacky way of solving this. - - const hasRelevantInitFormat = - record.current?.formats[ 0 ]?.[ 0 ]?.type === 'core/text-color'; - - if ( hasRelevantInitFormat ) { - handleChangesUponInit( record.current ); - } } else if ( selectionStart !== record.current.start || selectionEnd !== record.current.end @@ -155,29 +140,6 @@ export function useRichText( { forceRender(); } - function handleChangesUponInit( newRecord ) { - record.current = newRecord; - - _value.current = toHTMLString( { - value: __unstableBeforeSerialize - ? { - ...newRecord, - formats: __unstableBeforeSerialize( newRecord ), - } - : newRecord, - } ); - - const { formats, text } = newRecord; - - registry.batch( () => { - onChange( _value.current, { - __unstableFormats: formats, - __unstableText: text, - } ); - } ); - forceRender(); - } - function applyFromProps() { setRecordFromProps(); applyRecord( record.current ); diff --git a/packages/rich-text/src/create.js b/packages/rich-text/src/create.js index 63aac8c076b8b..a23baf70078bc 100644 --- a/packages/rich-text/src/create.js +++ b/packages/rich-text/src/create.js @@ -70,14 +70,6 @@ function toFormat( { tagName, attributes } ) { registeredAttributes[ key ] = _attributes[ name ]; - if ( formatType.__unstableFilterAttributeValue ) { - registeredAttributes[ key ] = - formatType.__unstableFilterAttributeValue( - key, - registeredAttributes[ key ] - ); - } - // delete the attribute and what's left is considered // to be unregistered. delete _attributes[ name ]; From b04f4d35358d418bc2316c09fb655091f842e54a Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Tue, 14 Nov 2023 15:43:59 +0400 Subject: [PATCH 016/116] Block Editor: Optimize 'Block Hooks' inspector controls (#56101) --- packages/block-editor/src/hooks/block-hooks.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/hooks/block-hooks.js b/packages/block-editor/src/hooks/block-hooks.js index fc08090b49889..0d75999192e5b 100644 --- a/packages/block-editor/src/hooks/block-hooks.js +++ b/packages/block-editor/src/hooks/block-hooks.js @@ -238,14 +238,15 @@ function BlockHooksControl( props ) { export const withBlockHooksControls = createHigherOrderComponent( ( BlockEdit ) => { return ( props ) => { - const blockEdit = ; return ( <> - { blockEdit } - + + { props.isSelected && ( + + ) } ); }; From 4d7b66f02e02b766c5756e7bc3ece73a157ae397 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Tue, 14 Nov 2023 14:18:30 +0200 Subject: [PATCH 017/116] Block lib: remove multiline=false (deprecated) (#56113) --- packages/block-library/src/details/edit.js | 1 - packages/block-library/src/post-author/edit.js | 1 - packages/block-library/src/post-terms/edit.js | 2 -- 3 files changed, 4 deletions(-) diff --git a/packages/block-library/src/details/edit.js b/packages/block-library/src/details/edit.js index 81e4d7a52056a..0d1d675893900 100644 --- a/packages/block-library/src/details/edit.js +++ b/packages/block-library/src/details/edit.js @@ -72,7 +72,6 @@ function DetailsEdit( { attributes, setAttributes, clientId } ) { onChange={ ( newSummary ) => setAttributes( { summary: newSummary } ) } - multiline={ false } /> { innerBlocksProps.children } diff --git a/packages/block-library/src/post-author/edit.js b/packages/block-library/src/post-author/edit.js index 4ee353fdd9bdc..05797fcc8250a 100644 --- a/packages/block-library/src/post-author/edit.js +++ b/packages/block-library/src/post-author/edit.js @@ -196,7 +196,6 @@ function PostAuthorEdit( { { ( ! RichText.isEmpty( byline ) || isSelected ) && ( Date: Tue, 14 Nov 2023 13:30:10 +0100 Subject: [PATCH 018/116] DataViews: add 10 as a new page size option (#56112) --- packages/edit-site/src/components/dataviews/view-actions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/dataviews/view-actions.js b/packages/edit-site/src/components/dataviews/view-actions.js index 5f808e99beeae..e1e85a3e56d09 100644 --- a/packages/edit-site/src/components/dataviews/view-actions.js +++ b/packages/edit-site/src/components/dataviews/view-actions.js @@ -95,7 +95,7 @@ function ViewTypeMenu( { view, onChangeView, supportedLayouts } ) { ); } -const PAGE_SIZE_VALUES = [ 20, 50, 100 ]; +const PAGE_SIZE_VALUES = [ 10, 20, 50, 100 ]; function PageSizeMenu( { view, onChangeView } ) { return ( Date: Tue, 14 Nov 2023 14:19:02 +0100 Subject: [PATCH 019/116] Template Part: Add fallback to the current theme when not provided (#55965) --- .../src/navigation/use-template-part-area-label.js | 6 ++++-- packages/block-library/src/pattern/edit.js | 3 ++- packages/block-library/src/template-part/edit/index.js | 6 +++++- packages/block-library/src/template-part/index.js | 5 +++-- packages/block-library/src/template-part/variations.js | 6 ++++-- packages/edit-site/src/hooks/template-part-edit.js | 6 ++++-- 6 files changed, 22 insertions(+), 10 deletions(-) diff --git a/packages/block-library/src/navigation/use-template-part-area-label.js b/packages/block-library/src/navigation/use-template-part-area-label.js index 91838b268b47d..48763a38ac62d 100644 --- a/packages/block-library/src/navigation/use-template-part-area-label.js +++ b/packages/block-library/src/navigation/use-template-part-area-label.js @@ -45,14 +45,16 @@ export default function useTemplatePartAreaLabel( clientId ) { 'core/editor' ).__experimentalGetDefaultTemplatePartAreas(); /* eslint-enable @wordpress/data-no-store-string-literals */ - const { getEditedEntityRecord } = select( coreStore ); + const { getCurrentTheme, getEditedEntityRecord } = + select( coreStore ); for ( const templatePartClientId of parentTemplatePartClientIds ) { const templatePartBlock = getBlock( templatePartClientId ); // The 'area' usually isn't stored on the block, but instead // on the entity. - const { theme, slug } = templatePartBlock.attributes; + const { theme = getCurrentTheme()?.stylesheet, slug } = + templatePartBlock.attributes; const templatePartEntityId = createTemplatePartId( theme, slug diff --git a/packages/block-library/src/pattern/edit.js b/packages/block-library/src/pattern/edit.js index 43d7875530481..5fd1b427a5e3e 100644 --- a/packages/block-library/src/pattern/edit.js +++ b/packages/block-library/src/pattern/edit.js @@ -20,7 +20,8 @@ const PatternEdit = ( { attributes, clientId } ) => { ); const currentThemeStylesheet = useSelect( - ( select ) => select( coreStore ).getCurrentTheme()?.stylesheet + ( select ) => select( coreStore ).getCurrentTheme()?.stylesheet, + [] ); const { replaceBlocks, __unstableMarkNextChangeAsNotPersistent } = diff --git a/packages/block-library/src/template-part/edit/index.js b/packages/block-library/src/template-part/edit/index.js index 4152280bf7336..163dfa5403ce6 100644 --- a/packages/block-library/src/template-part/edit/index.js +++ b/packages/block-library/src/template-part/edit/index.js @@ -34,7 +34,11 @@ export default function TemplatePartEdit( { setAttributes, clientId, } ) { - const { slug, theme, tagName, layout = {} } = attributes; + const currentTheme = useSelect( + ( select ) => select( coreStore ).getCurrentTheme()?.stylesheet, + [] + ); + const { slug, theme = currentTheme, tagName, layout = {} } = attributes; const templatePartId = createTemplatePartId( theme, slug ); const hasAlreadyRendered = useHasRecursion( templatePartId ); const [ isTemplatePartSelectionOpen, setIsTemplatePartSelectionOpen ] = diff --git a/packages/block-library/src/template-part/index.js b/packages/block-library/src/template-part/index.js index a68dd2301be22..c9b5e33a1c959 100644 --- a/packages/block-library/src/template-part/index.js +++ b/packages/block-library/src/template-part/index.js @@ -32,10 +32,11 @@ export const settings = { return; } - const entity = select( coreDataStore ).getEntityRecord( + const { getCurrentTheme, getEntityRecord } = select( coreDataStore ); + const entity = getEntityRecord( 'postType', 'wp_template_part', - theme + '//' + slug + ( theme || getCurrentTheme()?.stylesheet ) + '//' + slug ); if ( ! entity ) { return; diff --git a/packages/block-library/src/template-part/variations.js b/packages/block-library/src/template-part/variations.js index 866cf15d56c12..79881ee5f89e4 100644 --- a/packages/block-library/src/template-part/variations.js +++ b/packages/block-library/src/template-part/variations.js @@ -35,10 +35,12 @@ export function enhanceTemplatePartVariations( settings, name ) { // Find a matching variation from the created template part // by checking the entity's `area` property. if ( ! slug ) return false; - const entity = select( coreDataStore ).getEntityRecord( + const { getCurrentTheme, getEntityRecord } = + select( coreDataStore ); + const entity = getEntityRecord( 'postType', 'wp_template_part', - `${ theme }//${ slug }` + `${ theme || getCurrentTheme()?.stylesheet }//${ slug }` ); if ( entity?.slug ) { diff --git a/packages/edit-site/src/hooks/template-part-edit.js b/packages/edit-site/src/hooks/template-part-edit.js index 66f54967c55e2..0b14bbbbd7712 100644 --- a/packages/edit-site/src/hooks/template-part-edit.js +++ b/packages/edit-site/src/hooks/template-part-edit.js @@ -24,11 +24,13 @@ function EditTemplatePartMenuItem( { attributes } ) { const { params } = useLocation(); const templatePart = useSelect( ( select ) => { - return select( coreStore ).getEntityRecord( + const { getCurrentTheme, getEntityRecord } = select( coreStore ); + + return getEntityRecord( 'postType', TEMPLATE_PART_POST_TYPE, // Ideally this should be an official public API. - `${ theme }//${ slug }` + `${ theme || getCurrentTheme()?.stylesheet }//${ slug }` ); }, [ theme, slug ] From f137d97936cac3a0095019fa3eafeef1467c98a9 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Tue, 14 Nov 2023 16:06:01 +0200 Subject: [PATCH 020/116] Missing block: use raw source for originalContent (#56014) --- packages/block-library/src/missing/block.json | 2 +- test/integration/fixtures/blocks/core__form-input.json | 2 +- .../fixtures/blocks/core__form-input.serialized.html | 2 +- test/integration/fixtures/blocks/core__form.json | 10 +++++----- .../fixtures/blocks/core__form.serialized.html | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/block-library/src/missing/block.json b/packages/block-library/src/missing/block.json index 0bc512bbbf709..242a1d2c6b21a 100644 --- a/packages/block-library/src/missing/block.json +++ b/packages/block-library/src/missing/block.json @@ -15,7 +15,7 @@ }, "originalContent": { "type": "string", - "source": "html" + "source": "raw" } }, "supports": { diff --git a/test/integration/fixtures/blocks/core__form-input.json b/test/integration/fixtures/blocks/core__form-input.json index 33802bbcc2088..68dfb9a36e4e6 100644 --- a/test/integration/fixtures/blocks/core__form-input.json +++ b/test/integration/fixtures/blocks/core__form-input.json @@ -5,7 +5,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__form-input.serialized.html b/test/integration/fixtures/blocks/core__form-input.serialized.html index 4e1f6b77998de..718c592641bc3 100644 --- a/test/integration/fixtures/blocks/core__form-input.serialized.html +++ b/test/integration/fixtures/blocks/core__form-input.serialized.html @@ -1,3 +1,3 @@ - + diff --git a/test/integration/fixtures/blocks/core__form.json b/test/integration/fixtures/blocks/core__form.json index ba07b17e4d00c..6bad568b12c26 100644 --- a/test/integration/fixtures/blocks/core__form.json +++ b/test/integration/fixtures/blocks/core__form.json @@ -5,7 +5,7 @@ "attributes": { "originalName": "core/form", "originalUndelimitedContent": "
\n\n\n\n\n
\n
", - "originalContent": "\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n\n
\n" + "originalContent": "\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n\n
\n" }, "innerBlocks": [ { @@ -14,7 +14,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] }, @@ -24,7 +24,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] }, @@ -34,7 +34,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] }, @@ -44,7 +44,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] }, diff --git a/test/integration/fixtures/blocks/core__form.serialized.html b/test/integration/fixtures/blocks/core__form.serialized.html index 58a2a49967eb5..585a50868b85e 100644 --- a/test/integration/fixtures/blocks/core__form.serialized.html +++ b/test/integration/fixtures/blocks/core__form.serialized.html @@ -1,16 +1,16 @@
- + - + - + - +
From 5bcb30933846450ed25b3c9d0da39ccc95307b54 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Tue, 14 Nov 2023 14:59:28 +0000 Subject: [PATCH 021/116] Fix: Nested button tags on dataviews sidebar. (#56089) * Fix: Nested button tags on dataviews sidebar. * Fix lint issue --- .../sidebar-dataviews/dataview-item.js | 30 ++++++++++++++----- .../components/sidebar-dataviews/style.scss | 14 +++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/packages/edit-site/src/components/sidebar-dataviews/dataview-item.js b/packages/edit-site/src/components/sidebar-dataviews/dataview-item.js index fdd3272fbc24a..c6d7bbe4a231b 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/dataview-item.js +++ b/packages/edit-site/src/components/sidebar-dataviews/dataview-item.js @@ -1,8 +1,14 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { page, columns, pullRight } from '@wordpress/icons'; import { privateApis as routerPrivateApis } from '@wordpress/router'; +import { __experimentalHStack as HStack } from '@wordpress/components'; /** * Internal dependencies @@ -39,13 +45,23 @@ export default function DataViewItem( { isCustom, } ); return ( - - { title } - + + { title } + + { suffix } + ); } diff --git a/packages/edit-site/src/components/sidebar-dataviews/style.scss b/packages/edit-site/src/components/sidebar-dataviews/style.scss index 3e8812267b076..526670ee1e562 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/style.scss +++ b/packages/edit-site/src/components/sidebar-dataviews/style.scss @@ -6,3 +6,17 @@ text-transform: uppercase; } } + +.edit-site-sidebar-dataviews-dataview-item { + &:hover, + &:focus, + &[aria-current] { + color: $gray-200; + background: $gray-800; + } + + &.is-selected { + background: var(--wp-admin-theme-color); + color: $white; + } +} From 065188feb9200558e3ede4557c3acf7072114154 Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Wed, 15 Nov 2023 00:27:26 +0300 Subject: [PATCH 022/116] Block Editor: Optimize BlockListAppender (#56116) --- .../components/block-list-appender/index.js | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/block-list-appender/index.js b/packages/block-editor/src/components/block-list-appender/index.js index 7b37b93d8be8d..68f36f7dd2505 100644 --- a/packages/block-editor/src/components/block-list-appender/index.js +++ b/packages/block-editor/src/components/block-list-appender/index.js @@ -49,10 +49,6 @@ function useAppender( rootClientId, CustomAppender ) { getBlockEditingMode, } = select( blockEditorStore ); - if ( CustomAppender === false ) { - return false; - } - if ( ! CustomAppender ) { const selectedBlockClientId = getSelectedBlockClientId(); const isParentSelected = @@ -92,6 +88,26 @@ function BlockListAppender( { renderAppender, className, tagName: TagName = 'div', +} ) { + if ( renderAppender === false ) { + return null; + } + + return ( + + ); +} + +function BlockListAppenderInner( { + rootClientId, + renderAppender, + className, + tagName: TagName, } ) { const appender = useAppender( rootClientId, renderAppender ); const isDragOver = useSelect( From c64d93b59162f0757fe64c87837884c1c06c8cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Cerro=20L=C3=B3pez?= Date: Tue, 14 Nov 2023 22:35:16 +0100 Subject: [PATCH 023/116] Styles: More descriptive text for revisions timeline (#55868) * Styles: More descriptive text for revisions timeline Fixes https://github.com/WordPress/gutenberg/issues/55648 * Add more descriptive text * Replace by suggested text Co-authored-by: Ramon * Update packages/edit-site/src/components/global-styles/screen-revisions/index.js --------- Co-authored-by: Ramon --- .../src/components/global-styles/screen-revisions/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/global-styles/screen-revisions/index.js b/packages/edit-site/src/components/global-styles/screen-revisions/index.js index ca580edd12a2f..d5c884f9d20cf 100644 --- a/packages/edit-site/src/components/global-styles/screen-revisions/index.js +++ b/packages/edit-site/src/components/global-styles/screen-revisions/index.js @@ -121,7 +121,7 @@ function ScreenRevisions() { { isLoading && ( From 8850bfbf93c0683dfb0d20d884ee41aa4f48d456 Mon Sep 17 00:00:00 2001 From: Ramon Date: Wed, 15 Nov 2023 08:40:29 +1100 Subject: [PATCH 024/116] Download blob: remove downloadjs dependency (#56024) * Create a new function in the blob package: downloadBlob Removes downloadjs dependency Adds tests * Use new function in reusable blocks package Whoops * Update package json deps * - fileName var all to lower case - changed a var to anchorElement - regenerate docs * Removing HTMLElement return value and updating tests Updated docs * Updated test description * Set a default value of `''` for contentType, which matches the Web API spec for Blob Updates tests --- package-lock.json | 16 ++--- packages/blob/CHANGELOG.md | 4 ++ packages/blob/README.md | 25 ++++++++ packages/blob/src/index.js | 40 +++++++++++++ packages/blob/src/test/index.js | 59 ++++++++++++++++++- packages/edit-site/package.json | 2 +- .../header-edit-mode/more-menu/site-export.js | 8 +-- .../src/components/page-patterns/grid-item.js | 22 +------ packages/list-reusable-blocks/package.json | 1 + .../list-reusable-blocks/src/utils/export.js | 4 +- .../list-reusable-blocks/src/utils/file.js | 26 -------- 11 files changed, 139 insertions(+), 68 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9439981c29d7d..8a548f1e83031 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25835,11 +25835,6 @@ "node": ">=12" } }, - "node_modules/downloadjs": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz", - "integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q==" - }, "node_modules/downshift": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.0.tgz", @@ -55321,6 +55316,7 @@ "@tanstack/react-table": "^8.10.3", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/blob": "file:../blob", "@wordpress/block-editor": "file:../block-editor", "@wordpress/block-library": "file:../block-library", "@wordpress/blocks": "file:../blocks", @@ -55361,7 +55357,6 @@ "classnames": "^2.3.1", "colord": "^2.9.2", "deepmerge": "^4.3.0", - "downloadjs": "^1.4.7", "fast-deep-equal": "^3.1.3", "is-plain-object": "^5.0.0", "memize": "^2.1.0", @@ -55892,6 +55887,7 @@ "dependencies": { "@babel/runtime": "^7.16.0", "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/blob": "file:../blob", "@wordpress/components": "file:../components", "@wordpress/compose": "file:../compose", "@wordpress/element": "file:../element", @@ -70398,6 +70394,7 @@ "@tanstack/react-table": "^8.10.3", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/blob": "file:../blob", "@wordpress/block-editor": "file:../block-editor", "@wordpress/block-library": "file:../block-library", "@wordpress/blocks": "file:../blocks", @@ -70438,7 +70435,6 @@ "classnames": "^2.3.1", "colord": "^2.9.2", "deepmerge": "^4.3.0", - "downloadjs": "^1.4.7", "fast-deep-equal": "^3.1.3", "is-plain-object": "^5.0.0", "memize": "^2.1.0", @@ -70785,6 +70781,7 @@ "requires": { "@babel/runtime": "^7.16.0", "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/blob": "file:../blob", "@wordpress/components": "file:../components", "@wordpress/compose": "file:../compose", "@wordpress/element": "file:../element", @@ -76857,11 +76854,6 @@ "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", "dev": true }, - "downloadjs": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz", - "integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q==" - }, "downshift": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.0.tgz", diff --git a/packages/blob/CHANGELOG.md b/packages/blob/CHANGELOG.md index 8d88b3cc4062a..680d53971c018 100644 --- a/packages/blob/CHANGELOG.md +++ b/packages/blob/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### New feature + +- Add `downloadBlob` function and remove `downloadjs` dependency ([#56024](https://github.com/WordPress/gutenberg/pull/56024)). + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/blob/README.md b/packages/blob/README.md index 0305c4784d6cb..ff28e8879602f 100644 --- a/packages/blob/README.md +++ b/packages/blob/README.md @@ -26,6 +26,31 @@ _Returns_ - `string`: The blob URL. +### downloadBlob + +Downloads a file, e.g., a text or readable stream, in the browser. Appropriate for downloading smaller file sizes, e.g., \< 5 MB. + +Example usage: + +```js +const fileContent = JSON.stringify( + { + title: 'My Post', + }, + null, + 2 +); +const fileName = 'file.json'; + +downloadBlob( 'file.json', fileContent, 'application/json' ); +``` + +_Parameters_ + +- _filename_ `string`: File name. +- _content_ `BlobPart`: File content (BufferSource | Blob | string). +- _contentType_ `string`: (Optional) File mime type. Default is `''`. + ### getBlobByURL Retrieve a file based on a blob URL. The file must have been created by `createBlobURL` and not removed by `revokeBlobURL`, otherwise it will return `undefined`. diff --git a/packages/blob/src/index.js b/packages/blob/src/index.js index 496869703d2da..edc2e43729a23 100644 --- a/packages/blob/src/index.js +++ b/packages/blob/src/index.js @@ -70,3 +70,43 @@ export function isBlobURL( url ) { } return url.indexOf( 'blob:' ) === 0; } + +/** + * Downloads a file, e.g., a text or readable stream, in the browser. + * Appropriate for downloading smaller file sizes, e.g., < 5 MB. + * + * Example usage: + * + * ```js + * const fileContent = JSON.stringify( + * { + * "title": "My Post", + * }, + * null, + * 2 + * ); + * const fileName = 'file.json'; + * + * downloadBlob( 'file.json', fileContent, 'application/json' ); + * ``` + * + * @param {string} filename File name. + * @param {BlobPart} content File content (BufferSource | Blob | string). + * @param {string} contentType (Optional) File mime type. Default is `''`. + */ +export function downloadBlob( filename, content, contentType = '' ) { + if ( ! filename || ! content ) { + return; + } + + const file = new window.Blob( [ content ], { type: contentType } ); + const url = window.URL.createObjectURL( file ); + const anchorElement = document.createElement( 'a' ); + anchorElement.href = url; + anchorElement.download = filename; + anchorElement.style.display = 'none'; + document.body.appendChild( anchorElement ); + anchorElement.click(); + document.body.removeChild( anchorElement ); + window.URL.revokeObjectURL( url ); +} diff --git a/packages/blob/src/test/index.js b/packages/blob/src/test/index.js index 4e59917522b51..47dcb5019ee25 100644 --- a/packages/blob/src/test/index.js +++ b/packages/blob/src/test/index.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { isBlobURL, getBlobTypeByURL } from '../'; +import { isBlobURL, getBlobTypeByURL, downloadBlob } from '../'; describe( 'isBlobURL', () => { it( 'returns true if the url starts with "blob:"', () => { @@ -26,3 +26,60 @@ describe( 'getBlobTypeByURL', () => { expect( getBlobTypeByURL() ).toBe( undefined ); } ); } ); + +describe( 'downloadBlob', () => { + const originalURL = window.URL; + const createObjectURL = jest.fn().mockReturnValue( 'blob:pannacotta' ); + const revokeObjectURL = jest.fn().mockReturnValue( false ); + const mockAnchorElement = document.createElement( 'a' ); + mockAnchorElement.click = jest.fn(); + const createElementSpy = jest + .spyOn( global.document, 'createElement' ) + .mockReturnValue( mockAnchorElement ); + const mockBlob = jest.fn(); + const blobSpy = jest.spyOn( window, 'Blob' ).mockReturnValue( mockBlob ); + jest.spyOn( document.body, 'appendChild' ); + jest.spyOn( document.body, 'removeChild' ); + beforeEach( () => { + // Can't seem to spy on these static methods. They are `undefined`. + // Possibly overwritten: https://github.com/WordPress/gutenberg/blob/trunk/packages/jest-preset-default/scripts/setup-globals.js#L5 + window.URL = { + createObjectURL, + revokeObjectURL, + }; + } ); + + afterAll( () => { + window.URL = originalURL; + } ); + + it( 'requires a filename argument', () => { + downloadBlob( '', '{}', 'application/json' ); + expect( blobSpy ).not.toHaveBeenCalled(); + } ); + + it( 'requires a content argument', () => { + downloadBlob( 'text.txt', '', 'text/plain' ); + expect( blobSpy ).not.toHaveBeenCalled(); + } ); + + it( 'constructs an anchor element with attributes and removes it', () => { + downloadBlob( 'filename.json', '{}', 'application/json' ); + expect( blobSpy ).toHaveBeenCalledWith( [ '{}' ], { + type: 'application/json', + } ); + expect( createObjectURL ).toHaveBeenCalledWith( mockBlob ); + expect( createElementSpy ).toHaveBeenCalledWith( 'a' ); + expect( mockAnchorElement.download ).toBe( 'filename.json' ); + expect( mockAnchorElement.href ).toBe( 'blob:pannacotta' ); + expect( mockAnchorElement ).toHaveStyle( 'display:none' ); + expect( document.body.appendChild ).toHaveBeenCalledWith( + mockAnchorElement + ); + expect( mockAnchorElement.click ).toHaveBeenCalledTimes( 1 ); + expect( document.body.removeChild ).toHaveBeenCalledWith( + mockAnchorElement + ); + expect( revokeObjectURL ).toHaveBeenCalled(); + } ); +} ); diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index 03d1ea851ff9a..d7007e1d88fec 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -30,6 +30,7 @@ "@tanstack/react-table": "^8.10.3", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/blob": "file:../blob", "@wordpress/block-editor": "file:../block-editor", "@wordpress/block-library": "file:../block-library", "@wordpress/blocks": "file:../blocks", @@ -70,7 +71,6 @@ "classnames": "^2.3.1", "colord": "^2.9.2", "deepmerge": "^4.3.0", - "downloadjs": "^1.4.7", "fast-deep-equal": "^3.1.3", "is-plain-object": "^5.0.0", "memize": "^2.1.0", diff --git a/packages/edit-site/src/components/header-edit-mode/more-menu/site-export.js b/packages/edit-site/src/components/header-edit-mode/more-menu/site-export.js index ec9492081a42b..85ec4f0dd7335 100644 --- a/packages/edit-site/src/components/header-edit-mode/more-menu/site-export.js +++ b/packages/edit-site/src/components/header-edit-mode/more-menu/site-export.js @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import downloadjs from 'downloadjs'; - /** * WordPress dependencies */ @@ -11,6 +6,7 @@ import { MenuItem } from '@wordpress/components'; import apiFetch from '@wordpress/api-fetch'; import { download } from '@wordpress/icons'; import { useDispatch } from '@wordpress/data'; +import { downloadBlob } from '@wordpress/blob'; import { store as noticesStore } from '@wordpress/notices'; export default function SiteExport() { @@ -35,7 +31,7 @@ export default function SiteExport() { ? contentDispositionMatches[ 1 ] : 'edit-site-export'; - downloadjs( blob, fileName + '.zip', 'application/zip' ); + downloadBlob( fileName + '.zip', blob, 'application/zip' ); } catch ( errorResponse ) { let error = {}; try { diff --git a/packages/edit-site/src/components/page-patterns/grid-item.js b/packages/edit-site/src/components/page-patterns/grid-item.js index 64b70fb87de62..b394ef8eb6e76 100644 --- a/packages/edit-site/src/components/page-patterns/grid-item.js +++ b/packages/edit-site/src/components/page-patterns/grid-item.js @@ -36,6 +36,7 @@ import { } from '@wordpress/icons'; import { store as noticesStore } from '@wordpress/notices'; import { store as reusableBlocksStore } from '@wordpress/reusable-blocks'; +import { downloadBlob } from '@wordpress/blob'; /** * Internal dependencies @@ -51,25 +52,6 @@ import { store as editSiteStore } from '../../store'; import { useLink } from '../routes/link'; import { unlock } from '../../lock-unlock'; -/** - * Downloads a file. - * Also used in packages/list-reusable-blocks/src/utils/file.js. - * - * @param {string} fileName File Name. - * @param {string} content File Content. - * @param {string} contentType File mime type. - */ -function download( fileName, content, contentType ) { - const file = new window.Blob( [ content ], { type: contentType } ); - const a = document.createElement( 'a' ); - a.href = URL.createObjectURL( file ); - a.download = fileName; - a.style.display = 'none'; - document.body.appendChild( a ); - a.click(); - document.body.removeChild( a ); -} - const { useGlobalStyle } = unlock( blockEditorPrivateApis ); const templatePartIcons = { header, footer, uncategorized }; @@ -136,7 +118,7 @@ function GridItem( { categoryId, item, ...props } ) { syncStatus: item.patternBlock.wp_pattern_sync_status, }; - return download( + return downloadBlob( `${ kebabCase( item.title || item.name ) }.json`, JSON.stringify( json, null, 2 ), 'application/json' diff --git a/packages/list-reusable-blocks/package.json b/packages/list-reusable-blocks/package.json index b004d5fe803ee..9cc27c6911a91 100644 --- a/packages/list-reusable-blocks/package.json +++ b/packages/list-reusable-blocks/package.json @@ -27,6 +27,7 @@ "dependencies": { "@babel/runtime": "^7.16.0", "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/blob": "file:../blob", "@wordpress/components": "file:../components", "@wordpress/compose": "file:../compose", "@wordpress/element": "file:../element", diff --git a/packages/list-reusable-blocks/src/utils/export.js b/packages/list-reusable-blocks/src/utils/export.js index 4075c7576f134..4d7e76afcaa8f 100644 --- a/packages/list-reusable-blocks/src/utils/export.js +++ b/packages/list-reusable-blocks/src/utils/export.js @@ -11,7 +11,7 @@ import apiFetch from '@wordpress/api-fetch'; /** * Internal dependencies */ -import { download } from './file'; +import { downloadBlob } from '@wordpress/blob'; /** * Export a reusable block as a JSON file. @@ -38,7 +38,7 @@ async function exportReusableBlock( id ) { ); const fileName = kebabCase( title ) + '.json'; - download( fileName, fileContent, 'application/json' ); + downloadBlob( fileName, fileContent, 'application/json' ); } export default exportReusableBlock; diff --git a/packages/list-reusable-blocks/src/utils/file.js b/packages/list-reusable-blocks/src/utils/file.js index f4cff155c591f..d31e54ae41896 100644 --- a/packages/list-reusable-blocks/src/utils/file.js +++ b/packages/list-reusable-blocks/src/utils/file.js @@ -1,29 +1,3 @@ -/** - * Downloads a file. - * - * @param {string} fileName File Name. - * @param {string} content File Content. - * @param {string} contentType File mime type. - */ -export function download( fileName, content, contentType ) { - const file = new window.Blob( [ content ], { type: contentType } ); - - // IE11 can't use the click to download technique - // we use a specific IE11 technique instead. - if ( window.navigator.msSaveOrOpenBlob ) { - window.navigator.msSaveOrOpenBlob( file, fileName ); - } else { - const a = document.createElement( 'a' ); - a.href = URL.createObjectURL( file ); - a.download = fileName; - - a.style.display = 'none'; - document.body.appendChild( a ); - a.click(); - document.body.removeChild( a ); - } -} - /** * Reads the textual content of the given file. * From db508a2b74133cbcf8ba9260484ce7133f3b4a58 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Wed, 15 Nov 2023 08:51:19 +1100 Subject: [PATCH 025/116] Iframe: Bubble events from html element instead of body element to fix drag chip positioning (#56099) --- packages/block-editor/src/components/iframe/index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index 28697324aa8b8..1939f75811c8c 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -73,12 +73,13 @@ function bubbleEvent( event, Constructor, frame ) { * @param {Document} iframeDocument Document to attach listeners to. */ function useBubbleEvents( iframeDocument ) { - return useRefEffect( ( body ) => { + return useRefEffect( () => { const { defaultView } = iframeDocument; if ( ! defaultView ) { return; } const { frameElement } = defaultView; + const html = iframeDocument.documentElement; const eventTypes = [ 'dragover', 'mousemove' ]; const handlers = {}; for ( const name of eventTypes ) { @@ -88,12 +89,12 @@ function useBubbleEvents( iframeDocument ) { const Constructor = window[ constructorName ]; bubbleEvent( event, Constructor, frameElement ); }; - body.addEventListener( name, handlers[ name ] ); + html.addEventListener( name, handlers[ name ] ); } return () => { for ( const name of eventTypes ) { - body.removeEventListener( name, handlers[ name ] ); + html.removeEventListener( name, handlers[ name ] ); } }; } ); From c131cd00872b05fe067c6bd95326a3ca84ff066e Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 15 Nov 2023 09:36:52 +0400 Subject: [PATCH 026/116] Disable 'no-conditional-in-test' ESLint rule for Playwright (#56088) --- .eslintrc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.js b/.eslintrc.js index 8a44b5ef74a1e..122ec45369c22 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -331,6 +331,7 @@ module.exports = { message: 'Prefer page.locator instead.', }, ], + 'playwright/no-conditional-in-test': 'off', '@typescript-eslint/await-thenable': 'error', '@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-misused-promises': 'error', From a042badf8baf5bf7cbf3af84a9cfb27fb10a1192 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:01:49 +0900 Subject: [PATCH 027/116] Post Featured Image: Handling correctly when uploading a file without mime type (#56133) --- packages/editor/src/components/post-featured-image/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/editor/src/components/post-featured-image/index.js b/packages/editor/src/components/post-featured-image/index.js index 9304115b0b7f1..96eb164696228 100644 --- a/packages/editor/src/components/post-featured-image/index.js +++ b/packages/editor/src/components/post-featured-image/index.js @@ -115,7 +115,9 @@ function PostFeaturedImage( { setIsLoading( true ); return; } - onUpdateImage( image ); + if ( image ) { + onUpdateImage( image ); + } setIsLoading( false ); }, onError( message ) { From 52e9eb2950647c2439d4365fcae867dc01ea0b15 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 15 Nov 2023 08:09:25 +0100 Subject: [PATCH 028/116] SiteEditor: Refactor disable non page content blocks (#56103) Co-authored-by: Kai Hao --- .../disable-non-page-content-blocks.js | 71 ++++++++++--------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/packages/edit-site/src/components/page-content-focus-manager/disable-non-page-content-blocks.js b/packages/edit-site/src/components/page-content-focus-manager/disable-non-page-content-blocks.js index f3e021ba88524..2f81f80d0ce63 100644 --- a/packages/edit-site/src/components/page-content-focus-manager/disable-non-page-content-blocks.js +++ b/packages/edit-site/src/components/page-content-focus-manager/disable-non-page-content-blocks.js @@ -1,9 +1,11 @@ /** * WordPress dependencies */ -import { createHigherOrderComponent } from '@wordpress/compose'; -import { addFilter, removeFilter } from '@wordpress/hooks'; -import { useBlockEditingMode } from '@wordpress/block-editor'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { + useBlockEditingMode, + store as blockEditorStore, +} from '@wordpress/block-editor'; import { useEffect } from '@wordpress/element'; /** @@ -11,42 +13,45 @@ import { useEffect } from '@wordpress/element'; */ import { PAGE_CONTENT_BLOCK_TYPES } from '../../utils/constants'; +function DisableBlock( { clientId } ) { + const isDescendentOfQueryLoop = useSelect( + ( select ) => { + const { getBlockParentsByBlockName } = select( blockEditorStore ); + return ( + getBlockParentsByBlockName( clientId, 'core/query' ).length !== + 0 + ); + }, + [ clientId ] + ); + const mode = isDescendentOfQueryLoop ? undefined : 'contentOnly'; + const { setBlockEditingMode, unsetBlockEditingMode } = + useDispatch( blockEditorStore ); + useEffect( () => { + if ( mode ) { + setBlockEditingMode( clientId, mode ); + return () => { + unsetBlockEditingMode( clientId ); + }; + } + }, [ clientId, mode, setBlockEditingMode, unsetBlockEditingMode ] ); +} + /** * Component that when rendered, makes it so that the site editor allows only * page content to be edited. */ export default function DisableNonPageContentBlocks() { - useDisableNonPageContentBlocks(); - return null; -} - -/** - * Disables non-content blocks using the `useBlockEditingMode` hook. - */ -export function useDisableNonPageContentBlocks() { useBlockEditingMode( 'disabled' ); - useEffect( () => { - addFilter( - 'editor.BlockEdit', - 'core/edit-site/disable-non-content-blocks', - withDisableNonPageContentBlocks + const clientIds = useSelect( ( select ) => { + const { __experimentalGetGlobalBlocksByName } = + select( blockEditorStore ); + return __experimentalGetGlobalBlocksByName( + Object.keys( PAGE_CONTENT_BLOCK_TYPES ) ); - return () => - removeFilter( - 'editor.BlockEdit', - 'core/edit-site/disable-non-content-blocks' - ); }, [] ); -} -const withDisableNonPageContentBlocks = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const isDescendentOfQueryLoop = props.context.queryId !== undefined; - const isPageContent = - PAGE_CONTENT_BLOCK_TYPES[ props.name ] && ! isDescendentOfQueryLoop; - const mode = isPageContent ? 'contentOnly' : undefined; - useBlockEditingMode( mode ); - return ; - }, - 'withDisableNonPageContentBlocks' -); + return clientIds.map( ( clientId ) => { + return ; + } ); +} From 1d1abd2505b75715fabcf3914b98857f4239c8ce Mon Sep 17 00:00:00 2001 From: Brad Jorsch Date: Wed, 15 Nov 2023 03:54:19 -0500 Subject: [PATCH 029/116] Package `@ariakit/test` should be a dev dependency (#56091) * Package `@ariakit/test` should be a dev dependency In #54939 a new test was added that depends on `@ariakit/test`. But, even though that package is not needed in the production code, it was (accidentally?) added to `dependencies` instead of `devDependencies`. This means everyone using `@wordpress/components` winds up having to install this package. Let's move it to devDependencies where it belongs. * Add PR link to changelog * Remove extraneous `.` --- package-lock.json | 169 ++++++++++++++++++++++++++----- package.json | 1 + packages/components/CHANGELOG.md | 4 + packages/components/package.json | 1 - 4 files changed, 149 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8a548f1e83031..28f51a1408f64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -84,6 +84,7 @@ "devDependencies": { "@actions/core": "1.9.1", "@actions/github": "5.0.0", + "@ariakit/test": "^0.3.0", "@babel/core": "7.16.0", "@babel/plugin-proposal-export-namespace-from": "7.18.9", "@babel/plugin-syntax-jsx": "7.16.0", @@ -1664,6 +1665,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/@ariakit/test/-/test-0.3.0.tgz", "integrity": "sha512-fngAzkzCl9zM4O/tzVaUf7ixWUAk779hjTegr/zcegoxaMS5SmaLhNQ7RU0AGx06LrhJse6GYGy8ZtK58HP/EQ==", + "dev": true, "dependencies": { "@ariakit/core": "0.3.3", "@testing-library/dom": "^8.0.0 || ^9.0.0" @@ -1681,6 +1683,12 @@ } } }, + "node_modules/@ariakit/test/node_modules/@ariakit/core": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.3.3.tgz", + "integrity": "sha512-8x77R0aE9O9pheygg+h/z0oU9Wx/Xdlr7nfkl4klGnkJma8/nAhJ2RrchCTQCUef4WMsRnq/doCz8m/sslP6CA==", + "dev": true + }, "node_modules/@aw-web-design/x-default-browser": { "version": "1.4.126", "resolved": "https://registry.npmjs.org/@aw-web-design/x-default-browser/-/x-default-browser-1.4.126.tgz", @@ -15282,6 +15290,7 @@ "version": "9.3.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz", "integrity": "sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==", + "dev": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -15300,6 +15309,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "engines": { "node": ">=10" }, @@ -15311,6 +15321,7 @@ "version": "5.1.3", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, "dependencies": { "deep-equal": "^2.0.5" } @@ -15319,6 +15330,7 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.2", @@ -15346,12 +15358,14 @@ "node_modules/@testing-library/dom/node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true }, "node_modules/@testing-library/dom/node_modules/pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -15364,7 +15378,8 @@ "node_modules/@testing-library/dom/node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true }, "node_modules/@testing-library/jest-dom": { "version": "5.16.5", @@ -15567,7 +15582,8 @@ "node_modules/@types/aria-query": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", + "dev": true }, "node_modules/@types/async-lock": { "version": "1.4.0", @@ -19893,6 +19909,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "is-array-buffer": "^3.0.1" @@ -20232,6 +20249,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -21670,6 +21688,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -25107,6 +25126,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, "dependencies": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -25687,7 +25707,8 @@ "node_modules/dom-accessibility-api": { "version": "0.5.14", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz", - "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==" + "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==", + "dev": true }, "node_modules/dom-converter": { "version": "0.2.0", @@ -26305,6 +26326,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -26323,7 +26345,8 @@ "node_modules/es-get-iterator/node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true }, "node_modules/es-module-lexer": { "version": "1.3.1", @@ -28711,6 +28734,7 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, "dependencies": { "is-callable": "^1.1.3" } @@ -29097,6 +29121,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -29330,6 +29355,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -29820,6 +29846,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -29981,6 +30008,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -29997,6 +30025,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, "dependencies": { "get-intrinsic": "^1.1.1" }, @@ -30008,6 +30037,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -30019,6 +30049,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -30030,6 +30061,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -31203,6 +31235,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, "dependencies": { "get-intrinsic": "^1.2.0", "has": "^1.0.3", @@ -31332,6 +31365,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -31347,6 +31381,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.0", @@ -31365,6 +31400,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, "dependencies": { "has-bigints": "^1.0.1" }, @@ -31388,6 +31424,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -31423,6 +31460,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -31485,6 +31523,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -31678,6 +31717,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -31725,6 +31765,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -31835,6 +31876,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -31859,6 +31901,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -31867,6 +31910,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -31895,6 +31939,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -31909,6 +31954,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -31935,6 +31981,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, "dependencies": { "which-typed-array": "^1.1.11" }, @@ -31966,6 +32013,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -31986,6 +32034,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -36650,6 +36699,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, "bin": { "lz-string": "bin/bin.js" } @@ -41602,6 +41652,7 @@ "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -41610,6 +41661,7 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -41625,6 +41677,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "engines": { "node": ">= 0.4" } @@ -41644,6 +41697,7 @@ "version": "4.1.4", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -46379,6 +46433,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -48142,6 +48197,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -48978,6 +49034,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, "dependencies": { "internal-slot": "^1.0.4" }, @@ -53616,6 +53673,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -53631,6 +53689,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, "dependencies": { "is-map": "^2.0.1", "is-set": "^2.0.1", @@ -53650,6 +53709,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -54781,7 +54841,6 @@ "license": "GPL-2.0-or-later", "dependencies": { "@ariakit/react": "^0.3.5", - "@ariakit/test": "^0.3.0", "@babel/runtime": "^7.16.0", "@emotion/cache": "^11.7.1", "@emotion/css": "^11.7.1", @@ -57742,9 +57801,18 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/@ariakit/test/-/test-0.3.0.tgz", "integrity": "sha512-fngAzkzCl9zM4O/tzVaUf7ixWUAk779hjTegr/zcegoxaMS5SmaLhNQ7RU0AGx06LrhJse6GYGy8ZtK58HP/EQ==", + "dev": true, "requires": { "@ariakit/core": "0.3.3", "@testing-library/dom": "^8.0.0 || ^9.0.0" + }, + "dependencies": { + "@ariakit/core": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.3.3.tgz", + "integrity": "sha512-8x77R0aE9O9pheygg+h/z0oU9Wx/Xdlr7nfkl4klGnkJma8/nAhJ2RrchCTQCUef4WMsRnq/doCz8m/sslP6CA==", + "dev": true + } } }, "@aw-web-design/x-default-browser": { @@ -67420,6 +67488,7 @@ "version": "9.3.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz", "integrity": "sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==", + "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -67434,12 +67503,14 @@ "ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true }, "aria-query": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, "requires": { "deep-equal": "^2.0.5" } @@ -67448,6 +67519,7 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "dev": true, "requires": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.2", @@ -67472,12 +67544,14 @@ "isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true }, "pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, "requires": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -67487,7 +67561,8 @@ "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true } } }, @@ -67642,7 +67717,8 @@ "@types/aria-query": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", + "dev": true }, "@types/async-lock": { "version": "1.4.0", @@ -70019,7 +70095,6 @@ "version": "file:packages/components", "requires": { "@ariakit/react": "^0.3.5", - "@ariakit/test": "^0.3.0", "@babel/runtime": "^7.16.0", "@emotion/cache": "^11.7.1", "@emotion/css": "^11.7.1", @@ -72279,6 +72354,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, "requires": { "call-bind": "^1.0.2", "is-array-buffer": "^3.0.1" @@ -72544,7 +72620,8 @@ "available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true }, "axe-core": { "version": "4.7.2", @@ -73678,6 +73755,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -76289,6 +76367,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, "requires": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -76734,7 +76813,8 @@ "dom-accessibility-api": { "version": "0.5.14", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz", - "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==" + "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==", + "dev": true }, "dom-converter": { "version": "0.2.0", @@ -77239,6 +77319,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -77254,7 +77335,8 @@ "isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true } } }, @@ -79087,6 +79169,7 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, "requires": { "is-callable": "^1.1.3" } @@ -79386,7 +79469,8 @@ "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true }, "gauge": { "version": "4.0.4", @@ -79565,6 +79649,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -79948,6 +80033,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, "requires": { "get-intrinsic": "^1.1.3" } @@ -80077,7 +80163,8 @@ "has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true }, "has-flag": { "version": "3.0.0", @@ -80088,6 +80175,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, "requires": { "get-intrinsic": "^1.1.1" } @@ -80095,17 +80183,20 @@ "has-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true }, "has-tostringtag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -80988,6 +81079,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, "requires": { "get-intrinsic": "^1.2.0", "has": "^1.0.3", @@ -81090,6 +81182,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -81099,6 +81192,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.0", @@ -81114,6 +81208,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, "requires": { "has-bigints": "^1.0.1" } @@ -81131,6 +81226,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -81153,7 +81249,8 @@ "is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true }, "is-ci": { "version": "2.0.0", @@ -81202,6 +81299,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -81329,7 +81427,8 @@ "is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true }, "is-nan": { "version": "1.3.2", @@ -81369,6 +81468,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -81438,6 +81538,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -81452,12 +81553,14 @@ "is-set": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true }, "is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, "requires": { "call-bind": "^1.0.2" } @@ -81480,6 +81583,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -81488,6 +81592,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -81505,6 +81610,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, "requires": { "which-typed-array": "^1.1.11" } @@ -81523,7 +81629,8 @@ "is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true }, "is-weakref": { "version": "1.0.2", @@ -81538,6 +81645,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -85114,7 +85222,8 @@ "lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==" + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true }, "macos-release": { "version": "2.2.0", @@ -88993,12 +89102,14 @@ "object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true }, "object-is": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -89007,7 +89118,8 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true }, "object-visit": { "version": "1.0.1", @@ -89021,6 +89133,7 @@ "version": "4.1.4", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -92577,6 +92690,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -93969,6 +94083,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -94618,6 +94733,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, "requires": { "internal-slot": "^1.0.4" } @@ -98075,6 +98191,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, "requires": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -98087,6 +98204,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, "requires": { "is-map": "^2.0.1", "is-set": "^2.0.1", @@ -98103,6 +98221,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", diff --git a/package.json b/package.json index 9f456f359a741..2c3313b9337d4 100644 --- a/package.json +++ b/package.json @@ -96,6 +96,7 @@ "devDependencies": { "@actions/core": "1.9.1", "@actions/github": "5.0.0", + "@ariakit/test": "^0.3.0", "@babel/core": "7.16.0", "@babel/plugin-proposal-export-namespace-from": "7.18.9", "@babel/plugin-syntax-jsx": "7.16.0", diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 0ca8fb69cde4f..be179d3b2251d 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -20,6 +20,10 @@ - `ToggleGroupControl`: Add opt-in prop for 40px default size ([#55789](https://github.com/WordPress/gutenberg/pull/55789)). - `TextControl`: Add opt-in prop for 40px default size ([#55471](https://github.com/WordPress/gutenberg/pull/55471)). +### Bug Fix + +- Package should not depend on `@ariakit/test`, that package is only needed for testing ([#56091](https://github.com/WordPress/gutenberg/pull/56091)). + ## 25.11.0 (2023-11-02) ### Enhancements diff --git a/packages/components/package.json b/packages/components/package.json index f616b261c8ec4..2980553f5a284 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -31,7 +31,6 @@ "types": "build-types", "dependencies": { "@ariakit/react": "^0.3.5", - "@ariakit/test": "^0.3.0", "@babel/runtime": "^7.16.0", "@emotion/cache": "^11.7.1", "@emotion/css": "^11.7.1", From b7f2740d0e730a480da7a8ae8e700134c7b2a1c6 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 15 Nov 2023 11:49:53 +0100 Subject: [PATCH 030/116] Documentation: Add a first block type page to the platform docs (#56109) Co-authored-by: Ramon Co-authored-by: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> --- .../docs/create-block/first-block-type.md | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/platform-docs/docs/create-block/first-block-type.md b/platform-docs/docs/create-block/first-block-type.md index 26925aab51987..437f4ec43b3e5 100644 --- a/platform-docs/docs/create-block/first-block-type.md +++ b/platform-docs/docs/create-block/first-block-type.md @@ -2,4 +2,55 @@ sidebar_position: 1 --- -# Your first block type \ No newline at end of file +# Your first block type + +In addition to the built-in block types, Gutenberg offers a flexible API to build any kind of block type you can imagine. + +The `registerBlockType` function registers the block we are going to create and specifies the block type settings. + +```js +import { createElement } from 'react'; +import { registerBlockType } from '@wordpress/blocks'; + +registerBlockType( 'create-block/gutenpride', { + // This is just a flag that tells the block editor that this block + // is using the API version 3 (the latest block type API). + apiVersion: 3, + + // This is the display title for your block type. + title: 'Gutenpride', + + // This is the category this block type will be listed in. + // Default categories include: text, media, design, widgets, theme and embed. + category: 'widgets', + + // This is a short description for your block type. + // It will be shown in various places in the Gutenberg user interface. + description: 'Example static block scaffolded with Create Block tool.', + + // This is an icon for your block type. + icon: ( + + + + ), + + edit() { + return

Hello from the editor!

; + }, + + save() { + return

Hello from the saved content!

; + }, +} ); +``` + +The first parameter in the **registerBlockType** function is the block name. It's composed of two segments: a namespace and a specific name. The namespace is used to avoid collisions with other block types from different sources. The specific name is the name of the block type. The namespace and the specific name are separated by a slash. + +The second parameter to the function is the block type object. Two common object properties are **edit** and **save** — these are the key parts of a block. + +The result of the edit function is what the editor will render to the editor page when the block is inserted. + +The result of the save function is what the editor will produce as HTML when calling the `serialize` function. + +The `create-block/gutenpride` block type produces a static block at the moment, in the following sections of the tutorial, we will see how to make it editable. From 8f3405f9726793ed355df84ba190f52c8347c27e Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Wed, 15 Nov 2023 12:42:49 +0100 Subject: [PATCH 031/116] DropdownMenu: remove extra vertical space around the toggle button (#56136) * DropdownMenu: add default vertical-align for the toggle button * CHANGELOG --- packages/components/CHANGELOG.md | 1 + packages/components/src/dropdown-menu/style.scss | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index be179d3b2251d..a96c5dc5827c5 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -22,6 +22,7 @@ ### Bug Fix +- `DropdownMenu`: remove extra vertical space around the toggle button ([#56136](https://github.com/WordPress/gutenberg/pull/56136)). - Package should not depend on `@ariakit/test`, that package is only needed for testing ([#56091](https://github.com/WordPress/gutenberg/pull/56091)). ## 25.11.0 (2023-11-02) diff --git a/packages/components/src/dropdown-menu/style.scss b/packages/components/src/dropdown-menu/style.scss index 7d9e1b997f780..261662ab7256d 100644 --- a/packages/components/src/dropdown-menu/style.scss +++ b/packages/components/src/dropdown-menu/style.scss @@ -1,3 +1,7 @@ +.components-dropdown-menu__toggle { + vertical-align: top; +} + .components-dropdown-menu__menu { width: 100%; font-family: $default-font; From 90aa9bd9ae808dca6c37d5bd6c3a09ca00602a26 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 15 Nov 2023 16:28:49 +0400 Subject: [PATCH 032/116] Migrate 'Plugins API' e2e tests to Playwright (#55958) * Migrate 'Plugins API' e2e tests to Playwright * Remove old test file and snapshot --- .../__snapshots__/plugins-api.test.js.snap | 7 - .../specs/editor/plugins/plugins-api.test.js | 189 -------------- .../plugins-api-error-boundary.spec.js | 38 +++ .../specs/editor/plugins/plugins-api.spec.js | 233 ++++++++++++++++++ 4 files changed, 271 insertions(+), 196 deletions(-) delete mode 100644 packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap delete mode 100644 packages/e2e-tests/specs/editor/plugins/plugins-api.test.js create mode 100644 test/e2e/specs/editor/plugins/plugins-api-error-boundary.spec.js create mode 100644 test/e2e/specs/editor/plugins/plugins-api.spec.js diff --git a/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap b/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap deleted file mode 100644 index 9e4a5ac3ad6f6..0000000000000 --- a/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Using Plugins API Document Setting Custom Panel Should render a custom panel inside Document Setting sidebar 1`] = `"My Custom Panel"`; - -exports[`Using Plugins API Sidebar Medium screen Should open plugins sidebar using More Menu item and render content 1`] = `"
(no title)
Plugin title
"`; - -exports[`Using Plugins API Sidebar Should open plugins sidebar using More Menu item and render content 1`] = `"
(no title)
Plugin title
"`; diff --git a/packages/e2e-tests/specs/editor/plugins/plugins-api.test.js b/packages/e2e-tests/specs/editor/plugins/plugins-api.test.js deleted file mode 100644 index 4ad8d0e634204..0000000000000 --- a/packages/e2e-tests/specs/editor/plugins/plugins-api.test.js +++ /dev/null @@ -1,189 +0,0 @@ -/** - * WordPress dependencies - */ -import { - activatePlugin, - clickBlockAppender, - clickOnMoreMenuItem, - createNewPost, - deactivatePlugin, - openDocumentSettingsSidebar, - openPublishPanel, - publishPost, - setBrowserViewport, -} from '@wordpress/e2e-test-utils'; - -describe( 'Using Plugins API', () => { - beforeAll( async () => { - await activatePlugin( 'gutenberg-test-plugin-plugins-api' ); - } ); - - afterAll( async () => { - await deactivatePlugin( 'gutenberg-test-plugin-plugins-api' ); - } ); - - beforeEach( async () => { - await createNewPost(); - } ); - - describe( 'Post Status Info', () => { - it( 'Should render post status info inside Document Setting sidebar', async () => { - await openDocumentSettingsSidebar(); - - const pluginPostStatusInfoText = await page.$eval( - '.edit-post-post-status .my-post-status-info-plugin', - ( el ) => el.innerText - ); - expect( pluginPostStatusInfoText ).toBe( 'My post status info' ); - } ); - } ); - - describe( 'Publish Panel', () => { - beforeEach( async () => { - // Type something first to activate Publish button. - await clickBlockAppender(); - await page.keyboard.type( 'First paragraph' ); - } ); - - it( 'Should render publish panel inside Pre-publish sidebar', async () => { - await openPublishPanel(); - - const pluginPublishPanelText = await page.$eval( - '.editor-post-publish-panel .my-publish-panel-plugin__pre', - ( el ) => el.innerText - ); - expect( pluginPublishPanelText ).toMatch( 'My pre publish panel' ); - } ); - - it( 'Should render publish panel inside Post-publish sidebar', async () => { - await publishPost(); - const pluginPublishPanel = await page.waitForSelector( - '.editor-post-publish-panel .my-publish-panel-plugin__post' - ); - const pluginPublishPanelText = await pluginPublishPanel.evaluate( - ( node ) => node.innerText - ); - expect( pluginPublishPanelText ).toMatch( 'My post publish panel' ); - } ); - } ); - - describe( 'Sidebar', () => { - const SIDEBAR_PINNED_ITEM_BUTTON = - '.interface-pinned-items button[aria-label="Plugin title"]'; - const SIDEBAR_PANEL_SELECTOR = '.sidebar-title-plugin-panel'; - it( 'Should open plugins sidebar using More Menu item and render content', async () => { - await clickOnMoreMenuItem( 'Plugin more menu title' ); - - const pluginSidebarContent = await page.$eval( - '.edit-post-sidebar', - ( el ) => el.innerHTML - ); - expect( pluginSidebarContent ).toMatchSnapshot(); - } ); - - it( 'Should be pinned by default and can be opened and closed using pinned items', async () => { - const sidebarPinnedItem = await page.$( - SIDEBAR_PINNED_ITEM_BUTTON - ); - expect( sidebarPinnedItem ).not.toBeNull(); - await sidebarPinnedItem.click(); - expect( await page.$( SIDEBAR_PANEL_SELECTOR ) ).not.toBeNull(); - await sidebarPinnedItem.click(); - expect( await page.$( SIDEBAR_PANEL_SELECTOR ) ).toBeNull(); - } ); - - it( 'Can be pinned and unpinned', async () => { - await ( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).click(); - const unpinButton = await page.$( - 'button[aria-label="Unpin from toolbar"]' - ); - await unpinButton.click(); - expect( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).toBeNull(); - await page.click( - '.interface-complementary-area-header button[aria-label="Close plugin"]' - ); - await page.reload(); - await page.waitForSelector( '.edit-post-layout' ); - expect( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).toBeNull(); - await clickOnMoreMenuItem( 'Plugin more menu title' ); - await page.click( 'button[aria-label="Pin to toolbar"]' ); - expect( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).not.toBeNull(); - await page.reload(); - await page.waitForSelector( '.edit-post-layout' ); - expect( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).not.toBeNull(); - } ); - - it( 'Should close plugins sidebar using More Menu item', async () => { - await clickOnMoreMenuItem( 'Plugin more menu title' ); - - const pluginSidebarOpened = await page.$( '.edit-post-sidebar' ); - expect( pluginSidebarOpened ).not.toBeNull(); - - await clickOnMoreMenuItem( 'Plugin more menu title' ); - - const pluginSidebarClosed = await page.$( '.edit-post-sidebar' ); - expect( pluginSidebarClosed ).toBeNull(); - } ); - - describe( 'Medium screen', () => { - beforeAll( async () => { - await setBrowserViewport( 'medium' ); - } ); - - afterAll( async () => { - await setBrowserViewport( 'large' ); - } ); - - it( 'Should open plugins sidebar using More Menu item and render content', async () => { - await clickOnMoreMenuItem( 'Plugin more menu title' ); - - const pluginSidebarContent = await page.$eval( - '.edit-post-sidebar', - ( el ) => el.innerHTML - ); - expect( pluginSidebarContent ).toMatchSnapshot(); - } ); - } ); - } ); - - describe( 'Document Setting Custom Panel', () => { - it( 'Should render a custom panel inside Document Setting sidebar', async () => { - await openDocumentSettingsSidebar(); - const pluginDocumentSettingsText = await page.$eval( - '.edit-post-sidebar .my-document-setting-plugin', - ( el ) => el.innerText - ); - expect( pluginDocumentSettingsText ).toMatchSnapshot(); - } ); - } ); - - describe( 'Error Boundary', () => { - beforeAll( async () => { - await activatePlugin( - 'gutenberg-test-plugin-plugins-error-boundary' - ); - } ); - - afterAll( async () => { - await deactivatePlugin( - 'gutenberg-test-plugin-plugins-error-boundary' - ); - } ); - - it( 'Should create notice using plugin error boundary callback', async () => { - const noticeContent = await page.waitForSelector( - '.is-error .components-notice__content' - ); - expect( - await page.evaluate( - ( _noticeContent ) => _noticeContent.firstChild.nodeValue, - noticeContent - ) - ).toEqual( - 'The "my-error-plugin" plugin has encountered an error and cannot be rendered.' - ); - - expect( console ).toHaveErrored(); - } ); - } ); -} ); diff --git a/test/e2e/specs/editor/plugins/plugins-api-error-boundary.spec.js b/test/e2e/specs/editor/plugins/plugins-api-error-boundary.spec.js new file mode 100644 index 0000000000000..25f528be8a008 --- /dev/null +++ b/test/e2e/specs/editor/plugins/plugins-api-error-boundary.spec.js @@ -0,0 +1,38 @@ +/** + * WordPress dependencies + */ +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.describe( 'Plugins API Error Boundary', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activatePlugin( + 'gutenberg-test-plugin-plugins-error-boundary' + ); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.deactivatePlugin( + 'gutenberg-test-plugin-plugins-error-boundary' + ); + } ); + + test( 'Should create notice using plugin error boundary callback', async ( { + admin, + page, + } ) => { + let hasError = false; + page.on( 'console', ( msg ) => { + if ( msg.type() === 'error' && msg.text().includes( 'Whoops!' ) ) + hasError = true; + } ); + + await admin.createNewPost(); + + expect( hasError ).toBe( true ); + await expect( + page.locator( '.is-error .components-notice__content' ) + ).toContainText( + 'The "my-error-plugin" plugin has encountered an error and cannot be rendered.' + ); + } ); +} ); diff --git a/test/e2e/specs/editor/plugins/plugins-api.spec.js b/test/e2e/specs/editor/plugins/plugins-api.spec.js new file mode 100644 index 0000000000000..c71b49e3c4d81 --- /dev/null +++ b/test/e2e/specs/editor/plugins/plugins-api.spec.js @@ -0,0 +1,233 @@ +/** + * WordPress dependencies + */ +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.describe( 'Plugins API', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activatePlugin( + 'gutenberg-test-plugin-plugins-api' + ); + } ); + + test.beforeEach( async ( { admin } ) => { + await admin.createNewPost(); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.deactivatePlugin( + 'gutenberg-test-plugin-plugins-api' + ); + } ); + + test.describe( 'Post Status Info', () => { + test( 'Should render post status info inside Document Setting sidebar', async ( { + editor, + page, + } ) => { + await editor.openDocumentSettingsSidebar(); + + await expect( + page + .getByRole( 'region', { name: 'Editor settings' } ) + .locator( '.my-post-status-info-plugin' ) + ).toHaveText( 'My post status info' ); + } ); + } ); + + test.describe( 'Publish Panel', () => { + test( 'Should render publish panel inside Pre-publish sidebar', async ( { + editor, + page, + } ) => { + await editor.canvas + .getByRole( 'textbox', { name: 'Add title' } ) + .fill( 'A post' ); + + // Open pre-publish panel. + await page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Publish' } ) + .click(); + + await expect( + page + .getByRole( 'region', { name: 'Editor publish' } ) + .getByRole( 'button', { name: 'My pre publish panel' } ) + ).toBeVisible(); + } ); + + test( 'Should render publish panel inside Post-publish sidebar', async ( { + editor, + page, + } ) => { + await editor.canvas + .getByRole( 'textbox', { name: 'Add title' } ) + .fill( 'A post' ); + await editor.publishPost(); + + await expect( + page + .getByRole( 'region', { name: 'Editor publish' } ) + .getByRole( 'button', { name: 'My post publish panel' } ) + ).toBeVisible(); + } ); + } ); + + test.describe( 'Sidebar', () => { + test( 'Should open plugins sidebar using More Menu item and render content', async ( { + page, + } ) => { + await page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Options' } ) + .click(); + await page + .getByRole( 'menuitemcheckbox', { + name: 'Plugin more menu title', + } ) + .click(); + + const settingsSidebar = page.getByRole( 'region', { + name: 'Editor settings', + } ); + + await expect( + settingsSidebar.getByRole( 'textbox', { + name: 'Title', + } ) + ).toBeVisible(); + await expect( + settingsSidebar.getByRole( 'button', { + name: 'Reset', + } ) + ).toBeVisible(); + } ); + + test( 'Should be pinned by default and can be opened and closed using pinned items', async ( { + page, + } ) => { + const pinnedButton = page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Plugin title' } ); + const pluginField = page + .getByRole( 'region', { + name: 'Editor settings', + } ) + .getByRole( 'textbox', { + name: 'Title', + } ); + + await pinnedButton.click(); + await expect( pluginField ).toBeVisible(); + + await pinnedButton.click(); + await expect( pluginField ).toBeHidden(); + } ); + + test( 'Can be pinned and unpinned', async ( { page } ) => { + const pinnedButton = page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Plugin title' } ); + + await pinnedButton.click(); + await page + .getByRole( 'button', { name: 'Unpin from toolbar' } ) + .click(); + + await expect( pinnedButton ).toBeHidden(); + + await page.getByRole( 'button', { name: 'Close plugin' } ).click(); + await page.reload(); + + await expect( pinnedButton ).toBeHidden(); + + await page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Options' } ) + .click(); + await page + .getByRole( 'menuitemcheckbox', { + name: 'Plugin more menu title', + } ) + .click(); + await page + .getByRole( 'button', { name: 'Pin to toolbar' } ) + .click(); + + await expect( pinnedButton ).toBeVisible(); + await page.reload(); + await expect( pinnedButton ).toBeVisible(); + } ); + + test( 'Should close plugins sidebar using More Menu item', async ( { + page, + } ) => { + const options = page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Options' } ); + const moreMenuItem = page.getByRole( 'menuitemcheckbox', { + name: 'Plugin more menu title', + } ); + const pluginField = page + .getByRole( 'region', { + name: 'Editor settings', + } ) + .getByRole( 'textbox', { + name: 'Title', + } ); + + await options.click(); + await moreMenuItem.click(); + await expect( pluginField ).toBeVisible(); + + await options.click(); + await moreMenuItem.click(); + await expect( pluginField ).toBeHidden(); + } ); + + test( 'Should open plugins sidebar using More Menu item on smaller screens', async ( { + page, + pageUtils, + } ) => { + await pageUtils.setBrowserViewport( 'medium' ); + + await page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Options' } ) + .click(); + await page + .getByRole( 'menuitemcheckbox', { + name: 'Plugin more menu title', + } ) + .click(); + + await expect( + page + .getByRole( 'region', { + name: 'Editor settings', + } ) + .getByRole( 'textbox', { + name: 'Title', + } ) + ).toBeVisible(); + + await pageUtils.setBrowserViewport( 'large' ); + } ); + } ); + + test.describe( 'Document Setting Custom Panel', () => { + test( 'Should render a custom panel inside Document Setting sidebar', async ( { + editor, + page, + } ) => { + await editor.openDocumentSettingsSidebar(); + + await expect( + page + .getByRole( 'region', { name: 'Editor settings' } ) + .getByRole( 'button', { name: 'My Custom Panel' } ) + ).toBeVisible(); + } ); + } ); +} ); From 1bf654b6c7f794d598fc6980789185924168ee2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:18:04 +0100 Subject: [PATCH 033/116] DataViews: allow users to add filters dynamically (#55992) --- .../src/components/dataviews/README.md | 5 +- .../src/components/dataviews/add-filter.js | 111 ++++++++++++++++++ .../src/components/dataviews/filters.js | 66 ++++++----- .../src/components/dataviews/in-filter.js | 14 +-- .../src/components/dataviews/reset-filters.js | 34 +++--- .../src/components/dataviews/search.js | 1 + .../sidebar-dataviews/default-views.js | 1 - 7 files changed, 171 insertions(+), 61 deletions(-) create mode 100644 packages/edit-site/src/components/dataviews/add-filter.js diff --git a/packages/edit-site/src/components/dataviews/README.md b/packages/edit-site/src/components/dataviews/README.md index 5502165f0cfdc..8f1349044d6cf 100644 --- a/packages/edit-site/src/components/dataviews/README.md +++ b/packages/edit-site/src/components/dataviews/README.md @@ -47,7 +47,6 @@ Example: { field: 'author', operator: 'in', value: 2 }, { field: 'status', operator: 'in', value: 'publish,draft' } ], - visibleFilters: [ 'author', 'status' ], hiddenFields: [ 'date', 'featured-image' ], layout: {}, } @@ -62,8 +61,7 @@ Example: - `filters`: the filters applied to the dataset. Each item describes: - `field`: which field this filter is bound to. - `operator`: which type of filter it is. Only `in` available at the moment. - - `vaule`: the actual value selected by the user. -- `visibleFilters`: the `id` of the filters that are visible in the UI. + - `value`: the actual value selected by the user. - `hiddenFields`: the `id` of the fields that are hidden in the UI. - `layout`: ... @@ -88,7 +86,6 @@ function MyCustomPageList() { { field: 'author', operator: 'in', value: 2 }, { field: 'status', operator: 'in', value: 'publish,draft' } ], - visibleFilters: [ 'author', 'status' ], hiddenFields: [ 'date', 'featured-image' ], layout: {}, } ); diff --git a/packages/edit-site/src/components/dataviews/add-filter.js b/packages/edit-site/src/components/dataviews/add-filter.js new file mode 100644 index 0000000000000..2cc0051f0f2d4 --- /dev/null +++ b/packages/edit-site/src/components/dataviews/add-filter.js @@ -0,0 +1,111 @@ +/** + * WordPress dependencies + */ +import { + privateApis as componentsPrivateApis, + Button, + Icon, +} from '@wordpress/components'; +import { chevronRightSmall, plus } from '@wordpress/icons'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import { OPERATOR_IN } from './in-filter'; + +const { + DropdownMenuV2, + DropdownSubMenuV2, + DropdownSubMenuTriggerV2, + DropdownMenuItemV2, +} = unlock( componentsPrivateApis ); + +const VALID_OPERATORS = [ OPERATOR_IN ]; + +export default function AddFilter( { fields, view, onChangeView } ) { + const filters = []; + fields.forEach( ( field ) => { + if ( ! field.filters ) { + return; + } + + field.filters.forEach( ( filter ) => { + if ( VALID_OPERATORS.some( ( operator ) => operator === filter ) ) { + filters.push( { + field: field.id, + name: field.header, + operator: filter, + elements: field.elements || [], + isVisible: view.filters.some( + ( f ) => f.field === field.id && f.operator === filter + ), + } ); + } + } ); + } ); + + if ( filters.length === 0 ) { + return null; + } + + return ( + + { __( 'Add filter' ) } + + } + > + { filters.map( ( filter ) => { + if ( filter.isVisible ) { + return null; + } + + return ( + } + > + { filter.name } + + } + > + { filter.elements.map( ( element ) => ( + { + onChangeView( ( currentView ) => ( { + ...currentView, + page: 1, + filters: [ + ...currentView.filters, + { + field: filter.field, + operator: 'in', + value: element.value, + }, + ], + } ) ); + } } + role="menuitemcheckbox" + > + { element.label } + + ) ) } + + ); + } ) } + + ); +} diff --git a/packages/edit-site/src/components/dataviews/filters.js b/packages/edit-site/src/components/dataviews/filters.js index e34ba84040a95..dc268845df5c0 100644 --- a/packages/edit-site/src/components/dataviews/filters.js +++ b/packages/edit-site/src/components/dataviews/filters.js @@ -7,12 +7,13 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import { default as InFilter, OPERATOR_IN } from './in-filter'; +import AddFilter from './add-filter'; import ResetFilters from './reset-filters'; const VALID_OPERATORS = [ OPERATOR_IN ]; export default function Filters( { fields, view, onChangeView } ) { - const filtersRegistered = []; + const filters = []; fields.forEach( ( field ) => { if ( ! field.filters ) { return; @@ -20,7 +21,7 @@ export default function Filters( { fields, view, onChangeView } ) { field.filters.forEach( ( filter ) => { if ( VALID_OPERATORS.some( ( operator ) => operator === filter ) ) { - filtersRegistered.push( { + filters.push( { field: field.id, name: field.header, operator: filter, @@ -31,46 +32,47 @@ export default function Filters( { fields, view, onChangeView } ) { }, ...( field.elements || [] ), ], + isVisible: view.filters.some( + ( f ) => f.field === field.id && f.operator === filter + ), } ); } } ); } ); - const visibleFilters = view.visibleFilters - ?.map( ( fieldName ) => { - const visibleFiltersForField = filtersRegistered.filter( - ( f ) => f.field === fieldName + const filterComponents = filters?.map( ( filter ) => { + if ( ! filter.isVisible ) { + return null; + } + + if ( OPERATOR_IN === filter.operator ) { + return ( + ); + } - if ( visibleFiltersForField.length === 0 ) { - return null; - } + return null; + } ); - return visibleFiltersForField.map( ( filter ) => { - if ( OPERATOR_IN === filter.operator ) { - return ( - - ); - } - return null; - } ); - } ) - .filter( Boolean ); + filterComponents.push( + + ); - if ( visibleFilters?.length > 0 ) { - visibleFilters.push( - + if ( filterComponents.length > 1 ) { + filterComponents.push( + ); } - return visibleFilters; + return filterComponents; } diff --git a/packages/edit-site/src/components/dataviews/in-filter.js b/packages/edit-site/src/components/dataviews/in-filter.js index 9642169335aaf..4154e0576101c 100644 --- a/packages/edit-site/src/components/dataviews/in-filter.js +++ b/packages/edit-site/src/components/dataviews/in-filter.js @@ -24,6 +24,7 @@ export default ( { filter, view, onChangeView } ) => { return ( { ( f ) => f.field !== filter.field || f.operator !== OPERATOR_IN ); - if ( value !== '' ) { - filters.push( { - field: filter.field, - operator: OPERATOR_IN, - value, - } ); - } + + filters.push( { + field: filter.field, + operator: OPERATOR_IN, + value, + } ); onChangeView( ( currentView ) => ( { ...currentView, diff --git a/packages/edit-site/src/components/dataviews/reset-filters.js b/packages/edit-site/src/components/dataviews/reset-filters.js index 68b5c17590c97..d78c06624087a 100644 --- a/packages/edit-site/src/components/dataviews/reset-filters.js +++ b/packages/edit-site/src/components/dataviews/reset-filters.js @@ -1,26 +1,26 @@ /** * WordPress dependencies */ -import { BaseControl, Button } from '@wordpress/components'; +import { Button } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; export default ( { view, onChangeView } ) => { return ( - - - + ); }; diff --git a/packages/edit-site/src/components/dataviews/search.js b/packages/edit-site/src/components/dataviews/search.js index 3ade147922ac9..17a882637a718 100644 --- a/packages/edit-site/src/components/dataviews/search.js +++ b/packages/edit-site/src/components/dataviews/search.js @@ -31,6 +31,7 @@ export default function Search( { label, view, onChangeView } ) { const searchLabel = label || __( 'Filter list' ); return (
} - className={ `${ baseClassName }-list__item` } onClick={ () => onSelect( pattern.transformedBlocks ) } > Date: Thu, 16 Nov 2023 10:37:00 +0900 Subject: [PATCH 039/116] Lightbox: Fix close button position. (#56125) * use width 100% * remove scroll bar width * refactor * use documentElement --- packages/block-library/src/image/style.scss | 6 +++--- packages/block-library/src/image/view.js | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/image/style.scss b/packages/block-library/src/image/style.scss index 2b8631fffe3c9..303f43ce4ed5f 100644 --- a/packages/block-library/src/image/style.scss +++ b/packages/block-library/src/image/style.scss @@ -215,7 +215,7 @@ left: 0; z-index: 100000; overflow: hidden; - width: 100vw; + width: 100%; height: 100vh; box-sizing: border-box; visibility: hidden; @@ -372,7 +372,7 @@ @keyframes lightbox-zoom-in { 0% { - transform: translate(calc(-50vw + var(--wp--lightbox-initial-left-position)), calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale)); + transform: translate(calc((-100vw + var(--wp--lightbox-scrollbar-width)) / 2 + var(--wp--lightbox-initial-left-position)), calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale)); } 100% { transform: translate(-50%, -50%) scale(1, 1); @@ -389,6 +389,6 @@ } 100% { visibility: hidden; - transform: translate(calc(-50vw + var(--wp--lightbox-initial-left-position)), calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale)); + transform: translate(calc((-100vw + var(--wp--lightbox-scrollbar-width)) / 2 + var(--wp--lightbox-initial-left-position)), calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale)); } } diff --git a/packages/block-library/src/image/view.js b/packages/block-library/src/image/view.js index ef46e932d2490..74ed649a0df12 100644 --- a/packages/block-library/src/image/view.js +++ b/packages/block-library/src/image/view.js @@ -568,6 +568,9 @@ function setStyles( context, ref ) { --wp--lightbox-image-width: ${ lightboxImgWidth }px; --wp--lightbox-image-height: ${ lightboxImgHeight }px; --wp--lightbox-scale: ${ containerScale }; + --wp--lightbox-scrollbar-width: ${ + window.innerWidth - document.documentElement.clientWidth + }px; } `; } From 57ef059aabad25d730d04dff131b337e88d44699 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Thu, 16 Nov 2023 18:04:15 +1100 Subject: [PATCH 040/116] Update docs to clarify workflow branch for release package publishing. (#56183) --- docs/contributors/code/release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributors/code/release.md b/docs/contributors/code/release.md index 83868f95ce184..8c8ed3ff3c334 100644 --- a/docs/contributors/code/release.md +++ b/docs/contributors/code/release.md @@ -422,7 +422,7 @@ Now, the `wp/X.Y` branch is ready for publishing npm packages. In order to start ![Run workflow dropdown for npm publishing](https://developer.wordpress.org/files/2023/07/image-2.png) -To publish packages to npm for the WordPress major release, select `wp` from the "Release type" dropdown and enter `X.Y` (example `5.2`) in the "WordPress major release" input field. Finally, press the green "Run workflow" button. It triggers the npm publishing job, and this needs to be approved by a Gutenberg Core team member. Locate the ["Publish npm packages" action](https://github.com/WordPress/gutenberg/actions/workflows/publish-npm-packages.yml) for the current publishing, and have it [approved](https://docs.github.com/en/actions/managing-workflow-runs/reviewing-deployments#approving-or-rejecting-a-job). +To publish packages to npm for the WordPress major release, select `trunk` as the branch to run the workflow from (this means that the script used to run the workflow comes from the trunk branch, though the packages themselves will published from the release branch as long as the correct "Release type" is selected below), then select `wp` from the "Release type" dropdown and enter `X.Y` (example `5.2`) in the "WordPress major release" input field. Finally, press the green "Run workflow" button. It triggers the npm publishing job, and this needs to be approved by a Gutenberg Core team member. Locate the ["Publish npm packages" action](https://github.com/WordPress/gutenberg/actions/workflows/publish-npm-packages.yml) for the current publishing, and have it [approved](https://docs.github.com/en/actions/managing-workflow-runs/reviewing-deployments#approving-or-rejecting-a-job). For the record, the manual process would look like the following: From 506da3f4dc545b35e61964bc6905e125ec6ef4f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:51:11 +0100 Subject: [PATCH 041/116] DataViews: fix spacing issue in top-level bar (#56151) --- packages/edit-site/src/components/dataviews/dataviews.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/dataviews/dataviews.js b/packages/edit-site/src/components/dataviews/dataviews.js index 40bc87bed200c..e2e392f8fd95b 100644 --- a/packages/edit-site/src/components/dataviews/dataviews.js +++ b/packages/edit-site/src/components/dataviews/dataviews.js @@ -70,7 +70,7 @@ export default function DataViews( { onChangeView={ onChangeView } /> - + Date: Thu, 16 Nov 2023 08:00:59 +0000 Subject: [PATCH 042/116] Update data views 'View' button (#56144) * Update data views 'View' button * small tweaks and linter fix --------- Co-authored-by: ntsekouras --- .../src/components/dataviews/view-actions.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/edit-site/src/components/dataviews/view-actions.js b/packages/edit-site/src/components/dataviews/view-actions.js index e1e85a3e56d09..8953e70242af6 100644 --- a/packages/edit-site/src/components/dataviews/view-actions.js +++ b/packages/edit-site/src/components/dataviews/view-actions.js @@ -10,9 +10,10 @@ import { chevronRightSmall, check, blockTable, - chevronDown, arrowUp, arrowDown, + grid, + columns, } from '@wordpress/icons'; import { __ } from '@wordpress/i18n'; @@ -274,6 +275,8 @@ function SortMenu( { fields, view, onChangeView } ) { ); } +const VIEW_TYPE_ICONS = { list: blockTable, grid, 'side-by-side': columns }; + export default function ViewActions( { fields, view, @@ -284,9 +287,14 @@ export default function ViewActions( { + } > From c5b12496d67320ddcad2d8f43a991f01390bf2d1 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Thu, 16 Nov 2023 10:24:48 +0200 Subject: [PATCH 043/116] [Data views]: Update author and title fields in template's list (#56029) * [Data views]: Update author and title fields in template's list * add the icon in author for every case --- .../edit-site/src/components/list/added-by.js | 2 +- .../page-templates/dataviews-templates.js | 78 ++++++++++++------- 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/packages/edit-site/src/components/list/added-by.js b/packages/edit-site/src/components/list/added-by.js index da6111e0b29bd..e9c8df0fa7f26 100644 --- a/packages/edit-site/src/components/list/added-by.js +++ b/packages/edit-site/src/components/list/added-by.js @@ -152,7 +152,7 @@ export function useAddedBy( postType, postId ) { * @param {Object} props * @param {string} props.imageUrl */ -function AvatarImage( { imageUrl } ) { +export function AvatarImage( { imageUrl } ) { const [ isImageLoaded, setIsImageLoaded ] = useState( false ); return ( diff --git a/packages/edit-site/src/components/page-templates/dataviews-templates.js b/packages/edit-site/src/components/page-templates/dataviews-templates.js index 8f8a052b79b94..ce4927895b29b 100644 --- a/packages/edit-site/src/components/page-templates/dataviews-templates.js +++ b/packages/edit-site/src/components/page-templates/dataviews-templates.js @@ -7,11 +7,13 @@ import removeAccents from 'remove-accents'; * WordPress dependencies */ import { + Icon, __experimentalHeading as Heading, __experimentalText as Text, + __experimentalHStack as HStack, __experimentalVStack as VStack, } from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; +import { __, _x } from '@wordpress/i18n'; import { useState, useMemo, useCallback } from '@wordpress/element'; import { useEntityRecords } from '@wordpress/core-data'; import { decodeEntities } from '@wordpress/html-entities'; @@ -21,7 +23,7 @@ import { decodeEntities } from '@wordpress/html-entities'; */ import Page from '../page'; import Link from '../routes/link'; -import AddedBy from '../list/added-by'; +import { useAddedBy, AvatarImage } from '../list/added-by'; import { TEMPLATE_POST_TYPE } from '../../utils/constants'; import { DataViews } from '../dataviews'; import { @@ -47,6 +49,51 @@ function normalizeSearchInput( input = '' ) { return removeAccents( input.trim().toLowerCase() ); } +// TODO: these are going to be reused in the template part list. +// That's the reason for leaving the template parts code for now. +function TemplateTitle( { item } ) { + const { isCustomized } = useAddedBy( item.type, item.id ); + return ( + + + + { decodeEntities( item.title?.rendered || item.slug ) || + __( '(no title)' ) } + + + { isCustomized && ( + + { item.type === TEMPLATE_POST_TYPE + ? _x( 'Customized', 'template' ) + : _x( 'Customized', 'template part' ) } + + ) } + + ); +} + +function AuthorField( { item } ) { + const { text, icon, imageUrl } = useAddedBy( item.type, item.id ); + return ( + + { imageUrl ? ( + + ) : ( +
+ +
+ ) } + { text } +
+ ); +} + export default function DataviewsTemplates() { const [ view, setView ] = useState( DEFAULT_VIEW ); const { records: allTemplates, isResolving: isLoadingData } = @@ -110,25 +157,7 @@ export default function DataviewsTemplates() { header: __( 'Template' ), id: 'title', getValue: ( { item } ) => item.title?.rendered || item.slug, - render: ( { item } ) => { - return ( - - - - { decodeEntities( - item.title?.rendered || item.slug - ) || __( '(no title)' ) } - - - - ); - }, + render: ( { item } ) => , maxWidth: 400, enableHiding: false, }, @@ -145,17 +174,14 @@ export default function DataviewsTemplates() { ) ); }, + maxWidth: 200, enableSorting: false, }, { header: __( 'Author' ), id: 'author', getValue: () => {}, - render: ( { item } ) => { - return ( - - ); - }, + render: ( { item } ) => , enableHiding: false, enableSorting: false, }, From f9b544db9a372a7db6fbcd2eecc6cc4d84d398df Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 16 Nov 2023 09:26:33 +0100 Subject: [PATCH 044/116] Site Editor: use EditorProvider instead of custom logic (#56000) --- .../src/components/provider/use-block-sync.js | 23 +- packages/core-data/src/entity-provider.js | 9 +- .../default-block-editor-provider.js | 75 ----- .../block-editor-provider/index.js | 29 -- .../navigation-block-editor-provider.js | 114 -------- .../test/use-page-content-blocks.js | 116 -------- .../use-page-content-blocks.js | 90 ------ .../src/components/block-editor/index.js | 28 -- .../block-editor/use-site-editor-settings.js | 22 +- .../edit-site/src/components/editor/index.js | 262 ++++++++++-------- .../page-panels/edit-template.js | 34 +-- .../editor/src/components/provider/README.md | 50 ++++ .../editor/src/components/provider/index.js | 201 +++++++++++++- .../provider/use-block-editor-settings.js | 8 +- .../components/interface-skeleton/index.js | 2 - .../specs/site-editor/template-part.spec.js | 16 +- 16 files changed, 444 insertions(+), 635 deletions(-) delete mode 100644 packages/edit-site/src/components/block-editor/block-editor-provider/default-block-editor-provider.js delete mode 100644 packages/edit-site/src/components/block-editor/block-editor-provider/index.js delete mode 100644 packages/edit-site/src/components/block-editor/block-editor-provider/navigation-block-editor-provider.js delete mode 100644 packages/edit-site/src/components/block-editor/block-editor-provider/test/use-page-content-blocks.js delete mode 100644 packages/edit-site/src/components/block-editor/block-editor-provider/use-page-content-blocks.js delete mode 100644 packages/edit-site/src/components/block-editor/index.js create mode 100644 packages/editor/src/components/provider/README.md diff --git a/packages/block-editor/src/components/provider/use-block-sync.js b/packages/block-editor/src/components/provider/use-block-sync.js index 58aca847d80de..4f2300f380892 100644 --- a/packages/block-editor/src/components/provider/use-block-sync.js +++ b/packages/block-editor/src/components/provider/use-block-sync.js @@ -76,18 +76,11 @@ export default function useBlockSync( { resetBlocks, resetSelection, replaceInnerBlocks, - selectBlock, setHasControlledInnerBlocks, __unstableMarkNextChangeAsNotPersistent, } = registry.dispatch( blockEditorStore ); - const { - hasSelectedBlock, - getBlockName, - getBlocks, - getSelectionStart, - getSelectionEnd, - getBlock, - } = registry.select( blockEditorStore ); + const { getBlockName, getBlocks, getSelectionStart, getSelectionEnd } = + registry.select( blockEditorStore ); const isControlled = useSelect( ( select ) => { return ( @@ -180,9 +173,6 @@ export default function useBlockSync( { // bound sync, unset the outbound value to avoid considering it in // subsequent renders. pendingChanges.current.outgoing = []; - const hadSelection = hasSelectedBlock(); - const selectionAnchor = getSelectionStart(); - const selectionFocus = getSelectionEnd(); setControlledBlocks(); if ( controlledSelection ) { @@ -191,15 +181,6 @@ export default function useBlockSync( { controlledSelection.selectionEnd, controlledSelection.initialPosition ); - } else { - const selectionStillExists = getBlock( - selectionAnchor.clientId - ); - if ( hadSelection && ! selectionStillExists ) { - selectBlock( clientId ); - } else { - resetSelection( selectionAnchor, selectionFocus ); - } } } }, [ controlledBlocks, clientId ] ); diff --git a/packages/core-data/src/entity-provider.js b/packages/core-data/src/entity-provider.js index e2274629006ee..4b82b62e318bc 100644 --- a/packages/core-data/src/entity-provider.js +++ b/packages/core-data/src/entity-provider.js @@ -155,6 +155,9 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) { const id = _id ?? providerId; const { content, editedBlocks, meta } = useSelect( ( select ) => { + if ( ! id ) { + return {}; + } const { getEditedEntityRecord } = select( STORE_NAME ); const editedRecord = getEditedEntityRecord( kind, name, id ); return { @@ -169,6 +172,10 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) { useDispatch( STORE_NAME ); const blocks = useMemo( () => { + if ( ! id ) { + return undefined; + } + if ( editedBlocks ) { return editedBlocks; } @@ -176,7 +183,7 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) { return content && typeof content !== 'function' ? parse( content ) : EMPTY_ARRAY; - }, [ editedBlocks, content ] ); + }, [ id, editedBlocks, content ] ); const updateFootnotes = useCallback( ( _blocks ) => updateFootnotesFromMeta( _blocks, meta ), diff --git a/packages/edit-site/src/components/block-editor/block-editor-provider/default-block-editor-provider.js b/packages/edit-site/src/components/block-editor/block-editor-provider/default-block-editor-provider.js deleted file mode 100644 index c91c687ce5284..0000000000000 --- a/packages/edit-site/src/components/block-editor/block-editor-provider/default-block-editor-provider.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * WordPress dependencies - */ -import { useEntityBlockEditor } from '@wordpress/core-data'; -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; -import { useSelect } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { store as editSiteStore } from '../../../store'; -import { unlock } from '../../../lock-unlock'; -import useSiteEditorSettings from '../use-site-editor-settings'; -import usePageContentBlocks from './use-page-content-blocks'; - -const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis ); - -const noop = () => {}; - -/** - * The default block editor provider for the site editor. Typically used when - * the post type is `'wp_template_part'` or `'wp_template'` and allows editing - * of the template and its nested entities. - * - * If the page content focus type is `'hideTemplate'`, the provider will provide - * a set of page content blocks wrapped in a container that, together, - * mimic the look and feel of the post editor and - * allow editing of the page content only. - * - * @param {Object} props - * @param {Element} props.children - */ -export default function DefaultBlockEditorProvider( { children } ) { - const settings = useSiteEditorSettings(); - - const { templateType, isTemplateHidden } = useSelect( ( select ) => { - const { getEditedPostType } = select( editSiteStore ); - const { getPageContentFocusType, getCanvasMode } = unlock( - select( editSiteStore ) - ); - return { - templateType: getEditedPostType(), - isTemplateHidden: - getCanvasMode() === 'edit' && - getPageContentFocusType() === 'hideTemplate', - canvasMode: unlock( select( editSiteStore ) ).getCanvasMode(), - }; - }, [] ); - - const [ blocks, onInput, onChange ] = useEntityBlockEditor( - 'postType', - templateType - ); - const pageContentBlocks = usePageContentBlocks( { - blocks, - isPageContentFocused: isTemplateHidden, - wrapPageContent: true, - } ); - - return ( - - { children } - - ); -} diff --git a/packages/edit-site/src/components/block-editor/block-editor-provider/index.js b/packages/edit-site/src/components/block-editor/block-editor-provider/index.js deleted file mode 100644 index ab07a3fefc5d3..0000000000000 --- a/packages/edit-site/src/components/block-editor/block-editor-provider/index.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * WordPress dependencies - */ -import { useSelect } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { store as editSiteStore } from '../../../store'; -import DefaultBlockEditorProvider from './default-block-editor-provider'; -import NavigationBlockEditorProvider from './navigation-block-editor-provider'; -import { NAVIGATION_POST_TYPE } from '../../../utils/constants'; - -export default function BlockEditorProvider( { children } ) { - const entityType = useSelect( - ( select ) => select( editSiteStore ).getEditedPostType(), - [] - ); - if ( entityType === NAVIGATION_POST_TYPE ) { - return ( - - { children } - - ); - } - return ( - { children } - ); -} diff --git a/packages/edit-site/src/components/block-editor/block-editor-provider/navigation-block-editor-provider.js b/packages/edit-site/src/components/block-editor/block-editor-provider/navigation-block-editor-provider.js deleted file mode 100644 index 9927cbb040c7b..0000000000000 --- a/packages/edit-site/src/components/block-editor/block-editor-provider/navigation-block-editor-provider.js +++ /dev/null @@ -1,114 +0,0 @@ -/** - * WordPress dependencies - */ -import { useSelect, useDispatch } from '@wordpress/data'; -import { useMemo, useEffect } from '@wordpress/element'; -import { useEntityId } from '@wordpress/core-data'; -import { - store as blockEditorStore, - privateApis as blockEditorPrivateApis, -} from '@wordpress/block-editor'; -import { createBlock } from '@wordpress/blocks'; - -/** - * Internal dependencies - */ -import { unlock } from '../../../lock-unlock'; -import useSiteEditorSettings from '../use-site-editor-settings'; -import { store as editSiteStore } from '../../../store'; -import { NAVIGATION_POST_TYPE } from '../../../utils/constants'; - -const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis ); - -const noop = () => {}; - -/** - * Block editor component for editing navigation menus. - * - * Note: Navigation entities require a wrapping Navigation block to provide - * them with some basic layout and styling. Therefore we create a "ghost" block - * and provide it will a reference to the navigation entity ID being edited. - * - * In this scenario it is the **block** that handles syncing the entity content - * whereas for other entities this is handled by entity block editor. - * - * @param {number} navigationMenuId the navigation menu ID - * @return {[WPBlock[], Function, Function]} The block array and setters. - */ -export default function NavigationBlockEditorProvider( { children } ) { - const defaultSettings = useSiteEditorSettings(); - - const navigationMenuId = useEntityId( 'postType', NAVIGATION_POST_TYPE ); - - const blocks = useMemo( () => { - return [ - createBlock( 'core/navigation', { - ref: navigationMenuId, - // As the parent editor is locked with `templateLock`, the template locking - // must be explicitly "unset" on the block itself to allow the user to modify - // the block's content. - templateLock: false, - } ), - ]; - }, [ navigationMenuId ] ); - - const { isEditMode } = useSelect( ( select ) => { - const { getCanvasMode } = unlock( select( editSiteStore ) ); - - return { - isEditMode: getCanvasMode() === 'edit', - }; - }, [] ); - - const { selectBlock, setBlockEditingMode, unsetBlockEditingMode } = - useDispatch( blockEditorStore ); - - const navigationBlockClientId = blocks && blocks[ 0 ]?.clientId; - - const settings = useMemo( () => { - return { - ...defaultSettings, - // Lock the editor to allow the root ("ghost") Navigation block only. - templateLock: 'insert', - template: [ [ 'core/navigation', {}, [] ] ], - }; - }, [ defaultSettings ] ); - - // Auto-select the Navigation block when entering Navigation focus mode. - useEffect( () => { - if ( navigationBlockClientId && isEditMode ) { - selectBlock( navigationBlockClientId ); - } - }, [ navigationBlockClientId, isEditMode, selectBlock ] ); - - // Set block editing mode to contentOnly when entering Navigation focus mode. - // This ensures that non-content controls on the block will be hidden and thus - // the user can focus on editing the Navigation Menu content only. - useEffect( () => { - if ( ! navigationBlockClientId ) { - return; - } - - setBlockEditingMode( navigationBlockClientId, 'contentOnly' ); - - return () => { - unsetBlockEditingMode( navigationBlockClientId ); - }; - }, [ - navigationBlockClientId, - unsetBlockEditingMode, - setBlockEditingMode, - ] ); - - return ( - - { children } - - ); -} diff --git a/packages/edit-site/src/components/block-editor/block-editor-provider/test/use-page-content-blocks.js b/packages/edit-site/src/components/block-editor/block-editor-provider/test/use-page-content-blocks.js deleted file mode 100644 index 775aea0bdb391..0000000000000 --- a/packages/edit-site/src/components/block-editor/block-editor-provider/test/use-page-content-blocks.js +++ /dev/null @@ -1,116 +0,0 @@ -/** - * External dependencies - */ -import { renderHook } from '@testing-library/react'; -/** - * WordPress dependencies - */ -import { createBlock } from '@wordpress/blocks'; - -/** - * Internal dependencies - */ -import usePageContentBlocks from '../use-page-content-blocks'; - -jest.mock( '@wordpress/blocks', () => { - return { - __esModule: true, - ...jest.requireActual( '@wordpress/blocks' ), - createBlock( name, attributes = {}, innerBlocks = [] ) { - return { - name, - attributes, - innerBlocks, - }; - }, - }; -} ); - -describe( 'usePageContentBlocks', () => { - const blocksList = [ - createBlock( 'core/group', {}, [ - createBlock( 'core/post-title' ), - createBlock( 'core/post-featured-image' ), - createBlock( 'core/query', {}, [ - createBlock( 'core/post-title' ), - createBlock( 'core/post-featured-image' ), - createBlock( 'core/post-content' ), - ] ), - createBlock( 'core/post-content' ), - ] ), - createBlock( 'core/query' ), - createBlock( 'core/paragraph' ), - createBlock( 'core/post-content' ), - ]; - it( 'should return empty array if `isPageContentFocused` is `false`', () => { - const { result } = renderHook( () => - usePageContentBlocks( { - blocks: blocksList, - isPageContentFocused: false, - } ) - ); - expect( result.current ).toEqual( [] ); - } ); - it( 'should return empty array if `blocks` is undefined', () => { - const { result } = renderHook( () => - usePageContentBlocks( { - blocks: undefined, - isPageContentFocused: true, - } ) - ); - expect( result.current ).toEqual( [] ); - } ); - it( 'should return empty array if `blocks` is an empty array', () => { - const { result } = renderHook( () => - usePageContentBlocks( { - blocks: [], - isPageContentFocused: true, - } ) - ); - expect( result.current ).toEqual( [] ); - } ); - it( 'should return new block list', () => { - const { result } = renderHook( () => - usePageContentBlocks( { - blocks: blocksList, - isPageContentFocused: true, - } ) - ); - expect( result.current ).toEqual( [ - createBlock( 'core/post-title' ), - createBlock( 'core/post-featured-image' ), - createBlock( 'core/post-content' ), - createBlock( 'core/post-content' ), - ] ); - } ); - it( 'should return new block list wrapped in a Group block', () => { - const { result } = renderHook( () => - usePageContentBlocks( { - blocks: blocksList, - isPageContentFocused: true, - wrapPageContent: true, - } ) - ); - expect( result.current ).toEqual( [ - { - name: 'core/group', - attributes: { - layout: { type: 'constrained' }, - style: { - spacing: { - margin: { - top: '4em', // Mimics the post editor. - }, - }, - }, - }, - innerBlocks: [ - createBlock( 'core/post-title' ), - createBlock( 'core/post-featured-image' ), - createBlock( 'core/post-content' ), - createBlock( 'core/post-content' ), - ], - }, - ] ); - } ); -} ); diff --git a/packages/edit-site/src/components/block-editor/block-editor-provider/use-page-content-blocks.js b/packages/edit-site/src/components/block-editor/block-editor-provider/use-page-content-blocks.js deleted file mode 100644 index dd05f90a56bbb..0000000000000 --- a/packages/edit-site/src/components/block-editor/block-editor-provider/use-page-content-blocks.js +++ /dev/null @@ -1,90 +0,0 @@ -/** - * WordPress dependencies - */ -import { useMemo } from '@wordpress/element'; -import { createBlock } from '@wordpress/blocks'; - -/** - * Internal dependencies - */ -import { PAGE_CONTENT_BLOCK_TYPES } from '../../../utils/constants'; - -/** - * Helper method to iterate through all blocks, recursing into allowed inner blocks. - * Returns a flattened object of transformed blocks. - * - * @param {Array} blocks Blocks to flatten. - * @param {Function} transform Transforming function to be applied to each block. If transform returns `undefined`, the block is skipped. - * - * @return {Array} Flattened object. - */ -function flattenBlocks( blocks, transform ) { - const result = []; - for ( let i = 0; i < blocks.length; i++ ) { - // Since the Query Block could contain PAGE_CONTENT_BLOCK_TYPES block types, - // we skip it because we only want to render stand-alone page content blocks in the block list. - if ( [ 'core/query' ].includes( blocks[ i ].name ) ) { - continue; - } - const transformedBlock = transform( blocks[ i ] ); - if ( transformedBlock ) { - result.push( transformedBlock ); - } - result.push( ...flattenBlocks( blocks[ i ].innerBlocks, transform ) ); - } - - return result; -} - -/** - * Returns a memoized array of blocks that contain only page content blocks, - * surrounded by an optional group block to mimic the post editor. - * - * @param {Object} props The argument for the function. - * @param {Array} props.blocks Block list. - * @param {boolean} props.isPageContentFocused Whether the page content has focus (and the surrounding template is inert). If `true` return page content blocks. Default `false`. - * @param {boolean} props.wrapPageContent Whether to wrap the page content blocks in a group block to mimic the post editor. Default `false`. - * @return {Array} Page content blocks. - */ -export default function usePageContentBlocks( { - blocks = [], - isPageContentFocused = false, - wrapPageContent = false, -} ) { - return useMemo( () => { - if ( ! isPageContentFocused || ! blocks?.length ) { - return []; - } - - const innerBlocks = flattenBlocks( blocks, ( block ) => - PAGE_CONTENT_BLOCK_TYPES[ block.name ] - ? createBlock( block.name ) - : undefined - ); - - if ( ! innerBlocks.length ) { - return []; - } - - if ( ! wrapPageContent ) { - return innerBlocks; - } - - return [ - createBlock( - 'core/group', - { - layout: { type: 'constrained' }, - style: { - spacing: { - margin: { - top: '4em', // Mimics the post editor. - }, - }, - }, - }, - innerBlocks - ), - ]; - }, [ blocks, isPageContentFocused ] ); -} diff --git a/packages/edit-site/src/components/block-editor/index.js b/packages/edit-site/src/components/block-editor/index.js deleted file mode 100644 index 2c635ff860a5b..0000000000000 --- a/packages/edit-site/src/components/block-editor/index.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * WordPress dependencies - */ -import { BlockInspector } from '@wordpress/block-editor'; -import { privateApis as editPatternsPrivateApis } from '@wordpress/patterns'; - -/** - * Internal dependencies - */ -import TemplatePartConverter from '../template-part-converter'; -import { SidebarInspectorFill } from '../sidebar-edit-mode'; -import SiteEditorCanvas from './site-editor-canvas'; -import BlockEditorProvider from './block-editor-provider'; - -import { unlock } from '../../lock-unlock'; -const { PatternsMenuItems } = unlock( editPatternsPrivateApis ); -export default function BlockEditor() { - return ( - - - - - - - - - ); -} diff --git a/packages/edit-site/src/components/block-editor/use-site-editor-settings.js b/packages/edit-site/src/components/block-editor/use-site-editor-settings.js index f597abee0726d..cb3fb3f1cb333 100644 --- a/packages/edit-site/src/components/block-editor/use-site-editor-settings.js +++ b/packages/edit-site/src/components/block-editor/use-site-editor-settings.js @@ -87,7 +87,7 @@ function useArchiveLabel( templateSlug ) { ); } -export default function useSiteEditorSettings() { +export function useSpecificEditorSettings() { const { setIsInserterOpened } = useDispatch( editSiteStore ); const { templateSlug, @@ -97,8 +97,6 @@ export default function useSiteEditorSettings() { keepCaretInsideBlock, canvasMode, settings, - postType, - postId, } = useSelect( ( select ) => { const { getEditedPostType, @@ -132,8 +130,6 @@ export default function useSiteEditorSettings() { ), canvasMode: getCanvasMode(), settings: getSettings(), - postType: usedPostType, - postId: usedPostId, }; }, [] ); const archiveLabels = useArchiveLabel( templateSlug ); @@ -164,5 +160,21 @@ export default function useSiteEditorSettings() { archiveLabels.archiveNameLabel, ] ); + return defaultEditorSettings; +} + +export default function useSiteEditorSettings() { + const defaultEditorSettings = useSpecificEditorSettings(); + const { postType, postId } = useSelect( ( select ) => { + const { getEditedPostType, getEditedPostId } = unlock( + select( editSiteStore ) + ); + const usedPostType = getEditedPostType(); + const usedPostId = getEditedPostId(); + return { + postType: usedPostType, + postId: usedPostId, + }; + }, [] ); return useBlockEditorSettings( defaultEditorSettings, postType, postId ); } diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 70d033d14188c..110e891cc1858 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -6,31 +6,37 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useMemo } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; import { Notice } from '@wordpress/components'; import { useInstanceId } from '@wordpress/compose'; -import { EntityProvider } from '@wordpress/core-data'; import { store as preferencesStore } from '@wordpress/preferences'; import { - BlockContextProvider, BlockBreadcrumb, store as blockEditorStore, privateApis as blockEditorPrivateApis, + BlockInspector, } from '@wordpress/block-editor'; import { InterfaceSkeleton, ComplementaryArea, store as interfaceStore, } from '@wordpress/interface'; -import { EditorNotices, EditorSnackbars } from '@wordpress/editor'; +import { + EditorNotices, + EditorSnackbars, + privateApis as editorPrivateApis, +} from '@wordpress/editor'; import { __, sprintf } from '@wordpress/i18n'; +import { store as coreDataStore } from '@wordpress/core-data'; +import { useMemo } from '@wordpress/element'; /** * Internal dependencies */ -import { SidebarComplementaryAreaFills } from '../sidebar-edit-mode'; -import BlockEditor from '../block-editor'; +import { + SidebarComplementaryAreaFills, + SidebarInspectorFill, +} from '../sidebar-edit-mode'; import CodeEditor from '../code-editor'; import KeyboardShortcutsEditMode from '../keyboard-shortcuts/edit-mode'; import InserterSidebar from '../secondary-sidebar/inserter-sidebar'; @@ -46,8 +52,13 @@ import useEditedEntityRecord from '../use-edited-entity-record'; import { SidebarFixedBottomSlot } from '../sidebar-edit-mode/sidebar-fixed-bottom'; import PatternModal from '../pattern-modal'; import { POST_TYPE_LABELS, TEMPLATE_POST_TYPE } from '../../utils/constants'; +import SiteEditorCanvas from '../block-editor/site-editor-canvas'; +import TemplatePartConverter from '../template-part-converter'; +import { useSpecificEditorSettings } from '../block-editor/use-site-editor-settings'; const { BlockRemovalWarningModal } = unlock( blockEditorPrivateApis ); +const { ExperimentalEditorProvider: EditorProvider } = + unlock( editorPrivateApis ); const interfaceLabels = { /* translators: accessibility text for the editor content landmark region. */ @@ -79,10 +90,11 @@ export default function Editor( { listViewToggleElement, isLoading } ) { isLoaded: hasLoadedPost, } = useEditedEntityRecord(); - const { id: editedPostId, type: editedPostType } = editedPost; + const { type: editedPostType } = editedPost; const { context, + contextPost, editorMode, canvasMode, blockEditorMode, @@ -92,6 +104,7 @@ export default function Editor( { listViewToggleElement, isLoading } ) { showIconLabels, showBlockBreadcrumbs, hasPageContentFocus, + pageContentFocusType, } = useSelect( ( select ) => { const { getEditedPostContext, @@ -100,14 +113,24 @@ export default function Editor( { listViewToggleElement, isLoading } ) { isInserterOpened, isListViewOpened, hasPageContentFocus: _hasPageContentFocus, + getPageContentFocusType, } = unlock( select( editSiteStore ) ); const { __unstableGetEditorMode } = select( blockEditorStore ); const { getActiveComplementaryArea } = select( interfaceStore ); + const { getEntityRecord } = select( coreDataStore ); + const _context = getEditedPostContext(); // The currently selected entity to display. // Typically template or template part in the site editor. return { - context: getEditedPostContext(), + context: _context, + contextPost: _context?.postId + ? getEntityRecord( + 'postType', + _context.postType, + _context.postId + ) + : undefined, editorMode: getEditorMode(), canvasMode: getCanvasMode(), blockEditorMode: __unstableGetEditorMode(), @@ -125,6 +148,7 @@ export default function Editor( { listViewToggleElement, isLoading } ) { 'showBlockBreadcrumbs' ), hasPageContentFocus: _hasPageContentFocus(), + pageContentFocusType: getPageContentFocusType(), }; }, [] ); @@ -141,18 +165,7 @@ export default function Editor( { listViewToggleElement, isLoading } ) { const secondarySidebarLabel = isListViewOpen ? __( 'List View' ) : __( 'Block Library' ); - const blockContext = useMemo( () => { - const { postType, postId, ...nonPostFields } = context ?? {}; - - return { - ...( hasPageContentFocus ? context : nonPostFields ), - // Ideally this context should be removed. However, it is currently used by the Query Loop block. - templateSlug: - editedPostType === TEMPLATE_POST_TYPE - ? editedPost.slug - : undefined, - }; - }, [ editedPost.slug, editedPostType, hasPageContentFocus, context ] ); + const postWithTemplate = context?.postId; let title; if ( hasLoadedPost ) { @@ -174,110 +187,131 @@ export default function Editor( { listViewToggleElement, isLoading } ) { 'edit-site-editor__loading-progress' ); - const contentProps = isLoading - ? { - 'aria-busy': 'true', - 'aria-describedby': loadingProgressId, - } - : undefined; + const settings = useSpecificEditorSettings(); + const isReady = + ! isLoading && + ( ( postWithTemplate && !! contextPost && !! editedPost ) || + ( ! postWithTemplate && !! editedPost ) ); + const mode = useMemo( () => { + if ( isViewMode ) { + return postWithTemplate ? 'template-locked' : 'all'; + } + + if ( isEditMode && pageContentFocusType === 'hideTemplate' ) { + return 'post-only'; + } + + if ( postWithTemplate && hasPageContentFocus ) { + return 'template-locked'; + } + + if ( postWithTemplate && ! hasPageContentFocus ) { + return 'template-only'; + } + + return 'all'; + }, [ + isViewMode, + isEditMode, + postWithTemplate, + pageContentFocusType, + hasPageContentFocus, + ] ); return ( <> - { isLoading ? : null } + { ! isReady ? : null } { isEditMode && } - - + { __( + "You attempted to edit an item that doesn't exist. Perhaps it was deleted?" + ) } + + ) } + { isReady && ( + - - - { isEditMode && } - } - content={ - <> - - { isEditMode && } - { showVisualEditor && editedPost && ( - <> - - - - - ) } - { editorMode === 'text' && - editedPost && - isEditMode && } - { hasLoadedPost && ! editedPost && ( - - { __( - "You attempted to edit an item that doesn't exist. Perhaps it was deleted?" - ) } - - ) } - { isEditMode && ( - - ) } - - } - contentProps={ contentProps } - secondarySidebar={ - isEditMode && - ( ( shouldShowInserter && ( - - ) ) || - ( shouldShowListView && ( - - ) ) ) + + { isEditMode && } + } + content={ + <> + + { isEditMode && } + { showVisualEditor && ( <> - - + + + + + + + - ) - } - footer={ - shouldShowBlockBreadcrumbs && ( - + ) } + { isEditMode && } + + } + secondarySidebar={ + isEditMode && + ( ( shouldShowInserter && ) || + ( shouldShowListView && ( + - ) - } - labels={ { - ...interfaceLabels, - secondarySidebar: secondarySidebarLabel, - } } - /> - - - + ) ) ) + } + sidebar={ + isEditMode && + isRightSidebarOpen && ( + <> + + + + ) + } + footer={ + shouldShowBlockBreadcrumbs && ( + + ) + } + labels={ { + ...interfaceLabels, + secondarySidebar: secondarySidebarLabel, + } } + /> + + ) } ); } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js index fde2b63d6e833..1ee382420a7d9 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js @@ -11,8 +11,9 @@ import { __experimentalText as Text, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { store as coreStore, useEntityBlockEditor } from '@wordpress/core-data'; +import { store as coreStore } from '@wordpress/core-data'; import { check } from '@wordpress/icons'; +import { store as blockEditorStore } from '@wordpress/block-editor'; /** * Internal dependencies @@ -21,7 +22,7 @@ import { store as editSiteStore } from '../../../store'; import SwapTemplateButton from './swap-template-button'; import ResetDefaultTemplate from './reset-default-template'; import { unlock } from '../../../lock-unlock'; -import usePageContentBlocks from '../../block-editor/block-editor-provider/use-page-content-blocks'; +import { PAGE_CONTENT_BLOCK_TYPES } from '../../../utils/constants'; const POPOVER_PROPS = { className: 'edit-site-page-panels-edit-template__dropdown', @@ -29,8 +30,8 @@ const POPOVER_PROPS = { }; export default function EditTemplate() { - const { hasResolved, template, isTemplateHidden, postType } = useSelect( - ( select ) => { + const { hasPostContentBlocks, hasResolved, template, isTemplateHidden } = + useSelect( ( select ) => { const { getEditedPostContext, getEditedPostType, getEditedPostId } = select( editSiteStore ); const { getCanvasMode, getPageContentFocusType } = unlock( @@ -38,15 +39,15 @@ export default function EditTemplate() { ); const { getEditedEntityRecord, hasFinishedResolution } = select( coreStore ); + const { __experimentalGetGlobalBlocksByName } = + select( blockEditorStore ); const _context = getEditedPostContext(); const _postType = getEditedPostType(); - const queryArgs = [ - 'postType', - getEditedPostType(), - getEditedPostId(), - ]; - + const queryArgs = [ 'postType', _postType, getEditedPostId() ]; return { + hasPostContentBlocks: !! __experimentalGetGlobalBlocksByName( + Object.keys( PAGE_CONTENT_BLOCK_TYPES ) + ).length, context: _context, hasResolved: hasFinishedResolution( 'getEditedEntityRecord', @@ -58,21 +59,12 @@ export default function EditTemplate() { getPageContentFocusType() === 'hideTemplate', postType: _postType, }; - }, - [] - ); - - const [ blocks ] = useEntityBlockEditor( 'postType', postType ); + }, [] ); const { setHasPageContentFocus } = useDispatch( editSiteStore ); // Disable reason: `useDispatch` can't be called conditionally. // eslint-disable-next-line @wordpress/no-unused-vars-before-return const { setPageContentFocusType } = unlock( useDispatch( editSiteStore ) ); - // Check if there are any post content block types in the blocks tree. - const pageContentBlocks = usePageContentBlocks( { - blocks, - isPageContentFocused: true, - } ); if ( ! hasResolved ) { return null; @@ -108,7 +100,7 @@ export default function EditTemplate() { - { !! pageContentBlocks?.length && ( + { hasPostContentBlocks && ( {}; +export const PAGE_CONTENT_BLOCK_TYPES = [ + 'core/post-title', + 'core/post-featured-image', + 'core/post-content', +]; + +/** + * For the Navigation block editor, we need to force the block editor to contentOnly for that block. + * + * Set block editing mode to contentOnly when entering Navigation focus mode. + * this ensures that non-content controls on the block will be hidden and thus + * the user can focus on editing the Navigation Menu content only. + * + * @param {string} navigationBlockClientId ClientId. + */ +function useForceFocusModeForNavigation( navigationBlockClientId ) { + const { setBlockEditingMode, unsetBlockEditingMode } = + useDispatch( blockEditorStore ); + + useEffect( () => { + if ( ! navigationBlockClientId ) { + return; + } + + setBlockEditingMode( navigationBlockClientId, 'contentOnly' ); + + return () => { + unsetBlockEditingMode( navigationBlockClientId ); + }; + }, [ + navigationBlockClientId, + unsetBlockEditingMode, + setBlockEditingMode, + ] ); +} + +/** + * Helper method to extract the post content block types from a template. + * + * @param {Array} blocks Template blocks. + * + * @return {Array} Flattened object. + */ +function extractPageContentBlockTypesFromTemplateBlocks( blocks ) { + const result = []; + for ( let i = 0; i < blocks.length; i++ ) { + // Since the Query Block could contain PAGE_CONTENT_BLOCK_TYPES block types, + // we skip it because we only want to render stand-alone page content blocks in the block list. + if ( blocks[ i ].name === 'core/query' ) { + continue; + } + if ( PAGE_CONTENT_BLOCK_TYPES.includes( blocks[ i ].name ) ) { + result.push( createBlock( blocks[ i ].name ) ); + } + if ( blocks[ i ].innerBlocks.length ) { + result.push( + ...extractPageContentBlockTypesFromTemplateBlocks( + blocks[ i ].innerBlocks + ) + ); + } + } + + return result; +} + +/** + * Depending on the post, template and template mode, + * returns the appropriate blocks and change handlers for the block editor provider. + * + * @param {Array} post Block list. + * @param {boolean} template Whether the page content has focus (and the surrounding template is inert). If `true` return page content blocks. Default `false`. + * @param {string} mode Rendering mode. + * @return {Array} Block editor props. + */ +function useBlockEditorProps( post, template, mode ) { + const rootLevelPost = + mode === 'post-only' || ! template ? 'post' : 'template'; + const [ postBlocks, onInput, onChange ] = useEntityBlockEditor( + 'postType', + post.type, + { id: post.id } + ); + const [ templateBlocks, onInputTemplate, onChangeTemplate ] = + useEntityBlockEditor( 'postType', template?.type, { + id: template?.id, + } ); + const blocks = useMemo( () => { + if ( post.type === 'wp_navigation' ) { + return [ + createBlock( 'core/navigation', { + ref: post.id, + // As the parent editor is locked with `templateLock`, the template locking + // must be explicitly "unset" on the block itself to allow the user to modify + // the block's content. + templateLock: false, + } ), + ]; + } + + if ( mode === 'post-only' ) { + return [ + createBlock( + 'core/group', + { + layout: { type: 'constrained' }, + style: { + spacing: { + margin: { + top: '4em', // Mimics the post editor. + }, + }, + }, + }, + extractPageContentBlockTypesFromTemplateBlocks( + templateBlocks + ) + ), + ]; + } + + if ( rootLevelPost === 'template' ) { + return templateBlocks; + } + + return postBlocks; + }, [ + templateBlocks, + postBlocks, + rootLevelPost, + post.type, + post.id, + mode, + ] ); + const disableRootLevelChanges = + ( !! template && mode === 'template-locked' ) || + post.type === 'wp_navigation' || + mode === 'post-only'; + const navigationBlockClientId = + post.type === 'wp_navigation' && blocks && blocks[ 0 ]?.clientId; + useForceFocusModeForNavigation( navigationBlockClientId ); + if ( disableRootLevelChanges ) { + return [ blocks, noop, noop ]; + } + + return [ + blocks, + rootLevelPost === 'post' ? onInput : onInputTemplate, + rootLevelPost === 'post' ? onChange : onChangeTemplate, + ]; +} + export const ExperimentalEditorProvider = withRegistryProvider( ( { - __unstableTemplate, + mode = 'all', post, settings, recovery, initialEdits, children, BlockEditorProviderComponent = ExperimentalBlockEditorProvider, + __unstableTemplate: template, } ) => { + const shouldRenderTemplate = !! template && mode !== 'post-only'; + const rootLevelPost = shouldRenderTemplate ? template : post; const defaultBlockContext = useMemo( () => { - if ( post.type === 'wp_template' ) { - return {}; - } - return { postId: post.id, postType: post.type }; - }, [ post.id, post.type ] ); + const postContext = + rootLevelPost.type !== 'wp_template' || + ( shouldRenderTemplate && mode !== 'template-only' ) + ? { postId: post.id, postType: post.type } + : {}; + + return { + ...postContext, + templateSlug: + rootLevelPost.type === 'wp_template' + ? rootLevelPost.slug + : undefined, + }; + }, [ + mode, + post.id, + post.type, + rootLevelPost.type, + rootLevelPost?.slug, + shouldRenderTemplate, + ] ); const { editorSettings, selection, isReady } = useSelect( ( select ) => { const { @@ -55,17 +229,18 @@ export const ExperimentalEditorProvider = withRegistryProvider( }, [] ); - const { id, type } = __unstableTemplate ?? post; - const [ blocks, onInput, onChange ] = useEntityBlockEditor( - 'postType', - type, - { id } - ); + const { id, type } = rootLevelPost; const blockEditorSettings = useBlockEditorSettings( editorSettings, type, id ); + const [ blocks, onInput, onChange ] = useBlockEditorProps( + post, + template, + mode + ); + const { updatePostLock, setupEditor, @@ -109,7 +284,7 @@ export const ExperimentalEditorProvider = withRegistryProvider( // Synchronize the editor settings as they change. useEffect( () => { updateEditorSettings( settings ); - }, [ settings ] ); + }, [ settings, updateEditorSettings ] ); if ( ! isReady ) { return null; diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js index c0804febab0db..e2cbba7e6a757 100644 --- a/packages/editor/src/components/provider/use-block-editor-settings.js +++ b/packages/editor/src/components/provider/use-block-editor-settings.js @@ -67,8 +67,6 @@ const BLOCK_EDITOR_SETTINGS = [ 'postsPerPage', 'readOnly', 'styles', - 'template', - 'templateLock', 'titlePlaceholder', 'supportsLayout', 'widgetTypesToHideFromLegacyWidgetBlock', @@ -237,6 +235,12 @@ function useBlockEditorSettings( settings, postType, postId ) { pageOnFront, pageForPosts, __experimentalPreferPatternsOnRoot: postType === 'wp_template', + templateLock: + postType === 'wp_navigation' ? 'insert' : settings.templateLock, + template: + postType === 'wp_navigation' + ? [ [ 'core/navigation', {}, [] ] ] + : settings.template, } ), [ settings, diff --git a/packages/interface/src/components/interface-skeleton/index.js b/packages/interface/src/components/interface-skeleton/index.js index 58684ebaddd7e..baf98d153ed87 100644 --- a/packages/interface/src/components/interface-skeleton/index.js +++ b/packages/interface/src/components/interface-skeleton/index.js @@ -52,7 +52,6 @@ function InterfaceSkeleton( secondarySidebar, notices, content, - contentProps, actions, labels, className, @@ -151,7 +150,6 @@ function InterfaceSkeleton( { content } diff --git a/test/e2e/specs/site-editor/template-part.spec.js b/test/e2e/specs/site-editor/template-part.spec.js index ff4610a57ba27..9d4e1385627e7 100644 --- a/test/e2e/specs/site-editor/template-part.spec.js +++ b/test/e2e/specs/site-editor/template-part.spec.js @@ -382,9 +382,19 @@ test.describe( 'Template Part', () => { // Insert a group block with a Site Title block inside. await editor.insertBlock( { name: 'core/group', - innerBlocks: [ { name: 'core/site-title' } ], + innerBlocks: [ + { name: 'core/paragraph', attributes: { content: 'Hello' } }, + { name: 'core/site-title' }, + ], } ); + // Type within a first block. + const paragraph = editor.canvas.getByRole( 'document', { + name: 'Paragraph', + } ); + await editor.selectBlocks( paragraph ); + await page.keyboard.type( 'Modify' ); + // Select the Site Title block inside the group. const siteTitleInGroup = editor.canvas.getByRole( 'document', { name: 'Site title', @@ -401,8 +411,6 @@ test.describe( 'Template Part', () => { // Undo the change. await pageUtils.pressKeys( 'primary+z' ); - await expect( - page.locator( 'role=button[name="Change level"i]' ) - ).toBeFocused(); + await expect( paragraph ).toBeFocused(); } ); } ); From 8fa043bae1265a37ab27fc1cd25fb612feae26e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Thu, 16 Nov 2023 10:22:54 +0100 Subject: [PATCH 045/116] DataViews: add missing key to ResetFilters component (#56189) --- packages/edit-site/src/components/dataviews/filters.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/dataviews/filters.js b/packages/edit-site/src/components/dataviews/filters.js index dc268845df5c0..9c37a7501a155 100644 --- a/packages/edit-site/src/components/dataviews/filters.js +++ b/packages/edit-site/src/components/dataviews/filters.js @@ -70,7 +70,11 @@ export default function Filters( { fields, view, onChangeView } ) { if ( filterComponents.length > 1 ) { filterComponents.push( - + ); } From eb0a6f56a505d6bd84500504e8c778bf93eef1d6 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 16 Nov 2023 11:41:40 +0100 Subject: [PATCH 046/116] Button block: support double enter to skip to default block (#56134) --- packages/block-library/src/button/edit.js | 74 +++++++++++++++++++++-- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index 81861e44997a4..8400dabddad34 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -33,11 +33,17 @@ import { __experimentalGetSpacingClassesAndStyles as useSpacingProps, __experimentalLinkControl as LinkControl, __experimentalGetElementClassName, + store as blockEditorStore, } from '@wordpress/block-editor'; -import { displayShortcut, isKeyboardEvent } from '@wordpress/keycodes'; +import { displayShortcut, isKeyboardEvent, ENTER } from '@wordpress/keycodes'; import { link, linkOff } from '@wordpress/icons'; -import { createBlock } from '@wordpress/blocks'; -import { useMergeRefs } from '@wordpress/compose'; +import { + createBlock, + cloneBlock, + getDefaultBlockName, +} from '@wordpress/blocks'; +import { useMergeRefs, useRefEffect } from '@wordpress/compose'; +import { useSelect, useDispatch } from '@wordpress/data'; const LINK_SETTINGS = [ ...LinkControl.DEFAULT_LINK_SETTINGS, @@ -47,6 +53,62 @@ const LINK_SETTINGS = [ }, ]; +function useEnter( props ) { + const { replaceBlocks, selectionChange } = useDispatch( blockEditorStore ); + const { getBlock, getBlockRootClientId, getBlockIndex } = + useSelect( blockEditorStore ); + const propsRef = useRef( props ); + propsRef.current = props; + return useRefEffect( ( element ) => { + function onKeyDown( event ) { + if ( event.defaultPrevented || event.keyCode !== ENTER ) { + return; + } + const { content, clientId } = propsRef.current; + if ( content.length ) { + return; + } + event.preventDefault(); + const topParentListBlock = getBlock( + getBlockRootClientId( clientId ) + ); + const blockIndex = getBlockIndex( clientId ); + const head = cloneBlock( { + ...topParentListBlock, + innerBlocks: topParentListBlock.innerBlocks.slice( + 0, + blockIndex + ), + } ); + const middle = createBlock( getDefaultBlockName() ); + const after = topParentListBlock.innerBlocks.slice( + blockIndex + 1 + ); + const tail = after.length + ? [ + cloneBlock( { + ...topParentListBlock, + innerBlocks: after, + } ), + ] + : []; + replaceBlocks( + topParentListBlock.clientId, + [ head, middle, ...tail ], + 1 + ); + // We manually change the selection here because we are replacing + // a different block than the selected one. + selectionChange( middle.clientId ); + } + + element.addEventListener( 'keydown', onKeyDown ); + return () => { + element.removeEventListener( 'keydown', onKeyDown ); + }; + }, [] ); +} + function WidthPanel( { selectedWidth, setAttributes } ) { function handleChange( newWidth ) { // Check if we are toggling the width off @@ -88,6 +150,7 @@ function ButtonEdit( props ) { isSelected, onReplace, mergeBlocks, + clientId, } = props; const { tagName, @@ -164,6 +227,9 @@ function ButtonEdit( props ) { [ url, opensInNewTab, nofollow ] ); + const useEnterRef = useEnter( { content: text, clientId } ); + const mergedRef = useMergeRefs( [ useEnterRef, richTextRef ] ); + return ( <>
Date: Thu, 16 Nov 2023 11:03:34 +0000 Subject: [PATCH 047/116] Update 'All pages' sidebar heading (#56148) * Update 'All pages' sidebar heading * Remove description --- packages/edit-site/src/components/sidebar/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/edit-site/src/components/sidebar/index.js b/packages/edit-site/src/components/sidebar/index.js index cbedbabfc3af8..b66bf4390a6bc 100644 --- a/packages/edit-site/src/components/sidebar/index.js +++ b/packages/edit-site/src/components/sidebar/index.js @@ -59,8 +59,7 @@ function SidebarScreens() { { window?.__experimentalAdminViews && ( } /> From e3e9dd04d4092c051d79bdf06b6997f3266dec3e Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Thu, 16 Nov 2023 14:37:22 +0100 Subject: [PATCH 048/116] Heading level dropdown: remove obtrusive tooltips in favor of visible text (#56035) * Remove heading level dropdown tooltip in favor of visible text. * Adjust test. * Remove CSS changes. --- .../src/components/block-heading-level-dropdown/index.js | 2 +- test/e2e/specs/editor/various/rich-text.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/block-heading-level-dropdown/index.js b/packages/block-editor/src/components/block-heading-level-dropdown/index.js index be580042bb85e..a8296d48ad268 100644 --- a/packages/block-editor/src/components/block-heading-level-dropdown/index.js +++ b/packages/block-editor/src/components/block-heading-level-dropdown/index.js @@ -56,7 +56,7 @@ export default function HeadingLevelDropdown( { isPressed={ isActive } /> ), - label: + title: targetLevel === 0 ? __( 'Paragraph' ) : sprintf( diff --git a/test/e2e/specs/editor/various/rich-text.spec.js b/test/e2e/specs/editor/various/rich-text.spec.js index 2969a33d25485..1a307b2bc5437 100644 --- a/test/e2e/specs/editor/various/rich-text.spec.js +++ b/test/e2e/specs/editor/various/rich-text.spec.js @@ -20,7 +20,7 @@ test.describe( 'RichText', () => { // See: https://github.com/WordPress/gutenberg/issues/3091 await editor.insertBlock( { name: 'core/heading' } ); await editor.clickBlockToolbarButton( 'Change level' ); - await page.locator( 'button[aria-label="Heading 3"]' ).click(); + await page.locator( 'role=menuitemradio[name="Heading 3"]' ).click(); expect( await editor.getBlocks() ).toMatchObject( [ { From 9df15f77d7f0b914d58dbe2ce07ad03d738cd8a9 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Thu, 16 Nov 2023 15:09:14 +0100 Subject: [PATCH 049/116] Fix the image link button pressed state. (#56123) * Fix image link button pressed state. * Add changelog entry. --- .../src/components/url-popover/image-url-input-ui.js | 1 + packages/components/CHANGELOG.md | 4 ++++ packages/components/src/toolbar/toolbar-button/style.scss | 5 ----- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/components/url-popover/image-url-input-ui.js b/packages/block-editor/src/components/url-popover/image-url-input-ui.js index 2f849eaad7884..7caa218658b24 100644 --- a/packages/block-editor/src/components/url-popover/image-url-input-ui.js +++ b/packages/block-editor/src/components/url-popover/image-url-input-ui.js @@ -249,6 +249,7 @@ const ImageURLInputUI = ( { aria-expanded={ isOpen } onClick={ openLinkUI } ref={ setPopoverAnchor } + isActive={ !! url } /> { isOpen && ( Date: Thu, 16 Nov 2023 15:17:46 +0100 Subject: [PATCH 050/116] Unify the PageUrl and PageSlug components between site and post editors (#56203) --- .../components/sidebar/post-schedule/index.js | 1 + .../sidebar/post-schedule/style.scss | 10 +- .../components/sidebar/post-status/index.js | 9 +- .../sidebar/post-template/style.scss | 5 +- .../components/sidebar/post-url/style.scss | 26 --- .../sidebar/post-visibility/style.scss | 5 +- packages/edit-post/src/style.scss | 1 - .../page-panels/page-slug.js | 161 ------------------ .../page-panels/page-summary.js | 5 +- .../sidebar-edit-mode/page-panels/style.scss | 8 - packages/editor/src/components/index.js | 1 + .../components/post-sync-status/style.scss | 5 +- .../src/components/post-url/panel.js} | 32 ++-- .../editor/src/components/post-url/style.scss | 30 ++++ 14 files changed, 72 insertions(+), 227 deletions(-) delete mode 100644 packages/edit-post/src/components/sidebar/post-url/style.scss delete mode 100644 packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-slug.js rename packages/{edit-post/src/components/sidebar/post-url/index.js => editor/src/components/post-url/panel.js} (68%) diff --git a/packages/edit-post/src/components/sidebar/post-schedule/index.js b/packages/edit-post/src/components/sidebar/post-schedule/index.js index dca0dd12c6d6b..3b20880d73647 100644 --- a/packages/edit-post/src/components/sidebar/post-schedule/index.js +++ b/packages/edit-post/src/components/sidebar/post-schedule/index.js @@ -29,6 +29,7 @@ export default function PostSchedule() { { __( 'Publish' ) } ( diff --git a/packages/edit-post/src/components/sidebar/post-schedule/style.scss b/packages/edit-post/src/components/sidebar/post-schedule/style.scss index 056c2e68dbb5f..46fcd81964004 100644 --- a/packages/edit-post/src/components/sidebar/post-schedule/style.scss +++ b/packages/edit-post/src/components/sidebar/post-schedule/style.scss @@ -6,13 +6,15 @@ span { display: block; - width: 45%; - flex-shrink: 0; - // Match padding on tertiary buttons for alignment. - padding: $grid-unit-15 * 0.5 0; + width: 30%; + margin-right: 8px; } } +.edit-post-post-schedule__dropdown { + width: 70%; +} + .components-button.edit-post-post-schedule__toggle { text-align: left; white-space: normal; diff --git a/packages/edit-post/src/components/sidebar/post-status/index.js b/packages/edit-post/src/components/sidebar/post-status/index.js index 59fdc5d189c94..d903cbb2fa12b 100644 --- a/packages/edit-post/src/components/sidebar/post-status/index.js +++ b/packages/edit-post/src/components/sidebar/post-status/index.js @@ -7,7 +7,11 @@ import { PanelBody, } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; -import { PostSwitchToDraftButton, PostSyncStatus } from '@wordpress/editor'; +import { + PostSwitchToDraftButton, + PostSyncStatus, + PostURLPanel, +} from '@wordpress/editor'; /** * Internal dependencies @@ -23,7 +27,6 @@ import PostPendingStatus from '../post-pending-status'; import PluginPostStatusInfo from '../plugin-post-status-info'; import { store as editPostStore } from '../../../store'; import PostTemplate from '../post-template'; -import PostURL from '../post-url'; /** * Module Constants @@ -60,7 +63,7 @@ export default function PostStatus() { - + diff --git a/packages/edit-post/src/components/sidebar/post-template/style.scss b/packages/edit-post/src/components/sidebar/post-template/style.scss index caafabbe4227c..2746fc2eeec4f 100644 --- a/packages/edit-post/src/components/sidebar/post-template/style.scss +++ b/packages/edit-post/src/components/sidebar/post-template/style.scss @@ -4,9 +4,8 @@ span { display: block; - width: 45%; - // Match padding on tertiary buttons for alignment. - padding: $grid-unit-15 * 0.5 0; + width: 30%; + margin-right: 8px; } } diff --git a/packages/edit-post/src/components/sidebar/post-url/style.scss b/packages/edit-post/src/components/sidebar/post-url/style.scss deleted file mode 100644 index 73a93d477df58..0000000000000 --- a/packages/edit-post/src/components/sidebar/post-url/style.scss +++ /dev/null @@ -1,26 +0,0 @@ -.edit-post-post-url { - width: 100%; - justify-content: flex-start; - align-items: flex-start; - - span { - display: block; - width: 45%; - flex-shrink: 0; - // Match padding on tertiary buttons for alignment. - padding: $grid-unit-15 * 0.5 0; - } -} - -.components-button.edit-post-post-url__toggle { - text-align: left; - white-space: normal; - height: auto; - word-break: break-word; -} - -.edit-post-post-url__dialog .editor-post-url { - // sidebar width - popover padding - form margin - min-width: $sidebar-width - $grid-unit-20 - $grid-unit-20; - margin: $grid-unit-10; -} diff --git a/packages/edit-post/src/components/sidebar/post-visibility/style.scss b/packages/edit-post/src/components/sidebar/post-visibility/style.scss index d578905a482ac..b3876c8403aa0 100644 --- a/packages/edit-post/src/components/sidebar/post-visibility/style.scss +++ b/packages/edit-post/src/components/sidebar/post-visibility/style.scss @@ -4,9 +4,8 @@ span { display: block; - width: 45%; - // Match padding on tertiary buttons for alignment. - padding: $grid-unit-15 * 0.5 0; + width: 30%; + margin-right: 8px; } } diff --git a/packages/edit-post/src/style.scss b/packages/edit-post/src/style.scss index 60544e7fc3a8a..7a71d20ba0f1f 100644 --- a/packages/edit-post/src/style.scss +++ b/packages/edit-post/src/style.scss @@ -15,7 +15,6 @@ @import "./components/sidebar/post-schedule/style.scss"; @import "./components/sidebar/post-slug/style.scss"; @import "./components/sidebar/post-template/style.scss"; -@import "./components/sidebar/post-url/style.scss"; @import "./components/sidebar/post-visibility/style.scss"; @import "./components/sidebar/settings-header/style.scss"; @import "./components/sidebar/template-summary/style.scss"; diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-slug.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-slug.js deleted file mode 100644 index d6ffa1991333e..0000000000000 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-slug.js +++ /dev/null @@ -1,161 +0,0 @@ -/** - * WordPress dependencies - */ -import { useSelect, useDispatch } from '@wordpress/data'; -import { - safeDecodeURIComponent, - filterURLForDisplay, - cleanForSlug, -} from '@wordpress/url'; -import { useState, useMemo } from '@wordpress/element'; -import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor'; -import { __ } from '@wordpress/i18n'; -import { - __experimentalInputControl as InputControl, - __experimentalHStack as HStack, - __experimentalVStack as VStack, - __experimentalText as Text, - Dropdown, - Button, -} from '@wordpress/components'; -import { store as coreStore } from '@wordpress/core-data'; - -export const PERMALINK_POSTNAME_REGEX = /%(?:postname|pagename)%/; - -function getPostPermalink( record, isEditable ) { - if ( ! record?.permalink_template ) { - return; - } - const slug = record?.slug || record?.generated_slug; - const [ prefix, suffix ] = record.permalink_template.split( - PERMALINK_POSTNAME_REGEX - ); - const permalink = isEditable ? prefix + slug + suffix : record.link; - return filterURLForDisplay( safeDecodeURIComponent( permalink ) ); -} - -export default function PageSlug( { postType, postId } ) { - const { editEntityRecord } = useDispatch( coreStore ); - const { record, savedSlug } = useSelect( - ( select ) => { - const { getEntityRecord, getEditedEntityRecord } = - select( coreStore ); - const savedRecord = getEntityRecord( 'postType', postType, postId ); - return { - record: getEditedEntityRecord( 'postType', postType, postId ), - savedSlug: savedRecord?.slug || savedRecord?.generated_slug, - }; - }, - [ postType, postId ] - ); - const [ popoverAnchor, setPopoverAnchor ] = useState( null ); - const [ forceEmptyField, setForceEmptyField ] = useState( false ); - const isEditable = - PERMALINK_POSTNAME_REGEX.test( record?.permalink_template ) && - record?._links?.[ 'wp:action-publish' ]; - const popoverProps = useMemo( - () => ( { - // Anchor the popover to the middle of the entire row so that it doesn't - // move around when the label changes. - anchor: popoverAnchor, - 'aria-label': __( 'Change slug' ), - placement: 'bottom-end', - } ), - [ popoverAnchor ] - ); - if ( ! record || ! isEditable ) { - return null; - } - const recordSlug = safeDecodeURIComponent( - record?.slug || record?.generated_slug - ); - const permaLink = getPostPermalink( record, isEditable ); - const onSlugChange = ( newValue ) => { - editEntityRecord( 'postType', postType, postId, { - slug: newValue, - } ); - }; - return ( - - - { __( 'URL' ) } - - { - if ( forceEmptyField ) { - onSlugChange( cleanForSlug( savedSlug ) ); - setForceEmptyField( false ); - } - } } - renderToggle={ ( { onToggle } ) => ( - - ) } - renderContent={ ( { onClose } ) => { - return ( - <> - - - - { - onSlugChange( newValue ); - // When we delete the field the permalink gets - // reverted to the original value. - // The forceEmptyField logic allows the user to have - // the field temporarily empty while typing. - if ( ! newValue ) { - if ( ! forceEmptyField ) { - setForceEmptyField( true ); - } - return; - } - if ( forceEmptyField ) { - setForceEmptyField( false ); - } - } } - onBlur={ ( event ) => { - onSlugChange( - cleanForSlug( - event.target.value || - savedSlug - ) - ); - if ( forceEmptyField ) { - setForceEmptyField( false ); - } - } } - /> - - - - ); - } } - /> - - ); -} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js index 25b69985bcbd6..26fa86c933f11 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js @@ -2,13 +2,14 @@ * WordPress dependencies */ import { __experimentalVStack as VStack } from '@wordpress/components'; +import { PostURLPanel } from '@wordpress/editor'; + /** * Internal dependencies */ import PageStatus from './page-status'; import PublishDate from './publish-date'; import EditTemplate from './edit-template'; -import PageSlug from './page-slug'; export default function PageSummary( { status, @@ -33,7 +34,7 @@ export default function PageSummary( { postType={ postType } /> - + ); } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss index 64d72db4e15fd..acaf5cbfe35dd 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss @@ -90,11 +90,3 @@ color: inherit; } } - -.edit-site-page-panels-edit-slug__dropdown { - .components-popover__content { - min-width: 320px; - padding: $grid-unit-20; - } -} - diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js index 39b562806c109..bcfccc026ff72 100644 --- a/packages/editor/src/components/index.js +++ b/packages/editor/src/components/index.js @@ -71,6 +71,7 @@ export { default as PostTypeSupportCheck } from './post-type-support-check'; export { default as PostURL } from './post-url'; export { default as PostURLCheck } from './post-url/check'; export { default as PostURLLabel, usePostURLLabel } from './post-url/label'; +export { default as PostURLPanel } from './post-url/panel'; export { default as PostVisibility } from './post-visibility'; export { default as PostVisibilityLabel, diff --git a/packages/editor/src/components/post-sync-status/style.scss b/packages/editor/src/components/post-sync-status/style.scss index 90a75c86bf466..e18eead94ac83 100644 --- a/packages/editor/src/components/post-sync-status/style.scss +++ b/packages/editor/src/components/post-sync-status/style.scss @@ -6,9 +6,8 @@ > span { display: block; - width: 45%; - flex-shrink: 0; - padding: $grid-unit-15 * 0.5 0; + width: 30%; + margin-right: 8px; word-break: break-word; } diff --git a/packages/edit-post/src/components/sidebar/post-url/index.js b/packages/editor/src/components/post-url/panel.js similarity index 68% rename from packages/edit-post/src/components/sidebar/post-url/index.js rename to packages/editor/src/components/post-url/panel.js index 1dc1b8d804cd7..1fddc7df9922c 100644 --- a/packages/edit-post/src/components/sidebar/post-url/index.js +++ b/packages/editor/src/components/post-url/panel.js @@ -2,15 +2,21 @@ * WordPress dependencies */ import { useMemo, useState } from '@wordpress/element'; -import { PanelRow, Dropdown, Button } from '@wordpress/components'; -import { __, sprintf } from '@wordpress/i18n'; import { - PostURLCheck, - PostURL as PostURLForm, - usePostURLLabel, -} from '@wordpress/editor'; + __experimentalHStack as HStack, + Dropdown, + Button, +} from '@wordpress/components'; +import { __, sprintf } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import PostURLCheck from './check'; +import PostURL from './index'; +import { usePostURLLabel } from './label'; -export default function PostURL() { +export default function PostURLPanel() { // Use internal state instead of a ref to make sure that the component // re-renders when the popover's anchor updates. const [ popoverAnchor, setPopoverAnchor ] = useState( null ); @@ -22,21 +28,21 @@ export default function PostURL() { return ( - + { __( 'URL' ) } ( ) } renderContent={ ( { onClose } ) => ( - + ) } /> - + ); } @@ -45,7 +51,7 @@ function PostURLToggle( { isOpen, onClick } ) { const label = usePostURLLabel(); return (
) } From 3875618390ccf37c2df36d2ab4b7e249bc161660 Mon Sep 17 00:00:00 2001 From: Siobhan Bamber Date: Thu, 16 Nov 2023 14:44:07 +0000 Subject: [PATCH 052/116] [RNMobile] Ensure uploaded audio is always visible within Audio block (#55627) Ensure the Audio block is always visible when media's been uploaded to it. --- packages/components/src/index.native.js | 1 + .../src/mobile/audio-player/index.native.js | 22 ++++------ .../global-styles-context/utils.native.js | 44 +++++++++++++++++++ packages/react-native-editor/CHANGELOG.md | 1 + 4 files changed, 55 insertions(+), 13 deletions(-) diff --git a/packages/components/src/index.native.js b/packages/components/src/index.native.js index 9a66a62f98e18..f88399fbee287 100644 --- a/packages/components/src/index.native.js +++ b/packages/components/src/index.native.js @@ -141,4 +141,5 @@ export { getGlobalStyles, getColorsAndGradients, useMobileGlobalStylesColors, + useEditorColorScheme, } from './mobile/global-styles-context/utils'; diff --git a/packages/components/src/mobile/audio-player/index.native.js b/packages/components/src/mobile/audio-player/index.native.js index ad8f0dcb2e9e8..c5d7c0e8132c1 100644 --- a/packages/components/src/mobile/audio-player/index.native.js +++ b/packages/components/src/mobile/audio-player/index.native.js @@ -14,7 +14,7 @@ import { default as VideoPlayer } from 'react-native-video'; * WordPress dependencies */ import { View } from '@wordpress/primitives'; -import { Icon } from '@wordpress/components'; +import { Icon, useEditorColorScheme } from '@wordpress/components'; import { withPreferredColorScheme } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; import { audio, warning } from '@wordpress/icons'; @@ -34,7 +34,6 @@ import { parseAudioUrl } from './audio-url-parser.native'; const isIOS = Platform.OS === 'ios'; function Player( { - getStylesFromColorScheme, isUploadInProgress, isUploadFailed, attributes, @@ -70,14 +69,14 @@ function Player( { } }; - const containerStyle = getStylesFromColorScheme( + const containerStyle = useEditorColorScheme( styles.container, styles.containerDark ); - const iconStyle = getStylesFromColorScheme( styles.icon, styles.iconDark ); + const iconStyle = useEditorColorScheme( styles.icon, styles.iconDark ); - const iconDisabledStyle = getStylesFromColorScheme( + const iconDisabledStyle = useEditorColorScheme( styles.iconDisabled, styles.iconDisabledDark ); @@ -89,7 +88,7 @@ function Player( { ...( isDisabled && iconDisabledStyle ), }; - const iconContainerStyle = getStylesFromColorScheme( + const iconContainerStyle = useEditorColorScheme( styles.iconContainer, styles.iconContainerDark ); @@ -99,17 +98,14 @@ function Player( { ...( isIOS ? styles.titleContainerIOS : styles.titleContainerAndroid ), }; - const titleStyle = getStylesFromColorScheme( - styles.title, - styles.titleDark - ); + const titleStyle = useEditorColorScheme( styles.title, styles.titleDark ); - const uploadFailedStyle = getStylesFromColorScheme( + const uploadFailedStyle = useEditorColorScheme( styles.uploadFailed, styles.uploadFailedDark ); - const subtitleStyle = getStylesFromColorScheme( + const subtitleStyle = useEditorColorScheme( styles.subtitle, styles.subtitleDark ); @@ -119,7 +115,7 @@ function Player( { ...( isUploadFailed && uploadFailedStyle ), }; - const buttonBackgroundStyle = getStylesFromColorScheme( + const buttonBackgroundStyle = useEditorColorScheme( styles.buttonBackground, styles.buttonBackgroundDark ); diff --git a/packages/components/src/mobile/global-styles-context/utils.native.js b/packages/components/src/mobile/global-styles-context/utils.native.js index f7ce110060eb4..f2cbcae9c3f3e 100644 --- a/packages/components/src/mobile/global-styles-context/utils.native.js +++ b/packages/components/src/mobile/global-styles-context/utils.native.js @@ -3,6 +3,7 @@ */ import { camelCase } from 'change-case'; import { Dimensions } from 'react-native'; +import { colord } from 'colord'; /** * WordPress dependencies @@ -13,6 +14,12 @@ import { useMultipleOriginColorsAndGradients, SETTINGS_DEFAULTS, } from '@wordpress/block-editor'; +import { usePreferredColorSchemeStyle } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import { useGlobalStyles } from './index.native'; export const BLOCK_STYLE_ATTRIBUTES = [ 'textColor', @@ -441,3 +448,40 @@ export function getGlobalStyles( rawStyles, rawFeatures ) { __experimentalGlobalStylesBaseStyles: globalStyles, }; } + +/** + * Determine and apply appropriate color scheme based on global styles or device's light/dark mode. + * + * The function first attempts to retrieve the editor's background color from global styles. + * If the detected background color is light, light styles are applied, and dark styles otherwise. + * If no custom background color is defined, styles are applied using the device's dark/light setting. + * + * @param {Object} baseStyle - An object representing the base (light theme) styles for the editor. + * @param {Object} darkStyle - An object representing the additional styles to apply when the editor is in dark mode. + * + * @return {Object} - The combined style object that should be applied to the editor. + */ +export const useEditorColorScheme = ( baseStyle, darkStyle ) => { + const globalStyles = useGlobalStyles(); + + const deviceColorScheme = usePreferredColorSchemeStyle( + baseStyle, + darkStyle + ); + + const editorColors = globalStyles?.baseColors?.color; + const editorBackgroundColor = editorColors?.background; + + const isBackgroundColorDefined = + typeof editorBackgroundColor !== 'undefined' && + editorBackgroundColor !== 'undefined'; + + if ( isBackgroundColorDefined ) { + const isEditorBackgroundDark = colord( editorBackgroundColor ).isDark(); + return isEditorBackgroundDark + ? { ...baseStyle, ...darkStyle } + : baseStyle; + } + + return deviceColorScheme; +}; diff --git a/packages/react-native-editor/CHANGELOG.md b/packages/react-native-editor/CHANGELOG.md index 1a7de1314288b..2fef3d50be338 100644 --- a/packages/react-native-editor/CHANGELOG.md +++ b/packages/react-native-editor/CHANGELOG.md @@ -10,6 +10,7 @@ For each user feature we should also add a importance categorization label to i --> ## Unreleased +- [*] Audio block: Improve legibility of audio file details on various background colors [#55627] ## 1.108.0 - [*] Fix error when pasting deeply nested structure content [#55613] From 7cde29293f8a09b868c31e17598f5f961e6a6176 Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Thu, 16 Nov 2023 16:01:02 +0000 Subject: [PATCH 053/116] Bump plugin version to 17.1.0-rc.1 --- gutenberg.php | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gutenberg.php b/gutenberg.php index 8a8b1db6f85b9..3ccde2667f03a 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -5,7 +5,7 @@ * Description: Printing since 1440. This is the development plugin for the block editor, site editor, and other future WordPress core functionality. * Requires at least: 6.2 * Requires PHP: 7.0 - * Version: 17.0.2 + * Version: 17.1.0-rc.1 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index 28f51a1408f64..158d3ab9e25c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gutenberg", - "version": "17.0.2", + "version": "17.1.0-rc.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "gutenberg", - "version": "17.0.2", + "version": "17.1.0-rc.1", "hasInstallScript": true, "license": "GPL-2.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 2c3313b9337d4..eea10b3180540 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "17.0.2", + "version": "17.1.0-rc.1", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", From bc73a3d3461f8db4f705c137da9ef909d068649f Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Thu, 16 Nov 2023 16:31:31 +0000 Subject: [PATCH 054/116] Update Changelog for 17.1.0-rc.1 --- changelog.txt | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) diff --git a/changelog.txt b/changelog.txt index 8159928bd84fb..2435ab1eceb4a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,333 @@ == Changelog == += 17.1.0-rc.1 = + + + +## Changelog + +### Enhancements + +#### Block Library +- Navigation block: Fix Inaccurate description of the Show icon button setting. ([55429](https://github.com/WordPress/gutenberg/pull/55429)) +- Query Loop: Add accesibility markup at the end of the loop in all cases. ([55890](https://github.com/WordPress/gutenberg/pull/55890)) +- Template Part: Add fallback to the current theme when not provided. ([55965](https://github.com/WordPress/gutenberg/pull/55965)) +- Update components to use __next40pxDefaultSize. ([56022](https://github.com/WordPress/gutenberg/pull/56022)) + +#### Components +- Tabs: Improve focus behavior. ([55287](https://github.com/WordPress/gutenberg/pull/55287)) +- Tabs: Update subcomponents to accept full HTML element props. ([55860](https://github.com/WordPress/gutenberg/pull/55860)) +- TextControl: Add opt-in prop for 40px default size. ([55471](https://github.com/WordPress/gutenberg/pull/55471)) +- ToggleGroupControl: Add opt-in prop for 40px default size. ([55789](https://github.com/WordPress/gutenberg/pull/55789)) + +#### Patterns +- Move "Manage patterns" below "Detach pattern". ([56018](https://github.com/WordPress/gutenberg/pull/56018)) +- Show theme patterns from directory in site editor. ([55877](https://github.com/WordPress/gutenberg/pull/55877)) + +#### Global Styles +- Global Style Revisions: Ensure consistent back button behaviour. ([55881](https://github.com/WordPress/gutenberg/pull/55881)) +- Global Styles Revisions: More descriptive text timeline. ([55868](https://github.com/WordPress/gutenberg/pull/55868)) +- Global styles revisions: Add route for single styles revisions. ([55827](https://github.com/WordPress/gutenberg/pull/55827)) + +#### Block Locking +- Block Quick Navigation: Truncate text. ([56142](https://github.com/WordPress/gutenberg/pull/56142)) + +#### Block Editor +- Button block: Support double enter to skip to default block. ([56134](https://github.com/WordPress/gutenberg/pull/56134)) + +#### Design Tools +- Add block gap support to Quote block. ([56064](https://github.com/WordPress/gutenberg/pull/56064)) + +#### Post Editor +- "Detach" text change in template options. ([55870](https://github.com/WordPress/gutenberg/pull/55870)) + +#### Site Editor +- Site editor: Add edit page slug field. ([55767](https://github.com/WordPress/gutenberg/pull/55767)) + +#### Interactivity API +- Server directive processing: Process only root blocks. ([55739](https://github.com/WordPress/gutenberg/pull/55739)) + +#### Block settings menu +- Remove the extraneous template part title in replace control. ([55603](https://github.com/WordPress/gutenberg/pull/55603)) + +#### List View +- Add keyboard shortcut to select all blocks. ([54899](https://github.com/WordPress/gutenberg/pull/54899)) + + +### New APIs + +- Download blob: Remove downloadjs dependency. ([56024](https://github.com/WordPress/gutenberg/pull/56024)) + + +### Bug Fixes + +#### Block Library +- Background Image Support: Hide the background image reset button when there's no image. ([55973](https://github.com/WordPress/gutenberg/pull/55973)) +- Background image support: Fix focus loss when resetting background image. ([55984](https://github.com/WordPress/gutenberg/pull/55984)) +- Custom Link: Decode value in URL input field. ([55549](https://github.com/WordPress/gutenberg/pull/55549)) +- Fix lightbox trigger styles. ([55859](https://github.com/WordPress/gutenberg/pull/55859)) +- Form block: Use `type="submit"` for buttons. ([55690](https://github.com/WordPress/gutenberg/pull/55690)) +- Image block: Add check for lightbox values during image block migration. ([56057](https://github.com/WordPress/gutenberg/pull/56057)) +- Image block: Don't show pointer cursor on linked image in the editor. ([55882](https://github.com/WordPress/gutenberg/pull/55882)) +- Lightbox: Fix button misalignment in gallery image. ([56060](https://github.com/WordPress/gutenberg/pull/56060)) +- Lightbox: Fix close button position. ([56125](https://github.com/WordPress/gutenberg/pull/56125)) +- Missing block: Use raw source for originalContent. ([56014](https://github.com/WordPress/gutenberg/pull/56014)) +- Navigation Link block: Register variations on post type / taxonomy registration. ([54801](https://github.com/WordPress/gutenberg/pull/54801)) +- Pattern: Fix regression error in post type templates. ([55858](https://github.com/WordPress/gutenberg/pull/55858)) +- Pattern: Process embeds. ([55979](https://github.com/WordPress/gutenberg/pull/55979)) +- Post feature image block: Wrap images with hrefs in an A tag. ([55498](https://github.com/WordPress/gutenberg/pull/55498)) +- Quote Block: Fix the Quote block layout supports. ([55240](https://github.com/WordPress/gutenberg/pull/55240)) +- Read More block: Reduce text decoration specificity. ([56038](https://github.com/WordPress/gutenberg/pull/56038)) + +#### Data Views +- DataViews: Add missing key to `ResetFilters` component. ([56189](https://github.com/WordPress/gutenberg/pull/56189)) +- DataViews: Fix issue with irrelevant statuses. ([55967](https://github.com/WordPress/gutenberg/pull/55967)) +- DataViews: Fix nested button tags on sidebar. ([56089](https://github.com/WordPress/gutenberg/pull/56089)) +- DataViews: Fix pagination on manual input. ([55940](https://github.com/WordPress/gutenberg/pull/55940)) +- DataViews: Fix spacing issue in top-level bar. ([56151](https://github.com/WordPress/gutenberg/pull/56151)) +- DataViews: Fix status filter upon switching the default views from the sidebar. ([55856](https://github.com/WordPress/gutenberg/pull/55856)) +- DataViews: Make items per page an even number. ([55906](https://github.com/WordPress/gutenberg/pull/55906)) +- DataViews: Make used taxonomy private. ([55918](https://github.com/WordPress/gutenberg/pull/55918)) +- DataViews: Reset pagination upon filter change. ([55797](https://github.com/WordPress/gutenberg/pull/55797)) +- Dataviews: Add a missing icon for the side by side view. ([55925](https://github.com/WordPress/gutenberg/pull/55925)) + +#### Components +- DropdownMenu: Remove extra vertical space around the toggle button. ([56136](https://github.com/WordPress/gutenberg/pull/56136)) +- DropdownMenuV2: Prevent default on Escape key presses. ([55962](https://github.com/WordPress/gutenberg/pull/55962)) +- DropdownMenuV2: Use the `Icon` component to render radio checks. ([55964](https://github.com/WordPress/gutenberg/pull/55964)) + +#### Typography +- Fix fatal error in WP_Fonts_Resolver::Get_settings(). ([55981](https://github.com/WordPress/gutenberg/pull/55981)) +- Font Library: Create fonts dir if a font face needs to use the filesystem. ([56120](https://github.com/WordPress/gutenberg/pull/56120)) +- Font Library: Fix font installation failure. ([55893](https://github.com/WordPress/gutenberg/pull/55893)) + +#### Block Editor +- Iframe: Bubble events from html element instead of body element to fix drag chip positioning. ([56099](https://github.com/WordPress/gutenberg/pull/56099)) +- Post Featured Image: Handling correctly when uploading a file without mime type. ([56133](https://github.com/WordPress/gutenberg/pull/56133)) +- Block Editor: Fix Block editor crash. ([56051](https://github.com/WordPress/gutenberg/pull/56051)) +- Move clientId key to BlockContextualToolbar. ([56008](https://github.com/WordPress/gutenberg/pull/56008)) + +#### Patterns +- Add context for translators to any unclear usage of "synced". ([55935](https://github.com/WordPress/gutenberg/pull/55935)) +- Use existing download function for JSON downloads to fix non-ASCII encoding. ([55912](https://github.com/WordPress/gutenberg/pull/55912)) + +#### Inspector Controls +- Global Styles: Don't show "Apply Styles Globally" button in non-block based themes. ([56033](https://github.com/WordPress/gutenberg/pull/56033)) + +#### Template Editor +- Templates: Update filter to call all of the individual methods. ([55980](https://github.com/WordPress/gutenberg/pull/55980)) + +#### Global Styles +- Global styles revisions: Load unsaved revision item into the revisions preview. ([55880](https://github.com/WordPress/gutenberg/pull/55880)) + +#### Post Editor +- Edit Post: Fix pattern modal reopening when making the title empty again. ([55873](https://github.com/WordPress/gutenberg/pull/55873)) + +#### Data Layer +- Core data: Fix wrong store results when page receives less items that what is stored. ([55832](https://github.com/WordPress/gutenberg/pull/55832)) + + +### Accessibility + +#### Data Views +- DataViews: Add labels to "in-filters". ([56001](https://github.com/WordPress/gutenberg/pull/56001)) +- DataViews: Show actions label. ([56027](https://github.com/WordPress/gutenberg/pull/56027)) + +#### Components +- Fix the image link button pressed state. ([56123](https://github.com/WordPress/gutenberg/pull/56123)) + +#### Block Editor +- Fix mismatching link control action buttons visual order and DOM order. ([56042](https://github.com/WordPress/gutenberg/pull/56042)) +- Escape on Block Toolbar returns focus to Editor Canvas. ([55712](https://github.com/WordPress/gutenberg/pull/55712)) + +#### Site Editor +- Prevent sidebar focus in site editor on small screens. ([55934](https://github.com/WordPress/gutenberg/pull/55934)) + +#### Block Library +- Heading level dropdown: Remove obtrusive tooltips in favor of visible text. ([56035](https://github.com/WordPress/gutenberg/pull/56035)) + + +### Performance + +#### Tooling +- Add a metric to trace template navigation in the site editor. ([55796](https://github.com/WordPress/gutenberg/pull/55796)) + +#### List View +- ListViewBlock: Combine 'useSelect' hooks. ([55889](https://github.com/WordPress/gutenberg/pull/55889)) + +#### Block Editor +- Block Editor: Optimize 'Block Hooks' inspector controls. ([56101](https://github.com/WordPress/gutenberg/pull/56101)) +- Block Editor: Optimize BlockListAppender. ([56116](https://github.com/WordPress/gutenberg/pull/56116)) + +#### Site Editor +- Avoid rerendering the sitehub unnecessarily. ([55818](https://github.com/WordPress/gutenberg/pull/55818)) + +#### Layout +- Block Editor: Optimize layout style renderer subscription. ([55762](https://github.com/WordPress/gutenberg/pull/55762)) + + +### Experiments + +#### Data Views +- DataViews: Add ability to create custom views. ([55773](https://github.com/WordPress/gutenberg/pull/55773)) +- DataViews: Add control to reset all filters at once. ([55955](https://github.com/WordPress/gutenberg/pull/55955)) +- DataViews: Add delete and restore actions. ([55781](https://github.com/WordPress/gutenberg/pull/55781)) +- DataViews: Add initial "Side by side" prototype. ([55343](https://github.com/WordPress/gutenberg/pull/55343)) +- DataViews: Add new page size option. ([56112](https://github.com/WordPress/gutenberg/pull/56112)) +- DataViews: Add rename functionality to custom views. ([55997](https://github.com/WordPress/gutenberg/pull/55997)) +- DataViews: Allow users to add filters dynamically. ([55992](https://github.com/WordPress/gutenberg/pull/55992)) +- DataViews: Update 'All pages' sidebar heading. ([56148](https://github.com/WordPress/gutenberg/pull/56148)) +- DataViews: Update 'View' button. ([56144](https://github.com/WordPress/gutenberg/pull/56144)) +- DataViews: Update `all templates` page. ([55848](https://github.com/WordPress/gutenberg/pull/55848)) +- DataViews: Update author and title fields in template's list. ([56029](https://github.com/WordPress/gutenberg/pull/56029)) +- DataViews: Update filters in view configuration. ([55735](https://github.com/WordPress/gutenberg/pull/55735)) +- DataViews: Add filters to table columns. ([55508](https://github.com/WordPress/gutenberg/pull/55508)) +- DataViews: Add: Ability to delete custom views. ([55924](https://github.com/WordPress/gutenberg/pull/55924)) +- DataViews: Add: Custom views header indication. ([55926](https://github.com/WordPress/gutenberg/pull/55926)) +- DataViews: Remove unnecessary label when no visible filters exist. ([55838](https://github.com/WordPress/gutenberg/pull/55838)) + + +### Documentation + +- Add a first block type page to the platform documentation. ([56109](https://github.com/WordPress/gutenberg/pull/56109)) +- Add new block development "Quick Start Guide" and update the `create-block-tutorial-template`. ([56056](https://github.com/WordPress/gutenberg/pull/56056)) +- Clean up DataViews docs: `filter.id` is not used. ([55833](https://github.com/WordPress/gutenberg/pull/55833)) +- DataViews: Document `enableSorting` and `enableHiding`. ([55988](https://github.com/WordPress/gutenberg/pull/55988)) +- DataViews: Document actions. ([55959](https://github.com/WordPress/gutenberg/pull/55959)) +- Doc: Corrected + updated links. ([56084](https://github.com/WordPress/gutenberg/pull/56084)) +- Doc: Fixes wrong link in #56084. ([56106](https://github.com/WordPress/gutenberg/pull/56106)) +- Docs: Changes imports from `wp.editor` to `wp.blockEditor` for PlainText and RichText. ([55841](https://github.com/WordPress/gutenberg/pull/55841)) +- Fix formatting issue in the "Get started with create-block" doc. ([55872](https://github.com/WordPress/gutenberg/pull/55872)) +- Fix: 404 Link on git workflow docs. ([55897](https://github.com/WordPress/gutenberg/pull/55897)) +- Fix: 404 link in get-started-with-create-block docs. ([55932](https://github.com/WordPress/gutenberg/pull/55932)) +- Fix: Create meta block link in block attributes documentation. ([55804](https://github.com/WordPress/gutenberg/pull/55804)) +- Fix: Filter duotone link on block-supports documentation. ([55896](https://github.com/WordPress/gutenberg/pull/55896)) +- Fix: Two invalid links on docs/contributors/documentation/README.md. ([55843](https://github.com/WordPress/gutenberg/pull/55843)) +- New additional resource for wp-env. ([55987](https://github.com/WordPress/gutenberg/pull/55987)) +- Update documentation to clarify workflow branch for release package publishing. ([56183](https://github.com/WordPress/gutenberg/pull/56183)) +- Update jest links to the new site. ([55802](https://github.com/WordPress/gutenberg/pull/55802)) + + +### Code Quality + +- Block lib: Remove multiline=false (deprecated). ([56113](https://github.com/WordPress/gutenberg/pull/56113)) +- Delete unused `SelectedBlockPopover` component. ([55821](https://github.com/WordPress/gutenberg/pull/55821)) +- Fix: Remove unrequired nullish coalescing. ([55854](https://github.com/WordPress/gutenberg/pull/55854)) +- Fix: Use of integer value in a conditional rendering condition on Gradients. ([55855](https://github.com/WordPress/gutenberg/pull/55855)) +- Give nice unique names to block controls HOCs. ([55795](https://github.com/WordPress/gutenberg/pull/55795)) +- Migrating `PatternTransformationsMenu`. ([56122](https://github.com/WordPress/gutenberg/pull/56122)) +- Migrating block inserter media tab components. ([56195](https://github.com/WordPress/gutenberg/pull/56195)) +- Move document tools motion to header-edit-mode layout level. ([55904](https://github.com/WordPress/gutenberg/pull/55904)) +- Only render block toolbar if blockType has value. ([55861](https://github.com/WordPress/gutenberg/pull/55861)) +- Refactor Edit Widgets Document Tools Navigation to own component. ([55778](https://github.com/WordPress/gutenberg/pull/55778)) +- Refactor Selected Block Tools. ([55737](https://github.com/WordPress/gutenberg/pull/55737)) +- Refactor Site Editor Document Tools Navigation to own component. ([55770](https://github.com/WordPress/gutenberg/pull/55770)) +- Remove BlockStyles.Slot empty component. ([55991](https://github.com/WordPress/gutenberg/pull/55991)) +- Remove obsolete `queryContext`. ([56034](https://github.com/WordPress/gutenberg/pull/56034)) +- Remove unnecessary empty className. ([55998](https://github.com/WordPress/gutenberg/pull/55998)) +- Rename Unforward to Unforwarded and export the named const. ([55820](https://github.com/WordPress/gutenberg/pull/55820)) +- Render Selected Block Tools in Header when using Top Toolbar. ([55787](https://github.com/WordPress/gutenberg/pull/55787)) +- Reusable Blocks: Unlock a private hook and a component at the file level. ([55809](https://github.com/WordPress/gutenberg/pull/55809)) +- Server directive processing: Improve how block references are saved. ([56107](https://github.com/WordPress/gutenberg/pull/56107)) +- Share the editor settings between the post and site editors. ([55970](https://github.com/WordPress/gutenberg/pull/55970)) +- Site Editor: Fix deprecation console error in top toolbar. ([55678](https://github.com/WordPress/gutenberg/pull/55678)) +- Site Editor: Unlock global styles' private hooks at the file level. ([55800](https://github.com/WordPress/gutenberg/pull/55800)) +- Site Editor: Update edited entity sync logic. ([55928](https://github.com/WordPress/gutenberg/pull/55928)) +- Site Editor: Use EditorProvider instead of custom logic. ([56000](https://github.com/WordPress/gutenberg/pull/56000)) +- SiteEditor: Optimize BackToPageNotification component. ([56102](https://github.com/WordPress/gutenberg/pull/56102)) +- SiteEditor: Refactor disable non page content blocks. ([56103](https://github.com/WordPress/gutenberg/pull/56103)) +- Unify the PageUrl and PageSlug components between site and post editors. ([56203](https://github.com/WordPress/gutenberg/pull/56203)) + +#### Data Views +- DataViews: Fix translatable string. ([56075](https://github.com/WordPress/gutenberg/pull/56075)) +- DataViews: Remove `filter.name`. ([55834](https://github.com/WordPress/gutenberg/pull/55834)) +- DataViews: Remove reset values from filters. ([55839](https://github.com/WordPress/gutenberg/pull/55839)) +- DataViews: Remove unnecessary `sortingFn` prop from field description. ([55989](https://github.com/WordPress/gutenberg/pull/55989)) +- DataViews: Simplify filters API. ([55917](https://github.com/WordPress/gutenberg/pull/55917)) +- DataViews: Update actions API. ([56026](https://github.com/WordPress/gutenberg/pull/56026)) + +#### Block Editor +- Rich text: Remove preserveWhiteSpace serialisation differences. ([55999](https://github.com/WordPress/gutenberg/pull/55999)) +- Rich text: highlight format: Gracefully handle old span format. ([56071](https://github.com/WordPress/gutenberg/pull/56071)) +- Update Link Control labels to use gray-900. ([55867](https://github.com/WordPress/gutenberg/pull/55867)) + +#### Components +- `DisclosureContent`: Migrate from `reakit` to `@ariakit/react`. ([55639](https://github.com/WordPress/gutenberg/pull/55639)) +- `Divider`: Migrate from `reakit` to `@ariakit/react`. ([55622](https://github.com/WordPress/gutenberg/pull/55622)) +- `RadioGroup`: Migrate from `reakit` to `ariakit`. ([55580](https://github.com/WordPress/gutenberg/pull/55580)) + +#### Site Editor +- Core Data: Move the template lookup to core-data selectors/resolvers. ([55883](https://github.com/WordPress/gutenberg/pull/55883)) +- Don't use 'useEntityRecord' to only dispatch actions. ([56076](https://github.com/WordPress/gutenberg/pull/56076)) + +#### Block Library +- Navigation: Refactor the PHP render function to make it easier to make changes in the future. ([55605](https://github.com/WordPress/gutenberg/pull/55605)) +- Update `blockEditor.__unstableCanInsertBlockType` hook namespace. ([55845](https://github.com/WordPress/gutenberg/pull/55845)) + +#### Data Layer +- Data: Fix ESLint warnings for the 'useSelect' hook. ([55916](https://github.com/WordPress/gutenberg/pull/55916)) + +#### Post Editor +- Edit Post: Use a single 'useSelect' hook for getting selectors. ([55902](https://github.com/WordPress/gutenberg/pull/55902)) + +#### Colors +- Add Unit testing for duotone enhanced pagination. ([55542](https://github.com/WordPress/gutenberg/pull/55542)) + +#### Patterns +- Split up the block editor inserter patterns tab into separate component files. ([55315](https://github.com/WordPress/gutenberg/pull/55315)) + +#### Design Tools +- Block styles: Remove __unstableElementContext in favour of useStyleOverride. ([54493](https://github.com/WordPress/gutenberg/pull/54493)) + + +### Tools + +- Issue Templates: Add default type labels to issue templates. ([55826](https://github.com/WordPress/gutenberg/pull/55826)) +- Label enforcer: Make the warning message less scary for new contributors. ([55900](https://github.com/WordPress/gutenberg/pull/55900)) +- Quote feature request label. ([55862](https://github.com/WordPress/gutenberg/pull/55862)) + +#### Testing +- Disable 'no-conditional-in-test' ESLint rule for Playwright. ([56088](https://github.com/WordPress/gutenberg/pull/56088)) +- Fix 'Block Switcher' test file name for Playwright end-to-end tests. ([55840](https://github.com/WordPress/gutenberg/pull/55840)) +- Fix flaky 'Meta boxes' end-to-end tests. ([56083](https://github.com/WordPress/gutenberg/pull/56083)) +- Migrate 'CPT locking' end-to-end tests to Playwright. ([55929](https://github.com/WordPress/gutenberg/pull/55929)) +- Migrate 'Meta boxes' end-to-end tests to Playwright. ([55915](https://github.com/WordPress/gutenberg/pull/55915)) +- Migrate 'Plugins API' end-to-end tests to Playwright. ([55958](https://github.com/WordPress/gutenberg/pull/55958)) +- Migrate 'annotations' end-to-end tests to Playwright. ([55966](https://github.com/WordPress/gutenberg/pull/55966)) +- Migrate 'container blocks' end-to-end tests to Playwright. ([56141](https://github.com/WordPress/gutenberg/pull/56141)) +- Migrate 'inner-blocks-prioritized-inserter-blocks' end-to-end tests to Playwright. ([55828](https://github.com/WordPress/gutenberg/pull/55828)) +- Migrate 'inner-blocks-render-appender' end-to-end tests to Playwright. ([55814](https://github.com/WordPress/gutenberg/pull/55814)) +- Migrate 'meta-attribute-block' end-to-end tests to Playwright. ([55830](https://github.com/WordPress/gutenberg/pull/55830)) +- Migrate Child Block Test to Playwright. ([55199](https://github.com/WordPress/gutenberg/pull/55199)) +- Migrate flaky PostPublishButton end-to-end tests to Playwright. ([52285](https://github.com/WordPress/gutenberg/pull/52285)) +- Perf Tests: Stabilise the Site Editor metrics. ([55922](https://github.com/WordPress/gutenberg/pull/55922)) +- Playwright Utils: Fix 'clickBlockOptionsMenuItem' helper. ([55923](https://github.com/WordPress/gutenberg/pull/55923)) +- Query block enhanced pagination: Simplify test setup. ([55805](https://github.com/WordPress/gutenberg/pull/55805)) +- Site editor template preview: Add end-to-end test and aria-pressed attribute to template preview toggle. ([56096](https://github.com/WordPress/gutenberg/pull/56096)) +- Upgrade Playwright to 1.39.0. ([54051](https://github.com/WordPress/gutenberg/pull/54051)) +- end-to-end Utils: Add setPreferences and editPost utils. ([55099](https://github.com/WordPress/gutenberg/pull/55099)) +- end-to-end Utils: Add support for web-vitals.js. ([55660](https://github.com/WordPress/gutenberg/pull/55660)) + +#### Build Tooling +- Package `@ariakit/test` should be a dev dependency. ([56091](https://github.com/WordPress/gutenberg/pull/56091)) + + +## First time contributors + +The following PRs were merged by first time contributors: + +- @joanrodas: Update Link Control labels to use gray-900. ([55867](https://github.com/WordPress/gutenberg/pull/55867)) +- @JorgeVilchez95: "Detach" text change in template options. ([55870](https://github.com/WordPress/gutenberg/pull/55870)) +- @sacerro: Styles: More descriptive text for revisions timeline. ([55868](https://github.com/WordPress/gutenberg/pull/55868)) + + +## Contributors + +The following contributors merged PRs in this release: + +@afercia @andrewhayward @andrewserong @anomiex @anton-vlasenko @aristath @artemiomorales @bph @brookewp @c4rl0sbr4v0 @chad1008 @ciampo @DAreRodz @dcalhoun @dsas @ellatrix @flootr @fluiddot @gaambo @glendaviesnz @gziolo @jameskoster @jeryj @jhnstn @joanrodas @jorgefilipecosta @JorgeVilchez95 @jsnajdr @juanmaguitar @kevin940726 @Mamaduka @masteradhoc @matiasbenedetto @ndiego @ntsekouras @oandregal @peterwilsoncc @pooja-muchandikar @priethor @ramonjd @renatho @richtabor @sacerro @scruffian @shimotmk @SiobhyB @Soean @swissspidy @t-hamano @talldan @tellthemachines @torounit @tyxla @WunderBart @youknowriad + + = 17.0.2 = From 55c6741fa53338c9b695a0ceab3567faaea58f0b Mon Sep 17 00:00:00 2001 From: annezazu Date: Thu, 16 Nov 2023 09:08:37 -0800 Subject: [PATCH 055/116] Update for 6.4.1 for versions in WP (#56216) --- docs/contributors/versions-in-wordpress.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributors/versions-in-wordpress.md b/docs/contributors/versions-in-wordpress.md index 649fe10d439aa..4449f13996c62 100644 --- a/docs/contributors/versions-in-wordpress.md +++ b/docs/contributors/versions-in-wordpress.md @@ -6,6 +6,7 @@ If anything looks incorrect here, please bring it up in #core-editor in [WordPre | Gutenberg Versions | WordPress Version | | ------------------ | ----------------- | +| 16.2-16.7 | 6.4.1 | | 16.2-16.7 | 6.4 | | 15.2-16.1 | 6.3.1 | | 15.2-16.1 | 6.3 | From f55b2dc1ec046005dd06c29f7a18751db27b8c3e Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 16 Nov 2023 23:40:23 +0400 Subject: [PATCH 056/116] Global Styles: Make search more responsive for block type list (#56139) * Global Styles: Make search more responsive for block type list * Update selector getter method * No need to memoize filteredBlockTypes * Fix typo --- .../global-styles/screen-block-list.js | 63 +++++++++++-------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/screen-block-list.js b/packages/edit-site/src/components/global-styles/screen-block-list.js index 1db81377ff9a3..b4adcd64e4136 100644 --- a/packages/edit-site/src/components/global-styles/screen-block-list.js +++ b/packages/edit-site/src/components/global-styles/screen-block-list.js @@ -9,7 +9,13 @@ import { __experimentalHStack as HStack, } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; -import { useState, useMemo, useEffect, useRef } from '@wordpress/element'; +import { + useState, + useEffect, + useRef, + useDeferredValue, + memo, +} from '@wordpress/element'; import { BlockIcon, privateApis as blockEditorPrivateApis, @@ -99,22 +105,16 @@ function BlockMenuItem( { block } ) { ); } -function ScreenBlockList() { +function BlockList( { filterValue } ) { const sortedBlockTypes = useSortedBlockTypes(); - const [ filterValue, setFilterValue ] = useState( '' ); const debouncedSpeak = useDebounce( speak, 500 ); - const isMatchingSearchTerm = useSelect( - ( select ) => select( blocksStore ).isMatchingSearchTerm, - [] - ); - const filteredBlockTypes = useMemo( () => { - if ( ! filterValue ) { - return sortedBlockTypes; - } - return sortedBlockTypes.filter( ( blockType ) => - isMatchingSearchTerm( blockType, filterValue ) - ); - }, [ filterValue, sortedBlockTypes, isMatchingSearchTerm ] ); + const { isMatchingSearchTerm } = useSelect( blocksStore ); + + const filteredBlockTypes = ! filterValue + ? sortedBlockTypes + : sortedBlockTypes.filter( ( blockType ) => + isMatchingSearchTerm( blockType, filterValue ) + ); const blockTypesListRef = useRef(); @@ -140,6 +140,27 @@ function ScreenBlockList() { debouncedSpeak( resultsFoundMessage, count ); }, [ filterValue, debouncedSpeak ] ); + return ( +
+ { filteredBlockTypes.map( ( block ) => ( + + ) ) } +
+ ); +} + +const MemoizedBlockList = memo( BlockList ); + +function ScreenBlockList() { + const [ filterValue, setFilterValue ] = useState( '' ); + const deferredFilterValue = useDeferredValue( filterValue ); + return ( <> -
- { filteredBlockTypes.map( ( block ) => ( - - ) ) } -
+ ); } From d9995074b1b6de574a6e31ac269325778c0d8b54 Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Thu, 16 Nov 2023 19:35:47 +0000 Subject: [PATCH 057/116] Update changelog files --- packages/a11y/CHANGELOG.md | 2 ++ packages/a11y/package.json | 2 +- packages/annotations/CHANGELOG.md | 2 ++ packages/annotations/package.json | 2 +- packages/api-fetch/CHANGELOG.md | 2 ++ packages/api-fetch/package.json | 2 +- packages/autop/CHANGELOG.md | 2 ++ packages/autop/package.json | 2 +- packages/babel-plugin-import-jsx-pragma/CHANGELOG.md | 2 ++ packages/babel-plugin-import-jsx-pragma/package.json | 2 +- packages/babel-plugin-makepot/CHANGELOG.md | 2 ++ packages/babel-plugin-makepot/package.json | 2 +- packages/babel-preset-default/CHANGELOG.md | 2 ++ packages/babel-preset-default/package.json | 2 +- packages/base-styles/CHANGELOG.md | 2 ++ packages/base-styles/package.json | 2 +- packages/blob/CHANGELOG.md | 2 ++ packages/blob/package.json | 2 +- packages/block-directory/CHANGELOG.md | 2 ++ packages/block-directory/package.json | 2 +- packages/block-editor/CHANGELOG.md | 2 ++ packages/block-editor/package.json | 2 +- packages/block-library/CHANGELOG.md | 2 ++ packages/block-library/package.json | 2 +- packages/block-serialization-default-parser/CHANGELOG.md | 2 ++ packages/block-serialization-default-parser/package.json | 2 +- packages/block-serialization-spec-parser/CHANGELOG.md | 2 ++ packages/block-serialization-spec-parser/package.json | 2 +- packages/blocks/CHANGELOG.md | 2 ++ packages/blocks/package.json | 2 +- packages/browserslist-config/CHANGELOG.md | 2 ++ packages/browserslist-config/package.json | 2 +- packages/commands/CHANGELOG.md | 2 ++ packages/commands/package.json | 2 +- packages/components/CHANGELOG.md | 2 ++ packages/components/package.json | 2 +- packages/compose/CHANGELOG.md | 2 ++ packages/compose/package.json | 2 +- packages/core-commands/CHANGELOG.md | 2 ++ packages/core-commands/package.json | 2 +- packages/core-data/CHANGELOG.md | 2 ++ packages/core-data/package.json | 2 +- packages/create-block-interactive-template/CHANGELOG.md | 2 ++ packages/create-block-interactive-template/package.json | 2 +- packages/create-block-tutorial-template/CHANGELOG.md | 2 ++ packages/create-block-tutorial-template/package.json | 2 +- packages/create-block/CHANGELOG.md | 2 ++ packages/create-block/package.json | 2 +- packages/customize-widgets/CHANGELOG.md | 2 ++ packages/customize-widgets/package.json | 2 +- packages/data-controls/CHANGELOG.md | 2 ++ packages/data-controls/package.json | 2 +- packages/data/CHANGELOG.md | 2 ++ packages/data/package.json | 2 +- packages/date/CHANGELOG.md | 2 ++ packages/date/package.json | 2 +- packages/dependency-extraction-webpack-plugin/CHANGELOG.md | 2 ++ packages/dependency-extraction-webpack-plugin/package.json | 2 +- packages/deprecated/CHANGELOG.md | 2 ++ packages/deprecated/package.json | 2 +- packages/docgen/CHANGELOG.md | 2 ++ packages/docgen/package.json | 2 +- packages/dom-ready/CHANGELOG.md | 2 ++ packages/dom-ready/package.json | 2 +- packages/dom/CHANGELOG.md | 2 ++ packages/dom/package.json | 2 +- packages/e2e-test-utils-playwright/CHANGELOG.md | 2 ++ packages/e2e-test-utils-playwright/package.json | 2 +- packages/e2e-test-utils/CHANGELOG.md | 2 ++ packages/e2e-test-utils/package.json | 2 +- packages/e2e-tests/CHANGELOG.md | 2 ++ packages/e2e-tests/package.json | 2 +- packages/edit-post/CHANGELOG.md | 2 ++ packages/edit-post/package.json | 2 +- packages/edit-site/CHANGELOG.md | 2 ++ packages/edit-site/package.json | 2 +- packages/edit-widgets/CHANGELOG.md | 2 ++ packages/edit-widgets/package.json | 2 +- packages/editor/CHANGELOG.md | 2 ++ packages/editor/package.json | 2 +- packages/element/CHANGELOG.md | 2 ++ packages/element/package.json | 2 +- packages/env/CHANGELOG.md | 2 ++ packages/env/package.json | 2 +- packages/escape-html/CHANGELOG.md | 2 ++ packages/escape-html/package.json | 2 +- packages/eslint-plugin/CHANGELOG.md | 2 ++ packages/eslint-plugin/package.json | 2 +- packages/format-library/CHANGELOG.md | 2 ++ packages/format-library/package.json | 2 +- packages/hooks/CHANGELOG.md | 2 ++ packages/hooks/package.json | 2 +- packages/html-entities/CHANGELOG.md | 2 ++ packages/html-entities/package.json | 2 +- packages/i18n/CHANGELOG.md | 2 ++ packages/i18n/package.json | 2 +- packages/icons/CHANGELOG.md | 2 ++ packages/icons/package.json | 2 +- packages/interactivity/CHANGELOG.md | 2 ++ packages/interactivity/package.json | 2 +- packages/interface/CHANGELOG.md | 2 ++ packages/interface/package.json | 2 +- packages/is-shallow-equal/CHANGELOG.md | 2 ++ packages/is-shallow-equal/package.json | 2 +- packages/jest-console/CHANGELOG.md | 2 ++ packages/jest-console/package.json | 2 +- packages/jest-preset-default/CHANGELOG.md | 2 ++ packages/jest-preset-default/package.json | 2 +- packages/jest-puppeteer-axe/CHANGELOG.md | 2 ++ packages/jest-puppeteer-axe/package.json | 2 +- packages/keyboard-shortcuts/CHANGELOG.md | 2 ++ packages/keyboard-shortcuts/package.json | 2 +- packages/keycodes/CHANGELOG.md | 2 ++ packages/keycodes/package.json | 2 +- packages/lazy-import/CHANGELOG.md | 2 ++ packages/lazy-import/package.json | 2 +- packages/list-reusable-blocks/CHANGELOG.md | 2 ++ packages/list-reusable-blocks/package.json | 2 +- packages/media-utils/CHANGELOG.md | 2 ++ packages/media-utils/package.json | 2 +- packages/notices/CHANGELOG.md | 2 ++ packages/notices/package.json | 2 +- packages/npm-package-json-lint-config/CHANGELOG.md | 2 ++ packages/npm-package-json-lint-config/package.json | 2 +- packages/nux/CHANGELOG.md | 2 ++ packages/nux/package.json | 2 +- packages/patterns/CHANGELOG.md | 2 ++ packages/patterns/package.json | 2 +- packages/plugins/CHANGELOG.md | 2 ++ packages/plugins/package.json | 2 +- packages/postcss-plugins-preset/CHANGELOG.md | 2 ++ packages/postcss-plugins-preset/package.json | 2 +- packages/postcss-themes/CHANGELOG.md | 2 ++ packages/postcss-themes/package.json | 2 +- packages/preferences-persistence/CHANGELOG.md | 2 ++ packages/preferences-persistence/package.json | 2 +- packages/preferences/CHANGELOG.md | 2 ++ packages/preferences/package.json | 2 +- packages/prettier-config/CHANGELOG.md | 2 ++ packages/prettier-config/package.json | 2 +- packages/primitives/CHANGELOG.md | 2 ++ packages/primitives/package.json | 2 +- packages/priority-queue/CHANGELOG.md | 2 ++ packages/priority-queue/package.json | 2 +- packages/private-apis/CHANGELOG.md | 2 ++ packages/private-apis/package.json | 2 +- packages/project-management-automation/CHANGELOG.md | 2 ++ packages/project-management-automation/package.json | 2 +- packages/react-i18n/CHANGELOG.md | 2 ++ packages/react-i18n/package.json | 2 +- packages/readable-js-assets-webpack-plugin/CHANGELOG.md | 2 ++ packages/readable-js-assets-webpack-plugin/package.json | 2 +- packages/redux-routine/CHANGELOG.md | 2 ++ packages/redux-routine/package.json | 2 +- packages/reusable-blocks/CHANGELOG.md | 2 ++ packages/reusable-blocks/package.json | 2 +- packages/rich-text/CHANGELOG.md | 2 ++ packages/rich-text/package.json | 2 +- packages/router/CHANGELOG.md | 2 ++ packages/router/package.json | 2 +- packages/scripts/CHANGELOG.md | 2 ++ packages/scripts/package.json | 2 +- packages/server-side-render/CHANGELOG.md | 2 ++ packages/server-side-render/package.json | 2 +- packages/shortcode/CHANGELOG.md | 2 ++ packages/shortcode/package.json | 2 +- packages/style-engine/CHANGELOG.md | 2 ++ packages/style-engine/package.json | 2 +- packages/stylelint-config/CHANGELOG.md | 2 ++ packages/stylelint-config/package.json | 2 +- packages/sync/CHANGELOG.md | 2 ++ packages/sync/package.json | 2 +- packages/token-list/CHANGELOG.md | 2 ++ packages/token-list/package.json | 2 +- packages/undo-manager/CHANGELOG.md | 2 ++ packages/undo-manager/package.json | 2 +- packages/url/CHANGELOG.md | 2 ++ packages/url/package.json | 2 +- packages/viewport/CHANGELOG.md | 2 ++ packages/viewport/package.json | 2 +- packages/warning/CHANGELOG.md | 2 ++ packages/warning/package.json | 2 +- packages/widgets/CHANGELOG.md | 2 ++ packages/widgets/package.json | 2 +- packages/wordcount/CHANGELOG.md | 2 ++ packages/wordcount/package.json | 2 +- 186 files changed, 279 insertions(+), 93 deletions(-) diff --git a/packages/a11y/CHANGELOG.md b/packages/a11y/CHANGELOG.md index 2be0c0b64bb14..ef2826ea2f87b 100644 --- a/packages/a11y/CHANGELOG.md +++ b/packages/a11y/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/a11y/package.json b/packages/a11y/package.json index a48168ac57578..60bd6f5e7fbf1 100644 --- a/packages/a11y/package.json +++ b/packages/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/a11y", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "Accessibility (a11y) utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/annotations/CHANGELOG.md b/packages/annotations/CHANGELOG.md index a45627849418b..ccb8a4eb3b22f 100644 --- a/packages/annotations/CHANGELOG.md +++ b/packages/annotations/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.46.0 (2023-11-16) + ## 2.45.0 (2023-11-02) ## 2.44.0 (2023-10-18) diff --git a/packages/annotations/package.json b/packages/annotations/package.json index 32b3eee0e2ecb..a8aee11f46fab 100644 --- a/packages/annotations/package.json +++ b/packages/annotations/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/annotations", - "version": "2.45.0", + "version": "2.46.0-prerelease", "description": "Annotate content in the Gutenberg editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/api-fetch/CHANGELOG.md b/packages/api-fetch/CHANGELOG.md index 5806a41860d5c..07e50ad2cb451 100644 --- a/packages/api-fetch/CHANGELOG.md +++ b/packages/api-fetch/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.43.0 (2023-11-16) + ## 6.42.0 (2023-11-02) ## 6.41.0 (2023-10-18) diff --git a/packages/api-fetch/package.json b/packages/api-fetch/package.json index e5413887a61ce..cb5a477a706fe 100644 --- a/packages/api-fetch/package.json +++ b/packages/api-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/api-fetch", - "version": "6.42.0", + "version": "6.43.0-prerelease", "description": "Utility to make WordPress REST API requests.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/autop/CHANGELOG.md b/packages/autop/CHANGELOG.md index a3cba5718404b..c3ffd7dd4bb17 100644 --- a/packages/autop/CHANGELOG.md +++ b/packages/autop/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/autop/package.json b/packages/autop/package.json index 13eb7cac02d54..d6231e72dcd9d 100644 --- a/packages/autop/package.json +++ b/packages/autop/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/autop", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "WordPress's automatic paragraph functions `autop` and `removep`.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md b/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md index 292314b1c9fe1..8070de13c5955 100644 --- a/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md +++ b/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.29.0 (2023-11-16) + ## 4.28.0 (2023-11-02) ## 4.27.0 (2023-10-18) diff --git a/packages/babel-plugin-import-jsx-pragma/package.json b/packages/babel-plugin-import-jsx-pragma/package.json index 00a621f31b1e0..4e5fe879f8499 100644 --- a/packages/babel-plugin-import-jsx-pragma/package.json +++ b/packages/babel-plugin-import-jsx-pragma/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-import-jsx-pragma", - "version": "4.28.0", + "version": "4.29.0-prerelease", "description": "Babel transform plugin for automatically injecting an import to be used as the pragma for the React JSX Transform plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-makepot/CHANGELOG.md b/packages/babel-plugin-makepot/CHANGELOG.md index 0b57ac2d9b0a1..1b8137ab96e7f 100644 --- a/packages/babel-plugin-makepot/CHANGELOG.md +++ b/packages/babel-plugin-makepot/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.30.0 (2023-11-16) + ## 5.29.0 (2023-11-02) ## 5.28.0 (2023-10-18) diff --git a/packages/babel-plugin-makepot/package.json b/packages/babel-plugin-makepot/package.json index 4acc61c4819e6..c70ebc7008591 100644 --- a/packages/babel-plugin-makepot/package.json +++ b/packages/babel-plugin-makepot/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-makepot", - "version": "5.29.0", + "version": "5.30.0-prerelease", "description": "WordPress Babel internationalization (i18n) plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-preset-default/CHANGELOG.md b/packages/babel-preset-default/CHANGELOG.md index e5a4c06b4c92b..20ff5b49dbebe 100644 --- a/packages/babel-preset-default/CHANGELOG.md +++ b/packages/babel-preset-default/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 7.30.0 (2023-11-16) + ## 7.29.0 (2023-11-02) ## 7.28.0 (2023-10-18) diff --git a/packages/babel-preset-default/package.json b/packages/babel-preset-default/package.json index dd38c349bb171..fc8de1a030c61 100644 --- a/packages/babel-preset-default/package.json +++ b/packages/babel-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-preset-default", - "version": "7.29.0", + "version": "7.30.0-prerelease", "description": "Default Babel preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/base-styles/CHANGELOG.md b/packages/base-styles/CHANGELOG.md index b6135581dbd73..bac407def2873 100644 --- a/packages/base-styles/CHANGELOG.md +++ b/packages/base-styles/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.37.0 (2023-11-16) + ## 4.36.0 (2023-11-02) ## 4.35.0 (2023-10-18) diff --git a/packages/base-styles/package.json b/packages/base-styles/package.json index fe604a7cb0211..d747036f1bebd 100644 --- a/packages/base-styles/package.json +++ b/packages/base-styles/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/base-styles", - "version": "4.36.0", + "version": "4.37.0-prerelease", "description": "Base SCSS utilities and variables for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blob/CHANGELOG.md b/packages/blob/CHANGELOG.md index 680d53971c018..7fae8a61cabb1 100644 --- a/packages/blob/CHANGELOG.md +++ b/packages/blob/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ### New feature - Add `downloadBlob` function and remove `downloadjs` dependency ([#56024](https://github.com/WordPress/gutenberg/pull/56024)). diff --git a/packages/blob/package.json b/packages/blob/package.json index c3e89fb991823..8779cf3619947 100644 --- a/packages/blob/package.json +++ b/packages/blob/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blob", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "Blob utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-directory/CHANGELOG.md b/packages/block-directory/CHANGELOG.md index eb3a68dd24cc8..7cebd71db2fbc 100644 --- a/packages/block-directory/CHANGELOG.md +++ b/packages/block-directory/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/block-directory/package.json b/packages/block-directory/package.json index 71018738fac08..86f94996843ea 100644 --- a/packages/block-directory/package.json +++ b/packages/block-directory/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-directory", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "Extend editor with block directory features to search, download and install blocks.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-editor/CHANGELOG.md b/packages/block-editor/CHANGELOG.md index 94e0306e17565..497e419453f6a 100644 --- a/packages/block-editor/CHANGELOG.md +++ b/packages/block-editor/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 12.14.0 (2023-11-16) + ## 12.13.0 (2023-11-02) - Deprecated the `useSetting` function in favor of new `useSettings` one that can retrieve multiple settings at once ([#55337](https://github.com/WordPress/gutenberg/pull/55337)). diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index baebc82408652..baf9929585751 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-editor", - "version": "12.13.0", + "version": "12.14.0-prerelease", "description": "Generic block editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-library/CHANGELOG.md b/packages/block-library/CHANGELOG.md index 22f02cfcd6288..da6f0fa75152c 100644 --- a/packages/block-library/CHANGELOG.md +++ b/packages/block-library/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 8.23.0 (2023-11-16) + ## 8.22.0 (2023-11-02) ## 8.21.0 (2023-10-18) diff --git a/packages/block-library/package.json b/packages/block-library/package.json index 5fdec495443ef..5e2e0e40cfc7b 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-library", - "version": "8.22.0", + "version": "8.23.0-prerelease", "description": "Block library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-serialization-default-parser/CHANGELOG.md b/packages/block-serialization-default-parser/CHANGELOG.md index 7d8b2b6b582ae..38fbb2b327d63 100644 --- a/packages/block-serialization-default-parser/CHANGELOG.md +++ b/packages/block-serialization-default-parser/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.46.0 (2023-11-16) + ## 4.45.0 (2023-11-02) ## 4.44.0 (2023-10-18) diff --git a/packages/block-serialization-default-parser/package.json b/packages/block-serialization-default-parser/package.json index 3072546e446d1..3c0b3e5b8f698 100644 --- a/packages/block-serialization-default-parser/package.json +++ b/packages/block-serialization-default-parser/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-serialization-default-parser", - "version": "4.45.0", + "version": "4.46.0-prerelease", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-serialization-spec-parser/CHANGELOG.md b/packages/block-serialization-spec-parser/CHANGELOG.md index f4a3dea0b491b..5e44a000908e5 100644 --- a/packages/block-serialization-spec-parser/CHANGELOG.md +++ b/packages/block-serialization-spec-parser/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.46.0 (2023-11-16) + ## 4.45.0 (2023-11-02) ## 4.44.0 (2023-10-18) diff --git a/packages/block-serialization-spec-parser/package.json b/packages/block-serialization-spec-parser/package.json index 1056d871489c3..429caf6f66bf5 100644 --- a/packages/block-serialization-spec-parser/package.json +++ b/packages/block-serialization-spec-parser/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-serialization-spec-parser", - "version": "4.45.0", + "version": "4.46.0-prerelease", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blocks/CHANGELOG.md b/packages/blocks/CHANGELOG.md index a0f9d61e0b4c2..3b04d680cb3aa 100644 --- a/packages/blocks/CHANGELOG.md +++ b/packages/blocks/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 12.23.0 (2023-11-16) + ## 12.22.0 (2023-11-02) ## 12.21.0 (2023-10-18) diff --git a/packages/blocks/package.json b/packages/blocks/package.json index 813272be7ef6e..e88532e850146 100644 --- a/packages/blocks/package.json +++ b/packages/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blocks", - "version": "12.22.0", + "version": "12.23.0-prerelease", "description": "Block API for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/browserslist-config/CHANGELOG.md b/packages/browserslist-config/CHANGELOG.md index 28f88c40569bf..1b32704cfd577 100644 --- a/packages/browserslist-config/CHANGELOG.md +++ b/packages/browserslist-config/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.29.0 (2023-11-16) + ## 5.28.0 (2023-11-02) ## 5.27.0 (2023-10-18) diff --git a/packages/browserslist-config/package.json b/packages/browserslist-config/package.json index c7813290dedf5..69b1f02f9eb08 100644 --- a/packages/browserslist-config/package.json +++ b/packages/browserslist-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/browserslist-config", - "version": "5.28.0", + "version": "5.29.0-prerelease", "description": "WordPress Browserslist shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/commands/CHANGELOG.md b/packages/commands/CHANGELOG.md index a858b5af26543..6641cb29ca672 100644 --- a/packages/commands/CHANGELOG.md +++ b/packages/commands/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.17.0 (2023-11-16) + ## 0.16.0 (2023-11-02) ## 0.15.0 (2023-10-18) diff --git a/packages/commands/package.json b/packages/commands/package.json index 0acd14f3de8ad..bb74b5c238fd5 100644 --- a/packages/commands/package.json +++ b/packages/commands/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/commands", - "version": "0.16.0", + "version": "0.17.0-prerelease", "description": "Handles the commands menu.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 856926988089a..37ad2a65da28a 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 25.12.0 (2023-11-16) + ### Bug Fix - `Toolbar`: Remove CSS rule that prevented focus outline to be visible for toolbar buttons in the `:active` state. ([#56123](https://github.com/WordPress/gutenberg/pull/56123)). diff --git a/packages/components/package.json b/packages/components/package.json index 2980553f5a284..1eaf7e27ed3a6 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/components", - "version": "25.11.0", + "version": "25.12.0-prerelease", "description": "UI components for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/compose/CHANGELOG.md b/packages/compose/CHANGELOG.md index 519a4b7b98d9c..550b2ab057bd6 100644 --- a/packages/compose/CHANGELOG.md +++ b/packages/compose/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.23.0 (2023-11-16) + ## 6.22.0 (2023-11-02) ## 6.21.0 (2023-10-18) diff --git a/packages/compose/package.json b/packages/compose/package.json index 17c5ae01ccfb5..b55a73f976e29 100644 --- a/packages/compose/package.json +++ b/packages/compose/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/compose", - "version": "6.22.0", + "version": "6.23.0-prerelease", "description": "WordPress higher-order components (HOCs).", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/core-commands/CHANGELOG.md b/packages/core-commands/CHANGELOG.md index 6da22ab229627..420ab39a97fd1 100644 --- a/packages/core-commands/CHANGELOG.md +++ b/packages/core-commands/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.15.0 (2023-11-16) + ## 0.14.0 (2023-11-02) ## 0.13.0 (2023-10-18) diff --git a/packages/core-commands/package.json b/packages/core-commands/package.json index 1ca3d5d25d4d6..b91feb0ecb4f7 100644 --- a/packages/core-commands/package.json +++ b/packages/core-commands/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-commands", - "version": "0.14.0", + "version": "0.15.0-prerelease", "description": "WordPress core reusable commands.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/core-data/CHANGELOG.md b/packages/core-data/CHANGELOG.md index d6ee748693433..d20f8bd6c9d66 100644 --- a/packages/core-data/CHANGELOG.md +++ b/packages/core-data/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.23.0 (2023-11-16) + ## 6.22.0 (2023-11-02) ## 6.21.0 (2023-10-18) diff --git a/packages/core-data/package.json b/packages/core-data/package.json index 6ab22b7ca9a69..ef10939249150 100644 --- a/packages/core-data/package.json +++ b/packages/core-data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-data", - "version": "6.22.0", + "version": "6.23.0-prerelease", "description": "Access to and manipulation of core WordPress entities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block-interactive-template/CHANGELOG.md b/packages/create-block-interactive-template/CHANGELOG.md index 9a446ed2cfa7e..46e2a04014e6c 100644 --- a/packages/create-block-interactive-template/CHANGELOG.md +++ b/packages/create-block-interactive-template/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.9.0 (2023-11-16) + ## 1.8.0 (2023-11-02) ## 1.7.0 (2023-10-18) diff --git a/packages/create-block-interactive-template/package.json b/packages/create-block-interactive-template/package.json index 579ad04f6c251..ab2053e4dc860 100644 --- a/packages/create-block-interactive-template/package.json +++ b/packages/create-block-interactive-template/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block-interactive-template", - "version": "1.8.0", + "version": "1.9.0-prerelease", "description": "Template for @wordpress/create-block to create interactive blocks with the Interactivity API.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block-tutorial-template/CHANGELOG.md b/packages/create-block-tutorial-template/CHANGELOG.md index 20f2a56d36643..12d8de954281d 100644 --- a/packages/create-block-tutorial-template/CHANGELOG.md +++ b/packages/create-block-tutorial-template/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.0.0 (2023-11-16) + ### Breaking Change - Update the block example scaffolded by the template. diff --git a/packages/create-block-tutorial-template/package.json b/packages/create-block-tutorial-template/package.json index 33eb73835bfae..a1a733b3e8a57 100644 --- a/packages/create-block-tutorial-template/package.json +++ b/packages/create-block-tutorial-template/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block-tutorial-template", - "version": "2.33.0", + "version": "3.0.0-prerelease", "description": "This is a template for @wordpress/create-block that creates an example 'Copyright Date' block. This block is used in the official WordPress block development Quick Start Guide.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block/CHANGELOG.md b/packages/create-block/CHANGELOG.md index 7b48fe15b9f2b..2a3a522feebdf 100644 --- a/packages/create-block/CHANGELOG.md +++ b/packages/create-block/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.30.0 (2023-11-16) + ## 4.29.0 (2023-11-02) ## 4.28.0 (2023-10-18) diff --git a/packages/create-block/package.json b/packages/create-block/package.json index aad739e103804..2ed37c112c7a1 100644 --- a/packages/create-block/package.json +++ b/packages/create-block/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block", - "version": "4.29.0", + "version": "4.30.0-prerelease", "description": "Generates PHP, JS and CSS code for registering a block for a WordPress plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/customize-widgets/CHANGELOG.md b/packages/customize-widgets/CHANGELOG.md index 3165744b7a6a1..80eb09e9b4fe7 100644 --- a/packages/customize-widgets/CHANGELOG.md +++ b/packages/customize-widgets/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/customize-widgets/package.json b/packages/customize-widgets/package.json index 5f84578f6c6ca..2384f06a1253c 100644 --- a/packages/customize-widgets/package.json +++ b/packages/customize-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/customize-widgets", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "Widgets blocks in Customizer Module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data-controls/CHANGELOG.md b/packages/data-controls/CHANGELOG.md index 3068808b6e028..48ed94498657c 100644 --- a/packages/data-controls/CHANGELOG.md +++ b/packages/data-controls/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.15.0 (2023-11-16) + ## 3.14.0 (2023-11-02) ## 3.13.0 (2023-10-18) diff --git a/packages/data-controls/package.json b/packages/data-controls/package.json index 58ffc68766414..b86b70577e7e4 100644 --- a/packages/data-controls/package.json +++ b/packages/data-controls/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data-controls", - "version": "3.14.0", + "version": "3.15.0-prerelease", "description": "A set of common controls for the @wordpress/data api.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data/CHANGELOG.md b/packages/data/CHANGELOG.md index 630a9b01d0dda..4c7ec31897105 100644 --- a/packages/data/CHANGELOG.md +++ b/packages/data/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 9.16.0 (2023-11-16) + ## 9.15.0 (2023-11-02) ## 9.14.0 (2023-10-18) diff --git a/packages/data/package.json b/packages/data/package.json index b3f4c6b0dd922..2698c27f0091a 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data", - "version": "9.15.0", + "version": "9.16.0-prerelease", "description": "Data module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/date/CHANGELOG.md b/packages/date/CHANGELOG.md index 5d7eca2da82e4..b43273077d2e8 100644 --- a/packages/date/CHANGELOG.md +++ b/packages/date/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.46.0 (2023-11-16) + ## 4.45.0 (2023-11-02) ## 4.44.0 (2023-10-18) diff --git a/packages/date/package.json b/packages/date/package.json index 6b2e2dfe4280c..3d85c7f446d62 100644 --- a/packages/date/package.json +++ b/packages/date/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/date", - "version": "4.45.0", + "version": "4.46.0-prerelease", "description": "Date module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dependency-extraction-webpack-plugin/CHANGELOG.md b/packages/dependency-extraction-webpack-plugin/CHANGELOG.md index 4bc08d6a386b3..29bf83987880e 100644 --- a/packages/dependency-extraction-webpack-plugin/CHANGELOG.md +++ b/packages/dependency-extraction-webpack-plugin/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.29.0 (2023-11-16) + ## 4.28.0 (2023-11-02) ## 4.27.0 (2023-10-18) diff --git a/packages/dependency-extraction-webpack-plugin/package.json b/packages/dependency-extraction-webpack-plugin/package.json index 36eadbaff6335..b1370b1c359af 100644 --- a/packages/dependency-extraction-webpack-plugin/package.json +++ b/packages/dependency-extraction-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dependency-extraction-webpack-plugin", - "version": "4.28.0", + "version": "4.29.0-prerelease", "description": "Extract WordPress script dependencies from webpack bundles.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/deprecated/CHANGELOG.md b/packages/deprecated/CHANGELOG.md index 6bd3185175ee7..841f3cfd5dcfd 100644 --- a/packages/deprecated/CHANGELOG.md +++ b/packages/deprecated/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/deprecated/package.json b/packages/deprecated/package.json index 5f13accb2e27b..e596db980e8ec 100644 --- a/packages/deprecated/package.json +++ b/packages/deprecated/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/deprecated", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "Deprecation utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/docgen/CHANGELOG.md b/packages/docgen/CHANGELOG.md index 0b45b27df3ccb..d72a476531fee 100644 --- a/packages/docgen/CHANGELOG.md +++ b/packages/docgen/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.55.0 (2023-11-16) + ## 1.54.0 (2023-11-02) ## 1.53.0 (2023-10-18) diff --git a/packages/docgen/package.json b/packages/docgen/package.json index c8610b86d2cb8..ec282a093f1d8 100644 --- a/packages/docgen/package.json +++ b/packages/docgen/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/docgen", - "version": "1.54.0", + "version": "1.55.0-prerelease", "description": "Autogenerate public API documentation from exports and JSDoc comments.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dom-ready/CHANGELOG.md b/packages/dom-ready/CHANGELOG.md index 61b414f50d8c3..e0ae85e3cac5c 100644 --- a/packages/dom-ready/CHANGELOG.md +++ b/packages/dom-ready/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/dom-ready/package.json b/packages/dom-ready/package.json index fc7043e2c950f..763f21e317236 100644 --- a/packages/dom-ready/package.json +++ b/packages/dom-ready/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom-ready", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "Execute callback after the DOM is loaded.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dom/CHANGELOG.md b/packages/dom/CHANGELOG.md index 5a1567021b1ea..df938d2fa5799 100644 --- a/packages/dom/CHANGELOG.md +++ b/packages/dom/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/dom/package.json b/packages/dom/package.json index b40a161d683b4..f80a508f23b25 100644 --- a/packages/dom/package.json +++ b/packages/dom/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "DOM utilities module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-test-utils-playwright/CHANGELOG.md b/packages/e2e-test-utils-playwright/CHANGELOG.md index cd7425c68eeff..9f5c2a199ff0f 100644 --- a/packages/e2e-test-utils-playwright/CHANGELOG.md +++ b/packages/e2e-test-utils-playwright/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.14.0 (2023-11-16) + ## 0.13.0 (2023-11-02) ## 0.12.0 (2023-10-18) diff --git a/packages/e2e-test-utils-playwright/package.json b/packages/e2e-test-utils-playwright/package.json index f8d9b7cd2f017..553ad9ad15834 100644 --- a/packages/e2e-test-utils-playwright/package.json +++ b/packages/e2e-test-utils-playwright/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-test-utils-playwright", - "version": "0.13.0", + "version": "0.14.0-prerelease", "description": "End-To-End (E2E) test utils for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-test-utils/CHANGELOG.md b/packages/e2e-test-utils/CHANGELOG.md index bf5d32bb6cc94..617315dbfaa6c 100644 --- a/packages/e2e-test-utils/CHANGELOG.md +++ b/packages/e2e-test-utils/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 10.17.0 (2023-11-16) + ## 10.16.0 (2023-11-02) ## 10.15.0 (2023-10-18) diff --git a/packages/e2e-test-utils/package.json b/packages/e2e-test-utils/package.json index f4bd86e15f1ee..58506c9686d60 100644 --- a/packages/e2e-test-utils/package.json +++ b/packages/e2e-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-test-utils", - "version": "10.16.0", + "version": "10.17.0-prerelease", "description": "End-To-End (E2E) test utils for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-tests/CHANGELOG.md b/packages/e2e-tests/CHANGELOG.md index 66ab34e826759..76363c3fda102 100644 --- a/packages/e2e-tests/CHANGELOG.md +++ b/packages/e2e-tests/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 7.17.0 (2023-11-16) + ## 7.16.0 (2023-11-02) ## 7.15.0 (2023-10-18) diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index 001f395dec608..6c444d161f65f 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-tests", - "version": "7.16.0", + "version": "7.17.0-prerelease", "description": "End-To-End (E2E) tests for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-post/CHANGELOG.md b/packages/edit-post/CHANGELOG.md index 6417fcc4454c6..e8e0fa1632a7d 100644 --- a/packages/edit-post/CHANGELOG.md +++ b/packages/edit-post/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 7.23.0 (2023-11-16) + ## 7.22.0 (2023-11-02) ## 7.21.0 (2023-10-18) diff --git a/packages/edit-post/package.json b/packages/edit-post/package.json index ed9b4541103c9..d0a8c78ca436b 100644 --- a/packages/edit-post/package.json +++ b/packages/edit-post/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-post", - "version": "7.22.0", + "version": "7.23.0-prerelease", "description": "Edit Post module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-site/CHANGELOG.md b/packages/edit-site/CHANGELOG.md index ad970d703cb43..b8814356b2b6b 100644 --- a/packages/edit-site/CHANGELOG.md +++ b/packages/edit-site/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.23.0 (2023-11-16) + ## 5.22.0 (2023-11-02) ## 5.21.0 (2023-10-18) diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index d7007e1d88fec..bea0abb0ef0c8 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-site", - "version": "5.22.0", + "version": "5.23.0-prerelease", "description": "Edit Site Page module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-widgets/CHANGELOG.md b/packages/edit-widgets/CHANGELOG.md index e1d1c915a2ad2..65b83144691eb 100644 --- a/packages/edit-widgets/CHANGELOG.md +++ b/packages/edit-widgets/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.23.0 (2023-11-16) + ## 5.22.0 (2023-11-02) ## 5.21.0 (2023-10-18) diff --git a/packages/edit-widgets/package.json b/packages/edit-widgets/package.json index 754e83f54a5f2..1e68aecf8321f 100644 --- a/packages/edit-widgets/package.json +++ b/packages/edit-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-widgets", - "version": "5.22.0", + "version": "5.23.0-prerelease", "description": "Widgets Page module for WordPress..", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/editor/CHANGELOG.md b/packages/editor/CHANGELOG.md index 0e99e83f46418..1012c6163ec29 100644 --- a/packages/editor/CHANGELOG.md +++ b/packages/editor/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 13.23.0 (2023-11-16) + ## 13.22.0 (2023-11-02) ## 13.21.0 (2023-10-18) diff --git a/packages/editor/package.json b/packages/editor/package.json index b45a28c982ee4..d9d0afcdf1656 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/editor", - "version": "13.22.0", + "version": "13.23.0-prerelease", "description": "Enhanced block editor for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/element/CHANGELOG.md b/packages/element/CHANGELOG.md index abc424112d60c..a3d999401c24b 100644 --- a/packages/element/CHANGELOG.md +++ b/packages/element/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.23.0 (2023-11-16) + ## 5.22.0 (2023-11-02) ## 5.21.0 (2023-10-18) diff --git a/packages/element/package.json b/packages/element/package.json index f1c60680fd156..fa6b5e1ab5ce7 100644 --- a/packages/element/package.json +++ b/packages/element/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/element", - "version": "5.22.0", + "version": "5.23.0-prerelease", "description": "Element React module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/env/CHANGELOG.md b/packages/env/CHANGELOG.md index 67f674c4b6a57..b1dd4f778334f 100644 --- a/packages/env/CHANGELOG.md +++ b/packages/env/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 8.12.0 (2023-11-16) + ## 8.11.0 (2023-11-02) ### Enhancement diff --git a/packages/env/package.json b/packages/env/package.json index 42ebbdc9a821f..7e2cee5596a2b 100644 --- a/packages/env/package.json +++ b/packages/env/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/env", - "version": "8.11.0", + "version": "8.12.0-prerelease", "description": "A zero-config, self contained local WordPress environment for development and testing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/escape-html/CHANGELOG.md b/packages/escape-html/CHANGELOG.md index d6fa0a8963e1a..9f62bcec394e9 100644 --- a/packages/escape-html/CHANGELOG.md +++ b/packages/escape-html/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.46.0 (2023-11-16) + ## 2.45.0 (2023-11-02) ## 2.44.0 (2023-10-18) diff --git a/packages/escape-html/package.json b/packages/escape-html/package.json index 473a3bd5511ca..742813826477e 100644 --- a/packages/escape-html/package.json +++ b/packages/escape-html/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/escape-html", - "version": "2.45.0", + "version": "2.46.0-prerelease", "description": "Escape HTML utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 9b2b7e2bb7173..203f5246c10f4 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 17.3.0 (2023-11-16) + ## 17.2.0 (2023-11-02) ## 17.1.0 (2023-10-18) diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index b262f8801c422..e1fb50b541425 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/eslint-plugin", - "version": "17.2.0", + "version": "17.3.0-prerelease", "description": "ESLint plugin for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/format-library/CHANGELOG.md b/packages/format-library/CHANGELOG.md index 9d74bfe94817e..ca29a28fd3a4c 100644 --- a/packages/format-library/CHANGELOG.md +++ b/packages/format-library/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/format-library/package.json b/packages/format-library/package.json index 37672549d0b1d..687be3963fb43 100644 --- a/packages/format-library/package.json +++ b/packages/format-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/format-library", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "Format library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/hooks/CHANGELOG.md b/packages/hooks/CHANGELOG.md index 6ec9ae13bd9bd..d2f43c203979c 100644 --- a/packages/hooks/CHANGELOG.md +++ b/packages/hooks/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/hooks/package.json b/packages/hooks/package.json index 879a513e893a6..4595c47aa29a3 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/hooks", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "WordPress hooks library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/html-entities/CHANGELOG.md b/packages/html-entities/CHANGELOG.md index 4cb861f9ad09e..bf89467f2154e 100644 --- a/packages/html-entities/CHANGELOG.md +++ b/packages/html-entities/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/html-entities/package.json b/packages/html-entities/package.json index 5ff780e4b5cb1..9d72d46f7a5ff 100644 --- a/packages/html-entities/package.json +++ b/packages/html-entities/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/html-entities", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "HTML entity utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/i18n/CHANGELOG.md b/packages/i18n/CHANGELOG.md index e34507334f2aa..dfc007b50cd07 100644 --- a/packages/i18n/CHANGELOG.md +++ b/packages/i18n/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.46.0 (2023-11-16) + ## 4.45.0 (2023-11-02) ## 4.44.0 (2023-10-18) diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 2b53debe4f79a..bb82d509684fe 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/i18n", - "version": "4.45.0", + "version": "4.46.0-prerelease", "description": "WordPress internationalization (i18n) library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/icons/CHANGELOG.md b/packages/icons/CHANGELOG.md index d99b95eb4bf37..a906ef9f569d2 100644 --- a/packages/icons/CHANGELOG.md +++ b/packages/icons/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 9.37.0 (2023-11-16) + ### New features - Add new `funnel` icon. diff --git a/packages/icons/package.json b/packages/icons/package.json index b0117b28edca0..ecc11b411c828 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/icons", - "version": "9.36.0", + "version": "9.37.0-prerelease", "description": "WordPress Icons package, based on dashicon.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/interactivity/CHANGELOG.md b/packages/interactivity/CHANGELOG.md index 7b5faaeefa1b2..089280cee2144 100644 --- a/packages/interactivity/CHANGELOG.md +++ b/packages/interactivity/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.7.0 (2023-11-16) + ## 2.6.0 (2023-11-02) ### Bug Fix diff --git a/packages/interactivity/package.json b/packages/interactivity/package.json index 0580868b7d714..791ed276db6b3 100644 --- a/packages/interactivity/package.json +++ b/packages/interactivity/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/interactivity", - "version": "2.6.0", + "version": "2.7.0-prerelease", "description": "Package that provides a standard and simple way to handle the frontend interactivity of Gutenberg blocks.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/interface/CHANGELOG.md b/packages/interface/CHANGELOG.md index 73737f3ed99e9..9c7370291eef6 100644 --- a/packages/interface/CHANGELOG.md +++ b/packages/interface/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.23.0 (2023-11-16) + ## 5.22.0 (2023-11-02) ## 5.21.0 (2023-10-18) diff --git a/packages/interface/package.json b/packages/interface/package.json index 28b11d1cbee5f..8142df4fd443b 100644 --- a/packages/interface/package.json +++ b/packages/interface/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/interface", - "version": "5.22.0", + "version": "5.23.0-prerelease", "description": "Interface module for WordPress. The package contains shared functionality across the modern JavaScript-based WordPress screens.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/is-shallow-equal/CHANGELOG.md b/packages/is-shallow-equal/CHANGELOG.md index 9eef05af9f1d6..9f5db485bb540 100644 --- a/packages/is-shallow-equal/CHANGELOG.md +++ b/packages/is-shallow-equal/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.46.0 (2023-11-16) + ## 4.45.0 (2023-11-02) ## 4.44.0 (2023-10-18) diff --git a/packages/is-shallow-equal/package.json b/packages/is-shallow-equal/package.json index e6b553baaceb7..b7202d19a87e3 100644 --- a/packages/is-shallow-equal/package.json +++ b/packages/is-shallow-equal/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/is-shallow-equal", - "version": "4.45.0", + "version": "4.46.0-prerelease", "description": "Test for shallow equality between two objects or arrays.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-console/CHANGELOG.md b/packages/jest-console/CHANGELOG.md index 463bfd52db437..4032ec50a5ebf 100644 --- a/packages/jest-console/CHANGELOG.md +++ b/packages/jest-console/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 7.17.0 (2023-11-16) + ## 7.16.0 (2023-11-02) ## 7.15.0 (2023-10-18) diff --git a/packages/jest-console/package.json b/packages/jest-console/package.json index 40981febe941f..2152ff6a5c0dd 100644 --- a/packages/jest-console/package.json +++ b/packages/jest-console/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-console", - "version": "7.16.0", + "version": "7.17.0-prerelease", "description": "Custom Jest matchers for the Console object.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-preset-default/CHANGELOG.md b/packages/jest-preset-default/CHANGELOG.md index a56d34dddad38..30db9b59cca7c 100644 --- a/packages/jest-preset-default/CHANGELOG.md +++ b/packages/jest-preset-default/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 11.17.0 (2023-11-16) + ## 11.16.0 (2023-11-02) ## 11.15.0 (2023-10-18) diff --git a/packages/jest-preset-default/package.json b/packages/jest-preset-default/package.json index ecc0769060356..4fbd174c512c5 100644 --- a/packages/jest-preset-default/package.json +++ b/packages/jest-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-preset-default", - "version": "11.16.0", + "version": "11.17.0-prerelease", "description": "Default Jest preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-puppeteer-axe/CHANGELOG.md b/packages/jest-puppeteer-axe/CHANGELOG.md index acf19522a59bc..6755f2d3f4136 100644 --- a/packages/jest-puppeteer-axe/CHANGELOG.md +++ b/packages/jest-puppeteer-axe/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.17.0 (2023-11-16) + ## 6.16.0 (2023-11-02) ## 6.15.0 (2023-10-18) diff --git a/packages/jest-puppeteer-axe/package.json b/packages/jest-puppeteer-axe/package.json index 68af3143838f3..5e87a4a542e33 100644 --- a/packages/jest-puppeteer-axe/package.json +++ b/packages/jest-puppeteer-axe/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-puppeteer-axe", - "version": "6.16.0", + "version": "6.17.0-prerelease", "description": "Axe API integration with Jest and Puppeteer.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/keyboard-shortcuts/CHANGELOG.md b/packages/keyboard-shortcuts/CHANGELOG.md index b5988c7102d03..f6fb39c60931c 100644 --- a/packages/keyboard-shortcuts/CHANGELOG.md +++ b/packages/keyboard-shortcuts/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/keyboard-shortcuts/package.json b/packages/keyboard-shortcuts/package.json index 03100a616bc4a..43e4d11af5cbb 100644 --- a/packages/keyboard-shortcuts/package.json +++ b/packages/keyboard-shortcuts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keyboard-shortcuts", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "Handling keyboard shortcuts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/keycodes/CHANGELOG.md b/packages/keycodes/CHANGELOG.md index 3ab5dc90aa858..382510e52e367 100644 --- a/packages/keycodes/CHANGELOG.md +++ b/packages/keycodes/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/keycodes/package.json b/packages/keycodes/package.json index f3705c6e523c1..9ecc81007b71a 100644 --- a/packages/keycodes/package.json +++ b/packages/keycodes/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keycodes", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "Keycodes utilities for WordPress. Used to check for keyboard events across browsers/operating systems.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/lazy-import/CHANGELOG.md b/packages/lazy-import/CHANGELOG.md index e96828769051f..a092b101c7fe4 100644 --- a/packages/lazy-import/CHANGELOG.md +++ b/packages/lazy-import/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.33.0 (2023-11-16) + ## 1.32.0 (2023-11-02) ## 1.31.0 (2023-10-18) diff --git a/packages/lazy-import/package.json b/packages/lazy-import/package.json index f697a2c259598..7e5561e2b6d18 100644 --- a/packages/lazy-import/package.json +++ b/packages/lazy-import/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/lazy-import", - "version": "1.32.0", + "version": "1.33.0-prerelease", "description": "Lazily import a module, installing it automatically if missing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/list-reusable-blocks/CHANGELOG.md b/packages/list-reusable-blocks/CHANGELOG.md index bb86ca45b5965..3c16e7ca341d0 100644 --- a/packages/list-reusable-blocks/CHANGELOG.md +++ b/packages/list-reusable-blocks/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/list-reusable-blocks/package.json b/packages/list-reusable-blocks/package.json index 9cc27c6911a91..70a3ae145a799 100644 --- a/packages/list-reusable-blocks/package.json +++ b/packages/list-reusable-blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/list-reusable-blocks", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "Adding Export/Import support to the reusable blocks listing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/media-utils/CHANGELOG.md b/packages/media-utils/CHANGELOG.md index bc1ea49c74c86..791752726da0e 100644 --- a/packages/media-utils/CHANGELOG.md +++ b/packages/media-utils/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.37.0 (2023-11-16) + ## 4.36.0 (2023-11-02) ## 4.35.0 (2023-10-18) diff --git a/packages/media-utils/package.json b/packages/media-utils/package.json index 16477d6546ad7..2f2e4f454f9ea 100644 --- a/packages/media-utils/package.json +++ b/packages/media-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/media-utils", - "version": "4.36.0", + "version": "4.37.0-prerelease", "description": "WordPress Media Upload Utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/notices/CHANGELOG.md b/packages/notices/CHANGELOG.md index f22d214e00037..0bb727268bc07 100644 --- a/packages/notices/CHANGELOG.md +++ b/packages/notices/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.14.0 (2023-11-16) + ## 4.13.0 (2023-11-02) ## 4.12.0 (2023-10-18) diff --git a/packages/notices/package.json b/packages/notices/package.json index 798f2120b94df..38c7fac68afbc 100644 --- a/packages/notices/package.json +++ b/packages/notices/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/notices", - "version": "4.13.0", + "version": "4.14.0-prerelease", "description": "State management for notices.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/npm-package-json-lint-config/CHANGELOG.md b/packages/npm-package-json-lint-config/CHANGELOG.md index 1242e51b295a6..c4c811e7396d7 100644 --- a/packages/npm-package-json-lint-config/CHANGELOG.md +++ b/packages/npm-package-json-lint-config/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.31.0 (2023-11-16) + ## 4.30.0 (2023-11-02) ## 4.29.0 (2023-10-18) diff --git a/packages/npm-package-json-lint-config/package.json b/packages/npm-package-json-lint-config/package.json index a3f4a0dfcc930..3ad54a8a2a93a 100644 --- a/packages/npm-package-json-lint-config/package.json +++ b/packages/npm-package-json-lint-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/npm-package-json-lint-config", - "version": "4.30.0", + "version": "4.31.0-prerelease", "description": "WordPress npm-package-json-lint shareable configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/nux/CHANGELOG.md b/packages/nux/CHANGELOG.md index fa995b4dbcf54..d3fbfa4a70380 100644 --- a/packages/nux/CHANGELOG.md +++ b/packages/nux/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 8.8.0 (2023-11-16) + ## 8.7.0 (2023-11-02) ## 8.6.0 (2023-10-18) diff --git a/packages/nux/package.json b/packages/nux/package.json index f03f91dcf4c8b..124d3cfacd960 100644 --- a/packages/nux/package.json +++ b/packages/nux/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/nux", - "version": "8.7.0", + "version": "8.8.0-prerelease", "description": "NUX (New User eXperience) module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/patterns/CHANGELOG.md b/packages/patterns/CHANGELOG.md index 3a9c684d01b04..30df46641ff4c 100644 --- a/packages/patterns/CHANGELOG.md +++ b/packages/patterns/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.7.0 (2023-11-16) + ## 1.6.0 (2023-11-02) ## 1.5.0 (2023-10-18) diff --git a/packages/patterns/package.json b/packages/patterns/package.json index 41846c1047d93..8f417dc1aa592 100644 --- a/packages/patterns/package.json +++ b/packages/patterns/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/patterns", - "version": "1.6.0", + "version": "1.7.0-prerelease", "description": "Management of user pattern editing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/plugins/CHANGELOG.md b/packages/plugins/CHANGELOG.md index fd5dd315e0f87..7d6ad16901b7b 100644 --- a/packages/plugins/CHANGELOG.md +++ b/packages/plugins/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.14.0 (2023-11-16) + ## 6.13.0 (2023-11-02) ## 6.12.0 (2023-10-18) diff --git a/packages/plugins/package.json b/packages/plugins/package.json index 17d06c6b63e62..e9ffee30feba8 100644 --- a/packages/plugins/package.json +++ b/packages/plugins/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/plugins", - "version": "6.13.0", + "version": "6.14.0-prerelease", "description": "Plugins module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/postcss-plugins-preset/CHANGELOG.md b/packages/postcss-plugins-preset/CHANGELOG.md index d38ea1a8b8769..28088d4cfa0ae 100644 --- a/packages/postcss-plugins-preset/CHANGELOG.md +++ b/packages/postcss-plugins-preset/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.30.0 (2023-11-16) + ## 4.29.0 (2023-11-02) ## 4.28.0 (2023-10-18) diff --git a/packages/postcss-plugins-preset/package.json b/packages/postcss-plugins-preset/package.json index 83526a9fabb21..ffd3230b90bd7 100644 --- a/packages/postcss-plugins-preset/package.json +++ b/packages/postcss-plugins-preset/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/postcss-plugins-preset", - "version": "4.29.0", + "version": "4.30.0-prerelease", "description": "PostCSS sharable plugins preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/postcss-themes/CHANGELOG.md b/packages/postcss-themes/CHANGELOG.md index ac7fea38014d9..1b26ac952c41e 100644 --- a/packages/postcss-themes/CHANGELOG.md +++ b/packages/postcss-themes/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.29.0 (2023-11-16) + ## 5.28.0 (2023-11-02) ## 5.27.0 (2023-10-18) diff --git a/packages/postcss-themes/package.json b/packages/postcss-themes/package.json index 27f3fd4b586ea..2b65ddefc795a 100644 --- a/packages/postcss-themes/package.json +++ b/packages/postcss-themes/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/postcss-themes", - "version": "5.28.0", + "version": "5.29.0-prerelease", "description": "PostCSS plugin to generate theme colors.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/preferences-persistence/CHANGELOG.md b/packages/preferences-persistence/CHANGELOG.md index d713e87f8b830..531a57d613020 100644 --- a/packages/preferences-persistence/CHANGELOG.md +++ b/packages/preferences-persistence/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.38.0 (2023-11-16) + ## 1.37.0 (2023-11-02) ## 1.36.0 (2023-10-18) diff --git a/packages/preferences-persistence/package.json b/packages/preferences-persistence/package.json index 82749616cfd3f..6a76d6094bac5 100644 --- a/packages/preferences-persistence/package.json +++ b/packages/preferences-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/preferences-persistence", - "version": "1.37.0", + "version": "1.38.0-prerelease", "description": "Persistence utilities for `wordpress/preferences`.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/preferences/CHANGELOG.md b/packages/preferences/CHANGELOG.md index 30fdb20745de0..29c48cd51c787 100644 --- a/packages/preferences/CHANGELOG.md +++ b/packages/preferences/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.23.0 (2023-11-16) + ## 3.22.0 (2023-11-02) ## 3.21.0 (2023-10-18) diff --git a/packages/preferences/package.json b/packages/preferences/package.json index 3f11fbcdfd9a7..0ba849dc9787a 100644 --- a/packages/preferences/package.json +++ b/packages/preferences/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/preferences", - "version": "3.22.0", + "version": "3.23.0-prerelease", "description": "Utilities for managing WordPress preferences.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/prettier-config/CHANGELOG.md b/packages/prettier-config/CHANGELOG.md index 69b5e5cec92d6..3fb6aa431973f 100644 --- a/packages/prettier-config/CHANGELOG.md +++ b/packages/prettier-config/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.3.0 (2023-11-16) + ## 3.2.0 (2023-11-02) ## 3.1.0 (2023-10-18) diff --git a/packages/prettier-config/package.json b/packages/prettier-config/package.json index a6f46e47f2bf3..7e4168c931d8e 100644 --- a/packages/prettier-config/package.json +++ b/packages/prettier-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/prettier-config", - "version": "3.2.0", + "version": "3.3.0-prerelease", "description": "WordPress Prettier shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/primitives/CHANGELOG.md b/packages/primitives/CHANGELOG.md index 14c4937b0b8fe..0c24a126097ee 100644 --- a/packages/primitives/CHANGELOG.md +++ b/packages/primitives/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.44.0 (2023-11-16) + ## 3.43.0 (2023-11-02) ## 3.42.0 (2023-10-18) diff --git a/packages/primitives/package.json b/packages/primitives/package.json index fc7e91899106f..274755ff59b2d 100644 --- a/packages/primitives/package.json +++ b/packages/primitives/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/primitives", - "version": "3.43.0", + "version": "3.44.0-prerelease", "description": "WordPress cross-platform primitives.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/priority-queue/CHANGELOG.md b/packages/priority-queue/CHANGELOG.md index 19fe7c317c811..c9e8b4c7e566c 100644 --- a/packages/priority-queue/CHANGELOG.md +++ b/packages/priority-queue/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.46.0 (2023-11-16) + ## 2.45.0 (2023-11-02) ## 2.44.0 (2023-10-18) diff --git a/packages/priority-queue/package.json b/packages/priority-queue/package.json index 5888f6512d747..2290bceeb8cc3 100644 --- a/packages/priority-queue/package.json +++ b/packages/priority-queue/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/priority-queue", - "version": "2.45.0", + "version": "2.46.0-prerelease", "description": "Generic browser priority queue.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/private-apis/CHANGELOG.md b/packages/private-apis/CHANGELOG.md index 35b6922652f0f..65380c088560d 100644 --- a/packages/private-apis/CHANGELOG.md +++ b/packages/private-apis/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.28.0 (2023-11-16) + ## 0.27.0 (2023-11-02) ## 0.26.0 (2023-10-18) diff --git a/packages/private-apis/package.json b/packages/private-apis/package.json index 4fafa6a3300a6..ccc4999d2fb17 100644 --- a/packages/private-apis/package.json +++ b/packages/private-apis/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/private-apis", - "version": "0.27.0", + "version": "0.28.0-prerelease", "description": "Internal experimental APIs for WordPress core.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/project-management-automation/CHANGELOG.md b/packages/project-management-automation/CHANGELOG.md index 6a627754e9d95..945fac3a5cb1b 100644 --- a/packages/project-management-automation/CHANGELOG.md +++ b/packages/project-management-automation/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.45.0 (2023-11-16) + ## 1.44.0 (2023-11-02) ## 1.43.0 (2023-10-18) diff --git a/packages/project-management-automation/package.json b/packages/project-management-automation/package.json index 7c6d127547e68..a75b111d795cd 100644 --- a/packages/project-management-automation/package.json +++ b/packages/project-management-automation/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/project-management-automation", - "version": "1.44.0", + "version": "1.45.0-prerelease", "description": "GitHub Action that implements various automation to assist with managing the Gutenberg GitHub repository.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/react-i18n/CHANGELOG.md b/packages/react-i18n/CHANGELOG.md index 8182887ba3211..2ec98e2ed0eae 100644 --- a/packages/react-i18n/CHANGELOG.md +++ b/packages/react-i18n/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.44.0 (2023-11-16) + ## 3.43.0 (2023-11-02) ## 3.42.0 (2023-10-18) diff --git a/packages/react-i18n/package.json b/packages/react-i18n/package.json index 4f0ad12a58bf7..3a08d14983bc2 100644 --- a/packages/react-i18n/package.json +++ b/packages/react-i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/react-i18n", - "version": "3.43.0", + "version": "3.44.0-prerelease", "description": "React bindings for @wordpress/i18n.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/readable-js-assets-webpack-plugin/CHANGELOG.md b/packages/readable-js-assets-webpack-plugin/CHANGELOG.md index 1dcd6ffe2286c..73466451aaad3 100644 --- a/packages/readable-js-assets-webpack-plugin/CHANGELOG.md +++ b/packages/readable-js-assets-webpack-plugin/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.29.0 (2023-11-16) + ## 2.28.0 (2023-11-02) ## 2.27.0 (2023-10-18) diff --git a/packages/readable-js-assets-webpack-plugin/package.json b/packages/readable-js-assets-webpack-plugin/package.json index 34d4acff7dc7e..646b8999d3441 100644 --- a/packages/readable-js-assets-webpack-plugin/package.json +++ b/packages/readable-js-assets-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/readable-js-assets-webpack-plugin", - "version": "2.28.0", + "version": "2.29.0-prerelease", "description": "Generate a readable JS file for each JS asset.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/redux-routine/CHANGELOG.md b/packages/redux-routine/CHANGELOG.md index e7fd714fdf857..0bd8a9e3143f6 100644 --- a/packages/redux-routine/CHANGELOG.md +++ b/packages/redux-routine/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.46.0 (2023-11-16) + ## 4.45.0 (2023-11-02) ## 4.44.0 (2023-10-18) diff --git a/packages/redux-routine/package.json b/packages/redux-routine/package.json index 1929ddaf9e2e7..b6a8fe417da8d 100644 --- a/packages/redux-routine/package.json +++ b/packages/redux-routine/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/redux-routine", - "version": "4.45.0", + "version": "4.46.0-prerelease", "description": "Redux middleware for generator coroutines.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/reusable-blocks/CHANGELOG.md b/packages/reusable-blocks/CHANGELOG.md index c6905ac3ea567..c8208c76e0b74 100644 --- a/packages/reusable-blocks/CHANGELOG.md +++ b/packages/reusable-blocks/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/reusable-blocks/package.json b/packages/reusable-blocks/package.json index ebf4f7f7d9551..8ffdb18e59811 100644 --- a/packages/reusable-blocks/package.json +++ b/packages/reusable-blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/reusable-blocks", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "Reusable blocks utilities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/rich-text/CHANGELOG.md b/packages/rich-text/CHANGELOG.md index 6abaf8c9c50b1..46275b44ca2a9 100644 --- a/packages/rich-text/CHANGELOG.md +++ b/packages/rich-text/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.23.0 (2023-11-16) + ## 6.22.0 (2023-11-02) ## 6.21.0 (2023-10-18) diff --git a/packages/rich-text/package.json b/packages/rich-text/package.json index 4cfa58cbf1e0a..0d805777e2d4f 100644 --- a/packages/rich-text/package.json +++ b/packages/rich-text/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/rich-text", - "version": "6.22.0", + "version": "6.23.0-prerelease", "description": "Rich text value and manipulation API.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/router/CHANGELOG.md b/packages/router/CHANGELOG.md index 3c16003e01231..e2766c9819b3e 100644 --- a/packages/router/CHANGELOG.md +++ b/packages/router/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.15.0 (2023-11-16) + ## 0.14.0 (2023-11-02) ## 0.13.0 (2023-10-18) diff --git a/packages/router/package.json b/packages/router/package.json index ec7f3d68f2375..a27be42a33cd4 100644 --- a/packages/router/package.json +++ b/packages/router/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/router", - "version": "0.14.0", + "version": "0.15.0-prerelease", "description": "Router API for WordPress pages.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index 7bc907d146614..bf48542f5fc01 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 26.17.0 (2023-11-16) + ## 26.16.0 (2023-11-02) ## 26.15.0 (2023-10-18) diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 8cfd0a6e614cd..21194afad7cdd 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/scripts", - "version": "26.16.0", + "version": "26.17.0-prerelease", "description": "Collection of reusable scripts for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/server-side-render/CHANGELOG.md b/packages/server-side-render/CHANGELOG.md index 81dd8ffe39728..739fa28341ef1 100644 --- a/packages/server-side-render/CHANGELOG.md +++ b/packages/server-side-render/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/server-side-render/package.json b/packages/server-side-render/package.json index 647ee48df2438..74d84e29e28ad 100644 --- a/packages/server-side-render/package.json +++ b/packages/server-side-render/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/server-side-render", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "The component used with WordPress to server-side render a preview of dynamic blocks to display in the editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/shortcode/CHANGELOG.md b/packages/shortcode/CHANGELOG.md index b97c6725a71f5..7c2ff99196b59 100644 --- a/packages/shortcode/CHANGELOG.md +++ b/packages/shortcode/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/shortcode/package.json b/packages/shortcode/package.json index 6de5a6d67650a..3a59b60a29918 100644 --- a/packages/shortcode/package.json +++ b/packages/shortcode/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/shortcode", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "Shortcode module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/style-engine/CHANGELOG.md b/packages/style-engine/CHANGELOG.md index 037bd3fd280af..ddb01f0b2fdae 100644 --- a/packages/style-engine/CHANGELOG.md +++ b/packages/style-engine/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.29.0 (2023-11-16) + ## 1.28.0 (2023-11-02) ## 1.27.0 (2023-10-18) diff --git a/packages/style-engine/package.json b/packages/style-engine/package.json index b1bc0e7f4826d..19c15d261898a 100644 --- a/packages/style-engine/package.json +++ b/packages/style-engine/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/style-engine", - "version": "1.28.0", + "version": "1.29.0-prerelease", "description": "A suite of parsers and compilers for WordPress styles.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/stylelint-config/CHANGELOG.md b/packages/stylelint-config/CHANGELOG.md index f8343e6e3a8a6..c7c0ab1a036f4 100644 --- a/packages/stylelint-config/CHANGELOG.md +++ b/packages/stylelint-config/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 21.29.0 (2023-11-16) + ## 21.28.0 (2023-11-02) ## 21.27.0 (2023-10-18) diff --git a/packages/stylelint-config/package.json b/packages/stylelint-config/package.json index e3a5a9527b3e3..f82b2cee23502 100644 --- a/packages/stylelint-config/package.json +++ b/packages/stylelint-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/stylelint-config", - "version": "21.28.0", + "version": "21.29.0-prerelease", "description": "stylelint config for WordPress development.", "author": "The WordPress Contributors", "license": "MIT", diff --git a/packages/sync/CHANGELOG.md b/packages/sync/CHANGELOG.md index dff982dd59a4e..4465921540906 100644 --- a/packages/sync/CHANGELOG.md +++ b/packages/sync/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.8.0 (2023-11-16) + ## 0.7.0 (2023-11-02) ## 0.6.0 (2023-10-18) diff --git a/packages/sync/package.json b/packages/sync/package.json index bf2c2432979a8..cd48de011a183 100644 --- a/packages/sync/package.json +++ b/packages/sync/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/sync", - "version": "0.7.0", + "version": "0.8.0-prerelease", "description": "Sync Data.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/token-list/CHANGELOG.md b/packages/token-list/CHANGELOG.md index 6ef90fbbabd94..920705623ca7b 100644 --- a/packages/token-list/CHANGELOG.md +++ b/packages/token-list/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.46.0 (2023-11-16) + ## 2.45.0 (2023-11-02) ## 2.44.0 (2023-10-18) diff --git a/packages/token-list/package.json b/packages/token-list/package.json index 0c7e4c0cc8a79..cb7f13dceeec6 100644 --- a/packages/token-list/package.json +++ b/packages/token-list/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/token-list", - "version": "2.45.0", + "version": "2.46.0-prerelease", "description": "Constructable, plain JavaScript DOMTokenList implementation, supporting non-browser runtimes.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/undo-manager/CHANGELOG.md b/packages/undo-manager/CHANGELOG.md index 67cc197b926e1..9c7fc9d98f62c 100644 --- a/packages/undo-manager/CHANGELOG.md +++ b/packages/undo-manager/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.6.0 (2023-11-16) + ## 0.5.0 (2023-11-02) ## 0.4.0 (2023-10-18) diff --git a/packages/undo-manager/package.json b/packages/undo-manager/package.json index 212338276f4a1..f8b8401774dbf 100644 --- a/packages/undo-manager/package.json +++ b/packages/undo-manager/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/undo-manager", - "version": "0.5.0", + "version": "0.6.0-prerelease", "description": "A small package to manage undo/redo.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/url/CHANGELOG.md b/packages/url/CHANGELOG.md index e42e0e039647c..66632d73e945d 100644 --- a/packages/url/CHANGELOG.md +++ b/packages/url/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.47.0 (2023-11-16) + ## 3.46.0 (2023-11-02) ## 3.45.0 (2023-10-18) diff --git a/packages/url/package.json b/packages/url/package.json index 2d248f25ab804..af28dea0b4444 100644 --- a/packages/url/package.json +++ b/packages/url/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/url", - "version": "3.46.0", + "version": "3.47.0-prerelease", "description": "WordPress URL utilities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/viewport/CHANGELOG.md b/packages/viewport/CHANGELOG.md index fccff86661489..02c093f466c67 100644 --- a/packages/viewport/CHANGELOG.md +++ b/packages/viewport/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.23.0 (2023-11-16) + ## 5.22.0 (2023-11-02) ## 5.21.0 (2023-10-18) diff --git a/packages/viewport/package.json b/packages/viewport/package.json index e08791592ef65..0809dee6f1d9a 100644 --- a/packages/viewport/package.json +++ b/packages/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/viewport", - "version": "5.22.0", + "version": "5.23.0-prerelease", "description": "Viewport module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/warning/CHANGELOG.md b/packages/warning/CHANGELOG.md index dc65344a4af5c..68504579d3188 100644 --- a/packages/warning/CHANGELOG.md +++ b/packages/warning/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.46.0 (2023-11-16) + ## 2.45.0 (2023-11-02) ## 2.44.0 (2023-10-18) diff --git a/packages/warning/package.json b/packages/warning/package.json index 69f21eb47967e..899d36d9cafc0 100644 --- a/packages/warning/package.json +++ b/packages/warning/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/warning", - "version": "2.45.0", + "version": "2.46.0-prerelease", "description": "Warning utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/widgets/CHANGELOG.md b/packages/widgets/CHANGELOG.md index 8c1952f566939..97fd6909b10ad 100644 --- a/packages/widgets/CHANGELOG.md +++ b/packages/widgets/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.23.0 (2023-11-16) + ## 3.22.0 (2023-11-02) ## 3.21.0 (2023-10-18) diff --git a/packages/widgets/package.json b/packages/widgets/package.json index afdd9bb5e4fac..06e7e9a788f20 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/widgets", - "version": "3.22.0", + "version": "3.23.0-prerelease", "description": "Functionality used by the widgets block editor in the Widgets screen and the Customizer.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/wordcount/CHANGELOG.md b/packages/wordcount/CHANGELOG.md index 99501b5aec432..7b2a56464d083 100644 --- a/packages/wordcount/CHANGELOG.md +++ b/packages/wordcount/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/wordcount/package.json b/packages/wordcount/package.json index e87b45e895f3c..504e5c0b84bfc 100644 --- a/packages/wordcount/package.json +++ b/packages/wordcount/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/wordcount", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "WordPress word count utility.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", From ca5c86db2fb2a2ff63d20c409ad709969bb7fd2e Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Thu, 16 Nov 2023 19:37:35 +0000 Subject: [PATCH 058/116] chore(release): publish - @wordpress/a11y@3.46.0 - @wordpress/annotations@2.46.0 - @wordpress/api-fetch@6.43.0 - @wordpress/autop@3.46.0 - @wordpress/babel-plugin-import-jsx-pragma@4.29.0 - @wordpress/babel-plugin-makepot@5.30.0 - @wordpress/babel-preset-default@7.30.0 - @wordpress/base-styles@4.37.0 - @wordpress/blob@3.46.0 - @wordpress/block-directory@4.23.0 - @wordpress/block-editor@12.14.0 - @wordpress/block-library@8.23.0 - @wordpress/block-serialization-default-parser@4.46.0 - @wordpress/block-serialization-spec-parser@4.46.0 - @wordpress/blocks@12.23.0 - @wordpress/browserslist-config@5.29.0 - @wordpress/commands@0.17.0 - @wordpress/components@25.12.0 - @wordpress/compose@6.23.0 - @wordpress/core-commands@0.15.0 - @wordpress/core-data@6.23.0 - @wordpress/create-block@4.30.0 - @wordpress/create-block-interactive-template@1.9.0 - @wordpress/create-block-tutorial-template@3.0.0 - @wordpress/customize-widgets@4.23.0 - @wordpress/data@9.16.0 - @wordpress/data-controls@3.15.0 - @wordpress/date@4.46.0 - @wordpress/dependency-extraction-webpack-plugin@4.29.0 - @wordpress/deprecated@3.46.0 - @wordpress/docgen@1.55.0 - @wordpress/dom@3.46.0 - @wordpress/dom-ready@3.46.0 - @wordpress/e2e-test-utils@10.17.0 - @wordpress/e2e-test-utils-playwright@0.14.0 - @wordpress/e2e-tests@7.17.0 - @wordpress/edit-post@7.23.0 - @wordpress/edit-site@5.23.0 - @wordpress/edit-widgets@5.23.0 - @wordpress/editor@13.23.0 - @wordpress/element@5.23.0 - @wordpress/env@8.12.0 - @wordpress/escape-html@2.46.0 - @wordpress/eslint-plugin@17.3.0 - @wordpress/format-library@4.23.0 - @wordpress/hooks@3.46.0 - @wordpress/html-entities@3.46.0 - @wordpress/i18n@4.46.0 - @wordpress/icons@9.37.0 - @wordpress/interactivity@2.7.0 - @wordpress/interface@5.23.0 - @wordpress/is-shallow-equal@4.46.0 - @wordpress/jest-console@7.17.0 - @wordpress/jest-preset-default@11.17.0 - @wordpress/jest-puppeteer-axe@6.17.0 - @wordpress/keyboard-shortcuts@4.23.0 - @wordpress/keycodes@3.46.0 - @wordpress/lazy-import@1.33.0 - @wordpress/list-reusable-blocks@4.23.0 - @wordpress/media-utils@4.37.0 - @wordpress/notices@4.14.0 - @wordpress/npm-package-json-lint-config@4.31.0 - @wordpress/nux@8.8.0 - @wordpress/patterns@1.7.0 - @wordpress/plugins@6.14.0 - @wordpress/postcss-plugins-preset@4.30.0 - @wordpress/postcss-themes@5.29.0 - @wordpress/preferences@3.23.0 - @wordpress/preferences-persistence@1.38.0 - @wordpress/prettier-config@3.3.0 - @wordpress/primitives@3.44.0 - @wordpress/priority-queue@2.46.0 - @wordpress/private-apis@0.28.0 - @wordpress/project-management-automation@1.45.0 - @wordpress/react-i18n@3.44.0 - @wordpress/readable-js-assets-webpack-plugin@2.29.0 - @wordpress/redux-routine@4.46.0 - @wordpress/reusable-blocks@4.23.0 - @wordpress/rich-text@6.23.0 - @wordpress/router@0.15.0 - @wordpress/scripts@26.17.0 - @wordpress/server-side-render@4.23.0 - @wordpress/shortcode@3.46.0 - @wordpress/style-engine@1.29.0 - @wordpress/stylelint-config@21.29.0 - @wordpress/sync@0.8.0 - @wordpress/token-list@2.46.0 - @wordpress/undo-manager@0.6.0 - @wordpress/url@3.47.0 - @wordpress/viewport@5.23.0 - @wordpress/warning@2.46.0 - @wordpress/widgets@3.23.0 - @wordpress/wordcount@3.46.0 --- package-lock.json | 184 +++++++++--------- packages/a11y/package.json | 2 +- packages/annotations/package.json | 2 +- packages/api-fetch/package.json | 2 +- packages/autop/package.json | 2 +- .../package.json | 2 +- packages/babel-plugin-makepot/package.json | 2 +- packages/babel-preset-default/package.json | 2 +- packages/base-styles/package.json | 2 +- packages/blob/package.json | 2 +- packages/block-directory/package.json | 2 +- packages/block-editor/package.json | 2 +- packages/block-library/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- packages/blocks/package.json | 2 +- packages/browserslist-config/package.json | 2 +- packages/commands/package.json | 2 +- packages/components/package.json | 2 +- packages/compose/package.json | 2 +- packages/core-commands/package.json | 2 +- packages/core-data/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- packages/create-block/package.json | 2 +- packages/customize-widgets/package.json | 2 +- packages/data-controls/package.json | 2 +- packages/data/package.json | 2 +- packages/date/package.json | 2 +- .../package.json | 2 +- packages/deprecated/package.json | 2 +- packages/docgen/package.json | 2 +- packages/dom-ready/package.json | 2 +- packages/dom/package.json | 2 +- .../e2e-test-utils-playwright/package.json | 2 +- packages/e2e-test-utils/package.json | 2 +- packages/e2e-tests/package.json | 2 +- packages/edit-post/package.json | 2 +- packages/edit-site/package.json | 2 +- packages/edit-widgets/package.json | 2 +- packages/editor/package.json | 2 +- packages/element/package.json | 2 +- packages/env/package.json | 2 +- packages/escape-html/package.json | 2 +- packages/eslint-plugin/package.json | 2 +- packages/format-library/package.json | 2 +- packages/hooks/package.json | 2 +- packages/html-entities/package.json | 2 +- packages/i18n/package.json | 2 +- packages/icons/package.json | 2 +- packages/interactivity/package.json | 2 +- packages/interface/package.json | 2 +- packages/is-shallow-equal/package.json | 2 +- packages/jest-console/package.json | 2 +- packages/jest-preset-default/package.json | 2 +- packages/jest-puppeteer-axe/package.json | 2 +- packages/keyboard-shortcuts/package.json | 2 +- packages/keycodes/package.json | 2 +- packages/lazy-import/package.json | 2 +- packages/list-reusable-blocks/package.json | 2 +- packages/media-utils/package.json | 2 +- packages/notices/package.json | 2 +- .../npm-package-json-lint-config/package.json | 2 +- packages/nux/package.json | 2 +- packages/patterns/package.json | 2 +- packages/plugins/package.json | 2 +- packages/postcss-plugins-preset/package.json | 2 +- packages/postcss-themes/package.json | 2 +- packages/preferences-persistence/package.json | 2 +- packages/preferences/package.json | 2 +- packages/prettier-config/package.json | 2 +- packages/primitives/package.json | 2 +- packages/priority-queue/package.json | 2 +- packages/private-apis/package.json | 2 +- .../package.json | 2 +- packages/react-i18n/package.json | 2 +- .../package.json | 2 +- packages/redux-routine/package.json | 2 +- packages/reusable-blocks/package.json | 2 +- packages/rich-text/package.json | 2 +- packages/router/package.json | 2 +- packages/scripts/package.json | 2 +- packages/server-side-render/package.json | 2 +- packages/shortcode/package.json | 2 +- packages/style-engine/package.json | 2 +- packages/stylelint-config/package.json | 2 +- packages/sync/package.json | 2 +- packages/token-list/package.json | 2 +- packages/undo-manager/package.json | 2 +- packages/url/package.json | 2 +- packages/viewport/package.json | 2 +- packages/warning/package.json | 2 +- packages/widgets/package.json | 2 +- packages/wordcount/package.json | 2 +- 94 files changed, 185 insertions(+), 185 deletions(-) diff --git a/package-lock.json b/package-lock.json index 158d3ab9e25c1..8382dd2413d46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54404,7 +54404,7 @@ }, "packages/a11y": { "name": "@wordpress/a11y", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54417,7 +54417,7 @@ }, "packages/annotations": { "name": "@wordpress/annotations", - "version": "2.45.0", + "version": "2.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54445,7 +54445,7 @@ }, "packages/api-fetch": { "name": "@wordpress/api-fetch", - "version": "6.42.0", + "version": "6.43.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54458,7 +54458,7 @@ }, "packages/autop": { "name": "@wordpress/autop", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -54469,7 +54469,7 @@ }, "packages/babel-plugin-import-jsx-pragma": { "name": "@wordpress/babel-plugin-import-jsx-pragma", - "version": "4.28.0", + "version": "4.29.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -54481,7 +54481,7 @@ }, "packages/babel-plugin-makepot": { "name": "@wordpress/babel-plugin-makepot", - "version": "5.29.0", + "version": "5.30.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -54498,7 +54498,7 @@ }, "packages/babel-preset-default": { "name": "@wordpress/babel-preset-default", - "version": "7.29.0", + "version": "7.30.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -54521,13 +54521,13 @@ }, "packages/base-styles": { "name": "@wordpress/base-styles", - "version": "4.36.0", + "version": "4.37.0", "dev": true, "license": "GPL-2.0-or-later" }, "packages/blob": { "name": "@wordpress/blob", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -54538,7 +54538,7 @@ }, "packages/block-directory": { "name": "@wordpress/block-directory", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54573,7 +54573,7 @@ }, "packages/block-editor": { "name": "@wordpress/block-editor", - "version": "12.13.0", + "version": "12.14.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54670,7 +54670,7 @@ }, "packages/block-library": { "name": "@wordpress/block-library", - "version": "8.22.0", + "version": "8.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54732,7 +54732,7 @@ }, "packages/block-serialization-default-parser": { "name": "@wordpress/block-serialization-default-parser", - "version": "4.45.0", + "version": "4.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -54743,7 +54743,7 @@ }, "packages/block-serialization-spec-parser": { "name": "@wordpress/block-serialization-spec-parser", - "version": "4.45.0", + "version": "4.46.0", "license": "GPL-2.0-or-later", "dependencies": { "pegjs": "^0.10.0", @@ -54755,7 +54755,7 @@ }, "packages/blocks": { "name": "@wordpress/blocks", - "version": "12.22.0", + "version": "12.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54803,7 +54803,7 @@ }, "packages/browserslist-config": { "name": "@wordpress/browserslist-config", - "version": "5.28.0", + "version": "5.29.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -54812,7 +54812,7 @@ }, "packages/commands": { "name": "@wordpress/commands", - "version": "0.16.0", + "version": "0.17.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54837,7 +54837,7 @@ }, "packages/components": { "name": "@wordpress/components", - "version": "25.11.0", + "version": "25.12.0", "license": "GPL-2.0-or-later", "dependencies": { "@ariakit/react": "^0.3.5", @@ -54943,7 +54943,7 @@ }, "packages/compose": { "name": "@wordpress/compose", - "version": "6.22.0", + "version": "6.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54969,7 +54969,7 @@ }, "packages/core-commands": { "name": "@wordpress/core-commands", - "version": "0.14.0", + "version": "0.15.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54994,7 +54994,7 @@ }, "packages/core-data": { "name": "@wordpress/core-data", - "version": "6.22.0", + "version": "6.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55038,7 +55038,7 @@ }, "packages/create-block": { "name": "@wordpress/create-block", - "version": "4.29.0", + "version": "4.30.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55066,13 +55066,13 @@ }, "packages/create-block-tutorial-template": { "name": "@wordpress/create-block-tutorial-template", - "version": "2.33.0", + "version": "3.0.0", "dev": true, "license": "GPL-2.0-or-later" }, "packages/customize-widgets": { "name": "@wordpress/customize-widgets", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55109,7 +55109,7 @@ }, "packages/data": { "name": "@wordpress/data", - "version": "9.15.0", + "version": "9.16.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55137,7 +55137,7 @@ }, "packages/data-controls": { "name": "@wordpress/data-controls", - "version": "3.14.0", + "version": "3.15.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55154,7 +55154,7 @@ }, "packages/date": { "name": "@wordpress/date", - "version": "4.45.0", + "version": "4.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55168,7 +55168,7 @@ }, "packages/dependency-extraction-webpack-plugin": { "name": "@wordpress/dependency-extraction-webpack-plugin", - "version": "4.28.0", + "version": "4.29.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55184,7 +55184,7 @@ }, "packages/deprecated": { "name": "@wordpress/deprecated", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55196,7 +55196,7 @@ }, "packages/docgen": { "name": "@wordpress/docgen", - "version": "1.54.0", + "version": "1.55.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55214,7 +55214,7 @@ }, "packages/dom": { "name": "@wordpress/dom", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55226,7 +55226,7 @@ }, "packages/dom-ready": { "name": "@wordpress/dom-ready", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -55237,7 +55237,7 @@ }, "packages/e2e-test-utils": { "name": "@wordpress/e2e-test-utils", - "version": "10.16.0", + "version": "10.17.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55259,7 +55259,7 @@ }, "packages/e2e-test-utils-playwright": { "name": "@wordpress/e2e-test-utils-playwright", - "version": "0.13.0", + "version": "0.14.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55282,7 +55282,7 @@ }, "packages/e2e-tests": { "name": "@wordpress/e2e-tests", - "version": "7.16.0", + "version": "7.17.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55320,7 +55320,7 @@ }, "packages/edit-post": { "name": "@wordpress/edit-post", - "version": "7.22.0", + "version": "7.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55368,7 +55368,7 @@ }, "packages/edit-site": { "name": "@wordpress/edit-site", - "version": "5.22.0", + "version": "5.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55433,7 +55433,7 @@ }, "packages/edit-widgets": { "name": "@wordpress/edit-widgets", - "version": "5.22.0", + "version": "5.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55475,7 +55475,7 @@ }, "packages/editor": { "name": "@wordpress/editor", - "version": "13.22.0", + "version": "13.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55525,7 +55525,7 @@ }, "packages/element": { "name": "@wordpress/element", - "version": "5.22.0", + "version": "5.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55543,7 +55543,7 @@ }, "packages/env": { "name": "@wordpress/env", - "version": "8.11.0", + "version": "8.12.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55656,7 +55656,7 @@ }, "packages/escape-html": { "name": "@wordpress/escape-html", - "version": "2.45.0", + "version": "2.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -55667,7 +55667,7 @@ }, "packages/eslint-plugin": { "name": "@wordpress/eslint-plugin", - "version": "17.2.0", + "version": "17.3.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55710,7 +55710,7 @@ }, "packages/format-library": { "name": "@wordpress/format-library", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55736,7 +55736,7 @@ }, "packages/hooks": { "name": "@wordpress/hooks", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -55747,7 +55747,7 @@ }, "packages/html-entities": { "name": "@wordpress/html-entities", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -55758,7 +55758,7 @@ }, "packages/i18n": { "name": "@wordpress/i18n", - "version": "4.45.0", + "version": "4.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55777,7 +55777,7 @@ }, "packages/icons": { "name": "@wordpress/icons", - "version": "9.36.0", + "version": "9.37.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55790,7 +55790,7 @@ }, "packages/interactivity": { "name": "@wordpress/interactivity", - "version": "2.6.0", + "version": "2.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@preact/signals": "^1.1.3", @@ -55803,7 +55803,7 @@ }, "packages/interface": { "name": "@wordpress/interface", - "version": "5.22.0", + "version": "5.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55830,7 +55830,7 @@ }, "packages/is-shallow-equal": { "name": "@wordpress/is-shallow-equal", - "version": "4.45.0", + "version": "4.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -55841,7 +55841,7 @@ }, "packages/jest-console": { "name": "@wordpress/jest-console", - "version": "7.16.0", + "version": "7.17.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55857,7 +55857,7 @@ }, "packages/jest-preset-default": { "name": "@wordpress/jest-preset-default", - "version": "11.16.0", + "version": "11.17.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55874,7 +55874,7 @@ }, "packages/jest-puppeteer-axe": { "name": "@wordpress/jest-puppeteer-axe", - "version": "6.16.0", + "version": "6.17.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55896,7 +55896,7 @@ }, "packages/keyboard-shortcuts": { "name": "@wordpress/keyboard-shortcuts", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55914,7 +55914,7 @@ }, "packages/keycodes": { "name": "@wordpress/keycodes", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55927,7 +55927,7 @@ }, "packages/lazy-import": { "name": "@wordpress/lazy-import", - "version": "1.32.0", + "version": "1.33.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55941,7 +55941,7 @@ }, "packages/list-reusable-blocks": { "name": "@wordpress/list-reusable-blocks", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55963,7 +55963,7 @@ }, "packages/media-utils": { "name": "@wordpress/media-utils", - "version": "4.36.0", + "version": "4.37.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55978,7 +55978,7 @@ }, "packages/notices": { "name": "@wordpress/notices", - "version": "4.13.0", + "version": "4.14.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55994,7 +55994,7 @@ }, "packages/npm-package-json-lint-config": { "name": "@wordpress/npm-package-json-lint-config", - "version": "4.30.0", + "version": "4.31.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -56006,7 +56006,7 @@ }, "packages/nux": { "name": "@wordpress/nux", - "version": "8.7.0", + "version": "8.8.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56029,7 +56029,7 @@ }, "packages/patterns": { "name": "@wordpress/patterns", - "version": "1.6.0", + "version": "1.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56058,7 +56058,7 @@ }, "packages/plugins": { "name": "@wordpress/plugins", - "version": "6.13.0", + "version": "6.14.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56080,7 +56080,7 @@ }, "packages/postcss-plugins-preset": { "name": "@wordpress/postcss-plugins-preset", - "version": "4.29.0", + "version": "4.30.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -56096,7 +56096,7 @@ }, "packages/postcss-themes": { "name": "@wordpress/postcss-themes", - "version": "5.28.0", + "version": "5.29.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -56108,7 +56108,7 @@ }, "packages/preferences": { "name": "@wordpress/preferences", - "version": "3.22.0", + "version": "3.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56130,7 +56130,7 @@ }, "packages/preferences-persistence": { "name": "@wordpress/preferences-persistence", - "version": "1.37.0", + "version": "1.38.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56142,7 +56142,7 @@ }, "packages/prettier-config": { "name": "@wordpress/prettier-config", - "version": "3.2.0", + "version": "3.3.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -56154,7 +56154,7 @@ }, "packages/primitives": { "name": "@wordpress/primitives", - "version": "3.43.0", + "version": "3.44.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56167,7 +56167,7 @@ }, "packages/priority-queue": { "name": "@wordpress/priority-queue", - "version": "2.45.0", + "version": "2.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56179,7 +56179,7 @@ }, "packages/private-apis": { "name": "@wordpress/private-apis", - "version": "0.27.0", + "version": "0.28.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -56190,7 +56190,7 @@ }, "packages/project-management-automation": { "name": "@wordpress/project-management-automation", - "version": "1.44.0", + "version": "1.45.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -56203,7 +56203,7 @@ }, "packages/react-i18n": { "name": "@wordpress/react-i18n", - "version": "3.43.0", + "version": "3.44.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56351,7 +56351,7 @@ }, "packages/readable-js-assets-webpack-plugin": { "name": "@wordpress/readable-js-assets-webpack-plugin", - "version": "2.28.0", + "version": "2.29.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -56363,7 +56363,7 @@ }, "packages/redux-routine": { "name": "@wordpress/redux-routine", - "version": "4.45.0", + "version": "4.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56407,7 +56407,7 @@ }, "packages/reusable-blocks": { "name": "@wordpress/reusable-blocks", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56433,7 +56433,7 @@ }, "packages/rich-text": { "name": "@wordpress/rich-text", - "version": "6.22.0", + "version": "6.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56457,7 +56457,7 @@ }, "packages/router": { "name": "@wordpress/router", - "version": "0.14.0", + "version": "0.15.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56475,7 +56475,7 @@ }, "packages/scripts": { "name": "@wordpress/scripts", - "version": "26.16.0", + "version": "26.17.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -56565,7 +56565,7 @@ }, "packages/server-side-render": { "name": "@wordpress/server-side-render", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56590,7 +56590,7 @@ }, "packages/shortcode": { "name": "@wordpress/shortcode", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56602,7 +56602,7 @@ }, "packages/style-engine": { "name": "@wordpress/style-engine", - "version": "1.28.0", + "version": "1.29.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56614,7 +56614,7 @@ }, "packages/stylelint-config": { "name": "@wordpress/stylelint-config", - "version": "21.28.0", + "version": "21.29.0", "dev": true, "license": "MIT", "dependencies": { @@ -56630,7 +56630,7 @@ }, "packages/sync": { "name": "@wordpress/sync", - "version": "0.7.0", + "version": "0.8.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56650,7 +56650,7 @@ }, "packages/token-list": { "name": "@wordpress/token-list", - "version": "2.45.0", + "version": "2.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -56661,7 +56661,7 @@ }, "packages/undo-manager": { "name": "@wordpress/undo-manager", - "version": "0.5.0", + "version": "0.6.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56673,7 +56673,7 @@ }, "packages/url": { "name": "@wordpress/url", - "version": "3.46.0", + "version": "3.47.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56685,7 +56685,7 @@ }, "packages/viewport": { "name": "@wordpress/viewport", - "version": "5.22.0", + "version": "5.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56702,7 +56702,7 @@ }, "packages/warning": { "name": "@wordpress/warning", - "version": "2.45.0", + "version": "2.46.0", "license": "GPL-2.0-or-later", "engines": { "node": ">=12" @@ -56710,7 +56710,7 @@ }, "packages/widgets": { "name": "@wordpress/widgets", - "version": "3.22.0", + "version": "3.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56734,7 +56734,7 @@ }, "packages/wordcount": { "name": "@wordpress/wordcount", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" diff --git a/packages/a11y/package.json b/packages/a11y/package.json index 60bd6f5e7fbf1..10964d4f47800 100644 --- a/packages/a11y/package.json +++ b/packages/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/a11y", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "Accessibility (a11y) utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/annotations/package.json b/packages/annotations/package.json index a8aee11f46fab..653414da29014 100644 --- a/packages/annotations/package.json +++ b/packages/annotations/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/annotations", - "version": "2.46.0-prerelease", + "version": "2.46.0", "description": "Annotate content in the Gutenberg editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/api-fetch/package.json b/packages/api-fetch/package.json index cb5a477a706fe..c572e343edab8 100644 --- a/packages/api-fetch/package.json +++ b/packages/api-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/api-fetch", - "version": "6.43.0-prerelease", + "version": "6.43.0", "description": "Utility to make WordPress REST API requests.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/autop/package.json b/packages/autop/package.json index d6231e72dcd9d..d444d2d5a4779 100644 --- a/packages/autop/package.json +++ b/packages/autop/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/autop", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "WordPress's automatic paragraph functions `autop` and `removep`.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-import-jsx-pragma/package.json b/packages/babel-plugin-import-jsx-pragma/package.json index 4e5fe879f8499..a49af835b912f 100644 --- a/packages/babel-plugin-import-jsx-pragma/package.json +++ b/packages/babel-plugin-import-jsx-pragma/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-import-jsx-pragma", - "version": "4.29.0-prerelease", + "version": "4.29.0", "description": "Babel transform plugin for automatically injecting an import to be used as the pragma for the React JSX Transform plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-makepot/package.json b/packages/babel-plugin-makepot/package.json index c70ebc7008591..298a05f3f4425 100644 --- a/packages/babel-plugin-makepot/package.json +++ b/packages/babel-plugin-makepot/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-makepot", - "version": "5.30.0-prerelease", + "version": "5.30.0", "description": "WordPress Babel internationalization (i18n) plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-preset-default/package.json b/packages/babel-preset-default/package.json index fc8de1a030c61..d53a260359323 100644 --- a/packages/babel-preset-default/package.json +++ b/packages/babel-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-preset-default", - "version": "7.30.0-prerelease", + "version": "7.30.0", "description": "Default Babel preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/base-styles/package.json b/packages/base-styles/package.json index d747036f1bebd..8af7e6b7e3db1 100644 --- a/packages/base-styles/package.json +++ b/packages/base-styles/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/base-styles", - "version": "4.37.0-prerelease", + "version": "4.37.0", "description": "Base SCSS utilities and variables for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blob/package.json b/packages/blob/package.json index 8779cf3619947..ba0a355e19a47 100644 --- a/packages/blob/package.json +++ b/packages/blob/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blob", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "Blob utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-directory/package.json b/packages/block-directory/package.json index 86f94996843ea..438b0680db283 100644 --- a/packages/block-directory/package.json +++ b/packages/block-directory/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-directory", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "Extend editor with block directory features to search, download and install blocks.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index baf9929585751..a80fd2f9bca96 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-editor", - "version": "12.14.0-prerelease", + "version": "12.14.0", "description": "Generic block editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-library/package.json b/packages/block-library/package.json index 5e2e0e40cfc7b..558566bccaae0 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-library", - "version": "8.23.0-prerelease", + "version": "8.23.0", "description": "Block library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-serialization-default-parser/package.json b/packages/block-serialization-default-parser/package.json index 3c0b3e5b8f698..93fcef93acdd9 100644 --- a/packages/block-serialization-default-parser/package.json +++ b/packages/block-serialization-default-parser/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-serialization-default-parser", - "version": "4.46.0-prerelease", + "version": "4.46.0", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-serialization-spec-parser/package.json b/packages/block-serialization-spec-parser/package.json index 429caf6f66bf5..d5818b926323b 100644 --- a/packages/block-serialization-spec-parser/package.json +++ b/packages/block-serialization-spec-parser/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-serialization-spec-parser", - "version": "4.46.0-prerelease", + "version": "4.46.0", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blocks/package.json b/packages/blocks/package.json index e88532e850146..abfed4b763e7e 100644 --- a/packages/blocks/package.json +++ b/packages/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blocks", - "version": "12.23.0-prerelease", + "version": "12.23.0", "description": "Block API for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/browserslist-config/package.json b/packages/browserslist-config/package.json index 69b1f02f9eb08..315594a8bda1b 100644 --- a/packages/browserslist-config/package.json +++ b/packages/browserslist-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/browserslist-config", - "version": "5.29.0-prerelease", + "version": "5.29.0", "description": "WordPress Browserslist shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/commands/package.json b/packages/commands/package.json index bb74b5c238fd5..3d18b9f47a7ed 100644 --- a/packages/commands/package.json +++ b/packages/commands/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/commands", - "version": "0.17.0-prerelease", + "version": "0.17.0", "description": "Handles the commands menu.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/components/package.json b/packages/components/package.json index 1eaf7e27ed3a6..7e8c237b70024 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/components", - "version": "25.12.0-prerelease", + "version": "25.12.0", "description": "UI components for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/compose/package.json b/packages/compose/package.json index b55a73f976e29..24576ec7f2b50 100644 --- a/packages/compose/package.json +++ b/packages/compose/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/compose", - "version": "6.23.0-prerelease", + "version": "6.23.0", "description": "WordPress higher-order components (HOCs).", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/core-commands/package.json b/packages/core-commands/package.json index b91feb0ecb4f7..c46789e5fc698 100644 --- a/packages/core-commands/package.json +++ b/packages/core-commands/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-commands", - "version": "0.15.0-prerelease", + "version": "0.15.0", "description": "WordPress core reusable commands.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/core-data/package.json b/packages/core-data/package.json index ef10939249150..0d8fa19ec6be9 100644 --- a/packages/core-data/package.json +++ b/packages/core-data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-data", - "version": "6.23.0-prerelease", + "version": "6.23.0", "description": "Access to and manipulation of core WordPress entities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block-interactive-template/package.json b/packages/create-block-interactive-template/package.json index ab2053e4dc860..fa196823e5ad6 100644 --- a/packages/create-block-interactive-template/package.json +++ b/packages/create-block-interactive-template/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block-interactive-template", - "version": "1.9.0-prerelease", + "version": "1.9.0", "description": "Template for @wordpress/create-block to create interactive blocks with the Interactivity API.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block-tutorial-template/package.json b/packages/create-block-tutorial-template/package.json index a1a733b3e8a57..c180069b8263e 100644 --- a/packages/create-block-tutorial-template/package.json +++ b/packages/create-block-tutorial-template/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block-tutorial-template", - "version": "3.0.0-prerelease", + "version": "3.0.0", "description": "This is a template for @wordpress/create-block that creates an example 'Copyright Date' block. This block is used in the official WordPress block development Quick Start Guide.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block/package.json b/packages/create-block/package.json index 2ed37c112c7a1..94249456e48c9 100644 --- a/packages/create-block/package.json +++ b/packages/create-block/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block", - "version": "4.30.0-prerelease", + "version": "4.30.0", "description": "Generates PHP, JS and CSS code for registering a block for a WordPress plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/customize-widgets/package.json b/packages/customize-widgets/package.json index 2384f06a1253c..be21e250b7f06 100644 --- a/packages/customize-widgets/package.json +++ b/packages/customize-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/customize-widgets", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "Widgets blocks in Customizer Module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data-controls/package.json b/packages/data-controls/package.json index b86b70577e7e4..919e3479f326e 100644 --- a/packages/data-controls/package.json +++ b/packages/data-controls/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data-controls", - "version": "3.15.0-prerelease", + "version": "3.15.0", "description": "A set of common controls for the @wordpress/data api.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data/package.json b/packages/data/package.json index 2698c27f0091a..ebfccdc75819f 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data", - "version": "9.16.0-prerelease", + "version": "9.16.0", "description": "Data module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/date/package.json b/packages/date/package.json index 3d85c7f446d62..092eb7a1f234f 100644 --- a/packages/date/package.json +++ b/packages/date/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/date", - "version": "4.46.0-prerelease", + "version": "4.46.0", "description": "Date module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dependency-extraction-webpack-plugin/package.json b/packages/dependency-extraction-webpack-plugin/package.json index b1370b1c359af..87267a8a593ad 100644 --- a/packages/dependency-extraction-webpack-plugin/package.json +++ b/packages/dependency-extraction-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dependency-extraction-webpack-plugin", - "version": "4.29.0-prerelease", + "version": "4.29.0", "description": "Extract WordPress script dependencies from webpack bundles.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/deprecated/package.json b/packages/deprecated/package.json index e596db980e8ec..f0a823074c047 100644 --- a/packages/deprecated/package.json +++ b/packages/deprecated/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/deprecated", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "Deprecation utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/docgen/package.json b/packages/docgen/package.json index ec282a093f1d8..87d92d25e8053 100644 --- a/packages/docgen/package.json +++ b/packages/docgen/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/docgen", - "version": "1.55.0-prerelease", + "version": "1.55.0", "description": "Autogenerate public API documentation from exports and JSDoc comments.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dom-ready/package.json b/packages/dom-ready/package.json index 763f21e317236..542be436e09c6 100644 --- a/packages/dom-ready/package.json +++ b/packages/dom-ready/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom-ready", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "Execute callback after the DOM is loaded.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dom/package.json b/packages/dom/package.json index f80a508f23b25..263ee6d5a04ae 100644 --- a/packages/dom/package.json +++ b/packages/dom/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "DOM utilities module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-test-utils-playwright/package.json b/packages/e2e-test-utils-playwright/package.json index 553ad9ad15834..9c7401c5346f1 100644 --- a/packages/e2e-test-utils-playwright/package.json +++ b/packages/e2e-test-utils-playwright/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-test-utils-playwright", - "version": "0.14.0-prerelease", + "version": "0.14.0", "description": "End-To-End (E2E) test utils for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-test-utils/package.json b/packages/e2e-test-utils/package.json index 58506c9686d60..8fad38623a685 100644 --- a/packages/e2e-test-utils/package.json +++ b/packages/e2e-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-test-utils", - "version": "10.17.0-prerelease", + "version": "10.17.0", "description": "End-To-End (E2E) test utils for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index 6c444d161f65f..f3cabf4d6a2c9 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-tests", - "version": "7.17.0-prerelease", + "version": "7.17.0", "description": "End-To-End (E2E) tests for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-post/package.json b/packages/edit-post/package.json index d0a8c78ca436b..31c5c209fa96c 100644 --- a/packages/edit-post/package.json +++ b/packages/edit-post/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-post", - "version": "7.23.0-prerelease", + "version": "7.23.0", "description": "Edit Post module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index bea0abb0ef0c8..072dc0b1c027a 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-site", - "version": "5.23.0-prerelease", + "version": "5.23.0", "description": "Edit Site Page module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-widgets/package.json b/packages/edit-widgets/package.json index 1e68aecf8321f..33c7f9d75dd61 100644 --- a/packages/edit-widgets/package.json +++ b/packages/edit-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-widgets", - "version": "5.23.0-prerelease", + "version": "5.23.0", "description": "Widgets Page module for WordPress..", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/editor/package.json b/packages/editor/package.json index d9d0afcdf1656..5a4bf3ba7bf21 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/editor", - "version": "13.23.0-prerelease", + "version": "13.23.0", "description": "Enhanced block editor for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/element/package.json b/packages/element/package.json index fa6b5e1ab5ce7..b8753b952909b 100644 --- a/packages/element/package.json +++ b/packages/element/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/element", - "version": "5.23.0-prerelease", + "version": "5.23.0", "description": "Element React module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/env/package.json b/packages/env/package.json index 7e2cee5596a2b..28373f4f391b6 100644 --- a/packages/env/package.json +++ b/packages/env/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/env", - "version": "8.12.0-prerelease", + "version": "8.12.0", "description": "A zero-config, self contained local WordPress environment for development and testing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/escape-html/package.json b/packages/escape-html/package.json index 742813826477e..e45800c248dfc 100644 --- a/packages/escape-html/package.json +++ b/packages/escape-html/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/escape-html", - "version": "2.46.0-prerelease", + "version": "2.46.0", "description": "Escape HTML utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index e1fb50b541425..f3009f7a584f6 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/eslint-plugin", - "version": "17.3.0-prerelease", + "version": "17.3.0", "description": "ESLint plugin for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/format-library/package.json b/packages/format-library/package.json index 687be3963fb43..f7b9dc90224e6 100644 --- a/packages/format-library/package.json +++ b/packages/format-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/format-library", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "Format library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/hooks/package.json b/packages/hooks/package.json index 4595c47aa29a3..6b9a3fccd3c7a 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/hooks", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "WordPress hooks library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/html-entities/package.json b/packages/html-entities/package.json index 9d72d46f7a5ff..8d30d7c48173c 100644 --- a/packages/html-entities/package.json +++ b/packages/html-entities/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/html-entities", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "HTML entity utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/i18n/package.json b/packages/i18n/package.json index bb82d509684fe..47414963190cd 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/i18n", - "version": "4.46.0-prerelease", + "version": "4.46.0", "description": "WordPress internationalization (i18n) library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/icons/package.json b/packages/icons/package.json index ecc11b411c828..5cef81d4bc67b 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/icons", - "version": "9.37.0-prerelease", + "version": "9.37.0", "description": "WordPress Icons package, based on dashicon.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/interactivity/package.json b/packages/interactivity/package.json index 791ed276db6b3..fd2491695be5a 100644 --- a/packages/interactivity/package.json +++ b/packages/interactivity/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/interactivity", - "version": "2.7.0-prerelease", + "version": "2.7.0", "description": "Package that provides a standard and simple way to handle the frontend interactivity of Gutenberg blocks.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/interface/package.json b/packages/interface/package.json index 8142df4fd443b..429d2ad59d0fd 100644 --- a/packages/interface/package.json +++ b/packages/interface/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/interface", - "version": "5.23.0-prerelease", + "version": "5.23.0", "description": "Interface module for WordPress. The package contains shared functionality across the modern JavaScript-based WordPress screens.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/is-shallow-equal/package.json b/packages/is-shallow-equal/package.json index b7202d19a87e3..ffc4e97590bc9 100644 --- a/packages/is-shallow-equal/package.json +++ b/packages/is-shallow-equal/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/is-shallow-equal", - "version": "4.46.0-prerelease", + "version": "4.46.0", "description": "Test for shallow equality between two objects or arrays.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-console/package.json b/packages/jest-console/package.json index 2152ff6a5c0dd..1dfb50d5bd59c 100644 --- a/packages/jest-console/package.json +++ b/packages/jest-console/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-console", - "version": "7.17.0-prerelease", + "version": "7.17.0", "description": "Custom Jest matchers for the Console object.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-preset-default/package.json b/packages/jest-preset-default/package.json index 4fbd174c512c5..7e3b0812e3d06 100644 --- a/packages/jest-preset-default/package.json +++ b/packages/jest-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-preset-default", - "version": "11.17.0-prerelease", + "version": "11.17.0", "description": "Default Jest preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-puppeteer-axe/package.json b/packages/jest-puppeteer-axe/package.json index 5e87a4a542e33..eed831e07d801 100644 --- a/packages/jest-puppeteer-axe/package.json +++ b/packages/jest-puppeteer-axe/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-puppeteer-axe", - "version": "6.17.0-prerelease", + "version": "6.17.0", "description": "Axe API integration with Jest and Puppeteer.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/keyboard-shortcuts/package.json b/packages/keyboard-shortcuts/package.json index 43e4d11af5cbb..dfe02e6077367 100644 --- a/packages/keyboard-shortcuts/package.json +++ b/packages/keyboard-shortcuts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keyboard-shortcuts", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "Handling keyboard shortcuts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/keycodes/package.json b/packages/keycodes/package.json index 9ecc81007b71a..4ca561d68b83d 100644 --- a/packages/keycodes/package.json +++ b/packages/keycodes/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keycodes", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "Keycodes utilities for WordPress. Used to check for keyboard events across browsers/operating systems.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/lazy-import/package.json b/packages/lazy-import/package.json index 7e5561e2b6d18..62320482ae15b 100644 --- a/packages/lazy-import/package.json +++ b/packages/lazy-import/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/lazy-import", - "version": "1.33.0-prerelease", + "version": "1.33.0", "description": "Lazily import a module, installing it automatically if missing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/list-reusable-blocks/package.json b/packages/list-reusable-blocks/package.json index 70a3ae145a799..0feaddf684b5f 100644 --- a/packages/list-reusable-blocks/package.json +++ b/packages/list-reusable-blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/list-reusable-blocks", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "Adding Export/Import support to the reusable blocks listing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/media-utils/package.json b/packages/media-utils/package.json index 2f2e4f454f9ea..93ed96c45246a 100644 --- a/packages/media-utils/package.json +++ b/packages/media-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/media-utils", - "version": "4.37.0-prerelease", + "version": "4.37.0", "description": "WordPress Media Upload Utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/notices/package.json b/packages/notices/package.json index 38c7fac68afbc..9250d196365c4 100644 --- a/packages/notices/package.json +++ b/packages/notices/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/notices", - "version": "4.14.0-prerelease", + "version": "4.14.0", "description": "State management for notices.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/npm-package-json-lint-config/package.json b/packages/npm-package-json-lint-config/package.json index 3ad54a8a2a93a..a62009f5d88a0 100644 --- a/packages/npm-package-json-lint-config/package.json +++ b/packages/npm-package-json-lint-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/npm-package-json-lint-config", - "version": "4.31.0-prerelease", + "version": "4.31.0", "description": "WordPress npm-package-json-lint shareable configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/nux/package.json b/packages/nux/package.json index 124d3cfacd960..12f659accc950 100644 --- a/packages/nux/package.json +++ b/packages/nux/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/nux", - "version": "8.8.0-prerelease", + "version": "8.8.0", "description": "NUX (New User eXperience) module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/patterns/package.json b/packages/patterns/package.json index 8f417dc1aa592..bab11059bf92c 100644 --- a/packages/patterns/package.json +++ b/packages/patterns/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/patterns", - "version": "1.7.0-prerelease", + "version": "1.7.0", "description": "Management of user pattern editing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/plugins/package.json b/packages/plugins/package.json index e9ffee30feba8..98448a216daea 100644 --- a/packages/plugins/package.json +++ b/packages/plugins/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/plugins", - "version": "6.14.0-prerelease", + "version": "6.14.0", "description": "Plugins module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/postcss-plugins-preset/package.json b/packages/postcss-plugins-preset/package.json index ffd3230b90bd7..bee5573d2f883 100644 --- a/packages/postcss-plugins-preset/package.json +++ b/packages/postcss-plugins-preset/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/postcss-plugins-preset", - "version": "4.30.0-prerelease", + "version": "4.30.0", "description": "PostCSS sharable plugins preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/postcss-themes/package.json b/packages/postcss-themes/package.json index 2b65ddefc795a..1fd640b1b3f25 100644 --- a/packages/postcss-themes/package.json +++ b/packages/postcss-themes/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/postcss-themes", - "version": "5.29.0-prerelease", + "version": "5.29.0", "description": "PostCSS plugin to generate theme colors.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/preferences-persistence/package.json b/packages/preferences-persistence/package.json index 6a76d6094bac5..8137c703d6f33 100644 --- a/packages/preferences-persistence/package.json +++ b/packages/preferences-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/preferences-persistence", - "version": "1.38.0-prerelease", + "version": "1.38.0", "description": "Persistence utilities for `wordpress/preferences`.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/preferences/package.json b/packages/preferences/package.json index 0ba849dc9787a..78a0ed29aa354 100644 --- a/packages/preferences/package.json +++ b/packages/preferences/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/preferences", - "version": "3.23.0-prerelease", + "version": "3.23.0", "description": "Utilities for managing WordPress preferences.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/prettier-config/package.json b/packages/prettier-config/package.json index 7e4168c931d8e..f97e04f7fee6c 100644 --- a/packages/prettier-config/package.json +++ b/packages/prettier-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/prettier-config", - "version": "3.3.0-prerelease", + "version": "3.3.0", "description": "WordPress Prettier shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/primitives/package.json b/packages/primitives/package.json index 274755ff59b2d..e3e99b3d6d028 100644 --- a/packages/primitives/package.json +++ b/packages/primitives/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/primitives", - "version": "3.44.0-prerelease", + "version": "3.44.0", "description": "WordPress cross-platform primitives.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/priority-queue/package.json b/packages/priority-queue/package.json index 2290bceeb8cc3..3e3ecb57872b1 100644 --- a/packages/priority-queue/package.json +++ b/packages/priority-queue/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/priority-queue", - "version": "2.46.0-prerelease", + "version": "2.46.0", "description": "Generic browser priority queue.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/private-apis/package.json b/packages/private-apis/package.json index ccc4999d2fb17..be77c8334dcb4 100644 --- a/packages/private-apis/package.json +++ b/packages/private-apis/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/private-apis", - "version": "0.28.0-prerelease", + "version": "0.28.0", "description": "Internal experimental APIs for WordPress core.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/project-management-automation/package.json b/packages/project-management-automation/package.json index a75b111d795cd..b4c0389872dcd 100644 --- a/packages/project-management-automation/package.json +++ b/packages/project-management-automation/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/project-management-automation", - "version": "1.45.0-prerelease", + "version": "1.45.0", "description": "GitHub Action that implements various automation to assist with managing the Gutenberg GitHub repository.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/react-i18n/package.json b/packages/react-i18n/package.json index 3a08d14983bc2..662d8e288bcc0 100644 --- a/packages/react-i18n/package.json +++ b/packages/react-i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/react-i18n", - "version": "3.44.0-prerelease", + "version": "3.44.0", "description": "React bindings for @wordpress/i18n.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/readable-js-assets-webpack-plugin/package.json b/packages/readable-js-assets-webpack-plugin/package.json index 646b8999d3441..93a525c127bc0 100644 --- a/packages/readable-js-assets-webpack-plugin/package.json +++ b/packages/readable-js-assets-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/readable-js-assets-webpack-plugin", - "version": "2.29.0-prerelease", + "version": "2.29.0", "description": "Generate a readable JS file for each JS asset.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/redux-routine/package.json b/packages/redux-routine/package.json index b6a8fe417da8d..09d7b16795ae2 100644 --- a/packages/redux-routine/package.json +++ b/packages/redux-routine/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/redux-routine", - "version": "4.46.0-prerelease", + "version": "4.46.0", "description": "Redux middleware for generator coroutines.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/reusable-blocks/package.json b/packages/reusable-blocks/package.json index 8ffdb18e59811..f21c486014fc8 100644 --- a/packages/reusable-blocks/package.json +++ b/packages/reusable-blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/reusable-blocks", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "Reusable blocks utilities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/rich-text/package.json b/packages/rich-text/package.json index 0d805777e2d4f..4c2fe8e32adc9 100644 --- a/packages/rich-text/package.json +++ b/packages/rich-text/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/rich-text", - "version": "6.23.0-prerelease", + "version": "6.23.0", "description": "Rich text value and manipulation API.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/router/package.json b/packages/router/package.json index a27be42a33cd4..ae8eb364202e2 100644 --- a/packages/router/package.json +++ b/packages/router/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/router", - "version": "0.15.0-prerelease", + "version": "0.15.0", "description": "Router API for WordPress pages.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 21194afad7cdd..2a740ec41c6ab 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/scripts", - "version": "26.17.0-prerelease", + "version": "26.17.0", "description": "Collection of reusable scripts for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/server-side-render/package.json b/packages/server-side-render/package.json index 74d84e29e28ad..3e8f81b1476fd 100644 --- a/packages/server-side-render/package.json +++ b/packages/server-side-render/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/server-side-render", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "The component used with WordPress to server-side render a preview of dynamic blocks to display in the editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/shortcode/package.json b/packages/shortcode/package.json index 3a59b60a29918..6646c98fe46e0 100644 --- a/packages/shortcode/package.json +++ b/packages/shortcode/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/shortcode", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "Shortcode module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/style-engine/package.json b/packages/style-engine/package.json index 19c15d261898a..cdbb5d8f27251 100644 --- a/packages/style-engine/package.json +++ b/packages/style-engine/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/style-engine", - "version": "1.29.0-prerelease", + "version": "1.29.0", "description": "A suite of parsers and compilers for WordPress styles.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/stylelint-config/package.json b/packages/stylelint-config/package.json index f82b2cee23502..6d6ce676bbce3 100644 --- a/packages/stylelint-config/package.json +++ b/packages/stylelint-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/stylelint-config", - "version": "21.29.0-prerelease", + "version": "21.29.0", "description": "stylelint config for WordPress development.", "author": "The WordPress Contributors", "license": "MIT", diff --git a/packages/sync/package.json b/packages/sync/package.json index cd48de011a183..0110a281d46ae 100644 --- a/packages/sync/package.json +++ b/packages/sync/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/sync", - "version": "0.8.0-prerelease", + "version": "0.8.0", "description": "Sync Data.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/token-list/package.json b/packages/token-list/package.json index cb7f13dceeec6..de2e1d0c4d2a5 100644 --- a/packages/token-list/package.json +++ b/packages/token-list/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/token-list", - "version": "2.46.0-prerelease", + "version": "2.46.0", "description": "Constructable, plain JavaScript DOMTokenList implementation, supporting non-browser runtimes.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/undo-manager/package.json b/packages/undo-manager/package.json index f8b8401774dbf..b1f75f83d5978 100644 --- a/packages/undo-manager/package.json +++ b/packages/undo-manager/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/undo-manager", - "version": "0.6.0-prerelease", + "version": "0.6.0", "description": "A small package to manage undo/redo.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/url/package.json b/packages/url/package.json index af28dea0b4444..6acd999314b15 100644 --- a/packages/url/package.json +++ b/packages/url/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/url", - "version": "3.47.0-prerelease", + "version": "3.47.0", "description": "WordPress URL utilities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/viewport/package.json b/packages/viewport/package.json index 0809dee6f1d9a..2357182bdfd8d 100644 --- a/packages/viewport/package.json +++ b/packages/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/viewport", - "version": "5.23.0-prerelease", + "version": "5.23.0", "description": "Viewport module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/warning/package.json b/packages/warning/package.json index 899d36d9cafc0..a4c0f7df23070 100644 --- a/packages/warning/package.json +++ b/packages/warning/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/warning", - "version": "2.46.0-prerelease", + "version": "2.46.0", "description": "Warning utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/widgets/package.json b/packages/widgets/package.json index 06e7e9a788f20..06dc560470392 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/widgets", - "version": "3.23.0-prerelease", + "version": "3.23.0", "description": "Functionality used by the widgets block editor in the Widgets screen and the Customizer.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/wordcount/package.json b/packages/wordcount/package.json index 504e5c0b84bfc..dbb3fdd3bc1f4 100644 --- a/packages/wordcount/package.json +++ b/packages/wordcount/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/wordcount", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "WordPress word count utility.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", From fb2a2cfd5cbe413ddf3d62f0bacd5d3f2bc97a68 Mon Sep 17 00:00:00 2001 From: Ramon Date: Fri, 17 Nov 2023 08:06:27 +1100 Subject: [PATCH 059/116] Page spec: merging create page and toggle preview tests (#56129) * Merging create page and toggle preview tests * Disable no assertion linting rule Update commentszz * Undo test assertion abstraction --- test/e2e/specs/site-editor/pages.spec.js | 175 +++++++++++------------ 1 file changed, 87 insertions(+), 88 deletions(-) diff --git a/test/e2e/specs/site-editor/pages.spec.js b/test/e2e/specs/site-editor/pages.spec.js index 8008109be15ee..af58daeaedbe4 100644 --- a/test/e2e/specs/site-editor/pages.spec.js +++ b/test/e2e/specs/site-editor/pages.spec.js @@ -18,6 +18,53 @@ async function draftNewPage( page ) { ).toBeVisible(); } +async function addPageContent( editor, page ) { + await editor.canvas + .getByRole( 'document', { + name: 'Block: Content', + } ) + .getByRole( 'document', { + name: 'Empty block; start writing or type forward slash to choose a block', + } ) + .click(); + + // Insert into Page Content using default block. + await editor.canvas + .getByRole( 'document', { + name: 'Empty block; start writing or type forward slash to choose a block', + } ) + .fill( 'Lorem ipsum dolor sit amet' ); + + // Insert into Page Content using global inserter. + await page.getByRole( 'button', { name: 'Toggle block inserter' } ).click(); + await page.getByRole( 'option', { name: 'Heading', exact: true } ).click(); + await editor.canvas + .getByRole( 'document', { + name: 'Block: Heading', + } ) + .fill( 'A sweet heading 1' ); + + // Add some regular content blocks. + await page.keyboard.press( 'Enter' ); + await editor.insertBlock( { name: 'core/paragraph' } ); + await page.keyboard.type( 'A sweet paragraph 1' ); + await page.keyboard.press( 'Enter' ); + await editor.insertBlock( { name: 'core/paragraph' } ); + await page.keyboard.type( 'A sweet paragraph 2' ); + + // Insert into Page Content using appender. + await page + .getByRole( 'region', { name: 'Editor footer' } ) + .getByRole( 'button', { name: 'Content' } ) + .click(); + await editor.canvas.getByRole( 'button', { name: 'Add block' } ).click(); + await page.getByPlaceholder( 'Search' ).fill( 'list' ); + await page.getByRole( 'option', { name: 'List', exact: true } ).click(); + await page.keyboard.type( 'Sweet list 1' ); + await page.keyboard.press( 'Enter' ); + await page.keyboard.type( 'Sweet list 2' ); +} + test.describe( 'Pages', () => { test.beforeAll( async ( { requestUtils } ) => { await requestUtils.activateTheme( 'emptytheme' ); @@ -43,43 +90,17 @@ test.describe( 'Pages', () => { await admin.visitSiteEditor(); } ); - test( 'create a new page', async ( { page, editor } ) => { + test( 'create a new page, edit template and toggle page template preview', async ( { + page, + editor, + } ) => { + // Set up await draftNewPage( page ); + await addPageContent( editor, page ); - // Insert into Page Content using default block. - await editor.canvas - .getByRole( 'document', { - name: 'Empty block; start writing or type forward slash to choose a block', - } ) - .fill( 'Lorem ipsum dolor sit amet' ); - - // Insert into Page Content using global inserter. - await page - .getByRole( 'button', { name: 'Toggle block inserter' } ) - .click(); - await page - .getByRole( 'option', { name: 'Heading', exact: true } ) - .click(); - await editor.canvas - .getByRole( 'document', { - name: 'Block: Heading', - } ) - .fill( 'Lorem ipsum' ); - - // Insert into Page Content using appender. - await page - .getByRole( 'region', { name: 'Editor footer' } ) - .getByRole( 'button', { name: 'Content' } ) - .click(); - await editor.canvas - .getByRole( 'button', { name: 'Add block' } ) - .click(); - await page.getByPlaceholder( 'Search' ).fill( 'list' ); - await page.getByRole( 'option', { name: 'List', exact: true } ).click(); - await page.keyboard.type( 'Lorem ipsum' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.type( 'Dolor sit amet' ); - + /* + * Test create page.Test creating a new page and editing the template. + */ // Selecting a block in the template should display a notice. await editor.canvas .getByRole( 'document', { @@ -112,7 +133,14 @@ test.describe( 'Pages', () => { ) ).toBeVisible(); - // Edit a block that's in the template. + // Edit blocks that are in the template. + await editor.canvas + .getByRole( 'document', { name: 'Block: Title' } ) + .click(); + await page + .getByRole( 'button', { name: 'Move down', exact: true } ) + .click(); + await editor.canvas .getByRole( 'textbox', { name: 'Site title text' } ) .fill( 'New Site Title' ); @@ -135,47 +163,32 @@ test.describe( 'Pages', () => { 'role=region[name="Save panel"] >> role=checkbox[name="Test Page"]' ) ).toBeVisible(); - } ); - - test( 'toggle template preview', async ( { page, editor } ) => { - await draftNewPage( page ); - await editor.openDocumentSettingsSidebar(); - - await editor.canvas - .getByRole( 'document', { - name: 'Block: Content', - } ) - .getByRole( 'document', { - name: 'Empty block; start writing or type forward slash to choose a block', - } ) + await page + .getByRole( 'button', { name: 'Cancel', exact: true } ) .click(); - // Add some content to the page. - await page.keyboard.type( 'Sweet paragraph 1' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.type( 'Sweet paragraph 2' ); - - // Header template area and page content are visible. + /* + * Test toggling preview mode. + */ await expect( editor.canvas.getByRole( 'document', { name: 'Block: header', } ) ).toBeVisible(); - - const paragraphs = editor.canvas - .getByRole( 'document', { - name: 'Block: Content', - } ) - .getByText( 'Sweet paragraph ' ); - - await expect( paragraphs.nth( 0 ) ).toBeVisible(); - await expect( paragraphs.nth( 1 ) ).toBeVisible(); await expect( editor.canvas.getByRole( 'document', { - name: 'Block: Title', + name: 'Block: Content', } ) ).toBeVisible(); + // Ensure order is preserved between toggling. + await page + .locator( + '[aria-label="Block: Content"] + [aria-label="Block: Title"]' + ) + .isVisible(); + + await editor.openDocumentSettingsSidebar(); // Toggle template preview to "off". const templateOptionsButton = page .getByRole( 'region', { name: 'Editor settings' } ) @@ -202,36 +215,24 @@ test.describe( 'Pages', () => { } ) ).toBeHidden(); - // Content block is still visible and wrapped in a container. - const paragraphsInGroup = editor.canvas - .getByRole( 'document', { - name: 'Block: Group', - } ) - .getByRole( 'document', { - name: 'Block: Content', - } ) - .getByText( 'Sweet paragraph ' ); - - await expect( paragraphsInGroup.nth( 0 ) ).toBeVisible(); - await expect( paragraphsInGroup.nth( 1 ) ).toBeVisible(); - // Check order of paragraphs. - // Important to ensure the blocks are rendered as they are in the template. - await expect( paragraphsInGroup.nth( 0 ) ).toHaveText( - 'Sweet paragraph 1' - ); - await expect( paragraphsInGroup.nth( 1 ) ).toHaveText( - 'Sweet paragraph 2' - ); + // Content blocks are wrapped in a Group block by default. await expect( editor.canvas .getByRole( 'document', { name: 'Block: Group', } ) .getByRole( 'document', { - name: 'Block: Title', + name: 'Block: Content', } ) ).toBeVisible(); + // Ensure order is preserved between toggling. + await page + .locator( + '[aria-label="Block: Content"] + [aria-label="Block: Title"]' + ) + .isVisible(); + // Remove focus from templateOptionsButton button. await editor.canvas.locator( 'body' ).click(); @@ -249,8 +250,6 @@ test.describe( 'Pages', () => { name: 'Block: header', } ) ).toBeVisible(); - await expect( paragraphs.nth( 0 ) ).toBeVisible(); - await expect( paragraphs.nth( 1 ) ).toBeVisible(); await expect( editor.canvas.getByRole( 'document', { name: 'Block: Title', From 093d52cbfd3e2c140843d3fb91ad3d03330320a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Wrede?= Date: Thu, 16 Nov 2023 22:35:43 +0100 Subject: [PATCH 060/116] Docs: Improve downloadBlob example (#56225) --- packages/blob/README.md | 4 ++-- packages/blob/src/index.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/blob/README.md b/packages/blob/README.md index ff28e8879602f..64520a98bd6a7 100644 --- a/packages/blob/README.md +++ b/packages/blob/README.md @@ -40,9 +40,9 @@ const fileContent = JSON.stringify( null, 2 ); -const fileName = 'file.json'; +const filename = 'file.json'; -downloadBlob( 'file.json', fileContent, 'application/json' ); +downloadBlob( filename, fileContent, 'application/json' ); ``` _Parameters_ diff --git a/packages/blob/src/index.js b/packages/blob/src/index.js index edc2e43729a23..2493f81fc4c65 100644 --- a/packages/blob/src/index.js +++ b/packages/blob/src/index.js @@ -85,9 +85,9 @@ export function isBlobURL( url ) { * null, * 2 * ); - * const fileName = 'file.json'; + * const filename = 'file.json'; * - * downloadBlob( 'file.json', fileContent, 'application/json' ); + * downloadBlob( filename, fileContent, 'application/json' ); * ``` * * @param {string} filename File name. From d39d2dddfd888a8ddd174aa16630626d21ce5f81 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 17 Nov 2023 09:42:21 +1100 Subject: [PATCH 061/116] Add layout classes to legacy Group inner container (#56130) * Add layout classes to legacy Group inner container * Fix lint issues * fix lint warning * Add some tests for inner container function * Add fallback for `class_list` * Fix selectors for legacy group placeholder. * Add explanatory comments. --- lib/block-supports/layout.php | 52 ++++++++++- .../button-block-appender/content.scss | 4 +- packages/block-library/src/group/edit.js | 14 +-- phpunit/block-supports/layout-test.php | 88 +++++++++++++++++++ 4 files changed, 142 insertions(+), 16 deletions(-) diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 80be02db68360..0908f649bd5a9 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -865,17 +865,63 @@ function gutenberg_restore_group_inner_container( $block_content, $block ) { return $block_content; } - $replace_regex = sprintf( + /** + * This filter runs after the layout classnames have been added to the block, so they + * have to be removed from the outer wrapper and then added to the inner. + */ + $layout_classes = array(); + $processor = new WP_HTML_Tag_Processor( $block_content ); + + if ( $processor->next_tag( array( 'class_name' => 'wp-block-group' ) ) ) { + if ( method_exists( $processor, 'class_list' ) ) { + foreach ( $processor->class_list() as $class_name ) { + if ( str_contains( $class_name, 'layout' ) ) { + array_push( $layout_classes, $class_name ); + $processor->remove_class( $class_name ); + } + } + } else { + /** + * The class_list method was only added in 6.4 so this needs a temporary fallback. + * This fallback should be removed when the minimum supported version is 6.4. + */ + $classes = $processor->get_attribute( 'class' ); + if ( $classes ) { + $classes = explode( ' ', $classes ); + foreach ( $classes as $class_name ) { + if ( str_contains( $class_name, 'layout' ) ) { + array_push( $layout_classes, $class_name ); + $processor->remove_class( $class_name ); + } + } + } + } + } + + $content_without_layout_classes = $processor->get_updated_html(); + $replace_regex = sprintf( '/(^\s*<%1$s\b[^>]*wp-block-group[^>]*>)(.*)(<\/%1$s>\s*$)/ms', preg_quote( $tag_name, '/' ) ); - $updated_content = preg_replace_callback( + $updated_content = preg_replace_callback( $replace_regex, static function ( $matches ) { return $matches[1] . '
' . $matches[2] . '
' . $matches[3]; }, - $block_content + $content_without_layout_classes ); + + // Add layout classes to inner wrapper. + if ( ! empty( $layout_classes ) ) { + $processor = new WP_HTML_Tag_Processor( $updated_content ); + if ( $processor->next_tag( array( 'class_name' => 'wp-block-group__inner-container' ) ) ) { + foreach ( $layout_classes as $class_name ) { + $processor->add_class( $class_name ); + } + } + $updated_content = $processor->get_updated_html(); + } + return $updated_content; } diff --git a/packages/block-editor/src/components/button-block-appender/content.scss b/packages/block-editor/src/components/button-block-appender/content.scss index 941ccb7dd1ad3..50d93234b93f5 100644 --- a/packages/block-editor/src/components/button-block-appender/content.scss +++ b/packages/block-editor/src/components/button-block-appender/content.scss @@ -39,8 +39,8 @@ .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > &, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > &, // Legacy groups have an inner container so need to be targeted separately - .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > &, - .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > & { + .block-editor-block-list__block:not(.is-selected) > .is-layout-constrained.wp-block-group__inner-container > &, + .block-editor-block-list__block:not(.is-selected) > .is-layout-flow.wp-block-group__inner-container > & { pointer-events: none; &::after { diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index 277fa6872fa82..9c8690c4e0e8e 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -71,13 +71,7 @@ function GroupEditControls( { tagName, onSelectTagName } ) { ); } -function GroupEdit( { - attributes, - name, - setAttributes, - clientId, - __unstableLayoutClassNames: layoutClassNames, -} ) { +function GroupEdit( { attributes, name, setAttributes, clientId } ) { const { hasInnerBlocks, themeSupportsLayout } = useSelect( ( select ) => { const { getBlock, getSettings } = select( blockEditorStore ); @@ -103,9 +97,8 @@ function GroupEdit( { themeSupportsLayout || type === 'flex' || type === 'grid'; // Hooks. - const blockProps = useBlockProps( { - className: ! layoutSupportEnabled ? layoutClassNames : null, - } ); + const blockProps = useBlockProps(); + const [ showPlaceholder, setShowPlaceholder ] = useShouldShowPlaceHolder( { attributes, usedLayoutType: type, @@ -134,7 +127,6 @@ function GroupEdit( { templateLock, allowedBlocks, renderAppender, - __unstableDisableLayoutClassNames: ! layoutSupportEnabled, } ); diff --git a/phpunit/block-supports/layout-test.php b/phpunit/block-supports/layout-test.php index c29899e3f4d1b..41735fdc0939e 100644 --- a/phpunit/block-supports/layout-test.php +++ b/phpunit/block-supports/layout-test.php @@ -464,4 +464,92 @@ public function data_layout_support_flag_renders_classnames_on_wrapper() { ), ); } + + /** + * Check that gutenberg_restore_group_inner_container() restores the legacy inner container on the Group block. + * + * @dataProvider data_restore_group_inner_container + * + * @covers ::gutenberg_restore_group_inner_container + * + * @param array $args Dataset to test. + * @param string $expected_output The expected output. + */ + public function test_restore_group_inner_container( $args, $expected_output ) { + $actual_output = gutenberg_restore_group_inner_container( $args['block_content'], $args['block'] ); + $this->assertEquals( $expected_output, $actual_output ); + } + + /** + * Data provider for test_restore_group_inner_container. + * + * @return array + */ + public function data_restore_group_inner_container() { + return array( + 'group block with existing inner container' => array( + 'args' => array( + 'block_content' => '
', + 'block' => array( + 'blockName' => 'core/group', + 'attrs' => array( + 'layout' => array( + 'type' => 'default', + ), + ), + 'innerBlocks' => array(), + 'innerHTML' => '
', + 'innerContent' => array( + '
', + ' ', + '
', + ), + ), + ), + 'expected_output' => '
', + ), + 'group block with no existing inner container' => array( + 'args' => array( + 'block_content' => '
', + 'block' => array( + 'blockName' => 'core/group', + 'attrs' => array( + 'layout' => array( + 'type' => 'default', + ), + ), + 'innerBlocks' => array(), + 'innerHTML' => '
', + 'innerContent' => array( + '
', + ' ', + '
', + ), + ), + ), + 'expected_output' => '
', + ), + 'group block with layout classnames' => array( + 'args' => array( + 'block_content' => '
', + 'block' => array( + 'blockName' => 'core/group', + 'attrs' => array( + 'layout' => array( + 'type' => 'default', + ), + ), + 'innerBlocks' => array(), + 'innerHTML' => '
', + 'innerContent' => array( + '
', + ' ', + '
', + ), + ), + ), + 'expected_output' => '
', + ), + ); + } } From 802c7a5a6d46c7bbd95d5e05bf64c9483103a98c Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Fri, 17 Nov 2023 10:02:24 +1100 Subject: [PATCH 062/116] Layout: Fix issue where layout classnames are injected for blocks without layout support (#56187) * Layout: Fix issue where layout classnames were sometimes injected for blocks without layout support * Simplify comment --- lib/block-supports/layout.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 0908f649bd5a9..d35c963d0bed4 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -617,6 +617,9 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $processor->add_class( $class_name ); } return $processor->get_updated_html(); + } elseif ( ! $block_supports_layout ) { + // Ensure layout classnames are not injected if there is no layout support. + return $block_content; } $global_settings = gutenberg_get_global_settings(); From 178ca846d5c92e6a62ea3163fa883c0ff35df82a Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Fri, 17 Nov 2023 13:13:34 +1100 Subject: [PATCH 063/116] Drag and drop: allow dragging to the beginning and end of a document (#56070) * Try passing in a ref to allow dragging to the top and bottom of the editor canvas * Update naming * Implement in the site editor * Fix gap between post title and top of iframe * Add __unstable prefix in useInnerBlocksProps * Fix typo in comment --- .../block-editor/src/components/inner-blocks/index.js | 8 ++++++-- .../src/components/use-block-drop-zone/index.js | 5 ++++- packages/edit-post/src/components/visual-editor/index.js | 7 +++++++ .../src/components/block-editor/site-editor-canvas.js | 6 ++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index f5f216d6072e4..abcde9f096e81 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -169,8 +169,11 @@ const ForwardedInnerBlocks = forwardRef( ( props, ref ) => { * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inner-blocks/README.md */ export function useInnerBlocksProps( props = {}, options = {} ) { - const { __unstableDisableLayoutClassNames, __unstableDisableDropZone } = - options; + const { + __unstableDisableLayoutClassNames, + __unstableDisableDropZone, + __unstableDropZoneElement, + } = options; const { clientId, layout = null, @@ -211,6 +214,7 @@ export function useInnerBlocksProps( props = {}, options = {} ) { ); const blockDropZoneRef = useBlockDropZone( { + dropZoneElement: __unstableDropZoneElement, rootClientId: clientId, } ); diff --git a/packages/block-editor/src/components/use-block-drop-zone/index.js b/packages/block-editor/src/components/use-block-drop-zone/index.js index ba33e8ef8e74f..25dc6ee408982 100644 --- a/packages/block-editor/src/components/use-block-drop-zone/index.js +++ b/packages/block-editor/src/components/use-block-drop-zone/index.js @@ -127,7 +127,8 @@ export function getDropTargetPosition( /** * @typedef {Object} WPBlockDropZoneConfig - * @property {string} rootClientId The root client id for the block list. + * @property {?HTMLElement} dropZoneElement Optional element to be used as the drop zone. + * @property {string} rootClientId The root client id for the block list. */ /** @@ -136,6 +137,7 @@ export function getDropTargetPosition( * @param {WPBlockDropZoneConfig} dropZoneConfig configuration data for the drop zone. */ export default function useBlockDropZone( { + dropZoneElement, // An undefined value represents a top-level block. Default to an empty // string for this so that `targetRootClientId` can be easily compared to // values returned by the `getRootBlockClientId` selector, which also uses @@ -235,6 +237,7 @@ export default function useBlockDropZone( { ); return useDropZone( { + dropZoneElement, isDisabled, onDrop: onBlockDrop, onDragOver( event ) { diff --git a/packages/edit-post/src/components/visual-editor/index.js b/packages/edit-post/src/components/visual-editor/index.js index bd236551c7cf1..98fb302ce29c9 100644 --- a/packages/edit-post/src/components/visual-editor/index.js +++ b/packages/edit-post/src/components/visual-editor/index.js @@ -411,6 +411,13 @@ export default function VisualEditor( { styles } ) { : `${ blockListLayoutClass } wp-block-post-content` // Ensure root level blocks receive default/flow blockGap styling rules. } layout={ blockListLayout } + __unstableDropZoneElement={ + // When iframed, pass in the html element of the iframe to + // ensure the drop zone extends to the edges of the iframe. + isToBeIframed + ? ref.current?.parentNode + : ref.current + } /> diff --git a/packages/edit-site/src/components/block-editor/site-editor-canvas.js b/packages/edit-site/src/components/block-editor/site-editor-canvas.js index e715587891c0a..d3bc2ec56dfd8 100644 --- a/packages/edit-site/src/components/block-editor/site-editor-canvas.js +++ b/packages/edit-site/src/components/block-editor/site-editor-canvas.js @@ -134,6 +134,12 @@ export default function SiteEditorCanvas() { isTemplateTypeNavigation, } ) } + __unstableDropZoneElement={ + // Pass in the html element of the iframe to ensure that + // the drop zone extends to the very edges of the iframe, + // even if the template is shorter than the viewport. + contentRef.current?.parentNode + } layout={ LAYOUT } renderAppender={ showBlockAppender } /> From c9cad59cffb1fb7fef4786f3e157af032e629906 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Fri, 17 Nov 2023 15:46:58 +0800 Subject: [PATCH 064/116] Fix focus loss after converting to a synced pattern (#55473) * Fix focus lost after converting to a synced pattern * Fix for jsx --- packages/block-library/src/block/edit.js | 37 ++++---- packages/patterns/src/components/index.js | 3 +- .../src/components/pattern-convert-button.js | 14 ++- .../e2e/specs/editor/various/patterns.spec.js | 87 +++++++++++++++++++ 4 files changed, 117 insertions(+), 24 deletions(-) diff --git a/packages/block-library/src/block/edit.js b/packages/block-library/src/block/edit.js index 395e4bff4680b..979ae04c62282 100644 --- a/packages/block-library/src/block/edit.js +++ b/packages/block-library/src/block/edit.js @@ -114,33 +114,28 @@ export default function ReusableBlockEdit( { : InnerBlocks.ButtonBlockAppender, } ); + let children = null; if ( hasAlreadyRendered ) { - return ( -
- - { __( 'Block cannot be rendered inside itself.' ) } - -
+ children = ( + + { __( 'Block cannot be rendered inside itself.' ) } + ); } if ( isMissing ) { - return ( -
- - { __( 'Block has been deleted or is unavailable.' ) } - -
+ children = ( + + { __( 'Block has been deleted or is unavailable.' ) } + ); } if ( ! hasResolved ) { - return ( -
- - - -
+ children = ( + + + ); } @@ -157,7 +152,11 @@ export default function ReusableBlockEdit( { /> -
+ { children === null ? ( +
+ ) : ( +
{ children }
+ ) } ); } diff --git a/packages/patterns/src/components/index.js b/packages/patterns/src/components/index.js index a00d2d2bd262e..6fddc593911f4 100644 --- a/packages/patterns/src/components/index.js +++ b/packages/patterns/src/components/index.js @@ -12,11 +12,12 @@ import PatternsManageButton from './patterns-manage-button'; export default function PatternsMenuItems( { rootClientId } ) { return ( - { ( { selectedClientIds } ) => ( + { ( { selectedClientIds, onClose } ) => ( <> { selectedClientIds.length === 1 && ( void} props.closeBlockSettingsMenu Callback to close the block settings menu dropdown. * @return {import('react').ComponentType} The menu control or null. */ -export default function PatternConvertButton( { clientIds, rootClientId } ) { +export default function PatternConvertButton( { + clientIds, + rootClientId, + closeBlockSettingsMenu, +} ) { const { createSuccessNotice } = useDispatch( noticesStore ); const { replaceBlocks } = useDispatch( blockEditorStore ); // Ignore reason: false positive of the lint rule. @@ -104,6 +109,7 @@ export default function PatternConvertButton( { clientIds, rootClientId } ) { replaceBlocks( clientIds, newBlock ); setEditingPattern( newBlock.clientId, true ); + closeBlockSettingsMenu(); } createSuccessNotice( diff --git a/test/e2e/specs/editor/various/patterns.spec.js b/test/e2e/specs/editor/various/patterns.spec.js index 941ae7e910a9b..4b47b2dd70a35 100644 --- a/test/e2e/specs/editor/various/patterns.spec.js +++ b/test/e2e/specs/editor/various/patterns.spec.js @@ -81,3 +81,90 @@ test.describe( 'Unsynced pattern', () => { .toEqual( [ ...before, ...before ] ); } ); } ); + +test.describe( 'Synced pattern', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.deleteAllBlocks(); + await requestUtils.deleteAllPatternCategories(); + } ); + + test.beforeEach( async ( { admin } ) => { + await admin.createNewPost(); + } ); + + test.afterEach( async ( { requestUtils } ) => { + await requestUtils.deleteAllBlocks(); + await requestUtils.deleteAllPatternCategories(); + } ); + + test( 'create a new synced pattern via the block options menu', async ( { + editor, + page, + } ) => { + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'A useful paragraph to reuse' }, + } ); + + // Create a synced pattern from the paragraph block. + await editor.showBlockToolbar(); + await page + .getByRole( 'toolbar', { name: 'Block tools' } ) + .getByRole( 'button', { name: 'Options' } ) + .click(); + await page.getByRole( 'menuitem', { name: 'Create pattern' } ).click(); + + const createPatternDialog = page.getByRole( 'dialog', { + name: 'Create pattern', + } ); + await createPatternDialog + .getByRole( 'textbox', { name: 'Name' } ) + .fill( 'My synced pattern' ); + const newCategory = 'Contact details'; + await createPatternDialog + .getByRole( 'combobox', { name: 'Categories' } ) + .fill( newCategory ); + await createPatternDialog + .getByRole( 'checkbox', { name: 'Synced' } ) + .setChecked( true ); + + await createPatternDialog + .getByRole( 'button', { name: 'Create' } ) + .click(); + + await expect + .poll( + editor.getBlocks, + 'The block content should be wrapped by a pattern block wrapper' + ) + .toEqual( [ + { + name: 'core/block', + attributes: { ref: expect.any( Number ) }, + innerBlocks: [], + }, + ] ); + const after = await editor.getBlocks(); + + const patternBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Pattern', + } ); + await expect( patternBlock ).toBeFocused(); + + // Check that the new pattern is available in the inserter. + await page.getByLabel( 'Toggle block inserter' ).click(); + await page + .getByRole( 'tab', { + name: 'Patterns', + } ) + .click(); + await page + .getByRole( 'button', { + name: newCategory, + } ) + .click(); + await page.getByRole( 'option', { name: 'My synced pattern' } ).click(); + + await expect.poll( editor.getBlocks ).toEqual( [ ...after, ...after ] ); + } ); +} ); From 71f29d0f43dc32a7d51a9d778155164905da8faa Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Fri, 17 Nov 2023 12:43:11 +0400 Subject: [PATCH 065/116] useEntityRecord: Do not trigger REST API requests when disabled (#56108) * useEntityRecord: Do not trigger REST API requests when disabled * Adjust tests --- .../src/hooks/test/use-entity-record.js | 38 +++++++++++++++ .../core-data/src/hooks/use-entity-record.ts | 48 ++++++++++++------- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/packages/core-data/src/hooks/test/use-entity-record.js b/packages/core-data/src/hooks/test/use-entity-record.js index d78a64d5f2b62..1fe68c84a951b 100644 --- a/packages/core-data/src/hooks/test/use-entity-record.js +++ b/packages/core-data/src/hooks/test/use-entity-record.js @@ -23,6 +23,7 @@ describe( 'useEntityRecord', () => { beforeEach( () => { registry = createRegistry(); registry.register( coreDataStore ); + triggerFetch.mockReset(); } ); const TEST_RECORD = { id: 1, hello: 'world' }; @@ -113,4 +114,41 @@ describe( 'useEntityRecord', () => { expect( widget.editedRecord ).toEqual( { hello: 'foo', id: 1 } ); expect( widget.edits ).toEqual( { hello: 'foo' } ); } ); + + it( 'does not resolve entity record when disabled via options', async () => { + // Provide response + triggerFetch.mockImplementation( () => TEST_RECORD ); + + let data; + const TestComponent = () => { + data = useEntityRecord( 'root', 'widget', 2, { + options: { enabled: false }, + } ); + return
; + }; + render( + + + + ); + + expect( data ).toEqual( { + edit: expect.any( Function ), + editedRecord: {}, + hasEdits: false, + edits: {}, + record: null, + save: expect.any( Function ), + } ); + + // Fetch request should have been issued. + await waitFor( () => { + expect( triggerFetch ).not.toHaveBeenCalled(); + } ); + await waitFor( () => + expect( triggerFetch ).not.toHaveBeenCalledWith( { + path: '/wp/v2/widgets/2?context=edit', + } ) + ); + } ); } ); diff --git a/packages/core-data/src/hooks/use-entity-record.ts b/packages/core-data/src/hooks/use-entity-record.ts index 6c755c7bad6a6..60228893e5102 100644 --- a/packages/core-data/src/hooks/use-entity-record.ts +++ b/packages/core-data/src/hooks/use-entity-record.ts @@ -56,6 +56,8 @@ export interface Options { enabled: boolean; } +const EMPTY_OBJECT = {}; + /** * Resolves the specified entity record. * @@ -167,24 +169,34 @@ export default function useEntityRecord< RecordType >( ); const { editedRecord, hasEdits, edits } = useSelect( - ( select ) => ( { - editedRecord: select( coreStore ).getEditedEntityRecord( - kind, - name, - recordId - ), - hasEdits: select( coreStore ).hasEditsForEntityRecord( - kind, - name, - recordId - ), - edits: select( coreStore ).getEntityRecordNonTransientEdits( - kind, - name, - recordId - ), - } ), - [ kind, name, recordId ] + ( select ) => { + if ( ! options.enabled ) { + return { + editedRecord: EMPTY_OBJECT, + hasEdits: false, + edits: EMPTY_OBJECT, + }; + } + + return { + editedRecord: select( coreStore ).getEditedEntityRecord( + kind, + name, + recordId + ), + hasEdits: select( coreStore ).hasEditsForEntityRecord( + kind, + name, + recordId + ), + edits: select( coreStore ).getEntityRecordNonTransientEdits( + kind, + name, + recordId + ), + }; + }, + [ kind, name, recordId, options.enabled ] ); const { data: record, ...querySelectRest } = useQuerySelect( From 7aa1c8876a0bfca19490aadf9a21142e56c51d94 Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Fri, 17 Nov 2023 10:53:41 +0100 Subject: [PATCH 066/116] Site Editor Sidebar: fix actions vertical alignment (#56218) --- .../src/components/sidebar-navigation-screen/style.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/edit-site/src/components/sidebar-navigation-screen/style.scss b/packages/edit-site/src/components/sidebar-navigation-screen/style.scss index f658083cc19f4..b856837b7c6b6 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen/style.scss +++ b/packages/edit-site/src/components/sidebar-navigation-screen/style.scss @@ -72,6 +72,7 @@ } .edit-site-sidebar-navigation-screen__actions { + display: flex; flex-shrink: 0; } From 903778cb8b2d450c3ca0ba8a872c1f233b2f5c88 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Fri, 17 Nov 2023 11:21:10 +0100 Subject: [PATCH 067/116] Unify the PostSchedule component between site and post editors (#56196) --- .../specs/editor/various/datepicker.test.js | 16 ++-- .../specs/editor/various/scheduling.test.js | 2 +- .../components/sidebar/post-schedule/index.js | 67 ------------- .../sidebar/post-schedule/style.scss | 36 ------- .../components/sidebar/post-status/index.js | 4 +- packages/edit-post/src/style.scss | 1 - .../page-panels/page-summary.js | 10 +- .../page-panels/publish-date.js | 94 ------------------- packages/editor/src/components/index.js | 1 + .../src/components/post-schedule/panel.js | 72 ++++++++++++++ .../src/components/post-schedule/style.scss | 30 ++++++ packages/editor/src/style.scss | 1 + 12 files changed, 117 insertions(+), 217 deletions(-) delete mode 100644 packages/edit-post/src/components/sidebar/post-schedule/index.js delete mode 100644 packages/edit-post/src/components/sidebar/post-schedule/style.scss delete mode 100644 packages/edit-site/src/components/sidebar-edit-mode/page-panels/publish-date.js create mode 100644 packages/editor/src/components/post-schedule/panel.js create mode 100644 packages/editor/src/components/post-schedule/style.scss diff --git a/packages/e2e-tests/specs/editor/various/datepicker.test.js b/packages/e2e-tests/specs/editor/various/datepicker.test.js index b0fc3bf898d4a..6838fd56a2ba9 100644 --- a/packages/e2e-tests/specs/editor/various/datepicker.test.js +++ b/packages/e2e-tests/specs/editor/various/datepicker.test.js @@ -56,7 +56,7 @@ function formatDatePickerValues( async function getPublishingDate() { return page.$eval( - '.edit-post-post-schedule__toggle', + '.editor-post-schedule__dialog-toggle', ( dateLabel ) => dateLabel.textContent ); } @@ -83,7 +83,7 @@ describe.each( [ [ 'UTC-10' ], [ 'UTC' ], [ 'UTC+10' ] ] )( it( 'should show the publishing date if the date is in the past', async () => { // Open the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); // Change the publishing date to a year in the past. await page.click( '.components-datetime__time-field-year' ); @@ -91,7 +91,7 @@ describe.each( [ [ 'UTC-10' ], [ 'UTC' ], [ 'UTC+10' ] ] )( const datePickerValues = await getDatePickerValues(); // Close the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); const publishingDate = await getPublishingDate(); @@ -102,7 +102,7 @@ describe.each( [ [ 'UTC-10' ], [ 'UTC' ], [ 'UTC+10' ] ] )( it( 'should show the publishing date if the date is in the future', async () => { // Open the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); // Change the publishing date to a year in the future. await page.click( '.components-datetime__time-field-year' ); @@ -110,7 +110,7 @@ describe.each( [ [ 'UTC-10' ], [ 'UTC' ], [ 'UTC+10' ] ] )( const datePickerValues = await getDatePickerValues(); // Close the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); const publishingDate = await getPublishingDate(); @@ -123,17 +123,17 @@ describe.each( [ [ 'UTC-10' ], [ 'UTC' ], [ 'UTC+10' ] ] )( it( `should show the publishing date as "Immediately" if the date is cleared`, async () => { // Open the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); // Change the publishing date to a year in the future. await page.click( '.components-datetime__time-field-year' ); await page.keyboard.press( 'ArrowUp' ); // Close the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); // Open the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); // Clear the date. await page.click( diff --git a/packages/e2e-tests/specs/editor/various/scheduling.test.js b/packages/e2e-tests/specs/editor/various/scheduling.test.js index 61c3541c1f47e..df75dcb92f282 100644 --- a/packages/e2e-tests/specs/editor/various/scheduling.test.js +++ b/packages/e2e-tests/specs/editor/various/scheduling.test.js @@ -46,7 +46,7 @@ describe( 'Scheduling', () => { await page.keyboard.press( 'ArrowUp' ); // Close the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); expect( await getPublishButtonText() ).toBe( 'Schedule…' ); } ); diff --git a/packages/edit-post/src/components/sidebar/post-schedule/index.js b/packages/edit-post/src/components/sidebar/post-schedule/index.js deleted file mode 100644 index 3b20880d73647..0000000000000 --- a/packages/edit-post/src/components/sidebar/post-schedule/index.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * WordPress dependencies - */ -import { __, sprintf } from '@wordpress/i18n'; -import { PanelRow, Dropdown, Button } from '@wordpress/components'; -import { useState, useMemo } from '@wordpress/element'; -import { - PostSchedule as PostScheduleForm, - PostScheduleCheck, - usePostScheduleLabel, -} from '@wordpress/editor'; - -export default function PostSchedule() { - // Use internal state instead of a ref to make sure that the component - // re-renders when the popover's anchor updates. - const [ popoverAnchor, setPopoverAnchor ] = useState( null ); - // Memoize popoverProps to avoid returning a new object every time. - const popoverProps = useMemo( - () => ( { anchor: popoverAnchor, placement: 'bottom-end' } ), - [ popoverAnchor ] - ); - - return ( - - - { __( 'Publish' ) } - ( - - ) } - renderContent={ ( { onClose } ) => ( - - ) } - /> - - - ); -} - -function PostScheduleToggle( { isOpen, onClick } ) { - const label = usePostScheduleLabel(); - const fullLabel = usePostScheduleLabel( { full: true } ); - return ( - - ); -} diff --git a/packages/edit-post/src/components/sidebar/post-schedule/style.scss b/packages/edit-post/src/components/sidebar/post-schedule/style.scss deleted file mode 100644 index 46fcd81964004..0000000000000 --- a/packages/edit-post/src/components/sidebar/post-schedule/style.scss +++ /dev/null @@ -1,36 +0,0 @@ -.edit-post-post-schedule { - width: 100%; - position: relative; - justify-content: flex-start; - align-items: flex-start; - - span { - display: block; - width: 30%; - margin-right: 8px; - } -} - -.edit-post-post-schedule__dropdown { - width: 70%; -} - -.components-button.edit-post-post-schedule__toggle { - text-align: left; - white-space: normal; - height: auto; - - // This span is added by the Popover in Tooltip when no anchor is - // provided. We set its width to 0 so that it does not cause the button text - // to wrap to a new line when displaying the tooltip. A better fix would be - // to pass anchorRef and avoid the need for a span alltogether, which is - // what this PR allows us to do: - // https://github.com/WordPress/gutenberg/pull/41268. - span { - width: 0; - } -} - -.edit-post-post-schedule__dialog .block-editor-publish-date-time-picker { - margin: $grid-unit-10; -} diff --git a/packages/edit-post/src/components/sidebar/post-status/index.js b/packages/edit-post/src/components/sidebar/post-status/index.js index d903cbb2fa12b..c8c5a20adcfab 100644 --- a/packages/edit-post/src/components/sidebar/post-status/index.js +++ b/packages/edit-post/src/components/sidebar/post-status/index.js @@ -8,6 +8,7 @@ import { } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { + PostSchedulePanel, PostSwitchToDraftButton, PostSyncStatus, PostURLPanel, @@ -18,7 +19,6 @@ import { */ import PostVisibility from '../post-visibility'; import PostTrash from '../post-trash'; -import PostSchedule from '../post-schedule'; import PostSticky from '../post-sticky'; import PostAuthor from '../post-author'; import PostSlug from '../post-slug'; @@ -61,7 +61,7 @@ export default function PostStatus() { { ( fills ) => ( <> - + diff --git a/packages/edit-post/src/style.scss b/packages/edit-post/src/style.scss index 7a71d20ba0f1f..89a5c4483b97e 100644 --- a/packages/edit-post/src/style.scss +++ b/packages/edit-post/src/style.scss @@ -12,7 +12,6 @@ @import "./components/sidebar/last-revision/style.scss"; @import "./components/sidebar/post-author/style.scss"; @import "./components/sidebar/post-format/style.scss"; -@import "./components/sidebar/post-schedule/style.scss"; @import "./components/sidebar/post-slug/style.scss"; @import "./components/sidebar/post-template/style.scss"; @import "./components/sidebar/post-visibility/style.scss"; diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js index 26fa86c933f11..e847ec11953b1 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js @@ -2,13 +2,12 @@ * WordPress dependencies */ import { __experimentalVStack as VStack } from '@wordpress/components'; -import { PostURLPanel } from '@wordpress/editor'; +import { PostURLPanel, PostSchedulePanel } from '@wordpress/editor'; /** * Internal dependencies */ import PageStatus from './page-status'; -import PublishDate from './publish-date'; import EditTemplate from './edit-template'; export default function PageSummary( { @@ -27,12 +26,7 @@ export default function PageSummary( { postId={ postId } postType={ postType } /> - + diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/publish-date.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/publish-date.js deleted file mode 100644 index d000394f6816b..0000000000000 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/publish-date.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * WordPress dependencies - */ -import { - Button, - Dropdown, - __experimentalText as Text, - __experimentalHStack as HStack, -} from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; -import { useDispatch } from '@wordpress/data'; -import { useState, useMemo } from '@wordpress/element'; -import { store as coreStore } from '@wordpress/core-data'; -import { store as noticesStore } from '@wordpress/notices'; -import { __experimentalPublishDateTimePicker as PublishDateTimePicker } from '@wordpress/block-editor'; -import { humanTimeDiff } from '@wordpress/date'; - -export default function ChangeStatus( { postType, postId, status, date } ) { - const { editEntityRecord } = useDispatch( coreStore ); - const { createErrorNotice } = useDispatch( noticesStore ); - - const [ popoverAnchor, setPopoverAnchor ] = useState( null ); - // Memoize popoverProps to avoid returning a new object every time. - const popoverProps = useMemo( - () => ( { - // Anchor the popover to the middle of the entire row so that it doesn't - // move around when the label changes. - anchor: popoverAnchor, - 'aria-label': __( 'Change publish date' ), - placement: 'bottom-end', - } ), - [ popoverAnchor ] - ); - - const saveDate = async ( newDate ) => { - try { - let newStatus = status; - if ( status === 'future' && new Date( newDate ) < new Date() ) { - newStatus = 'publish'; - } else if ( - status === 'publish' && - new Date( newDate ) > new Date() - ) { - newStatus = 'future'; - } - await editEntityRecord( 'postType', postType, postId, { - status: newStatus, - date: newDate, - } ); - } catch ( error ) { - const errorMessage = - error.message && error.code !== 'unknown_error' - ? error.message - : __( 'An error occurred while updating the status' ); - - createErrorNotice( errorMessage, { - type: 'snackbar', - } ); - } - }; - - const relateToNow = date ? humanTimeDiff( date ) : __( 'Immediately' ); - - return ( - - - { __( 'Publish' ) } - - ( - - ) } - renderContent={ ( { onClose } ) => ( - - ) } - /> - - ); -} diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js index bcfccc026ff72..a5a4fc7fcac36 100644 --- a/packages/editor/src/components/index.js +++ b/packages/editor/src/components/index.js @@ -50,6 +50,7 @@ export { default as PostScheduleLabel, usePostScheduleLabel, } from './post-schedule/label'; +export { default as PostSchedulePanel } from './post-schedule/panel'; export { default as PostSlug } from './post-slug'; export { default as PostSlugCheck } from './post-slug/check'; export { default as PostSticky } from './post-sticky'; diff --git a/packages/editor/src/components/post-schedule/panel.js b/packages/editor/src/components/post-schedule/panel.js new file mode 100644 index 0000000000000..834e7237e0e94 --- /dev/null +++ b/packages/editor/src/components/post-schedule/panel.js @@ -0,0 +1,72 @@ +/** + * WordPress dependencies + */ +import { + Button, + Dropdown, + __experimentalHStack as HStack, +} from '@wordpress/components'; +import { __, sprintf } from '@wordpress/i18n'; +import { useState, useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import PostScheduleCheck from './check'; +import PostScheduleForm from './index'; +import { usePostScheduleLabel } from './label'; + +export default function PostSchedulePanel() { + const [ popoverAnchor, setPopoverAnchor ] = useState( null ); + // Memoize popoverProps to avoid returning a new object every time. + const popoverProps = useMemo( + () => ( { + // Anchor the popover to the middle of the entire row so that it doesn't + // move around when the label changes. + anchor: popoverAnchor, + 'aria-label': __( 'Change publish date' ), + placement: 'bottom-end', + } ), + [ popoverAnchor ] + ); + + const label = usePostScheduleLabel(); + const fullLabel = usePostScheduleLabel( { full: true } ); + + return ( + + + { __( 'Publish' ) } + ( + + ) } + renderContent={ ( { onClose } ) => ( + + ) } + /> + + + ); +} diff --git a/packages/editor/src/components/post-schedule/style.scss b/packages/editor/src/components/post-schedule/style.scss new file mode 100644 index 0000000000000..d70a9e9576fbb --- /dev/null +++ b/packages/editor/src/components/post-schedule/style.scss @@ -0,0 +1,30 @@ +.editor-post-schedule__panel { + width: 100%; + justify-content: flex-start; + align-items: flex-start; + + span { + display: block; + width: 30%; + } +} + +.editor-post-schedule__panel-dropdown { + width: 70%; +} + +.editor-post-schedule__dialog { + .components-popover__content { + min-width: 320px; + padding: $grid-unit-20; + } +} + +.editor-post-schedule__dialog-toggle { + display: block; + max-width: 100%; + overflow: hidden; + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss index dbffbbef4d521..5428bf5cb1f15 100644 --- a/packages/editor/src/style.scss +++ b/packages/editor/src/style.scss @@ -11,6 +11,7 @@ @import "./components/post-publish-button/style.scss"; @import "./components/post-publish-panel/style.scss"; @import "./components/post-saved-state/style.scss"; +@import "./components/post-schedule/style.scss"; @import "./components/post-sync-status/style.scss"; @import "./components/post-taxonomies/style.scss"; @import "./components/post-text-editor/style.scss"; From cc426adab1b187298b32dbb8cb4e10dca44ae40d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Fri, 17 Nov 2023 13:43:24 +0100 Subject: [PATCH 068/116] DataViews: update field API to generate filters based on type (#55996) --- .../src/components/dataviews/README.md | 4 +- .../src/components/dataviews/add-filter.js | 18 ++++----- .../src/components/dataviews/filters.js | 37 ++++++++----------- .../src/components/dataviews/in-filter.js | 1 + .../src/components/dataviews/view-list.js | 15 ++++---- .../src/components/page-pages/index.js | 4 +- 6 files changed, 38 insertions(+), 41 deletions(-) diff --git a/packages/edit-site/src/components/dataviews/README.md b/packages/edit-site/src/components/dataviews/README.md index 8f1349044d6cf..0645f22821cb9 100644 --- a/packages/edit-site/src/components/dataviews/README.md +++ b/packages/edit-site/src/components/dataviews/README.md @@ -154,11 +154,11 @@ Example: { item.author } ); }, + type: 'enumeration', elements: [ { value: 1, label: 'Admin' } { value: 2, label: 'User' } ] - filters: [ 'in' ], enableSorting: false } ] @@ -169,7 +169,7 @@ Example: - `getValue`: function that returns the value of the field. - `render`: function that renders the field. - `elements`: the set of valid values for the field's value. -- `filters`: what filter operators are available for the user to use over this field. Only `in` available at the moment. +- `type`: the type of the field. Used to generate the proper filters. Only `enumeration` available at the moment. - `enableSorting`: whether the data can be sorted by the given field. True by default. - `enableHiding`: whether the field can be hidden. True by default. diff --git a/packages/edit-site/src/components/dataviews/add-filter.js b/packages/edit-site/src/components/dataviews/add-filter.js index 2cc0051f0f2d4..374a90eab9df0 100644 --- a/packages/edit-site/src/components/dataviews/add-filter.js +++ b/packages/edit-site/src/components/dataviews/add-filter.js @@ -22,28 +22,28 @@ const { DropdownMenuItemV2, } = unlock( componentsPrivateApis ); -const VALID_OPERATORS = [ OPERATOR_IN ]; +// TODO: find a place where these constants can be shared across components. +const ENUMERATION_TYPE = 'enumeration'; export default function AddFilter( { fields, view, onChangeView } ) { const filters = []; fields.forEach( ( field ) => { - if ( ! field.filters ) { + if ( ! field.type ) { return; } - field.filters.forEach( ( filter ) => { - if ( VALID_OPERATORS.some( ( operator ) => operator === filter ) ) { + switch ( field.type ) { + case ENUMERATION_TYPE: filters.push( { field: field.id, name: field.header, - operator: filter, elements: field.elements || [], isVisible: view.filters.some( - ( f ) => f.field === field.id && f.operator === filter + ( f ) => + f.field === field.id && f.operator === OPERATOR_IN ), } ); - } - } ); + } } ); if ( filters.length === 0 ) { @@ -92,7 +92,7 @@ export default function AddFilter( { fields, view, onChangeView } ) { ...currentView.filters, { field: filter.field, - operator: 'in', + operator: OPERATOR_IN, value: element.value, }, ], diff --git a/packages/edit-site/src/components/dataviews/filters.js b/packages/edit-site/src/components/dataviews/filters.js index 9c37a7501a155..72ba28fd06326 100644 --- a/packages/edit-site/src/components/dataviews/filters.js +++ b/packages/edit-site/src/components/dataviews/filters.js @@ -10,21 +10,20 @@ import { default as InFilter, OPERATOR_IN } from './in-filter'; import AddFilter from './add-filter'; import ResetFilters from './reset-filters'; -const VALID_OPERATORS = [ OPERATOR_IN ]; +const ENUMERATION_TYPE = 'enumeration'; export default function Filters( { fields, view, onChangeView } ) { const filters = []; fields.forEach( ( field ) => { - if ( ! field.filters ) { + if ( ! field.type ) { return; } - field.filters.forEach( ( filter ) => { - if ( VALID_OPERATORS.some( ( operator ) => operator === filter ) ) { + switch ( field.type ) { + case ENUMERATION_TYPE: filters.push( { field: field.id, name: field.header, - operator: filter, elements: [ { value: '', @@ -33,30 +32,26 @@ export default function Filters( { fields, view, onChangeView } ) { ...( field.elements || [] ), ], isVisible: view.filters.some( - ( f ) => f.field === field.id && f.operator === filter + ( f ) => + f.field === field.id && f.operator === OPERATOR_IN ), } ); - } - } ); + } } ); - const filterComponents = filters?.map( ( filter ) => { + const filterComponents = filters.map( ( filter ) => { if ( ! filter.isVisible ) { return null; } - if ( OPERATOR_IN === filter.operator ) { - return ( - - ); - } - - return null; + return ( + + ); } ); filterComponents.push( diff --git a/packages/edit-site/src/components/dataviews/in-filter.js b/packages/edit-site/src/components/dataviews/in-filter.js index 4154e0576101c..cb76bab0f870a 100644 --- a/packages/edit-site/src/components/dataviews/in-filter.js +++ b/packages/edit-site/src/components/dataviews/in-filter.js @@ -7,6 +7,7 @@ import { } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; +// TODO: find a place where these constants can be shared across components. export const OPERATOR_IN = 'in'; export default ( { filter, view, onChangeView } ) => { diff --git a/packages/edit-site/src/components/dataviews/view-list.js b/packages/edit-site/src/components/dataviews/view-list.js index 2fec328631423..fc8b407502579 100644 --- a/packages/edit-site/src/components/dataviews/view-list.js +++ b/packages/edit-site/src/components/dataviews/view-list.js @@ -52,6 +52,11 @@ const sortingItemsInfo = { desc: { icon: arrowDown, label: __( 'Sort descending' ) }, }; const sortIcons = { asc: chevronUp, desc: chevronDown }; + +// TODO: find a place where these constants can be shared across components. +const ENUMERATION_TYPE = 'enumeration'; +const OPERATOR_IN = 'in'; + function HeaderMenu( { dataView, header } ) { if ( header.isPlaceholder ) { return null; @@ -68,12 +73,7 @@ function HeaderMenu( { dataView, header } ) { const sortedDirection = header.column.getIsSorted(); let filter; - if ( - header.column.columnDef.filters?.length > 0 && - header.column.columnDef.filters.some( - ( f ) => 'string' === typeof f && f === 'in' - ) - ) { + if ( header.column.columnDef.type === ENUMERATION_TYPE ) { filter = { field: header.column.columnDef.id, elements: [ @@ -202,7 +202,8 @@ function HeaderMenu( { dataView, header } ) { return ( field !== filter.field || - operator !== 'in' + operator !== + OPERATOR_IN ); } ); diff --git a/packages/edit-site/src/components/page-pages/index.js b/packages/edit-site/src/components/page-pages/index.js index c2461adc34f8d..d6c295dc72ff0 100644 --- a/packages/edit-site/src/components/page-pages/index.js +++ b/packages/edit-site/src/components/page-pages/index.js @@ -227,7 +227,7 @@ export default function PagePages() { ); }, - filters: [ 'in' ], + type: 'enumeration', elements: authors?.map( ( { id, name } ) => ( { value: id, @@ -240,7 +240,7 @@ export default function PagePages() { getValue: ( { item } ) => STATUSES.find( ( { value } ) => value === item.status ) ?.label ?? item.status, - filters: [ 'in' ], + type: 'enumeration', elements: STATUSES, enableSorting: false, }, From 22dcbde7c2f61d7534f262c3c38fe277063821ea Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Fri, 17 Nov 2023 22:01:32 +0900 Subject: [PATCH 069/116] Image Block: Enable image block to be selected correctly when clicked (#56043) * Image Block: Enable image blocks to be selected correctly when clicked * Add tabIndex * Update packages/block-library/src/image/editor.scss Co-authored-by: Ramon * Wrap img element directly to make the image resizable * Use `display:inline` instead of `display:inline-block` --------- Co-authored-by: Ramon --- packages/block-library/src/image/editor.scss | 7 -- packages/block-library/src/image/image.js | 77 ++++++++++++-------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/packages/block-library/src/image/editor.scss b/packages/block-library/src/image/editor.scss index e172192836214..934682ed91b7d 100644 --- a/packages/block-library/src/image/editor.scss +++ b/packages/block-library/src/image/editor.scss @@ -62,13 +62,6 @@ figure.wp-block-image:not(.wp-block) { left: 50%; transform: translate(-50%, -50%); } - - // When the Image block is linked, - // it's wrapped with a disabled tag. - // Restore cursor style so it doesn't appear 'clickable'. - > a { - cursor: default; - } } // This is necessary for the editor resize handles to accurately work on a non-floated, non-resized, small image. diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index ae5f749fff3b5..64eb03adedb32 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -83,9 +83,29 @@ const scaleOptions = [ }, ]; -const disabledClickProps = { - onClick: ( event ) => event.preventDefault(), - 'aria-disabled': true, +// If the image has a href, wrap in an tag to trigger any inherited link element styles. +const ImageWrapper = ( { href, children } ) => { + if ( ! href ) { + return children; + } + return ( + event.preventDefault() } + aria-disabled={ true } + style={ { + // When the Image block is linked, + // it's wrapped with a disabled tag. + // Restore cursor style so it doesn't appear 'clickable' + // and remove pointer events. Safari needs the display property. + pointerEvents: 'none', + cursor: 'default', + display: 'inline', + } } + > + { children } + + ); }; export default function Image( { @@ -653,25 +673,31 @@ export default function Image( { if ( canEditImage && isEditingImage ) { img = ( - - setAttributes( imageAttributes ) - } - onFinishEditing={ () => { - setIsEditingImage( false ); - } } - borderProps={ isRounded ? undefined : borderProps } - /> + + + setAttributes( imageAttributes ) + } + onFinishEditing={ () => { + setIsEditingImage( false ); + } } + borderProps={ isRounded ? undefined : borderProps } + /> + ); } else if ( ! isResizable ) { - img =
{ img }
; + img = ( +
+ { img } +
+ ); } else { const numericRatio = aspectRatio && evalAspectRatio( aspectRatio ); const customRatio = numericWidth / numericHeight; @@ -774,7 +800,7 @@ export default function Image( { } } resizeRatio={ align === 'center' ? 2 : 1 } > - { img } + { img } ); } @@ -788,14 +814,7 @@ export default function Image( { { /* Hide controls during upload to avoid component remount, which causes duplicated image upload. */ } { ! temporaryURL && controls } - { /* If the image has a href, wrap in an tag to trigger any inherited link element styles */ } - { !! href ? ( - - { img } - - ) : ( - img - ) } + { img } { showCaption && ( ! RichText.isEmpty( caption ) || isSelected ) && ( Date: Fri, 17 Nov 2023 08:26:46 -0500 Subject: [PATCH 070/116] Update reference to the gutenberg-examples repo to the new block-development-examples repo. (#56119) --- docs/README.md | 4 ++-- docs/how-to-guides/block-tutorial/README.md | 4 ++-- .../block-tutorial/applying-styles-with-stylesheets.md | 4 ++-- .../block-tutorial/creating-dynamic-blocks.md | 2 +- .../block-tutorial/writing-your-first-block-type.md | 8 ++++---- docs/how-to-guides/data-basics/1-data-basics-setup.md | 2 +- .../data-basics/2-building-a-list-of-pages.md | 2 +- docs/how-to-guides/data-basics/3-building-an-edit-form.md | 2 +- .../data-basics/4-building-a-create-page-form.md | 2 +- .../how-to-guides/data-basics/5-adding-a-delete-button.md | 2 +- docs/how-to-guides/data-basics/README.md | 2 +- docs/how-to-guides/format-api.md | 4 ++-- docs/how-to-guides/javascript/js-build-setup.md | 4 ++-- docs/how-to-guides/metabox.md | 2 +- docs/how-to-guides/plugin-sidebar-0.md | 4 ++-- 15 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/README.md b/docs/README.md index d04df59e95752..219c622dc3d73 100644 --- a/docs/README.md +++ b/docs/README.md @@ -58,7 +58,7 @@ This handbook should be considered the canonical resource for all things related - [**WordPress Developer Blog**](https://developer.wordpress.org/news/) - An ever-growing resource of technical articles covering specific topics related to block development and a wide variety of use cases. The blog is also an excellent way to [keep up with the latest developments in WordPress](https://developer.wordpress.org/news/tag/roundup/). - [**Learn WordPress**](https://learn.wordpress.org/) - The WordPress hub for learning resources where you can find courses like [Introduction to Block Development: Build your first custom block](https://learn.wordpress.org/course/introduction-to-block-development-build-your-first-custom-block/), [Converting a Shortcode to a Block](https://learn.wordpress.org/course/converting-a-shortcode-to-a-block/) or [Using the WordPress Data Layer](https://learn.wordpress.org/course/using-the-wordpress-data-layer/) - [**WordPress.tv**](https://wordpress.tv/) - A hub of WordPress-related videos (from talks at WordCamps to recordings of online workshops) curated and moderated by the WordPress.org community. You’re sure to find something to aid your learning about [block development](https://wordpress.tv/?s=block%20development&sort=newest) or the [block-editor](https://wordpress.tv/?s=block%20editor&sort=relevance) here. -- [**Gutenberg repository**](https://github.com/WordPress/gutenberg/) - Development of the block editor project is carried out in this GitHub repository. It contains the code of interesting packages such as [`block-library`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src) (core blocks) or [`components`](https://github.com/WordPress/gutenberg/tree/trunk/packages/components) (common UI elements). _The [gutenberg-examples](https://github.com/WordPress/gutenberg-examples) repository is another useful reference._ +- [**Gutenberg repository**](https://github.com/WordPress/gutenberg/) - Development of the block editor project is carried out in this GitHub repository. It contains the code of interesting packages such as [`block-library`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src) (core blocks) or [`components`](https://github.com/WordPress/gutenberg/tree/trunk/packages/components) (common UI elements). _The [block-development-examples](https://github.com/WordPress/block-development-examples) repository is another useful reference._ ## Are you in the right place? @@ -70,4 +70,4 @@ This handbook should be considered the canonical resource for all things related - [/apis](https://developer.wordpress.org/apis) - Common APIs Handbook - [/advanced-administration](https://developer.wordpress.org/advanced-administration) - WP Advanced Administration Handbook - [/rest-api](https://developer.wordpress.org/rest-api/) - REST API Handbook -- [/coding-standards](https://developer.wordpress.org/coding-standards) - Best practices for WordPress developers \ No newline at end of file +- [/coding-standards](https://developer.wordpress.org/coding-standards) - Best practices for WordPress developers diff --git a/docs/how-to-guides/block-tutorial/README.md b/docs/how-to-guides/block-tutorial/README.md index 95aa4182430c0..8688bd09416d7 100644 --- a/docs/how-to-guides/block-tutorial/README.md +++ b/docs/how-to-guides/block-tutorial/README.md @@ -2,9 +2,9 @@ The purpose of this tutorial is to step through the fundamentals of creating a new block type. Beginning with the simplest possible example, each new section will incrementally build upon the last to include more of the common functionality you could expect to need when implementing your own block types. -To follow along with this tutorial, you can download the [accompanying WordPress plugin](https://github.com/WordPress/gutenberg-examples) which includes all of the examples for you to try on your own site. At each step along the way, experiment by modifying the examples with your own ideas, and observe the effects they have on the block's behavior. +To follow along with this tutorial, you can download the [accompanying WordPress plugin](https://github.com/WordPress/block-development-examples) which includes all of the examples for you to try on your own site. At each step along the way, experiment by modifying the examples with your own ideas, and observe the effects they have on the block's behavior. -> To find the latest version of the .zip file go to the repo's [releases page](https://github.com/WordPress/gutenberg-examples/releases) and look in the latest release under 'Assets'. +> To find the latest version of the .zip file go to the repo's [releases page](https://github.com/WordPress/block-development-examples/releases) and look in the latest release under 'Assets'. Code snippets are provided in two formats "JSX" and "Plain". JSX refers to JavaScript code that uses JSX syntax which requires a build step. Plain refers to "classic" JavaScript that does not require building. You can change between them using tabs found above each code example. Using JSX, does require you to run [the JavaScript build step](/docs/how-to-guides/javascript/js-build-setup/) to compile your code to a browser compatible format. diff --git a/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md b/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md index 2cd79198b70b9..e24231c5cf13a 100644 --- a/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md +++ b/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md @@ -199,7 +199,7 @@ Use the `editorStyle` property to a CSS file you want to load in the editor view It is worth noting that, if the editor content is iframed, both of these will load in the iframe. `editorStyle` will also load outside the iframe, so it can -be used for editor content as well as UI. +be used for editor content as well as UI. For example: @@ -249,4 +249,4 @@ The files will automatically be enqueued when specified in the block.json. This guide showed a couple of different ways to apply styles to your block, by either inline or in its own style sheet. Both of these methods use the `useBlockProps` hook, see the [block wrapper reference documentation](/docs/reference-guides/block-api/block-edit-save.md#block-wrapper-props) for additional details. -See the complete [example-02-stylesheets](https://github.com/WordPress/gutenberg-examples/tree/trunk/blocks-non-jsx/02-stylesheets) code in the [gutenberg-examples repository](https://github.com/WordPress/gutenberg-examples). +See the complete [stylesheets-79a4c3](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/stylesheets-79a4c3) code in the [block-development-examples repository](https://github.com/WordPress/block-development-examples). diff --git a/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md b/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md index f8d4041c4542e..b70d1956d681b 100644 --- a/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md +++ b/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md @@ -221,4 +221,4 @@ registerBlockType( 'gutenberg-examples/example-dynamic', { {% end %} -Note that this code uses the `wp-server-side-render` package but not `wp-data`. Make sure to update the dependencies in the PHP code. You can use wp-scripts to automatically build dependencies (see the [gutenberg-examples repo](https://github.com/WordPress/gutenberg-examples/tree/trunk/blocks-jsx/01-basic-esnext) for PHP code setup). +Note that this code uses the `wp-server-side-render` package but not `wp-data`. Make sure to update the dependencies in the PHP code. You can use wp-scripts to automatically build dependencies (see the [block-development-examples repo](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/basic-esnext-a2ab62) for PHP code setup). diff --git a/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md b/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md index a9dfc0d51a682..c17045372a65e 100644 --- a/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md +++ b/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md @@ -207,11 +207,11 @@ When you save the post and view it published, you will see the `Hola mundo (from ## Conclusion -This shows the most basic static block. The [gutenberg-examples](https://github.com/WordPress/gutenberg-examples) repository has complete examples for both. +This shows the most basic static block. The [block-development-examples](https://github.com/WordPress/block-development-examples) repository has complete examples for both. -- [Basic Example with JSX build](https://github.com/WordPress/gutenberg-examples/tree/trunk/blocks-jsx/01-basic-esnext) +- [Basic Example with JSX build](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/basic-esnext-a2ab62) -- [Basic Example Plain JavaScript](https://github.com/WordPress/gutenberg-examples/tree/trunk/blocks-non-jsx/01-basic), +- [Basic Example Plain JavaScript](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/minimal-block-no-build-e621a6), **NOTE:** The examples include a more complete block setup with translation features included, it is recommended to follow those examples for a production block. The internationalization features were left out of this guide for simplicity and focusing on the very basics of a block. @@ -219,7 +219,7 @@ This shows the most basic static block. The [gutenberg-examples](https://github. A couple of things to note when creating your blocks: -- A block name must be prefixed with a namespace specific to your plugin. This helps prevent conflicts when more than one plugin registers a block with the same name. In this example, the namespace is `gutenberg-examples`. +- A block name must be prefixed with a namespace specific to your plugin. This helps prevent conflicts when more than one plugin registers a block with the same name. In this example, the namespace is `block-development-examples`. - Block names _must_ include only lowercase alphanumeric characters or dashes and start with a letter. Example: `my-plugin/my-custom-block`. diff --git a/docs/how-to-guides/data-basics/1-data-basics-setup.md b/docs/how-to-guides/data-basics/1-data-basics-setup.md index 3657b65791a65..e61db83c4ecbd 100644 --- a/docs/how-to-guides/data-basics/1-data-basics-setup.md +++ b/docs/how-to-guides/data-basics/1-data-basics-setup.md @@ -212,4 +212,4 @@ Congratulations! You are now ready to start building the app! - Previous part: [Introduction](/docs/how-to-guides/data-basics/README.md) - Next part: [Building a basic list of pages](/docs/how-to-guides/data-basics/2-building-a-list-of-pages.md) -- (optional) Review the [finished app](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/09-code-data-basics-esnext) in the gutenberg-examples repository +- (optional) Review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository diff --git a/docs/how-to-guides/data-basics/2-building-a-list-of-pages.md b/docs/how-to-guides/data-basics/2-building-a-list-of-pages.md index aee5575cdb5ad..8a0d172e45f45 100644 --- a/docs/how-to-guides/data-basics/2-building-a-list-of-pages.md +++ b/docs/how-to-guides/data-basics/2-building-a-list-of-pages.md @@ -446,4 +446,4 @@ All that’s left is to refresh the page and enjoy the brand new status indicato * **Previous part:** [Setup](/docs/how-to-guides/data-basics/1-data-basics-setup.md) * **Next part:** [Building an edit form](/docs/how-to-guides/data-basics/3-building-an-edit-form.md) -* (optional) Review the [finished app](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/09-code-data-basics-esnext) in the gutenberg-examples repository +* (optional) Review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository diff --git a/docs/how-to-guides/data-basics/3-building-an-edit-form.md b/docs/how-to-guides/data-basics/3-building-an-edit-form.md index 754a31f1bc492..68c8738170151 100644 --- a/docs/how-to-guides/data-basics/3-building-an-edit-form.md +++ b/docs/how-to-guides/data-basics/3-building-an-edit-form.md @@ -540,4 +540,4 @@ function EditPageForm( { pageId, onCancel, onSaveFinished } ) { * **Previous part:** [Building a list of pages](/docs/how-to-guides/data-basics/2-building-a-list-of-pages.md) * **Next part:** Building a *New Page* form (coming soon) -* (optional) Review the [finished app](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/09-code-data-basics-esnext) in the gutenberg-examples repository +* (optional) Review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository diff --git a/docs/how-to-guides/data-basics/4-building-a-create-page-form.md b/docs/how-to-guides/data-basics/4-building-a-create-page-form.md index 19aada07c2fc7..33c6e9a5ccff5 100644 --- a/docs/how-to-guides/data-basics/4-building-a-create-page-form.md +++ b/docs/how-to-guides/data-basics/4-building-a-create-page-form.md @@ -389,4 +389,4 @@ All that’s left is to refresh the page and enjoy the form: * **Next part:** [Adding a delete button](/docs/how-to-guides/data-basics/5-adding-a-delete-button.md) * **Previous part:** [Building an edit form](/docs/how-to-guides/data-basics/3-building-an-edit-form.md) -* (optional) Review the [finished app](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/09-code-data-basics-esnext) in the gutenberg-examples repository +* (optional) Review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository diff --git a/docs/how-to-guides/data-basics/5-adding-a-delete-button.md b/docs/how-to-guides/data-basics/5-adding-a-delete-button.md index 07b10ac822c54..e0a0b0d1e9337 100644 --- a/docs/how-to-guides/data-basics/5-adding-a-delete-button.md +++ b/docs/how-to-guides/data-basics/5-adding-a-delete-button.md @@ -446,4 +446,4 @@ function DeletePageButton( { pageId } ) { ## What's next? * **Previous part:** [Building a *Create page form*](/docs/how-to-guides/data-basics/4-building-a-create-page-form.md) -* (optional) Review the [finished app](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/09-code-data-basics-esnext) in the gutenberg-examples repository +* (optional) Review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository diff --git a/docs/how-to-guides/data-basics/README.md b/docs/how-to-guides/data-basics/README.md index 88e901a90e11d..3cb07eae2b659 100644 --- a/docs/how-to-guides/data-basics/README.md +++ b/docs/how-to-guides/data-basics/README.md @@ -4,7 +4,7 @@ This tutorial aims to get you comfortable with the Gutenberg data layer. It guid ![](https://raw.githubusercontent.com/WordPress/gutenberg/HEAD/docs/how-to-guides/data-basics/media/list-of-pages/part1-finished.jpg) -You may review the [finished app](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/09-code-data-basics-esnext) in the gutenberg-examples repository. +You may review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository. ### Table of Contents diff --git a/docs/how-to-guides/format-api.md b/docs/how-to-guides/format-api.md index a23293bbb27e3..00e1b82675c00 100644 --- a/docs/how-to-guides/format-api.md +++ b/docs/how-to-guides/format-api.md @@ -18,7 +18,7 @@ You will need: - A minimal plugin activated and setup ready to edit - JavaScript setup for building and enqueuing -The [complete format-api example](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/format-api) is available that you can use as a reference for your setup. +The [complete format-api example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/format-api-f14b86) is available that you can use as a reference for your setup. ## Step-by-step guide @@ -234,4 +234,4 @@ Reference documentation used in this guide: The guide showed you how to add a button to the toolbar and have it apply a format to the selected text. Try it out and see what you can build with it in your next plugin. -Download the [format-api example](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/format-api) from the [gutenberg-examples](https://github.com/WordPress/gutenberg-examples) repository. +Download the [format-api example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/format-api-f14b86) from the [block-development-examples](https://github.com/WordPress/block-development-examples) repository. diff --git a/docs/how-to-guides/javascript/js-build-setup.md b/docs/how-to-guides/javascript/js-build-setup.md index b915f4dd444f9..cf49154b590a9 100644 --- a/docs/how-to-guides/javascript/js-build-setup.md +++ b/docs/how-to-guides/javascript/js-build-setup.md @@ -22,7 +22,7 @@ The [@wordpress/scripts](https://www.npmjs.com/package/@wordpress/scripts) packa ## Quick Start -If you prefer a quick start, you can use one of the examples from the [Gutenberg Examples repository](https://github.com/wordpress/gutenberg-examples/) and skip below. Each one of the `-esnext` directories in the examples repository contain the necessary files for working with ESNext and JSX. +If you prefer a quick start, you can use one of the examples from the [Block Development Examples repository](https://github.com/wordpress/block-development-examples/) and skip below. Each one of the `-esnext` directories in the examples repository contain the necessary files for working with ESNext and JSX. ## Setup @@ -168,7 +168,7 @@ wp_register_script( ); ``` -See [ESNext blocks in gutenberg-examples repo](https://github.com/WordPress/gutenberg-examples) for full examples. +See [blocks in the block-development-examples repo](https://github.com/WordPress/block-development-examples) for full examples. ## Summary diff --git a/docs/how-to-guides/metabox.md b/docs/how-to-guides/metabox.md index 7a8686968d2cf..e0402b1180c1c 100644 --- a/docs/how-to-guides/metabox.md +++ b/docs/how-to-guides/metabox.md @@ -26,7 +26,7 @@ You will need: - A minimal plugin activated and ready to edit - JavaScript setup for building and enqueuing -A [complete meta-block example](https://github.com/WordPress/gutenberg-examples/tree/trunk/blocks-jsx/meta-block) is available that you can use as a reference for your setup. +A [complete meta-block example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/meta-block-bb1e55) is available that you can use as a reference for your setup. ## Step-by-step guide diff --git a/docs/how-to-guides/plugin-sidebar-0.md b/docs/how-to-guides/plugin-sidebar-0.md index 9543eaf876154..bf084680c3d1b 100644 --- a/docs/how-to-guides/plugin-sidebar-0.md +++ b/docs/how-to-guides/plugin-sidebar-0.md @@ -379,7 +379,7 @@ Functions used in this guide: You now have a custom sidebar that you can use to update `post_meta` content. -A complete example is available, download the [plugin-sidebar example](https://github.com/WordPress/gutenberg-examples/tree/trunk/blocks-non-jsx/plugin-sidebar) from the [gutenberg-examples](https://github.com/WordPress/gutenberg-examples) repository. +A complete example is available, download the [plugin-sidebar example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/plugin-sidebar-9ee4a6) from the [block-development-examples](https://github.com/WordPress/block-development-examples) repository. ### Note @@ -407,4 +407,4 @@ return el( TextControl, { document.querySelector( {the-value-textarea} ).innerHTML = content; }, } ); -``` \ No newline at end of file +``` From b827bed9a850d318f84d7ab114fc999e1c0489c5 Mon Sep 17 00:00:00 2001 From: Ryan Welcher Date: Fri, 17 Nov 2023 08:27:03 -0500 Subject: [PATCH 071/116] Remove all {% codetabs %} instances and any vanilla JS references. (#56121) --- .../applying-styles-with-stylesheets.md | 100 ------- .../block-controls-toolbar-and-sidebar.md | 92 ------- .../block-supports-in-static-blocks.md | 61 ----- .../block-tutorial/creating-dynamic-blocks.md | 81 +----- ...roducing-attributes-and-editable-fields.md | 61 ----- .../nested-blocks-inner-blocks.md | 161 +----------- .../writing-your-first-block-type.md | 60 +---- docs/how-to-guides/internationalization.md | 30 --- docs/how-to-guides/themes/theme-json.md | 72 ++--- .../block-api/block-attributes.md | 18 +- .../block-api/block-deprecation.md | 135 ---------- .../block-api/block-edit-save.md | 248 ------------------ .../filters/autocomplete-filters.md | 48 +--- .../reference-guides/filters/block-filters.md | 102 ------- docs/reference-guides/richtext.md | 43 +-- .../src/components/editable-text/README.md | 36 --- .../src/components/plain-text/README.md | 28 -- .../src/components/rich-text/README.md | 58 ---- .../src/components/url-input/README.md | 73 ------ 19 files changed, 35 insertions(+), 1472 deletions(-) diff --git a/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md b/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md index e24231c5cf13a..697984c9456e0 100644 --- a/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md +++ b/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md @@ -18,9 +18,6 @@ The first method shows adding the style inline. This transforms the defined styl The `useBlockProps` React hook is used to set and apply properties on the block's wrapper element. The following example shows how: -{% codetabs %} -{% JSX %} - ```jsx import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps } from '@wordpress/block-editor'; @@ -55,49 +52,6 @@ registerBlockType( 'gutenberg-examples/example-02-stylesheets', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, blockEditor ) { - var el = React.createElement; - - blocks.registerBlockType( 'gutenberg-examples/example-02-stylesheets', { - edit: function ( props ) { - const greenBackground = { - backgroundColor: '#090', - color: '#fff', - padding: '20px', - }; - const blockProps = blockEditor.useBlockProps( { - style: greenBackground, - } ); - return el( - 'p', - blockProps, - 'Hello World (from the editor, in green).' - ); - }, - save: function () { - const redBackground = { - backgroundColor: '#090', - color: '#fff', - padding: '20px', - }; - const blockProps = blockEditor.useBlockProps.save( { - style: redBackground, - } ); - return el( - 'p', - blockProps, - 'Hello World (from the frontend, in red).' - ); - }, - } ); -} )( window.wp.blocks, window.React, window.wp.blockEditor ); -``` - -{% end %} - ## Method 2: Block classname The inline style works well for a small amount of CSS to apply. If you have much more than the above you will likely find that it is easier to manage with them in a separate stylesheet file. @@ -106,9 +60,6 @@ The `useBlockProps` hooks includes the classname for the block automatically, it For example the block name: `gutenberg-examples/example-02-stylesheets` would get the classname: `wp-block-gutenberg-examples-example-02-stylesheets`. It might be a bit long but best to avoid conflicts with other blocks. -{% codetabs %} -{% JSX %} - ```jsx import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps } from '@wordpress/block-editor'; @@ -131,66 +82,15 @@ registerBlockType( 'gutenberg-examples/example-02-stylesheets', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, blockEditor ) { - var el = React.createElement; - - blocks.registerBlockType( 'gutenberg-examples/example-02-stylesheets', { - edit: function ( props ) { - var blockProps = blockEditor.useBlockProps(); - return el( - 'p', - blockProps, - 'Hello World (from the editor, in green).' - ); - }, - save: function () { - var blockProps = blockEditor.useBlockProps.save(); - return el( - 'p', - blockProps, - 'Hello World (from the frontend, in red).' - ); - }, - } ); -} )( window.wp.blocks, window.React, window.wp.blockEditor ); -``` - -{% end %} - ### Build or add dependency In order to include the blockEditor as a dependency, make sure to run the build step, or update the asset php file. -{% codetabs %} -{% JSX %} - Build the scripts and update the asset file which is used to keep track of dependencies and the build version. ```bash npm run build ``` -{% Plain %} - -Edit the asset file to include the block-editor dependency for the scripts. - -```php - - array( - 'react', - 'wp-blocks', - 'wp-block-editor', - 'wp-polyfill' - ), - 'version' => '0.1' - ); -``` - -{% end %} - ### Enqueue stylesheets Like scripts, you can enqueue your block's styles using the `block.json` file. diff --git a/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md b/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md index 1b3a54592b996..4436696b55261 100644 --- a/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md +++ b/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md @@ -10,9 +10,6 @@ When the user selects a block, a number of control buttons may be shown in a too You can also customize the toolbar to include controls specific to your block type. If the return value of your block type's `edit` function includes a `BlockControls` element, those controls will be shown in the selected block's toolbar. -{% codetabs %} -{% JSX %} - ```jsx import { registerBlockType } from '@wordpress/blocks'; @@ -92,95 +89,6 @@ registerBlockType( 'gutenberg-examples/example-04-controls-esnext', { } ); ``` -{% Plain %} - -```js -( function ( blocks, blockEditor, React ) { - var el = React.createElement; - var RichText = blockEditor.RichText; - var AlignmentToolbar = blockEditor.AlignmentToolbar; - var BlockControls = blockEditor.BlockControls; - var useBlockProps = blockEditor.useBlockProps; - - blocks.registerBlockType( 'gutenberg-examples/example-04-controls', { - title: 'Example: Controls', - icon: 'universal-access-alt', - category: 'design', - - attributes: { - content: { - type: 'string', - source: 'html', - selector: 'p', - }, - alignment: { - type: 'string', - default: 'none', - }, - }, - example: { - attributes: { - content: 'Hello World', - alignment: 'right', - }, - }, - edit: function ( props ) { - var content = props.attributes.content; - var alignment = props.attributes.alignment; - - function onChangeContent( newContent ) { - props.setAttributes( { content: newContent } ); - } - - function onChangeAlignment( newAlignment ) { - props.setAttributes( { - alignment: - newAlignment === undefined ? 'none' : newAlignment, - } ); - } - - return el( - 'div', - useBlockProps(), - el( - BlockControls, - { key: 'controls' }, - el( AlignmentToolbar, { - value: alignment, - onChange: onChangeAlignment, - } ) - ), - el( RichText, { - key: 'richtext', - tagName: 'p', - style: { textAlign: alignment }, - onChange: onChangeContent, - value: content, - } ) - ); - }, - - save: function ( props ) { - var blockProps = useBlockProps.save(); - - return el( - 'div', - blockProps, - el( RichText.Content, { - tagName: 'p', - className: - 'gutenberg-examples-align-' + - props.attributes.alignment, - value: props.attributes.content, - } ) - ); - }, - } ); -} )( window.wp.blocks, window.wp.blockEditor, window.React ); -``` - -{% end %} - Note that `BlockControls` is only visible when the block is currently selected and in visual editing mode. `BlockControls` are not shown when editing a block in HTML editing mode. ## Settings Sidebar diff --git a/docs/how-to-guides/block-tutorial/block-supports-in-static-blocks.md b/docs/how-to-guides/block-tutorial/block-supports-in-static-blocks.md index a6350470bb797..47fa3a86b75eb 100644 --- a/docs/how-to-guides/block-tutorial/block-supports-in-static-blocks.md +++ b/docs/how-to-guides/block-tutorial/block-supports-in-static-blocks.md @@ -8,8 +8,6 @@ Let's take the block we wrote in the previous chapter (example 3) and with just Here's the exact same code we used to register the block previously. -{% codetabs %} -{% JSX %} ```jsx import { registerBlockType } from '@wordpress/blocks'; @@ -64,65 +62,6 @@ registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { } ); ``` -{% Plain %} - -```js -( function ( blocks, blockEditor, React ) { - var el = React.createElement; - var RichText = blockEditor.RichText; - var useBlockProps = blockEditor.useBlockProps; - - blocks.registerBlockType( 'gutenberg-examples/example-03-editable', { - apiVersion: 3, - title: 'Example: Basic with block supports', - icon: 'universal-access-alt', - category: 'design', - - attributes: { - content: { - type: 'string', - source: 'html', - selector: 'p', - }, - }, - example: { - attributes: { - content: 'Hello World', - }, - }, - edit: function ( props ) { - var blockProps = useBlockProps(); - var content = props.attributes.content; - function onChangeContent( newContent ) { - props.setAttributes( { content: newContent } ); - } - - return el( - RichText, - Object.assign( blockProps, { - tagName: 'p', - onChange: onChangeContent, - value: content, - } ) - ); - }, - - save: function ( props ) { - var blockProps = useBlockProps.save(); - return el( - RichText.Content, - Object.assign( blockProps, { - tagName: 'p', - value: props.attributes.content, - } ) - ); - }, - } ); -} )( window.wp.blocks, window.wp.blockEditor, window.React ); -``` - -{% end %} - Now, let's alter the block.json file for that block, and add the supports key. (If you're not using a block.json file, you can also add the key to the `registerBlockType` function call) ```json diff --git a/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md b/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md index b70d1956d681b..89ef666abe494 100644 --- a/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md +++ b/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md @@ -17,8 +17,7 @@ Block attributes can be used for any content or setting you want to save for tha The following code example shows how to create a dynamic block that shows only the last post as a link. -{% codetabs %} -{% JSX %} + ```jsx import { registerBlockType } from '@wordpress/blocks'; @@ -52,47 +51,7 @@ registerBlockType( 'gutenberg-examples/example-dynamic', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, data, blockEditor ) { - var el = React.createElement, - registerBlockType = blocks.registerBlockType, - useSelect = data.useSelect, - useBlockProps = blockEditor.useBlockProps; - - registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 3, - title: 'Example: last post', - icon: 'megaphone', - category: 'widgets', - edit: function () { - var content; - var blockProps = useBlockProps(); - var posts = useSelect( function ( select ) { - return select( 'core' ).getEntityRecords( 'postType', 'post' ); - }, [] ); - if ( ! posts ) { - content = 'Loading...'; - } else if ( posts.length === 0 ) { - content = 'No posts'; - } else { - var post = posts[ 0 ]; - content = el( 'a', { href: post.link }, post.title.rendered ); - } - - return el( 'div', blockProps, content ); - }, - } ); -} )( - window.wp.blocks, - window.React, - window.wp.data, - window.wp.blockEditor -); -``` -{% end %} Because it is a dynamic block it doesn't need to override the default `save` implementation on the client. Instead, it needs a server component. The contents in the front of your site depend on the function called by the `render_callback` property of `register_block_type`. @@ -156,8 +115,7 @@ Gutenberg 2.8 added the [``](/packages/server-side-render/READ _Server-side render is meant as a fallback; client-side rendering in JavaScript is always preferred (client rendering is faster and allows better editor manipulation)._ -{% codetabs %} -{% JSX %} + ```jsx import { registerBlockType } from '@wordpress/blocks'; @@ -184,41 +142,6 @@ registerBlockType( 'gutenberg-examples/example-dynamic', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, serverSideRender, blockEditor ) { - var el = React.createElement, - registerBlockType = blocks.registerBlockType, - ServerSideRender = serverSideRender, - useBlockProps = blockEditor.useBlockProps; - - registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 3, - title: 'Example: last post', - icon: 'megaphone', - category: 'widgets', - - edit: function ( props ) { - var blockProps = useBlockProps(); - return el( - 'div', - blockProps, - el( ServerSideRender, { - block: 'gutenberg-examples/example-dynamic', - attributes: props.attributes, - } ) - ); - }, - } ); -} )( - window.wp.blocks, - window.React, - window.wp.serverSideRender, - window.wp.blockEditor -); -``` -{% end %} Note that this code uses the `wp-server-side-render` package but not `wp-data`. Make sure to update the dependencies in the PHP code. You can use wp-scripts to automatically build dependencies (see the [block-development-examples repo](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/basic-esnext-a2ab62) for PHP code setup). diff --git a/docs/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields.md b/docs/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields.md index 7586081af4216..3d8e10cae7ab2 100644 --- a/docs/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields.md +++ b/docs/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields.md @@ -52,8 +52,6 @@ Because `RichText` allows for nested nodes, you'll most often use it in conjunct Here is the complete block definition for Example 03. -{% codetabs %} -{% JSX %} ```jsx import { registerBlockType } from '@wordpress/blocks'; @@ -107,62 +105,3 @@ registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { }, } ); ``` - -{% Plain %} - -```js -( function ( blocks, blockEditor, React ) { - var el = React.createElement; - var RichText = blockEditor.RichText; - var useBlockProps = blockEditor.useBlockProps; - - blocks.registerBlockType( 'gutenberg-examples/example-03-editable', { - apiVersion: 3, - title: 'Example: Editable', - icon: 'universal-access-alt', - category: 'design', - - attributes: { - content: { - type: 'string', - source: 'html', - selector: 'p', - }, - }, - example: { - attributes: { - content: 'Hello World', - }, - }, - edit: function ( props ) { - var blockProps = useBlockProps(); - var content = props.attributes.content; - function onChangeContent( newContent ) { - props.setAttributes( { content: newContent } ); - } - - return el( - RichText, - Object.assign( blockProps, { - tagName: 'p', - onChange: onChangeContent, - value: content, - } ) - ); - }, - - save: function ( props ) { - var blockProps = useBlockProps.save(); - return el( - RichText.Content, - Object.assign( blockProps, { - tagName: 'p', - value: props.attributes.content, - } ) - ); - }, - } ); -} )( window.wp.blocks, window.wp.blockEditor, window.React ); -``` - -{% end %} diff --git a/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md b/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md index e2c37f341427e..9dc7f1f324743 100644 --- a/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md +++ b/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md @@ -6,8 +6,6 @@ Note: A single block can only contain one `InnerBlocks` component. Here is the basic InnerBlocks usage. -{% codetabs %} -{% JSX %} ```js import { registerBlockType } from '@wordpress/blocks'; @@ -38,35 +36,6 @@ registerBlockType( 'gutenberg-examples/example-06', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, blockEditor ) { - var el = React.createElement; - var InnerBlocks = blockEditor.InnerBlocks; - var useBlockProps = blockEditor.useBlockProps; - - blocks.registerBlockType( 'gutenberg-examples/example-06', { - title: 'Example: Inner Blocks', - category: 'design', - - edit: function () { - var blockProps = useBlockProps(); - - return el( 'div', blockProps, el( InnerBlocks ) ); - }, - - save: function () { - var blockProps = useBlockProps.save(); - - return el( 'div', blockProps, el( InnerBlocks.Content ) ); - }, - } ); -} )( window.wp.blocks, window.React, window.wp.blockEditor ); -``` - -{% end %} - ## Allowed Blocks Using the `allowedBlocks` property, you can define the set of blocks allowed in your InnerBlock. This restricts the blocks that can be included only to those listed, all other blocks will not show in the inserter. @@ -101,8 +70,6 @@ By default this behavior is disabled until the `directInsert` prop is set to `tr Use the template property to define a set of blocks that prefill the InnerBlocks component when inserted. You can set attributes on the blocks to define their use. The example below shows a book review template using InnerBlocks component and setting placeholders values to show the block usage. -{% codetabs %} -{% JSX %} ```js const MY_TEMPLATE = [ @@ -123,29 +90,6 @@ const MY_TEMPLATE = [ }, ``` -{% Plain %} - -```js -const MY_TEMPLATE = [ - [ 'core/image', {} ], - [ 'core/heading', { placeholder: 'Book Title' } ], - [ 'core/paragraph', { placeholder: 'Summary' } ], -]; - -//... - - edit: function( props ) { - return el( - InnerBlocks, - { - template: MY_TEMPLATE, - templateLock: "all", - } - ); - }, -``` - -{% end %} Use the `templateLock` property to lock down the template. Using `all` locks the template completely so no changes can be made. Using `insert` prevents additional blocks from being inserted, but existing blocks can be reordered. See [templateLock documentation](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-editor/src/components/inner-blocks/README.md#templatelock) for additional information. @@ -167,7 +111,7 @@ add_action( 'init', function() { ## Using Parent and Ancestor Relationships in Blocks -A common pattern for using InnerBlocks is to create a custom block that will be only be available if its parent block is inserted. This allows builders to establish a relationship between blocks, while limiting a nested block's discoverability. Currently, there are two relationships builders can use: `parent` and `ancestor`. The differences are: +A common pattern for using InnerBlocks is to create a custom block that will be only be available if its parent block is inserted. This allows builders to establish a relationship between blocks, while limiting a nested block's discoverability. Currently, there are two relationships builders can use: `parent` and `ancestor`. The differences are: - If you assign a `parent` then you’re stating that the nested block can only be used and inserted as a __direct descendant of the parent__. - If you assign an `ancestor` then you’re stating that the nested block can only be used and inserted as a __descendent of the parent__. @@ -214,8 +158,7 @@ The `useInnerBlocksProps` is exported from the `@wordpress/block-editor` package Here is the basic `useInnerBlocksProps` hook usage. -{% codetabs %} -{% JSX %} + ```js import { registerBlockType } from '@wordpress/blocks'; @@ -248,42 +191,9 @@ registerBlockType( 'gutenberg-examples/example-06', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, blockEditor ) { - var el = React.createElement; - var InnerBlocks = blockEditor.InnerBlocks; - var useBlockProps = blockEditor.useBlockProps; - var useInnerBlocksProps = blockEditor.useInnerBlocksProps; - - blocks.registerBlockType( 'gutenberg-examples/example-06', { - title: 'Example: Inner Blocks', - category: 'design', - - edit: function () { - var blockProps = useBlockProps(); - var innerBlocksProps = useInnerBlocksProps(); - - return el( 'div', blockProps, el( 'div', innerBlocksProps ) ); - }, - - save: function () { - var blockProps = useBlockProps.save(); - var innerBlocksProps = useInnerBlocksProps.save(); - - return el( 'div', blockProps, el( 'div', innerBlocksProps ) ); - }, - } ); -} )( window.wp.blocks, window.React, window.wp.blockEditor ); -``` - -{% end %} - This hook can also pass objects returned from the `useBlockProps` hook to the `useInnerBlocksProps` hook. This reduces the number of elements we need to create. -{% codetabs %} -{% JSX %} + ```js import { registerBlockType } from '@wordpress/blocks'; @@ -312,36 +222,6 @@ registerBlockType( 'gutenberg-examples/example-06', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, blockEditor ) { - var el = React.createElement; - var InnerBlocks = blockEditor.InnerBlocks; - var useBlockProps = blockEditor.useBlockProps; - var useInnerBlocksProps = blockEditor.useInnerBlocksProps; - - blocks.registerBlockType( 'gutenberg-examples/example-06', { - // ... - - edit: function () { - var blockProps = useBlockProps(); - var innerBlocksProps = useInnerBlocksProps(); - - return el( 'div', innerBlocksProps ); - }, - - save: function () { - var blockProps = useBlockProps.save(); - var innerBlocksProps = useInnerBlocksProps.save(); - - return el( 'div', innerBlocksProps ); - }, - } ); -} )( window.wp.blocks, window.React, window.wp.blockEditor ); -``` - -{% end %} The above code will render to the following markup in the editor: @@ -353,8 +233,6 @@ The above code will render to the following markup in the editor: Another benefit to using the hook approach is using the returned value, which is just an object, and deconstruct to get the react children from the object. This property contains the actual child inner blocks thus we can place elements on the same level as our inner blocks. -{% codetabs %} -{% JSX %} ```js import { registerBlockType } from '@wordpress/blocks'; @@ -379,39 +257,6 @@ registerBlockType( 'gutenberg-examples/example-06', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, blockEditor ) { - var el = React.createElement; - var InnerBlocks = blockEditor.InnerBlocks; - var useBlockProps = blockEditor.useBlockProps; - var useInnerBlocksProps = blockEditor.useInnerBlocksProps; - - blocks.registerBlockType( 'gutenberg-examples/example-06', { - // ... - - edit: function () { - var blockProps = useBlockProps(); - var { children, ...innerBlocksProps } = useInnerBlocksProps( blockProps ); - - return el( - 'div', - innerBlocksProps, - children, - el( - 'div', - {}, - '', - ) - ); - }, - // ... - } ); -} )( window.wp.blocks, window.React, window.wp.blockEditor ); -``` - -{% end %} ```html
diff --git a/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md b/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md index c17045372a65e..4a690984011e0 100644 --- a/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md +++ b/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md @@ -64,8 +64,6 @@ The `block.json` file should be added to your plugin. To start a new plugin, cre Create a basic `block.json` file there: -{% codetabs %} -{% JSX %} ```json { @@ -77,22 +75,6 @@ Create a basic `block.json` file there: "editorScript": "file:./build/index.js" } ``` - -{% Plain %} - -```json -{ - "apiVersion": 3, - "title": "Example: Basic", - "name": "gutenberg-examples/example-01-basic", - "category": "layout", - "icon": "universal-access-alt", - "editorScript": "file:./block.js" -} -``` - -{% end %} - ### Step 2: Register block in plugin With the `block.json` in place, the registration for the block is a single function call in PHP, this will setup the block and JavaScript file specified in the `editorScript` property to load in the editor. @@ -118,8 +100,6 @@ The `edit` function is a component that is shown in the editor when the block is The `save` function is a component that defines the final markup returned by the block and saved in `post_content`. -{% codetabs %} -{% JSX %} Add the following in `src/index.js` @@ -140,33 +120,12 @@ registerBlockType( 'gutenberg-examples/example-01-basic-esnext', { } ); ``` -{% Plain %} - -Add the following to `block.js` - -```js -( function ( blocks, React ) { - var el = React.createElement; - - blocks.registerBlockType( 'gutenberg-examples/example-01-basic', { - edit: function () { - return el( 'p', {}, 'Hello World (from the editor).' ); - }, - save: function () { - return el( 'p', {}, 'Hola mundo (from the frontend).' ); - }, - } ); -} )( window.wp.blocks, window.React ); -``` - -{% end %} ### Step 4: Build or add dependency In order to register the block, an asset php file is required in the same directory as the directory used in `register_block_type()` and must begin with the script's filename. -{% codetabs %} -{% JSX %} + Build the scripts and asset file which is used to keep track of dependencies and the build version. @@ -174,23 +133,6 @@ Build the scripts and asset file which is used to keep track of dependencies and npm run build ``` -{% Plain %} - -Create the asset file to load the dependencies for the scripts. The name of this file should be the name of the js file then .asset.php. For this example, create `block.asset.php` with the following: - -```php - - array( - 'react', - 'wp-blocks', - 'wp-polyfill' - ), - 'version' => '0.1' - ); -``` - -{% end %} ### Step 5: Confirm diff --git a/docs/how-to-guides/internationalization.md b/docs/how-to-guides/internationalization.md index c3194f309fca6..08ce46edb3f58 100644 --- a/docs/how-to-guides/internationalization.md +++ b/docs/how-to-guides/internationalization.md @@ -37,9 +37,6 @@ add_action( 'init', 'myguten_block_init' ); In your code, you can include the i18n functions. The most common function is **\_\_** (a double underscore) which provides translation of a simple string. Here is a basic block example: -{% codetabs %} -{% JSX %} - ```js import { __ } from '@wordpress/i18n'; import { registerBlockType } from '@wordpress/blocks'; @@ -64,33 +61,6 @@ registerBlockType( 'myguten/simple', { } ); ``` -{% Plain %} - -```js -const el = React.createElement; -const { __ } = wp.i18n; -const { registerBlockType } = wp.blocks; -const { useBlockProps } = wp.blockEditor; - -registerBlockType( 'myguten/simple', { - title: __( 'Simple Block', 'myguten' ), - category: 'widgets', - - edit: function () { - const blockProps = useBlockProps( { style: { color: 'red' } } ); - - return el( 'p', blockProps, __( 'Hello World', 'myguten' ) ); - }, - - save: function () { - const blockProps = useBlockProps.save( { style: { color: 'red' } } ); - return el( 'p', blockProps, __( 'Hello World', 'myguten' ) ); - }, -} ); -``` - -{% end %} - In the above example, the function will use the first argument for the string to be translated. The second argument is the text domain which must match the text domain slug specified by your plugin. Common functions available, these mirror their PHP counterparts are: diff --git a/docs/how-to-guides/themes/theme-json.md b/docs/how-to-guides/themes/theme-json.md index 024564b7c9eae..2a1161827c136 100644 --- a/docs/how-to-guides/themes/theme-json.md +++ b/docs/how-to-guides/themes/theme-json.md @@ -69,8 +69,7 @@ To address this need, we've started to experiment with CSS Custom Properties, ak - **Presets**: [color palettes](/docs/how-to-guides/themes/theme-support.md#block-color-palettes), [font sizes](/docs/how-to-guides/themes/theme-support.md#block-font-sizes), or [gradients](/docs/how-to-guides/themes/theme-support.md#block-gradient-presets) declared by the theme are converted to CSS Custom Properties and enqueued both the front-end and the editors. -{% codetabs %} -{% Input %} +#### Input ```json { @@ -94,7 +93,7 @@ To address this need, we've started to experiment with CSS Custom Properties, ak } ``` -{% Output %} +#### Output ```css body { @@ -103,12 +102,10 @@ body { } ``` -{% end %} - - **Custom properties**: there's also a mechanism to create your own CSS Custom Properties. -{% codetabs %} -{% Input %} + +#### Input ```json { @@ -124,7 +121,7 @@ body { } ``` -{% Output %} +#### Output ```css body { @@ -133,8 +130,6 @@ body { } ``` -{% end %} - ## Specification This specification is the same for the three different origins that use this format: core, themes, and users. Themes can override core's defaults by creating a file called `theme.json`. Users, via the site editor, will also be able to override theme's or core's preferences via an user interface that is being worked on. @@ -166,8 +161,8 @@ The tabs below show WordPress 5.8 supported settings and the ones supported by t The settings section has the following structure: -{% codetabs %} -{% WordPress %} + +#### WordPress ```json { @@ -231,7 +226,7 @@ The settings section has the following structure: } ``` -{% Gutenberg %} +#### Gutenberg ```json { @@ -310,8 +305,6 @@ The settings section has the following structure: } ``` -{% end %} - Each block can configure any of these settings separately, providing a more fine-grained control over what exists via `add_theme_support`. The settings declared at the top-level affect to all blocks, unless a particular block overwrites it. It's a way to provide inheritance and configure all blocks at once. Note, however, that not all settings are relevant for all blocks. The settings section provides an opt-in/opt-out mechanism for themes, but it's the block's responsibility to add support for the features that are relevant to it. For example, if a block doesn't implement the `dropCap` feature, a theme can't enable it for such a block through `theme.json`. @@ -376,8 +369,8 @@ The naming schema for the classes and the custom properties is as follows: - Custom Properties: `--wp--preset--{preset-category}--{preset-slug}` such as `--wp--preset--color--black` - Classes: `.has-{preset-slug}-{preset-category}` such as `.has-black-color`. -{% codetabs %} -{% Input %} + +#### Input ```json { @@ -490,7 +483,7 @@ The naming schema for the classes and the custom properties is as follows: } ``` -{% Output %} +#### Output ```css /* Top-level custom properties */ @@ -540,8 +533,6 @@ body { ``` -{% end %} - To maintain backward compatibility, the presets declared via `add_theme_support` will also generate the CSS Custom Properties. If the `theme.json` contains any presets, these will take precedence over the ones declared via `add_theme_support`. Preset classes are attached to the content of a post by some user action. That's why the engine will add `!important` to these, because user styles should take precedence over theme styles. @@ -552,8 +543,7 @@ In addition to create CSS Custom Properties for the presets, the `theme.json` al For example: -{% codetabs %} -{% Input %} +#### Input ```json { @@ -578,7 +568,7 @@ For example: } ``` -{% Output %} +#### Output ```css body { @@ -592,7 +582,6 @@ body { } ``` -{% end %} Note that the name of the variable is created by adding `--` in between each nesting level and `camelCase` fields are transformed to `kebab-case`. @@ -702,9 +691,9 @@ The tabs below show WordPress 5.8 supported styles and the ones supported by the Each block declares which style properties it exposes via the [block supports mechanism](/docs/reference-guides/block-api/block-supports.md). The support declarations are used to automatically generate the UI controls for the block in the editor. Themes can use any style property via the `theme.json` for any block ― it's the theme's responsibility to verify that it works properly according to the block markup, etc. -{% codetabs %} -{% WordPress %} + +#### WordPress ```json { @@ -784,7 +773,7 @@ Each block declares which style properties it exposes via the [block supports me } ``` -{% Gutenberg %} +#### Gutenberg ```json { @@ -873,14 +862,11 @@ Each block declares which style properties it exposes via the [block supports me } ``` -{% end %} - ### Top-level styles Styles found at the top-level will be enqueued using the `body` selector. -{% codetabs %} -{% Input %} +#### Input ```json { @@ -893,7 +879,7 @@ Styles found at the top-level will be enqueued using the `body` selector. } ``` -{% Output %} +#### Output ```css body { @@ -901,7 +887,6 @@ body { } ``` -{% end %} ### Block styles @@ -909,8 +894,7 @@ Styles found within a block will be enqueued using the block selector. By default, the block selector is generated based on its name such as `.wp-block-`. For example, `.wp-block-group` for the `core/group` block. There are some blocks that want to opt-out from this default behavior. They can do so by explicitly telling the system which selector to use for them via the `__experimentalSelector` key within the `supports` section of its `block.json` file. Note that the block needs to be registered server-side for the `__experimentalSelector` field to be available to the style engine. -{% codetabs %} -{% Input %} +#### Input ```json { @@ -935,7 +919,7 @@ By default, the block selector is generated based on its name such as `.wp-block } ``` -{% Output %} +#### Output ```css body { @@ -949,7 +933,6 @@ p { /* The core/paragraph opts out from the default behaviour and uses p as a se } ``` -{% end %} #### Referencing a style @@ -996,8 +979,8 @@ Supported by WordPress: If they're found in the top-level the element selector will be used. If they're found within a block, the selector to be used will be the element's appended to the corresponding block. -{% codetabs %} -{% Input %} + +#### Input ```json { @@ -1043,7 +1026,7 @@ If they're found in the top-level the element selector will be used. If they're } ``` -{% Output %} +#### Output ```css body { @@ -1066,8 +1049,6 @@ h3 { } ``` -{% end %} - ##### Element pseudo selectors Pseudo selectors `:hover`, `:focus`, `:visited`, `:active`, `:link`, `:any-link` are supported by Gutenberg. @@ -1236,8 +1217,8 @@ This is for clarity, but also because we want a mechanism to parse back a variab For example: -{% codetabs %} -{% Input %} + +#### Input ```json { @@ -1253,7 +1234,7 @@ For example: } ``` -{% Output %} +#### Output ```css body { @@ -1262,7 +1243,6 @@ body { } ``` -{% end %} A few notes about this process: diff --git a/docs/reference-guides/block-api/block-attributes.md b/docs/reference-guides/block-api/block-attributes.md index 765d69584a669..35ec1c1e7c64e 100644 --- a/docs/reference-guides/block-api/block-attributes.md +++ b/docs/reference-guides/block-api/block-attributes.md @@ -375,7 +375,7 @@ Attribute definition: From here, meta attributes can be read and written by a block using the same interface as any attribute: -{% codetabs %} + {% JSX %} ```js @@ -388,22 +388,6 @@ edit( { attributes, setAttributes } ) { }, ``` -{% Plain %} - -```js -edit: function( props ) { - function onChange( event ) { - props.setAttributes( { author: event.target.value } ); - } - - return el( 'input', { - value: props.attributes.author, - onChange: onChange, - } ); -}, -``` - -{% end %} #### Considerations diff --git a/docs/reference-guides/block-api/block-deprecation.md b/docs/reference-guides/block-api/block-deprecation.md index a1497ec346936..4d69d9d46843c 100644 --- a/docs/reference-guides/block-api/block-deprecation.md +++ b/docs/reference-guides/block-api/block-deprecation.md @@ -61,9 +61,6 @@ It's important to note that attributes, supports, and ### Example: -{% codetabs %} -{% JSX %} - ```js const { registerBlockType } = wp.blocks; const attributes = { @@ -101,46 +98,6 @@ registerBlockType( 'gutenberg/block-with-deprecated-version', { } ); ``` -{% Plain %} - -```js -var el = React.createElement, - registerBlockType = wp.blocks.registerBlockType, - attributes = { - text: { - type: 'string', - default: 'some random value', - }, - }, - supports = { - className: false, - }; - -registerBlockType( 'gutenberg/block-with-deprecated-version', { - // ... other block properties go here - - attributes: attributes, - - supports: supports, - - save: function ( props ) { - return el( 'div', {}, props.attributes.text ); - }, - - deprecated: [ - { - attributes: attributes, - - save: function ( props ) { - return el( 'p', {}, props.attributes.text ); - }, - }, - ], -} ); -``` - -{% end %} - In the example above we updated the markup of the block to use a `div` instead of `p`. ## Changing the attributes set @@ -149,8 +106,6 @@ Sometimes, you need to update the attributes set to rename or modify old attribu ### Example: -{% codetabs %} -{% JSX %} ```js const { registerBlockType } = wp.blocks; @@ -192,50 +147,6 @@ registerBlockType( 'gutenberg/block-with-deprecated-version', { } ); ``` -{% Plain %} - -```js -var el = React.createElement, - registerBlockType = wp.blocks.registerBlockType; - -registerBlockType( 'gutenberg/block-with-deprecated-version', { - // ... other block properties go here - - attributes: { - content: { - type: 'string', - default: 'some random value', - }, - }, - - save: function ( props ) { - return el( 'div', {}, props.attributes.content ); - }, - - deprecated: [ - { - attributes: { - text: { - type: 'string', - default: 'some random value', - }, - }, - - migrate: function ( attributes ) { - return { - content: attributes.text, - }; - }, - - save: function ( props ) { - return el( 'p', {}, props.attributes.text ); - }, - }, - ], -} ); -``` - -{% end %} In the example above we updated the markup of the block to use a `div` instead of `p` and rename the `text` attribute to `content`. @@ -246,9 +157,6 @@ E.g: a block wants to migrate a title attribute to a paragraph innerBlock. ### Example: -{% codetabs %} -{% JSX %} - ```js const { registerBlockType } = wp.blocks; @@ -292,49 +200,6 @@ registerBlockType( 'gutenberg/block-with-deprecated-version', { } ); ``` -{% Plain %} - -```js -var el = React.createElement, - registerBlockType = wp.blocks.registerBlockType; - -registerBlockType( 'gutenberg/block-with-deprecated-version', { - // ... block properties go here - - deprecated: [ - { - attributes: { - title: { - type: 'string', - source: 'html', - selector: 'p', - }, - }, - - migrate: function ( attributes, innerBlocks ) { - const { title, ...restAttributes } = attributes; - - return [ - restAttributes, - [ - createBlock( 'core/paragraph', { - content: attributes.title, - fontSize: 'large', - } ), - ].concat( innerBlocks ), - ]; - }, - - save: function ( props ) { - return el( 'p', {}, props.attributes.title ); - }, - }, - ], -} ); -``` - -{% end %} - In the example above we updated the block to use an inner Paragraph block with a title instead of a title attribute. _Above are example cases of block deprecation. For more, real-world examples, check for deprecations in the [core block library](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-library/src). Core blocks have been updated across releases and contain simple and complex deprecations._ diff --git a/docs/reference-guides/block-api/block-edit-save.md b/docs/reference-guides/block-api/block-edit-save.md index 35bbd5ae13e1e..a8b6f9171bdef 100644 --- a/docs/reference-guides/block-api/block-edit-save.md +++ b/docs/reference-guides/block-api/block-edit-save.md @@ -6,8 +6,6 @@ When registering a block with JavaScript on the client, the `edit` and `save` fu The `edit` function describes the structure of your block in the context of the editor. This represents what the editor will render when the block is used. -{% codetabs %} -{% JSX %} ```jsx import { useBlockProps } from '@wordpress/block-editor'; @@ -26,32 +24,12 @@ const blockSettings = { }; ``` -{% Plain %} - -```js -var blockSettings = { - apiVersion: 3, - - // ... - - edit: function () { - var blockProps = wp.blockEditor.useBlockProps(); - - return React.createElement( 'div', blockProps, 'Your block.' ); - }, -}; -``` - -{% end %} - ### block wrapper props The first thing to notice here is the use of the `useBlockProps` React hook on the block wrapper element. In the example above, the block wrapper renders a "div" in the editor, but in order for the Gutenberg editor to know how to manipulate the block, add any extra classNames that are needed for the block... the block wrapper element should apply props retrieved from the `useBlockProps` react hook call. The block wrapper element should be a native DOM element, like `
` and ``, or a React component that forwards any additional props to native DOM elements. Using a `` or `` component, for instance, would be invalid. If the element wrapper needs any extra custom HTML attributes, these need to be passed as an argument to the `useBlockProps` hook. For example to add a `my-random-classname` className to the wrapper, you can use the following code: -{% codetabs %} -{% JSX %} ```jsx import { useBlockProps } from '@wordpress/block-editor'; @@ -72,25 +50,6 @@ const blockSettings = { }; ``` -{% Plain %} - -```js -var blockSettings = { - apiVersion: 3, - - // ... - - edit: function () { - var blockProps = wp.blockEditor.useBlockProps( { - className: 'my-random-classname', - } ); - - return React.createElement( 'div', blockProps, 'Your block.' ); - }, -}; -``` - -{% end %} ### attributes @@ -100,8 +59,6 @@ The `attributes` property surfaces all the available attributes and their corres In this case, assuming we had defined an attribute of `content` during block registration, we would receive and use that value in our edit function: -{% codetabs %} -{% JSX %} ```js edit: ( { attributes } ) => { @@ -111,21 +68,6 @@ edit: ( { attributes } ) => { }; ``` -{% Plain %} - -```js -edit: function( props ) { - var blockProps = wp.blockEditor.useBlockProps(); - - return React.createElement( - 'div', - blockProps, - props.attributes.content - ); -} -``` - -{% end %} The value of `attributes.content` will be displayed inside the `div` when inserting the block in the editor. @@ -133,8 +75,6 @@ The value of `attributes.content` will be displayed inside the `div` when insert The isSelected property is an boolean that communicates whether the block is currently selected. -{% codetabs %} -{% JSX %} ```jsx edit: ( { attributes, isSelected } ) => { @@ -151,35 +91,10 @@ edit: ( { attributes, isSelected } ) => { }; ``` -{% Plain %} - -```js -edit: function( props ) { - var blockProps = wp.blockEditor.useBlockProps(); - - return React.createElement( - 'div', - blockProps, - [ - 'Your block.', - props.isSelected ? React.createElement( - 'span', - null, - 'Shows only when the block is selected.' - ) - ] - ); -} -``` - -{% end %} - ### setAttributes This function allows the block to update individual attributes based on user interactions. -{% codetabs %} -{% JSX %} ```jsx edit: ( { attributes, setAttributes, isSelected } ) => { @@ -201,40 +116,8 @@ edit: ( { attributes, setAttributes, isSelected } ) => { }; ``` -{% Plain %} - -```js -edit: function( props ) { - var blockProps = wp.blockEditor.useBlockProps(); - - // Simplify access to attributes - let content = props.attributes.content; - let mySetting = props.attributes.mySetting; - - // Toggle a setting when the user clicks the button - let toggleSetting = () => props.setAttributes( { mySetting: ! mySetting } ); - return React.createElement( - 'div', - blockProps, - [ - content, - props.isSelected ? React.createElement( - 'button', - { onClick: toggleSetting }, - 'Toggle setting' - ) : null - ] - ); -}, -``` - -{% end %} - When using attributes that are objects or arrays it's a good idea to copy or clone the attribute prior to updating it: -{% codetabs %} -{% JSX %} - ```js // Good - a new array is created from the old list attribute and a new list item: const { list } = attributes; @@ -249,25 +132,6 @@ const addListItem = ( newListItem ) => { }; ``` -{% Plain %} - -```js -// Good - cloning the old list -var newList = attributes.list.slice(); - -var addListItem = function ( newListItem ) { - setAttributes( { list: newList.concat( [ newListItem ] ) } ); -}; - -// Bad - the list from the existing attribute is modified directly to add the new list item: -var list = attributes.list; -var addListItem = function ( newListItem ) { - list.push( newListItem ); - setAttributes( { list: list } ); -}; -``` - -{% end %} Why do this? In JavaScript, arrays and objects are passed by reference, so this practice ensures changes won't affect other code that might hold references to the same data. Furthermore, the Gutenberg project follows the philosophy of the Redux library that [state should be immutable](https://redux.js.org/faq/immutable-data#what-are-the-benefits-of-immutability)—data should not be changed directly, but instead a new version of the data created containing the changes. @@ -275,8 +139,6 @@ Why do this? In JavaScript, arrays and objects are passed by reference, so this The `save` function defines the way in which the different attributes should be combined into the final markup, which is then serialized into `post_content`. -{% codetabs %} -{% JSX %} ```jsx save: () => { @@ -286,21 +148,6 @@ save: () => { }; ``` -{% Plain %} - -```js -save: function() { - var blockProps = wp.blockEditor.useBlockProps.save(); - - return React.createElement( - 'div', - blockProps, - 'Your block.' - ); -} -``` - -{% end %} For most blocks, the return value of `save` should be an [instance of WordPress Element](/packages/element/README.md) representing how the block is to appear on the front of the site. @@ -326,8 +173,6 @@ Like the `edit` function, when rendering static blocks, it's important to add th As with `edit`, the `save` function also receives an object argument including attributes which can be inserted into the markup. -{% codetabs %} -{% JSX %} ```jsx save: ( { attributes } ) => { @@ -337,21 +182,7 @@ save: ( { attributes } ) => { }; ``` -{% Plain %} -```js -save: function( props ) { - var blockProps = wp.blockEditor.useBlockProps.save(); - - return React.createElement( - 'div', - blockProps, - props.attributes.content - ); -} -``` - -{% end %} When saving your block, you want to save the attributes in the same format specified by the attribute source definition. If no attribute source is specified, the attribute will be saved to the block's comment delimiter. See the [Block Attributes documentation](/docs/reference-guides/block-api/block-attributes.md) for more details. @@ -361,8 +192,6 @@ Here are a couple examples of using attributes, edit, and save all together. For ### Saving Attributes to Child Elements -{% codetabs %} -{% JSX %} ```jsx attributes: { @@ -396,46 +225,6 @@ save: ( { attributes } ) => { }, ``` -{% Plain %} - -```js -attributes: { - content: { - type: 'string', - source: 'html', - selector: 'p' - } -}, - -edit: function( props ) { - var blockProps = wp.blockEditor.useBlockProps(); - var updateFieldValue = function( val ) { - props.setAttributes( { content: val } ); - } - - return React.createElement( - 'div', - blockProps, - React.createElement( - wp.components.TextControl, - { - label: 'My Text Field', - value: props.attributes.content, - onChange: updateFieldValue, - - } - ) - ); -}, - -save: function( props ) { - var blockProps = wp.blockEditor.useBlockProps.save(); - - return React.createElement( 'div', blockProps, props.attributes.content ); -}, -``` - -{% end %} ### Saving Attributes via Serialization @@ -443,8 +232,6 @@ Ideally, the attributes saved should be included in the markup. However, there a This example could be for a dynamic block, such as the [Latest Posts block](https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-library/src/latest-posts/index.js), which renders the markup server-side. The save function is still required, however in this case it simply returns null since the block is not saving content from the editor. -{% codetabs %} -{% JSX %} ```jsx attributes: { @@ -474,41 +261,6 @@ save: () => { } ``` -{% Plain %} - -```js -attributes: { - postsToShow: { - type: 'number', - } -}, - -edit: function( props ) { - var blockProps = wp.blockEditor.useBlockProps(); - - return React.createEleement( - 'div', - blockProps, - React.createElement( - wp.components.TextControl, - { - label: 'Number Posts to Show', - value: props.attributes.postsToShow, - onChange: function( val ) { - props.setAttributes( { postsToShow: parseInt( val ) } ); - }, - } - ) - ); -}, - -save: function() { - return null; -} -``` - -{% end %} - ## Validation When the editor loads, all blocks within post content are validated to determine their accuracy in order to protect against content loss. This is closely related to the saving implementation of a block, as a user may unintentionally remove or modify their content if the editor is unable to restore a block correctly. During editor initialization, the saved markup for each block is regenerated using the attributes that were parsed from the post's content. If the newly-generated markup does not match what was already stored in post content, the block is marked as invalid. This is because we assume that unless the user makes edits, the markup should remain identical to the saved content. diff --git a/docs/reference-guides/filters/autocomplete-filters.md b/docs/reference-guides/filters/autocomplete-filters.md index 1ce4721952918..85581f62e4af0 100644 --- a/docs/reference-guides/filters/autocomplete-filters.md +++ b/docs/reference-guides/filters/autocomplete-filters.md @@ -8,8 +8,7 @@ The `Autocomplete` component found in `@wordpress/block-editor` applies this fil Here is an example of using the `editor.Autocomplete.completers` filter to add an acronym completer. You can find full documentation for the autocompleter interface with the `Autocomplete` component in the `@wordpress/components` package. -{% codetabs %} -{% JSX %} + ```jsx // Our completer @@ -45,48 +44,3 @@ wp.hooks.addFilter( appendAcronymCompleter ); ``` - -{% Plain %} - -```js -// Our completer -var acronymCompleter = { - name: 'acronyms', - triggerPrefix: '::', - options: [ - { letters: 'FYI', expansion: 'For Your Information' }, - { letters: 'AFAIK', expansion: 'As Far As I Know' }, - { letters: 'IIRC', expansion: 'If I Recall Correctly' }, - ], - getOptionKeywords: function ( abbr ) { - var expansionWords = abbr.expansion.split( /\s+/ ); - return [ abbr.letters ].concat( expansionWords ); - }, - getOptionLabel: function ( acronym ) { - return acronym.letters; - }, - getOptionCompletion: function ( abbr ) { - return React.createElement( - 'abbr', - { title: abbr.expansion }, - abbr.letters - ); - }, -}; - -// Our filter function -function appendAcronymCompleter( completers, blockName ) { - return blockName === 'my-plugin/foo' - ? completers.concat( acronymCompleter ) - : completers; -} - -// Adding the filter -wp.hooks.addFilter( - 'editor.Autocomplete.completers', - 'my-plugin/autocompleters/acronyms', - appendAcronymCompleter -); -``` - -{% end %} diff --git a/docs/reference-guides/filters/block-filters.md b/docs/reference-guides/filters/block-filters.md index 912403c483894..e269ba9ef1991 100644 --- a/docs/reference-guides/filters/block-filters.md +++ b/docs/reference-guides/filters/block-filters.md @@ -179,8 +179,6 @@ Used to modify the block's `edit` component. It receives the original block `Blo _Example:_ -{% codetabs %} -{% JSX %} ```js const { createHigherOrderComponent } = wp.compose; @@ -207,36 +205,6 @@ wp.hooks.addFilter( ); ``` -{% Plain %} - -```js -var el = React.createElement; - -var withMyPluginControls = wp.compose.createHigherOrderComponent( function ( - BlockEdit -) { - return function ( props ) { - return el( - React.Fragment, - {}, - el( BlockEdit, props ), - el( - wp.blockEditor.InspectorControls, - {}, - el( wp.components.PanelBody, {}, 'My custom control' ) - ) - ); - }; -}, 'withMyPluginControls' ); - -wp.hooks.addFilter( - 'editor.BlockEdit', - 'my-plugin/with-inspector-controls', - withMyPluginControls -); -``` - -{% end %} Note that as this hook is run for _all blocks_, consuming it has potential for performance regressions particularly around block selection metrics. @@ -267,9 +235,6 @@ Used to modify the block's wrapper component containing the block's `edit` compo _Example:_ -{% codetabs %} -{% JSX %} - ```js const { createHigherOrderComponent } = wp.compose; @@ -294,39 +259,10 @@ wp.hooks.addFilter( ); ``` -{% Plain %} - -```js -var el = React.createElement; - -var withClientIdClassName = wp.compose.createHigherOrderComponent( function ( - BlockListBlock -) { - return function ( props ) { - var newProps = { - ...props, - className: 'block-' + props.clientId, - }; - - return el( BlockListBlock, newProps ); - }; -}, 'withClientIdClassName' ); - -wp.hooks.addFilter( - 'editor.BlockListBlock', - 'my-plugin/with-client-id-class-name', - withClientIdClassName -); -``` - -{% end %} - Adding new properties to the block's wrapper component can be achieved by adding them to the `wrapperProps` property of the returned component. _Example:_ -{% codetabs %} -{% JSX %} ```js const { createHigherOrderComponent } = wp.compose; @@ -346,32 +282,6 @@ wp.hooks.addFilter( ); ``` -{% Plain %} - -```js -var el = React.createElement; -var hoc = wp.compose.createHigherOrderComponent; - -var withMyWrapperProp = hoc( function ( BlockListBlock ) { - return function ( props ) { - var newProps = { - ...props, - wrapperProps: { - ...props.wrapperProps, - 'data-my-property': 'the-value', - }, - }; - return el( BlockListBlock, newProps ); - }; -}, 'withMyWrapperProp' ); -wp.hooks.addFilter( - 'editor.BlockListBlock', - 'my-plugin/with-my-wrapper-prop', - withMyWrapperProp -); -``` - -{% end %} ## Removing Blocks @@ -379,8 +289,6 @@ wp.hooks.addFilter( Adding blocks is easy enough, removing them is as easy. Plugin or theme authors have the possibility to "unregister" blocks. -{% codetabs %} -{% JSX %} ```js // my-plugin.js @@ -392,16 +300,6 @@ domReady( function () { } ); ``` -{% Plain %} - -```js -// my-plugin.js -wp.domReady( function () { - wp.blocks.unregisterBlockType( 'core/verse' ); -} ); -``` - -{% end %} and load this script in the Editor diff --git a/docs/reference-guides/richtext.md b/docs/reference-guides/richtext.md index f908c7585bc1b..1a4509318b72b 100644 --- a/docs/reference-guides/richtext.md +++ b/docs/reference-guides/richtext.md @@ -25,8 +25,7 @@ There are a number of core blocks using the RichText component. The JavaScript e ## Example -{% codetabs %} -{% JSX %} + ```jsx import { registerBlockType } from '@wordpress/blocks'; @@ -66,46 +65,6 @@ registerBlockType( /* ... */, { } ); ``` -{% Plain %} - -```js -wp.blocks.registerBlockType( /* ... */, { - // ... - - attributes: { - content: { - type: 'string', - source: 'html', - selector: 'h2', - }, - }, - - edit: function( props ) { - var blockProps = wp.blockEditor.useBlockProps(); - - return React.createElement( wp.blockEditor.RichText, Object.assign( blockProps, { - tagName: 'h2', // The tag here is the element output and editable in the admin - value: props.attributes.content, // Any existing content, either from the database or an attribute default - allowedFormats: [ 'core/bold', 'core/italic' ], // Allow the content to be made bold or italic, but do not allow other formatting options - onChange: function( content ) { - props.setAttributes( { content: content } ); // Store updated content as a block attribute - }, - placeholder: __( 'Heading...' ), // Display this text before any content has been added by the user - } ) ); - }, - - save: function( props ) { - var blockProps = wp.blockEditor.useBlockProps.save(); - - return React.createElement( wp.blockEditor.RichText.Content, Object.assign( blockProps, { - tagName: 'h2', value: props.attributes.content // Saves

Content added in the editor...

to the database for frontend display - } ) ); - } -} ); -``` - -{% end %} - ## Common Issues & Solutions While using the RichText component a number of common issues tend to appear. diff --git a/packages/block-editor/src/components/editable-text/README.md b/packages/block-editor/src/components/editable-text/README.md index 86607349ae817..aa5a2f4b1962b 100644 --- a/packages/block-editor/src/components/editable-text/README.md +++ b/packages/block-editor/src/components/editable-text/README.md @@ -47,40 +47,6 @@ _Optional._ Called when the block can be removed. `forward` is true when the sel ## Example -{% codetabs %} -{% ES5 %} - -```js -wp.blocks.registerBlockType( /* ... */, { - // ... - - attributes: { - content: { - source: 'html', - selector: 'div', - }, - }, - - edit: function( props ) { - return React.createElement( wp.editor.EditableText, { - className: props.className, - value: props.attributes.content, - onChange: function( content ) { - props.setAttributes( { content: content } ); - } - } ); - }, - - save: function( props ) { - return React.createElement( wp.editor.EditableText.Content, { - value: props.attributes.content - } ); - } -} ); -``` - -{% ESNext %} - ```js const { registerBlockType } = wp.blocks; const { EditableText } = wp.editor; @@ -110,5 +76,3 @@ registerBlockType( /* ... */, { } } ); ``` - -{% end %} diff --git a/packages/block-editor/src/components/plain-text/README.md b/packages/block-editor/src/components/plain-text/README.md index 4e59789fd612c..aa15758118afd 100644 --- a/packages/block-editor/src/components/plain-text/README.md +++ b/packages/block-editor/src/components/plain-text/README.md @@ -20,33 +20,6 @@ _Optional._ The component forwards the `ref` property to the `TextareaAutosize` ## Example -{% codetabs %} -{% ES5 %} - -```js -wp.blocks.registerBlockType( /* ... */, { - // ... - - attributes: { - content: { - type: 'string', - }, - }, - - edit: function( props ) { - return React.createElement( wp.blockEditor.PlainText, { - className: props.className, - value: props.attributes.content, - onChange: function( content ) { - props.setAttributes( { content: content } ); - }, - } ); - }, -} ); -``` - -{% ESNext %} - ```js import { registerBlockType } from '@wordpress/blocks'; import { PlainText } from '@wordpress/block-editor'; @@ -72,4 +45,3 @@ registerBlockType( /* ... */, { } ); ``` -{% end %} diff --git a/packages/block-editor/src/components/rich-text/README.md b/packages/block-editor/src/components/rich-text/README.md index d17f987a34cf0..4251debfa16c5 100644 --- a/packages/block-editor/src/components/rich-text/README.md +++ b/packages/block-editor/src/components/rich-text/README.md @@ -80,41 +80,6 @@ trimmed. ## Example -{% codetabs %} -{% ES5 %} - -```js -wp.blocks.registerBlockType( /* ... */, { - // ... - - attributes: { - content: { - source: 'html', - selector: 'h2', - }, - }, - - edit: function( props ) { - return React.createElement( wp.blockEditor.RichText, { - tagName: 'h2', - className: props.className, - value: props.attributes.content, - onChange: function( content ) { - props.setAttributes( { content: content } ); - } - } ); - }, - - save: function( props ) { - return React.createElement( wp.blockEditor.RichText.Content, { - tagName: 'h2', value: props.attributes.content - } ); - } -} ); -``` - -{% ESNext %} - ```js import { registerBlockType } from '@wordpress/blocks'; import { RichText } from '@wordpress/block-editor'; @@ -146,7 +111,6 @@ registerBlockType( /* ... */, { } ); ``` -{% end %} ## RichTextToolbarButton @@ -154,26 +118,6 @@ Slot to extend the format toolbar. Use it in the edit function of a `registerFor ### Example -{% codetabs %} -{% ES5 %} - -```js -wp.richText.registerFormatType( /* ... */, { - /* ... */ - edit: function( props ) { - return React.createElement( - wp.blockEditor.RichTextToolbarButton, { - icon: 'editor-code', - title: 'My formatting button', - onClick: function() { /* ... */ } - isActive: props.isActive, - } ); - }, - /* ... */ -} ); -``` - -{% ESNext %} ```js import { registerFormatType } from '@wordpress/rich-text'; @@ -194,5 +138,3 @@ registerFormatType( /* ... */, { /* ... */ } ); ``` - -{% end %} diff --git a/packages/block-editor/src/components/url-input/README.md b/packages/block-editor/src/components/url-input/README.md index 46f673ecd3554..b7c48c191cc28 100644 --- a/packages/block-editor/src/components/url-input/README.md +++ b/packages/block-editor/src/components/url-input/README.md @@ -36,41 +36,6 @@ This prop is passed directly to the `URLInput` component. ## Example -{% codetabs %} -{% ES5 %} - -```js -wp.blocks.registerBlockType( /* ... */, { - // ... - - attributes: { - url: { - type: 'string' - }, - text: { - type: 'string' - } - }, - - edit: function( props ) { - return React.createElement( wp.blockEditor.URLInputButton, { - className: props.className, - url: props.attributes.url, - onChange: function( url, post ) { - props.setAttributes( { url: url, text: (post && post.title) || 'Click here' } ); - } - } ); - }, - - save: function( props ) { - return React.createElement( 'a', { - href: props.attributes.url, - }, props.attributes.text ); - } -} ); -``` - -{% ESNext %} ```js import { registerBlockType } from '@wordpress/blocks'; @@ -103,7 +68,6 @@ registerBlockType( /* ... */, { } ); ``` -{% end %} # `URLInput` @@ -172,41 +136,6 @@ Start opting into the new margin-free styles that will become the default in a f ## Example -{% codetabs %} -{% ES5 %} - -```js -wp.blocks.registerBlockType( /* ... */, { - // ... - - attributes: { - url: { - type: 'string' - }, - text: { - type: 'string' - } - }, - - edit: function( props ) { - return React.createElement( wp.blockEditor.URLInput, { - className: props.className, - value: props.attributes.url, - onChange: function( url, post ) { - props.setAttributes( { url: url, text: (post && post.title) || 'Click here' } ); - } - } ); - }, - - save: function( props ) { - return React.createElement( 'a', { - href: props.attributes.url, - }, props.attributes.text ); - } -} ); -``` - -{% ESNext %} ```js import { registerBlockType } from '@wordpress/blocks'; @@ -240,5 +169,3 @@ registerBlockType( /* ... */, { } } ); ``` - -{% end %} From 55285a8c85b3d802b894571fd616fddbdbb6dbbe Mon Sep 17 00:00:00 2001 From: Chad Chadbourne <13856531+chad1008@users.noreply.github.com> Date: Fri, 17 Nov 2023 10:18:58 -0500 Subject: [PATCH 072/116] Tabs: Fix flaky unit tests (#55950) --- packages/components/src/tabs/test/index.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/components/src/tabs/test/index.tsx b/packages/components/src/tabs/test/index.tsx index d2a035e436c19..fac8127c4cc0d 100644 --- a/packages/components/src/tabs/test/index.tsx +++ b/packages/components/src/tabs/test/index.tsx @@ -524,6 +524,15 @@ describe( 'Tabs', () => { await screen.findByRole( 'tab', { name: 'Alpha' } ) ).toHaveFocus(); + // This assertion ensures the component has had time to fully + // render, preventing flakiness. + // see https://github.com/WordPress/gutenberg/pull/55950 + await waitFor( () => + expect( + screen.getByRole( 'tab', { name: 'Beta' } ) + ).toHaveAttribute( 'tabindex', '-1' ) + ); + // Because all other tabs should have `tabindex=-1`, pressing Tab // should NOT move the focus to the next tab, which is Beta. // Instead, focus should go to the currently selected tabpanel (alpha). @@ -847,6 +856,16 @@ describe( 'Tabs', () => { // onSelect should not be called since the disabled tab is // highlighted, but not selected. await user.keyboard( '[Tab]' ); + + // This assertion ensures focus has time to move to the first + // tab before the test proceeds, preventing flakiness. + // see https://github.com/WordPress/gutenberg/pull/55950 + await waitFor( () => + expect( + screen.getByRole( 'tab', { name: 'Alpha' } ) + ).toHaveFocus() + ); + await user.keyboard( '[ArrowLeft]' ); expect( mockOnSelect ).toHaveBeenCalledTimes( 1 ); From bb8adcd41cea151b3529204249b899c3a53abada Mon Sep 17 00:00:00 2001 From: Chad Chadbourne <13856531+chad1008@users.noreply.github.com> Date: Fri, 17 Nov 2023 11:04:25 -0500 Subject: [PATCH 073/116] Tabs: cleanup and improvements (#56224) --- packages/components/CHANGELOG.md | 4 ++++ packages/components/src/tabs/index.tsx | 14 ++++++++++++-- .../components/src/tabs/stories/index.story.tsx | 8 ++++++++ packages/components/src/tabs/tab.tsx | 8 ++++---- packages/components/src/tabs/tabpanel.tsx | 6 +++--- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 37ad2a65da28a..eb6e595e304ec 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Experimental + +- `Tabs`: Memoize and expose the component context ([#56224](https://github.com/WordPress/gutenberg/pull/56224)). + ## 25.12.0 (2023-11-16) ### Bug Fix diff --git a/packages/components/src/tabs/index.tsx b/packages/components/src/tabs/index.tsx index 59eb83f524059..12dd0b4fcc83f 100644 --- a/packages/components/src/tabs/index.tsx +++ b/packages/components/src/tabs/index.tsx @@ -8,7 +8,7 @@ import * as Ariakit from '@ariakit/react'; * WordPress dependencies */ import { useInstanceId } from '@wordpress/compose'; -import { useLayoutEffect, useRef } from '@wordpress/element'; +import { useLayoutEffect, useMemo, useRef } from '@wordpress/element'; /** * Internal dependencies @@ -154,8 +154,16 @@ function Tabs( { setSelectedId, ] ); + const contextValue = useMemo( + () => ( { + store, + instanceId, + } ), + [ store, instanceId ] + ); + return ( - + { children } ); @@ -164,4 +172,6 @@ function Tabs( { Tabs.TabList = TabList; Tabs.Tab = Tab; Tabs.TabPanel = TabPanel; +Tabs.Context = TabsContext; + export default Tabs; diff --git a/packages/components/src/tabs/stories/index.story.tsx b/packages/components/src/tabs/stories/index.story.tsx index 08e2958988170..ce8c8324edaee 100644 --- a/packages/components/src/tabs/stories/index.story.tsx +++ b/packages/components/src/tabs/stories/index.story.tsx @@ -20,6 +20,14 @@ import Button from '../../button'; const meta: Meta< typeof Tabs > = { title: 'Components (Experimental)/Tabs', component: Tabs, + subcomponents: { + // @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170 + 'Tabs.TabList': Tabs.TabList, + // @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170 + 'Tabs.Tab': Tabs.Tab, + // @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170 + 'Tabs.TabPanel': Tabs.TabPanel, + }, parameters: { actions: { argTypesRegex: '^on.*' }, controls: { expanded: true }, diff --git a/packages/components/src/tabs/tab.tsx b/packages/components/src/tabs/tab.tsx index 03e5d80871c56..4bfc99e8ef43b 100644 --- a/packages/components/src/tabs/tab.tsx +++ b/packages/components/src/tabs/tab.tsx @@ -2,14 +2,14 @@ * WordPress dependencies */ -import { useContext, forwardRef } from '@wordpress/element'; +import { forwardRef } from '@wordpress/element'; /** * Internal dependencies */ import type { TabProps } from './types'; import warning from '@wordpress/warning'; -import { TabsContext } from './context'; +import { useTabsContext } from './context'; import { Tab as StyledTab } from './styles'; import type { WordPressComponentProps } from '../context'; @@ -17,9 +17,9 @@ export const Tab = forwardRef< HTMLButtonElement, WordPressComponentProps< TabProps, 'button', false > >( function Tab( { children, id, disabled, render, ...otherProps }, ref ) { - const context = useContext( TabsContext ); + const context = useTabsContext(); if ( ! context ) { - warning( '`Tabs.TabList` must be wrapped in a `Tabs` component.' ); + warning( '`Tabs.Tab` must be wrapped in a `Tabs` component.' ); return null; } const { store, instanceId } = context; diff --git a/packages/components/src/tabs/tabpanel.tsx b/packages/components/src/tabs/tabpanel.tsx index f477d1d3b4b43..8e8d72280a493 100644 --- a/packages/components/src/tabs/tabpanel.tsx +++ b/packages/components/src/tabs/tabpanel.tsx @@ -6,7 +6,7 @@ * WordPress dependencies */ -import { forwardRef, useContext } from '@wordpress/element'; +import { forwardRef } from '@wordpress/element'; /** * Internal dependencies @@ -15,14 +15,14 @@ import type { TabPanelProps } from './types'; import { TabPanel as StyledTabPanel } from './styles'; import warning from '@wordpress/warning'; -import { TabsContext } from './context'; +import { useTabsContext } from './context'; import type { WordPressComponentProps } from '../context'; export const TabPanel = forwardRef< HTMLDivElement, WordPressComponentProps< TabPanelProps, 'div', false > >( function TabPanel( { children, id, focusable = true, ...otherProps }, ref ) { - const context = useContext( TabsContext ); + const context = useTabsContext(); if ( ! context ) { warning( '`Tabs.TabPanel` must be wrapped in a `Tabs` component.' ); return null; From 2969b5910ad2a88c18914db645cb540d1ec0250f Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Sat, 18 Nov 2023 13:36:29 -0500 Subject: [PATCH 074/116] Font Library: remove insecure properties (#56230) * Add additional sanitization to fonts. * Add test case to remove insecure font family. * Format php. --- .../font-library/class-wp-font-family.php | 7 ++- phpunit/class-wp-theme-json-test.php | 46 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/lib/experimental/fonts/font-library/class-wp-font-family.php b/lib/experimental/fonts/font-library/class-wp-font-family.php index a4f55d8c0cece..309b1c8b7902b 100644 --- a/lib/experimental/fonts/font-library/class-wp-font-family.php +++ b/lib/experimental/fonts/font-library/class-wp-font-family.php @@ -300,12 +300,17 @@ private function sanitize() { 'version' => '2', 'settings' => array( 'typography' => array( - 'fontFamilies' => array( $this->data ), + 'fontFamilies' => array( + 'custom' => array( + $this->data, + ), + ), ), ), ); // Creates a new WP_Theme_JSON object with the new fonts to // leverage sanitization and validation. + $fonts_json = WP_Theme_JSON_Gutenberg::remove_insecure_properties( $fonts_json ); $theme_json = new WP_Theme_JSON_Gutenberg( $fonts_json ); $theme_data = $theme_json->get_data(); $sanitized_font = ! empty( $theme_data['settings']['typography']['fontFamilies'] ) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 6ccbe2fb1d03b..e0c11766eaaae 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -896,6 +896,52 @@ public function test_remove_invalid_element_pseudo_selectors() { $this->assertEqualSetsWithIndex( $expected, $actual ); } + public function test_remove_invalid_font_family_settings() { + $actual = WP_Theme_JSON_Gutenberg::remove_insecure_properties( + array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'settings' => array( + 'typography' => array( + 'fontFamilies' => array( + 'custom' => array( + array( + 'name' => 'Open Sans', + 'slug' => 'open-sans', + 'fontFamily' => '"Open Sans", sans-serif', + ), + array( + 'name' => 'Arial', + 'slug' => 'arial', + 'fontFamily' => 'Arial, serif', + ), + ), + ), + ), + ), + ), + true + ); + + $expected = array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'settings' => array( + 'typography' => array( + 'fontFamilies' => array( + 'custom' => array( + array( + 'name' => 'Arial', + 'slug' => 'arial', + 'fontFamily' => 'Arial, serif', + ), + ), + ), + ), + ), + ); + + $this->assertEqualSetsWithIndex( $expected, $actual ); + } + public function test_get_element_class_name_button() { $expected = 'wp-element-button'; $actual = WP_Theme_JSON_Gutenberg::get_element_class_name( 'button' ); From 1646cd81faae808cd3eff0e3ee11dddb7c754b07 Mon Sep 17 00:00:00 2001 From: JuanMa Date: Sun, 19 Nov 2023 12:36:25 +0000 Subject: [PATCH 075/116] Update quick-start-guide.md (#56281) Update proper link for template --- docs/getting-started/quick-start-guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/quick-start-guide.md b/docs/getting-started/quick-start-guide.md index 4ad3998e7c27d..e978b250ab8af 100644 --- a/docs/getting-started/quick-start-guide.md +++ b/docs/getting-started/quick-start-guide.md @@ -16,7 +16,7 @@ Next, use the [`@wordpress/create-block`](https://developer.wordpress.org/block- Choose the folder where you want to create the plugin, and then execute the following command in the terminal from within that folder: ```sh -npx @wordpress/create-block copyright-date-block --template create-block-tutorial-template +npx @wordpress/create-block copyright-date-block --template @wordpress/create-block-tutorial-template ``` The `slug` provided (`copyright-date-block`) defines the folder name for the scaffolded plugin and the internal block name. @@ -41,4 +41,4 @@ When you are finished making changes, run the `npm run build` command. This opti - [Get started with create-block](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-create-block/) - [Get started with wp-scripts](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-scripts/) -- [Get started with wp-env](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-env/) \ No newline at end of file +- [Get started with wp-env](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-env/) From d11351f104288de28233f67fdfac8d4d66ac174c Mon Sep 17 00:00:00 2001 From: Ramon Date: Mon, 20 Nov 2023 09:13:31 +1100 Subject: [PATCH 076/116] Global style revisions: add details and redesign style revision items (#55913) * First commit: - add basic function to return translated labels of top-level changes - showing humantime diff for changes < 1 day - rearranging elements * - timeline redesign - minor optimization refactoring * There is no "colors" property * Some style tweaks * Tweak font sizes * Display Unsaved for unsaved changes * Remove revision changes labels. To be done in a follow up * Moving date format setting call into the comoponent rejigging getLabel function adding css var --- .../screen-revisions/revisions-buttons.js | 110 +++++++++++------- .../global-styles/screen-revisions/style.scss | 80 ++++++++----- 2 files changed, 117 insertions(+), 73 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/screen-revisions/revisions-buttons.js b/packages/edit-site/src/components/global-styles/screen-revisions/revisions-buttons.js index feec0f25ac882..2786bf6d79121 100644 --- a/packages/edit-site/src/components/global-styles/screen-revisions/revisions-buttons.js +++ b/packages/edit-site/src/components/global-styles/screen-revisions/revisions-buttons.js @@ -12,20 +12,28 @@ import { dateI18n, getDate, humanTimeDiff, getSettings } from '@wordpress/date'; import { store as coreStore } from '@wordpress/core-data'; import { useSelect } from '@wordpress/data'; +const DAY_IN_MILLISECONDS = 60 * 60 * 1000 * 24; + /** * Returns a button label for the revision. * - * @param {Object} revision A revision object. + * @param {string|number} id A revision object. + * @param {boolean} isLatest Whether the revision is the most current. + * @param {string} authorDisplayName Author name. + * @param {string} formattedModifiedDate Revision modified date formatted. * @return {string} Translated label. */ -function getRevisionLabel( revision ) { - const authorDisplayName = revision?.author?.name || __( 'User' ); - - if ( 'parent' === revision?.id ) { +function getRevisionLabel( + id, + isLatest, + authorDisplayName, + formattedModifiedDate +) { + if ( 'parent' === id ) { return __( 'Reset the styles to the theme defaults' ); } - if ( 'unsaved' === revision?.id ) { + if ( 'unsaved' === id ) { return sprintf( /* translators: %s author display name */ __( 'Unsaved changes by %s' ), @@ -33,23 +41,18 @@ function getRevisionLabel( revision ) { ); } - const formattedDate = dateI18n( - getSettings().formats.datetimeAbbreviated, - getDate( revision?.modified ) - ); - - return revision?.isLatest + return isLatest ? sprintf( /* translators: %1$s author display name, %2$s: revision creation date */ __( 'Changes saved by %1$s on %2$s (current)' ), authorDisplayName, - formattedDate + formattedModifiedDate ) : sprintf( /* translators: %1$s author display name, %2$s: revision creation date */ __( 'Changes saved by %1$s on %2$s' ), authorDisplayName, - formattedDate + formattedModifiedDate ); } @@ -65,10 +68,18 @@ function getRevisionLabel( revision ) { * @return {JSX.Element} The modal component. */ function RevisionsButtons( { userRevisions, selectedRevisionId, onChange } ) { - const currentTheme = useSelect( - ( select ) => select( coreStore ).getCurrentTheme(), - [] - ); + const { currentThemeName, currentUser } = useSelect( ( select ) => { + const { getCurrentTheme, getCurrentUser } = select( coreStore ); + const currentTheme = getCurrentTheme(); + return { + currentThemeName: + currentTheme?.name?.rendered || currentTheme?.stylesheet, + currentUser: getCurrentUser(), + }; + }, [] ); + const dateNowInMs = getDate().getTime(); + const { date: dateFormat, datetimeAbbreviated } = getSettings().formats; + return (
    { userRevisions.map( ( revision, index ) => { - const { id, author, modified } = revision; - const authorDisplayName = author?.name || __( 'User' ); - const authorAvatar = author?.avatar_urls?.[ '48' ]; - const isUnsaved = 'unsaved' === revision?.id; + const { id, isLatest, author, modified } = revision; + const isUnsaved = 'unsaved' === id; + // Unsaved changes are created by the current user. + const revisionAuthor = isUnsaved ? currentUser : author; + const authorDisplayName = revisionAuthor?.name || __( 'User' ); + const authorAvatar = revisionAuthor?.avatar_urls?.[ '48' ]; const isSelected = selectedRevisionId - ? selectedRevisionId === revision?.id + ? selectedRevisionId === id : index === 0; - const isReset = 'parent' === revision?.id; + const isReset = 'parent' === id; + const modifiedDate = getDate( modified ); + const displayDate = + modified && + dateNowInMs - modifiedDate.getTime() > DAY_IN_MILLISECONDS + ? dateI18n( dateFormat, modifiedDate ) + : humanTimeDiff( modified ); + const revisionLabel = getRevisionLabel( + id, + isLatest, + authorDisplayName, + dateI18n( datetimeAbbreviated, modifiedDate ) + ); return (
  1. { onChange( revision ); } } - label={ getRevisionLabel( revision ) } + label={ revisionLabel } > { isReset ? ( { __( 'Default styles' ) } - { currentTheme?.name?.rendered || - currentTheme?.stylesheet } + { currentThemeName } ) : ( - + { isUnsaved ? ( + + { __( '(Unsaved)' ) } + + ) : ( + + ) } - { isUnsaved - ? sprintf( - /* translators: %s author display name */ - __( - 'Unsaved changes by %s' - ), - authorDisplayName - ) - : sprintf( - /* translators: %s author display name */ - __( 'Changes saved by %s' ), - authorDisplayName - ) } - { + { authorDisplayName } ) } diff --git a/packages/edit-site/src/components/global-styles/screen-revisions/style.scss b/packages/edit-site/src/components/global-styles/screen-revisions/style.scss index 238f3f7d116e1..6598fcb5ce1c7 100644 --- a/packages/edit-site/src/components/global-styles/screen-revisions/style.scss +++ b/packages/edit-site/src/components/global-styles/screen-revisions/style.scss @@ -8,62 +8,80 @@ margin: 0; li { margin-bottom: 0; - border-left: 1px solid $gray-300; } } .edit-site-global-styles-screen-revisions__revision-item { position: relative; - padding: $grid-unit-10 0 $grid-unit-10 $grid-unit-15; + padding-left: $grid-unit-20; + overflow: hidden; + cursor: pointer; - &:first-child { - padding-top: 0; + &:hover { + background: rgba(var(--wp-admin-theme-color--rgb), 0.04); + .edit-site-global-styles-screen-revisions__date { + color: var(--wp-admin-theme-color); + } } - &:last-child { - padding-bottom: 0; + &::before, + &::after { + position: absolute; + content: "\a"; + display: block; } &::before { background: $gray-300; border-radius: 50%; - content: "\a"; - display: inline-block; height: $grid-unit-10; width: $grid-unit-10; - position: absolute; - top: 50%; - left: 0; + top: $grid-unit-20 + 2; + left: $grid-unit-20 + 1; // So the circle is centered on the line. transform: translate(-50%, -50%); + z-index: 1; } &.is-selected::before { background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #007cba)); } -} -.edit-site-global-styles-screen-revisions__revision-button { - width: 100%; - height: auto; - display: block; - padding: $grid-unit-10 $grid-unit-15; + &::after { + height: 100%; + left: $grid-unit-20; + top: 0; + width: 0; + border: 0.5px solid $gray-300; + } - &:hover { - background: rgba(var(--wp-admin-theme-color--rgb), 0.04); + &:first-child::after { + top: $grid-unit-20 + 2; + } - .edit-site-global-styles-screen-revisions__date { - color: var(--wp-admin-theme-color); + &:last-child::after { + height: $grid-unit-20 + 2; + } + + // Nested to override specificity of .components-button. + .edit-site-global-styles-screen-revisions__revision-button { + width: 100%; + height: auto; + display: block; + padding: $grid-unit-15 $grid-unit-15 $grid-unit-15 $grid-unit-30; + &:focus, + &:active { + outline: 0; + box-shadow: none; } } } .is-selected { + color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #007cba)); + background: rgba(var(--wp-admin-theme-color--rgb), 0.04); .edit-site-global-styles-screen-revisions__revision-button { - color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #007cba)); opacity: 1; - background: rgba(var(--wp-admin-theme-color--rgb), 0.04); } - - .edit-site-global-styles-screen-revisions__meta { + .edit-site-global-styles-screen-revisions__date { color: var(--wp-admin-theme-color); } } @@ -78,20 +96,26 @@ flex-direction: column; align-items: flex-start; gap: $grid-unit-10; + .edit-site-global-styles-screen-revisions__date { + text-transform: uppercase; + font-weight: 600; + font-size: 12px; + } } .edit-site-global-styles-screen-revisions__meta { - color: $gray-700; + color: $gray-600; display: flex; - justify-content: space-between; + justify-content: start; width: 100%; align-items: center; - text-align: left; + font-size: 12px; img { width: $grid-unit-20; height: $grid-unit-20; border-radius: 100%; + margin-right: $grid-unit-10; } } From 272d0a9c61551ab2da8d682896e6baec0fdcb93d Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 20 Nov 2023 17:48:39 +1000 Subject: [PATCH 077/116] Fix: Theme.json font settings in unit test (#56309) --- phpunit/class-wp-theme-json-test.php | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index e0c11766eaaae..07bec961553c9 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -221,12 +221,19 @@ public function test_get_stylesheet() { 'typography' => array( 'fontFamilies' => array( array( - 'slug' => 'small', - 'fontFamily' => '14px', + 'name' => 'Arial', + 'slug' => 'arial', + 'fontFamily' => 'Arial, serif', + ), + ), + 'fontSizes' => array( + array( + 'slug' => 'small', + 'size' => '14px', ), array( - 'slug' => 'big', - 'fontFamily' => '41px', + 'slug' => 'big', + 'size' => '41px', ), ), ), @@ -329,10 +336,11 @@ public function test_get_stylesheet() { ) ); - $variables = 'body{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}'; + $variables = 'body{--wp--preset--color--grey: grey;--wp--preset--font-size--small: 14px;--wp--preset--font-size--big: 41px;--wp--preset--font-family--arial: Arial, serif;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}'; $styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}body{color: var(--wp--preset--color--grey);}a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;min-height: 50vh;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}.wp-block-heading{color: #123456;}.wp-block-heading a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-post-excerpt{column-count: 2;}.wp-block-image{margin-bottom: 30px;}.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder{border-top-left-radius: 10px;border-bottom-right-radius: 1em;}'; - $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-small-font-family{font-family: var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family: var(--wp--preset--font-family--big) !important;}'; - $all = $variables . $styles . $presets; + $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-big-font-size{font-size: var(--wp--preset--font-size--big) !important;}.has-arial-font-family{font-family: var(--wp--preset--font-family--arial) !important;}'; + + $all = $variables . $styles . $presets; $this->assertEquals( $all, $theme_json->get_stylesheet() ); $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) ); From 8863b49b7e686f555e8b8adf70cc588c4feebfbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Mon, 20 Nov 2023 11:05:41 +0100 Subject: [PATCH 078/116] DataViews: extract common constants to file (#56251) --- .../edit-site/src/components/dataviews/README.md | 14 +++++++------- .../src/components/dataviews/add-filter.js | 5 +---- .../src/components/dataviews/constants.js | 5 +++++ .../edit-site/src/components/dataviews/filters.js | 5 ++--- .../src/components/dataviews/in-filter.js | 6 ++++-- .../src/components/dataviews/view-list.js | 5 +---- .../edit-site/src/components/page-pages/index.js | 15 +++++++++++---- .../components/sidebar-dataviews/default-views.js | 9 +++++++-- 8 files changed, 38 insertions(+), 26 deletions(-) create mode 100644 packages/edit-site/src/components/dataviews/constants.js diff --git a/packages/edit-site/src/components/dataviews/README.md b/packages/edit-site/src/components/dataviews/README.md index 0645f22821cb9..5e01c17dcd940 100644 --- a/packages/edit-site/src/components/dataviews/README.md +++ b/packages/edit-site/src/components/dataviews/README.md @@ -44,8 +44,8 @@ Example: }, search: '', filters: [ - { field: 'author', operator: 'in', value: 2 }, - { field: 'status', operator: 'in', value: 'publish,draft' } + { field: 'author', operator: OPERATOR_IN, value: 2 }, + { field: 'status', operator: OPERATOR_IN, value: 'publish,draft' } ], hiddenFields: [ 'date', 'featured-image' ], layout: {}, @@ -83,8 +83,8 @@ function MyCustomPageList() { }, search: '', filters: [ - { field: 'author', operator: 'in', value: 2 }, - { field: 'status', operator: 'in', value: 'publish,draft' } + { field: 'author', operator: OPERATOR_IN, value: 2 }, + { field: 'status', operator: OPERATOR_IN, value: 'publish,draft' } ], hiddenFields: [ 'date', 'featured-image' ], layout: {}, @@ -93,10 +93,10 @@ function MyCustomPageList() { const queryArgs = useMemo( () => { const filters = {}; view.filters.forEach( ( filter ) => { - if ( filter.field === 'status' && filter.operator === 'in' ) { + if ( filter.field === 'status' && filter.operator === OPERATOR_IN ) { filters.status = filter.value; } - if ( filter.field === 'author' && filter.operator === 'in' ) { + if ( filter.field === 'author' && filter.operator === OPERATOR_IN ) { filters.author = filter.value; } } ); @@ -154,7 +154,7 @@ Example: { item.author } ); }, - type: 'enumeration', + type: ENUMERATION_TYPE, elements: [ { value: 1, label: 'Admin' } { value: 2, label: 'User' } diff --git a/packages/edit-site/src/components/dataviews/add-filter.js b/packages/edit-site/src/components/dataviews/add-filter.js index 374a90eab9df0..147b5a09ca59a 100644 --- a/packages/edit-site/src/components/dataviews/add-filter.js +++ b/packages/edit-site/src/components/dataviews/add-filter.js @@ -13,7 +13,7 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import { unlock } from '../../lock-unlock'; -import { OPERATOR_IN } from './in-filter'; +import { ENUMERATION_TYPE, OPERATOR_IN } from './constants'; const { DropdownMenuV2, @@ -22,9 +22,6 @@ const { DropdownMenuItemV2, } = unlock( componentsPrivateApis ); -// TODO: find a place where these constants can be shared across components. -const ENUMERATION_TYPE = 'enumeration'; - export default function AddFilter( { fields, view, onChangeView } ) { const filters = []; fields.forEach( ( field ) => { diff --git a/packages/edit-site/src/components/dataviews/constants.js b/packages/edit-site/src/components/dataviews/constants.js new file mode 100644 index 0000000000000..2af12b04c559d --- /dev/null +++ b/packages/edit-site/src/components/dataviews/constants.js @@ -0,0 +1,5 @@ +// Field types. +export const ENUMERATION_TYPE = 'enumeration'; + +// Filter operators. +export const OPERATOR_IN = 'in'; diff --git a/packages/edit-site/src/components/dataviews/filters.js b/packages/edit-site/src/components/dataviews/filters.js index 72ba28fd06326..72ca0eb35bd87 100644 --- a/packages/edit-site/src/components/dataviews/filters.js +++ b/packages/edit-site/src/components/dataviews/filters.js @@ -6,11 +6,10 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import { default as InFilter, OPERATOR_IN } from './in-filter'; +import { default as InFilter } from './in-filter'; import AddFilter from './add-filter'; import ResetFilters from './reset-filters'; - -const ENUMERATION_TYPE = 'enumeration'; +import { ENUMERATION_TYPE, OPERATOR_IN } from './constants'; export default function Filters( { fields, view, onChangeView } ) { const filters = []; diff --git a/packages/edit-site/src/components/dataviews/in-filter.js b/packages/edit-site/src/components/dataviews/in-filter.js index cb76bab0f870a..4f4170fdcbb0b 100644 --- a/packages/edit-site/src/components/dataviews/in-filter.js +++ b/packages/edit-site/src/components/dataviews/in-filter.js @@ -7,8 +7,10 @@ import { } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; -// TODO: find a place where these constants can be shared across components. -export const OPERATOR_IN = 'in'; +/** + * Internal dependencies + */ +import { OPERATOR_IN } from './constants'; export default ( { filter, view, onChangeView } ) => { const valueFound = view.filters.find( diff --git a/packages/edit-site/src/components/dataviews/view-list.js b/packages/edit-site/src/components/dataviews/view-list.js index fc8b407502579..07190663de02b 100644 --- a/packages/edit-site/src/components/dataviews/view-list.js +++ b/packages/edit-site/src/components/dataviews/view-list.js @@ -36,6 +36,7 @@ import { useMemo, Children, Fragment } from '@wordpress/element'; */ import { unlock } from '../../lock-unlock'; import ItemActions from './item-actions'; +import { ENUMERATION_TYPE, OPERATOR_IN } from './constants'; const { DropdownMenuV2, @@ -53,10 +54,6 @@ const sortingItemsInfo = { }; const sortIcons = { asc: chevronUp, desc: chevronDown }; -// TODO: find a place where these constants can be shared across components. -const ENUMERATION_TYPE = 'enumeration'; -const OPERATOR_IN = 'in'; - function HeaderMenu( { dataView, header } ) { if ( header.isPlaceholder ) { return null; diff --git a/packages/edit-site/src/components/page-pages/index.js b/packages/edit-site/src/components/page-pages/index.js index d6c295dc72ff0..ea29d29335e27 100644 --- a/packages/edit-site/src/components/page-pages/index.js +++ b/packages/edit-site/src/components/page-pages/index.js @@ -31,6 +31,7 @@ import { import SideEditor from './side-editor'; import Media from '../media'; import { unlock } from '../../lock-unlock'; +import { ENUMERATION_TYPE, OPERATOR_IN } from '../dataviews/constants'; const { useLocation } = unlock( routerPrivateApis ); const EMPTY_ARRAY = []; @@ -120,10 +121,16 @@ export default function PagePages() { const queryArgs = useMemo( () => { const filters = {}; view.filters.forEach( ( filter ) => { - if ( filter.field === 'status' && filter.operator === 'in' ) { + if ( + filter.field === 'status' && + filter.operator === OPERATOR_IN + ) { filters.status = filter.value; } - if ( filter.field === 'author' && filter.operator === 'in' ) { + if ( + filter.field === 'author' && + filter.operator === OPERATOR_IN + ) { filters.author = filter.value; } } ); @@ -227,7 +234,7 @@ export default function PagePages() { ); }, - type: 'enumeration', + type: ENUMERATION_TYPE, elements: authors?.map( ( { id, name } ) => ( { value: id, @@ -240,7 +247,7 @@ export default function PagePages() { getValue: ( { item } ) => STATUSES.find( ( { value } ) => value === item.status ) ?.label ?? item.status, - type: 'enumeration', + type: ENUMERATION_TYPE, elements: STATUSES, enableSorting: false, }, diff --git a/packages/edit-site/src/components/sidebar-dataviews/default-views.js b/packages/edit-site/src/components/sidebar-dataviews/default-views.js index a1557e3b8a344..d853b6cde112f 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/default-views.js +++ b/packages/edit-site/src/components/sidebar-dataviews/default-views.js @@ -4,6 +4,11 @@ import { __ } from '@wordpress/i18n'; import { trash } from '@wordpress/icons'; +/** + * Internal dependencies + */ +import { OPERATOR_IN } from '../dataviews/constants'; + const DEFAULT_PAGE_BASE = { type: 'list', search: '', @@ -33,7 +38,7 @@ const DEFAULT_VIEWS = { view: { ...DEFAULT_PAGE_BASE, filters: [ - { field: 'status', operator: 'in', value: 'draft' }, + { field: 'status', operator: OPERATOR_IN, value: 'draft' }, ], }, }, @@ -44,7 +49,7 @@ const DEFAULT_VIEWS = { view: { ...DEFAULT_PAGE_BASE, filters: [ - { field: 'status', operator: 'in', value: 'trash' }, + { field: 'status', operator: OPERATOR_IN, value: 'trash' }, ], }, }, From 447a6de8eb79f307921a22fb8814cc01affded46 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 20 Nov 2023 14:05:51 +0100 Subject: [PATCH 079/116] Extract a PostPanelRow component from the different sidebar panels (#56238) --- .../sidebar/post-pending-status/index.js | 13 +++++-- .../components/sidebar/post-status/index.js | 2 +- .../components/sidebar/post-sticky/index.js | 13 +++++-- .../components/sidebar/post-template/index.js | 16 +++++---- .../sidebar/post-template/style.scss | 15 -------- .../sidebar/post-visibility/index.js | 17 +++++++--- .../sidebar/post-visibility/style.scss | 11 ------ .../page-panels/edit-template.js | 18 ++++------ .../page-panels/page-status.js | 12 +++---- .../sidebar-edit-mode/page-panels/style.scss | 28 +++++---------- .../src/components/post-panel-row/index.js | 34 +++++++++++++++++++ .../src/components/post-panel-row/style.scss | 15 ++++++++ .../src/components/post-schedule/panel.js | 15 +++----- .../src/components/post-schedule/style.scss | 13 +------ .../src/components/post-sync-status/index.js | 9 +++-- .../components/post-sync-status/style.scss | 20 ++--------- .../editor/src/components/post-url/panel.js | 12 +++---- .../editor/src/components/post-url/style.scss | 13 +------ packages/editor/src/private-apis.js | 2 ++ packages/editor/src/style.scss | 1 + 20 files changed, 133 insertions(+), 146 deletions(-) create mode 100644 packages/editor/src/components/post-panel-row/index.js create mode 100644 packages/editor/src/components/post-panel-row/style.scss diff --git a/packages/edit-post/src/components/sidebar/post-pending-status/index.js b/packages/edit-post/src/components/sidebar/post-pending-status/index.js index 739aff6034b50..de1f02b00d746 100644 --- a/packages/edit-post/src/components/sidebar/post-pending-status/index.js +++ b/packages/edit-post/src/components/sidebar/post-pending-status/index.js @@ -1,18 +1,25 @@ /** * WordPress dependencies */ -import { PanelRow } from '@wordpress/components'; import { PostPendingStatus as PostPendingStatusForm, PostPendingStatusCheck, + privateApis as editorPrivateApis, } from '@wordpress/editor'; +/** + * Internal dependencies + */ +import { unlock } from '../../../lock-unlock'; + +const { PostPanelRow } = unlock( editorPrivateApis ); + export function PostPendingStatus() { return ( - + - + ); } diff --git a/packages/edit-post/src/components/sidebar/post-status/index.js b/packages/edit-post/src/components/sidebar/post-status/index.js index c8c5a20adcfab..ba6afa2ae9f27 100644 --- a/packages/edit-post/src/components/sidebar/post-status/index.js +++ b/packages/edit-post/src/components/sidebar/post-status/index.js @@ -64,12 +64,12 @@ export default function PostStatus() { + - { fills } - + - + ); } diff --git a/packages/edit-post/src/components/sidebar/post-template/index.js b/packages/edit-post/src/components/sidebar/post-template/index.js index 88809294f17db..fa1579fa3a82a 100644 --- a/packages/edit-post/src/components/sidebar/post-template/index.js +++ b/packages/edit-post/src/components/sidebar/post-template/index.js @@ -2,10 +2,13 @@ * WordPress dependencies */ import { useState, useMemo } from '@wordpress/element'; -import { PanelRow, Dropdown, Button } from '@wordpress/components'; +import { Dropdown, Button } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import { useSelect } from '@wordpress/data'; -import { store as editorStore } from '@wordpress/editor'; +import { + store as editorStore, + privateApis as editorPrivateApis, +} from '@wordpress/editor'; import { store as coreStore } from '@wordpress/core-data'; /** @@ -13,6 +16,9 @@ import { store as coreStore } from '@wordpress/core-data'; */ import PostTemplateForm from './form'; import { store as editPostStore } from '../../../store'; +import { unlock } from '../../../lock-unlock'; + +const { PostPanelRow } = unlock( editorPrivateApis ); export default function PostTemplate() { // Use internal state instead of a ref to make sure that the component @@ -53,11 +59,9 @@ export default function PostTemplate() { } return ( - - { __( 'Template' ) } + ( @@ -70,7 +74,7 @@ export default function PostTemplate() { ) } /> - + ); } diff --git a/packages/edit-post/src/components/sidebar/post-template/style.scss b/packages/edit-post/src/components/sidebar/post-template/style.scss index 2746fc2eeec4f..91f82d4d0f9f3 100644 --- a/packages/edit-post/src/components/sidebar/post-template/style.scss +++ b/packages/edit-post/src/components/sidebar/post-template/style.scss @@ -1,18 +1,3 @@ -.edit-post-post-template { - width: 100%; - justify-content: flex-start; - - span { - display: block; - width: 30%; - margin-right: 8px; - } -} - -.edit-post-post-template__dropdown { - max-width: 55%; -} - .components-button.edit-post-post-template__toggle { display: inline-block; width: 100%; diff --git a/packages/edit-post/src/components/sidebar/post-visibility/index.js b/packages/edit-post/src/components/sidebar/post-visibility/index.js index 080737c431f1e..9a70d636388af 100644 --- a/packages/edit-post/src/components/sidebar/post-visibility/index.js +++ b/packages/edit-post/src/components/sidebar/post-visibility/index.js @@ -2,15 +2,23 @@ * WordPress dependencies */ import { __, sprintf } from '@wordpress/i18n'; -import { PanelRow, Dropdown, Button } from '@wordpress/components'; +import { Dropdown, Button } from '@wordpress/components'; import { PostVisibility as PostVisibilityForm, PostVisibilityLabel, PostVisibilityCheck, usePostVisibilityLabel, + privateApis as editorPrivateApis, } from '@wordpress/editor'; import { useMemo, useState } from '@wordpress/element'; +/** + * Internal dependencies + */ +import { unlock } from '../../../lock-unlock'; + +const { PostPanelRow } = unlock( editorPrivateApis ); + export function PostVisibility() { // Use internal state instead of a ref to make sure that the component // re-renders when the popover's anchor updates. @@ -29,11 +37,10 @@ export function PostVisibility() { return ( ( - - { __( 'Visibility' ) } { ! canEdit && ( @@ -55,7 +62,7 @@ export function PostVisibility() { ) } /> ) } - + ) } /> ); diff --git a/packages/edit-post/src/components/sidebar/post-visibility/style.scss b/packages/edit-post/src/components/sidebar/post-visibility/style.scss index b3876c8403aa0..0dd9824e5bde7 100644 --- a/packages/edit-post/src/components/sidebar/post-visibility/style.scss +++ b/packages/edit-post/src/components/sidebar/post-visibility/style.scss @@ -1,14 +1,3 @@ -.edit-post-post-visibility { - width: 100%; - justify-content: flex-start; - - span { - display: block; - width: 30%; - margin-right: 8px; - } -} - .edit-post-post-visibility__dialog .editor-post-visibility { // sidebar width - popover padding - form margin min-width: $sidebar-width - $grid-unit-20 - $grid-unit-20; diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js index 1ee382420a7d9..4bc81b8c7a292 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js @@ -3,17 +3,12 @@ */ import { useSelect, useDispatch } from '@wordpress/data'; import { decodeEntities } from '@wordpress/html-entities'; -import { - DropdownMenu, - MenuGroup, - MenuItem, - __experimentalHStack as HStack, - __experimentalText as Text, -} from '@wordpress/components'; +import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { store as coreStore } from '@wordpress/core-data'; import { check } from '@wordpress/icons'; import { store as blockEditorStore } from '@wordpress/block-editor'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies @@ -24,6 +19,8 @@ import ResetDefaultTemplate from './reset-default-template'; import { unlock } from '../../../lock-unlock'; import { PAGE_CONTENT_BLOCK_TYPES } from '../../../utils/constants'; +const { PostPanelRow } = unlock( editorPrivateApis ); + const POPOVER_PROPS = { className: 'edit-site-page-panels-edit-template__dropdown', placement: 'bottom-start', @@ -71,10 +68,7 @@ export default function EditTemplate() { } return ( - - - { __( 'Template' ) } - + ) } - + ); } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-status.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-status.js index f80ed4d3fe820..1d74b09db773e 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-status.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-status.js @@ -6,7 +6,6 @@ import { ToggleControl, Dropdown, __experimentalText as Text, - __experimentalHStack as HStack, __experimentalVStack as VStack, TextControl, RadioControl, @@ -19,11 +18,15 @@ import { store as coreStore } from '@wordpress/core-data'; import { store as noticesStore } from '@wordpress/notices'; import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor'; import { useInstanceId } from '@wordpress/compose'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies */ import StatusLabel from '../../sidebar-navigation-screen-page/status-label'; +import { unlock } from '../../../lock-unlock'; + +const { PostPanelRow } = unlock( editorPrivateApis ); const STATUS_OPTIONS = [ { @@ -159,10 +162,7 @@ export default function PageStatus( { }; return ( - - - { __( 'Status' ) } - + ) } /> - + ); } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss index acaf5cbfe35dd..f3da54c244bd1 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss @@ -59,25 +59,15 @@ } } -.edit-site-summary-field { - .components-dropdown { - width: 70%; - } - - .edit-site-summary-field__trigger { - max-width: 100%; - - // Truncate - display: block; - text-align: left; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .edit-site-summary-field__label { - width: 30%; - } +.edit-site-summary-field__trigger { + max-width: 100%; + + // Truncate + display: block; + text-align: left; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .edit-site-page-panels-edit-template__dropdown { diff --git a/packages/editor/src/components/post-panel-row/index.js b/packages/editor/src/components/post-panel-row/index.js new file mode 100644 index 0000000000000..a746486ea25f6 --- /dev/null +++ b/packages/editor/src/components/post-panel-row/index.js @@ -0,0 +1,34 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { __experimentalHStack as HStack } from '@wordpress/components'; +import { forwardRef } from '@wordpress/element'; + +const PostPanelRow = forwardRef( ( { className, label, children }, ref ) => { + return ( + + { label ? ( + <> +
    + { label } +
    +
    + { children } +
    + + ) : ( + children + ) } +
    + ); +} ); + +export default PostPanelRow; diff --git a/packages/editor/src/components/post-panel-row/style.scss b/packages/editor/src/components/post-panel-row/style.scss new file mode 100644 index 0000000000000..b21679e9b9697 --- /dev/null +++ b/packages/editor/src/components/post-panel-row/style.scss @@ -0,0 +1,15 @@ +.editor-post-panel__row { + width: 100%; + justify-content: flex-start; + align-items: flex-start; + min-height: $button-size; +} + +.editor-post-panel__row-label { + width: 30%; + flex-shrink: 0; +} + +.editor-post-panel__row-control { + flex-grow: 1; +} diff --git a/packages/editor/src/components/post-schedule/panel.js b/packages/editor/src/components/post-schedule/panel.js index 834e7237e0e94..2e725a06bc9fd 100644 --- a/packages/editor/src/components/post-schedule/panel.js +++ b/packages/editor/src/components/post-schedule/panel.js @@ -1,11 +1,7 @@ /** * WordPress dependencies */ -import { - Button, - Dropdown, - __experimentalHStack as HStack, -} from '@wordpress/components'; +import { Button, Dropdown } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import { useState, useMemo } from '@wordpress/element'; @@ -15,6 +11,7 @@ import { useState, useMemo } from '@wordpress/element'; import PostScheduleCheck from './check'; import PostScheduleForm from './index'; import { usePostScheduleLabel } from './label'; +import PostPanelRow from '../post-panel-row'; export default function PostSchedulePanel() { const [ popoverAnchor, setPopoverAnchor ] = useState( null ); @@ -35,11 +32,7 @@ export default function PostSchedulePanel() { return ( - - { __( 'Publish' ) } + ) } /> - + ); } diff --git a/packages/editor/src/components/post-schedule/style.scss b/packages/editor/src/components/post-schedule/style.scss index d70a9e9576fbb..fb8503962f7cd 100644 --- a/packages/editor/src/components/post-schedule/style.scss +++ b/packages/editor/src/components/post-schedule/style.scss @@ -1,16 +1,5 @@ -.editor-post-schedule__panel { - width: 100%; - justify-content: flex-start; - align-items: flex-start; - - span { - display: block; - width: 30%; - } -} - .editor-post-schedule__panel-dropdown { - width: 70%; + width: 100%; } .editor-post-schedule__dialog { diff --git a/packages/editor/src/components/post-sync-status/index.js b/packages/editor/src/components/post-sync-status/index.js index abc45146c36af..c1a317e8e1812 100644 --- a/packages/editor/src/components/post-sync-status/index.js +++ b/packages/editor/src/components/post-sync-status/index.js @@ -4,7 +4,6 @@ import { useSelect, useDispatch } from '@wordpress/data'; import { __, _x } from '@wordpress/i18n'; import { - PanelRow, Modal, Button, __experimentalHStack as HStack, @@ -17,6 +16,7 @@ import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; /** * Internal dependencies */ +import PostPanelRow from '../post-panel-row'; import { store as editorStore } from '../../store'; import { unlock } from '../../lock-unlock'; @@ -44,14 +44,13 @@ export default function PostSyncStatus() { } return ( - - { __( 'Sync status' ) } -
    + +
    { syncStatus === 'unsynced' ? __( 'Not synced' ) : __( 'Fully synced' ) }
    - +
    ); } diff --git a/packages/editor/src/components/post-sync-status/style.scss b/packages/editor/src/components/post-sync-status/style.scss index e18eead94ac83..d5ee21cad8ee4 100644 --- a/packages/editor/src/components/post-sync-status/style.scss +++ b/packages/editor/src/components/post-sync-status/style.scss @@ -1,18 +1,4 @@ -.edit-post-sync-status { - width: 100%; - position: relative; - justify-content: flex-start; - align-items: flex-start; - - > span { - display: block; - width: 30%; - margin-right: 8px; - word-break: break-word; - } - - > div { - // Match padding on tertiary buttons for alignment. - padding: $grid-unit-15 * 0.5 0 $grid-unit-15 * 0.5 $grid-unit-15; - } +.editor-post-sync-status__value { + // Match padding on tertiary buttons for alignment. + padding: $grid-unit-15 * 0.5 0 $grid-unit-15 * 0.5 $grid-unit-15; } diff --git a/packages/editor/src/components/post-url/panel.js b/packages/editor/src/components/post-url/panel.js index 1fddc7df9922c..4c4fc38d3e2df 100644 --- a/packages/editor/src/components/post-url/panel.js +++ b/packages/editor/src/components/post-url/panel.js @@ -2,11 +2,7 @@ * WordPress dependencies */ import { useMemo, useState } from '@wordpress/element'; -import { - __experimentalHStack as HStack, - Dropdown, - Button, -} from '@wordpress/components'; +import { Dropdown, Button } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; /** @@ -15,6 +11,7 @@ import { __, sprintf } from '@wordpress/i18n'; import PostURLCheck from './check'; import PostURL from './index'; import { usePostURLLabel } from './label'; +import PostPanelRow from '../post-panel-row'; export default function PostURLPanel() { // Use internal state instead of a ref to make sure that the component @@ -28,8 +25,7 @@ export default function PostURLPanel() { return ( - - { __( 'URL' ) } + ) } /> - + ); } diff --git a/packages/editor/src/components/post-url/style.scss b/packages/editor/src/components/post-url/style.scss index dbc68d7eda77d..4a3e8e1b39c9f 100644 --- a/packages/editor/src/components/post-url/style.scss +++ b/packages/editor/src/components/post-url/style.scss @@ -1,16 +1,5 @@ -.editor-post-url__panel { - width: 100%; - justify-content: flex-start; - align-items: flex-start; - - span { - display: block; - width: 30%; - } -} - .editor-post-url__panel-dropdown { - width: 70%; + width: 100%; } .components-button.editor-post-url__panel-toggle { diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index b599278f872dd..a44720eb93ac8 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -5,11 +5,13 @@ import { ExperimentalEditorProvider } from './components/provider'; import { lock } from './lock-unlock'; import { EntitiesSavedStatesExtensible } from './components/entities-saved-states'; import useBlockEditorSettings from './components/provider/use-block-editor-settings'; +import PostPanelRow from './components/post-panel-row'; export const privateApis = {}; lock( privateApis, { ExperimentalEditorProvider, EntitiesSavedStatesExtensible, + PostPanelRow, // This is a temporary private API while we're updating the site editor to use EditorProvider. useBlockEditorSettings, diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss index 5428bf5cb1f15..5861764ff8737 100644 --- a/packages/editor/src/style.scss +++ b/packages/editor/src/style.scss @@ -8,6 +8,7 @@ @import "./components/post-format/style.scss"; @import "./components/post-last-revision/style.scss"; @import "./components/post-locked-modal/style.scss"; +@import "./components/post-panel-row/style.scss"; @import "./components/post-publish-button/style.scss"; @import "./components/post-publish-panel/style.scss"; @import "./components/post-saved-state/style.scss"; From d4dc45f014a052cd7ece453872d83dfae7450337 Mon Sep 17 00:00:00 2001 From: JuanMa Date: Mon, 20 Nov 2023 14:14:25 +0000 Subject: [PATCH 080/116] Added clarifications and examples to "Get started with wp-scripts" (#56298) --- .../devenv/get-started-with-wp-scripts.md | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/getting-started/devenv/get-started-with-wp-scripts.md b/docs/getting-started/devenv/get-started-with-wp-scripts.md index 8a7d100c8921f..6416adc081e70 100644 --- a/docs/getting-started/devenv/get-started-with-wp-scripts.md +++ b/docs/getting-started/devenv/get-started-with-wp-scripts.md @@ -20,7 +20,7 @@ The package abstracts away much of the initial setup, configuration, and boilerp ## Quick start
    - If you want to build a custom block, the @wordpress/create-block package allows you to scaffold the structure of files needed to create and register a block. It generates all the necessary code to start a project and integrates a modern JavaScript build setup (using wp-scripts) with no configuration required. Refer to Get started with create-block for more details. + If you use @wordpress/create-block package to scaffold the structure of files needed to create and register a block, you'll also get a modern JavaScript build setup (using wp-scripts) with no configuration required, so you don't need to worry about installing wp-scripts or enqueuing assets. Refer to Get started with create-block for more details.
    ### Installation @@ -64,15 +64,25 @@ Once installed, you can run the predefined scripts provided with `wp-scripts` by } ``` -These scripts can then be run using the command `npm run {script name}`. The two scripts you will use most often are `start` and `build` since they handle the build step. See the [package documentation](https://developer.wordpress.org/block-editor/packages/packages-scripts/) for all options. +These scripts can then be run using the command `npm run {script name}`. + +### The build process with `wp-scripts` + +The two scripts you will use most often are `start` and `build` since they handle the build step. See the [package documentation](https://developer.wordpress.org/block-editor/packages/packages-scripts/) for all options. When working on your project, use the `npm run start` command. This will start a development server and automatically rebuild the project whenever any change is detected. Note that the compiled code in `build/index.js` will not be optimized. When you are ready to deploy your project, use the `npm run build` command. This optimizes your code and makes it production-ready. -After the build finishes, you will see the compiled JavaScript file created at `build/index.js`. A `build/index.asset.php` file will also be created, which contains an array of dependencies and a version number (for cache busting). +After the build finishes, you will see the compiled JavaScript file created at `build/index.js`. + +A `build/index.asset.php` file will also be created in the build process, which contains an array of dependencies and a version number (for cache busting). Please, note that to register a block without this `wp-scripts` build process you'll need to manually create `*.asset.php` dependencies files (see [example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/minimal-block-no-build-e621a6)). -Enqueue the file in the Editor using PHP as you would any other JavaScript file. You can refer to the [Enqueueing assets in the Editor](https://developer.wordpress.org/block-editor/how-to-guides/enqueueing-assets-in-the-editor/) guide for more information, but here's a typical implementation. +### Enqueuing assets + +If you register a block via `register_block_type` the scripts defined in `block.json` will be automatically enqueued (see [example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/minimal-block-ca6eda)) + +To manually enqueue files in the editor, in any other context, you can refer to the [Enqueueing assets in the Editor](https://developer.wordpress.org/block-editor/how-to-guides/enqueueing-assets-in-the-editor/) guide for more information, but here's a typical implementation. ```php /** @@ -91,6 +101,8 @@ function example_project_enqueue_editor_assets() { add_action( 'enqueue_block_editor_assets', 'example_project_enqueue_editor_assets' ); ``` +Here's [an example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) of manually enqueuing files in the editor. + ## Next steps While `start` and `build` will be the two most used scripts, several other useful tools come with `wp-scripts` that are worth exploring. Here's a look at a few. From 02c0fc6452475b6cfdbdf8f6cf8ac4b0d216a800 Mon Sep 17 00:00:00 2001 From: JuanMa Date: Mon, 20 Nov 2023 15:05:50 +0000 Subject: [PATCH 081/116] Link preview image to live example using WordPress Playground (#56292) * Embed preview of the example using iframe and WordPress Playground Embed preview of the example using iframe and WordPress Playground * Add link to live preview * Update docs/how-to-guides/data-basics/README.md Co-authored-by: Alex Stine * proper alt and titles attributes added * proper alt and titles attributes added * Update docs/how-to-guides/data-basics/README.md Co-authored-by: Alex Stine --------- Co-authored-by: Alex Stine --- docs/how-to-guides/data-basics/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/how-to-guides/data-basics/README.md b/docs/how-to-guides/data-basics/README.md index 3cb07eae2b659..3e92a216b60c5 100644 --- a/docs/how-to-guides/data-basics/README.md +++ b/docs/how-to-guides/data-basics/README.md @@ -2,7 +2,8 @@ This tutorial aims to get you comfortable with the Gutenberg data layer. It guides you through building a simple React application that enables the user to manage their WordPress pages. The finished app will look like this: -![](https://raw.githubusercontent.com/WordPress/gutenberg/HEAD/docs/how-to-guides/data-basics/media/list-of-pages/part1-finished.jpg) + +[![Open demo in WordPress Playground](https://raw.githubusercontent.com/WordPress/gutenberg/HEAD/docs/how-to-guides/data-basics/media/list-of-pages/part1-finished.jpg)](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/WordPress/block-development-examples/trunk/plugins/data-basics-59c8f8/_playground/blueprint.json "Opens demo in WordPress Playground") You may review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository. From 0ba206b88120ef93da94cd7df6e427cf918700e9 Mon Sep 17 00:00:00 2001 From: Joen A <1204802+jasmussen@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:35:19 +0100 Subject: [PATCH 082/116] Try: Change "Detach pattern" to "Detach" (#56323) * Update: Change "Detach patterns" to singular. * Try: "Detach" instead of "Detach pattern". --- .../block-toolbar-menu.native.js | 5 +- .../block-library/src/block/edit.native.js | 18 ++--- .../editor/various/pattern-blocks.test.js | 6 +- .../src/components/patterns-manage-button.js | 71 +++++++++---------- .../reusable-blocks-manage-button.js | 71 +++++++++---------- 5 files changed, 77 insertions(+), 94 deletions(-) diff --git a/packages/block-editor/src/components/block-toolbar/block-toolbar-menu.native.js b/packages/block-editor/src/components/block-toolbar/block-toolbar-menu.native.js index b579de1f046d9..c8d220fedfb35 100644 --- a/packages/block-editor/src/components/block-toolbar/block-toolbar-menu.native.js +++ b/packages/block-editor/src/components/block-toolbar/block-toolbar-menu.native.js @@ -212,10 +212,7 @@ const BlockActionsMenu = ( { }, convertToRegularBlocks: { id: 'convertToRegularBlocksOption', - label: - innerBlockCount > 1 - ? __( 'Detach patterns' ) - : __( 'Detach pattern' ), + label: __( 'Detach' ), value: 'convertToRegularBlocksOption', onSelect: () => { /* translators: %s: name of the synced block */ diff --git a/packages/block-library/src/block/edit.native.js b/packages/block-library/src/block/edit.native.js index ddc22c01e40de..9ab6ccf86a1e1 100644 --- a/packages/block-library/src/block/edit.native.js +++ b/packages/block-library/src/block/edit.native.js @@ -78,7 +78,7 @@ export default function ReusableBlockEdit( { styles.spinnerDark ); - const { hasResolved, isEditing, isMissing, innerBlockCount } = useSelect( + const { hasResolved, isEditing, isMissing } = useSelect( ( select ) => { const persistedBlock = select( coreStore ).getEntityRecord( 'postType', @@ -176,20 +176,12 @@ export default function ReusableBlockEdit( { { infoTitle } - { innerBlockCount > 1 - ? __( - 'Alternatively, you can detach and edit these blocks separately by tapping “Detach patterns”.' - ) - : __( - 'Alternatively, you can detach and edit this block separately by tapping “Detach pattern”.' - ) } + { __( + 'Alternatively, you can detach and edit this block separately by tapping “Detach”.' + ) } 1 - ? __( 'Detach patterns' ) - : __( 'Detach pattern' ) - } + label={ __( 'Detach' ) } separatorType="topFullWidth" onPress={ onConvertToRegularBlocks } labelStyle={ actionButtonStyle } diff --git a/packages/e2e-tests/specs/editor/various/pattern-blocks.test.js b/packages/e2e-tests/specs/editor/various/pattern-blocks.test.js index 442ed2b21915a..cb5187a390e8b 100644 --- a/packages/e2e-tests/specs/editor/various/pattern-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/pattern-blocks.test.js @@ -112,7 +112,7 @@ describe( 'Pattern blocks', () => { // Convert block to a regular block. await clickBlockToolbarButton( 'Options' ); - await clickMenuItem( 'Detach pattern' ); + await clickMenuItem( 'Detach' ); // Check that we have a paragraph block on the page. const paragraphBlock = await canvas().$( @@ -219,7 +219,7 @@ describe( 'Pattern blocks', () => { // Convert block to a regular block. await clickBlockToolbarButton( 'Options' ); - await clickMenuItem( 'Detach patterns' ); + await clickMenuItem( 'Detach' ); // Check that we have two paragraph blocks on the page. expect( await getEditedPostContent() ).toMatchSnapshot(); @@ -352,7 +352,7 @@ describe( 'Pattern blocks', () => { // Convert back to regular blocks. await clickBlockToolbarButton( 'Select Edited block' ); await clickBlockToolbarButton( 'Options' ); - await clickMenuItem( 'Detach pattern' ); + await clickMenuItem( 'Detach' ); await page.waitForXPath( selector, { hidden: true, } ); diff --git a/packages/patterns/src/components/patterns-manage-button.js b/packages/patterns/src/components/patterns-manage-button.js index a86208a04b601..45ad96d8d8aae 100644 --- a/packages/patterns/src/components/patterns-manage-button.js +++ b/packages/patterns/src/components/patterns-manage-button.js @@ -16,41 +16,40 @@ import { store as patternsStore } from '../store'; import { unlock } from '../lock-unlock'; function PatternsManageButton( { clientId } ) { - const { canRemove, isVisible, innerBlockCount, managePatternsUrl } = - useSelect( - ( select ) => { - const { getBlock, canRemoveBlock, getBlockCount, getSettings } = - select( blockEditorStore ); - const { canUser } = select( coreStore ); - const reusableBlock = getBlock( clientId ); - const isBlockTheme = getSettings().__unstableIsBlockBasedTheme; + const { canRemove, isVisible, managePatternsUrl } = useSelect( + ( select ) => { + const { getBlock, canRemoveBlock, getBlockCount, getSettings } = + select( blockEditorStore ); + const { canUser } = select( coreStore ); + const reusableBlock = getBlock( clientId ); + const isBlockTheme = getSettings().__unstableIsBlockBasedTheme; - return { - canRemove: canRemoveBlock( clientId ), - isVisible: - !! reusableBlock && - isReusableBlock( reusableBlock ) && - !! canUser( - 'update', - 'blocks', - reusableBlock.attributes.ref - ), - innerBlockCount: getBlockCount( clientId ), - // The site editor and templates both check whether the user - // has edit_theme_options capabilities. We can leverage that here - // and omit the manage patterns link if the user can't access it. - managePatternsUrl: - isBlockTheme && canUser( 'read', 'templates' ) - ? addQueryArgs( 'site-editor.php', { - path: '/patterns', - } ) - : addQueryArgs( 'edit.php', { - post_type: 'wp_block', - } ), - }; - }, - [ clientId ] - ); + return { + canRemove: canRemoveBlock( clientId ), + isVisible: + !! reusableBlock && + isReusableBlock( reusableBlock ) && + !! canUser( + 'update', + 'blocks', + reusableBlock.attributes.ref + ), + innerBlockCount: getBlockCount( clientId ), + // The site editor and templates both check whether the user + // has edit_theme_options capabilities. We can leverage that here + // and omit the manage patterns link if the user can't access it. + managePatternsUrl: + isBlockTheme && canUser( 'read', 'templates' ) + ? addQueryArgs( 'site-editor.php', { + path: '/patterns', + } ) + : addQueryArgs( 'edit.php', { + post_type: 'wp_block', + } ), + }; + }, + [ clientId ] + ); // Ignore reason: false positive of the lint rule. // eslint-disable-next-line @wordpress/no-unused-vars-before-return @@ -68,9 +67,7 @@ function PatternsManageButton( { clientId } ) { convertSyncedPatternToStatic( clientId ) } > - { innerBlockCount > 1 - ? __( 'Detach patterns' ) - : __( 'Detach pattern' ) } + { __( 'Detach' ) } ) } diff --git a/packages/reusable-blocks/src/components/reusable-blocks-menu-items/reusable-blocks-manage-button.js b/packages/reusable-blocks/src/components/reusable-blocks-menu-items/reusable-blocks-manage-button.js index 6ca19269d40f6..cf03c2a07b7a0 100644 --- a/packages/reusable-blocks/src/components/reusable-blocks-menu-items/reusable-blocks-manage-button.js +++ b/packages/reusable-blocks/src/components/reusable-blocks-menu-items/reusable-blocks-manage-button.js @@ -15,41 +15,40 @@ import { store as coreStore } from '@wordpress/core-data'; import { store as reusableBlocksStore } from '../../store'; function ReusableBlocksManageButton( { clientId } ) { - const { canRemove, isVisible, innerBlockCount, managePatternsUrl } = - useSelect( - ( select ) => { - const { getBlock, canRemoveBlock, getBlockCount, getSettings } = - select( blockEditorStore ); - const { canUser } = select( coreStore ); - const reusableBlock = getBlock( clientId ); - const isBlockTheme = getSettings().__unstableIsBlockBasedTheme; + const { canRemove, isVisible, managePatternsUrl } = useSelect( + ( select ) => { + const { getBlock, canRemoveBlock, getBlockCount, getSettings } = + select( blockEditorStore ); + const { canUser } = select( coreStore ); + const reusableBlock = getBlock( clientId ); + const isBlockTheme = getSettings().__unstableIsBlockBasedTheme; - return { - canRemove: canRemoveBlock( clientId ), - isVisible: - !! reusableBlock && - isReusableBlock( reusableBlock ) && - !! canUser( - 'update', - 'blocks', - reusableBlock.attributes.ref - ), - innerBlockCount: getBlockCount( clientId ), - // The site editor and templates both check whether the user - // has edit_theme_options capabilities. We can leverage that here - // and omit the manage patterns link if the user can't access it. - managePatternsUrl: - isBlockTheme && canUser( 'read', 'templates' ) - ? addQueryArgs( 'site-editor.php', { - path: '/patterns', - } ) - : addQueryArgs( 'edit.php', { - post_type: 'wp_block', - } ), - }; - }, - [ clientId ] - ); + return { + canRemove: canRemoveBlock( clientId ), + isVisible: + !! reusableBlock && + isReusableBlock( reusableBlock ) && + !! canUser( + 'update', + 'blocks', + reusableBlock.attributes.ref + ), + innerBlockCount: getBlockCount( clientId ), + // The site editor and templates both check whether the user + // has edit_theme_options capabilities. We can leverage that here + // and omit the manage patterns link if the user can't access it. + managePatternsUrl: + isBlockTheme && canUser( 'read', 'templates' ) + ? addQueryArgs( 'site-editor.php', { + path: '/patterns', + } ) + : addQueryArgs( 'edit.php', { + post_type: 'wp_block', + } ), + }; + }, + [ clientId ] + ); const { __experimentalConvertBlockToStatic: convertBlockToStatic } = useDispatch( reusableBlocksStore ); @@ -65,9 +64,7 @@ function ReusableBlocksManageButton( { clientId } ) { { canRemove && ( convertBlockToStatic( clientId ) }> - { innerBlockCount > 1 - ? __( 'Detach patterns' ) - : __( 'Detach pattern' ) } + { __( 'Detach' ) } ) } From 5cfe09466314a46dba814629341c552cc5adc8dd Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 20 Nov 2023 18:28:44 +0100 Subject: [PATCH 083/116] Post Schedule Panel: Remove text overflow ellipsis (#56319) --- .../editor/src/components/post-panel-row/style.scss | 7 +++++-- .../editor/src/components/post-schedule/style.scss | 10 +++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/editor/src/components/post-panel-row/style.scss b/packages/editor/src/components/post-panel-row/style.scss index b21679e9b9697..b3dfc8c6bcf6b 100644 --- a/packages/editor/src/components/post-panel-row/style.scss +++ b/packages/editor/src/components/post-panel-row/style.scss @@ -1,13 +1,16 @@ .editor-post-panel__row { width: 100%; - justify-content: flex-start; - align-items: flex-start; min-height: $button-size; + justify-content: flex-start !important; + align-items: flex-start !important; } .editor-post-panel__row-label { width: 30%; flex-shrink: 0; + min-height: $button-size; + display: flex; + align-items: center; } .editor-post-panel__row-control { diff --git a/packages/editor/src/components/post-schedule/style.scss b/packages/editor/src/components/post-schedule/style.scss index fb8503962f7cd..ca5bc19ae7d5c 100644 --- a/packages/editor/src/components/post-schedule/style.scss +++ b/packages/editor/src/components/post-schedule/style.scss @@ -9,11 +9,15 @@ } } -.editor-post-schedule__dialog-toggle { +.editor-post-schedule__dialog-toggle.components-button { display: block; max-width: 100%; overflow: hidden; text-align: left; - text-overflow: ellipsis; - white-space: nowrap; + white-space: unset; + height: auto; + + // The line height + the padding should be the same as the button size. + padding: ( ( $button-size - $grid-unit-20 ) / 2 ) 12px; + line-height: $grid-unit-20; } From 0253471becaf06274b0de4ece9d986b60191108c Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Tue, 21 Nov 2023 03:23:19 +0900 Subject: [PATCH 084/116] Duotone: Backport from Core to fix filters in classic themes (#54778) Co-authored-by: Alex Lende --- lib/class-wp-duotone-gutenberg.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/class-wp-duotone-gutenberg.php b/lib/class-wp-duotone-gutenberg.php index 11f6c6dcccdd9..93714e5974006 100644 --- a/lib/class-wp-duotone-gutenberg.php +++ b/lib/class-wp-duotone-gutenberg.php @@ -938,9 +938,17 @@ public static function output_footer_assets() { echo self::get_svg_definitions( self::$used_svg_filter_data ); } - // This is for classic themes - in block themes, the CSS is added in the head via wp_add_inline_style in the wp_enqueue_scripts action. - if ( ! wp_is_block_theme() && ! empty( self::$used_global_styles_presets ) ) { - wp_add_inline_style( 'core-block-supports', self::get_global_styles_presets( self::$used_global_styles_presets ) ); + // In block themes, the CSS is added in the head via wp_add_inline_style in the wp_enqueue_scripts action. + if ( ! wp_is_block_theme() ) { + $style_tag_id = 'core-block-supports-duotone'; + wp_register_style( $style_tag_id, false ); + if ( ! empty( self::$used_global_styles_presets ) ) { + wp_add_inline_style( $style_tag_id, self::get_global_styles_presets( self::$used_global_styles_presets ) ); + } + if ( ! empty( self::$block_css_declarations ) ) { + wp_add_inline_style( $style_tag_id, gutenberg_style_engine_get_stylesheet_from_css_rules( self::$block_css_declarations ) ); + } + wp_enqueue_style( $style_tag_id ); } } From d7f8cff991435546e097fa8348298b6ffd774d43 Mon Sep 17 00:00:00 2001 From: JuanMa Date: Mon, 20 Nov 2023 18:37:26 +0000 Subject: [PATCH 085/116] Docs - Block Editor Handbook - Add end user documentation about Block Editor as a resource on the Landing Page of the Block Editor Handbook (#49854) * add end user documentation as a resource * Update docs/README.md Co-authored-by: Nick Diego * Moved End User Documentation to the end of the list --------- Co-authored-by: Nick Diego --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 219c622dc3d73..b94a8d78d41a7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -58,8 +58,8 @@ This handbook should be considered the canonical resource for all things related - [**WordPress Developer Blog**](https://developer.wordpress.org/news/) - An ever-growing resource of technical articles covering specific topics related to block development and a wide variety of use cases. The blog is also an excellent way to [keep up with the latest developments in WordPress](https://developer.wordpress.org/news/tag/roundup/). - [**Learn WordPress**](https://learn.wordpress.org/) - The WordPress hub for learning resources where you can find courses like [Introduction to Block Development: Build your first custom block](https://learn.wordpress.org/course/introduction-to-block-development-build-your-first-custom-block/), [Converting a Shortcode to a Block](https://learn.wordpress.org/course/converting-a-shortcode-to-a-block/) or [Using the WordPress Data Layer](https://learn.wordpress.org/course/using-the-wordpress-data-layer/) - [**WordPress.tv**](https://wordpress.tv/) - A hub of WordPress-related videos (from talks at WordCamps to recordings of online workshops) curated and moderated by the WordPress.org community. You’re sure to find something to aid your learning about [block development](https://wordpress.tv/?s=block%20development&sort=newest) or the [block-editor](https://wordpress.tv/?s=block%20editor&sort=relevance) here. -- [**Gutenberg repository**](https://github.com/WordPress/gutenberg/) - Development of the block editor project is carried out in this GitHub repository. It contains the code of interesting packages such as [`block-library`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src) (core blocks) or [`components`](https://github.com/WordPress/gutenberg/tree/trunk/packages/components) (common UI elements). _The [block-development-examples](https://github.com/WordPress/block-development-examples) repository is another useful reference._ - +- [**Gutenberg repository**](https://github.com/WordPress/gutenberg/) - Development of the block editor project is carried out in this GitHub repository. It contains the code of interesting packages such as [`block-library`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src) (core blocks) or [`components`](https://github.com/WordPress/gutenberg/tree/trunk/packages/components) (common UI elements). _The [gutenberg-examples](https://github.com/WordPress/gutenberg-examples) repository is another useful reference._ +- [**End User Documentation**](https://wordpress.org/documentation/) - Documentation site targeted to the end user (not developers) where you can also find documentation about the [Block Editor](https://wordpress.org/documentation/category/block-editor/) and [working with blocks](https://wordpress.org/documentation/article/work-with-blocks/). ## Are you in the right place? From 59c0356f5282745ddbbda0e0852dde00a70cf9fb Mon Sep 17 00:00:00 2001 From: JuanMa Date: Mon, 20 Nov 2023 19:09:23 +0000 Subject: [PATCH 086/116] Update webpack options for wp-scripts in README.md (#56314) * Update webpack options in README.md * Add support for custom output directory in build process --- packages/scripts/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/scripts/README.md b/packages/scripts/README.md index 89ae3f1fff05c..4a3c13b27445a 100644 --- a/packages/scripts/README.md +++ b/packages/scripts/README.md @@ -48,7 +48,7 @@ It might also be a good idea to get familiar with the [JavaScript Build Setup tu ## Automatic block.json detection and the source code directory -When using the `start` or `build` commands, the source code directory ( the default is `./src`) and its subdirectories are scanned for the existence of `block.json` files. If one or more are found, they are treated a entry points and will be output into corresponding folders in the `build` directory. This allows for the creation of multiple blocks that use a single build process. The source directory can be customized using the `--webpack-src-dir` flag. +When using the `start` or `build` commands, the source code directory ( the default is `./src`) and its subdirectories are scanned for the existence of `block.json` files. If one or more are found, they are treated a entry points and will be output into corresponding folders in the `build` directory. This allows for the creation of multiple blocks that use a single build process. The source directory can be customized using the `--webpack-src-dir` flag and the output directory with the `--output-path` flag. ## Updating to New Release @@ -106,6 +106,7 @@ This script automatically use the optimized config but sometimes you may want to - `--webpack-copy-php` – enables copying all PHP files from the source directory ( default is `src` ) and its subfolders to the output directory. - `--webpack-no-externals` – disables scripts' assets generation, and omits the list of default externals. - `--webpack-src-dir` – Allows customization of the source code directory. Default is `src`. +- `--output-path` – Allows customization of the output directory. Default is `build`. #### Advanced information @@ -388,6 +389,7 @@ This script automatically use the optimized config but sometimes you may want to - `--webpack-devtool` – controls how source maps are generated. See options at https://webpack.js.org/configuration/devtool/#devtool. - `--webpack-no-externals` – disables scripts' assets generation, and omits the list of default externals. - `--webpack-src-dir` – Allows customization of the source code directory. Default is `src`. +- `--output-path` – Allows customization of the output directory. Default is `build`. #### Advanced information From 8eb63ddb51525164860e785900d7d86544f37afc Mon Sep 17 00:00:00 2001 From: Ramon Date: Tue, 21 Nov 2023 09:43:59 +1100 Subject: [PATCH 087/116] Revisions: add new selectors to fetch entity revisions (#54046) * Fetching entity revisions using loaded name argument e.g., post:id:revisions Revisions loaded into state tree under revisions[parent] Invalidate revisions after saved entity Revisions url params are contained in entity config Testing with global styles - modifying CPT to show in rest Implementing thin API layer for Revisions over the getEntityRecords implementation Duplicated the logic in the selectors for revisions functions Added tests * Revert edit context query param when fetching post types Reverting timeout in performance tests. * Tidying up reducer, allowing revisions for posts and pages only * Adding types to the base entity records for revisions and global styles revisions. * Removed unnecessary REST API change for global styles: it was to pull in the CPT in the /types response, which we don't need for core-data since it's a root entity. * Remove duplicated queried-data reducer functions for revisions, and use them in the main reducer Create dedicated resolvers for getRevision/s, thereby removing the split name parsing required (name:id:revisions) Create dedicated action receivers for revisions Rename from getEntityRevisions to getRevisions Fully remove parseEntityName Updated selector tests Use queriedDataReducer shape for revisions. The queriedDataReducer doesn't need to know about the revisions action type. Update doc comments Updated CHANGELOG.md * This commit: - removes `hasRevisions` because it has no noticeable benefit, at least as far as I can see. I'm probably wrong. - removes the default revisions query context for the API call (the default is 'view' anyway) - fixes the revisions reducer - Add _fields logic to resolvers and selectors Adds basic reducer tests * updated variable names: parentId > recordKey, key > revisionKey removing lock-related code deleting `recordKey` from action object before sending to queriedDataReducer updating docs * Removing revisions when items are removed. --- docs/reference-guides/data/data-core.md | 51 ++++ packages/core-data/CHANGELOG.md | 1 + packages/core-data/README.md | 55 +++- packages/core-data/src/actions.js | 33 +++ packages/core-data/src/entities.js | 21 ++ .../entity-types/global-styles-revision.ts | 47 ++++ packages/core-data/src/entity-types/index.ts | 6 + .../src/entity-types/post-revision.ts | 93 +++++++ packages/core-data/src/reducer.js | 47 +++- packages/core-data/src/resolvers.js | 147 ++++++++++- packages/core-data/src/selectors.ts | 111 +++++++++ packages/core-data/src/test/entities.js | 9 + packages/core-data/src/test/reducer.js | 235 ++++++++++++++++++ packages/core-data/src/test/selectors.js | 96 +++++++ 14 files changed, 947 insertions(+), 5 deletions(-) create mode 100644 packages/core-data/src/entity-types/global-styles-revision.ts create mode 100644 packages/core-data/src/entity-types/post-revision.ts diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index ea97ce28e4d85..6084eff930394 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -420,6 +420,39 @@ _Returns_ - A value whose reference will change only when an edit occurs. +### getRevision + +Returns a single, specific revision of a parent entity. + +_Parameters_ + +- _state_ `State`: State tree +- _kind_ `string`: Entity kind. +- _name_ `string`: Entity name. +- _recordKey_ `EntityRecordKey`: The key of the entity record whose revisions you want to fetch. +- _revisionKey_ `EntityRecordKey`: The revision's key. +- _query_ `GetRecordsHttpQuery`: Optional query. If requesting specific fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [entity kind]". + +_Returns_ + +- `RevisionRecord | Record< PropertyKey, never > | undefined`: Record. + +### getRevisions + +Returns an entity's revisions. + +_Parameters_ + +- _state_ `State`: State tree +- _kind_ `string`: Entity kind. +- _name_ `string`: Entity name. +- _recordKey_ `EntityRecordKey`: The key of the entity record whose revisions you want to fetch. +- _query_ `GetRecordsHttpQuery`: Optional query. If requesting specific fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [Entity kind]". + +_Returns_ + +- `RevisionRecord[] | null`: Record. + ### getThemeSupports Return theme supports data in the index. @@ -704,6 +737,24 @@ _Returns_ - `Object`: Action object. +### receiveRevisions + +Returns an action object used in signalling that revisions have been received. + +_Parameters_ + +- _kind_ `string`: Kind of the received entity record revisions. +- _name_ `string`: Name of the received entity record revisions. +- _recordKey_ `number|string`: The key of the entity record whose revisions you want to fetch. +- _records_ `Array|Object`: Revisions received. +- _query_ `?Object`: Query Object. +- _invalidateCache_ `?boolean`: Should invalidate query caches. +- _meta_ `?Object`: Meta information about pagination. + +_Returns_ + +- `Object`: Action object. + ### receiveThemeSupports > **Deprecated** since WP 5.9, this is not useful anymore, use the selector direclty. diff --git a/packages/core-data/CHANGELOG.md b/packages/core-data/CHANGELOG.md index d20f8bd6c9d66..b54e8e01e48fb 100644 --- a/packages/core-data/CHANGELOG.md +++ b/packages/core-data/CHANGELOG.md @@ -11,6 +11,7 @@ ## Enhancements - Add `getEntityRecordsTotalItems` and `getEntityRecordsTotalPages` selectors. [#55164](https://github.com/WordPress/gutenberg/pull/55164). +- Revisions: add new selectors, `getRevisions` and `getRevision`, to fetch entity revisions. [#54046](https://github.com/WordPress/gutenberg/pull/54046). ## 6.20.0 (2023-10-05) diff --git a/packages/core-data/README.md b/packages/core-data/README.md index ef5d9c1197f09..f7a177b5c5587 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -123,7 +123,7 @@ The package provides general methods to interact with the entities (`getEntityRe ```js // Get the record collection for the user entity. -wp.data.select( 'core' ).getEntityRecords( 'root' 'user' ); +wp.data.select( 'core' ).getEntityRecords( 'root', 'user' ); // Get a single record for the user entity. wp.data.select( 'core' ).getEntityRecord( 'root', 'user', recordId ); @@ -138,7 +138,7 @@ In addition to the general utilities (`getEntityRecords`, `getEntityRecord`, etc ```js // Collection -wp.data.select( 'core' ).getEntityRecords( 'root' 'user' ); +wp.data.select( 'core' ).getEntityRecords( 'root', 'user' ); wp.data.select( 'core' ).getUsers(); // Single record @@ -248,6 +248,24 @@ _Returns_ - `Object`: Action object. +### receiveRevisions + +Returns an action object used in signalling that revisions have been received. + +_Parameters_ + +- _kind_ `string`: Kind of the received entity record revisions. +- _name_ `string`: Name of the received entity record revisions. +- _recordKey_ `number|string`: The key of the entity record whose revisions you want to fetch. +- _records_ `Array|Object`: Revisions received. +- _query_ `?Object`: Query Object. +- _invalidateCache_ `?boolean`: Should invalidate query caches. +- _meta_ `?Object`: Meta information about pagination. + +_Returns_ + +- `Object`: Action object. + ### receiveThemeSupports > **Deprecated** since WP 5.9, this is not useful anymore, use the selector direclty. @@ -727,6 +745,39 @@ _Returns_ - A value whose reference will change only when an edit occurs. +### getRevision + +Returns a single, specific revision of a parent entity. + +_Parameters_ + +- _state_ `State`: State tree +- _kind_ `string`: Entity kind. +- _name_ `string`: Entity name. +- _recordKey_ `EntityRecordKey`: The key of the entity record whose revisions you want to fetch. +- _revisionKey_ `EntityRecordKey`: The revision's key. +- _query_ `GetRecordsHttpQuery`: Optional query. If requesting specific fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [entity kind]". + +_Returns_ + +- `RevisionRecord | Record< PropertyKey, never > | undefined`: Record. + +### getRevisions + +Returns an entity's revisions. + +_Parameters_ + +- _state_ `State`: State tree +- _kind_ `string`: Entity kind. +- _name_ `string`: Entity name. +- _recordKey_ `EntityRecordKey`: The key of the entity record whose revisions you want to fetch. +- _query_ `GetRecordsHttpQuery`: Optional query. If requesting specific fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [Entity kind]". + +_Returns_ + +- `RevisionRecord[] | null`: Record. + ### getThemeSupports Return theme supports data in the index. diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index 9e7277f35a62a..d71c5d6120089 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -924,3 +924,36 @@ export function receiveDefaultTemplateId( query, templateId ) { templateId, }; } + +/** + * Returns an action object used in signalling that revisions have been received. + * + * @param {string} kind Kind of the received entity record revisions. + * @param {string} name Name of the received entity record revisions. + * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch. + * @param {Array|Object} records Revisions received. + * @param {?Object} query Query Object. + * @param {?boolean} invalidateCache Should invalidate query caches. + * @param {?Object} meta Meta information about pagination. + * @return {Object} Action object. + */ +export function receiveRevisions( + kind, + name, + recordKey, + records, + query, + invalidateCache = false, + meta +) { + return { + type: 'RECEIVE_ITEM_REVISIONS', + items: Array.isArray( records ) ? records : [ records ], + recordKey, + meta, + query, + kind, + name, + invalidateCache, + }; +} diff --git a/packages/core-data/src/entities.js b/packages/core-data/src/entities.js index af8829d0bc852..e85673492ef56 100644 --- a/packages/core-data/src/entities.js +++ b/packages/core-data/src/entities.js @@ -19,6 +19,10 @@ export const DEFAULT_ENTITY_KEY = 'id'; const POST_RAW_ATTRIBUTES = [ 'title', 'excerpt', 'content' ]; +// A hardcoded list of post types that support revisions. +// @TODO: Ideally this should be fetched from the `/types` REST API's view context. +const POST_TYPES_WITH_REVISIONS_SUPPORT = [ 'post', 'page' ]; + export const rootEntitiesConfig = [ { label: __( 'Base' ), @@ -207,6 +211,12 @@ export const rootEntitiesConfig = [ baseURLParams: { context: 'edit' }, plural: 'globalStylesVariations', // Should be different than name. getTitle: ( record ) => record?.title?.rendered || record?.title, + getRevisionsUrl: ( parentId ) => + `/wp/v2/global-styles/${ parentId }/revisions`, + supports: { + revisions: true, + }, + supportsPagination: true, }, { label: __( 'Themes' ), @@ -295,6 +305,11 @@ async function loadPostTypeEntities() { selection: true, }, mergedEdits: { meta: true }, + supports: { + revisions: POST_TYPES_WITH_REVISIONS_SUPPORT.includes( + postType?.slug + ), + }, rawAttributes: POST_RAW_ATTRIBUTES, getTitle: ( record ) => record?.title?.rendered || @@ -328,6 +343,12 @@ async function loadPostTypeEntities() { syncObjectType: 'postType/' + postType.name, getSyncObjectId: ( id ) => id, supportsPagination: true, + getRevisionsUrl: ( parentId, revisionId ) => + `/${ namespace }/${ + postType.rest_base + }/${ parentId }/revisions${ + revisionId ? '/' + revisionId : '' + }`, }; } ); } diff --git a/packages/core-data/src/entity-types/global-styles-revision.ts b/packages/core-data/src/entity-types/global-styles-revision.ts new file mode 100644 index 0000000000000..1a89c164e313b --- /dev/null +++ b/packages/core-data/src/entity-types/global-styles-revision.ts @@ -0,0 +1,47 @@ +/** + * Internal dependencies + */ +import type { Context, ContextualField, OmitNevers } from './helpers'; + +import type { BaseEntityRecords as _BaseEntityRecords } from './base-entity-records'; + +declare module './base-entity-records' { + export namespace BaseEntityRecords { + export interface GlobalStylesRevision< C extends Context > { + /** + * The ID for the author of the global styles revision. + */ + author: number; + /** + * The date the post global styles revision published, in the site's timezone. + */ + date: string | null; + /** + * The date the global styles revision was published, as GMT. + */ + date_gmt: ContextualField< string | null, 'view' | 'edit', C >; + /** + * Unique identifier for the revision. + */ + id: number; + /** + * The date the global styles revision was last modified, in the site's timezone. + */ + modified: ContextualField< string, 'view' | 'edit', C >; + /** + * The date the global styles revision was last modified, as GMT. + */ + modified_gmt: ContextualField< string, 'view' | 'edit', C >; + /** + * Identifier for the parent of the revision. + */ + parent: number; + styles: Record< string, Object >; + settings: Record< string, Object >; + } + } +} + +export type GlobalStylesRevision< C extends Context = 'view' > = OmitNevers< + _BaseEntityRecords.GlobalStylesRevision< C > +>; diff --git a/packages/core-data/src/entity-types/index.ts b/packages/core-data/src/entity-types/index.ts index 19d10a28ad698..0e601137cbcb6 100644 --- a/packages/core-data/src/entity-types/index.ts +++ b/packages/core-data/src/entity-types/index.ts @@ -4,12 +4,14 @@ import type { Context, Updatable } from './helpers'; import type { Attachment } from './attachment'; import type { Comment } from './comment'; +import type { GlobalStylesRevision } from './global-styles-revision'; import type { MenuLocation } from './menu-location'; import type { NavMenu } from './nav-menu'; import type { NavMenuItem } from './nav-menu-item'; import type { Page } from './page'; import type { Plugin } from './plugin'; import type { Post } from './post'; +import type { PostRevision } from './post-revision'; import type { Settings } from './settings'; import type { Sidebar } from './sidebar'; import type { Taxonomy } from './taxonomy'; @@ -27,12 +29,14 @@ export type { Attachment, Comment, Context, + GlobalStylesRevision, MenuLocation, NavMenu, NavMenuItem, Page, Plugin, Post, + PostRevision, Settings, Sidebar, Taxonomy, @@ -82,12 +86,14 @@ export interface PerPackageEntityRecords< C extends Context > { core: | Attachment< C > | Comment< C > + | GlobalStylesRevision< C > | MenuLocation< C > | NavMenu< C > | NavMenuItem< C > | Page< C > | Plugin< C > | Post< C > + | PostRevision< C > | Settings< C > | Sidebar< C > | Taxonomy< C > diff --git a/packages/core-data/src/entity-types/post-revision.ts b/packages/core-data/src/entity-types/post-revision.ts new file mode 100644 index 0000000000000..354a3fc02af70 --- /dev/null +++ b/packages/core-data/src/entity-types/post-revision.ts @@ -0,0 +1,93 @@ +/** + * Internal dependencies + */ +import type { + Context, + ContextualField, + RenderedText, + OmitNevers, +} from './helpers'; + +import type { BaseEntityRecords as _BaseEntityRecords } from './base-entity-records'; + +declare module './base-entity-records' { + export namespace BaseEntityRecords { + export interface PostRevision< C extends Context > { + /** + * The ID for the author of the post revision. + */ + author: number; + /** + * The content for the post. + */ + content: ContextualField< + RenderedText< C > & { + /** + * Whether the content is protected with a password. + */ + is_protected: boolean; + /** + * Version of the content block format used by the post. + */ + block_version: ContextualField< string, 'edit', C >; + }, + 'view' | 'edit', + C + >; + /** + * The date the post was published, in the site's timezone. + */ + date: string | null; + /** + * The date the post was published, as GMT. + */ + date_gmt: ContextualField< string | null, 'view' | 'edit', C >; + /** + * The excerpt for the post revision. + */ + excerpt: RenderedText< C > & { + protected: boolean; + }; + /** + * The globally unique identifier for the post. + */ + guid: ContextualField< RenderedText< C >, 'view' | 'edit', C >; + /** + * Unique identifier for the revision. + */ + id: number; + /** + * Meta fields. + */ + meta: ContextualField< + Record< string, string >, + 'view' | 'edit', + C + >; + /** + * The date the post was last modified, in the site's timezone. + */ + modified: ContextualField< string, 'view' | 'edit', C >; + /** + * The date the post revision was last modified, as GMT. + */ + modified_gmt: ContextualField< string, 'view' | 'edit', C >; + /** + * Identifier for the parent of the revision. + */ + parent: number; + /** + * An alphanumeric identifier for the post unique to its type. + */ + slug: string; + /** + * The title for the post revision. + */ + title: RenderedText< C >; + } + } +} + +export type PostRevision< C extends Context = 'view' > = OmitNevers< + _BaseEntityRecords.PostRevision< C > +>; diff --git a/packages/core-data/src/reducer.js b/packages/core-data/src/reducer.js index a21623d8ba89d..34558fcfbb142 100644 --- a/packages/core-data/src/reducer.js +++ b/packages/core-data/src/reducer.js @@ -245,7 +245,6 @@ function entity( entityConfig ) { ] )( combineReducers( { queriedData: queriedDataReducer, - edits: ( state = {}, action ) => { switch ( action.type ) { case 'RECEIVE_ITEMS': @@ -355,6 +354,52 @@ function entity( entityConfig ) { return state; }, + + // Add revisions to the state tree if the post type supports it. + ...( entityConfig?.supports?.revisions + ? { + revisions: ( state = {}, action ) => { + // Use the same queriedDataReducer shape for revisions. + if ( action.type === 'RECEIVE_ITEM_REVISIONS' ) { + const recordKey = action.recordKey; + delete action.recordKey; + const newState = queriedDataReducer( + state[ recordKey ], + { + ...action, + type: 'RECEIVE_ITEMS', + } + ); + return { + ...state, + [ recordKey ]: newState, + }; + } + + if ( action.type === 'REMOVE_ITEMS' ) { + return Object.fromEntries( + Object.entries( state ).filter( + ( [ id ] ) => + ! action.itemIds.some( + ( itemId ) => { + if ( + Number.isInteger( + itemId + ) + ) { + return itemId === +id; + } + return itemId === id; + } + ) + ) + ); + } + + return state; + }, + } + : {} ), } ) ); } diff --git a/packages/core-data/src/resolvers.js b/packages/core-data/src/resolvers.js index cd2a65a60b013..8735764a880b8 100644 --- a/packages/core-data/src/resolvers.js +++ b/packages/core-data/src/resolvers.js @@ -244,7 +244,7 @@ export const getEntityRecords = // If we request fields but the result doesn't contain the fields, // explicitly set these fields as "undefined" - // that way we consider the query "fullfilled". + // that way we consider the query "fulfilled". if ( query._fields ) { records = records.map( ( record ) => { query._fields.split( ',' ).forEach( ( field ) => { @@ -322,7 +322,7 @@ export const getCurrentTheme = export const getThemeSupports = forwardResolver( 'getCurrentTheme' ); /** - * Requests a preview from the from the Embed API. + * Requests a preview from the Embed API. * * @param {string} url URL to get the preview for. */ @@ -718,3 +718,146 @@ export const getDefaultTemplateId = dispatch.receiveDefaultTemplateId( query, template.id ); } }; + +/** + * Requests an entity's revisions from the REST API. + * + * @param {string} kind Entity kind. + * @param {string} name Entity name. + * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch. + * @param {Object|undefined} query Optional object of query parameters to + * include with request. If requesting specific + * fields, fields must always include the ID. + */ +export const getRevisions = + ( kind, name, recordKey, query = {} ) => + async ( { dispatch } ) => { + const configs = await dispatch( getOrLoadEntitiesConfig( kind ) ); + const entityConfig = configs.find( + ( config ) => config.name === name && config.kind === kind + ); + + if ( + ! entityConfig || + entityConfig?.__experimentalNoFetch || + ! entityConfig?.supports?.revisions + ) { + return; + } + + if ( query._fields ) { + // If requesting specific fields, items and query association to said + // records are stored by ID reference. Thus, fields must always include + // the ID. + query = { + ...query, + _fields: [ + ...new Set( [ + ...( getNormalizedCommaSeparable( query._fields ) || + [] ), + DEFAULT_ENTITY_KEY, + ] ), + ].join(), + }; + } + + const path = addQueryArgs( + entityConfig.getRevisionsUrl( recordKey ), + query + ); + + let records, meta; + if ( entityConfig.supportsPagination && query.per_page !== -1 ) { + const response = await apiFetch( { path, parse: false } ); + records = Object.values( await response.json() ); + meta = { + totalItems: parseInt( response.headers.get( 'X-WP-Total' ) ), + }; + } else { + records = Object.values( await apiFetch( { path } ) ); + } + + // If we request fields but the result doesn't contain the fields, + // explicitly set these fields as "undefined" + // that way we consider the query "fulfilled". + if ( query._fields ) { + records = records.map( ( record ) => { + query._fields.split( ',' ).forEach( ( field ) => { + if ( ! record.hasOwnProperty( field ) ) { + record[ field ] = undefined; + } + } ); + + return record; + } ); + } + + dispatch.receiveRevisions( + kind, + name, + recordKey, + records, + query, + false, + meta + ); + }; + +// Invalidate cache when a new revision is created. +getRevisions.shouldInvalidate = ( action, kind, name, recordKey ) => + action.type === 'SAVE_ENTITY_RECORD_FINISH' && + name === action.name && + kind === action.kind && + ! action.error && + recordKey === action.recordId; + +/** + * Requests a specific Entity revision from the REST API. + * + * @param {string} kind Entity kind. + * @param {string} name Entity name. + * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch. + * @param {number|string} revisionKey The revision's key. + * @param {Object|undefined} query Optional object of query parameters to + * include with request. If requesting specific + * fields, fields must always include the ID. + */ +export const getRevision = + ( kind, name, recordKey, revisionKey, query = {} ) => + async ( { dispatch } ) => { + const configs = await dispatch( getOrLoadEntitiesConfig( kind ) ); + const entityConfig = configs.find( + ( config ) => config.name === name && config.kind === kind + ); + + if ( + ! entityConfig || + entityConfig?.__experimentalNoFetch || + ! entityConfig?.supports?.revisions + ) { + return; + } + + if ( query !== undefined && query._fields ) { + // If requesting specific fields, items and query association to said + // records are stored by ID reference. Thus, fields must always include + // the ID. + query = { + ...query, + _fields: [ + ...new Set( [ + ...( getNormalizedCommaSeparable( query._fields ) || + [] ), + DEFAULT_ENTITY_KEY, + ] ), + ].join(), + }; + } + const path = addQueryArgs( + entityConfig.getRevisionsUrl( recordKey, revisionKey ), + query + ); + + const record = await apiFetch( { path } ); + dispatch.receiveRevisions( kind, name, recordKey, record, query ); + }; diff --git a/packages/core-data/src/selectors.ts b/packages/core-data/src/selectors.ts index 2a046941611c7..4a893f5557d86 100644 --- a/packages/core-data/src/selectors.ts +++ b/packages/core-data/src/selectors.ts @@ -62,6 +62,16 @@ interface QueriedData { queries: Record< ET.Context, Record< string, Array< number > > >; } +type RevisionRecord = + | Record< ET.Context, Record< number, ET.PostRevision > > + | Record< ET.Context, Record< number, ET.GlobalStylesRevision > >; + +interface RevisionsQueriedData { + items: RevisionRecord; + itemIsComplete: Record< ET.Context, Record< number, boolean > >; + queries: Record< ET.Context, Record< string, Array< number > > >; +} + interface EntityState< EntityRecord extends ET.EntityRecord > { edits: Record< string, Partial< EntityRecord > >; saving: Record< @@ -70,6 +80,7 @@ interface EntityState< EntityRecord extends ET.EntityRecord > { >; deleting: Record< string, Partial< { pending: boolean; error: Error } > >; queriedData: QueriedData; + revisions?: RevisionsQueriedData; } interface EntityConfig { @@ -1373,3 +1384,103 @@ export function getDefaultTemplateId( ): string { return state.defaultTemplates[ JSON.stringify( query ) ]; } + +/** + * Returns an entity's revisions. + * + * @param state State tree + * @param kind Entity kind. + * @param name Entity name. + * @param recordKey The key of the entity record whose revisions you want to fetch. + * @param query Optional query. If requesting specific + * fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [Entity kind]". + * + * @return Record. + */ +export const getRevisions = ( + state: State, + kind: string, + name: string, + recordKey: EntityRecordKey, + query?: GetRecordsHttpQuery +): RevisionRecord[] | null => { + const queriedStateRevisions = + state.entities.records?.[ kind ]?.[ name ]?.revisions?.[ recordKey ]; + if ( ! queriedStateRevisions ) { + return null; + } + + return getQueriedItems( queriedStateRevisions, query ); +}; + +/** + * Returns a single, specific revision of a parent entity. + * + * @param state State tree + * @param kind Entity kind. + * @param name Entity name. + * @param recordKey The key of the entity record whose revisions you want to fetch. + * @param revisionKey The revision's key. + * @param query Optional query. If requesting specific + * fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [entity kind]". + * + * @return Record. + */ +export const getRevision = createSelector( + ( + state: State, + kind: string, + name: string, + recordKey: EntityRecordKey, + revisionKey: EntityRecordKey, + query?: GetRecordsHttpQuery + ): RevisionRecord | Record< PropertyKey, never > | undefined => { + const queriedState = + state.entities.records?.[ kind ]?.[ name ]?.revisions?.[ + recordKey + ]; + + if ( ! queriedState ) { + return undefined; + } + + const context = query?.context ?? 'default'; + + if ( query === undefined ) { + // If expecting a complete item, validate that completeness. + if ( ! queriedState.itemIsComplete[ context ]?.[ revisionKey ] ) { + return undefined; + } + + return queriedState.items[ context ][ revisionKey ]; + } + + const item = queriedState.items[ context ]?.[ revisionKey ]; + if ( item && query._fields ) { + const filteredItem = {}; + const fields = getNormalizedCommaSeparable( query._fields ) ?? []; + + for ( let f = 0; f < fields.length; f++ ) { + const field = fields[ f ].split( '.' ); + let value = item; + field.forEach( ( fieldName ) => { + value = value?.[ fieldName ]; + } ); + setNestedValue( filteredItem, field, value ); + } + + return filteredItem; + } + + return item; + }, + ( state: State, kind, name, recordKey, revisionKey, query ) => { + const context = query?.context ?? 'default'; + return [ + state.entities.records?.[ kind ]?.[ name ]?.revisions?.[ recordKey ] + ?.items?.[ context ]?.[ revisionKey ], + state.entities.records?.[ kind ]?.[ name ]?.revisions?.[ recordKey ] + ?.itemIsComplete?.[ context ]?.[ revisionKey ], + ]; + } +); diff --git a/packages/core-data/src/test/entities.js b/packages/core-data/src/test/entities.js index 9afbbb8de055e..c9a432c92c144 100644 --- a/packages/core-data/src/test/entities.js +++ b/packages/core-data/src/test/entities.js @@ -80,6 +80,9 @@ describe( 'getKindEntities', () => { labels: { singular_name: 'post', }, + supports: { + revisions: true, + }, }, ]; const dispatch = jest.fn(); @@ -95,6 +98,12 @@ describe( 'getKindEntities', () => { expect( dispatch.mock.calls[ 0 ][ 0 ].entities[ 0 ].baseURL ).toBe( '/wp/v2/posts' ); + expect( + dispatch.mock.calls[ 0 ][ 0 ].entities[ 0 ].getRevisionsUrl( 1 ) + ).toBe( '/wp/v2/posts/1/revisions' ); + expect( + dispatch.mock.calls[ 0 ][ 0 ].entities[ 0 ].getRevisionsUrl( 1, 2 ) + ).toBe( '/wp/v2/posts/1/revisions/2' ); } ); } ); diff --git a/packages/core-data/src/test/reducer.js b/packages/core-data/src/test/reducer.js index 4142f65af4c7c..d5d5bc5c8692f 100644 --- a/packages/core-data/src/test/reducer.js +++ b/packages/core-data/src/test/reducer.js @@ -139,6 +139,241 @@ describe( 'entities', () => { .map( ( [ , cfg ] ) => cfg ) ).toEqual( [ { kind: 'postType', name: 'posts' } ] ); } ); + + describe( 'entity revisions', () => { + const stateWithConfig = entities( undefined, { + type: 'ADD_ENTITIES', + entities: [ + { + kind: 'root', + name: 'postType', + supports: { revisions: true }, + }, + ], + } ); + it( 'appends revisions state', () => { + expect( stateWithConfig.records.root.postType ).toHaveProperty( + 'revisions', + {} + ); + } ); + + it( 'returns with received revisions', () => { + const initialState = deepFreeze( { + config: stateWithConfig.config, + records: {}, + } ); + const state = entities( initialState, { + type: 'RECEIVE_ITEM_REVISIONS', + items: [ { id: 1, parent: 2 } ], + kind: 'root', + name: 'postType', + recordKey: 2, + } ); + expect( state.records.root.postType.revisions ).toEqual( { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + }, + }, + queries: {}, + }, + } ); + } ); + + it( 'returns with appended received revisions at the parent level', () => { + const initialState = deepFreeze( { + config: stateWithConfig.config, + records: { + root: { + postType: { + revisions: { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + }, + }, + queries: {}, + }, + }, + }, + }, + }, + } ); + const state = entities( initialState, { + type: 'RECEIVE_ITEM_REVISIONS', + items: [ { id: 3, parent: 4 } ], + kind: 'root', + name: 'postType', + recordKey: 4, + } ); + expect( state.records.root.postType.revisions ).toEqual( { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + }, + }, + queries: {}, + }, + 4: { + items: { + default: { + 3: { id: 3, parent: 4 }, + }, + }, + itemIsComplete: { + default: { + 3: true, + }, + }, + queries: {}, + }, + } ); + } ); + + it( 'returns with appended received revision items', () => { + const initialState = deepFreeze( { + config: stateWithConfig.config, + records: { + root: { + postType: { + revisions: { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + }, + }, + queries: {}, + }, + }, + }, + }, + }, + } ); + const state = entities( initialState, { + type: 'RECEIVE_ITEM_REVISIONS', + items: [ { id: 7, parent: 2 } ], + kind: 'root', + name: 'postType', + recordKey: 2, + } ); + expect( state.records.root.postType.revisions ).toEqual( { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + 7: { id: 7, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + 7: true, + }, + }, + queries: {}, + }, + } ); + } ); + + it( 'returns with removed revision items', () => { + const initialState = deepFreeze( { + config: stateWithConfig.config, + records: { + root: { + postType: { + revisions: { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + }, + }, + queries: {}, + }, + 4: { + items: { + default: { + 3: { id: 3, parent: 4 }, + }, + }, + itemIsComplete: { + default: { + 3: true, + }, + }, + queries: {}, + }, + 6: { + items: { + default: { + 9: { id: 11, parent: 6 }, + }, + }, + itemIsComplete: { + default: { + 9: true, + }, + }, + queries: {}, + }, + }, + }, + }, + }, + } ); + const state = entities( initialState, { + type: 'REMOVE_ITEMS', + itemIds: [ 4, 6 ], + kind: 'root', + name: 'postType', + } ); + expect( state.records.root.postType.revisions ).toEqual( { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + }, + }, + queries: {}, + }, + } ); + } ); + } ); } ); describe( 'embedPreviews()', () => { diff --git a/packages/core-data/src/test/selectors.js b/packages/core-data/src/test/selectors.js index b7c583098c4a5..43c84a3e97891 100644 --- a/packages/core-data/src/test/selectors.js +++ b/packages/core-data/src/test/selectors.js @@ -22,6 +22,8 @@ import { getAutosave, getAutosaves, getCurrentUser, + getRevisions, + getRevision, } from '../selectors'; // getEntityRecord and __experimentalGetEntityRecordNoResolver selectors share the same tests. describe.each( [ @@ -896,3 +898,97 @@ describe( 'getCurrentUser', () => { expect( getCurrentUser( state ) ).toEqual( currentUser ); } ); } ); + +describe( 'getRevisions', () => { + it( 'should return revisions', () => { + const state = deepFreeze( { + entities: { + records: { + postType: { + post: { + revisions: { + 1: { + items: { + default: { + 10: { + id: 10, + content: 'chicken', + author: 'bob', + parent: 1, + }, + }, + }, + itemIsComplete: { + default: { + 10: true, + }, + }, + queries: { + default: { + '': { itemIds: [ 10 ] }, + }, + }, + }, + }, + }, + }, + }, + }, + } ); + + expect( getRevisions( state, 'postType', 'post', 1 ) ).toEqual( [ + { + id: 10, + content: 'chicken', + author: 'bob', + parent: 1, + }, + ] ); + } ); +} ); + +describe( 'getRevision', () => { + it( 'should return a specific revision', () => { + const state = deepFreeze( { + entities: { + records: { + postType: { + post: { + revisions: { + 1: { + items: { + default: { + 10: { + id: 10, + content: 'chicken', + author: 'bob', + parent: 1, + }, + }, + }, + itemIsComplete: { + default: { + 10: true, + }, + }, + queries: { + default: { + '': [ 10 ], + }, + }, + }, + }, + }, + }, + }, + }, + } ); + + expect( getRevision( state, 'postType', 'post', 1, 10 ) ).toEqual( { + id: 10, + content: 'chicken', + author: 'bob', + parent: 1, + } ); + } ); +} ); From 0b153a408a6e1ba14e84e58845347b3735869a36 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Mon, 20 Nov 2023 22:50:32 +0000 Subject: [PATCH 088/116] Migrating `BlockPatternSetup` to use updated `Composite` implementation (#55425) - Removes `__unstableComposite` imports from `@wordpress/components` - Adds private `Composite*` exports from `@wordpress/components` - Refactors `BlockPatternSetup` and subcomponents to use updated `Composite` components - Additionally adds image semantics, and ensures buttons are available when disabled --- .../components/block-pattern-setup/index.js | 60 ++++++++++++------- .../block-pattern-setup/setup-toolbar.js | 2 + .../components/block-pattern-setup/style.scss | 5 +- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/packages/block-editor/src/components/block-pattern-setup/index.js b/packages/block-editor/src/components/block-pattern-setup/index.js index 22d51466b3b6e..edd55e90dc3e2 100644 --- a/packages/block-editor/src/components/block-pattern-setup/index.js +++ b/packages/block-editor/src/components/block-pattern-setup/index.js @@ -5,9 +5,7 @@ import { useDispatch } from '@wordpress/data'; import { cloneBlock } from '@wordpress/blocks'; import { VisuallyHidden, - __unstableComposite as Composite, - __unstableUseCompositeState as useCompositeState, - __unstableCompositeItem as CompositeItem, + privateApis as componentsPrivateApis, } from '@wordpress/components'; import { useState } from '@wordpress/element'; @@ -22,6 +20,13 @@ import BlockPreview from '../block-preview'; import SetupToolbar from './setup-toolbar'; import usePatternsSetup from './use-patterns-setup'; import { VIEWMODES } from './constants'; +import { unlock } from '../../lock-unlock'; + +const { + CompositeV2: Composite, + CompositeItemV2: CompositeItem, + useCompositeStoreV2: useCompositeStore, +} = unlock( componentsPrivateApis ); const SetupContent = ( { viewMode, @@ -30,8 +35,9 @@ const SetupContent = ( { onBlockPatternSelect, showTitles, } ) => { - const composite = useCompositeState(); + const compositeStore = useCompositeStore(); const containerClass = 'block-editor-block-pattern-setup__container'; + if ( viewMode === VIEWMODES.carousel ) { const slideClass = new Map( [ [ activeSlide, 'active-slide' ], @@ -41,23 +47,25 @@ const SetupContent = ( { return (
    -
      +
      { patterns.map( ( pattern, index ) => ( ) ) } -
    +
    ); } + return (
    ) ) } @@ -76,7 +83,7 @@ const SetupContent = ( { ); }; -function BlockPattern( { pattern, onSelect, composite, showTitles } ) { +function BlockPattern( { pattern, onSelect, showTitles } ) { const baseClassName = 'block-editor-block-pattern-setup-list'; const { blocks, description, viewportWidth = 700 } = pattern; const descriptionId = useInstanceId( @@ -84,16 +91,19 @@ function BlockPattern( { pattern, onSelect, composite, showTitles } ) { `${ baseClassName }__item-description` ); return ( -
    +
    + } + id={ `${ baseClassName }__pattern__${ pattern.name }` } role="option" - as="div" - { ...composite } - className={ `${ baseClassName }__item` } onClick={ () => onSelect( blocks ) } > ) } -
  2. + ); } @@ -178,10 +190,14 @@ const BlockPatternSetup = ( { activeSlide={ activeSlide } totalSlides={ patterns.length } handleNext={ () => { - setActiveSlide( ( active ) => active + 1 ); + setActiveSlide( ( active ) => + Math.min( active + 1, patterns.length - 1 ) + ); } } handlePrevious={ () => { - setActiveSlide( ( active ) => active - 1 ); + setActiveSlide( ( active ) => + Math.max( active - 1, 0 ) + ); } } onBlockPatternSelect={ () => { onPatternSelectCallback( diff --git a/packages/block-editor/src/components/block-pattern-setup/setup-toolbar.js b/packages/block-editor/src/components/block-pattern-setup/setup-toolbar.js index 69922f9560ab0..91b68456cda71 100644 --- a/packages/block-editor/src/components/block-pattern-setup/setup-toolbar.js +++ b/packages/block-editor/src/components/block-pattern-setup/setup-toolbar.js @@ -35,12 +35,14 @@ const CarouselNavigation = ( { label={ __( 'Previous pattern' ) } onClick={ handlePrevious } disabled={ activeSlide === 0 } + __experimentalIsFocusable />
{ row.getVisibleCells().map( ( cell ) => (
item.id } isLoading={ isLoadingPages || isLoadingAuthors } view={ view } onChangeView={ onChangeView } diff --git a/packages/edit-site/src/components/page-templates/dataviews-templates.js b/packages/edit-site/src/components/page-templates/dataviews-templates.js index ce4927895b29b..39a9d1b60abad 100644 --- a/packages/edit-site/src/components/page-templates/dataviews-templates.js +++ b/packages/edit-site/src/components/page-templates/dataviews-templates.js @@ -214,6 +214,7 @@ export default function DataviewsTemplates() { fields={ fields } actions={ actions } data={ shownTemplates } + getItemId={ ( item ) => item.id } isLoading={ isLoadingData } view={ view } onChangeView={ onChangeView } From 3e42c038cbcbcccbe95bade99e1811a951d1ef1e Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 21 Nov 2023 13:07:10 +0100 Subject: [PATCH 098/116] Site Editor: Add the Post Author component to the Page sidebar (#56368) --- .../components/sidebar/post-author/index.js | 20 ------------------- .../components/sidebar/post-author/style.scss | 5 ----- .../components/sidebar/post-status/index.js | 4 ++-- packages/edit-post/src/style.scss | 1 - .../page-panels/page-summary.js | 9 +++++++-- packages/editor/src/components/index.js | 1 + .../src/components/post-author/panel.js | 18 +++++++++++++++++ .../src/components/post-author/style.scss | 7 +++++++ .../src/components/post-panel-row/index.js | 14 +++---------- .../src/components/post-panel-row/style.scss | 3 +++ packages/editor/src/style.scss | 1 + 11 files changed, 42 insertions(+), 41 deletions(-) delete mode 100644 packages/edit-post/src/components/sidebar/post-author/index.js delete mode 100644 packages/edit-post/src/components/sidebar/post-author/style.scss create mode 100644 packages/editor/src/components/post-author/panel.js create mode 100644 packages/editor/src/components/post-author/style.scss diff --git a/packages/edit-post/src/components/sidebar/post-author/index.js b/packages/edit-post/src/components/sidebar/post-author/index.js deleted file mode 100644 index 8f5eca9aea46b..0000000000000 --- a/packages/edit-post/src/components/sidebar/post-author/index.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * WordPress dependencies - */ -import { PanelRow } from '@wordpress/components'; -import { - PostAuthor as PostAuthorForm, - PostAuthorCheck, -} from '@wordpress/editor'; - -export function PostAuthor() { - return ( - - - - - - ); -} - -export default PostAuthor; diff --git a/packages/edit-post/src/components/sidebar/post-author/style.scss b/packages/edit-post/src/components/sidebar/post-author/style.scss deleted file mode 100644 index bfc80bdd2cf70..0000000000000 --- a/packages/edit-post/src/components/sidebar/post-author/style.scss +++ /dev/null @@ -1,5 +0,0 @@ -.edit-post-post-author { - display: flex; - flex-direction: column; - align-items: stretch; -} diff --git a/packages/edit-post/src/components/sidebar/post-status/index.js b/packages/edit-post/src/components/sidebar/post-status/index.js index ba6afa2ae9f27..1b24de6082d16 100644 --- a/packages/edit-post/src/components/sidebar/post-status/index.js +++ b/packages/edit-post/src/components/sidebar/post-status/index.js @@ -8,6 +8,7 @@ import { } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { + PostAuthorPanel, PostSchedulePanel, PostSwitchToDraftButton, PostSyncStatus, @@ -20,7 +21,6 @@ import { import PostVisibility from '../post-visibility'; import PostTrash from '../post-trash'; import PostSticky from '../post-sticky'; -import PostAuthor from '../post-author'; import PostSlug from '../post-slug'; import PostFormat from '../post-format'; import PostPendingStatus from '../post-pending-status'; @@ -69,7 +69,7 @@ export default function PostStatus() { - + { fills } + + ); } diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js index a5a4fc7fcac36..a3dfc99152322 100644 --- a/packages/editor/src/components/index.js +++ b/packages/editor/src/components/index.js @@ -26,6 +26,7 @@ export { default as PageAttributesParent } from './page-attributes/parent'; export { default as PageTemplate } from './post-template'; export { default as PostAuthor } from './post-author'; export { default as PostAuthorCheck } from './post-author/check'; +export { default as PostAuthorPanel } from './post-author/panel'; export { default as PostComments } from './post-comments'; export { default as PostExcerpt } from './post-excerpt'; export { default as PostExcerptCheck } from './post-excerpt/check'; diff --git a/packages/editor/src/components/post-author/panel.js b/packages/editor/src/components/post-author/panel.js new file mode 100644 index 0000000000000..78f0e0a5f2cc8 --- /dev/null +++ b/packages/editor/src/components/post-author/panel.js @@ -0,0 +1,18 @@ +/** + * Internal dependencies + */ +import PostAuthorCheck from './check'; +import PostAuthorForm from './index'; +import PostPanelRow from '../post-panel-row'; + +export function PostAuthor() { + return ( + + + + + + ); +} + +export default PostAuthor; diff --git a/packages/editor/src/components/post-author/style.scss b/packages/editor/src/components/post-author/style.scss new file mode 100644 index 0000000000000..349ad712334c8 --- /dev/null +++ b/packages/editor/src/components/post-author/style.scss @@ -0,0 +1,7 @@ +.editor-post-author__panel { + padding-top: $grid-unit-10; +} + +.editor-post-author__panel .editor-post-panel__row-control > div { + width: 100%; +} diff --git a/packages/editor/src/components/post-panel-row/index.js b/packages/editor/src/components/post-panel-row/index.js index a746486ea25f6..f6f0c658cd724 100644 --- a/packages/editor/src/components/post-panel-row/index.js +++ b/packages/editor/src/components/post-panel-row/index.js @@ -15,18 +15,10 @@ const PostPanelRow = forwardRef( ( { className, label, children }, ref ) => { className={ classnames( 'editor-post-panel__row', className ) } ref={ ref } > - { label ? ( - <> -
- { label } -
-
- { children } -
- - ) : ( - children + { label && ( +
{ label }
) } +
{ children }
); } ); diff --git a/packages/editor/src/components/post-panel-row/style.scss b/packages/editor/src/components/post-panel-row/style.scss index b3dfc8c6bcf6b..bc1c7fbd000c6 100644 --- a/packages/editor/src/components/post-panel-row/style.scss +++ b/packages/editor/src/components/post-panel-row/style.scss @@ -15,4 +15,7 @@ .editor-post-panel__row-control { flex-grow: 1; + min-height: $button-size; + display: flex; + align-items: center; } diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss index 5861764ff8737..ccc26e23b430b 100644 --- a/packages/editor/src/style.scss +++ b/packages/editor/src/style.scss @@ -3,6 +3,7 @@ @import "./components/editor-notices/style.scss"; @import "./components/entities-saved-states/style.scss"; @import "./components/error-boundary/style.scss"; +@import "./components/post-author/style.scss"; @import "./components/post-excerpt/style.scss"; @import "./components/post-featured-image/style.scss"; @import "./components/post-format/style.scss"; From e95bb8c9530bbdef1db623eca11b80bd73493197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20K=C3=A4gy?= Date: Tue, 21 Nov 2023 13:48:12 +0100 Subject: [PATCH 099/116] Fix version in useSetting deprecation notice (#56377) --- packages/block-editor/README.md | 2 +- packages/block-editor/src/components/use-settings/index.js | 4 ++-- .../block-editor/src/components/use-settings/test/index.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 9c7a72f089714..2d6a5627a52a4 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -954,7 +954,7 @@ _Parameters_ ### useSetting -> **Deprecated** 6.4.0 Use useSettings instead. +> **Deprecated** 6.5.0 Use useSettings instead. Hook that retrieves the given setting for the block instance in use. diff --git a/packages/block-editor/src/components/use-settings/index.js b/packages/block-editor/src/components/use-settings/index.js index 12a442c5c98f3..36be1f914baf2 100644 --- a/packages/block-editor/src/components/use-settings/index.js +++ b/packages/block-editor/src/components/use-settings/index.js @@ -254,7 +254,7 @@ export function useSettings( ...paths ) { * * @param {string} path The path to the setting. * @return {any} Returns the value defined for the setting. - * @deprecated 6.4.0 Use useSettings instead. + * @deprecated 6.5.0 Use useSettings instead. * @example * ```js * const isEnabled = useSetting( 'typography.dropCap' ); @@ -262,7 +262,7 @@ export function useSettings( ...paths ) { */ export function useSetting( path ) { deprecated( 'wp.blockEditor.useSetting', { - since: '6.4', + since: '6.5', alternative: 'wp.blockEditor.useSettings', note: 'The new useSettings function can retrieve multiple settings at once, with better performance.', } ); diff --git a/packages/block-editor/src/components/use-settings/test/index.js b/packages/block-editor/src/components/use-settings/test/index.js index 89de12655338f..c9174cf35df5f 100644 --- a/packages/block-editor/src/components/use-settings/test/index.js +++ b/packages/block-editor/src/components/use-settings/test/index.js @@ -135,7 +135,7 @@ describe( 'useSettings', () => { const result = runHook( () => useSetting( 'layout.contentSize' ) ); expect( result ).toBe( '840px' ); expect( console ).toHaveWarnedWith( - 'wp.blockEditor.useSetting is deprecated since version 6.4. Please use wp.blockEditor.useSettings instead.' + 'wp.blockEditor.useSetting is deprecated since version 6.5. Please use wp.blockEditor.useSettings instead.' ); } ); } ); From 68b0d5b1db1a154e1b92f6ca2148a7e8ad0ef6fc Mon Sep 17 00:00:00 2001 From: Ramon Date: Wed, 22 Nov 2023 08:00:19 +1100 Subject: [PATCH 100/116] Global styles revisions: migrate API call to getRevisions() (#56349) * Migrating global styles revisions to new core data API and deprecating *ThemeGlobalStyleRevision selector and action. * Limiting the results to 100 --- docs/reference-guides/data/data-core.md | 2 ++ packages/core-data/README.md | 2 ++ packages/core-data/src/actions.js | 9 +++++++++ packages/core-data/src/selectors.ts | 9 ++++++++- .../screen-revisions/use-global-styles-revisions.js | 12 ++++++++++-- 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index 6084eff930394..b2a75638ace9f 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -128,6 +128,8 @@ _Returns_ ### getCurrentThemeGlobalStylesRevisions +> **Deprecated** since WordPress 6.5.0. Callers should use `select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )` instead, where `recordKey` is the id of the global styles parent post. + Returns the revisions of the current global styles theme. _Parameters_ diff --git a/packages/core-data/README.md b/packages/core-data/README.md index f7a177b5c5587..ebc467f7fede2 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -453,6 +453,8 @@ _Returns_ ### getCurrentThemeGlobalStylesRevisions +> **Deprecated** since WordPress 6.5.0. Callers should use `select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )` instead, where `recordKey` is the id of the global styles parent post. + Returns the revisions of the current global styles theme. _Parameters_ diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index d71c5d6120089..4c5622ac78058 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -218,6 +218,8 @@ export function receiveThemeSupports() { * Returns an action object used in signalling that the theme global styles CPT post revisions have been received. * Ignored from documentation as it's internal to the data store. * + * @deprecated since WordPress 6.5.0. Callers should use `dispatch( 'core' ).receiveRevision` instead. + * * @ignore * * @param {number} currentId The post id. @@ -226,6 +228,13 @@ export function receiveThemeSupports() { * @return {Object} Action object. */ export function receiveThemeGlobalStyleRevisions( currentId, revisions ) { + deprecated( + "wp.data.dispatch( 'core' ).receiveThemeGlobalStyleRevisions()", + { + since: '6.5.0', + alternative: "wp.data.dispatch( 'core' ).receiveRevisions", + } + ); return { type: 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS', currentId, diff --git a/packages/core-data/src/selectors.ts b/packages/core-data/src/selectors.ts index 4a893f5557d86..5751a80b9106c 100644 --- a/packages/core-data/src/selectors.ts +++ b/packages/core-data/src/selectors.ts @@ -1353,13 +1353,20 @@ export function getUserPatternCategories( /** * Returns the revisions of the current global styles theme. * - * @param state Data state. + * @deprecated since WordPress 6.5.0. Callers should use `select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )` instead, where `recordKey` is the id of the global styles parent post. + * + * @param state Data state. * * @return The current global styles. */ export function getCurrentThemeGlobalStylesRevisions( state: State ): Array< object > | null { + deprecated( "select( 'core' ).getCurrentThemeGlobalStylesRevisions()", { + since: '6.5.0', + alternative: + "select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )", + } ); const currentGlobalStylesId = __experimentalGetCurrentGlobalStylesId( state ); diff --git a/packages/edit-site/src/components/global-styles/screen-revisions/use-global-styles-revisions.js b/packages/edit-site/src/components/global-styles/screen-revisions/use-global-styles-revisions.js index 6e3573061a421..0c293e417cf8e 100644 --- a/packages/edit-site/src/components/global-styles/screen-revisions/use-global-styles-revisions.js +++ b/packages/edit-site/src/components/global-styles/screen-revisions/use-global-styles-revisions.js @@ -32,14 +32,22 @@ export default function useGlobalStylesRevisions() { __experimentalGetDirtyEntityRecords, getCurrentUser, getUsers, - getCurrentThemeGlobalStylesRevisions, + getRevisions, + __experimentalGetCurrentGlobalStylesId, isResolving, } = select( coreStore ); const dirtyEntityRecords = __experimentalGetDirtyEntityRecords(); const _currentUser = getCurrentUser(); const _isDirty = dirtyEntityRecords.length > 0; const globalStylesRevisions = - getCurrentThemeGlobalStylesRevisions() || EMPTY_ARRAY; + getRevisions( + 'root', + 'globalStyles', + __experimentalGetCurrentGlobalStylesId(), + { + per_page: 100, + } + ) || EMPTY_ARRAY; const _authors = getUsers( SITE_EDITOR_AUTHORS_QUERY ) || EMPTY_ARRAY; return { From aa91684eb5e58384e6d9b6244d7d9dd3791ffb52 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 22 Nov 2023 10:21:22 +1300 Subject: [PATCH 101/116] Spacing theme.json - check that the first item in the units array is defined before trying to assign its value (#56306) --- .../input-controls/spacing-input-control.js | 2 +- schemas/json/theme.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js b/packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js index a7efd10bce712..7ef5c17f82943 100644 --- a/packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js +++ b/packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js @@ -139,7 +139,7 @@ export default function SpacingInputControl( { useMemo( () => parseQuantityAndUnitFromRawValue( currentValue ), [ currentValue ] - )[ 1 ] || units[ 0 ].value; + )[ 1 ] || units[ 0 ]?.value; const setInitialValue = () => { if ( value === undefined ) { diff --git a/schemas/json/theme.json b/schemas/json/theme.json index 8414c939c8c7a..5a24f1b16c1a3 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -364,7 +364,8 @@ "items": { "type": "string" }, - "default": [ "px", "em", "rem", "vh", "vw", "%" ] + "default": [ "px", "em", "rem", "vh", "vw", "%" ], + "minItems": 1 }, "customSpacingSize": { "description": "Allow users to set custom space sizes.", From c283c4419e2773203ca84a32901418c9210586f1 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 22 Nov 2023 14:28:46 +1300 Subject: [PATCH 102/116] Patterns: Fix bug with templates in replace template screen showing as synced patterns (#56407) --- .../components/block-patterns-list/index.js | 28 +++++++++++-------- .../block-patterns-explorer/pattern-list.js | 6 +++- .../pattern-category-previews.js | 6 +++- .../use-pattern-categories.js | 7 ++++- .../inserter/block-patterns-tab/utils.js | 8 ++++-- .../inserter/hooks/use-patterns-state.js | 4 ++- packages/block-editor/src/store/selectors.js | 2 ++ .../components/page-patterns/use-patterns.js | 2 +- .../src/components/duplicate-pattern-modal.js | 13 +++++---- 9 files changed, 51 insertions(+), 25 deletions(-) diff --git a/packages/block-editor/src/components/block-patterns-list/index.js b/packages/block-editor/src/components/block-patterns-list/index.js index bebeb1f44184c..daf07fa5c7fc0 100644 --- a/packages/block-editor/src/components/block-patterns-list/index.js +++ b/packages/block-editor/src/components/block-patterns-list/index.js @@ -25,6 +25,7 @@ import { Icon, symbol } from '@wordpress/icons'; import BlockPreview from '../block-preview'; import InserterDraggableBlocks from '../inserter-draggable-blocks'; import BlockPatternsPaging from '../block-patterns-paging'; +import { PATTERN_TYPES } from '../inserter/block-patterns-tab/utils'; const WithToolTip = ( { showTooltip, title, children } ) => { if ( showTooltip ) { @@ -71,7 +72,9 @@ function BlockPattern( { } } > { @@ -107,15 +111,17 @@ function BlockPattern( { /> - { pattern.id && ! pattern.syncStatus && ( -
- -
- ) } - { ( ! showTooltip || pattern.id ) && ( + { pattern.type === PATTERN_TYPES.user && + ! pattern.syncStatus && ( +
+ +
+ ) } + { ( ! showTooltip || + pattern.type === PATTERN_TYPES.user ) && (
{ pattern.title }
diff --git a/packages/block-editor/src/components/inserter/block-patterns-explorer/pattern-list.js b/packages/block-editor/src/components/inserter/block-patterns-explorer/pattern-list.js index 7cd2320a4fd1f..bf2867be5cdf3 100644 --- a/packages/block-editor/src/components/inserter/block-patterns-explorer/pattern-list.js +++ b/packages/block-editor/src/components/inserter/block-patterns-explorer/pattern-list.js @@ -18,6 +18,7 @@ import { searchItems } from '../search-items'; import BlockPatternsPaging from '../../block-patterns-paging'; import usePatternsPaging from '../hooks/use-patterns-paging'; import { + PATTERN_TYPES, allPatternsCategory, myPatternsCategory, } from '../block-patterns-tab/utils'; @@ -70,7 +71,10 @@ function PatternList( { searchValue, selectedCategory, patternCategories } ) { if ( selectedCategory === allPatternsCategory.name ) { return true; } - if ( selectedCategory === myPatternsCategory.name && pattern.id ) { + if ( + selectedCategory === myPatternsCategory.name && + pattern.type === PATTERN_TYPES.user + ) { return true; } if ( selectedCategory === 'uncategorized' ) { diff --git a/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js b/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js index 2fef53cfa2a19..76864a6a00ccc 100644 --- a/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js +++ b/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js @@ -30,6 +30,7 @@ import { isPatternFiltered, allPatternsCategory, myPatternsCategory, + PATTERN_TYPES, } from './utils'; const noop = () => {}; @@ -69,7 +70,10 @@ export function PatternCategoryPreviews( { if ( category.name === allPatternsCategory.name ) { return true; } - if ( category.name === myPatternsCategory.name && pattern.id ) { + if ( + category.name === myPatternsCategory.name && + pattern.type === PATTERN_TYPES.user + ) { return true; } if ( category.name !== 'uncategorized' ) { diff --git a/packages/block-editor/src/components/inserter/block-patterns-tab/use-pattern-categories.js b/packages/block-editor/src/components/inserter/block-patterns-tab/use-pattern-categories.js index 9c7a7a32a60c0..12e885954f4bf 100644 --- a/packages/block-editor/src/components/inserter/block-patterns-tab/use-pattern-categories.js +++ b/packages/block-editor/src/components/inserter/block-patterns-tab/use-pattern-categories.js @@ -14,6 +14,7 @@ import { isPatternFiltered, allPatternsCategory, myPatternsCategory, + PATTERN_TYPES, } from './utils'; export function usePatternCategories( rootClientId, sourceFilter = 'all' ) { @@ -69,7 +70,11 @@ export function usePatternCategories( rootClientId, sourceFilter = 'all' ) { label: _x( 'Uncategorized' ), } ); } - if ( filteredPatterns.some( ( pattern ) => pattern.id ) ) { + if ( + filteredPatterns.some( + ( pattern ) => pattern.type === PATTERN_TYPES.user + ) + ) { categories.unshift( myPatternsCategory ); } if ( filteredPatterns.length > 0 ) { diff --git a/packages/block-editor/src/components/inserter/block-patterns-tab/utils.js b/packages/block-editor/src/components/inserter/block-patterns-tab/utils.js index 9f222c6a2f93c..439955eca92b3 100644 --- a/packages/block-editor/src/components/inserter/block-patterns-tab/utils.js +++ b/packages/block-editor/src/components/inserter/block-patterns-tab/utils.js @@ -53,9 +53,11 @@ export function isPatternFiltered( pattern, sourceFilter, syncFilter ) { return true; } - // If user source selected, filter out theme patterns. Any pattern without - // an id wasn't created by a user. - if ( sourceFilter === PATTERN_TYPES.user && ! pattern.id ) { + // If user source selected, filter out theme patterns. + if ( + sourceFilter === PATTERN_TYPES.user && + pattern.type !== PATTERN_TYPES.user + ) { return true; } diff --git a/packages/block-editor/src/components/inserter/hooks/use-patterns-state.js b/packages/block-editor/src/components/inserter/hooks/use-patterns-state.js index 1924187e04179..576768c76abca 100644 --- a/packages/block-editor/src/components/inserter/hooks/use-patterns-state.js +++ b/packages/block-editor/src/components/inserter/hooks/use-patterns-state.js @@ -11,6 +11,7 @@ import { store as noticesStore } from '@wordpress/notices'; * Internal dependencies */ import { store as blockEditorStore } from '../../../store'; +import { PATTERN_TYPES } from '../block-patterns-tab/utils'; /** * Retrieves the block patterns inserter state. @@ -57,7 +58,8 @@ const usePatternsState = ( onInsert, rootClientId ) => { const onClickPattern = useCallback( ( pattern, blocks ) => { const patternBlocks = - pattern.id && pattern.syncStatus !== 'unsynced' + pattern.type === PATTERN_TYPES.user && + pattern.syncStatus !== 'unsynced' ? [ createBlock( 'core/block', { ref: pattern.id } ) ] : blocks; onInsert( diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 548ad71664b5e..c0441cd3b3755 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -27,6 +27,7 @@ import { createRegistrySelector } from '@wordpress/data'; * Internal dependencies */ import { orderBy } from '../utils/sorting'; +import { PATTERN_TYPES } from '../components/inserter/block-patterns-tab/utils'; /** * A block selection object. @@ -2287,6 +2288,7 @@ function getUserPatterns( state ) { return { name: `core/block/${ userPattern.id }`, id: userPattern.id, + type: PATTERN_TYPES.user, title: userPattern.title.raw, categories: userPattern.wp_pattern_category.map( ( catId ) => categories && categories.get( catId ) diff --git a/packages/edit-site/src/components/page-patterns/use-patterns.js b/packages/edit-site/src/components/page-patterns/use-patterns.js index 9cb6c8b998c41..be5992bd9b4ef 100644 --- a/packages/edit-site/src/components/page-patterns/use-patterns.js +++ b/packages/edit-site/src/components/page-patterns/use-patterns.js @@ -159,7 +159,7 @@ const selectPatterns = createSelector( // User patterns can have their sync statuses checked directly // Non-user patterns are all unsynced for the time being. patterns = patterns.filter( ( pattern ) => { - return pattern.id + return pattern.type === PATTERN_TYPES.user ? pattern.syncStatus === syncStatus : syncStatus === PATTERN_SYNC_TYPES.unsynced; } ); diff --git a/packages/patterns/src/components/duplicate-pattern-modal.js b/packages/patterns/src/components/duplicate-pattern-modal.js index baf977a7b27e2..a62e7306dc90e 100644 --- a/packages/patterns/src/components/duplicate-pattern-modal.js +++ b/packages/patterns/src/components/duplicate-pattern-modal.js @@ -10,11 +10,11 @@ import { store as noticesStore } from '@wordpress/notices'; * Internal dependencies */ import CreatePatternModal from './create-pattern-modal'; -import { PATTERN_SYNC_TYPES } from '../constants'; +import { PATTERN_SYNC_TYPES, PATTERN_TYPES } from '../constants'; function getTermLabels( pattern, categories ) { - // Theme patterns don't have an id and rely on core pattern categories. - if ( ! pattern.id ) { + // Theme patterns rely on core pattern categories. + if ( pattern.type !== PATTERN_TYPES.user ) { return categories.core ?.filter( ( category ) => pattern.categories.includes( category.name ) @@ -52,9 +52,10 @@ export default function DuplicatePatternModal( { const duplicatedProps = { content: pattern.content, defaultCategories: getTermLabels( pattern, categories ), - defaultSyncType: ! pattern.id // Theme patterns don't have an ID. - ? PATTERN_SYNC_TYPES.unsynced - : pattern.wp_pattern_sync_status || PATTERN_SYNC_TYPES.full, + defaultSyncType: + pattern.type !== PATTERN_TYPES.user // Theme patterns are unsynced by default. + ? PATTERN_SYNC_TYPES.unsynced + : pattern.wp_pattern_sync_status || PATTERN_SYNC_TYPES.full, defaultTitle: sprintf( /* translators: %s: Existing pattern title */ __( '%s (Copy)' ), From ae57cac36a9cf661fbb769fac44f9e80911e03a3 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Wed, 22 Nov 2023 15:15:06 +1100 Subject: [PATCH 103/116] useMovingAnimation: Clear translate3d rule when animation is finished (#56410) * useMovingAnimation: Clear translate3d rule when animation is finished * Add inline comment for clarity --- .../block-editor/src/components/use-moving-animation/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/use-moving-animation/index.js b/packages/block-editor/src/components/use-moving-animation/index.js index bf49a480bc6b4..e6c888330fca7 100644 --- a/packages/block-editor/src/components/use-moving-animation/index.js +++ b/packages/block-editor/src/components/use-moving-animation/index.js @@ -129,7 +129,7 @@ function useMovingAnimation( { const finishedMoving = x === 0 && y === 0; ref.current.style.transformOrigin = 'center center'; ref.current.style.transform = finishedMoving - ? undefined + ? null // Set to `null` to explicitly remove the transform. : `translate3d(${ x }px,${ y }px,0)`; ref.current.style.zIndex = isSelected ? '1' : ''; From 537fa574e0e9bc18f6bb800d7c673c8fae88c99c Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 22 Nov 2023 16:32:23 +1100 Subject: [PATCH 104/116] Reduce specificity of default Cover text color styles. (#56411) --- packages/block-library/src/cover/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/cover/style.scss b/packages/block-library/src/cover/style.scss index d9312a71f0faa..837e3834e2e1b 100644 --- a/packages/block-library/src/cover/style.scss +++ b/packages/block-library/src/cover/style.scss @@ -123,7 +123,7 @@ h4, h5, h6 { - &:not(.has-text-color) { + &:where(:not(.has-text-color)) { color: inherit; } } From ee6acea556b7475af296e41b6ba3bd38f642901a Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 22 Nov 2023 09:48:09 +0400 Subject: [PATCH 105/116] Pattern placeholder: Remove duplicate 'useDispatch' hook (#56397) --- packages/block-library/src/pattern/edit.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/pattern/edit.js b/packages/block-library/src/pattern/edit.js index 5fd1b427a5e3e..e01fb37eb849e 100644 --- a/packages/block-library/src/pattern/edit.js +++ b/packages/block-library/src/pattern/edit.js @@ -24,9 +24,11 @@ const PatternEdit = ( { attributes, clientId } ) => { [] ); - const { replaceBlocks, __unstableMarkNextChangeAsNotPersistent } = - useDispatch( blockEditorStore ); - const { setBlockEditingMode } = useDispatch( blockEditorStore ); + const { + replaceBlocks, + setBlockEditingMode, + __unstableMarkNextChangeAsNotPersistent, + } = useDispatch( blockEditorStore ); const { getBlockRootClientId, getBlockEditingMode } = useSelect( blockEditorStore ); From 10034176c30ae7b9e0d224d9d1aadbadf7963215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20K=C3=A4gy?= Date: Wed, 22 Nov 2023 08:11:17 +0100 Subject: [PATCH 106/116] Fix overly complex code example in ComboboxControl readme (#56365) --- packages/components/src/combobox-control/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/components/src/combobox-control/README.md b/packages/components/src/combobox-control/README.md index 30f1f47e653e8..cc15248678d27 100644 --- a/packages/components/src/combobox-control/README.md +++ b/packages/components/src/combobox-control/README.md @@ -47,9 +47,7 @@ function MyComboboxControl() { onFilterValueChange={ ( inputValue ) => setFilteredOptions( options.filter( ( option ) => - option.label - .toLowerCase() - .startsWith( inputValue.toLowerCase() ) + option.value === inputValue ) ) } From 3861da94ce0f9888b5aacb24a22884586a6961d4 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 22 Nov 2023 11:13:17 +0400 Subject: [PATCH 107/116] Block Editor: Undeprecate the '__experimentalImageSizeControl' component (#56414) --- .../block-editor/src/components/image-size-control/index.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/block-editor/src/components/image-size-control/index.js b/packages/block-editor/src/components/image-size-control/index.js index d929b12931393..46e87de60f2fc 100644 --- a/packages/block-editor/src/components/image-size-control/index.js +++ b/packages/block-editor/src/components/image-size-control/index.js @@ -8,7 +8,6 @@ import { __experimentalNumberControl as NumberControl, __experimentalHStack as HStack, } from '@wordpress/components'; -import deprecated from '@wordpress/deprecated'; import { __ } from '@wordpress/i18n'; /** @@ -31,11 +30,6 @@ export default function ImageSizeControl( { onChange, onChangeImage = noop, } ) { - deprecated( 'wp.blockEditor.__experimentalImageSizeControl', { - since: '6.3', - alternative: - 'wp.blockEditor.privateApis.DimensionsTool and wp.blockEditor.privateApis.ResolutionTool', - } ); const { currentHeight, currentWidth, updateDimension, updateDimensions } = useDimensionHandler( height, width, imageHeight, imageWidth, onChange ); From d7d680e7a0f54fa6ef8d961a936327f632853f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20K=C3=A4gy?= Date: Wed, 22 Nov 2023 09:07:01 +0100 Subject: [PATCH 108/116] Simplify code example in ToggleControl component readme (#56389) --- packages/components/src/toggle-control/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/toggle-control/README.md b/packages/components/src/toggle-control/README.md index 5e2732fb07416..3a77ef6942d2e 100644 --- a/packages/components/src/toggle-control/README.md +++ b/packages/components/src/toggle-control/README.md @@ -22,8 +22,8 @@ const MyToggleControl = () => { : 'No fixed background.' } checked={ hasFixedBackground } - onChange={ () => { - setHasFixedBackground( ( state ) => ! state ); + onChange={ (newValue) => { + setHasFixedBackground( newValue ); } } /> ); From 12f286c4605db3ee2a3640eefb52d3fa894bc766 Mon Sep 17 00:00:00 2001 From: James Koster Date: Wed, 22 Nov 2023 08:53:40 +0000 Subject: [PATCH 109/116] Fix data view menu item radius (#56395) * Fix data view menu item radius * Update packages/edit-site/src/components/sidebar-dataviews/style.scss * fix wrong GH suggestion --------- Co-authored-by: Nik Tsekouras --- packages/edit-site/src/components/sidebar-dataviews/style.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/edit-site/src/components/sidebar-dataviews/style.scss b/packages/edit-site/src/components/sidebar-dataviews/style.scss index 526670ee1e562..6d8561dc8edca 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/style.scss +++ b/packages/edit-site/src/components/sidebar-dataviews/style.scss @@ -8,6 +8,8 @@ } .edit-site-sidebar-dataviews-dataview-item { + border-radius: $radius-block-ui; + &:hover, &:focus, &[aria-current] { From de3c98e1bc335b5d727b9b5f4a8f08f02cfee445 Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Wed, 22 Nov 2023 09:18:14 +0000 Subject: [PATCH 110/116] Bump plugin version to 17.1.0 --- gutenberg.php | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gutenberg.php b/gutenberg.php index 3ccde2667f03a..018c269f4f565 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -5,7 +5,7 @@ * Description: Printing since 1440. This is the development plugin for the block editor, site editor, and other future WordPress core functionality. * Requires at least: 6.2 * Requires PHP: 7.0 - * Version: 17.1.0-rc.1 + * Version: 17.1.0 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index 8382dd2413d46..601aafc18b268 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gutenberg", - "version": "17.1.0-rc.1", + "version": "17.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "gutenberg", - "version": "17.1.0-rc.1", + "version": "17.1.0", "hasInstallScript": true, "license": "GPL-2.0-or-later", "dependencies": { diff --git a/package.json b/package.json index eea10b3180540..43ca7f0858f60 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "17.1.0-rc.1", + "version": "17.1.0", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", From 014d1633b6986f54a0dd597d3d751f566a569570 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Wed, 22 Nov 2023 09:23:25 +0000 Subject: [PATCH 111/116] Migrating `InserterListbox` to use updated Composite implementation (#56246) - Removes `__unstableComposite` imports from `@wordpress/components` - Adds private `Composite*` exports from `@wordpress/components` - Refactors `InserterListbox`, `InserterListboxRow` and `InserterListboxItem` to use updated `Composite` components - Additionally updates `BlockTypesList` to ensure listbox items are appropriately grouped --- .../src/components/block-types-list/index.js | 9 ++++---- .../src/components/inserter-listbox/index.js | 18 +++++++++------ .../src/components/inserter-listbox/item.js | 23 +++++++++---------- .../src/components/inserter-listbox/row.js | 18 +++++---------- 4 files changed, 33 insertions(+), 35 deletions(-) diff --git a/packages/block-editor/src/components/block-types-list/index.js b/packages/block-editor/src/components/block-types-list/index.js index 40e04b040d5a8..0be6f82a653d1 100644 --- a/packages/block-editor/src/components/block-types-list/index.js +++ b/packages/block-editor/src/components/block-types-list/index.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { getBlockMenuDefaultClassName } from '@wordpress/blocks'; +import { useInstanceId } from '@wordpress/compose'; /** * Internal dependencies @@ -25,11 +26,10 @@ function BlockTypesList( { label, isDraggable = true, } ) { + const className = 'block-editor-block-types-list'; + const listId = useInstanceId( BlockTypesList, className ); return ( - + { chunk( items, 3 ).map( ( row, i ) => ( { row.map( ( item, j ) => ( @@ -43,6 +43,7 @@ function BlockTypesList( { onHover={ onHover } isDraggable={ isDraggable && ! item.isDisabled } isFirst={ i === 0 && j === 0 } + rowId={ `${ listId }-${ i }` } /> ) ) } diff --git a/packages/block-editor/src/components/inserter-listbox/index.js b/packages/block-editor/src/components/inserter-listbox/index.js index 6345cb38c494a..6af26a1d746bf 100644 --- a/packages/block-editor/src/components/inserter-listbox/index.js +++ b/packages/block-editor/src/components/inserter-listbox/index.js @@ -1,26 +1,30 @@ /** * WordPress dependencies */ -import { __unstableUseCompositeState as useCompositeState } from '@wordpress/components'; +import { privateApis as componentsPrivateApis } from '@wordpress/components'; /** * Internal dependencies */ -import InserterListboxContext from './context'; +import { unlock } from '../../lock-unlock'; export { default as InserterListboxGroup } from './group'; export { default as InserterListboxRow } from './row'; export { default as InserterListboxItem } from './item'; +const { CompositeV2: Composite, useCompositeStoreV2: useCompositeStore } = + unlock( componentsPrivateApis ); + function InserterListbox( { children } ) { - const compositeState = useCompositeState( { - shift: true, - wrap: 'horizontal', + const store = useCompositeStore( { + focusShift: true, + focusWrap: 'horizontal', } ); + return ( - + }> { children } - + ); } diff --git a/packages/block-editor/src/components/inserter-listbox/item.js b/packages/block-editor/src/components/inserter-listbox/item.js index 50adb4a788038..951eb86223ce8 100644 --- a/packages/block-editor/src/components/inserter-listbox/item.js +++ b/packages/block-editor/src/components/inserter-listbox/item.js @@ -3,32 +3,31 @@ */ import { Button, - __unstableCompositeItem as CompositeItem, + privateApis as componentsPrivateApis, } from '@wordpress/components'; -import { forwardRef, useContext } from '@wordpress/element'; +import { forwardRef } from '@wordpress/element'; /** * Internal dependencies */ -import InserterListboxContext from './context'; +import { unlock } from '../../lock-unlock'; + +const { CompositeItemV2: CompositeItem } = unlock( componentsPrivateApis ); function InserterListboxItem( { isFirst, as: Component, children, ...props }, ref ) { - const state = useContext( InserterListboxContext ); return ( - { ( htmlProps ) => { + render={ ( htmlProps ) => { const propsWithTabIndex = { ...htmlProps, tabIndex: isFirst ? 0 : htmlProps.tabIndex, @@ -45,7 +44,7 @@ function InserterListboxItem( } return ; } } - + /> ); } diff --git a/packages/block-editor/src/components/inserter-listbox/row.js b/packages/block-editor/src/components/inserter-listbox/row.js index 710267660199d..f9827f08b3fa3 100644 --- a/packages/block-editor/src/components/inserter-listbox/row.js +++ b/packages/block-editor/src/components/inserter-listbox/row.js @@ -1,24 +1,18 @@ /** * WordPress dependencies */ -import { forwardRef, useContext } from '@wordpress/element'; -import { __unstableCompositeGroup as CompositeGroup } from '@wordpress/components'; +import { forwardRef } from '@wordpress/element'; +import { privateApis as componentsPrivateApis } from '@wordpress/components'; /** * Internal dependencies */ -import InserterListboxContext from './context'; +import { unlock } from '../../lock-unlock'; + +const { CompositeGroupV2: CompositeGroup } = unlock( componentsPrivateApis ); function InserterListboxRow( props, ref ) { - const state = useContext( InserterListboxContext ); - return ( - - ); + return ; } export default forwardRef( InserterListboxRow ); From 9c6f6b1738a45f2891b5c7d4fde5c9a5ff80dc7e Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Wed, 22 Nov 2023 09:35:13 +0000 Subject: [PATCH 112/116] Update Changelog for 17.1.0 --- changelog.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 2435ab1eceb4a..0f86c2d8f593b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,7 +1,6 @@ == Changelog == -= 17.1.0-rc.1 = - += 17.1.0 = ## Changelog @@ -27,7 +26,7 @@ #### Global Styles - Global Style Revisions: Ensure consistent back button behaviour. ([55881](https://github.com/WordPress/gutenberg/pull/55881)) - Global Styles Revisions: More descriptive text timeline. ([55868](https://github.com/WordPress/gutenberg/pull/55868)) -- Global styles revisions: Add route for single styles revisions. ([55827](https://github.com/WordPress/gutenberg/pull/55827)) +- Global Styles Revisions: Add route for single styles revisions. ([55827](https://github.com/WordPress/gutenberg/pull/55827)) #### Block Locking - Block Quick Navigation: Truncate text. ([56142](https://github.com/WordPress/gutenberg/pull/56142)) @@ -89,7 +88,7 @@ - DataViews: Make items per page an even number. ([55906](https://github.com/WordPress/gutenberg/pull/55906)) - DataViews: Make used taxonomy private. ([55918](https://github.com/WordPress/gutenberg/pull/55918)) - DataViews: Reset pagination upon filter change. ([55797](https://github.com/WordPress/gutenberg/pull/55797)) -- Dataviews: Add a missing icon for the side by side view. ([55925](https://github.com/WordPress/gutenberg/pull/55925)) +- DataViews: Add a missing icon for the side by side view. ([55925](https://github.com/WordPress/gutenberg/pull/55925)) #### Components - DropdownMenu: Remove extra vertical space around the toggle button. ([56136](https://github.com/WordPress/gutenberg/pull/56136)) @@ -328,6 +327,8 @@ The following contributors merged PRs in this release: @afercia @andrewhayward @andrewserong @anomiex @anton-vlasenko @aristath @artemiomorales @bph @brookewp @c4rl0sbr4v0 @chad1008 @ciampo @DAreRodz @dcalhoun @dsas @ellatrix @flootr @fluiddot @gaambo @glendaviesnz @gziolo @jameskoster @jeryj @jhnstn @joanrodas @jorgefilipecosta @JorgeVilchez95 @jsnajdr @juanmaguitar @kevin940726 @Mamaduka @masteradhoc @matiasbenedetto @ndiego @ntsekouras @oandregal @peterwilsoncc @pooja-muchandikar @priethor @ramonjd @renatho @richtabor @sacerro @scruffian @shimotmk @SiobhyB @Soean @swissspidy @t-hamano @talldan @tellthemachines @torounit @tyxla @WunderBart @youknowriad + + = 17.0.2 = From a7911582cda6f11d1ebddcd27ccbb82fb86022c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:39:45 +0100 Subject: [PATCH 113/116] DataViews: update filter component (#56110) --- .../src/components/dataviews/add-filter.js | 2 +- .../src/components/dataviews/filters.js | 13 +-- .../src/components/dataviews/in-filter.js | 105 ++++++++++-------- .../src/components/dataviews/view-list.js | 35 ++---- 4 files changed, 71 insertions(+), 84 deletions(-) diff --git a/packages/edit-site/src/components/dataviews/add-filter.js b/packages/edit-site/src/components/dataviews/add-filter.js index 147b5a09ca59a..7192a507b2afe 100644 --- a/packages/edit-site/src/components/dataviews/add-filter.js +++ b/packages/edit-site/src/components/dataviews/add-filter.js @@ -54,10 +54,10 @@ export default function AddFilter( { fields, view, onChangeView } ) { } diff --git a/packages/edit-site/src/components/dataviews/filters.js b/packages/edit-site/src/components/dataviews/filters.js index 72ca0eb35bd87..c7681f53fe0ae 100644 --- a/packages/edit-site/src/components/dataviews/filters.js +++ b/packages/edit-site/src/components/dataviews/filters.js @@ -1,8 +1,3 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; - /** * Internal dependencies */ @@ -23,13 +18,7 @@ export default function Filters( { fields, view, onChangeView } ) { filters.push( { field: field.id, name: field.header, - elements: [ - { - value: '', - label: __( 'All' ), - }, - ...( field.elements || [] ), - ], + elements: field.elements || [], isVisible: view.filters.some( ( f ) => f.field === field.id && f.operator === OPERATOR_IN diff --git a/packages/edit-site/src/components/dataviews/in-filter.js b/packages/edit-site/src/components/dataviews/in-filter.js index 4f4170fdcbb0b..9dd85eb1eedb2 100644 --- a/packages/edit-site/src/components/dataviews/in-filter.js +++ b/packages/edit-site/src/components/dataviews/in-filter.js @@ -2,65 +2,78 @@ * WordPress dependencies */ import { - __experimentalInputControlPrefixWrapper as InputControlPrefixWrapper, - SelectControl, + Button, + privateApis as componentsPrivateApis, + Icon, } from '@wordpress/components'; +import { chevronDown } from '@wordpress/icons'; import { __, sprintf } from '@wordpress/i18n'; /** * Internal dependencies */ import { OPERATOR_IN } from './constants'; +import { unlock } from '../../lock-unlock'; + +const { + DropdownMenuV2: DropdownMenu, + DropdownMenuCheckboxItemV2: DropdownMenuCheckboxItem, +} = unlock( componentsPrivateApis ); export default ( { filter, view, onChangeView } ) => { - const valueFound = view.filters.find( - ( f ) => f.field === filter.field && f.operator === OPERATOR_IN + const filterInView = view.filters.find( ( f ) => f.field === filter.field ); + const activeElement = filter.elements.find( + ( element ) => element.value === filterInView?.value ); - const activeValue = - ! valueFound || ! valueFound.hasOwnProperty( 'value' ) - ? '' - : valueFound.value; - - const id = `dataviews__filters-in-${ filter.field }`; - return ( - - { sprintf( - /* translators: filter name. */ - __( '%s:' ), - filter.name - ) } - + + { activeElement !== undefined + ? sprintf( + /* translators: 1: Filter name. 2: filter value. e.g.: "Author is Admin". */ + __( '%1$s is %2$s' ), + filter.name, + activeElement.label + ) + : filter.name } + + } - options={ filter.elements } - onChange={ ( value ) => { - const filters = view.filters.filter( - ( f ) => - f.field !== filter.field || f.operator !== OPERATOR_IN + > + { filter.elements.map( ( element ) => { + return ( + + onChangeView( ( currentView ) => ( { + ...currentView, + page: 1, + filters: [ + ...view.filters.filter( + ( f ) => f.field !== filter.field + ), + { + field: filter.field, + operator: OPERATOR_IN, + value: + activeElement?.value === + element.value + ? undefined + : element.value, + }, + ], + } ) ) + } + > + { element.label } + ); - - filters.push( { - field: filter.field, - operator: OPERATOR_IN, - value, - } ); - - onChangeView( ( currentView ) => ( { - ...currentView, - page: 1, - filters, - } ) ); - } } - /> + } ) } + ); }; diff --git a/packages/edit-site/src/components/dataviews/view-list.js b/packages/edit-site/src/components/dataviews/view-list.js index 0939297e374df..8e131a350ac7d 100644 --- a/packages/edit-site/src/components/dataviews/view-list.js +++ b/packages/edit-site/src/components/dataviews/view-list.js @@ -73,13 +73,7 @@ function HeaderMenu( { dataView, header } ) { if ( header.column.columnDef.type === ENUMERATION_TYPE ) { filter = { field: header.column.columnDef.id, - elements: [ - { - value: '', - label: __( 'All' ), - }, - ...( header.column.columnDef.elements || [] ), - ], + elements: header.column.columnDef.elements || [], }; } const isFilterable = !! filter; @@ -166,11 +160,6 @@ function HeaderMenu( { dataView, header } ) { )[ 0 ] === filter.field ); - // Set the empty item as active if the filter is not set. - if ( ! columnFilter && element.value === '' ) { - isActive = true; - } - if ( columnFilter ) { const value = Object.values( columnFilter )[ 0 ]; @@ -205,19 +194,15 @@ function HeaderMenu( { dataView, header } ) { } ); - if ( element.value === '' ) { - dataView.setColumnFilters( - otherFilters - ); - } else { - dataView.setColumnFilters( [ - ...otherFilters, - { - [ filter.field + - ':in' ]: element.value, - }, - ] ); - } + dataView.setColumnFilters( [ + ...otherFilters, + { + [ filter.field + ':in' ]: + isActive + ? undefined + : element.value, + }, + ] ); } } > { element.label } From 3b380b0917e2b39a1bd30e9228f37669e7c0c7f6 Mon Sep 17 00:00:00 2001 From: Birgit Pauli-Haack Date: Wed, 22 Nov 2023 12:20:06 +0100 Subject: [PATCH 114/116] Update Readme.txt tested up to 6.4 (#56427) * fixes wrong link in #56084 * update 'tested up to' in readme.txt of GB plugin --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 668ccca48a5dc..8ebcfd1406b0d 100644 --- a/readme.txt +++ b/readme.txt @@ -1,6 +1,6 @@ === Gutenberg === Contributors: matveb, joen, karmatosed -Tested up to: 6.3 +Tested up to: 6.4 Stable tag: V.V.V License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html From 6e532f444a72d997b09441197caade90c49f19f3 Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Wed, 22 Nov 2023 13:31:02 +0200 Subject: [PATCH 115/116] Add align support to the image block - alternative (#55954) * only remove the alignment control * use an effect to reset width, height, aspect ratio and cover when align is wide or full * try a filter on block attributes when align control updates attributes * new fixtures for the default align attribute of core/image * updated snapshots * modify the filter to always return the same shape of object, update naming * remove filter, add undo skip * update the react native component * Remove align from custom image attributes This allows the block supports to add the attribute instead keeping things cleaner. * Fix tests * Fix another fixture --------- Co-authored-by: Alex Lende --- docs/reference-guides/core-blocks.md | 4 +- .../test/__snapshots__/align.native.js.snap | 10 ++--- packages/block-library/src/image/block.json | 4 +- packages/block-library/src/image/edit.js | 37 ++++++++----------- .../block-library/src/image/edit.native.js | 35 +++++++++--------- packages/block-library/src/image/image.js | 22 ----------- .../src/mobile/utils/alignments.native.js | 1 + .../blocks-raw-handling.test.js.snap | 6 +-- .../blocks/core__image__center-caption.json | 4 +- ...ed-v2-add-is-resized-class.serialized.html | 2 +- ...cated-v3-add-align-wrapper.serialized.html | 2 +- ...ed-v4-remove-align-wrapper.serialized.html | 2 +- ...-v6-add-style-width-height.serialized.html | 2 +- .../fixtures/documents/wordpress-out.html | 2 +- 14 files changed, 52 insertions(+), 81 deletions(-) diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 0ae5979b79704..10f0f76d9eb0d 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -378,8 +378,8 @@ Insert an image to make a visual statement. ([Source](https://github.com/WordPre - **Name:** core/image - **Category:** media -- **Supports:** anchor, color (~~background~~, ~~text~~), filter (duotone) -- **Attributes:** align, alt, aspectRatio, caption, height, href, id, lightbox, linkClass, linkDestination, linkTarget, rel, scale, sizeSlug, title, url, width +- **Supports:** align (center, full, left, right, wide), anchor, color (~~background~~, ~~text~~), filter (duotone) +- **Attributes:** alt, aspectRatio, caption, height, href, id, lightbox, linkClass, linkDestination, linkTarget, rel, scale, sizeSlug, title, url, width ## Latest Comments diff --git a/packages/block-editor/src/hooks/test/__snapshots__/align.native.js.snap b/packages/block-editor/src/hooks/test/__snapshots__/align.native.js.snap index 2782d6ae0b984..045fb0e3bd944 100644 --- a/packages/block-editor/src/hooks/test/__snapshots__/align.native.js.snap +++ b/packages/block-editor/src/hooks/test/__snapshots__/align.native.js.snap @@ -19,25 +19,25 @@ exports[`Align options for group block sets Wide width option 1`] = ` `; exports[`Align options for media block sets Align center option 1`] = ` -" +"
" `; exports[`Align options for media block sets Align left option 1`] = ` -" +"
" `; exports[`Align options for media block sets Align right option 1`] = ` -" +"
" `; exports[`Align options for media block sets Full width option 1`] = ` -" +"
" `; @@ -49,7 +49,7 @@ exports[`Align options for media block sets None option 1`] = ` `; exports[`Align options for media block sets Wide width option 1`] = ` -" +"
" `; diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index d665a8a8f7708..b46829e5059a2 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -9,9 +9,6 @@ "keywords": [ "img", "photo", "picture" ], "textdomain": "default", "attributes": { - "align": { - "type": "string" - }, "url": { "type": "string", "source": "attribute", @@ -95,6 +92,7 @@ } }, "supports": { + "align": [ "left", "center", "right", "wide", "full" ], "anchor": true, "color": { "text": false, diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index c58a96e594911..d189af32efcbe 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -10,8 +10,6 @@ import { getBlobByURL, isBlobURL, revokeBlobURL } from '@wordpress/blob'; import { Placeholder } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { - BlockAlignmentControl, - BlockControls, BlockIcon, MediaPlaceholder, useBlockProps, @@ -106,13 +104,13 @@ export function ImageEdit( { url = '', alt, caption, - align, id, width, height, sizeSlug, aspectRatio, scale, + align, } = attributes; const [ temporaryURL, setTemporaryURL ] = useState(); @@ -126,6 +124,21 @@ export function ImageEdit( { captionRef.current = caption; }, [ caption ] ); + const { __unstableMarkNextChangeAsNotPersistent } = + useDispatch( blockEditorStore ); + + useEffect( () => { + if ( [ 'wide', 'full' ].includes( align ) ) { + __unstableMarkNextChangeAsNotPersistent(); + setAttributes( { + width: undefined, + height: undefined, + aspectRatio: undefined, + scale: undefined, + } ); + } + }, [ align ] ); + const ref = useRef(); const { imageDefaultSize, mediaUpload } = useSelect( ( select ) => { const { getSettings } = select( blockEditorStore ); @@ -255,16 +268,6 @@ export function ImageEdit( { } } - function updateAlignment( nextAlign ) { - const extraUpdatedAttributes = [ 'wide', 'full' ].includes( nextAlign ) - ? { width: undefined, height: undefined } - : {}; - setAttributes( { - ...extraUpdatedAttributes, - align: nextAlign, - } ); - } - let isTemp = isTemporaryImage( id, url ); // Upload a temporary image on mount. @@ -375,14 +378,6 @@ export function ImageEdit( { clientId={ clientId } blockEditingMode={ blockEditingMode } /> - { ! url && blockEditingMode === 'default' && ( - - - - ) } } onSelect={ onSelectImage } diff --git a/packages/block-library/src/image/edit.native.js b/packages/block-library/src/image/edit.native.js index 804ae9e1671f6..44ebfda67d875 100644 --- a/packages/block-library/src/image/edit.native.js +++ b/packages/block-library/src/image/edit.native.js @@ -44,7 +44,6 @@ import { MEDIA_TYPE_IMAGE, BlockControls, InspectorControls, - BlockAlignmentToolbar, BlockStyles, store as blockEditorStore, blockSettingsScreens, @@ -212,7 +211,6 @@ export class ImageEdit extends Component { this.onSetFeatured = this.onSetFeatured.bind( this ); this.onFocusCaption = this.onFocusCaption.bind( this ); this.onSelectURL = this.onSelectURL.bind( this ); - this.updateAlignment = this.updateAlignment.bind( this ); this.accessibilityLabelCreator = this.accessibilityLabelCreator.bind( this ); this.setMappedAttributes = this.setMappedAttributes.bind( this ); @@ -305,6 +303,20 @@ export class ImageEdit extends Component { this.replacedFeaturedImage = false; setFeaturedImage( id ); } + + const { align } = attributes; + const { __unstableMarkNextChangeAsNotPersistent } = this.props; + + // Update the attributes if the align is wide or full + if ( [ 'wide', 'full' ].includes( align ) ) { + __unstableMarkNextChangeAsNotPersistent(); + setAttributes( { + width: undefined, + height: undefined, + aspectRatio: undefined, + scale: undefined, + } ); + } } static getDerivedStateFromProps( props, state ) { @@ -391,18 +403,6 @@ export class ImageEdit extends Component { } ); } - updateAlignment( nextAlign ) { - const extraUpdatedAttributes = Object.values( - WIDE_ALIGNMENTS.alignments - ).includes( nextAlign ) - ? { width: undefined, height: undefined } - : {}; - this.props.setAttributes( { - ...extraUpdatedAttributes, - align: nextAlign, - } ); - } - onSetNewTab( value ) { const updatedLinkTarget = getUpdatedLinkTargetSettings( value, @@ -711,10 +711,6 @@ export class ImageEdit extends Component { onClick={ open } /> - ); @@ -941,8 +937,11 @@ export default compose( [ } ), withDispatch( ( dispatch ) => { const { createErrorNotice } = dispatch( noticesStore ); + const { __unstableMarkNextChangeAsNotPersistent } = + dispatch( blockEditorStore ); return { + __unstableMarkNextChangeAsNotPersistent, createErrorNotice, closeSettingsBottomSheet() { dispatch( editPostStore ).closeGeneralSidebar(); diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 64eb03adedb32..11d460efd472c 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -25,7 +25,6 @@ import { MediaReplaceFlow, store as blockEditorStore, useSettings, - BlockAlignmentControl, __experimentalImageEditor as ImageEditor, __experimentalGetElementClassName, __experimentalUseBorderProps as useBorderProps, @@ -353,21 +352,6 @@ export default function Image( { } ); } - function updateAlignment( nextAlign ) { - const extraUpdatedAttributes = [ 'wide', 'full' ].includes( nextAlign ) - ? { - width: undefined, - height: undefined, - aspectRatio: undefined, - scale: undefined, - } - : {}; - setAttributes( { - ...extraUpdatedAttributes, - align: nextAlign, - } ); - } - useEffect( () => { if ( ! isSelected ) { setIsEditingImage( false ); @@ -455,12 +439,6 @@ export default function Image( { const controls = ( <> - { hasNonContentControls && ( - - ) } { hasNonContentControls && ( { diff --git a/packages/components/src/mobile/utils/alignments.native.js b/packages/components/src/mobile/utils/alignments.native.js index 98635ea4681ad..bc42385988a5d 100644 --- a/packages/components/src/mobile/utils/alignments.native.js +++ b/packages/components/src/mobile/utils/alignments.native.js @@ -10,6 +10,7 @@ export const WIDE_ALIGNMENTS = { }, excludeBlocks: [ 'core/heading' ], notInnerContainers: [ + 'core/image', 'core/separator', 'core/media-text', 'core/pullquote', diff --git a/test/integration/__snapshots__/blocks-raw-handling.test.js.snap b/test/integration/__snapshots__/blocks-raw-handling.test.js.snap index 32f2dab713766..071870a420817 100644 --- a/test/integration/__snapshots__/blocks-raw-handling.test.js.snap +++ b/test/integration/__snapshots__/blocks-raw-handling.test.js.snap @@ -158,19 +158,19 @@ exports[`rawHandler should convert HTML post to blocks with minimal content chan `; exports[`rawHandler should convert a caption shortcode 1`] = ` -" +"
test
" `; exports[`rawHandler should convert a caption shortcode with caption 1`] = ` -" +"
test
" `; exports[`rawHandler should convert a caption shortcode with link 1`] = ` -" +"
Bell on Wharf
Bell on wharf in San Francisco
" `; diff --git a/test/integration/fixtures/blocks/core__image__center-caption.json b/test/integration/fixtures/blocks/core__image__center-caption.json index a369e433b4028..034047c07089b 100644 --- a/test/integration/fixtures/blocks/core__image__center-caption.json +++ b/test/integration/fixtures/blocks/core__image__center-caption.json @@ -3,10 +3,10 @@ "name": "core/image", "isValid": true, "attributes": { - "align": "center", "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "", - "caption": "Give it a try. Press the \"really wide\" button on the image toolbar." + "caption": "Give it a try. Press the \"really wide\" button on the image toolbar.", + "align": "center" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html index 9a66da6c01898..c03189e9b456c 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html @@ -1,3 +1,3 @@ - +
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html index 9a66da6c01898..c03189e9b456c 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html @@ -1,3 +1,3 @@ - +
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html index 99da2155bce88..b9e58cc24fddb 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html @@ -1,3 +1,3 @@ - +
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html index 807ba3abc9f9c..57545968847e1 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html @@ -1,3 +1,3 @@ - +
diff --git a/test/integration/fixtures/documents/wordpress-out.html b/test/integration/fixtures/documents/wordpress-out.html index c394fa232081d..a0ac4b89ec552 100644 --- a/test/integration/fixtures/documents/wordpress-out.html +++ b/test/integration/fixtures/documents/wordpress-out.html @@ -28,7 +28,7 @@

Shortcode

- +
From 77d0226badb0769b12e28b19fb439cf6777b672a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20K=C3=A4gy?= Date: Wed, 22 Nov 2023 12:53:32 +0100 Subject: [PATCH 116/116] fix remove removal version from deprecated prop (#56336) --- packages/components/src/angle-picker-control/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/components/src/angle-picker-control/index.tsx b/packages/components/src/angle-picker-control/index.tsx index f90394b12078f..06178e0b40101 100644 --- a/packages/components/src/angle-picker-control/index.tsx +++ b/packages/components/src/angle-picker-control/index.tsx @@ -41,7 +41,6 @@ function UnforwardedAnglePickerControl( 'Bottom margin styles for wp.components.AnglePickerControl', { since: '6.1', - version: '6.4', hint: 'Set the `__nextHasNoMarginBottom` prop to true to start opting into the new styles, which will become the default in a future version.', } );