@salla.sa/twilight-theme-engine 1.0.124 → 1.0.126
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AddToCartForm-7C5NJOT3.js → AddToCartForm-BY24SGTR.js} +3 -3
- package/dist/{AddToCartForm-7C5NJOT3.js.map → AddToCartForm-BY24SGTR.js.map} +1 -1
- package/dist/{BlogAuthorPage-T5AQINIT.js → BlogAuthorPage-UAQ6266M.js} +17 -17
- package/dist/{BlogAuthorPage-T5AQINIT.js.map → BlogAuthorPage-UAQ6266M.js.map} +1 -1
- package/dist/{BlogCategoryPage-NNDOLC3G.js → BlogCategoryPage-UX5OZZRZ.js} +17 -17
- package/dist/{BlogCategoryPage-NNDOLC3G.js.map → BlogCategoryPage-UX5OZZRZ.js.map} +1 -1
- package/dist/{BlogPage-F52ASL2W.js → BlogPage-AAITQ3UZ.js} +15 -15
- package/dist/{BlogPage-F52ASL2W.js.map → BlogPage-AAITQ3UZ.js.map} +1 -1
- package/dist/{BlogSinglePage-33OTX2SH.js → BlogSinglePage-R7VG3WNP.js} +15 -15
- package/dist/{BlogSinglePage-33OTX2SH.js.map → BlogSinglePage-R7VG3WNP.js.map} +1 -1
- package/dist/{BlogTagPage-DOTS5CLM.js → BlogTagPage-YCJL3FNS.js} +17 -17
- package/dist/{BlogTagPage-DOTS5CLM.js.map → BlogTagPage-YCJL3FNS.js.map} +1 -1
- package/dist/{BrandsPage-R5DRBHNZ.js → BrandsPage-4M4J7YH5.js} +16 -16
- package/dist/{BrandsPage-R5DRBHNZ.js.map → BrandsPage-4M4J7YH5.js.map} +1 -1
- package/dist/{Breadcrumb-4YXIEAFY.js → Breadcrumb-WB5NXLLA.js} +15 -15
- package/dist/{Breadcrumb-4YXIEAFY.js.map → Breadcrumb-WB5NXLLA.js.map} +1 -1
- package/dist/{CartItem-KMQJU6BO.js → CartItem-UWCMEGW7.js} +15 -15
- package/dist/{CartItem-KMQJU6BO.js.map → CartItem-UWCMEGW7.js.map} +1 -1
- package/dist/{CartSummary-EW6Q6JS7.js → CartSummary-TK55II7A.js} +15 -15
- package/dist/{CartSummary-EW6Q6JS7.js.map → CartSummary-TK55II7A.js.map} +1 -1
- package/dist/{Copyright-AVJL3KJR.js → Copyright-PHLEOCO4.js} +3 -3
- package/dist/{Copyright-AVJL3KJR.js.map → Copyright-PHLEOCO4.js.map} +1 -1
- package/dist/{CustomerLayout-5343GESW.js → CustomerLayout-BCTFI56B.js} +15 -15
- package/dist/{CustomerLayout-5343GESW.js.map → CustomerLayout-BCTFI56B.js.map} +1 -1
- package/dist/{Footer-ODWJ3HQH.js → Footer-AXIXSATN.js} +4 -4
- package/dist/{Footer-ODWJ3HQH.js.map → Footer-AXIXSATN.js.map} +1 -1
- package/dist/{Header-VQJILH5R.js → Header-5GD53HC5.js} +8 -8
- package/dist/{Header-VQJILH5R.js.map → Header-5GD53HC5.js.map} +1 -1
- package/dist/{LiveEditorBar-WSASAFCL.js → LiveEditorBar-IQLFFBHE.js} +38 -11
- package/dist/LiveEditorBar-IQLFFBHE.js.map +1 -0
- package/dist/{LoyaltyPage-HDEWDV6M.js → LoyaltyPage-MBYLZF7B.js} +15 -15
- package/dist/{LoyaltyPage-HDEWDV6M.js.map → LoyaltyPage-MBYLZF7B.js.map} +1 -1
- package/dist/{LoyaltyPointsPage-5ZML2PHB.js → LoyaltyPointsPage-SFAL3TOO.js} +6 -6
- package/dist/{LoyaltyPointsPage-5ZML2PHB.js.map → LoyaltyPointsPage-SFAL3TOO.js.map} +1 -1
- package/dist/{MainMenu-YTGZSTRC.js → MainMenu-VEZTUNCZ.js} +5 -5
- package/dist/{MainMenu-YTGZSTRC.js.map → MainMenu-VEZTUNCZ.js.map} +1 -1
- package/dist/{MasterLayout-ITSFTBZD.js → MasterLayout-TFHNWIRE.js} +15 -15
- package/dist/{MasterLayout-ITSFTBZD.js.map → MasterLayout-TFHNWIRE.js.map} +1 -1
- package/dist/{MobileMenu-FJTSMNGS.js → MobileMenu-JWD22FVU.js} +16 -16
- package/dist/{MobileMenu-FJTSMNGS.js.map → MobileMenu-JWD22FVU.js.map} +1 -1
- package/dist/{NotificationsPage-EVQ7KTKD.js → NotificationsPage-QVE7AOCV.js} +15 -15
- package/dist/{NotificationsPage-EVQ7KTKD.js.map → NotificationsPage-QVE7AOCV.js.map} +1 -1
- package/dist/{OrderSinglePage-IJQ2BW6N.js → OrderSinglePage-QSNZVQ22.js} +16 -16
- package/dist/{OrderSinglePage-IJQ2BW6N.js.map → OrderSinglePage-QSNZVQ22.js.map} +1 -1
- package/dist/{OrdersPage-5PW3D7NP.js → OrdersPage-WGIHZJNJ.js} +15 -15
- package/dist/{OrdersPage-5PW3D7NP.js.map → OrdersPage-WGIHZJNJ.js.map} +1 -1
- package/dist/{PageSingle-DQA45NP5.js → PageSingle-3HXGOYLZ.js} +3 -3
- package/dist/{PageSingle-DQA45NP5.js.map → PageSingle-3HXGOYLZ.js.map} +1 -1
- package/dist/{ProductDetails-IAJZJOPE.js → ProductDetails-ALVRCBP4.js} +4 -4
- package/dist/{ProductDetails-IAJZJOPE.js.map → ProductDetails-ALVRCBP4.js.map} +1 -1
- package/dist/{ProfilePage-7SEMN3OY.js → ProfilePage-AVJYAQOG.js} +15 -15
- package/dist/{ProfilePage-7SEMN3OY.js.map → ProfilePage-AVJYAQOG.js.map} +1 -1
- package/dist/{ReviewsPage-HEC24XWB.js → ReviewsPage-ULGQMLGH.js} +3 -3
- package/dist/{ReviewsPage-HEC24XWB.js.map → ReviewsPage-ULGQMLGH.js.map} +1 -1
- package/dist/{SeoCartWidget-VZ2VAKQ6.js → SeoCartWidget-5WY6AV2F.js} +15 -15
- package/dist/{SeoCartWidget-VZ2VAKQ6.js.map → SeoCartWidget-5WY6AV2F.js.map} +1 -1
- package/dist/{SettingsPage-7N2V7IXZ.js → SettingsPage-ZHTSKKBD.js} +15 -15
- package/dist/{SettingsPage-7N2V7IXZ.js.map → SettingsPage-ZHTSKKBD.js.map} +1 -1
- package/dist/{StoreClosedNotification-XMX4T26T.js → StoreClosedNotification-5V7QGKMC.js} +16 -16
- package/dist/{StoreClosedNotification-XMX4T26T.js.map → StoreClosedNotification-5V7QGKMC.js.map} +1 -1
- package/dist/{TestimonialsPage-TD7G4REM.js → TestimonialsPage-7YS7QRTY.js} +3 -3
- package/dist/{TestimonialsPage-TD7G4REM.js.map → TestimonialsPage-7YS7QRTY.js.map} +1 -1
- package/dist/{ThankYouPage-23Y5VNJL.js → ThankYouPage-PLCUI7LC.js} +15 -15
- package/dist/{ThankYouPage-23Y5VNJL.js.map → ThankYouPage-PLCUI7LC.js.map} +1 -1
- package/dist/{WalletPage-QOEE4C73.js → WalletPage-C6ZFJTSA.js} +16 -16
- package/dist/{WalletPage-QOEE4C73.js.map → WalletPage-C6ZFJTSA.js.map} +1 -1
- package/dist/{WishlistPage-YTN4SYZA.js → WishlistPage-3CIW7AIZ.js} +17 -17
- package/dist/{WishlistPage-YTN4SYZA.js.map → WishlistPage-3CIW7AIZ.js.map} +1 -1
- package/dist/api/advertisement.js +2 -2
- package/dist/api/apps.js +2 -2
- package/dist/api/blog.js +3 -3
- package/dist/api/brands.js +3 -3
- package/dist/api/cart.js +3 -3
- package/dist/api/category.js +3 -3
- package/dist/api/client.js +1 -1
- package/dist/api/home.js +2 -2
- package/dist/api/loyalty.js +3 -3
- package/dist/api/menu.js +2 -2
- package/dist/api/notification.js +2 -2
- package/dist/api/order.js +3 -3
- package/dist/api/page.js +3 -3
- package/dist/api/product.js +3 -3
- package/dist/api/profile.js +1 -1
- package/dist/api/store.js +2 -2
- package/dist/api/translations.js +2 -2
- package/dist/api/user.js +2 -2
- package/dist/api/wallet.js +2 -2
- package/dist/api/wishlist.js +4 -4
- package/dist/{chunk-IFPTZL77.js → chunk-47BPYZJF.js} +3 -3
- package/dist/{chunk-IFPTZL77.js.map → chunk-47BPYZJF.js.map} +1 -1
- package/dist/{chunk-N4M5Y3CH.js → chunk-4C76FZV4.js} +4 -4
- package/dist/{chunk-N4M5Y3CH.js.map → chunk-4C76FZV4.js.map} +1 -1
- package/dist/{chunk-ZHW5KZJM.js → chunk-4VYKXIYA.js} +12 -8
- package/dist/chunk-4VYKXIYA.js.map +1 -0
- package/dist/{chunk-E5JIVIBY.js → chunk-4ZYJDSYQ.js} +3 -3
- package/dist/{chunk-E5JIVIBY.js.map → chunk-4ZYJDSYQ.js.map} +1 -1
- package/dist/{chunk-XO4S6BKT.js → chunk-53IXPTVY.js} +4 -4
- package/dist/{chunk-XO4S6BKT.js.map → chunk-53IXPTVY.js.map} +1 -1
- package/dist/{chunk-WNV73ZFT.js → chunk-5LP2K2J7.js} +3 -3
- package/dist/{chunk-WNV73ZFT.js.map → chunk-5LP2K2J7.js.map} +1 -1
- package/dist/{chunk-AS4A6I5D.js → chunk-5SJRY6P3.js} +4 -4
- package/dist/{chunk-AS4A6I5D.js.map → chunk-5SJRY6P3.js.map} +1 -1
- package/dist/{chunk-I44YRS6T.js → chunk-6PK4GITC.js} +3 -3
- package/dist/{chunk-I44YRS6T.js.map → chunk-6PK4GITC.js.map} +1 -1
- package/dist/{chunk-RMKB3MJS.js → chunk-75STIRBZ.js} +4 -4
- package/dist/{chunk-RMKB3MJS.js.map → chunk-75STIRBZ.js.map} +1 -1
- package/dist/{chunk-6MF7FWER.js → chunk-A6AAG7U6.js} +4 -4
- package/dist/{chunk-6MF7FWER.js.map → chunk-A6AAG7U6.js.map} +1 -1
- package/dist/{chunk-Z3MSALIT.js → chunk-A6IKHCIA.js} +4 -4
- package/dist/{chunk-Z3MSALIT.js.map → chunk-A6IKHCIA.js.map} +1 -1
- package/dist/{chunk-XAG4TLX4.js → chunk-ANLG2WBG.js} +4 -4
- package/dist/{chunk-XAG4TLX4.js.map → chunk-ANLG2WBG.js.map} +1 -1
- package/dist/{chunk-NPSABKKR.js → chunk-BWTUGXHI.js} +5 -5
- package/dist/{chunk-NPSABKKR.js.map → chunk-BWTUGXHI.js.map} +1 -1
- package/dist/{chunk-DRV4QRIS.js → chunk-CKH5HDHS.js} +4 -4
- package/dist/{chunk-DRV4QRIS.js.map → chunk-CKH5HDHS.js.map} +1 -1
- package/dist/{chunk-5EKTGKJY.js → chunk-FN2GQ2B5.js} +3 -3
- package/dist/{chunk-5EKTGKJY.js.map → chunk-FN2GQ2B5.js.map} +1 -1
- package/dist/{chunk-7NOGCBED.js → chunk-GHLPK63Q.js} +7 -7
- package/dist/{chunk-7NOGCBED.js.map → chunk-GHLPK63Q.js.map} +1 -1
- package/dist/{chunk-J52AQPKU.js → chunk-GLE6TNJ3.js} +3 -3
- package/dist/{chunk-J52AQPKU.js.map → chunk-GLE6TNJ3.js.map} +1 -1
- package/dist/{chunk-PNAWYJP2.js → chunk-HFCZIPYO.js} +3 -3
- package/dist/{chunk-PNAWYJP2.js.map → chunk-HFCZIPYO.js.map} +1 -1
- package/dist/{chunk-PCGKPANV.js → chunk-IGGIH6GL.js} +3 -3
- package/dist/{chunk-PCGKPANV.js.map → chunk-IGGIH6GL.js.map} +1 -1
- package/dist/{chunk-2QJXTJCF.js → chunk-IM5NMPNU.js} +7 -7
- package/dist/{chunk-2QJXTJCF.js.map → chunk-IM5NMPNU.js.map} +1 -1
- package/dist/{chunk-VEY7PJK7.js → chunk-JAKLD546.js} +3 -3
- package/dist/{chunk-VEY7PJK7.js.map → chunk-JAKLD546.js.map} +1 -1
- package/dist/{chunk-TLH4C6H4.js → chunk-JL7MKSCD.js} +10 -10
- package/dist/{chunk-TLH4C6H4.js.map → chunk-JL7MKSCD.js.map} +1 -1
- package/dist/{chunk-R2LXUFTW.js → chunk-KDV6WZYJ.js} +3 -3
- package/dist/{chunk-R2LXUFTW.js.map → chunk-KDV6WZYJ.js.map} +1 -1
- package/dist/{chunk-CDLT7UJB.js → chunk-KEOCLT62.js} +3 -3
- package/dist/{chunk-CDLT7UJB.js.map → chunk-KEOCLT62.js.map} +1 -1
- package/dist/{chunk-N7EFUGP4.js → chunk-KKOFHYTI.js} +3 -3
- package/dist/{chunk-N7EFUGP4.js.map → chunk-KKOFHYTI.js.map} +1 -1
- package/dist/{chunk-4HV2MRZD.js → chunk-LWPIGNCW.js} +4 -4
- package/dist/{chunk-4HV2MRZD.js.map → chunk-LWPIGNCW.js.map} +1 -1
- package/dist/{chunk-EFMAJAIS.js → chunk-MHLKLADI.js} +3 -3
- package/dist/{chunk-EFMAJAIS.js.map → chunk-MHLKLADI.js.map} +1 -1
- package/dist/{chunk-PDIFXQDX.js → chunk-MVNWWZWQ.js} +23 -4
- package/dist/chunk-MVNWWZWQ.js.map +1 -0
- package/dist/{chunk-XCIMWJ7P.js → chunk-NHJ5U6WK.js} +3 -3
- package/dist/{chunk-XCIMWJ7P.js.map → chunk-NHJ5U6WK.js.map} +1 -1
- package/dist/{chunk-IIVUBE4K.js → chunk-R2FXTCRK.js} +23 -22
- package/dist/chunk-R2FXTCRK.js.map +1 -0
- package/dist/{chunk-ICKIPKCC.js → chunk-RE4QQM4Q.js} +3 -3
- package/dist/{chunk-ICKIPKCC.js.map → chunk-RE4QQM4Q.js.map} +1 -1
- package/dist/{chunk-QUDLGIR6.js → chunk-SGET4UYI.js} +3 -3
- package/dist/{chunk-QUDLGIR6.js.map → chunk-SGET4UYI.js.map} +1 -1
- package/dist/{chunk-MHBBN7O6.js → chunk-TCRZSLXH.js} +6 -6
- package/dist/{chunk-MHBBN7O6.js.map → chunk-TCRZSLXH.js.map} +1 -1
- package/dist/{chunk-JN4EYPHY.js → chunk-TNUK62YF.js} +4 -4
- package/dist/{chunk-JN4EYPHY.js.map → chunk-TNUK62YF.js.map} +1 -1
- package/dist/chunk-UE65NYZF.js +14 -0
- package/dist/{chunk-QTTABDVW.js.map → chunk-UE65NYZF.js.map} +1 -1
- package/dist/{chunk-COF5OFQX.js → chunk-UHCNMJDI.js} +7 -7
- package/dist/{chunk-COF5OFQX.js.map → chunk-UHCNMJDI.js.map} +1 -1
- package/dist/{chunk-3EYNFA67.js → chunk-WBDU6KDP.js} +4 -4
- package/dist/{chunk-3EYNFA67.js.map → chunk-WBDU6KDP.js.map} +1 -1
- package/dist/{chunk-74EGP2KE.js → chunk-WFSKX5AI.js} +3 -3
- package/dist/{chunk-74EGP2KE.js.map → chunk-WFSKX5AI.js.map} +1 -1
- package/dist/{chunk-K5TWJICH.js → chunk-XRDQAJW5.js} +3 -3
- package/dist/{chunk-K5TWJICH.js.map → chunk-XRDQAJW5.js.map} +1 -1
- package/dist/{chunk-4SKMLRLX.js → chunk-Z76YTG4W.js} +3 -3
- package/dist/{chunk-4SKMLRLX.js.map → chunk-Z76YTG4W.js.map} +1 -1
- package/dist/components/cart/index.js +1 -1
- package/dist/components/common/index.js +1 -1
- package/dist/components/drawer/index.js +13 -13
- package/dist/components/home/HomePageRenderer.d.ts.map +1 -1
- package/dist/components/home/index.js +17 -17
- package/dist/components/layout/index.js +4 -4
- package/dist/components/live-editor/LiveEditorBar.d.ts +5 -1
- package/dist/components/live-editor/LiveEditorBar.d.ts.map +1 -1
- package/dist/components/live-editor/frame.d.ts +7 -0
- package/dist/components/live-editor/frame.d.ts.map +1 -1
- package/dist/components/live-editor/index.d.ts.map +1 -1
- package/dist/components/product/index.js +14 -14
- package/dist/components/store/index.js +14 -14
- package/dist/dev/editor/ThemeEditor.d.ts.map +1 -1
- package/dist/dev/editor/index.js +108 -26
- package/dist/dev/editor/index.js.map +1 -1
- package/dist/dev/editor/live-actions.d.ts +19 -0
- package/dist/dev/editor/live-actions.d.ts.map +1 -0
- package/dist/dev/index.js +1 -1
- package/dist/{document-class-QZGAXN2W.js → document-class-P2H6HKXA.js} +11 -11
- package/dist/{document-class-QZGAXN2W.js.map → document-class-P2H6HKXA.js.map} +1 -1
- package/dist/hooks/index.js +13 -13
- package/dist/hooks/useGtm.js +13 -13
- package/dist/hooks/useMoney.js +13 -13
- package/dist/hooks/useStore.js +13 -13
- package/dist/hooks/useUser.js +3 -3
- package/dist/index.js +13 -13
- package/dist/{navigation-3SFDZIDH.js → navigation-4STP3ZMK.js} +4 -4
- package/dist/{navigation-3SFDZIDH.js.map → navigation-4STP3ZMK.js.map} +1 -1
- package/dist/{navigation-WAAWAQV2.js → navigation-6Y2SKWH3.js} +5 -5
- package/dist/{navigation-WAAWAQV2.js.map → navigation-6Y2SKWH3.js.map} +1 -1
- package/dist/{not-found-DJOWWOUH.js → not-found-LLCXGKVS.js} +16 -16
- package/dist/{not-found-DJOWWOUH.js.map → not-found-LLCXGKVS.js.map} +1 -1
- package/dist/providers/index.js +13 -13
- package/dist/routes/account/orders.js +4 -4
- package/dist/routes/account.js +13 -13
- package/dist/routes/blog.js +8 -8
- package/dist/routes/brands.js +4 -4
- package/dist/routes/cart.js +21 -21
- package/dist/routes/home.js +18 -18
- package/dist/routes/index.js +3 -3
- package/dist/routes/loyalty.js +5 -5
- package/dist/routes/page.js +4 -4
- package/dist/routes/product-listing.js +19 -19
- package/dist/routes/product.js +17 -17
- package/dist/routes/seo-redirects.js +3 -3
- package/dist/routes/testimonials.js +2 -2
- package/dist/routes/thank-you.js +4 -4
- package/dist/skeleton.js +18 -18
- package/dist/{store-lookup-UONSSGJ3.js → store-lookup-XKL42Y4H.js} +8 -8
- package/dist/{store-lookup-UONSSGJ3.js.map → store-lookup-XKL42Y4H.js.map} +1 -1
- package/dist/tanstack.js +11 -11
- package/dist/utils/index.js +2 -2
- package/package.json +1 -1
- package/tailwind/components/home/HomePageRenderer.tsx.txt +13 -6
- package/tailwind/components/live-editor/LiveEditorBar.tsx.txt +51 -8
- package/tailwind/components/live-editor/frame.ts.txt +34 -1
- package/tailwind/components/live-editor/index.tsx.txt +9 -7
- package/dist/LiveEditorBar-WSASAFCL.js.map +0 -1
- package/dist/chunk-IIVUBE4K.js.map +0 -1
- package/dist/chunk-PDIFXQDX.js.map +0 -1
- package/dist/chunk-QTTABDVW.js +0 -14
- package/dist/chunk-ZHW5KZJM.js.map +0 -1
package/dist/tanstack.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
export { tanstackDocumentAdapter as attrs, createRouter, createTwilightRootRoute, useTanstackDocumentAttrs as useAttrs } from './chunk-
|
|
2
|
-
import { requestHostOf } from './chunk-
|
|
3
|
-
export { TanStackLinkAdapter, TanStackNavigationProvider, createTanStackLinkAdapter } from './chunk-
|
|
1
|
+
export { tanstackDocumentAdapter as attrs, createRouter, createTwilightRootRoute, useTanstackDocumentAttrs as useAttrs } from './chunk-JL7MKSCD.js';
|
|
2
|
+
import { requestHostOf } from './chunk-47BPYZJF.js';
|
|
3
|
+
export { TanStackLinkAdapter, TanStackNavigationProvider, createTanStackLinkAdapter } from './chunk-47BPYZJF.js';
|
|
4
4
|
import './chunk-Z4Y55HWX.js';
|
|
5
5
|
export { tanstackHeadAdapter as head, withHead } from './chunk-EHTLXK5F.js';
|
|
6
6
|
import { CRITICAL_STYLE_HREF } from './chunk-4FJGZQD3.js';
|
|
7
|
-
import './chunk-
|
|
8
|
-
import { readNativeAppHeaders } from './chunk-
|
|
9
|
-
import './chunk-
|
|
10
|
-
import './chunk-
|
|
7
|
+
import './chunk-IGGIH6GL.js';
|
|
8
|
+
import { readNativeAppHeaders } from './chunk-KEOCLT62.js';
|
|
9
|
+
import './chunk-KDV6WZYJ.js';
|
|
10
|
+
import './chunk-TNUK62YF.js';
|
|
11
11
|
import { rootHead, maintenanceEvidence, MAINTENANCE_EVIDENCE_HEADER, maintenanceEvidenceHeader } from './chunk-KQEBYXYB.js';
|
|
12
12
|
import './chunk-JYV25VNZ.js';
|
|
13
|
-
import './chunk-
|
|
13
|
+
import './chunk-RE4QQM4Q.js';
|
|
14
14
|
import './chunk-5FJFN3IW.js';
|
|
15
15
|
import './chunk-GD26FI4J.js';
|
|
16
16
|
import './chunk-OM2GRPDH.js';
|
|
17
|
-
import './chunk-
|
|
17
|
+
import './chunk-GLE6TNJ3.js';
|
|
18
18
|
import './chunk-OUW6WESU.js';
|
|
19
19
|
import './chunk-JWXJPJBO.js';
|
|
20
20
|
export { mergeDocumentDescriptors as mergeAttrs } from './chunk-CW625T2E.js';
|
|
21
|
-
import './chunk-
|
|
22
|
-
import './chunk-
|
|
21
|
+
import './chunk-FN2GQ2B5.js';
|
|
22
|
+
import './chunk-5LP2K2J7.js';
|
|
23
23
|
import './chunk-TYNZ5B2B.js';
|
|
24
24
|
import './chunk-BYMOPN2S.js';
|
|
25
25
|
import './chunk-2TLIULJZ.js';
|
package/dist/utils/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { stripUnsafeHtml } from '../chunk-RUHSV4Z6.js';
|
|
2
2
|
export { formatSallaPlural } from '../chunk-BT6HEEAP.js';
|
|
3
|
-
export { dispatchRouteChanged } from '../chunk-
|
|
3
|
+
export { dispatchRouteChanged } from '../chunk-IGGIH6GL.js';
|
|
4
4
|
export { sortOptions } from '../chunk-3LZJXKVO.js';
|
|
5
5
|
export { color } from '../chunk-VVZNW5CB.js';
|
|
6
6
|
export { applyAppScopeMocks, registerThemeHookSlots } from '../chunk-5FJFN3IW.js';
|
|
@@ -8,7 +8,7 @@ export { mergeHead, resolveHead, setHeadAdapter } from '../chunk-GD26FI4J.js';
|
|
|
8
8
|
export { buildBaseHead, buildHreflangAlternates, localeToOgLocale } from '../chunk-OM2GRPDH.js';
|
|
9
9
|
export { asset, cdn, isPlaceholder } from '../chunk-ZCH7W7DZ.js';
|
|
10
10
|
export { mergeDocumentDescriptors, mergeElementAttrs, normalizeClasses, syncAttrsToElement, toReactProps } from '../chunk-CW625T2E.js';
|
|
11
|
-
import '../chunk-
|
|
11
|
+
import '../chunk-5LP2K2J7.js';
|
|
12
12
|
export { getSallaSDK, getStoreIdentifier, onSallaEvent, whenSallaLoaded, whenSallaReady } from '../chunk-GYXUYHKO.js';
|
|
13
13
|
export { AUTH_TOKEN_COOKIE_NAME, clearAuthTokenCookie, extractTokenFromCookies } from '../chunk-FHU2MXZA.js';
|
|
14
14
|
import '../chunk-7VNVCHID.js';
|
package/package.json
CHANGED
|
@@ -205,6 +205,18 @@ function resolveComponentConfig(path: string): HomeComponentConfig | undefined {
|
|
|
205
205
|
return themeComponentConfig[path] ?? COMPONENT_CONFIG[path];
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
/**
|
|
209
|
+
* What the theme editor addresses a block by: the dev editor's layout id (less
|
|
210
|
+
* the remount suffix), its row id, or the uuid of one not saved yet. The layout
|
|
211
|
+
* id comes first: a customized layout keeps the store blocks' row ids among
|
|
212
|
+
* their fields, and duplicates share them.
|
|
213
|
+
*/
|
|
214
|
+
function liveBlockIdOf(data: HomeComponentData): string | undefined {
|
|
215
|
+
const devId = typeof data.__dev_id === 'string' ? data.__dev_id.replace(/~\d+$/, '') : undefined;
|
|
216
|
+
const id = devId ?? data.id ?? data.key;
|
|
217
|
+
return typeof id === 'number' || (typeof id === 'string' && id) ? String(id) : undefined;
|
|
218
|
+
}
|
|
219
|
+
|
|
208
220
|
/**
|
|
209
221
|
* Memoized component renderer with scroll-based lazy loading
|
|
210
222
|
* Components only mount when scrolled into view - preventing API calls until needed
|
|
@@ -253,12 +265,7 @@ export const HomeComponentRenderer = memo(function HomeComponentRenderer({
|
|
|
253
265
|
? config.id(data)
|
|
254
266
|
: config.id
|
|
255
267
|
: undefined;
|
|
256
|
-
|
|
257
|
-
const blockId = data.id ?? data.key;
|
|
258
|
-
const liveBlockId =
|
|
259
|
-
typeof blockId === 'number' || (typeof blockId === 'string' && blockId)
|
|
260
|
-
? String(blockId)
|
|
261
|
-
: undefined;
|
|
268
|
+
const liveBlockId = liveBlockIdOf(data);
|
|
262
269
|
const height = config?.height || '400px';
|
|
263
270
|
// A theme's config replaces the engine's, but keeps its mount timing unless the theme sets one.
|
|
264
271
|
const renderOnMount = config?.renderOnMount ?? COMPONENT_CONFIG[data.path]?.renderOnMount;
|
|
@@ -55,6 +55,8 @@ const BLOCK_ACTIONS: BlockAction[] = [
|
|
|
55
55
|
'delete',
|
|
56
56
|
];
|
|
57
57
|
|
|
58
|
+
const DEV_ACTIONS = BLOCK_ACTIONS.filter((action) => action !== 'hide');
|
|
59
|
+
|
|
58
60
|
/** Lucide-style 24px stroke icons. */
|
|
59
61
|
const ICONS: Record<BlockAction, ReactElement> = {
|
|
60
62
|
edit: (
|
|
@@ -172,6 +174,29 @@ function connected(el: HTMLElement | null): HTMLElement | null {
|
|
|
172
174
|
}
|
|
173
175
|
|
|
174
176
|
/** Re-renders on scroll, resize and layout shifts, so the overlay follows what it outlines. */
|
|
177
|
+
interface Box {
|
|
178
|
+
top: number;
|
|
179
|
+
left: number;
|
|
180
|
+
width: number;
|
|
181
|
+
height: number;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Where `el` is on screen. One with no box of its own (`display: contents`, as
|
|
186
|
+
* Raed's header) measures 0×0 at the corner, so it's measured by its children.
|
|
187
|
+
*/
|
|
188
|
+
function boxOf(el: Element): Box {
|
|
189
|
+
const rect = el.getBoundingClientRect();
|
|
190
|
+
if (rect.width || rect.height) return rect;
|
|
191
|
+
const boxes = Array.from(el.children, boxOf).filter((box) => box.width || box.height);
|
|
192
|
+
if (!boxes.length) return rect;
|
|
193
|
+
const top = Math.min(...boxes.map((box) => box.top));
|
|
194
|
+
const left = Math.min(...boxes.map((box) => box.left));
|
|
195
|
+
const right = Math.max(...boxes.map((box) => box.left + box.width));
|
|
196
|
+
const bottom = Math.max(...boxes.map((box) => box.top + box.height));
|
|
197
|
+
return { top, left, width: right - left, height: bottom - top };
|
|
198
|
+
}
|
|
199
|
+
|
|
175
200
|
function useLayoutTick(active: boolean): void {
|
|
176
201
|
const [, setTick] = useState(0);
|
|
177
202
|
useEffect(() => {
|
|
@@ -253,7 +278,7 @@ function useHeldLinkClicks(barRef: RefObject<HTMLDivElement | null>): void {
|
|
|
253
278
|
}
|
|
254
279
|
|
|
255
280
|
function Outline({ el, label }: { el: HTMLElement; label?: string }) {
|
|
256
|
-
const rect = el
|
|
281
|
+
const rect = boxOf(el);
|
|
257
282
|
return (
|
|
258
283
|
<div
|
|
259
284
|
data-testid="live-editor-outline"
|
|
@@ -269,12 +294,13 @@ interface ToolbarProps {
|
|
|
269
294
|
labels: Labels;
|
|
270
295
|
busy: BlockAction | null;
|
|
271
296
|
barRef: RefObject<HTMLDivElement | null>;
|
|
297
|
+
actions: BlockAction[];
|
|
272
298
|
onAct: (el: HTMLElement, action: BlockAction) => void;
|
|
273
299
|
}
|
|
274
300
|
|
|
275
301
|
/** One edit button for the header or footer; the full set for a block. */
|
|
276
|
-
function Toolbar({ target, labels, busy, barRef, onAct }: ToolbarProps) {
|
|
277
|
-
const rect = target
|
|
302
|
+
function Toolbar({ target, labels, busy, barRef, actions, onAct }: ToolbarProps) {
|
|
303
|
+
const rect = boxOf(target);
|
|
278
304
|
const style: CSSProperties = {
|
|
279
305
|
...BAR,
|
|
280
306
|
top: Math.max(rect.top + 8, 8),
|
|
@@ -312,7 +338,7 @@ function Toolbar({ target, labels, busy, barRef, onAct }: ToolbarProps) {
|
|
|
312
338
|
aria-label={labels.edit}
|
|
313
339
|
style={style}
|
|
314
340
|
>
|
|
315
|
-
{
|
|
341
|
+
{actions.map((action) => (
|
|
316
342
|
<button
|
|
317
343
|
key={action}
|
|
318
344
|
type="button"
|
|
@@ -348,8 +374,17 @@ function blockRefOf(el: HTMLElement, id: string): { id: string; copy?: number }
|
|
|
348
374
|
* edit, hide, move, duplicate, add and delete; hovering the header or footer
|
|
349
375
|
* shows an edit button. Double-clicking either edits it. Each action is a
|
|
350
376
|
* message to the editor, which saves the change and reloads the preview.
|
|
377
|
+
*
|
|
378
|
+
* In the engine's dev editor (`dev`) edits reach the page live, so nothing
|
|
379
|
+
* waits for a reload, and there is no hide: its layout has no hidden blocks.
|
|
351
380
|
*/
|
|
352
|
-
export function LiveEditorBar({
|
|
381
|
+
export function LiveEditorBar({
|
|
382
|
+
origin,
|
|
383
|
+
dev = false,
|
|
384
|
+
}: {
|
|
385
|
+
origin: string;
|
|
386
|
+
dev?: boolean;
|
|
387
|
+
}): ReactElement | null {
|
|
353
388
|
const [hovered, setHovered] = useState<HTMLElement | null>(null);
|
|
354
389
|
const [editing, setEditing] = useState<HTMLElement | null>(null);
|
|
355
390
|
const [busy, setBusy] = useState<BlockAction | null>(null);
|
|
@@ -371,9 +406,10 @@ export function LiveEditorBar({ origin }: { origin: string }): ReactElement | nu
|
|
|
371
406
|
if (!id) return;
|
|
372
407
|
postToEditor(origin, `preview::${action}.component`, blockRefOf(el, id));
|
|
373
408
|
if (action === 'edit') setEditing(el);
|
|
374
|
-
else if (action === 'hide' || action === 'duplicate' || action === 'delete')
|
|
409
|
+
else if (!dev && (action === 'hide' || action === 'duplicate' || action === 'delete'))
|
|
410
|
+
setBusy(action);
|
|
375
411
|
},
|
|
376
|
-
[origin]
|
|
412
|
+
[origin, dev]
|
|
377
413
|
);
|
|
378
414
|
|
|
379
415
|
useEffect(() => {
|
|
@@ -421,7 +457,14 @@ export function LiveEditorBar({ origin }: { origin: string }): ReactElement | nu
|
|
|
421
457
|
{selected && selected !== target && <Outline el={selected} />}
|
|
422
458
|
{target && <Outline el={target} label={targetArea ? labels[targetArea] : undefined} />}
|
|
423
459
|
{target && (
|
|
424
|
-
<Toolbar
|
|
460
|
+
<Toolbar
|
|
461
|
+
target={target}
|
|
462
|
+
labels={labels}
|
|
463
|
+
busy={busy}
|
|
464
|
+
barRef={barRef}
|
|
465
|
+
actions={dev ? DEV_ACTIONS : BLOCK_ACTIONS}
|
|
466
|
+
onAct={act}
|
|
467
|
+
/>
|
|
425
468
|
)}
|
|
426
469
|
</>,
|
|
427
470
|
host
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* protocol the twig themes' `live-themes-editor.js` speaks.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { isEditorFrame } from '../../dev/schema-types';
|
|
9
|
+
|
|
8
10
|
/** Where the theme editor runs. Messages go to the one that framed the page, never to `*`. */
|
|
9
11
|
export const EDITOR_ORIGINS = [
|
|
10
12
|
'https://s.salla.sa',
|
|
@@ -47,6 +49,21 @@ function parentOrigin(): string | null {
|
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
|
|
52
|
+
/**
|
|
53
|
+
* On a dev server, a page on another localhost port (an editor run locally, or
|
|
54
|
+
* a test harness) can frame the store too. Not its own origin: that is the
|
|
55
|
+
* engine's dev editor, which has its own controls.
|
|
56
|
+
*/
|
|
57
|
+
function isLocalEditor(origin: string): boolean {
|
|
58
|
+
if (origin === window.location.origin) return false;
|
|
59
|
+
try {
|
|
60
|
+
const { protocol, hostname } = new URL(origin);
|
|
61
|
+
return protocol === 'http:' && (hostname === 'localhost' || hostname === '127.0.0.1');
|
|
62
|
+
} catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
50
67
|
/** The theme editor's origin when it frames this page, otherwise `null`. Browser only. */
|
|
51
68
|
export function editorOrigin(): string | null {
|
|
52
69
|
if (typeof window === 'undefined') return null;
|
|
@@ -56,7 +73,23 @@ export function editorOrigin(): string | null {
|
|
|
56
73
|
} catch {
|
|
57
74
|
return null;
|
|
58
75
|
}
|
|
59
|
-
|
|
76
|
+
if (!origin) return null;
|
|
77
|
+
if ((EDITOR_ORIGINS as readonly string[]).includes(origin)) return origin;
|
|
78
|
+
return import.meta.env.DEV && isLocalEditor(origin) ? origin : null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface EditorFrame {
|
|
82
|
+
origin: string;
|
|
83
|
+
/** The engine's own dev editor (`/__twilight/editor`): edits apply live, and blocks can't be hidden. */
|
|
84
|
+
dev: boolean;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** The editor framing this page, the merchant's or (on a dev server) the engine's own. Browser only. */
|
|
88
|
+
export function editorFrame(): EditorFrame | null {
|
|
89
|
+
if (typeof window === 'undefined') return null;
|
|
90
|
+
if (import.meta.env.DEV && isEditorFrame()) return { origin: window.location.origin, dev: true };
|
|
91
|
+
const origin = editorOrigin();
|
|
92
|
+
return origin ? { origin, dev: false } : null;
|
|
60
93
|
}
|
|
61
94
|
|
|
62
95
|
export function postToEditor(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { lazy, Suspense, useEffect, useState, type ReactElement } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { editorFrame, FRAME_LOADED_ACTION, postToEditor, type EditorFrame } from './frame';
|
|
3
3
|
|
|
4
4
|
/** Off the shell chunk: only a store framed by the theme editor ever loads it. */
|
|
5
5
|
const LazyLiveEditorBar = lazy(() =>
|
|
@@ -13,13 +13,15 @@ const LazyLiveEditorBar = lazy(() =>
|
|
|
13
13
|
* nothing on the server, so it changes no markup.
|
|
14
14
|
*/
|
|
15
15
|
export function LiveEditor(): ReactElement | null {
|
|
16
|
-
const [
|
|
16
|
+
const [frame, setFrame] = useState<EditorFrame | null>(null);
|
|
17
17
|
|
|
18
18
|
useEffect(() => {
|
|
19
|
-
const found =
|
|
19
|
+
const found = editorFrame();
|
|
20
20
|
if (!found) return;
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
setFrame(found);
|
|
22
|
+
// The merchant's editor checks the preview's health with it; the dev editor doesn't.
|
|
23
|
+
if (found.dev) return;
|
|
24
|
+
const announce = () => postToEditor(found.origin, FRAME_LOADED_ACTION);
|
|
23
25
|
if (document.readyState === 'complete') {
|
|
24
26
|
announce();
|
|
25
27
|
return;
|
|
@@ -28,10 +30,10 @@ export function LiveEditor(): ReactElement | null {
|
|
|
28
30
|
return () => window.removeEventListener('load', announce);
|
|
29
31
|
}, []);
|
|
30
32
|
|
|
31
|
-
if (!
|
|
33
|
+
if (!frame) return null;
|
|
32
34
|
return (
|
|
33
35
|
<Suspense fallback={null}>
|
|
34
|
-
<LazyLiveEditorBar origin={origin} />
|
|
36
|
+
<LazyLiveEditorBar origin={frame.origin} dev={frame.dev} />
|
|
35
37
|
</Suspense>
|
|
36
38
|
);
|
|
37
39
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/live-editor/LiveEditorBar.tsx"],"names":[],"mappings":"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","file":"LiveEditorBar-WSASAFCL.js","sourcesContent":["import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n type ReactElement,\n type RefObject,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { useTranslation } from '../../providers/I18nProvider';\nimport { BLOCK_ATTRIBUTE, areaOf, postToEditor, targetOf, type BlockAction } from './frame';\n\nconst ACCENT = '#5dd5c4';\nconst LAYER = 2147483000;\n/** The editor reloads the preview after hide, duplicate and delete; stop waiting if it doesn't. */\nconst BUSY_TIMEOUT_MS = 10_000;\n/** How long a link's click waits for a second one, so a double-click edits instead of navigating. */\nconst DOUBLE_CLICK_MS = 300;\n\n/** Defaults for the `blocks.live_editor.*` keys, in the store's language. */\nconst DEFAULT_LABELS = {\n ar: {\n edit: 'تعديل',\n hide: 'إخفاء',\n moveup: 'تحريك لأعلى',\n movedown: 'تحريك لأسفل',\n duplicate: 'تكرار',\n add: 'إضافة عنصر',\n delete: 'حذف',\n header: 'رأس الصفحة',\n footer: 'ذيل الصفحة',\n },\n en: {\n edit: 'Edit',\n hide: 'Hide',\n moveup: 'Move up',\n movedown: 'Move down',\n duplicate: 'Duplicate',\n add: 'Add element',\n delete: 'Delete',\n header: 'Header',\n footer: 'Footer',\n },\n} as const;\n\n/** Twig's order, read from the start of the line: edit first, delete last. */\nconst BLOCK_ACTIONS: BlockAction[] = [\n 'edit',\n 'hide',\n 'moveup',\n 'movedown',\n 'duplicate',\n 'add',\n 'delete',\n];\n\n/** Lucide-style 24px stroke icons. */\nconst ICONS: Record<BlockAction, ReactElement> = {\n edit: (\n <>\n <path d=\"M12 20h9\" />\n <path d=\"M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z\" />\n </>\n ),\n hide: (\n <>\n <path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 10 8 10 8a13.16 13.16 0 0 1-1.67 2.68\" />\n <path d=\"M6.61 6.61A13.53 13.53 0 0 0 2 12s3 8 10 8a9.74 9.74 0 0 0 5.39-1.61\" />\n <path d=\"M9.88 9.88a3 3 0 1 0 4.24 4.24\" />\n <path d=\"m2 2 20 20\" />\n </>\n ),\n moveup: <path d=\"m18 15-6-6-6 6\" />,\n movedown: <path d=\"m6 9 6 6 6-6\" />,\n duplicate: (\n <>\n <rect x=\"8\" y=\"8\" width=\"14\" height=\"14\" rx=\"2\" />\n <path d=\"M4 16a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2\" />\n </>\n ),\n add: <path d=\"M12 5v14M5 12h14\" />,\n delete: (\n <>\n <path d=\"M3 6h18\" />\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\" />\n <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n </>\n ),\n};\n\nconst OUTLINE: CSSProperties = {\n position: 'fixed',\n zIndex: LAYER,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n border: `2px solid ${ACCENT}`,\n};\n\nconst CHIP: CSSProperties = {\n position: 'absolute',\n top: 0,\n insetInlineStart: 0,\n padding: '4px 12px',\n background: ACCENT,\n color: '#0f172a',\n font: '500 14px/1.4 system-ui, sans-serif',\n whiteSpace: 'nowrap',\n};\n\nconst BAR: CSSProperties = {\n position: 'fixed',\n zIndex: LAYER + 1,\n display: 'flex',\n gap: 4,\n padding: 6,\n background: '#fff',\n borderRadius: 8,\n boxShadow: '0 4px 16px rgba(15, 23, 42, 0.18)',\n transform: 'translateX(-50%)',\n};\n\nfunction buttonStyle(action: BlockAction | 'area', disabled: boolean): CSSProperties {\n return {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 6,\n minWidth: 36,\n height: 36,\n padding: '0 8px',\n border: 0,\n borderRadius: 6,\n background: 'transparent',\n color: action === 'delete' ? '#e11d48' : action === 'edit' ? '#0d9488' : '#475569',\n font: '500 14px/1 system-ui, sans-serif',\n cursor: disabled ? 'default' : 'pointer',\n opacity: disabled ? 0.35 : 1,\n };\n}\n\nfunction Icon({ children }: { children: ReactElement }) {\n return (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n {children}\n </svg>\n );\n}\n\n/** The blocks `el` can trade places with: its siblings in the same list. */\nfunction blockSiblings(el: HTMLElement): HTMLElement[] {\n const parent = el.parentElement;\n if (!parent) return [el];\n return Array.from(parent.children).filter(\n (child): child is HTMLElement =>\n child instanceof HTMLElement && child.hasAttribute(BLOCK_ATTRIBUTE)\n );\n}\n\nfunction connected(el: HTMLElement | null): HTMLElement | null {\n return el?.isConnected ? el : null;\n}\n\n/** Re-renders on scroll, resize and layout shifts, so the overlay follows what it outlines. */\nfunction useLayoutTick(active: boolean): void {\n const [, setTick] = useState(0);\n useEffect(() => {\n if (!active) return;\n let frame = 0;\n const schedule = () => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(() => setTick((n) => n + 1));\n };\n window.addEventListener('scroll', schedule, { capture: true, passive: true });\n window.addEventListener('resize', schedule);\n const observer = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(schedule) : null;\n observer?.observe(document.body);\n return () => {\n cancelAnimationFrame(frame);\n window.removeEventListener('scroll', schedule, { capture: true });\n window.removeEventListener('resize', schedule);\n observer?.disconnect();\n };\n }, [active]);\n}\n\ntype LabelKey = keyof typeof DEFAULT_LABELS.en;\ntype Labels = Record<LabelKey, string>;\n\nfunction useLabels(): Labels {\n const { t, i18n } = useTranslation();\n const defaults = i18n?.language?.startsWith('ar') ? DEFAULT_LABELS.ar : DEFAULT_LABELS.en;\n return Object.fromEntries(\n (Object.keys(defaults) as LabelKey[]).map((key) => [\n key,\n t(`blocks.live_editor.${key}`, { defaultValue: defaults[key] }),\n ])\n ) as Labels;\n}\n\n/**\n * Holds a link's click inside a block, the header or the footer for\n * {@link DOUBLE_CLICK_MS}: a second click on the same link makes it a\n * double-click, which edits the area, and the link never navigates; otherwise\n * the click is replayed. A click on another link drops the first one.\n */\nfunction useHeldLinkClicks(barRef: RefObject<HTMLDivElement | null>): void {\n useEffect(() => {\n let held: { link: HTMLAnchorElement; timer: number } | null = null;\n let replaying = false;\n\n const onClick = (event: MouseEvent) => {\n if (replaying || event.button !== 0) return;\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;\n if (barRef.current?.contains(event.target as Node)) return;\n const link = event.target instanceof Element ? event.target.closest('a[href]') : null;\n if (!(link instanceof HTMLAnchorElement) || !targetOf(link)) return;\n\n // Before the router's own handler, which sits below the document.\n event.preventDefault();\n event.stopPropagation();\n const previous = held;\n if (previous) {\n window.clearTimeout(previous.timer);\n held = null;\n if (previous.link === link) return;\n }\n const timer = window.setTimeout(() => {\n held = null;\n replaying = true;\n link.click();\n replaying = false;\n }, DOUBLE_CLICK_MS);\n held = { link, timer };\n };\n\n document.addEventListener('click', onClick, true);\n return () => {\n document.removeEventListener('click', onClick, true);\n if (held) window.clearTimeout(held.timer);\n };\n }, [barRef]);\n}\n\nfunction Outline({ el, label }: { el: HTMLElement; label?: string }) {\n const rect = el.getBoundingClientRect();\n return (\n <div\n data-testid=\"live-editor-outline\"\n style={{ ...OUTLINE, top: rect.top, left: rect.left, width: rect.width, height: rect.height }}\n >\n {label && <span style={CHIP}>{label}</span>}\n </div>\n );\n}\n\ninterface ToolbarProps {\n target: HTMLElement;\n labels: Labels;\n busy: BlockAction | null;\n barRef: RefObject<HTMLDivElement | null>;\n onAct: (el: HTMLElement, action: BlockAction) => void;\n}\n\n/** One edit button for the header or footer; the full set for a block. */\nfunction Toolbar({ target, labels, busy, barRef, onAct }: ToolbarProps) {\n const rect = target.getBoundingClientRect();\n const style: CSSProperties = {\n ...BAR,\n top: Math.max(rect.top + 8, 8),\n left: rect.left + rect.width / 2,\n };\n\n if (areaOf(target)) {\n return (\n <div ref={barRef} data-testid=\"live-editor-bar\" style={style}>\n <button\n type=\"button\"\n data-testid=\"live-editor-edit\"\n style={buttonStyle('area', false)}\n onClick={() => onAct(target, 'edit')}\n >\n <Icon>{ICONS.edit}</Icon>\n {labels.edit}\n </button>\n </div>\n );\n }\n\n const siblings = blockSiblings(target);\n const index = siblings.indexOf(target);\n const isDisabled = (action: BlockAction) =>\n busy !== null ||\n (action === 'moveup' && index <= 0) ||\n (action === 'movedown' && index >= siblings.length - 1);\n\n return (\n <div\n ref={barRef}\n data-testid=\"live-editor-bar\"\n role=\"toolbar\"\n aria-label={labels.edit}\n style={style}\n >\n {BLOCK_ACTIONS.map((action) => (\n <button\n key={action}\n type=\"button\"\n data-testid={`live-editor-${action}`}\n title={labels[action]}\n aria-label={labels[action]}\n aria-busy={busy === action || undefined}\n disabled={isDisabled(action)}\n style={buttonStyle(action, isDisabled(action))}\n onClick={() => onAct(target, action)}\n >\n <Icon>{ICONS[action]}</Icon>\n </button>\n ))}\n </div>\n );\n}\n\n/**\n * The block an action names. A uuid is shared by every copy of one component,\n * so it comes with which copy, in page order; a row id is unique on its own.\n */\nfunction blockRefOf(el: HTMLElement, id: string): { id: string; copy?: number } {\n if (/^\\d+$/.test(id)) return { id };\n const copies = Array.from(document.querySelectorAll(`[${BLOCK_ATTRIBUTE}]`)).filter(\n (block) => block.getAttribute(BLOCK_ATTRIBUTE) === id\n );\n return { id, copy: copies.indexOf(el) };\n}\n\n/**\n * The live editor's action bar: hovering a home block outlines it and shows\n * edit, hide, move, duplicate, add and delete; hovering the header or footer\n * shows an edit button. Double-clicking either edits it. Each action is a\n * message to the editor, which saves the change and reloads the preview.\n */\nexport function LiveEditorBar({ origin }: { origin: string }): ReactElement | null {\n const [hovered, setHovered] = useState<HTMLElement | null>(null);\n const [editing, setEditing] = useState<HTMLElement | null>(null);\n const [busy, setBusy] = useState<BlockAction | null>(null);\n const barRef = useRef<HTMLDivElement>(null);\n // Taken after mount, so nothing reads the DOM while rendering.\n const [host, setHost] = useState<HTMLElement | null>(null);\n const labels = useLabels();\n useHeldLinkClicks(barRef);\n\n const act = useCallback(\n (el: HTMLElement, action: BlockAction) => {\n const area = areaOf(el);\n if (area) {\n postToEditor(origin, `preview::edit.${area}`, { id: `store-${area}` });\n setEditing(el);\n return;\n }\n const id = el.getAttribute(BLOCK_ATTRIBUTE);\n if (!id) return;\n postToEditor(origin, `preview::${action}.component`, blockRefOf(el, id));\n if (action === 'edit') setEditing(el);\n else if (action === 'hide' || action === 'duplicate' || action === 'delete') setBusy(action);\n },\n [origin]\n );\n\n useEffect(() => {\n const onOver = (event: MouseEvent) => {\n // The bar sits over the block it acts on: reaching it keeps that block.\n if (barRef.current?.contains(event.target as Node)) return;\n setHovered(targetOf(event.target));\n };\n const onOut = (event: MouseEvent) => {\n if (!event.relatedTarget) setHovered(null);\n };\n const onDoubleClick = (event: MouseEvent) => {\n if (barRef.current?.contains(event.target as Node)) return;\n const el = targetOf(event.target);\n if (el) act(el, 'edit');\n };\n document.addEventListener('mouseover', onOver);\n document.addEventListener('mouseout', onOut);\n document.addEventListener('dblclick', onDoubleClick);\n return () => {\n document.removeEventListener('mouseover', onOver);\n document.removeEventListener('mouseout', onOut);\n document.removeEventListener('dblclick', onDoubleClick);\n };\n }, [act]);\n\n useEffect(() => setHost(document.body), []);\n\n useEffect(() => {\n if (!busy) return;\n const timer = window.setTimeout(() => setBusy(null), BUSY_TIMEOUT_MS);\n return () => window.clearTimeout(timer);\n }, [busy]);\n\n const target = connected(hovered);\n const selected = connected(editing);\n useLayoutTick(Boolean(target || selected));\n\n if (!host || (!target && !selected)) return null;\n\n const targetArea = target ? areaOf(target) : null;\n\n return createPortal(\n <>\n {selected && selected !== target && <Outline el={selected} />}\n {target && <Outline el={target} label={targetArea ? labels[targetArea] : undefined} />}\n {target && (\n <Toolbar target={target} labels={labels} busy={busy} barRef={barRef} onAct={act} />\n )}\n </>,\n host\n );\n}\n"]}
|