@simten/embed 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +167 -0
  3. package/dist/CircuitEmbed.d.ts +92 -0
  4. package/dist/CircuitEmbed.d.ts.map +1 -0
  5. package/dist/CircuitEmbed.js +104 -0
  6. package/dist/CircuitEmbed.js.map +1 -0
  7. package/dist/CircuitViewer.d.ts +100 -0
  8. package/dist/CircuitViewer.d.ts.map +1 -0
  9. package/dist/CircuitViewer.js +76 -0
  10. package/dist/CircuitViewer.js.map +1 -0
  11. package/dist/canvas/index.d.ts +6 -0
  12. package/dist/canvas/index.d.ts.map +1 -0
  13. package/dist/canvas/index.js +5 -0
  14. package/dist/canvas/index.js.map +1 -0
  15. package/dist/circuit-embed.js +79 -0
  16. package/dist/components/ErrorBoundary.d.ts +23 -0
  17. package/dist/components/ErrorBoundary.d.ts.map +1 -0
  18. package/dist/components/ErrorBoundary.js +34 -0
  19. package/dist/components/ErrorBoundary.js.map +1 -0
  20. package/dist/components/ErrorDisplay.d.ts +18 -0
  21. package/dist/components/ErrorDisplay.d.ts.map +1 -0
  22. package/dist/components/ErrorDisplay.js +24 -0
  23. package/dist/components/ErrorDisplay.js.map +1 -0
  24. package/dist/components/LoadingSkeleton.d.ts +11 -0
  25. package/dist/components/LoadingSkeleton.d.ts.map +1 -0
  26. package/dist/components/LoadingSkeleton.js +10 -0
  27. package/dist/components/LoadingSkeleton.js.map +1 -0
  28. package/dist/components/nodes/index.d.ts +7 -0
  29. package/dist/components/nodes/index.d.ts.map +1 -0
  30. package/dist/components/nodes/index.js +7 -0
  31. package/dist/components/nodes/index.js.map +1 -0
  32. package/dist/hooks/useCircuitSimulator.d.ts +95 -0
  33. package/dist/hooks/useCircuitSimulator.d.ts.map +1 -0
  34. package/dist/hooks/useCircuitSimulator.js +568 -0
  35. package/dist/hooks/useCircuitSimulator.js.map +1 -0
  36. package/dist/index.d.ts +13 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +8 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/lib/utils.d.ts +3 -0
  41. package/dist/lib/utils.d.ts.map +1 -0
  42. package/dist/lib/utils.js +6 -0
  43. package/dist/lib/utils.js.map +1 -0
  44. package/dist/share-context.d.ts +18 -0
  45. package/dist/share-context.d.ts.map +1 -0
  46. package/dist/share-context.js +10 -0
  47. package/dist/share-context.js.map +1 -0
  48. package/dist/styles.css +1 -0
  49. package/dist/types.d.ts +30 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +6 -0
  52. package/dist/types.js.map +1 -0
  53. package/dist/webcomponent/WebComponentEmbed.d.ts +24 -0
  54. package/dist/webcomponent/WebComponentEmbed.d.ts.map +1 -0
  55. package/dist/webcomponent/WebComponentEmbed.js +61 -0
  56. package/dist/webcomponent/WebComponentEmbed.js.map +1 -0
  57. package/dist/webcomponent/index.d.ts +19 -0
  58. package/dist/webcomponent/index.d.ts.map +1 -0
  59. package/dist/webcomponent/index.js +38 -0
  60. package/dist/webcomponent/index.js.map +1 -0
  61. package/package.json +85 -0
