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,61 @@
1
+ <!--
2
+ 条件表达式设置器:对应编辑器 forms/IfForm。
3
+
4
+ 编辑器里点一下会弹「条件选择器」(依赖平台的数据域面板),本地没有那套服务,
5
+ 所以直接把底层数据结构摊开来编辑 —— DSL 中该值就是 `{name, expression}`:
6
+ name 面板上显示的条件名
7
+ expression 真正参与求值的表达式,如 `$singleMode`
8
+ 两者一般同值;这里默认联动,name 留空时自动取 expression。
9
+ -->
10
+ <template>
11
+ <div class="st-ifform">
12
+ <SetExpr
13
+ :value="expression"
14
+ :disabled="disabled"
15
+ placeholder="表达式,如 $singleMode 或 $data.count > 0"
16
+ @input="setExpression"
17
+ @change="$emit('change')"
18
+ />
19
+ <input
20
+ class="ni-input"
21
+ type="text"
22
+ placeholder="显示名(留空跟随表达式)"
23
+ :disabled="disabled"
24
+ :value="name"
25
+ @input="setName($event.target.value)"
26
+ @change="$emit('change')"
27
+ />
28
+ </div>
29
+ </template>
30
+
31
+ <script>
32
+ import { setterProps, setterEmits } from './props.js'
33
+ import SetExpr from './SetExpr.vue'
34
+
35
+ export default {
36
+ name: 'SetIfForm',
37
+ components: { SetExpr },
38
+ props: setterProps,
39
+ emits: setterEmits,
40
+ computed: {
41
+ obj() {
42
+ return this.value && typeof this.value === 'object' ? this.value : {}
43
+ },
44
+ expression() {
45
+ return this.obj.expression || ''
46
+ },
47
+ name() {
48
+ return this.obj.name || ''
49
+ },
50
+ },
51
+ methods: {
52
+ setExpression(v) {
53
+ const named = !this.name || this.name === this.expression
54
+ this.$emit('input', { name: named ? v : this.name, expression: v })
55
+ },
56
+ setName(v) {
57
+ this.$emit('input', { name: v, expression: this.expression })
58
+ },
59
+ },
60
+ }
61
+ </script>
@@ -0,0 +1,43 @@
1
+ <!--
2
+ 图片素材设置器:对应 itemValueFrom === '2' 的图片来源。
3
+
4
+ 编辑器里这里是素材库选择器;本地没有素材库服务,故退化为:
5
+ - 可预览的直接给缩略图(http / data: / 以 / 开头的相对路径);
6
+ - @filestore/... 这类虚拟路径只显示原文(无法预览);
7
+ - 文本框手输路径 + 清空按钮。
8
+ -->
9
+ <template>
10
+ <div class="st-image">
11
+ <div class="st-image__row">
12
+ <input
13
+ class="ni-input"
14
+ type="text"
15
+ :disabled="disabled"
16
+ :value="value || ''"
17
+ placeholder="图片路径,如 @filestore/...png 或 https://..."
18
+ @input="$emit('input', $event.target.value)"
19
+ @change="$emit('change')"
20
+ />
21
+ <button v-if="value" class="st-image__clear" type="button" title="清空" :disabled="disabled" @click="clear">
22
+ <svg viewBox="0 0 16 16" class="st-ic" aria-hidden="true"><use href="#icon-reset" /></svg>
23
+ </button>
24
+ </div>
25
+ </div>
26
+ </template>
27
+
28
+ <script>
29
+ import { setterProps, setterEmits } from './props.js'
30
+
31
+ export default {
32
+ name: 'SetImage',
33
+ props: setterProps,
34
+ emits: setterEmits,
35
+ methods: {
36
+ clear() {
37
+ if (this.disabled) return
38
+ this.$emit('input', '')
39
+ this.$emit('change')
40
+ },
41
+ },
42
+ }
43
+ </script>
@@ -0,0 +1,139 @@
1
+ <!--
2
+ 列表设置器:对应编辑器 common/List。
3
+
4
+ DSL 里 List 类型的实体数据在 property.itemList(数组,每项是带 properties 的 PropertyList),
5
+ itemValue 固定为空数组。itemOption.iFieldList 给出「列定义」{key, value},
6
+ 但已落库的每项实际字段往往比 iFieldList 更全(编辑器按组件包里的富模板生成)。
7
+
8
+ 这里:
9
+ - 逐项渲染:复用全局 <prop-control> 把每项的子属性交给对应类型化控件编辑;
10
+ - 增 / 删 / 上下移:直接操作 property.itemList(PropertyList[]);
11
+ - 新增项:优先克隆首项结构(空白值),没有首项时退化为 iFieldList 生成的 Input 字段。
12
+ -->
13
+ <template>
14
+ <div class="st-list">
15
+ <div
16
+ v-for="(item, idx) in list"
17
+ :key="item.id"
18
+ class="st-list__item"
19
+ >
20
+ <div class="st-list__head">
21
+ <span class="st-list__idx">#{{ idx + 1 }}</span>
22
+ <span class="st-list__head-spacer" />
23
+ <button class="st-list__op" type="button" title="上移" :disabled="disabled || idx === 0" @click="move(idx, -1)">↑</button>
24
+ <button class="st-list__op" type="button" title="下移" :disabled="disabled || idx === list.length - 1" @click="move(idx, 1)">↓</button>
25
+ <button class="st-list__op st-list__op--del" type="button" title="删除" :disabled="disabled" @click="remove(idx)">
26
+ <svg viewBox="0 0 16 16" class="st-ic" aria-hidden="true"><use href="#icon-delete" /></svg>
27
+ </button>
28
+ </div>
29
+ <div class="st-list__body">
30
+ <div
31
+ v-for="sub in item.properties"
32
+ v-show="sub.itemVisible"
33
+ :key="sub.itemId"
34
+ class="st-list__row"
35
+ >
36
+ <label class="st-list__label" :title="sub.itemDesc || displayName(sub)">{{ displayName(sub) }}</label>
37
+ <div class="st-list__control">
38
+ <prop-control
39
+ :property="sub"
40
+ :disabled="disabled"
41
+ @change="$emit('change')"
42
+ @sync="$emit('sync', $event)"
43
+ />
44
+ </div>
45
+ </div>
46
+ <p v-if="!item.properties.length" class="st-list__empty">该项无字段</p>
47
+ </div>
48
+ </div>
49
+
50
+ <p v-if="!list.length" class="st-list__empty">暂无项</p>
51
+
52
+ <button class="st-minibtn st-list__add" type="button" :disabled="disabled" @click="add">{{ addText }}</button>
53
+ </div>
54
+ </template>
55
+
56
+ <script>
57
+ import { setterProps, setterEmits } from './props.js'
58
+ import { PropertyList } from '../../runtime/property.js'
59
+
60
+ export default {
61
+ name: 'SetList',
62
+ props: setterProps,
63
+ emits: setterEmits,
64
+ computed: {
65
+ /** itemInfo 即承载本 List 的 Property 实例;其 itemList 为 PropertyList[] */
66
+ list() {
67
+ const info = this.itemInfo
68
+ return (info && info.itemList) || []
69
+ },
70
+ addText() {
71
+ const t = this.options && this.options.btnText
72
+ return t || '添加项'
73
+ },
74
+ },
75
+ methods: {
76
+ /** 消除 meta 中重复标签(如 fontStyle/textDecoration 均名「字体样式」) */
77
+ displayName(sub) {
78
+ const raw = sub.itemName || sub.itemKey || ''
79
+ // MultiText textList 中的字段名消歧
80
+ const MAP = {
81
+ fontStyle: '字体风格',
82
+ textDecoration: '文字装饰',
83
+ }
84
+ return MAP[sub.itemKey] || raw
85
+ },
86
+ add() {
87
+ if (this.disabled) return
88
+ const info = this.itemInfo
89
+ const src = this.list[0]
90
+ let list
91
+ if (src) {
92
+ // 克隆首项结构、清空值,保证新增项字段与已有项一致
93
+ list = new PropertyList(
94
+ src.properties.map((p) => ({
95
+ itemId: p.itemId,
96
+ itemKey: p.itemKey,
97
+ itemName: p.itemName,
98
+ itemType: p.itemType,
99
+ itemOption: p.itemOption,
100
+ itemParam: p.itemParam,
101
+ itemDefaultValue: p.itemDefaultValue,
102
+ itemDesc: p.itemDesc,
103
+ itemTypeRange: p.itemTypeRange,
104
+ itemValueFrom: '0',
105
+ itemValue: '',
106
+ })),
107
+ {},
108
+ )
109
+ } else {
110
+ // 没有可参考的项时,退化用 iFieldList 生成 Input 字段
111
+ const fields = (this.options && this.options.iFieldList) || []
112
+ list = new PropertyList(
113
+ fields.map((f) => ({
114
+ itemId: f.key,
115
+ itemKey: f.key,
116
+ itemName: f.value || f.key,
117
+ itemType: 'Input',
118
+ itemValueFrom: '0',
119
+ itemValue: '',
120
+ })),
121
+ {},
122
+ )
123
+ }
124
+ info.itemList.push(list)
125
+ this.$emit('change')
126
+ },
127
+ remove(idx) {
128
+ if (this.disabled) return
129
+ this.itemInfo.removeAt(idx)
130
+ this.$emit('change')
131
+ },
132
+ move(idx, dir) {
133
+ if (this.disabled) return
134
+ this.itemInfo.moveItem(idx, idx + dir)
135
+ this.$emit('change')
136
+ },
137
+ },
138
+ }
139
+ </script>
@@ -0,0 +1,118 @@
1
+ <!--
2
+ 数字输入设置器:对应编辑器 common/InputNumber。
3
+ - itemOption.type 取值 integer/+integer/-integer/float/+float/-float,决定输入正则
4
+ - itemOption.iParamList 预设值列表(点击右侧箭头弹出,如字号 12/14/16…)
5
+ - itemOption.symbol 右侧单位文案;NumberStyle 通过具名插槽 symbol 注入单位下拉
6
+ -->
7
+ <template>
8
+ <div class="st-number-wrap">
9
+ <div class="st-number">
10
+ <input
11
+ ref="field"
12
+ class="st-number__field"
13
+ type="text"
14
+ :placeholder="options.placeholder || '请输入'"
15
+ :disabled="disabled"
16
+ :value="inputValue"
17
+ @input="onInput($event.target.value)"
18
+ @change="emitChange()"
19
+ @keydown.up.prevent="step(1)"
20
+ @keydown.down.prevent="step(-1)"
21
+ @blur="closeSug()"
22
+ />
23
+
24
+ <span v-if="$slots.symbol" class="st-number__symbol st-number__symbol--btn">
25
+ <slot name="symbol" />
26
+ </span>
27
+ <span v-else-if="options.symbol && options.symbol !== true" class="st-number__symbol">{{ options.symbol }}</span>
28
+
29
+ <span
30
+ v-if="suggestions.length"
31
+ class="st-number__caret"
32
+ title="预设值"
33
+ @mousedown.prevent="sugOpen = !sugOpen"
34
+ >▾</span>
35
+ </div>
36
+
37
+ <!-- 预设值浮层:移出 .st-number,避免被 overflow:hidden 裁切 -->
38
+ <div v-if="sugOpen && suggestions.length" class="st-pop st-pop--sug">
39
+ <div
40
+ v-for="s in suggestions"
41
+ :key="s.key"
42
+ class="st-pop__item"
43
+ :class="{ 'st-pop__item--on': String(s.key) === String(inputValue) }"
44
+ @mousedown.prevent="pick(s)"
45
+ >{{ s.value }}</div>
46
+ </div>
47
+ </div>
48
+ </template>
49
+
50
+ <script>
51
+ import { setterProps, setterEmits } from './props.js'
52
+
53
+ const TYPES = {
54
+ integer: /^-?(0|[1-9][0-9]*)?$/,
55
+ '+integer': /^(0|[1-9][0-9]*)?$/,
56
+ '-integer': /^(0|-[1-9]?[0-9]*)?$/,
57
+ float: /^-?([0-9]*|(0|[1-9][0-9]*)\.[0-9]*)?$/,
58
+ '+float': /^([0-9]*|(0|[1-9][0-9]*)\.[0-9]*)?$/,
59
+ '-float': /^(0|-[0-9]*|-(0|[1-9][0-9]*)\.[0-9]*)?$/,
60
+ }
61
+
62
+ export default {
63
+ name: 'SetNumber',
64
+ props: setterProps,
65
+ emits: setterEmits,
66
+ data() {
67
+ return { inputValue: '', sugOpen: false }
68
+ },
69
+ computed: {
70
+ suggestions() {
71
+ return this.options.iParamList || []
72
+ },
73
+ pattern() {
74
+ return TYPES[this.options.type] || TYPES.integer
75
+ },
76
+ },
77
+ watch: {
78
+ value: {
79
+ immediate: true,
80
+ handler(v) {
81
+ this.inputValue = v === undefined || v === null ? '' : String(v)
82
+ },
83
+ },
84
+ },
85
+ methods: {
86
+ onInput(v) {
87
+ if (!this.pattern.test(v)) {
88
+ // 非法输入回滚(与编辑器一致:直接丢弃这次按键)
89
+ this.$refs.field.value = this.inputValue
90
+ return
91
+ }
92
+ this.inputValue = v
93
+ this.$emit('input', v)
94
+ },
95
+ step(delta) {
96
+ const n = parseFloat(this.inputValue)
97
+ const next = String((Number.isNaN(n) ? 0 : n) + delta)
98
+ if (!this.pattern.test(next)) return
99
+ this.inputValue = next
100
+ this.$emit('input', next)
101
+ this.emitChange()
102
+ },
103
+ pick(s) {
104
+ this.sugOpen = false
105
+ this.inputValue = String(s.key)
106
+ this.$emit('input', this.inputValue)
107
+ this.emitChange()
108
+ },
109
+ closeSug() {
110
+ // 交给 mousedown 先跑完(pick 用的是 mousedown)
111
+ setTimeout(() => (this.sugOpen = false), 0)
112
+ },
113
+ emitChange() {
114
+ this.$emit('change')
115
+ },
116
+ },
117
+ }
118
+ </script>
@@ -0,0 +1,113 @@
1
+ <!--
2
+ 带单位的数值设置器:对应编辑器 style/NumberStyle。
3
+
4
+ DSL 里 width/height 这类字段是**单个字符串**,靠后缀区分单位:
5
+ "120" → px
6
+ "50%" → 百分比
7
+ "auto" → 自适应
8
+ 切换单位时编辑器会重置数值(percent→100、auto→'auto'、number→''),这里保持一致。
9
+ -->
10
+ <template>
11
+ <div class="st-numberstyle">
12
+ <SetNumber
13
+ :value="numValue"
14
+ :options="numberOptions"
15
+ :disabled="disabled || isAuto"
16
+ @input="onNum"
17
+ @change="$emit('change')"
18
+ >
19
+ <template #symbol>
20
+ <span class="st-unit" @mousedown.prevent="menuOpen = !menuOpen">{{ unitLabel }}</span>
21
+ </template>
22
+ </SetNumber>
23
+
24
+ <!-- 单位切换浮层:移到 .st-number 之外,避免被 overflow:hidden 裁切 -->
25
+ <div v-if="menuOpen" class="st-pop-mask" @mousedown.prevent="menuOpen = false"></div>
26
+ <div v-if="menuOpen" class="st-pop st-pop--unit">
27
+ <div
28
+ v-for="u in unitList"
29
+ :key="u.key"
30
+ class="st-pop__item"
31
+ :class="{ 'st-pop__item--on': u.key === unit }"
32
+ @mousedown.prevent="pickUnit(u.key)"
33
+ >{{ u.value }}</div>
34
+ </div>
35
+ </div>
36
+ </template>
37
+
38
+ <script>
39
+ import { setterProps, setterEmits } from './props.js'
40
+ import SetNumber from './SetNumber.vue'
41
+
42
+ const DEFAULT_UNITS = [
43
+ { key: 'number', value: 'px' },
44
+ { key: 'percent', value: '%' },
45
+ { key: 'auto', value: '@' },
46
+ ]
47
+
48
+ export default {
49
+ name: 'SetNumberStyle',
50
+ components: { SetNumber },
51
+ props: setterProps,
52
+ emits: setterEmits,
53
+ data() {
54
+ return { unit: 'number', numValue: '', menuOpen: false }
55
+ },
56
+ computed: {
57
+ unitList() {
58
+ return this.options.iTypeList || DEFAULT_UNITS
59
+ },
60
+ unitLabel() {
61
+ const hit = this.unitList.filter((u) => u.key === this.unit)[0]
62
+ return hit ? hit.value : 'px'
63
+ },
64
+ // @/auto 单位下,输入框只读(显示 auto 且不可编辑)
65
+ isAuto() {
66
+ return this.unit === 'auto'
67
+ },
68
+ numberOptions() {
69
+ return {
70
+ ...this.options,
71
+ type: this.unit === 'percent' ? 'integer' : 'float',
72
+ placeholder: this.options.placeholder || '',
73
+ symbol: true,
74
+ }
75
+ },
76
+ },
77
+ watch: {
78
+ value: { immediate: true, handler() { this.parse() } },
79
+ },
80
+ methods: {
81
+ parse() {
82
+ const v = this.value
83
+ if (/%$/.test(String(v))) {
84
+ this.unit = 'percent'
85
+ this.numValue = String(v).replace(/%/g, '')
86
+ } else if (v === 'auto') {
87
+ this.unit = 'auto'
88
+ this.numValue = 'auto'
89
+ } else {
90
+ this.unit = 'number'
91
+ this.numValue = v === 0 ? '0' : v === undefined || v === null ? '' : String(v)
92
+ }
93
+ },
94
+ onNum(v) {
95
+ this.numValue = v
96
+ this.emit()
97
+ },
98
+ pickUnit(key) {
99
+ this.menuOpen = false
100
+ this.unit = key
101
+ if (key === 'percent') this.numValue = '100'
102
+ else if (key === 'auto') this.numValue = 'auto'
103
+ else this.numValue = ''
104
+ this.emit()
105
+ this.$emit('change')
106
+ },
107
+ emit() {
108
+ if (this.unit === 'percent' && this.numValue) this.$emit('input', this.numValue + '%')
109
+ else this.$emit('input', this.numValue)
110
+ },
111
+ },
112
+ }
113
+ </script>
@@ -0,0 +1,77 @@
1
+ <!--
2
+ 四向内边距设置器:对应编辑器 style/PaddingStyle。
3
+
4
+ DSL 里是一个字符串,默认形态 `{2,2,2,2}`:
5
+ - itemOption.brackets 包裹符,默认 ['{','}']
6
+ - itemOption.seperator 分隔符,默认 ','
7
+ - itemOption.normal true → 顺序同 CSS:上,右,下,左
8
+ false(默认)→ 上,左,下,右
9
+ 顺序错了会让上下/左右内边距互换,所以这里严格照抄编辑器的分支。
10
+ -->
11
+ <template>
12
+ <div class="st-pad">
13
+ <SetNumber :value="form.top" :options="opt('上')" :disabled="disabled" @input="set('top', $event)" @change="emitOut" />
14
+ <SetNumber :value="form.right" :options="opt('右')" :disabled="disabled" @input="set('right', $event)" @change="emitOut" />
15
+ <SetNumber :value="form.bottom" :options="opt('下')" :disabled="disabled" @input="set('bottom', $event)" @change="emitOut" />
16
+ <SetNumber :value="form.left" :options="opt('左')" :disabled="disabled" @input="set('left', $event)" @change="emitOut" />
17
+ </div>
18
+ </template>
19
+
20
+ <script>
21
+ import { setterProps, setterEmits } from './props.js'
22
+ import SetNumber from './SetNumber.vue'
23
+
24
+ export default {
25
+ name: 'SetPadding',
26
+ components: { SetNumber },
27
+ props: setterProps,
28
+ emits: setterEmits,
29
+ data() {
30
+ return { form: { top: '', right: '', bottom: '', left: '' } }
31
+ },
32
+ computed: {
33
+ brackets() {
34
+ return this.options.brackets || ['{', '}']
35
+ },
36
+ seperator() {
37
+ return this.options.seperator || ','
38
+ },
39
+ },
40
+ watch: {
41
+ value: { immediate: true, handler() { this.parse() } },
42
+ },
43
+ methods: {
44
+ parse() {
45
+ let s = String(this.value || '')
46
+ if (this.brackets.length) {
47
+ s = s.replace(new RegExp(`[${this.brackets.join('')}]`, 'g'), '')
48
+ }
49
+ const p = s.split(this.seperator)
50
+ if (this.options.normal) {
51
+ this.form = { top: p[0] || '', right: p[1] || '', bottom: p[2] || '', left: p[3] || '' }
52
+ } else {
53
+ this.form = { top: p[0] || '', left: p[1] || '', bottom: p[2] || '', right: p[3] || '' }
54
+ }
55
+ },
56
+ opt(symbol) {
57
+ return { type: 'integer', symbol, placeholder: '0' }
58
+ },
59
+ set(k, v) {
60
+ this.form[k] = v
61
+ this.emitValue()
62
+ },
63
+ emitValue() {
64
+ const f = this.form
65
+ const arr = this.options.normal
66
+ ? [f.top, f.right, f.bottom, f.left]
67
+ : [f.top, f.left, f.bottom, f.right]
68
+ const body = arr.map((x) => (x === '' || x === undefined ? '0' : x)).join(this.seperator)
69
+ const [l, r] = this.brackets.length ? this.brackets : ['', '']
70
+ this.$emit('input', `${l || ''}${body}${r || ''}`)
71
+ },
72
+ emitOut() {
73
+ this.$emit('change')
74
+ },
75
+ },
76
+ }
77
+ </script>