@gem-sdk/core 1.42.7 → 1.43.0-dev.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/cjs/components/ComponentToolbarPreview.js +126 -7
  2. package/dist/cjs/components/ComponentWrapperPreview.js +44 -1
  3. package/dist/cjs/components/Render.liquid.js +3 -0
  4. package/dist/cjs/components/RenderCustomCode.js +3 -0
  5. package/dist/cjs/components/RenderPreview.js +1 -0
  6. package/dist/cjs/components/ai-generator/AIContentGenerator.js +252 -0
  7. package/dist/cjs/components/ai-generator/AIGenContentLoading.js +85 -0
  8. package/dist/cjs/components/ai-generator/components/PickProduct.js +219 -0
  9. package/dist/cjs/components/ai-generator/components/ToneAndVoice.js +77 -0
  10. package/dist/cjs/components/ai-generator/hooks/useCheckingProductInside.js +47 -0
  11. package/dist/cjs/components/ai-generator/hooks/useFlipPopup.js +110 -0
  12. package/dist/cjs/components/ai-generator/hooks/useGettingGenerateRequest.js +37 -0
  13. package/dist/cjs/components/ai-generator/hooks/useListenEventGenerate.js +70 -0
  14. package/dist/cjs/components/ai-generator/icons/AIIcon.js +67 -0
  15. package/dist/cjs/components/ai-generator/icons/CloseIcon.js +19 -0
  16. package/dist/cjs/components/ai-generator/icons/DropdownIcon.js +37 -0
  17. package/dist/cjs/components/ai-generator/icons/SearchIcon.js +21 -0
  18. package/dist/cjs/components/ai-generator/icons/ShowMoreIcon.js +21 -0
  19. package/dist/cjs/components/ai-generator/icons/UpgradeIcon.js +27 -0
  20. package/dist/cjs/components/ai-generator/icons/WarningIcon.js +31 -0
  21. package/dist/cjs/components/constant.js +19 -2
  22. package/dist/cjs/components/resize/Spacing.js +21 -11
  23. package/dist/cjs/components/theme-section/CreateThemeSection.js +3 -0
  24. package/dist/cjs/components/theme-section/ThemeSectionStatus.js +14 -5
  25. package/dist/cjs/contexts/ArticleContext.js +39 -0
  26. package/dist/cjs/contexts/ArticleListContext.js +31 -0
  27. package/dist/cjs/contexts/BuilderPreviewContext.js +17 -10
  28. package/dist/cjs/contexts/SectionContext.js +1 -0
  29. package/dist/cjs/contexts/ShopContext.js +18 -0
  30. package/dist/cjs/graphql/queries/articles.generated.js +55 -0
  31. package/dist/cjs/graphql/queries/blogs.generated.js +63 -0
  32. package/dist/cjs/helpers/align.js +19 -0
  33. package/dist/cjs/helpers/background.js +6 -3
  34. package/dist/cjs/helpers/carousel.js +7 -10
  35. package/dist/cjs/helpers/colors.js +2 -2
  36. package/dist/cjs/helpers/queries/get-products.js +23 -0
  37. package/dist/cjs/helpers/shadow.js +1 -1
  38. package/dist/cjs/helpers/typography.js +43 -8
  39. package/dist/cjs/hooks/articles/useArticlesQuery.js +32 -0
  40. package/dist/cjs/hooks/shop/use-products-query.js +29 -0
  41. package/dist/cjs/hooks/useAnimations.js +3 -0
  42. package/dist/cjs/hooks/useFormatMoney.js +61 -60
  43. package/dist/cjs/hooks/useInitialSwatchesOptions.js +3 -0
  44. package/dist/cjs/hooks/useProduct.js +3 -0
  45. package/dist/cjs/index.js +14 -0
  46. package/dist/esm/components/ComponentToolbarPreview.js +127 -8
  47. package/dist/esm/components/ComponentWrapperPreview.js +44 -1
  48. package/dist/esm/components/Render.liquid.js +3 -0
  49. package/dist/esm/components/RenderCustomCode.js +3 -0
  50. package/dist/esm/components/RenderPreview.js +1 -0
  51. package/dist/esm/components/ai-generator/AIContentGenerator.js +250 -0
  52. package/dist/esm/components/ai-generator/AIGenContentLoading.js +83 -0
  53. package/dist/esm/components/ai-generator/components/PickProduct.js +217 -0
  54. package/dist/esm/components/ai-generator/components/ToneAndVoice.js +75 -0
  55. package/dist/esm/components/ai-generator/hooks/useCheckingProductInside.js +45 -0
  56. package/dist/esm/components/ai-generator/hooks/useFlipPopup.js +108 -0
  57. package/dist/esm/components/ai-generator/hooks/useGettingGenerateRequest.js +35 -0
  58. package/dist/esm/components/ai-generator/hooks/useListenEventGenerate.js +68 -0
  59. package/dist/esm/components/ai-generator/icons/AIIcon.js +65 -0
  60. package/dist/esm/components/ai-generator/icons/CloseIcon.js +17 -0
  61. package/dist/esm/components/ai-generator/icons/DropdownIcon.js +34 -0
  62. package/dist/esm/components/ai-generator/icons/SearchIcon.js +19 -0
  63. package/dist/esm/components/ai-generator/icons/ShowMoreIcon.js +19 -0
  64. package/dist/esm/components/ai-generator/icons/UpgradeIcon.js +25 -0
  65. package/dist/esm/components/ai-generator/icons/WarningIcon.js +29 -0
  66. package/dist/esm/components/constant.js +19 -3
  67. package/dist/esm/components/resize/Spacing.js +21 -11
  68. package/dist/esm/components/theme-section/CreateThemeSection.js +3 -0
  69. package/dist/esm/components/theme-section/ThemeSectionStatus.js +14 -5
  70. package/dist/esm/contexts/ArticleContext.js +36 -0
  71. package/dist/esm/contexts/ArticleListContext.js +27 -0
  72. package/dist/esm/contexts/BuilderPreviewContext.js +17 -10
  73. package/dist/esm/contexts/SectionContext.js +1 -0
  74. package/dist/esm/contexts/ShopContext.js +19 -1
  75. package/dist/esm/graphql/queries/articles.generated.js +53 -0
  76. package/dist/esm/graphql/queries/blogs.generated.js +61 -0
  77. package/dist/esm/helpers/align.js +17 -0
  78. package/dist/esm/helpers/background.js +6 -4
  79. package/dist/esm/helpers/carousel.js +7 -10
  80. package/dist/esm/helpers/colors.js +2 -2
  81. package/dist/esm/helpers/queries/get-products.js +23 -1
  82. package/dist/esm/helpers/shadow.js +1 -1
  83. package/dist/esm/helpers/typography.js +43 -9
  84. package/dist/esm/hooks/articles/useArticlesQuery.js +29 -0
  85. package/dist/esm/hooks/shop/use-products-query.js +30 -2
  86. package/dist/esm/hooks/useAnimations.js +3 -0
  87. package/dist/esm/hooks/useFormatMoney.js +61 -61
  88. package/dist/esm/hooks/useInitialSwatchesOptions.js +3 -0
  89. package/dist/esm/hooks/useProduct.js +3 -0
  90. package/dist/esm/index.js +7 -3
  91. package/dist/types/index.d.ts +263 -51
  92. package/package.json +6 -3
