@gem-sdk/pages 1.21.17 → 1.22.31-new-feature.1

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.
@@ -0,0 +1,490 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var react = require('react');
7
+
8
+ const TOOLBAR_HOVER_HEIGHT = 24;
9
+ // const TOOLBAR_ACTIVE_HEIGHT = 32;
10
+ const getDOMElementParents = ($el, selector, limit)=>{
11
+ // Set up a parent array
12
+ const parents = [];
13
+ // Push each parent $elms to the array
14
+ while($el){
15
+ $el = $el.parentElement ?? undefined;
16
+ if ($el) {
17
+ if ($el.tagName === 'BODY' || $el.getAttribute('data-uid') === 'ROOT') {
18
+ break;
19
+ }
20
+ if (selector) {
21
+ if ($el.matches(selector)) {
22
+ parents.push($el);
23
+ if (limit && parents.length == limit) {
24
+ return parents;
25
+ }
26
+ }
27
+ continue;
28
+ }
29
+ parents.push($el);
30
+ if (limit && parents.length == limit) {
31
+ return parents;
32
+ }
33
+ }
34
+ }
35
+ // Return our parent array
36
+ return parents;
37
+ };
38
+ const getChildrenByAttrSelector = ($el, attrSelector)=>{
39
+ const childLen = $el.children.length;
40
+ if (childLen) {
41
+ for(let i = 0; i < childLen; i++){
42
+ const children = $el.children[i];
43
+ if (children) {
44
+ const is = children.getAttribute(attrSelector);
45
+ if (is) {
46
+ return children;
47
+ }
48
+ }
49
+ }
50
+ }
51
+ };
52
+ const isOverParent = (current, parent, index)=>{
53
+ for(let i = 0; i < index; i++){
54
+ 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;
55
+ if (is) return true;
56
+ }
57
+ return false;
58
+ };
59
+ const waitForElementToExist = (selector, timeout = 200)=>{
60
+ return new Promise((resolve)=>{
61
+ const intervalID = setInterval(()=>{
62
+ const el = document.querySelector(selector);
63
+ if (el) {
64
+ clearInterval(intervalID);
65
+ clearTimeout(timeoutID);
66
+ resolve(el);
67
+ }
68
+ }, 50);
69
+ const timeoutID = setTimeout(()=>{
70
+ clearInterval(intervalID);
71
+ clearTimeout(timeoutID);
72
+ resolve(null);
73
+ }, timeout);
74
+ });
75
+ };
76
+ const Toolbar = ()=>{
77
+ const currentComponentActive = react.useRef(null);
78
+ const isDragging = react.useRef(false);
79
+ /* Functions */ const setHoverComponent = react.useCallback(({ $component, componentUid, focus })=>{
80
+ if (!$component && !componentUid) return;
81
+ if (!$component) {
82
+ const $c = document.querySelector(`[data-uid="${componentUid}"]`);
83
+ if (!$c) return;
84
+ $component = $c;
85
+ }
86
+ if (!componentUid) {
87
+ const cUid = $component.getAttribute('data-uid');
88
+ if (!cUid) return;
89
+ componentUid = cUid;
90
+ }
91
+ const $toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
92
+ const $outline = getChildrenByAttrSelector($component, 'data-outline');
93
+ const $btnAddTop = getChildrenByAttrSelector($component, 'data-toolbar-add-top');
94
+ const $btnAddBottom = getChildrenByAttrSelector($component, 'data-toolbar-add-bottom');
95
+ if ($toolbar) {
96
+ $toolbar.removeAttribute('style');
97
+ $toolbar.setAttribute('data-toolbar-hover', 'true');
98
+ if (focus) {
99
+ $toolbar.setAttribute('data-toolbar-hover-focus', 'true');
100
+ }
101
+ }
102
+ if ($outline) {
103
+ $outline.setAttribute('data-outline-hover', 'true');
104
+ if (focus) {
105
+ $outline.setAttribute('data-outline-hover-focus', 'true');
106
+ }
107
+ }
108
+ if ($btnAddTop) {
109
+ $btnAddTop.setAttribute('data-toolbar-add-hover', 'true');
110
+ }
111
+ if ($btnAddBottom) {
112
+ $btnAddBottom.setAttribute('data-toolbar-add-hover', 'true');
113
+ }
114
+ }, []);
115
+ const setHoverComponentParents = react.useCallback(({ $component, componentUid })=>{
116
+ if (!$component) {
117
+ const $c = document.querySelector(`[data-uid="${componentUid}"]`);
118
+ if (!$c) return;
119
+ $component = $c;
120
+ }
121
+ const $parents = getDOMElementParents($component, '[data-uid][data-component-type="component"]:not([data-component-no-setting])');
122
+ if ($parents.length) {
123
+ for (const $parent of $parents){
124
+ if ($parent) {
125
+ setHoverComponent({
126
+ $component: $parent
127
+ });
128
+ }
129
+ }
130
+ changePositionToolbarParents({
131
+ $component,
132
+ $parents
133
+ });
134
+ }
135
+ }, [
136
+ setHoverComponent
137
+ ]);
138
+ const changePositionToolbarParents = ({ $component, $parents })=>{
139
+ if (!$component) return;
140
+ if (!$parents?.length) return;
141
+ const $currentToolbar = getChildrenByAttrSelector($component, 'data-toolbar-hover-focus');
142
+ if ($currentToolbar) {
143
+ const currentRect = $currentToolbar.getBoundingClientRect();
144
+ let index = 1;
145
+ for (const $parent of $parents){
146
+ if ($parent) {
147
+ const $toolbar = getChildrenByAttrSelector($parent, 'data-toolbar-hover');
148
+ if ($toolbar) {
149
+ // Ignore with toolbar active
150
+ const isActive = $toolbar.getAttribute('data-toolbar-active');
151
+ if (isActive) continue;
152
+ // Start calc
153
+ const parentRect = $toolbar.getBoundingClientRect();
154
+ if (isOverParent(currentRect, parentRect, index)) {
155
+ const parentStyle = getComputedStyle($toolbar);
156
+ // parentStyle.top
157
+ const diffTop = currentRect.top - parentRect.top;
158
+ const diffLeft = currentRect.left - parentRect.left;
159
+ const newTop = parseFloat(parentStyle.top) + diffTop - (TOOLBAR_HOVER_HEIGHT - 1) * index; // -1 border bottom
160
+ const newLeft = parseFloat(parentStyle.left) + diffLeft;
161
+ $toolbar.setAttribute('style', `top: ${newTop}px;left: ${newLeft}px;`);
162
+ index++;
163
+ }
164
+ }
165
+ }
166
+ }
167
+ }
168
+ };
169
+ const removeHoverOverlayComponent = react.useCallback(()=>{
170
+ const clearAttrs = [
171
+ 'data-outline-overlay'
172
+ ];
173
+ const $elms = document.querySelectorAll(clearAttrs.map((attr)=>`[${attr}]`).join(','));
174
+ if ($elms) {
175
+ clearAttrs.forEach((attr)=>{
176
+ $elms.forEach(($el)=>$el.removeAttribute(attr));
177
+ });
178
+ }
179
+ }, []);
180
+ const removeHoverComponent = react.useCallback(()=>{
181
+ const clearAttrs = [
182
+ 'data-toolbar-hover-focus',
183
+ 'data-toolbar-hover',
184
+ 'data-outline-hover-focus',
185
+ 'data-outline-hover',
186
+ 'data-toolbar-add-hover'
187
+ ];
188
+ const $elms = document.querySelectorAll(clearAttrs.map((attr)=>`[${attr}]`).join(','));
189
+ if ($elms) {
190
+ clearAttrs.forEach((attr)=>{
191
+ $elms.forEach(($el)=>$el.removeAttribute(attr));
192
+ });
193
+ }
194
+ removeHoverOverlayComponent();
195
+ }, [
196
+ removeHoverOverlayComponent
197
+ ]);
198
+ const removeActiveComponent = react.useCallback(()=>{
199
+ currentComponentActive.current = null;
200
+ const clearAttrs = [
201
+ 'data-toolbar-active',
202
+ 'data-outline-active',
203
+ 'data-toolbar-add-active',
204
+ 'data-spacing-margin-bottom-active'
205
+ ];
206
+ const $elms = document.querySelectorAll(clearAttrs.map((attr)=>`[${attr}]`).join(','));
207
+ if ($elms) {
208
+ clearAttrs.forEach((attr)=>{
209
+ $elms.forEach(($el)=>$el.removeAttribute(attr));
210
+ });
211
+ }
212
+ setFocusTextEditor(false);
213
+ }, []);
214
+ const setActiveComponent = react.useCallback(async ({ componentUid, productId })=>{
215
+ if (!componentUid) return;
216
+ const $component = await waitForElementToExist(`${productId ? `[data-product-id="${productId}"] ` : ''}[data-uid="${componentUid}"]`, 500);
217
+ if (!$component) return;
218
+ if (componentUid == currentComponentActive.current?.componentUid && productId == currentComponentActive.current?.productId) return;
219
+ if (componentUid !== currentComponentActive.current?.componentUid || productId !== currentComponentActive.current?.productId) removeActiveComponent();
220
+ const $toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
221
+ const $outline = getChildrenByAttrSelector($component, 'data-outline');
222
+ const $btnAddTop = getChildrenByAttrSelector($component, 'data-toolbar-add-top');
223
+ const $btnAddBottom = getChildrenByAttrSelector($component, 'data-toolbar-add-bottom');
224
+ if ($toolbar) {
225
+ currentComponentActive.current = {
226
+ componentUid,
227
+ productId
228
+ };
229
+ $toolbar.removeAttribute('style');
230
+ $toolbar.setAttribute('data-toolbar-active', 'true');
231
+ }
232
+ if ($outline) {
233
+ $outline.setAttribute('data-outline-active', 'true');
234
+ }
235
+ if ($btnAddTop) {
236
+ $btnAddTop.setAttribute('data-toolbar-add-active', 'true');
237
+ }
238
+ if ($btnAddBottom) {
239
+ $btnAddBottom.setAttribute('data-toolbar-add-active', 'true');
240
+ }
241
+ setActiveComponentSpacing({
242
+ $component
243
+ });
244
+ removeHoverComponent();
245
+ }, [
246
+ removeActiveComponent,
247
+ removeHoverComponent
248
+ ]);
249
+ const setFocusTextEditor = async (value)=>{
250
+ if (!value) {
251
+ const $components = document.querySelectorAll('[data-outline-editor-inline-focus],[data-toolbar-editor-inline-focus]');
252
+ if ($components.length) {
253
+ $components.forEach(($component)=>{
254
+ if ($component) {
255
+ $component.removeAttribute('data-toolbar-editor-inline-focus');
256
+ $component.removeAttribute('data-outline-editor-inline-focus');
257
+ }
258
+ });
259
+ }
260
+ } else {
261
+ if (currentComponentActive.current?.componentUid) {
262
+ const componentUid = currentComponentActive.current?.componentUid;
263
+ const productId = currentComponentActive.current?.productId;
264
+ const $component = await waitForElementToExist(`${productId ? `[data-product-id="${productId}"] ` : ''}[data-uid="${componentUid}"]`, 500);
265
+ if ($component) {
266
+ const $toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
267
+ const $outline = getChildrenByAttrSelector($component, 'data-outline');
268
+ if ($toolbar) {
269
+ if (value) {
270
+ $toolbar.setAttribute('data-toolbar-editor-inline-focus', 'true');
271
+ }
272
+ }
273
+ if ($outline) {
274
+ if (value) {
275
+ $outline.setAttribute('data-outline-editor-inline-focus', 'true');
276
+ }
277
+ }
278
+ }
279
+ }
280
+ }
281
+ };
282
+ const setShowParents = async ({ value })=>{
283
+ if (!value) {
284
+ return;
285
+ }
286
+ const $component = await waitForElementToExist(`${currentComponentActive.current?.productId ? `[data-product-id="${currentComponentActive.current?.productId}"] ` : ''}[data-uid="${currentComponentActive.current?.componentUid}"]`, 500);
287
+ if ($component) {
288
+ const $parents = $component?.querySelectorAll('[data-toolbar-parent]');
289
+ if ($parents.length) {
290
+ const onHover = ($parent)=>{
291
+ const uid = $parent.getAttribute('data-parent-uid');
292
+ if (!uid) return;
293
+ const $parentComponents = document.querySelectorAll(`[data-uid="${uid}"]`);
294
+ if ($parentComponents.length) {
295
+ $parentComponents.forEach(($parentComponent)=>{
296
+ const $outline = getChildrenByAttrSelector($parentComponent, 'data-outline');
297
+ if ($outline) {
298
+ $outline.setAttribute('data-outline-force-hover', 'true');
299
+ $outline.setAttribute('data-outline-force-overlay', 'true');
300
+ }
301
+ });
302
+ }
303
+ };
304
+ const outHover = ($parent)=>{
305
+ const uid = $parent.getAttribute('data-parent-uid');
306
+ if (!uid) return;
307
+ const $parentComponents = document.querySelectorAll(`[data-uid="${uid}"]`);
308
+ if ($parentComponents.length) {
309
+ $parentComponents.forEach(($parentComponent)=>{
310
+ const $outline = getChildrenByAttrSelector($parentComponent, 'data-outline');
311
+ if ($outline) {
312
+ $outline.removeAttribute('data-outline-force-hover');
313
+ $outline.removeAttribute('data-outline-force-overlay');
314
+ }
315
+ });
316
+ }
317
+ };
318
+ $parents.forEach(($parent)=>{
319
+ $parent.addEventListener('mouseover', ()=>onHover($parent));
320
+ $parent.addEventListener('mouseout', ()=>outHover($parent));
321
+ $parent.addEventListener('click', ()=>{
322
+ const uid = $parent.getAttribute('data-parent-uid');
323
+ if (!uid) return;
324
+ const $product = $parent.closest('[data-product-id]');
325
+ const productId = $product?.getAttribute('data-product-id') || '';
326
+ const event = new CustomEvent('editor:toolbar:force-active-component', {
327
+ bubbles: true,
328
+ detail: {
329
+ componentUid: uid,
330
+ productId: productId
331
+ }
332
+ });
333
+ outHover($parent);
334
+ window.dispatchEvent(event);
335
+ });
336
+ });
337
+ }
338
+ }
339
+ };
340
+ const setActiveComponentSpacing = react.useCallback(({ $component })=>{
341
+ if (!$component) return;
342
+ const style = getComputedStyle($component);
343
+ const $spacing = getChildrenByAttrSelector($component, 'data-spacing');
344
+ const $marginBottom = ($spacing?.querySelector('[data-spacing-margin-bottom]')) || null;
345
+ if ($marginBottom) {
346
+ const $bg = $marginBottom.querySelector('[data-spacing-margin-bottom-bg]') || null;
347
+ const $drag = $marginBottom.querySelector('[data-spacing-margin-bottom-drag]') || null;
348
+ if ($bg && $drag) {
349
+ const value = style.marginBottom;
350
+ $bg.style.height = value;
351
+ $drag.style.top = value;
352
+ $marginBottom.setAttribute('data-spacing-margin-bottom-active', 'true');
353
+ }
354
+ }
355
+ }, []);
356
+ /* Event listener */ const onMouseMove = react.useCallback((e)=>{
357
+ if (isDragging.current) return;
358
+ const $target = e.target;
359
+ if ($target) {
360
+ const $toolbarHover = $target.closest('[data-toolbar-hover]');
361
+ if ($toolbarHover) {
362
+ removeHoverOverlayComponent(); // remove overlay old
363
+ // Hover to toolbar is showing
364
+ const $component = $target.closest('[data-toolbar-wrap]');
365
+ if ($component) {
366
+ const $outline = getChildrenByAttrSelector($component, 'data-outline');
367
+ if ($outline) {
368
+ $outline.setAttribute('data-outline-overlay', 'true');
369
+ }
370
+ }
371
+ } else {
372
+ // Hover to other component
373
+ const $component = $target.closest('[data-toolbar-wrap]');
374
+ if ($component) {
375
+ const componentUid = $component.getAttribute('data-uid');
376
+ const $toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
377
+ const $outline = getChildrenByAttrSelector($component, 'data-outline');
378
+ if ($outline) $outline.removeAttribute('data-outline-overlay');
379
+ if (!componentUid) return;
380
+ if (componentUid == 'ROOT') return;
381
+ if ($toolbar?.getAttribute('data-toolbar-hover-focus')) return;
382
+ if (!$toolbar?.getAttribute('data-toolbar-hover-focus')) removeHoverComponent();
383
+ // Disable event when hover active component
384
+ if (componentUid == currentComponentActive.current?.componentUid) {
385
+ if (currentComponentActive.current.productId) {
386
+ const $product = $component.closest(`[data-product-id]`);
387
+ if ($product) {
388
+ const productId = $product.getAttribute('data-product-id');
389
+ if (productId == currentComponentActive.current.productId) {
390
+ return;
391
+ }
392
+ }
393
+ } else {
394
+ return;
395
+ }
396
+ }
397
+ setHoverComponent({
398
+ $component,
399
+ componentUid,
400
+ focus: true
401
+ });
402
+ setHoverComponentParents({
403
+ $component,
404
+ componentUid
405
+ });
406
+ }
407
+ }
408
+ }
409
+ }, [
410
+ removeHoverComponent,
411
+ setHoverComponent,
412
+ setHoverComponentParents,
413
+ removeHoverOverlayComponent,
414
+ currentComponentActive
415
+ ]);
416
+ const onActiveComponent = react.useCallback((e)=>{
417
+ if (isDragging.current) return;
418
+ const detail = e.detail;
419
+ if (detail?.componentUid) {
420
+ setActiveComponent({
421
+ componentUid: detail.componentUid,
422
+ productId: detail.productId
423
+ });
424
+ } else {
425
+ removeActiveComponent();
426
+ }
427
+ }, [
428
+ setActiveComponent,
429
+ removeActiveComponent,
430
+ isDragging
431
+ ]);
432
+ const onFocusOutsidePreview = react.useCallback(()=>{
433
+ removeHoverComponent();
434
+ }, [
435
+ removeHoverComponent
436
+ ]);
437
+ const onIsDragging = react.useCallback((e)=>{
438
+ const detail = e.detail;
439
+ if (detail.value) {
440
+ removeHoverComponent();
441
+ removeActiveComponent();
442
+ }
443
+ isDragging.current = detail.value;
444
+ }, [
445
+ removeHoverComponent,
446
+ removeActiveComponent
447
+ ]);
448
+ const onIsEditingTextEditor = react.useCallback((e)=>{
449
+ const detail = e.detail;
450
+ if (detail.value) {
451
+ setFocusTextEditor(true);
452
+ } else {
453
+ setFocusTextEditor(false);
454
+ }
455
+ }, []);
456
+ const onShowParents = react.useCallback((e)=>{
457
+ if (isDragging.current) return;
458
+ const detail = e.detail;
459
+ setShowParents({
460
+ value: detail?.value || false
461
+ });
462
+ }, []);
463
+ /* Register event */ react.useEffect(()=>{
464
+ document.addEventListener('mousemove', onMouseMove);
465
+ window.addEventListener('editor:active-component', onActiveComponent);
466
+ window.addEventListener('editor:focus-outside-preview', onFocusOutsidePreview);
467
+ window.addEventListener('editor:is-dragging', onIsDragging);
468
+ window.addEventListener('editor:is-editing-text-editor', onIsEditingTextEditor);
469
+ window.addEventListener('editor:toolbar:show-parents', onShowParents);
470
+ return ()=>{
471
+ document.removeEventListener('mousemove', onMouseMove);
472
+ window.removeEventListener('editor:active-component', onActiveComponent);
473
+ window.removeEventListener('editor:is-dragging', onFocusOutsidePreview);
474
+ window.removeEventListener('editor:is-dragging', onIsDragging);
475
+ window.removeEventListener('editor:is-editing-text-editor', onIsEditingTextEditor);
476
+ window.removeEventListener('editor:toolbar:show-parents', onShowParents);
477
+ };
478
+ }, [
479
+ onMouseMove,
480
+ onActiveComponent,
481
+ onFocusOutsidePreview,
482
+ onIsDragging,
483
+ onIsEditingTextEditor,
484
+ onShowParents
485
+ ]);
486
+ return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {});
487
+ };
488
+ var Toolbar$1 = /*#__PURE__*/ react.memo(Toolbar);
489
+
490
+ exports.default = Toolbar$1;
@@ -12,6 +12,7 @@ var CollectionGlobalProvider = require('./CollectionGlobalProvider.js');
12
12
  var PopupManager = require('../components/builder/PopupManager.js');
