cardbuddy 0.6.0

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 (167) hide show
  1. package/README.md +211 -0
  2. package/dist/cli.js +76 -0
  3. package/dist/config.js +63 -0
  4. package/dist/core.js +2 -0
  5. package/dist/preview-editor/assets/apple-touch-icon-BQcES9QK.png +0 -0
  6. package/dist/preview-editor/assets/default-image-wzZYQ86K.png +0 -0
  7. package/dist/preview-editor/assets/favicon-16-Cg6Nrosk.png +0 -0
  8. package/dist/preview-editor/assets/favicon-32-B_1744sp.png +0 -0
  9. package/dist/preview-editor/assets/index-BYB0hngG.js +72 -0
  10. package/dist/preview-editor/assets/index-CpBZEQDy.css +1 -0
  11. package/dist/preview-editor/assets/site-icon-CFMif8z4.png +0 -0
  12. package/dist/preview-editor/assets/svg-symbols-B2exBrAr.svg +118 -0
  13. package/dist/preview-editor/index.html +17 -0
  14. package/dist/server-core/_vendor/finmall-env.mjs +96 -0
  15. package/dist/server-core/assetProxy.js +154 -0
  16. package/dist/server-core/bbox.js +153 -0
  17. package/dist/server-core/browser.js +108 -0
  18. package/dist/server-core/buildDataFromSchema.js +50 -0
  19. package/dist/server-core/cardFiles.js +188 -0
  20. package/dist/server-core/cardHistory.js +156 -0
  21. package/dist/server-core/cardImage.js +85 -0
  22. package/dist/server-core/cardImportMeta.js +139 -0
  23. package/dist/server-core/cardListCache.js +68 -0
  24. package/dist/server-core/cardOpenFolder.js +135 -0
  25. package/dist/server-core/cardSave.js +127 -0
  26. package/dist/server-core/cardSidecar.js +72 -0
  27. package/dist/server-core/cardSync.js +259 -0
  28. package/dist/server-core/cardValidate.js +134 -0
  29. package/dist/server-core/index.js +82 -0
  30. package/dist/server-core/logger.js +241 -0
  31. package/dist/server-core/nodeModels.js +52 -0
  32. package/dist/server-core/renderStatus.js +207 -0
  33. package/dist/server-core/screenshot.js +123 -0
  34. package/dist/server-core/sliceStatic.js +44 -0
  35. package/dist/standalone.js +447 -0
  36. package/dist/vendored/App.vue +2330 -0
  37. package/dist/vendored/api.js +142 -0
  38. package/dist/vendored/assets/apple-touch-icon.png +0 -0
  39. package/dist/vendored/assets/default-image.png +0 -0
  40. package/dist/vendored/assets/favicon-16.png +0 -0
  41. package/dist/vendored/assets/favicon-32.png +0 -0
  42. package/dist/vendored/assets/logo.png +0 -0
  43. package/dist/vendored/assets/site-icon.png +0 -0
  44. package/dist/vendored/assets/svg-symbols.svg +118 -0
  45. package/dist/vendored/assets/svgIcons/icons.svg +54 -0
  46. package/dist/vendored/assets/svgIcons/index.js +39 -0
  47. package/dist/vendored/components/AbsoluteLayout.vue +42 -0
  48. package/dist/vendored/components/AlertCardInstance.vue +58 -0
  49. package/dist/vendored/components/AlertCardLayer.vue +59 -0
  50. package/dist/vendored/components/ApiPayloadTree.vue +168 -0
  51. package/dist/vendored/components/AppToast.vue +37 -0
  52. package/dist/vendored/components/Button.vue +37 -0
  53. package/dist/vendored/components/Canvas.vue +65 -0
  54. package/dist/vendored/components/CardGallery.vue +243 -0
  55. package/dist/vendored/components/CardPreview.vue +72 -0
  56. package/dist/vendored/components/CardSelect.vue +200 -0
  57. package/dist/vendored/components/CheckGroup.vue +131 -0
  58. package/dist/vendored/components/Column.vue +25 -0
  59. package/dist/vendored/components/ComponentPalette.vue +294 -0
  60. package/dist/vendored/components/ConfirmDialog.vue +39 -0
  61. package/dist/vendored/components/CustomPlaceholder.vue +33 -0
  62. package/dist/vendored/components/DatePickerOverlay.vue +345 -0
  63. package/dist/vendored/components/DebugPanel.vue +806 -0
  64. package/dist/vendored/components/DeviceOverlay.vue +70 -0
  65. package/dist/vendored/components/Divider.vue +22 -0
  66. package/dist/vendored/components/Dropdown.vue +191 -0
  67. package/dist/vendored/components/EventEditor.vue +247 -0
  68. package/dist/vendored/components/GridLayout.vue +67 -0
  69. package/dist/vendored/components/HoverGuides.vue +122 -0
  70. package/dist/vendored/components/Icon.vue +34 -0
  71. package/dist/vendored/components/Image.vue +34 -0
  72. package/dist/vendored/components/Input.vue +90 -0
  73. package/dist/vendored/components/JsonTree.vue +516 -0
  74. package/dist/vendored/components/ListLayout.vue +68 -0
  75. package/dist/vendored/components/LogValue.vue +51 -0
  76. package/dist/vendored/components/Map.vue +110 -0
  77. package/dist/vendored/components/MultiColumn.vue +49 -0
  78. package/dist/vendored/components/MultiText.vue +58 -0
  79. package/dist/vendored/components/NodeInspector.vue +295 -0
  80. package/dist/vendored/components/PickerOverlay.vue +131 -0
  81. package/dist/vendored/components/ProgressSlider.vue +167 -0
  82. package/dist/vendored/components/PropControl.vue +241 -0
  83. package/dist/vendored/components/PropTree.vue +128 -0
  84. package/dist/vendored/components/RadioButton.vue +74 -0
  85. package/dist/vendored/components/RemotePreview.vue +171 -0
  86. package/dist/vendored/components/RenderTree.vue +437 -0
  87. package/dist/vendored/components/Root.vue +30 -0
  88. package/dist/vendored/components/Row.vue +25 -0
  89. package/dist/vendored/components/SelectionOverlay.vue +105 -0
  90. package/dist/vendored/components/StructureTree.vue +949 -0
  91. package/dist/vendored/components/SvgCode.vue +19 -0
  92. package/dist/vendored/components/SvgSymbols.vue +30 -0
  93. package/dist/vendored/components/Switch.vue +38 -0
  94. package/dist/vendored/components/Text.vue +32 -0
  95. package/dist/vendored/components/Video.vue +70 -0
  96. package/dist/vendored/components/ViewContainer.vue +52 -0
  97. package/dist/vendored/components/base.js +12 -0
  98. package/dist/vendored/components/icons.js +47 -0
  99. package/dist/vendored/components/index.js +58 -0
  100. package/dist/vendored/components/setters/SetBgPosition.vue +64 -0
  101. package/dist/vendored/components/setters/SetBgSize.vue +90 -0
  102. package/dist/vendored/components/setters/SetCode.vue +90 -0
  103. package/dist/vendored/components/setters/SetColor.vue +244 -0
  104. package/dist/vendored/components/setters/SetCustomSelect.vue +58 -0
  105. package/dist/vendored/components/setters/SetExpr.vue +107 -0
  106. package/dist/vendored/components/setters/SetGradient.vue +125 -0
  107. package/dist/vendored/components/setters/SetGrid9.vue +68 -0
  108. package/dist/vendored/components/setters/SetIconSelect.vue +67 -0
  109. package/dist/vendored/components/setters/SetIfForm.vue +61 -0
  110. package/dist/vendored/components/setters/SetImage.vue +43 -0
  111. package/dist/vendored/components/setters/SetList.vue +139 -0
  112. package/dist/vendored/components/setters/SetNumber.vue +118 -0
  113. package/dist/vendored/components/setters/SetNumberStyle.vue +113 -0
  114. package/dist/vendored/components/setters/SetPadding.vue +77 -0
  115. package/dist/vendored/components/setters/SetSegment.vue +160 -0
  116. package/dist/vendored/components/setters/SetSelect.vue +51 -0
  117. package/dist/vendored/components/setters/SetSwitch.vue +49 -0
  118. package/dist/vendored/components/setters/SetText.vue +52 -0
  119. package/dist/vendored/components/setters/props.js +23 -0
  120. package/dist/vendored/fidelity/baseline-messageOverview.json +87 -0
  121. package/dist/vendored/fidelity/calibration.json +29 -0
  122. package/dist/vendored/fidelity/fidelity-messageOverview-after.html +114 -0
  123. package/dist/vendored/fidelity/fidelity-messageOverview-after.json +272 -0
  124. package/dist/vendored/fidelity/fidelity-messageOverview.html +185 -0
  125. package/dist/vendored/fidelity/fidelity-messageOverview.json +336 -0
  126. package/dist/vendored/fidelity/fidelity-messageOverview_v2.html +262 -0
  127. package/dist/vendored/fidelity/fidelity-messageOverview_v2.json +502 -0
  128. package/dist/vendored/fidelity/fidelity-messageOverview_v3.html +201 -0
  129. package/dist/vendored/fidelity/fidelity-messageOverview_v3.json +417 -0
  130. package/dist/vendored/fidelity/fidelity-messageOverview_visual.html +125 -0
  131. package/dist/vendored/fidelity/fidelity-messageOverview_visual.json +338 -0
  132. package/dist/vendored/index.html +16 -0
  133. package/dist/vendored/main.js +36 -0
  134. package/dist/vendored/meta/action-meta.json +141 -0
  135. package/dist/vendored/meta/component-meta.json +2714 -0
  136. package/dist/vendored/meta/directive-meta.json +40 -0
  137. package/dist/vendored/meta/style-meta.json +1086 -0
  138. package/dist/vendored/runtime/StyleParser.js +179 -0
  139. package/dist/vendored/runtime/adapter.js +166 -0
  140. package/dist/vendored/runtime/alert-card.js +125 -0
  141. package/dist/vendored/runtime/app-toast.js +33 -0
  142. package/dist/vendored/runtime/assets.js +16 -0
  143. package/dist/vendored/runtime/canvas-context.js +141 -0
  144. package/dist/vendored/runtime/card-runtime.js +289 -0
  145. package/dist/vendored/runtime/clipboard-node.js +83 -0
  146. package/dist/vendored/runtime/clipboard.js +29 -0
  147. package/dist/vendored/runtime/evaluate.js +152 -0
  148. package/dist/vendored/runtime/event-model.js +300 -0
  149. package/dist/vendored/runtime/hoverGuide.js +31 -0
  150. package/dist/vendored/runtime/jsapi-mock.js +256 -0
  151. package/dist/vendored/runtime/node-model.js +217 -0
  152. package/dist/vendored/runtime/property.js +364 -0
  153. package/dist/vendored/runtime/selectionOverlay.js +53 -0
  154. package/dist/vendored/runtime/toPreview.js +648 -0
  155. package/dist/vendored/standalone-main.js +36 -0
  156. package/dist/vendored/standalone.html +12 -0
  157. package/dist/vendored/styles/app.css +2565 -0
  158. package/dist/vendored/styles/card-gallery.css +234 -0
  159. package/dist/vendored/styles/card-select.css +281 -0
  160. package/dist/vendored/styles/components.css +383 -0
  161. package/dist/vendored/styles/dropdown.css +337 -0
  162. package/dist/vendored/styles/json-tree.css +308 -0
  163. package/dist/vendored/styles/node-inspector.css +1003 -0
  164. package/dist/vendored/styles/setters.css +962 -0
  165. package/dist/vendored/styles/standalone.css +27 -0
  166. package/dist/vendored/styles/structure-tree.css +320 -0
  167. package/package.json +42 -0
