km-card-layout-core 0.1.24 → 0.1.25

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 CHANGED
@@ -1,18 +1,16 @@
1
1
  # km-card-layout-core
2
2
 
3
- 纯函数渲染核心:负责将布局 JSON 与数据合成渲染树,处理绑定路径、样式单位(px/rpx)等。
3
+ Utilities for working with card layout schemas: sanitize layouts, handle bindings, convert style units, and apply background/decoration helpers. Rendering now uses `CardElement` directly without intermediate RenderNode conversion.
4
4
 
5
5
  ## API
6
6
 
7
- - `normalizeLayout(layout)`:清洗/容错布局对象或 JSON 字符串,补齐默认尺寸/children。
8
- - `buildRenderResult(layout, data, unit?)`:返回 `{ renderTree, cardStyle, backgroundImage, backgroundStyle }`,可直接用于 PC/Vue、小程序等多端。
9
- - `buildRenderNodes(children, data, unit?, context?)`:仅展开 children 为渲染节点列表。
10
- - 其他工具:`resolveBindingValue`(绑定读取,支持 `$item.` dataPath 上下文)、`styleObjectToString`、`addUnit`。
7
+ - `normalizeLayout(layout)`: sanitize layout objects and fill defaults.
8
+ - `resolveBindingValue(path, data, context?)`: read bound data with optional context.
9
+ - `styleObjectToString(style, unit?)`: convert a style object to a CSS string.
10
+ - `addUnit(value, unit)`: append px/rpx to numbers or numeric strings.
11
+ - Background helpers: `applyBackground`, `applySpecialStyle`, `backgroundChange`, `buildRenderData`, etc.
11
12
 
12
- ## 适用场景
13
+ ## Usage
13
14
 
14
- - PC 端:在 Vue 组件里调用 `buildRenderResult`,把 renderTree 映射为 VDOM。
15
- - 小程序:被 `km-card-layout-component-miniprogram` 依赖,组件中通过 core 得到 renderTree。
16
- - 预渲染/快照:Node 环境按相同逻辑生成渲染树后做静态输出或图片化。
15
+ Use the layout schema and card elements directly for rendering on web or mini-program targets—no extra RenderNode transformation layer is required. The core is platform-agnostic and can be imported via `require('km-card-layout-core')`.
17
16
 
18
- 核心不依赖 DOM/平台 API,可直接通过 `require('km-card-layout-core')` 使用。
package/data.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { isObject } from './helpers';
2
+ import type { BindingContext } from './interface';
2
3
 
3
4
  const pathToSegments = (path: string): string[] =>
4
5
  `${path || ''}`
