km-card-layout-component-miniprogram 0.1.5 → 0.1.6
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/example/pages/home/index.js +341 -237
- package/miniprogram_dist/components/card-layout/index.js +209 -29
- package/miniprogram_dist/components/card-layout/index.wxml +21 -5
- package/miniprogram_dist/components/card-layout/index.wxss +26 -5
- package/miniprogram_dist/vendor/km-card-layout-core/index.js +57 -181
- package/miniprogram_dist/vendor/km-card-layout-core/interface/data/payload.js +2 -0
- package/miniprogram_dist/vendor/km-card-layout-core/interface/elements.js +2 -0
- package/miniprogram_dist/vendor/km-card-layout-core/interface/index.js +19 -0
- package/miniprogram_dist/vendor/km-card-layout-core/interface/layout.js +2 -0
- package/miniprogram_dist/vendor/km-card-layout-core/interface/render.js +2 -0
- package/package.json +1 -1
- package/script/sync-core.js +9 -1
- package/src/components/card-layout/index.ts +331 -56
- package/src/components/card-layout/index.wxml +21 -5
- package/src/components/card-layout/index.wxss +26 -5
- package/src/vendor/km-card-layout-core/index.ts +151 -461
- package/src/vendor/km-card-layout-core/interface/data/payload.ts +27 -0
- package/src/vendor/km-card-layout-core/interface/elements.ts +73 -0
- package/src/vendor/km-card-layout-core/interface/index.ts +3 -0
- package/src/vendor/km-card-layout-core/interface/layout.ts +19 -0
- package/src/vendor/km-card-layout-core/interface/render.ts +52 -0
- package/src/vendor/km-card-layout-core/types.d.ts +26 -155
|
@@ -5,12 +5,26 @@
|
|
|
5
5
|
* - 平台无关:不依赖 DOM/小程序 API,方便在 Web/小程序/Node 复用。
|
|
6
6
|
* - 职责:将布局 Schema 与业务数据合成为带内联样式的渲染树,外层只需将节点映射到各端组件。
|
|
7
7
|
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
20
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
21
|
+
};
|
|
8
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
23
|
exports.buildRenderResult = exports.buildRenderNodes = exports.resolveBindingValue = exports.normalizeLayout = exports.styleObjectToString = exports.addUnit = void 0;
|
|
24
|
+
__exportStar(require("./interface/index"), exports);
|
|
10
25
|
/** ---------- 常量 ---------- */
|
|
11
26
|
const DEFAULT_CARD_WIDTH = 343; // 默认卡片宽度(像素)
|
|
12
27
|
const DEFAULT_CARD_HEIGHT = 210; // 默认卡片高度(像素)
|
|
13
|
-
const DEFAULT_GROUP_GAP = 22; // repeatable-item 默认纵向间距
|
|
14
28
|
const DIMENSION_PROPS = new Set([
|
|
15
29
|
'width',
|
|
16
30
|
'height',
|
|
@@ -36,7 +50,6 @@ const DIMENSION_PROPS = new Set([
|
|
|
36
50
|
'gap',
|
|
37
51
|
'rowGap',
|
|
38
52
|
'columnGap',
|
|
39
|
-
'flexBasis',
|
|
40
53
|
]);
|
|
41
54
|
/** ---------- 基础工具 ---------- */
|
|
42
55
|
/**
|
|
@@ -110,9 +123,10 @@ const isObject = (val) => Boolean(val) && typeof val === 'object';
|
|
|
110
123
|
const getAbsLayout = (el) => el.layout && el.layout.mode === 'absolute'
|
|
111
124
|
? el.layout
|
|
112
125
|
: null;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
126
|
+
/** ---------- 布局与数据解析 ---------- */
|
|
127
|
+
/**
|
|
128
|
+
* 归一化布局输入(对象或 JSON 字符串),补齐宽高/容器/children 默认值。
|
|
129
|
+
*/
|
|
116
130
|
const normalizeLayout = (layout) => {
|
|
117
131
|
if (!Array.isArray(layout))
|
|
118
132
|
return [];
|
|
@@ -169,46 +183,21 @@ const readByPath = (data, path) => {
|
|
|
169
183
|
return cursor;
|
|
170
184
|
};
|
|
171
185
|
/**
|
|
172
|
-
*
|
|
173
|
-
* - 全局 binding:直接基于根数据;
|
|
174
|
-
* - repeatable-group:binding 等于/前缀 dataPath 或以 `$item.` 开头时,改用当前条目数据。
|
|
186
|
+
* Resolve element binding against provided data.
|
|
175
187
|
*/
|
|
176
188
|
const resolveBindingValue = (binding, rootData, context) => {
|
|
177
189
|
if (!binding)
|
|
178
190
|
return undefined;
|
|
179
|
-
const
|
|
180
|
-
let target = rootData;
|
|
181
|
-
let path = binding;
|
|
182
|
-
// repeatable-group: binding 等于 dataPath 或以其为前缀时,切换到当前条目数据
|
|
183
|
-
if (contextBinding &&
|
|
184
|
-
(binding === contextBinding || binding.startsWith(`${contextBinding}.`))) {
|
|
185
|
-
target = contextData;
|
|
186
|
-
path =
|
|
187
|
-
binding === contextBinding
|
|
188
|
-
? ''
|
|
189
|
-
: binding.slice(contextBinding.length + 1);
|
|
190
|
-
}
|
|
191
|
-
else if (binding.startsWith('$item.')) {
|
|
192
|
-
target = contextData;
|
|
193
|
-
path = binding.slice('$item.'.length);
|
|
194
|
-
}
|
|
195
|
-
const value = readByPath(target, path);
|
|
191
|
+
const value = readByPath(rootData, binding);
|
|
196
192
|
return value === undefined ? undefined : value;
|
|
197
193
|
};
|
|
198
194
|
exports.resolveBindingValue = resolveBindingValue;
|
|
199
195
|
/** ---------- 样式构建 ---------- */
|
|
200
|
-
const justifyByTextAlign = (textAlign) => {
|
|
201
|
-
if (textAlign === 'center')
|
|
202
|
-
return 'center';
|
|
203
|
-
if (textAlign === 'right')
|
|
204
|
-
return 'flex-end';
|
|
205
|
-
return 'flex-start';
|
|
206
|
-
};
|
|
207
196
|
/**
|
|
208
197
|
* 生成元素外层样式(绝对/弹性布局),始终返回内联样式字符串。
|
|
209
198
|
*/
|
|
210
199
|
const buildWrapperStyle = (el, unit) => {
|
|
211
|
-
var _a
|
|
200
|
+
var _a;
|
|
212
201
|
const abs = getAbsLayout(el);
|
|
213
202
|
if (abs) {
|
|
214
203
|
const textAlign = (_a = el === null || el === void 0 ? void 0 : el.style) === null || _a === void 0 ? void 0 : _a.textAlign;
|
|
@@ -223,65 +212,18 @@ const buildWrapperStyle = (el, unit) => {
|
|
|
223
212
|
textAlign,
|
|
224
213
|
}, unit);
|
|
225
214
|
}
|
|
226
|
-
|
|
227
|
-
if (!flex)
|
|
228
|
-
return '';
|
|
229
|
-
const item = flex.item || {};
|
|
230
|
-
return (0, exports.styleObjectToString)({
|
|
231
|
-
width: (0, exports.addUnit)(flex.width, unit),
|
|
232
|
-
height: (0, exports.addUnit)(flex.height, unit),
|
|
233
|
-
order: item.order,
|
|
234
|
-
flexGrow: item.flexGrow,
|
|
235
|
-
flexShrink: item.flexShrink,
|
|
236
|
-
flexBasis: item.flexBasis,
|
|
237
|
-
alignSelf: item.alignSelf,
|
|
238
|
-
boxSizing: 'border-box',
|
|
239
|
-
textAlign: (_b = el === null || el === void 0 ? void 0 : el.style) === null || _b === void 0 ? void 0 : _b.textAlign,
|
|
240
|
-
}, unit);
|
|
215
|
+
return '';
|
|
241
216
|
};
|
|
242
217
|
/**
|
|
243
218
|
* padding 数组/数字转 CSS 缩写字符串。
|
|
244
219
|
*/
|
|
245
|
-
const formatPadding = (padding, unit) => {
|
|
246
|
-
if (padding === undefined || padding === null)
|
|
247
|
-
return undefined;
|
|
248
|
-
if (typeof padding === 'number')
|
|
249
|
-
return (0, exports.addUnit)(padding, unit);
|
|
250
|
-
if (Array.isArray(padding)) {
|
|
251
|
-
const list = padding
|
|
252
|
-
.filter(v => v !== undefined && v !== null)
|
|
253
|
-
.map(v => (0, exports.addUnit)(v, unit));
|
|
254
|
-
if (!list.length)
|
|
255
|
-
return undefined;
|
|
256
|
-
if (list.length === 2)
|
|
257
|
-
return `${list[0]} ${list[1]}`;
|
|
258
|
-
if (list.length === 3)
|
|
259
|
-
return `${list[0]} ${list[1]} ${list[2]}`;
|
|
260
|
-
if (list.length >= 4)
|
|
261
|
-
return `${list[0]} ${list[1]} ${list[2]} ${list[3]}`;
|
|
262
|
-
}
|
|
263
|
-
return undefined;
|
|
264
|
-
};
|
|
265
220
|
/**
|
|
266
|
-
* 构建 layout-panel
|
|
221
|
+
* 构建 layout-panel 的容器样式(绝对布局容器)。
|
|
267
222
|
*/
|
|
268
223
|
const buildPanelStyle = (el, unit) => {
|
|
269
|
-
const options = (el.container && el.container.options) || {};
|
|
270
224
|
const style = {
|
|
271
|
-
display: '
|
|
272
|
-
flexDirection: options.direction || 'row',
|
|
273
|
-
flexWrap: options.wrap || 'nowrap',
|
|
274
|
-
justifyContent: options.justifyContent,
|
|
275
|
-
alignItems: options.alignItems,
|
|
276
|
-
padding: formatPadding(options.padding, unit),
|
|
225
|
+
display: 'block',
|
|
277
226
|
};
|
|
278
|
-
if (options.gap && typeof options.gap === 'number') {
|
|
279
|
-
style.gap = (0, exports.addUnit)(options.gap, unit);
|
|
280
|
-
}
|
|
281
|
-
else if (options.gap && isObject(options.gap)) {
|
|
282
|
-
style.rowGap = (0, exports.addUnit)(options.gap.row, unit);
|
|
283
|
-
style.columnGap = (0, exports.addUnit)(options.gap.column, unit);
|
|
284
|
-
}
|
|
285
227
|
return (0, exports.styleObjectToString)(style, unit);
|
|
286
228
|
};
|
|
287
229
|
/**
|
|
@@ -292,106 +234,47 @@ const normalizeElementStyle = (style, unit) => {
|
|
|
292
234
|
return '';
|
|
293
235
|
return (0, exports.styleObjectToString)(style, unit);
|
|
294
236
|
};
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
(group.itemTemplate || []).length;
|
|
325
|
-
const template = (group.items && group.items[0] && group.items[0].elements) ||
|
|
326
|
-
group.itemTemplate ||
|
|
327
|
-
[];
|
|
328
|
-
const gap = inferGroupGap(group);
|
|
329
|
-
// Use saved items (from designer) first
|
|
330
|
-
if (group.items && group.items.length) {
|
|
331
|
-
group.items.slice(0, maxItems).forEach((item, idx) => {
|
|
332
|
-
const payload = dataList[idx] !== undefined ? dataList[idx] : item.data;
|
|
333
|
-
(item.elements || []).forEach(el => {
|
|
334
|
-
result.push({
|
|
335
|
-
element: el,
|
|
336
|
-
contextData: payload,
|
|
337
|
-
contextBinding: group.dataPath,
|
|
338
|
-
});
|
|
339
|
-
});
|
|
340
|
-
});
|
|
341
|
-
return result;
|
|
342
|
-
}
|
|
343
|
-
// Otherwise clone from template by gap
|
|
344
|
-
dataList.slice(0, maxItems).forEach((payload, idx) => {
|
|
345
|
-
template.forEach(el => {
|
|
346
|
-
const abs = getAbsLayout(el);
|
|
347
|
-
const cloned = abs
|
|
348
|
-
? {
|
|
349
|
-
...el,
|
|
350
|
-
layout: { ...abs, y: abs.y + idx * gap },
|
|
351
|
-
}
|
|
352
|
-
: el;
|
|
353
|
-
result.push({
|
|
354
|
-
element: cloned,
|
|
355
|
-
contextData: payload,
|
|
356
|
-
contextBinding: group.dataPath,
|
|
357
|
-
});
|
|
358
|
-
});
|
|
359
|
-
});
|
|
360
|
-
return result;
|
|
237
|
+
const buildTextIcon = (el, unit) => {
|
|
238
|
+
var _a, _b, _c;
|
|
239
|
+
const icon = el.icon;
|
|
240
|
+
if (!icon || icon.enable === false)
|
|
241
|
+
return undefined;
|
|
242
|
+
const style = icon.style || 'fill';
|
|
243
|
+
const baseName = el.key || el.binding || el.id;
|
|
244
|
+
let name;
|
|
245
|
+
if (style === 'dot')
|
|
246
|
+
name = 'round';
|
|
247
|
+
else if (style === 'line')
|
|
248
|
+
name = baseName ? `${baseName}-line` : undefined;
|
|
249
|
+
else
|
|
250
|
+
name = baseName || undefined;
|
|
251
|
+
if (!name)
|
|
252
|
+
return undefined;
|
|
253
|
+
const size = icon.size !== undefined && icon.size !== null
|
|
254
|
+
? icon.size
|
|
255
|
+
: (_a = el.style) === null || _a === void 0 ? void 0 : _a.fontSize;
|
|
256
|
+
const gap = icon.gap !== undefined && icon.gap !== null ? icon.gap : 4;
|
|
257
|
+
const color = (_b = icon.color) !== null && _b !== void 0 ? _b : (typeof ((_c = el.style) === null || _c === void 0 ? void 0 : _c.color) === 'string' ? el.style.color : undefined);
|
|
258
|
+
return {
|
|
259
|
+
name: `${name}`,
|
|
260
|
+
text: `${name}`,
|
|
261
|
+
size: (0, exports.addUnit)(size, unit),
|
|
262
|
+
gap: (0, exports.addUnit)(gap, unit),
|
|
263
|
+
color: color,
|
|
264
|
+
align: icon.align || 'left',
|
|
265
|
+
};
|
|
361
266
|
};
|
|
362
267
|
/** ---------- 渲染树构建 ---------- */
|
|
363
268
|
/**
|
|
364
|
-
* 将 children
|
|
269
|
+
* 将 children 展开为渲染节点。
|
|
365
270
|
*/
|
|
366
271
|
const buildRenderNodes = (children, rootData, unit = 'px', context = {}) => {
|
|
367
272
|
if (!Array.isArray(children))
|
|
368
273
|
return [];
|
|
369
|
-
// Mark mutually exclusive bindings to hide them when repeatable-group is present
|
|
370
|
-
const excluded = new Set();
|
|
371
|
-
children.forEach(el => {
|
|
372
|
-
if (el && el.type === 'repeatable-group' && !!el.visible) {
|
|
373
|
-
(el.mutualExcludes || []).forEach(b => excluded.add(b));
|
|
374
|
-
}
|
|
375
|
-
});
|
|
376
274
|
const nodes = [];
|
|
377
275
|
children.forEach(el => {
|
|
378
276
|
if (!el || el.visible === false)
|
|
379
277
|
return;
|
|
380
|
-
if (el.type === 'repeatable-group') {
|
|
381
|
-
const instances = materializeRepeatableItems(el, rootData);
|
|
382
|
-
instances.forEach(({ element, contextData, contextBinding }) => {
|
|
383
|
-
const node = buildNode(element, rootData, unit, {
|
|
384
|
-
...context,
|
|
385
|
-
contextData,
|
|
386
|
-
contextBinding,
|
|
387
|
-
});
|
|
388
|
-
if (node)
|
|
389
|
-
nodes.push(node);
|
|
390
|
-
});
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
if (el.binding && excluded.has(el.binding))
|
|
394
|
-
return;
|
|
395
278
|
const node = buildNode(el, rootData, unit, context);
|
|
396
279
|
if (node)
|
|
397
280
|
nodes.push(node);
|
|
@@ -429,6 +312,7 @@ const buildNode = (el, rootData, unit, context) => {
|
|
|
429
312
|
contentStyle: textStyle,
|
|
430
313
|
text: `${value}`,
|
|
431
314
|
visible: !!el.visible,
|
|
315
|
+
icon: buildTextIcon(el, unit),
|
|
432
316
|
};
|
|
433
317
|
}
|
|
434
318
|
if (el.type === 'image') {
|
|
@@ -465,15 +349,7 @@ const buildNode = (el, rootData, unit, context) => {
|
|
|
465
349
|
visible: !!el.visible,
|
|
466
350
|
};
|
|
467
351
|
}
|
|
468
|
-
|
|
469
|
-
return {
|
|
470
|
-
id: el.id,
|
|
471
|
-
type: 'text',
|
|
472
|
-
wrapperStyle,
|
|
473
|
-
contentStyle: baseStyle,
|
|
474
|
-
text: el.defaultValue || '',
|
|
475
|
-
visible: !!el.visible,
|
|
476
|
-
};
|
|
352
|
+
return null;
|
|
477
353
|
};
|
|
478
354
|
/**
|
|
479
355
|
* 主入口:合并布局 Schema 与数据,生成供前端使用的渲染结果。
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./elements"), exports);
|
|
18
|
+
__exportStar(require("./layout"), exports);
|
|
19
|
+
__exportStar(require("./render"), exports);
|
package/package.json
CHANGED
package/script/sync-core.js
CHANGED
|
@@ -6,6 +6,7 @@ const coreRoot = path.resolve(pkgRoot, '../km-card-layout-core');
|
|
|
6
6
|
const targetDir = path.resolve(pkgRoot, 'src/vendor/km-card-layout-core');
|
|
7
7
|
|
|
8
8
|
const filesToCopy = ['index.ts', 'types.d.ts'];
|
|
9
|
+
const dirsToCopy = ['interface'];
|
|
9
10
|
|
|
10
11
|
function ensureFileExists(filePath) {
|
|
11
12
|
if (!fs.existsSync(filePath)) {
|
|
@@ -24,11 +25,18 @@ function syncCore() {
|
|
|
24
25
|
fs.copyFileSync(source, target);
|
|
25
26
|
});
|
|
26
27
|
|
|
28
|
+
dirsToCopy.forEach((dirName) => {
|
|
29
|
+
const sourceDir = path.join(coreRoot, dirName);
|
|
30
|
+
if (!fs.existsSync(sourceDir)) return;
|
|
31
|
+
const target = path.join(targetDir, dirName);
|
|
32
|
+
fs.cpSync(sourceDir, target, { recursive: true });
|
|
33
|
+
});
|
|
34
|
+
|
|
27
35
|
console.log(
|
|
28
36
|
`Synced km-card-layout-core -> ${path.relative(
|
|
29
37
|
pkgRoot,
|
|
30
38
|
targetDir,
|
|
31
|
-
)} (${filesToCopy.join(', ')})`,
|
|
39
|
+
)} (${filesToCopy.concat(dirsToCopy).join(', ')})`,
|
|
32
40
|
);
|
|
33
41
|
}
|
|
34
42
|
|