Skip to content

Commit 13e58c4

Browse files
Merge pull request #271 from RtlZeroMemory/fix/issue-270-badge-color
fix(core): correctly render badge recipe background/text
2 parents 3e45eaa + 4eea133 commit 13e58c4

File tree

3 files changed

+69
-21
lines changed

3 files changed

+69
-21
lines changed

packages/core/src/renderer/__tests__/sliderRecipeRendering.test.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,37 @@ describe("slider/badge/tag recipe rendering", () => {
4646
viewport: { cols: 24, rows: 2 },
4747
theme: dsTheme,
4848
});
49+
const fill = ops.find((op) => op.kind === "fillRect" && op.style?.bg === dsTheme.colors.info);
4950
const text = firstDrawText(ops, (s) => s.includes("Info"));
51+
assert.ok(fill && fill.kind === "fillRect");
5052
assert.ok(text && text.kind === "drawText");
51-
if (!text || text.kind !== "drawText") return;
53+
if (!fill || fill.kind !== "fillRect" || !text || text.kind !== "drawText") return;
54+
assert.ok(text.text.includes("( Info )"));
55+
assert.deepEqual(fill.style?.bg, dsTheme.colors.info);
56+
assert.deepEqual(text.style?.bg, dsTheme.colors.info);
57+
assert.deepEqual(text.style?.fg, dsTheme.colors["fg.inverse"]);
58+
assert.equal(text.style?.bold, true);
59+
});
60+
61+
test("badge explicit style overrides recipe fg/bg", () => {
62+
const explicitFg = 0x11_88_ff;
63+
const explicitBg = 0x22_33_44;
64+
const ops = renderOps(
65+
ui.badge("Info", { variant: "info", style: { fg: explicitFg, bg: explicitBg } }),
66+
{
67+
viewport: { cols: 24, rows: 2 },
68+
theme: dsTheme,
69+
},
70+
);
71+
const fill = ops.find((op) => op.kind === "fillRect" && op.style?.bg === explicitBg);
72+
const text = firstDrawText(ops, (s) => s.includes("Info"));
73+
assert.ok(fill && fill.kind === "fillRect");
74+
assert.ok(text && text.kind === "drawText");
75+
if (!fill || fill.kind !== "fillRect" || !text || text.kind !== "drawText") return;
5276
assert.ok(text.text.includes("( Info )"));
53-
assert.deepEqual(text.style?.fg, dsTheme.colors.info);
54-
assert.notEqual(text.style?.bg, dsTheme.colors.info);
77+
assert.deepEqual(fill.style?.bg, explicitBg);
78+
assert.deepEqual(text.style?.bg, explicitBg);
79+
assert.deepEqual(text.style?.fg, explicitFg);
5580
assert.equal(text.style?.bold, true);
5681
});
5782

packages/core/src/renderer/renderToDrawlist/widgets/renderTextWidgets.ts

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -541,19 +541,16 @@ function variantToRecipeTone(
541541
}
542542
}
543543

