const WIRE_COLORS = [ { name: "Black", hex: "#000000" }, { name: "Brown", hex: "#8B4513" }, { name: "Red", hex: "#CC0000" }, { name: "Orange", hex: "#FF8C00" }, { name: "Yellow", hex: "#FFD700" }, { name: "Green", hex: "#007700" }, { name: "Blue", hex: "#0000CC" }, { name: "Violet", hex: "#7B00CC" }, { name: "Grey", hex: "#808080" }, { name: "White", hex: "#DDDDDD" }, { name: "Pink", hex: "#FF69B4" }, { name: "Tan", hex: "#D2B48C" }, ]; const SIDE = { LEFT: "left", RIGHT: "right", TOP: "top", BOTTOM: "bottom" }; function makePins(side, count, w, h, prefix = "") { return Array.from({ length: count }, (_, i) => { const t = (i + 1) / (count + 1); const x = side === SIDE.LEFT ? 0 : side === SIDE.RIGHT ? w : t * w; const y = side === SIDE.TOP ? 0 : side === SIDE.BOTTOM ? h : t * h; return { id: `${prefix}pin_${i + 1}`, name: String(i + 1), side, x_offset: x, y_offset: y }; }); } const DEVICE_TYPES = { connector: { label: "Connector", description: "Multi-pin connector (inline/header)", icon: "🔌", defaultProps: { pinCount: 4, orientation: "right", partNumber: "", manufacturer: "" }, defaultSize: (p) => ({ w: 100, h: Math.max(60, (p.pinCount || 4) * 20 + 20) }), getPins: (p, w, h) => makePins(p.orientation || SIDE.RIGHT, p.pinCount || 4, w, h), }, terminal_block: { label: "Terminal Block", description: "Screw terminal block", icon: "⬛", defaultProps: { terminalCount: 4, partNumber: "", manufacturer: "" }, defaultSize: (p) => ({ w: Math.max(60, (p.terminalCount || 4) * 24), h: 60 }), getPins: (p, w, h) => { const count = p.terminalCount || 4; const pins = []; for (let i = 0; i < count; i++) { const x = ((i + 0.5) / count) * w; pins.push({ id: `t${i + 1}`, name: String(i + 1), side: SIDE.TOP, x_offset: x, y_offset: 0 }); pins.push({ id: `b${i + 1}`, name: String(i + 1), side: SIDE.BOTTOM, x_offset: x, y_offset: h }); } return pins; }, }, component: { label: "Component", description: "Generic component / IC", icon: "⬜", defaultProps: { leftPins: 2, rightPins: 2, partNumber: "", manufacturer: "" }, defaultSize: () => ({ w: 120, h: 80 }), getPins: (p, w, h) => { const left = makePins(SIDE.LEFT, p.leftPins || 2, w, h, "L"); const right = makePins(SIDE.RIGHT, p.rightPins || 2, w, h, "R"); left.forEach((pin, i) => (pin.name = `L${i + 1}`)); right.forEach((pin, i) => (pin.name = `R${i + 1}`)); return [...left, ...right]; }, }, splice: { label: "Splice / Junction", description: "Wire splice or junction point", icon: "✕", defaultProps: {}, defaultSize: () => ({ w: 32, h: 32 }), getPins: (p, w, h) => [ { id: "left", name: "L", side: SIDE.LEFT, x_offset: 0, y_offset: h / 2 }, { id: "right", name: "R", side: SIDE.RIGHT, x_offset: w, y_offset: h / 2 }, { id: "top", name: "T", side: SIDE.TOP, x_offset: w / 2, y_offset: 0 }, { id: "bottom", name: "B", side: SIDE.BOTTOM, x_offset: w / 2, y_offset: h }, ], }, label: { label: "Note / Label", description: "Text annotation on the diagram", icon: "📝", defaultProps: { text: "Note" }, defaultSize: () => ({ w: 160, h: 40 }), getPins: () => [], }, group: { label: "Section Box", description: "Labeled section rectangle for visual grouping", icon: "⬚", defaultProps: { fillColor: "#2828a0", fillOpacity: 0.15 }, defaultSize: () => ({ w: 320, h: 220 }), getPins: () => [], }, // ── Electrical components ─────────────────────────────────────────────────── fuse: { label: "Fuse", description: "In-line fuse or fusible link", icon: "⚡", defaultProps: { ampRating: "10A", fuseType: "blade", partNumber: "", manufacturer: "" }, defaultSize: () => ({ w: 80, h: 44 }), getPins: (p, w, h) => [ { id: "A", name: "A", side: SIDE.LEFT, x_offset: 0, y_offset: h / 2 }, { id: "B", name: "B", side: SIDE.RIGHT, x_offset: w, y_offset: h / 2 }, ], }, relay: { label: "Relay", description: "Electromagnetic relay — SPDT 5-pin (85/86/30/87/87a)", icon: "🔁", defaultProps: { coilVoltage: "12V", ampRating: "30A", partNumber: "", manufacturer: "" }, defaultSize: () => ({ w: 110, h: 100 }), getPins: (p, w, h) => [ { id: "85", name: "85", side: SIDE.LEFT, x_offset: 0, y_offset: h * 0.30 }, { id: "86", name: "86", side: SIDE.LEFT, x_offset: 0, y_offset: h * 0.70 }, { id: "87a", name: "87a", side: SIDE.RIGHT, x_offset: w, y_offset: h * 0.20 }, { id: "30", name: "30", side: SIDE.RIGHT, x_offset: w, y_offset: h * 0.50 }, { id: "87", name: "87", side: SIDE.RIGHT, x_offset: w, y_offset: h * 0.80 }, ], }, switch: { label: "Switch", description: "SPDT switch — common, normally-open, normally-closed", icon: "⎘", defaultProps: { switchType: "SPDT", partNumber: "", manufacturer: "" }, defaultSize: () => ({ w: 90, h: 70 }), getPins: (p, w, h) => [ { id: "C", name: "C", side: SIDE.LEFT, x_offset: 0, y_offset: h / 2 }, { id: "NO", name: "NO", side: SIDE.RIGHT, x_offset: w, y_offset: h * 0.30 }, { id: "NC", name: "NC", side: SIDE.RIGHT, x_offset: w, y_offset: h * 0.70 }, ], }, bulb: { label: "Bulb / Light", description: "Indicator lamp or lighting load", icon: "💡", defaultProps: { voltage: "12V", wattage: "", partNumber: "", manufacturer: "" }, defaultSize: () => ({ w: 80, h: 50 }), getPins: (p, w, h) => [ { id: "+", name: "+", side: SIDE.LEFT, x_offset: 0, y_offset: h / 2 }, { id: "-", name: "−", side: SIDE.RIGHT, x_offset: w, y_offset: h / 2 }, ], }, motor: { label: "Motor", description: "DC motor or actuator", icon: "⚙", defaultProps: { voltage: "12V", ampRating: "", partNumber: "", manufacturer: "" }, defaultSize: () => ({ w: 90, h: 60 }), getPins: (p, w, h) => [ { id: "+", name: "+", side: SIDE.LEFT, x_offset: 0, y_offset: h / 2 }, { id: "-", name: "−", side: SIDE.RIGHT, x_offset: w, y_offset: h / 2 }, ], }, diode: { label: "Diode", description: "Diode, Schottky, or TVS — anode / cathode", icon: "⊳", defaultProps: { diodeType: "rectifier", voltage: "", current: "", partNumber: "", manufacturer: "" }, defaultSize: () => ({ w: 80, h: 44 }), getPins: (p, w, h) => [ { id: "A", name: "A", side: SIDE.LEFT, x_offset: 0, y_offset: h / 2 }, { id: "K", name: "K", side: SIDE.RIGHT, x_offset: w, y_offset: h / 2 }, ], }, resistor: { label: "Resistor", description: "Fixed resistor or load", icon: "Ω", defaultProps: { resistance: "", wattage: "", partNumber: "", manufacturer: "" }, defaultSize: () => ({ w: 80, h: 44 }), getPins: (p, w, h) => [ { id: "1", name: "1", side: SIDE.LEFT, x_offset: 0, y_offset: h / 2 }, { id: "2", name: "2", side: SIDE.RIGHT, x_offset: w, y_offset: h / 2 }, ], }, capacitor: { label: "Capacitor", description: "Electrolytic or film capacitor", icon: "⊏", defaultProps: { capacitance: "", voltage: "", partNumber: "", manufacturer: "" }, defaultSize: () => ({ w: 80, h: 44 }), getPins: (p, w, h) => [ { id: "+", name: "+", side: SIDE.LEFT, x_offset: 0, y_offset: h / 2 }, { id: "-", name: "−", side: SIDE.RIGHT, x_offset: w, y_offset: h / 2 }, ], }, ground: { label: "Ground", description: "Chassis or signal ground reference", icon: "⏚", defaultProps: { groundType: "chassis", reference: "" }, defaultSize: () => ({ w: 60, h: 50 }), getPins: (p, w, h) => [ { id: "GND", name: "GND", side: SIDE.TOP, x_offset: w / 2, y_offset: 0 }, ], }, power: { label: "Power Rail", description: "Battery positive, ignition, or supply rail", icon: "⊕", defaultProps: { voltage: "12V", sourceType: "battery", reference: "" }, defaultSize: () => ({ w: 70, h: 50 }), getPins: (p, w, h) => [ { id: "PWR", name: "+", side: SIDE.BOTTOM, x_offset: w / 2, y_offset: h }, ], }, }; const CABLE_DEFAULT_COLORS = [ "#dddddd", "#cc0000", "#111111", "#007700", "#0000cc", "#ff8c00", "#8b4513", "#7b00cc", ]; const DEVICE_TYPES_EXTRA = { cable: { label: "Cable", description: "Multi-conductor cable under one jacket", icon: "🔗", defaultProps: { conductorCount: 4, partNumber: "", manufacturer: "", jacketColor: "#2a2a2a", sleeveLength: 60, conductors: [ { name: "1", color: "#dddddd" }, { name: "2", color: "#cc0000" }, { name: "3", color: "#111111" }, { name: "4", color: "#007700" }, ], }, defaultSize: (p) => { const n = p.conductorCount || p.conductors?.length || 4; return { w: 200, h: n * 24 + 40 }; }, getPins: (p, w, h) => { const conductors = p.conductors || Array.from({ length: p.conductorCount || 4 }, (_, i) => ({ name: String(i + 1) })); return conductors.flatMap((c, i) => { const yOff = 26 + i * 24 + 12; return [ { id: `L${i + 1}`, name: c.name || String(i + 1), side: "left", x_offset: 0, y_offset: yOff }, { id: `R${i + 1}`, name: c.name || String(i + 1), side: "right", x_offset: w, y_offset: yOff }, ]; }); }, }, }; Object.assign(DEVICE_TYPES, DEVICE_TYPES_EXTRA); function buildDefaultDevice(typeKey, diagramId) { const type = DEVICE_TYPES[typeKey]; if (!type) return null; const props = { ...type.defaultProps }; const { w, h } = type.defaultSize(props); const pins = type.getPins(props, w, h); return { diagram_id: diagramId, device_type: typeKey, label: type.label, reference: "", x: 200, y: 200, width: w, height: h, properties: props, pins, }; }