@akinon/projectzero 2.0.0-beta.2 → 2.0.0-beta.20

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.
Files changed (377) hide show
  1. package/CHANGELOG.md +147 -6
  2. package/app-template/.env.example +8 -0
  3. package/app-template/.github/instructions/account.instructions.md +749 -0
  4. package/app-template/.github/instructions/checkout.instructions.md +678 -0
  5. package/app-template/.github/instructions/default.instructions.md +279 -0
  6. package/app-template/.github/instructions/edge-cases.instructions.md +73 -0
  7. package/app-template/.github/instructions/routing.instructions.md +603 -0
  8. package/app-template/.github/instructions/settings.instructions.md +338 -0
  9. package/app-template/.gitignore +5 -0
  10. package/app-template/AGENTS.md +7 -0
  11. package/app-template/CHANGELOG.md +1645 -61
  12. package/app-template/Procfile +1 -1
  13. package/app-template/README.md +6 -0
  14. package/app-template/akinon.json +1 -4
  15. package/app-template/build.sh +10 -0
  16. package/app-template/config/prebuild-tests.json +5 -0
  17. package/app-template/docs/advanced-usage.md +111 -0
  18. package/app-template/docs/plugins.md +60 -25
  19. package/app-template/docs/sentry-usage.md +35 -0
  20. package/app-template/jest.config.ts +2 -2
  21. package/app-template/next-env.d.ts +1 -0
  22. package/app-template/next.config.mjs +8 -5
  23. package/app-template/package.json +60 -50
  24. package/app-template/postcss.config.mjs +5 -0
  25. package/app-template/public/amex.svg +12 -0
  26. package/app-template/public/apple-pay.svg +16 -0
  27. package/app-template/public/assets/images/product-placeholder-1.jpg +0 -0
  28. package/app-template/public/assets/images/product-placeholder-2.jpg +0 -0
  29. package/app-template/public/assets/images/product-placeholder-3.jpg +0 -0
  30. package/app-template/public/assets/images/product-placeholder-4.jpg +0 -0
  31. package/app-template/public/google-pay.svg +16 -0
  32. package/app-template/public/locales/en/account.json +13 -4
  33. package/app-template/public/locales/en/auth.json +6 -7
  34. package/app-template/public/locales/en/basket.json +6 -6
  35. package/app-template/public/locales/en/blog.json +7 -0
  36. package/app-template/public/locales/en/category.json +3 -1
  37. package/app-template/public/locales/en/checkout.json +17 -4
  38. package/app-template/public/locales/en/common.json +71 -3
  39. package/app-template/public/locales/en/forgot_password.json +6 -7
  40. package/app-template/public/locales/en/product.json +84 -4
  41. package/app-template/public/locales/tr/account.json +13 -4
  42. package/app-template/public/locales/tr/auth.json +16 -17
  43. package/app-template/public/locales/tr/basket.json +4 -4
  44. package/app-template/public/locales/tr/blog.json +7 -0
  45. package/app-template/public/locales/tr/category.json +3 -1
  46. package/app-template/public/locales/tr/checkout.json +48 -36
  47. package/app-template/public/locales/tr/common.json +70 -2
  48. package/app-template/public/locales/tr/forgot_password.json +12 -13
  49. package/app-template/public/locales/tr/product.json +82 -0
  50. package/app-template/public/logo.svg +3 -27
  51. package/app-template/public/mastercard.svg +14 -0
  52. package/app-template/public/masterpass-javascript-sdk-web.min.js +1 -0
  53. package/app-template/public/promotion-banner.jpg +0 -0
  54. package/app-template/public/shop-pay.svg +12 -0
  55. package/app-template/public/visa.svg +12 -0
  56. package/app-template/src/__tests__/middleware-matcher.test.ts +135 -0
  57. package/app-template/src/app/[commerce]/[locale]/[currency]/blog/[slug]/page.tsx +118 -0
  58. package/app-template/src/app/[commerce]/[locale]/[currency]/pages/[slug]/page.tsx +15 -0
  59. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/[...prettyurl]/page.tsx +9 -9
  60. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/layout.tsx +2 -2
  61. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/cancellation/page.tsx +105 -13
  62. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/page.tsx +136 -52
  63. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/profile/page.tsx +2 -2
  64. package/app-template/src/app/[pz]/category/[pk]/page.tsx +27 -0
  65. package/app-template/src/app/[pz]/error.tsx +17 -0
  66. package/app-template/src/app/[pz]/flat-page/[pk]/page.tsx +23 -0
  67. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/forms/[pk]/generate/page.tsx +1 -2
  68. package/app-template/src/app/[pz]/group-product/[pk]/page.tsx +93 -0
  69. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/landing-page/[pk]/page.tsx +2 -4
  70. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/layout.tsx +3 -10
  71. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/list/page.tsx +2 -4
  72. package/app-template/src/app/{[commerce]/[locale]/[currency]/pz-not-found/page.tsx → [pz]/not-found.tsx} +5 -7
  73. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/checkout/page.tsx +7 -4
  74. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/completed/[token]/page.tsx +6 -4
  75. package/app-template/src/app/[pz]/product/[pk]/page.tsx +102 -0
  76. package/app-template/src/app/[pz]/special-page/[pk]/page.tsx +35 -0
  77. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/email-set-primary/[[...id]]/page.tsx +3 -4
  78. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/registration/account-confirm-email/[[...id]]/page.tsx +3 -3
  79. package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/reset/[[...id]]/page.tsx +41 -5
  80. package/app-template/src/app/[pz]/xml-sitemap/[node]/route.ts +73 -0
  81. package/app-template/src/app/api/auth/[...nextauth]/route.ts +3 -0
  82. package/app-template/src/app/api/barcode-search/route.ts +1 -0
  83. package/app-template/src/app/api/form/[...id]/route.ts +1 -7
  84. package/app-template/src/app/api/image-proxy/route.ts +1 -0
  85. package/app-template/src/app/api/product-categories/route.ts +1 -0
  86. package/app-template/src/app/api/similar-product-list/route.ts +1 -0
  87. package/app-template/src/app/api/similar-products/route.ts +1 -0
  88. package/app-template/src/app/api/theme-settings/route.ts +12 -0
  89. package/app-template/src/app/api/virtual-try-on/limited-categories/route.ts +1 -0
  90. package/app-template/src/app/api/virtual-try-on/route.ts +1 -0
  91. package/app-template/src/assets/fonts/pz-icon.css +211 -49
  92. package/app-template/src/assets/fonts/pz-icon.eot +0 -0
  93. package/app-template/src/assets/fonts/pz-icon.html +486 -0
  94. package/app-template/src/assets/fonts/pz-icon.scss +373 -49
  95. package/app-template/src/assets/fonts/pz-icon.svg +215 -53
  96. package/app-template/src/assets/fonts/pz-icon.ttf +0 -0
  97. package/app-template/src/assets/fonts/pz-icon.woff +0 -0
  98. package/app-template/src/assets/fonts/pz-icon.woff2 +0 -0
  99. package/app-template/src/assets/globals.scss +37 -34
  100. package/app-template/src/assets/icons/arrow-right.svg +3 -0
  101. package/app-template/src/assets/icons/cart.svg +4 -12
  102. package/app-template/src/assets/icons/check.svg +2 -18
  103. package/app-template/src/assets/icons/chevron-down.svg +2 -7
  104. package/app-template/src/assets/icons/delete.svg +3 -0
  105. package/app-template/src/assets/icons/facebook.svg +2 -8
  106. package/app-template/src/assets/icons/fav-off.svg +5 -0
  107. package/app-template/src/assets/icons/fav-on.svg +5 -0
  108. package/app-template/src/assets/icons/filter-and-sort.svg +3 -0
  109. package/app-template/src/assets/icons/heart.svg +3 -0
  110. package/app-template/src/assets/icons/instagram.svg +2 -13
  111. package/app-template/src/assets/icons/materials.svg +3 -0
  112. package/app-template/src/assets/icons/person.svg +4 -0
  113. package/app-template/src/assets/icons/pinterest.svg +5 -11
  114. package/app-template/src/assets/icons/ruler.svg +3 -0
  115. package/app-template/src/assets/icons/search.svg +8 -11
  116. package/app-template/src/assets/icons/share.svg +2 -9
  117. package/app-template/src/assets/icons/snapchat.svg +3 -0
  118. package/app-template/src/assets/icons/tiktok.svg +3 -0
  119. package/app-template/src/assets/icons/tumblr.svg +6 -0
  120. package/app-template/src/assets/icons/twitter.svg +2 -10
  121. package/app-template/src/assets/icons/vimeo.svg +3 -0
  122. package/app-template/src/assets/icons/youtube.svg +3 -0
  123. package/app-template/src/assets/icons/zoom.svg +8 -0
  124. package/app-template/src/auth.ts +3 -0
  125. package/app-template/src/components/__tests__/link.test.tsx +2 -0
  126. package/app-template/src/components/accordion.tsx +48 -23
  127. package/app-template/src/components/action-tooltip.tsx +160 -0
  128. package/app-template/src/components/button.tsx +50 -35
  129. package/app-template/src/components/carousel-core.tsx +4 -11
  130. package/app-template/src/components/checkbox.tsx +2 -1
  131. package/app-template/src/components/currency-select.tsx +150 -4
  132. package/app-template/src/components/file-input.tsx +64 -2
  133. package/app-template/src/components/generate-form-fields.tsx +49 -10
  134. package/app-template/src/components/icon.tsx +5 -6
  135. package/app-template/src/components/index.ts +4 -1
  136. package/app-template/src/components/input.tsx +8 -2
  137. package/app-template/src/components/language-select.tsx +88 -2
  138. package/app-template/src/components/modal.tsx +34 -16
  139. package/app-template/src/components/pagination.tsx +133 -20
  140. package/app-template/src/components/price.tsx +1 -1
  141. package/app-template/src/components/pwa-tags.tsx +1 -0
  142. package/app-template/src/components/quantity-input.tsx +63 -0
  143. package/app-template/src/components/quantity-selector.tsx +203 -0
  144. package/app-template/src/components/route-handler.tsx +50 -0
  145. package/app-template/src/components/select.tsx +86 -54
  146. package/app-template/src/components/tabs.tsx +2 -2
  147. package/app-template/src/components/types/index.ts +55 -2
  148. package/app-template/src/components/widget-content.tsx +323 -0
  149. package/app-template/src/data/server/theme.ts +70 -0
  150. package/app-template/src/hooks/use-fav-button.tsx +9 -10
  151. package/app-template/src/hooks/use-product-cart.ts +80 -0
  152. package/app-template/src/hooks/use-stock-alert.ts +74 -0
  153. package/app-template/src/hooks/use-theme-settings.ts +42 -0
  154. package/app-template/src/lib/fonts.ts +149 -0
  155. package/app-template/src/middleware.ts +1 -0
  156. package/app-template/src/plugins.js +13 -2
  157. package/app-template/src/redux/middlewares/category.ts +6 -5
  158. package/app-template/src/redux/reducers/category.ts +1 -1
  159. package/app-template/src/redux/store.ts +21 -1
  160. package/app-template/src/routes/index.ts +2 -1
  161. package/app-template/src/settings.js +5 -3
  162. package/app-template/src/types/hookform-resolvers-yup.d.ts +28 -0
  163. package/app-template/src/types/index.ts +74 -3
  164. package/app-template/src/types/next-auth.d.ts +2 -2
  165. package/app-template/src/types/widget.ts +169 -0
  166. package/app-template/src/utils/convert-facet-search-params.ts +1 -1
  167. package/app-template/src/utils/formatDate.ts +48 -0
  168. package/app-template/src/utils/styles.ts +71 -0
  169. package/app-template/src/utils/variant-validation.ts +41 -0
  170. package/app-template/src/views/account/address-form.tsx +8 -4
  171. package/app-template/src/views/account/contact-form.tsx +148 -136
  172. package/app-template/src/views/account/content-header.tsx +2 -2
  173. package/app-template/src/views/account/faq/faq-tabs.tsx +8 -2
  174. package/app-template/src/views/account/favorite-item.tsx +1 -1
  175. package/app-template/src/views/account/order.tsx +10 -8
  176. package/app-template/src/views/account/orders/order-cancellation-item.tsx +4 -3
  177. package/app-template/src/views/account/orders/order-detail-header.tsx +1 -1
  178. package/app-template/src/views/anonymous-tracking/order-detail/index.tsx +44 -37
  179. package/app-template/src/views/basket/basket-item.tsx +697 -107
  180. package/app-template/src/views/basket/basket-summary-context.tsx +560 -0
  181. package/app-template/src/views/basket/designer-context.tsx +617 -0
  182. package/app-template/src/views/basket/index.ts +2 -0
  183. package/app-template/src/views/basket/summary.tsx +497 -60
  184. package/app-template/src/views/breadcrumb/breadcrumb-client.tsx +190 -0
  185. package/app-template/src/views/breadcrumb/breadcrumb-registrar.tsx +286 -0
  186. package/app-template/src/views/breadcrumb/constants.ts +15 -0
  187. package/app-template/src/views/breadcrumb/index.tsx +127 -0
  188. package/app-template/src/views/breadcrumb.tsx +13 -38
  189. package/app-template/src/views/category/category-active-filters.tsx +1 -1
  190. package/app-template/src/views/category/category-banner.tsx +4 -23
  191. package/app-template/src/views/category/category-header.tsx +289 -60
  192. package/app-template/src/views/category/category-info.tsx +177 -27
  193. package/app-template/src/views/category/filters/filter-item.tsx +138 -42
  194. package/app-template/src/views/category/filters/index.tsx +209 -49
  195. package/app-template/src/views/category/layout.tsx +7 -4
  196. package/app-template/src/views/category/native-widget-context.tsx +257 -0
  197. package/app-template/src/views/category/product-list-registrar.tsx +665 -0
  198. package/app-template/src/views/checkout/auth.tsx +64 -40
  199. package/app-template/src/views/checkout/checkout-address-registrar.tsx +254 -0
  200. package/app-template/src/views/checkout/checkout-buttons-registrar.tsx +183 -0
  201. package/app-template/src/views/checkout/checkout-delivery-method-registrar.tsx +259 -0
  202. package/app-template/src/views/checkout/checkout-payment-options-registrar.tsx +253 -0
  203. package/app-template/src/views/checkout/checkout-summary-registrar.tsx +183 -0
  204. package/app-template/src/views/checkout/constants.ts +5 -0
  205. package/app-template/src/views/checkout/index.tsx +5 -0
  206. package/app-template/src/views/checkout/layout/header.tsx +9 -5
  207. package/app-template/src/views/checkout/steps/payment/index.tsx +5 -2
  208. package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +93 -6
  209. package/app-template/src/views/checkout/steps/payment/options/funds-transfer.tsx +25 -5
  210. package/app-template/src/views/checkout/steps/payment/options/loyalty.tsx +21 -2
  211. package/app-template/src/views/checkout/steps/payment/options/masterpass-rest.tsx +15 -0
  212. package/app-template/src/views/checkout/steps/payment/options/redirection.tsx +27 -5
  213. package/app-template/src/views/checkout/steps/payment/options/saved-card.tsx +18 -0
  214. package/app-template/src/views/checkout/steps/payment/options/store-credit.tsx +464 -0
  215. package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +171 -40
  216. package/app-template/src/views/checkout/steps/shipping/address-box.tsx +104 -29
  217. package/app-template/src/views/checkout/steps/shipping/addresses.tsx +129 -46
  218. package/app-template/src/views/checkout/steps/shipping/shipping-options.tsx +232 -27
  219. package/app-template/src/views/checkout/summary.tsx +310 -26
  220. package/app-template/src/views/find-in-store/index.tsx +2 -2
  221. package/app-template/src/views/footer/footer-app-banner-context.tsx +326 -0
  222. package/app-template/src/views/footer/footer-bottom-context.tsx +215 -0
  223. package/app-template/src/views/footer/footer-bottom-wrapper.tsx +74 -0
  224. package/app-template/src/views/footer/footer-layout-constants.ts +35 -0
  225. package/app-template/src/views/footer/footer-layout-registrar.tsx +342 -0
  226. package/app-template/src/views/footer/footer-layout-switcher.tsx +110 -0
  227. package/app-template/src/views/footer/footer-menu-context.tsx +211 -0
  228. package/app-template/src/views/footer/footer-native-widgets.tsx +60 -0
  229. package/app-template/src/views/footer/footer-social-context.tsx +254 -0
  230. package/app-template/src/views/footer/footer-subscription-context.tsx +210 -0
  231. package/app-template/src/views/footer/footer-utils.ts +43 -0
  232. package/app-template/src/views/footer/footer-value-props-context.tsx +326 -0
  233. package/app-template/src/views/footer/logo-settings.ts +183 -0
  234. package/app-template/src/views/footer/native-widget-config.ts +262 -0
  235. package/app-template/src/views/footer/subscription-settings.ts +122 -0
  236. package/app-template/src/views/footer/use-footer-logo.ts +162 -0
  237. package/app-template/src/views/footer.tsx +415 -13
  238. package/app-template/src/views/guest-login/index.tsx +62 -58
  239. package/app-template/src/views/header/action-menu.tsx +284 -49
  240. package/app-template/src/views/header/band.tsx +6 -21
  241. package/app-template/src/views/header/designer-context.tsx +261 -0
  242. package/app-template/src/views/header/header-announcement-registrar.tsx +267 -0
  243. package/app-template/src/views/header/header-client-wrapper.tsx +496 -0
  244. package/app-template/src/views/header/header-content.tsx +1026 -0
  245. package/app-template/src/views/header/header-currency-registrar.tsx +348 -0
  246. package/app-template/src/views/header/header-icons-context.tsx +262 -0
  247. package/app-template/src/views/header/header-language-registrar.tsx +348 -0
  248. package/app-template/src/views/header/header-layout-context.tsx +143 -0
  249. package/app-template/src/views/header/header-layout-registrar.tsx +658 -0
  250. package/app-template/src/views/header/header-logo-context.tsx +228 -0
  251. package/app-template/src/views/header/header-logo.tsx +118 -0
  252. package/app-template/src/views/header/header-mini-basket-context.tsx +524 -0
  253. package/app-template/src/views/header/header-search-registrar.tsx +511 -0
  254. package/app-template/src/views/header/header-text-slider-registrar.tsx +382 -0
  255. package/app-template/src/views/header/index.tsx +110 -48
  256. package/app-template/src/views/header/inline-search.tsx +262 -0
  257. package/app-template/src/views/header/mini-basket.tsx +832 -46
  258. package/app-template/src/views/header/mobile-hamburger-button.tsx +5 -8
  259. package/app-template/src/views/header/mobile-menu.tsx +12 -0
  260. package/app-template/src/views/header/navbar-menu-context.tsx +219 -0
  261. package/app-template/src/views/header/navbar.tsx +178 -111
  262. package/app-template/src/views/header/search/index.tsx +85 -24
  263. package/app-template/src/views/header/search/results.tsx +127 -65
  264. package/app-template/src/views/header/search/search-input.tsx +61 -0
  265. package/app-template/src/views/header/server-settings-parser.ts +1105 -0
  266. package/app-template/src/views/header/use-header-icons.ts +241 -0
  267. package/app-template/src/views/header/use-header-logo.ts +213 -0
  268. package/app-template/src/views/header/use-navbar-menu.ts +179 -0
  269. package/app-template/src/views/installment-options/index.tsx +1 -1
  270. package/app-template/src/views/login/index.tsx +89 -56
  271. package/app-template/src/views/otp-login/index.tsx +23 -20
  272. package/app-template/src/views/product/accordion-section.tsx +61 -0
  273. package/app-template/src/views/product/accordion-wrapper.tsx +135 -43
  274. package/app-template/src/views/product/custom-button-group.tsx +69 -0
  275. package/app-template/src/views/product/favorites-button-section.tsx +69 -0
  276. package/app-template/src/views/product/find-in-store-section.tsx +60 -0
  277. package/app-template/src/views/product/index.ts +1 -0
  278. package/app-template/src/views/product/layout.tsx +21 -6
  279. package/app-template/src/views/product/misc-buttons.tsx +339 -25
  280. package/app-template/src/views/product/price-wrapper.tsx +3 -24
  281. package/app-template/src/views/product/product-actions.tsx +294 -0
  282. package/app-template/src/views/product/product-info-section.tsx +140 -0
  283. package/app-template/src/views/product/product-info.tsx +130 -254
  284. package/app-template/src/views/product/product-share.tsx +61 -0
  285. package/app-template/src/views/product/product-variants.tsx +26 -0
  286. package/app-template/src/views/product/quantity-section.tsx +73 -0
  287. package/app-template/src/views/product/sale-tag.tsx +10 -0
  288. package/app-template/src/views/product/share-section.tsx +357 -0
  289. package/app-template/src/views/product/slider.tsx +135 -76
  290. package/app-template/src/views/product/variant.tsx +69 -41
  291. package/app-template/src/views/product/variants-section.tsx +126 -0
  292. package/app-template/src/views/product-detail/constants.ts +272 -0
  293. package/app-template/src/views/product-detail/index.ts +10 -0
  294. package/app-template/src/views/product-detail/product-detail-registrar.tsx +616 -0
  295. package/app-template/src/views/product-item/index.tsx +119 -46
  296. package/app-template/src/views/register/index.tsx +54 -44
  297. package/app-template/src/views/share/index.tsx +9 -6
  298. package/app-template/src/views/widgets/home-hero-slider-content.tsx +41 -39
  299. package/app-template/src/widgets/flatpages/about-us/index.tsx +78 -0
  300. package/app-template/src/widgets/flatpages/blog-list/index.tsx +129 -0
  301. package/app-template/src/widgets/footer-app-banner.tsx +444 -0
  302. package/app-template/src/widgets/footer-bottom.tsx +127 -0
  303. package/app-template/src/widgets/footer-menu-compact.tsx +238 -0
  304. package/app-template/src/widgets/footer-menu-two.tsx +298 -0
  305. package/app-template/src/widgets/footer-menu.tsx +6 -2
  306. package/app-template/src/widgets/footer-social-client.tsx +251 -0
  307. package/app-template/src/widgets/footer-social.tsx +47 -16
  308. package/app-template/src/widgets/footer-subscription/footer-subscription-form.tsx +17 -14
  309. package/app-template/src/widgets/footer-subscription/index.tsx +183 -17
  310. package/app-template/src/widgets/footer-value-props.tsx +201 -0
  311. package/app-template/src/widgets/home-stories-eng.tsx +42 -34
  312. package/app-template/src/widgets/index.ts +7 -0
  313. package/app-template/src/widgets/schemas/about-us.json +46 -0
  314. package/app-template/src/widgets/schemas/blog-list.json +37 -0
  315. package/app-template/src/widgets/schemas/blog.json +29 -0
  316. package/app-template/tailwind.config.js +19 -7
  317. package/app-template/tsconfig.json +29 -11
  318. package/codemods/migrate-segments/index.js +591 -0
  319. package/codemods/sentry-9/index.js +30 -0
  320. package/codemods/sentry-9/remove-sentry-configs.js +14 -0
  321. package/codemods/sentry-9/remove-sentry-dependency.js +25 -0
  322. package/codemods/sentry-9/replace-error-page.js +32 -0
  323. package/codemods/update-tailwind-config/index.js +30 -0
  324. package/codemods/update-tailwind-config/transform.js +102 -0
  325. package/commands/codemod.ts +17 -0
  326. package/commands/index.ts +3 -1
  327. package/commands/plugins.ts +115 -46
  328. package/dist/codemods/sentry-9/templates/error.js +14 -0
  329. package/dist/commands/codemod.js +15 -0
  330. package/dist/commands/index.js +3 -1
  331. package/dist/commands/plugins.js +85 -34
  332. package/package.json +3 -2
  333. package/app-template/postcss.config.js +0 -6
  334. package/app-template/sentry.client.config.ts +0 -16
  335. package/app-template/sentry.edge.config.ts +0 -3
  336. package/app-template/sentry.properties +0 -4
  337. package/app-template/sentry.server.config.ts +0 -3
  338. package/app-template/src/app/[commerce]/[locale]/[currency]/category/[pk]/page.tsx +0 -22
  339. package/app-template/src/app/[commerce]/[locale]/[currency]/error.tsx +0 -20
  340. package/app-template/src/app/[commerce]/[locale]/[currency]/flat-page/[pk]/page.tsx +0 -20
  341. package/app-template/src/app/[commerce]/[locale]/[currency]/group-product/[pk]/page.tsx +0 -74
  342. package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/loading.tsx +0 -67
  343. package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/page.tsx +0 -84
  344. package/app-template/src/app/[commerce]/[locale]/[currency]/special-page/[pk]/page.tsx +0 -27
  345. package/app-template/src/app/[commerce]/[locale]/[currency]/xml-sitemap/[node]/route.ts +0 -25
  346. package/app-template/src/pages/api/auth/[...nextauth].ts +0 -3
  347. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/address/page.tsx +0 -0
  348. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/change-email/page.tsx +0 -0
  349. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/change-password/page.tsx +0 -0
  350. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/contact/page.tsx +0 -0
  351. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/coupons/page.tsx +0 -0
  352. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/email-verification/page.tsx +0 -0
  353. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/faq/page.tsx +0 -0
  354. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/favourite-products/page.tsx +0 -0
  355. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/my-quotations/page.tsx +0 -0
  356. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/layout.tsx +0 -0
  357. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/page.tsx +0 -0
  358. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/page.tsx +0 -0
  359. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/address/stores/page.tsx +0 -0
  360. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/anonymous-tracking/page.tsx +0 -0
  361. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/auth/oauth-login/page.tsx +0 -0
  362. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/auth/page.tsx +0 -0
  363. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/basket/page.tsx +0 -0
  364. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/basket-b2b/page.tsx +0 -0
  365. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/category/[pk]/loading.tsx +0 -0
  366. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/client-root.tsx +0 -0
  367. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/contact-us/page.tsx +0 -0
  368. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/flat-page/[pk]/loading.tsx +0 -0
  369. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/group-product/[pk]/loading.tsx +0 -0
  370. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/landing-page/[pk]/loading.tsx +0 -0
  371. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/list/loading.tsx +0 -0
  372. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/completed/[token]/layout.tsx +0 -0
  373. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/page.tsx +0 -0
  374. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/special-page/[pk]/loading.tsx +0 -0
  375. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/template.tsx +0 -0
  376. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/password/reset/page.tsx +0 -0
  377. /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/xml-sitemap/route.ts +0 -0