@@ -30,7 +31,7 @@ const readByPath = (data: any, path: string): any => {
30
31
  export const resolveBindingValue = (
31
32
  binding: string | undefined,
32
33
  rootData: Record<string, any>,
33
- context?: Record<string, any>
34
+ context?: BindingContext
34
35
  ): any => {
35
36
  if (!binding) return undefined;
36
37
  const value = readByPath(rootData, binding);
package/dist/index.js CHANGED
@@ -20,12 +20,30 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
20
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
21
  };
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.updateElementsStyle = exports.applyBackground = exports.applySpecialStyle = exports.resolveSpecialStyle = exports.DEFAULT_DECOR_COLOR = exports.backgroundChange = void 0;
23
+ exports.buildTextIconMeta = exports.getIconName = exports.getImageSrc = exports.getTextValue = exports.buildImageContentStyle = exports.buildTextContentStyle = exports.buildPanelContentStyle = exports.buildBaseContentStyle = exports.buildBackgroundStyle = exports.buildCardStyle = exports.buildWrapperStyle = exports.buildRenderData = exports.updateElementsStyle = exports.applyBackground = exports.applySpecialStyle = exports.resolveSpecialStyle = exports.DEFAULT_DECOR_COLOR = exports.backgroundChange = exports.getTemplateBackgrounds = exports.getTemplateItems = exports.applyItemCollectBindings = exports.stripLayoutBindings = exports.resolveBindingValue = exports.areChildrenEqual = exports.parseLayout = exports.normalizeId = exports.collectBindings = exports.getAbsLayout = exports.roundToInt = exports.sanitizeElement = exports.sanitizeLayout = exports.normalizeLayout = exports.isObject = exports.toNumber = exports.styleObjectToString = exports.addUnit = void 0;
24
24
  __exportStar(require("./interface/index"), exports);
25
- __exportStar(require("./helpers"), exports);
26
- __exportStar(require("./layout"), exports);
27
- __exportStar(require("./data"), exports);
28
- __exportStar(require("./bindings"), exports);
25
+ var helpers_1 = require("./helpers");
26
+ Object.defineProperty(exports, "addUnit", { enumerable: true, get: function () { return helpers_1.addUnit; } });
27
+ Object.defineProperty(exports, "styleObjectToString", { enumerable: true, get: function () { return helpers_1.styleObjectToString; } });
28
+ Object.defineProperty(exports, "toNumber", { enumerable: true, get: function () { return helpers_1.toNumber; } });
29
+ Object.defineProperty(exports, "isObject", { enumerable: true, get: function () { return helpers_1.isObject; } });
30
+ var layout_1 = require("./layout");
31
+ Object.defineProperty(exports, "normalizeLayout", { enumerable: true, get: function () { return layout_1.normalizeLayout; } });
32
+ Object.defineProperty(exports, "sanitizeLayout", { enumerable: true, get: function () { return layout_1.sanitizeLayout; } });
33
+ Object.defineProperty(exports, "sanitizeElement", { enumerable: true, get: function () { return layout_1.sanitizeElement; } });
34
+ Object.defineProperty(exports, "roundToInt", { enumerable: true, get: function () { return layout_1.roundToInt; } });
35
+ Object.defineProperty(exports, "getAbsLayout", { enumerable: true, get: function () { return layout_1.getAbsLayout; } });
36
+ Object.defineProperty(exports, "collectBindings", { enumerable: true, get: function () { return layout_1.collectBindings; } });
37
+ Object.defineProperty(exports, "normalizeId", { enumerable: true, get: function () { return layout_1.normalizeId; } });
38
+ Object.defineProperty(exports, "parseLayout", { enumerable: true, get: function () { return layout_1.parseLayout; } });
39
+ Object.defineProperty(exports, "areChildrenEqual", { enumerable: true, get: function () { return layout_1.areChildrenEqual; } });
40
+ var data_1 = require("./data");
41
+ Object.defineProperty(exports, "resolveBindingValue", { enumerable: true, get: function () { return data_1.resolveBindingValue; } });
42
+ var bindings_1 = require("./bindings");
43
+ Object.defineProperty(exports, "stripLayoutBindings", { enumerable: true, get: function () { return bindings_1.stripLayoutBindings; } });
44
+ Object.defineProperty(exports, "applyItemCollectBindings", { enumerable: true, get: function () { return bindings_1.applyItemCollectBindings; } });
45
+ Object.defineProperty(exports, "getTemplateItems", { enumerable: true, get: function () { return bindings_1.getTemplateItems; } });
46
+ Object.defineProperty(exports, "getTemplateBackgrounds", { enumerable: true, get: function () { return bindings_1.getTemplateBackgrounds; } });
29
47
  var changeBackground_1 = require("./ops/changeBackground");
30
48
  Object.defineProperty(exports, "backgroundChange", { enumerable: true, get: function () { return changeBackground_1.backgroundChange; } });
31
49
  Object.defineProperty(exports, "DEFAULT_DECOR_COLOR", { enumerable: true, get: function () { return changeBackground_1.DEFAULT_DECOR_COLOR; } });
@@ -33,5 +51,17 @@ Object.defineProperty(exports, "resolveSpecialStyle", { enumerable: true, get: f
33
51
  Object.defineProperty(exports, "applySpecialStyle", { enumerable: true, get: function () { return changeBackground_1.applySpecialStyle; } });
34
52
  Object.defineProperty(exports, "applyBackground", { enumerable: true, get: function () { return changeBackground_1.applyBackground; } });
35
53
  Object.defineProperty(exports, "updateElementsStyle", { enumerable: true, get: function () { return changeBackground_1.updateElementsStyle; } });
36
- __exportStar(require("./render/builder"), exports);
37
- __exportStar(require("./render/tool"), exports);
54
+ var tool_1 = require("./render/tool");
55
+ Object.defineProperty(exports, "buildRenderData", { enumerable: true, get: function () { return tool_1.buildRenderData; } });
56
+ var helpers_2 = require("./render/helpers");
57
+ Object.defineProperty(exports, "buildWrapperStyle", { enumerable: true, get: function () { return helpers_2.buildWrapperStyle; } });
58
+ Object.defineProperty(exports, "buildCardStyle", { enumerable: true, get: function () { return helpers_2.buildCardStyle; } });
59
+ Object.defineProperty(exports, "buildBackgroundStyle", { enumerable: true, get: function () { return helpers_2.buildBackgroundStyle; } });
60
+ Object.defineProperty(exports, "buildBaseContentStyle", { enumerable: true, get: function () { return helpers_2.buildBaseContentStyle; } });
61
+ Object.defineProperty(exports, "buildPanelContentStyle", { enumerable: true, get: function () { return helpers_2.buildPanelContentStyle; } });
62
+ Object.defineProperty(exports, "buildTextContentStyle", { enumerable: true, get: function () { return helpers_2.buildTextContentStyle; } });
63
+ Object.defineProperty(exports, "buildImageContentStyle", { enumerable: true, get: function () { return helpers_2.buildImageContentStyle; } });
64
+ Object.defineProperty(exports, "getTextValue", { enumerable: true, get: function () { return helpers_2.getTextValue; } });
65
+ Object.defineProperty(exports, "getImageSrc", { enumerable: true, get: function () { return helpers_2.getImageSrc; } });
66
+ Object.defineProperty(exports, "getIconName", { enumerable: true, get: function () { return helpers_2.getIconName; } });
67
+ Object.defineProperty(exports, "buildTextIconMeta", { enumerable: true, get: function () { return helpers_2.buildTextIconMeta; } });
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -16,5 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./elements"), exports);
18
18
  __exportStar(require("./layout"), exports);
19
- __exportStar(require("./render"), exports);
20
19
  __exportStar(require("./data/payload"), exports);
20
+ __exportStar(require("./context"), exports);
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildTextIconMeta = exports.getIconName = exports.getImageSrc = exports.getTextValue = exports.buildImageContentStyle = exports.buildTextContentStyle = exports.buildPanelContentStyle = exports.buildBaseContentStyle = exports.buildBackgroundStyle = exports.buildCardStyle = exports.buildWrapperStyle = void 0;
4
+ const helpers_1 = require("../helpers");
5
+ const layout_1 = require("../layout");
6
+ const buildWrapperStyle = (el, unit = 'px') => {
7
+ const abs = (0, layout_1.getAbsLayout)(el);
8
+ if (!abs)
9
+ return {};
10
+ return {
11
+ position: 'absolute',
12
+ left: (0, helpers_1.addUnit)(abs.x, unit),
13
+ top: (0, helpers_1.addUnit)(abs.y, unit),
14
+ width: (0, helpers_1.addUnit)(abs.width, unit),
15
+ height: (0, helpers_1.addUnit)(abs.height, unit),
16
+ zIndex: abs.zIndex,
17
+ boxSizing: 'border-box',
18
+ };
19
+ };
20
+ exports.buildWrapperStyle = buildWrapperStyle;
21
+ const buildCardStyle = (layout, unit = 'px') => ({
22
+ width: (0, helpers_1.addUnit)(layout.width, unit),
23
+ height: (0, helpers_1.addUnit)(layout.height, unit),
24
+ color: layout.fontColor,
25
+ borderRadius: layout.borderRadius !== undefined
26
+ ? (0, helpers_1.addUnit)(layout.borderRadius, unit)
27
+ : undefined,
28
+ padding: layout.padding !== undefined ? (0, helpers_1.addUnit)(layout.padding, unit) : undefined,
29
+ position: 'relative',
30
+ overflow: 'hidden',
31
+ boxSizing: 'border-box',
32
+ backgroundColor: 'transparent',
33
+ });
34
+ exports.buildCardStyle = buildCardStyle;
35
+ const buildBackgroundStyle = (layout, unit = 'px') => ({
36
+ zIndex: layout.backgroundZIndex,
37
+ borderRadius: layout.borderRadius !== undefined
38
+ ? (0, helpers_1.addUnit)(layout.borderRadius, unit)
39
+ : undefined,
40
+ width: '100%',
41
+ height: '100%',
42
+ position: 'absolute',
43
+ left: 0,
44
+ top: 0,
45
+ });
46
+ exports.buildBackgroundStyle = buildBackgroundStyle;
47
+ const buildBaseContentStyle = (el) => ({
48
+ ...(el.style || {}),
49
+ boxSizing: 'border-box',
50
+ });
51
+ exports.buildBaseContentStyle = buildBaseContentStyle;
52
+ const buildPanelContentStyle = (el, unit = 'px') => ({
53
+ position: 'relative',
54
+ width: '100%',
55
+ height: '100%',
56
+ display: 'block',
57
+ boxSizing: 'border-box',
58
+ ...(el.style || {}),
59
+ });
60
+ exports.buildPanelContentStyle = buildPanelContentStyle;
61
+ const buildTextContentStyle = (el, unit = 'px') => {
62
+ var _a, _b, _c, _d;
63
+ const textAlign = ((_a = el.style) === null || _a === void 0 ? void 0 : _a.textAlign) || el.align || undefined;
64
+ const style = {
65
+ ...(el.style || {}),
66
+ fontSize: (0, helpers_1.addUnit)((_b = el.style) === null || _b === void 0 ? void 0 : _b.fontSize, unit),
67
+ whiteSpace: 'pre-wrap',
68
+ wordBreak: 'break-word',
69
+ lineHeight: ((_c = el.style) === null || _c === void 0 ? void 0 : _c.lineHeight) !== undefined && ((_d = el.style) === null || _d === void 0 ? void 0 : _d.lineHeight) !== null
70
+ ? (0, helpers_1.addUnit)(el.style.lineHeight, unit)
71
+ : '1',
72
+ };
73
+ if (textAlign)
74
+ style.textAlign = textAlign;
75
+ return style;
76
+ };
77
+ exports.buildTextContentStyle = buildTextContentStyle;
78
+ const buildImageContentStyle = (el) => {
79
+ const style = { ...(el.style || {}) };
80
+ const borderWidth = Number(style.borderWidth);
81
+ if (Number.isFinite(borderWidth) && borderWidth > 0) {
82
+ if (!style.borderStyle)
83
+ style.borderStyle = 'solid';
84
+ if (!style.borderColor)
85
+ style.borderColor = '#000000';
86
+ }
87
+ return style;
88
+ };
89
+ exports.buildImageContentStyle = buildImageContentStyle;
90
+ const getTextValue = (el) => el.defaultValue !== undefined && el.defaultValue !== null
91
+ ? `${el.defaultValue}`
92
+ : '';
93
+ exports.getTextValue = getTextValue;
94
+ const getImageSrc = (el) => el.defaultUrl || el.defaultValue || '';
95
+ exports.getImageSrc = getImageSrc;
96
+ const getIconName = (el) => (el.name || el.defaultValue || '');
97
+ exports.getIconName = getIconName;
98
+ const buildTextIconMeta = (el, unit = 'px') => {
99
+ var _a, _b, _c, _d, _e, _f;
100
+ const icon = el.icon;
101
+ const enabled = (icon === null || icon === void 0 ? void 0 : icon.enable) === true;
102
+ if (!icon || !enabled)
103
+ return null;
104
+ const style = icon.style || 'fill';
105
+ const baseName = icon.name || el.key || el.binding || el.id;
106
+ let name;
107
+ if (style === 'dot')
108
+ name = 'round';
109
+ else if (style === 'line')
110
+ name = baseName ? `${baseName}-line` : undefined;
111
+ else
112
+ name = baseName || undefined;
113
+ if (!name)
114
+ return null;
115
+ const size = icon.size !== undefined && icon.size !== null
116
+ ? icon.size
117
+ : (_a = el.style) === null || _a === void 0 ? void 0 : _a.fontSize;
118
+ const gap = icon.gap !== undefined && icon.gap !== null ? icon.gap : 4;
119
+ 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);
120
+ return {
121
+ name: `${name}`,
122
+ size: (0, helpers_1.addUnit)(size, unit),
123
+ gap: (0, helpers_1.addUnit)(gap, unit),
124
+ color,
125
+ align: icon.align || 'left',
126
+ wrapperStyle: {
127
+ height: ((_d = el.style) === null || _d === void 0 ? void 0 : _d.lineHeight) !== undefined && ((_e = el.style) === null || _e === void 0 ? void 0 : _e.lineHeight) !== null
128
+ ? (0, helpers_1.addUnit)(el.style.lineHeight, unit)
129
+ : (_f = el.style) === null || _f === void 0 ? void 0 : _f.fontSize,
130
+ },
131
+ };
132
+ };
133
+ exports.buildTextIconMeta = buildTextIconMeta;
package/index.ts CHANGED
@@ -10,10 +10,25 @@
10
10
 
11
11
 
12
12
  export * from './interface/index';
13
- export * from './helpers';
14
- export * from './layout';
15
- export * from './data';
16
- export * from './bindings';
13
+ export { addUnit, styleObjectToString, toNumber, isObject } from './helpers';
14
+ export {
15
+ normalizeLayout,
16
+ sanitizeLayout,
17
+ sanitizeElement,
18
+ roundToInt,
19
+ getAbsLayout,
20
+ collectBindings,
21
+ normalizeId,
22
+ parseLayout,
23
+ areChildrenEqual,
24
+ } from './layout';
25
+ export { resolveBindingValue } from './data';
26
+ export {
27
+ stripLayoutBindings,
28
+ applyItemCollectBindings,
29
+ getTemplateItems,
30
+ getTemplateBackgrounds,
31
+ } from './bindings';
17
32
  export {
18
33
  backgroundChange,
19
34
  DEFAULT_DECOR_COLOR,
@@ -22,7 +37,17 @@ export {
22
37
  applyBackground,
23
38
  updateElementsStyle,
24
39
  } from './ops/changeBackground';
25
- export * from './render/builder';
26
- export * from './render/tool';
27
-
28
-
40
+ export { buildRenderData } from './render/tool';
41
+ export {
42
+ buildWrapperStyle,
43
+ buildCardStyle,
44
+ buildBackgroundStyle,
45
+ buildBaseContentStyle,
46
+ buildPanelContentStyle,
47
+ buildTextContentStyle,
48
+ buildImageContentStyle,
49
+ getTextValue,
50
+ getImageSrc,
51
+ getIconName,
52
+ buildTextIconMeta,
53
+ } from './render/helpers';
@@ -0,0 +1,6 @@
1
+ export interface BindingContext {
2
+ // Optional binding prefix for nested contexts
3
+ contextBinding?: string;
4
+ // Optional nested context data
5
+ contextData?: any;
6
+ }
@@ -1,4 +1,4 @@
1
1
  export * from './elements';
2
2
  export * from './layout';
3
- export * from './render';
4
- export * from './data/payload';
3
+ export * from './data/payload';
4
+ export * from './context';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "km-card-layout-core",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "description": "Shared render helpers for CardMaster layout JSON (binding resolution, layout normalization).",
5
5
  "main": "dist/index.js",
6
6
  "types": "types.d.ts",
@@ -0,0 +1,144 @@
1
+ import { addUnit } from '../helpers';
2
+ import { getAbsLayout } from '../layout';
3
+ import type {
4
+ CardElement,
5
+ CardLayoutSchema,
6
+ IconElement,
7
+ ImageElement,
8
+ LayoutPanelElement,
9
+ TextElement,
10
+ } from '../interface';
11
+
12
+ export const buildWrapperStyle = (el: CardElement, unit: 'px' | 'rpx' = 'px') => {
13
+ const abs = getAbsLayout(el);
14
+ if (!abs) return {};
15
+ return {
16
+ position: 'absolute',
17
+ left: addUnit(abs.x, unit),
18
+ top: addUnit(abs.y, unit),
19
+ width: addUnit(abs.width, unit),
20
+ height: addUnit(abs.height, unit),
21
+ zIndex: abs.zIndex,
22
+ boxSizing: 'border-box',
23
+ };
24
+ };
25
+
26
+ export const buildCardStyle = (layout: CardLayoutSchema, unit: 'px' | 'rpx' = 'px') => ({
27
+ width: addUnit(layout.width, unit),
28
+ height: addUnit(layout.height, unit),
29
+ color: layout.fontColor,
30
+ borderRadius:
31
+ layout.borderRadius !== undefined
32
+ ? addUnit(layout.borderRadius, unit)
33
+ : undefined,
34
+ padding:
35
+ layout.padding !== undefined ? addUnit(layout.padding, unit) : undefined,
36
+ position: 'relative',
37
+ overflow: 'hidden',
38
+ boxSizing: 'border-box',
39
+ backgroundColor: 'transparent',
40
+ });
41
+
42
+ export const buildBackgroundStyle = (layout: CardLayoutSchema, unit: 'px' | 'rpx' = 'px') => ({
43
+ zIndex: layout.backgroundZIndex,
44
+ borderRadius:
45
+ layout.borderRadius !== undefined
46
+ ? addUnit(layout.borderRadius, unit)
47
+ : undefined,
48
+ width: '100%',
49
+ height: '100%',
50
+ position: 'absolute',
51
+ left: 0,
52
+ top: 0,
53
+ });
54
+
55
+ export const buildBaseContentStyle = (el: CardElement) => ({
56
+ ...(el.style || {}),
57
+ boxSizing: 'border-box',
58
+ });
59
+
60
+ export const buildPanelContentStyle = (el: LayoutPanelElement, unit: 'px' | 'rpx' = 'px') => ({
61
+ position: 'relative',
62
+ width: '100%',
63
+ height: '100%',
64
+ display: 'block',
65
+ boxSizing: 'border-box',
66
+ ...(el.style || {}),
67
+ });
68
+
69
+ export const buildTextContentStyle = (el: TextElement, unit: 'px' | 'rpx' = 'px') => {
70
+ const textAlign =
71
+ (el.style?.textAlign as string | undefined) || el.align || undefined;
72
+ const style: Record<string, any> = {
73
+ ...(el.style || {}),
74
+ fontSize: addUnit(el.style?.fontSize, unit),
75
+ whiteSpace: 'pre-wrap',
76
+ wordBreak: 'break-word',
77
+ lineHeight:
78
+ el.style?.lineHeight !== undefined && el.style?.lineHeight !== null
79
+ ? addUnit(el.style.lineHeight as any, unit)
80
+ : '1',
81
+ };
82
+ if (textAlign) style.textAlign = textAlign;
83
+ return style;
84
+ };
85
+
86
+ export const buildImageContentStyle = (el: ImageElement) => {
87
+ const style: Record<string, any> = { ...(el.style || {}) };
88
+ const borderWidth = Number(style.borderWidth);
89
+ if (Number.isFinite(borderWidth) && borderWidth > 0) {
90
+ if (!style.borderStyle) style.borderStyle = 'solid';
91
+ if (!style.borderColor) style.borderColor = '#000000';
92
+ }
93
+ return style;
94
+ };
95
+
96
+ export const getTextValue = (el: TextElement) =>
97
+ el.defaultValue !== undefined && el.defaultValue !== null
98
+ ? `${el.defaultValue}`
99
+ : '';
100
+
101
+ export const getImageSrc = (el: ImageElement) =>
102
+ el.defaultUrl || el.defaultValue || '';
103
+
104
+ export const getIconName = (el: IconElement) =>
105
+ (el.name || el.defaultValue || '') as string;
106
+
107
+ export const buildTextIconMeta = (el: TextElement, unit: 'px' | 'rpx' = 'px') => {
108
+ const icon = el.icon;
109
+ const enabled = icon?.enable === true;
110
+ if (!icon || !enabled) return null;
111
+
112
+ const style = icon.style || 'fill';
113
+ const baseName = icon.name || el.key || el.binding || el.id;
114
+ let name: string | undefined;
115
+ if (style === 'dot') name = 'round';
116
+ else if (style === 'line') name = baseName ? `${baseName}-line` : undefined;
117
+ else name = baseName || undefined;
118
+ if (!name) return null;
119
+
120
+ const size =
121
+ icon.size !== undefined && icon.size !== null
122
+ ? icon.size
123
+ : (el.style?.fontSize as any);
124
+ const gap = icon.gap !== undefined && icon.gap !== null ? icon.gap : 4;
125
+ const color =
126
+ icon.color ??
127
+ ((typeof el.style?.color === 'string' ? el.style.color : undefined) as
128
+ | string
129
+ | undefined);
130
+
131
+ return {
132
+ name: `${name}`,
133
+ size: addUnit(size as any, unit),
134
+ gap: addUnit(gap as any, unit),
135
+ color,
136
+ align: icon.align || 'left',
137
+ wrapperStyle: {
138
+ height:
139
+ el.style?.lineHeight !== undefined && el.style?.lineHeight !== null
140
+ ? addUnit(el.style.lineHeight, unit)
141
+ : el.style?.fontSize,
142
+ },
143
+ };
144
+ };
package/types.d.ts CHANGED
@@ -10,8 +10,6 @@ import type {
10
10
  CardElement,
11
11
  CardLayoutInput,
12
12
  CardLayoutSchema,
13
- RenderNode,
14
- RenderResult,
15
13
  TemplateItem,
16
14
  TemplateBackground
17
15
  } from './interface';
@@ -148,22 +146,65 @@ export function updateElementsStyle(
148
146
  updates: Record<string, any>
149
147
  ): CardLayoutSchema;
150
148
 
151
- export function buildRenderNodes(
152
- children: CardElement[],
153
- data: Record<string, any>,
154
- unit?: 'px' | 'rpx',
155
- context?: BindingContext
156
- ): RenderNode[];
149
+ export function buildWrapperStyle(
150
+ el: CardElement,
151
+ unit?: 'px' | 'rpx'
152
+ ): Record<string, any>;
153
+
154
+ export function buildCardStyle(
155
+ layout: CardLayoutSchema,
156
+ unit?: 'px' | 'rpx'
157
+ ): Record<string, any>;
158
+
159
+ export function buildBackgroundStyle(
160
+ layout: CardLayoutSchema,
161
+ unit?: 'px' | 'rpx'
162
+ ): Record<string, any>;
163
+
164
+ export function buildBaseContentStyle(
165
+ el: CardElement
166
+ ): Record<string, any>;
157
167
 
158
- export function buildRenderResult(
159
- layout: CardLayoutInput,
160
- data: Record<string, any>,
168
+ export function buildPanelContentStyle(
169
+ el: import('./interface/elements').LayoutPanelElement,
161
170
  unit?: 'px' | 'rpx'
162
- ): RenderResult;
171
+ ): Record<string, any>;
172
+
173
+ export function buildTextContentStyle(
174
+ el: import('./interface/elements').TextElement,
175
+ unit?: 'px' | 'rpx'
176
+ ): Record<string, any>;
177
+
178
+ export function buildImageContentStyle(
179
+ el: import('./interface/elements').ImageElement
180
+ ): Record<string, any>;
181
+
182
+ export function getTextValue(
183
+ el: import('./interface/elements').TextElement
184
+ ): string;
185
+
186
+ export function getImageSrc(
187
+ el: import('./interface/elements').ImageElement
188
+ ): string;
163
189
 
190
+ export function getIconName(
191
+ el: import('./interface/elements').IconElement
192
+ ): string;
193
+
194
+ export function buildTextIconMeta(
195
+ el: import('./interface/elements').TextElement,
196
+ unit?: 'px' | 'rpx'
197
+ ): {
198
+ name: string;
199
+ size?: string;
200
+ gap?: string;
201
+ color?: string;
202
+ align: 'left' | 'right';
203
+ wrapperStyle?: Record<string, any>;
204
+ } | null;
164
205
 
165
206
  export function buildRenderData (
166
207
  layout: CardLayoutSchema[],
167
208
  items: TemplateItem[],
168
209
  config: Config
169
- ): CardLayoutSchema[];
210
+ ): CardLayoutSchema[];
@@ -1,53 +0,0 @@
1
- import type { CardElementType, CardElement } from './elements';
2
- import type { CardLayoutInput, CardLayoutSchema } from './layout';
3
-
4
- export interface RenderNodeIcon {
5
- name: string;
6
- text?: string;
7
- size?: string;
8
- color?: string;
9
- gap?: string;
10
- align?: 'left' | 'right';
11
- wrapperStyle?: string;
12
- }
13
-
14
- export interface RenderNode {
15
- id: string;
16
- type: CardElementType | 'text';
17
- wrapperStyle: string;
18
- contentStyle: string;
19
- name?: string;
20
- text?: string;
21
- src?: string;
22
- mode?: string;
23
- children?: RenderNode[];
24
- visible?: boolean;
25
- icon?: RenderNodeIcon;
26
- }
27
-
28
- export interface RenderPageResult {
29
- renderTree: RenderNode[];
30
- cardStyle: string;
31
- backgroundImage: string;
32
- backgroundStyle: string;
33
- }
34
-
35
- export type RenderResult = RenderPageResult[];
36
-
37
- export interface BindingContext {
38
- /**
39
- * 当前上下文数据的绑定前缀(预留给嵌套场景)
40
- */
41
- contextBinding?: string;
42
- /**
43
- * 当前上下文数据(预留给嵌套场景)
44
- */
45
- contextData?: any;
46
- }
47
-
48
- export type {
49
- CardElement,
50
- CardElementType,
51
- CardLayoutInput,
52
- CardLayoutSchema,
53
- };
package/render/builder.ts DELETED
@@ -1,287 +0,0 @@
1
- import type {
2
- CardElement,
3
- IconElement,
4
- ImageElement,
5
- LayoutPanelElement,
6
- TextElement,
7
- } from '../interface/elements';
8
- import type { CardLayoutSchema, CardLayoutInput } from '../interface/layout';
9
- import type {
10
- BindingContext,
11
- RenderNode,
12
- RenderResult,
13
- } from '../interface/render';
14
- import { addUnit, styleObjectToString } from '../helpers';
15
- import { getAbsLayout, normalizeLayout } from '../layout';
16
- import { resolveBindingValue } from '../data';
17
-
18
- const buildCardStyle = (layout: CardLayoutSchema, unit: 'px' | 'rpx') =>
19
- styleObjectToString(
20
- {
21
- width: addUnit(layout.width, unit),
22
- height: addUnit(layout.height, unit),
23
- color: layout.fontColor,
24
- borderRadius:
25
- layout.borderRadius !== undefined
26
- ? addUnit(layout.borderRadius, unit)
27
- : undefined,
28
- padding:
29
- layout.padding !== undefined ? addUnit(layout.padding, unit) : undefined,
30
- position: 'relative',
31
- overflow: 'hidden',
32
- boxSizing: 'border-box',
33
- backgroundColor: 'transparent',
34
- },
35
- unit
36
- );
37
-
38
- const buildBackgroundStyle = (layout: CardLayoutSchema, unit: 'px' | 'rpx') =>
39
- styleObjectToString(
40
- {
41
- zIndex: layout.backgroundZIndex,
42
- borderRadius:
43
- layout.borderRadius !== undefined
44
- ? addUnit(layout.borderRadius, unit)
45
- : undefined,
46
- width: '100%',
47
- height: '100%',
48
- position: 'absolute',
49
- left: 0,
50
- top: 0,
51
- },
52
- unit
53
- );
54
-
55
- const buildWrapperStyle = (el: CardElement, unit: 'px' | 'rpx'): string => {
56
- const abs = getAbsLayout(el);
57
- if (!abs) return '';
58
- return styleObjectToString(
59
- {
60
- position: 'absolute',
61
- left: addUnit(abs.x, unit),
62
- top: addUnit(abs.y, unit),
63
- width: addUnit(abs.width, unit),
64
- height: addUnit(abs.height, unit),
65
- zIndex: abs.zIndex,
66
- boxSizing: 'border-box',
67
- },
68
- unit
69
- );
70
- };
71
-
72
- const buildPanelContentStyle = (
73
- el: LayoutPanelElement,
74
- unit: 'px' | 'rpx'
75
- ) =>
76
- styleObjectToString(
77
- {
78
- position: 'relative',
79
- width: '100%',
80
- height: '100%',
81
- display: 'block',
82
- boxSizing: 'border-box',
83
- ...(el.style || {}),
84
- },
85
- unit
86
- );
87
-
88
- const buildTextContentStyle = (el: TextElement, unit: 'px' | 'rpx') => {
89
- const textAlign =
90
- (el.style?.textAlign as string | undefined) || el.align || undefined;
91
- const style: Record<string, any> = {
92
- ...(el.style || {}),
93
- whiteSpace: 'pre-wrap',
94
- wordBreak: 'break-word',
95
- lineHeight:
96
- el.style?.lineHeight !== undefined && el.style?.lineHeight !== null
97
- ? el.style.lineHeight
98
- : '1',
99
- };
100
- if (textAlign) style.textAlign = textAlign;
101
- return styleObjectToString(style, unit);
102
- };
103
-
104
- const buildBaseContentStyle = (el: CardElement, unit: 'px' | 'rpx') =>
105
- styleObjectToString(
106
- {
107
- ...(el.style || {}),
108
- boxSizing: 'border-box',
109
- },
110
- unit
111
- );
112
-
113
- const buildImageContentStyle = (el: ImageElement, unit: 'px' | 'rpx') => {
114
- const style: Record<string, any> = { ...(el.style || {}) };
115
- const borderWidth = Number(style.borderWidth);
116
- if (Number.isFinite(borderWidth) && borderWidth > 0) {
117
- if (!style.borderStyle) style.borderStyle = 'solid';
118
- if (!style.borderColor) style.borderColor = '#000000';
119
- }
120
- return styleObjectToString(style, unit);
121
- };
122
-
123
- const buildTextIcon = (
124
- el: TextElement,
125
- unit: 'px' | 'rpx'
126
- ): RenderNode['icon'] | undefined => {
127
- const icon = el.icon;
128
- const enabled = icon?.enable === true;
129
- if (!icon || !enabled) return undefined;
130
-
131
- const style = icon.style || 'fill';
132
- const baseName = icon.name || el.key || el.binding || el.id;
133
- let name: string | undefined;
134
- if (style === 'dot') name = 'round';
135
- else if (style === 'line') name = baseName ? `${baseName}-line` : undefined;
136
- else name = baseName || undefined;
137
- if (!name) return undefined;
138
-
139
- const size =
140
- icon.size !== undefined && icon.size !== null
141
- ? icon.size
142
- : (el.style?.fontSize as any);
143
- const gap = icon.gap !== undefined && icon.gap !== null ? icon.gap : 4;
144
- const color =
145
- icon.color ??
146
- ((typeof el.style?.color === 'string' ? el.style.color : undefined) as
147
- | string
148
- | undefined);
149
-
150
- return {
151
- name: `${name}`,
152
- text: `${name}`,
153
- size: addUnit(size as any, unit),
154
- gap: addUnit(gap as any, unit),
155
- color: color as any,
156
- align: icon.align || 'left',
157
- wrapperStyle: styleObjectToString(
158
- {
159
- height: el.style?.lineHeight || el.style?.fontSize,
160
- },
161
- unit
162
- ),
163
- };
164
- };
165
-
166
- const buildNode = (
167
- el: CardElement,
168
- rootData: Record<string, any>,
169
- unit: 'px' | 'rpx',
170
- context: BindingContext
171
- ): RenderNode | null => {
172
- if (!el || el.visible === false) return null;
173
- const wrapperStyle = buildWrapperStyle(el, unit);
174
-
175
- if (el.type === 'layout-panel') {
176
- return {
177
- id: el.id,
178
- type: el.type,
179
- visible: el.visible,
180
- wrapperStyle,
181
- contentStyle: buildPanelContentStyle(el as LayoutPanelElement, unit),
182
- children: buildRenderNodes(el.children || [], rootData, unit, context),
183
- };
184
- }
185
-
186
- const baseStyle = buildBaseContentStyle(el, unit);
187
- if (el.type === 'text') {
188
- const value =
189
- resolveBindingValue(el.binding, rootData, context) ??
190
- el.defaultValue ??
191
- '';
192
- return {
193
- id: el.id,
194
- type: el.type,
195
- wrapperStyle,
196
- contentStyle: buildTextContentStyle(el as TextElement, unit),
197
- text: `${value}`,
198
- visible: el.visible,
199
- icon: buildTextIcon(el as TextElement, unit),
200
- };
201
- }
202
-
203
- if (el.type === 'image') {
204
- const src =
205
- resolveBindingValue(el.binding, rootData, context) ??
206
- (el as ImageElement).defaultUrl ??
207
- el.defaultValue ??
208
- '';
209
- const mode =
210
- (el as ImageElement).fit === 'contain' ? 'aspectFit' : 'aspectFill';
211
- return {
212
- id: el.id,
213
- type: el.type,
214
- wrapperStyle,
215
- contentStyle: buildImageContentStyle(el as ImageElement, unit),
216
- src,
217
- mode,
218
- visible: el.visible,
219
- };
220
- }
221
-
222
- if (el.type === 'icon') {
223
- const name =
224
- resolveBindingValue(el.binding, rootData, context) ??
225
- (el as IconElement).name ??
226
- el.defaultValue ??
227
- '';
228
- return {
229
- id: el.id,
230
- type: el.type,
231
- wrapperStyle,
232
- contentStyle: baseStyle,
233
- name: `${name}`,
234
- text: `${name}`,
235
- visible: el.visible,
236
- };
237
- }
238
-
239
- if (el.type === 'custom') {
240
- return {
241
- id: el.id,
242
- type: el.type,
243
- wrapperStyle,
244
- contentStyle: baseStyle,
245
- visible: el.visible,
246
- };
247
- }
248
-
249
- return null;
250
- };
251
-
252
- export const buildRenderNodes = (
253
- children: CardElement[],
254
- rootData: Record<string, any>,
255
- unit: 'px' | 'rpx' = 'px',
256
- context: BindingContext = {}
257
- ): RenderNode[] => {
258
- if (!Array.isArray(children)) return [];
259
-
260
- const nodes: RenderNode[] = [];
261
- children.forEach(el => {
262
- if (!el || el.visible === false) return;
263
- const node = buildNode(el, rootData, unit, context);
264
- if (node) nodes.push(node);
265
- });
266
-
267
- return nodes;
268
- };
269
-
270
- export const buildRenderResult = (
271
- layoutInput: CardLayoutInput,
272
- dataInput: Record<string, any>,
273
- unit: 'px' | 'rpx' = 'px'
274
- ): RenderResult => {
275
- const layouts = normalizeLayout(layoutInput);
276
- return layouts.map(layout => {
277
- const cardStyle = buildCardStyle(layout, unit);
278
- const bgStyle = buildBackgroundStyle(layout, unit);
279
- const renderTree = buildRenderNodes(layout.children || [], dataInput || {}, unit);
280
- return {
281
- renderTree,
282
- cardStyle,
283
- backgroundImage: layout.backgroundImage || '',
284
- backgroundStyle: bgStyle,
285
- };
286
- });
287
- };