@akinon/projectzero 2.0.0-beta.19 → 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 (223) hide show
  1. package/CHANGELOG.md +9 -7
  2. package/app-template/CHANGELOG.md +251 -204
  3. package/app-template/akinon.json +1 -1
  4. package/app-template/package.json +28 -28
  5. package/app-template/public/amex.svg +12 -0
  6. package/app-template/public/apple-pay.svg +16 -0
  7. package/app-template/public/assets/images/product-placeholder-1.jpg +0 -0
  8. package/app-template/public/assets/images/product-placeholder-2.jpg +0 -0
  9. package/app-template/public/assets/images/product-placeholder-3.jpg +0 -0
  10. package/app-template/public/assets/images/product-placeholder-4.jpg +0 -0
  11. package/app-template/public/google-pay.svg +16 -0
  12. package/app-template/public/locales/en/account.json +6 -3
  13. package/app-template/public/locales/en/auth.json +6 -7
  14. package/app-template/public/locales/en/basket.json +6 -6
  15. package/app-template/public/locales/en/blog.json +7 -0
  16. package/app-template/public/locales/en/category.json +3 -1
  17. package/app-template/public/locales/en/checkout.json +5 -4
  18. package/app-template/public/locales/en/common.json +11 -2
  19. package/app-template/public/locales/en/forgot_password.json +6 -7
  20. package/app-template/public/locales/en/product.json +4 -3
  21. package/app-template/public/locales/tr/account.json +6 -3
  22. package/app-template/public/locales/tr/auth.json +16 -17
  23. package/app-template/public/locales/tr/basket.json +4 -4
  24. package/app-template/public/locales/tr/blog.json +7 -0
  25. package/app-template/public/locales/tr/category.json +3 -1
  26. package/app-template/public/locales/tr/checkout.json +39 -38
  27. package/app-template/public/locales/tr/common.json +10 -1
  28. package/app-template/public/locales/tr/forgot_password.json +12 -13
  29. package/app-template/public/locales/tr/product.json +1 -0
  30. package/app-template/public/logo.svg +3 -27
  31. package/app-template/public/mastercard.svg +14 -0
  32. package/app-template/public/promotion-banner.jpg +0 -0
  33. package/app-template/public/shop-pay.svg +12 -0
  34. package/app-template/public/visa.svg +12 -0
  35. package/app-template/src/app/[commerce]/[locale]/[currency]/blog/[slug]/page.tsx +118 -0
  36. package/app-template/src/app/[commerce]/[locale]/[currency]/pages/[slug]/page.tsx +15 -0
  37. package/app-template/src/app/api/theme-settings/route.ts +12 -0
  38. package/app-template/src/assets/fonts/pz-icon.css +211 -49
  39. package/app-template/src/assets/fonts/pz-icon.eot +0 -0
  40. package/app-template/src/assets/fonts/pz-icon.html +486 -0
  41. package/app-template/src/assets/fonts/pz-icon.scss +373 -49
  42. package/app-template/src/assets/fonts/pz-icon.svg +215 -53
  43. package/app-template/src/assets/fonts/pz-icon.ttf +0 -0
  44. package/app-template/src/assets/fonts/pz-icon.woff +0 -0
  45. package/app-template/src/assets/fonts/pz-icon.woff2 +0 -0
  46. package/app-template/src/assets/globals.scss +4 -0
  47. package/app-template/src/assets/icons/arrow-right.svg +3 -0
  48. package/app-template/src/assets/icons/cart.svg +4 -12
  49. package/app-template/src/assets/icons/check.svg +2 -18
  50. package/app-template/src/assets/icons/chevron-down.svg +2 -7
  51. package/app-template/src/assets/icons/delete.svg +3 -0
  52. package/app-template/src/assets/icons/facebook.svg +2 -8
  53. package/app-template/src/assets/icons/fav-off.svg +5 -0
  54. package/app-template/src/assets/icons/fav-on.svg +5 -0
  55. package/app-template/src/assets/icons/filter-and-sort.svg +3 -0
  56. package/app-template/src/assets/icons/heart.svg +3 -0
  57. package/app-template/src/assets/icons/instagram.svg +2 -13
  58. package/app-template/src/assets/icons/materials.svg +3 -0
  59. package/app-template/src/assets/icons/person.svg +4 -0
  60. package/app-template/src/assets/icons/pinterest.svg +5 -11
  61. package/app-template/src/assets/icons/ruler.svg +3 -0
  62. package/app-template/src/assets/icons/search.svg +8 -11
  63. package/app-template/src/assets/icons/share.svg +2 -9
  64. package/app-template/src/assets/icons/snapchat.svg +3 -0
  65. package/app-template/src/assets/icons/tiktok.svg +3 -0
  66. package/app-template/src/assets/icons/tumblr.svg +6 -0
  67. package/app-template/src/assets/icons/twitter.svg +2 -10
  68. package/app-template/src/assets/icons/vimeo.svg +3 -0
  69. package/app-template/src/assets/icons/youtube.svg +3 -0
  70. package/app-template/src/assets/icons/zoom.svg +8 -0
  71. package/app-template/src/components/accordion.tsx +33 -11
  72. package/app-template/src/components/action-tooltip.tsx +160 -0
  73. package/app-template/src/components/currency-select.tsx +149 -4
  74. package/app-template/src/components/icon.tsx +5 -6
  75. package/app-template/src/components/index.ts +4 -1
  76. package/app-template/src/components/language-select.tsx +88 -2
  77. package/app-template/src/components/pagination.tsx +132 -20
  78. package/app-template/src/components/quantity-input.tsx +63 -0
  79. package/app-template/src/components/quantity-selector.tsx +203 -0
  80. package/app-template/src/components/route-handler.tsx +50 -0
  81. package/app-template/src/components/select.tsx +89 -69
  82. package/app-template/src/components/types/index.ts +26 -0
  83. package/app-template/src/components/widget-content.tsx +323 -0
  84. package/app-template/src/data/server/theme.ts +70 -0
  85. package/app-template/src/hooks/use-fav-button.tsx +5 -2
  86. package/app-template/src/hooks/use-product-cart.ts +11 -8
  87. package/app-template/src/hooks/use-theme-settings.ts +42 -0
  88. package/app-template/src/lib/fonts.ts +149 -0
  89. package/app-template/src/settings.js +2 -2
  90. package/app-template/src/types/hookform-resolvers-yup.d.ts +28 -0
  91. package/app-template/src/types/widget.ts +169 -0
  92. package/app-template/src/utils/formatDate.ts +48 -0
  93. package/app-template/src/utils/styles.ts +71 -0
  94. package/app-template/src/views/account/contact-form.tsx +147 -130
  95. package/app-template/src/views/basket/basket-item.tsx +691 -107
  96. package/app-template/src/views/basket/basket-summary-context.tsx +560 -0
  97. package/app-template/src/views/basket/designer-context.tsx +617 -0
  98. package/app-template/src/views/basket/index.ts +2 -0
  99. package/app-template/src/views/basket/summary.tsx +496 -75
  100. package/app-template/src/views/breadcrumb/breadcrumb-client.tsx +190 -0
  101. package/app-template/src/views/breadcrumb/breadcrumb-registrar.tsx +286 -0
  102. package/app-template/src/views/breadcrumb/constants.ts +15 -0
  103. package/app-template/src/views/breadcrumb/index.tsx +127 -0
  104. package/app-template/src/views/breadcrumb.tsx +13 -38
  105. package/app-template/src/views/category/category-banner.tsx +4 -23
  106. package/app-template/src/views/category/category-header.tsx +289 -66
  107. package/app-template/src/views/category/category-info.tsx +173 -24
  108. package/app-template/src/views/category/filters/filter-item.tsx +138 -42
  109. package/app-template/src/views/category/filters/index.tsx +208 -48
  110. package/app-template/src/views/category/layout.tsx +7 -4
  111. package/app-template/src/views/category/native-widget-context.tsx +257 -0
  112. package/app-template/src/views/category/product-list-registrar.tsx +665 -0
  113. package/app-template/src/views/checkout/auth.tsx +64 -40
  114. package/app-template/src/views/checkout/checkout-address-registrar.tsx +254 -0
  115. package/app-template/src/views/checkout/checkout-buttons-registrar.tsx +183 -0
  116. package/app-template/src/views/checkout/checkout-delivery-method-registrar.tsx +259 -0
  117. package/app-template/src/views/checkout/checkout-payment-options-registrar.tsx +253 -0
  118. package/app-template/src/views/checkout/checkout-summary-registrar.tsx +183 -0
  119. package/app-template/src/views/checkout/constants.ts +5 -0
  120. package/app-template/src/views/checkout/index.tsx +5 -0
  121. package/app-template/src/views/checkout/layout/header.tsx +9 -5
  122. package/app-template/src/views/checkout/steps/payment/index.tsx +5 -2
  123. package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +72 -1
  124. package/app-template/src/views/checkout/steps/payment/options/masterpass-rest.tsx +15 -0
  125. package/app-template/src/views/checkout/steps/payment/options/saved-card.tsx +18 -0
  126. package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +171 -40
  127. package/app-template/src/views/checkout/steps/shipping/address-box.tsx +74 -12
  128. package/app-template/src/views/checkout/steps/shipping/addresses.tsx +128 -45
  129. package/app-template/src/views/checkout/steps/shipping/shipping-options.tsx +232 -27
  130. package/app-template/src/views/checkout/summary.tsx +303 -29
  131. package/app-template/src/views/footer/footer-app-banner-context.tsx +326 -0
  132. package/app-template/src/views/footer/footer-bottom-context.tsx +215 -0
  133. package/app-template/src/views/footer/footer-bottom-wrapper.tsx +74 -0
  134. package/app-template/src/views/footer/footer-layout-constants.ts +35 -0
  135. package/app-template/src/views/footer/footer-layout-registrar.tsx +342 -0
  136. package/app-template/src/views/footer/footer-layout-switcher.tsx +110 -0
  137. package/app-template/src/views/footer/footer-menu-context.tsx +211 -0
  138. package/app-template/src/views/footer/footer-native-widgets.tsx +60 -0
  139. package/app-template/src/views/footer/footer-social-context.tsx +254 -0
  140. package/app-template/src/views/footer/footer-subscription-context.tsx +210 -0
  141. package/app-template/src/views/footer/footer-utils.ts +43 -0
  142. package/app-template/src/views/footer/footer-value-props-context.tsx +326 -0
  143. package/app-template/src/views/footer/logo-settings.ts +183 -0
  144. package/app-template/src/views/footer/native-widget-config.ts +262 -0
  145. package/app-template/src/views/footer/subscription-settings.ts +122 -0
  146. package/app-template/src/views/footer/use-footer-logo.ts +162 -0
  147. package/app-template/src/views/footer.tsx +415 -13
  148. package/app-template/src/views/guest-login/index.tsx +62 -58
  149. package/app-template/src/views/header/action-menu.tsx +277 -45
  150. package/app-template/src/views/header/band.tsx +6 -21
  151. package/app-template/src/views/header/designer-context.tsx +261 -0
  152. package/app-template/src/views/header/header-announcement-registrar.tsx +267 -0
  153. package/app-template/src/views/header/header-client-wrapper.tsx +496 -0
  154. package/app-template/src/views/header/header-content.tsx +1026 -0
  155. package/app-template/src/views/header/header-currency-registrar.tsx +348 -0
  156. package/app-template/src/views/header/header-icons-context.tsx +262 -0
  157. package/app-template/src/views/header/header-language-registrar.tsx +348 -0
  158. package/app-template/src/views/header/header-layout-context.tsx +143 -0
  159. package/app-template/src/views/header/header-layout-registrar.tsx +658 -0
  160. package/app-template/src/views/header/header-logo-context.tsx +228 -0
  161. package/app-template/src/views/header/header-logo.tsx +118 -0
  162. package/app-template/src/views/header/header-mini-basket-context.tsx +524 -0
  163. package/app-template/src/views/header/header-search-registrar.tsx +511 -0
  164. package/app-template/src/views/header/header-text-slider-registrar.tsx +382 -0
  165. package/app-template/src/views/header/index.tsx +109 -47
  166. package/app-template/src/views/header/inline-search.tsx +262 -0
  167. package/app-template/src/views/header/mini-basket.tsx +819 -44
  168. package/app-template/src/views/header/mobile-hamburger-button.tsx +5 -8
  169. package/app-template/src/views/header/mobile-menu.tsx +12 -0
  170. package/app-template/src/views/header/navbar-menu-context.tsx +219 -0
  171. package/app-template/src/views/header/navbar.tsx +178 -111
  172. package/app-template/src/views/header/search/index.tsx +71 -32
  173. package/app-template/src/views/header/search/results.tsx +127 -65
  174. package/app-template/src/views/header/search/search-input.tsx +61 -0
  175. package/app-template/src/views/header/server-settings-parser.ts +1105 -0
  176. package/app-template/src/views/header/use-header-icons.ts +241 -0
  177. package/app-template/src/views/header/use-header-logo.ts +213 -0
  178. package/app-template/src/views/header/use-navbar-menu.ts +179 -0
  179. package/app-template/src/views/login/index.tsx +54 -46
  180. package/app-template/src/views/product/accordion-section.tsx +61 -0
  181. package/app-template/src/views/product/accordion-wrapper.tsx +135 -43
  182. package/app-template/src/views/product/custom-button-group.tsx +69 -0
  183. package/app-template/src/views/product/favorites-button-section.tsx +69 -0
  184. package/app-template/src/views/product/find-in-store-section.tsx +60 -0
  185. package/app-template/src/views/product/index.ts +1 -0
  186. package/app-template/src/views/product/layout.tsx +6 -5
  187. package/app-template/src/views/product/misc-buttons.tsx +339 -25
  188. package/app-template/src/views/product/price-wrapper.tsx +3 -29
  189. package/app-template/src/views/product/product-actions.tsx +137 -8
  190. package/app-template/src/views/product/product-info-section.tsx +140 -0
  191. package/app-template/src/views/product/product-info.tsx +69 -31
  192. package/app-template/src/views/product/product-share.tsx +13 -8
  193. package/app-template/src/views/product/product-variants.tsx +2 -2
  194. package/app-template/src/views/product/quantity-section.tsx +73 -0
  195. package/app-template/src/views/product/sale-tag.tsx +10 -0
  196. package/app-template/src/views/product/share-section.tsx +357 -0
  197. package/app-template/src/views/product/slider.tsx +117 -79
  198. package/app-template/src/views/product/variant.tsx +69 -41
  199. package/app-template/src/views/product/variants-section.tsx +126 -0
  200. package/app-template/src/views/product-detail/constants.ts +272 -0
  201. package/app-template/src/views/product-detail/index.ts +10 -0
  202. package/app-template/src/views/product-detail/product-detail-registrar.tsx +616 -0
  203. package/app-template/src/views/product-item/index.tsx +119 -46
  204. package/app-template/src/views/register/index.tsx +14 -25
  205. package/app-template/src/views/share/index.tsx +9 -6
  206. package/app-template/src/views/widgets/home-hero-slider-content.tsx +41 -39
  207. package/app-template/src/widgets/flatpages/about-us/index.tsx +78 -0
  208. package/app-template/src/widgets/flatpages/blog-list/index.tsx +129 -0
  209. package/app-template/src/widgets/footer-app-banner.tsx +444 -0
  210. package/app-template/src/widgets/footer-bottom.tsx +127 -0
  211. package/app-template/src/widgets/footer-menu-compact.tsx +238 -0
  212. package/app-template/src/widgets/footer-menu-two.tsx +298 -0
  213. package/app-template/src/widgets/footer-social-client.tsx +251 -0
  214. package/app-template/src/widgets/footer-social.tsx +47 -16
  215. package/app-template/src/widgets/footer-subscription/footer-subscription-form.tsx +17 -14
  216. package/app-template/src/widgets/footer-subscription/index.tsx +183 -17
  217. package/app-template/src/widgets/footer-value-props.tsx +201 -0
  218. package/app-template/src/widgets/index.ts +7 -0
  219. package/app-template/src/widgets/schemas/about-us.json +46 -0
  220. package/app-template/src/widgets/schemas/blog-list.json +37 -0
  221. package/app-template/src/widgets/schemas/blog.json +29 -0
  222. package/app-template/tailwind.config.js +18 -2
  223. package/package.json +1 -1
