@useinsider/guido 1.4.4-beta.b4adc85 → 1.4.4

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 +664 -295
  2. package/dist/components/Guido.vue.js +1 -1
  3. package/dist/components/Guido.vue2.js +89 -63
  4. package/dist/components/organisms/email-preview/desktop-preview/EmailHeaderInfo.vue2.js +13 -13
  5. package/dist/components/organisms/email-preview/mobile-preview/InboxView.vue.js +5 -5
  6. package/dist/components/organisms/email-preview/mobile-preview/InboxView.vue2.js +13 -13
  7. package/dist/components/organisms/header/LeftSlot.vue.js +1 -1
  8. package/dist/components/organisms/header/LeftSlot.vue2.js +15 -18
  9. package/dist/components/organisms/header/RightSlot.vue.js +10 -10
  10. package/dist/components/organisms/onboarding/NewVersionPopup.vue2.js +19 -22
  11. package/dist/components/organisms/unsubscribe/UnsubscribeBreadcrumb.vue.js +4 -4
  12. package/dist/components/organisms/unsubscribe/UnsubscribeBreadcrumb.vue2.js +8 -8
  13. package/dist/components/organisms/unsubscribe/UnsubscribeTypeSelection.vue.js +3 -3
  14. package/dist/components/organisms/unsubscribe/UnsubscribeTypeSelection.vue2.js +17 -17
  15. package/dist/components/organisms/unsubscribe/UnsubscribeWrapper.vue.js +10 -10
  16. package/dist/composables/useBlocksConfig.js +20 -23
  17. package/dist/composables/useConfig.js +5 -51
  18. package/dist/composables/useHtmlCompiler.js +19 -20
  19. package/dist/composables/useHtmlValidator.js +41 -41
  20. package/dist/composables/usePartner.js +9 -19
  21. package/dist/composables/useStripo.js +11 -11
  22. package/dist/composables/useTranslations.js +2 -3
  23. package/dist/config/compiler/unsubscribeCompilerRules.js +1 -1
  24. package/dist/enums/defaults.js +67 -3
  25. package/dist/enums/unsubscribe.js +20 -23
  26. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +11 -12
  27. package/dist/guido.css +1 -1
  28. package/dist/library.js +2 -12
  29. package/dist/node_modules/lodash-es/_apply.js +16 -0
  30. package/dist/node_modules/lodash-es/_arrayLikeKeys.js +10 -10
  31. package/dist/node_modules/lodash-es/_assignMergeValue.js +8 -0
  32. package/dist/node_modules/lodash-es/_assignValue.js +10 -0
  33. package/dist/node_modules/lodash-es/_baseAssignValue.js +12 -0
  34. package/dist/node_modules/lodash-es/_baseCreate.js +17 -0
  35. package/dist/node_modules/lodash-es/_baseKeysIn.js +15 -0
  36. package/dist/node_modules/lodash-es/_baseMerge.js +20 -0
  37. package/dist/node_modules/lodash-es/_baseMergeDeep.js +31 -0
  38. package/dist/node_modules/lodash-es/_baseRest.js +9 -0
  39. package/dist/node_modules/lodash-es/_baseSetToString.js +14 -0
  40. package/dist/node_modules/lodash-es/_cloneArrayBuffer.js +8 -0
  41. package/dist/node_modules/lodash-es/_cloneBuffer.js +9 -0
  42. package/dist/node_modules/lodash-es/_cloneTypedArray.js +8 -0
  43. package/dist/node_modules/lodash-es/_copyArray.js +9 -0
  44. package/dist/node_modules/lodash-es/_copyObject.js +14 -0
  45. package/dist/node_modules/lodash-es/_createAssigner.js +15 -0
  46. package/dist/node_modules/lodash-es/_defineProperty.js +11 -0
  47. package/dist/node_modules/lodash-es/_getPrototype.js +5 -0
  48. package/dist/node_modules/lodash-es/_initCloneObject.js +9 -0
  49. package/dist/node_modules/lodash-es/_nativeKeysIn.js +10 -0
  50. package/dist/node_modules/lodash-es/_overRest.js +15 -0
  51. package/dist/node_modules/lodash-es/_safeGet.js +7 -0
  52. package/dist/node_modules/lodash-es/_setToString.js +6 -0
  53. package/dist/node_modules/lodash-es/_shortOut.js +16 -0
  54. package/dist/node_modules/lodash-es/constant.js +8 -0
  55. package/dist/node_modules/lodash-es/isArrayLikeObject.js +8 -0
  56. package/dist/node_modules/lodash-es/isPlainObject.js +16 -0
  57. package/dist/node_modules/lodash-es/keysIn.js +9 -0
  58. package/dist/node_modules/lodash-es/merge.js +8 -0
  59. package/dist/node_modules/lodash-es/toPlainObject.js +8 -0
  60. package/dist/node_modules/valibot/dist/index.js +103 -476
  61. package/dist/services/templateLibraryApi.js +18 -18
  62. package/dist/src/@types/generic.d.ts +45 -4
  63. package/dist/src/components/Guido.vue.d.ts +12 -13
  64. package/dist/src/components/wrappers/WpModal.vue.d.ts +1 -1
  65. package/dist/src/composables/useConfig.d.ts +2 -184
  66. package/dist/src/composables/usePartner.d.ts +0 -8
  67. package/dist/src/enums/defaults.d.ts +6 -4
  68. package/dist/src/enums/unsubscribe.d.ts +1 -5
  69. package/dist/src/library.d.ts +1 -3
  70. package/dist/src/stores/config.d.ts +102 -1547
  71. package/dist/stores/config.js +9 -141
  72. package/package.json +1 -1
  73. package/dist/@types/config/defaults.js +0 -44
  74. package/dist/@types/config/schemas.js +0 -229
  75. package/dist/@types/config/validator.js +0 -56
  76. package/dist/src/@types/config/defaults.d.ts +0 -68
  77. package/dist/src/@types/config/index.d.ts +0 -14
  78. package/dist/src/@types/config/schemas.d.ts +0 -505
  79. package/dist/src/@types/config/types.d.ts +0 -142
  80. package/dist/src/@types/config/validator.d.ts +0 -119
