@gem-sdk/pages 1.23.0-staging.27 → 1.23.0-staging.270

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.
@@ -1,105 +1,66 @@
1
- import { memo, useRef, useCallback, useEffect } from 'react';
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { memo, useRef, useState, useCallback, useEffect } from 'react';
3
+ import Onboarding from './toolbar/Onboarding.js';
2
4
 
3
5
  const TOOLBAR_HOVER_HEIGHT = 24;
4
- // const TOOLBAR_ACTIVE_HEIGHT = 32;
5
- const getDOMElementParents = ($el, selector, limit)=>{
6
- // Set up a parent array
7
- const parents = [];
8
- // Push each parent $elms to the array
9
- while($el){
10
- $el = $el.parentElement ?? undefined;
11
- if ($el) {
12
- if ($el.tagName === 'BODY' || $el.getAttribute('data-uid') === 'ROOT') {
13
- break;
14
- }
15
- if (selector) {
16
- if ($el.matches(selector)) {
17
- parents.push($el);
18
- if (limit && parents.length == limit) {
19
- return parents;
20
- }
21
- }
22
- continue;
23
- }
24
- parents.push($el);
25
- if (limit && parents.length == limit) {
26
- return parents;
27
- }
28
- }
29
- }
30
- // Return our parent array
31
- return parents;
32
- };
33
- const getChildrenByAttrSelector = ($el, attrSelector)=>{
34
- const childLen = $el.children.length;
35
- if (childLen) {
36
- for(let i = 0; i < childLen; i++){
37
- const children = $el.children[i];
38
- if (children) {
39
- const is = children.getAttribute(attrSelector);
40
- if (is) {
41
- return children;
42
- }
43
- }
44
- }
45
- }
46
- };
47
- const isOverParent = (current, parent, index)=>{
48
- for(let i = 0; i < index; i++){
49
- const is = current.top - (TOOLBAR_HOVER_HEIGHT - 1) * i >= parent.top && current.top - (TOOLBAR_HOVER_HEIGHT - 1) * i <= parent.top + parent.height && current.left >= parent.left && current.left <= parent.left + parent.width;
50
- if (is) return true;
51
- }
52
- return false;
53
- };
54
- const waitForElementToExist = (selector, timeout = 200)=>{
55
- return new Promise((resolve)=>{
56
- const intervalID = setInterval(()=>{
57
- const el = document.querySelector(selector);
58
- if (el) {
59
- clearInterval(intervalID);
60
- clearTimeout(timeoutID);
61
- resolve(el);
62
- }
63
- }, 50);
64
- const timeoutID = setTimeout(()=>{
65
- clearInterval(intervalID);
66
- clearTimeout(timeoutID);
67
- resolve(null);
68
- }, timeout);
69
- });
70
- };
71
- const notVisible = (el)=>{
72
- const overflow = getComputedStyle(el).overflow;
73
- return overflow !== 'visible';
74
- };
75
- const isSection = (el)=>{
6
+ const TOOLBAR_ACTIVE_HEIGHT = 32;
7
+ const isPopup = (el)=>{
76
8
  const tag = el.getAttribute('data-component-tag');
77
- return tag === 'Section';
78
- };
79
- const isOverToolbarPosition = (el, parent)=>{
80
- const rect = el.getBoundingClientRect();
81
- const rectP = parent.getBoundingClientRect();
82
- // 32px = toolbar active height
83
- return rect.top - rectP.top < 32 + 5;
9
+ return tag === 'Dialog';
84
10
  };
85
- const findOverflowParent = (element, initEl)=>{
86
- const thisEl = element;
87
- const origEl = initEl || thisEl;
88
- if (!thisEl) return;
89
- if (isSection(thisEl)) return;
90
- if (notVisible(thisEl) && isOverToolbarPosition(initEl, thisEl)) return thisEl;
91
- if (thisEl.parentElement) {
92
- return findOverflowParent(thisEl.parentElement, origEl);
93
- } else {
94
- return;
95
- }
11
+ const isSticky = (el)=>{
12
+ const tag = el.getAttribute('data-component-tag');
13
+ return tag === 'Sticky';
96
14
  };
97
15
  const Toolbar = ()=>{
98
16
  const currentComponentActive = useRef(null);
99
17
  const isDragging = useRef(false);
100
- const obsActiveComponent = useRef();
18
+ const stopWatchReRenderComponent = useRef();
101
19
  const isResizeSpacing = useRef(false);
102
- /* Functions */ const setHoverComponent = useCallback(({ $component, componentUid, focus, isThemeSection })=>{
20
+ const [isOnboarding, setIsOnboarding] = useState(false);
21
+ const [countShowOnboarding, setCountShowOnboarding] = useState(0);
22
+ const [onboardingPosition, setOnboardingPosition] = useState('bottom');
23
+ const timeoutRef = useRef(null);
24
+ const timeoutOnboarding = 5000;
25
+ /* Functions */ const changePositionToolbar = ({ state, $toolbar, $component })=>{
26
+ const $parentOverflow = findOverflowParent($component, $toolbar);
27
+ const rect = $toolbar.getBoundingClientRect();
28
+ const rectComponent = $component.getBoundingClientRect();
29
+ const windowWidth = window.innerWidth;
30
+ if ($parentOverflow) {
31
+ if (rectComponent?.height <= 60) {
32
+ $toolbar.setAttribute(`data-toolbar-${state}-revert`, 'true');
33
+ } else {
34
+ $toolbar.setAttribute(`data-toolbar-${state}-inside`, 'true');
35
+ }
36
+ // fix toolbar overflow right side
37
+ if (rectComponent.left + rect.width > windowWidth) {
38
+ $toolbar.setAttribute(`data-toolbar-${state}-overflow`, 'true');
39
+ }
40
+ } else {
41
+ if (rect.top < TOOLBAR_ACTIVE_HEIGHT + 1) {
42
+ if (rectComponent?.height <= 60) {
43
+ $toolbar.setAttribute(`data-toolbar-${state}-revert`, 'true');
44
+ } else {
45
+ $toolbar.setAttribute(`data-toolbar-${state}-inside`, 'true');
46
+ }
47
+ }
48
+ // fix toolbar overflow right side
49
+ if (rectComponent.left + rect.width > windowWidth) {
50
+ $toolbar.setAttribute(`data-toolbar-${state}-overflow`, 'true');
51
+ }
52
+ }
53
+ // fix Popup overflow right position
54
+ const popupEl = $component?.closest('[aria-label="Dialog body"]');
55
+ if (popupEl) {
56
+ const rectPopupEl = popupEl.getBoundingClientRect();
57
+ const popupElRightPosition = rectPopupEl.left + rectPopupEl.width - 20;
58
+ if (rectComponent.left + rect.width > popupElRightPosition) {
59
+ $toolbar.setAttribute(`data-toolbar-${state}-overflow`, 'true');
60
+ }
61
+ }
62
+ };
63
+ const setHoverComponent = useCallback(({ $component, componentUid, focus, isThemeSection, isParent })=>{
103
64
  if (!$component && !componentUid) return;
104
65
  if (!$component) {
105
66
  const $c = document.querySelector(`[data-uid="${componentUid}"]`);
@@ -121,17 +82,23 @@ const Toolbar = ()=>{
121
82
  }
122
83
  if ($toolbar) {
123
84
  $toolbar.removeAttribute('style');
124
- $toolbar.setAttribute('data-toolbar-hover', 'true');
85
+ if (!isParent) {
86
+ $toolbar.setAttribute('data-toolbar-hover', 'true');
87
+ }
125
88
  if (focus) {
126
89
  $toolbar.setAttribute('data-toolbar-hover-focus', 'true');
127
90
  }
128
- const $parentOverflow = findOverflowParent($component, $toolbar);
129
- if ($parentOverflow) {
130
- $toolbar.setAttribute('data-toolbar-hover-revert', 'true');
131
- }
91
+ changePositionToolbar({
92
+ $toolbar,
93
+ $component,
94
+ state: 'hover'
95
+ });
132
96
  }
133
97
  if ($outline) {
134
98
  $outline.setAttribute('data-outline-hover', 'true');
99
+ if (isParent) {
100
+ $outline.setAttribute('data-outline-parent-hover', 'true');
101
+ }
135
102
  if (isThemeSection) {
136
103
  $outline.setAttribute('data-outline-overlay-theme-section', 'true');
137
104
  }
@@ -140,10 +107,14 @@ const Toolbar = ()=>{
140
107
  }
141
108
  }
142
109
  if ($btnAddTop) {
143
- $btnAddTop.setAttribute('data-toolbar-add-hover', 'true');
110
+ if (!isParent) {
111
+ $btnAddTop.setAttribute('data-toolbar-add-hover', 'true');
112
+ }
144
113
  }
145
114
  if ($btnAddBottom) {
146
- $btnAddBottom.setAttribute('data-toolbar-add-hover', 'true');
115
+ if (!isParent) {
116
+ $btnAddBottom.setAttribute('data-toolbar-add-hover', 'true');
117
+ }
147
118
  }
148
119
  }, []);
149
120
  const setHoverComponentParents = useCallback(({ $component, componentUid })=>{
@@ -152,12 +123,13 @@ const Toolbar = ()=>{
152
123
  if (!$c) return;
153
124
  $component = $c;
154
125
  }
155
- const $parents = getDOMElementParents($component, '[data-uid][data-component-type="component"]:not([data-component-no-setting])');
126
+ const $parents = getDOMElementParents($component, '[data-uid][data-component-type="component"]:not([data-component-no-setting])', 1);
156
127
  if ($parents.length) {
157
128
  for (const $parent of $parents){
158
129
  if ($parent) {
159
130
  setHoverComponent({
160
- $component: $parent
131
+ $component: $parent,
132
+ isParent: true
161
133
  });
162
134
  }
163
135
  }
@@ -175,6 +147,8 @@ const Toolbar = ()=>{
175
147
  const $currentToolbar = getChildrenByAttrSelector($component, 'data-toolbar-hover-focus');
176
148
  if ($currentToolbar) {
177
149
  const currentRect = $currentToolbar.getBoundingClientRect();
150
+ const isRevert = $currentToolbar.getAttribute('data-toolbar-hover-revert') ? true : false;
151
+ const isInside = $currentToolbar.getAttribute('data-toolbar-hover-inside') ? true : false;
178
152
  let index = 1;
179
153
  for (const $parent of $parents){
180
154
  if ($parent) {
@@ -187,14 +161,19 @@ const Toolbar = ()=>{
187
161
  if (isActive) continue;
188
162
  // Start calc
189
163
  const parentRect = $toolbar.getBoundingClientRect();
190
- if (isOverParent(currentRect, parentRect, index)) {
164
+ const checkRevert = isRevert || isInside;
165
+ if (isOverParent({
166
+ current: currentRect,
167
+ parent: parentRect,
168
+ index,
169
+ revert: checkRevert
170
+ })) {
191
171
  const parentStyle = getComputedStyle($toolbar);
192
- const isRevert = $toolbar.getAttribute('data-toolbar-hover-revert') ? true : false;
193
172
  // parentStyle.top
194
173
  const diffTop = currentRect.top - parentRect.top;
195
174
  const diffLeft = currentRect.left - parentRect.left;
196
175
  let newTop = parseFloat(parentStyle.top) + diffTop - (TOOLBAR_HOVER_HEIGHT - 1) * index; // -1 border bottom
197
- if (isRevert) {
176
+ if (checkRevert) {
198
177
  newTop = parseFloat(parentStyle.top) - diffTop + (TOOLBAR_HOVER_HEIGHT - 1) * index; // -1 border bottom
199
178
  }
200
179
  const newLeft = parseFloat(parentStyle.left) + diffLeft;
@@ -225,8 +204,11 @@ const Toolbar = ()=>{
225
204
  'data-toolbar-hover',
226
205
  'data-outline-hover-focus',
227
206
  'data-toolbar-hover-revert',
207
+ 'data-toolbar-hover-inside',
228
208
  'data-outline-hover',
229
- 'data-toolbar-add-hover'
209
+ 'data-toolbar-add-hover',
210
+ 'data-outline-parent-hover',
211
+ 'data-toolbar-hover-overflow'
230
212
  ];
231
213
  const $elms = document.querySelectorAll(clearAttrs.map((attr)=>`[${attr}]`).join(','));
232
214
  if ($elms) {
@@ -238,6 +220,21 @@ const Toolbar = ()=>{
238
220
  }, [
239
221
  removeHoverOverlayComponent
240
222
  ]);
223
+ const onCloseOnboarding = useCallback(()=>{
224
+ timeoutRef.current && clearTimeout(timeoutRef.current);
225
+ if (countShowOnboarding > 0) {
226
+ const eventCreate = new CustomEvent('editor:toolbar:close-onboarding', {
227
+ bubbles: true,
228
+ detail: {
229
+ close: 'close Onboarding'
230
+ }
231
+ });
232
+ window.dispatchEvent(eventCreate);
233
+ setIsOnboarding(false);
234
+ }
235
+ }, [
236
+ countShowOnboarding
237
+ ]);
241
238
  const removeActiveComponent = useCallback(()=>{
242
239
  currentComponentActive.current = null;
243
240
  const clearAttrs = [
@@ -245,9 +242,11 @@ const Toolbar = ()=>{
245
242
  'data-outline-active',
246
243
  'data-toolbar-add-active',
247
244
  'data-toolbar-active-revert',
245
+ 'data-toolbar-active-inside',
248
246
  'data-spacing-margin-bottom-active',
249
247
  'data-toolbar-force-hover',
250
- 'data-outline-force-hover'
248
+ 'data-outline-force-hover',
249
+ 'data-toolbar-active-overflow'
251
250
  ];
252
251
  const $elms = document.querySelectorAll(clearAttrs.map((attr)=>`[${attr}]`).join(','));
253
252
  if ($elms) {
@@ -256,25 +255,32 @@ const Toolbar = ()=>{
256
255
  });
257
256
  }
258
257
  setFocusTextEditor(false);
259
- if (obsActiveComponent.current) obsActiveComponent.current.disconnect();
260
- }, []);
258
+ if (stopWatchReRenderComponent.current) stopWatchReRenderComponent.current();
259
+ onCloseOnboarding();
260
+ }, [
261
+ onCloseOnboarding
262
+ ]);
261
263
  const watchComponentReRender = ($el, callback)=>{
262
- const parent = $el.parentNode;
263
- if (!parent) return;
264
- if (obsActiveComponent.current) obsActiveComponent.current.disconnect();
265
- obsActiveComponent.current = new MutationObserver((mutations)=>{
266
- for (const mutation of mutations){
267
- mutation.removedNodes.forEach((el)=>{
268
- if (el === $el) {
269
- if (obsActiveComponent.current) obsActiveComponent.current.disconnect();
270
- callback();
271
- }
272
- });
264
+ // editor:component:render
265
+ const onComponentReRender = (e)=>{
266
+ const detail = e.detail;
267
+ if (detail?.componentUid == currentComponentActive.current?.componentUid) {
268
+ callback();
273
269
  }
274
- });
275
- obsActiveComponent.current.observe(parent, {
276
- childList: true
277
- });
270
+ };
271
+ window.removeEventListener('editor:component:render', onComponentReRender);
272
+ window.addEventListener('editor:component:render', onComponentReRender);
273
+ const $images = $el.querySelectorAll('img');
274
+ if ($images?.length) {
275
+ $images.forEach(($img)=>{
276
+ $img.addEventListener('load', ()=>{
277
+ callback();
278
+ });
279
+ });
280
+ }
281
+ stopWatchReRenderComponent.current = ()=>{
282
+ window.removeEventListener('editor:component:render', onComponentReRender);
283
+ };
278
284
  };
279
285
  const setActiveComponentSpacing = useCallback(({ $component })=>{
280
286
  if (!$component) return;
@@ -285,43 +291,96 @@ const Toolbar = ()=>{
285
291
  const $bg = $marginBottom.querySelector('[data-spacing-margin-bottom-bg]') || null;
286
292
  const $drag = $marginBottom.querySelector('[data-spacing-margin-bottom-drag]') || null;
287
293
  if ($bg && $drag) {
288
- const value = style.marginBottom;
294
+ let value = style.marginBottom;
295
+ if (parseFloat(value) < 0) {
296
+ value = '0';
297
+ }
289
298
  $bg.style.height = value;
290
299
  $drag.style.top = value;
291
300
  $marginBottom.setAttribute('data-spacing-margin-bottom-active', 'true');
301
+ if (isLayoutElement($component)) {
302
+ $bg.style.left = '0';
303
+ } else {
304
+ const paddingLeft = style.paddingLeft;
305
+ const leftValue = `-${paddingLeft}`;
306
+ const translateCss = `translate(${leftValue}, -100%)`;
307
+ $bg.style.left = leftValue;
308
+ $drag.style.transform = translateCss;
309
+ }
292
310
  }
293
311
  }
294
312
  }, []);
295
- const setActiveComponentForceHoverSection = ($component, value)=>{
296
- const $section = $component.closest('[data-toolbar-wrap][data-component-tag="Section"]');
297
- if ($section) {
298
- if (value) {
299
- const $toolbar = getChildrenByAttrSelector($section, 'data-toolbar');
300
- const $outline = getChildrenByAttrSelector($section, 'data-outline');
301
- if ($toolbar) {
302
- $toolbar.setAttribute('data-toolbar-force-hover', 'true');
303
- }
304
- if ($outline) {
305
- $outline.setAttribute('data-outline-force-hover', 'true');
306
- }
307
- } else {
308
- const $toolbar = getChildrenByAttrSelector($section, 'data-toolbar');
309
- const $outline = getChildrenByAttrSelector($section, 'data-outline');
310
- if ($toolbar) {
311
- $toolbar.removeAttribute('data-toolbar-force-hover');
312
- }
313
- if ($outline) {
314
- $outline.removeAttribute('data-outline-force-hover');
313
+ const calculateOnboardingPosition = ()=>{
314
+ const toolbar = document.querySelector('[data-toolbar-active]');
315
+ const toolbarOnboading = document.querySelector('[data-toolbar-onboarding]');
316
+ if (toolbar && toolbarOnboading) {
317
+ toolbarOnboading?.removeAttribute('data-onboarding-active');
318
+ setTimeout(()=>{
319
+ const rect = toolbar.getBoundingClientRect();
320
+ const rectTop = rect.top || 0;
321
+ const rectOnboading = toolbarOnboading?.getBoundingClientRect();
322
+ const onboardingHeight = rectOnboading?.height || 0;
323
+ const $iframe = parent.document.querySelector('.iframe');
324
+ const $iframeWin = $iframe?.contentWindow;
325
+ const iframeWinScrollY = $iframeWin?.scrollY || 0;
326
+ const iframeHeight = $iframe?.clientHeight || 0;
327
+ if (rectTop + onboardingHeight > iframeHeight) {
328
+ const oboardingTop = rect.top + iframeWinScrollY - onboardingHeight - 8;
329
+ toolbarOnboading?.setAttribute('style', `top: ${oboardingTop}px;left: ${rect.left}px;`);
330
+ setOnboardingPosition('top');
331
+ if ($iframeWin && oboardingTop < rect.top + iframeWinScrollY) {
332
+ setTimeout(()=>{
333
+ const toTop = oboardingTop - 20;
334
+ $iframeWin.scrollTo({
335
+ top: toTop,
336
+ behavior: 'smooth'
337
+ });
338
+ }, 200);
339
+ }
340
+ } else {
341
+ const oboardingTop = rect.top + iframeWinScrollY + rect.height + 8;
342
+ toolbarOnboading?.setAttribute('style', `top: ${oboardingTop}px;left: ${rect.left}px;`);
343
+ setOnboardingPosition('bottom');
315
344
  }
316
- }
345
+ setCountShowOnboarding((countShowOnboarding)=>countShowOnboarding + 1);
346
+ toolbarOnboading?.setAttribute('data-onboarding-active', 'true');
347
+ }, 100);
317
348
  }
318
349
  };
350
+ const setToolbarOnboarding = useCallback(({ $component })=>{
351
+ if (!$component) return;
352
+ if (isSection($component) || isPopup($component) || isSticky($component)) return;
353
+ const toolbarOnboading = document.querySelector('[data-toolbar-onboarding]');
354
+ // only show one time
355
+ if (countShowOnboarding == 0) {
356
+ calculateOnboardingPosition();
357
+ } else {
358
+ onCloseOnboarding();
359
+ toolbarOnboading?.removeAttribute('data-onboarding-active');
360
+ }
361
+ }, [
362
+ countShowOnboarding,
363
+ onCloseOnboarding
364
+ ]);
319
365
  const setActiveComponent = useCallback(async ({ componentUid, productId, timeAwait = 500, forceReActive })=>{
320
366
  if (!componentUid) return;
321
- const $component = await waitForElementToExist(`${productId ? `[data-product-id="${productId}"] ` : ''}[data-uid="${componentUid}"]`, timeAwait);
322
- if (!$component) return;
367
+ let $component = await waitForElementToExist(`${productId ? `[data-product-id="${productId}"] ` : ''}[data-uid="${componentUid}"]`, timeAwait);
368
+ // check element fetch data: product, product list
369
+ if (!$component) {
370
+ const isLoading = document.querySelector(`.gp-loading-placeholder`);
371
+ if (!isLoading) {
372
+ return;
373
+ }
374
+ if (isLoading) {
375
+ // await element onload
376
+ $component = await waitForElementToExist(`${productId ? `[data-product-id="${productId}"] ` : ''}[data-uid="${componentUid}"]`, 15000);
377
+ }
378
+ }
379
+ if (!$component) {
380
+ return;
381
+ }
323
382
  if (!forceReActive && componentUid == currentComponentActive.current?.componentUid && productId == currentComponentActive.current?.productId) return;
324
- if (!forceReActive && componentUid !== currentComponentActive.current?.componentUid || productId !== currentComponentActive.current?.productId) removeActiveComponent();
383
+ if (componentUid !== currentComponentActive.current?.componentUid || productId !== currentComponentActive.current?.productId || forceReActive) removeActiveComponent();
325
384
  const $toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
326
385
  const $outline = getChildrenByAttrSelector($component, 'data-outline');
327
386
  const $btnAddTop = getChildrenByAttrSelector($component, 'data-toolbar-add-top');
@@ -333,10 +392,11 @@ const Toolbar = ()=>{
333
392
  };
334
393
  $toolbar.removeAttribute('style');
335
394
  $toolbar.setAttribute('data-toolbar-active', 'true');
336
- const $parentOverflow = findOverflowParent($component, $toolbar);
337
- if ($parentOverflow) {
338
- $toolbar.setAttribute('data-toolbar-active-revert', 'true');
339
- }
395
+ changePositionToolbar({
396
+ $toolbar,
397
+ $component,
398
+ state: 'active'
399
+ });
340
400
  }
341
401
  if ($outline) {
342
402
  $outline.setAttribute('data-outline-active', 'true');
@@ -362,7 +422,14 @@ const Toolbar = ()=>{
362
422
  setActiveComponentSpacing({
363
423
  $component
364
424
  });
365
- setActiveComponentForceHoverSection($component, true);
425
+ timeoutRef.current && clearTimeout(timeoutRef.current);
426
+ timeoutRef.current = setTimeout(()=>{
427
+ if ($component) {
428
+ setToolbarOnboarding({
429
+ $component
430
+ });
431
+ }
432
+ }, timeoutOnboarding);
366
433
  removeHoverComponent();
367
434
  // Reactive when component re-render
368
435
  watchComponentReRender($component, ()=>{
@@ -376,7 +443,8 @@ const Toolbar = ()=>{
376
443
  }, [
377
444
  removeActiveComponent,
378
445
  removeHoverComponent,
379
- setActiveComponentSpacing
446
+ setActiveComponentSpacing,
447
+ setToolbarOnboarding
380
448
  ]);
381
449
  const setFocusTextEditor = async (value)=>{
382
450
  if (!value) {
@@ -499,59 +567,53 @@ const Toolbar = ()=>{
499
567
  if (isDragging.current) return;
500
568
  if (isResizeSpacing.current) return;
501
569
  const $target = e.target;
502
- if (!$target) {
570
+ if (!$target || typeof $target.closest !== 'function') {
503
571
  removeHoverOverlayComponent();
504
572
  return;
505
573
  }
506
574
  const $toolbarHover = $target.closest('[data-toolbar-hover]');
507
575
  if ($toolbarHover) {
508
- removeHoverOverlayComponent(); // remove overlay old
509
- // Hover to toolbar is focus
510
- if ($toolbarHover?.getAttribute('data-toolbar-hover-focus')) return;
511
- const $component = $target.closest('[data-toolbar-wrap]');
512
- if (!$component) return;
513
- const $outline = getChildrenByAttrSelector($component, 'data-outline');
514
- if (!$outline) return;
515
- const isThemeSection = $component.getAttribute('data-theme-section');
516
- const outlineOverlay = isThemeSection ? 'data-outline-overlay-theme-section' : 'data-outline-overlay';
517
- $outline.setAttribute(outlineOverlay, 'true');
518
- } else {
519
- // Hover to other component
520
- const $component = $target.closest('[data-toolbar-wrap]');
521
- const componentUid = $component?.getAttribute('data-uid');
522
- if (!$component || !componentUid || componentUid == 'ROOT') {
523
- removeHoverComponent();
524
- return;
525
- }
526
- const $toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
527
- const $outline = getChildrenByAttrSelector($component, 'data-outline');
528
- if ($outline) $outline.removeAttribute('data-outline-overlay');
529
- if (!componentUid) return;
530
- if (componentUid == 'ROOT') return;
531
- if ($toolbar?.getAttribute('data-toolbar-hover-focus')) return;
532
- if (!$toolbar?.getAttribute('data-toolbar-hover-focus')) removeHoverComponent();
533
- hoverActiveThemeSection($target);
534
- // Disable event when hover active component
535
- if (componentUid == currentComponentActive.current?.componentUid) {
536
- if (currentComponentActive.current.productId) {
537
- const $product = $component.closest(`[data-product-id]`);
538
- if ($product) {
539
- const productId = $product.getAttribute('data-product-id');
540
- if (productId == currentComponentActive.current.productId) {
541
- return;
542
- }
576
+ // Disable feature overlay when hover to toolbar parents
577
+ return;
578
+ // removeHoverOverlayComponent(); // remove overlay old
579
+ // // Hover to toolbar is focus
580
+ // if ($toolbarHover?.getAttribute('data-toolbar-hover-focus')) return;
581
+ // const $component = $target.closest('[data-toolbar-wrap]');
582
+ // if (!$component) return;
583
+ // const $outline = getChildrenByAttrSelector($component, 'data-outline');
584
+ // if (!$outline) return;
585
+ // const isThemeSection = $component.getAttribute('data-theme-section');
586
+ // const outlineOverlay = isThemeSection
587
+ // ? 'data-outline-overlay-theme-section'
588
+ // : 'data-outline-overlay';
589
+ // $outline.setAttribute(outlineOverlay, 'true');
590
+ }
591
+ // Hover to other component
592
+ const $component = $target.closest('[data-toolbar-wrap]');
593
+ const componentUid = $component?.getAttribute('data-uid');
594
+ if (!$component || !componentUid || componentUid == 'ROOT') {
595
+ removeHoverComponent();
596
+ return;
597
+ }
598
+ const $toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
599
+ const $outline = getChildrenByAttrSelector($component, 'data-outline');
600
+ if ($outline) $outline.removeAttribute('data-outline-overlay');
601
+ if (!componentUid) return;
602
+ if (componentUid == 'ROOT') return;
603
+ if ($toolbar?.getAttribute('data-toolbar-hover-focus')) return;
604
+ if (!$toolbar?.getAttribute('data-toolbar-hover-focus')) removeHoverComponent();
605
+ hoverActiveThemeSection($target);
606
+ // Disable event when hover active component
607
+ if (componentUid == currentComponentActive.current?.componentUid) {
608
+ if (currentComponentActive.current.productId) {
609
+ const $product = $component.closest(`[data-product-id]`);
610
+ if ($product) {
611
+ const productId = $product.getAttribute('data-product-id');
612
+ if (productId == currentComponentActive.current.productId) {
613
+ removeHoverComponent();
614
+ return;
543
615
  }
544
616
  }
545
- const $themeSection = $target.closest('[data-theme-section]');
546
- if ($themeSection) {
547
- setHoverComponent({
548
- $component: $themeSection,
549
- focus: true,
550
- isThemeSection: true
551
- });
552
- } else {
553
- return;
554
- }
555
617
  }
556
618
  const $themeSection = $target.closest('[data-theme-section]');
557
619
  if ($themeSection) {
@@ -561,17 +623,27 @@ const Toolbar = ()=>{
561
623
  isThemeSection: true
562
624
  });
563
625
  } else {
564
- setHoverComponent({
565
- $component,
566
- componentUid,
567
- focus: true
568
- });
569
- setHoverComponentParents({
570
- $component,
571
- componentUid
572
- });
626
+ return;
573
627
  }
574
628
  }
629
+ const $themeSection = $target.closest('[data-theme-section]');
630
+ if ($themeSection) {
631
+ setHoverComponent({
632
+ $component: $themeSection,
633
+ focus: true,
634
+ isThemeSection: true
635
+ });
636
+ } else {
637
+ setHoverComponent({
638
+ $component,
639
+ componentUid,
640
+ focus: true
641
+ });
642
+ setHoverComponentParents({
643
+ $component,
644
+ componentUid
645
+ });
646
+ }
575
647
  }, [
576
648
  hoverActiveThemeSection,
577
649
  removeHoverComponent,
@@ -638,6 +710,46 @@ const Toolbar = ()=>{
638
710
  }, [
639
711
  removeHoverComponent
640
712
  ]);
713
+ const setHoverParentComponent = (uid, type)=>{
714
+ if (!uid) return;
715
+ const $parentComponents = document.querySelectorAll(`[data-uid="${uid}"]`);
716
+ if ($parentComponents.length) {
717
+ $parentComponents.forEach(($parentComponent)=>{
718
+ const $outline = getChildrenByAttrSelector($parentComponent, 'data-outline');
719
+ if ($outline) {
720
+ if (type === 'in') {
721
+ $outline.setAttribute('data-outline-force-hover', 'true');
722
+ $outline.setAttribute('data-outline-force-overlay', 'true');
723
+ } else {
724
+ $outline.removeAttribute('data-outline-force-hover');
725
+ $outline.removeAttribute('data-outline-force-overlay');
726
+ }
727
+ }
728
+ });
729
+ }
730
+ };
731
+ const onHoverComponent = useCallback((e)=>{
732
+ if (isDragging.current) return;
733
+ const detail = e.detail;
734
+ if (detail?.componentUid) {
735
+ setHoverParentComponent(detail?.componentUid, detail?.type);
736
+ }
737
+ }, [
738
+ isDragging
739
+ ]);
740
+ const onToolbarOnboarding = useCallback((e)=>{
741
+ const detail = e.detail;
742
+ if (detail?.isNewUser) {
743
+ setIsOnboarding(true);
744
+ }
745
+ }, []);
746
+ const onWindowResize = useCallback(()=>{
747
+ if (isOnboarding) {
748
+ calculateOnboardingPosition();
749
+ }
750
+ }, [
751
+ isOnboarding
752
+ ]);
641
753
  /* Register event */ useEffect(()=>{
642
754
  document.addEventListener('mousemove', onMouseMove);
643
755
  window.addEventListener('editor:active-component', onActiveComponent);
@@ -646,6 +758,9 @@ const Toolbar = ()=>{
646
758
  window.addEventListener('editor:is-editing-text-editor', onIsEditingTextEditor);
647
759
  window.addEventListener('editor:toolbar:show-parents', onShowParents);
648
760
  window.addEventListener('editor:toolbar:resize-spacing', onResizeSpacing);
761
+ window.addEventListener('editor:hover-component', onHoverComponent);
762
+ window.addEventListener('editor:toolbar-onboarding', onToolbarOnboarding);
763
+ window.addEventListener('resize', onWindowResize);
649
764
  return ()=>{
650
765
  document.removeEventListener('mousemove', onMouseMove);
651
766
  window.removeEventListener('editor:active-component', onActiveComponent);
@@ -654,6 +769,9 @@ const Toolbar = ()=>{
654
769
  window.removeEventListener('editor:is-editing-text-editor', onIsEditingTextEditor);
655
770
  window.removeEventListener('editor:toolbar:show-parents', onShowParents);
656
771
  window.removeEventListener('editor:toolbar:resize-spacing', onResizeSpacing);
772
+ window.removeEventListener('editor:hover-component', onHoverComponent);
773
+ window.removeEventListener('editor:toolbar-onboarding', onToolbarOnboarding);
774
+ window.removeEventListener('resize', onWindowResize);
657
775
  };
658
776
  }, [
659
777
  onMouseMove,
@@ -662,9 +780,115 @@ const Toolbar = ()=>{
662
780
  onIsDragging,
663
781
  onIsEditingTextEditor,
664
782
  onShowParents,
665
- onResizeSpacing
783
+ onResizeSpacing,
784
+ onHoverComponent,
785
+ onToolbarOnboarding,
786
+ onWindowResize
666
787
  ]);
667
- return null;
788
+ return isOnboarding && /*#__PURE__*/ jsx(Onboarding, {
789
+ enable: true,
790
+ position: onboardingPosition,
791
+ onCloseOnboarding: onCloseOnboarding
792
+ });
793
+ };
794
+ const getDOMElementParents = ($el, selector, limit)=>{
795
+ // Set up a parent array
796
+ const parents = [];
797
+ // Push each parent $elms to the array
798
+ while($el){
799
+ $el = $el.parentElement ?? undefined;
800
+ if ($el) {
801
+ if ($el.tagName === 'BODY' || $el.getAttribute('data-uid') === 'ROOT') {
802
+ break;
803
+ }
804
+ if (selector) {
805
+ if ($el.matches(selector)) {
806
+ parents.push($el);
807
+ if (limit && parents.length == limit) {
808
+ return parents;
809
+ }
810
+ }
811
+ continue;
812
+ }
813
+ parents.push($el);
814
+ if (limit && parents.length == limit) {
815
+ return parents;
816
+ }
817
+ }
818
+ }
819
+ // Return our parent array
820
+ return parents;
821
+ };
822
+ const getChildrenByAttrSelector = ($el, attrSelector)=>{
823
+ const childLen = $el.children.length;
824
+ if (childLen) {
825
+ for(let i = 0; i < childLen; i++){
826
+ const children = $el.children[i];
827
+ if (children) {
828
+ const is = children.getAttribute(attrSelector);
829
+ if (is) {
830
+ return children;
831
+ }
832
+ }
833
+ }
834
+ }
835
+ };
836
+ const isOverParent = ({ current, parent: parent1, index, revert })=>{
837
+ for(let i = 0; i < index; i++){
838
+ let is = current.top - (TOOLBAR_HOVER_HEIGHT - 1) * i >= parent1.top && current.top - (TOOLBAR_HOVER_HEIGHT - 1) * i <= parent1.top + parent1.height || current.top - (TOOLBAR_HOVER_HEIGHT - 1) * i >= parent1.top + parent1.height && current.top - (TOOLBAR_HOVER_HEIGHT - 1) * i <= parent1.top;
839
+ if (revert) {
840
+ is = current.bottom + (TOOLBAR_HOVER_HEIGHT - 1) * i >= parent1.bottom && current.bottom + (TOOLBAR_HOVER_HEIGHT - 1) * i <= parent1.bottom - parent1.height || current.bottom + (TOOLBAR_HOVER_HEIGHT - 1) * i >= parent1.bottom - parent1.height && current.bottom + (TOOLBAR_HOVER_HEIGHT - 1) * i <= parent1.bottom;
841
+ }
842
+ if (is) return true;
843
+ }
844
+ return false;
845
+ };
846
+ const waitForElementToExist = (selector, timeout = 200)=>{
847
+ return new Promise((resolve)=>{
848
+ const intervalID = setInterval(()=>{
849
+ const el = document.querySelector(selector);
850
+ if (el) {
851
+ clearInterval(intervalID);
852
+ clearTimeout(timeoutID);
853
+ resolve(el);
854
+ }
855
+ }, 50);
856
+ const timeoutID = setTimeout(()=>{
857
+ clearInterval(intervalID);
858
+ clearTimeout(timeoutID);
859
+ resolve(null);
860
+ }, timeout);
861
+ });
862
+ };
863
+ const notVisible = (el)=>{
864
+ const overflow = getComputedStyle(el).overflow;
865
+ return overflow !== 'visible';
866
+ };
867
+ const isSection = (el)=>{
868
+ const tag = el.getAttribute('data-component-tag');
869
+ return tag === 'Section';
870
+ };
871
+ const isLayoutElement = (el)=>{
872
+ const tag = el.getAttribute('data-component-tag');
873
+ return tag === 'Row' || tag === 'Product';
874
+ };
875
+ const isOverToolbarPosition = (el, parent1)=>{
876
+ const rect = el.getBoundingClientRect();
877
+ const rectP = parent1.getBoundingClientRect();
878
+ // 32px = toolbar active height
879
+ return rect.top - rectP.top < TOOLBAR_ACTIVE_HEIGHT + 1;
880
+ };
881
+ const findOverflowParent = (element, initEl)=>{
882
+ const thisEl = element;
883
+ const origEl = initEl || thisEl;
884
+ if (!thisEl) return;
885
+ if (isSection(thisEl)) return;
886
+ if (notVisible(thisEl) && isOverToolbarPosition(initEl, thisEl)) return thisEl;
887
+ if (thisEl.parentElement) {
888
+ return findOverflowParent(thisEl.parentElement, origEl);
889
+ } else {
890
+ return;
891
+ }
668
892
  };
669
893
  var Toolbar$1 = /*#__PURE__*/ memo(Toolbar);
670
894