@dongmingzhixiu/vuexir-compiler 0.7.2 → 0.7.4

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.
@@ -463,6 +463,9 @@ function capsuleColorExpr(c) {
463
463
  }
464
464
  export function boxModifiers(props) {
465
465
  const mods = [];
466
+ if (props.aspectRatio !== undefined) {
467
+ mods.push(`.aspectRatio(${props.aspectRatio}, contentMode: .fit)`);
468
+ }
466
469
  if (props.gradient) {
467
470
  const a = props.gradient.angle * Math.PI / 180;
468
471
  const x = Math.sin(a) / 2, y = -Math.cos(a) / 2;
@@ -700,6 +703,9 @@ function emitNodeInner(node, ctx) {
700
703
  const size = sizeModifiers(props, axis, ctx);
701
704
  let padMods = paddingModifiers(props);
702
705
  let boxMods = boxModifiers(props);
706
+ if (node.type === 'image' && props.objectFit === 'cover' && !props.clip) {
707
+ boxMods.unshift('.clipped()');
708
+ }
703
709
  // R44:胶囊标签(大圆角+同色背景描边+对称 padding)→ 单次 .tagCapsule(...)
704
710
  const capsule = currentFrameShort && isCapsule(props, padMods) ? capsuleExpr(props) : undefined;
705
711
  if (capsule !== undefined) {
@@ -1258,8 +1264,6 @@ function emitNodeInner(node, ctx) {
1258
1264
  return line + box.map((m) => ' ' + m).join('');
1259
1265
  }
1260
1266
  case 'vector':
1261
- if (props.aspectRatio)
1262
- box.unshift(`.aspectRatio(${props.aspectRatio}, contentMode: .fit)`);
1263
1267
  return pad(swiftVector(props, colorExpr, (name) => swiftBoundValue(name, ctx.runtime)).split('\n').join('\n' + indent(L))) + box.map((m) => ' ' + m).join('');
1264
1268
  case 'image': {
1265
1269
  const source = props.src ?? '';
package/dist/ir/schema.js CHANGED
@@ -138,11 +138,11 @@ const PROPS_VALIDATORS = {
138
138
  /** 各节点允许的 props 键(P0 最小集,防 Taro 化:未知 prop 即报错) */
139
139
  const NODE_ALLOWED_PROPS = {
140
140
  root: ['minWidth', 'minHeight', 'gradient', 'shadow', 'width', 'height', 'background'],
141
- group: ['flexWrap', 'alignSelf', 'widthFraction', 'widthFractionDynamic', 'zIndex', 'widthDynamic', 'heightDynamic', 'minWidth', 'minHeight', 'gradient', 'shadow', 'width', 'height', 'padding', 'gap', 'flex', 'flexDirection', 'justifyContent', 'alignItems', 'background', 'radius', 'borderWidth', 'borderColor', 'marginTopAuto', 'marginTop', 'marginLeftAuto', 'marginBottom', 'marginRight', 'marginLeft', 'borderSides', 'clip', 'onClick', 'onSet', 'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'transform', 'show', 'opacity', 'gridColumns'],
142
- text: ['alignSelf', 'widthFraction', 'widthFractionDynamic', 'textRuns', 'zIndex', 'fontFamily', 'widthDynamic', 'heightDynamic', 'letterSpacing', 'minWidth', 'minHeight', 'gradient', 'shadow', 'height', 'radius', 'borderWidth', 'borderColor', 'borderSides', 'clip', 'marginBottom', 'marginRight', 'marginLeft', 'width', 'text', 'ref', 'bind', 'bindExpr', 'dynField', 'bindParts', 'fontSize', 'fontWeight', 'textAlign', 'lineHeight', 'lineHeightMultiplier', 'color', 'padding', 'background', 'colorActive', 'marginLeftAuto', 'marginTop', 'colorDynamic', 'fontSizeDynamic', 'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'transform', 'show', 'flex', 'opacity', 'onClick', 'onSet', 'fieldOf'],
141
+ group: ['aspectRatio', 'flexWrap', 'alignSelf', 'widthFraction', 'widthFractionDynamic', 'zIndex', 'widthDynamic', 'heightDynamic', 'minWidth', 'minHeight', 'gradient', 'shadow', 'width', 'height', 'padding', 'gap', 'flex', 'flexDirection', 'justifyContent', 'alignItems', 'background', 'radius', 'borderWidth', 'borderColor', 'marginTopAuto', 'marginTop', 'marginLeftAuto', 'marginBottom', 'marginRight', 'marginLeft', 'borderSides', 'clip', 'onClick', 'onSet', 'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'transform', 'show', 'opacity', 'gridColumns'],
142
+ text: ['aspectRatio', 'alignSelf', 'widthFraction', 'widthFractionDynamic', 'textRuns', 'zIndex', 'fontFamily', 'widthDynamic', 'heightDynamic', 'letterSpacing', 'minWidth', 'minHeight', 'gradient', 'shadow', 'height', 'radius', 'borderWidth', 'borderColor', 'borderSides', 'clip', 'marginBottom', 'marginRight', 'marginLeft', 'width', 'text', 'ref', 'bind', 'bindExpr', 'dynField', 'bindParts', 'fontSize', 'fontWeight', 'textAlign', 'lineHeight', 'lineHeightMultiplier', 'color', 'padding', 'background', 'colorActive', 'marginLeftAuto', 'marginTop', 'colorDynamic', 'fontSizeDynamic', 'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'transform', 'show', 'flex', 'opacity', 'onClick', 'onSet', 'fieldOf'],
143
143
  vector: ['aspectRatio', 'widthFraction', 'widthFractionDynamic', 'zIndex', 'widthDynamic', 'heightDynamic', 'vector', 'width', 'height', 'flex', 'color', 'opacity', 'padding', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft', 'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'transform', 'show', 'onClick'],
144
- image: ['widthFraction', 'widthFractionDynamic', 'zIndex', 'widthDynamic', 'heightDynamic', 'padding', 'background', 'onClick', 'onSet', 'minWidth', 'minHeight', 'gradient', 'shadow', 'width', 'height', 'src', 'objectFit', 'radius', 'borderSides', 'borderWidth', 'borderColor', 'clip', 'flex', 'marginTop', 'marginBottom', 'marginRight', 'marginLeft', 'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'transform', 'show', 'opacity'],
145
- button: ['alignSelf', 'widthFraction', 'widthFractionDynamic', 'icon', 'fontFamily', 'letterSpacing', 'zIndex', 'widthDynamic', 'heightDynamic', 'marginLeftAuto', 'minWidth', 'minHeight', 'gradient', 'shadow', 'width', 'height', 'label', 'bind', 'background', 'radius', 'borderWidth', 'borderColor', 'fontSize', 'fontWeight', 'color', 'flex', 'padding', 'marginTopAuto', 'marginTop', 'marginBottom', 'marginRight', 'marginLeft', 'borderSides', 'clip', 'onClick', 'onSet', 'colorDynamic', 'fontSizeDynamic', 'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'transform', 'show', 'pressBg', 'opacity'],
144
+ image: ['aspectRatio', 'widthFraction', 'widthFractionDynamic', 'zIndex', 'widthDynamic', 'heightDynamic', 'padding', 'background', 'onClick', 'onSet', 'minWidth', 'minHeight', 'gradient', 'shadow', 'width', 'height', 'src', 'objectFit', 'radius', 'borderSides', 'borderWidth', 'borderColor', 'clip', 'flex', 'marginTop', 'marginBottom', 'marginRight', 'marginLeft', 'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'transform', 'show', 'opacity'],
145
+ button: ['aspectRatio', 'alignSelf', 'widthFraction', 'widthFractionDynamic', 'icon', 'fontFamily', 'letterSpacing', 'zIndex', 'widthDynamic', 'heightDynamic', 'marginLeftAuto', 'minWidth', 'minHeight', 'gradient', 'shadow', 'width', 'height', 'label', 'bind', 'background', 'radius', 'borderWidth', 'borderColor', 'fontSize', 'fontWeight', 'color', 'flex', 'padding', 'marginTopAuto', 'marginTop', 'marginBottom', 'marginRight', 'marginLeft', 'borderSides', 'clip', 'onClick', 'onSet', 'colorDynamic', 'fontSizeDynamic', 'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'transform', 'show', 'pressBg', 'opacity'],
146
146
  input: ['widthFraction', 'widthFractionDynamic', 'fontFamily', 'letterSpacing', 'zIndex', 'widthDynamic', 'heightDynamic', 'opacity', 'minWidth', 'minHeight', 'gradient', 'shadow', 'width', 'height', 'value', 'placeholder', 'fontSize', 'color', 'background', 'padding', 'radius', 'borderWidth', 'borderColor', 'borderSides', 'clip', 'flex', 'marginTop', 'marginTopAuto', 'marginBottom', 'marginRight', 'marginLeft', 'onSet', 'colorDynamic', 'fontSizeDynamic', 'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'transform', 'show'],
147
147
  scroll: ['widthFraction', 'widthFractionDynamic', 'zIndex', 'widthDynamic', 'heightDynamic', 'minWidth', 'minHeight', 'gradient', 'shadow', 'marginBottom', 'marginRight', 'marginLeft', 'marginTopAuto', 'marginLeftAuto', 'width', 'height', 'padding', 'gap', 'flexDirection', 'background', 'showsIndicators', 'flex', 'justifyContent', 'alignItems', 'radius', 'borderWidth', 'borderColor', 'marginTop', 'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'transform', 'show', 'opacity', 'borderSides', 'clip'],
148
148
  spacer: ['borderSides', 'onSet', 'onClick', 'marginRight', 'marginBottom', 'marginLeft', 'position', 'absTop', 'absLeft', 'absRight', 'absBottom', 'clip', 'zIndex', 'widthFraction', 'widthFractionDynamic', 'widthDynamic', 'heightDynamic', 'minWidth', 'minHeight', 'gradient', 'shadow', 'width', 'height', 'flex', 'background', 'padding', 'radius', 'borderWidth', 'borderColor', 'marginTop', 'alignSelf', 'opacity'],
@@ -70,6 +70,9 @@ export function resolveCssRules(rules, element, ancestors, inline, warnings) {
70
70
  const props = {};
71
71
  for (const rule of matched)
72
72
  mergeIrProps(props, rule.props);
73
+ // object-fit 只影响图片内容,容器复用同一个类时不产生 IR 属性。
74
+ if (element.tag !== 'img')
75
+ delete props.objectFit;
73
76
  return props;
74
77
  }
75
78
  const px = (v) => {
@@ -118,6 +121,13 @@ function mapDeclInner(prop, value, warnings) {
118
121
  if (prop.startsWith('--'))
119
122
  return []; // 变量声明由 token 解析器处理,不是未支持的视觉属性。
120
123
  switch (prop) {
124
+ case 'object-fit':
125
+ return v === 'contain' || v === 'cover' ? [['objectFit', v]] : null;
126
+ case 'aspect-ratio': {
127
+ const parts = v.split('/').map((part) => Number(part.trim()));
128
+ const ratio = parts.length === 1 ? parts[0] : parts.length === 2 ? parts[0] / parts[1] : NaN;
129
+ return Number.isFinite(ratio) && ratio > 0 ? [['aspectRatio', ratio]] : null;
130
+ }
121
131
  case 'grid-template-columns': {
122
132
  // R136:CSS grid 的最小支持——`repeat(N, 1fr)` / `1fr 1fr 1fr` → 列数
123
133
  const rep = String(v).match(/repeat\(\s*(\d+)\s*,/);
@@ -2359,7 +2359,7 @@ function walkElement(node, classProps, comboRules, scopedRules, pseudoRules, war
2359
2359
  warnings.push(`属性 ${attrName}="${attrValue}" 暂不支持,已忽略`);
2360
2360
  }
2361
2361
  }
2362
- const inlineTags = new Set(['span', 'b', 'strong', 'i', 'em', 'small', 'u', 'code']);
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
2365
  const inlineConditional = content.some((c) => c.type === NodeTypes.ELEMENT && c.props.some((p) => p.type === NodeTypes.DIRECTIVE && ['if', 'else-if', 'else', 'show'].includes(p.name)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dongmingzhixiu/vuexir-compiler",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "description": "Vue SFC → IR → 原生源码(SwiftUI / Compose)编译器核心:纯函数、零 IO",
5
5
  "type": "module",
6
6
  "license": "MIT",