km-card-layout-component-miniprogram 0.1.6 → 0.1.8

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 (30) hide show
  1. package/example/pages/home/index.js +1 -351
  2. package/miniprogram_dist/components/card-layout/index.js +25 -188
  3. package/miniprogram_dist/components/card-layout/index.wxml +17 -9
  4. package/miniprogram_dist/components/card-layout/index.wxss +11 -8
  5. package/miniprogram_dist/vendor/km-card-layout-core/bindings.js +74 -0
  6. package/miniprogram_dist/vendor/km-card-layout-core/data.js +38 -0
  7. package/miniprogram_dist/vendor/km-card-layout-core/helpers.js +72 -0
  8. package/miniprogram_dist/vendor/km-card-layout-core/index.js +15 -366
  9. package/miniprogram_dist/vendor/km-card-layout-core/interface/index.js +1 -0
  10. package/miniprogram_dist/vendor/km-card-layout-core/layout.js +117 -0
  11. package/miniprogram_dist/vendor/km-card-layout-core/ops/changeBackground.js +135 -0
  12. package/miniprogram_dist/vendor/km-card-layout-core/render/builder.js +210 -0
  13. package/miniprogram_dist/vendor/km-card-layout-core/utils.js +25 -0
  14. package/package.json +1 -1
  15. package/script/sync-core.js +10 -2
  16. package/src/components/card-layout/index.ts +30 -278
  17. package/src/components/card-layout/index.wxml +17 -9
  18. package/src/components/card-layout/index.wxss +11 -8
  19. package/src/vendor/km-card-layout-core/bindings.ts +84 -0
  20. package/src/vendor/km-card-layout-core/data.ts +38 -0
  21. package/src/vendor/km-card-layout-core/helpers.ts +76 -0
  22. package/src/vendor/km-card-layout-core/index.ts +21 -458
  23. package/src/vendor/km-card-layout-core/interface/data/payload.ts +20 -2
  24. package/src/vendor/km-card-layout-core/interface/index.ts +1 -0
  25. package/src/vendor/km-card-layout-core/interface/render.ts +1 -0
  26. package/src/vendor/km-card-layout-core/layout.ts +129 -0
  27. package/src/vendor/km-card-layout-core/ops/changeBackground.ts +169 -0
  28. package/src/vendor/km-card-layout-core/render/builder.ts +288 -0
  29. package/src/vendor/km-card-layout-core/types.d.ts +97 -8
  30. package/src/vendor/km-card-layout-core/utils.ts +9 -0
@@ -1,17 +1,11 @@
1
1
  import type {
2
- CardElement,
3
2
  CardLayoutInput,
4
3
  CardLayoutSchema,
5
- IconElement,
6
- ImageElement,
7
- LayoutPanelElement,
8
- TextElement,
4
+ RenderNode,
9
5
  } from '../../vendor/km-card-layout-core/index';
10
6
  import {
11
- addUnit,
7
+ buildRenderResult,
12
8
  normalizeLayout,
13
- resolveBindingValue,
14
- styleObjectToString,
15
9
  } from '../../vendor/km-card-layout-core/index';
16
10
  import { ICON_CODE_MAP } from './icon-map';
17
11
 
@@ -19,34 +13,12 @@ type LayoutData = {
19
13
  [key: string]: any;
20
14
  };
21
15
 
22
- interface RenderIcon {
23
- name?: string;
24
- text?: string;
25
- size?: string;
26
- color?: string;
27
- gap?: string;
28
- align?: 'left' | 'right';
29
- }
30
-
31
- interface RenderElement {
32
- id: string;
33
- type: CardElement['type'];
34
- wrapperStyle: string;
35
- contentStyle: string;
36
- name?: string;
37
- text?: string;
38
- src?: string;
39
- mode?: string;
40
- icon?: RenderIcon;
41
- children?: RenderElement[];
42
- }
43
-
44
16
  interface RenderCard {
45
17
  id: string;
46
18
  cardStyle: string;
47
19
  backgroundImage?: string;
48
20
  backgroundStyle: string;
49
- nodes: RenderElement[];
21
+ nodes: RenderNode[];
50
22
  }
51
23
 
