@vc-shell/vc-app-skill 2.0.0-alpha.32 → 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 +15 -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/useBladeForm/useBladeForm.docs.md +55 -1
- package/runtime/knowledge/docs/shell/auth/ChangePasswordPage/change-password-page.docs.md +102 -0
- 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/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
# [2.0.0-alpha.33](https://github.com/VirtoCommerce/vc-shell/compare/v2.0.0-alpha.32...v2.0.0-alpha.33) (2026-04-14)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **vc-app-skill:** add VC_SHELL_MIGRATE_CLI env override for local testing ([010d2f2](https://github.com/VirtoCommerce/vc-shell/commit/010d2f2ecb29d31d9134406bcd18e46e5883208b))
|
|
7
|
+
* **vc-app-skill:** resolve migrate CLI from project node_modules before npx fallback ([82a8156](https://github.com/VirtoCommerce/vc-shell/commit/82a81563f7fdb94a94a7b8a80796ecffc671a39c))
|
|
8
|
+
* **vc-app-skill:** resolve migrate CLI locally in dev mode, fallback to npx ([89888a0](https://github.com/VirtoCommerce/vc-shell/commit/89888a06cc0b4a1519f46f070ee06ebb0d82fd09))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **vc-app-skill:** add /vc-app migrate command with full migration pipeline ([35a8b11](https://github.com/VirtoCommerce/vc-shell/commit/35a8b119457b14f6f4626caf133476222afd6663))
|
|
14
|
+
* **vc-app-skill:** add migration prompt knowledge base (nswag, widgets, form, blade-props, notifications) ([a0b0eb2](https://github.com/VirtoCommerce/vc-shell/commit/a0b0eb2a96521916a72bdbf787961c1c96f96f6d))
|
|
15
|
+
* **vc-app-skill:** add migration-agent subagent prompt ([29ac155](https://github.com/VirtoCommerce/vc-shell/commit/29ac1550c8e3c9b71d5dbc2ade7ea86b4d40213f))
|
|
1
16
|
# [2.0.0-alpha.32](https://github.com/VirtoCommerce/vc-shell/compare/v2.0.0-alpha.31...v2.0.0-alpha.32) (2026-04-02)
|
|
2
17
|
|
|
3
18
|
**Note:** Version bump only for package @vc-shell/vc-app-skill
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vc-shell/vc-app-skill",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.33",
|
|
4
4
|
"description": "AI coding skill for scaffolding and generating VirtoCommerce Shell applications. Works with Claude Code, OpenCode, Gemini, Codex, Cursor.",
|
|
5
5
|
"bin": "./bin/install.cjs",
|
|
6
6
|
"files": [
|
package/runtime/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.0.0-alpha.
|
|
1
|
+
2.0.0-alpha.33
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: migration-agent
|
|
3
|
+
description: Performs AI-powered manual migrations on files identified by MIGRATION_REPORT.md, using transformation rules from migration prompts.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Input Contract
|
|
7
|
+
|
|
8
|
+
```json
|
|
9
|
+
{
|
|
10
|
+
"required": {
|
|
11
|
+
"cwd": "string — absolute path to project root",
|
|
12
|
+
"reportPath": "string — path to MIGRATION_REPORT.md",
|
|
13
|
+
"topics": "array — migration topics to process, each with: { name, affectedFiles, migrationPromptPath, patternPath? }"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Knowledge Loading
|
|
19
|
+
|
|
20
|
+
For each topic in `topics`:
|
|
21
|
+
1. Read the migration prompt from `migrationPromptPath` — these contain specific transformation rules with BEFORE/AFTER examples
|
|
22
|
+
2. If `patternPath` is provided, read the pattern file — this shows what correct target code looks like
|
|
23
|
+
|
|
24
|
+
Do NOT read all prompts upfront. Load each topic's knowledge just before processing that topic.
|
|
25
|
+
|
|
26
|
+
## Processing Strategy
|
|
27
|
+
|
|
28
|
+
### Topic Order
|
|
29
|
+
|
|
30
|
+
Process topics in this order (dependencies first):
|
|
31
|
+
1. `notifications-migration` — may create new files and restructure directories
|
|
32
|
+
2. `nswag-migration` — type-level changes that affect all other code
|
|
33
|
+
3. `widgets-migration` — creates new composable files referenced by blades
|
|
34
|
+
4. `blade-form-migration` — depends on correct types from nswag
|
|
35
|
+
5. `blade-props-migration` — final cleanup of reusable components
|
|
36
|
+
|
|
37
|
+
Skip topics not present in the `topics` input.
|
|
38
|
+
|
|
39
|
+
### Per-File Strategy
|
|
40
|
+
|
|
41
|
+
For each affected file in the current topic:
|
|
42
|
+
|
|
43
|
+
1. **Read the file** completely
|
|
44
|
+
2. **Apply transformation rules** from the loaded migration prompt — follow the BEFORE/AFTER patterns exactly
|
|
45
|
+
3. **Create new files if required** by the prompt (e.g. `widgets/useXxxWidgets.ts` for widget migration)
|
|
46
|
+
4. **Write the modified file**
|
|
47
|
+
5. **Type-check:** Run `cd {cwd} && npx vue-tsc --noEmit 2>&1 | head -30` to check for errors
|
|
48
|
+
6. **If errors in this file:** Read error messages, fix, re-check. Max 3 attempts.
|
|
49
|
+
7. **If fixed or clean:** Commit: `fix(migrate): {topic name} — {filename}`
|
|
50
|
+
8. **If still broken after 3 attempts:** Revert the file (`git checkout -- {filepath}`), report as "needs manual intervention", continue to next file
|
|
51
|
+
|
|
52
|
+
### Important Rules
|
|
53
|
+
|
|
54
|
+
1. **Only modify files listed in the topic's `affectedFiles`** — do not touch other files unless creating new files required by the migration prompt (e.g. widget composables)
|
|
55
|
+
2. **Follow transformation rules exactly** — each migration prompt has specific BEFORE/AFTER patterns. Apply them mechanically.
|
|
56
|
+
3. **Do not add features or refactor** — only transform existing code to the new API
|
|
57
|
+
4. **Preserve all business logic** — the behavior must stay identical after migration
|
|
58
|
+
5. **Commit after each successfully migrated file** — atomic commits for easy rollback
|
|
59
|
+
6. **Do not modify `api_client/` directory** — generated code, not consumer code
|
|
60
|
+
7. **Do not modify `node_modules/`**
|
|
61
|
+
|
|
62
|
+
## Output
|
|
63
|
+
|
|
64
|
+
When all topics are processed, report:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
## Migration Agent Report
|
|
68
|
+
|
|
69
|
+
### Completed
|
|
70
|
+
- {topic}: {N} files migrated
|
|
71
|
+
- src/path/to/file.vue ✅
|
|
72
|
+
- src/path/to/other.ts ✅
|
|
73
|
+
|
|
74
|
+
### Failed (needs manual intervention)
|
|
75
|
+
- {topic}: {M} files failed
|
|
76
|
+
- src/path/to/problem.vue — {error description}
|
|
77
|
+
|
|
78
|
+
### New Files Created
|
|
79
|
+
- src/modules/xxx/widgets/useXxxWidgets.ts
|
|
80
|
+
|
|
81
|
+
### Remaining TypeScript Errors
|
|
82
|
+
{output of final vue-tsc --noEmit, if any}
|
|
83
|
+
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Synced from framework at commit
|
|
1
|
+
Synced from framework at commit b399787ff on 2026-04-14T15:15:27.844Z
|
|
@@ -54,6 +54,7 @@ const toolbar = ref<IBladeToolbar[]>([
|
|
|
54
54
|
| Property | Type | Description |
|
|
55
55
|
|----------|------|-------------|
|
|
56
56
|
| `setBaseline()` | `() => void` | Snapshot current data as pristine. Call after load and after save |
|
|
57
|
+
| `markReady()` | `() => void` | Mark form ready without resetting pristine snapshot. Computes modification state from current data vs setup-time snapshot |
|
|
57
58
|
| `revert()` | `() => void \| Promise<void>` | Revert data to pristine (or call onRevert) |
|
|
58
59
|
| `canSave` | `ComputedRef<boolean>` | `isReady && valid && modified && canSaveOverride` |
|
|
59
60
|
| `isModified` | `ComputedRef<boolean>` | Data differs from pristine (false until setBaseline) |
|
|
@@ -64,9 +65,16 @@ const toolbar = ref<IBladeToolbar[]>([
|
|
|
64
65
|
|
|
65
66
|
## Lifecycle
|
|
66
67
|
|
|
68
|
+
### Standard (edit existing entity)
|
|
67
69
|
```
|
|
68
70
|
Mount → Load data → setBaseline() → User edits → Save → setBaseline()
|
|
69
|
-
|
|
71
|
+
└→ Cancel → revert()
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Pre-filled (create from template)
|
|
75
|
+
```
|
|
76
|
+
Mount → Pre-fill data → markReady() → canSave = true immediately
|
|
77
|
+
└→ Save → setBaseline()
|
|
70
78
|
```
|
|
71
79
|
|
|
72
80
|
## VcBlade Integration
|
|
@@ -102,6 +110,52 @@ const form = useBladeForm({
|
|
|
102
110
|
});
|
|
103
111
|
```
|
|
104
112
|
|
|
113
|
+
## Advanced: Pre-filled Entity (markReady)
|
|
114
|
+
|
|
115
|
+
When creating a new entity that is pre-populated from a parent (e.g. new offer from a product), the form should be immediately saveable. Use `markReady()` instead of `setBaseline()`:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const form = useBladeForm({ data: item });
|
|
119
|
+
|
|
120
|
+
onMounted(async () => {
|
|
121
|
+
// Populate base fields
|
|
122
|
+
item.value.sku = generateSku();
|
|
123
|
+
await addEmptyInventory();
|
|
124
|
+
|
|
125
|
+
const hasTemplate = !param.value && !!options.value?.templateId;
|
|
126
|
+
|
|
127
|
+
if (hasTemplate) {
|
|
128
|
+
// Fill from template — data diverges from the setup-time snapshot
|
|
129
|
+
await fillFromTemplate(options.value.templateId);
|
|
130
|
+
// Mark ready: compares current data to setup-time snapshot → isModified = true
|
|
131
|
+
form.markReady();
|
|
132
|
+
} else {
|
|
133
|
+
// Standard load — current state becomes the pristine baseline
|
|
134
|
+
await loadItem({ id: param.value });
|
|
135
|
+
form.setBaseline();
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### setBaseline vs markReady
|
|
141
|
+
|
|
142
|
+
| | `setBaseline()` | `markReady()` |
|
|
143
|
+
|--|-----------------|---------------|
|
|
144
|
+
| Sets `isReady` | yes | yes |
|
|
145
|
+
| Updates pristine snapshot | yes (current data → pristine) | no (keeps setup-time snapshot) |
|
|
146
|
+
| `trackerIsModified` after call | `false` | computed: `data !== pristineSnapshot` |
|
|
147
|
+
| Use case | Load / Save — "this is the clean state" | Pre-fill — "form is ready, changes are intentional" |
|
|
148
|
+
|
|
149
|
+
### How it works
|
|
150
|
+
|
|
151
|
+
At composable creation, `useBladeForm` takes a snapshot of `data` (the **setup-time snapshot**). When `markReady()` is called:
|
|
152
|
+
|
|
153
|
+
1. `isReady` → `true` (gates `canSave` and the deep watcher)
|
|
154
|
+
2. `trackerIsModified` = `!semanticEqual(data, setupTimeSnapshot)` — since data was mutated during `onMounted`, this evaluates to `true`
|
|
155
|
+
3. Subsequent edits are tracked normally by the deep watcher
|
|
156
|
+
|
|
157
|
+
After save, call `setBaseline()` as usual to capture the saved state as the new pristine snapshot.
|
|
158
|
+
|
|
105
159
|
## Constraints
|
|
106
160
|
|
|
107
161
|
- **Must be called from component `setup()`** (or `<script setup>`). Do NOT call from shared data-composables.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# ChangePasswordPage
|
|
2
|
+
|
|
3
|
+
Change password page with current, new, and confirm password fields. Supports a `forced` mode for expired passwords that displays an info banner and is triggered by post-login redirect. This full-page variant is used when the user must change their password before accessing the application (e.g., expired password policy). For voluntary password changes from within the app, the `ChangePasswordButton` in the settings menu opens a popup instead.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- When a signed-in user wants to change their password (full-page flow)
|
|
8
|
+
- In `forced` mode after login when the user's password has expired
|
|
9
|
+
- The standard vc-shell routing maps `/change-password` to this page
|
|
10
|
+
|
|
11
|
+
## Basic Usage
|
|
12
|
+
|
|
13
|
+
```vue
|
|
14
|
+
<template>
|
|
15
|
+
<ChangePassword />
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<!-- Forced mode (expired password) -->
|
|
19
|
+
<template>
|
|
20
|
+
<ChangePassword forced />
|
|
21
|
+
</template>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
With custom branding:
|
|
25
|
+
|
|
26
|
+
```vue
|
|
27
|
+
<template>
|
|
28
|
+
<ChangePassword
|
|
29
|
+
forced
|
|
30
|
+
logo="/assets/my-company-logo.svg"
|
|
31
|
+
background="/assets/custom-background.jpg"
|
|
32
|
+
/>
|
|
33
|
+
</template>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Key Props
|
|
37
|
+
|
|
38
|
+
| Prop | Type | Default | Description |
|
|
39
|
+
|------|------|---------|-------------|
|
|
40
|
+
| `forced` | `boolean` | `false` | Show expired-password info banner and adjusted title |
|
|
41
|
+
| `logo` | `string` | - | Override logo image URL |
|
|
42
|
+
| `background` | `string` | - | Custom background image URL |
|
|
43
|
+
|
|
44
|
+
## Recipe: Router Configuration with Forced Mode
|
|
45
|
+
|
|
46
|
+
Set up the route so the login page can redirect here when the password is expired:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import ChangePassword from "@vc-shell/framework/shared/pages/ChangePasswordPage";
|
|
50
|
+
|
|
51
|
+
const routes = [
|
|
52
|
+
{
|
|
53
|
+
path: "/change-password",
|
|
54
|
+
name: "ChangePassword",
|
|
55
|
+
component: ChangePassword,
|
|
56
|
+
props: (route) => ({
|
|
57
|
+
forced: route.query.forced === "true",
|
|
58
|
+
}),
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
In the login flow, redirect when the user's password has expired:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
async function handleLogin() {
|
|
67
|
+
const result = await signIn(username.value, password.value);
|
|
68
|
+
if (result.passwordExpired) {
|
|
69
|
+
router.push({ name: "ChangePassword", query: { forced: "true" } });
|
|
70
|
+
} else {
|
|
71
|
+
router.push("/");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Features
|
|
77
|
+
|
|
78
|
+
- **Real-time password policy validation**: Uses `useUserManagement().validatePassword` to check the new password against the platform's policy as the user types (minimum length, required uppercase, lowercase, digits, special characters)
|
|
79
|
+
- **Equal password detection**: Shows a specific "Equal-passwords" error when the new password matches the current password, without making an API call
|
|
80
|
+
- **Confirm-password mismatch detection**: Validates that the new password and confirm password fields match
|
|
81
|
+
- **Forced mode banner**: When `forced` is `true`, displays an info banner explaining that the password has expired and must be changed
|
|
82
|
+
- **Cancel behavior**: Cancel button signs out the user and redirects to `/login`
|
|
83
|
+
- **Success redirect**: On successful password change, redirects to `/` (main application)
|
|
84
|
+
|
|
85
|
+
## Details
|
|
86
|
+
|
|
87
|
+
- **Auth layout**: Renders inside `VcAuthLayout`, providing the centered card design with logo and background.
|
|
88
|
+
- **Password policy**: The validation rules are fetched from the platform API and include configurable requirements (minimum length, character classes, etc.). The component displays these rules as a checklist.
|
|
89
|
+
- **Forced vs voluntary**: In forced mode (`forced=true`), the page title changes to reflect the expired password scenario, and an info banner explains why the change is required. The form fields and behavior are otherwise identical.
|
|
90
|
+
- **Sign-out on cancel**: If the user cancels during a forced password change, they are signed out. This prevents access to the application with an expired password.
|
|
91
|
+
|
|
92
|
+
## Tips
|
|
93
|
+
|
|
94
|
+
- The `forced` prop is typically set via a route query parameter, not hardcoded. The login page detects expired passwords and redirects with the appropriate flag.
|
|
95
|
+
- Password policy validation runs on keyup, providing immediate feedback. The submit button is disabled until all policy requirements are met and the passwords match.
|
|
96
|
+
- This page is distinct from the `ChangePasswordButton` popup. The page is for full-screen flow (forced changes), while the popup is for voluntary in-app password changes.
|
|
97
|
+
|
|
98
|
+
## Related Components
|
|
99
|
+
|
|
100
|
+
- **VcAuthLayout** - The underlying centered card layout
|
|
101
|
+
- **LoginPage** - Redirects here when `user.passwordExpired` is true
|
|
102
|
+
- **ChangePasswordButton** - Settings menu popup variant for voluntary password changes
|
|
@@ -351,3 +351,7 @@ const validationHeader = computed(() =>
|
|
|
351
351
|
- [VcContainer](../vc-container/) -- scrollable content wrapper without header or collapsing
|
|
352
352
|
- [VcBanner](../vc-banner/) -- for alert/notification messages rather than content grouping
|
|
353
353
|
- [VcCol](../vc-col/) / [VcRow](../vc-row/) -- for grid-based layout within card bodies
|
|
354
|
+
|
|
355
|
+
## Skeleton / Loading State
|
|
356
|
+
|
|
357
|
+
When placed inside a `VcBlade` with `loading=true`, VcCard shows a skeleton header (if the `header` prop is set) while its body content renders normally — child components self-skeletonize via their own `BladeLoadingKey` injection.
|
|
@@ -250,3 +250,7 @@ interface AccordionItem {
|
|
|
250
250
|
## Related Components
|
|
251
251
|
|
|
252
252
|
- [VcAccordionItem](./_internal/vc-accordion-item/) -- individual accordion panel (used internally and available via the default slot)
|
|
253
|
+
|
|
254
|
+
## Skeleton / Loading State
|
|
255
|
+
|
|
256
|
+
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.
|
|
@@ -323,3 +323,8 @@ const selected = ref<string[]>([]);
|
|
|
323
323
|
- [VcSwitch](../vc-switch/) -- toggle switch for on/off settings
|
|
324
324
|
- [VcRadioButton](../vc-radio-button/) -- mutually exclusive single selection
|
|
325
325
|
- [VcInputGroup](../vc-input-group/) -- semantic wrapper for grouping checkboxes or radio buttons
|
|
326
|
+
|
|
327
|
+
## Skeleton / Loading State
|
|
328
|
+
|
|
329
|
+
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.
|
|
330
|
+
|
package/runtime/knowledge/docs/ui/components/molecules/vc-checkbox-group/vc-checkbox-group.docs.md
CHANGED
|
@@ -144,3 +144,8 @@ interface CheckboxGroupOption<V = string | number | boolean> {
|
|
|
144
144
|
- [VcCheckbox](../vc-checkbox/) — individual checkbox component
|
|
145
145
|
- [VcRadioGroup](../vc-radio-group/) — mutually exclusive 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
|
+
|
package/runtime/knowledge/docs/ui/components/molecules/vc-color-input/vc-color-input.docs.md
CHANGED
|
@@ -151,3 +151,8 @@ The native color picker does not support alpha/transparency. If you need RGBA co
|
|
|
151
151
|
|
|
152
152
|
- [VcInput](../vc-input/) -- general-purpose input (delegates to VcColorInput for `type="color"`)
|
|
153
153
|
- [VcField](../vc-field/) -- read-only field display (for showing a color value without editing)
|
|
154
|
+
|
|
155
|
+
## Skeleton / Loading State
|
|
156
|
+
|
|
157
|
+
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.
|
|
158
|
+
|
package/runtime/knowledge/docs/ui/components/molecules/vc-date-picker/vc-date-picker.docs.md
CHANGED
|
@@ -359,3 +359,10 @@ Uses the same `--input-*` variables as VcInput for consistent styling across all
|
|
|
359
359
|
|
|
360
360
|
- [VcInput](../vc-input/) -- general-purpose input; delegates to VcDatePicker for `type="date"` and `type="datetime-local"`
|
|
361
361
|
- [VcMultivalue](../vc-multivalue/) -- can handle multiple date values with `type="date"`
|
|
362
|
+
|
|
363
|
+
## Skeleton / Loading State
|
|
364
|
+
|
|
365
|
+
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.
|
|
366
|
+
|
|
367
|
+
This behavior is powered by `BladeLoadingKey` via Vue's provide/inject. The component injects the loading state from the nearest `VcBlade` ancestor.
|
|
368
|
+
|
|
@@ -298,3 +298,8 @@ const content = ref("<h1>Title</h1>");
|
|
|
298
298
|
|
|
299
299
|
- [VcTextarea](../vc-textarea/) -- plain multi-line text input (no formatting)
|
|
300
300
|
- [VcInput](../vc-input/) -- single-line text input
|
|
301
|
+
|
|
302
|
+
## Skeleton / Loading State
|
|
303
|
+
|
|
304
|
+
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.
|
|
305
|
+
|
|
@@ -166,3 +166,8 @@ The `type` prop affects rendering, not validation. Setting `type="email"` does n
|
|
|
166
166
|
- [VcInput](../vc-input/) -- editable text field (use instead when user input is needed)
|
|
167
167
|
- [VcLabel](../../atoms/vc-label/) -- standalone label atom used internally
|
|
168
168
|
- [VcCol](../../atoms/vc-col/) -- column layout atom used for aspect ratio
|
|
169
|
+
|
|
170
|
+
## Skeleton / Loading State
|
|
171
|
+
|
|
172
|
+
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.
|
|
173
|
+
|
package/runtime/knowledge/docs/ui/components/molecules/vc-file-upload/vc-file-upload.docs.md
CHANGED
|
@@ -322,3 +322,8 @@ async function onUpload(files: FileList) {
|
|
|
322
322
|
- [VcGallery](../../organisms/vc-gallery/) -- Full image gallery with preview, reorder, drag-and-drop sorting, and upload
|
|
323
323
|
- [VcImageTile](../vc-image-tile/) -- Image display tile used inside galleries
|
|
324
324
|
- [VcHint](../../atoms/vc-hint/) -- Used internally for error message display
|
|
325
|
+
|
|
326
|
+
## Skeleton / Loading State
|
|
327
|
+
|
|
328
|
+
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.
|
|
329
|
+
|
|
@@ -786,3 +786,10 @@ VcInput follows WAI-ARIA best practices for form fields:
|
|
|
786
786
|
- [VcInputGroup](../vc-input-group/) -- Groups multiple inputs with shared label, error state, and disabled state
|
|
787
787
|
- [VcLabel](../../atoms/vc-label/) -- The label atom used internally by VcInput
|
|
788
788
|
- [VcHint](../../atoms/vc-hint/) -- The hint/error atom used internally by VcInput
|
|
789
|
+
|
|
790
|
+
## Skeleton / Loading State
|
|
791
|
+
|
|
792
|
+
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.
|
|
793
|
+
|
|
794
|
+
This behavior is powered by `BladeLoadingKey` via Vue's provide/inject. The component injects the loading state from the nearest `VcBlade` ancestor.
|
|
795
|
+
|
package/runtime/knowledge/docs/ui/components/molecules/vc-input-currency/vc-input-currency.docs.md
CHANGED
|
@@ -368,3 +368,10 @@ Additionally inherits all `--input-*` CSS variables from VcInput/VcInputDropdown
|
|
|
368
368
|
- [VcInputDropdown](../vc-input-dropdown/) -- the underlying composite input + dropdown component
|
|
369
369
|
- [VcInput](../vc-input/) -- plain input for non-currency numbers
|
|
370
370
|
- [VcSelect](../vc-select/) -- standalone dropdown selection
|
|
371
|
+
|
|
372
|
+
## Skeleton / Loading State
|
|
373
|
+
|
|
374
|
+
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.
|
|
375
|
+
|
|
376
|
+
This behavior is powered by `BladeLoadingKey` via Vue's provide/inject. The component injects the loading state from the nearest `VcBlade` ancestor.
|
|
377
|
+
|
package/runtime/knowledge/docs/ui/components/molecules/vc-input-dropdown/vc-input-dropdown.docs.md
CHANGED
|
@@ -305,3 +305,10 @@ Replace the default dropdown toggle with a custom element using the `button` slo
|
|
|
305
305
|
- [VcInputCurrency](../vc-input-currency/) -- Currency-specific variant with built-in locale formatting
|
|
306
306
|
- [VcInput](../vc-input/) -- Standalone text input (used internally)
|
|
307
307
|
- [VcSelect](../vc-select/) -- Standalone dropdown selection (used internally)
|
|
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
|
+
|
|
@@ -345,3 +345,10 @@ The component uses `--multivalue-*` variables that fall back to `--select-*` tok
|
|
|
345
345
|
- [VcSelect](../vc-select/) -- dropdown for single/multi selection without manual entry
|
|
346
346
|
- [VcInput](../vc-input/) -- single-value text input
|
|
347
347
|
- [VcInputGroup](../vc-input-group/) -- semantic wrapper for grouping form controls
|
|
348
|
+
|
|
349
|
+
## Skeleton / Loading State
|
|
350
|
+
|
|
351
|
+
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.
|
|
352
|
+
|
|
353
|
+
This behavior is powered by `BladeLoadingKey` via Vue's provide/inject. The component injects the loading state from the nearest `VcBlade` ancestor.
|
|
354
|
+
|
package/runtime/knowledge/docs/ui/components/molecules/vc-radio-button/vc-radio-button.docs.md
CHANGED
|
@@ -161,3 +161,8 @@ Do not mix `binary` mode with regular `value` comparison in the same group. Bina
|
|
|
161
161
|
- [VcSwitch](../vc-switch/) -- for on/off toggles
|
|
162
162
|
- [VcInputGroup](../vc-input-group/) -- semantic wrapper with `role="radiogroup"`
|
|
163
163
|
- [VcSelect](../vc-select/) -- dropdown for larger option sets
|
|
164
|
+
|
|
165
|
+
## Skeleton / Loading State
|
|
166
|
+
|
|
167
|
+
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.
|
|
168
|
+
|
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
|
|