component-auto-docs 0.1.0 → 0.1.2
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/README.md +125 -34
- package/bin/component-auto-docs.mjs +1 -0
- package/core/generate-component-docs.mjs +590 -83
- package/package.json +2 -1
- package/templates/docs/components/README.md +1 -1
- package/templates/src/docs/runtime/component-doc-page.vue +166 -71
- package/templates/src/docs/runtime/use-auto-component-doc.ts +87 -44
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "component-auto-docs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Component docs automation CLI for uni-app component libraries.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"SHARING.md"
|
|
15
15
|
],
|
|
16
16
|
"peerDependencies": {
|
|
17
|
+
"@vue/compiler-sfc": ">=3.4.0",
|
|
17
18
|
"typescript": ">=5.0.0"
|
|
18
19
|
},
|
|
19
20
|
"engines": {
|
|
@@ -69,7 +69,7 @@ pnpm exec component-auto-docs gen
|
|
|
69
69
|
pnpm exec component-auto-docs check
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
`scaffold` 会复制 `docs.config.mjs`、`src/docs/runtime/*`、`src/docs/index.vue` 和本文档规范,并向 `package.json` 写入 `docs:init`、`docs:gen`、`docs:check`、`docs:dev` 脚本。已有文件默认跳过;如需覆盖模板文件和脚本,可使用:
|
|
72
|
+
`scaffold` 会复制 `docs.config.mjs`、`src/docs/runtime/*`、`src/docs/index.vue` 和本文档规范,并向 `package.json` 写入 `docs:scaffold`、`docs:init`、`docs:gen`、`docs:check`、`docs:dev` 脚本。已有文件默认跳过;如需覆盖模板文件和脚本,可使用:
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
75
|
pnpm exec component-auto-docs scaffold --force
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { computed, ref } from 'vue';
|
|
3
|
+
|
|
2
4
|
type DocItem = {
|
|
3
5
|
name: string;
|
|
4
6
|
title?: string;
|
|
@@ -26,13 +28,49 @@ type ComponentDoc = {
|
|
|
26
28
|
related: string[];
|
|
27
29
|
};
|
|
28
30
|
|
|
29
|
-
withDefaults(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const props = withDefaults(
|
|
32
|
+
defineProps<{
|
|
33
|
+
doc: ComponentDoc;
|
|
34
|
+
showControls?: boolean;
|
|
35
|
+
}>(),
|
|
36
|
+
{
|
|
37
|
+
showControls: true,
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const activeTab = ref('preview');
|
|
42
|
+
|
|
43
|
+
const docTabs = computed(() => {
|
|
44
|
+
const tabs = [{ key: 'preview', label: '预览' }];
|
|
45
|
+
|
|
46
|
+
if (props.doc.props.length || props.doc.events.length || props.doc.slots.length) {
|
|
47
|
+
tabs.push({ key: 'api', label: 'API' });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (props.doc.examples.length) {
|
|
51
|
+
tabs.push({ key: 'examples', label: '示例' });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (
|
|
55
|
+
props.doc.useWhen.length ||
|
|
56
|
+
props.doc.avoidWhen.length ||
|
|
57
|
+
props.doc.notes.length ||
|
|
58
|
+
props.doc.related.length
|
|
59
|
+
) {
|
|
60
|
+
tabs.push({ key: 'guide', label: '说明' });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return tabs;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const currentTab = computed(() => {
|
|
67
|
+
return docTabs.value.some((tab) => tab.key === activeTab.value) ? activeTab.value : 'preview';
|
|
34
68
|
});
|
|
35
69
|
|
|
70
|
+
function chooseTab(tabKey: string) {
|
|
71
|
+
activeTab.value = tabKey;
|
|
72
|
+
}
|
|
73
|
+
|
|
36
74
|
function formatDefault(value: unknown) {
|
|
37
75
|
if (value === null || value === undefined || value === '') return '-';
|
|
38
76
|
|
|
@@ -49,96 +87,116 @@ function formatDefault(value: unknown) {
|
|
|
49
87
|
<text class="doc-description">{{ doc.description }}</text>
|
|
50
88
|
</view>
|
|
51
89
|
|
|
52
|
-
<view class="doc-
|
|
53
|
-
<text
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
<text class="section-title">Props 控制面板</text>
|
|
63
|
-
<slot name="controls"></slot>
|
|
90
|
+
<view class="doc-tabs">
|
|
91
|
+
<text
|
|
92
|
+
v-for="tab in docTabs"
|
|
93
|
+
:key="tab.key"
|
|
94
|
+
class="doc-tab"
|
|
95
|
+
:class="{ active: currentTab === tab.key }"
|
|
96
|
+
@click="chooseTab(tab.key)"
|
|
97
|
+
>
|
|
98
|
+
{{ tab.label }}
|
|
99
|
+
</text>
|
|
64
100
|
</view>
|
|
65
101
|
|
|
66
|
-
<view v-if="
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
102
|
+
<view v-if="currentTab === 'preview'" class="doc-tab-panel">
|
|
103
|
+
<view class="doc-section">
|
|
104
|
+
<text class="section-title">真实组件预览</text>
|
|
105
|
+
<view class="preview-panel">
|
|
106
|
+
<slot name="preview">
|
|
107
|
+
<text class="empty-text">暂无可交互预览</text>
|
|
108
|
+
</slot>
|
|
109
|
+
</view>
|
|
110
|
+
</view>
|
|
70
111
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
112
|
+
<view v-if="showControls && $slots.controls" class="doc-section">
|
|
113
|
+
<text class="section-title">Props 控制面板</text>
|
|
114
|
+
<slot name="controls"></slot>
|
|
115
|
+
</view>
|
|
75
116
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
{{ item }}
|
|
117
|
+
<view v-if="$slots.code" class="doc-section">
|
|
118
|
+
<text class="section-title">当前代码片段预览</text>
|
|
119
|
+
<slot name="code"></slot>
|
|
80
120
|
</view>
|
|
81
121
|
</view>
|
|
82
122
|
|
|
83
|
-
<view class="doc-
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
<view class="api-card
|
|
87
|
-
<
|
|
88
|
-
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
123
|
+
<view v-else-if="currentTab === 'api'" class="doc-tab-panel">
|
|
124
|
+
<view v-if="doc.props.length" class="doc-section">
|
|
125
|
+
<text class="section-title">Props</text>
|
|
126
|
+
<view v-for="prop in doc.props" :key="prop.name" class="api-card">
|
|
127
|
+
<view class="api-card-head">
|
|
128
|
+
<text class="api-name">{{ prop.name }}</text>
|
|
129
|
+
<view class="api-head-meta">
|
|
130
|
+
<text class="api-pill">{{ prop.type }}</text>
|
|
131
|
+
<text class="api-pill">default: {{ formatDefault(prop.default) }}</text>
|
|
132
|
+
<text v-if="prop.required" class="api-pill is-required">必填</text>
|
|
133
|
+
</view>
|
|
134
|
+
</view>
|
|
135
|
+
<text class="api-desc">{{ prop.description || '暂无说明' }}</text>
|
|
136
|
+
<view v-if="prop.values?.length" class="chip-list">
|
|
137
|
+
<text v-for="value in prop.values" :key="value" class="chip">{{ value }}</text>
|
|
92
138
|
</view>
|
|
93
139
|
</view>
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
140
|
+
</view>
|
|
141
|
+
|
|
142
|
+
<view v-if="doc.events.length" class="doc-section">
|
|
143
|
+
<text class="section-title">Events</text>
|
|
144
|
+
<view v-for="event in doc.events" :key="event.name" class="api-card">
|
|
145
|
+
<view class="api-card-head">
|
|
146
|
+
<text class="api-name">{{ event.name }}</text>
|
|
147
|
+
<text class="api-pill">{{ event.type }}</text>
|
|
148
|
+
</view>
|
|
149
|
+
<text class="api-desc">{{ event.description || '暂无说明' }}</text>
|
|
97
150
|
</view>
|
|
98
151
|
</view>
|
|
99
|
-
</view>
|
|
100
152
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
153
|
+
<view v-if="doc.slots.length" class="doc-section">
|
|
154
|
+
<text class="section-title">Slots</text>
|
|
155
|
+
<view v-for="slot in doc.slots" :key="slot.name" class="api-card">
|
|
156
|
+
<view class="api-card-head">
|
|
157
|
+
<text class="api-name">{{ slot.name }}</text>
|
|
158
|
+
</view>
|
|
159
|
+
<text class="api-desc">{{ slot.description || '暂无说明' }}</text>
|
|
107
160
|
</view>
|
|
108
|
-
<text class="api-desc">{{ event.description || '暂无说明' }}</text>
|
|
109
161
|
</view>
|
|
110
162
|
</view>
|
|
111
163
|
|
|
112
|
-
<view class="doc-
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
<view class="
|
|
116
|
-
<text class="
|
|
164
|
+
<view v-else-if="currentTab === 'examples'" class="doc-tab-panel">
|
|
165
|
+
<view class="doc-section">
|
|
166
|
+
<text class="section-title">示例代码</text>
|
|
167
|
+
<view v-for="example in doc.examples" :key="example.code" class="example-card">
|
|
168
|
+
<text class="example-title">{{ example.title }}</text>
|
|
169
|
+
<text v-if="example.description" class="example-desc">{{ example.description }}</text>
|
|
170
|
+
<view class="code-card">
|
|
171
|
+
<text class="code-text">{{ example.code }}</text>
|
|
172
|
+
</view>
|
|
117
173
|
</view>
|
|
118
|
-
<text class="api-desc">{{ slot.description || '暂无说明' }}</text>
|
|
119
174
|
</view>
|
|
120
175
|
</view>
|
|
121
176
|
|
|
122
|
-
<view class="doc-
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
|
|
177
|
+
<view v-else-if="currentTab === 'guide'" class="doc-tab-panel">
|
|
178
|
+
<view v-if="doc.useWhen.length" class="doc-section">
|
|
179
|
+
<text class="section-title">何时使用</text>
|
|
180
|
+
<view v-for="item in doc.useWhen" :key="item" class="text-card">{{ item }}</view>
|
|
181
|
+
</view>
|
|
126
182
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
<text v-if="example.description" class="example-desc">{{ example.description }}</text>
|
|
132
|
-
<view class="code-card">
|
|
133
|
-
<text class="code-text">{{ example.code }}</text>
|
|
183
|
+
<view v-if="doc.avoidWhen.length" class="doc-section">
|
|
184
|
+
<text class="section-title">不建议使用</text>
|
|
185
|
+
<view v-for="item in doc.avoidWhen" :key="item" class="text-card is-warning">
|
|
186
|
+
{{ item }}
|
|
134
187
|
</view>
|
|
135
188
|
</view>
|
|
136
|
-
</view>
|
|
137
189
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
190
|
+
<view v-if="doc.notes.length" class="doc-section">
|
|
191
|
+
<text class="section-title">注意事项</text>
|
|
192
|
+
<view v-for="item in doc.notes" :key="item" class="text-card">{{ item }}</view>
|
|
193
|
+
</view>
|
|
194
|
+
|
|
195
|
+
<view v-if="doc.related.length" class="doc-section">
|
|
196
|
+
<text class="section-title">相关组件</text>
|
|
197
|
+
<view class="chip-list">
|
|
198
|
+
<text v-for="item in doc.related" :key="item" class="chip">{{ item }}</text>
|
|
199
|
+
</view>
|
|
142
200
|
</view>
|
|
143
201
|
</view>
|
|
144
202
|
</view>
|
|
@@ -211,6 +269,43 @@ page {
|
|
|
211
269
|
font-size: 26rpx;
|
|
212
270
|
}
|
|
213
271
|
|
|
272
|
+
.doc-tabs {
|
|
273
|
+
position: sticky;
|
|
274
|
+
top: 0;
|
|
275
|
+
z-index: 5;
|
|
276
|
+
display: flex;
|
|
277
|
+
flex-direction: row;
|
|
278
|
+
gap: 10rpx;
|
|
279
|
+
padding: 18rpx 0 8rpx;
|
|
280
|
+
overflow-x: auto;
|
|
281
|
+
background: #f4f7fb;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.doc-tab {
|
|
285
|
+
box-sizing: border-box;
|
|
286
|
+
flex: 0 0 auto;
|
|
287
|
+
min-width: 124rpx;
|
|
288
|
+
padding: 13rpx 20rpx;
|
|
289
|
+
font-size: 25rpx;
|
|
290
|
+
font-weight: 600;
|
|
291
|
+
line-height: 1.35;
|
|
292
|
+
color: #475569;
|
|
293
|
+
text-align: center;
|
|
294
|
+
background: #fff;
|
|
295
|
+
border: 1rpx solid #d9e2ef;
|
|
296
|
+
border-radius: 8rpx;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.doc-tab.active {
|
|
300
|
+
color: #fff;
|
|
301
|
+
background: #2563eb;
|
|
302
|
+
border-color: #2563eb;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.doc-tab-panel {
|
|
306
|
+
width: 100%;
|
|
307
|
+
}
|
|
308
|
+
|
|
214
309
|
.doc-section {
|
|
215
310
|
display: flex;
|
|
216
311
|
flex-direction: column;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, reactive, watch } from 'vue';
|
|
1
|
+
import { computed, reactive, ref, watch } from 'vue';
|
|
2
2
|
|
|
3
3
|
export type DocItem = {
|
|
4
4
|
name: string;
|
|
@@ -11,6 +11,18 @@ export type DocItem = {
|
|
|
11
11
|
code?: string;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
export type ComponentPreview = {
|
|
15
|
+
source?: string;
|
|
16
|
+
kind?: 'inline' | 'form' | 'data-list' | 'measure' | 'overlay' | 'page-shell' | 'native' | 'composite';
|
|
17
|
+
code?: string;
|
|
18
|
+
props?: Record<string, unknown>;
|
|
19
|
+
slots?: Record<string, string>;
|
|
20
|
+
vModel?: {
|
|
21
|
+
prop?: string;
|
|
22
|
+
variable?: string;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
14
26
|
export type ComponentDoc = {
|
|
15
27
|
name: string;
|
|
16
28
|
title: string;
|
|
@@ -19,6 +31,7 @@ export type ComponentDoc = {
|
|
|
19
31
|
props: DocItem[];
|
|
20
32
|
events: DocItem[];
|
|
21
33
|
slots: DocItem[];
|
|
34
|
+
preview?: ComponentPreview | null;
|
|
22
35
|
examples: DocItem[];
|
|
23
36
|
useWhen: string[];
|
|
24
37
|
avoidWhen: string[];
|
|
@@ -28,6 +41,7 @@ export type ComponentDoc = {
|
|
|
28
41
|
|
|
29
42
|
export function useAutoComponentDoc(doc: ComponentDoc) {
|
|
30
43
|
const propControls = reactive<Record<string, unknown>>({});
|
|
44
|
+
const overlayPreviewVisible = ref(false);
|
|
31
45
|
|
|
32
46
|
function isBooleanProp(prop: DocItem) {
|
|
33
47
|
return (prop.type || '').toLowerCase().includes('boolean');
|
|
@@ -51,20 +65,6 @@ export function useAutoComponentDoc(doc: ComponentDoc) {
|
|
|
51
65
|
return type.includes('object') || type.includes('Object');
|
|
52
66
|
}
|
|
53
67
|
|
|
54
|
-
function getFallbackNumber(prop: DocItem) {
|
|
55
|
-
const name = prop.name.toLowerCase();
|
|
56
|
-
|
|
57
|
-
if (name === 'modelvalue') return 1;
|
|
58
|
-
if (name.includes('percent')) return 60;
|
|
59
|
-
if (name.includes('size') || name.includes('font')) return 32;
|
|
60
|
-
if (name === 'w' || name.includes('width')) return 240;
|
|
61
|
-
if (name === 'h' || name.includes('height')) return 80;
|
|
62
|
-
if (name.includes('max')) return 10;
|
|
63
|
-
if (name.includes('min')) return 0;
|
|
64
|
-
|
|
65
|
-
return 1;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
68
|
function parseNumberValue(value: unknown) {
|
|
69
69
|
if (typeof value === 'number') return Number.isFinite(value) ? value : undefined;
|
|
70
70
|
if (typeof value !== 'string') return undefined;
|
|
@@ -78,36 +78,28 @@ export function useAutoComponentDoc(doc: ComponentDoc) {
|
|
|
78
78
|
return Number.isFinite(numberValue) ? numberValue : undefined;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
function
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
function hasPreviewProp(propName: string) {
|
|
82
|
+
return Boolean(doc.preview?.props && Object.prototype.hasOwnProperty.call(doc.preview.props, propName));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function formatInitialControlValue(prop: DocItem, value: unknown) {
|
|
86
|
+
if ((isArrayProp(prop) || isObjectProp(prop)) && typeof value !== 'string') {
|
|
87
|
+
return JSON.stringify(value ?? (isArrayProp(prop) ? [] : {}), null, 2);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
84
92
|
|
|
85
|
-
|
|
93
|
+
function getSampleValue(prop: DocItem) {
|
|
94
|
+
if (hasPreviewProp(prop.name)) {
|
|
95
|
+
return formatInitialControlValue(prop, doc.preview?.props?.[prop.name]);
|
|
86
96
|
}
|
|
87
97
|
|
|
88
|
-
if (prop.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (isBooleanProp(prop)) return false;
|
|
93
|
-
if (isNumberProp(prop)) return getFallbackNumber(prop);
|
|
94
|
-
if (isArrayProp(prop)) {
|
|
95
|
-
return JSON.stringify(
|
|
96
|
-
[
|
|
97
|
-
{ label: '选项一', value: 'one' },
|
|
98
|
-
{ label: '选项二', value: 'two' },
|
|
99
|
-
],
|
|
100
|
-
null,
|
|
101
|
-
2,
|
|
102
|
-
);
|
|
98
|
+
if (prop.default !== null && prop.default !== undefined && prop.default !== '') {
|
|
99
|
+
if (isNumberProp(prop)) return parseNumberValue(prop.default) ?? '';
|
|
100
|
+
|
|
101
|
+
return formatInitialControlValue(prop, prop.default);
|
|
103
102
|
}
|
|
104
|
-
if (isObjectProp(prop)) return '{}';
|
|
105
|
-
if (name.includes('placeholder')) return '请输入';
|
|
106
|
-
if (name.includes('title')) return '标题';
|
|
107
|
-
if (name.includes('label')) return '标签';
|
|
108
|
-
if (name.includes('text') || name.includes('content')) return '示例内容';
|
|
109
|
-
if (name.includes('phone')) return '13800000000';
|
|
110
|
-
if (name === 'icon') return '/static/icon/avatar.svg';
|
|
111
103
|
|
|
112
104
|
return '';
|
|
113
105
|
}
|
|
@@ -147,6 +139,8 @@ export function useAutoComponentDoc(doc: ComponentDoc) {
|
|
|
147
139
|
}
|
|
148
140
|
|
|
149
141
|
function resetControls() {
|
|
142
|
+
overlayPreviewVisible.value = false;
|
|
143
|
+
|
|
150
144
|
for (const prop of doc.props) {
|
|
151
145
|
propControls[prop.name] = getSampleValue(prop);
|
|
152
146
|
}
|
|
@@ -166,18 +160,61 @@ export function useAutoComponentDoc(doc: ComponentDoc) {
|
|
|
166
160
|
return result;
|
|
167
161
|
});
|
|
168
162
|
|
|
163
|
+
const isOverlayPreview = computed(() => doc.preview?.kind === 'overlay');
|
|
164
|
+
|
|
165
|
+
const overlayModelProp = computed(() => {
|
|
166
|
+
if (!isOverlayPreview.value) return '';
|
|
167
|
+
|
|
168
|
+
const configuredProp = doc.preview?.vModel?.prop;
|
|
169
|
+
if (configuredProp && doc.props.some((prop) => prop.name === configuredProp)) return configuredProp;
|
|
170
|
+
|
|
171
|
+
const modelProp = doc.props.find((prop) => prop.name === 'modelValue' && isBooleanProp(prop));
|
|
172
|
+
return modelProp?.name || '';
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const renderedPreviewProps = computed(() => {
|
|
176
|
+
const result = { ...previewProps.value };
|
|
177
|
+
|
|
178
|
+
if (isOverlayPreview.value && overlayModelProp.value) {
|
|
179
|
+
result[overlayModelProp.value] = overlayPreviewVisible.value;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return result;
|
|
183
|
+
});
|
|
184
|
+
|
|
169
185
|
const slotText = computed(() => {
|
|
170
|
-
|
|
186
|
+
return doc.preview?.slots?.default || '';
|
|
187
|
+
});
|
|
171
188
|
|
|
172
|
-
|
|
189
|
+
const previewKey = computed(() => {
|
|
190
|
+
return JSON.stringify({
|
|
191
|
+
props: renderedPreviewProps.value,
|
|
192
|
+
slot: slotText.value,
|
|
193
|
+
});
|
|
173
194
|
});
|
|
174
195
|
|
|
196
|
+
const overlayTriggerText = computed(() => {
|
|
197
|
+
return overlayPreviewVisible.value ? '重新打开预览' : '打开预览';
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
function openOverlayPreview() {
|
|
201
|
+
overlayPreviewVisible.value = true;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function handlePreviewModelValueUpdate(propName: string, value: unknown) {
|
|
205
|
+
setControlValue(propName, value);
|
|
206
|
+
|
|
207
|
+
if (isOverlayPreview.value && propName === overlayModelProp.value) {
|
|
208
|
+
overlayPreviewVisible.value = Boolean(value);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
175
212
|
const codeSnippet = computed(() => {
|
|
176
213
|
const attrs = doc.props
|
|
177
214
|
.map((prop) => {
|
|
178
215
|
const value = parseControlValue(prop, propControls[prop.name]);
|
|
179
216
|
if (value === '' || value === null || value === undefined) return '';
|
|
180
|
-
if (prop.name === 'modelValue') return
|
|
217
|
+
if (prop.name === 'modelValue') return `v-model="${doc.preview?.vModel?.variable || 'value'}"`;
|
|
181
218
|
if (typeof value === 'boolean') return value ? prop.name : `:${prop.name}="false"`;
|
|
182
219
|
if (typeof value === 'number') return `:${prop.name}="${value}"`;
|
|
183
220
|
if (Array.isArray(value) || typeof value === 'object') return `:${prop.name}="${prop.name}"`;
|
|
@@ -194,8 +231,14 @@ export function useAutoComponentDoc(doc: ComponentDoc) {
|
|
|
194
231
|
return {
|
|
195
232
|
propControls,
|
|
196
233
|
previewProps,
|
|
234
|
+
renderedPreviewProps,
|
|
235
|
+
previewKey,
|
|
197
236
|
slotText,
|
|
198
237
|
codeSnippet,
|
|
238
|
+
isOverlayPreview,
|
|
239
|
+
overlayTriggerText,
|
|
240
|
+
openOverlayPreview,
|
|
241
|
+
handlePreviewModelValueUpdate,
|
|
199
242
|
isBooleanProp,
|
|
200
243
|
isNumberProp,
|
|
201
244
|
isArrayProp,
|