feat: add local custom elements for capacitor and inductor, enhancing SPICE simulation support

This commit is contained in:
David Montero Crespo 2026-04-21 13:50:45 -03:00
parent a1d3179e1c
commit 7bdbac9f83
4 changed files with 125 additions and 2 deletions

View File

@ -17,9 +17,12 @@ import { useSimulatorStore } from '../store/useSimulatorStore';
import { PartSimulationRegistry } from '../simulation/parts';
import { isBoardComponent, boardPinToNumber } from '../utils/boardPinMapping';
// Side-effect import: registers ALL wokwi custom elements (including new ones
// like wokwi-capacitor, wokwi-inductor) so document.createElement() works.
// Side-effect imports: register every web component we'll create at runtime.
// `@wokwi/elements` covers the upstream catalog; `../wokwi-custom` adds the
// velxio-local elements (e.g. <wokwi-capacitor>, <wokwi-inductor>) that we
// can't push back to the upstream wokwi-elements repo.
import '@wokwi/elements';
import '../wokwi-custom';
interface DynamicComponentProps {
id: string;

View File

@ -0,0 +1,50 @@
/**
* <wokwi-capacitor> local replacement for the upstream wokwi-elements
* version. Kept inside velxio because we cannot push the original Lit
* sources to wokwi/wokwi-elements.
*
* Plain HTMLElement (no Lit) the SVG is static and `value` is read by
* the SPICE layer from the simulator store, not from this DOM node, so
* we don't need reactive rendering.
*/
interface ElementPin {
name: string;
x: number;
y: number;
signals: unknown[];
}
const SVG = `
<svg width="15.645mm" height="3mm" version="1.1"
viewBox="0 0 15.645 3" xmlns="http://www.w3.org/2000/svg">
<rect y="1.175" width="15.558" height="0.638" fill="#aaa" />
<ellipse cx="7.82" cy="1.5" rx="3.2" ry="1.5" fill="#165696" />
<ellipse cx="6.8" cy="0.9" rx="1.0" ry="0.55" fill="#3a7cc8" opacity="0.5" />
</svg>`;
export class CapacitorElement extends HTMLElement {
static observedAttributes = ['value'];
readonly pinInfo: ElementPin[] = [
{ name: '1', x: 0, y: 5.65, signals: [] },
{ name: '2', x: 58.8, y: 5.65, signals: [] },
];
constructor() {
super();
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = `<style>:host{display:flex}</style>${SVG}`;
}
get value(): string {
return this.getAttribute('value') ?? '1u';
}
set value(v: string) {
this.setAttribute('value', String(v));
}
}
if (!customElements.get('wokwi-capacitor')) {
customElements.define('wokwi-capacitor', CapacitorElement);
}

View File

@ -0,0 +1,18 @@
/**
* Velxio-local custom elements.
*
* These are wokwi-style web components that live IN this project rather
* than in the upstream `@wokwi/elements` package useful when we don't
* have push access to wokwi/wokwi-elements but still need to ship new
* parts (e.g. `<wokwi-capacitor>`, `<wokwi-inductor>` for SPICE).
*
* Side-effect import: each module calls `customElements.define(...)` at
* load time (guarded against double-registration), so a single
* `import './wokwi-custom';` is enough to make the tags resolvable.
*/
import './capacitor-element';
import './inductor-element';
export { CapacitorElement } from './capacitor-element';
export { InductorElement } from './inductor-element';

View File

@ -0,0 +1,52 @@
/**
* <wokwi-inductor> local replacement for the upstream wokwi-elements
* version. Kept inside velxio because we cannot push the original Lit
* sources to wokwi/wokwi-elements.
*
* Plain HTMLElement (no Lit) the SVG is static and `value` is read by
* the SPICE layer from the simulator store, not from this DOM node.
*/
interface ElementPin {
name: string;
x: number;
y: number;
signals: unknown[];
}
const SVG = `
<svg width="15.645mm" height="3mm" version="1.1"
viewBox="0 0 15.645 3" xmlns="http://www.w3.org/2000/svg">
<rect y="1.175" width="15.558" height="0.638" fill="#aaa" />
<path d="M4.7,1.5 C5.2,0 6.0,0 6.5,1.5 C7.0,3 7.8,3 8.3,1.5 C8.8,0 9.6,0 10.1,1.5 C10.6,3 11.4,3 11.0,1.5"
fill="none" stroke="#B23820" stroke-width="0.5" stroke-linecap="round" />
<rect x="4.5" y="0.15" width="6.7" height="2.7" rx="0.6" fill="#752119" opacity="0.7" />
<path d="M4.7,1.5 C5.2,-0.2 6.0,-0.2 6.5,1.5 C7.0,3.2 7.8,3.2 8.3,1.5 C8.8,-0.2 9.6,-0.2 10.1,1.5 C10.6,3.2 11.4,3.2 11.0,1.5"
fill="none" stroke="#B23820" stroke-width="0.45" stroke-linecap="round" />
</svg>`;
export class InductorElement extends HTMLElement {
static observedAttributes = ['value'];
readonly pinInfo: ElementPin[] = [
{ name: '1', x: 0, y: 5.65, signals: [] },
{ name: '2', x: 58.8, y: 5.65, signals: [] },
];
constructor() {
super();
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = `<style>:host{display:flex}</style>${SVG}`;
}
get value(): string {
return this.getAttribute('value') ?? '1m';
}
set value(v: string) {
this.setAttribute('value', String(v));
}
}
if (!customElements.get('wokwi-inductor')) {
customElements.define('wokwi-inductor', InductorElement);
}