package/LICENSE ADDED
@@ -0,0 +1,176 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for describing the origin of the Work and
141
+ reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Support. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or support.
175
+
176
+ END OF TERMS AND CONDITIONS
package/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # @simten/embed
2
+
3
+ Embeddable interactive hardware circuits. Drop live, cycle-accurate simulations into any React app.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @simten/embed @simten/core
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### CircuitEmbed — read-only interactive viewer
14
+
15
+ ```tsx
16
+ import '@simten/embed/styles.css'
17
+ import { CircuitEmbed } from '@simten/embed'
18
+ import { circuit, bit } from '@simten/core/circuit'
19
+ import { Xor, And } from '@simten/core/std'
20
+
21
+ const HalfAdder = circuit('HalfAdder', {
22
+ inputs: { a: bit, b: bit },
23
+ outputs: { sum: bit, carry: bit },
24
+ nodes: { xor1: Xor, and1: And },
25
+ connect: ({ inputs, outputs, nodes: { xor1, and1 } }) => [
26
+ inputs.a.to(xor1.a, and1.a),
27
+ inputs.b.to(xor1.b, and1.b),
28
+ xor1.out.to(outputs.sum),
29
+ and1.out.to(outputs.carry),
30
+ ],
31
+ })
32
+
33
+ function App() {
34
+ return <CircuitEmbed circuit={HalfAdder} height={300} />
35
+ }
36
+ ```
37
+
38
+ The circuit compiles, simulates, and renders in the browser. Users can toggle switches, see values propagate, and interact with the simulation.
39
+
40
+ ### useCircuitSimulator — custom layouts
41
+
42
+ ```tsx
43
+ import { useCircuitSimulator } from '@simten/embed'
44
+ import { circuit, bit } from '@simten/core/circuit'
45
+ import { Xor, And } from '@simten/core/std'
46
+
47
+ const HalfAdder = circuit('HalfAdder', {
48
+ inputs: { a: bit, b: bit },
49
+ outputs: { sum: bit, carry: bit },
50
+ nodes: { xor1: Xor, and1: And },
51
+ connect: ({ inputs, outputs, nodes: { xor1, and1 } }) => [
52
+ inputs.a.to(xor1.a, and1.a),
53
+ inputs.b.to(xor1.b, and1.b),
54
+ xor1.out.to(outputs.sum),
55
+ and1.out.to(outputs.carry),
56
+ ],
57
+ })
58
+
59
+ function MyComponent() {
60
+ const sim = useCircuitSimulator(HalfAdder)
61
+
62
+ // sim.ready, sim.error, sim.circuit
63
+ // sim.inputs, sim.outputs, sim.portValues
64
+ // sim.setNode(), sim.toggleNode(), sim.tick(), sim.reset()
65
+ }
66
+ ```
67
+
68
+ Build your own UI around the simulator. Each hook instance has its own isolated component library — multiple embeds on the same page won't interfere.
69
+
70
+ ## Props
71
+
72
+ ### CircuitEmbed
73
+
74
+ | Prop | Type | Default | Description |
75
+ |------|------|---------|-------------|
76
+ | `circuit` | `BuiltCircuit` | required | Circuit definition (result of `circuit()`) |
77
+ | `height` | `number \| string` | `300` | Component height |
78
+ | `showControls` | `boolean` | `true` | Show tick/auto/reset for sequential circuits |
79
+ | `title` | `string` | — | Header title |
80
+ | `description` | `string` | — | Header subtitle |
81
+ | `focus` | `string \| string[]` | — | Highlight specific nodes, dim others |
82
+ | `layout` | `CircuitLayout<C>` | — | Pre-computed positions, keyed by node label or id. Bypasses the runtime layout engine. Keys are constrained at compile time to the circuit's input/output/node names. |
83
+ | `initialInputs` | `Record<string, number \| boolean>` | — | Set initial input values |
84
+ | `autoRunSpeed` | `number` | `500` | Auto-run interval in ms |
85
+ | `showPortLabels` | `boolean` | — | Show port labels on nodes |
86
+ | `glowUnconnected` | `boolean` | — | Highlight unconnected ports |
87
+ | `theme` | `"light" \| "dark"` | — | Force a color theme |
88
+
89
+ ## How it works
90
+
91
+ 1. The `BuiltCircuit` is elaborated (composites flattened to primitives)
92
+ 2. A simulator engine evaluates the netlist
93
+ 3. ReactFlow renders the circuit as interactive nodes and edges
94
+ 4. The layout engine computes positions when no `layout` prop is provided (lazy-loaded, SSR-safe)
95
+
96
+ Each `useCircuitSimulator` call creates its own component library instance. Sub-circuits are registered into that instance during elaboration. No global state is shared between embeds.
97
+
98
+ ## Type-safe layouts
99
+
100
+ `CircuitLayout<C>` constrains keys to the circuit's actual port/node names at compile time:
101
+
102
+ ```tsx
103
+ import { circuit, bit } from '@simten/core/circuit'
104
+ import { CircuitEmbed, type CircuitLayout } from '@simten/embed'
105
+
106
+ const HalfAdder = circuit('HalfAdder', {
107
+ inputs: { a: bit, b: bit },
108
+ outputs: { sum: bit, carry: bit },
109
+ nodes: { xor1: Xor, and1: And },
110
+ connect: /* ... */
111
+ })
112
+
113
+ // TS infers the valid keys: a | b | sum | carry | xor1 | and1
114
+ const halfAdderLayout: CircuitLayout<typeof HalfAdder> = {
115
+ a: { x: 0, y: 0 },
116
+ b: { x: 0, y: 80 },
117
+ xor1: { x: 200, y: 0 },
118
+ and1: { x: 200, y: 100 },
119
+ // typo: { x: 1, y: 1 } // TS error: not a valid key
120
+ }
121
+
122
+ <CircuitEmbed circuit={HalfAdder} layout={halfAdderLayout} />
123
+ ```
124
+
125
+ In dev mode, a runtime warning also fires if `layout` keys don't match the circuit's nodes — useful for circuits compiled at runtime via the web component path where TS can't help.
126
+
127
+ ## CSS
128
+
129
+ The package ships compiled CSS at `dist/styles.css`. All classes are prefixed with `ti-` to avoid collisions with host app styles.
130
+
131
+ ```tsx
132
+ import '@simten/embed/styles.css'
133
+ ```
134
+
135
+ No Tailwind configuration required in the consuming app.
136
+
137
+ ## Server-side rendering (SSR)
138
+
139
+ All embed components include `"use client"` directives and are compatible with React server component frameworks.
140
+
141
+ ### Next.js App Router
142
+
143
+ Components work directly — the `"use client"` boundary is automatic.
144
+
145
+ ### Next.js Pages Router
146
+
147
+ ```tsx
148
+ import dynamic from 'next/dynamic'
149
+
150
+ const CircuitEmbed = dynamic(
151
+ () => import('@simten/embed').then(m => m.CircuitEmbed),
152
+ { ssr: false }
153
+ )
154
+ ```
155
+
156
+ ### What happens during SSR
157
+
158
+ Components are skipped on the server and render only on the client. The layout engine uses `dynamic import()` so it is never loaded on the server. If you pass a `layout` prop, the engine isn't loaded at all — positions are applied directly.
159
+
160
+ ## Requirements
161
+
162
+ - React 18 or 19
163
+ - A bundler that supports ESM (Vite, Next.js, etc.)
164
+
165
+ ## License
166
+
167
+ Business Source License 1.1
@@ -0,0 +1,92 @@
1
+ /**
2
+ * CircuitEmbed — embeddable circuit viewer with optional info bar.
3
+ *
4
+ * Thin wrapper around CircuitViewer that adds:
5
+ * - Auto-harness (wraps bare circuits with Switch/Led nodes)
6
+ * - Info bar (title, subtitle, description, link)
7
+ *
8
+ * For React users: pass a BuiltCircuit object.
9
+ * For web component users: <circuit-embed code="..."> goes through the
10
+ * web component bridge which sandboxes compilation via an iframe.
11
+ */
12
+ import { type ForwardedRef, type ReactElement } from "react";
13
+ import { type CircuitViewerHandle, type HarnessedLayout } from "./CircuitViewer";
14
+ import { type BuiltCircuit } from "@simten/core/circuit";
15
+ import type { FlatPortValueMap } from "@simten/core/simulator";
16
+ export interface CircuitEmbedProps<C extends BuiltCircuit = BuiltCircuit> {
17
+ /** The circuit to display (result of circuit()) */
18
+ circuit: C;
19
+ /**
20
+ * Container height. Optional — when omitted, the embed sizes itself
21
+ * width-responsively using `aspectRatio` (or one inferred from `layout`)
22
+ * with sensible mobile-friendly min/max clamps.
23
+ */
24
+ height?: number | string;
25
+ /**
26
+ * Width-to-height ratio of the embed. Used only when `height` is not set.
27
+ * If omitted and `layout` is passed, the ratio is computed from the
28
+ * layout's bounding box. Otherwise defaults to 1.5 (3:2).
29
+ */
30
+ aspectRatio?: number;
31
+ /** Show clock controls for sequential circuits */
32
+ showControls?: boolean;
33
+ /**
34
+ * Pre-computed node positions. Keys are constrained to the circuit's
35
+ * input names, output names, and node labels at compile time.
36
+ * Pass to bypass the runtime layout engine.
37
+ */
38
+ layout?: HarnessedLayout<C>;
39
+ /** Theme */
40
+ theme?: "light" | "dark";
41
+ /** Title shown in bottom bar */
42
+ title?: string;
43
+ /** Subtitle shown next to title */
44
+ subtitle?: string;
45
+ /** Description shown below title */
46
+ description?: string;
47
+ /**
48
+ * Custom URL for the card's right-side link. When omitted (the common case),
49
+ * a Fork button is rendered that opens the circuit in the simten.dev editor
50
+ * via `/circuit/<lz-encoded-source>`. Pass `href` only to override.
51
+ */
52
+ href?: string;
53
+ /**
54
+ * Optional raw TypeScript source for the Fork button. When provided, the
55
+ * Fork button encodes this verbatim instead of running the BuiltCircuit
56
+ * through the IR-to-source serializer (which drops comments and helpers).
57
+ * The web-component path passes the user's original `code` here.
58
+ */
59
+ forkSource?: string;
60
+ /** Focus on specific node(s) */
61
+ focus?: string | string[];
62
+ /** Show port labels on nodes */
63
+ showPortLabels?: boolean;
64
+ /** Callback when a port is clicked */
65
+ onPortClick?: (nodeLabel: string, portName: string, portType: "input" | "output") => void;
66
+ /** Highlight unconnected ports */
67
+ glowUnconnected?: boolean;
68
+ /** Auto-run speed (ms between ticks) */
69
+ autoRunSpeed?: number;
70
+ /** Initial values for input ports (set on harness Switch/Input nodes) */
71
+ initialInputs?: Record<string, number | boolean>;
72
+ /**
73
+ * Called when the embed's internal simulator settles on a new set of
74
+ * port values — once on first settle, then on every subsequent settled
75
+ * change (e.g. when the user toggles a switch on the canvas). Forwarded
76
+ * verbatim to CircuitViewer; see its docs for full firing semantics.
77
+ *
78
+ * Use this to drive sibling UI (truth-table highlights, external value
79
+ * readouts) without giving up the embed's chrome. The callback is
80
+ * ref-stabilized inside the embed, so inline functions are safe.
81
+ */
82
+ onPortValuesChange?: (portValues: FlatPortValueMap) => void;
83
+ }
84
+ export type CircuitEmbedHandle = CircuitViewerHandle;
85
+ /**
86
+ * CircuitEmbed component with generic inference over the circuit type.
87
+ * Cast preserves the generic so `layout` keys are constrained at compile time.
88
+ */
89
+ export declare const CircuitEmbed: <C extends BuiltCircuit>(props: CircuitEmbedProps<C> & {
90
+ ref?: ForwardedRef<CircuitEmbedHandle>;
91
+ }) => ReactElement;
92
+ //# sourceMappingURL=CircuitEmbed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CircuitEmbed.d.ts","sourceRoot":"","sources":["../src/CircuitEmbed.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAA4C,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AACvG,OAAO,EAAiB,KAAK,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAChG,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAgB/D,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY;IACtE,mDAAmD;IACnD,OAAO,EAAE,CAAC,CAAC;IACX;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;IAC5B,YAAY;IACZ,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,gCAAgC;IAChC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,sCAAsC;IACtC,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,QAAQ,KAAK,IAAI,CAAC;IAC1F,kCAAkC;IAClC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;IACjD;;;;;;;;;OASG;IACH,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAC7D;AAED,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AAkJrD;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAuB,CAAC,CAAC,SAAS,YAAY,EACrE,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,YAAY,CAAC,kBAAkB,CAAC,CAAA;CAAE,KACrE,YAAY,CAAC"}
@@ -0,0 +1,104 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * CircuitEmbed — embeddable circuit viewer with optional info bar.
4
+ *
5
+ * Thin wrapper around CircuitViewer that adds:
6
+ * - Auto-harness (wraps bare circuits with Switch/Led nodes)
7
+ * - Info bar (title, subtitle, description, link)
8
+ *
9
+ * For React users: pass a BuiltCircuit object.
10
+ * For web component users: <circuit-embed code="..."> goes through the
11
+ * web component bridge which sandboxes compilation via an iframe.
12
+ */
13
+ import { forwardRef, useState } from "react";
14
+ import { CircuitViewer } from "./CircuitViewer";
15
+ import { circuitToSource } from "@simten/core/circuit";
16
+ import { encodeSourceForUrl } from "@simten/ui/share";
17
+ import { useShareCircuit } from "./share-context";
18
+ /**
19
+ * Where Fork links open. simten.dev for everything except local dev of the
20
+ * embed itself (where the embed is mounted at localhost). Detected at runtime
21
+ * because the embed runs on third-party origins we don't control at build time.
22
+ */
23
+ function simtenHost() {
24
+ if (typeof window === "undefined")
25
+ return "https://simten.dev";
26
+ return window.location.hostname === "localhost"
27
+ ? window.location.origin
28
+ : "https://simten.dev";
29
+ }
30
+ // Approximate node footprint used when inferring aspect ratio from a layout.
31
+ // Layout coords are top-left of each node, so we add ~one node's width/height
32
+ // to the bounding box so the rightmost / bottommost nodes aren't clipped.
33
+ const NODE_W = 160;
34
+ const NODE_H = 90;
35
+ function inferAspectFromLayout(layout) {
36
+ if (!layout)
37
+ return 1.5; // default 3:2 — sane for auto-laid-out circuits
38
+ const positions = Object.values(layout);
39
+ if (positions.length === 0)
40
+ return 1.5;
41
+ const w = Math.max(...positions.map(p => p.x)) + NODE_W;
42
+ const h = Math.max(...positions.map(p => p.y)) + NODE_H;
43
+ if (w <= 0 || h <= 0)
44
+ return 1.5;
45
+ return w / h;
46
+ }
47
+ const CircuitEmbedImpl = forwardRef(function CircuitEmbed({ circuit, height, aspectRatio, showControls = true, layout, theme, title, subtitle, description, href, focus, showPortLabels, onPortClick, glowUnconnected, autoRunSpeed = 500, initialInputs, forkSource, onPortValuesChange, }, ref) {
48
+ const hasInfoBar = title || description;
49
+ const [forkError, setForkError] = useState(null);
50
+ const [forkPending, setForkPending] = useState(false);
51
+ const shareCircuit = useShareCircuit();
52
+ const onFork = async () => {
53
+ if (forkPending)
54
+ return;
55
+ try {
56
+ const source = forkSource ?? circuitToSource(circuit);
57
+ // Use the KV shortener when available (simten.dev). Outside simten.dev
58
+ // — embeds on third-party pages — fall back to the inline-encoded URL.
59
+ if (shareCircuit) {
60
+ setForkPending(true);
61
+ const { hash } = await shareCircuit(source);
62
+ window.open(`${simtenHost()}/circuit/s/${hash}`, "_blank", "noopener");
63
+ }
64
+ else {
65
+ const encoded = encodeSourceForUrl(source);
66
+ window.open(`${simtenHost()}/circuit/${encoded}`, "_blank", "noopener");
67
+ }
68
+ }
69
+ catch (err) {
70
+ setForkError(err instanceof Error ? err.message : "Couldn't fork this circuit");
71
+ setTimeout(() => setForkError(null), 3000);
72
+ }
73
+ finally {
74
+ setForkPending(false);
75
+ }
76
+ };
77
+ // Sizing strategy: if `height` is set, use it (backwards compat).
78
+ // Otherwise size width-responsively via aspect-ratio with mobile clamps.
79
+ const useResponsive = height === undefined;
80
+ const aspect = aspectRatio ?? inferAspectFromLayout(layout);
81
+ const responsiveStyle = {
82
+ width: '100%',
83
+ aspectRatio: String(aspect),
84
+ minHeight: 240,
85
+ maxHeight: '70vh',
86
+ };
87
+ const outerStyle = hasInfoBar
88
+ ? undefined
89
+ : useResponsive
90
+ ? responsiveStyle
91
+ : { height };
92
+ const canvasStyle = hasInfoBar
93
+ ? useResponsive
94
+ ? responsiveStyle
95
+ : { height }
96
+ : { height: '100%' };
97
+ return (_jsxs("div", { style: outerStyle, className: `relative flex flex-col ${hasInfoBar ? 'rounded-xl border border-[var(--embed-border)] overflow-hidden bg-[var(--embed-bg-secondary)]' : ''}`, children: [!hasInfoBar && !href && (_jsx("button", { type: "button", onClick: onFork, title: forkError ?? "Open and modify this circuit in the Simten editor", className: "absolute top-2 right-2 z-10 hidden md:flex items-center px-2.5 py-1 rounded border border-[var(--embed-border)] bg-[var(--embed-bg-secondary)] text-[11px] text-[var(--embed-text-primary)] hover:opacity-80 transition-colors shadow-sm", children: forkError ? "Fork failed" : "Fork →" })), _jsx("div", { style: canvasStyle, className: "min-h-0", children: _jsx(CircuitViewer, { ref: ref, circuit: circuit, height: "100%", showControls: showControls, autoHarness: true, initialInputs: initialInputs, layout: layout, theme: theme, focus: focus, showPortLabels: showPortLabels, onPortClick: onPortClick, glowUnconnected: glowUnconnected, autoRunSpeed: autoRunSpeed, onPortValuesChange: onPortValuesChange }) }), hasInfoBar && (_jsxs("div", { className: "border-t border-[var(--embed-border)] px-4 py-3 flex items-end justify-between gap-4", children: [_jsxs("div", { children: [_jsx("div", { className: "text-base font-semibold text-[var(--embed-text-primary)]", children: title }), subtitle && _jsx("div", { className: "text-xs text-[var(--embed-text-muted)] font-mono mt-0.5", children: subtitle }), description && _jsx("div", { className: "text-sm text-[var(--embed-text-secondary)] mt-1.5 leading-relaxed", children: description })] }), href ? (_jsx("a", { href: href, className: "shrink-0 px-3 py-1.5 rounded border border-[var(--embed-border)] text-xs text-[var(--embed-text-primary)] hover:opacity-80 transition-colors", children: "Open \u2192" })) : (_jsx("button", { type: "button", onClick: onFork, title: forkError ?? "Open and modify this circuit in the Simten editor", className: "hidden md:flex items-center shrink-0 px-3 py-1.5 rounded border border-[var(--embed-border)] text-xs text-[var(--embed-text-primary)] hover:opacity-80 transition-colors", children: forkError ? `Can't fork: ${forkError.slice(0, 40)}` : "Fork →" }))] }))] }));
98
+ });
99
+ /**
100
+ * CircuitEmbed component with generic inference over the circuit type.
101
+ * Cast preserves the generic so `layout` keys are constrained at compile time.
102
+ */
103
+ export const CircuitEmbed = CircuitEmbedImpl;
104
+ //# sourceMappingURL=CircuitEmbed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CircuitEmbed.js","sourceRoot":"","sources":["../src/CircuitEmbed.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * CircuitViewer — the single "render an interactive circuit" component.
3
+ *
4
+ * Takes a BuiltCircuit, wires up simulation, and renders CircuitCanvas + ClockControls.
5
+ * Pure props — no stores. Everything else (CircuitEmbed, EditorWorkspace, <circuit-embed>)
6
+ * is a thin wrapper around this.
7
+ */
8
+ import { type ForwardedRef, type ReactElement } from "react";
9
+ import type { BuiltCircuit } from "@simten/core/circuit";
10
+ import type { CircuitLayout } from "@simten/ui/canvas";
11
+ import type { FlatPortValueMap } from "@simten/core/simulator";
12
+ /**
13
+ * Type-level model of what `autoHarness` produces at runtime: it wraps the
14
+ * original circuit `C` as a single `dut` node and adds one Switch per input
15
+ * and one Led per output. The placeable nodes therefore become the input
16
+ * names ∪ output names ∪ `'dut'`. CircuitLayout<HarnessedCircuit<C>>
17
+ * resolves to exactly that key set.
18
+ */
19
+ export type HarnessedCircuit<C extends BuiltCircuit> = C extends BuiltCircuit<infer Ins, infer Outs, any> ? BuiltCircuit<Ins, Outs, {
20
+ [K in keyof Ins]: BuiltCircuit;
21
+ } & {
22
+ [K in keyof Outs]: BuiltCircuit;
23
+ } & {
24
+ dut: C;
25
+ }> : never;
26
+ /** Strictly-keyed layout for an autoHarness-wrapped circuit. */
27
+ export type HarnessedLayout<C extends BuiltCircuit> = CircuitLayout<HarnessedCircuit<C>>;
28
+ export interface CircuitViewerProps<C extends BuiltCircuit = BuiltCircuit> {
29
+ /** The circuit to display (result of circuit()) */
30
+ circuit: C;
31
+ /** Container height */
32
+ height?: number | string;
33
+ /** Show clock controls for sequential circuits */
34
+ showControls?: boolean;
35
+ /** Auto-wrap with Switch/Led nodes for bare circuits */
36
+ autoHarness?: boolean;
37
+ /** Initial values for auto-harnessed input nodes */
38
+ initialInputs?: Record<string, number | boolean>;
39
+ /**
40
+ * Pre-computed node positions. Keys are constrained at compile time.
41
+ * Accepts either the raw circuit's layout shape (when autoHarness is
42
+ * off) or the harnessed layout shape (when autoHarness is on, with
43
+ * keys = input names ∪ output names ∪ 'dut').
44
+ */
45
+ layout?: CircuitLayout<C> | HarnessedLayout<C>;
46
+ /** Theme */
47
+ theme?: "light" | "dark";
48
+ /** Focus on specific node(s) */
49
+ focus?: string | string[];
50
+ /** Show port labels on nodes */
51
+ showPortLabels?: boolean;
52
+ /** Callback when a port is clicked */
53
+ onPortClick?: (nodeLabel: string, portName: string, portType: "input" | "output") => void;
54
+ /** Highlight unconnected ports */
55
+ glowUnconnected?: boolean;
56
+ /** Auto-run speed (ms between ticks) */
57
+ autoRunSpeed?: number;
58
+ /** Render custom content when no circuit is compiled */
59
+ renderEmptyState?: () => React.ReactNode;
60
+ /** Render custom overlay on top of the canvas */
61
+ renderOverlay?: () => React.ReactNode;
62
+ /**
63
+ * Called when the simulator's port values settle. Fires once on first
64
+ * settled state (after the circuit compiles and propagates) and on every
65
+ * subsequent settled change (e.g. when the user toggles a switch). Use
66
+ * this to drive sibling UI that needs to react to live simulator state
67
+ * — a truth-table highlight, an external value readout, etc.
68
+ *
69
+ * Firing semantics:
70
+ * - Does NOT fire before `ready` or while `portValues` is empty.
71
+ * - Fires only on settled (post-propagation) states; the simulator
72
+ * never exposes intermediate propagation states.
73
+ * - The map reference is NOT guaranteed stable across no-op ticks
74
+ * (sequential auto-run loops can produce new Map instances with
75
+ * unchanged contents). Memoize derived state if perf matters.
76
+ *
77
+ * The callback is captured in a ref internally so inline functions
78
+ * (e.g. `onPortValuesChange={(pv) => setX(pv)}`) don't cause spurious
79
+ * re-fires — pass whatever shape is convenient for the caller.
80
+ */
81
+ onPortValuesChange?: (portValues: FlatPortValueMap) => void;
82
+ }
83
+ export interface CircuitViewerHandle {
84
+ tick: () => void;
85
+ reset: () => void;
86
+ setNodeValue: (nodeId: string, value: number | boolean | Map<number, number>) => void;
87
+ /** Start the simulator's internal auto-run loop. Equivalent to clicking the
88
+ * in-canvas play button — the play/pause control will stop it normally. */
89
+ startAutoRun: (ticksPerSecond: number) => void;
90
+ /** Stop the simulator's internal auto-run loop. */
91
+ stopAutoRun: () => void;
92
+ }
93
+ /**
94
+ * CircuitViewer with generic inference over the circuit type.
95
+ * Cast preserves the generic so `layout` keys are constrained at compile time.
96
+ */
97
+ export declare const CircuitViewer: <C extends BuiltCircuit>(props: CircuitViewerProps<C> & {
98
+ ref?: ForwardedRef<CircuitViewerHandle>;
99
+ }) => ReactElement;
100
+ //# sourceMappingURL=CircuitViewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CircuitViewer.d.ts","sourceRoot":"","sources":["../src/CircuitViewer.tsx"],"names":[],"mappings":"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"}