@vc-shell/vc-app-skill 2.1.0 → 2.2.0-pr260.a8bd3a7

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 (141) hide show
  1. package/package.json +1 -1
  2. package/runtime/VERSION +1 -1
  3. package/runtime/agents/migration-agent.md +4 -2
  4. package/runtime/knowledge/docs/_BUILD_HASH.md +1 -1
  5. package/runtime/knowledge/docs/core/api/platform.docs.md +20 -18
  6. package/runtime/knowledge/docs/core/blade-navigation/blade-nav-composables.docs.md +43 -34
  7. package/runtime/knowledge/docs/core/composables/useAppBarMobileButtons/useAppBarMobileButtons.docs.md +5 -3
  8. package/runtime/knowledge/docs/core/composables/useAppBarWidget/useAppBarWidget.docs.md +12 -10
  9. package/runtime/knowledge/docs/core/composables/useAppInsights/useAppInsights.docs.md +7 -5
  10. package/runtime/knowledge/docs/core/composables/useAssets/useAssets.docs.md +8 -6
  11. package/runtime/knowledge/docs/core/composables/useAssetsManager/useAssetsManager.docs.md +3 -1
  12. package/runtime/knowledge/docs/core/composables/useAsync/useAsync.docs.md +1 -1
  13. package/runtime/knowledge/docs/core/composables/useBladeRegistry/useBladeRegistry.docs.md +8 -5
  14. package/runtime/knowledge/docs/core/composables/useBladeWidgets/index.docs.md +12 -12
  15. package/runtime/knowledge/docs/core/composables/useBreadcrumbs/useBreadcrumbs.docs.md +3 -3
  16. package/runtime/knowledge/docs/core/composables/useConnectionStatus/useConnectionStatus.docs.md +4 -3
  17. package/runtime/knowledge/docs/core/composables/useDynamicProperties/useDynamicProperties.docs.md +1 -0
  18. package/runtime/knowledge/docs/core/composables/useFunctions/useFunctions.docs.md +3 -3
  19. package/runtime/knowledge/docs/core/composables/useKeyboardNavigation/useKeyboardNavigation.docs.md +5 -4
  20. package/runtime/knowledge/docs/core/composables/useLanguages/useLanguages.docs.md +3 -3
  21. package/runtime/knowledge/docs/core/composables/useLoading/useLoading.docs.md +2 -0
  22. package/runtime/knowledge/docs/core/composables/useModificationTracker/useModificationTracker.docs.md +1 -2
  23. package/runtime/knowledge/docs/core/composables/useNotifications/useNotifications.docs.md +1 -1
  24. package/runtime/knowledge/docs/core/composables/usePermissions/usePermissions.docs.md +3 -3
  25. package/runtime/knowledge/docs/core/composables/usePlatformLocaleSync/usePlatformLocaleSync.docs.md +1 -0
  26. package/runtime/knowledge/docs/core/composables/usePopup/usePopup.docs.md +1 -1
  27. package/runtime/knowledge/docs/core/composables/useResponsive/useResponsive.docs.md +2 -2
  28. package/runtime/knowledge/docs/core/composables/useSettings/useSettings.docs.md +2 -1
  29. package/runtime/knowledge/docs/core/composables/useSettingsMenu/useSettingsMenu.docs.md +18 -18
  30. package/runtime/knowledge/docs/core/composables/useSidebarState/useSidebarState.docs.md +3 -3
  31. package/runtime/knowledge/docs/core/composables/useSlowNetworkDetection/useSlowNetworkDetection.docs.md +10 -7
  32. package/runtime/knowledge/docs/core/composables/useTheme/useTheme.docs.md +7 -7
  33. package/runtime/knowledge/docs/core/composables/useToolbar/useToolbar.docs.md +18 -12
  34. package/runtime/knowledge/docs/core/composables/useUser/useUser.docs.md +2 -2
  35. package/runtime/knowledge/docs/core/composables/useUserManagement/useUserManagement.docs.md +20 -20
  36. package/runtime/knowledge/docs/core/composables/useWidgets/useWidgets.docs.md +15 -24
  37. package/runtime/knowledge/docs/core/directives/loading/loading.docs.md +2 -2
  38. package/runtime/knowledge/docs/core/notifications/composables/useBladeNotifications.docs.md +1 -2
  39. package/runtime/knowledge/docs/core/notifications/composables/useBroadcastFilter.docs.md +3 -3
  40. package/runtime/knowledge/docs/core/notifications/composables/useNotificationStore.docs.md +19 -18
  41. package/runtime/knowledge/docs/core/notifications/notifications.docs.md +50 -30
  42. package/runtime/knowledge/docs/core/plugins/ai-agent/ai-agent.docs.md +30 -11
  43. package/runtime/knowledge/docs/core/plugins/extension-points/extension-points.docs.md +1 -1
  44. package/runtime/knowledge/docs/core/plugins/global-error-handler/global-error-handler.docs.md +2 -3
  45. package/runtime/knowledge/docs/core/plugins/modularity/modularity.docs.md +26 -26
  46. package/runtime/knowledge/docs/core/plugins/permissions/permissions.docs.md +2 -3
  47. package/runtime/knowledge/docs/core/plugins/signalR/signalR.docs.md +11 -50
  48. package/runtime/knowledge/docs/core/plugins/validation/validation.docs.md +9 -6
  49. package/runtime/knowledge/docs/core/services/services.docs.md +15 -13
  50. package/runtime/knowledge/docs/core/types/types.docs.md +37 -40
  51. package/runtime/knowledge/docs/core/utilities/date/date-utilities.docs.md +1 -2
  52. package/runtime/knowledge/docs/core/utilities/shared-utilities.docs.md +21 -30
  53. package/runtime/knowledge/docs/core/utilities/thumbnail/thumbnail.docs.md +2 -2
  54. package/runtime/knowledge/docs/core/utilities/utilities.docs.md +9 -8
  55. package/runtime/knowledge/docs/injection-keys.docs.md +6 -11
  56. package/runtime/knowledge/docs/modules/assets/assets-details.docs.md +7 -7
  57. package/runtime/knowledge/docs/modules/assets-manager/assets-manager.docs.md +1 -1
  58. package/runtime/knowledge/docs/shell/_internal/popup/common/popup-common.docs.md +20 -12
  59. package/runtime/knowledge/docs/shell/auth/ChangePasswordPage/change-password-page.docs.md +10 -10
  60. package/runtime/knowledge/docs/shell/auth/ForgotPasswordPage/forgot-password-page.docs.md +6 -6
  61. package/runtime/knowledge/docs/shell/auth/InvitePage/invite-page.docs.md +4 -4
  62. package/runtime/knowledge/docs/shell/auth/LoginPage/login-page.docs.md +16 -14
  63. package/runtime/knowledge/docs/shell/auth/ResetPasswordPage/reset-password-page.docs.md +1 -1
  64. package/runtime/knowledge/docs/shell/auth/sign-in/sign-in.docs.md +12 -11
  65. package/runtime/knowledge/docs/shell/components/change-password/change-password.docs.md +10 -3
  66. package/runtime/knowledge/docs/shell/components/change-password-button/change-password-button.docs.md +3 -3
  67. package/runtime/knowledge/docs/shell/components/error-interceptor/error-interceptor.docs.md +9 -2
  68. package/runtime/knowledge/docs/shell/components/language-selector/language-selector.docs.md +4 -2
  69. package/runtime/knowledge/docs/shell/components/logout-button/logout-button.docs.md +1 -1
  70. package/runtime/knowledge/docs/shell/components/notification-dropdown/notification-dropdown.docs.md +35 -31
  71. package/runtime/knowledge/docs/shell/components/notification-template/notification-template.docs.md +17 -11
  72. package/runtime/knowledge/docs/shell/components/settings-menu/settings-menu.docs.md +8 -7
  73. package/runtime/knowledge/docs/shell/components/settings-menu-item/settings-menu-item.docs.md +23 -21
  74. package/runtime/knowledge/docs/shell/components/sidebar/sidebar.docs.md +5 -3
  75. package/runtime/knowledge/docs/shell/components/theme-selector/theme-selector.docs.md +7 -7
  76. package/runtime/knowledge/docs/shell/components/user-dropdown-button/user-dropdown-button.docs.md +11 -11
  77. package/runtime/knowledge/docs/shell/dashboard/dashboard-charts/dashboard-charts.docs.md +28 -16
  78. package/runtime/knowledge/docs/shell/dashboard/dashboard-widget-card/dashboard-widget-card.docs.md +17 -19
  79. package/runtime/knowledge/docs/shell/dashboard/draggable-dashboard/draggable-dashboard.docs.md +21 -0
  80. package/runtime/knowledge/docs/ui/components/atoms/vc-badge/vc-badge.docs.md +2 -1
  81. package/runtime/knowledge/docs/ui/components/atoms/vc-banner/vc-banner.docs.md +2 -2
  82. package/runtime/knowledge/docs/ui/components/atoms/vc-button/vc-button.docs.md +15 -14
  83. package/runtime/knowledge/docs/ui/components/atoms/vc-container/vc-container.docs.md +9 -6
  84. package/runtime/knowledge/docs/ui/components/atoms/vc-environment-banner/vc-environment-banner.docs.md +42 -0
  85. package/runtime/knowledge/docs/ui/components/atoms/vc-hint/vc-hint.docs.md +1 -1
  86. package/runtime/knowledge/docs/ui/components/atoms/vc-icon/vc-icon.docs.md +10 -9
  87. package/runtime/knowledge/docs/ui/components/atoms/vc-image/vc-image.docs.md +19 -4
  88. package/runtime/knowledge/docs/ui/components/atoms/vc-label/vc-label.docs.md +2 -2
  89. package/runtime/knowledge/docs/ui/components/atoms/vc-link/vc-link.docs.md +5 -4
  90. package/runtime/knowledge/docs/ui/components/atoms/vc-loading/vc-loading.docs.md +5 -4
  91. package/runtime/knowledge/docs/ui/components/atoms/vc-progress/vc-progress.docs.md +9 -8
  92. package/runtime/knowledge/docs/ui/components/atoms/vc-scrollable-container/vc-scrollable-container.docs.md +7 -0
  93. package/runtime/knowledge/docs/ui/components/atoms/vc-skeleton/vc-skeleton.docs.md +1 -1
  94. package/runtime/knowledge/docs/ui/components/atoms/vc-status/vc-status.docs.md +2 -2
  95. package/runtime/knowledge/docs/ui/components/atoms/vc-status-icon/vc-status-icon.docs.md +1 -1
  96. package/runtime/knowledge/docs/ui/components/atoms/vc-tooltip/vc-tooltip.docs.md +11 -10
  97. package/runtime/knowledge/docs/ui/components/atoms/vc-video/vc-video.docs.md +28 -8
  98. package/runtime/knowledge/docs/ui/components/atoms/vc-widget/vc-widget.docs.md +22 -19
  99. package/runtime/knowledge/docs/ui/components/molecules/multilanguage-selector/multilanguage-selector.docs.md +8 -8
  100. package/runtime/knowledge/docs/ui/components/molecules/vc-accordion/vc-accordion.docs.md +16 -6
  101. package/runtime/knowledge/docs/ui/components/molecules/vc-breadcrumbs/vc-breadcrumbs.docs.md +9 -8
  102. package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox/vc-checkbox.docs.md +42 -34
  103. package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox-group/vc-checkbox-group.docs.md +1 -1
  104. package/runtime/knowledge/docs/ui/components/molecules/vc-color-input/vc-color-input.docs.md +14 -1
  105. package/runtime/knowledge/docs/ui/components/molecules/vc-date-picker/vc-date-picker.docs.md +3 -1
  106. package/runtime/knowledge/docs/ui/components/molecules/vc-dropdown/vc-dropdown.docs.md +34 -33
  107. package/runtime/knowledge/docs/ui/components/molecules/vc-editor/vc-editor.docs.md +26 -24
  108. package/runtime/knowledge/docs/ui/components/molecules/vc-field/vc-field.docs.md +12 -14
  109. package/runtime/knowledge/docs/ui/components/molecules/vc-file-upload/vc-file-upload.docs.md +30 -30
  110. package/runtime/knowledge/docs/ui/components/molecules/vc-input/vc-input.docs.md +2 -2
  111. package/runtime/knowledge/docs/ui/components/molecules/vc-input-currency/vc-input-currency.docs.md +1 -1
  112. package/runtime/knowledge/docs/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.docs.md +34 -31
  113. package/runtime/knowledge/docs/ui/components/molecules/vc-input-group/vc-input-group.docs.md +14 -12
  114. package/runtime/knowledge/docs/ui/components/molecules/vc-menu/vc-menu.docs.md +1 -1
  115. package/runtime/knowledge/docs/ui/components/molecules/vc-multivalue/vc-multivalue.docs.md +36 -27
  116. package/runtime/knowledge/docs/ui/components/molecules/vc-pagination/vc-pagination.docs.md +5 -1
  117. package/runtime/knowledge/docs/ui/components/molecules/{vc-dropdown-panel/vc-dropdown-panel.docs.md → vc-popover/vc-popover.docs.md} +24 -27
  118. package/runtime/knowledge/docs/ui/components/molecules/vc-radio-button/vc-radio-button.docs.md +10 -9
  119. package/runtime/knowledge/docs/ui/components/molecules/vc-select/vc-select.docs.md +44 -19
  120. package/runtime/knowledge/docs/ui/components/molecules/vc-slider/vc-slider.docs.md +11 -11
  121. package/runtime/knowledge/docs/ui/components/molecules/vc-switch/vc-switch.docs.md +15 -14
  122. package/runtime/knowledge/docs/ui/components/molecules/vc-textarea/vc-textarea.docs.md +15 -15
  123. package/runtime/knowledge/docs/ui/components/molecules/vc-toast/vc-toast.docs.md +15 -13
  124. package/runtime/knowledge/docs/ui/components/organisms/vc-app/vc-app.docs.md +5 -1
  125. package/runtime/knowledge/docs/ui/components/organisms/vc-auth-layout/vc-auth-layout.docs.md +18 -0
  126. package/runtime/knowledge/docs/ui/components/organisms/vc-blade/vc-blade.docs.md +48 -78
  127. package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/composables/table-composables.docs.md +9 -11
  128. package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/vc-data-table.docs.md +71 -43
  129. package/runtime/knowledge/docs/ui/components/organisms/vc-dynamic-property/vc-dynamic-property.docs.md +27 -20
  130. package/runtime/knowledge/docs/ui/components/organisms/vc-gallery/vc-gallery.docs.md +2 -2
  131. package/runtime/knowledge/docs/ui/components/organisms/vc-image-upload/vc-image-upload.docs.md +12 -12
  132. package/runtime/knowledge/docs/ui/components/organisms/vc-popup/vc-popup.docs.md +33 -24
  133. package/runtime/knowledge/docs/ui/components/organisms/vc-scheduler/vc-scheduler.docs.md +509 -0
  134. package/runtime/knowledge/docs/ui/components/organisms/vc-sidebar/vc-sidebar.docs.md +43 -26
  135. package/runtime/knowledge/docs/ui/composables/ui-composables.docs.md +15 -9
  136. package/runtime/knowledge/docs/ui/composables/useDataTableSort.docs.md +8 -6
  137. package/runtime/knowledge/docs/ui/composables/useTableSearch.docs.md +3 -3
  138. package/runtime/knowledge/docs/ui/composables/useTableSelection.docs.md +4 -4
  139. package/runtime/knowledge/docs/ui/composables/useTableSort.docs.md +2 -3
  140. package/runtime/knowledge/migration-prompts/table-url-state-migration.md +221 -0
  141. package/runtime/vc-app.md +1 -0
