@gem-sdk/core 1.36.0 → 1.36.6

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.
@@ -163,15 +163,7 @@ const ComponentToolbarPreview = ({ ...props })=>{
163
163
  return false;
164
164
  };
165
165
  const toolbarName = ()=>{
166
- const tag = props.tag;
167
- if (tag === 'IconListV2') {
168
- return 'Item list';
169
- }
170
- if (tag === 'IconList') {
171
- return 'Advanced list';
172
- }
173
- const name = props.customLabel || props.label;
174
- return name;
166
+ return props.customLabel || props.label;
175
167
  };
176
168
  const onZoomOut = (e)=>{
177
169
  e.preventDefault();
@@ -23,6 +23,10 @@ function Spacing(props) {
23
23
  const isDragging = react.useRef(false);
24
24
  const startY = react.useRef(0);
25
25
  const marginBottom = react.useRef(0);
26
+ const $visualNumberValue = react.useRef(null);
27
+ const [marginBottomValue, setMarginBottomValue] = react.useState(0);
28
+ const [isShowVisual, setIsShowVisual] = react.useState(false);
29
+ const hideVisualNumberValue = react.useRef(null);
26
30
  const getNewValueMargin = (event)=>{
27
31
  const top = event.clientY;
28
32
  const diffY = Math.ceil(top - startY.current);
@@ -41,6 +45,7 @@ function Spacing(props) {
41
45
  const $component = $bottomDrag.current.closest('[data-toolbar-wrap]');
42
46
  if ($component) {
43
47
  $component.style.marginBottom = newValue;
48
+ onShowMarginBottomNumber(newValue);
44
49
  }
45
50
  }
46
51
  };
@@ -116,80 +121,84 @@ function Spacing(props) {
116
121
  }
117
122
  }
118
123
  };