52
24
  const ensureArray = (input: CardLayoutInput | any): CardLayoutInput => {
@@ -59,106 +31,6 @@ const pickCardId = (layout: any, idx: number) => {
59
31
  return `card-${idx}`;
60
32
  };
61
33
 
62
- const withUnit = (value: any, unit: 'px' | 'rpx') => addUnit(value, unit);
63
-
64
- const buildCardStyle = (layout: CardLayoutSchema, unit: 'px' | 'rpx') =>
65
- styleObjectToString(
66
- {
67
- width: withUnit(layout.width, unit),
68
- height: withUnit(layout.height, unit),
69
- color: layout.fontColor,
70
- borderRadius:
71
- layout.borderRadius !== undefined
72
- ? withUnit(layout.borderRadius, unit)
73
- : undefined,
74
- padding:
75
- layout.padding !== undefined ? withUnit(layout.padding, unit) : undefined,
76
- position: 'relative',
77
- overflow: 'hidden',
78
- boxSizing: 'border-box',
79
- backgroundColor: 'transparent',
80
- },
81
- unit,
82
- );
83
-
84
- const buildBackgroundStyle = (layout: CardLayoutSchema, unit: 'px' | 'rpx') =>
85
- styleObjectToString(
86
- {
87
- zIndex: layout.backgroundZIndex,
88
- borderRadius:
89
- layout.borderRadius !== undefined
90
- ? withUnit(layout.borderRadius, unit)
91
- : undefined,
92
- width: '100%',
93
- height: '100%',
94
- position: 'absolute',
95
- left: 0,
96
- top: 0,
97
- },
98
- unit,
99
- );
100
-
101
- const buildWrapperStyle = (el: CardElement, unit: 'px' | 'rpx') => {
102
- if (!el.layout || el.layout.mode !== 'absolute') return '';
103
- return styleObjectToString(
104
- {
105
- position: 'absolute',
106
- left: withUnit(el.layout.x, unit),
107
- top: withUnit(el.layout.y, unit),
108
- width: withUnit(el.layout.width, unit),
109
- height: withUnit(el.layout.height, unit),
110
- zIndex: el.layout.zIndex,
111
- boxSizing: 'border-box',
112
- display: 'flex',
113
- alignItems: 'center',
114
- },
115
- unit,
116
- );
117
- };
118
-
119
- const buildPanelContentStyle = (
120
- el: LayoutPanelElement,
121
- unit: 'px' | 'rpx',
122
- ) =>
123
- styleObjectToString(
124
- {
125
- position: 'relative',
126
- width: '100%',
127
- height: '100%',
128
- display: 'block',
129
- boxSizing: 'border-box',
130
- ...(el.style || {}),
131
- },
132
- unit,
133
- );
134
-
135
- const buildTextContentStyle = (el: TextElement, unit: 'px' | 'rpx') => {
136
- const textAlign =
137
- (el.style?.textAlign as string | undefined) || el.align || undefined;
138
- const style: Record<string, any> = {
139
- ...el.style,
140
- whiteSpace: 'pre-wrap',
141
- wordBreak: 'break-word',
142
- lineHeight:
143
- el.style?.lineHeight !== undefined && el.style?.lineHeight !== null
144
- ? el.style.lineHeight
145
- : '1.2',
146
- display: 'inline-flex',
147
- alignItems: 'center',
148
- };
149
- if (textAlign) style.textAlign = textAlign;
150
- return styleObjectToString(style, unit);
151
- };
152
-
153
- const buildBaseContentStyle = (el: CardElement, unit: 'px' | 'rpx') =>
154
- styleObjectToString(
155
- {
156
- ...(el.style || {}),
157
- boxSizing: 'border-box',
158
- },
159
- unit,
160
- );
161
-
162
34
  const mapIconGlyph = (name?: string, fallback?: string) => {
163
35
  if (!name) return fallback;
164
36
  const glyph = ICON_CODE_MAP[name];
@@ -166,153 +38,38 @@ const mapIconGlyph = (name?: string, fallback?: string) => {
166
38
  return fallback || name;
167
39
  };
168
40
 
169
- const buildTextIcon = (
170
- el: TextElement,
171
- unit: 'px' | 'rpx',
172
- ): RenderIcon | undefined => {
173
- const icon = el.icon;
174
- if (!icon || icon.enable === false) return undefined;
175
-
176
- const style = icon.style || 'fill';
177
- const baseName = el.key || el.binding || el.id;
178
- let name: string | undefined;
179
- if (style === 'dot') name = 'round';
180
- else if (style === 'line') name = baseName ? `${baseName}-line` : undefined;
181
- else name = baseName || undefined;
182
- if (!name) return undefined;
183
-
184
- const size =
185
- icon.size !== undefined && icon.size !== null
186
- ? icon.size
187
- : (el.style?.fontSize as number | string | undefined);
188
- const gap = icon.gap !== undefined && icon.gap !== null ? icon.gap : 4;
189
- const color =
190
- icon.color ?? (el.style?.color as string | undefined) ?? undefined;
41
+ const mapRenderNode = (node: RenderNode): RenderNode => {
42
+ const icon = node.icon
43
+ ? {
44
+ ...node.icon,
45
+ text: mapIconGlyph(node.icon.name, node.icon.text),
46
+ }
47
+ : undefined;
48
+ const children = node.children?.map(mapRenderNode);
49
+ const mappedText =
50
+ node.type === 'icon' ? mapIconGlyph(node.name, node.text) : node.text;
191
51
 
192
- const text = mapIconGlyph(name, name);
193
52
  return {
194
- name,
195
- text,
196
- size: size !== undefined ? withUnit(size, unit) : undefined,
197
- gap: gap !== undefined ? withUnit(gap, unit) : undefined,
198
- color,
199
- align: icon.align || 'left',
53
+ ...node,
54
+ text: mappedText,
55
+ icon,
56
+ children,
200
57
  };
201
58
  };
202
59
 
203
- const buildRenderNode = (
204
- el: CardElement,
205
- data: LayoutData,
206
- unit: 'px' | 'rpx',
207
- ): RenderElement | null => {
208
- if (!el || el.visible === false) return null;
209
- const wrapperStyle = buildWrapperStyle(el, unit);
210
-
211
- if (el.type === 'layout-panel') {
212
- const panel = el as LayoutPanelElement;
213
- return {
214
- id: el.id,
215
- type: el.type,
216
- wrapperStyle,
217
- contentStyle: buildPanelContentStyle(panel, unit),
218
- children: buildRenderNodes(panel.children || [], data, unit),
219
- };
220
- }
221
-
222
- if (el.type === 'text') {
223
- const textValue =
224
- resolveBindingValue(el.binding, data) ?? el.defaultValue ?? '';
225
- return {
226
- id: el.id,
227
- type: el.type,
228
- wrapperStyle,
229
- contentStyle: buildTextContentStyle(el as TextElement, unit),
230
- text: `${textValue}`,
231
- icon: buildTextIcon(el as TextElement, unit),
232
- };
233
- }
234
-
235
- if (el.type === 'image') {
236
- const style: Record<string, any> = { ...(el.style || {}) };
237
- const borderWidth = Number(style.borderWidth);
238
- if (Number.isFinite(borderWidth) && borderWidth > 0) {
239
- if (!style.borderStyle) style.borderStyle = 'solid';
240
- if (!style.borderColor) style.borderColor = '#000000';
241
- }
242
-
243
- const src =
244
- resolveBindingValue(el.binding, data) ??
245
- (el as ImageElement).defaultUrl ??
246
- el.defaultValue ??
247
- '';
248
- const mode =
249
- (el as ImageElement).fit === 'contain' ? 'aspectFit' : 'aspectFill';
250
- return {
251
- id: el.id,
252
- type: el.type,
253
- wrapperStyle,
254
- contentStyle: styleObjectToString(style, unit),
255
- src,
256
- mode,
257
- };
258
- }
259
-
260
- if (el.type === 'icon') {
261
- const resolved =
262
- resolveBindingValue(el.binding, data) ??
263
- (el as IconElement).name ??
264
- el.defaultValue ??
265
- '';
266
- const text = mapIconGlyph(`${resolved}`, `${resolved}`);
267
- return {
268
- id: el.id,
269
- type: el.type,
270
- wrapperStyle,
271
- contentStyle: buildBaseContentStyle(el, unit),
272
- name: `${resolved}`,
273
- text,
274
- };
275
- }
276
-
277
- if (el.type === 'custom') {
278
- return {
279
- id: el.id,
280
- type: el.type,
281
- wrapperStyle,
282
- contentStyle: buildBaseContentStyle(el, unit),
283
- };
284
- }
285
-
286
- return null;
287
- };
288
-
289
- const buildRenderNodes = (
290
- children: CardElement[],
291
- data: LayoutData,
292
- unit: 'px' | 'rpx',
293
- ) => {
294
- if (!Array.isArray(children)) return [];
295
- const nodes: RenderElement[] = [];
296
- children.forEach(el => {
297
- if (!el || el.visible === false) return;
298
- const node = buildRenderNode(el, data, unit);
299
- if (node) nodes.push(node);
300
- });
301
- return nodes;
302
- };
303
-
304
- const buildCards = (
305
- layouts: CardLayoutInput,
306
- data: LayoutData,
307
- unit: 'px' | 'rpx',
308
- ) =>
309
- layouts.map(layout => ({
310
- id: layout.name || (layout as any).id || '',
311
- cardStyle: buildCardStyle(layout, unit),
312
- backgroundImage: layout.backgroundImage || '',
313
- backgroundStyle: buildBackgroundStyle(layout, unit),
314
- nodes: buildRenderNodes(layout.children || [], data, unit),
60
+ const mapRenderTree = (nodes: RenderNode[]) =>
61
+ Array.isArray(nodes) ? nodes.map(mapRenderNode) : [];
62
+
63
+ const buildCards = (layouts: CardLayoutSchema[], data: LayoutData) => {
64
+ const renders = buildRenderResult(layouts as CardLayoutInput, data, 'rpx');
65
+ return renders.map((render, idx) => ({
66
+ id: pickCardId(layouts[idx], idx),
67
+ cardStyle: render.cardStyle,
68
+ backgroundImage: render.backgroundImage || '',
69
+ backgroundStyle: render.backgroundStyle,
70
+ nodes: mapRenderTree(render.renderTree),
315
71
  }));
72
+ };
316
73
 
317
74
  Component({
318
75
  options: {
@@ -358,12 +115,7 @@ Component({
358
115
  }
359
116
 
360
117
  const normalizedLayouts = normalizeLayout(layoutInput);
361
- const cards = buildCards(normalizedLayouts, dataInput, 'rpx').map(
362
- (card, idx) => ({
363
- ...card,
364
- id: pickCardId(layoutInput[idx], idx),
365
- }),
366
- );
118
+ const cards = buildCards(normalizedLayouts, dataInput);
367
119
 
368
120
  this.setData({ cards });
369
121
  },
@@ -62,15 +62,23 @@
62
62
  <view class="km-node km-node--text" style="{{node.wrapperStyle}}">
63
63
  <view class="km-node__text" style="{{node.contentStyle}}">
64
64
  <block wx:if="{{node.icon && node.icon.name}}">
65
- <view
66
- class="km-node__text-content"
67
- style="flex-direction: {{node.icon.align === 'right' ? 'row-reverse' : 'row'}};">
68
- <text
69
- class="km-node__text-icon icon"
70
- style="font-size: {{node.icon.size || '16px'}}; color: {{node.icon.color || ''}}; margin-right: {{node.icon.align !== 'right' ? (node.icon.gap || '') : ''}}; margin-left: {{node.icon.align === 'right' ? (node.icon.gap || '') : ''}};">
71
- {{node.icon.text || node.icon.name || ''}}
72
- </text>
73
- <text class="km-node__text-value">{{node.text || ''}}</text>
65
+ <view class="km-node__text-content">
66
+ <block wx:if="{{node.icon.align === 'right'}}">
67
+ <text class="km-node__text-value">{{node.text || ''}}</text>
68
+ <view style="{{node.icon.wrapperStyle}}">
69
+ <text
70
+ class="km-node__text-icon icon"
71
+ style="font-size: {{node.icon.size || '16px'}}; color: {{node.icon.color || ''}}; margin-right: {{node.icon.gap || ''}};">{{node.icon.text || node.icon.name || ''}}</text>
72
+ </view>
73
+ </block>
74
+ <block wx:else>
75
+ <view style="{{node.icon.wrapperStyle}}">
76
+ <text
77
+ class="km-node__text-icon icon"
78
+ style="font-size: {{node.icon.size || '16px'}}; color: {{node.icon.color || ''}}; margin-right: {{node.icon.gap || ''}};">{{node.icon.text || node.icon.name || ''}}</text>
79
+ </view>
80
+ <text class="km-node__text-value">{{node.text || ''}}</text>
81
+ </block>
74
82
  </view>
75
83
  </block>
76
84
  <block wx:else>
@@ -78,25 +78,28 @@
78
78
  .km-node__text {
79
79
  width: 100%;
80
80
  height: 100%;
81
- display: flex;
82
- align-items: center;
81
+ display: block;
82
+ box-sizing: border-box;
83
+ text-align: inherit;
83
84
  }
84
85
 
85
86
  .km-node__text-content {
86
- display: inline-flex;
87
- align-items: center;
87
+ display: inline-block;
88
+ vertical-align: middle;
89
+ height: 100%;
88
90
  }
89
91
 
90
92
  .km-node__text-value {
91
93
  display: inline-block;
92
94
  white-space: pre-wrap;
93
95
  word-break: break-word;
96
+ vertical-align: middle;
97
+ }
98
+ .km-node--text{
99
+ /* 溢出隐藏 */
94
100
  }
95
-
96
101
  .km-node--text text {
97
- display: block;
98
- white-space: pre-wrap;
99
- word-break: break-word;
102
+ display: inline;
100
103
  }
101
104
 
102
105
  /* ICON */
@@ -0,0 +1,84 @@
1
+ import type { CardElement, CardLayoutSchema } from './interface';
2
+ import type {
3
+ TemplateBackground,
4
+ TemplateItem,
5
+ } from './interface/data/payload';
6
+
7
+ export function stripLayoutBindings(
8
+ layouts: CardLayoutSchema[] = []
9
+ ): CardLayoutSchema[] {
10
+ const targetLayouts = Array.isArray(layouts) ? layouts : [];
11
+ const stripElement = (el: CardElement): CardElement => {
12
+ const { binding: _b, defaultValue: _d, ...rest } = el as any;
13
+ if (el.type === 'layout-panel') {
14
+ return {
15
+ ...rest,
16
+ children: (el.children || []).map(stripElement),
17
+ } as CardElement;
18
+ }
19
+ return rest as CardElement;
20
+ };
21
+
22
+ return targetLayouts.map(layout => ({
23
+ ...layout,
24
+ children: (layout.children || []).map(stripElement),
25
+ }));
26
+ }
27
+
28
+ export function applyItemCollectBindings(
29
+ layouts: CardLayoutSchema[] = [],
30
+ items: TemplateItem[] = []
31
+ ): CardLayoutSchema[] {
32
+ const targetLayouts = Array.isArray(layouts) ? layouts : [];
33
+ const metaMap = new Map<string, TemplateItem>();
34
+ const metaList = Array.isArray(items) ? items : [];
35
+ metaList.forEach(item => {
36
+ if (item && item.id !== undefined && item.id !== null) {
37
+ metaMap.set(String(item.id), item);
38
+ }
39
+ });
40
+
41
+ const assignBinding = (el: CardElement): CardElement => {
42
+ const meta = metaMap.get(String(el.id));
43
+ const binding =
44
+ meta && meta.bind !== undefined && meta.bind !== null
45
+ ? meta.bind
46
+ : el.binding;
47
+ const defaultValue =
48
+ meta && meta.default !== undefined ? meta.default : el.defaultValue;
49
+ const key = meta && meta.key !== undefined ? meta.key : el.key;
50
+ const base: any = { ...el };
51
+ if (binding !== undefined) base.binding = binding;
52
+ else delete base.binding;
53
+ if (defaultValue !== undefined) base.defaultValue = defaultValue;
54
+ else delete base.defaultValue;
55
+ if (key !== undefined) base.key = key;
56
+ else delete base.key;
57
+
58
+ if (el.type === 'layout-panel') {
59
+ return {
60
+ ...base,
61
+ children: (el.children || []).map(assignBinding),
62
+ } as CardElement;
63
+ }
64
+ return base as CardElement;
65
+ };
66
+
67
+ return targetLayouts.map(layout => ({
68
+ ...layout,
69
+ children: (layout.children || []).map(assignBinding),
70
+ }));
71
+ }
72
+
73
+ export function getTemplateItems(ids: string, items: TemplateItem[]) {
74
+ const idArray = ids.split(',').map(id => id.trim());
75
+ return items.filter(item => idArray.includes(String(item.id)));
76
+ }
77
+
78
+ export function getTemplateBackgrounds(
79
+ ids: string,
80
+ items: TemplateBackground[]
81
+ ) {
82
+ const idArray = ids.split(',').map(id => id.trim());
83
+ return items.filter(item => idArray.includes(String(item.id)));
84
+ }
@@ -0,0 +1,38 @@
1
+ import { isObject } from './helpers';
2
+
3
+ const pathToSegments = (path: string): string[] =>
4
+ `${path || ''}`
5
+ .replace(/\[(\d+)\]/g, '.$1')
6
+ .split('.')
7
+ .map(p => p.trim())
8
+ .filter(Boolean);
9
+
10
+ const readByPath = (data: any, path: string): any => {
11
+ if (path === undefined || path === null || path === '') return data;
12
+ const segments = pathToSegments(path);
13
+ let cursor: any = data;
14
+ for (let i = 0; i < segments.length; i += 1) {
15
+ if (!isObject(cursor) && !Array.isArray(cursor)) return undefined;
16
+ const key = segments[i];
17
+ if (Array.isArray(cursor)) {
18
+ const idx = Number(key);
19
+ cursor = Number.isNaN(idx) ? undefined : cursor[idx];
20
+ } else {
21
+ cursor = (cursor as Record<string, any>)[key];
22
+ }
23
+ if (cursor === undefined || cursor === null) {
24
+ return cursor;
25
+ }
26
+ }
27
+ return cursor;
28
+ };
29
+
30
+ export const resolveBindingValue = (
31
+ binding: string | undefined,
32
+ rootData: Record<string, any>,
33
+ context?: Record<string, any>
34
+ ): any => {
35
+ if (!binding) return undefined;
36
+ const value = readByPath(rootData, binding);
37
+ return value === undefined ? undefined : value;
38
+ };
@@ -0,0 +1,76 @@
1
+ const DIMENSION_PROPS = new Set([
2
+ 'width',
3
+ 'height',
4
+ 'top',
5
+ 'right',
6
+ 'bottom',
7
+ 'left',
8
+ 'padding',
9
+ 'paddingTop',
10
+ 'paddingBottom',
11
+ 'paddingLeft',
12
+ 'paddingRight',
13
+ 'margin',
14
+ 'marginTop',
15
+ 'marginBottom',
16
+ 'marginLeft',
17
+ 'marginRight',
18
+ 'fontSize',
19
+ 'lineHeight',
20
+ 'borderRadius',
21
+ 'borderWidth',
22
+ 'letterSpacing',
23
+ 'gap',
24
+ 'rowGap',
25
+ 'columnGap',
26
+ ]);
27
+
28
+ export const toNumber = (value: unknown): number | undefined => {
29
+ const num = Number(value);
30
+ return Number.isFinite(num) ? num : undefined;
31
+ };
32
+
33
+ const toKebab = (key: string): string =>
34
+ key.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
35
+
36
+ export const addUnit = (
37
+ value: string | number | undefined | null,
38
+ unit: 'px' | 'rpx'
39
+ ): string | undefined => {
40
+ if (value === undefined || value === null || value === '') return undefined;
41
+ if (typeof value === 'number') {
42
+ const ratio = unit === 'rpx' ? 2 : 1;
43
+ return `${value * ratio}${unit}`;
44
+ }
45
+ if (typeof value === 'string') {
46
+ const parsed = Number(value);
47
+ if (Number.isFinite(parsed)) {
48
+ const ratio = unit === 'rpx' ? 2 : 1;
49
+ return `${parsed * ratio}${unit}`;
50
+ }
51
+ }
52
+ return `${value}`;
53
+ };
54
+
55
+ export const styleObjectToString = (
56
+ style?: Record<string, any>,
57
+ unit: 'px' | 'rpx' = 'px'
58
+ ): string => {
59
+ if (!style) return '';
60
+ const pairs: string[] = [];
61
+ Object.keys(style).forEach(key => {
62
+ const value = style[key];
63
+ if (value === undefined || value === null || value === '') return;
64
+ const useUnit = DIMENSION_PROPS.has(key)
65
+ ? addUnit(value as any, unit)
66
+ : value;
67
+ if (useUnit === undefined || useUnit === null || useUnit === '') return;
68
+ pairs.push(`${toKebab(key)}:${useUnit}`);
69
+ });
70
+ return pairs.join(';');
71
+ };
72
+
73
+ export const isObject = (
74
+ val: unknown
75
+ ): val is Record<string, any> | any[] =>
76
+ Boolean(val) && typeof val === 'object';