@@ -53,7 +53,6 @@ Use VcBlade for every screen in a vc-shell application -- it is the standard con
53
53
  <VcBlade
54
54
  title="My First Blade"
55
55
  icon="lucide-box"
56
- @close="$emit('close:blade')"
57
56
  >
58
57
  <div class="tw-p-4">Hello from a blade!</div>
59
58
  </VcBlade>
@@ -64,6 +63,9 @@ defineBlade({ name: "MyFirstBlade", url: "/my-first-blade" });
64
63
  </script>
65
64
  ```
66
65
 
66
+ !!! tip "No close/expand wiring needed"
67
+ Inside the navigation stack VcBlade closes itself and reads its expanded/closable state from the stack automatically. You don't declare `expanded`/`closable` props or forward `@close`/`@expand`/`@collapse` events — that wiring is a legacy fallback kept only for standalone (Storybook) use.
68
+
67
69
  !!! tip "Every blade needs a name"
68
70
  Every blade must define a `name` in `defineBlade`. This is how other blades reference it: `openBlade({ name: "MyFirstBlade" })`. The `url` is optional and controls the URL segment.
69
71
 
@@ -101,14 +103,9 @@ A blade has four visual zones, rendered top-to-bottom:
101
103
  :title="title"
102
104
  icon="lucide-tag"
103
105
  width="50%"
104
- :expanded="expanded"
105
- :closable="closable"
106
106
  :toolbar-items="toolbar"
107
107
  :modified="hasChanges"
108
108
  :loading="isLoading"
109
- @close="$emit('close:blade')"
110
- @expand="$emit('expand:blade')"
111
- @collapse="$emit('collapse:blade')"
112
109
  >
113
110
  <!-- Your content here -->
114
111
  </VcBlade>
@@ -125,29 +122,13 @@ defineBlade({
125
122
  routable: false, // Optional: exclude from direct URL access
126
123
  });
127
124
 
128
- // Standard props injected by the navigation system
129
- export interface Props {
130
- expanded: boolean;
131
- closable: boolean;
132
- param?: string; // Entity ID
133
- options?: { sellerProduct?: object };
134
- }
135
-
136
- const props = withDefaults(defineProps<Props>(), {
137
- expanded: true,
138
- closable: true,
139
- });
140
-
141
- export interface Emits {
142
- (event: "close:blade"): void;
143
- (event: "expand:blade"): void;
144
- (event: "collapse:blade"): void;
145
- }
146
- const emit = defineEmits<Emits>();
147
-
148
- const { openBlade, closeSelf, callParent, onBeforeClose } = useBlade();
125
+ // Navigation state and data come from useBlade() — not props.
126
+ // `param` (entity id) and `options` (rich context) are reactive refs.
127
+ const { openBlade, closeSelf, callParent, onBeforeClose, param, options } = useBlade<{
128
+ sellerProduct?: object;
129
+ }>();
149
130
 
150
- const title = computed(() => (props.param ? "Edit Offer" : "New Offer"));
131
+ const title = computed(() => (param.value ? "Edit Offer" : "New Offer"));
151
132
  const isLoading = ref(false);
152
133
  const hasChanges = ref(false);
153
134
 
@@ -166,15 +147,18 @@ defineExpose({ title });
166
147
  </script>
167
148
  ```