@@ -0,0 +1,294 @@
1
+ <!--
2
+ 组件选择面板:参考线上卡片编辑器「卡片-组件」面板(布局组件 / 基础组件 两组)。
3
+ 点击结构树每行的「+」后弹出,选择某类型组件即回调 pick(className),由上层负责插入。
4
+ 数据完全取自本地 component-meta.json(与线上分组一致),无图标资源时用文字占位。
5
+ -->
6
+ <template>
7
+ <div class="cp__mask" @click.self="$emit('close')">
8
+ <div class="cp" role="dialog" aria-label="选择组件类型">
9
+ <div class="cp__head">
10
+ <span class="cp__title">添加组件</span>
11
+ <span class="cp__hint">选择要插入的组件类型</span>
12
+ <button class="cp__close" type="button" title="关闭" @click="$emit('close')">✕</button>
13
+ </div>
14
+
15
+ <div class="cp__body">
16
+ <input
17
+ class="cp__search"
18
+ type="text"
19
+ v-model="query"
20
+ placeholder="搜索组件…"
21
+ title="按组件名 / 类型过滤"
22
+ />
23
+ <section v-for="g in filteredGroups" :key="g.key" class="cp__group">
24
+ <h4 class="cp__group-title">{{ g.key }}</h4>
25
+ <div class="cp__grid">
26
+ <button
27
+ v-for="item in g.items"
28
+ :key="item.className"
29
+ class="cp__item"
30
+ type="button"
31
+ :title="item.className"
32
+ @click="$emit('pick', item.className)"
33
+ >
34
+ <span class="cp__avatar" :data-g="g.key === '布局组件' ? 'layout' : 'basic'" v-html="iconSvg(item.glyph)"></span>
35
+ <span class="cp__item-name">{{ item.name }}</span>
36
+ <span class="cp__item-class">{{ item.className }}</span>
37
+ </button>
38
+ </div>
39
+ </section>
40
+ <p v-if="query && !filteredGroups.length" class="cp__empty">无匹配组件</p>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ </template>
45
+
46
+ <script>
47
+ import componentMetaJson from '../meta/component-meta.json'
48
+
49
+ /*
50
+ 统一风格的线性图标(Feather 同款:24x24、stroke=currentColor、圆角端点、无填充)。
51
+ 每个图标贴合组件语义:布局类用「容器框 + 内部排布示意」,基础类用「组件形态/用途」示意。
52
+ 几何统一集中在 preview/assets/svgIcons/icons.svg 的 #icon-glyph-<Name> 符号中;
53
+ 此处仅登记「有哪些组件类型具备语义图标」,供 iconSvg() 判断是否引用 sprite,否则回退首字。
54
+ */
55
+ const GLYPH_NAMES = [
56
+ 'Row', 'Column', 'MultiColumn', 'ListLayout', 'GridLayout', 'AbsoluteLayout',
57
+ 'ViewContainer', 'Text', 'Button', 'Image', 'Icon', 'MultiText', 'Canvas',
58
+ 'Input', 'CheckGroup', 'RadioButton', 'ProgressSlider', 'Video', 'Map', 'Divider',
59
+ ]
60
+
61
+ function buildGroups() {
62
+ const order = componentMetaJson.groups && componentMetaJson.groups.length
63
+ ? componentMetaJson.groups
64
+ : ['布局组件', '基础组件']
65
+ const byGroup = {}
66
+ const comps = componentMetaJson.components || {}
67
+ for (const key in comps) {
68
+ const m = comps[key]
69
+ const g = m.group || '基础组件'
70
+ if (!byGroup[g]) byGroup[g] = []
71
+ const name = m.name || key
72
+ byGroup[g].push({
73
+ className: key,
74
+ name,
75
+ // 用语义图标符号名(对应 icons.svg 的 #icon-glyph-<className>);缺失时回退首字
76
+ glyph: key,
77
+ })
78
+ }
79
+ return order
80
+ .filter((g) => byGroup[g] && byGroup[g].length)
81
+ .map((g) => ({ key: g, items: byGroup[g] }))
82
+ }
83
+
84
+ export default {
85
+ name: 'ComponentPalette',
86
+ emits: ['pick', 'close'],
87
+ data() {
88
+ return {
89
+ groups: buildGroups(),
90
+ query: '',
91
+ }
92
+ },
93
+ computed: {
94
+ /** 按组件名 / 类型过滤;无搜索词时返回全部分组 */
95
+ filteredGroups() {
96
+ const q = (this.query || '').trim().toLowerCase()
97
+ if (!q) return this.groups
98
+ return this.groups
99
+ .map((g) => ({
100
+ key: g.key,
101
+ items: g.items.filter((it) => {
102
+ const name = (it.name || '').toLowerCase()
103
+ const cls = (it.className || '').toLowerCase()
104
+ return name.indexOf(q) !== -1 || cls.indexOf(q) !== -1
105
+ }),
106
+ }))
107
+ .filter((g) => g.items.length)
108
+ },
109
+ },
110
+ methods: {
111
+ /** 统一引用 sprite 中的语义图标(#icon-glyph-<className>),保证尺寸/描边/配色一致 */
112
+ iconSvg(name) {
113
+ if (GLYPH_NAMES.indexOf(name) !== -1) {
114
+ return (
115
+ '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" ' +
116
+ 'stroke-linecap="round" stroke-linejoin="round" width="18" height="18">' +
117
+ '<use href="#icon-glyph-' + name + '"></use>' +
118
+ '</svg>'
119
+ )
120
+ }
121
+ // 兜底:无对应语义图标时使用中文名首字
122
+ return '<span class="cp__avatar-text">' + String(name).slice(0, 1) + '</span>'
123
+ },
124
+ },
125
+ }
126
+ </script>
127
+
128
+ <style scoped>
129
+ .cp__mask {
130
+ position: fixed;
131
+ inset: 0;
132
+ background: var(--scrim);
133
+ display: flex;
134
+ align-items: center;
135
+ justify-content: center;
136
+ z-index: 1000;
137
+ }
138
+
139
+ .cp {
140
+ width: 560px;
141
+ max-width: calc(100vw - 32px);
142
+ max-height: calc(100vh - 64px);
143
+ background: var(--bg-panel);
144
+ border: 1px solid var(--border-strong);
145
+ border-radius: 10px;
146
+ box-shadow: 0 18px 48px var(--shadow-pop);
147
+ display: flex;
148
+ flex-direction: column;
149
+ overflow: hidden;
150
+ color: var(--text);
151
+ }
152
+
153
+ .cp__head {
154
+ display: flex;
155
+ align-items: baseline;
156
+ gap: 10px;
157
+ padding: 14px 16px;
158
+ border-bottom: 1px solid var(--border-strong);
159
+ }
160
+ .cp__title {
161
+ font-size: 15px;
162
+ font-weight: 600;
163
+ }
164
+ .cp__hint {
165
+ font-size: 12px;
166
+ color: var(--text-dim);
167
+ }
168
+ .cp__close {
169
+ margin-left: auto;
170
+ background: transparent;
171
+ border: none;
172
+ color: var(--text-dim);
173
+ font-size: 16px;
174
+ cursor: pointer;
175
+ line-height: 1;
176
+ padding: 2px 6px;
177
+ border-radius: 4px;
178
+ }
179
+ .cp__close:hover {
180
+ background: var(--bg-hover);
181
+ color: var(--text);
182
+ }
183
+
184
+ .cp__body {
185
+ padding: 8px 16px 16px;
186
+ overflow-y: auto;
187
+ }
188
+
189
+ .cp__group {
190
+ margin-top: 12px;
191
+ }
192
+ .cp__group-title {
193
+ margin: 0 0 8px;
194
+ font-size: 12px;
195
+ font-weight: 600;
196
+ color: var(--text-faint);
197
+ letter-spacing: 0.04em;
198
+ }
199
+
200
+ .cp__grid {
201
+ display: grid;
202
+ grid-template-columns: repeat(4, 1fr);
203
+ gap: 8px;
204
+ }
205
+
206
+ .cp__item {
207
+ display: flex;
208
+ flex-direction: column;
209
+ align-items: center;
210
+ gap: 4px;
211
+ padding: 10px 6px;
212
+ background: var(--bg-input);
213
+ border: 1px solid var(--border);
214
+ border-radius: 8px;
215
+ cursor: pointer;
216
+ color: var(--text);
217
+ transition: border-color 0.12s, background 0.12s, transform 0.08s;
218
+ }
219
+ .cp__item:hover {
220
+ border-color: var(--accent);
221
+ background: var(--bg-hover);
222
+ transform: translateY(-1px);
223
+ }
224
+ .cp__item:active {
225
+ transform: translateY(0);
226
+ }
227
+
228
+ .cp__avatar {
229
+ width: 28px;
230
+ height: 28px;
231
+ border-radius: 6px;
232
+ display: flex;
233
+ align-items: center;
234
+ justify-content: center;
235
+ font-size: 15px;
236
+ font-weight: 600;
237
+ color: var(--on-accent);
238
+ background: var(--accent);
239
+ }
240
+ .cp__avatar[data-g='layout'] {
241
+ background: var(--accent-2);
242
+ }
243
+ .cp__avatar[data-g='basic'] {
244
+ background: var(--ok);
245
+ }
246
+ .cp__avatar svg {
247
+ display: block;
248
+ width: 18px;
249
+ height: 18px;
250
+ }
251
+ .cp__avatar-text {
252
+ display: flex;
253
+ align-items: center;
254
+ justify-content: center;
255
+ width: 18px;
256
+ height: 18px;
257
+ font-size: 13px;
258
+ font-weight: 600;
259
+ }
260
+
261
+ .cp__item-name {
262
+ font-size: 12px;
263
+ line-height: 1.2;
264
+ text-align: center;
265
+ }
266
+ .cp__item-class {
267
+ font-size: 10px;
268
+ color: var(--text-faint);
269
+ font-family: 'SF Mono', 'JetBrains Mono', Menlo, Consolas, monospace;
270
+ }
271
+ /* 组件面板搜索框 */
272
+ .cp__search {
273
+ box-sizing: border-box;
274
+ width: 100%;
275
+ height: 32px;
276
+ margin-bottom: 10px;
277
+ padding: 0 10px;
278
+ font-size: 13px;
279
+ color: var(--text);
280
+ background: var(--bg-input);
281
+ border: 1px solid var(--border);
282
+ border-radius: 8px;
283
+ outline: none;
284
+ }
285
+ .cp__search:focus {
286
+ border-color: var(--accent);
287
+ }
288
+ .cp__empty {
289
+ margin: 8px 0;
290
+ color: var(--text-dim);
291
+ font-size: 12px;
292
+ text-align: center;
293
+ }
294
+ </style>
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <transition name="confirm-fade">
3
+ <div v-if="visible" class="confirm-mask" @click.self="$emit('cancel')">
4
+ <div class="confirm-modal" role="alertdialog" aria-modal="true" :aria-label="title">
5
+ <div class="confirm-modal__title" :class="{ 'is-danger': danger }">
6
+ <svg v-if="danger" class="confirm-modal__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><use href="#icon-no-entry" /></svg>
7
+ <svg v-else class="confirm-modal__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><use href="#icon-gear" /></svg>
8
+ {{ title }}
9
+ </div>
10
+ <div class="confirm-modal__desc">{{ message }}</div>
11
+ <div class="confirm-modal__actions">
12
+ <button class="confirm-modal__btn confirm-modal__btn--ghost" type="button" @click="$emit('cancel')">{{ cancelText }}</button>
13
+ <button class="confirm-modal__btn" :class="danger ? 'confirm-modal__btn--danger' : 'confirm-modal__btn--primary'" type="button" @click="$emit('confirm')">{{ confirmText }}</button>
14
+ </div>
15
+ </div>
16
+ </div>
17
+ </transition>
18
+ </template>
19
+
20
+ <script>
21
+ export default {
22
+ name: 'ConfirmDialog',
23
+ props: {
24
+ /** 是否显示弹窗 */
25
+ visible: { type: Boolean, default: false },
26
+ /** 标题 */
27
+ title: { type: String, default: '' },
28
+ /** 操作说明 / 风险描述(纯文本,支持换行由调用方控制) */
29
+ message: { type: String, default: '' },
30
+ /** 确认按钮文案,默认「继续」 */
31
+ confirmText: { type: String, default: '继续' },
32
+ /** 取消按钮文案,默认「取消」 */
33
+ cancelText: { type: String, default: '取消' },
34
+ /** 是否为危险(破坏性)操作:确认按钮转红、标题加警示图标 */
35
+ danger: { type: Boolean, default: false },
36
+ },
37
+ emits: ['confirm', 'cancel'],
38
+ }
39
+ </script>
@@ -0,0 +1,33 @@
1
+ <!--
2
+ ViewContainer 的兜底实现。官方宿主会按 customClass 注入真实业务组件,
3
+ 预览里拿不到,画一个带类名的虚线占位块,方便定位是哪个自定义组件。
4
+ -->
5
+ <template>
6
+ <div class="ce_custom_placeholder">
7
+ <span class="ce_custom_placeholder_tag">{{ tagText }}</span>
8
+ <span class="ce_custom_placeholder_name">{{ label }}</span>
9
+ <slot />
10
+ </div>
11
+ </template>
12
+
13
+ <script>
14
+ export default {
15
+ name: 'CustomPlaceholder',
16
+ props: {
17
+ icon: { type: String, default: '' },
18
+ props: { type: Object, default: () => ({}) },
19
+ customClass: { type: String, default: '' },
20
+ title: { type: String, default: '' },
21
+ },
22
+ computed: {
23
+ tagText() {
24
+ return this.title || '自定义组件'
25
+ },
26
+ label() {
27
+ if (this.customClass) return this.customClass
28
+ const keys = Object.keys(this.props || {})
29
+ return keys.length ? keys.join(', ') : '未指定 customClass'
30
+ },
31
+ },
32
+ }
33
+ </script>