@@ -0,0 +1,83 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState, useRef, useCallback, useEffect } from 'react';
3
+ import { AIIcon } from './icons/AIIcon.js';
4
+
5
+ function getRandomArbitrary(min, max) {
6
+ const randomNum = Math.random();
7
+ return randomNum * (max - min) + min;
8
+ }
9
+ const AIGenContentLoading = ({ ...props })=>{
10
+ const [isGenerating, setIsGenerating] = useState(false);
11
+ const [time, setTime] = useState(0);
12
+ const interval = useRef(null);
13
+ const onGenerateContentStatus = useCallback((e)=>{
14
+ const detail = e.detail;
15
+ if (detail?.generatingUid !== props.uid) {
16
+ return;
17
+ }
18
+ if (detail.status === 'loading') {
19
+ setIsGenerating(true);
20
+ return;
21
+ }
22
+ if (detail.status === 'success') {
23
+ setIsGenerating(false);
24
+ return;
25
+ }
26
+ }, [
27
+ props.uid
28
+ ]);
29
+ useEffect(()=>{
30
+ if (isGenerating) {
31
+ handleFakeLoading();
32
+ } else {
33
+ setTime(0);
34
+ }
35
+ return ()=>{
36
+ interval.current && clearInterval(interval.current);
37
+ };
38
+ }, [
39
+ isGenerating
40
+ ]);
41
+ const handleFakeLoading = ()=>{
42
+ setTime(0);
43
+ interval.current = setInterval(()=>{
44
+ setTime((time)=>{
45
+ const randomNum = getRandomArbitrary(0, 6);
46
+ return time >= 580 ? time : time + randomNum;
47
+ });
48
+ }, 50);
49
+ };
50
+ useEffect(()=>{
51
+ window.addEventListener('editor:ai-generate-content-status', onGenerateContentStatus);
52
+ return ()=>{
53
+ window.removeEventListener('editor:ai-generate-content-status', onGenerateContentStatus);
54
+ };
55
+ }, [
56
+ onGenerateContentStatus
57
+ ]);
58
+ return isGenerating ? /*#__PURE__*/ jsxs("div", {
59
+ className: "gp-absolute gp-top-0 gp-left-0 gp-w-full gp-h-full gp-bg-white gp-bg-opacity-70 gp-flex gp-justify-center gp-items-center gp-z-100 gp-gap-2",
60
+ children: [
61
+ /*#__PURE__*/ jsx("div", {
62
+ className: "gp-absolute gp-left-0 gp-top-0 gp-z-2 gp-flex gp-h-full gp-w-full",
63
+ children: /*#__PURE__*/ jsxs("div", {
64
+ className: `gp-relative gp-h-[2px] gp-w-full gp-overflow-hidden gp-rounded-md`,
65
+ children: [
66
+ /*#__PURE__*/ jsx("div", {
67
+ className: "gp-absolute gp-h-full gp-w-full gp-rounded-md gp-bg-[#F4F4F4]"
68
+ }),
69
+ /*#__PURE__*/ jsx("div", {
70
+ className: "gps-image-to-layout-progress-bar gp-absolute gp-h-full gp-rounded-md gp-transition-all",
71
+ style: {
72
+ width: `${time / 600 * 100}%`
73
+ }
74
+ })
75
+ ]
76
+ })
77
+ }),
78
+ /*#__PURE__*/ jsx(AIIcon, {})
79
+ ]
80
+ }) : null;
81
+ };
82
+
83
+ export { AIGenContentLoading };
@@ -0,0 +1,217 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState, useRef, useMemo, useEffect } from 'react';
3
+ import { SearchIcon } from '../icons/SearchIcon.js';
4
+ import { useListProductQuery } from '../../../hooks/shop/use-products-query.js';
5
+ import classNames from 'classnames';
6
+ import 'zustand';
7
+ import 'swr';
8
+ import '@gem-sdk/adapter-shopify';
9
+ import 'swr/mutation';
10
+ import { useProductQuery } from '../../../hooks/shop/use-product-query.js';
11
+ import 'vanilla-lazyload';
12
+ import '../../../hooks/useCartUI.js';
13
+ import 'react-transition-group';
14
+ import '@gem-sdk/core';
15
+ import 'dayjs';
16
+ import '../../../helpers/convert.js';
17
+
18
+ const PickProduct = (props)=>{
19
+ const LIMIT_PRODUCTS = 8;
20
+ const [productVariables, setProductVariables] = useState(!props.productId ? {
21
+ first: LIMIT_PRODUCTS
22
+ } : undefined);
23
+ const { data: productList, isLoading: isLoadingGetProducts, isValidating: isValidatingGetProducts, size: productsSize, setSize: setProductsSize } = useListProductQuery(productVariables, {
24
+ revalidateFirstPage: false
25
+ });
26
+ const { data: sectionProduct } = useProductQuery(props.productId);
27
+ const [activeProduct, setActiveProduct] = useState();
28
+ const [isShowChooseProduct, setIsShowChooseProduct] = useState(false);
29
+ const debounceSearch = useRef(null);
30
+ const debounceScroll = useRef(null);
31
+ const toggleChooseProduct = ()=>{
32
+ if (props.productId) return;
33
+ setIsShowChooseProduct(!isShowChooseProduct);
34
+ };
35
+ const chooseProduct = (product)=>{
36
+ setActiveProduct(product);
37
+ setIsShowChooseProduct(false);
38
+ };
39
+ const searchProduct = (e)=>{
40
+ debounceSearch.current && clearTimeout(debounceSearch.current);
41
+ debounceSearch.current = setTimeout(()=>{
42
+ const searchValue = e.target.value ?? '';
43
+ if (searchValue) {
44
+ setProductVariables({
45
+ first: LIMIT_PRODUCTS,
46
+ where: {
47
+ titleContainsFold: searchValue
48
+ }
49
+ });
50
+ return;
51
+ }
52
+ setProductVariables({
53
+ first: LIMIT_PRODUCTS
54
+ });
55
+ }, 200);
56
+ };
57
+ const handleOpenProductElementSettings = ()=>{
58
+ props.openProductSetting();
59
+ };
60
+ const handleLoadMore = (e)=>{
61
+ const target = e.target;
62
+ if (target.scrollHeight - target.scrollTop === target.clientHeight) {
63
+ debounceScroll.current && clearTimeout(debounceScroll.current);
64
+ debounceScroll.current = setTimeout(()=>{
65
+ setProductsSize(productsSize + 1);
66
+ }, 50);
67
+ }
68
+ };
69
+ const products = useMemo(()=>{
70
+ return productList?.reduce((acc, curr)=>{
71
+ return [
72
+ ...acc,
73
+ ...curr.products?.edges ?? []
74
+ ];
75
+ }, []) ?? [];
76
+ }, [
77
+ productList
78
+ ]);
79
+ useEffect(()=>{
80
+ if (products.length && !activeProduct && !props.productId) {
81
+ const firstProduct = products[0]?.node;
82
+ if (!firstProduct) return;
83
+ setActiveProduct({
84
+ id: firstProduct?.id,
85
+ name: firstProduct?.title,
86
+ image: firstProduct.featuredImage?.src
87
+ });
88
+ }
89
+ }, [
90
+ products,
91
+ activeProduct,
92
+ props.productId
93
+ ]);
94
+ useEffect(()=>{
95
+ if (activeProduct && activeProduct.name) {
96
+ props.changeProductName(activeProduct.name);
97
+ }
98
+ }, [
99
+ activeProduct,
100
+ props
101
+ ]);
102
+ useEffect(()=>{
103
+ if (sectionProduct) {
104
+ setActiveProduct({
105
+ id: sectionProduct.id,
106
+ name: sectionProduct.title,
107
+ image: sectionProduct.featuredImage?.src
108
+ });
109
+ }
110
+ }, [
111
+ sectionProduct
112
+ ]);
113
+ return /*#__PURE__*/ jsxs("div", {
114
+ className: "gp-flex gp-flex-col gp-gap-2",
115
+ children: [
116
+ /*#__PURE__*/ jsx("p", {
117
+ className: "gp-py-2 gp-text-xs",
118
+ children: "Product"
119
+ }),
120
+ /*#__PURE__*/ jsxs("div", {
121
+ className: "gp-relative",
122
+ children: [
123
+ !isLoadingGetProducts || activeProduct ? /*#__PURE__*/ jsxs("button", {
124
+ className: classNames({
125
+ 'gp-cursor-default': props.productId
126
+ }, 'gp-flex gp-gap-2 gp-items-center gp-w-full gp-p-2 gp-rounded-lg gp-bg-[#333333] gp-text-xs'),
127
+ onClick: toggleChooseProduct,
128
+ children: [
129
+ /*#__PURE__*/ jsx("img", {
130
+ className: "gp-rounded-lg gp-w-10 gp-h-10",
131
+ src: activeProduct?.image,
132
+ alt: "product_image"
133
+ }),
134
+ /*#__PURE__*/ jsx("span", {
135
+ className: "gp-truncate gp-max-w-[210px]",
136
+ children: activeProduct?.name
137
+ })
138
+ ]
139
+ }) : /*#__PURE__*/ jsx("div", {
140
+ children: /*#__PURE__*/ jsx("span", {
141
+ className: "gp-text-xs",
142
+ children: "Getting products..."
143
+ })
144
+ }),
145
+ props.productId && /*#__PURE__*/ jsx("div", {
146
+ className: "gp-mt-2 gp-text-xs",
147
+ children: /*#__PURE__*/ jsxs("p", {
148
+ children: [
149
+ "You can manage it in",
150
+ ' ',
151
+ /*#__PURE__*/ jsx("button", {
152
+ className: "gp-text-[#8AA4FF] gp-cursor-pointer hover:gp-underline",
153
+ onClick: handleOpenProductElementSettings,
154
+ children: "Product element"
155
+ })
156
+ ]
157
+ })
158
+ }),
159
+ isShowChooseProduct && /*#__PURE__*/ jsxs("div", {
160
+ className: "gp-absolute gp-w-full gp-top-16 gp-left-0 gp-rounded-lg gp-bg-[#333333] gp-p-2 gp-flex gp-flex-col gp-gap-2 gp-z-10",
161
+ children: [
162
+ /*#__PURE__*/ jsxs("div", {
163
+ className: "gp-flex gp-items-center gp-gap-2 gp-p-2",
164
+ children: [
165
+ /*#__PURE__*/ jsx(SearchIcon, {}),
166
+ /*#__PURE__*/ jsx("input", {
167
+ className: "gp-bg-transparent gp-w-full focus-visible:!gp-outline-none gp-text-xs",
168
+ placeholder: "Search product...",
169
+ onChange: searchProduct
170
+ })
171
+ ]
172
+ }),
173
+ /*#__PURE__*/ jsxs("div", {
174
+ className: "gp-max-h-[168px] gp-overflow-auto scrollbar:gp-w-1 scrollbar-thumb:gp-bg-[#999] scrollbar-thumb:gp-rounded-xl",
175
+ onScroll: handleLoadMore,
176
+ children: [
177
+ products?.map((item)=>{
178
+ return /*#__PURE__*/ jsxs("button", {
179
+ className: "gp-flex gp-p-2 hover:gp-bg-[#3B3B3B] gp-rounded-lg gp-cursor-pointer gp-gap-2 gp-items-center",
180
+ onClick: ()=>{
181
+ chooseProduct({
182
+ id: item.node?.id,
183
+ name: item.node?.title,
184
+ image: item.node?.featuredImage?.src
185
+ });
186
+ },
187
+ children: [
188
+ /*#__PURE__*/ jsx("img", {
189
+ className: "gp-rounded-lg gp-w-10 gp-h-10",
190
+ src: item.node?.featuredImage?.src,
191
+ alt: "product_image"
192
+ }),
193
+ /*#__PURE__*/ jsx("span", {
194
+ className: "gp-truncate gp-max-w-[210px] gp-text-xs",
195
+ children: item.node?.title
196
+ })
197
+ ]
198
+ }, item.node?.id);
199
+ }),
200
+ isLoadingGetProducts || isValidatingGetProducts && /*#__PURE__*/ jsx("div", {
201
+ className: "gp-p-2",
202
+ children: /*#__PURE__*/ jsx("span", {
203
+ className: "gp-text-xs",
204
+ children: "Getting products..."
205
+ })
206
+ })
207
+ ]
208
+ })
209
+ ]
210
+ })
211
+ ]
212
+ })
213
+ ]
214
+ });
215
+ };
216
+
217
+ export { PickProduct };
@@ -0,0 +1,75 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useState, useEffect } from 'react';
3
+ import { DropdownIcon, TickIcon } from '../icons/DropdownIcon.js';
4
+ import classNames from 'classnames';
5
+
6
+ const ToneAndVoice = (props)=>{
7
+ const listToneAndVoice = [
8
+ 'Persuasive',
9
+ 'Friendly',
10
+ 'Professional',
11
+ 'Casual'
12
+ ];
13
+ const [tone, setTone] = useState(listToneAndVoice[0]);
14
+ const [isShow, setIsShow] = useState(false);
15
+ const toggle = ()=>{
16
+ setIsShow(!isShow);
17
+ };
18
+ const setValue = (value)=>{
19
+ setTone(value);
20
+ setIsShow(false);
21
+ };
22
+ useEffect(()=>{
23
+ tone && props.changeToneAndVoice(tone);
24
+ }, [
25
+ tone,
26
+ props
27
+ ]);
28
+ return /*#__PURE__*/ jsx("div", {
29
+ children: /*#__PURE__*/ jsxs("div", {
30
+ className: "gp-flex gp-flex-col gp-gap-2",
31
+ children: [
32
+ /*#__PURE__*/ jsx("p", {
33
+ className: "gp-py-2 gp-text-xs",
34
+ children: "Tone and Voice"
35
+ }),
36
+ /*#__PURE__*/ jsxs("div", {
37
+ className: "gp-relative",
38
+ children: [
39
+ /*#__PURE__*/ jsxs("button", {
40
+ className: "gp-flex gp-justify-between gp-items-center gp-w-full gp-p-2 gp-rounded-lg gp-bg-[#333333] gp-text-xs",
41
+ onClick: toggle,
42
+ children: [
43
+ tone,
44
+ /*#__PURE__*/ jsx(DropdownIcon, {})
45
+ ]
46
+ }),
47
+ isShow ? /*#__PURE__*/ jsx("div", {
48
+ className: "gp-absolute gp-w-full gp-top-10 gp-left-0 gp-rounded-lg gp-bg-[#333333] gp-p-2 gp-flex gp-flex-col gp-gap-2 gp-z-10",
49
+ children: listToneAndVoice.map((item)=>{
50
+ return /*#__PURE__*/ jsxs("button", {
51
+ className: "gp-flex gp-p-2 hover:gp-bg-[#3B3B3B] gp-rounded-lg gp-cursor-pointer gp-gap-3 gp-items-center",
52
+ onClick: ()=>setValue(item),
53
+ children: [
54
+ /*#__PURE__*/ jsx("div", {
55
+ className: classNames({
56
+ 'gp-invisible': tone !== item
57
+ }),
58
+ children: /*#__PURE__*/ jsx(TickIcon, {})
59
+ }),
60
+ /*#__PURE__*/ jsx("span", {
61
+ className: "gp-text-xs",
62
+ children: item
63
+ })
64
+ ]
65
+ }, item);
66
+ })
67
+ }) : null
68
+ ]
69
+ })
70
+ ]
71
+ })
72
+ });
73
+ };
74
+
75
+ export { ToneAndVoice };
@@ -0,0 +1,45 @@
1
+ import { useState, useCallback, useEffect } from 'react';
2
+
3
+ const useCheckingProductInside = (genTool, options)=>{
4
+ const [productElement, setProductElement] = useState({});
5
+ const checkSectionHasProduct = useCallback(()=>{
6
+ if (!genTool.current) {
7
+ setProductElement({
8
+ productId: '',
9
+ uid: ''
10
+ });
11
+ return;
12
+ }
13
+ const sectionEl = genTool.current?.closest('[data-component-tag="Section"]');
14
+ const productEl = sectionEl?.querySelector('[data-product-id]:not([data-product-id=""])');
15
+ const productId = productEl?.getAttribute('data-product-id');
16
+ const productElUid = productEl?.getAttribute('data-uid');
17
+ const productListOutSideProduct = productEl?.closest('[data-component-tag="ProductList"]');
18
+ if (productListOutSideProduct || !productId) {
19
+ setProductElement({
20
+ productId: '',
21
+ uid: ''
22
+ });
23
+ return;
24
+ }
25
+ setProductElement({
26
+ productId: productId ? 'gid://shopify/Product/' + productId : '',
27
+ uid: productElUid ?? ''
28
+ });
29
+ }, [
30
+ genTool
31
+ ]);
32
+ useEffect(()=>{
33
+ if (!options?.isEnabled) return;
34
+ checkSectionHasProduct();
35
+ }, [
36
+ options?.isEnabled,
37
+ checkSectionHasProduct
38
+ ]);
39
+ return {
40
+ productElement,
41
+ checkSectionHasProduct
42
+ };
43
+ };
44
+
45
+ export { useCheckingProductInside };
@@ -0,0 +1,108 @@
1
+ import { useState, useCallback, useEffect } from 'react';
2
+
3
+ const useFlipPopup = (isShowPopup, dom)=>{
4
+ const { genTool, genPopup, genPopupHeader, genButtonWrapper } = dom;
5
+ const [popupPositionY, setPopupPositionY] = useState('top');
6
+ const [popupPositionX, setPopupPositionX] = useState('left');
7
+ const [bodyMaxHeight, setBodyMaxHeight] = useState(null);
8
+ const [isValidating, setIsValidating] = useState(true);
9
+ const calculateMaxHeight = useCallback((currentPopupPositionY)=>{
10
+ const parentOverflow = genTool.current?.closest("[class~='gp-overflow-hidden']");
11
+ if (!parentOverflow || !genTool.current) {
12
+ return {
13
+ positionY: currentPopupPositionY,
14
+ maxHeight: null
15
+ };
16
+ }
17
+ const parentOverflowPos = parentOverflow.getBoundingClientRect();
18
+ const genToolPos = genTool.current.getBoundingClientRect();
19
+ const genToolHeaderHeight = genPopupHeader.current?.getBoundingClientRect().height || 0;
20
+ const genButtonHeight = genButtonWrapper.current?.getBoundingClientRect().height || 0;
21
+ const DISTANCE = 8;
22
+ const maxHeightForPositionTop = Math.max(parentOverflowPos.bottom - genToolPos.bottom - genToolHeaderHeight - genButtonHeight - DISTANCE, 0);
23
+ const maxHeightForPositionBottom = Math.max(genToolPos.top - parentOverflowPos.top - genToolHeaderHeight - genButtonHeight - DISTANCE, 0);
24
+ if (maxHeightForPositionBottom > maxHeightForPositionTop) {
25
+ return {
26
+ positionY: 'bottom',
27
+ maxHeight: maxHeightForPositionBottom
28
+ };
29
+ }
30
+ return {
31
+ positionY: 'top',
32
+ maxHeight: maxHeightForPositionTop
33
+ };
34
+ }, [
35
+ genTool,
36
+ genPopupHeader,
37
+ genButtonWrapper
38
+ ]);
39
+ const handleChangePopupPositionY = useCallback((posY)=>{
40
+ const { positionY: calcPosY, maxHeight } = calculateMaxHeight(posY);
41
+ setPopupPositionY(calcPosY);
42
+ setBodyMaxHeight(maxHeight);
43
+ }, [
44
+ calculateMaxHeight
45
+ ]);
46
+ const calculatePopupPositionY = useCallback(()=>{
47
+ if (!genTool.current || !genPopup.current) return;
48
+ const viewHeight = window.innerHeight;
49
+ const scrollHeight = document.documentElement.scrollHeight;
50
+ const scrollTop = document.documentElement.scrollTop;
51
+ const toolPos = genTool.current?.getBoundingClientRect();
52
+ const genPopupHeight = genPopup.current?.getBoundingClientRect().height;
53
+ const MIN_DISTANCE = 50;
54
+ if (scrollTop + toolPos.top + genPopupHeight >= scrollHeight - MIN_DISTANCE) {
55
+ handleChangePopupPositionY('bottom');
56
+ return;
57
+ }
58
+ if (toolPos.bottom + genPopupHeight > viewHeight) {
59
+ if (toolPos.top - genPopupHeight < 0) {
60
+ handleChangePopupPositionY('top');
61
+ return;
62
+ }
63
+ handleChangePopupPositionY('bottom');
64
+ return;
65
+ }
66
+ handleChangePopupPositionY('top');
67
+ }, [
68
+ genPopup,
69
+ genTool,
70
+ handleChangePopupPositionY
71
+ ]);
72
+ const calculatePopupPositionX = useCallback(()=>{
73
+ if (!genTool.current || !genPopup.current) return;
74
+ const viewWidth = window.innerWidth;
75
+ const toolPos = genTool.current?.getBoundingClientRect();
76
+ const genPopupWidth = genPopup.current?.getBoundingClientRect().width;
77
+ if (toolPos.left + genPopupWidth > viewWidth) {
78
+ setPopupPositionX('right');
79
+ return;
80
+ }
81
+ setPopupPositionX('left');
82
+ }, [
83
+ genPopup,
84
+ genTool
85
+ ]);
86
+ useEffect(()=>{
87
+ if (!isShowPopup) {
88
+ setIsValidating(true);
89
+ return;
90
+ }
91
+ setIsValidating(true);
92
+ calculatePopupPositionY();
93
+ calculatePopupPositionX();
94
+ setIsValidating(false);
95
+ }, [
96
+ isShowPopup,
97
+ calculatePopupPositionX,
98
+ calculatePopupPositionY
99
+ ]);
100
+ return {
101
+ isValidating,
102
+ bodyMaxHeight,
103
+ popupPositionY,
104
+ popupPositionX
105
+ };
106
+ };
107
+
108
+ export { useFlipPopup };
@@ -0,0 +1,35 @@
1
+ import { useState } from 'react';
2
+
3
+ const useGettingGenerateRequest = ()=>{
4
+ const [prompt, setPrompt] = useState('');
5
+ const [productName, setProductName] = useState('');
6
+ const [tone, setTone] = useState('');
7
+ const changePrompt = (value)=>{
8
+ const limit = 200;
9
+ setPrompt(value.slice(0, limit));
10
+ };
11
+ const changeProductName = (value)=>{
12
+ setProductName(value);
13
+ };
14
+ const changeTone = (value)=>{
15
+ setTone(value);
16
+ };
17
+ const getRequestBody = ()=>{
18
+ return {
19
+ prompt,
20
+ productName,
21
+ tone
22
+ };
23
+ };
24
+ return {
25
+ prompt,
26
+ changePrompt,
27
+ productName,
28
+ changeProductName,
29
+ tone,
30
+ changeTone,
31
+ getRequestBody
32
+ };
33
+ };
34
+
35
+ export { useGettingGenerateRequest };
@@ -0,0 +1,68 @@
1
+ import { useState, useCallback, useEffect } from 'react';
2
+
3
+ const useListenEventGenerate = (componentInfo)=>{
4
+ const { uid: componentUid, tag: componentTag } = componentInfo;
5
+ const [isGenerating, setIsGenerating] = useState(false);
6
+ const onGenerate = (body)=>{
7
+ const eventCreate = new CustomEvent('editor:toolbar:ai-generate-content', {
8
+ bubbles: true,
9
+ detail: {
10
+ componentUid: componentUid,
11
+ componentTag: componentTag,
12
+ genRequest: body
13
+ }
14
+ });
15
+ window.dispatchEvent(eventCreate);
16
+ setIsGenerating(true);
17
+ onNotifyStatus('loading');
18
+ };
19
+ const onNotifyStatus = (status)=>{
20
+ const eventNotifyStatus = new CustomEvent('editor:ai-generate-content-status', {
21
+ bubbles: true,
22
+ detail: {
23
+ status: status,
24
+ generatingUid: componentUid
25
+ }
26
+ });
27
+ window.dispatchEvent(eventNotifyStatus);
28
+ };
29
+ const onGenerateContentStatus = useCallback((e)=>{
30
+ const detail = e.detail;
31
+ if (detail?.generatingUid === componentUid && detail.status === 'success') {
32
+ setIsGenerating(false);
33
+ }
34
+ }, [
35
+ componentUid
36
+ ]);
37
+ const onOpenProductElementSettings = (productElementUid)=>{
38
+ const eventCreate = new CustomEvent('editor:toolbar:open-product-element', {
39
+ bubbles: true,
40
+ detail: {
41
+ productElementUid: productElementUid
42
+ }
43
+ });
44
+ window.dispatchEvent(eventCreate);
45
+ };
46
+ const goToPricing = ()=>{
47
+ const eventCreate = new CustomEvent('editor:toolbar:ai-gen-content-go-to-pricing', {
48
+ bubbles: true
49
+ });
50
+ window.dispatchEvent(eventCreate);
51
+ };
52
+ useEffect(()=>{
53
+ window.addEventListener('editor:ai-generate-content-status', onGenerateContentStatus);
54
+ return ()=>{
55
+ window.removeEventListener('editor:ai-generate-content-status', onGenerateContentStatus);
56
+ };
57
+ }, [
58
+ onGenerateContentStatus
59
+ ]);
60
+ return {
61
+ isGenerating,
62
+ onGenerate,
63
+ onOpenProductElementSettings,
64
+ goToPricing
65
+ };
66
+ };
67
+
68
+ export { useListenEventGenerate };