168
149
 
150
+ !!! warning "Legacy pattern: `expanded` / `closable` props and `close:blade` emits"
151
+ Older blades declared `defineProps<{ expanded; closable; param }>()`, wired `withDefaults`, and re-emitted `close:blade` / `expand:blade` / `collapse:blade`. This is no longer needed. The navigation stack owns expanded/closable state (a workspace root is not closable, the rightmost blade is expanded), and VcBlade closes itself. Read `param`, `options`, `query`, `expanded`, and `closable` from `useBlade()` instead — see [useBlade docs](../../../../core/composables/useBlade/useBlade.docs.md).
152
+
169
153
  ### defineOptions Reference
170
154
 
171
- | Property | Type | Description |
172
- | ------------- | --------- | ----------------------------------------------------------------------- |
173
- | `name` | `string` | **Required.** Unique blade identifier for `openBlade({ name: "..." })`. |
174
- | `url` | `string` | URL path segment (e.g., `"/offers"` produces `/#/.../offers`). |
175
- | `isWorkspace` | `boolean` | Marks blade as a workspace (root-level, not closable). |
176
- | `routable` | `boolean` | When `false`, blade cannot be opened via direct URL navigation. |
177
- | `menuItem` | `object` | Registers a sidebar menu entry: `{ id, title, icon, priority }`. |
155
+ | Property | Type | Description |
156
+ | ------------- | --------- | ------------------------------------------------------------------------------------------------------------------ |
157
+ | `name` | `string` | **Required.** Unique blade identifier for `openBlade({ name: "..." })`. |
158
+ | `url` | `string` | URL path segment (e.g., `"/offers"` produces `/#/.../offers`). |
159
+ | `isWorkspace` | `boolean` | Marks blade as a workspace (root-level, not closable). |
160
+ | `routable` | `boolean` | When `false`, blade cannot be opened via direct URL navigation. |
161
+ | `menuItem` | `object` | Registers a sidebar menu entry: `{ title, icon, priority }` (plus optional `groupConfig`, `permissions`, `badge`). |
178
162
 
