@useinsider/guido 1.4.3-beta.6a4beb1 → 1.4.4-beta.b4adc85

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 (80) hide show
  1. package/README.md +295 -664
  2. package/dist/@types/config/defaults.js +44 -0
  3. package/dist/@types/config/schemas.js +229 -0
  4. package/dist/@types/config/validator.js +56 -0
  5. package/dist/components/Guido.vue.js +1 -1
  6. package/dist/components/Guido.vue2.js +63 -89
  7. package/dist/components/organisms/email-preview/desktop-preview/EmailHeaderInfo.vue2.js +13 -13
  8. package/dist/components/organisms/email-preview/mobile-preview/InboxView.vue.js +5 -5
  9. package/dist/components/organisms/email-preview/mobile-preview/InboxView.vue2.js +13 -13
  10. package/dist/components/organisms/header/LeftSlot.vue.js +1 -1
  11. package/dist/components/organisms/header/LeftSlot.vue2.js +18 -15
  12. package/dist/components/organisms/header/RightSlot.vue.js +10 -10
  13. package/dist/components/organisms/onboarding/NewVersionPopup.vue2.js +22 -19
  14. package/dist/components/organisms/unsubscribe/UnsubscribeBreadcrumb.vue.js +4 -4
  15. package/dist/components/organisms/unsubscribe/UnsubscribeBreadcrumb.vue2.js +8 -8
  16. package/dist/components/organisms/unsubscribe/UnsubscribeTypeSelection.vue.js +3 -3
  17. package/dist/components/organisms/unsubscribe/UnsubscribeTypeSelection.vue2.js +17 -17
  18. package/dist/components/organisms/unsubscribe/UnsubscribeWrapper.vue.js +10 -10
  19. package/dist/composables/useBlocksConfig.js +23 -20
  20. package/dist/composables/useConfig.js +51 -5
  21. package/dist/composables/useHtmlCompiler.js +20 -19
  22. package/dist/composables/useHtmlValidator.js +41 -41
  23. package/dist/composables/usePartner.js +19 -9
  24. package/dist/composables/useStripo.js +11 -11
  25. package/dist/composables/useTranslations.js +3 -2
  26. package/dist/config/compiler/unsubscribeCompilerRules.js +1 -1
  27. package/dist/enums/defaults.js +3 -67
  28. package/dist/enums/unsubscribe.js +23 -20
  29. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +12 -11
  30. package/dist/guido.css +1 -1
  31. package/dist/library.js +12 -2
  32. package/dist/node_modules/lodash-es/_arrayLikeKeys.js +10 -10
  33. package/dist/node_modules/valibot/dist/index.js +476 -103
  34. package/dist/services/templateLibraryApi.js +18 -18
  35. package/dist/src/@types/config/defaults.d.ts +68 -0
  36. package/dist/src/@types/config/index.d.ts +14 -0
  37. package/dist/src/@types/config/schemas.d.ts +505 -0
  38. package/dist/src/@types/config/types.d.ts +142 -0
  39. package/dist/src/@types/config/validator.d.ts +119 -0
  40. package/dist/src/@types/generic.d.ts +4 -45
  41. package/dist/src/components/Guido.vue.d.ts +13 -12
  42. package/dist/src/components/wrappers/WpModal.vue.d.ts +1 -1
  43. package/dist/src/composables/useConfig.d.ts +184 -2
  44. package/dist/src/composables/usePartner.d.ts +8 -0
  45. package/dist/src/enums/defaults.d.ts +4 -6
  46. package/dist/src/enums/unsubscribe.d.ts +5 -1
  47. package/dist/src/library.d.ts +3 -1
  48. package/dist/src/stores/config.d.ts +1547 -102
  49. package/dist/stores/config.js +141 -9
  50. package/package.json +1 -1
  51. package/dist/node_modules/lodash-es/_apply.js +0 -16
  52. package/dist/node_modules/lodash-es/_assignMergeValue.js +0 -8
  53. package/dist/node_modules/lodash-es/_assignValue.js +0 -10
  54. package/dist/node_modules/lodash-es/_baseAssignValue.js +0 -12
  55. package/dist/node_modules/lodash-es/_baseCreate.js +0 -17
  56. package/dist/node_modules/lodash-es/_baseKeysIn.js +0 -15
  57. package/dist/node_modules/lodash-es/_baseMerge.js +0 -20
  58. package/dist/node_modules/lodash-es/_baseMergeDeep.js +0 -31
  59. package/dist/node_modules/lodash-es/_baseRest.js +0 -9
  60. package/dist/node_modules/lodash-es/_baseSetToString.js +0 -14
  61. package/dist/node_modules/lodash-es/_cloneArrayBuffer.js +0 -8
  62. package/dist/node_modules/lodash-es/_cloneBuffer.js +0 -9
  63. package/dist/node_modules/lodash-es/_cloneTypedArray.js +0 -8
  64. package/dist/node_modules/lodash-es/_copyArray.js +0 -9
  65. package/dist/node_modules/lodash-es/_copyObject.js +0 -14
  66. package/dist/node_modules/lodash-es/_createAssigner.js +0 -15
  67. package/dist/node_modules/lodash-es/_defineProperty.js +0 -11
  68. package/dist/node_modules/lodash-es/_getPrototype.js +0 -5
  69. package/dist/node_modules/lodash-es/_initCloneObject.js +0 -9
  70. package/dist/node_modules/lodash-es/_nativeKeysIn.js +0 -10
  71. package/dist/node_modules/lodash-es/_overRest.js +0 -15
  72. package/dist/node_modules/lodash-es/_safeGet.js +0 -7
  73. package/dist/node_modules/lodash-es/_setToString.js +0 -6
  74. package/dist/node_modules/lodash-es/_shortOut.js +0 -16
  75. package/dist/node_modules/lodash-es/constant.js +0 -8
  76. package/dist/node_modules/lodash-es/isArrayLikeObject.js +0 -8
  77. package/dist/node_modules/lodash-es/isPlainObject.js +0 -16
  78. package/dist/node_modules/lodash-es/keysIn.js +0 -9
  79. package/dist/node_modules/lodash-es/merge.js +0 -8
  80. package/dist/node_modules/lodash-es/toPlainObject.js +0 -8