544-
function resolveChipColor(theme: Theme, variant: unknown, kind: "badge" | "tag"): Rgb24 {
544+
function resolveTagColor(theme: Theme, variant: unknown): Rgb24 {
545545
const colorTokens = getColorTokens(theme);
546546
if (colorTokens !== null) {
547547
const tone = variantToRecipeTone(variant);
548-
const bgStyle = (
549-
kind === "badge" ? badgeRecipe(colorTokens, { tone }).bg : tagRecipe(colorTokens, { tone }).bg
550-
) as { bg?: unknown };
548+
const bgStyle = tagRecipe(colorTokens, { tone }).bg as { bg?: unknown };
551549
if (typeof bgStyle.bg === "number") {
552550
return bgStyle.bg;
553551
}
554552
}
555-
const fallbackTone =
556-
kind === "badge" || variant === "primary" ? ("primary" as const) : ("secondary" as const);
553+
const fallbackTone = variant === "primary" ? ("primary" as const) : ("secondary" as const);
557554
return variantToThemeColor(theme, variant, fallbackTone);
558555
}
559556

@@ -887,12 +884,35 @@ export function renderTextWidgets(
887884
const props = vnode.props as { text?: unknown; variant?: unknown; style?: unknown };
888885
const text = readString(props.text) ?? "";
889886
const ownStyle = asTextStyle(props.style, theme);
890-
const color = resolveChipColor(theme, props.variant, "badge");
891-
const chipStyle = mergeTextStyle(
892-
mergeTextStyle(parentStyle, { fg: color, bold: true }),
893-
ownStyle,
894-
);
895-
maybeFillOwnBackground(builder, rect, ownStyle, chipStyle);
887+
const colorTokens = getColorTokens(theme);
888+
const recipeResult =
889+
colorTokens !== null
890+
? badgeRecipe(colorTokens, { tone: variantToRecipeTone(props.variant) })
891+
: null;
892+
const fallbackStyle = mergeTextStyle(parentStyle, {
893+
fg: variantToThemeColor(theme, props.variant, "primary"),
894+
bold: true,
895+
});
896+
const chipBaseStyle =
897+
recipeResult !== null
898+
? mergeTextStyle(
899+
parentStyle,
900+
recipeResult.bg.bg !== undefined
901+
? { ...recipeResult.text, bg: recipeResult.bg.bg }
902+
: recipeResult.text,
903+
)
904+
: fallbackStyle;
905+
const chipStyle = ownStyle ? mergeTextStyle(chipBaseStyle, ownStyle) : chipBaseStyle;
906+
if (recipeResult?.bg.bg !== undefined) {
907+
const bgBaseStyle = mergeTextStyle(parentStyle, recipeResult.bg);
908+
const bgStyle = mergeTextStyle(
909+
bgBaseStyle,
910+
ownStyle && ownStyle.bg !== undefined ? { bg: ownStyle.bg } : undefined,
911+
);
912+
builder.fillRect(rect.x, rect.y, rect.w, rect.h, bgStyle);
913+
} else {
914+
maybeFillOwnBackground(builder, rect, ownStyle, chipStyle);
915+
}
896916
const content = `( ${text} )`;
897917
const segments: StyledSegment[] = [{ text: content, style: chipStyle }];
898918

@@ -1014,7 +1034,7 @@ export function renderTextWidgets(
10141034
const text = readString(props.text) ?? "";
10151035
const removable = props.removable === true;
10161036
const ownStyle = asTextStyle(props.style, theme);
1017-
const variantColor = resolveChipColor(theme, props.variant, "tag");
1037+
const variantColor = resolveTagColor(theme, props.variant);
10181038
const chipStyle = mergeTextStyle(
10191039
mergeTextStyle(parentStyle, { fg: variantColor, bold: true }),
10201040
ownStyle,

packages/core/src/widgets/__tests__/composition.animationOrchestration.test.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,14 @@ describe("composition animation hooks - orchestration", () => {
200200
pausedValue = render.result[0]?.value ?? 0;
201201
h.runPending(render.pendingEffects);
202202

203-
await sleep(80);
204-
render = h.render((hooks) => useParallel(hooks, paused));
205-
h.runPending(render.pendingEffects);
206-
assert.ok(Math.abs((render.result[0]?.value ?? 0) - pausedValue) <= 0.1);
207-
assert.equal(render.result[0]?.isAnimating, false);
203+
await waitFor(() => {
204+
const next = h.render((hooks) => useParallel(hooks, paused));
205+
render = next;
206+
h.runPending(next.pendingEffects);
207+
const entry = next.result[0];
208+
if (!entry) return false;
209+
return Math.abs(entry.value - pausedValue) <= 0.1 && entry.isAnimating === false;
210+
});
208211

209212
render = h.render((hooks) => useParallel(hooks, running));
210213
h.runPending(render.pendingEffects);

0 commit comments

Comments
 (0)