@vc-shell/framework 1.1.82 → 1.1.83

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 (38) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/core/api/virtocommerce.platform.ts +10457 -0
  3. package/core/plugins/extension-points/ExtensionSlot.vue +23 -0
  4. package/core/plugins/extension-points/README.md +406 -0
  5. package/core/plugins/extension-points/index.ts +8 -0
  6. package/core/plugins/extension-points/migration-examples.md +613 -0
  7. package/core/plugins/extension-points/simple-extensions.ts +148 -0
  8. package/core/plugins/index.ts +1 -0
  9. package/core/plugins/modularity/loader.ts +2 -2
  10. package/dist/core/api/virtocommerce.platform.d.ts +2442 -0
  11. package/dist/core/api/virtocommerce.platform.d.ts.map +1 -0
  12. package/dist/core/plugins/extension-points/ExtensionSlot.vue.d.ts +6 -0
  13. package/dist/core/plugins/extension-points/ExtensionSlot.vue.d.ts.map +1 -0
  14. package/dist/core/plugins/extension-points/index.d.ts +3 -0
  15. package/dist/core/plugins/extension-points/index.d.ts.map +1 -0
  16. package/dist/core/plugins/extension-points/simple-extensions.d.ts +29 -0
  17. package/dist/core/plugins/extension-points/simple-extensions.d.ts.map +1 -0
  18. package/dist/core/plugins/index.d.ts +1 -0
  19. package/dist/core/plugins/index.d.ts.map +1 -1
  20. package/dist/framework.js +5104 -5031
  21. package/dist/locales/de.json +1 -0
  22. package/dist/locales/en.json +1 -0
  23. package/dist/shared/components/notification-template/notification-template.vue.d.ts +8 -1
  24. package/dist/shared/components/notification-template/notification-template.vue.d.ts.map +1 -1
  25. package/dist/shared/composables/useModificationTracker/index.d.ts +5 -0
  26. package/dist/shared/composables/useModificationTracker/index.d.ts.map +1 -1
  27. package/dist/shared/pages/LoginPage/components/login/Login.vue.d.ts.map +1 -1
  28. package/dist/tsconfig.tsbuildinfo +1 -1
  29. package/dist/ui/components/molecules/vc-form/vc-form.vue.d.ts +5 -1
  30. package/dist/ui/components/molecules/vc-form/vc-form.vue.d.ts.map +1 -1
  31. package/dist/ui/components/molecules/vc-select/vc-select.vue.d.ts +10 -5
  32. package/dist/ui/components/molecules/vc-select/vc-select.vue.d.ts.map +1 -1
  33. package/package.json +4 -4
  34. package/shared/components/notification-template/notification-template.vue +5 -1
  35. package/shared/composables/useModificationTracker/index.ts +6 -0
  36. package/shared/pages/LoginPage/components/login/Login.vue +30 -34
  37. package/ui/components/molecules/vc-form/vc-form.vue +11 -3
  38. package/ui/components/molecules/vc-select/vc-select.vue +1 -2
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <template
3
+ v-for="extension in components"
4
+ :key="extension.id"
5
+ >
6
+ <component
7
+ :is="extension.component"
8
+ v-bind="extension.props || {}"
9
+ />
10
+ </template>
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ import { useExtensionSlot } from './simple-extensions';
15
+
16
+ interface Props {
17
+ name: string;
18
+ }
19
+
20
+ const props = defineProps<Props>();
21
+
22
+ const { components } = useExtensionSlot(props.name);
23
+ </script>
@@ -0,0 +1,406 @@
1
+ # 🔌 Extension Points System
2
+
3
+ A simple and powerful extension system for VirtoCommerce Shell, built on Vue 3 composables.
4
+
5
+ ## 📋 Table of Contents
6
+
7
+ - [Quick Start](#-quick-start)
8
+ - [API Documentation](#-api-documentation)
9
+ - [Migration from Current System](#-migration-from-current-system)
10
+ - [Usage Examples](#-usage-examples)
11
+ - [Best Practices](#-best-practices)
12
+
13
+ ## 🚀 Quick Start
14
+
15
+ ### 1. Adding a slot to your component
16
+
17
+ ```vue
18
+ <template>
19
+ <div>
20
+ <!-- Your content -->
21
+ <h1>Page Title</h1>
22
+
23
+ <!-- Extension point -->
24
+ <ExtensionSlot name="page-after-title" />
25
+
26
+ <!-- Rest of content -->
27
+ </div>
28
+ </template>
29
+
30
+ <script setup lang="ts">
31
+ import { ExtensionSlot } from '@vc-shell/framework/core/plugins/extension-points';
32
+ </script>
33
+ ```
34
+
35
+ ### 2. Registering a component in a slot
36
+
37
+ ```typescript
38
+ // In any module
39
+ import { useExtensionSlot } from '@vc-shell/framework/core/plugins/extension-points';
40
+ import MyComponent from './MyComponent.vue';
41
+
42
+ const { addComponent } = useExtensionSlot('page-after-title');
43
+
44
+ addComponent({
45
+ id: 'my-custom-component',
46
+ component: MyComponent,
47
+ props: { message: 'Hello from extension!' },
48
+ priority: 10,
49
+ });
50
+ ```
51
+
52
+ ### 3. Data exchange between modules
53
+
54
+ ```typescript
55
+ // Data provider module
56
+ import { useExtensionData } from '@vc-shell/framework/core/plugins/extension-points';
57
+
58
+ const { updateData } = useExtensionData('user-profile');
59
+ updateData({ userId: '123', userName: 'John Doe' });
60
+
61
+ // Data consumer module
62
+ const { data } = useExtensionData('user-profile');
63
+ console.log(data.value.userName); // 'John Doe'
64
+ ```
65
+
66
+ ## 📚 API Documentation
67
+
68
+ ### useExtensionSlot(slotName: string)
69
+
70
+ Composable for working with extension slots.
71
+
72
+ ```typescript
73
+ const {
74
+ components, // computed<ExtensionComponent[]> - list of components
75
+ addComponent, // (component: ExtensionComponent) => void
76
+ removeComponent, // (componentId: string) => void
77
+ hasComponents, // computed<boolean> - whether slot has components
78
+ } = useExtensionSlot('slot-name');
79
+ ```
80
+
81
+ #### ExtensionComponent interface:
82
+ ```typescript
83
+ interface ExtensionComponent {
84
+ id: string; // unique component ID
85
+ component: Component; // Vue component
86
+ props?: Record<string, unknown>; // props for component
87
+ priority?: number; // priority (lower = higher)
88
+ }
89
+ ```
90
+
91
+ ### useExtensionData(namespace: string)
92
+
93
+ Composable for data exchange between modules.
94
+
95
+ ```typescript
96
+ const {
97
+ data, // computed<Record<string, any>> - reactive data
98
+ updateData, // (newData: Record<string, any>) => void - merge data
99
+ setData, // (newData: Record<string, any>) => void - replace data
100
+ getValue, // (key: string, defaultValue?: any) => any
101
+ setValue, // (key: string, value: any) => void
102
+ } = useExtensionData('namespace');
103
+ ```
104
+
105
+ ### useExtensions()
106
+
107
+ Composable for global extension system management.
108
+
109
+ ```typescript
110
+ const {
111
+ getAllSlots, // () => string[] - all slots
112
+ getSlotComponents, // (slotName: string) => ExtensionComponent[]
113
+ getAllData, // () => Record<string, any> - all data
114
+ getNamespaceData, // (namespace: string) => Record<string, any>
115
+ clearSlot, // (slotName: string) => void
116
+ clearData, // (namespace: string) => void
117
+ } = useExtensions();
118
+ ```
119
+
120
+ ## 🔄 Migration from Current System
121
+
122
+ ### Before (current system):
123
+
124
+ ```typescript
125
+ // registration-module/index.ts - old system
126
+ export default {
127
+ install(app: App) {
128
+ // Complex setup...
129
+ },
130
+ extensions: {
131
+ inbound: {
132
+ "registration-form": useRegistrationForm(),
133
+ },
134
+ outbound: {
135
+ "login-after-form": [{ id: "RegistrationButton", component: RegistrationButton }],
136
+ },
137
+ },
138
+ };
139
+ ```
140
+
141
+ ```vue
142
+ <!-- Login.vue - old system -->
143
+ <template>
144
+ <!-- Extensions after form -->
145
+ <template
146
+ v-for="extension in afterLoginFormExtensions"
147
+ :key="extension.id"
148
+ >
149
+ <div class="vc-login-page__extension">
150
+ <component :is="extension.component" />
151
+ </div>
152
+ </template>
153
+ </template>
154
+
155
+ <script setup>
156
+ import { inject } from "vue";
157
+ import { extensionsHelperSymbol } from "../extensions-helper";
158
+
159
+ const extensionsHelper = inject(extensionsHelperSymbol);
160
+ const afterLoginFormExtensions = computed(
161
+ (): ExtensionPoint[] =>
162
+ (extensionsHelper?.getOutboundExtensions("login-after-form") as ExtensionPoint[]) || []
163
+ );
164
+ </script>
165
+ ```
166
+
167
+ ### After (new system):
168
+
169
+ ```typescript
170
+ // registration-module/index.ts - new system
171
+ import { useExtensionSlot } from '@vc-shell/framework/core/plugins/extension-points';
172
+ import RegistrationButton from './RegistrationButton.vue';
173
+
174
+ export default {
175
+ install() {
176
+ const { addComponent } = useExtensionSlot('login-after-form');
177
+
178
+ addComponent({
179
+ id: 'registration-button',
180
+ component: RegistrationButton,
181
+ priority: 10,
182
+ });
183
+ }
184
+ };
185
+ ```
186
+
187
+ ```vue
188
+ <!-- Login.vue - new system -->
189
+ <template>
190
+ <!-- One simple component instead of complex logic -->
191
+ <ExtensionSlot name="login-after-form" />
192
+ </template>
193
+
194
+ <script setup>
195
+ import { ExtensionSlot } from '@vc-shell/framework/core/plugins/extension-points';
196
+ </script>
197
+ ```
198
+
199
+ ## 📖 Detailed Registration Migration Example
200
+
201
+ ### Step 1: Update Login.vue
202
+
203
+ ```vue
204
+ <!-- framework/shared/pages/LoginPage/components/login/Login.vue -->
205
+ <template>
206
+ <VcLoginForm>
207
+ <template v-if="isLogin">
208
+ <VcForm @submit.prevent="login">
209
+ <!-- Existing form fields -->
210
+ <Field v-slot="{ errorMessage, handleChange, errors }" ...>
211
+ <VcInput ... />
212
+ </Field>
213
+ <!-- ... other fields ... -->
214
+ </VcForm>
215
+
216
+ <!-- External providers -->
217
+ <div v-if="loginProviders && loginProviders.length" ...>
218
+ <ExternalProviders :providers="loginProviders" />
219
+ </div>
220
+
221
+ <!-- 🎯 REPLACE complex system with simple slot -->
222
+ <ExtensionSlot name="login-after-form" />
223
+ </template>
224
+ </VcLoginForm>
225
+ </template>
226
+
227
+ <script setup lang="ts">
228
+ // Remove:
229
+ // import { extensionsHelperSymbol } from "../extensions-helper";
230
+ // const extensionsHelper = inject(extensionsHelperSymbol);
231
+ // const afterLoginFormExtensions = computed(...);
232
+
233
+ // Add:
234
+ import { ExtensionSlot } from '@vc-shell/framework/core/plugins/extension-points';
235
+
236
+ // Rest of the code remains unchanged
237
+ const { signIn, loading, user } = useUserManagement();
238
+ // ...
239
+ </script>
240
+ ```
241
+
242
+ ### Step 2: Simplify Registration Module
243
+
244
+ ```typescript
245
+ // vc-module-marketplace-registration/src/.../registration/index.ts
246
+
247
+ // Before: Complex extensions object
248
+ export default {
249
+ extensions: {
250
+ inbound: {
251
+ "registration-form": useRegistrationForm(),
252
+ },
253
+ outbound: {
254
+ "login-after-form": [{ id: "RegistrationButton", component: RegistrationButton }],
255
+ },
256
+ },
257
+ };
258
+
259
+ // After: Simple composable calls
260
+ import { useExtensionSlot, useExtensionData } from '@vc-shell/framework/core/plugins/extension-points';
261
+ import RegistrationButton from './components/RegistrationButton.vue';
262
+
263
+ export default {
264
+ install() {
265
+ // 🎯 NEW: Simple component registration
266
+ const { addComponent } = useExtensionSlot('login-after-form');
267
+
268
+ addComponent({
269
+ id: 'registration-button',
270
+ component: RegistrationButton,
271
+ props: {
272
+ text: 'Register',
273
+ },
274
+ priority: 10,
275
+ });
276
+
277
+ // Provide registration form data
278
+ const { updateData } = useExtensionData('registration-form');
279
+ updateData({
280
+ fields: [
281
+ {
282
+ name: 'firstName',
283
+ type: 'text',
284
+ component: 'VcInput',
285
+ label: 'VCMP_VENDOR_REGISTRATION.LABELS.FIRST_NAME',
286
+ required: true,
287
+ priority: 10,
288
+ },
289
+ // ... other fields
290
+ ],
291
+ });
292
+ },
293
+ };
294
+ ```
295
+
296
+ ## 💡 Usage Examples
297
+
298
+ ### Application-level Customization
299
+
300
+ ```typescript
301
+ // main.ts or any app module file
302
+ import { useExtensionSlot, useExtensionData } from '@vc-shell/framework/core/plugins/extension-points';
303
+ import CustomButton from './components/CustomButton.vue';
304
+
305
+ // Replace registration button with custom one
306
+ const { addComponent } = useExtensionSlot('login-after-form');
307
+ addComponent({
308
+ id: 'registration-button', // same ID - will replace existing
309
+ component: CustomButton,
310
+ props: {
311
+ text: 'Create Account',
312
+ variant: 'primary',
313
+ showIcon: true,
314
+ },
315
+ priority: 10,
316
+ });
317
+
318
+ // Add custom fields to registration form
319
+ const { data } = useExtensionData('registration-form');
320
+ const { extendForm } = useRegistrationForm();
321
+
322
+ extendForm([
323
+ {
324
+ name: 'companyTaxId',
325
+ type: 'text',
326
+ component: 'VcInput',
327
+ label: 'Company Tax ID',
328
+ required: true,
329
+ priority: 25, // between lastName (20) and organizationName (30)
330
+ }
331
+ ]);
332
+ ```
333
+
334
+ ### Adding Slots to Blades
335
+
336
+ ```vue
337
+ <!-- seller-details-edit.vue -->
338
+ <template>
339
+ <VcBlade>
340
+ <VcContainer>
341
+ <!-- Main cards -->
342
+ <VcRow>
343
+ <VcCol><!-- Info card --></VcCol>
344
+ <VcCol><!-- Address card --></VcCol>
345
+
346
+ <!-- 🎯 Slot for additional cards -->
347
+ <ExtensionSlot name="seller-details-additional-cards" />
348
+ </VcRow>
349
+
350
+ <!-- 🎯 Slot for additional sections -->
351
+ <ExtensionSlot name="seller-details-sections" />
352
+ </VcContainer>
353
+ </VcBlade>
354
+ </template>
355
+ ```
356
+
357
+ ## ✅ Best Practices
358
+
359
+ ### 1. Slot Naming
360
+ - Use kebab-case: `seller-details-cards`
361
+ - Include context: `login-after-form`, `profile-before-save`
362
+ - Be descriptive: `product-listing-filters`
363
+
364
+ ### 2. Priorities
365
+ - Use multiples of 10: 10, 20, 30, ...
366
+ - Leave room for insertions: between 10 and 30 you can insert 20
367
+ - Document priorities in comments
368
+
369
+ ### 3. Component IDs
370
+ - Use unique IDs: `module-name-component-purpose`
371
+ - Avoid generic names: `button`, `form`
372
+ - Use for replacement: same ID = component replacement
373
+
374
+ ### 4. Data Namespaces
375
+ - Group by functionality: `user-profile`, `order-details`
376
+ - Avoid conflicts: use module prefixes
377
+ - Document data structure
378
+
379
+ ### 5. Performance
380
+ - Components are lazy-loaded by default
381
+ - Don't overuse number of slots
382
+ - Use `v-if` with `hasComponents` for conditional rendering
383
+
384
+ ```vue
385
+ <template>
386
+ <div v-if="hasComponents" class="extensions-section">
387
+ <ExtensionSlot name="optional-content" />
388
+ </div>
389
+ </template>
390
+
391
+ <script setup>
392
+ const { hasComponents } = useExtensionSlot('optional-content');
393
+ </script>
394
+ ```
395
+
396
+ ## 🎯 Conclusion
397
+
398
+ The new extension system provides:
399
+
400
+ - ✅ **Simplicity** - 3 main functions instead of complex hierarchy
401
+ - ✅ **Flexibility** - easy component replacement and extension
402
+ - ✅ **Performance** - minimal overhead, Vue 3 optimizations
403
+ - ✅ **TypeScript** - full type safety
404
+ - ✅ **Backward compatibility** - doesn't break existing code
405
+
406
+ The system is ready to use and allows easy migration of existing extensions!
@@ -0,0 +1,8 @@
1
+ export {
2
+ useExtensionSlot,
3
+ useExtensionData,
4
+ useExtensions,
5
+ type ExtensionComponent,
6
+ } from './simple-extensions';
7
+
8
+ export { default as ExtensionSlot } from './ExtensionSlot.vue';