From 9499a6244f06848d0530dd2ee72cf75a157c474e Mon Sep 17 00:00:00 2001 From: Anil Kumar Date: Thu, 1 Oct 2026 07:23:01 +0530 Subject: [PATCH 1/2] Preserve explicit silkscreen text mirroring --- .../primitive-components/SilkscreenText.ts | 1 + lib/utils/createComponentsFromCircuitJson.ts | 1 + lib/utils/createPinrowSilkscreenText.ts | 1 + package.json | 3 ++ patches/@tscircuit%2Fprops@0.0.672.patch | 38 +++++++++++++++++ patches/README.md | 3 ++ .../silkscreen-text-mirrored-pcb.snap.svg | 1 + .../silkscreen-text-mirrored.test.tsx | 41 +++++++++++++++++++ 8 files changed, 89 insertions(+) create mode 100644 patches/@tscircuit%2Fprops@0.0.672.patch create mode 100644 patches/README.md create mode 100644 tests/components/primitive-components/__snapshots__/silkscreen-text-mirrored-pcb.snap.svg create mode 100644 tests/components/primitive-components/silkscreen-text-mirrored.test.tsx diff --git a/lib/components/primitive-components/SilkscreenText.ts b/lib/components/primitive-components/SilkscreenText.ts index 3cf358c4de..1cfa3847ae 100644 --- a/lib/components/primitive-components/SilkscreenText.ts +++ b/lib/components/primitive-components/SilkscreenText.ts @@ -152,6 +152,7 @@ export class SilkscreenText extends PrimitiveComponent< subcircuit_id: subcircuit?.subcircuit_id ?? undefined, pcb_group_id: this.getGroup()?.pcb_group_id ?? undefined, is_knockout: props.isKnockout, + is_mirrored: props.mirrored, knockout_padding: knockoutPadding, }) this.pcb_silkscreen_text_ids.push( diff --git a/lib/utils/createComponentsFromCircuitJson.ts b/lib/utils/createComponentsFromCircuitJson.ts index 7c7660223b..e7709870cc 100644 --- a/lib/utils/createComponentsFromCircuitJson.ts +++ b/lib/utils/createComponentsFromCircuitJson.ts @@ -586,6 +586,7 @@ export const createComponentsFromCircuitJson = ( ) } else { const silkscreenText = new SilkscreenText({ + mirrored: elm.is_mirrored, anchorAlignment: elm.anchor_alignment || "center", // Footprinter-generated reference text is a placeholder that should // resolve to the component name. A literal from the explicit diff --git a/lib/utils/createPinrowSilkscreenText.ts b/lib/utils/createPinrowSilkscreenText.ts index 924aa2d826..792cee50ee 100644 --- a/lib/utils/createPinrowSilkscreenText.ts +++ b/lib/utils/createPinrowSilkscreenText.ts @@ -31,6 +31,7 @@ export const createPinrowSilkscreenText = ({ pcbX: isNaN(elm.anchor_position.x) ? 0 : elm.anchor_position.x, pcbY: elm.anchor_position.y, pcbRotation: readableRotation ?? 0, + mirrored: elm.is_mirrored, }) silkscreenText._footprinterFontSize = elm.font_size + 0.2 return silkscreenText diff --git a/package.json b/package.json index 9017c9eb26..3d02bbc496 100644 --- a/package.json +++ b/package.json @@ -138,5 +138,8 @@ "@tscircuit/circuit-json-util": "^0.0.117", "@tscircuit/props": "^0.0.672", "circuit-json": "^0.0.507" + }, + "patchedDependencies": { + "@tscircuit/props@0.0.672": "patches/@tscircuit%2Fprops@0.0.672.patch" } } diff --git a/patches/@tscircuit%2Fprops@0.0.672.patch b/patches/@tscircuit%2Fprops@0.0.672.patch new file mode 100644 index 0000000000..a914c7f57e --- /dev/null +++ b/patches/@tscircuit%2Fprops@0.0.672.patch @@ -0,0 +1,38 @@ +--- a/dist/index.js ++++ b/dist/index.js +@@ -19228,6 +19228,8 @@ + anchorAlignment: ninePointAnchor.default("center"), + font: z142.enum(["tscircuit2024"]).optional(), + fontSize: length9.optional(), ++ /** Explicit text mirroring, independent of layer. Omitted preserves the renderer default. */ ++ mirrored: z142.boolean().optional(), + /** + * If true, text will knock out underlying silkscreen + */ +--- a/dist/index.d.ts ++++ b/dist/index.d.ts +@@ -239229,6 +239229,8 @@ + anchorAlignment: z.ZodDefault>; + font: z.ZodOptional>; + fontSize: z.ZodOptional, number, string | number>>; ++ /** Explicit text mirroring, independent of layer. Omitted preserves the renderer default. */ ++ mirrored: z.ZodOptional; + /** + * If true, text will knock out underlying silkscreen + */ +@@ -239285,6 +239287,7 @@ + pcbSx?: PcbSx | undefined; + pcbRelative?: boolean | undefined; + relative?: boolean | undefined; ++ mirrored?: boolean | undefined; + isKnockout?: boolean | undefined; + knockoutPadding?: number | undefined; + knockoutPaddingLeft?: number | undefined; +@@ -239333,6 +239336,7 @@ + pcbRelative?: boolean | undefined; + relative?: boolean | undefined; + anchorAlignment?: "top_left" | "top_center" | "top_right" | "center_left" | "center" | "center_right" | "bottom_left" | "bottom_center" | "bottom_right" | undefined; ++ mirrored?: boolean | undefined; + isKnockout?: boolean | undefined; + knockoutPadding?: string | number | undefined; + knockoutPaddingLeft?: string | number | undefined; diff --git a/patches/README.md b/patches/README.md new file mode 100644 index 0000000000..b49f8600b0 --- /dev/null +++ b/patches/README.md @@ -0,0 +1,3 @@ +The props patch mirrors https://github.com/tscircuit/props/pull/885 and allows this PR's mirroring regression tests and type declarations to run against the currently published `@tscircuit/props@0.0.672`. + +Before merging, replace the patch with a released props version containing that PR (update both the development dependency and the override). The patch is only used for local/CI development; consumers need the corresponding props release. diff --git a/tests/components/primitive-components/__snapshots__/silkscreen-text-mirrored-pcb.snap.svg b/tests/components/primitive-components/__snapshots__/silkscreen-text-mirrored-pcb.snap.svg new file mode 100644 index 0000000000..33ac5caaca --- /dev/null +++ b/tests/components/primitive-components/__snapshots__/silkscreen-text-mirrored-pcb.snap.svg @@ -0,0 +1 @@ +ABC trueABC falseABC undefinedABC trueABC falseABC undefined \ No newline at end of file diff --git a/tests/components/primitive-components/silkscreen-text-mirrored.test.tsx b/tests/components/primitive-components/silkscreen-text-mirrored.test.tsx new file mode 100644 index 0000000000..313c00256b --- /dev/null +++ b/tests/components/primitive-components/silkscreen-text-mirrored.test.tsx @@ -0,0 +1,41 @@ +import { expect, test } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" + +test("silkscreen text preserves explicit mirroring through layer flips", () => { + const { circuit } = getTestFixture() + const mirrors = [true, false, undefined] + circuit.add( + + {(["top", "bottom"] as const).flatMap((layer, row) => + mirrors.map((mirrored, i) => ( + + + + } + /> + )), + )} + , + ) + circuit.render() + const texts = circuit.db.pcb_silkscreen_text + .list() + .filter((t) => t.text.startsWith("ABC")) + expect(texts).toHaveLength(6) + texts.forEach((text, i) => { + expect(text.is_mirrored).toBe(mirrors[i % 3]) + expect(text.layer).toBe(i < 3 ? "top" : "bottom") + }) + expect(circuit).toMatchPcbSnapshot(import.meta.path) +}) From 71443fc9a7be5a444b79a6a07e8a12175a5d043a Mon Sep 17 00:00:00 2001 From: Anil Kumar Date: Thu, 1 Oct 2026 07:29:12 +0530 Subject: [PATCH 2/2] Preserve omission of unspecified silkscreen mirroring --- lib/components/primitive-components/SilkscreenText.ts | 4 +++- .../primitive-components/silkscreen-text-mirrored.test.tsx | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/components/primitive-components/SilkscreenText.ts b/lib/components/primitive-components/SilkscreenText.ts index 1cfa3847ae..a546967ec9 100644 --- a/lib/components/primitive-components/SilkscreenText.ts +++ b/lib/components/primitive-components/SilkscreenText.ts @@ -152,7 +152,9 @@ export class SilkscreenText extends PrimitiveComponent< subcircuit_id: subcircuit?.subcircuit_id ?? undefined, pcb_group_id: this.getGroup()?.pcb_group_id ?? undefined, is_knockout: props.isKnockout, - is_mirrored: props.mirrored, + ...(props.mirrored === undefined + ? {} + : { is_mirrored: props.mirrored }), knockout_padding: knockoutPadding, }) this.pcb_silkscreen_text_ids.push( diff --git a/tests/components/primitive-components/silkscreen-text-mirrored.test.tsx b/tests/components/primitive-components/silkscreen-text-mirrored.test.tsx index 313c00256b..a266c3d0af 100644 --- a/tests/components/primitive-components/silkscreen-text-mirrored.test.tsx +++ b/tests/components/primitive-components/silkscreen-text-mirrored.test.tsx @@ -35,6 +35,8 @@ test("silkscreen text preserves explicit mirroring through layer flips", () => { expect(texts).toHaveLength(6) texts.forEach((text, i) => { expect(text.is_mirrored).toBe(mirrors[i % 3]) + if (mirrors[i % 3] === undefined) + expect(text).not.toHaveProperty("is_mirrored") expect(text.layer).toBe(i < 3 ? "top" : "bottom") }) expect(circuit).toMatchPcbSnapshot(import.meta.path)