@@ -0,0 +1,658 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * Header Layout Section Registrar
5
+ *
6
+ * This component registers the "Layout" section for the header placeholder.
7
+ * It's a minimal client component that only handles native widget registration
8
+ * and applies selection highlight to the header when Layout section is selected.
9
+ *
10
+ * When the Layout section is selected in Theme Editor, the entire header
11
+ * gets highlighted.
12
+ *
13
+ * It also provides the current layout type to child components via context.
14
+ */
15
+
16
+ import {
17
+ createContext,
18
+ useContext,
19
+ useEffect,
20
+ useRef,
21
+ useState,
22
+ useCallback,
23
+ ReactNode
24
+ } from 'react';
25
+
26
+ // Constants
27
+ export const HEADER_LAYOUT_PLACEHOLDER_ID = 'header';
28
+ export const HEADER_LAYOUT_SECTION_ID = 'header-layout';
29
+ export const HEADER_LAYOUT_WIDGET_SLUG = 'header-layout-settings-2';
30
+
31
+ // Block definitions for row containers
32
+ export const HEADER_LAYOUT_BLOCKS = {
33
+ UTILITY_ROW: {
34
+ id: 'header-utility-row',
35
+ type: 'container',
36
+ label: 'Utility Row'
37
+ },
38
+ MAIN_ROW: {
39
+ id: 'header-main-row',
40
+ type: 'container',
41
+ label: 'Main Row'
42
+ },
43
+ TOP_ROW: {
44
+ id: 'header-top-row',
45
+ type: 'container',
46
+ label: 'Top Row'
47
+ },
48
+ BOTTOM_ROW: {
49
+ id: 'header-bottom-row',
50
+ type: 'container',
51
+ label: 'Bottom Row'
52
+ }
53
+ } as const;
54
+
55
+ // Layout types
56
+ export type HeaderLayoutType = 'default' | 'two-row';
57
+
58
+ // Global flag to track if registration has been done (survives component remount)
59
+ declare global {
60
+ interface Window {
61
+ __headerLayoutRegistered?: boolean;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Check if running inside designer iframe
67
+ */
68
+ function isInDesignerMode(): boolean {
69
+ if (typeof window === 'undefined') return false;
70
+ return window.self !== window.top;
71
+ }
72
+
73
+ export type MenuPositionType = 'left' | 'center' | 'right';
74
+ export type SearchPositionType = 'left' | 'center' | 'right';
75
+ export type UtilityPositionType = 'left' | 'right';
76
+
77
+ export interface HeaderLayoutProperties {
78
+ layout?: HeaderLayoutType | Record<string, string>;
79
+ menuPosition?: MenuPositionType | Record<string, string>;
80
+ searchPosition?: SearchPositionType | Record<string, string>;
81
+ utilityPosition?: UtilityPositionType | Record<string, string>;
82
+ sticky?: boolean | string | Record<string, string>;
83
+ }
84
+
85
+ // Block styles interface
86
+ interface BlockStyles {
87
+ [key: string]: unknown;
88
+ }
89
+
90
+ // Context for sharing layout type with other components
91
+ interface HeaderLayoutContextValue {
92
+ layout: HeaderLayoutType;
93
+ menuPosition: MenuPositionType;
94
+ searchPosition: SearchPositionType;
95
+ utilityPosition: UtilityPositionType;
96
+ sticky: boolean;
97
+ isDesigner: boolean;
98
+ selectedBlockId: string | null;
99
+ getBlockStyles: (blockId: string) => BlockStyles | undefined;
100
+ }
101
+
102
+ const HeaderLayoutContext = createContext<HeaderLayoutContextValue>({
103
+ layout: 'default',
104
+ menuPosition: 'center',
105
+ searchPosition: 'center',
106
+ utilityPosition: 'right',
107
+ sticky: true,
108
+ isDesigner: false,
109
+ selectedBlockId: null,
110
+ getBlockStyles: () => undefined
111
+ });
112
+
113
+ export const useHeaderLayout = () => useContext(HeaderLayoutContext);
114
+
115
+ /**
116
+ * HeaderLayoutRegistrar
117
+ *
118
+ * Registers the Layout native section with Theme Editor so it appears in the sidebar,
119
+ * handles header highlight when Layout section is selected, and provides
120
+ * layout type to children via context.
121
+ */
122
+ interface HeaderLayoutRegistrarProps {
123
+ children?: ReactNode;
124
+ /** Initial layout settings from server to avoid layout flash */
125
+ initialLayout?: HeaderLayoutType;
126
+ initialMenuPosition?: MenuPositionType;
127
+ initialSearchPosition?: SearchPositionType;
128
+ initialUtilityPosition?: UtilityPositionType;
129
+ initialSticky?: boolean;
130
+ /** Initial block styles from server (for standalone mode) */
131
+ initialBlockStyles?: Record<string, Record<string, string>>;
132
+ }
133
+
134
+ export default function HeaderLayoutRegistrar({
135
+ children,
136
+ initialLayout = 'default',
137
+ initialMenuPosition = 'center',
138
+ initialSearchPosition = 'center',
139
+ initialUtilityPosition = 'right',
140
+ initialSticky = true,
141
+ initialBlockStyles = {}
142
+ }: HeaderLayoutRegistrarProps) {
143
+ const isDesignerRef = useRef(false);
144
+ // Initialize with server-provided values to avoid flash
145
+ const [sectionProperties, setSectionProperties] =
146
+ useState<HeaderLayoutProperties>({
147
+ layout: initialLayout,
148
+ menuPosition: initialMenuPosition,
149
+ searchPosition: initialSearchPosition,
150
+ utilityPosition: initialUtilityPosition,
151
+ sticky: initialSticky
152
+ });
153
+ const [isLayoutSelected, setIsLayoutSelected] = useState(false);
154
+ const [selectedBlockId, setSelectedBlockId] = useState<string | null>(null);
155
+ // Initialize block styles from server-provided values
156
+ const [blockStyles, setBlockStyles] = useState<Map<string, BlockStyles>>(
157
+ () => {
158
+ const initialMap = new Map<string, BlockStyles>();
159
+ Object.entries(initialBlockStyles).forEach(([blockId, styles]) => {
160
+ initialMap.set(blockId, styles);
161
+ });
162
+ return initialMap;
163
+ }
164
+ );
165
+ const blockStylesRef = useRef<Map<string, BlockStyles>>(
166
+ (() => {
167
+ const initialMap = new Map<string, BlockStyles>();
168
+ Object.entries(initialBlockStyles).forEach(([blockId, styles]) => {
169
+ initialMap.set(blockId, styles);
170
+ });
171
+ return initialMap;
172
+ })()
173
+ );
174
+ const hasReceivedThemeProps = useRef(false);
175
+ const previousLayoutRef = useRef<HeaderLayoutType | null>(initialLayout);
176
+
177
+ useEffect(() => {
178
+ isDesignerRef.current = isInDesignerMode();
179
+ }, []);
180
+
181
+ const isDesigner = isDesignerRef.current;
182
+
183
+ // Helper to get block styles
184
+ const getBlockStyles = useCallback(
185
+ (blockId: string) => blockStyles.get(blockId),
186
+ [blockStyles]
187
+ );
188
+
189
+ // Helper to get blocks based on current layout
190
+ const getBlocksForLayout = useCallback((layout: HeaderLayoutType) => {
191
+ // UTILITY_ROW is always included - it's used for Language/Currency selects
192
+ const utilityRowBlock = {
193
+ id: HEADER_LAYOUT_BLOCKS.UTILITY_ROW.id,
194
+ type: HEADER_LAYOUT_BLOCKS.UTILITY_ROW.type,
195
+ label: HEADER_LAYOUT_BLOCKS.UTILITY_ROW.label
196
+ };
197
+
198
+ if (layout === 'two-row') {
199
+ return [
200
+ utilityRowBlock,
201
+ {
202
+ id: HEADER_LAYOUT_BLOCKS.TOP_ROW.id,
203
+ type: HEADER_LAYOUT_BLOCKS.TOP_ROW.type,
204
+ label: HEADER_LAYOUT_BLOCKS.TOP_ROW.label
205
+ },
206
+ {
207
+ id: HEADER_LAYOUT_BLOCKS.BOTTOM_ROW.id,
208
+ type: HEADER_LAYOUT_BLOCKS.BOTTOM_ROW.type,
209
+ label: HEADER_LAYOUT_BLOCKS.BOTTOM_ROW.label
210
+ }
211
+ ];
212
+ }
213
+ // Default layout - utility row + single main row
214
+ return [
215
+ utilityRowBlock,
216
+ {
217
+ id: HEADER_LAYOUT_BLOCKS.MAIN_ROW.id,
218
+ type: HEADER_LAYOUT_BLOCKS.MAIN_ROW.type,
219
+ label: HEADER_LAYOUT_BLOCKS.MAIN_ROW.label
220
+ }
221
+ ];
222
+ }, []);
223
+
224
+ // Register native widget with Theme Editor
225
+ // Properties are managed by Theme Editor, not sent with registration
226
+ useEffect(() => {
227
+ const isInIframe =
228
+ typeof window !== 'undefined' && window.self !== window.top;
229
+ if (!isInIframe || !window.parent) {
230
+ return;
231
+ }
232
+
233
+ const blocks = getBlocksForLayout(initialLayout);
234
+
235
+ // If already registered, just update blocks (in case layout changed)
236
+ if (typeof window !== 'undefined' && window.__headerLayoutRegistered) {
237
+ window.parent.postMessage(
238
+ {
239
+ type: 'UPDATE_SECTION_BLOCKS',
240
+ data: {
241
+ placeholderId: HEADER_LAYOUT_PLACEHOLDER_ID,
242
+ sectionId: HEADER_LAYOUT_SECTION_ID,
243
+ blocks
244
+ }
245
+ },
246
+ '*'
247
+ );
248
+ return;
249
+ }
250
+
251
+ // Send native widget registration to Theme Editor
252
+ // Include blocks for row containers
253
+ const nativeWidgetConfig = {
254
+ placeholderId: HEADER_LAYOUT_PLACEHOLDER_ID,
255
+ section: {
256
+ id: HEADER_LAYOUT_SECTION_ID,
257
+ type: 'native',
258
+ label: 'Layout',
259
+ blocks
260
+ }
261
+ };
262
+
263
+ window.parent.postMessage(
264
+ {
265
+ type: 'REGISTER_NATIVE_WIDGETS',
266
+ data: { widgets: [nativeWidgetConfig] }
267
+ },
268
+ '*'
269
+ );
270
+
271
+ // Mark as registered in window to survive component remount
272
+ window.__headerLayoutRegistered = true;
273
+ }, [initialLayout, getBlocksForLayout]);
274
+
275
+ // Apply highlight style to header when Layout section is selected
276
+ useEffect(() => {
277
+ if (typeof window === 'undefined') return;
278
+
279
+ const headerElement = document.querySelector('header');
280
+ if (!headerElement) return;
281
+
282
+ if (isLayoutSelected) {
283
+ // Apply selection highlight
284
+ headerElement.style.outline = '2px solid #3b82f6';
285
+ headerElement.style.outlineOffset = '-2px';
286
+ } else {
287
+ // Remove selection highlight
288
+ headerElement.style.outline = '';
289
+ headerElement.style.outlineOffset = '';
290
+ }
291
+
292
+ return () => {
293
+ // Cleanup on unmount
294
+ headerElement.style.outline = '';
295
+ headerElement.style.outlineOffset = '';
296
+ };
297
+ }, [isLayoutSelected]);
298
+
299
+ // Listen for theme updates and selection changes from Theme Editor
300
+ useEffect(() => {
301
+ if (typeof window === 'undefined') return;
302
+
303
+ const handleMessage = (event: MessageEvent) => {
304
+ const { type, data } = event.data || {};
305
+
306
+ // Handle theme updates
307
+ if (
308
+ (type === 'UPDATE_THEME' || type === 'LOAD_THEME') &&
309
+ data?.theme?.placeholders
310
+ ) {
311
+ const placeholder = data.theme.placeholders?.find(
312
+ (p: { slug: string }) => p.slug === HEADER_LAYOUT_PLACEHOLDER_ID
313
+ );
314
+
315
+ const layoutSection = placeholder?.sections?.find(
316
+ (s: { id: string }) => s.id === HEADER_LAYOUT_SECTION_ID
317
+ );
318
+
319
+ if (layoutSection) {
320
+ hasReceivedThemeProps.current = true;
321
+ if (layoutSection.properties) {
322
+ setSectionProperties(layoutSection.properties);
323
+ }
324
+
325
+ // Extract block styles from theme update
326
+ if (layoutSection.blocks && Array.isArray(layoutSection.blocks)) {
327
+ setBlockStyles((prev) => {
328
+ const newMap = new Map(prev);
329
+ layoutSection.blocks.forEach(
330
+ (block: { id: string; styles?: Record<string, unknown> }) => {
331
+ if (block.id && block.styles) {
332
+ // Convert responsive styles to flat styles for current breakpoint
333
+ // Block styles format: { 'background-color': { desktop: '#ff0000', mobile: '#00ff00' } }
334
+ const flatStyles: Record<string, string> = {};
335
+ Object.entries(block.styles).forEach(([key, value]) => {
336
+ if (typeof value === 'object' && value !== null) {
337
+ // Get desktop value first, fallback to any available value
338
+ const responsiveValue = value as Record<string, string>;
339
+ flatStyles[key] =
340
+ responsiveValue.desktop ||
341
+ responsiveValue.mobile ||
342
+ Object.values(responsiveValue)[0] ||
343
+ '';
344
+ } else if (typeof value === 'string') {
345
+ flatStyles[key] = value;
346
+ }
347
+ });
348
+ if (Object.keys(flatStyles).length > 0) {
349
+ newMap.set(block.id, flatStyles);
350
+ }
351
+ }
352
+ }
353
+ );
354
+ blockStylesRef.current = newMap;
355
+ return newMap;
356
+ });
357
+ }
358
+ }
359
+ }
360
+
361
+ // Handle property updates (when user changes dropdown in Theme Editor)
362
+ if (type === 'UPDATE_SECTION_PROPERTY' || type === 'UPDATE_PROPERTY') {
363
+ const { sectionId, placeholderId, key, value, properties } = data || {};
364
+
365
+ // Check if this is for our section
366
+ if (
367
+ sectionId === HEADER_LAYOUT_SECTION_ID ||
368
+ placeholderId === HEADER_LAYOUT_PLACEHOLDER_ID
369
+ ) {
370
+ // If we get individual key/value
371
+ if (key && value !== undefined) {
372
+ setSectionProperties((prev) => ({
373
+ ...prev,
374
+ [key]: value
375
+ }));
376
+ }
377
+ // If we get full properties object
378
+ if (properties) {
379
+ setSectionProperties(properties);
380
+ }
381
+ }
382
+ }
383
+
384
+ // Handle block style updates
385
+ if (type === 'UPDATE_BLOCK_STYLE') {
386
+ const { sectionId, blockId, key, value, styles } = data || {};
387
+
388
+ if (sectionId === HEADER_LAYOUT_SECTION_ID && blockId) {
389
+ setBlockStyles((prev) => {
390
+ const newMap = new Map(prev);
391
+ const existingStyles = newMap.get(blockId) || {};
392
+
393
+ if (key && value !== undefined) {
394
+ newMap.set(blockId, { ...existingStyles, [key]: value });
395
+ }
396
+ if (styles) {
397
+ newMap.set(blockId, { ...existingStyles, ...styles });
398
+ }
399
+
400
+ blockStylesRef.current = newMap;
401
+ return newMap;
402
+ });
403
+ }
404
+ }
405
+
406
+ // Handle selection changes
407
+ if (type === 'SELECT_SECTION') {
408
+ const { placeholderId, sectionId } = data || {};
409
+
410
+ // Check if Layout section is selected
411
+ const isSelected =
412
+ placeholderId === HEADER_LAYOUT_PLACEHOLDER_ID &&
413
+ sectionId === HEADER_LAYOUT_SECTION_ID;
414
+
415
+ setIsLayoutSelected(isSelected);
416
+ if (!isSelected) {
417
+ setSelectedBlockId(null);
418
+ }
419
+ }
420
+
421
+ // Handle block selection
422
+ if (type === 'SELECT_BLOCK') {
423
+ const { sectionId, blockId } = data || {};
424
+ if (sectionId === HEADER_LAYOUT_SECTION_ID) {
425
+ setSelectedBlockId(blockId || null);
426
+ setIsLayoutSelected(true);
427
+ } else {
428
+ setIsLayoutSelected(false);
429
+ setSelectedBlockId(null);
430
+ }
431
+ }
432
+
433
+ // Handle deselection
434
+ if (type === 'DESELECT' || type === 'CLEAR_SELECTION') {
435
+ setIsLayoutSelected(false);
436
+ setSelectedBlockId(null);
437
+ }
438
+ };
439
+
440
+ window.addEventListener('message', handleMessage);
441
+ return () => window.removeEventListener('message', handleMessage);
442
+ }, []);
443
+
444
+ // Helper to extract layout value from potentially responsive property
445
+ const extractLayoutValue = (layoutProp: unknown): HeaderLayoutType => {
446
+ if (!layoutProp) return 'default';
447
+
448
+ // If it's a direct string value
449
+ if (typeof layoutProp === 'string') {
450
+ return layoutProp as HeaderLayoutType;
451
+ }
452
+
453
+ // If it's a responsive object (e.g., { desktop: 'two-row' })
454
+ if (typeof layoutProp === 'object' && layoutProp !== null) {
455
+ const obj = layoutProp as Record<string, string>;
456
+ // Try desktop first, then mobile, then any first value
457
+ return (obj.desktop ||
458
+ obj.mobile ||
459
+ Object.values(obj)[0] ||
460
+ 'default') as HeaderLayoutType;
461
+ }
462
+
463
+ return 'default';
464
+ };
465
+
466
+ // Get the current layout type
467
+ const currentLayout: HeaderLayoutType = extractLayoutValue(
468
+ sectionProperties.layout
469
+ );
470
+
471
+ // Helper to extract menu position value from potentially responsive property
472
+ const extractMenuPositionValue = (menuPosProp: unknown): MenuPositionType => {
473
+ if (!menuPosProp) return 'center';
474
+
475
+ if (typeof menuPosProp === 'string') {
476
+ return menuPosProp as MenuPositionType;
477
+ }
478
+
479
+ if (typeof menuPosProp === 'object' && menuPosProp !== null) {
480
+ const obj = menuPosProp as Record<string, string>;
481
+ return (obj.desktop ||
482
+ obj.mobile ||
483
+ Object.values(obj)[0] ||
484
+ 'center') as MenuPositionType;
485
+ }
486
+
487
+ return 'center';
488
+ };
489
+
490
+ // Get the current menu position
491
+ const currentMenuPosition: MenuPositionType = extractMenuPositionValue(
492
+ sectionProperties.menuPosition
493
+ );
494
+
495
+ // Helper to extract search position value from potentially responsive property
496
+ const extractSearchPositionValue = (
497
+ searchPosProp: unknown
498
+ ): SearchPositionType => {
499
+ if (!searchPosProp) return 'center';
500
+
501
+ if (typeof searchPosProp === 'string') {
502
+ return searchPosProp as SearchPositionType;
503
+ }
504
+
505
+ if (typeof searchPosProp === 'object' && searchPosProp !== null) {
506
+ const obj = searchPosProp as Record<string, string>;
507
+ return (obj.desktop ||
508
+ obj.mobile ||
509
+ Object.values(obj)[0] ||
510
+ 'center') as SearchPositionType;
511
+ }
512
+
513
+ return 'center';
514
+ };
515
+
516
+ // Get the current search position
517
+ const currentSearchPosition: SearchPositionType = extractSearchPositionValue(
518
+ sectionProperties.searchPosition
519
+ );
520
+
521
+ // Helper to extract utility position value from potentially responsive property
522
+ const extractUtilityPositionValue = (
523
+ utilityPosProp: unknown
524
+ ): UtilityPositionType => {
525
+ if (!utilityPosProp) return 'right';
526
+
527
+ if (typeof utilityPosProp === 'string') {
528
+ return utilityPosProp as UtilityPositionType;
529
+ }
530
+
531
+ if (typeof utilityPosProp === 'object' && utilityPosProp !== null) {
532
+ const obj = utilityPosProp as Record<string, string>;
533
+ return (obj.desktop ||
534
+ obj.mobile ||
535
+ Object.values(obj)[0] ||
536
+ 'right') as UtilityPositionType;
537
+ }
538
+
539
+ return 'right';
540
+ };
541
+
542
+ // Get the current utility position (Language/Currency selects position)
543
+ const currentUtilityPosition: UtilityPositionType =
544
+ extractUtilityPositionValue(sectionProperties.utilityPosition);
545
+
546
+ // Helper to extract sticky value from potentially responsive property
547
+ const extractStickyValue = (stickyProp: unknown): boolean => {
548
+ if (stickyProp === undefined || stickyProp === null) return true;
549
+
550
+ if (typeof stickyProp === 'boolean') {
551
+ return stickyProp;
552
+ }
553
+
554
+ if (typeof stickyProp === 'string') {
555
+ return stickyProp === 'true';
556
+ }
557
+
558
+ if (typeof stickyProp === 'object' && stickyProp !== null) {
559
+ const obj = stickyProp as Record<string, string | boolean>;
560
+ const value = obj.desktop ?? obj.mobile ?? Object.values(obj)[0];
561
+ return value === 'true' || value === true;
562
+ }
563
+
564
+ return true;
565
+ };
566
+
567
+ // Get the current sticky value
568
+ const currentSticky: boolean = extractStickyValue(sectionProperties.sticky);
569
+
570
+ // Apply sticky styles to header element when sticky value changes
571
+ useEffect(() => {
572
+ if (typeof window === 'undefined') return;
573
+
574
+ const headerElement = document.querySelector('header');
575
+ if (!headerElement) return;
576
+
577
+ if (currentSticky) {
578
+ headerElement.style.position = 'sticky';
579
+ headerElement.style.top = '0';
580
+ headerElement.style.zIndex = '40';
581
+ } else {
582
+ headerElement.style.position = 'relative';
583
+ headerElement.style.top = 'auto';
584
+ headerElement.style.zIndex = 'auto';
585
+ }
586
+ }, [currentSticky]);
587
+
588
+ // Handle layout changes - unregister search section when switching to default
589
+ // and update blocks in Theme Editor
590
+ useEffect(() => {
591
+ const isInIframe =
592
+ typeof window !== 'undefined' && window.self !== window.top;
593
+ if (!isInIframe || !window.parent) {
594
+ return;
595
+ }
596
+
597
+ const previousLayout = previousLayoutRef.current;
598
+
599
+ // If layout changed from two-row to default, remove search section
600
+ if (previousLayout === 'two-row' && currentLayout === 'default') {
601
+ window.parent.postMessage(
602
+ {
603
+ type: 'UNREGISTER_NATIVE_SECTION',
604
+ data: {
605
+ placeholderId: 'header',
606
+ sectionId: 'header-search'
607
+ }
608
+ },
609
+ '*'
610
+ );
611
+ // Reset registration flags
612
+ if (typeof window !== 'undefined') {
613
+ window.__headerSearchRegistered = false;
614
+ }
615
+ }
616
+
617
+ // Update blocks when layout changes
618
+ if (previousLayout !== currentLayout && previousLayout !== null) {
619
+ window.parent.postMessage(
620
+ {
621
+ type: 'UPDATE_SECTION_BLOCKS',
622
+ data: {
623
+ placeholderId: HEADER_LAYOUT_PLACEHOLDER_ID,
624
+ sectionId: HEADER_LAYOUT_SECTION_ID,
625
+ blocks: getBlocksForLayout(currentLayout)
626
+ }
627
+ },
628
+ '*'
629
+ );
630
+ }
631
+
632
+ // Update previous layout ref
633
+ previousLayoutRef.current = currentLayout;
634
+ }, [currentLayout, getBlocksForLayout]);
635
+
636
+ // If no children, just return null (registration-only mode)
637
+ if (!children) {
638
+ return null;
639
+ }
640
+
641
+ // Provide layout context to children
642
+ return (
643
+ <HeaderLayoutContext.Provider
644
+ value={{
645
+ layout: currentLayout,
646
+ menuPosition: currentMenuPosition,
647
+ searchPosition: currentSearchPosition,
648
+ utilityPosition: currentUtilityPosition,
649
+ sticky: currentSticky,
650
+ isDesigner,
651
+ selectedBlockId,
652
+ getBlockStyles
653
+ }}
654
+ >
655
+ {children}
656
+ </HeaderLayoutContext.Provider>
657
+ );
658
+ }