astra/am3352-sbc
A tscircuit package created by astra.
- Version
- 0.1.28
- License
- unset
- Stars
- 0
components/pmos-symbol.tsx
import { Fragment } from "react"
import { symbols, type SchSymbol } from "schematic-symbols"
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null
}
function isPoint(value: unknown): value is Record<string, unknown> & { x: number; y: number } {
return isRecord(value) && typeof value.x === "number" && Number.isFinite(value.x)
&& typeof value.y === "number" && Number.isFinite(value.y)
}
/** Check the library entry because schematic-symbols declares this variant as undefined. */
function isPmosSymbol(value: unknown): value is SchSymbol {
if (!isRecord(value) || !isPoint(value.center) || !isRecord(value.size)
|| typeof value.size.width !== "number" || typeof value.size.height !== "number"
|| !Array.isArray(value.ports) || !Array.isArray(value.primitives)) return false
const anchorNames = new Set(["top_left", "top_right", "bottom_left", "bottom_right", "center",
"middle_top", "middle_bottom", "middle_left", "middle_right"])
const labels = value.ports.flatMap((port: unknown) => isRecord(port) && Array.isArray(port.labels)
? port.labels.filter((label: unknown): label is string => typeof label === "string") : [])
if (value.ports.length !== 3 || !["gate", "source", "drain"].every(
(name) => labels.filter((label) => label === name).length === 1)) return false
return value.ports.every((port: unknown) => isPoint(port) && isRecord(port)
&& Array.isArray(port.labels) && port.labels.every((label: unknown) => typeof label === "string"))
&& value.primitives.every((primitive: unknown) => {
if (!isRecord(primitive)) return false
if (primitive.type === "path") return Array.isArray(primitive.points)
&& primitive.points.every(isPoint) && typeof primitive.color === "string"
&& (primitive.fill === undefined || typeof primitive.fill === "boolean")
if (primitive.type === "circle") return isPoint(primitive) && typeof primitive.radius === "number"
&& typeof primitive.fill === "boolean" && typeof primitive.color === "string"
if (primitive.type === "text") return isPoint(primitive) && typeof primitive.text === "string"
&& typeof primitive.anchor === "string" && anchorNames.has(primitive.anchor)
return false
})
}
/** A standard PMOS symbol with this board's SOT-23 G=1, S=2, D=3 pin numbering. */
export function PmosSymbol({ name, value }: { name: string; value: string }) {
const candidate: unknown = symbols.p_channel_e_mosfet_transistor_gate_left_drain_top
if (!isPmosSymbol(candidate)) throw new Error("The standard PMOS schematic symbol is missing or invalid")
const symbol = candidate
const scale = 1.8
const point = ({ x, y }: { x: number; y: number }) => ({
x: (x - symbol.center.x) * scale,
y: (y - symbol.center.y) * scale,
})
return <symbol>
{symbol.primitives.map((primitive, index) => {
if (primitive.type === "path") return <Fragment key={index}>
<schematicpath points={primitive.points.map(point)} strokeColor="#880000"
isFilled={Boolean(primitive.fill)} fillColor="#880000" />
</Fragment>
if (primitive.type === "circle") return <Fragment key={index}>
<schematiccircle center={point(primitive)} radius={primitive.radius * scale} color="#880000" />
</Fragment>
if (primitive.type === "text") {
const position = point(primitive)
return <Fragment key={index}>
<schematictext text={primitive.text === "{REF}" ? name : value}
schX={position.x} schY={position.y} fontSize={0.18} />
</Fragment>
}
return null
})}
{symbol.ports.map((port) => {
const pin = port.labels.includes("gate") ? { name: "G", number: 1, direction: "left" as const }
: port.labels.includes("source") ? { name: "S", number: 2, direction: "down" as const }
: { name: "D", number: 3, direction: "up" as const }
const position = point(port)
return <Fragment key={pin.name}>
<port name={pin.name} pinNumber={pin.number} aliases={[pin.name]}
direction={pin.direction} schX={position.x} schY={position.y} schStemLength={0.3} />
</Fragment>
})}
</symbol>
}