package/README.md CHANGED
@@ -4,420 +4,789 @@
4
4
  </a>
5
5
  </p>
6
6
 
7
+
7
8
  # @useinsider/guido
8
9
 
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.
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.
10
11
 
11
- ## Installation
12
+ ## 📦 Install
12
13
 
13
14
  ```bash
14
15
  npm install @useinsider/guido
15
16
  ```
16
-
17
17
  ### Prerequisites
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
-
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
+ ```
40
43
  ---
44
+ ## 🚀 Usage
41
45
 
42
- ## Quick Start
46
+ ### Basic Usage
43
47
 
44
- ```vue
48
+ ```html
45
49
  <template>
46
- <Guido
47
- ref="guidoRef"
48
- :config="config"
49
- @ready="onReady"
50
- @dynamic-content:open="onDynamicContentOpen"
51
- @save:complete="onSaveComplete"
52
- />
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>
53
65
  </template>
54
66
 
55
- <script setup lang="ts">
56
- import { ref } from 'vue';
67
+ <script lang="ts">
57
68
  import { Guido } from '@useinsider/guido';
58
- import type { GuidoConfigInput } from '@useinsider/guido';
59
-
60
- const guidoRef = ref<InstanceType<typeof Guido> | null>(null);
61
69
 
62
- const config = ref<GuidoConfigInput>({
63
- identity: {
64
- templateId: 'template-123',
65
- userId: 'user-456',
66
- },
67
- partner: {
68
- name: 'your-partner-name',
70
+ export default {
71
+ components: {
72
+ Guido
69
73
  },
70
- template: {
71
- html: '<p>Initial content</p>',
72
- css: '',
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
+ };
73
95
  },
74
- });
75
96
 
76
- const onReady = () => console.log('Editor ready');
77
- const onDynamicContentOpen = () => console.log('Dynamic content requested');
78
- const onSaveComplete = (template) => console.log('Saved:', template);
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
+ };
79
140
  </script>
80
141
  ```
81
142
 
82
- ---
83
-
84
- ## Configuration
85
-
86
- Guido uses a single, validated `config` prop organized by domain:
87
-
88
- ```typescript
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
- },
143
+ ## 📚 API
98
144
 
99
- // Required: Partner
100
- partner: {
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
- },
145
+ ### Guido Component Props
106
146
 
107
- // Optional: Template content
108
- template?: {
109
- html?: string,
110
- css?: string,
111
- preselectedDynamicContent?: DynamicContent[],
112
- selectedUnsubscribePages?: number[],
113
- },
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 |
114
158
 
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
- },
159
+ ### Guido Component Events
125
160
 
126
- // Optional: UI settings
127
- ui?: {
128
- showHeader?: boolean, // Default: true
129
- backButtonLabel?: string,
130
- },
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
+ ```typescript
174
+ dynamicContent.insert(DynamicContent);
175
+ dynamicContent.close();
176
+ saveSilent();
177
+ ```
131
178
 
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
- },
179
+ ### Guido Interfaces
141
180
 
142
- // Optional: Block configuration
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
+ };
191
+ 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
+ };
143
203
  blocks?: {
144
- excludeDefaults?: DefaultBlockType[],
145
- includeCustoms?: CustomBlockType[],
146
- },
147
-
148
- // Optional: HTML compiler
149
- compiler?: {
150
- customRules?: CompilerRule[],
151
- ignoreDefaultRules?: boolean, // Default: false
152
- },
153
- };
204
+ excludeDefaults?: GuidoBlockType[];
205
+ includeCustoms?: GuidoCustomBlockType[];
206
+ };
207
+ }
154
208
  ```
