@vc-shell/vc-app-skill 2.0.0-alpha.31 → 2.0.0-alpha.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/package.json +1 -1
- package/runtime/VERSION +1 -1
- package/runtime/agents/migration-agent.md +83 -0
- package/runtime/knowledge/docs/_BUILD_HASH.md +1 -1
- package/runtime/knowledge/docs/core/composables/bladeContext/index.docs.md +111 -0
- package/runtime/knowledge/docs/core/composables/useBladeForm/useBladeForm.docs.md +167 -0
- package/runtime/knowledge/docs/core/composables/useBladeWidgets/index.docs.md +305 -0
- package/runtime/knowledge/docs/core/composables/useMenuExpanded/index.docs.md +83 -0
- package/runtime/knowledge/docs/core/utilities/thumbnail/thumbnail.docs.md +116 -0
- package/runtime/knowledge/docs/shell/components/change-password-button/change-password-button.docs.md +1 -1
- package/runtime/knowledge/docs/ui/components/atoms/vc-card/vc-card.docs.md +4 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-accordion/vc-accordion.docs.md +4 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox/vc-checkbox.docs.md +5 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox-group/vc-checkbox-group.docs.md +5 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-color-input/vc-color-input.docs.md +5 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-date-picker/vc-date-picker.docs.md +7 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-editor/vc-editor.docs.md +5 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-field/vc-field.docs.md +5 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-file-upload/vc-file-upload.docs.md +5 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-input/vc-input.docs.md +7 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-input-currency/vc-input-currency.docs.md +7 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.docs.md +7 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-multivalue/vc-multivalue.docs.md +7 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-radio-button/vc-radio-button.docs.md +5 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-radio-group/vc-radio-group.docs.md +5 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-rating/vc-rating.docs.md +5 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-select/vc-select.docs.md +7 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-slider/vc-slider.docs.md +5 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-switch/vc-switch.docs.md +5 -0
- package/runtime/knowledge/docs/ui/components/molecules/vc-textarea/vc-textarea.docs.md +7 -0
- package/runtime/knowledge/docs/ui/components/organisms/vc-blade/vc-blade.docs.md +30 -0
- package/runtime/knowledge/docs/ui/components/organisms/vc-data-table/vc-data-table.docs.md +28 -0
- package/runtime/knowledge/migration-prompts/blade-form-migration.md +246 -0
- package/runtime/knowledge/migration-prompts/blade-props-migration.md +195 -0
- package/runtime/knowledge/migration-prompts/notifications-migration.md +218 -0
- package/runtime/knowledge/migration-prompts/nswag-migration.md +248 -0
- package/runtime/knowledge/migration-prompts/widgets-migration.md +157 -0
- package/runtime/vc-app.md +126 -0
- package/runtime/knowledge/docs/core/constants/constants.docs.md +0 -185
- /package/runtime/knowledge/docs/shell/{pages → auth}/ChangePasswordPage/change-password-page.docs.md +0 -0
package/runtime/knowledge/docs/ui/components/molecules/vc-radio-group/vc-radio-group.docs.md
CHANGED
|
@@ -144,3 +144,8 @@ interface RadioGroupOption<V = string | number | boolean> {
|
|
|
144
144
|
- [VcRadioButton](../vc-radio-button/) — individual radio button component
|
|
145
145
|
- [VcCheckboxGroup](../vc-checkbox-group/) — multiple-selection option group
|
|
146
146
|
- [VcInputGroup](../vc-input-group/) — generic form field group (used internally)
|
|
147
|
+
|
|
148
|
+
## Skeleton / Loading State
|
|
149
|
+
|
|
150
|
+
When placed inside a `VcBlade` with `loading=true`, the component renders a skeleton placeholder matching its shape — a control indicator and label block. No configuration needed.
|
|
151
|
+
|
|
@@ -251,3 +251,8 @@ Use the `"star-and-text"` or `"text"` variant in table cell slots for a compact
|
|
|
251
251
|
- [VcField](../vc-field/) -- Read-only field display, often used alongside ratings in detail views
|
|
252
252
|
- [VcLabel](../../atoms/vc-label/) -- Label atom used internally for the label and tooltip
|
|
253
253
|
- [VcIcon](../../atoms/vc-icon/) -- Renders the star icons internally
|
|
254
|
+
|
|
255
|
+
## Skeleton / Loading State
|
|
256
|
+
|
|
257
|
+
When placed inside a `VcBlade` with `loading=true`, the component automatically renders a skeleton placeholder matching its visual footprint. No additional props or configuration needed.
|
|
258
|
+
|
|
@@ -682,3 +682,10 @@ Don't forget `:key` with cascading selects, otherwise the second select will ret
|
|
|
682
682
|
- [VcInput](../vc-input/) — simple text field
|
|
683
683
|
- [VcDatePicker](../vc-date-picker/) — date selection
|
|
684
684
|
- [VcField](../vc-field/) — wrapper with label/error/hint (read-only display)
|
|
685
|
+
|
|
686
|
+
## Skeleton / Loading State
|
|
687
|
+
|
|
688
|
+
When placed inside a `VcBlade` with `loading=true`, the component automatically renders a skeleton placeholder matching its visual footprint — a label block (when the `label` prop is set) and an input-shaped block. No additional props or configuration needed.
|
|
689
|
+
|
|
690
|
+
This behavior is powered by `BladeLoadingKey` via Vue's provide/inject. The component injects the loading state from the nearest `VcBlade` ancestor.
|
|
691
|
+
|
|
@@ -113,3 +113,8 @@ const products = [
|
|
|
113
113
|
## Related Components
|
|
114
114
|
|
|
115
115
|
- [VcImage](../../atoms/vc-image/) -- image component often used inside slides
|
|
116
|
+
|
|
117
|
+
## Skeleton / Loading State
|
|
118
|
+
|
|
119
|
+
When placed inside a `VcBlade` with `loading=true`, the component automatically renders a skeleton placeholder matching its visual footprint. No additional props or configuration needed.
|
|
120
|
+
|
|
@@ -298,3 +298,8 @@ const isActive = ref(true);
|
|
|
298
298
|
- [VcCheckbox](../vc-checkbox/) -- for checkboxes and checkbox groups
|
|
299
299
|
- [VcRadioButton](../vc-radio-button/) -- for mutually exclusive choices
|
|
300
300
|
- [VcInputGroup](../vc-input-group/) -- semantic wrapper for grouping form controls
|
|
301
|
+
|
|
302
|
+
## Skeleton / Loading State
|
|
303
|
+
|
|
304
|
+
When placed inside a `VcBlade` with `loading=true`, the component renders a skeleton placeholder matching its shape — a control indicator and label block. No configuration needed.
|
|
305
|
+
|
|
@@ -305,3 +305,10 @@ const description = ref<string>("");
|
|
|
305
305
|
- [VcInput](../vc-input/) -- single-line text input
|
|
306
306
|
- [VcEditor](../vc-editor/) -- rich text / Markdown editor
|
|
307
307
|
- [VcInputGroup](../vc-input-group/) -- semantic wrapper for grouping form controls
|
|
308
|
+
|
|
309
|
+
## Skeleton / Loading State
|
|
310
|
+
|
|
311
|
+
When placed inside a `VcBlade` with `loading=true`, the component automatically renders a skeleton placeholder matching its visual footprint — a label block (when the `label` prop is set) and an input-shaped block. No additional props or configuration needed.
|
|
312
|
+
|
|
313
|
+
This behavior is powered by `BladeLoadingKey` via Vue's provide/inject. The component injects the loading state from the nearest `VcBlade` ancestor.
|
|
314
|
+
|
|
@@ -659,3 +659,33 @@ openBlade({ name: "ProductsList" });
|
|
|
659
659
|
| `useLoading()` | Merges multiple loading refs into a single boolean. |
|
|
660
660
|
| `usePopup()` | Confirmation dialogs and error messages. |
|
|
661
661
|
| `useBladeWidgets()` | Register contextual widgets for the blade widget area. |
|
|
662
|
+
|
|
663
|
+
## Content Skeleton Mode
|
|
664
|
+
|
|
665
|
+
When `loading=true`, VcBlade provides `BladeLoadingKey` to all descendant components via Vue's provide/inject. Each framework UI component automatically renders a skeleton placeholder matching its visual footprint.
|
|
666
|
+
|
|
667
|
+
### How It Works
|
|
668
|
+
|
|
669
|
+
1. Set `loading` prop on VcBlade (typically bound to your data-fetching composable's loading ref)
|
|
670
|
+
2. All child components (`VcInput`, `VcSelect`, `VcCard`, etc.) detect the loading state and render skeletons
|
|
671
|
+
3. Layout containers (`VcContainer`, `VcRow`, `VcCol`, `VcForm`) are transparent — they preserve layout structure
|
|
672
|
+
4. When loading completes, components switch to their normal rendering
|
|
673
|
+
|
|
674
|
+
### What Shows During Loading
|
|
675
|
+
|
|
676
|
+
- **Config-gated fields** (`v-if="config.showName"`) — config is available immediately, so these fields show skeletons
|
|
677
|
+
- **Data-gated fields** (`v-if="item.productData"`) — data not yet loaded, so these fields don't appear in the skeleton
|
|
678
|
+
- **Header and toolbar** — have their own dedicated skeletons (unchanged)
|
|
679
|
+
|
|
680
|
+
No changes to existing blade pages are required.
|
|
681
|
+
|
|
682
|
+
### Custom Components
|
|
683
|
+
|
|
684
|
+
To make custom components skeleton-aware:
|
|
685
|
+
|
|
686
|
+
```ts
|
|
687
|
+
import { useBladeLoading } from "@vc-shell/framework";
|
|
688
|
+
|
|
689
|
+
const bladeLoading = useBladeLoading();
|
|
690
|
+
// bladeLoading.value === true when parent VcBlade is loading
|
|
691
|
+
```
|
|
@@ -619,6 +619,33 @@ Customize expand/collapse icons:
|
|
|
619
619
|
</VcDataTable>
|
|
620
620
|
```
|
|
621
621
|
|
|
622
|
+
### Conditional expansion
|
|
623
|
+
|
|
624
|
+
Use `isRowExpandable` to control which rows show the expand toggle. Rows that fail the predicate cannot be expanded:
|
|
625
|
+
|
|
626
|
+
```vue
|
|
627
|
+
<template>
|
|
628
|
+
<VcDataTable
|
|
629
|
+
:items="orders"
|
|
630
|
+
v-model:expanded-rows="expandedRows"
|
|
631
|
+
:is-row-expandable="(order) => order.lineItems.length > 0"
|
|
632
|
+
>
|
|
633
|
+
<VcColumn id="expand" :expander="true" :width="40" />
|
|
634
|
+
<VcColumn id="orderNumber" field="number" title="Order #" />
|
|
635
|
+
|
|
636
|
+
<template #expansion="{ data }">
|
|
637
|
+
<div class="tw-p-4">
|
|
638
|
+
<p v-for="item in data.lineItems" :key="item.id">{{ item.name }}</p>
|
|
639
|
+
</div>
|
|
640
|
+
</template>
|
|
641
|
+
</VcDataTable>
|
|
642
|
+
</template>
|
|
643
|
+
|
|
644
|
+
<script setup lang="ts">
|
|
645
|
+
const expandedRows = ref<Order[]>([]);
|
|
646
|
+
</script>
|
|
647
|
+
```
|
|
648
|
+
|
|
622
649
|
---
|
|
623
650
|
|
|
624
651
|
## Row Grouping
|
|
@@ -1264,6 +1291,7 @@ function onRowRemove(event: { data: Product; index: number; cancel: () => void }
|
|
|
1264
1291
|
| `expandedRows` | `T[]` | `[]` | Expanded rows. Use with `v-model:expandedRows`. |
|
|
1265
1292
|
| `expandedRowIcon` | `string` | `"lucide-chevron-down"` | Icon for expanded state. |
|
|
1266
1293
|
| `collapsedRowIcon` | `string` | `"lucide-chevron-right"` | Icon for collapsed state. |
|
|
1294
|
+
| `isRowExpandable` | `(data: T) => boolean` | -- | Per-row predicate to hide the expand toggle. |
|
|
1267
1295
|
|
|
1268
1296
|
### Row Grouping
|
|
1269
1297
|
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: blade-form-migration
|
|
3
|
+
description: AI transformation rules for useForm + onBeforeClose → useBladeForm.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Blade Form Migration: useForm → useBladeForm
|
|
7
|
+
|
|
8
|
+
Replace manual wiring of `useForm()` (vee-validate) + `useModificationTracker()` + `useBeforeUnload()` + `onBeforeClose()` with the unified `useBladeForm()` composable.
|
|
9
|
+
|
|
10
|
+
## RULE 1: Replace useForm + onBeforeClose with useBladeForm
|
|
11
|
+
|
|
12
|
+
**BEFORE:**
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { useForm } from "vee-validate";
|
|
16
|
+
import { useBeforeUnload, useModificationTracker, useBlade, usePopup } from "@vc-shell/framework";
|
|
17
|
+
|
|
18
|
+
const { item, loading, load, save } = useMyDetails();
|
|
19
|
+
const { onBeforeClose } = useBlade();
|
|
20
|
+
const { showConfirmation } = usePopup();
|
|
21
|
+
|
|
22
|
+
const { errorBag, setFieldError, meta: formMeta } = useForm({
|
|
23
|
+
initialValues: item,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const { currentValue, resetModificationState, isModified } = useModificationTracker(item);
|
|
27
|
+
|
|
28
|
+
useBeforeUnload(computed(() => isModified.value));
|
|
29
|
+
|
|
30
|
+
onBeforeClose(async () => {
|
|
31
|
+
if (isModified.value) {
|
|
32
|
+
return showConfirmation(t("MY_MODULE.ALERTS.CLOSE_CONFIRMATION"));
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const canSave = computed(
|
|
38
|
+
() => isModified.value && formMeta.value.valid && !loading.value,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
async function handleSave() {
|
|
42
|
+
await save(item.value);
|
|
43
|
+
resetModificationState();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function handleCancel() {
|
|
47
|
+
item.value = JSON.parse(JSON.stringify(currentValue.value));
|
|
48
|
+
resetModificationState();
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**AFTER:**
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { useBladeForm } from "@vc-shell/framework";
|
|
56
|
+
|
|
57
|
+
const { item, loading, load, save } = useMyDetails();
|
|
58
|
+
|
|
59
|
+
const { canSave, isModified, setBaseline, revert, setFieldError, errorBag } = useBladeForm({
|
|
60
|
+
data: item,
|
|
61
|
+
closeConfirmMessage: () => t("MY_MODULE.ALERTS.CLOSE_CONFIRMATION"),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
watch(item, () => {
|
|
65
|
+
if (item.value) setBaseline();
|
|
66
|
+
}, { once: true });
|
|
67
|
+
|
|
68
|
+
async function handleSave() {
|
|
69
|
+
await save(item.value);
|
|
70
|
+
setBaseline();
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## RULE 2: Remove onBeforeClose Entirely
|
|
75
|
+
|
|
76
|
+
`useBladeForm` handles the unsaved-changes guard automatically via `autoBeforeClose` (defaults to `true`).
|
|
77
|
+
|
|
78
|
+
**BEFORE:**
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const { onBeforeClose } = useBlade();
|
|
82
|
+
|
|
83
|
+
onBeforeClose(async () => {
|
|
84
|
+
if (formMeta.value.dirty) {
|
|
85
|
+
return confirm("You have unsaved changes. Discard?");
|
|
86
|
+
}
|
|
87
|
+
return true;
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**AFTER:**
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// Remove entirely. useBladeForm handles this.
|
|
95
|
+
// If you need a custom message, pass closeConfirmMessage option:
|
|
96
|
+
const form = useBladeForm({
|
|
97
|
+
data: item,
|
|
98
|
+
closeConfirmMessage: () => t("MY_MODULE.ALERTS.CLOSE_CONFIRMATION"),
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## RULE 3: Update Toolbar Disabled Logic
|
|
103
|
+
|
|
104
|
+
**BEFORE:**
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
const canSave = computed(
|
|
108
|
+
() => !meta.value.valid || !isModified.value,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// or in toolbar items:
|
|
112
|
+
{
|
|
113
|
+
id: "save",
|
|
114
|
+
disabled: computed(() => !formMeta.value.valid || !isModified.value),
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**AFTER:**
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
// canSave is returned directly from useBladeForm:
|
|
122
|
+
const { canSave } = useBladeForm({ data: item });
|
|
123
|
+
|
|
124
|
+
// In toolbar items:
|
|
125
|
+
{
|
|
126
|
+
id: "save",
|
|
127
|
+
disabled: computed(() => !canSave.value),
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
For additional disabled conditions (e.g., async validation in progress), use `canSaveOverride`:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const { canSave } = useBladeForm({
|
|
135
|
+
data: item,
|
|
136
|
+
canSaveOverride: computed(() => !isSkuValidating.value && !loading.value),
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## RULE 4: Keep Field from vee-validate
|
|
141
|
+
|
|
142
|
+
Only remove `useForm` from vee-validate imports. Keep `Field`, `ErrorMessage`, and other template-level components — they still work with `useBladeForm` which uses vee-validate internally.
|
|
143
|
+
|
|
144
|
+
**BEFORE:**
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { useForm, Field, ErrorMessage } from "vee-validate";
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**AFTER:**
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { Field, ErrorMessage } from "vee-validate";
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## RULE 5: Remove useBeforeUnload / useModificationTracker
|
|
157
|
+
|
|
158
|
+
`useBladeForm` handles both browser unload guards and modification tracking internally.
|
|
159
|
+
|
|
160
|
+
**BEFORE:**
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { useBeforeUnload, useModificationTracker } from "@vc-shell/framework";
|
|
164
|
+
|
|
165
|
+
const { currentValue, resetModificationState, isModified } = useModificationTracker(item);
|
|
166
|
+
useBeforeUnload(computed(() => isModified.value));
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**AFTER:**
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// Remove entirely. useBladeForm provides:
|
|
173
|
+
// - isModified (deep comparison against baseline)
|
|
174
|
+
// - setBaseline() (replaces resetModificationState)
|
|
175
|
+
// - revert() (replaces manual JSON.parse(JSON.stringify(currentValue.value)))
|
|
176
|
+
// - Browser unload guard (automatic)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Also remove `useModificationTracker` from data composables if present:
|
|
180
|
+
|
|
181
|
+
**BEFORE (data composable):**
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
export function useMyDetails() {
|
|
185
|
+
const item = ref<MyItem>();
|
|
186
|
+
const { currentValue, resetModificationState, isModified } = useModificationTracker(item);
|
|
187
|
+
|
|
188
|
+
async function load(id: string) {
|
|
189
|
+
item.value = await api.get(id);
|
|
190
|
+
resetModificationState();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return { item, currentValue, resetModificationState, isModified, load, save };
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**AFTER (data composable):**
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
export function useMyDetails() {
|
|
201
|
+
const item = ref<MyItem>();
|
|
202
|
+
|
|
203
|
+
async function load(id: string) {
|
|
204
|
+
item.value = await api.get(id);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return { item, load, save };
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Template Changes
|
|
212
|
+
|
|
213
|
+
Remove `:modified` prop from `<VcBlade>` — it is auto-detected via provide/inject.
|
|
214
|
+
|
|
215
|
+
**BEFORE:**
|
|
216
|
+
|
|
217
|
+
```vue
|
|
218
|
+
<template>
|
|
219
|
+
<VcBlade :modified="isModified" :closable="true">
|
|
220
|
+
<!-- content -->
|
|
221
|
+
</VcBlade>
|
|
222
|
+
</template>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**AFTER:**
|
|
226
|
+
|
|
227
|
+
```vue
|
|
228
|
+
<template>
|
|
229
|
+
<VcBlade :closable="true">
|
|
230
|
+
<!-- content — no :modified prop needed -->
|
|
231
|
+
</VcBlade>
|
|
232
|
+
</template>
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Verification
|
|
236
|
+
|
|
237
|
+
After migration:
|
|
238
|
+
|
|
239
|
+
1. Run `npx tsc --noEmit` to verify no TypeScript errors
|
|
240
|
+
2. Confirm the blade shows a modified indicator when data changes
|
|
241
|
+
3. Confirm closing a modified blade shows the confirmation dialog
|
|
242
|
+
4. Confirm the save button is disabled when form is clean or invalid
|
|
243
|
+
5. Confirm `setBaseline()` is called after initial load and after save
|
|
244
|
+
6. Confirm cancel/revert restores data to the last baseline
|
|
245
|
+
7. Confirm `useModificationTracker` is removed from data composables
|
|
246
|
+
8. Confirm no stale imports of `useForm`, `useBeforeUnload`, `useModificationTracker`, or `onBeforeClose`
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: blade-props-migration
|
|
3
|
+
description: AI transformation rules for reusable blade components skipped by CLI migrator.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Blade Props Migration: Boilerplate Removal
|
|
7
|
+
|
|
8
|
+
Remove blade prop/emit boilerplate from blade pages. VcBlade is now context-aware — it reads `expanded` and `closable` from the BladeDescriptor automatically via provide/inject. Use `useBlade()` for `param`, `options`, `closeSelf`, and `callParent`.
|
|
9
|
+
|
|
10
|
+
## RULE 1: Remove Blade Prop Forwarding from Template
|
|
11
|
+
|
|
12
|
+
Remove `:expanded`, `:closable`, `@close`, `@expand`, `@collapse` from the `<VcBlade>` tag.
|
|
13
|
+
|
|
14
|
+
**BEFORE:**
|
|
15
|
+
|
|
16
|
+
```vue
|
|
17
|
+
<template>
|
|
18
|
+
<VcBlade
|
|
19
|
+
:title="bladeTitle"
|
|
20
|
+
:expanded="expanded"
|
|
21
|
+
:closable="closable"
|
|
22
|
+
:toolbar-items="bladeToolbar"
|
|
23
|
+
@close="$emit('close:blade')"
|
|
24
|
+
@expand="$emit('expand:blade')"
|
|
25
|
+
@collapse="$emit('collapse:blade')"
|
|
26
|
+
>
|
|
27
|
+
<VcDataTable ... />
|
|
28
|
+
</VcBlade>
|
|
29
|
+
</template>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**AFTER:**
|
|
33
|
+
|
|
34
|
+
```vue
|
|
35
|
+
<template>
|
|
36
|
+
<VcBlade
|
|
37
|
+
:title="bladeTitle"
|
|
38
|
+
:toolbar-items="bladeToolbar"
|
|
39
|
+
>
|
|
40
|
+
<VcDataTable ... />
|
|
41
|
+
</VcBlade>
|
|
42
|
+
</template>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## RULE 2: Remove Props and Emits Interfaces
|
|
46
|
+
|
|
47
|
+
Remove `expanded`, `closable`, `param`, `options` from Props interface. Remove blade events from Emits. Use `useBlade()` to access `param` and `options`.
|
|
48
|
+
|
|
49
|
+
**BEFORE:**
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
export interface Props {
|
|
53
|
+
expanded?: boolean;
|
|
54
|
+
closable?: boolean;
|
|
55
|
+
param?: string;
|
|
56
|
+
options?: { sellerProduct?: SellerProduct };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface Emits {
|
|
60
|
+
(event: "parent:call", args: IParentCallArgs): void;
|
|
61
|
+
(event: "close:blade"): void;
|
|
62
|
+
(event: "collapse:blade"): void;
|
|
63
|
+
(event: "expand:blade"): void;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
67
|
+
expanded: true,
|
|
68
|
+
closable: true,
|
|
69
|
+
});
|
|
70
|
+
const emit = defineEmits<Emits>();
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**AFTER:**
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { useBlade } from "@vc-shell/framework";
|
|
77
|
+
|
|
78
|
+
const { param, options, openBlade, closeSelf, callParent } =
|
|
79
|
+
useBlade<{ sellerProduct?: SellerProduct }>();
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
If the Props interface has other non-blade props, keep only those:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// Keep non-blade props
|
|
86
|
+
export interface Props {
|
|
87
|
+
config?: DetailConfig;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const props = defineProps<Props>();
|
|
91
|
+
|
|
92
|
+
// Blade concerns via composable
|
|
93
|
+
const { param, options, closeSelf, callParent } = useBlade<{ orderId: string }>();
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## RULE 3: Replace emit("parent:call") with callParent()
|
|
97
|
+
|
|
98
|
+
**BEFORE:**
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
const emit = defineEmits<Emits>();
|
|
102
|
+
|
|
103
|
+
const reload = async () => {
|
|
104
|
+
await loadOffers({ ... });
|
|
105
|
+
emit("parent:call", { method: "reload" });
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
function onItemSelect(item: Product) {
|
|
109
|
+
emit("parent:call", { method: "onItemClick", args: { data: item } });
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**AFTER:**
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const { callParent } = useBlade();
|
|
117
|
+
|
|
118
|
+
const reload = async () => {
|
|
119
|
+
await loadOffers({ ... });
|
|
120
|
+
callParent("reload");
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
function onItemSelect(item: Product) {
|
|
124
|
+
callParent("onItemClick", { data: item });
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## RULE 4: Replace emit("close:blade") with closeSelf()
|
|
129
|
+
|
|
130
|
+
**BEFORE:**
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const emit = defineEmits<Emits>();
|
|
134
|
+
|
|
135
|
+
function handleClose() {
|
|
136
|
+
emit("close:blade");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// or in template:
|
|
140
|
+
// @click="$emit('close:blade')"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**AFTER:**
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const { closeSelf } = useBlade();
|
|
147
|
+
|
|
148
|
+
function handleClose() {
|
|
149
|
+
closeSelf();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// or in template:
|
|
153
|
+
// @click="closeSelf()"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Wrapper Components
|
|
157
|
+
|
|
158
|
+
If a wrapper component forwards blade props to a base component, remove the forwarding. The base component should call `useBlade()` directly.
|
|
159
|
+
|
|
160
|
+
**BEFORE:**
|
|
161
|
+
|
|
162
|
+
```vue
|
|
163
|
+
<template>
|
|
164
|
+
<ProductDetailsBase
|
|
165
|
+
:expanded="expanded"
|
|
166
|
+
:closable="closable"
|
|
167
|
+
:param="param"
|
|
168
|
+
:options="options"
|
|
169
|
+
@parent:call="$emit('parent:call', $event)"
|
|
170
|
+
@close:blade="$emit('close:blade')"
|
|
171
|
+
@expand:blade="$emit('expand:blade')"
|
|
172
|
+
@collapse:blade="$emit('collapse:blade')"
|
|
173
|
+
/>
|
|
174
|
+
</template>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**AFTER:**
|
|
178
|
+
|
|
179
|
+
```vue
|
|
180
|
+
<template>
|
|
181
|
+
<ProductDetailsBase />
|
|
182
|
+
</template>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Verification
|
|
186
|
+
|
|
187
|
+
After migration:
|
|
188
|
+
|
|
189
|
+
1. Run `npx tsc --noEmit` to verify no TypeScript errors
|
|
190
|
+
2. Confirm blades open and close correctly
|
|
191
|
+
3. Confirm `param.value` is accessible in script (use `param` without `.value` in templates)
|
|
192
|
+
4. Confirm `options.value` provides typed options from parent
|
|
193
|
+
5. Confirm `callParent()` triggers the parent's exposed method
|
|
194
|
+
6. Confirm no remaining `emit("close:blade")` or `emit("parent:call", ...)` calls
|
|
195
|
+
7. Confirm no remaining `:expanded`, `:closable`, `@close`, `@expand`, `@collapse` on `<VcBlade>`
|