@gem-sdk/core 1.41.0-dev.20 → 1.41.0-dev.26

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 (52) hide show
  1. package/dist/cjs/components/ComponentToolbarPreview.js +10 -0
  2. package/dist/cjs/components/ComponentWrapperPreview.js +1 -0
  3. package/dist/cjs/components/Render.liquid.js +2 -0
  4. package/dist/cjs/components/RenderCustomCode.js +2 -0
  5. package/dist/cjs/components/ai-generator/AIContentGenerator.js +189 -0
  6. package/dist/cjs/components/ai-generator/AIGenContentLoading.js +57 -0
  7. package/dist/cjs/components/ai-generator/components/PickProduct.js +218 -0
  8. package/dist/cjs/components/ai-generator/components/ToneAndVoice.js +77 -0
  9. package/dist/cjs/components/ai-generator/hooks/useCheckingProductInside.js +47 -0
  10. package/dist/cjs/components/ai-generator/hooks/useFlipPopup.js +70 -0
  11. package/dist/cjs/components/ai-generator/hooks/useGettingGenerateRequest.js +37 -0
  12. package/dist/cjs/components/ai-generator/hooks/useListenEventGenerate.js +63 -0
  13. package/dist/cjs/components/ai-generator/icons/AIIcon.js +67 -0
  14. package/dist/cjs/components/ai-generator/icons/CloseIcon.js +19 -0
  15. package/dist/cjs/components/ai-generator/icons/DropdownIcon.js +37 -0
  16. package/dist/cjs/components/ai-generator/icons/SearchIcon.js +21 -0
  17. package/dist/cjs/components/ai-generator/icons/ShowMoreIcon.js +21 -0
  18. package/dist/cjs/components/constant.js +13 -0
  19. package/dist/cjs/components/resize/Spacing.js +2 -0
  20. package/dist/cjs/components/theme-section/CreateThemeSection.js +2 -0
  21. package/dist/cjs/helpers/queries/get-products.js +60 -2
  22. package/dist/cjs/hooks/shop/use-products-query.js +29 -0
  23. package/dist/cjs/hooks/useAnimations.js +2 -0
  24. package/dist/cjs/hooks/useInitialSwatchesOptions.js +2 -0
  25. package/dist/cjs/hooks/useProduct.js +2 -0
  26. package/dist/esm/components/ComponentToolbarPreview.js +10 -0
  27. package/dist/esm/components/ComponentWrapperPreview.js +1 -0
  28. package/dist/esm/components/Render.liquid.js +2 -0
  29. package/dist/esm/components/RenderCustomCode.js +2 -0
  30. package/dist/esm/components/ai-generator/AIContentGenerator.js +187 -0
  31. package/dist/esm/components/ai-generator/AIGenContentLoading.js +55 -0
  32. package/dist/esm/components/ai-generator/components/PickProduct.js +216 -0
  33. package/dist/esm/components/ai-generator/components/ToneAndVoice.js +75 -0
  34. package/dist/esm/components/ai-generator/hooks/useCheckingProductInside.js +45 -0
  35. package/dist/esm/components/ai-generator/hooks/useFlipPopup.js +68 -0
  36. package/dist/esm/components/ai-generator/hooks/useGettingGenerateRequest.js +35 -0
  37. package/dist/esm/components/ai-generator/hooks/useListenEventGenerate.js +61 -0
  38. package/dist/esm/components/ai-generator/icons/AIIcon.js +65 -0
  39. package/dist/esm/components/ai-generator/icons/CloseIcon.js +17 -0
  40. package/dist/esm/components/ai-generator/icons/DropdownIcon.js +34 -0
  41. package/dist/esm/components/ai-generator/icons/SearchIcon.js +19 -0
  42. package/dist/esm/components/ai-generator/icons/ShowMoreIcon.js +19 -0
  43. package/dist/esm/components/constant.js +13 -1
  44. package/dist/esm/components/resize/Spacing.js +2 -0
  45. package/dist/esm/components/theme-section/CreateThemeSection.js +2 -0
  46. package/dist/esm/helpers/queries/get-products.js +60 -3
  47. package/dist/esm/hooks/shop/use-products-query.js +30 -2
  48. package/dist/esm/hooks/useAnimations.js +2 -0
  49. package/dist/esm/hooks/useInitialSwatchesOptions.js +2 -0
  50. package/dist/esm/hooks/useProduct.js +2 -0
  51. package/dist/types/index.d.ts +2 -1
  52. package/package.json +3 -3