155
209
 
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 |
224
+
225
+ ```typescript
226
+ interface DynamicContent {
227
+ value: string;
228
+ text: string;
229
+ fallback?: string;
230
+ }
231
+ ```
156
232
  ---
157
233
 
158
- ## Events
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 |
159
239
 
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 |
240
+ ## 🧱 Blocks Configuration
170
241
 
171
- ---
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.
243
+
244
+ ### Block Types
245
+
246
+ #### Default Blocks (GuidoBlockType)
172
247
 
173
- ## Exposed Methods
248
+ These are the standard Stripo email editor blocks that can be excluded:
174
249
 
175
250
  ```typescript
176
- const guidoRef = ref<InstanceType<typeof Guido> | null>(null);
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
+ ```
177
266
 
178
- // Insert dynamic content
179
- guidoRef.value?.dynamicContent.insert({
180
- text: 'Display Name',
181
- value: 'variable_name',
182
- fallback: 'Default Value',
183
- });
267
+ #### Custom Blocks (GuidoCustomBlockType)
184
268
 
185
- // Close dynamic content modal
186
- guidoRef.value?.dynamicContent.close();
269
+ These are custom blocks that can be selectively included:
187
270
 
188
- // Silent save (no UI feedback)
189
- guidoRef.value?.saveSilent();
271
+ ```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
190
280
  ```
191
281
 
192
- ---
282
+ ### Configuration Examples
193
283
 
194
- ## Block Configuration
284
+ #### Example 1: Exclude Specific Default Blocks
195
285
 
196
- ### Default Blocks (can be excluded)
286
+ Disable button, image, and video blocks while keeping all custom blocks:
197
287
 
198
288
  ```typescript
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)
216
-
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';
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
+ };
226
301
  ```
227
302
 
228
- ### Examples
303
+ **Result:**
304
+ - Button, Image, Video blocks disabled
305
+ - All other default blocks enabled
306
+ - All custom blocks are disabled.
307
+
308
+ #### Example 2: Include Only Specific Custom Blocks
309
+
310
+ Enable only coupon and recommendation blocks:
229
311
 
230
312
  ```typescript
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'],
313
+ const guidoConfig = {
314
+ translationsPath: 'window.trans.en',
315
+ features: {
316
+ dynamicContent: true,
317
+ saveAsTemplate: true,
318
+ versionHistory: true,
319
+ testMessage: true
237
320
  },
238
- };
239
-
240
- // Include custom blocks
241
- const config: GuidoConfigInput = {
242
- identity: { templateId: 'tpl-123', userId: 'user-456' },
243
- partner: { name: 'partner' },
244
321
  blocks: {
245
- includeCustoms: ['recommendation-block', 'coupon-block', 'dynamic-content'],
246
- },
322
+ includeCustoms: ['coupon-block', 'recommendation-block']
323
+ }
247
324
  };
248
325
  ```
249
326
 
250
- ---
327
+ **Result:**
328
+ - All default blocks enabled
329
+ - Only Coupon and Recommendation extensions enabled.
330
+ - Other custom blocks are disabled
251
331
 
252
- ## HTML Compiler Rules
332
+ ### Default Behavior
253
333
 
254
- Add custom rules to transform HTML during export:
334
+ When `blocks` is not provided or is `undefined`:
255
335
 
256
336
  ```typescript
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
337
+ const guidoConfig = {
338
+ translationsPath: 'window.trans.en',
339
+ features: {
340
+ dynamicContent: true,
341
+ saveAsTemplate: true,
342
+ versionHistory: true,
343
+ testMessage: true
288
344
  },
345
+ // No blocks config
289
346
  };
290
347
  ```
291
348
 
292
- ---
349
+ **Result:**
350
+ - All 13 default Stripo blocks enabled
351
+ - All custom blocks are disabled.
352
+
353
+ ### Block Configuration Interface
293
354
 
294
- ## TypeScript Exports
355
+ ```typescript
356
+ interface BlocksConfig {
357
+ excludeDefaults?: GuidoBlockType[];
358
+ includeCustoms?: GuidoCustomBlockType[];
359
+ }
360
+ ```
361
+
362
+ ### TypeScript Types
363
+
364
+ The library exports the following TypeScript types:
295
365
 
