diff --git a/README.md b/README.md index c2aee406..ea1650cf 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,7 @@ resistorProps.parse({ resistance: "10k" } as ResistorPropsInput); | `` | [`SchematicRowProps`](#schematicrowprops-schematicrow) | | `` | [`SchematicSectionProps`](#schematicsectionprops-schematicsection) | | `` | [`SchematicSheetProps`](#schematicsheetprops-schematicsheet) | +| `` | [`SchematicSymbolProps`](#schematicsymbolprops-schematicsymbol) | | `` | [`SchematicTableProps`](#schematictableprops-schematictable) | | `` | [`SchematicTextProps`](#schematictextprops-schematictext) | | `` | [`SilkscreenCircleProps`](#silkscreencircleprops-silkscreencircle) | @@ -1691,6 +1692,30 @@ export interface SchematicSheetProps { [Source](https://github.com/tscircuit/props/blob/main/lib/components/schematic-sheet.ts) +### SchematicSymbolProps `` + +```ts +export interface SchematicSymbolProps { + /** Stable name for this representation, such as `A` or `B`. */ + name: string; + /** Optional human-facing name shown in the schematic. */ + displayName?: string; + /** Selector for the physical component represented by this symbol. */ + chipRef?: string; + /** Name of the symbol from the schematic-symbol library. */ + symbolName: string; + /** Maps symbol port labels to physical component port selectors. */ + connections?: Connections; + schX?: Distance; + schY?: Distance; + schRotation?: number | string; + schSectionName?: string; + schSheetName?: string; +} +``` + +[Source](https://github.com/tscircuit/props/blob/main/lib/components/schematic-symbol.ts) + ### SchematicTableProps `` ```ts diff --git a/generated/COMPONENT_TYPES.md b/generated/COMPONENT_TYPES.md index 39b5cdcc..3a76247c 100644 --- a/generated/COMPONENT_TYPES.md +++ b/generated/COMPONENT_TYPES.md @@ -3719,6 +3719,45 @@ export const schematicSheetProps = z.object({ }) ``` +### schematic-symbol + +```typescript +/** + * Places a named schematic-symbol representation of an existing physical + * component. The connection keys are labels exposed by `symbolName`; each + * value selects the corresponding port on the component referenced by + * `chipRef`. + * + * This is a schematic-only projection, so it accepts only the identity, + * connection, and schematic placement props it needs. + */ +export interface SchematicSymbolProps { + name: string + displayName?: string + chipRef?: string + symbolName: string + connections?: Connections + schX?: Distance + schY?: Distance + schRotation?: number | string + schSectionName?: string + schSheetName?: string +} +/** Maps symbol port labels to physical component port selectors. */ +export const schematicSymbolProps = z.object({ + name: z.string().min(1), + displayName: z.string().optional(), + chipRef: z.string().min(1).optional(), + symbolName: z.string().min(1), + connections: schematicSymbolConnections.optional(), + schX: distance.optional(), + schY: distance.optional(), + schRotation: rotation.optional(), + schSectionName: z.string().optional(), + schSheetName: z.string().optional(), +}) +``` + ### schematic-table ```typescript diff --git a/generated/PROPS_OVERVIEW.md b/generated/PROPS_OVERVIEW.md index 6dd36661..c6229d94 100644 --- a/generated/PROPS_OVERVIEW.md +++ b/generated/PROPS_OVERVIEW.md @@ -2101,6 +2101,25 @@ export interface SchematicSheetProps { } +export interface SchematicSymbolProps { + /** Stable name for this representation, such as `A` or `B`. */ + name: string + /** Optional human-facing name shown in the schematic. */ + displayName?: string + /** Selector for the physical component represented by this symbol. */ + chipRef?: string + /** Name of the symbol from the schematic-symbol library. */ + symbolName: string + /** Maps symbol port labels to physical component port selectors. */ + connections?: Connections + schX?: Distance + schY?: Distance + schRotation?: number | string + schSectionName?: string + schSheetName?: string +} + + export interface SchematicTableProps { schX?: number | string schY?: number | string diff --git a/lib/components/schematic-symbol.ts b/lib/components/schematic-symbol.ts new file mode 100644 index 00000000..d097d5f7 --- /dev/null +++ b/lib/components/schematic-symbol.ts @@ -0,0 +1,59 @@ +import { rotation } from "circuit-json" +import { connectionTarget } from "lib/common/connectionsProp" +import { distance, type Distance } from "lib/common/distance" +import { expectTypesMatch } from "lib/typecheck" +import type { Connections } from "lib/utility-types/connections-and-selectors" +import { z } from "zod" + +/** + * Places a named schematic-symbol representation of an existing physical + * component. The connection keys are labels exposed by `symbolName`; each + * value selects the corresponding port on the component referenced by + * `chipRef`. + * + * This is a schematic-only projection, so it accepts only the identity, + * connection, and schematic placement props it needs. + */ +export interface SchematicSymbolProps { + /** Stable name for this representation, such as `A` or `B`. */ + name: string + /** Optional human-facing name shown in the schematic. */ + displayName?: string + /** Selector for the physical component represented by this symbol. */ + chipRef?: string + /** Name of the symbol from the schematic-symbol library. */ + symbolName: string + /** Maps symbol port labels to physical component port selectors. */ + connections?: Connections + schX?: Distance + schY?: Distance + schRotation?: number | string + schSectionName?: string + schSheetName?: string +} + +const schematicSymbolConnections = z + .custom() + .pipe(z.record(z.string(), connectionTarget)) + .refine((value) => Object.keys(value).length > 0, { + message: "connections must map at least one schematic symbol port", + }) + +export const schematicSymbolProps = z.object({ + name: z.string().min(1), + displayName: z.string().optional(), + chipRef: z.string().min(1).optional(), + symbolName: z.string().min(1), + connections: schematicSymbolConnections.optional(), + schX: distance.optional(), + schY: distance.optional(), + schRotation: rotation.optional(), + schSectionName: z.string().optional(), + schSheetName: z.string().optional(), +}) + +export type InferredSchematicSymbolProps = z.input + +expectTypesMatch>( + true, +) diff --git a/lib/index.ts b/lib/index.ts index 421456d5..f6584961 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -104,6 +104,7 @@ export * from "./components/ammeter" export * from "./components/schematic-arc" export * from "./components/toolingrail" export * from "./components/schematic-box" +export * from "./components/schematic-symbol" export * from "./components/schematic-circle" export * from "./components/schematic-rect" export * from "./components/schematic-line" diff --git a/tests/schematic-symbol.test.ts b/tests/schematic-symbol.test.ts new file mode 100644 index 00000000..fea8694e --- /dev/null +++ b/tests/schematic-symbol.test.ts @@ -0,0 +1,59 @@ +import { expect, test } from "bun:test" +import { schematicSymbolProps } from "lib/components/schematic-symbol" + +test("schematic symbol parses a physical component projection", () => { + const parsed = schematicSymbolProps.parse({ + name: "A", + displayName: "Q1A", + chipRef: ".Q1", + symbolName: "n_channel_e_mosfet_transistor", + connections: { + gate: ".Q1 > .G1", + source: ".Q1 > .S1", + drain: [".Q1 > .pin7", ".Q1 > .pin8"], + }, + schX: "2mm", + schY: "-1mm", + schRotation: "90deg", + schSectionName: "Switching", + schSheetName: "Power", + }) + + expect(parsed).toEqual({ + name: "A", + displayName: "Q1A", + chipRef: ".Q1", + symbolName: "n_channel_e_mosfet_transistor", + connections: { + gate: ".Q1 > .G1", + source: ".Q1 > .S1", + drain: [".Q1 > .pin7", ".Q1 > .pin8"], + }, + schX: 2, + schY: -1, + schRotation: 90, + schSectionName: "Switching", + schSheetName: "Power", + }) +}) + +test("schematic symbol allows optional chipRef and connections", () => { + const parsed = schematicSymbolProps.parse({ + name: "B", + symbolName: "n_channel_e_mosfet_transistor", + }) + + expect(parsed.chipRef).toBeUndefined() + expect(parsed.connections).toBeUndefined() +}) + +test("schematic symbol rejects an empty connections map", () => { + expect( + schematicSymbolProps.safeParse({ + name: "A", + chipRef: ".Q1", + symbolName: "n_channel_e_mosfet_transistor", + connections: {}, + }).success, + ).toBe(false) +})