13
13
  var ImageToLayout = require('../components/image-to-layout/ImageToLayout.js');
14
14
  var AddSectionImageToLayout = require('../components/image-to-layout/AddSectionImageToLayout.js');
15
+ var Toolbar = require('../components/builder/Toolbar.js');
15
16
 
16
17
  const BuilderPage = ({ components, seo, themeStyle, fontStyle, sectionData, pageType, editorImageToLayout })=>{
17
18
  const [loadSuccess, setLoadSuccess] = react.useState(false);
@@ -57,6 +58,7 @@ const BuilderPage = ({ components, seo, themeStyle, fontStyle, sectionData, page
57
58
  state: initState,
58
59
  children: [
59
60
  /*#__PURE__*/ jsxRuntime.jsx(Toolbox.default, {}),
61
+ /*#__PURE__*/ jsxRuntime.jsx(Toolbar.default, {}),
60
62
  /*#__PURE__*/ jsxRuntime.jsx(PopupManager.default, {}),
61
63
  loadSuccess && /*#__PURE__*/ jsxRuntime.jsxs("div", {
62
64
  className: "builder z-1 relative",
@@ -0,0 +1,486 @@
1
+ import { jsx, Fragment } from 'react/jsx-runtime';
2
+ import { memo, useRef, useCallback, useEffect } from 'react';
3
+
4
+ const TOOLBAR_HOVER_HEIGHT = 24;
5
+ // const TOOLBAR_ACTIVE_HEIGHT = 32;
6
+ const getDOMElementParents = ($el, selector, limit)=>{
7
+ // Set up a parent array
8
+ const parents = [];
9
+ // Push each parent $elms to the array
10
+ while($el){
11
+ $el = $el.parentElement ?? undefined;
12
+ if ($el) {
13
+ if ($el.tagName === 'BODY' || $el.getAttribute('data-uid') === 'ROOT') {
14
+ break;
15
+ }
16
+ if (selector) {
17
+ if ($el.matches(selector)) {
18
+ parents.push($el);
19
+ if (limit && parents.length == limit) {
20
+ return parents;
21
+ }
22
+ }
23
+ continue;
24
+ }
25
+ parents.push($el);
26
+ if (limit && parents.length == limit) {
27
+ return parents;
28
+ }
29
+ }
30
+ }
31
+ // Return our parent array
32
+ return parents;
33
+ };
34
+ const getChildrenByAttrSelector = ($el, attrSelector)=>{
35
+ const childLen = $el.children.length;
36
+ if (childLen) {
37
+ for(let i = 0; i < childLen; i++){
38
+ const children = $el.children[i];
39
+ if (children) {
40
+ const is = children.getAttribute(attrSelector);
41
+ if (is) {
42
+ return children;
43
+ }
44
+ }
45
+ }
46
+ }
47
+ };
48
+ const isOverParent = (current, parent, index)=>{
49
+ for(let i = 0; i < index; i++){
50
+ 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;
51
+ if (is) return true;
52
+ }
53
+ return false;
54
+ };
55
+ const waitForElementToExist = (selector, timeout = 200)=>{
56
+ return new Promise((resolve)=>{
57
+ const intervalID = setInterval(()=>{
58
+ const el = document.querySelector(selector);
59
+ if (el) {
60
+ clearInterval(intervalID);
61
+ clearTimeout(timeoutID);
62
+ resolve(el);
63
+ }
64
+ }, 50);
65
+ const timeoutID = setTimeout(()=>{
66
+ clearInterval(intervalID);
67
+ clearTimeout(timeoutID);
68
+ resolve(null);
69
+ }, timeout);
70
+ });
71
+ };
72
+ const Toolbar = ()=>{
73
+ const currentComponentActive = useRef(null);
74
+ const isDragging = useRef(false);
75
+ /* Functions */ const setHoverComponent = useCallback(({ $component, componentUid, focus })=>{
76
+ if (!$component && !componentUid) return;
77
+ if (!$component) {
78
+ const $c = document.querySelector(`[data-uid="${componentUid}"]`);
79
+ if (!$c) return;
80
+ $component = $c;
81
+ }
82
+ if (!componentUid) {
83
+ const cUid = $component.getAttribute('data-uid');
84
+ if (!cUid) return;
85
+ componentUid = cUid;
86
+ }
87
+ const $toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
88
+ const $outline = getChildrenByAttrSelector($component, 'data-outline');
89
+ const $btnAddTop = getChildrenByAttrSelector($component, 'data-toolbar-add-top');
90
+ const $btnAddBottom = getChildrenByAttrSelector($component, 'data-toolbar-add-bottom');
91
+ if ($toolbar) {
92
+ $toolbar.removeAttribute('style');
93
+ $toolbar.setAttribute('data-toolbar-hover', 'true');
94
+ if (focus) {
95
+ $toolbar.setAttribute('data-toolbar-hover-focus', 'true');
96
+ }
97
+ }
98
+ if ($outline) {
99
+ $outline.setAttribute('data-outline-hover', 'true');
100
+ if (focus) {
101
+ $outline.setAttribute('data-outline-hover-focus', 'true');
102
+ }
103
+ }
104
+ if ($btnAddTop) {
105
+ $btnAddTop.setAttribute('data-toolbar-add-hover', 'true');
106
+ }
107
+ if ($btnAddBottom) {
108
+ $btnAddBottom.setAttribute('data-toolbar-add-hover', 'true');
109
+ }
110
+ }, []);
111
+ const setHoverComponentParents = useCallback(({ $component, componentUid })=>{
112
+ if (!$component) {
113
+ const $c = document.querySelector(`[data-uid="${componentUid}"]`);
114
+ if (!$c) return;
115
+ $component = $c;
116
+ }
117
+ const $parents = getDOMElementParents($component, '[data-uid][data-component-type="component"]:not([data-component-no-setting])');
118
+ if ($parents.length) {
119
+ for (const $parent of $parents){
120
+ if ($parent) {
121
+ setHoverComponent({
122
+ $component: $parent
123
+ });
124
+ }
125
+ }
126
+ changePositionToolbarParents({
127
+ $component,
128
+ $parents
129
+ });
130
+ }
131
+ }, [
132
+ setHoverComponent
133
+ ]);
134
+ const changePositionToolbarParents = ({ $component, $parents })=>{
135
+ if (!$component) return;
136
+ if (!$parents?.length) return;
137
+ const $currentToolbar = getChildrenByAttrSelector($component, 'data-toolbar-hover-focus');
138
+ if ($currentToolbar) {
139
+ const currentRect = $currentToolbar.getBoundingClientRect();
140
+ let index = 1;
141
+ for (const $parent of $parents){
142
+ if ($parent) {
143
+ const $toolbar = getChildrenByAttrSelector($parent, 'data-toolbar-hover');
144
+ if ($toolbar) {
145
+ // Ignore with toolbar active
146
+ const isActive = $toolbar.getAttribute('data-toolbar-active');
147
+ if (isActive) continue;
148
+ // Start calc
149
+ const parentRect = $toolbar.getBoundingClientRect();
150
+ if (isOverParent(currentRect, parentRect, index)) {
151
+ const parentStyle = getComputedStyle($toolbar);
152
+ // parentStyle.top
153
+ const diffTop = currentRect.top - parentRect.top;
154
+ const diffLeft = currentRect.left - parentRect.left;
155
+ const newTop = parseFloat(parentStyle.top) + diffTop - (TOOLBAR_HOVER_HEIGHT - 1) * index; // -1 border bottom
156
+ const newLeft = parseFloat(parentStyle.left) + diffLeft;
157
+ $toolbar.setAttribute('style', `top: ${newTop}px;left: ${newLeft}px;`);
158
+ index++;
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ };
165
+ const removeHoverOverlayComponent = useCallback(()=>{
166
+ const clearAttrs = [
167
+ 'data-outline-overlay'
168
+ ];
169
+ const $elms = document.querySelectorAll(clearAttrs.map((attr)=>`[${attr}]`).join(','));
170
+ if ($elms) {
171
+ clearAttrs.forEach((attr)=>{
172
+ $elms.forEach(($el)=>$el.removeAttribute(attr));
173
+ });
174
+ }
175
+ }, []);
176
+ const removeHoverComponent = useCallback(()=>{
177
+ const clearAttrs = [
178
+ 'data-toolbar-hover-focus',
179
+ 'data-toolbar-hover',
180
+ 'data-outline-hover-focus',
181
+ 'data-outline-hover',
182
+ 'data-toolbar-add-hover'
183
+ ];
184
+ const $elms = document.querySelectorAll(clearAttrs.map((attr)=>`[${attr}]`).join(','));
185
+ if ($elms) {
186
+ clearAttrs.forEach((attr)=>{
187
+ $elms.forEach(($el)=>$el.removeAttribute(attr));
188
+ });
189
+ }
190
+ removeHoverOverlayComponent();
191
+ }, [
192
+ removeHoverOverlayComponent
193
+ ]);
194
+ const removeActiveComponent = useCallback(()=>{
195
+ currentComponentActive.current = null;
196
+ const clearAttrs = [
197
+ 'data-toolbar-active',
198
+ 'data-outline-active',
199
+ 'data-toolbar-add-active',
200
+ 'data-spacing-margin-bottom-active'
201
+ ];
202
+ const $elms = document.querySelectorAll(clearAttrs.map((attr)=>`[${attr}]`).join(','));
203
+ if ($elms) {
204
+ clearAttrs.forEach((attr)=>{
205
+ $elms.forEach(($el)=>$el.removeAttribute(attr));
206
+ });
207
+ }
208
+ setFocusTextEditor(false);
209
+ }, []);
210
+ const setActiveComponent = useCallback(async ({ componentUid, productId })=>{
211
+ if (!componentUid) return;
212
+ const $component = await waitForElementToExist(`${productId ? `[data-product-id="${productId}"] ` : ''}[data-uid="${componentUid}"]`, 500);
213
+ if (!$component) return;
214
+ if (componentUid == currentComponentActive.current?.componentUid && productId == currentComponentActive.current?.productId) return;
215
+ if (componentUid !== currentComponentActive.current?.componentUid || productId !== currentComponentActive.current?.productId) removeActiveComponent();
216
+ const $toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
217
+ const $outline = getChildrenByAttrSelector($component, 'data-outline');
218
+ const $btnAddTop = getChildrenByAttrSelector($component, 'data-toolbar-add-top');
219
+ const $btnAddBottom = getChildrenByAttrSelector($component, 'data-toolbar-add-bottom');
220
+ if ($toolbar) {
221
+ currentComponentActive.current = {
222
+ componentUid,
223
+ productId
224
+ };
225
+ $toolbar.removeAttribute('style');
226
+ $toolbar.setAttribute('data-toolbar-active', 'true');
227
+ }
228
+ if ($outline) {
229
+ $outline.setAttribute('data-outline-active', 'true');
230
+ }
231
+ if ($btnAddTop) {
232
+ $btnAddTop.setAttribute('data-toolbar-add-active', 'true');
233
+ }
234
+ if ($btnAddBottom) {
235
+ $btnAddBottom.setAttribute('data-toolbar-add-active', 'true');
236
+ }
237
+ setActiveComponentSpacing({
238
+ $component
239
+ });
240
+ removeHoverComponent();
241
+ }, [
242
+ removeActiveComponent,
243
+ removeHoverComponent
244
+ ]);
245
+ const setFocusTextEditor = async (value)=>{
246
+ if (!value) {
247
+ const $components = document.querySelectorAll('[data-outline-editor-inline-focus],[data-toolbar-editor-inline-focus]');
248
+ if ($components.length) {
249
+ $components.forEach(($component)=>{
250
+ if ($component) {
251
+ $component.removeAttribute('data-toolbar-editor-inline-focus');
252
+ $component.removeAttribute('data-outline-editor-inline-focus');
253
+ }
254
+ });
255
+ }
256
+ } else {
257
+ if (currentComponentActive.current?.componentUid) {
258
+ const componentUid = currentComponentActive.current?.componentUid;
259
+ const productId = currentComponentActive.current?.productId;
260
+ const $component = await waitForElementToExist(`${productId ? `[data-product-id="${productId}"] ` : ''}[data-uid="${componentUid}"]`, 500);
261
+ if ($component) {
262
+ const $toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
263
+ const $outline = getChildrenByAttrSelector($component, 'data-outline');
264
+ if ($toolbar) {
265
+ if (value) {
266
+ $toolbar.setAttribute('data-toolbar-editor-inline-focus', 'true');
267
+ }
268
+ }
269
+ if ($outline) {
270
+ if (value) {
271
+ $outline.setAttribute('data-outline-editor-inline-focus', 'true');
272
+ }
273
+ }
274
+ }
275
+ }
276
+ }
277
+ };
278
+ const setShowParents = async ({ value })=>{
279
+ if (!value) {
280
+ return;
281
+ }
282
+ const $component = await waitForElementToExist(`${currentComponentActive.current?.productId ? `[data-product-id="${currentComponentActive.current?.productId}"] ` : ''}[data-uid="${currentComponentActive.current?.componentUid}"]`, 500);
283
+ if ($component) {
284
+ const $parents = $component?.querySelectorAll('[data-toolbar-parent]');
285
+ if ($parents.length) {
286
+ const onHover = ($parent)=>{
287
+ const uid = $parent.getAttribute('data-parent-uid');
288
+ if (!uid) return;
289
+ const $parentComponents = document.querySelectorAll(`[data-uid="${uid}"]`);
290
+ if ($parentComponents.length) {
291
+ $parentComponents.forEach(($parentComponent)=>{
292
+ const $outline = getChildrenByAttrSelector($parentComponent, 'data-outline');
293
+ if ($outline) {
294
+ $outline.setAttribute('data-outline-force-hover', 'true');
295
+ $outline.setAttribute('data-outline-force-overlay', 'true');
296
+ }
297
+ });
298
+ }
299
+ };
300
+ const outHover = ($parent)=>{
301
+ const uid = $parent.getAttribute('data-parent-uid');
302
+ if (!uid) return;
303
+ const $parentComponents = document.querySelectorAll(`[data-uid="${uid}"]`);
304
+ if ($parentComponents.length) {
305
+ $parentComponents.forEach(($parentComponent)=>{
306
+ const $outline = getChildrenByAttrSelector($parentComponent, 'data-outline');
307
+ if ($outline) {
308
+ $outline.removeAttribute('data-outline-force-hover');
309
+ $outline.removeAttribute('data-outline-force-overlay');
310
+ }
311
+ });
312
+ }
313
+ };
314
+ $parents.forEach(($parent)=>{
315
+ $parent.addEventListener('mouseover', ()=>onHover($parent));
316
+ $parent.addEventListener('mouseout', ()=>outHover($parent));
317
+ $parent.addEventListener('click', ()=>{
318
+ const uid = $parent.getAttribute('data-parent-uid');
319
+ if (!uid) return;
320
+ const $product = $parent.closest('[data-product-id]');
321
+ const productId = $product?.getAttribute('data-product-id') || '';
322
+ const event = new CustomEvent('editor:toolbar:force-active-component', {
323
+ bubbles: true,
324
+ detail: {
325
+ componentUid: uid,
326
+ productId: productId
327
+ }
328
+ });
329
+ outHover($parent);
330
+ window.dispatchEvent(event);
331
+ });
332
+ });
333
+ }
334
+ }
335
+ };
336
+ const setActiveComponentSpacing = useCallback(({ $component })=>{
337
+ if (!$component) return;
338
+ const style = getComputedStyle($component);
339
+ const $spacing = getChildrenByAttrSelector($component, 'data-spacing');
340
+ const $marginBottom = ($spacing?.querySelector('[data-spacing-margin-bottom]')) || null;
341
+ if ($marginBottom) {
342
+ const $bg = $marginBottom.querySelector('[data-spacing-margin-bottom-bg]') || null;
343
+ const $drag = $marginBottom.querySelector('[data-spacing-margin-bottom-drag]') || null;
344
+ if ($bg && $drag) {
345
+ const value = style.marginBottom;
346
+ $bg.style.height = value;
347
+ $drag.style.top = value;
348
+ $marginBottom.setAttribute('data-spacing-margin-bottom-active', 'true');
349
+ }
350
+ }
351
+ }, []);
352
+ /* Event listener */ const onMouseMove = useCallback((e)=>{
353
+ if (isDragging.current) return;
354
+ const $target = e.target;
355
+ if ($target) {
356
+ const $toolbarHover = $target.closest('[data-toolbar-hover]');
357
+ if ($toolbarHover) {
358
+ removeHoverOverlayComponent(); // remove overlay old
359
+ // Hover to toolbar is showing
360
+ const $component = $target.closest('[data-toolbar-wrap]');
361
+ if ($component) {
362
+ const $outline = getChildrenByAttrSelector($component, 'data-outline');
363
+ if ($outline) {
364
+ $outline.setAttribute('data-outline-overlay', 'true');
365
+ }
366
+ }
367
+ } else {
368
+ // Hover to other component
369
+ const $component = $target.closest('[data-toolbar-wrap]');
370
+ if ($component) {
371
+ const componentUid = $component.getAttribute('data-uid');
372
+ const $toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
373
+ const $outline = getChildrenByAttrSelector($component, 'data-outline');
374
+ if ($outline) $outline.removeAttribute('data-outline-overlay');
375
+ if (!componentUid) return;
376
+ if (componentUid == 'ROOT') return;
377
+ if ($toolbar?.getAttribute('data-toolbar-hover-focus')) return;
378
+ if (!$toolbar?.getAttribute('data-toolbar-hover-focus')) removeHoverComponent();
379
+ // Disable event when hover active component
380
+ if (componentUid == currentComponentActive.current?.componentUid) {
381
+ if (currentComponentActive.current.productId) {
382
+ const $product = $component.closest(`[data-product-id]`);
383
+ if ($product) {
384
+ const productId = $product.getAttribute('data-product-id');
385
+ if (productId == currentComponentActive.current.productId) {
386
+ return;
387
+ }
388
+ }
389
+ } else {
390
+ return;
391
+ }
392
+ }
393
+ setHoverComponent({
394
+ $component,
395
+ componentUid,
396
+ focus: true
397
+ });
398
+ setHoverComponentParents({
399
+ $component,
400
+ componentUid
401
+ });
402
+ }
403
+ }
404
+ }
405
+ }, [
406
+ removeHoverComponent,
407
+ setHoverComponent,
408
+ setHoverComponentParents,
409
+ removeHoverOverlayComponent,
410
+ currentComponentActive
411
+ ]);
412
+ const onActiveComponent = useCallback((e)=>{
413
+ if (isDragging.current) return;
414
+ const detail = e.detail;
415
+ if (detail?.componentUid) {
416
+ setActiveComponent({
417
+ componentUid: detail.componentUid,
418
+ productId: detail.productId
419
+ });
420
+ } else {
421
+ removeActiveComponent();
422
+ }
423
+ }, [
424
+ setActiveComponent,
425
+ removeActiveComponent,
426
+ isDragging
427
+ ]);
428
+ const onFocusOutsidePreview = useCallback(()=>{
429
+ removeHoverComponent();
430
+ }, [
431
+ removeHoverComponent
432
+ ]);
433
+ const onIsDragging = useCallback((e)=>{
434
+ const detail = e.detail;
435
+ if (detail.value) {
436
+ removeHoverComponent();
437
+ removeActiveComponent();
438
+ }
439
+ isDragging.current = detail.value;
440
+ }, [
441
+ removeHoverComponent,
442
+ removeActiveComponent
443
+ ]);
444
+ const onIsEditingTextEditor = useCallback((e)=>{
445
+ const detail = e.detail;
446
+ if (detail.value) {
447
+ setFocusTextEditor(true);
448
+ } else {
449
+ setFocusTextEditor(false);
450
+ }
451
+ }, []);
452
+ const onShowParents = useCallback((e)=>{
453
+ if (isDragging.current) return;
454
+ const detail = e.detail;
455
+ setShowParents({
456
+ value: detail?.value || false
457
+ });
458
+ }, []);
459
+ /* Register event */ useEffect(()=>{
460
+ document.addEventListener('mousemove', onMouseMove);
461
+ window.addEventListener('editor:active-component', onActiveComponent);
462
+ window.addEventListener('editor:focus-outside-preview', onFocusOutsidePreview);
463
+ window.addEventListener('editor:is-dragging', onIsDragging);
464
+ window.addEventListener('editor:is-editing-text-editor', onIsEditingTextEditor);
465
+ window.addEventListener('editor:toolbar:show-parents', onShowParents);
466
+ return ()=>{
467
+ document.removeEventListener('mousemove', onMouseMove);
468
+ window.removeEventListener('editor:active-component', onActiveComponent);
469
+ window.removeEventListener('editor:is-dragging', onFocusOutsidePreview);
470
+ window.removeEventListener('editor:is-dragging', onIsDragging);
471
+ window.removeEventListener('editor:is-editing-text-editor', onIsEditingTextEditor);
472
+ window.removeEventListener('editor:toolbar:show-parents', onShowParents);
473
+ };
474
+ }, [
475
+ onMouseMove,
476
+ onActiveComponent,
477
+ onFocusOutsidePreview,
478
+ onIsDragging,
479
+ onIsEditingTextEditor,
480
+ onShowParents
481
+ ]);
482
+ return /*#__PURE__*/ jsx(Fragment, {});
483
+ };
484
+ var Toolbar$1 = /*#__PURE__*/ memo(Toolbar);
485
+
486
+ export { Toolbar$1 as default };
@@ -10,6 +10,7 @@ import CollectionGlobalProvider from './CollectionGlobalProvider.js';
10
10
  import PopupManager from '../components/builder/PopupManager.js';
11
11
  import ImageToLayout from '../components/image-to-layout/ImageToLayout.js';
12
12
  import AddSectionImageToLayout from '../components/image-to-layout/AddSectionImageToLayout.js';
13
+ import Toolbar from '../components/builder/Toolbar.js';
13
14
 
14
15
  const BuilderPage = ({ components, seo, themeStyle, fontStyle, sectionData, pageType, editorImageToLayout })=>{
15
16
  const [loadSuccess, setLoadSuccess] = useState(false);
@@ -55,6 +56,7 @@ const BuilderPage = ({ components, seo, themeStyle, fontStyle, sectionData, page
55
56
  state: initState,
56
57
  children: [
57
58
  /*#__PURE__*/ jsx(Toolbox, {}),
59
+ /*#__PURE__*/ jsx(Toolbar, {}),
58
60
  /*#__PURE__*/ jsx(PopupManager, {}),
59
61
  loadSuccess && /*#__PURE__*/ jsxs("div", {
60
62
  className: "builder z-1 relative",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gem-sdk/pages",
3
- "version": "1.21.17",
3
+ "version": "1.22.31-new-feature.1",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
6
6
  "main": "dist/cjs/index.js",
@@ -25,10 +25,10 @@
25
25
  "next-seo": "^6.0.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@gem-sdk/core": "1.21.12",
29
- "@gem-sdk/plugin-cookie-bar": "*",
30
- "@gem-sdk/plugin-quick-view": "*",
31
- "@gem-sdk/plugin-sticky-add-to-cart": "*"
28
+ "@gem-sdk/core": "1.22.31-new-feature.1",
29
+ "@gem-sdk/plugin-cookie-bar": "1.22.31-staging.0",
30
+ "@gem-sdk/plugin-quick-view": "1.22.31-staging.0",
31
+ "@gem-sdk/plugin-sticky-add-to-cart": "1.22.31-staging.0"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "next": ">=13"