@capillarytech/creatives-library 8.0.236-alpha.7 → 8.0.236
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.
- package/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/constants/unified.js +1 -1
- package/initialReducer.js +0 -2
- package/package.json +1 -1
- package/services/api.js +0 -5
- package/services/tests/api.test.js +0 -18
- package/utils/common.js +2 -1
- package/utils/commonUtils.js +1 -14
- package/utils/tests/commonUtil.test.js +0 -224
- package/utils/transformTemplateConfig.js +10 -0
- package/v2Components/CapDeviceContent/index.js +56 -61
- package/v2Components/CapTagList/index.js +0 -4
- package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
- package/v2Components/HtmlEditor/HTMLEditor.js +83 -235
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +19 -932
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +12 -17
- package/v2Components/HtmlEditor/_htmlEditor.scss +4 -2
- package/v2Components/HtmlEditor/_index.lazy.scss +1 -0
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +101 -2
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +131 -105
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -1
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
- package/v2Components/HtmlEditor/constants.js +20 -29
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +148 -130
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +85 -85
- package/v2Components/MobilePushPreviewV2/index.js +7 -32
- package/v2Components/TemplatePreview/_templatePreview.scss +24 -44
- package/v2Components/TemplatePreview/index.js +32 -47
- package/v2Components/TemplatePreview/messages.js +0 -4
- package/v2Containers/BeeEditor/index.js +80 -82
- package/v2Containers/CreativesContainer/SlideBoxContent.js +34 -69
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -2
- package/v2Containers/CreativesContainer/constants.js +0 -1
- package/v2Containers/CreativesContainer/index.js +32 -92
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +12 -4
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -15
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
- package/v2Containers/InApp/actions.js +0 -7
- package/v2Containers/InApp/constants.js +4 -20
- package/v2Containers/InApp/index.js +386 -984
- package/v2Containers/InApp/index.scss +3 -4
- package/v2Containers/InApp/messages.js +3 -7
- package/v2Containers/InApp/reducer.js +3 -21
- package/v2Containers/InApp/sagas.js +9 -29
- package/v2Containers/InApp/selectors.js +5 -25
- package/v2Containers/InApp/tests/index.test.js +50 -154
- package/v2Containers/InApp/tests/reducer.test.js +0 -34
- package/v2Containers/InApp/tests/sagas.test.js +9 -61
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +0 -3
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +0 -2
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +0 -2
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +0 -9
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +0 -12
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +0 -4
- package/v2Containers/TagList/index.js +1 -65
- package/v2Containers/Templates/_templates.scss +1 -60
- package/v2Containers/Templates/index.js +5 -99
- package/v2Containers/Templates/messages.js +0 -4
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +0 -35
- package/v2Containers/BeePopupEditor/constants.js +0 -10
- package/v2Containers/BeePopupEditor/index.js +0 -193
- package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
- package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
- package/v2Containers/InApp/tests/selectors.test.js +0 -612
- package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -162
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -9
- package/v2Containers/InAppWrapper/constants.js +0 -16
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
- package/v2Containers/InAppWrapper/index.js +0 -148
- package/v2Containers/InAppWrapper/messages.js +0 -49
- package/v2Containers/InappAdvance/index.js +0 -1115
- package/v2Containers/InappAdvance/index.scss +0 -10
- package/v2Containers/InappAdvance/tests/index.test.js +0 -448
|
@@ -9,23 +9,19 @@ import { render, screen, waitFor } from '@testing-library/react';
|
|
|
9
9
|
import '@testing-library/jest-dom';
|
|
10
10
|
|
|
11
11
|
// Mock CapSpin before importing the component
|
|
12
|
-
jest.mock('@capillarytech/cap-ui-library/CapSpin', () =>
|
|
13
|
-
return
|
|
12
|
+
jest.mock('@capillarytech/cap-ui-library/CapSpin', () => {
|
|
13
|
+
return function MockCapSpin({ size }) {
|
|
14
|
+
return <div data-testid="cap-spin" data-size={size}>Loading...</div>;
|
|
15
|
+
};
|
|
14
16
|
});
|
|
15
17
|
|
|
16
18
|
// Mock the HTMLEditor component
|
|
17
19
|
jest.mock('../HTMLEditor', () => {
|
|
18
|
-
const MockHTMLEditor = function MockHTMLEditor(props) {
|
|
19
|
-
return (
|
|
20
|
-
<div data-testid="html-editor">
|
|
21
|
-
Mock HTML Editor -
|
|
22
|
-
{props.variant}
|
|
23
|
-
</div>
|
|
24
|
-
);
|
|
25
|
-
};
|
|
26
20
|
return {
|
|
27
21
|
__esModule: true,
|
|
28
|
-
default: MockHTMLEditor
|
|
22
|
+
default: function MockHTMLEditor(props) {
|
|
23
|
+
return <div data-testid="html-editor">Mock HTML Editor - {props.variant}</div>;
|
|
24
|
+
}
|
|
29
25
|
};
|
|
30
26
|
});
|
|
31
27
|
|
|
@@ -117,8 +113,7 @@ describe('index.lazy.js', () => {
|
|
|
117
113
|
expect(screen.getByTestId('html-editor')).toBeInTheDocument();
|
|
118
114
|
});
|
|
119
115
|
|
|
120
|
-
|
|
121
|
-
expect(editor.textContent).toBe('Mock HTML Editor -email');
|
|
116
|
+
expect(screen.getByText(/Mock HTML Editor - email/)).toBeInTheDocument();
|
|
122
117
|
});
|
|
123
118
|
|
|
124
119
|
it('shows fallback while loading', async () => {
|
|
@@ -139,7 +134,7 @@ describe('index.lazy.js', () => {
|
|
|
139
134
|
<HTMLEditorLazy
|
|
140
135
|
variant="inapp"
|
|
141
136
|
onSave={mockOnSave}
|
|
142
|
-
readOnly
|
|
137
|
+
readOnly={true}
|
|
143
138
|
className="custom-class"
|
|
144
139
|
/>
|
|
145
140
|
);
|
|
@@ -148,8 +143,7 @@ describe('index.lazy.js', () => {
|
|
|
148
143
|
expect(screen.getByTestId('html-editor')).toBeInTheDocument();
|
|
149
144
|
});
|
|
150
145
|
|
|
151
|
-
|
|
152
|
-
expect(editor.textContent).toBe('Mock HTML Editor -inapp');
|
|
146
|
+
expect(screen.getByText(/Mock HTML Editor - inapp/)).toBeInTheDocument();
|
|
153
147
|
});
|
|
154
148
|
|
|
155
149
|
it('has correct display name', async () => {
|
|
@@ -221,7 +215,7 @@ describe('index.lazy.js', () => {
|
|
|
221
215
|
render(
|
|
222
216
|
<HTMLEditorLazy
|
|
223
217
|
className="custom-editor"
|
|
224
|
-
readOnly
|
|
218
|
+
readOnly={true}
|
|
225
219
|
showFullscreenButton={false}
|
|
226
220
|
autoSave={false}
|
|
227
221
|
autoSaveInterval={60000}
|
|
@@ -535,3 +529,4 @@ describe('index.lazy.js', () => {
|
|
|
535
529
|
});
|
|
536
530
|
});
|
|
537
531
|
});
|
|
532
|
+
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
padding: 0;
|
|
29
29
|
min-height: 3.25rem;
|
|
30
30
|
height: 3.25rem;
|
|
31
|
-
position: relative;
|
|
32
31
|
|
|
33
32
|
// Right-align toolbar actions
|
|
34
33
|
&__right {
|
|
@@ -129,7 +128,6 @@
|
|
|
129
128
|
padding: 0;
|
|
130
129
|
min-height: 3.25rem; // 52px = 3.25rem
|
|
131
130
|
height: 3.25rem;
|
|
132
|
-
position: relative;
|
|
133
131
|
|
|
134
132
|
// Right-align toolbar actions
|
|
135
133
|
&__right {
|
|
@@ -269,6 +267,10 @@
|
|
|
269
267
|
|
|
270
268
|
// Focus states and accessibility
|
|
271
269
|
.html-editor {
|
|
270
|
+
&:focus-within {
|
|
271
|
+
outline: 0.125rem solid map-get($CAP_PRIMARY, base); // 2px = 0.125rem
|
|
272
|
+
outline-offset: -0.125rem; // -2px = -0.125rem
|
|
273
|
+
}
|
|
272
274
|
|
|
273
275
|
// High contrast mode support
|
|
274
276
|
@media (prefers-contrast: high) {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
align-items: center;
|
|
14
14
|
min-height: 25rem; // 400px = 25rem
|
|
15
15
|
background: $CAP_G11; // Light background similar to #fafbfc
|
|
16
|
+
border: 0.0625rem solid $CAP_G07; // 1px border similar to #dfe2e7
|
|
16
17
|
border-radius: 0.5rem; // 8px = 0.5rem
|
|
17
18
|
flex-direction: column;
|
|
18
19
|
gap: 1rem; // 16px = 1rem
|
|
@@ -31,6 +31,79 @@
|
|
|
31
31
|
display: flex;
|
|
32
32
|
align-items: center;
|
|
33
33
|
gap: 0.5rem;
|
|
34
|
+
|
|
35
|
+
.cap-button,
|
|
36
|
+
.ant-btn,
|
|
37
|
+
button {
|
|
38
|
+
color: map-get($CAP_PRIMARY, base);
|
|
39
|
+
border: none;
|
|
40
|
+
background: $CAP_WHITE;
|
|
41
|
+
border-radius: 0.25rem;
|
|
42
|
+
padding: 0.375rem 0.5rem;
|
|
43
|
+
font-size: 0.875rem;
|
|
44
|
+
font-family: $FONT_FAMILY;
|
|
45
|
+
font-weight: 500;
|
|
46
|
+
height: auto;
|
|
47
|
+
min-width: 5.9375rem;
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
gap: 0.25rem;
|
|
51
|
+
box-shadow: 0 0 0.0625rem 0 rgba(9, 30, 66, 0.31), 0 0.25rem 0.5rem -0.125rem rgba(9, 30, 66, 0.25);
|
|
52
|
+
line-height: 1.25rem;
|
|
53
|
+
text-align: left;
|
|
54
|
+
|
|
55
|
+
&:hover {
|
|
56
|
+
background: $CAP_G09;
|
|
57
|
+
box-shadow: 0 0 0.0625rem 0 rgba(9, 30, 66, 0.31), 0 0.375rem 0.75rem -0.125rem rgba(9, 30, 66, 0.25);
|
|
58
|
+
color: map-get($CAP_PRIMARY, base);
|
|
59
|
+
border: none;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
&:active,
|
|
63
|
+
&:focus {
|
|
64
|
+
background: $CAP_G08;
|
|
65
|
+
box-shadow: 0 0 0.0625rem 0 rgba(9, 30, 66, 0.31), 0 0.125rem 0.25rem -0.125rem rgba(9, 30, 66, 0.25);
|
|
66
|
+
color: map-get($CAP_PRIMARY, base);
|
|
67
|
+
border: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.anticon,
|
|
71
|
+
.cap-icon {
|
|
72
|
+
font-size: 1rem;
|
|
73
|
+
color: map-get($CAP_PRIMARY, base);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
span {
|
|
77
|
+
font-size: 0.875rem;
|
|
78
|
+
font-weight: 500;
|
|
79
|
+
line-height: 1.25rem;
|
|
80
|
+
color: map-get($CAP_PRIMARY, base);
|
|
81
|
+
white-space: nowrap;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
&:before,
|
|
85
|
+
&:after {
|
|
86
|
+
display: none;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.tooltip-add-label-container {
|
|
91
|
+
|
|
92
|
+
.cap-button,
|
|
93
|
+
.ant-btn {
|
|
94
|
+
color: map-get($CAP_PRIMARY, base);
|
|
95
|
+
background: $CAP_WHITE;
|
|
96
|
+
border: none;
|
|
97
|
+
box-shadow: 0 0 0.0625rem 0 rgba(9, 30, 66, 0.31), 0 0.25rem 0.5rem -0.125rem rgba(9, 30, 66, 0.25);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.cap-button-flat,
|
|
102
|
+
.cap-button-add {
|
|
103
|
+
background: $CAP_WHITE;
|
|
104
|
+
color: map-get($CAP_PRIMARY, base);
|
|
105
|
+
border: none;
|
|
106
|
+
}
|
|
34
107
|
}
|
|
35
108
|
|
|
36
109
|
&__content {
|
|
@@ -40,7 +113,7 @@
|
|
|
40
113
|
overflow: auto;
|
|
41
114
|
position: relative;
|
|
42
115
|
height: 100%;
|
|
43
|
-
max-height:
|
|
116
|
+
max-height: 31.25rem;
|
|
44
117
|
background-color: $CAP_G01;
|
|
45
118
|
}
|
|
46
119
|
|
|
@@ -150,7 +223,7 @@
|
|
|
150
223
|
.codemirror-wrapper {
|
|
151
224
|
position: relative;
|
|
152
225
|
height: 100%;
|
|
153
|
-
max-height:
|
|
226
|
+
max-height: 31.25rem;
|
|
154
227
|
background-color: $CAP_G01;
|
|
155
228
|
border-radius: 0;
|
|
156
229
|
overflow: hidden;
|
|
@@ -161,6 +234,31 @@
|
|
|
161
234
|
top: 0.5rem;
|
|
162
235
|
right: 0.5rem;
|
|
163
236
|
z-index: 20;
|
|
237
|
+
|
|
238
|
+
.cap-button,
|
|
239
|
+
.ant-btn,
|
|
240
|
+
button {
|
|
241
|
+
background: $CAP_WHITE;
|
|
242
|
+
color: map-get($CAP_PRIMARY, base);
|
|
243
|
+
border: none;
|
|
244
|
+
border-radius: 0.25rem;
|
|
245
|
+
padding: 0.375rem 0.5rem;
|
|
246
|
+
font-size: 0.875rem;
|
|
247
|
+
font-family: $FONT_FAMILY;
|
|
248
|
+
font-weight: 500;
|
|
249
|
+
min-width: 5.9375rem;
|
|
250
|
+
box-shadow: 0 0 0.0625rem 0 rgba(9, 30, 66, 0.31), 0 0.25rem 0.5rem -0.125rem rgba(9, 30, 66, 0.25);
|
|
251
|
+
|
|
252
|
+
&:hover {
|
|
253
|
+
background: $CAP_G09;
|
|
254
|
+
color: map-get($CAP_PRIMARY, base);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
&:active {
|
|
258
|
+
background: $CAP_G08;
|
|
259
|
+
color: map-get($CAP_PRIMARY, base);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
164
262
|
}
|
|
165
263
|
|
|
166
264
|
.codemirror-editor {
|
|
@@ -198,6 +296,7 @@
|
|
|
198
296
|
}
|
|
199
297
|
|
|
200
298
|
.cm-gutters {
|
|
299
|
+
background-color: var(--editor-gutter-bg, $CAP_G02);
|
|
201
300
|
border-right: 0.0625rem solid var(--editor-border, $CAP_G04);
|
|
202
301
|
color: var(--editor-gutter-foreground, $FONT_COLOR_02);
|
|
203
302
|
}
|
|
@@ -8,57 +8,45 @@
|
|
|
8
8
|
* - Theme support with proper styling
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import React, {
|
|
12
|
-
forwardRef, useImperativeHandle, useRef, useEffect, useCallback,
|
|
13
|
-
} from 'react';
|
|
11
|
+
import React, { forwardRef, useImperativeHandle, useRef, useEffect, useState } from 'react';
|
|
14
12
|
import PropTypes from 'prop-types';
|
|
15
13
|
|
|
16
14
|
// CodeMirror 6 imports
|
|
17
15
|
import { EditorState } from '@codemirror/state';
|
|
18
16
|
import { EditorView, lineNumbers, highlightActiveLine } from '@codemirror/view';
|
|
19
17
|
|
|
18
|
+
// Import our comprehensive syntax highlighting solution
|
|
19
|
+
import { createRobustExtensions } from '../../utils/properSyntaxHighlighting';
|
|
20
|
+
|
|
20
21
|
|
|
21
22
|
import { injectIntl, intlShape } from 'react-intl';
|
|
22
23
|
|
|
23
24
|
// Messages
|
|
24
|
-
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
25
25
|
import messages from '../../messages';
|
|
26
26
|
|
|
27
27
|
// Cap UI Components
|
|
28
|
+
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
28
29
|
|
|
29
30
|
// Components
|
|
30
31
|
import TagList from '../../../../v2Containers/TagList';
|
|
31
32
|
|
|
32
|
-
// Constants - removed unused imports since tag fetching is handled by parent
|
|
33
|
-
|
|
34
33
|
// Context
|
|
35
34
|
import { useEditorContext } from '../common/EditorContext';
|
|
36
35
|
|
|
37
36
|
// Styles
|
|
38
37
|
import './_codeEditorPane.scss';
|
|
39
38
|
|
|
40
|
-
// Define Theme and Highlighting inline to avoid "multiple instances of @codemirror/state" error
|
|
41
|
-
|
|
42
|
-
|
|
43
39
|
// Legacy CodeMirrorEditor removed - using enhanced implementation only
|
|
44
40
|
|
|
45
41
|
const CodeEditorPaneComponent = ({
|
|
46
42
|
intl,
|
|
47
43
|
readOnly = false,
|
|
48
44
|
className = '',
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
injectedTags = {},
|
|
53
|
-
location,
|
|
54
|
-
eventContextTags = [],
|
|
55
|
-
selectedOfferDetails = [],
|
|
56
|
-
channel,
|
|
57
|
-
userLocale = 'en',
|
|
58
|
-
moduleFilterEnabled = true,
|
|
59
|
-
onTagContextChange,
|
|
45
|
+
isFullscreenMode = false,
|
|
46
|
+
onLabelInsert,
|
|
47
|
+
forwardedRef
|
|
60
48
|
}) => {
|
|
61
|
-
const { content } = useEditorContext();
|
|
49
|
+
const { content, validation } = useEditorContext();
|
|
62
50
|
const { content: contentValue, updateContent } = content;
|
|
63
51
|
const editorRef = useRef(null);
|
|
64
52
|
const viewRef = useRef(null);
|
|
@@ -73,7 +61,7 @@ const CodeEditorPaneComponent = ({
|
|
|
73
61
|
get view() {
|
|
74
62
|
return viewRef.current;
|
|
75
63
|
},
|
|
76
|
-
viewRef, // For compatibility with existing code
|
|
64
|
+
viewRef: viewRef, // For compatibility with existing code
|
|
77
65
|
|
|
78
66
|
focus: () => {
|
|
79
67
|
if (viewRef.current) {
|
|
@@ -87,7 +75,7 @@ const CodeEditorPaneComponent = ({
|
|
|
87
75
|
const pos = position !== undefined ? position : head;
|
|
88
76
|
view.dispatch({
|
|
89
77
|
changes: { from: pos, insert: text },
|
|
90
|
-
selection: { anchor: pos + text.length }
|
|
78
|
+
selection: { anchor: pos + text.length }
|
|
91
79
|
});
|
|
92
80
|
} else {
|
|
93
81
|
throw new Error('CodeMirror view not initialized');
|
|
@@ -100,7 +88,9 @@ const CodeEditorPaneComponent = ({
|
|
|
100
88
|
}
|
|
101
89
|
return 0;
|
|
102
90
|
},
|
|
103
|
-
getValue: () =>
|
|
91
|
+
getValue: () => {
|
|
92
|
+
return contentValue || '';
|
|
93
|
+
},
|
|
104
94
|
setValue: (value) => {
|
|
105
95
|
updateContent(value);
|
|
106
96
|
},
|
|
@@ -117,7 +107,7 @@ const CodeEditorPaneComponent = ({
|
|
|
117
107
|
|
|
118
108
|
view.dispatch({
|
|
119
109
|
selection: { anchor: pos },
|
|
120
|
-
effects: EditorView.scrollIntoView(pos, { y: 'center' })
|
|
110
|
+
effects: EditorView.scrollIntoView(pos, { y: 'center' })
|
|
121
111
|
});
|
|
122
112
|
view.focus();
|
|
123
113
|
} catch (error) {
|
|
@@ -127,7 +117,7 @@ const CodeEditorPaneComponent = ({
|
|
|
127
117
|
}
|
|
128
118
|
}
|
|
129
119
|
}
|
|
130
|
-
}
|
|
120
|
+
}
|
|
131
121
|
}), [contentValue]);
|
|
132
122
|
|
|
133
123
|
// Note: handleContentChange removed - using updateContentRef directly in CodeMirror
|
|
@@ -143,9 +133,7 @@ const CodeEditorPaneComponent = ({
|
|
|
143
133
|
if (typeof tagData === 'string') {
|
|
144
134
|
tagText = tagData;
|
|
145
135
|
} else if (tagData) {
|
|
146
|
-
const {
|
|
147
|
-
text, name, label, value,
|
|
148
|
-
} = tagData;
|
|
136
|
+
const { text, name, label, value } = tagData;
|
|
149
137
|
tagText = text || name || label || value;
|
|
150
138
|
if (!tagText) {
|
|
151
139
|
console.warn('Invalid tag data:', tagData);
|
|
@@ -159,59 +147,49 @@ const CodeEditorPaneComponent = ({
|
|
|
159
147
|
// For unified HTML editor, insert as template variable
|
|
160
148
|
const formattedTag = `{{${tagText}}}`;
|
|
161
149
|
|
|
162
|
-
// Insert the tag at cursor position
|
|
150
|
+
// Insert the tag at cursor position
|
|
163
151
|
view.dispatch({
|
|
164
152
|
changes: { from: pos, insert: formattedTag },
|
|
165
|
-
selection: { anchor: pos + formattedTag.length }
|
|
153
|
+
selection: { anchor: pos + formattedTag.length }
|
|
166
154
|
});
|
|
167
155
|
|
|
168
156
|
// Focus back to editor
|
|
169
157
|
view.focus();
|
|
170
158
|
|
|
171
|
-
//
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// The direct insertion via view.dispatch is sufficient
|
|
159
|
+
// Call the parent's handleLabelInsert if available
|
|
160
|
+
if (onLabelInsert) {
|
|
161
|
+
onLabelInsert(formattedTag, pos);
|
|
162
|
+
}
|
|
176
163
|
}
|
|
177
164
|
};
|
|
178
165
|
|
|
179
|
-
// Handle tag context change - delegate to parent component
|
|
180
|
-
// Tags are fetched in parent components (EmailHTMLEditor, INAPP, etc.)
|
|
181
|
-
// This component just passes the context change event up
|
|
182
|
-
const handleTagContextChange = useCallback((data) => {
|
|
183
|
-
if (onTagContextChange) {
|
|
184
|
-
// Parent component handles tag fetching and updates
|
|
185
|
-
onTagContextChange(data);
|
|
186
|
-
}
|
|
187
|
-
// No fallback - tags must be managed by parent component
|
|
188
|
-
}, [onTagContextChange]);
|
|
189
|
-
|
|
190
166
|
// Initialize CodeMirror effect
|
|
191
167
|
useEffect(() => {
|
|
192
168
|
if (editorRef.current && !viewRef.current) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
169
|
+
// Use the comprehensive extensions from properSyntaxHighlighting.js
|
|
170
|
+
// This includes: html(), syntaxHighlighting(comprehensiveVSCodeTheme), cleanEditorTheme
|
|
171
|
+
const robustExtensions = createRobustExtensions();
|
|
172
|
+
|
|
173
|
+
// Add additional extensions for line numbers, active line, and update listener
|
|
174
|
+
const extensions = [
|
|
175
|
+
lineNumbers(),
|
|
176
|
+
highlightActiveLine(),
|
|
177
|
+
...robustExtensions, // Spread the robust extensions (html, syntax highlighting, theme)
|
|
178
|
+
EditorView.updateListener.of((update) => {
|
|
179
|
+
if (update.docChanged) {
|
|
180
|
+
updateContentRef.current(update.state.doc.toString());
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
];
|
|
206
184
|
|
|
207
185
|
const state = EditorState.create({
|
|
208
186
|
doc: contentValue || '',
|
|
209
|
-
extensions
|
|
187
|
+
extensions
|
|
210
188
|
});
|
|
211
189
|
|
|
212
190
|
viewRef.current = new EditorView({
|
|
213
191
|
state,
|
|
214
|
-
parent: editorRef.current
|
|
192
|
+
parent: editorRef.current
|
|
215
193
|
});
|
|
216
194
|
}
|
|
217
195
|
|
|
@@ -237,43 +215,100 @@ const CodeEditorPaneComponent = ({
|
|
|
237
215
|
changes: {
|
|
238
216
|
from: 0,
|
|
239
217
|
to: length,
|
|
240
|
-
insert: contentValue || ''
|
|
241
|
-
}
|
|
218
|
+
insert: contentValue || ''
|
|
219
|
+
}
|
|
242
220
|
});
|
|
243
221
|
}
|
|
244
222
|
}, [contentValue]);
|
|
245
223
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
224
|
+
return (
|
|
225
|
+
<CapRow className={`code-editor-pane ${className}`}>
|
|
226
|
+
{/* Unified Code Editor with Floating Add Label Button */}
|
|
227
|
+
<CapRow className="code-editor-pane__content">
|
|
228
|
+
<div className="codemirror-wrapper">
|
|
229
|
+
<div ref={editorRef} className="codemirror-editor" />
|
|
230
|
+
{/* Floating Add Label Button */}
|
|
231
|
+
<CapRow className="code-editor-pane__actions">
|
|
232
|
+
<TagList
|
|
233
|
+
key="html-editor-taglist"
|
|
234
|
+
label={intl.formatMessage(messages.addLabel)}
|
|
235
|
+
onTagSelect={handleTagSelect}
|
|
236
|
+
onContextChange={(context) => {
|
|
237
|
+
}}
|
|
238
|
+
className="tag-list-trigger"
|
|
239
|
+
tags={[]} // Empty initially - TagList will fetch from API
|
|
240
|
+
injectedTags={{
|
|
241
|
+
// Add common HTML/Email specific tags as fallback
|
|
242
|
+
'Customer Info': {
|
|
243
|
+
name: 'Customer Info',
|
|
244
|
+
desc: 'Customer information tags',
|
|
245
|
+
resolved: true,
|
|
246
|
+
'tag-header': true,
|
|
247
|
+
subtags: {
|
|
248
|
+
'customer.firstName': {
|
|
249
|
+
name: 'First Name',
|
|
250
|
+
desc: 'Customer first name',
|
|
251
|
+
resolved: true
|
|
252
|
+
},
|
|
253
|
+
'customer.lastName': {
|
|
254
|
+
name: 'Last Name',
|
|
255
|
+
desc: 'Customer last name',
|
|
256
|
+
resolved: true
|
|
257
|
+
},
|
|
258
|
+
'customer.email': {
|
|
259
|
+
name: 'Email',
|
|
260
|
+
desc: 'Customer email address',
|
|
261
|
+
resolved: true
|
|
262
|
+
},
|
|
263
|
+
'customer.phone': {
|
|
264
|
+
name: 'Phone',
|
|
265
|
+
desc: 'Customer phone number',
|
|
266
|
+
resolved: true
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
'Common Tags': {
|
|
271
|
+
name: 'Common Tags',
|
|
272
|
+
desc: 'Commonly used template tags',
|
|
273
|
+
resolved: true,
|
|
274
|
+
'tag-header': true,
|
|
275
|
+
subtags: {
|
|
276
|
+
'organization.name': {
|
|
277
|
+
name: 'Organization Name',
|
|
278
|
+
desc: 'Organization name',
|
|
279
|
+
resolved: true
|
|
280
|
+
},
|
|
281
|
+
'currentDate': {
|
|
282
|
+
name: 'Current Date',
|
|
283
|
+
desc: 'Current date',
|
|
284
|
+
resolved: true
|
|
285
|
+
},
|
|
286
|
+
'unsubscribeLink': {
|
|
287
|
+
name: 'Unsubscribe Link',
|
|
288
|
+
desc: 'Unsubscribe link',
|
|
289
|
+
resolved: true
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}}
|
|
294
|
+
moduleFilterEnabled={true}
|
|
295
|
+
userLocale="en"
|
|
296
|
+
channel="email"
|
|
297
|
+
disabled={readOnly}
|
|
298
|
+
location={{
|
|
299
|
+
query: {
|
|
300
|
+
type: 'html-editor' // Identify the context
|
|
301
|
+
}
|
|
302
|
+
}}
|
|
303
|
+
selectedOfferDetails={[]}
|
|
304
|
+
eventContextTags={[]}
|
|
305
|
+
/>
|
|
306
|
+
</CapRow>
|
|
307
|
+
</div>
|
|
308
|
+
</CapRow>
|
|
274
309
|
|
|
275
|
-
|
|
276
|
-
|
|
310
|
+
</CapRow>
|
|
311
|
+
);
|
|
277
312
|
};
|
|
278
313
|
|
|
279
314
|
// Create the forwardRef wrapper
|
|
@@ -288,18 +323,9 @@ CodeEditorPane.propTypes = {
|
|
|
288
323
|
readOnly: PropTypes.bool,
|
|
289
324
|
className: PropTypes.string,
|
|
290
325
|
isFullscreenMode: PropTypes.bool,
|
|
291
|
-
onLabelInsert: PropTypes.func
|
|
292
|
-
// Tag-related props - tags are fetched and managed by parent component
|
|
293
|
-
tags: PropTypes.array,
|
|
294
|
-
injectedTags: PropTypes.object,
|
|
295
|
-
location: PropTypes.object,
|
|
296
|
-
eventContextTags: PropTypes.array,
|
|
297
|
-
selectedOfferDetails: PropTypes.array,
|
|
298
|
-
channel: PropTypes.string,
|
|
299
|
-
userLocale: PropTypes.string,
|
|
300
|
-
moduleFilterEnabled: PropTypes.bool,
|
|
301
|
-
onTagContextChange: PropTypes.func, // Required - parent must handle tag fetching
|
|
326
|
+
onLabelInsert: PropTypes.func
|
|
302
327
|
};
|
|
303
328
|
|
|
304
329
|
// Export with injectIntl - ref forwarding is handled by forwardRef wrapper
|
|
305
330
|
export default injectIntl(CodeEditorPane);
|
|
331
|
+
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
.html-editor .device-toggle {
|
|
10
10
|
display: flex;
|
|
11
11
|
align-items: center;
|
|
12
|
-
|
|
12
|
+
gap: 1rem;
|
|
13
13
|
padding: 0;
|
|
14
14
|
background-color: $CAP_G10;
|
|
15
15
|
border-radius: 0.25rem 0.25rem 0 0;
|
|
@@ -220,7 +220,6 @@
|
|
|
220
220
|
|
|
221
221
|
// Integration with editor toolbar
|
|
222
222
|
.html-editor.html-editor--inapp {
|
|
223
|
-
margin-top: 4%;
|
|
224
223
|
.editor-toolbar {
|
|
225
224
|
padding: 0 1rem 0 0; // Remove left padding to align with device toggle
|
|
226
225
|
background-color: $CAP_G10;
|
|
@@ -32,7 +32,7 @@ const DeviceToggle = ({
|
|
|
32
32
|
onDeviceChange,
|
|
33
33
|
keepContentSame = false,
|
|
34
34
|
onKeepContentSameChange,
|
|
35
|
-
className = ''
|
|
35
|
+
className = ''
|
|
36
36
|
}) => {
|
|
37
37
|
const handleDeviceClick = (device) => {
|
|
38
38
|
if (onDeviceChange && device !== activeDevice) {
|
|
@@ -97,7 +97,7 @@ DeviceToggle.propTypes = {
|
|
|
97
97
|
onDeviceChange: PropTypes.func,
|
|
98
98
|
keepContentSame: PropTypes.bool,
|
|
99
99
|
onKeepContentSameChange: PropTypes.func,
|
|
100
|
-
className: PropTypes.string
|
|
100
|
+
className: PropTypes.string
|
|
101
101
|
};
|
|
102
102
|
|
|
103
103
|
DeviceToggle.defaultProps = {
|
|
@@ -105,7 +105,7 @@ DeviceToggle.defaultProps = {
|
|
|
105
105
|
onDeviceChange: null,
|
|
106
106
|
keepContentSame: false,
|
|
107
107
|
onKeepContentSameChange: null,
|
|
108
|
-
className: ''
|
|
108
|
+
className: ''
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
export default injectIntl(DeviceToggle);
|