view-contracts 0.5.3 → 0.5.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.
- package/dist/preview.mjs +126 -126
- package/dist/preview.mjs.map +3 -3
- package/dist/view-contracts.bundle.mjs +216 -216
- package/dist/view-contracts.bundle.mjs.map +3 -3
- package/package.json +1 -1
- package/renderers/compose/lowering/lowerToCompose.ts +53 -11
- package/renderers/compose/lowering/modifiers.ts +10 -0
- package/renderers/compose/renderTheme.ts +26 -7
package/package.json
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
extractClipRadiusDp,
|
|
25
25
|
extractPaddingModifiers,
|
|
26
26
|
extractTextMaxLines,
|
|
27
|
+
composeRowArrangement,
|
|
27
28
|
extractTextOverflow,
|
|
28
29
|
extractTextStyleModifiers,
|
|
29
30
|
hasFillMaxHeight,
|
|
@@ -429,11 +430,51 @@ function renderStyledBox(
|
|
|
429
430
|
].join('\n');
|
|
430
431
|
}
|
|
431
432
|
|
|
433
|
+
function isInlineDisplayVariant(
|
|
434
|
+
elementName: string,
|
|
435
|
+
variantLit: string,
|
|
436
|
+
ctx: ComposeRenderContext,
|
|
437
|
+
): boolean {
|
|
438
|
+
const merged = mergeVisualProps({
|
|
439
|
+
elementName,
|
|
440
|
+
theme: ctx.theme,
|
|
441
|
+
tokens: ctx.tokens,
|
|
442
|
+
variantLiteral: variantLit,
|
|
443
|
+
instanceLiterals: {},
|
|
444
|
+
});
|
|
445
|
+
const display = merged.display;
|
|
446
|
+
return typeof display === 'string' && display.includes('inline');
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function isShrinkWrapStyledText(
|
|
450
|
+
props: Record<string, IrValue>,
|
|
451
|
+
ctx: ComposeRenderContext,
|
|
452
|
+
itemScope?: string,
|
|
453
|
+
): boolean {
|
|
454
|
+
if (ctx.cellTextBehavior) return true;
|
|
455
|
+
const variantLit = propLiteral(props, 'variant');
|
|
456
|
+
if (typeof variantLit === 'string') {
|
|
457
|
+
return isInlineDisplayVariant('Text', variantLit, ctx);
|
|
458
|
+
}
|
|
459
|
+
if (isDynamicVariant(props)) {
|
|
460
|
+
const v = props.variant;
|
|
461
|
+
if (typeof v === 'object' && v !== null && 'kind' in v && v.kind === 'concat') {
|
|
462
|
+
const concat = v as IrConcat;
|
|
463
|
+
const first = concat.parts[0];
|
|
464
|
+
if (first === 'badge-') return true;
|
|
465
|
+
if (typeof first === 'string' && first.startsWith('badge-')) return true;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return false;
|
|
469
|
+
}
|
|
470
|
+
|
|
432
471
|
function formatTextComposable(
|
|
433
472
|
pad: string,
|
|
434
473
|
content: string,
|
|
435
474
|
modifiers: string[],
|
|
436
475
|
ctx: ComposeRenderContext,
|
|
476
|
+
textProps?: Record<string, IrValue>,
|
|
477
|
+
itemScope?: string,
|
|
437
478
|
): string {
|
|
438
479
|
const paddingMods = extractPaddingModifiers(modifiers);
|
|
439
480
|
const runtimeStyleExpr = extractApplyVcStyleExpr(applyModifiers('Modifier', modifiers));
|
|
@@ -464,7 +505,8 @@ function formatTextComposable(
|
|
|
464
505
|
const textLine = `${pad} Text(text = ${content}${maxLinesParam}${overflowParam}${styleParam})`;
|
|
465
506
|
|
|
466
507
|
if (runtimeStyleExpr) {
|
|
467
|
-
const
|
|
508
|
+
const shrinkWrap = textProps ? isShrinkWrapStyledText(textProps, ctx, itemScope) : ctx.cellTextBehavior === true;
|
|
509
|
+
const styleBase = shrinkWrap ? 'Modifier' : 'Modifier.fillMaxWidth()';
|
|
468
510
|
const styleModifier = `${styleBase}.applyVcStyle(${runtimeStyleExpr})`;
|
|
469
511
|
if (paddingMods.length > 0) {
|
|
470
512
|
const outerModifier = applyModifiers(modifierBase, [...layoutMods, ...paddingMods]);
|
|
@@ -670,7 +712,7 @@ function renderLeaf(
|
|
|
670
712
|
|
|
671
713
|
if (entry.leaf === 'text') {
|
|
672
714
|
const content = renderTextContent(node.children, ctx, itemScope) ?? '""';
|
|
673
|
-
return formatTextComposable(pad, content, modifiers, ctx);
|
|
715
|
+
return formatTextComposable(pad, content, modifiers, ctx, node.props, itemScope);
|
|
674
716
|
}
|
|
675
717
|
if (entry.leaf === 'button') {
|
|
676
718
|
return renderVcButton(node, level, itemScope, ctx, modifiers);
|
|
@@ -763,7 +805,9 @@ function renderLeaf(
|
|
|
763
805
|
return `${pad}Spacer(modifier = ${modifierExpr})`;
|
|
764
806
|
}
|
|
765
807
|
if (entry.leaf === 'divider') {
|
|
766
|
-
|
|
808
|
+
const axisLit = propLiteral(node.props, 'axis');
|
|
809
|
+
const divider = axisLit === 'vertical' ? 'VerticalDivider' : 'HorizontalDivider';
|
|
810
|
+
return `${pad}${divider}(modifier = ${modifierExpr})`;
|
|
767
811
|
}
|
|
768
812
|
if (entry.leaf === 'image') {
|
|
769
813
|
const src = propLiteral(node.props, 'src') ?? propLiteral(node.props, 'name');
|
|
@@ -814,13 +858,7 @@ function renderContainer(
|
|
|
814
858
|
const spacing = typeof spacingLit === 'number' ? `${spacingLit}.dp` : '0.dp';
|
|
815
859
|
const justifyLit = propLiteral(node.props, 'justify');
|
|
816
860
|
const wrapLit = propLiteral(node.props, 'wrap');
|
|
817
|
-
const arrangement = justifyLit
|
|
818
|
-
? 'Arrangement.SpaceBetween'
|
|
819
|
-
: justifyLit === 'end'
|
|
820
|
-
? 'Arrangement.End'
|
|
821
|
-
: justifyLit === 'center'
|
|
822
|
-
? 'Arrangement.Center'
|
|
823
|
-
: `Arrangement.spacedBy(${spacing})`;
|
|
861
|
+
const arrangement = composeRowArrangement(justifyLit, spacing);
|
|
824
862
|
const alignLit = propLiteral(node.props, 'align');
|
|
825
863
|
const alignItemsLit = propLiteral(node.props, 'alignItems');
|
|
826
864
|
const heightLit = propLiteral(node.props, 'height');
|
|
@@ -848,7 +886,7 @@ function renderContainer(
|
|
|
848
886
|
const childContent = wrapWithInheritedStyles(renderChildren(node.children, level + 1, renderNested, ctx, itemScope), modifiers, level + 1);
|
|
849
887
|
if (node.name === 'TableHeader') ctx.inTableHeader = prevTableHeader;
|
|
850
888
|
|
|
851
|
-
if (wrapLit === true && justifyLit !== 'between') {
|
|
889
|
+
if (wrapLit === true && justifyLit !== 'between' && justifyLit !== 'spaceBetween') {
|
|
852
890
|
return [
|
|
853
891
|
`${indent(level)}FlowRow(modifier = ${rowModifier}, horizontalArrangement = Arrangement.spacedBy(${spacing}), verticalArrangement = Arrangement.spacedBy(${spacing})) {`,
|
|
854
892
|
childContent,
|
|
@@ -987,6 +1025,8 @@ function renderContainer(
|
|
|
987
1025
|
JSON.stringify((child as IrTextNode).value),
|
|
988
1026
|
dedupeModifiers([...cellTextBehaviorMods(), `@textAlign(${textAlign})`, ...paddingMods, ...inheritedMods.map((m) => m)]),
|
|
989
1027
|
ctx,
|
|
1028
|
+
undefined,
|
|
1029
|
+
itemScope,
|
|
990
1030
|
);
|
|
991
1031
|
}
|
|
992
1032
|
if (child.kind === 'binding') {
|
|
@@ -995,6 +1035,8 @@ function renderContainer(
|
|
|
995
1035
|
bindingExpr(child as IrBinding, ctx, itemScope),
|
|
996
1036
|
dedupeModifiers([...cellTextBehaviorMods(), `@textAlign(${textAlign})`, ...paddingMods, ...inheritedMods.map((m) => m)]),
|
|
997
1037
|
ctx,
|
|
1038
|
+
undefined,
|
|
1039
|
+
itemScope,
|
|
998
1040
|
);
|
|
999
1041
|
}
|
|
1000
1042
|
return renderNested(child, level + 1, itemScope);
|
|
@@ -85,6 +85,16 @@ function composeSelfAlign(value: string | number | boolean): string | null {
|
|
|
85
85
|
return map[value] ?? null;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
/** Map DSL justify enum to Compose Row horizontalArrangement (accepts schema + legacy aliases). */
|
|
89
|
+
export function composeRowArrangement(justifyLit: unknown, spacing: string): string {
|
|
90
|
+
if (justifyLit === 'between' || justifyLit === 'spaceBetween') return 'Arrangement.SpaceBetween';
|
|
91
|
+
if (justifyLit === 'around' || justifyLit === 'spaceAround') return 'Arrangement.SpaceAround';
|
|
92
|
+
if (justifyLit === 'spaceEvenly') return 'Arrangement.SpaceEvenly';
|
|
93
|
+
if (justifyLit === 'end') return 'Arrangement.End';
|
|
94
|
+
if (justifyLit === 'center') return 'Arrangement.Center';
|
|
95
|
+
return `Arrangement.spacedBy(${spacing})`;
|
|
96
|
+
}
|
|
97
|
+
|
|
88
98
|
export function composeContentAlignment(value: string): string {
|
|
89
99
|
const map: Record<string, string> = {
|
|
90
100
|
topStart: 'Alignment.TopStart',
|
|
@@ -89,7 +89,10 @@ function resolveVariantEntries(
|
|
|
89
89
|
case 'minHeight':
|
|
90
90
|
case 'maxWidth': {
|
|
91
91
|
const px = parsePx(value);
|
|
92
|
-
if (px !== null)
|
|
92
|
+
if (px !== null) {
|
|
93
|
+
const kotlinValue = property === 'fontSize' ? `${px}.sp` : `${px}.dp`;
|
|
94
|
+
entries.push({ property, kotlinValue });
|
|
95
|
+
}
|
|
93
96
|
break;
|
|
94
97
|
}
|
|
95
98
|
case 'width': {
|
|
@@ -127,6 +130,12 @@ function resolveVariantEntries(
|
|
|
127
130
|
entries.push({ property, kotlinValue: value === 'none' ? 'false' : 'true' });
|
|
128
131
|
break;
|
|
129
132
|
}
|
|
133
|
+
case 'display': {
|
|
134
|
+
if (value.includes('inline')) {
|
|
135
|
+
entries.push({ property: 'shrinkWrap', kotlinValue: 'true' });
|
|
136
|
+
}
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
130
139
|
default:
|
|
131
140
|
break;
|
|
132
141
|
}
|
|
@@ -135,13 +144,21 @@ function resolveVariantEntries(
|
|
|
135
144
|
}
|
|
136
145
|
|
|
137
146
|
const STRUCT_FIELD_ORDER = [
|
|
138
|
-
'foreground', 'background', 'padding', 'paddingH', 'paddingV', 'widthFill', 'heightFill',
|
|
147
|
+
'foreground', 'background', 'padding', 'paddingH', 'paddingV', 'widthFill', 'heightFill', 'shrinkWrap',
|
|
139
148
|
'radius', 'fontSize', 'fontWeight', 'shadow', 'borderWidth', 'borderColor', 'minHeight', 'maxWidth',
|
|
140
149
|
];
|
|
141
150
|
|
|
151
|
+
function finalizeVariantEntries(entries: ResolvedEntry[]): ResolvedEntry[] {
|
|
152
|
+
if (entries.some((entry) => entry.property === 'shrinkWrap')) {
|
|
153
|
+
return entries.filter((entry) => entry.property !== 'widthFill');
|
|
154
|
+
}
|
|
155
|
+
return entries;
|
|
156
|
+
}
|
|
157
|
+
|
|
142
158
|
function emitVariantStyleInit(entries: ResolvedEntry[]): string {
|
|
143
|
-
|
|
144
|
-
|
|
159
|
+
const finalized = finalizeVariantEntries(entries);
|
|
160
|
+
if (finalized.length === 0) return 'VcVariantStyle()';
|
|
161
|
+
const sorted = [...finalized].sort(
|
|
145
162
|
(a, b) => STRUCT_FIELD_ORDER.indexOf(a.property) - STRUCT_FIELD_ORDER.indexOf(b.property),
|
|
146
163
|
);
|
|
147
164
|
return `VcVariantStyle(${sorted.map((e) => `${e.property} = ${e.kotlinValue}`).join(', ')})`;
|
|
@@ -183,6 +200,7 @@ export function renderComposeTheme(theme: ThemeIR, tokens: TokenIR): string {
|
|
|
183
200
|
lines.push('import androidx.compose.ui.text.TextStyle');
|
|
184
201
|
lines.push('import androidx.compose.ui.text.font.FontWeight');
|
|
185
202
|
lines.push('import androidx.compose.ui.unit.Dp');
|
|
203
|
+
lines.push('import androidx.compose.ui.unit.TextUnit');
|
|
186
204
|
lines.push('import androidx.compose.ui.unit.dp');
|
|
187
205
|
lines.push('import androidx.compose.ui.unit.sp');
|
|
188
206
|
lines.push('');
|
|
@@ -194,8 +212,9 @@ export function renderComposeTheme(theme: ThemeIR, tokens: TokenIR): string {
|
|
|
194
212
|
lines.push(' val paddingV: Dp? = null,');
|
|
195
213
|
lines.push(' val widthFill: Boolean? = null,');
|
|
196
214
|
lines.push(' val heightFill: Boolean? = null,');
|
|
215
|
+
lines.push(' val shrinkWrap: Boolean? = null,');
|
|
197
216
|
lines.push(' val radius: Dp? = null,');
|
|
198
|
-
lines.push(' val fontSize:
|
|
217
|
+
lines.push(' val fontSize: TextUnit? = null,');
|
|
199
218
|
lines.push(' val fontWeight: FontWeight? = null,');
|
|
200
219
|
lines.push(' val shadow: Boolean? = null,');
|
|
201
220
|
lines.push(' val borderWidth: Dp? = null,');
|
|
@@ -207,7 +226,7 @@ export function renderComposeTheme(theme: ThemeIR, tokens: TokenIR): string {
|
|
|
207
226
|
lines.push('fun VcVariantStyle.asTextStyle(): TextStyle {');
|
|
208
227
|
lines.push(' var style = TextStyle()');
|
|
209
228
|
lines.push(' foreground?.let { style = style.copy(color = it) }');
|
|
210
|
-
lines.push(' fontSize?.let { style = style.copy(fontSize = it
|
|
229
|
+
lines.push(' fontSize?.let { style = style.copy(fontSize = it) }');
|
|
211
230
|
lines.push(' fontWeight?.let { style = style.copy(fontWeight = it) }');
|
|
212
231
|
lines.push(' return style');
|
|
213
232
|
lines.push('}');
|
|
@@ -223,7 +242,7 @@ export function renderComposeTheme(theme: ThemeIR, tokens: TokenIR): string {
|
|
|
223
242
|
lines.push('');
|
|
224
243
|
lines.push('fun Modifier.applyVcStyle(style: VcVariantStyle): Modifier {');
|
|
225
244
|
lines.push(' var out = this');
|
|
226
|
-
lines.push(' if (style.widthFill == true) out = out.fillMaxWidth()');
|
|
245
|
+
lines.push(' if (style.widthFill == true && style.shrinkWrap != true) out = out.fillMaxWidth()');
|
|
227
246
|
lines.push(' if (style.heightFill == true) out = out.fillMaxHeight()');
|
|
228
247
|
lines.push(' if (style.shadow == true) out = out.then(vcSoftShadowModifier(style.radius ?: 0.dp))');
|
|
229
248
|
lines.push(' style.background?.let { out = out.background(it, RoundedCornerShape(style.radius ?: 0.dp)) }');
|