119
- const onUpdateMarginBottom = react.useCallback((e)=>{
120
- if (isDragging.current) return;
121
- const detail = e.detail;
122
- const $component = $bottomDrag.current?.closest('[data-toolbar-wrap]');
123
- const toolbar = $component && getChildrenByAttrSelector($component, 'data-toolbar');
124
- const isActive = toolbar && toolbar.getAttribute('data-toolbar-active');
125
- if (isActive && detail?.marginBottom) {
126
- const currentValue = parseInt(detail?.marginBottom);
127
- const newValue = `${currentValue}px`;
128
- if ($bottomDrag.current && $bottomBg.current) {
129
- if (currentValue < 0) {
130
- $bottomBg.current.style.display = 'none';
131
- $bottomDrag.current.style.display = 'none';
132
- } else {
133
- $bottomBg.current.style.display = 'block';
134
- $bottomDrag.current.style.display = 'block';
135
- $bottomBg.current.style.height = newValue;
136
- $bottomDrag.current.style.top = newValue;
137
- }
138
- }
139
- }
140
- }, []);
141
- const isPopup = (el)=>{
124
+ const isLayoutElement = (el)=>{
142
125
  const tag = el.getAttribute('data-component-tag');
143
- return tag === 'Dialog';
126
+ return tag === 'Row' || tag === 'Product';
144
127
  };
145
- const isSticky = (el)=>{
146
- const tag = el.getAttribute('data-component-tag');
147
- return tag === 'Sticky';
148
- };
149
- const setPositionSpacing = react.useCallback((paddingLeft)=>{
128
+ const updateSpacing = react.useCallback(()=>{
150
129
  const $component = $bottomDrag.current?.closest('[data-toolbar-wrap]');
151
- if ($component) {
152
- if (isPopup($component) || isSticky($component)) return;
153
- const toolbar = $component && getChildrenByAttrSelector($component, 'data-toolbar');
154
- const isActive = toolbar && toolbar.getAttribute('data-toolbar-active');
155
- if (isActive && paddingLeft) {
156
- const currentValue = isNaN(parseInt(paddingLeft)) ? 0 : Math.max(parseInt(paddingLeft), 0);
157
- const newValue = `-${currentValue}px`;
158
- const translateCss = `translate(-${currentValue}px, -100%)`;
159
- if ($bottomDrag.current && $bottomBg.current) {
160
- $bottomBg.current.style.left = newValue;
130
+ if (!$component) return;
131
+ const toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
132
+ if (!toolbar) return;
133
+ const isActive = toolbar.getAttribute('data-toolbar-active');
134
+ if (!isActive) return;
135
+ const style = getComputedStyle($component);
136
+ const $spacing = getChildrenByAttrSelector($component, 'data-spacing');
137
+ const $marginBottom = ($spacing?.querySelector('[data-spacing-margin-bottom]')) || null;
138
+ if ($marginBottom) {
139
+ if ($bottomBg.current && $bottomDrag.current) {
140
+ let value = style.marginBottom;
141
+ onShowMarginBottomNumber(value);
142
+ if (parseFloat(value) < 0) {
143
+ value = '0';
144
+ }
145
+ $bottomBg.current.style.height = value;
146
+ $bottomDrag.current.style.top = value;
147
+ $marginBottom.setAttribute('data-spacing-margin-bottom-active', 'true');
148
+ if (isLayoutElement($component)) {
149
+ $bottomBg.current.style.left = '0';
150
+ } else {
151
+ const paddingLeft = style.paddingLeft;
152
+ const leftValue = `-${paddingLeft}`;
153
+ const translateCss = `translate(${leftValue}, -100%)`;
154
+ $bottomBg.current.style.left = leftValue;
161
155
  $bottomDrag.current.style.transform = translateCss;
162
156
  }
163
157
  }
164
158
  }
165
159
  }, []);
166
- const onUpdatePaddingLeft = react.useCallback((e)=>{
167
- if (isDragging.current) return;
168
- const detail = e.detail;
169
- if (detail?.paddingLeft) {
170
- setPositionSpacing(detail.paddingLeft);
160
+ const onShowMarginBottomNumber = (value)=>{
161
+ const parsedValue = parseFloat(value);
162
+ setMarginBottomValue(parsedValue);
163
+ setIsShowVisual(true);
164
+ if (hideVisualNumberValue.current) clearTimeout(hideVisualNumberValue.current);
165
+ hideVisualNumberValue.current = setTimeout(()=>{
166
+ setIsShowVisual(false);
167
+ }, 2000);
168
+ // break point 28px
169
+ const topPosition = parsedValue < 28 && parsedValue >= 0 ? parsedValue / 2 + 16 : parsedValue > 28 ? 0 : 16;
170
+ if ($visualNumberValue.current) {
171
+ $visualNumberValue.current.style.transform = `translateY(${topPosition}px)`;
171
172
  }
172
- }, [
173
- setPositionSpacing
174
- ]);
173
+ };
174
+ const previousAdvanced = usePrevious(props.advanced?.['spacing-setting']);
175
175
  react.useEffect(()=>{
176
- const $component = $bottomDrag.current?.closest('[data-toolbar-wrap]');
177
- if ($component) {
178
- const style = getComputedStyle($component);
179
- const paddingLeft = style.paddingLeft;
180
- setPositionSpacing(paddingLeft);
176
+ // validate spacing setting changed
177
+ if (JSON.stringify(previousAdvanced) !== JSON.stringify(props.advanced?.['spacing-setting'])) {
178
+ updateSpacing();
181
179
  }
182
- });
180
+ }, [
181
+ previousAdvanced,
182
+ props.advanced,
183
+ updateSpacing
184
+ ]);
185
+ const onWindowResize = react.useCallback(()=>{
186
+ updateSpacing();
187
+ }, [
188
+ updateSpacing
189
+ ]);
183
190
  react.useEffect(()=>{
184
- window.addEventListener('editor:toolbar:update-margin-bottom', onUpdateMarginBottom);
185
- window.addEventListener('editor:toolbar:update-padding-left', onUpdatePaddingLeft);
191
+ window.addEventListener('editor:toolbar:update-margin-bottom', updateSpacing);
192
+ window.addEventListener('editor:toolbar:update-padding-left', updateSpacing);
193
+ window.addEventListener('resize', onWindowResize);
186
194
  return ()=>{
187
- window.removeEventListener('editor:toolbar:update-margin-bottom', onUpdateMarginBottom);
188
- window.removeEventListener('editor:toolbar:update-padding-left', onUpdatePaddingLeft);
195
+ window.removeEventListener('editor:toolbar:update-margin-bottom', updateSpacing);
196
+ window.removeEventListener('editor:toolbar:update-padding-left', updateSpacing);
197
+ window.removeEventListener('resize', onWindowResize);
189
198
  };
190
199
  }, [
191
- onUpdateMarginBottom,
192
- onUpdatePaddingLeft
200
+ onWindowResize,
201
+ updateSpacing
193
202
  ]);
194
203
  return /*#__PURE__*/ jsxRuntime.jsx(jsxRuntime.Fragment, {
195
204
  children: props.tag !== 'Section' && /*#__PURE__*/ jsxRuntime.jsx("div", {
@@ -199,12 +208,20 @@ function Spacing(props) {
199
208
  children: /*#__PURE__*/ jsxRuntime.jsxs("div", {
200
209
  "data-spacing-margin-bottom": true,
201
210
  children: [
202
- /*#__PURE__*/ jsxRuntime.jsx("div", {
211
+ /*#__PURE__*/ jsxRuntime.jsxs("div", {
203
212
  "data-spacing-margin-bottom-bg": true,
204
213
  ref: $bottomBg,
205
- children: /*#__PURE__*/ jsxRuntime.jsx("div", {
206
- "data-spacing-margin-bottom-value": true
207
- })
214
+ children: [
215
+ /*#__PURE__*/ jsxRuntime.jsx("div", {
216
+ "data-spacing-margin-bottom-value": true
217
+ }),
218
+ /*#__PURE__*/ jsxRuntime.jsx("div", {
219
+ "data-active": isShowVisual,
220
+ "data-value-number": true,
221
+ ref: $visualNumberValue,
222
+ children: marginBottomValue
223
+ })
224
+ ]
208
225
  }),
209
226
  /*#__PURE__*/ jsxRuntime.jsx("div", {
210
227
  ref: $bottomDrag,
@@ -218,5 +235,14 @@ function Spacing(props) {
218
235
  })
219
236
  });
220
237
  }
238
+ const usePrevious = (value)=>{
239
+ const ref = react.useRef();
240
+ react.useEffect(()=>{
241
+ ref.current = value;
242
+ }, [
243
+ value
244
+ ]);
245
+ return ref.current;
246
+ };
221
247
 
222
248
  exports.default = Spacing;
@@ -424,6 +424,30 @@ const createBuilderPreviewProvider = (args, isThemeSectionEditor)=>zustand.creat
424
424
  }
425
425
  });
426
426
  }
427
+ },
428
+ updateItemAttribute: (id, value, attr)=>{
429
+ if (!attr || ![
430
+ 'label',
431
+ 'customLabel'
432
+ ].includes(attr)) return;
433
+ const state = get().state;
434
+ const item = state[id];
435
+ // Ignore section
436
+ if (item?.type === 'section') return;
437
+ if (item) {
438
+ const dateModified = Date.now();
439
+ item.dateModified = dateModified;
440
+ const updatedItem = {
441
+ ...item,
442
+ [attr]: value
443
+ };
444
+ set({
445
+ state: {
446
+ ...state,
447
+ [id]: updatedItem
448
+ }
449
+ });
450
+ }
427
451
  }
428
452
  }));
429
453
  const BuilderPreviewProvider = ({ children, state, isThemeSectionEditor, lazy, ...passProps })=>{
@@ -161,15 +161,7 @@ const ComponentToolbarPreview = ({ ...props })=>{
161
161
  return false;
162
162
  };
163
163
  const toolbarName = ()=>{
164
- const tag = props.tag;
165
- if (tag === 'IconListV2') {
166
- return 'Item list';
167
- }
168
- if (tag === 'IconList') {
169
- return 'Advanced list';
170
- }
171
- const name = props.customLabel || props.label;
172
- return name;
164
+ return props.customLabel || props.label;
173
165
  };
174
166
  const onZoomOut = (e)=>{
175
167
  e.preventDefault();
@@ -1,5 +1,5 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
- import { useRef, useCallback, useEffect } from 'react';
2
+ import { useRef, useState, useCallback, useEffect } from 'react';
3
3
  import 'zustand';
4
4
  import { useBuilderPreviewStore } from '../../contexts/BuilderPreviewContext.js';
5
5
  import 'swr';
@@ -19,6 +19,10 @@ function Spacing(props) {
19
19
  const isDragging = useRef(false);
20
20
  const startY = useRef(0);
21
21
  const marginBottom = useRef(0);
22
+ const $visualNumberValue = useRef(null);
23
+ const [marginBottomValue, setMarginBottomValue] = useState(0);
24
+ const [isShowVisual, setIsShowVisual] = useState(false);
25
+ const hideVisualNumberValue = useRef(null);
22
26
  const getNewValueMargin = (event)=>{
23
27
  const top = event.clientY;
24
28
  const diffY = Math.ceil(top - startY.current);
@@ -37,6 +41,7 @@ function Spacing(props) {
37
41
  const $component = $bottomDrag.current.closest('[data-toolbar-wrap]');
38
42
  if ($component) {
39
43
  $component.style.marginBottom = newValue;
44
+ onShowMarginBottomNumber(newValue);
40
45
  }
41
46
  }
42
47
  };
@@ -112,80 +117,84 @@ function Spacing(props) {
112
117
  }
113
118
  }
114
119
  };
115
- const onUpdateMarginBottom = useCallback((e)=>{
116
- if (isDragging.current) return;
117
- const detail = e.detail;
118
- const $component = $bottomDrag.current?.closest('[data-toolbar-wrap]');
119
- const toolbar = $component && getChildrenByAttrSelector($component, 'data-toolbar');
120
- const isActive = toolbar && toolbar.getAttribute('data-toolbar-active');
121
- if (isActive && detail?.marginBottom) {
122
- const currentValue = parseInt(detail?.marginBottom);
123
- const newValue = `${currentValue}px`;
124
- if ($bottomDrag.current && $bottomBg.current) {
125
- if (currentValue < 0) {
126
- $bottomBg.current.style.display = 'none';
127
- $bottomDrag.current.style.display = 'none';
128
- } else {
129
- $bottomBg.current.style.display = 'block';
130
- $bottomDrag.current.style.display = 'block';
131
- $bottomBg.current.style.height = newValue;
132
- $bottomDrag.current.style.top = newValue;
133
- }
134
- }
135
- }
136
- }, []);
137
- const isPopup = (el)=>{
120
+ const isLayoutElement = (el)=>{
138
121
  const tag = el.getAttribute('data-component-tag');
139
- return tag === 'Dialog';
122
+ return tag === 'Row' || tag === 'Product';
140
123
  };
141
- const isSticky = (el)=>{
142
- const tag = el.getAttribute('data-component-tag');
143
- return tag === 'Sticky';
144
- };
145
- const setPositionSpacing = useCallback((paddingLeft)=>{
124
+ const updateSpacing = useCallback(()=>{
146
125
  const $component = $bottomDrag.current?.closest('[data-toolbar-wrap]');
147
- if ($component) {
148
- if (isPopup($component) || isSticky($component)) return;
149
- const toolbar = $component && getChildrenByAttrSelector($component, 'data-toolbar');
150
- const isActive = toolbar && toolbar.getAttribute('data-toolbar-active');
151
- if (isActive && paddingLeft) {
152
- const currentValue = isNaN(parseInt(paddingLeft)) ? 0 : Math.max(parseInt(paddingLeft), 0);
153
- const newValue = `-${currentValue}px`;
154
- const translateCss = `translate(-${currentValue}px, -100%)`;
155
- if ($bottomDrag.current && $bottomBg.current) {
156
- $bottomBg.current.style.left = newValue;
126
+ if (!$component) return;
127
+ const toolbar = getChildrenByAttrSelector($component, 'data-toolbar');
128
+ if (!toolbar) return;
129
+ const isActive = toolbar.getAttribute('data-toolbar-active');
130
+ if (!isActive) return;
131
+ const style = getComputedStyle($component);
132
+ const $spacing = getChildrenByAttrSelector($component, 'data-spacing');
133
+ const $marginBottom = ($spacing?.querySelector('[data-spacing-margin-bottom]')) || null;
134
+ if ($marginBottom) {
135
+ if ($bottomBg.current && $bottomDrag.current) {
136
+ let value = style.marginBottom;
137
+ onShowMarginBottomNumber(value);
138
+ if (parseFloat(value) < 0) {
139
+ value = '0';
140
+ }
141
+ $bottomBg.current.style.height = value;
142
+ $bottomDrag.current.style.top = value;
143
+ $marginBottom.setAttribute('data-spacing-margin-bottom-active', 'true');
144
+ if (isLayoutElement($component)) {
145
+ $bottomBg.current.style.left = '0';
146
+ } else {
147
+ const paddingLeft = style.paddingLeft;
148
+ const leftValue = `-${paddingLeft}`;
149
+ const translateCss = `translate(${leftValue}, -100%)`;
150
+ $bottomBg.current.style.left = leftValue;
157
151
  $bottomDrag.current.style.transform = translateCss;
158
152
  }
159
153
  }
160
154
  }
161
155
  }, []);
162
- const onUpdatePaddingLeft = useCallback((e)=>{
163
- if (isDragging.current) return;
164
- const detail = e.detail;
165
- if (detail?.paddingLeft) {
166
- setPositionSpacing(detail.paddingLeft);
156
+ const onShowMarginBottomNumber = (value)=>{
157
+ const parsedValue = parseFloat(value);
158
+ setMarginBottomValue(parsedValue);
159
+ setIsShowVisual(true);
160
+ if (hideVisualNumberValue.current) clearTimeout(hideVisualNumberValue.current);
161
+ hideVisualNumberValue.current = setTimeout(()=>{
162
+ setIsShowVisual(false);
163
+ }, 2000);
164
+ // break point 28px
165
+ const topPosition = parsedValue < 28 && parsedValue >= 0 ? parsedValue / 2 + 16 : parsedValue > 28 ? 0 : 16;
166
+ if ($visualNumberValue.current) {
167
+ $visualNumberValue.current.style.transform = `translateY(${topPosition}px)`;
167
168
  }
168
- }, [
169
- setPositionSpacing
170
- ]);
169
+ };
170
+ const previousAdvanced = usePrevious(props.advanced?.['spacing-setting']);
171
171
  useEffect(()=>{
172
- const $component = $bottomDrag.current?.closest('[data-toolbar-wrap]');
173
- if ($component) {
174
- const style = getComputedStyle($component);
175
- const paddingLeft = style.paddingLeft;
176
- setPositionSpacing(paddingLeft);
172
+ // validate spacing setting changed
173
+ if (JSON.stringify(previousAdvanced) !== JSON.stringify(props.advanced?.['spacing-setting'])) {
174
+ updateSpacing();
177
175
  }
178
- });
176
+ }, [
177
+ previousAdvanced,
178
+ props.advanced,
179
+ updateSpacing
180
+ ]);
181
+ const onWindowResize = useCallback(()=>{
182
+ updateSpacing();
183
+ }, [
184
+ updateSpacing
185
+ ]);
179
186
  useEffect(()=>{
180
- window.addEventListener('editor:toolbar:update-margin-bottom', onUpdateMarginBottom);
181
- window.addEventListener('editor:toolbar:update-padding-left', onUpdatePaddingLeft);
187
+ window.addEventListener('editor:toolbar:update-margin-bottom', updateSpacing);
188
+ window.addEventListener('editor:toolbar:update-padding-left', updateSpacing);
189
+ window.addEventListener('resize', onWindowResize);
182
190
  return ()=>{
183
- window.removeEventListener('editor:toolbar:update-margin-bottom', onUpdateMarginBottom);
184
- window.removeEventListener('editor:toolbar:update-padding-left', onUpdatePaddingLeft);
191
+ window.removeEventListener('editor:toolbar:update-margin-bottom', updateSpacing);
192
+ window.removeEventListener('editor:toolbar:update-padding-left', updateSpacing);
193
+ window.removeEventListener('resize', onWindowResize);
185
194
  };
186
195
  }, [
187
- onUpdateMarginBottom,
188
- onUpdatePaddingLeft
196
+ onWindowResize,
197
+ updateSpacing
189
198
  ]);
190
199
  return /*#__PURE__*/ jsx(Fragment, {
191
200
  children: props.tag !== 'Section' && /*#__PURE__*/ jsx("div", {
@@ -195,12 +204,20 @@ function Spacing(props) {
195
204
  children: /*#__PURE__*/ jsxs("div", {
196
205
  "data-spacing-margin-bottom": true,
197
206
  children: [
198
- /*#__PURE__*/ jsx("div", {
207
+ /*#__PURE__*/ jsxs("div", {
199
208
  "data-spacing-margin-bottom-bg": true,
200
209
  ref: $bottomBg,
201
- children: /*#__PURE__*/ jsx("div", {
202
- "data-spacing-margin-bottom-value": true
203
- })
210
+ children: [
211
+ /*#__PURE__*/ jsx("div", {
212
+ "data-spacing-margin-bottom-value": true
213
+ }),
214
+ /*#__PURE__*/ jsx("div", {
215
+ "data-active": isShowVisual,
216
+ "data-value-number": true,
217
+ ref: $visualNumberValue,
218
+ children: marginBottomValue
219
+ })
220
+ ]
204
221
  }),
205
222
  /*#__PURE__*/ jsx("div", {
206
223
  ref: $bottomDrag,
@@ -214,5 +231,14 @@ function Spacing(props) {
214
231
  })
215
232
  });
216
233
  }
234
+ const usePrevious = (value)=>{
235
+ const ref = useRef();
236
+ useEffect(()=>{
237
+ ref.current = value;
238
+ }, [
239
+ value
240
+ ]);
241
+ return ref.current;
242
+ };
217
243
 
218
244
  export { Spacing as default };
@@ -422,6 +422,30 @@ const createBuilderPreviewProvider = (args, isThemeSectionEditor)=>createStore((
422
422
  }
423
423
  });
424
424
  }
425
+ },
426
+ updateItemAttribute: (id, value, attr)=>{
427
+ if (!attr || ![
428
+ 'label',
429
+ 'customLabel'
430
+ ].includes(attr)) return;
431
+ const state = get().state;
432
+ const item = state[id];
433
+ // Ignore section
434
+ if (item?.type === 'section') return;
435
+ if (item) {
436
+ const dateModified = Date.now();
437
+ item.dateModified = dateModified;
438
+ const updatedItem = {
439
+ ...item,
440
+ [attr]: value
441
+ };
442
+ set({
443
+ state: {
444
+ ...state,
445
+ [id]: updatedItem
446
+ }
447
+ });
448
+ }
425
449
  }
426
450
  }));
427
451
  const BuilderPreviewProvider = ({ children, state, isThemeSectionEditor, lazy, ...passProps })=>{
@@ -7704,6 +7704,7 @@ type BuilderPreviewContextProps = {
7704
7704
  initState: (data: BuilderEntityNested | BuilderEntityNested[]) => void;
7705
7705
  getParents: (id: string, limit?: number) => BuilderEntity[];
7706
7706
  updateItemName: (id: string, name: string) => void;
7707
+ updateItemAttribute: (id: string, value: string, attr: string) => void;
7707
7708
  };
7708
7709
  type BuilderPreviewProviderProps = Pick<BuilderPreviewContextProps, 'state'> & {
7709
7710
  children: React.ReactNode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gem-sdk/core",
3
- "version": "1.36.0",
3
+ "version": "1.36.6",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
6
6
  "main": "dist/cjs/index.js",
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "devDependencies": {
27
27
  "@gem-sdk/adapter-shopify": "1.25.0",
28
- "@gem-sdk/styles": "1.35.0"
28
+ "@gem-sdk/styles": "1.36.1"
29
29
  },
30
30
  "dependencies": {
31
31
  "react-error-boundary": "4.0.10",