@@ -0,0 +1,511 @@
1
+ 'use client';
2
+
3
+ import {
4
+ createContext,
5
+ useContext,
6
+ useEffect,
7
+ useRef,
8
+ useState,
9
+ useCallback,
10
+ PropsWithChildren
11
+ } from 'react';
12
+ import { useNativeWidgetData } from '@akinon/next/components/theme-editor/hooks/use-native-widget-data';
13
+ import { useHeaderLayout } from './header-layout-registrar';
14
+
15
+ export const HEADER_SEARCH_PLACEHOLDER_ID = 'header';
16
+ export const HEADER_SEARCH_SECTION_ID = 'header-search';
17
+ export const HEADER_SEARCH_WIDGET_SLUG = 'header-search-settings-2';
18
+
19
+ export const HEADER_SEARCH_BLOCKS = {
20
+ ICON: {
21
+ id: 'header-search-icon',
22
+ type: 'icon-button',
23
+ label: 'Search Icon'
24
+ }
25
+ } as const;
26
+
27
+ const BLOCK_META = [HEADER_SEARCH_BLOCKS.ICON];
28
+
29
+ declare global {
30
+ interface Window {
31
+ __headerSearchRegistered?: boolean;
32
+ __headerSearchCurrentLayout?: string;
33
+ }
34
+ }
35
+
36
+ interface ThemeBlock {
37
+ id: string;
38
+ type: string;
39
+ label: string;
40
+ styles?: Record<string, unknown>;
41
+ properties?: Record<string, unknown>;
42
+ }
43
+
44
+ interface ThemeSection {
45
+ id: string;
46
+ blocks: ThemeBlock[];
47
+ visible?: boolean;
48
+ properties?: Record<string, unknown>;
49
+ styles?: Record<string, unknown>;
50
+ }
51
+
52
+ interface ThemePlaceholder {
53
+ slug: string;
54
+ sections: ThemeSection[];
55
+ }
56
+
57
+ export interface HeaderSearchProperties {
58
+ placeholder?: string;
59
+ visible?: boolean;
60
+ width?: string | number | Record<string, string | number>;
61
+ }
62
+
63
+ interface HeaderSearchContextValue {
64
+ isDesigner: boolean;
65
+ isSearchSectionSelected: boolean;
66
+ isSectionVisible: boolean;
67
+ properties: HeaderSearchProperties;
68
+ sectionStyles: Record<string, unknown>;
69
+ selectedBlockId: string | null;
70
+ getBlockStyles: (blockId: string) => Record<string, unknown> | undefined;
71
+ getBlockProperties: (blockId: string) => Record<string, unknown> | undefined;
72
+ }
73
+
74
+ const HeaderSearchContext = createContext<HeaderSearchContextValue>({
75
+ isDesigner: false,
76
+ isSearchSectionSelected: false,
77
+ isSectionVisible: true,
78
+ properties: {},
79
+ sectionStyles: {},
80
+ selectedBlockId: null,
81
+ getBlockStyles: () => undefined,
82
+ getBlockProperties: () => undefined
83
+ });
84
+
85
+ export const useHeaderSearch = () => useContext(HeaderSearchContext);
86
+
87
+ export interface InitialSearchSettings {
88
+ sectionStyles?: {
89
+ width?: string | number;
90
+ maxWidth?: string;
91
+ height?: string | number;
92
+ backgroundColor?: string;
93
+ borderColor?: string;
94
+ borderWidth?: string;
95
+ borderRadius?: string;
96
+ fontSize?: string;
97
+ paddingLeft?: string;
98
+ paddingRight?: string;
99
+ };
100
+ iconStyles?: {
101
+ color?: string;
102
+ iconSize?: number;
103
+ };
104
+ properties?: {
105
+ placeholder?: string;
106
+ visible?: boolean;
107
+ width?: string | number;
108
+ };
109
+ }
110
+
111
+ interface HeaderSearchRegistrarProps extends PropsWithChildren {
112
+ autoRegister?: boolean;
113
+ initialSettings?: InitialSearchSettings;
114
+ }
115
+
116
+ export default function HeaderSearchRegistrar({
117
+ children,
118
+ autoRegister = false,
119
+ initialSettings = {}
120
+ }: HeaderSearchRegistrarProps) {
121
+ const isDesignerRef = useRef(false);
122
+ const [isDesignerChecked, setIsDesignerChecked] = useState(false);
123
+ const [sectionProperties, setSectionProperties] =
124
+ useState<HeaderSearchProperties>(initialSettings.properties || {});
125
+ const [sectionStyles, setSectionStyles] = useState<Record<string, unknown>>(
126
+ initialSettings.sectionStyles || {}
127
+ );
128
+ const [isSearchSelected, setIsSearchSelected] = useState(false);
129
+ const [selectedBlockId, setSelectedBlockId] = useState<string | null>(null);
130
+ const [isSectionVisible, setIsSectionVisible] = useState(true);
131
+ const [themeBlocks, setThemeBlocks] = useState<Map<string, ThemeBlock>>(
132
+ () => {
133
+ const initialMap = new Map<string, ThemeBlock>();
134
+ if (
135
+ initialSettings.iconStyles &&
136
+ Object.keys(initialSettings.iconStyles).length > 0
137
+ ) {
138
+ initialMap.set(HEADER_SEARCH_BLOCKS.ICON.id, {
139
+ id: HEADER_SEARCH_BLOCKS.ICON.id,
140
+ type: HEADER_SEARCH_BLOCKS.ICON.type,
141
+ label: HEADER_SEARCH_BLOCKS.ICON.label,
142
+ styles: initialSettings.iconStyles,
143
+ properties: {}
144
+ });
145
+ }
146
+ return initialMap;
147
+ }
148
+ );
149
+ const themeBlocksRef = useRef<Map<string, ThemeBlock>>(
150
+ (() => {
151
+ const initialMap = new Map<string, ThemeBlock>();
152
+ if (
153
+ initialSettings.iconStyles &&
154
+ Object.keys(initialSettings.iconStyles).length > 0
155
+ ) {
156
+ initialMap.set(HEADER_SEARCH_BLOCKS.ICON.id, {
157
+ id: HEADER_SEARCH_BLOCKS.ICON.id,
158
+ type: HEADER_SEARCH_BLOCKS.ICON.type,
159
+ label: HEADER_SEARCH_BLOCKS.ICON.label,
160
+ styles: initialSettings.iconStyles,
161
+ properties: {}
162
+ });
163
+ }
164
+ return initialMap;
165
+ })()
166
+ );
167
+ const hasRegisteredNativeWidget = useRef(false);
168
+
169
+ const hasInitialSettings = !!(
170
+ (initialSettings.sectionStyles &&
171
+ Object.keys(initialSettings.sectionStyles).length > 0) ||
172
+ (initialSettings.iconStyles &&
173
+ Object.keys(initialSettings.iconStyles).length > 0) ||
174
+ (initialSettings.properties &&
175
+ Object.keys(initialSettings.properties).length > 0)
176
+ );
177
+ const hasReceivedThemeProps = useRef(false);
178
+
179
+ const { layout } = useHeaderLayout();
180
+
181
+ useEffect(() => {
182
+ if (typeof window === 'undefined') return;
183
+ isDesignerRef.current = window.self !== window.top;
184
+ setIsDesignerChecked(true);
185
+ }, []);
186
+
187
+ const isDesigner = isDesignerRef.current;
188
+
189
+ const widgetData = useNativeWidgetData({
190
+ widgetSlug: HEADER_SEARCH_WIDGET_SLUG,
191
+ sectionId: HEADER_SEARCH_SECTION_ID,
192
+ skip: !isDesignerChecked || !isDesigner || hasInitialSettings,
193
+ blockMeta: BLOCK_META
194
+ });
195
+
196
+ const getBlockWithStyles = useCallback(
197
+ (
198
+ blockDef: typeof HEADER_SEARCH_BLOCKS[keyof typeof HEADER_SEARCH_BLOCKS]
199
+ ) => {
200
+ const existingBlock = themeBlocksRef.current.get(blockDef.id);
201
+ return {
202
+ id: blockDef.id,
203
+ type: blockDef.type,
204
+ label: blockDef.label,
205
+ properties: existingBlock?.properties || {},
206
+ styles: existingBlock?.styles || {}
207
+ };
208
+ },
209
+ []
210
+ );
211
+
212
+ useEffect(() => {
213
+ const isInIframe =
214
+ typeof window !== 'undefined' && window.self !== window.top;
215
+ if (!isInIframe || !window.parent) {
216
+ return;
217
+ }
218
+
219
+ const previousLayout = window.__headerSearchCurrentLayout;
220
+ window.__headerSearchCurrentLayout = layout;
221
+
222
+ const shouldRegister = autoRegister || layout === 'two-row';
223
+
224
+ if (previousLayout === 'two-row' && layout === 'default' && !autoRegister) {
225
+ window.parent.postMessage(
226
+ {
227
+ type: 'UNREGISTER_NATIVE_SECTION',
228
+ data: {
229
+ placeholderId: HEADER_SEARCH_PLACEHOLDER_ID,
230
+ sectionId: HEADER_SEARCH_SECTION_ID
231
+ }
232
+ },
233
+ '*'
234
+ );
235
+ hasRegisteredNativeWidget.current = false;
236
+ window.__headerSearchRegistered = false;
237
+ return;
238
+ }
239
+
240
+ if (!shouldRegister) {
241
+ return;
242
+ }
243
+
244
+ if (
245
+ typeof window !== 'undefined' &&
246
+ window.__headerSearchRegistered &&
247
+ hasRegisteredNativeWidget.current
248
+ ) {
249
+ return;
250
+ }
251
+
252
+ const nativeWidgetConfig = {
253
+ placeholderId: HEADER_SEARCH_PLACEHOLDER_ID,
254
+ section: {
255
+ id: HEADER_SEARCH_SECTION_ID,
256
+ type: 'native',
257
+ label: 'Search',
258
+ blocks: [getBlockWithStyles(HEADER_SEARCH_BLOCKS.ICON)],
259
+ properties: sectionProperties,
260
+ styles: sectionStyles
261
+ }
262
+ };
263
+
264
+ window.parent.postMessage(
265
+ {
266
+ type: 'REGISTER_NATIVE_WIDGETS',
267
+ data: { widgets: [nativeWidgetConfig] }
268
+ },
269
+ '*'
270
+ );
271
+
272
+ window.__headerSearchRegistered = true;
273
+ hasRegisteredNativeWidget.current = true;
274
+ }, [
275
+ layout,
276
+ autoRegister,
277
+ getBlockWithStyles,
278
+ sectionProperties,
279
+ sectionStyles
280
+ ]);
281
+
282
+ useEffect(() => {
283
+ if (typeof window === 'undefined') return;
284
+
285
+ const searchContainer = document.querySelector(
286
+ '[data-section-id="header-search"]'
287
+ );
288
+ if (!searchContainer) return;
289
+
290
+ if (isSearchSelected) {
291
+ (searchContainer as HTMLElement).style.outline = '2px solid #3b82f6';
292
+ (searchContainer as HTMLElement).style.outlineOffset = '-2px';
293
+ } else {
294
+ (searchContainer as HTMLElement).style.outline = '';
295
+ (searchContainer as HTMLElement).style.outlineOffset = '';
296
+ }
297
+
298
+ return () => {
299
+ (searchContainer as HTMLElement).style.outline = '';
300
+ (searchContainer as HTMLElement).style.outlineOffset = '';
301
+ };
302
+ }, [isSearchSelected]);
303
+
304
+ useEffect(() => {
305
+ if (!isDesignerChecked) return;
306
+ if (!isDesigner) return;
307
+ if (hasInitialSettings) return;
308
+ if (widgetData.isLoading || hasReceivedThemeProps.current) return;
309
+
310
+ if (widgetData.sectionProperties && Object.keys(widgetData.sectionProperties).length > 0) {
311
+ setSectionProperties(widgetData.sectionProperties as HeaderSearchProperties);
312
+ }
313
+ if (widgetData.sectionStyles && Object.keys(widgetData.sectionStyles).length > 0) {
314
+ setSectionStyles(widgetData.sectionStyles);
315
+ }
316
+
317
+ const blockMap = new Map<string, ThemeBlock>();
318
+ widgetData.blocks.forEach((block) => {
319
+ blockMap.set(block.id, {
320
+ id: block.id,
321
+ type: block.type || 'icon-button',
322
+ label: block.label || block.id,
323
+ styles: block.styles,
324
+ properties: block.properties
325
+ });
326
+ });
327
+
328
+ if (blockMap.size > 0) {
329
+ setThemeBlocks(blockMap);
330
+ themeBlocksRef.current = blockMap;
331
+ }
332
+
333
+ hasReceivedThemeProps.current = true;
334
+ }, [widgetData, isDesignerChecked, isDesigner, hasInitialSettings]);
335
+
336
+ const indexBlocks = useCallback(
337
+ (blocks: ThemeBlock[], map: Map<string, ThemeBlock>) => {
338
+ blocks.forEach((block) => {
339
+ map.set(block.id, block);
340
+ });
341
+ },
342
+ []
343
+ );
344
+
345
+ useEffect(() => {
346
+ if (typeof window === 'undefined') return;
347
+
348
+ const handleMessage = (event: MessageEvent) => {
349
+ const { type, data } = event.data || {};
350
+
351
+ if (
352
+ (type === 'UPDATE_THEME' || type === 'LOAD_THEME') &&
353
+ data?.theme?.placeholders
354
+ ) {
355
+ const placeholder = data.theme.placeholders?.find(
356
+ (p: ThemePlaceholder) => p.slug === HEADER_SEARCH_PLACEHOLDER_ID
357
+ );
358
+
359
+ const searchSection = placeholder?.sections?.find(
360
+ (s: ThemeSection) => s.id === HEADER_SEARCH_SECTION_ID
361
+ );
362
+
363
+ if (searchSection) {
364
+ const shouldUpdateStyles =
365
+ type === 'UPDATE_THEME' || !hasInitialSettings;
366
+
367
+ if (shouldUpdateStyles) {
368
+ hasReceivedThemeProps.current = true;
369
+
370
+ if (searchSection.properties) {
371
+ setSectionProperties(searchSection.properties as HeaderSearchProperties);
372
+ }
373
+
374
+ if (searchSection.styles) {
375
+ setSectionStyles(searchSection.styles);
376
+ }
377
+
378
+ if (searchSection.blocks) {
379
+ const blockMap = new Map<string, ThemeBlock>();
380
+ indexBlocks(searchSection.blocks, blockMap);
381
+ if (blockMap.size > 0) {
382
+ setThemeBlocks(blockMap);
383
+ themeBlocksRef.current = blockMap;
384
+ }
385
+ }
386
+ }
387
+
388
+ if (typeof searchSection.visible === 'boolean') {
389
+ setIsSectionVisible(searchSection.visible);
390
+ } else {
391
+ setIsSectionVisible(true);
392
+ }
393
+ } else if (placeholder) {
394
+ setIsSectionVisible(false);
395
+ }
396
+ }
397
+
398
+ if (type === 'UPDATE_SECTION_PROPERTY' || type === 'UPDATE_PROPERTY') {
399
+ const { sectionId, placeholderId, key, value, properties } = data || {};
400
+
401
+ if (
402
+ sectionId === HEADER_SEARCH_SECTION_ID ||
403
+ placeholderId === HEADER_SEARCH_PLACEHOLDER_ID
404
+ ) {
405
+ if (key && value !== undefined) {
406
+ setSectionProperties((prev) => ({
407
+ ...prev,
408
+ [key]: value
409
+ }));
410
+ }
411
+ if (properties) {
412
+ setSectionProperties(properties);
413
+ }
414
+ }
415
+ }
416
+
417
+ if (type === 'UPDATE_SECTION_STYLE' || type === 'UPDATE_STYLE') {
418
+ const { sectionId, placeholderId, key, value, styles } = data || {};
419
+
420
+ if (
421
+ sectionId === HEADER_SEARCH_SECTION_ID ||
422
+ placeholderId === HEADER_SEARCH_PLACEHOLDER_ID
423
+ ) {
424
+ if (key && value !== undefined) {
425
+ setSectionStyles((prev) => ({
426
+ ...prev,
427
+ [key]: value
428
+ }));
429
+ }
430
+ if (styles) {
431
+ setSectionStyles(styles);
432
+ }
433
+ }
434
+ }
435
+
436
+ if (type === 'SELECT_SECTION') {
437
+ const { placeholderId, sectionId } = data || {};
438
+
439
+ const isSelected =
440
+ placeholderId === HEADER_SEARCH_PLACEHOLDER_ID &&
441
+ sectionId === HEADER_SEARCH_SECTION_ID;
442
+
443
+ setIsSearchSelected(isSelected);
444
+ if (!isSelected) {
445
+ setSelectedBlockId(null);
446
+ }
447
+ }
448
+
449
+ if (type === 'SELECT_BLOCK') {
450
+ const { sectionId, blockId } = data || {};
451
+ if (sectionId === HEADER_SEARCH_SECTION_ID) {
452
+ setSelectedBlockId(blockId || null);
453
+ setIsSearchSelected(true);
454
+ } else {
455
+ setIsSearchSelected(false);
456
+ setSelectedBlockId(null);
457
+ }
458
+ }
459
+
460
+ if (type === 'DESELECT' || type === 'CLEAR_SELECTION') {
461
+ setIsSearchSelected(false);
462
+ setSelectedBlockId(null);
463
+ }
464
+
465
+ if (type === 'TOGGLE_SECTION_VISIBILITY') {
466
+ const { sectionId } = data || {};
467
+ if (sectionId === HEADER_SEARCH_SECTION_ID) {
468
+ setIsSectionVisible((prev) => !prev);
469
+ }
470
+ }
471
+ };
472
+
473
+ window.addEventListener('message', handleMessage);
474
+ return () => window.removeEventListener('message', handleMessage);
475
+ }, [indexBlocks, hasInitialSettings]);
476
+
477
+ const getBlockStyles = useCallback(
478
+ (blockId: string) => {
479
+ return themeBlocks.get(blockId)?.styles;
480
+ },
481
+ [themeBlocks]
482
+ );
483
+
484
+ const getBlockProperties = useCallback(
485
+ (blockId: string) => {
486
+ return themeBlocks.get(blockId)?.properties;
487
+ },
488
+ [themeBlocks]
489
+ );
490
+
491
+ if (!children) {
492
+ return null;
493
+ }
494
+
495
+ return (
496
+ <HeaderSearchContext.Provider
497
+ value={{
498
+ isDesigner,
499
+ isSearchSectionSelected: isSearchSelected,
500
+ isSectionVisible,
501
+ properties: sectionProperties,
502
+ sectionStyles,
503
+ selectedBlockId,
504
+ getBlockStyles,
505
+ getBlockProperties
506
+ }}
507
+ >
508
+ {children}
509
+ </HeaderSearchContext.Provider>
510
+ );
511
+ }