179
163
  ### defineExpose
180
164
 
@@ -310,10 +294,13 @@ const entityId = computed(() => ctx.value.item?.id);
310
294
 
311
295
  ### Expanded / Collapsed
312
296
 
313
- `expanded` indicates whether this blade is the active (rightmost) one. The navigation system manages it -- just pass through:
297
+ `expanded` indicates whether this blade is the active (rightmost) one. The navigation system manages it entirely -- **don't** declare an `expanded` prop or forward `@expand`/`@collapse`. If you need the current value, read it reactively from `useBlade()`:
314
298
 
315
- ```vue
316
- <VcBlade :expanded="expanded" @expand="$emit('expand:blade')" @collapse="$emit('collapse:blade')">
299
+ ```ts
300
+ const { expanded } = useBlade();
301
+
302
+ // e.g. show a compact layout when this blade is collapsed behind others
303
+ const layout = computed(() => (expanded.value ? "full" : "compact"));
317
304
  ```
318
305
 
319
306
  ### Closing
@@ -372,10 +359,11 @@ interface IBladeToolbar {
372
359
  id?: string;
373
360
  title?: string | Ref<string> | ComputedRef<string>;
374
361
  icon?: string | (() => string);
375
- clickHandler?(): void;
376
- disabled?: boolean | ComputedRef<boolean>;
377
- isVisible?: boolean | Ref<boolean> | ComputedRef<boolean> | ((blade?: BladeDescriptor) => boolean);
362
+ clickHandler?(app?: Record<string, any> | null): void;
363
+ disabled?: boolean | ComputedRef<boolean | undefined>;
364
+ isVisible?: boolean | Ref<boolean | undefined> | ComputedRef<boolean | undefined> | ((blade?: BladeDescriptor) => boolean | undefined);
378
365
  separator?: "left" | "right" | "both";
366
+ permissions?: string | string[];
379
367
  }
380
368
  ```
381
369
 