@@ -0,0 +1,187 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState, useRef, useCallback, useEffect } from 'react';
3
+ import { AIIcon } from './icons/AIIcon.js';
4
+ import { CloseIcon } from './icons/CloseIcon.js';
5
+ import { ShowMoreIcon } from './icons/ShowMoreIcon.js';
6
+ import { PickProduct } from './components/PickProduct.js';
7
+ import { ToneAndVoice } from './components/ToneAndVoice.js';
8
+ import classNames from 'classnames';
9
+ import { useListenEventGenerate } from './hooks/useListenEventGenerate.js';
10
+ import { useGettingGenerateRequest } from './hooks/useGettingGenerateRequest.js';
11
+ import { useFlipPopup } from './hooks/useFlipPopup.js';
12
+ import { useCheckingProductInside } from './hooks/useCheckingProductInside.js';
13
+
14
+ const AIContentGenerator = ({ ...props })=>{
15
+ const [isShowPopup, setIsShowPopup] = useState(false);
16
+ const [isShowMore, setIsShowMore] = useState(false);
17
+ const genTool = useRef(null);
18
+ const genPopup = useRef(null);
19
+ const { popupPositionX, popupPositionY, isValidating: isValidatingFlipPopup } = useFlipPopup(isShowPopup, {
20
+ genTool,
21
+ genPopup
22
+ });
23
+ const { isGenerating, onGenerate, onOpenProductElementSettings } = useListenEventGenerate({
24
+ uid: props.uid,
25
+ tag: String(props.tag)
26
+ });
27
+ const { getRequestBody, prompt, changeProductName, changePrompt, changeTone } = useGettingGenerateRequest();
28
+ const { productElement, checkSectionHasProduct } = useCheckingProductInside(genTool);
29
+ const togglePopup = ()=>{
30
+ setIsShowPopup(!isShowPopup);
31
+ };
32
+ const hidePopup = ()=>{
33
+ setIsShowPopup(false);
34
+ };
35
+ const onChangePrompt = (e)=>{
36
+ changePrompt(e.target.value);
37
+ };
38
+ const onActiveComponent = useCallback((e)=>{
39
+ const detail = e.detail;
40
+ if (detail?.componentUid !== props.uid) {
41
+ hidePopup();
42
+ return;
43
+ }
44
+ checkSectionHasProduct();
45
+ }, [
46
+ props.uid,
47
+ checkSectionHasProduct
48
+ ]);
49
+ const toggleShowMore = ()=>{
50
+ setIsShowMore(!isShowMore);
51
+ };
52
+ const handleGenerateContent = ()=>{
53
+ const body = getRequestBody();
54
+ onGenerate(body);
55
+ };
56
+ const handleOpenProductSetting = ()=>{
57
+ onOpenProductElementSettings(productElement.uid ?? '');
58
+ };
59
+ useEffect(()=>{
60
+ if (!isGenerating) {
61
+ hidePopup();
62
+ }
63
+ }, [
64
+ isGenerating
65
+ ]);
66
+ useEffect(()=>{
67
+ if (productElement.productId) {
68
+ setIsShowMore(false);
69
+ return;
70
+ }
71
+ setIsShowMore(true);
72
+ }, [
73
+ productElement
74
+ ]);
75
+ useEffect(()=>{
76
+ window.addEventListener('editor:active-component', onActiveComponent);
77
+ return ()=>{
78
+ window.removeEventListener('editor:active-component', onActiveComponent);
79
+ };
80
+ }, [
81
+ onActiveComponent
82
+ ]);
83
+ return /*#__PURE__*/ jsxs("div", {
84
+ className: "gp-relative",
85
+ ref: genTool,
86
+ children: [
87
+ /*#__PURE__*/ jsx("div", {
88
+ className: "gp-gen-content-toolbar gp-border-r-[#6a6a6a] gp-border-r gp-pr-1 gp-mr-1",
89
+ children: /*#__PURE__*/ jsxs("button", {
90
+ className: "gp-p-1 gp-text-xs gp-flex gp-gap-1 gp-items-center gp-rounded-md hover:gp-bg-[#3B3B3B] gp-font-medium",
91
+ onClick: togglePopup,
92
+ children: [
93
+ /*#__PURE__*/ jsx(AIIcon, {}),
94
+ "AI Content"
95
+ ]
96
+ })
97
+ }),
98
+ /*#__PURE__*/ jsxs("div", {
99
+ className: classNames({
100
+ 'gp-hidden': !isShowPopup,
101
+ 'gp-right-0': props.tag === 'Section' || popupPositionX === 'right',
102
+ 'gp-left-0': popupPositionX === 'left' && props.tag !== 'Section',
103
+ 'gp-top-8': popupPositionY === 'top',
104
+ 'gp-bottom-8': popupPositionY === 'bottom',
105
+ '!gp-visible': !isValidatingFlipPopup
106
+ }, 'gp-absolute gp-invisible gp-rounded-lg gp-bg-[#151515] gp-p-4 gp-w-[312px] !gp-max-w-[312px] !gp-cursor-default'),
107
+ ref: genPopup,
108
+ children: [
109
+ /*#__PURE__*/ jsxs("div", {
110
+ className: "gp-flex gp-items-center gp-justify-between gp-mb-4",
111
+ children: [
112
+ /*#__PURE__*/ jsx("span", {
113
+ className: "gp-font-medium gp-text-sm",
114
+ children: "Write with GemAI"
115
+ }),
116
+ /*#__PURE__*/ jsx("button", {
117
+ className: "gp-p-2 gp-cursor-pointer hover:gp-bg-[#3B3B3B] gp-rounded-md",
118
+ onClick: hidePopup,
119
+ children: /*#__PURE__*/ jsx(CloseIcon, {})
120
+ })
121
+ ]
122
+ }),
123
+ /*#__PURE__*/ jsxs("div", {
124
+ className: "gp-mt-2 gp-text-left",
125
+ children: [
126
+ /*#__PURE__*/ jsx("div", {
127
+ className: "gp-mb-4",
128
+ children: /*#__PURE__*/ jsx("span", {
129
+ className: "gp-text-xs",
130
+ children: "What would you like to describe here?"
131
+ })
132
+ }),
133
+ /*#__PURE__*/ jsx("div", {
134
+ className: "gp-mb-4 gp-flex",
135
+ children: /*#__PURE__*/ jsx("textarea", {
136
+ className: "gp-p-2 gp-bg-[#333333] gp-rounded-lg gp-w-full gp-text-xs gp-text-white placeholder:gp-text-[#AAAAAA] gp-resize-none focus-visible:gp-outline-none",
137
+ placeholder: "e.g: Generate feature benefits",
138
+ rows: 4,
139
+ value: prompt,
140
+ onChange: onChangePrompt
141
+ })
142
+ }),
143
+ /*#__PURE__*/ jsxs("div", {
144
+ className: classNames({
145
+ 'gp-hidden': !isShowMore
146
+ }, 'gp-mb-4 gp-gap-4 gp-flex gp-flex-col'),
147
+ children: [
148
+ /*#__PURE__*/ jsx(ToneAndVoice, {
149
+ changeToneAndVoice: changeTone
150
+ }),
151
+ /*#__PURE__*/ jsx(PickProduct, {
152
+ changeProductName: changeProductName,
153
+ openProductSetting: handleOpenProductSetting,
154
+ productId: productElement.productId
155
+ })
156
+ ]
157
+ }),
158
+ /*#__PURE__*/ jsx("div", {
159
+ className: "gp-mb-4",
160
+ children: /*#__PURE__*/ jsxs("button", {
161
+ className: "gp-flex gp-justify-center gp-items-center gp-w-full gp-bg-[#333333] gp-py-2 gp-rounded-lg gp-gap-2 gp-text-xs gp-font-medium",
162
+ onClick: toggleShowMore,
163
+ children: [
164
+ "Show more",
165
+ /*#__PURE__*/ jsx("span", {
166
+ className: classNames({
167
+ 'gp-rotate-180': isShowMore
168
+ }),
169
+ children: /*#__PURE__*/ jsx(ShowMoreIcon, {})
170
+ })
171
+ ]
172
+ })
173
+ }),
174
+ /*#__PURE__*/ jsx("button", {
175
+ className: "gp-rounded-lg gp-w-full gp-text-xs gp-font-medium gp-bg-gradient-to-tl gp-from-[#3C38E1] gp-to-[#874CFD] gp-py-2",
176
+ onClick: handleGenerateContent,
177
+ children: isGenerating ? 'Generating...' : 'Generate'
178
+ })
179
+ ]
180
+ })
181
+ ]
182
+ })
183
+ ]
184
+ });
185
+ };
186
+
187
+ export { AIContentGenerator };
@@ -0,0 +1,55 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useState, useRef, useCallback, useEffect } from 'react';
3
+
4
+ const AIGenContentLoading = ({ ...props })=>{
5
+ const [isGenerating, setIsGenerating] = useState(false);
6
+ const [numDots, setNumDots] = useState(1);
7
+ const dotIncreaseInterval = useRef(null);
8
+ const onGenerateContentStatus = useCallback((e)=>{
9
+ const detail = e.detail;
10
+ if (detail?.generatingUid !== props.uid) {
11
+ return;
12
+ }
13
+ if (detail.status === 'loading') {
14
+ setIsGenerating(true);
15
+ return;
16
+ }
17
+ if (detail.status === 'success') {
18
+ setIsGenerating(false);
19
+ return;
20
+ }
21
+ }, [
22
+ props.uid
23
+ ]);
24
+ useEffect(()=>{
25
+ if (isGenerating) {
26
+ dotIncreaseInterval.current = setInterval(()=>{
27
+ setNumDots((prev)=>prev === 3 ? 1 : prev + 1);
28
+ }, 500);
29
+ return;
30
+ }
31
+ if (dotIncreaseInterval.current) clearInterval(dotIncreaseInterval.current);
32
+ }, [
33
+ isGenerating
34
+ ]);
35
+ useEffect(()=>{
36
+ window.addEventListener('editor:ai-generate-content-status', onGenerateContentStatus);
37
+ return ()=>{
38
+ window.removeEventListener('editor:ai-generate-content-status', onGenerateContentStatus);
39
+ };
40
+ }, [
41
+ onGenerateContentStatus
42
+ ]);
43
+ return isGenerating ? /*#__PURE__*/ jsx("div", {
44
+ 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",
45
+ children: /*#__PURE__*/ jsxs("span", {
46
+ className: "gp-font-medium",
47
+ children: [
48
+ "Generating",
49
+ Array.from(Array(numDots).keys()).map(()=>'.')
50
+ ]
51
+ })
52
+ }) : null;
53
+ };
54
+
55
+ export { AIGenContentLoading };
@@ -0,0 +1,216 @@
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 '../../../helpers/convert.js';
16
+
17
+ const PickProduct = (props)=>{
18
+ const LIMIT_PRODUCTS = 8;
19
+ const [productVariables, setProductVariables] = useState(!props.productId ? {
20
+ first: LIMIT_PRODUCTS
21
+ } : undefined);
22
+ const { data: productList, isLoading: isLoadingGetProducts, isValidating: isValidatingGetProducts, size: productsSize, setSize: setProductsSize } = useListProductQuery(productVariables, {
23
+ revalidateFirstPage: false
24
+ });
25
+ const { data: sectionProduct } = useProductQuery(props.productId);
26
+ const [activeProduct, setActiveProduct] = useState();
27
+ const [isShowChooseProduct, setIsShowChooseProduct] = useState(false);
28
+ const debounceSearch = useRef(null);
29
+ const debounceScroll = useRef(null);
30
+ const toggleChooseProduct = ()=>{
31
+ if (props.productId) return;
32
+ setIsShowChooseProduct(!isShowChooseProduct);
33
+ };
34
+ const chooseProduct = (product)=>{
35
+ setActiveProduct(product);
36
+ setIsShowChooseProduct(false);
37
+ };
38
+ const searchProduct = (e)=>{
39
+ debounceSearch.current && clearTimeout(debounceSearch.current);
40
+ debounceSearch.current = setTimeout(()=>{
41
+ const searchValue = e.target.value ?? '';
42
+ if (searchValue) {
43
+ setProductVariables({
44
+ first: LIMIT_PRODUCTS,
45
+ where: {
46
+ titleContainsFold: searchValue
47
+ }
48
+ });
49
+ return;
50
+ }
51
+ setProductVariables({
52
+ first: LIMIT_PRODUCTS
53
+ });
54
+ }, 200);
55
+ };
56
+ const handleOpenProductElementSettings = ()=>{
57
+ props.openProductSetting();
58
+ };
59
+ const handleLoadMore = (e)=>{
60
+ const target = e.target;
61
+ if (target.scrollHeight - target.scrollTop === target.clientHeight) {
62
+ debounceScroll.current && clearTimeout(debounceScroll.current);
63
+ debounceScroll.current = setTimeout(()=>{
64
+ setProductsSize(productsSize + 1);
65
+ }, 50);
66
+ }
67
+ };
68
+ const products = useMemo(()=>{
69
+ return productList?.reduce((acc, curr)=>{
70
+ return [
71
+ ...acc,
72
+ ...curr.products?.edges ?? []
73
+ ];
74
+ }, []) ?? [];
75
+ }, [
76
+ productList
77
+ ]);
78
+ useEffect(()=>{
79
+ if (products.length && !activeProduct && !props.productId) {
80
+ const firstProduct = products[0]?.node;
81
+ if (!firstProduct) return;
82
+ setActiveProduct({
83
+ id: firstProduct?.id,
84
+ name: firstProduct?.title,
85
+ image: firstProduct.featuredImage?.src
86
+ });
87
+ }
88
+ }, [
89
+ products,
90
+ activeProduct,
91
+ props.productId
92
+ ]);
93
+ useEffect(()=>{
94
+ if (activeProduct && activeProduct.name) {
95
+ props.changeProductName(activeProduct.name);
96
+ }
97
+ }, [
98
+ activeProduct,
99
+ props
100
+ ]);
101
+ useEffect(()=>{
102
+ if (sectionProduct) {
103
+ setActiveProduct({
104
+ id: sectionProduct.id,
105
+ name: sectionProduct.title,
106
+ image: sectionProduct.featuredImage?.src
107
+ });
108
+ }
109
+ }, [
110
+ sectionProduct
111
+ ]);
112
+ return /*#__PURE__*/ jsxs("div", {
113
+ className: "gp-flex gp-flex-col gp-gap-2",
114
+ children: [
115
+ /*#__PURE__*/ jsx("p", {
116
+ className: "gp-py-2 gp-text-xs",
117
+ children: "Product"
118
+ }),
119
+ /*#__PURE__*/ jsxs("div", {
120
+ className: "gp-relative",
121
+ children: [
122
+ !isLoadingGetProducts || activeProduct ? /*#__PURE__*/ jsxs("button", {
123
+ className: classNames({
124
+ 'gp-cursor-default': props.productId
125
+ }, 'gp-flex gp-gap-2 gp-items-center gp-w-full gp-p-2 gp-rounded-lg gp-bg-[#333333] gp-text-xs'),
126
+ onClick: toggleChooseProduct,
127
+ children: [
128
+ /*#__PURE__*/ jsx("img", {
129
+ className: "gp-rounded-lg gp-w-10 gp-h-10",
130
+ src: activeProduct?.image,
131
+ alt: "product_image"
132
+ }),
133
+ /*#__PURE__*/ jsx("span", {
134
+ className: "gp-truncate gp-max-w-[210px]",
135
+ children: activeProduct?.name
136
+ })
137
+ ]
138
+ }) : /*#__PURE__*/ jsx("div", {
139
+ children: /*#__PURE__*/ jsx("span", {
140
+ className: "gp-text-xs",
141
+ children: "Getting products..."
142
+ })
143
+ }),
144
+ props.productId && /*#__PURE__*/ jsx("div", {
145
+ className: "gp-mt-2 gp-text-xs",
146
+ children: /*#__PURE__*/ jsxs("p", {
147
+ children: [
148
+ "You can manage it in",
149
+ ' ',
150
+ /*#__PURE__*/ jsx("button", {
151
+ className: "gp-text-[#8AA4FF] gp-cursor-pointer hover:gp-underline",
152
+ onClick: handleOpenProductElementSettings,
153
+ children: "Product element"
154
+ })
155
+ ]
156
+ })
157
+ }),
158
+ isShowChooseProduct && /*#__PURE__*/ jsxs("div", {
159
+ 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",
160
+ children: [
161
+ /*#__PURE__*/ jsxs("div", {
162
+ className: "gp-flex gp-items-center gp-gap-2 gp-p-2",
163
+ children: [
164
+ /*#__PURE__*/ jsx(SearchIcon, {}),
165
+ /*#__PURE__*/ jsx("input", {
166
+ className: "gp-bg-transparent gp-w-full focus-visible:!gp-outline-none gp-text-xs",
167
+ placeholder: "Search product...",
168
+ onChange: searchProduct
169
+ })
170
+ ]
171
+ }),
172
+ /*#__PURE__*/ jsxs("div", {
173
+ className: "gp-max-h-[168px] gp-overflow-auto scrollbar:gp-w-1 scrollbar-thumb:gp-bg-[#999] scrollbar-thumb:gp-rounded-xl",
174
+ onScroll: handleLoadMore,
175
+ children: [
176
+ products?.map((item)=>{
177
+ return /*#__PURE__*/ jsxs("button", {
178
+ className: "gp-flex gp-p-2 hover:gp-bg-[#3B3B3B] gp-rounded-lg gp-cursor-pointer gp-gap-2 gp-items-center",
179
+ onClick: ()=>{
180
+ chooseProduct({
181
+ id: item.node?.id,
182
+ name: item.node?.title,
183
+ image: item.node?.featuredImage?.src
184
+ });
185
+ },
186
+ children: [
187
+ /*#__PURE__*/ jsx("img", {
188
+ className: "gp-rounded-lg gp-w-10 gp-h-10",
189
+ src: item.node?.featuredImage?.src,
190
+ alt: "product_image"
191
+ }),
192
+ /*#__PURE__*/ jsx("span", {
193
+ className: "gp-truncate gp-max-w-[210px] gp-text-xs",
194
+ children: item.node?.title
195
+ })
196
+ ]
197
+ }, item.node?.id);
198
+ }),
199
+ isLoadingGetProducts || isValidatingGetProducts && /*#__PURE__*/ jsx("div", {
200
+ className: "gp-p-2",
201
+ children: /*#__PURE__*/ jsx("span", {
202
+ className: "gp-text-xs",
203
+ children: "Getting products..."
204
+ })
205
+ })
206
+ ]
207
+ })
208
+ ]
209
+ })
210
+ ]
211
+ })
212
+ ]
213
+ });
214
+ };
215
+
216
+ 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,68 @@
1
+ import { useState, useCallback, useEffect } from 'react';
2
+
3
+ const useFlipPopup = (isShowPopup, dom)=>{
4
+ const { genTool, genPopup } = dom;
5
+ const [popupPositionY, setPopupPositionY] = useState('top');
6
+ const [popupPositionX, setPopupPositionX] = useState('left');
7
+ const [isValidating, setIsValidating] = useState(true);
8
+ const calculatePopupPositionY = useCallback(()=>{
9
+ if (!genTool.current || !genPopup.current) return;
10
+ const viewHeight = window.innerHeight;
11
+ const scrollHeight = document.documentElement.scrollHeight;
12
+ const scrollTop = document.documentElement.scrollTop;
13
+ const toolPos = genTool.current?.getBoundingClientRect();
14
+ const genPopupHeight = genPopup.current?.getBoundingClientRect().height;
15
+ const MIN_DISTANCE = 50;
16
+ if (scrollTop + toolPos.top + genPopupHeight >= scrollHeight - MIN_DISTANCE) {
17
+ setPopupPositionY('bottom');
18
+ return;
19
+ }
20
+ if (toolPos.bottom + genPopupHeight > viewHeight) {
21
+ if (toolPos.top - genPopupHeight < 0) {
22
+ setPopupPositionY('top');
23
+ return;
24
+ }
25
+ setPopupPositionY('bottom');
26
+ return;
27
+ }
28
+ setPopupPositionY('top');
29
+ }, [
30
+ genPopup,
31
+ genTool
32
+ ]);
33
+ const calculatePopupPositionX = useCallback(()=>{
34
+ if (!genTool.current || !genPopup.current) return;
35
+ const viewWidth = window.innerWidth;
36
+ const toolPos = genTool.current?.getBoundingClientRect();
37
+ const genPopupWidth = genPopup.current?.getBoundingClientRect().width;
38
+ if (toolPos.left + genPopupWidth > viewWidth) {
39
+ setPopupPositionX('right');
40
+ return;
41
+ }
42
+ setPopupPositionX('left');
43
+ }, [
44
+ genPopup,
45
+ genTool
46
+ ]);
47
+ useEffect(()=>{
48
+ if (!isShowPopup) {
49
+ setIsValidating(true);
50
+ return;
51
+ }
52
+ setIsValidating(true);
53
+ calculatePopupPositionY();
54
+ calculatePopupPositionX();
55
+ setIsValidating(false);
56
+ }, [
57
+ isShowPopup,
58
+ calculatePopupPositionX,
59
+ calculatePopupPositionY
60
+ ]);
61
+ return {
62
+ isValidating,
63
+ popupPositionY,
64
+ popupPositionX
65
+ };
66
+ };
67
+
68
+ 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 };