package/README.md CHANGED
@@ -4,789 +4,420 @@
4
4
  </a>
5
5
  </p>
6
6
 
7
-
8
7
  # @useinsider/guido
9
8
 
10
- Guido is a Vue 2 + TypeScript wrapper for the Stripo Email Editor plugin. Easily embed the professional email editor in your Vue applications with a clean, customizable interface.
9
+ Guido is a Vue 2 + TypeScript wrapper for the Stripo Email Editor plugin. Easily embed the professional email editor in your Vue applications with a clean, type-safe configuration.
11
10
 
12
- ## 📦 Install
11
+ ## Installation
13
12
 
14
13
  ```bash
15
14
  npm install @useinsider/guido
16
15
  ```
16
+
17
17
  ### Prerequisites
18
- 🍍 Your project should have `pinia`
19
- You need to be sure those lines added in your config file:
20
-
21
- ℹ️ It helps to optimize your dependencies and sharing by Guido. This is why Guido pretty fast and tiny.
22
-
23
- #### For Webpack
24
- `/webpack.config.js` or `/vue.config.js`
25
- ```js
26
- // ... Previous Configs
27
- shared: {
28
- vue: { singleton: true },
29
- pinia: { singleton: true },
30
- },
31
- // ... Upcoming Configs
32
- ```
33
-
34
- ##### For Vite:
35
- `/vite.config.js`
36
- ```js
37
- // ... Previous Configs
38
- resolve: {
39
- dedupe: ['vue', 'pinia'],
40
- },
41
- // ... Upcoming Configs
42
- ```
18
+
19
+ Your project needs:
20
+ - Vue 2.7+
21
+ - Pinia (state management)
22
+
23
+ Add these to your bundler config to optimize dependencies:
24
+
25
+ **Webpack** (`webpack.config.js` or `vue.config.js`):
26
+ ```js
27
+ shared: {
28
+ vue: { singleton: true },
29
+ pinia: { singleton: true },
30
+ },
31
+ ```
32
+
33
+ **Vite** (`vite.config.js`):
34
+ ```js
35
+ resolve: {
36
+ dedupe: ['vue', 'pinia'],
37
+ },
38
+ ```
39
+
43
40
  ---
44
- ## 🚀 Usage
45
41
 
46
- ### Basic Usage
42
+ ## Quick Start
47
43
 
48
- ```html
44
+ ```vue
49
45
  <template>
50
- <div>
51
- <Guido
52
- ref="guidoEditor"
53
- :template-id="templateId"
54
- :user-id="userId"
55
- :migration-date="migrationDate"
56
- :guido-config="guidoConfig"
57
- :html="initialHtml"
58
- :css="initialCss"
59
- @dynamic-content:open="handleDynamicContentOpen"
60
- @back="handleBack"
61
- @save:start="handleSaveStart"
62
- @save:complete="handleSaveComplete"
63
- />
64
- </div>
46
+ <Guido
47
+ ref="guidoRef"
48
+ :config="config"
49
+ @ready="onReady"
50
+ @dynamic-content:open="onDynamicContentOpen"
51
+ @save:complete="onSaveComplete"
52
+ />
65
53
  </template>
66
54
 
67
- <script lang="ts">
55
+ <script setup lang="ts">
56
+ import { ref } from 'vue';
68
57
  import { Guido } from '@useinsider/guido';
58
+ import type { GuidoConfigInput } from '@useinsider/guido';
59
+
60
+ const guidoRef = ref<InstanceType<typeof Guido> | null>(null);
69
61
 