@@ -555,7 +543,7 @@ const toolbar = ref([
555
543
  ### Blade with Data Table
556
544
 
557
545
  ```vue
558
- <VcBlade :title="$t('ORDERS.LIST.TITLE')" icon="lucide-file-text" width="50%" :expanded="expanded" :closable="closable" :toolbar-items="toolbar">
546
+ <VcBlade :title="$t('ORDERS.LIST.TITLE')" icon="lucide-file-text" width="50%" :toolbar-items="toolbar">
559
547
  <VcDataTable
560
548
  v-model:sort-field="sortField" v-model:sort-order="sortOrder"
561
549
  v-model:search-value="searchValue" v-model:active-item-id="selectedItemId"
@@ -582,16 +570,6 @@ defineOptions({});
582
570
  defineBlade({ name: "ProductDetails", url: "/product" });
583
571
  ```
584
572
 
585
- ### Forgetting to expose the title
586
-
587
- ```ts
588
- // WRONG -- Breadcrumbs show nothing
589
- const title = computed(() => product.value?.name);
590
-
591
- // CORRECT
592
- defineExpose({ title });
593
- ```
594
-
595
573
  ### Wrong onBeforeClose return value
596
574
 
597
575
  ```ts
@@ -614,37 +592,29 @@ const { openBlade } = useBlade();
614
592
  openBlade({ name: "ProductsList" });
615
593
  ```
616
594
 
617
- ### Not passing expanded/closable through
618
-
619
- ```vue
620
- <!-- WRONG -- hardcoded, ignores navigation system -->
621
- <VcBlade :expanded="true" :closable="true">
622
-
623
- <!-- CORRECT -- pass props from navigation -->
624
- <VcBlade :expanded="expanded" :closable="closable">
625
- ```
626
-
627
595
  ## Props
628
596
 
629
- | Prop | Type | Default | Description |
630
- | -------------- | ------------------ | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
631
- | `title` | `string` | `undefined` | Title text in the blade header. |
632
- | `subtitle` | `string` | `undefined` | Secondary text below the title. |
633
- | `icon` | `string` | `undefined` | Icon name (e.g., `"lucide-box"`) displayed before the title. |
634
- | `width` | `number \| string` | `"30%"` | Blade width. Numbers are pixels; strings are CSS values. |
635
- | `expanded` | `boolean` | `undefined` | Whether the blade fills all available width. Inside a blade-navigation context this prop is overridden by the active blade's expanded state; in standalone use the prop is read directly. |
636
- | `closable` | `boolean` | `true` | Whether the close button is shown. |
637
- | `toolbarItems` | `IBladeToolbar[]` | `[]` | Action buttons in the toolbar zone. |
638
- | `modified` | `boolean` | `undefined` | Shows unsaved changes indicator and banner. |
639
- | `loading` | `boolean` | `undefined` | Shows skeleton placeholders for all blade zones. |
597
+ | Prop | Type | Default | Description |
598
+ | -------------- | ------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
599
+ | `title` | `string` | `undefined` | Title text in the blade header. |
600
+ | `subtitle` | `string` | `undefined` | Secondary text below the title. |
601
+ | `icon` | `string` | `undefined` | Icon name (e.g., `"lucide-box"`) displayed before the title. |
602
+ | `width` | `number \| string` | `"30%"` | Blade width. Numbers are pixels; strings are CSS values. |
603
+ | ~~`expanded`~~ | `boolean` | `undefined` | **Deprecated.** Managed by the navigation stack ignored inside blade navigation, where the active (rightmost) blade is expanded automatically. Read the live value from `useBlade().expanded`. Retained only as a standalone/Storybook fallback. |
604
+ | ~~`closable`~~ | `boolean` | `true` | **Deprecated.** Managed by the navigation stack — ignored inside blade navigation, where closability is derived from stack position (a workspace root is not closable). Read the live value from `useBlade().closable`. Retained only as a standalone/Storybook fallback. |
605
+ | `toolbarItems` | `IBladeToolbar[]` | `[]` | Action buttons in the toolbar zone. |
606
+ | `modified` | `boolean` | `undefined` | Shows unsaved changes indicator and banner. |
607
+ | `loading` | `boolean` | `undefined` | Shows skeleton placeholders for all blade zones. |
640
608
 
641
609
  ## Events
642
610
 
643
- | Event | Payload | Description |
644
- | ---------- | ------- | ----------------------------------------------- |
645
- | `close` | -- | Close button clicked. Re-emit as `close:blade`. |
646
- | `expand` | -- | Blade expanded. Re-emit as `expand:blade`. |
647
- | `collapse` | -- | Blade collapsed. Re-emit as `collapse:blade`. |
611
+ > **Note:** These events fire **only in standalone/Storybook use**. Inside the navigation stack VcBlade closes itself (via `closeSelf()`) and handles expand/collapse internally, so there is nothing to forward. Use `onBeforeClose()` from `useBlade()` to run logic (like an unsaved-changes guard) before the blade closes. A leftover `@close` listener inside blade navigation triggers a dev-mode deprecation warning.
612
+
613
+ | Event | Payload | Description |
614
+ | ---------- | ------- | ------------------------------------------------------------------ |
615
+ | `close` | -- | Standalone only. Close button clicked. |
616
+ | `expand` | -- | Standalone only. Blade expanded (no `maximized` context present). |
617
+ | `collapse` | -- | Standalone only. Blade collapsed (no `maximized` context present). |
648
618
 
649
619
  ## Slots
650
620
 
@@ -73,20 +73,18 @@ The central engine. Distributes `availableWidth` among visible columns according
73
73
 
74
74
  ```ts
75
75
  interface EngineInput {
76
- visibleIds: string[]; // Ordered list of visible column IDs
77
- specs: Record<string, ColumnSpec>; // Per-column: weight, minWidth, maxWidth
78
76
  availableWidth: number; // Container width in px
79
- fitMode: "gap" | "fit"; // "gap" leaves filler space, "fit" fills width
77
+ columns: { id: string; spec: ColumnSpec }[]; // Ordered visible columns with per-column weight, minPx, maxPx
78
+ mode: "fit" | "gap"; // "gap" leaves filler space, "fit" fills width
80
79
  }
81
80
 
82
81
  interface EngineOutput {
83
82
  widths: Record<string, number>; // Computed px width per column ID
84
- totalWidth: number; // Sum of all computed widths
85
- overflow: boolean; // true when sum(minWidth) > availableWidth
83
+ fillerWidth: number; // Leftover space returned to the filler pseudo-element
86
84
  }
87
85
  ```
88
86
 
89
- In crisis (`overflow: true`), each column receives its `minWidth` regardless of weight, and a console warning is emitted.
87
+ In crisis (when `sum(minPx) > availableWidth`), the engine squeezes columns proportionally below their minimums (`crisisSqueeze`) and emits a `console.warn`.
90
88
 
91
89
  #### `parseColumnWidth(value: string | number | undefined, availableWidth: number): ParsedWidth`
92
90
 
@@ -94,14 +92,14 @@ Parses a `VcColumn` `width` prop into a concrete pixel value.
94
92
 
95
93
  ```ts
96
94
  type ParsedWidth =
97
- | { type: "px"; value: number } // "200", 200, "200px"
98
- | { type: "pct"; value: number } // "20%" → 0.2 * availableWidth
99
- | { type: "auto"; value: undefined }; // undefined, "auto"
95
+ | { type: "px"; desiredPx: number } // "200", 200, "200px"
96
+ | { type: "percent"; desiredPx: number } // "20%" → 0.2 * availableWidth
97
+ | { type: "auto"; desiredPx: null }; // undefined, "auto"
100
98
  ```
101
99
 
102
- #### `buildInitialWeights(parsed: ParsedWidth[], availableWidth: number): Record<string, number>`
100
+ #### `buildInitialWeights(parsed: { id: string; parsed: ParsedWidth }[], availableWidth: number): Record<string, number>`
103
101
 
104
- Converts an array of `ParsedWidth` values (one per column) into initial weights. Auto columns receive an equal share of the space not claimed by px/% columns.
102
+ Converts an array of `{ id, parsed }` entries (one per column) into initial weights. Auto columns receive an equal share of the space not claimed by px/% columns.
105
103
 
106
104
  ```ts
107
105
  // Example: three columns — 200px, 20%, auto — with 800px available
@@ -19,7 +19,7 @@ Columns are defined as `<VcColumn>` child components -- no configuration objects
19
19
 
20
20
  **Key facts:**
21
21
 
22
- - 82 Storybook stories covering every feature permutation
22
+ - 90 Storybook stories covering every feature permutation
23
23
  - Automatic mobile card view on small screens
24
24
  - State persistence (column widths, order, sort, filters) to localStorage/sessionStorage
25
25
  - Full TypeScript generics -- `VcDataTable<Product>` propagates types to events and slots
@@ -266,10 +266,10 @@ Clicking a sortable column header cycles: unsorted -> ascending -> descending.
266
266
 
267
267
  ### Removable Sort
268
268
 
269
- Allow users to remove sorting entirely (3-state cycle: asc -> desc -> none):
269
+ Enabled by default: the sort cycle is 3-state (asc -> desc -> none), so users can remove sorting entirely. Set `:removable-sort="false"` to force the 2-state cycle (asc -> desc):
270
270
 
271
271
  ```vue
272
- <VcDataTable :items="products" :removable-sort="true">
272
+ <VcDataTable :items="products" :removable-sort="false">
273
273
  <VcColumn id="name" field="name" title="Name" sortable />
274
274
  </VcDataTable>
275
275
  ```
@@ -1109,8 +1109,14 @@ async function load() {
1109
1109
  });
1110
1110
  }
1111
1111
 
1112
+ // The initial load reads the values already restored from the URL.
1112
1113
  onMounted(() => load());
1113
- watch(sortExpression, () => load());
1114
+
1115
+ // Reset to page 1 when the search changes, BEFORE the reload watcher fires.
1116
+ watch(searchValue, () => pagination.setPage(1));
1117
+
1118
+ // Reload whenever any query dimension changes.
1119
+ watch([sortExpression, searchValue, () => pagination.skip], () => load());
1114
1120
  </script>
1115
1121
 
1116
1122
  <template>
@@ -1140,6 +1146,12 @@ watch(sortExpression, () => load());
1140
1146
 
1141
1147
  The `state-key` on `VcDataTable` here persists column layout to localStorage; the `stateKey` passed to the composables persists query state to the URL. Both use the same string value but serve different purposes.
1142
1148
 
1149
+ !!! warning "Reset the page to 1 when the search changes"
1150
+ `watch(searchValue, () => pagination.setPage(1))` is required, not optional. Without it, searching while on a later page leaves a stale `<stateKey>_page` in the URL. On the next reload the list requests that page of the **filtered** result set — `skip` overshoots the (smaller) result count and the table renders an empty "nothing found" state even though matches exist on page 1. Resetting to page 1 drops `_page` from the URL and keeps the `(search, page)` pair consistent. Apply the same reset whenever a filter changes.
1151
+
1152
+ !!! tip "Composable-owned pagination"
1153
+ When `useDataTablePagination` lives inside a list composable (so `onPageChange` can drive the fetch), thread the `stateKey` through as a composable option (`useOffersList({ stateKey })`) instead of hard-coding it — the blade still owns the key. Make sure the **initial** load passes `skip: pagination.skip` so a restored page is applied on first paint.
1154
+
1143
1155
  ---
1144
1156
 
1145
1157
  ## Row Actions
@@ -1365,38 +1377,39 @@ function onRowRemove(event: { data: Product; index: number; cancel: () => void }
1365
1377
 
1366
1378
  ### Props
1367
1379
 
1368
- | Prop | Type | Default | Description |
1369
- | ------------------- | ------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
1370
- | `id` | `string` | **required** | Unique column identifier. Must be unique within the table. |
1371
- | `field` | `string` | same as `id` | Data field path to read from each row item. |
1372
- | `title` | `string` | -- | Header text displayed in the column header. |
1373
- | `type` | `CellType` | `"text"` | Cell formatter: `"text"`, `"number"`, `"money"`, `"date"`, `"datetime"`, `"date-ago"`, `"time"`, `"image"`, `"link"`, `"html"`, `"status"`, `"status-icon"`. |
1374
- | `currencyField` | `string` | `"currency"` | Field to read currency code from (for `type="money"`). |
1375
- | `format` | `string` | -- | Date/number format string (e.g. `"DD.MM.YYYY"`). |
1376
- | `width` | `string \| number` | -- | Column width in px or CSS value (e.g. `200`, `"150px"`). |
1377
- | `minWidth` | `string \| number` | `60` | Minimum column width during resize. |
1378
- | `maxWidth` | `string \| number` | -- | Maximum column width during resize. |
1379
- | `align` | `"start" \| "center" \| "end"` | -- | Cell text alignment. |
1380
- | `headerAlign` | `"start" \| "center" \| "end"` | same as `align` | Header text alignment. |
1381
- | `sortable` | `boolean` | `false` | Enable sorting on this column. |
1382
- | `sortField` | `string` | same as `id` | Backend field name used in sort events. |
1383
- | `filter` | `ColumnFilterConfig` | -- | Filter config: `true` (text), `"field"` (text with custom field), `{ options }` (select), `{ range }` (date range). |
1384
- | `filterField` | `string` | same as `id` | Backend field name used in filter events. |
1385
- | `filterPlaceholder` | `string` | -- | Placeholder text for the filter input. |
1386
- | `visible` | `boolean` | `true` | Initial visibility. Hidden columns can be toggled via column switcher. |
1387
- | `alwaysVisible` | `boolean` | `false` | Keep visible when `showAllColumns=false` (blade narrows). |
1388
- | `editable` | `boolean` | `false` | Enable inline editing for this column's cells. |
1389
- | `rules` | `Record<string, unknown>` | -- | Validation rules for the editable cell. |
1390
- | `class` | `string` | -- | CSS class applied to header and body cells. |
1391
- | `headerClass` | `string` | -- | CSS class applied only to the header cell. |
1392
- | `bodyClass` | `string` | -- | CSS class applied only to body cells. |
1393
- | `lineClamp` | `number` | `2` | Max lines to display before truncating. `0` = no clamp. |
1394
- | `selectionMode` | `"single" \| "multiple"` | -- | Renders a selection checkbox/radio column. |
1395
- | `rowEditor` | `boolean` | `false` | Renders save/cancel buttons for row edit mode. |
1396
- | `rowReorder` | `boolean` | `false` | Renders a drag handle for row reordering. |
1397
- | `expander` | `boolean` | `false` | Renders an expand/collapse toggle. |
1398
- | `mobileRole` | `"title" \| "image" \| "field" \| "status"` | -- | Role in mobile card layout. |
1399
- | `mobileVisible` | `boolean` | `false` | Whether column is visible on mobile (hidden unless `mobileRole` set). |
1380
+ | Prop | Type | Default | Description |
1381
+ | ------------------- | -------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
1382
+ | `id` | `string` | **required** | Unique column identifier. Must be unique within the table. |
1383
+ | `field` | `string` | same as `id` | Data field path to read from each row item. |
1384
+ | `title` | `string` | -- | Header text displayed in the column header. |
1385
+ | `type` | `CellType` | `"text"` | Cell formatter: `"text"`, `"number"`, `"money"`, `"date"`, `"datetime"`, `"date-ago"`, `"time"`, `"image"`, `"link"`, `"html"`, `"status"`, `"status-icon"`. |
1386
+ | `currencyField` | `string` | `"currency"` | Field to read currency code from (for `type="money"`). |
1387
+ | `format` | `string` | -- | Date/number format string (e.g. `"DD.MM.YYYY"`). |
1388
+ | `width` | `string \| number` | -- | Column width in px or CSS value (e.g. `200`, `"150px"`). |
1389
+ | `minWidth` | `string \| number` | -- | Minimum column width during resize. When unset, the engine applies a 40px minimum. |
1390
+ | `maxWidth` | `string \| number` | -- | Maximum column width during resize. |
1391
+ | `align` | `"start" \| "center" \| "end"` | -- | Cell text alignment. |
1392
+ | `headerAlign` | `"start" \| "center" \| "end"` | same as `align` | Header text alignment. |
1393
+ | `sortable` | `boolean` | `false` | Enable sorting on this column. |
1394
+ | `sortField` | `string` | same as `id` | Backend field name used in sort events. |
1395
+ | `filter` | `ColumnFilterConfig` | -- | Filter config: `true` (text), `"field"` (text with custom field), `{ options }` (select), `{ range }` (date range). |
1396
+ | `filterField` | `string` | same as `id` | Backend field name used in filter events. |
1397
+ | `filterPlaceholder` | `string` | -- | Placeholder text for the filter input. |
1398
+ | `visible` | `boolean` | `true` | Initial visibility. Hidden columns can be toggled via column switcher. |
1399
+ | `alwaysVisible` | `boolean` | `false` | Keep visible when `showAllColumns=false` (blade narrows). |
1400
+ | `editable` | `boolean` | `false` | Enable inline editing for this column's cells. |
1401
+ | `rules` | `Record<string, unknown>` | -- | Validation rules for the editable cell. |
1402
+ | `class` | `string` | -- | CSS class applied to header and body cells. |
1403
+ | `headerClass` | `string` | -- | CSS class applied only to the header cell. |
1404
+ | `bodyClass` | `string` | -- | CSS class applied only to body cells. |
1405
+ | `lineClamp` | `number` | `2` | Max lines to display before truncating. `0` = no clamp. |
1406
+ | `selectionMode` | `"single" \| "multiple"` | -- | Renders a selection checkbox/radio column. |
1407
+ | `rowEditor` | `boolean` | `false` | Renders save/cancel buttons for row edit mode. |
1408
+ | `rowReorder` | `boolean` | `false` | Renders a drag handle for row reordering. |
1409
+ | `expander` | `boolean` | `false` | Renders an expand/collapse toggle. |
1410
+ | `mobileRole` | `"title" \| "image" \| "field" \| "status"` | -- | Role in mobile card layout. |
1411
+ | `mobilePosition` | `"top-left" \| "top-right" \| "bottom-left" \| "bottom-right"` | -- | Explicit grid position for the mobile card layout. |
1412
+ | `mobileVisible` | `boolean` | `true` | Whether column is visible on mobile. |
1400
1413
 
1401
1414
  ### Slots
1402
1415
 
@@ -1434,13 +1447,13 @@ function onRowRemove(event: { data: Product; index: number; cancel: () => void }
1434
1447
 
1435
1448
  ### Sorting
1436
1449
 
1437
- | Prop | Type | Default | Description |
1438
- | --------------- | ------------------------ | ---------- | ------------------------------------------------------ |
1439
- | `sortField` | `string` | -- | Currently sorted field. Use with `v-model:sortField`. |
1440
- | `sortOrder` | `1 \| -1 \| 0` | `0` | Sort direction. Use with `v-model:sortOrder`. |
1441
- | `sortMode` | `"single" \| "multiple"` | `"single"` | Single or multi-column sort. |
1442
- | `multiSortMeta` | `SortMeta[]` | `[]` | Multi-sort metadata. Use with `v-model:multiSortMeta`. |
1443
- | `removableSort` | `boolean` | `false` | Allow 3-state sort cycle (asc -> desc -> none). |
1450
+ | Prop | Type | Default | Description |
1451
+ | --------------- | ------------------------ | ---------- | -------------------------------------------------------------------------- |
1452
+ | `sortField` | `string` | -- | Currently sorted field. Use with `v-model:sortField`. |
1453
+ | `sortOrder` | `1 \| -1 \| 0` | `0` | Sort direction. Use with `v-model:sortOrder`. |
1454
+ | `sortMode` | `"single" \| "multiple"` | `"single"` | Single or multi-column sort. |
1455
+ | `multiSortMeta` | `SortMeta[]` | `[]` | Multi-sort metadata. Use with `v-model:multiSortMeta`. |
1456
+ | `removableSort` | `boolean` | `true` | 3-state sort cycle (asc -> desc -> none). Set `false` for a 2-state cycle. |
1444
1457
 
1445
1458
  ### Editing
1446
1459
 
@@ -2070,6 +2083,21 @@ const isSelectable = (item) => item.stock > 0;
2070
2083
  <VcDataTable :items="orders" state-key="orders-list">...</VcDataTable>
2071
2084
  ```
2072
2085
 
2086
+ ### 9. Not resetting the page when the search changes
2087
+
2088
+ ```ts
2089
+ // WRONG: search persists, but the page is not reset.
2090
+ // On a later page, the URL keeps `_page=3`; reloading a narrow search
2091
+ // requests page 3 of the filtered set → empty "nothing found" on reload.
2092
+ const { searchValue } = useTableSearch({ stateKey: "products_list" });
2093
+ watch([sortExpression, searchValue, () => pagination.skip], load);
2094
+
2095
+ // CORRECT: reset to page 1 before reloading on a new keyword.
2096
+ const { searchValue } = useTableSearch({ stateKey: "products_list" });
2097
+ watch(searchValue, () => pagination.setPage(1));
2098
+ watch([sortExpression, searchValue, () => pagination.skip], load);
2099
+ ```
2100
+
2073
2101
  ---
2074
2102
 
2075
2103
  ## Related Components
@@ -46,20 +46,25 @@ The prop names match the `DynamicObjectProperty` shape returned by the platform
46
46
 
47
47
  ## Key Props
48
48
 
49
- | Prop | Type | Default | Description |
50
- | -------------------- | ---------- | ------- | ----------------------------------------------------------------------------- |
51
- | `property` | `T` | - | Property object with `id` and metadata |
52
- | `modelValue` | `any` | - | Current property value (v-model) |
53
- | `valueType` | `string` | - | Type: ShortText, LongText, Number, Integer, DateTime, Boolean, Measure, Color |
54
- | `name` | `string` | - | Property name for display and field identification |
55
- | `required` | `boolean` | - | Whether the field is required |
56
- | `disabled` | `boolean` | `false` | Disables the input |
57
- | `dictionary` | `boolean` | `false` | Uses VcSelect/VcMultivalue with options |
58
- | `multivalue` | `boolean` | `false` | Supports multiple values |
59
- | `multilanguage` | `boolean` | `false` | Supports localized values |
60
- | `optionsGetter` | `Function` | - | Async loader for dictionary options |
61
- | `measurementsGetter` | `Function` | - | Async loader for measurement units |
62
- | `rules` | `object` | - | Validation rules: `{ min, max, regex }` |
49
+ | Prop | Type | Default | Description |
50
+ | -------------------- | ---------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
51
+ | `property` | `T` | _required_ | Property object with `id` and metadata |
52
+ | `modelValue` | `any` | _required_ | Current property value (v-model) |
53
+ | `valueType` | `string` | _required_ | Type: ShortText, LongText, Number, Integer, DateTime, Boolean, Measure, Color |
54
+ | `name` | `string` | _required_ | Property name for display and field identification |
55
+ | `required` | `boolean` | _required_ | Whether the field is required |
56
+ | `disabled` | `boolean` | `false` | Disables the input |
57
+ | `dictionary` | `boolean` | `false` | Uses VcSelect/VcMultivalue with options |
58
+ | `multivalue` | `boolean` | `false` | Supports multiple values |
59
+ | `multilanguage` | `boolean` | `false` | Supports localized values |
60
+ | `currentLanguage` | `string` | - | Active locale used for localized values |
61
+ | `optionsGetter` | `Function` | _required_ | Async loader for dictionary options, called as `(propertyId, keyword?, locale?)` |
62
+ | `measurementsGetter` | `Function` | - | Async loader for measurement units |
63
+ | `optionsValue` | `string` | `"id"` | Field on each option used as its value (VcSelect mapping) |
64
+ | `optionsLabel` | `string` | `"value"` | Inert. The option label is fixed to `"value"` when `multilanguage` is true and `"alias"` otherwise; only `optionsValue` is honored for VcSelect mapping. |
65
+ | `displayNames` | `{ name?; languageCode? }[]` | - | Localized display names used to resolve the field label per locale |
66
+ | `placeholder` | `string` | - | Placeholder text for the input |
67
+ | `rules` | `object` | - | Validation rules: `{ min, max, regex }` |
63
68
 
64
69
  ::storybook id="data-display-vcdynamicproperty--property-form" height="500"
65
70
 
@@ -99,8 +104,8 @@ async function loadProperties() {
99
104
  properties.value = result;
100
105
  }
101
106
 
102
- async function loadDictionaryOptions(propertyId: string, keyword?: string) {
103
- return await api.searchDictionaryItems(propertyId, keyword);
107
+ async function loadDictionaryOptions(propertyId: string, keyword?: string, locale?: string) {
108
+ return await api.searchDictionaryItems(propertyId, keyword, locale);
104
109
  }
105
110
 
106
111
  function handlePropertyUpdate(property: any, newValue: any) {
@@ -121,25 +126,27 @@ function handlePropertyUpdate(property: any, newValue: any) {
121
126
  :dictionary="prop.isDictionary"
122
127
  :multivalue="prop.isMultivalue"
123
128
  :multilanguage="prop.isMultilanguage"
124
- :options-getter="(kw) => loadDictionaryOptions(prop.id, kw)"
125
- @update:model-value="(val) => handlePropertyUpdate(prop, val)"
129
+ :options-getter="loadDictionaryOptions"
130
+ @update:model-value="(payload) => handlePropertyUpdate(prop, payload.value)"
126
131
  />
127
132
  </div>
128
133
  </template>
129
134
  ```
130
135
 
136
+ `update:model-value` emits an object, not a raw value: `{ value, dictionary?, locale?, unitOfMeasureId?, colorCode? }`. Read `payload.value` for the primary value; the other keys carry dictionary items, the active locale, the selected measure unit, and a color code where applicable. `optionsGetter` is invoked as `(propertyId, keyword?, locale?)` — bind it directly rather than wrapping the property id into the first argument.
137
+
131
138
  ::storybook id="data-display-vcdynamicproperty--required-with-validation" height="300"
132
139
 
133
140
  ## Recipe: Dynamic Property with Validation
134
141
 
135
142
  ```vue
136
- <VcDynamicProperty :property="skuProperty" :model-value="skuProperty.values?.[0]?.value" value-type="ShortText" name="SKU" :required="true" :rules="{ regex: '^[A-Z0-9-]+$', min: 3, max: 50 }" @update:model-value="(val) => updateProperty(skuProperty, val)" />
143
+ <VcDynamicProperty :property="skuProperty" :model-value="skuProperty.values?.[0]?.value" value-type="ShortText" name="SKU" :required="true" :rules="{ regex: '^[A-Z0-9-]+$', min: 3, max: 50 }" @update:model-value="(payload) => updateProperty(skuProperty, payload.value)" />
137
144
  ```
138
145
 
139
146
  ## Recipe: Measurement Property with Units
140
147
 
141
148
  ```vue
142
- <VcDynamicProperty :property="weightProperty" :model-value="weightProperty.values?.[0]?.value" value-type="Measure" name="Weight" :measurements-getter="loadMeasurementUnits" @update:model-value="(val) => updateProperty(weightProperty, val)" />
149
+ <VcDynamicProperty :property="weightProperty" :model-value="weightProperty.values?.[0]?.value" value-type="Measure" name="Weight" :measurements-getter="loadMeasurementUnits" @update:model-value="(payload) => updateProperty(weightProperty, payload.value)" />
143
150
  ```
144
151
 
145
152
  ## Common Mistakes
@@ -29,7 +29,7 @@ A responsive multi-image gallery with drag-and-drop reorder, file upload, lightb
29
29
  | `multiple` | `boolean` | `false` | Allow selecting multiple files in upload dialog. |
30
30
  | `loading` | `boolean` | `false` | Shows a loading overlay with spinner on the gallery. |
31
31
  | `itemActions` | `{ preview?: boolean; edit?: boolean; remove?: boolean }` | `{ preview: true, edit: true, remove: true }` | Per-tile action visibility. |
32
- | `rules` | `IValidationRules` | `undefined` | Validation rules for uploaded files. |
32
+ | `rules` | `keyof IValidationRules \| IValidationRules` | `undefined` | Validation rules for uploaded files. |
33
33
  | `name` | `string` | `"Gallery"` | Field name for validation messages. |
34
34
  | `accept` | `string` | `"image/*"` | Accepted file MIME types / extensions. Gallery is image-only by default — non-image files dropped from the OS are filtered out. Override (e.g. `"image/png,image/jpeg"`) to narrow further. |
35
35
  | `size` | `"sm" \| "md" \| "lg"` | `"md"` | Tile size preset. Sizes are smaller on mobile. |
@@ -190,6 +190,6 @@ function handleRemove(image: ICommonAsset) {
190
190
  ## Related Components
191
191
 
192
192
  - **VcImageUpload** -- single-image upload component
193
- - **VcImageTile** -- the internal tile component used for each image (topbar with name + drag handle, bottom tray with actions)
193
+ - **VcGalleryItem** -- the internal tile component (`_internal/vc-gallery-item`) rendered for each image (topbar with name + drag handle, bottom tray with actions)
194
194
  - **VcFileUpload** -- the file upload drop zone used in empty gallery state
195
195
  - **VcLabel** -- used internally when `label` prop is set
@@ -19,18 +19,18 @@ A single-image upload organism that displays either a drag-and-drop upload zone
19
19
 
20
20
  ## Props
21
21
 
22
- | Prop | Type | Default | Description |
23
- | ------------- | -------------------------------- | ---------------------------------- | ---------------------------------------------- |
24
- | `image` | `ICommonAsset` | `undefined` | The currently displayed image asset. |
25
- | `disabled` | `boolean` | `false` | Disables upload and remove actions. |
26
- | `loading` | `boolean` | `false` | Shows a loading spinner on the upload zone. |
27
- | `accept` | `string` | `.jpg,.png,.jpeg,.webp,.heic,.svg` | Accepted file extensions. |
28
- | `rules` | `IValidationRules` | `undefined` | Validation rules (e.g. `{ fileWeight: 300 }`). |
29
- | `name` | `string` | `"Image"` | Field name for validation messages. |
30
- | `icon` | `string` | `"lucide-cloud-upload"` | Upload zone placeholder icon. |
31
- | `placeholder` | `{ text: string; link: string }` | `undefined` | Custom text for the upload zone. |
32
- | `previewable` | `boolean` | `true` | Enables lightbox preview on click. |
33
- | `removable` | `boolean` | `true` | Shows the remove action on the image tile. |
22
+ | Prop | Type | Default | Description |
23
+ | ------------- | -------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------- |
24
+ | `image` | `ICommonAsset` | `undefined` | The currently displayed image asset. |
25
+ | `disabled` | `boolean` | `false` | Disables upload and remove actions. |
26
+ | `loading` | `boolean` | `false` | Shows a loading spinner on the upload zone. |
27
+ | `accept` | `string` | `.jpg,.png,.jpeg,.webp,.heic,.svg` | Accepted file extensions. |
28
+ | `rules` | `keyof IValidationRules \| IValidationRules` | `undefined` | Validation rules (rule name or object, e.g. `{ fileWeight: 300 }`). |
29
+ | `name` | `string` | `"Image"` | Field name for validation messages. |
30
+ | `icon` | `string` | `"lucide-cloud-upload"` | Upload zone placeholder icon. |
31
+ | `placeholder` | `{ text: string; link: string }` | `undefined` | Custom text for the upload zone. |
32
+ | `previewable` | `boolean` | `true` | Enables lightbox preview on click. |
33
+ | `removable` | `boolean` | `true` | Shows the remove action on the image tile. |
34
34
 
35
35
  ## Events
36
36