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,42 @@
1
+ <!--
2
+ 官方 module 2117 / 549。
3
+ 子元素由 CSS `.ce_absolutelayout > *{position:absolute}` 脱标,
4
+ 容器自身按 align 用 flex 对齐(positionMap)。
5
+ -->
6
+ <template>
7
+ <div class="ce_absolutelayout" :style="styleObj">
8
+ <slot />
9
+ </div>
10
+ </template>
11
+
12
+ <script>
13
+ import StyleParser from '../runtime/StyleParser.js'
14
+ import base from './base.js'
15
+
16
+ const POSITION_MAP = {
17
+ TopLeft: { justifyContent: 'flex-start', alignItems: 'flex-start' },
18
+ TopCenter: { justifyContent: 'flex-start', alignItems: 'center' },
19
+ TopRight: { justifyContent: 'flex-start', alignItems: 'flex-end' },
20
+ CenterLeft: { justifyContent: 'center', alignItems: 'flex-start' },
21
+ Center: { justifyContent: 'center', alignItems: 'center' },
22
+ CenterRight: { justifyContent: 'center', alignItems: 'flex-end' },
23
+ BottomLeft: { justifyContent: 'flex-end', alignItems: 'flex-start' },
24
+ BottomCenter: { justifyContent: 'flex-end', alignItems: 'center' },
25
+ BottomRight: { justifyContent: 'flex-end', alignItems: 'flex-end' },
26
+ }
27
+
28
+ export default {
29
+ name: 'CeAbsoluteLayout',
30
+ mixins: [base],
31
+ props: {
32
+ styleProps: { type: Object, default: () => ({}) },
33
+ align: { type: String, default: '' },
34
+ },
35
+ computed: {
36
+ styleObj() {
37
+ const out = new StyleParser(this, this.styleProps).parse()
38
+ return Object.assign(out, POSITION_MAP[this.align] || {})
39
+ },
40
+ },
41
+ }
42
+ </script>
@@ -0,0 +1,58 @@
1
+ <!--
2
+ 单张弹窗卡片实例:为 alertCard 弹出的卡片提供「独立」的 cardRuntime,
3
+ 使其脚本里的 this.data / this.state / setData / setRootData 都指向自身作用域,
4
+ 而不是父卡片(主卡片)的作用域。渲染复用 RenderTree 同一套预览管线。
5
+
6
+ 同时把弹窗卡片内部的「绑定错误 / 接口调用」转发到主运行时(mainRt),
7
+ 以便右侧调试面板能像主卡片一样看到弹窗卡片的运行情况。
8
+ -->
9
+ <script>
10
+ import { h } from 'vue'
11
+ import Adapter from '@/runtime/adapter.js'
12
+ import { createCardRuntime } from '@/runtime/card-runtime.js'
13
+ import RenderTree from './RenderTree.vue'
14
+
15
+ export default {
16
+ name: 'AlertCardInstance',
17
+ components: { RenderTree },
18
+ props: {
19
+ entry: { type: Object, required: true },
20
+ mainRt: { type: Object, default: null },
21
+ },
22
+ data() {
23
+ const adapter = new Adapter()
24
+ const cardRuntime = createCardRuntime(this.entry.scope, adapter)
25
+
26
+ // 转发弹窗卡片的绑定错误 / 接口调用到主运行时,方便调试面板查看
27
+ const mainRt = this.mainRt
28
+ if (mainRt && mainRt.pushError && mainRt.pushApiCall) {
29
+ const origErr = cardRuntime.pushError.bind(cardRuntime)
30
+ cardRuntime.pushError = (k, m) => {
31
+ origErr(k, m)
32
+ mainRt.pushError(k, m)
33
+ }
34
+ const origApi = cardRuntime.pushApiCall.bind(cardRuntime)
35
+ cardRuntime.pushApiCall = (api, p) => {
36
+ origApi(api, p)
37
+ mainRt.pushApiCall(api, p)
38
+ }
39
+ }
40
+
41
+ return { adapter, cardRuntime }
42
+ },
43
+ provide() {
44
+ return {
45
+ adapter: this.adapter,
46
+ cardRuntime: this.cardRuntime,
47
+ customComponents: {},
48
+ }
49
+ },
50
+ render() {
51
+ return h(RenderTree, {
52
+ node: this.entry.preview.view,
53
+ scope: this.cardRuntime.rootScope,
54
+ key: this.entry.id,
55
+ })
56
+ },
57
+ }
58
+ </script>
@@ -0,0 +1,59 @@
1
+ <!--
2
+ 弹窗卡片图层:固定全屏遮罩 + 按 gravity 定位的卡片面板,渲染 alertStack 栈顶的卡片。
3
+ 点击遮罩(仅当该弹窗 clickOutsideCanHide)关闭栈顶弹窗。
4
+ -->
5
+ <template>
6
+ <div class="alert-layer" v-if="top">
7
+ <div
8
+ class="alert-mask"
9
+ :class="'alert-mask--' + top.gravity"
10
+ @click.self="onMaskClick(top)"
11
+ >
12
+ <div class="alert-panel" :style="panelStyle(top)">
13
+ <AlertCardInstance
14
+ :entry="top"
15
+ :main-rt="mainRt"
16
+ />
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </template>
21
+
22
+ <script>
23
+ import AlertCardInstance from './AlertCardInstance.vue'
24
+ import { alertStore, closeAlertCard } from '@/runtime/alert-card.js'
25
+
26
+ export default {
27
+ name: 'AlertCardLayer',
28
+ components: { AlertCardInstance },
29
+ props: {
30
+ mainRt: { type: Object, default: null },
31
+ },
32
+ computed: {
33
+ top() {
34
+ // 必须先读 alertStore.stack(走对象 getter)才能收集到数组依赖,
35
+ // 直接对导出的数组做索引/length 访问不会触发响应式更新。
36
+ const stack = alertStore.stack
37
+ return stack.length ? stack[stack.length - 1] : null
38
+ },
39
+ },
40
+ methods: {
41
+ onMaskClick(entry) {
42
+ if (entry.clickOutsideCanHide) {
43
+ closeAlertCard({ cardCode: entry.cardCode })
44
+ }
45
+ },
46
+ panelStyle(entry) {
47
+ const s = {}
48
+ if (entry.width) s.width = entry.width + 'px'
49
+ if (entry.height) s.height = entry.height + 'px'
50
+ // offsetX / offsetY:在 gravity 定位基础上做平移微调
51
+ const transforms = []
52
+ if (entry.offsetX) transforms.push('translateX(' + entry.offsetX + 'px)')
53
+ if (entry.offsetY) transforms.push('translateY(' + entry.offsetY + 'px)')
54
+ if (transforms.length) s.transform = transforms.join(' ')
55
+ return s
56
+ },
57
+ },
58
+ }
59
+ </script>
@@ -0,0 +1,168 @@
1
+ <!--
2
+ 接口调用 tab 的「返回数据」结构化折叠树(只读,对齐 Chrome 控制台对象检视器)。
3
+ - 复合类型(对象 / 数组)可点击折叠 / 展开,默认全部折叠,折叠时显示预览摘要。
4
+ - 基础类型按类型着色(复用 .jt__val--* 配色),字符串不带引号(DevTools 风格)。
5
+ - 折叠状态在整棵树内共享(openState),按节点路径独立记录。
6
+ -->
7
+ <template>
8
+ <div class="apt" :class="{ 'apt--root': isRoot }">
9
+ <!-- 根级别:非复合值(如 payload 就是字符串)直接作为单个叶子展示 -->
10
+ <div v-if="!isComplex(value)" class="apt__leaf apt__leaf--root">
11
+ <span class="apt__caret apt__caret--leaf">▶</span>
12
+ <span v-if="rootKeyLabel !== null" class="jt__key">{{ rootKeyLabel }}</span>
13
+ <span v-if="rootKeyLabel !== null" class="jt__colon">:</span>
14
+ <span class="jt__val" :class="'jt__val--' + typeOf(value)">{{ format(value) }}</span>
15
+ </div>
16
+
17
+ <template v-else>
18
+ <div class="apt__list">
19
+ <div v-for="(entry, i) in entries" :key="i" class="apt__node">
20
+ <!-- 复合类型且未超最大深度:可折叠分支 -->
21
+ <div v-if="canExpand(entry)" class="apt__branch" @click="toggle(entry)">
22
+ <span class="apt__caret" :class="{ 'apt__caret--open': isOpen(entry) }">▶</span>
23
+ <span v-if="entry.keyLabel !== null" class="jt__key">{{ entry.keyLabel }}</span>
24
+ <span class="jt__bracket">{{ entry.isArray ? '[' : '{' }}</span>
25
+ <template v-if="!isOpen(entry)">
26
+ <span class="jt__preview">{{ preview(entry.value) }}</span>
27
+ <span class="jt__bracket">{{ entry.isArray ? ']' : '}' }}</span>
28
+ </template>
29
+ </div>
30
+ <!-- 复合类型但已达最大深度:不再可展开,仅作摘要叶子 -->
31
+ <div v-else-if="isComplex(entry.value)" class="apt__leaf">
32
+ <span class="apt__caret apt__caret--leaf">▶</span>
33
+ <span v-if="entry.keyLabel !== null" class="jt__key">{{ entry.keyLabel }}</span>
34
+ <span v-if="entry.keyLabel !== null" class="jt__colon">:</span>
35
+ <span class="jt__val" :class="'jt__val--' + (entry.isArray ? 'array' : 'object')">{{ entry.count }} {{ entry.isArray ? '项' : '键' }}(已折叠)</span>
36
+ </div>
37
+ <!-- 基础类型:叶子 -->
38
+ <div v-else class="apt__leaf">
39
+ <span class="apt__caret apt__caret--leaf">▶</span>
40
+ <span v-if="entry.keyLabel !== null" class="jt__key">{{ entry.keyLabel }}</span>
41
+ <span v-if="entry.keyLabel !== null" class="jt__colon">:</span>
42
+ <span class="jt__val" :class="'jt__val--' + entry.type">{{ format(entry.value) }}</span>
43
+ </div>
44
+
45
+ <!-- 展开后的子层级 -->
46
+ <div v-if="isComplex(entry.value) && isOpen(entry)" class="apt__children">
47
+ <ApiPayloadTree
48
+ :value="entry.value"
49
+ :depth="depth + 1"
50
+ :path="entry.path"
51
+ :open-state="state"
52
+ :max-depth="maxDepth"
53
+ />
54
+ <div class="apt__close">
55
+ <span class="jt__bracket">{{ entry.isArray ? ']' : '}' }}</span>
56
+ <span class="jt__count">{{ entry.count }} {{ entry.isArray ? '项' : '键' }}</span>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </template>
62
+ </div>
63
+ </template>
64
+
65
+ <script>
66
+ import { reactive } from 'vue'
67
+
68
+ export default {
69
+ name: 'ApiPayloadTree',
70
+ props: {
71
+ // 当前节点的值(对象 / 数组 / 基础类型均可)
72
+ value: { default: () => ({}) },
73
+ // 当前层级深度(根=0),用于根判断
74
+ depth: { type: Number, default: 0 },
75
+ // 从根到当前节点的路径(key 数组),用作折叠状态的唯一 key
76
+ path: { type: Array, default: () => [] },
77
+ // 跨整棵树共享的折叠状态对象:{ '<path>': bool }
78
+ openState: { type: Object, default: null },
79
+ // 仅当根级别 value 为基元类型且需要展示 key 时传入(如顶层字符串)
80
+ rootKeyLabel: { type: [String, Number, null], default: null },
81
+ // 最大可展开深度(保护):达到该深度的复合节点不再可展开,
82
+ // 避免日志中循环引用 / 超深结构在展开时无限递归。默认 100(接口调用场景基本无感)。
83
+ maxDepth: { type: Number, default: 100 },
84
+ },
85
+ data() {
86
+ return {
87
+ // 若未传入共享状态(理论只发生在根),自行创建,保证递归子组件拿到同一引用
88
+ localOpenState: this.openState || reactive({}),
89
+ }
90
+ },
91
+ computed: {
92
+ isRoot() {
93
+ return this.depth === 0
94
+ },
95
+ state() {
96
+ return this.openState || this.localOpenState
97
+ },
98
+ entries() {
99
+ const d = this.value
100
+ if (Array.isArray(d)) {
101
+ return d.map((v, i) => this.makeEntry(String(i), v, true, i))
102
+ }
103
+ if (d && typeof d === 'object') {
104
+ return Object.keys(d).map((k) => this.makeEntry(k, d[k], false, k))
105
+ }
106
+ return []
107
+ },
108
+ },
109
+ methods: {
110
+ typeOf(v) {
111
+ if (v === null) return 'null'
112
+ if (Array.isArray(v)) return 'array'
113
+ return typeof v
114
+ },
115
+ isComplex(v) {
116
+ return v !== null && typeof v === 'object'
117
+ },
118
+ makeEntry(keyLabel, value, isArrayBranch, rawKey) {
119
+ const isArr = Array.isArray(value)
120
+ const count = isArr
121
+ ? value.length
122
+ : value && typeof value === 'object'
123
+ ? Object.keys(value).length
124
+ : 0
125
+ return {
126
+ keyLabel,
127
+ value,
128
+ isArray: isArr,
129
+ count,
130
+ type: this.typeOf(value),
131
+ path: [...this.path, rawKey],
132
+ }
133
+ },
134
+ pathKey(entry) {
135
+ return entry.path.join('/')
136
+ },
137
+ isOpen(entry) {
138
+ // 必须直接以 st[k] 读取:Vue 3 的 reactive get 陷阱对「不存在的 key」同样会 track,
139
+ // 而 hasOwnProperty 走 getOwnPropertyDescriptor(Vue 未代理)不会 track——
140
+ // 若先用 hasOwnProperty 短路返回,首次点击写入新 key 时无人订阅,视图不会重渲染(点了没反应)。
141
+ const v = this.state[this.pathKey(entry)]
142
+ // 默认全部折叠,由用户逐层点开
143
+ return v === undefined ? false : v
144
+ },
145
+ /** 当前节点是否可展开:复合类型且未超过最大深度(保护循环引用 / 超深结构) */
146
+ canExpand(entry) {
147
+ return this.isComplex(entry.value) && this.depth < this.maxDepth
148
+ },
149
+ toggle(entry) {
150
+ const k = this.pathKey(entry)
151
+ this.state[k] = !this.isOpen(entry)
152
+ },
153
+ preview(val) {
154
+ if (Array.isArray(val)) return ' … ' + val.length + ' 项'
155
+ const keys = Object.keys(val)
156
+ const head = keys.slice(0, 3).join(', ')
157
+ return ' … ' + head + (keys.length > 3 ? ', …' : '') + ' '
158
+ },
159
+ format(v) {
160
+ if (v === null) return 'null'
161
+ if (typeof v === 'string') return v // DevTools 风格:字符串不带引号
162
+ if (typeof v === 'number') return String(v)
163
+ if (typeof v === 'boolean') return String(v)
164
+ return JSON.stringify(v)
165
+ },
166
+ },
167
+ }
168
+ </script>
@@ -0,0 +1,37 @@
1
+ <!--
2
+ App 级弱提示(toast):顶栏异步操作(远端保存 / 同步)完成后的反馈。
3
+ 固定悬浮在 App 外壳顶部居中,不随手机预览框定位(区别于设备框内的 showToast)。
4
+ 通过 runtime/app-toast.js 的 appToast 响应式单例读取,2.4s 自动消失。
5
+ -->
6
+ <template>
7
+ <transition name="apptoast-fade">
8
+ <div
9
+ v-if="toast.visible"
10
+ class="apptoast"
11
+ :class="'apptoast--' + toast.type"
12
+ role="status"
13
+ aria-live="polite"
14
+ >
15
+ <span class="apptoast__icon">
16
+ <svg class="apptoast__icon-svg" viewBox="0 0 24 24" aria-hidden="true">
17
+ <path v-if="toast.type === 'ok'" d="M5 13l4 4L19 7" />
18
+ <path v-else d="M6 6l12 12M18 6L6 18" />
19
+ </svg>
20
+ </span>
21
+ <span class="apptoast__msg">{{ toast.message }}</span>
22
+ </div>
23
+ </transition>
24
+ </template>
25
+
26
+ <script>
27
+ import { appToast } from '@/runtime/app-toast.js'
28
+
29
+ export default {
30
+ name: 'AppToast',
31
+ computed: {
32
+ toast() {
33
+ return appToast
34
+ },
35
+ },
36
+ }
37
+ </script>
@@ -0,0 +1,37 @@
1
+ <!-- 官方 module 2000 / 515 -->
2
+ <template>
3
+ <button
4
+ class="ce_button"
5
+ :class="{ ce_button_disabled: disabled }"
6
+ :style="styleObj"
7
+ @click="!disabled && $emit('click', $event)"
8
+ >
9
+ {{ doI18n(value) }}
10
+ </button>
11
+ </template>
12
+
13
+ <script>
14
+ import StyleParser from '../runtime/StyleParser.js'
15
+ import base from './base.js'
16
+
17
+ export default {
18
+ name: 'CeButton',
19
+ emits: ['click'],
20
+ mixins: [base],
21
+ props: {
22
+ styleProps: { type: Object, default: () => ({}) },
23
+ // 官方是 String / Boolean,这里放宽以兼容变量算出的其它原始类型;
24
+ // 真值判断规则与官方完全相同(字符串 "false" 同样是真)
25
+ value: { type: [String, Number], default: '' },
26
+ disabled: { type: [Boolean, String, Number], default: false },
27
+ },
28
+ computed: {
29
+ styleObj() {
30
+ const parser = new StyleParser(this, this.styleProps)
31
+ const out = parser.parse()
32
+ parser.parseFont(this.styleProps.font || {}, out)
33
+ return out
34
+ },
35
+ },
36
+ }
37
+ </script>
@@ -0,0 +1,65 @@
1
+ <!--
2
+ 官方 module 1985 / 506。
3
+ 挂载后按 devicePixelRatio 放大位图并 scale 上下文,然后把「设计稿坐标系」的
4
+ canvas 包装对象通过 onMeasured 抛给卡片脚本去画。
5
+ -->
6
+ <template>
7
+ <canvas ref="canvas" class="ce_canvas" :style="styleObj" />
8
+ </template>
9
+
10
+ <script>
11
+ import StyleParser from '../runtime/StyleParser.js'
12
+ import { makeCanvasWrapperClass } from '../runtime/canvas-context.js'
13
+ import base from './base.js'
14
+
15
+ export default {
16
+ name: 'CeCanvas',
17
+ emits: ['onMeasured'],
18
+ mixins: [base],
19
+ props: {
20
+ styleProps: { type: Object, default: () => ({}) },
21
+ },
22
+ computed: {
23
+ styleObj() {
24
+ return new StyleParser(this, this.styleProps).parse()
25
+ },
26
+ },
27
+ created() {
28
+ this.resizeEvt =
29
+ typeof window !== 'undefined' && 'orientationchange' in window ? 'orientationchange' : 'resize'
30
+ },
31
+ mounted() {
32
+ this.$nextTick(() => this.doPaint())
33
+ if (typeof window !== 'undefined') window.addEventListener(this.resizeEvt, this.doRepaint, false)
34
+ },
35
+ unmounted() {
36
+ if (typeof window !== 'undefined') window.removeEventListener(this.resizeEvt, this.doRepaint, false)
37
+ },
38
+ methods: {
39
+ doPaint() {
40
+ const el = this.$refs.canvas
41
+ if (!el) return
42
+ const rect = el.getBoundingClientRect()
43
+ const { availableWidth, applyUnitRatio, fontRatio = 1 } = this.adapter.getSystemInfo()
44
+ // availableWidth=0 时退化为 1,即 1:1 使用设计稿 px
45
+ const scale =
46
+ (availableWidth * applyUnitRatio) / this.adapter.getDesignInfo().styleWidth || 1
47
+ const ctx = el.getContext('2d')
48
+ const dpr = (typeof window !== 'undefined' ? window.devicePixelRatio : 1) || 1
49
+ el.width = rect.width * dpr
50
+ el.height = rect.height * dpr
51
+ ctx.scale(dpr, dpr)
52
+
53
+ const CanvasWrapper = makeCanvasWrapperClass(el, this)
54
+ const canvas = new CanvasWrapper(rect, scale, fontRatio)
55
+ this.$emit('onMeasured', { canvas, width: canvas.width, height: canvas.height })
56
+ },
57
+ doRepaint() {
58
+ const el = this.$refs.canvas
59
+ if (!el) return
60
+ el.getContext('2d').clearRect(0, 0, el.width, el.height)
61
+ this.doPaint()
62
+ },
63
+ },
64
+ }
65
+ </script>