@dongmingzhixiu/vuexir-compiler 0.7.8 → 0.7.9
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/dist/codegen/compose.js +3 -2
- package/dist/codegen/swiftui.js +3 -1
- package/dist/ir/schema.d.ts +1 -1
- package/dist/ir/schema.js +1 -1
- package/dist/transform/css.js +1 -1
- package/dist/transform/vue2ir.js +18 -4
- package/package.json +1 -1
package/dist/codegen/compose.js
CHANGED
|
@@ -1529,17 +1529,18 @@ function emitNodeInner(node, ctx, depth, loop, useParamModifier = false, parentS
|
|
|
1529
1529
|
}
|
|
1530
1530
|
case 'image': {
|
|
1531
1531
|
const source = p.src ?? '';
|
|
1532
|
+
const contentScale = p.objectFit === 'fill' ? 'FillBounds' : p.objectFit === 'contain' ? 'Fit' : 'Crop';
|
|
1532
1533
|
const chain = modChain([...sizeModifiers(p, ctx), ...absM(p), ...clipModifiers(p), ...visualModifiers(p), ...paddingModifiers(p), ...alphaArr], pad + ' ');
|
|
1533
1534
|
if (source.startsWith('asset://')) {
|
|
1534
1535
|
const name = source.slice(8);
|
|
1535
|
-
return pad + 'run { val imageContext = androidx.compose.ui.platform.LocalContext.current; val bitmap = remember { imageContext.assets.open(' + kotlinStr(name) + ').use { android.graphics.BitmapFactory.decodeStream(it) } }; if(bitmap != null) Image(bitmap = bitmap.asImageBitmap(), contentDescription = null, contentScale = androidx.compose.ui.layout.ContentScale.' +
|
|
1536
|
+
return pad + 'run { val imageContext = androidx.compose.ui.platform.LocalContext.current; val bitmap = remember { imageContext.assets.open(' + kotlinStr(name) + ').use { android.graphics.BitmapFactory.decodeStream(it) } }; if(bitmap != null) Image(bitmap = bitmap.asImageBitmap(), contentDescription = null, contentScale = androidx.compose.ui.layout.ContentScale.' + contentScale + ', modifier = Modifier' + chain + ') }';
|
|
1536
1537
|
}
|
|
1537
1538
|
if (/^data:image\/[^;]+;base64,/.test(source)) {
|
|
1538
1539
|
const encoded = source.slice(source.indexOf(',') + 1);
|
|
1539
1540
|
return pad + 'run {\n' + pad + ' val imageBytes = remember { android.util.Base64.decode(' + kotlinStr(encoded) + ', android.util.Base64.DEFAULT) }\n' +
|
|
1540
1541
|
pad + ' val bitmap = remember { android.graphics.BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) }\n' +
|
|
1541
1542
|
pad + ' if (bitmap != null) Image(bitmap = bitmap.asImageBitmap(), contentDescription = null, contentScale = androidx.compose.ui.layout.ContentScale.' +
|
|
1542
|
-
|
|
1543
|
+
contentScale + ', modifier = Modifier' + chain + ')\n' + pad + '}';
|
|
1543
1544
|
}
|
|
1544
1545
|
ctx.warnings.push(`图片 ${source.slice(0, 80)} 需要 data URI 资源映射,Android 未生成图片内容`);
|
|
1545
1546
|
return pad + 'Box(modifier = Modifier' + chain + ')';
|
package/dist/codegen/swiftui.js
CHANGED
|
@@ -1292,7 +1292,9 @@ function emitNodeInner(node, ctx) {
|
|
|
1292
1292
|
else {
|
|
1293
1293
|
image = `Image(uiImage: UIImage(named: "${swiftStringEscape(source.replace(/^bundle:\/\//, ''))}") ?? UIImage()).resizable()`;
|
|
1294
1294
|
}
|
|
1295
|
-
|
|
1295
|
+
if (props.objectFit !== 'fill') {
|
|
1296
|
+
image += props.objectFit === 'contain' ? '.scaledToFit()' : '.scaledToFill()';
|
|
1297
|
+
}
|
|
1296
1298
|
return pad(image) + box.map((m) => ' ' + m).join('');
|
|
1297
1299
|
}
|
|
1298
1300
|
case 'component': {
|
package/dist/ir/schema.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export type Justify = 'start' | 'center' | 'end' | 'spaceBetween' | 'spaceAround
|
|
|
17
17
|
export type Align = 'start' | 'center' | 'end' | 'stretch';
|
|
18
18
|
export type FontWeight = 'normal' | 'medium' | 'bold';
|
|
19
19
|
export type TextAlign = 'left' | 'center' | 'right';
|
|
20
|
-
export type ObjectFit = 'cover' | 'contain';
|
|
20
|
+
export type ObjectFit = 'cover' | 'contain' | 'fill';
|
|
21
21
|
export interface IrProps {
|
|
22
22
|
/** 尺寸 */
|
|
23
23
|
width?: Size;
|
package/dist/ir/schema.js
CHANGED
|
@@ -101,7 +101,7 @@ const PROPS_VALIDATORS = {
|
|
|
101
101
|
lineHeight: (v) => typeof v === 'number' && v > 0,
|
|
102
102
|
color: isColor,
|
|
103
103
|
src: (v) => typeof v === 'string',
|
|
104
|
-
objectFit: (v) => v === 'cover' || v === 'contain',
|
|
104
|
+
objectFit: (v) => v === 'cover' || v === 'contain' || v === 'fill',
|
|
105
105
|
label: (v) => typeof v === 'string',
|
|
106
106
|
onClick: (v) => typeof v === 'string',
|
|
107
107
|
showsIndicators: (v) => typeof v === 'boolean',
|
package/dist/transform/css.js
CHANGED
|
@@ -122,7 +122,7 @@ function mapDeclInner(prop, value, warnings) {
|
|
|
122
122
|
return []; // 变量声明由 token 解析器处理,不是未支持的视觉属性。
|
|
123
123
|
switch (prop) {
|
|
124
124
|
case 'object-fit':
|
|
125
|
-
return v === 'contain' || v === 'cover' ? [['objectFit', v]] : null;
|
|
125
|
+
return v === 'contain' || v === 'cover' || v === 'fill' ? [['objectFit', v]] : null;
|
|
126
126
|
case 'aspect-ratio': {
|
|
127
127
|
const parts = v.split('/').map((part) => Number(part.trim()));
|
|
128
128
|
const ratio = parts.length === 1 ? parts[0] : parts.length === 2 ? parts[0] / parts[1] : NaN;
|
package/dist/transform/vue2ir.js
CHANGED
|
@@ -2362,10 +2362,18 @@ function walkElement(node, classProps, comboRules, scopedRules, pseudoRules, war
|
|
|
2362
2362
|
const inlineTags = new Set(['span', 'b', 'strong', 'i', 'em', 'small', 'u', 'code', 'br']);
|
|
2363
2363
|
const content = node.children.filter((c) => c.type !== NodeTypes.COMMENT && !(c.type === NodeTypes.TEXT && !c.content.trim()));
|
|
2364
2364
|
const readable = (n) => n.type === NodeTypes.INTERPOLATION || (n.type === NodeTypes.TEXT && !!n.content.trim()) || (n.type === NodeTypes.ELEMENT && n.children.some(readable));
|
|
2365
|
-
|
|
2366
|
-
|
|
2365
|
+
// 行内分支或循环需要独立节点;合并为富文本会丢弃这些动态子树。
|
|
2366
|
+
const hasInlineStructure = (child) => {
|
|
2367
|
+
if (child.type !== NodeTypes.ELEMENT)
|
|
2368
|
+
return false;
|
|
2369
|
+
return child.props.some((p) => p.type === NodeTypes.DIRECTIVE &&
|
|
2370
|
+
['if', 'else-if', 'else', 'show', 'for'].includes(p.name)) ||
|
|
2371
|
+
(inlineTags.has(child.tag) && child.children.some(hasInlineStructure));
|
|
2372
|
+
};
|
|
2373
|
+
const inlineStructure = content.some(hasInlineStructure);
|
|
2374
|
+
if (inlineComponentsFlag && mapping.type === 'group' && !inlineStructure && props.flexDirection === undefined && props.gridColumns === undefined && content.some(readable) && content.every((c) => c.type === NodeTypes.TEXT || c.type === NodeTypes.INTERPOLATION || (c.type === NodeTypes.ELEMENT && inlineTags.has(c.tag))))
|
|
2367
2375
|
mapping = { type: 'text' };
|
|
2368
|
-
if (mapping.type === 'text' &&
|
|
2376
|
+
if (mapping.type === 'text' && inlineStructure)
|
|
2369
2377
|
mapping = { type: 'group' };
|
|
2370
2378
|
if (mapping.type === 'text' && content.length === 0 && ['i', 'span', 'b'].includes(node.tag))
|
|
2371
2379
|
mapping = { type: 'spacer' };
|
|
@@ -2680,7 +2688,13 @@ function walkElement(node, classProps, comboRules, scopedRules, pseudoRules, war
|
|
|
2680
2688
|
warnings.push(`<${node.tag}> 无子节点 → 降级为占位 spacer(R17/R77;可用 padding/height 表达留白)`);
|
|
2681
2689
|
const keep = {};
|
|
2682
2690
|
const src = props;
|
|
2683
|
-
|
|
2691
|
+
// 空盒仍需脱离文档流并保持叠放顺序,避免占位改变父容器布局。
|
|
2692
|
+
for (const k of [
|
|
2693
|
+
'width', 'height', 'widthFraction', 'widthFractionDynamic', 'flex', 'marginTop',
|
|
2694
|
+
'background', 'gradient', 'radius', 'shadow', 'borderWidth', 'borderColor',
|
|
2695
|
+
'padding', 'minHeight', 'minWidth', 'opacity',
|
|
2696
|
+
'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'zIndex',
|
|
2697
|
+
]) {
|
|
2684
2698
|
if (src[k] !== undefined)
|
|
2685
2699
|
keep[k] = src[k];
|
|
2686
2700
|
}
|