296
366
  ```typescript
297
- // Component
367
+ // Main component
298
368
  import { Guido } from '@useinsider/guido';
299
369
 
300
370
  // Types
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';
371
+ import type { GuidoConfig } from '@useinsider/guido';
372
+ import type { StripoEventType } from '@useinsider/guido';
327
373
  ```
328
374
 
329
- ---
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.
330
378
 
331
- ## Constants
379
+ ### Rule Types
380
+
381
+ There are 4 types of compiler rules:
382
+
383
+ #### 1. Replace Rule
384
+ Replace specific strings in HTML content.
332
385
 
333
386
  ```typescript
334
- import { MessageType, ProductType } from '@useinsider/guido';
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
+ ```
335
397
 
336
- MessageType.PROMOTIONAL // 1
337
- MessageType.TRANSACTIONAL // 2
398
+ #### 2. Regex Rule
399
+ Use regular expressions for complex pattern matching and replacement.
338
400
 
339
- ProductType.EMAIL // 60
340
- ProductType.ARCHITECT // 49
341
- ProductType.UNSUBSCRIBE_PAGES // 97
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
+ }
342
411
  ```
343
412
 
344
- ---
413
+ #### 3. Remove Rule
414
+ Remove specific strings or patterns from HTML content.
345
415
 
346
- ## Dynamic Content Modal
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
+ ```
347
428
 
348
- When the `dynamic-content:open` event fires, show your custom modal and call the insert method:
429
+ #### 4. Custom Rule
430
+ Define complex transformation logic with a custom processor function.
349
431
 
350
- ```vue
351
- <template>
352
- <Guido ref="guidoRef" :config="config" @dynamic-content:open="showModal = true" />
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
+ ```
353
445
 
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>
446
+ ### Using HTML Compiler Rules
357
447
 
358
- <script setup>
359
- const showModal = ref(false);
448
+ #### Basic Usage with Custom Rules
360
449
 
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;
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
+ ]
368
479
  };
480
+ ```
481
+
482
+ #### Ignoring Default Rules
369
483
 
370
- const closeModal = () => {
371
- guidoRef.value?.dynamicContent.close();
372
- showModal.value = false;
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
+ ]
373
504
  };
374
- </script>
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;
375
564
  ```
376
565
 
377
566
  ---
378
567
 
379
- ## Development
568
+ ## 🔧 Development
569
+
570
+ ### Prerequisites
571
+
572
+ - 🧄 `Bun` (strongly recommended)
573
+ or
574
+ - NodeJS 18+ & `npm`
575
+
576
+ ### Setup
380
577
 
381
578
  ```bash
382
- # Install
579
+ # Install dependencies
383
580
  bun install
384
581
 
385
- # Start dev server
582
+ # Start development server
386
583
  bun start
387
584
 
388
- # Build
585
+ # Build for production
389
586
  bun run build
390
587
 
391
- # Lint & type-check
588
+ # Type checking
589
+ bun run type-check
590
+
591
+ # Linting
392
592
  bun run lint
393
593
  ```
394
594
 
395
595
  ### Environment Variables
396
596
 
597
+ Create a `.env` file with the following variables: (You can get env variables from your senior)
598
+
397
599
  ```env
398
600
  VITE_STRIPO_PLUGIN_ID=your_plugin_id
399
601
  VITE_STRIPO_SECRET_KEY=your_secret_key
400
602
  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
401
606
  ```
402
607
 
403
- ---
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
+ ```
404
624
 
405
- ## Local Testing
625
+ ## 🔌 Provide/Inject Utilities
406
626
 
407
- ```bash
408
- # Build the package
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
+ ```
660
+
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
+ ```
718
+
719
+ ## 📦 Local Building (Recommended)
720
+
721
+ Run this commands if you want to test the package on your local before sending to NPM.
722
+ ```sh
409
723
  bun run build
724
+ ```
410
725
 
411
- # Create tarball
726
+ Since bun does not have packaging yet, use npm here: 🥲
727
+ ```sh
412
728
  npm pack
729
+ ```
730
+
731
+ It'll crate like `useinsider-guido-1.0.0.tgz` file.
413
732
 
414
- # Install in your project
415
- cd ../your-project
416
- npm install ../guido/useinsider-guido-1.0.0.tgz
733
+ Move this file to your project path like: `email-fe` via:
734
+ ```sh
735
+ cp useinsider-guido-1.0.0.tgz ../email-fe
417
736
  ```
418
737
 
419
- ---
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:
420
750
 
421
- ## License
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
422
777
 
423
778
  ISC License
779
+
780
+ ---
781
+
782
+ ## 🔗 Related
783
+
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