70
- export default {
71
- components: {
72
- Guido
62
+ const config = ref<GuidoConfigInput>({
63
+ identity: {
64
+ templateId: 'template-123',
65
+ userId: 'user-456',
73
66
  },
74
- data() {
75
- return {
76
- templateId: 'template-123',
77
- userId: 'user-456',
78
- migrationDate: 1699488000,
79
- initialHtml: '<p>Initial HTML content</p>',
80
- initialCss: 'p { color: #333; }',
81
- guidoConfig: {
82
- translationsPath: 'window.trans.en',
83
- htmlCompilerRules: [],
84
- ignoreDefaultHtmlCompilerRules: false,
85
- backButtonLabel?: "Back to Design",
86
- features: {
87
- dynamicContent: true,
88
- saveAsTemplate: true,
89
- versionHistory: true,
90
- testMessage: true
91
- }
92
- },
93
- dynamicContentModalVisible: false
94
- };
67
+ partner: {
68
+ name: 'your-partner-name',
95
69
  },
70
+ template: {
71
+ html: '<p>Initial content</p>',
72
+ css: '',
73
+ },
74
+ });
96
75
 
97
- methods: {
98
- handleDynamicContentOpen(detail) {
99
- console.log('Dynamic content requested:', detail);
100
- this.dynamicContentModalVisible = true;
101
- },
102
-
103
- handleBack() {
104
- console.log('User clicked back button');
105
- // Handle navigation back
106
- },
107
-
108
- handleSaveStart() {
109
- console.log('Save process started');
110
- // Show loading indicator
111
- },
112
-
113
- handleSaveComplete(template) {
114
- console.log('Save completed:', template);
115
- // Handle saved template data
116
- },
117
-
118
- // ⚠️ Your own Dynamic Content Modal should have this id: #guido-dynamic-content-modal
119
- handleDynamicContentInsert() {
120
- this.$refs.guidoEditor?.dynamicContent.insert({
121
- text: 'Display Text',
122
- value: 'actual-value',
123
- fallback: 'Fallback Text'
124
- });
125
-
126
- this.dynamicContentModalVisible = false;
127
- },
128
-
129
- // ⚠️ It's mandatory. There is no way to understand if user closes the modal without selection.
130
- handleDynamicContentClose() {
131
- this.$refs.guidoEditor?.dynamicContent.close();
132
- },
133
-
134
- // If you need to trigger save manually like leave modal cases, you can use this method.
135
- save () {
136
- this.$refs.guidoEditor?.saveSilent();
137
- }
138
- }
139
- };
76
+ const onReady = () => console.log('Editor ready');
77
+ const onDynamicContentOpen = () => console.log('Dynamic content requested');
78
+ const onSaveComplete = (template) => console.log('Saved:', template);
140
79
  </script>
141
80
  ```
142
81
 
143
- ## 📚 API
144
-
145
- ### Guido Component Props
82
+ ---
146
83
 
147
- | Prop | Type | Required | Default | Description |
148
- |------|------|----------|---------|-------------|
149
- | `templateId` | `string` | ✅ | - | Unique identifier for the email template |
150
- | `userId` | `string` | ✅ | - | Unique identifier for the user |
151
- | `guidoConfig` | `GuidoConfig` | ✅ | - | Configuration object for the editor |
152
- | `migrationDate` | `number` | ✅ | - | Stripo migration date in Unix timestamp (seconds). Retrieved from backend `/partner-settings` endpoint as `migrationDate`. Used for onboarding process |
153
- | `partnerName` | `string` | ⚪ | From URL host | Partner identifier |
154
- | `productType` | `string` | ⚪ | From URL path | Product type identifier |
155
- | `username` | `string` | ⚪ | `'Guido User'` | Display name for the user |
156
- | `html` | `string` | ⚪ | `''` | Initial HTML content for the template |
157
- | `css` | `string` | ⚪ | `''` | Initial CSS styles for the template |
84
+ ## Configuration
158
85
 
159
- ### Guido Component Events
86
+ Guido uses a single, validated `config` prop organized by domain:
160
87
 
161
- | Event | Payload | Description |
162
- |-------|---------|-------------|
163
- | `dynamic-content:open` | `DynamicContent \| null` | Fired when user requests to insert dynamic content |
164
- | `back` | - | Fired when user clicks the back button |
165
- | `save:start` | - | Fired when the save process begins |
166
- | `save:complete` | `Omit<Template, 'forceRecreate'>` | Fired when template is successfully saved |
167
- | `on-change` | void | It Fires once for managing leave modal etc. |
168
- | `ready` | void | Fired when the editor is ready and template is loaded |
169
- | `onboarding-finished` | void | Fired when the onboarding popup is dismissed or completed, allowing parent applications to track onboarding state |
170
- | `test-email:click` | - | Fired when user clicks the test email button in the header |
171
-
172
- ### Guido Exposed Methods
173
88
  ```typescript
174
- dynamicContent.insert(DynamicContent);
175
- dynamicContent.close();
176
- saveSilent();
177
- ```
178
-
179
- ### Guido Interfaces
89
+ import type { GuidoConfigInput } from '@useinsider/guido';
90
+
91
+ const config: GuidoConfigInput = {
92
+ // Required: Identity
93
+ identity: {
94
+ templateId: string, // Required - Template identifier
95
+ userId: string, // Required - User identifier
96
+ variationId?: string, // Optional - A/B test variation
97
+ },
180
98
 
181
- ```typescript
182
- interface GuidoConfig {
183
- translationsPath: string;
184
- htmlCompilerRules?: CompilerRule[];
185
- ignoreDefaultHtmlCompilerRules?: boolean;
186
- useHeader: boolean
187
- emailHeader: {
188
- senderName: string;
189
- subject: string;
190
- };
99
+ // Required: Partner
191
100
  partner: {
192
- partnerName: string;
193
- productType: number;
194
- messageType: number;
195
- };
196
- features: {
197
- dynamicContent: boolean;
198
- saveAsTemplate: boolean;
199
- versionHistory: boolean;
200
- testMessage: boolean;
201
- displayConditions: boolean;
202
- };
203
- blocks?: {
204
- excludeDefaults?: GuidoBlockType[];
205
- includeCustoms?: GuidoCustomBlockType[];
206
- };
207
- }
208
- ```
101
+ name: string, // Required - Partner name
102
+ productType?: number, // Optional - Default: 60 (Email)
103
+ messageType?: number, // Optional - Default: 1 (Promotional)
104
+ username?: string, // Optional - Default: 'Guido User'
105
+ },
209
106
 
210
- | Property | Type | Default | Description |
211
- |----------|------|---------|-------------|
212
- | `translationsPath` | `string` | `'window.trans.en'` | JavaScript path to the translations object |
213
- | `htmlCompilerRules` | `CompilerRule[]` | `[]` | Additional compiler rules to apply to HTML content. See [HTML Compiler Rules](#-html-compiler-rules) section below |
214
- | `ignoreDefaultHtmlCompilerRules` | `boolean` | `false` | Skip default compiler rules and only use custom rules. Default rules: `src/config/compiler/htmlCompilerRules.ts` |
215
- | `useHeader` | `boolean` | `true` | Adds extra spaces to height for adjusting. If you don't use Inone Page header, override as `false` |
216
- | `features` | `Features` | `{ dynamicContent: true, saveAsTemplate: true, versionHistory: true }` | Feature flags to enable/disable editor functionality |
217
- | `features.dynamicContent` | `boolean` | `true` | Enable dynamic content insertion feature |
218
- | `features.saveAsTemplate` | `boolean` | `true` | Enable save as template feature |
219
- | `features.versionHistory` | `boolean` | `true` | Enable version history feature |
220
- | `features.displayConditions` | `boolean` | `true` | Enable display conditions |
221
- | `blocks` | `BlocksConfig` | `{ excludeDefaults: [], includeCustoms: [] }` | Block configuration for excluding default blocks and including custom blocks. See [Blocks Configuration](#-blocks-configuration) section below |
222
- | `blocks.excludeDefaults` | `GuidoBlockType[]` | `[]` | Array of default Stripo blocks to exclude from the editor |
223
- | `blocks.includeCustoms` | `GuidoCustomBlockType[]` | `[]` | Array of custom blocks to include in the editor |
107
+ // Optional: Template content
108
+ template?: {
109
+ html?: string,
110
+ css?: string,
111
+ preselectedDynamicContent?: DynamicContent[],
112
+ selectedUnsubscribePages?: number[],
113
+ },
224
114
 
225
- ```typescript
226
- interface DynamicContent {
227
- value: string;
228
- text: string;
229
- fallback?: string;
230
- }
231
- ```
232
- ---
115
+ // Optional: Editor settings
116
+ editor?: {
117
+ locale?: string, // Default: 'en'
118
+ translationsPath?: string, // Default: 'window.trans.en'
119
+ migrationDate?: number, // Stripo migration timestamp
120
+ emailHeader?: {
121
+ senderName?: string,
122
+ subject?: string,
123
+ },
124
+ },
233
125
 
234
- | Property | Type | Default | Description |
235
- |----------|------|---------|-------------|
236
- | `value` | `string` | '' | Value of the dynamic content |
237
- | `text` | `string` | '' | Visible value of the dynamic content |
238
- | `fallback?` | `string` | '' | Fallback value of the dynamic content. Optional |
126
+ // Optional: UI settings
127
+ ui?: {
128
+ showHeader?: boolean, // Default: true
129
+ backButtonLabel?: string,
130
+ },
239
131
 
240
- ## 🧱 Blocks Configuration
132
+ // Optional: Feature toggles
133
+ features?: {
134
+ dynamicContent?: boolean, // Default: true
135
+ saveAsTemplate?: boolean, // Default: true
136
+ versionHistory?: boolean, // Default: true
137
+ testMessage?: boolean, // Default: true
138
+ displayConditions?: boolean, // Default: true
139
+ unsubscribe?: boolean, // Default: true
140
+ },
241
141
 
242
- Guido allows you to customize which blocks are available in the editor. You can exclude default Stripo blocks and selectively include custom blocks to create tailored editing experiences for different product types.
142
+ // Optional: Block configuration
143
+ blocks?: {
144
+ excludeDefaults?: DefaultBlockType[],
145
+ includeCustoms?: CustomBlockType[],
146
+ },
243
147
 
244
- ### Block Types
148
+ // Optional: HTML compiler
149
+ compiler?: {
150
+ customRules?: CompilerRule[],
151
+ ignoreDefaultRules?: boolean, // Default: false
152
+ },
153
+ };
154
+ ```
245
155
 
246
- #### Default Blocks (GuidoBlockType)
156
+ ---
247
157
 
248
- These are the standard Stripo email editor blocks that can be excluded:
158
+ ## Events
249
159
 
250
- ```typescript
251
- type GuidoBlockType =
252
- | 'amp-accordion' // AMP accordion component
253
- | 'amp-carousel' // AMP image carousel
254
- | 'amp-form-controls' // AMP form elements
255
- | 'banner-block' // Banner/hero section
256
- | 'button-block' // Call-to-action buttons
257
- | 'html-block' // Custom HTML
258
- | 'image-block' // Image elements
259
- | 'menu-block' // Navigation menu
260
- | 'social-block' // Social media links
261
- | 'spacer-block' // Vertical spacing
262
- | 'text-block' // Text content
263
- | 'timer-block' // Countdown timer
264
- | 'video-block' // Video embeds
265
- ```
160
+ | Event | Payload | Description |
161
+ |-------|---------|-------------|
162
+ | `ready` | - | Editor is loaded and ready |
163
+ | `dynamic-content:open` | `DynamicContent \| null` | User wants to insert dynamic content |
164
+ | `back` | - | Back button clicked |
165
+ | `save:start` | - | Save process started |
166
+ | `save:complete` | `Template` | Save completed successfully |
167
+ | `on-change` | - | Template was modified |
168
+ | `test-email:click` | - | Test email button clicked |
169
+ | `onboarding-finished` | - | Onboarding popup dismissed |
266
170
 
267
- #### Custom Blocks (GuidoCustomBlockType)
171
+ ---
268
172
 
269
- These are custom blocks that can be selectively included:
173
+ ## Exposed Methods
270
174
 
271
175
  ```typescript
272
- type GuidoCustomBlockType =
273
- | 'dynamic-content' // Dynamic content merge tags
274
- | 'checkbox-block' // Checkbox form input
275
- | 'radio-button-block' // Radio button form input
276
- | 'recommendation-block' // Product recommendations
277
- | 'unsubscribe-block' // Unsubscribe link
278
- | 'coupon-block' // Coupon/promo code
279
- | 'items-block' // Cart items display
176
+ const guidoRef = ref<InstanceType<typeof Guido> | null>(null);
177
+
178
+ // Insert dynamic content
179
+ guidoRef.value?.dynamicContent.insert({
180
+ text: 'Display Name',
181
+ value: 'variable_name',
182
+ fallback: 'Default Value',
183
+ });
184
+
185
+ // Close dynamic content modal
186
+ guidoRef.value?.dynamicContent.close();
187
+
188
+ // Silent save (no UI feedback)
189
+ guidoRef.value?.saveSilent();
280
190
  ```
281
191
 
282
- ### Configuration Examples
192
+ ---
283
193
 
284
- #### Example 1: Exclude Specific Default Blocks
194
+ ## Block Configuration
285
195
 
286
- Disable button, image, and video blocks while keeping all custom blocks:
196
+ ### Default Blocks (can be excluded)
287
197
 
288
198
  ```typescript
289
- const guidoConfig = {
290
- translationsPath: 'window.trans.en',
291
- features: {
292
- dynamicContent: true,
293
- saveAsTemplate: true,
294
- versionHistory: true,
295
- testMessage: true
296
- },
297
- blocks: {
298
- excludeDefaults: ['button-block', 'image-block', 'video-block']
299
- }
300
- };
301
- ```
302
-
303
- **Result:**
304
- - Button, Image, Video blocks disabled
305
- - All other default blocks enabled
306
- - All custom blocks are disabled.
199
+ type DefaultBlockType =
200
+ | 'amp-accordion'
201
+ | 'amp-carousel'
202
+ | 'amp-form-controls'
203
+ | 'banner-block'
204
+ | 'button-block'
205
+ | 'html-block'
206
+ | 'image-block'
207
+ | 'menu-block'
208
+ | 'social-block'
209
+ | 'spacer-block'
210
+ | 'text-block'
211
+ | 'timer-block'
212
+ | 'video-block';
213
+ ```
214
+
215
+ ### Custom Blocks (opt-in)
307
216
 
308
- #### Example 2: Include Only Specific Custom Blocks
217
+ ```typescript
218
+ type CustomBlockType =
219
+ | 'dynamic-content'
220
+ | 'checkbox-block'
221
+ | 'radio-button-block'
222
+ | 'recommendation-block'
223
+ | 'unsubscribe-block'
224
+ | 'coupon-block'
225
+ | 'items-block';
226
+ ```
309
227
 
310
- Enable only coupon and recommendation blocks:
228
+ ### Examples
311
229
 
312
230
  ```typescript
313
- const guidoConfig = {
314
- translationsPath: 'window.trans.en',
315
- features: {
316
- dynamicContent: true,
317
- saveAsTemplate: true,
318
- versionHistory: true,
319
- testMessage: true
231
+ // Exclude specific default blocks
232
+ const config: GuidoConfigInput = {
233
+ identity: { templateId: 'tpl-123', userId: 'user-456' },
234
+ partner: { name: 'partner' },
235
+ blocks: {
236
+ excludeDefaults: ['timer-block', 'video-block'],
320
237
  },
238
+ };
239
+
240
+ // Include custom blocks
241
+ const config: GuidoConfigInput = {
242
+ identity: { templateId: 'tpl-123', userId: 'user-456' },
243
+ partner: { name: 'partner' },
321
244
  blocks: {
322
- includeCustoms: ['coupon-block', 'recommendation-block']
323
- }
245
+ includeCustoms: ['recommendation-block', 'coupon-block', 'dynamic-content'],
246
+ },
324
247
  };
325
248
  ```
326
249
 
327
- **Result:**
328
- - All default blocks enabled
329
- - Only Coupon and Recommendation extensions enabled.
330
- - Other custom blocks are disabled
250
+ ---
331
251
 
332
- ### Default Behavior
252
+ ## HTML Compiler Rules
333
253
 
334
- When `blocks` is not provided or is `undefined`:
254
+ Add custom rules to transform HTML during export:
335
255
 
336
256
  ```typescript
337
- const guidoConfig = {
338
- translationsPath: 'window.trans.en',
339
- features: {
340
- dynamicContent: true,
341
- saveAsTemplate: true,
342
- versionHistory: true,
343
- testMessage: true
257
+ const config: GuidoConfigInput = {
258
+ identity: { templateId: 'tpl-123', userId: 'user-456' },
259
+ partner: { name: 'partner' },
260
+ compiler: {
261
+ customRules: [
262
+ // Replace rule
263
+ {
264
+ id: 'replace-domain',
265
+ type: 'replace',
266
+ search: 'old-domain.com',
267
+ replacement: 'new-domain.com',
268
+ priority: 10,
269
+ },
270
+ // Regex rule
271
+ {
272
+ id: 'remove-comments',
273
+ type: 'regex',
274
+ pattern: '<!--.*?-->',
275
+ replacement: '',
276
+ flags: 'g',
277
+ priority: 20,
278
+ },
279
+ // Custom processor
280
+ {
281
+ id: 'add-tracking',
282
+ type: 'custom',
283
+ processor: (html) => html.replace('</body>', '<img src="track.gif"/></body>'),
284
+ priority: 30,
285
+ },
286
+ ],
287
+ ignoreDefaultRules: false, // Set true to skip built-in rules
344
288
  },
345
- // No blocks config
346
289
  };
347
290
  ```
348
291
 
349
- **Result:**
350
- - All 13 default Stripo blocks enabled
351
- - All custom blocks are disabled.
352
-
353
- ### Block Configuration Interface
354
-
355
- ```typescript
356
- interface BlocksConfig {
357
- excludeDefaults?: GuidoBlockType[];
358
- includeCustoms?: GuidoCustomBlockType[];
359
- }
360
- ```
361
-
362
- ### TypeScript Types
292
+ ---
363
293
 
364
- The library exports the following TypeScript types:
294
+ ## TypeScript Exports
365
295
 
366
296
  ```typescript
367
- // Main component
297
+ // Component
368
298
  import { Guido } from '@useinsider/guido';
369
299
 
370
300
  // Types
371
- import type { GuidoConfig } from '@useinsider/guido';
372
- import type { StripoEventType } from '@useinsider/guido';
301
+ import type {
302
+ GuidoConfig,
303
+ GuidoConfigInput,
304
+ IdentityConfig,
305
+ PartnerConfig,
306
+ TemplateConfig,
307
+ EditorConfig,
308
+ UIConfig,
309
+ FeaturesConfig,
310
+ BlocksConfig,
311
+ CompilerConfig,
312
+ DynamicContent,
313
+ DefaultBlockType,
314
+ CustomBlockType,
315
+ } from '@useinsider/guido';
316
+
317
+ // Utilities
318
+ import {
319
+ validateConfig,
320
+ parseConfig,
321
+ MessageType,
322
+ ProductType,
323
+ } from '@useinsider/guido';
324
+
325
+ // Styles
326
+ import '@useinsider/guido/style';
373
327
  ```
374
328
 
375
- ## 🔨 HTML Compiler Rules
376
-
377
- Guido includes a powerful HTML compiler system that allows you to transform HTML content with custom rules. You can define additional rules and optionally ignore the default rules.
378
-
379
- ### Rule Types
380
-
381
- There are 4 types of compiler rules:
329
+ ---
382
330
 
383
- #### 1. Replace Rule
384
- Replace specific strings in HTML content.
331
+ ## Constants
385
332
 
386
333
  ```typescript
387
- {
388
- id: 'fix-encoding',
389
- description: 'Fix URL encoding issues',
390
- type: 'replace',
391
- search: '{%22', // String to find
392
- replacement: '%7B%22', // String to replace with
393
- replaceAll: true, // Replace all occurrences (default: true)
394
- priority: 10 // Execution priority (lower = earlier)
395
- }
396
- ```
334
+ import { MessageType, ProductType } from '@useinsider/guido';
397
335
 
398
- #### 2. Regex Rule
399
- Use regular expressions for complex pattern matching and replacement.
336
+ MessageType.PROMOTIONAL // 1
337
+ MessageType.TRANSACTIONAL // 2
400
338
 
401
- ```typescript
402
- {
403
- id: 'remove-comments',
404
- description: 'Remove HTML comments',
405
- type: 'regex',
406
- pattern: '<!--.*?-->', // Regex pattern
407
- replacement: '', // Replacement string
408
- flags: 'g', // Regex flags (default: 'g')
409
- priority: 20
410
- }
339
+ ProductType.EMAIL // 60
340
+ ProductType.ARCHITECT // 49
341
+ ProductType.UNSUBSCRIBE_PAGES // 97
411
342
  ```
412
343
 
413
- #### 3. Remove Rule
414
- Remove specific strings or patterns from HTML content.
344
+ ---
415
345
 
416
- ```typescript
417
- {
418
- id: 'cleanup-scripts',
419
- description: 'Remove unwanted script tags',
420
- type: 'remove',
421
- targets: [ // Array of strings or RegExp objects
422
- '<script src="unwanted.js"></script>',
423
- /onclick="[^"]*"/g
424
- ],
425
- priority: 30
426
- }
427
- ```
346
+ ## Dynamic Content Modal
428
347
 
429
- #### 4. Custom Rule
430
- Define complex transformation logic with a custom processor function.
348
+ When the `dynamic-content:open` event fires, show your custom modal and call the insert method:
431
349
 
432
- ```typescript
433
- {
434
- id: 'add-meta-tags',
435
- description: 'Add custom meta tags to head',
436
- type: 'custom',
437
- processor: (html: string): string => {
438
- // Custom transformation logic
439
- const metaTags = '<meta name="custom" content="value">';
440
- return html.replace('</head>', `${metaTags}</head>`);
441
- },
442
- priority: 40
443
- }
444
- ```
350
+ ```vue
351
+ <template>
352
+ <Guido ref="guidoRef" :config="config" @dynamic-content:open="showModal = true" />
445
353
 
446
- ### Using HTML Compiler Rules
354
+ <!-- Your modal must have id="guido-dynamic-content-modal" -->
355
+ <YourModal v-if="showModal" id="guido-dynamic-content-modal" @select="insertContent" @close="closeModal" />
356
+ </template>
447
357
 
448
- #### Basic Usage with Custom Rules
358
+ <script setup>
359
+ const showModal = ref(false);
449
360
 
450
- ```typescript
451
- const guidoConfig = {
452
- translationsPath: 'window.trans.en',
453
- features: {
454
- dynamicContent: true,
455
- saveAsTemplate: true,
456
- versionHistory: false, // Disable version history
457
- testMessage: true
458
- },
459
- htmlCompilerRules: [
460
- {
461
- id: 'replace-domain',
462
- description: 'Replace old domain with new one',
463
- type: 'replace',
464
- search: 'old-domain.com',
465
- replacement: 'new-domain.com',
466
- replaceAll: true,
467
- priority: 10
468
- },
469
- {
470
- id: 'remove-tracking',
471
- description: 'Remove tracking pixels',
472
- type: 'regex',
473
- pattern: '<img[^>]*tracking[^>]*>',
474
- replacement: '',
475
- flags: 'gi',
476
- priority: 20
477
- }
478
- ]
361
+ const insertContent = (content) => {
362
+ guidoRef.value?.dynamicContent.insert({
363
+ text: content.label,
364
+ value: content.value,
365
+ fallback: content.fallback || '',
366
+ });
367
+ showModal.value = false;
479
368
  };
480
- ```
481
-
482
- #### Ignoring Default Rules
483
369
 
484
- ```typescript
485
- const guidoConfig = {
486
- translationsPath: 'window.trans.en',
487
- features: {
488
- dynamicContent: true,
489
- saveAsTemplate: true,
490
- versionHistory: true,
491
- testMessage: true
492
- },
493
- ignoreDefaultHtmlCompilerRules: true, // Skip all default rules
494
- htmlCompilerRules: [
495
- // Only your custom rules will be applied
496
- {
497
- id: 'custom-transformation',
498
- type: 'replace',
499
- search: 'old-text',
500
- replacement: 'new-text',
501
- priority: 1
502
- }
503
- ]
370
+ const closeModal = () => {
371
+ guidoRef.value?.dynamicContent.close();
372
+ showModal.value = false;
504
373
  };
505
- ```
506
-
507
- ### Rule Execution Order
508
-
509
- Rules are executed in priority order (lower numbers first). Rules with the same priority are executed in array order.
510
-
511
- - **Priority 1-99**: Reserved for critical transformations
512
- - **Priority 100-999**: Standard transformations
513
- - **Priority 1000+**: Additional custom rules (automatically assigned)
514
-
515
- ### Default Rules
516
-
517
- Guido includes several default rules for common email HTML optimizations:
518
-
519
- - **URL encoding fixes**: Fixes malformed URL encoding in dynamic content
520
- - **Template tag restoration**: Restores `{{}}` template tags that got URL encoded
521
- - **HTML entity decoding**: Converts `&lt;` and `&gt;` back to `<` and `>`
522
- - **Cleanup rules**: Removes unwanted iframe and style elements
523
- - **MSO conditions**: Manages Outlook-specific conditional comments
524
- - **Domain replacement**: Updates old image domains to current ones
525
-
526
- You can view all default rules in: `src/config/compiler/htmlCompilerRules.ts`
527
-
528
- ### CompilerRule Interface
529
-
530
- ```typescript
531
- type CompilerRuleType = 'replace' | 'regex' | 'remove' | 'custom';
532
-
533
- interface BaseCompilerRule {
534
- id: string;
535
- description?: string;
536
- priority: number;
537
- }
538
-
539
- interface ReplaceRule extends BaseCompilerRule {
540
- type: 'replace';
541
- search: string;
542
- replacement: string;
543
- replaceAll?: boolean; // Default: true
544
- }
545
-
546
- interface RegexRule extends BaseCompilerRule {
547
- type: 'regex';
548
- pattern: string;
549
- replacement: string;
550
- flags?: string; // Default: 'g'
551
- }
552
-
553
- interface RemoveRule extends BaseCompilerRule {
554
- type: 'remove';
555
- targets: (string | RegExp)[]; // Array of strings or RegExp objects
556
- }
557
-
558
- interface CustomRule extends BaseCompilerRule {
559
- type: 'custom';
560
- processor: (html: string) => string;
561
- }
562
-
563
- type CompilerRule = ReplaceRule | RegexRule | RemoveRule | CustomRule;
374
+ </script>
564
375
  ```
565
376
 
566
377
  ---
567
378
 
568
- ## 🔧 Development
569
-
570
- ### Prerequisites
571
-
572
- - 🧄 `Bun` (strongly recommended)
573
- or
574
- - NodeJS 18+ & `npm`
575
-
576
- ### Setup
379
+ ## Development
577
380
 
578
381
  ```bash
579
- # Install dependencies
382
+ # Install
580
383
  bun install
581
384
 
582
- # Start development server
385
+ # Start dev server
583
386
  bun start
584
387
 
585
- # Build for production
388
+ # Build
586
389
  bun run build
587
390
 
588
- # Type checking
589
- bun run type-check
590
-
591
- # Linting
391
+ # Lint & type-check
592
392
  bun run lint
593
393
  ```
594
394
 
595
395
  ### Environment Variables
596
396
 
597
- Create a `.env` file with the following variables: (You can get env variables from your senior)
598
-
599
397
  ```env
600
398
  VITE_STRIPO_PLUGIN_ID=your_plugin_id
601
399
  VITE_STRIPO_SECRET_KEY=your_secret_key
602
400
  VITE_STRIPO_ROLE=your_role
603
-
604
- # Playwright Test Configuration (Optional - for local debugging only)
605
- HEADED=false # Set to 'true' to run tests with visible browser
606
- ```
607
-
608
- ### Project Structure
609
-
610
- ```
611
- src/
612
- ├── components/ # Vue components
613
- ├── composables/ # Vue composables & business logic
614
- ├── services/ # API layer
615
- ├── stores/ # State management
616
- ├── @types/ # TypeScript definitions
617
- ├── static/ # Static assets & templates
618
- ├── utils/ # Utility functions
619
- ├── enums/ # Constants & enums
620
- ├── mock/ # Mock data for development
621
- ├── plugins/ # Vue plugins
622
- └── library.ts # Main export
623
- ```
624
-
625
- ## 🔌 Provide/Inject Utilities
626
-
627
- Guido includes type-safe utilities for Vue's provide/inject system to facilitate dependency injection between components.
628
-
629
- ### useProvideInject
630
-
631
- The `useProvideInject` composable provides two helper functions for type-safe dependency injection:
632
-
633
- #### Basic Usage
634
-
635
- ```typescript
636
- // Parent component
637
- import { provideValue } from '@useinsider/guido';
638
- import { InjectionKey } from 'vue';
639
-
640
- // Define a typed injection key
641
- const MyServiceKey: InjectionKey<MyService> = Symbol('MyService');
642
-
643
- // Provide the value
644
- const myService = new MyService();
645
- provideValue(MyServiceKey, myService);
646
-
647
- // Child component
648
- import { useInjectedValue } from '@useinsider/guido';
649
-
650
- // Inject the value with type safety
651
- const myService = useInjectedValue(MyServiceKey);
652
- ```
653
-
654
- #### With Default Value
655
-
656
- ```typescript
657
- // Inject with a fallback value
658
- const myService = useInjectedValue(MyServiceKey, new DefaultService());
659
401
  ```
660
402
 
661
- #### Error Handling
662
-
663
- The `useInjectedValue` function will throw a descriptive error if no provider is found and no default value is provided:
664
-
665
- ```typescript
666
- // This will throw an error if no provider exists
667
- try {
668
- const myService = useInjectedValue(MyServiceKey);
669
- } catch (error) {
670
- console.error('No provider found for MyService');
671
- }
672
- ```
673
-
674
- ### API Reference
675
-
676
- #### `provideValue`
677
-
678
- ```typescript
679
- provideValue<T>(key: InjectionKey<T>, value: T): void
680
- ```
681
-
682
- Provides a value using Vue's provide system with type safety.
683
-
684
- | Parameter | Type | Description |
685
- |-----------|------|-------------|
686
- | `key` | `InjectionKey<T>` | The typed injection key |
687
- | `value` | `T` | The value to provide |
688
-
689
- #### `useInjectedValue`
690
-
691
- ```typescript
692
- useInjectedValue<T>(key: InjectionKey<T>, defaultValue?: T): T
693
- ```
694
-
695
- Injects a value using Vue's inject system with type safety and error handling.
696
-
697
- | Parameter | Type | Required | Description |
698
- |-----------|------|----------|-------------|
699
- | `key` | `InjectionKey<T>` | ✅ | The typed injection key |
700
- | `defaultValue` | `T` | ⚪ | Optional fallback value |
701
-
702
- **Returns:** `T` - The injected value
703
-
704
- **Throws:** `Error` - When no provider is found and no default value is provided
705
-
706
- ## 🌐 i18n
707
- Before running the project, it sends to request to inone.useinsider.com/translations and writes the JSON file into - [trans.json](src/mock/responses/trans.json).
708
- It allows to use production or local translations on your code. 🚀
709
- Example usage:
710
- ```js
711
- import { useTranslations } from '@@/Composables/useTranslations';
712
-
713
- const trans = useTranslations();
714
-
715
- // use everywhere like this:
716
- trans('foo.bar')
717
- ```
403
+ ---
718
404
 
719
- ## 📦 Local Building (Recommended)
405
+ ## Local Testing
720
406
 
721
- Run this commands if you want to test the package on your local before sending to NPM.
722
- ```sh
407
+ ```bash
408
+ # Build the package
723
409
  bun run build
724
- ```
725
410
 
726
- Since bun does not have packaging yet, use npm here: 🥲
727
- ```sh
411
+ # Create tarball
728
412
  npm pack
729
- ```
730
-
731
- It'll crate like `useinsider-guido-1.0.0.tgz` file.
732
413
 
733
- Move this file to your project path like: `email-fe` via:
734
- ```sh
735
- cp useinsider-guido-1.0.0.tgz ../email-fe
414
+ # Install in your project
415
+ cd ../your-project
416
+ npm install ../guido/useinsider-guido-1.0.0.tgz
736
417
  ```
737
418
 
738
- Install the file to your project:
739
- ```sh
740
- npm i ./useinsider-guido-1.0.0.tgz
741
- ```
742
-
743
- Then you just need to rebuild to your project or restart the Container. 🎉
744
-
745
- For Future, we can create a shell script for it. Feel free to help 🙃
746
-
747
- ## 📦 Build Output
748
-
749
- The library builds to multiple formats:
750
-
751
- - **ES Module**: `dist/library.js` (recommended)
752
- - **CSS**: `dist/guido.css` (custom styles)
753
-
754
- ### Package Exports
755
-
756
- ```json
757
- {
758
- "exports": {
759
- ".": {
760
- "import": "./dist/library.js",
761
- "types": "./dist/components/Guido.vue.d.ts",
762
- "require": "./dist/components/Guido.vue.js"
763
- },
764
- "./style": "./dist/guido.css"
765
- }
766
- }
767
- ```
768
-
769
- ## 🤝 Contributing
770
- - PR Titles should be structured like `TASK-ID | 🔥 | Some Clear Task Descriptions`
771
- - PR Labels should be filled.
772
- - PR Assignee required.
773
- - Tests should be covered.
774
- - All required checks should be passed before sending review request.
775
-
776
- ## 📄 License
777
-
778
- ISC License
779
-
780
419
  ---
781
420
 
782
- ## 🔗 Related
421
+ ## License
783
422
 
784
- - [Stripo Email Editor](https://stripo.email/) - The underlying email editor
785
- - [@useinsider/design-system-vue](https://github.com/useinsider/design-system-vue) - Insider's Vue design system
786
-
787
- ## 🎯 TODO:
788
- - CSS part should be optimized with variables & `sass-loader`.
789
- - Master Version Generator should be fixed.
790
- - Playwright integrationBoilerplate/control.ts
791
- - Commitlint & Precommit Hooks integration
792
- - Get Pre-built display conditions from API
423
+ ISC License