pixalynx/edge-connector
Configures USB-A, Micro-USB, and USB-C PCB-edge connectors with exposed copper contacts and automatically shaped, positioned board tongues.
- Version
- 1.0.0
- License
- GPL-3.0-only
- Stars
- 0
dist/index.cjs
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var jsxRuntime = require('react/jsx-runtime');
var react = require('react');
/** Exposed contacts with no stencil openings, on their original copper faces. */
function EdgeContactFootprint({ pads, solderMaskMargin = 0.025, }) {
return (jsxRuntime.jsx("footprint", { insertionDirection: "from_top", children: pads.map((pad) => (jsxRuntime.jsx(react.Fragment, { children: jsxRuntime.jsx("smtpad", { portHints: [pad.pin], pcbX: pad.x, pcbY: pad.y, width: pad.width, height: pad.height, shape: "rect", layer: pad.layer, coveredWithSolderMask: false, solderMaskMargin: solderMaskMargin, solderPasteMargin: -pad.width / 2 }) }, pad.pin))) }));
}
const usbAEdgeConnectorPinLabels = {
pin1: ["VBUS"],
pin2: ["DM", "D_MINUS"],
pin3: ["DP", "D_PLUS"],
pin4: ["GND"],
};
/** Millimetres, relative to the component origin at pcbRotation={0}. */
const usbAEdgeConnectorGeometry = {
tongueWidth: 12,
boardThickness: 2,
tipY: 4.8,
shoulderY: -3.9,
edgeProfile: [
{ x: -6, y: -3.9 },
{ x: -6, y: 4.3 },
{ x: -5.5, y: 4.8 },
{ x: 5.5, y: 4.8 },
{ x: 6, y: 4.3 },
{ x: 6, y: -3.9 },
],
};
/**
* USB 2.0 Type-A male PCB contacts. Top copper, insertion toward local +Y.
* Looking down at the contacts with the tip up: VBUS, D-, D+, GND.
* The host board must supply the tongue outline and thickness (see README).
*/
function UsbAEdgeConnector(props) {
return (jsxRuntime.jsx("connector", { schWidth: 2.2, schHeight: 1, schPinArrangement: {
rightSide: { pins: [1, 2, 3, 4], direction: "top-to-bottom" },
}, showPinAliases: true, ...props, layer: "top", doNotPlace: true, pinLabels: usbAEdgeConnectorPinLabels, footprint: jsxRuntime.jsx(EdgeContactFootprint, { solderMaskMargin: 0.05,
// USB-A-PCB reference geometry, rounded to 0.01 mm; see README.
pads: [
{ pin: "pin1", x: -3.5, y: 0, width: 1.5, height: 7.5, layer: "top" },
{ pin: "pin2", x: -1, y: -0.5, width: 1, height: 6.5, layer: "top" },
{ pin: "pin3", x: 1, y: -0.5, width: 1, height: 6.5, layer: "top" },
{ pin: "pin4", x: 3.5, y: 0, width: 1.5, height: 7.5, layer: "top" },
] }) }));
}
// Adapted from vasya-zh/PCB-Edge-USB-connector-KiCad-library (GPL-3.0).
// Source commit: 909b6ed3d7b6456c385dab109aba96fdece8a3d9.
// KiCad coordinates mapped to insertion along +Y; arcs sampled at <=10 degrees.
const usbCEdgePads = [
{
"pin": "A1",
"x": 2.75,
"y": 0.0,
"width": 0.25,
"height": 3.8,
"layer": "top"
},
{
"pin": "A2",
"x": 2.25,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "top"
},
{
"pin": "A3",
"x": 1.75,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "top"
},
{
"pin": "A4",
"x": 1.25,
"y": -0.075,
"width": 0.25,
"height": 3.65,
"layer": "top"
},
{
"pin": "A5",
"x": 0.75,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "top"
},
{
"pin": "A6",
"x": 0.25,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "top"
},
{
"pin": "A7",
"x": -0.25,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "top"
},
{
"pin": "A8",
"x": -0.75,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "top"
},
{
"pin": "A9",
"x": -1.25,
"y": -0.075,
"width": 0.25,
"height": 3.65,
"layer": "top"
},
{
"pin": "A10",
"x": -1.75,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "top"
},
{
"pin": "A11",
"x": -2.25,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "top"
},
{
"pin": "A12",
"x": -2.75,
"y": 0.0,
"width": 0.25,
"height": 3.8,
"layer": "top"
},
{
"pin": "B1",
"x": -2.75,
"y": 0.0,
"width": 0.25,
"height": 3.8,
"layer": "bottom"
},
{
"pin": "B2",
"x": -2.25,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "bottom"
},
{
"pin": "B3",
"x": -1.75,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "bottom"
},
{
"pin": "B4",
"x": -1.25,
"y": -0.075,
"width": 0.25,
"height": 3.65,
"layer": "bottom"
},
{
"pin": "B5",
"x": -0.75,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "bottom"
},
{
"pin": "B6",
"x": -0.25,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "bottom"
},
{
"pin": "B7",
"x": 0.25,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "bottom"
},
{
"pin": "B8",
"x": 0.75,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "bottom"
},
{
"pin": "B9",
"x": 1.25,
"y": -0.075,
"width": 0.25,
"height": 3.65,
"layer": "bottom"
},
{
"pin": "B10",
"x": 1.75,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "bottom"
},
{
"pin": "B11",
"x": 2.25,
"y": -0.175,
"width": 0.25,
"height": 3.45,
"layer": "bottom"
},
{
"pin": "B12",
"x": 2.75,
"y": 0.0,
"width": 0.25,
"height": 3.8,
"layer": "bottom"
}
];
const usbCEdgeProfile = [
{
"x": -4.445,
"y": -1.765
},
{
"x": -4.437499,
"y": -1.855527
},
{
"x": -4.415199,
"y": -1.943585
},
{
"x": -4.378711,
"y": -2.026771
},
{
"x": -4.329027,
"y": -2.102817
},
{
"x": -4.267505,
"y": -2.169648
},
{
"x": -4.195821,
"y": -2.225442
},
{
"x": -4.115932,
"y": -2.268675
},
{
"x": -4.030017,
"y": -2.29817
},
{
"x": -3.940419,
"y": -2.313121
},
{
"x": -3.849581,
"y": -2.313121
},
{
"x": -3.759983,
"y": -2.29817
},
{
"x": -3.674068,
"y": -2.268675
},
{
"x": -3.594179,
"y": -2.225442
},
{
"x": -3.522495,
"y": -2.169648
},
{
"x": -3.460973,
"y": -2.102817
},
{
"x": -3.411289,
"y": -2.026771
},
{
"x": -3.374801,
"y": -1.943585
},
{
"x": -3.352501,
"y": -1.855527
},
{
"x": -3.345,
"y": -1.765
},
{
"x": -3.345,
"y": -0.2
},
{
"x": -3.292906,
"y": -0.195442
},
{
"x": -3.242394,
"y": -0.181908
},
{
"x": -3.195,
"y": -0.159808
},
{
"x": -3.152164,
"y": -0.129813
},
{
"x": -3.115187,
"y": -0.092836
},
{
"x": -3.085192,
"y": -0.05
},
{
"x": -3.063092,
"y": -2606e-6
},
{
"x": -3.049558,
"y": 0.047906
},
{
"x": -3.045,
"y": 0.1
},
{
"x": -3.045,
"y": 1.0
},
{
"x": -3.049558,
"y": 1.052094
},
{
"x": -3.063092,
"y": 1.102606
},
{
"x": -3.085192,
"y": 1.15
},
{
"x": -3.115187,
"y": 1.192836
},
{
"x": -3.152164,
"y": 1.229813
},
{
"x": -3.195,
"y": 1.259808
},
{
"x": -3.242394,
"y": 1.281908
},
{
"x": -3.292906,
"y": 1.295442
},
{
"x": -3.345,
"y": 1.3
},
{
"x": -3.345,
"y": 1.8
},
{
"x": -3.045,
"y": 2.55
},
{
"x": 3.05,
"y": 2.55
},
{
"x": 3.35,
"y": 1.8
},
{
"x": 3.35,
"y": 1.3
},
{
"x": 3.297906,
"y": 1.295442
},
{
"x": 3.247394,
"y": 1.281908
},
{
"x": 3.2,
"y": 1.259808
},
{
"x": 3.157164,
"y": 1.229813
},
{
"x": 3.120187,
"y": 1.192836
},
{
"x": 3.090192,
"y": 1.15
},
{
"x": 3.068092,
"y": 1.102606
},
{
"x": 3.054558,
"y": 1.052094
},
{
"x": 3.05,
"y": 1.0
},
{
"x": 3.05,
"y": 0.1
},
{
"x": 3.054558,
"y": 0.047906
},
{
"x": 3.068092,
"y": -2606e-6
},
{
"x": 3.090192,
"y": -0.05
},
{
"x": 3.120187,
"y": -0.092836
},
{
"x": 3.157164,
"y": -0.129813
},
{
"x": 3.2,
"y": -0.159808
},
{
"x": 3.247394,
"y": -0.181908
},
{
"x": 3.297906,
"y": -0.195442
},
{
"x": 3.35,
"y": -0.2
},
{
"x": 3.35,
"y": -1.765
},
{
"x": 3.357501,
"y": -1.855527
},
{
"x": 3.379801,
"y": -1.943585
},
{
"x": 3.416289,
"y": -2.026771
},
{
"x": 3.465973,
"y": -2.102817
},
{
"x": 3.527495,
"y": -2.169648
},
{
"x": 3.599179,
"y": -2.225442
},
{
"x": 3.679068,
"y": -2.268675
},
{
"x": 3.764983,
"y": -2.29817
},
{
"x": 3.854581,
"y": -2.313121
},
{
"x": 3.945419,
"y": -2.313121
},
{
"x": 4.035017,
"y": -2.29817
},
{
"x": 4.120932,
"y": -2.268675
},
{
"x": 4.200821,
"y": -2.225442
},
{
"x": 4.272505,
"y": -2.169648
},
{
"x": 4.334027,
"y": -2.102817
},
{
"x": 4.383711,
"y": -2.026771
},
{
"x": 4.420199,
"y": -1.943585
},
{
"x": 4.442499,
"y": -1.855527
},
{
"x": 4.45,
"y": -1.765
}
];
// Each physical contact stays independent; aliases never short repeated signals.
const usbCEdgeConnectorPinLabels = {
pin1: ["A1", "GND_A1"],
pin2: ["A2", "TX1_P"],
pin3: ["A3", "TX1_N"],
pin4: ["A4", "VBUS_A4"],
pin5: ["A5", "CC1"],
pin6: ["A6", "DP_A6"],
pin7: ["A7", "DM_A7"],
pin8: ["A8", "SBU1"],
pin9: ["A9", "VBUS_A9"],
pin10: ["A10", "RX2_N"],
pin11: ["A11", "RX2_P"],
pin12: ["A12", "GND_A12"],
pin13: ["B1", "GND_B1"],
pin14: ["B2", "TX2_P"],
pin15: ["B3", "TX2_N"],
pin16: ["B4", "VBUS_B4"],
pin17: ["B5", "CC2"],
pin18: ["B6", "DP_B6"],
pin19: ["B7", "DM_B7"],
pin20: ["B8", "SBU2"],
pin21: ["B9", "VBUS_B9"],
pin22: ["B10", "RX1_N"],
pin23: ["B11", "RX1_P"],
pin24: ["B12", "GND_B12"],
};
const usbCEdgeConnectorGeometry = {
boardThickness: 0.6,
tipY: 2.55,
// Open edge profile from left to right, including the mating reliefs.
edgeProfile: usbCEdgeProfile,
};
/** 24-contact, shell-less USB-C receptacle tongue. A on top, B on bottom. */
function UsbCEdgeConnector(props) {
return (jsxRuntime.jsx("connector", { schWidth: 1.7, schHeight: 2.6, schPinArrangement: {
leftSide: { pins: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], direction: "top-to-bottom" },
rightSide: { pins: [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], direction: "top-to-bottom" },
}, ...props,
// An explicit component layer overrides every pad layer in this version
// of tscircuit. Leave it unset to preserve A/top and B/bottom contacts.
layer: undefined, doNotPlace: true, pinLabels: usbCEdgeConnectorPinLabels, footprint: jsxRuntime.jsx(EdgeContactFootprint, { pads: usbCEdgePads }) }));
}
// Adapted from vasya-zh/PCB-Edge-USB-connector-KiCad-library (GPL-3.0).
// Source commit: 909b6ed3d7b6456c385dab109aba96fdece8a3d9.
// KiCad coordinates mapped to insertion along +Y; arcs sampled at <=10 degrees.
const microUsbEdgePads = [
{
"pin": "1",
"x": -1.3,
"y": -0,
"width": 0.35,
"height": 2.7,
"layer": "top"
},
{
"pin": "2",
"x": -0.65,
"y": -0,
"width": 0.35,
"height": 2.7,
"layer": "top"
},
{
"pin": "3",
"x": -0,
"y": -0,
"width": 0.35,
"height": 2.7,
"layer": "top"
},
{
"pin": "4",
"x": 0.65,
"y": -0,
"width": 0.35,
"height": 2.7,
"layer": "top"
},
{
"pin": "5",
"x": 1.3,
"y": -0,
"width": 0.35,
"height": 2.7,
"layer": "top"
}
];
const microUsbEdgeProfile = [
{
"x": -3.905,
"y": 1.58
},
{
"x": -3.87027,
"y": 1.576961
},
{
"x": -3.836596,
"y": 1.567938
},
{
"x": -3.805,
"y": 1.553205
},
{
"x": -3.776443,
"y": 1.533209
},
{
"x": -3.751791,
"y": 1.508557
},
{
"x": -3.731795,
"y": 1.48
},
{
"x": -3.717062,
"y": 1.448404
},
{
"x": -3.708039,
"y": 1.41473
},
{
"x": -3.705,
"y": 1.38
},
{
"x": -3.705,
"y": -1.92
},
{
"x": -3.692688,
"y": -2.076435
},
{
"x": -3.656057,
"y": -2.229017
},
{
"x": -3.596007,
"y": -2.373991
},
{
"x": -3.514017,
"y": -2.507785
},
{
"x": -3.412107,
"y": -2.627107
},
{
"x": -3.292785,
"y": -2.729017
},
{
"x": -3.158991,
"y": -2.811007
},
{
"x": -3.014017,
"y": -2.871057
},
{
"x": -2.861435,
"y": -2.907688
},
{
"x": -2.705,
"y": -2.92
},
{
"x": -2.548565,
"y": -2.907688
},
{
"x": -2.395983,
"y": -2.871057
},
{
"x": -2.251009,
"y": -2.811007
},
{
"x": -2.117215,
"y": -2.729017
},
{
"x": -1.997893,
"y": -2.627107
},
{
"x": -1.895983,
"y": -2.507785
},
{
"x": -1.813993,
"y": -2.373991
},
{
"x": -1.753943,
"y": -2.229017
},
{
"x": -1.717312,
"y": -2.076435
},
{
"x": -1.705,
"y": -1.92
},
{
"x": -1.705,
"y": 1.38
},
{
"x": -1.701961,
"y": 1.41473
},
{
"x": -1.692938,
"y": 1.448404
},
{
"x": -1.678205,
"y": 1.48
},
{
"x": -1.658209,
"y": 1.508557
},
{
"x": -1.633557,
"y": 1.533209
},
{
"x": -1.605,
"y": 1.553205
},
{
"x": -1.573404,
"y": 1.567938
},
{
"x": -1.53973,
"y": 1.576961
},
{
"x": -1.505,
"y": 1.58
},
{
"x": 1.505,
"y": 1.58
},
{
"x": 1.53973,
"y": 1.576961
},
{
"x": 1.573404,
"y": 1.567938
},
{
"x": 1.605,
"y": 1.553205
},
{
"x": 1.633557,
"y": 1.533209
},
{
"x": 1.658209,
"y": 1.508557
},
{
"x": 1.678205,
"y": 1.48
},
{
"x": 1.692938,
"y": 1.448404
},
{
"x": 1.701961,
"y": 1.41473
},
{
"x": 1.705,
"y": 1.38
},
{
"x": 1.705,
"y": -1.92
},
{
"x": 1.717312,
"y": -2.076435
},
{
"x": 1.753943,
"y": -2.229017
},
{
"x": 1.813993,
"y": -2.373991
},
{
"x": 1.895983,
"y": -2.507785
},
{
"x": 1.997893,
"y": -2.627107
},
{
"x": 2.117215,
"y": -2.729017
},
{
"x": 2.251009,
"y": -2.811007
},
{
"x": 2.395983,
"y": -2.871057
},
{
"x": 2.548565,
"y": -2.907688
},
{
"x": 2.705,
"y": -2.92
},
{
"x": 2.861435,
"y": -2.907688
},
{
"x": 3.014017,
"y": -2.871057
},
{
"x": 3.158991,
"y": -2.811007
},
{
"x": 3.292785,
"y": -2.729017
},
{
"x": 3.412107,
"y": -2.627107
},
{
"x": 3.514017,
"y": -2.507785
},
{
"x": 3.596007,
"y": -2.373991
},
{
"x": 3.656057,
"y": -2.229017
},
{
"x": 3.692688,
"y": -2.076435
},
{
"x": 3.705,
"y": -1.92
},
{
"x": 3.705,
"y": 1.38
},
{
"x": 3.708039,
"y": 1.41473
},
{
"x": 3.717062,
"y": 1.448404
},
{
"x": 3.731795,
"y": 1.48
},
{
"x": 3.751791,
"y": 1.508557
},
{
"x": 3.776443,
"y": 1.533209
},
{
"x": 3.805,
"y": 1.553205
},
{
"x": 3.836596,
"y": 1.567938
},
{
"x": 3.87027,
"y": 1.576961
},
{
"x": 3.905,
"y": 1.58
}
];
const microUsbEdgeConnectorPinLabels = {
pin1: ["VBUS"],
pin2: ["DM", "D_MINUS"],
pin3: ["DP", "D_PLUS"],
pin4: ["ID"],
pin5: ["GND"],
};
const microUsbEdgeConnectorGeometry = {
boardThickness: 0.6,
tipY: 1.58,
edgeProfile: microUsbEdgeProfile,
};
/** Five-contact Micro-B receptacle tongue, top copper, mating toward +Y. */
function MicroUsbEdgeConnector(props) {
return (jsxRuntime.jsx("connector", { schWidth: 2.2, schHeight: 1.2, schPinArrangement: { rightSide: { pins: [1, 2, 3, 4, 5], direction: "top-to-bottom" } }, showPinAliases: true, ...props, layer: "top", doNotPlace: true, pinLabels: microUsbEdgeConnectorPinLabels, footprint: jsxRuntime.jsx(EdgeContactFootprint, { pads: microUsbEdgePads }) }));
}
const geometries = {
"usb-a": usbAEdgeConnectorGeometry,
"usb-c": usbCEdgeConnectorGeometry,
"micro-usb": microUsbEdgeConnectorGeometry,
};
/** Internal layout calculation shared by the wrapper and its geometry tests. */
function getUsbEdgeBoardLayout({ connector, width, height, edge = "top", offset = 0 }) {
if (![width, height, offset].every(Number.isFinite) || width <= 0 || height <= 0) {
throw new Error("USB edge board width and height must be positive millimetres; offset must be finite.");
}
const geometry = geometries[connector];
if (!geometry)
throw new Error(`Unknown USB edge connector: ${connector}`);
const rotations = { top: 0, left: 90, bottom: 180, right: 270 };
const rotation = rotations[edge];
if (rotation === undefined)
throw new Error(`Unknown board edge: ${edge}`);
const sideways = edge === "left" || edge === "right";
const localWidth = sideways ? height : width;
const localHeight = sideways ? width : height;
const localOffset = edge === "bottom" || edge === "right" ? -offset : offset;
const connectorY = localHeight / 2 - geometry.tipY;
const profile = geometry.edgeProfile.map(({ x, y }) => ({ x: x + localOffset, y: y + connectorY }));
if (profile.some(p => Math.abs(p.x) > localWidth / 2 - 0.2)) {
throw new Error("Connector profile does not fit this edge. Increase the board size or reduce offset (0.2 mm shoulder margin required).");
}
if (Math.min(...profile.map(p => p.y)) <= -localHeight / 2 + 0.2) {
throw new Error("Board is too short for the connector tongue and reliefs. Increase the board size.");
}
const rotate = ({ x, y }) => {
switch (edge) {
case "top": return { x, y };
case "left": return { x: -y, y: x };
case "bottom": return { x: -x, y: -y };
case "right": return { x: y, y: -x };
}
};
const position = rotate({ x: localOffset, y: connectorY });
return {
outline: [
{ x: -localWidth / 2, y: -localHeight / 2 },
{ x: -localWidth / 2, y: profile[0].y },
...profile,
{ x: localWidth / 2, y: profile[profile.length - 1].y },
{ x: localWidth / 2, y: -localHeight / 2 },
].map(rotate),
thickness: geometry.boardThickness,
minBoardEdgeClearance: connector === "usb-c" ? 0.15 : 0.2,
placement: { pcbX: position.x, pcbY: position.y, pcbRotation: rotation },
};
}
/** A rectangular carrier with one automatically shaped and placed USB edge connector. */
function UsbEdgeConnectorBoard(props) {
const { connector, connectorProps, width, height, edge, offset, children, ...boardProps } = props;
const layout = getUsbEdgeBoardLayout({ connector, width, height, edge, offset });
const contact = connector === "usb-a"
? jsxRuntime.jsx(UsbAEdgeConnector, { ...connectorProps, ...layout.placement })
: connector === "usb-c"
? jsxRuntime.jsx(UsbCEdgeConnector, { ...connectorProps, ...layout.placement })
: jsxRuntime.jsx(MicroUsbEdgeConnector, { ...connectorProps, ...layout.placement });
return (jsxRuntime.jsxs("board", { minBoardEdgeClearance: layout.minBoardEdgeClearance, ...boardProps, width: width, height: height, outline: layout.outline, thickness: layout.thickness, children: [contact, children] }));
}
exports.MicroUsbEdgeConnector = MicroUsbEdgeConnector;
exports.UsbAEdgeConnector = UsbAEdgeConnector;
exports.UsbCEdgeConnector = UsbCEdgeConnector;
exports.UsbEdgeConnectorBoard = UsbEdgeConnectorBoard;
exports.default = UsbAEdgeConnector;
exports.microUsbEdgeConnectorGeometry = microUsbEdgeConnectorGeometry;
exports.microUsbEdgeConnectorPinLabels = microUsbEdgeConnectorPinLabels;
exports.usbAEdgeConnectorGeometry = usbAEdgeConnectorGeometry;
exports.usbAEdgeConnectorPinLabels = usbAEdgeConnectorPinLabels;
exports.usbCEdgeConnectorGeometry = usbCEdgeConnectorGeometry;
exports.usbCEdgeConnectorPinLabels = usbCEdgeConnectorPinLabels;