@simten/embed 0.1.14 → 0.1.15

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 (55) hide show
  1. package/dist/CircuitEmbed.d.ts +6 -6
  2. package/dist/CircuitEmbed.d.ts.map +1 -1
  3. package/dist/CircuitEmbed.js +18 -19
  4. package/dist/CircuitEmbed.js.map +1 -1
  5. package/dist/CircuitViewer.d.ts +6 -6
  6. package/dist/CircuitViewer.d.ts.map +1 -1
  7. package/dist/CircuitViewer.js +4 -11
  8. package/dist/CircuitViewer.js.map +1 -1
  9. package/dist/canvas/index.d.ts +2 -2
  10. package/dist/canvas/index.d.ts.map +1 -1
  11. package/dist/canvas/index.js +1 -1
  12. package/dist/canvas/index.js.map +1 -1
  13. package/dist/circuit-embed.js +25 -25
  14. package/dist/components/ErrorBoundary.d.ts +1 -1
  15. package/dist/components/ErrorBoundary.d.ts.map +1 -1
  16. package/dist/components/ErrorBoundary.js +4 -4
  17. package/dist/components/ErrorBoundary.js.map +1 -1
  18. package/dist/components/ErrorDisplay.d.ts +1 -1
  19. package/dist/components/ErrorDisplay.d.ts.map +1 -1
  20. package/dist/components/ErrorDisplay.js +8 -8
  21. package/dist/components/ErrorDisplay.js.map +1 -1
  22. package/dist/components/LoadingSkeleton.d.ts.map +1 -1
  23. package/dist/components/LoadingSkeleton.js +1 -1
  24. package/dist/components/LoadingSkeleton.js.map +1 -1
  25. package/dist/components/nodes/index.d.ts +1 -1
  26. package/dist/components/nodes/index.d.ts.map +1 -1
  27. package/dist/components/nodes/index.js +1 -1
  28. package/dist/components/nodes/index.js.map +1 -1
  29. package/dist/hooks/useCircuitSimulator.d.ts +3 -3
  30. package/dist/hooks/useCircuitSimulator.d.ts.map +1 -1
  31. package/dist/hooks/useCircuitSimulator.js +64 -19
  32. package/dist/hooks/useCircuitSimulator.js.map +1 -1
  33. package/dist/index.d.ts +9 -9
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +3 -3
  36. package/dist/index.js.map +1 -1
  37. package/dist/lib/utils.d.ts +1 -1
  38. package/dist/lib/utils.d.ts.map +1 -1
  39. package/dist/lib/utils.js +2 -2
  40. package/dist/lib/utils.js.map +1 -1
  41. package/dist/share-context.d.ts +1 -1
  42. package/dist/share-context.d.ts.map +1 -1
  43. package/dist/share-context.js +2 -2
  44. package/dist/share-context.js.map +1 -1
  45. package/dist/types.d.ts +2 -2
  46. package/dist/types.d.ts.map +1 -1
  47. package/dist/types.js.map +1 -1
  48. package/dist/webcomponent/WebComponentEmbed.d.ts +1 -1
  49. package/dist/webcomponent/WebComponentEmbed.d.ts.map +1 -1
  50. package/dist/webcomponent/WebComponentEmbed.js +8 -17
  51. package/dist/webcomponent/WebComponentEmbed.js.map +1 -1
  52. package/dist/webcomponent/index.d.ts +1 -1
  53. package/dist/webcomponent/index.js +14 -14
  54. package/dist/webcomponent/index.js.map +1 -1
  55. package/package.json +3 -3
@@ -1,4 +1,4 @@
1
- import React, { type ErrorInfo, type ReactNode } from "react";
1
+ import React, { type ErrorInfo, type ReactNode } from 'react';
2
2
  interface ErrorBoundaryProps {
3
3
  children: ReactNode;
4
4
  fallback?: ReactNode | ((error: Error) => ReactNode);
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorBoundary.d.ts","sourceRoot":"","sources":["../../src/components/ErrorBoundary.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG9D,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC;IACrD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,kBAAkB;IAC1B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED;;;GAGG;AACH,qBAAa,aAAc,SAAQ,KAAK,CAAC,SAAS,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;gBAC5E,KAAK,EAAE,kBAAkB;IAKrC,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,kBAAkB;IAIjE,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;IAIpD,WAAW,aAET;IAEF,MAAM;CAiBP"}
1
+ {"version":3,"file":"ErrorBoundary.d.ts","sourceRoot":"","sources":["../../src/components/ErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG9D,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC;IACrD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,kBAAkB;IAC1B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED;;;GAGG;AACH,qBAAa,aAAc,SAAQ,KAAK,CAAC,SAAS,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;gBAC5E,KAAK,EAAE,kBAAkB;IAKrC,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,kBAAkB;IAIjE,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;IAIpD,WAAW,aAET;IAEF,MAAM;CAiBP"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import React from "react";
3
- import { ErrorDisplay } from "./ErrorDisplay";
2
+ import React from 'react';
3
+ import { ErrorDisplay } from './ErrorDisplay';
4
4
  /**
5
5
  * React error boundary for circuit embed components.
6
6
  * Catches render errors and displays a styled fallback instead of crashing.
@@ -22,11 +22,11 @@ export class ErrorBoundary extends React.Component {
22
22
  render() {
23
23
  if (this.state.error) {
24
24
  if (this.props.fallback) {
25
- return typeof this.props.fallback === "function"
25
+ return typeof this.props.fallback === 'function'
26
26
  ? this.props.fallback(this.state.error)
27
27
  : this.props.fallback;
28
28
  }
29
- return (_jsx(ErrorDisplay, { error: this.state.error.message, title: this.props.title ?? "Render Error", onRetry: this.handleRetry }));
29
+ return (_jsx(ErrorDisplay, { error: this.state.error.message, title: this.props.title ?? 'Render Error', onRetry: this.handleRetry }));
30
30
  }
31
31
  return this.props.children;
32
32
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorBoundary.js","sourceRoot":"","sources":["../../src/components/ErrorBoundary.tsx"],"names":[],"mappings":";AACA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAa9C;;;GAGG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK,CAAC,SAAiD;IACxF,YAAY,KAAyB;QACnC,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,KAAK,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC/B,CAAC;IAED,MAAM,CAAC,wBAAwB,CAAC,KAAY;QAC1C,OAAO,EAAE,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,iBAAiB,CAAC,KAAY,EAAE,SAAoB;QAClD,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;IAED,WAAW,GAAG,GAAG,EAAE;QACjB,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC;IAEF,MAAM;QACJ,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACrB,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACxB,OAAO,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,UAAU;oBAC9C,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;oBACvC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;YAC1B,CAAC;YACD,OAAO,CACL,KAAC,YAAY,IACX,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAC/B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,cAAc,EACzC,OAAO,EAAE,IAAI,CAAC,WAAW,GACzB,CACH,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC7B,CAAC;CACF","sourcesContent":["\nimport React, { type ErrorInfo, type ReactNode } from \"react\";\nimport { ErrorDisplay } from \"./ErrorDisplay\";\n\ninterface ErrorBoundaryProps {\n children: ReactNode;\n fallback?: ReactNode | ((error: Error) => ReactNode);\n onError?: (error: Error, errorInfo: ErrorInfo) => void;\n title?: string;\n}\n\ninterface ErrorBoundaryState {\n error: Error | null;\n}\n\n/**\n * React error boundary for circuit embed components.\n * Catches render errors and displays a styled fallback instead of crashing.\n */\nexport class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { error: null };\n }\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { error };\n }\n\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n this.props.onError?.(error, errorInfo);\n }\n\n handleRetry = () => {\n this.setState({ error: null });\n };\n\n render() {\n if (this.state.error) {\n if (this.props.fallback) {\n return typeof this.props.fallback === \"function\"\n ? this.props.fallback(this.state.error)\n : this.props.fallback;\n }\n return (\n <ErrorDisplay\n error={this.state.error.message}\n title={this.props.title ?? \"Render Error\"}\n onRetry={this.handleRetry}\n />\n );\n }\n return this.props.children;\n }\n}\n"]}
1
+ {"version":3,"file":"ErrorBoundary.js","sourceRoot":"","sources":["../../src/components/ErrorBoundary.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAa9C;;;GAGG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK,CAAC,SAAiD;IACxF,YAAY,KAAyB;QACnC,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,KAAK,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC/B,CAAC;IAED,MAAM,CAAC,wBAAwB,CAAC,KAAY;QAC1C,OAAO,EAAE,KAAK,EAAE,CAAC;IACnB,CAAC;IAED,iBAAiB,CAAC,KAAY,EAAE,SAAoB;QAClD,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;IAED,WAAW,GAAG,GAAG,EAAE;QACjB,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC;IAEF,MAAM;QACJ,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACrB,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACxB,OAAO,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,KAAK,UAAU;oBAC9C,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;oBACvC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;YAC1B,CAAC;YACD,OAAO,CACL,KAAC,YAAY,IACX,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAC/B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,cAAc,EACzC,OAAO,EAAE,IAAI,CAAC,WAAW,GACzB,CACH,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC7B,CAAC;CACF","sourcesContent":["import React, { type ErrorInfo, type ReactNode } from 'react';\nimport { ErrorDisplay } from './ErrorDisplay';\n\ninterface ErrorBoundaryProps {\n children: ReactNode;\n fallback?: ReactNode | ((error: Error) => ReactNode);\n onError?: (error: Error, errorInfo: ErrorInfo) => void;\n title?: string;\n}\n\ninterface ErrorBoundaryState {\n error: Error | null;\n}\n\n/**\n * React error boundary for circuit embed components.\n * Catches render errors and displays a styled fallback instead of crashing.\n */\nexport class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { error: null };\n }\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { error };\n }\n\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n this.props.onError?.(error, errorInfo);\n }\n\n handleRetry = () => {\n this.setState({ error: null });\n };\n\n render() {\n if (this.state.error) {\n if (this.props.fallback) {\n return typeof this.props.fallback === 'function'\n ? this.props.fallback(this.state.error)\n : this.props.fallback;\n }\n return (\n <ErrorDisplay\n error={this.state.error.message}\n title={this.props.title ?? 'Render Error'}\n onRetry={this.handleRetry}\n />\n );\n }\n return this.props.children;\n }\n}\n"]}
@@ -2,7 +2,7 @@ export interface SimulatorError {
2
2
  message: string;
3
3
  line?: number;
4
4
  column?: number;
5
- stage: "parse" | "compile" | "elaborate" | "simulate";
5
+ stage: 'parse' | 'compile' | 'elaborate' | 'simulate';
6
6
  }
7
7
  interface ErrorDisplayProps {
8
8
  error: string | SimulatorError | SimulatorError[];
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorDisplay.d.ts","sourceRoot":"","sources":["../../src/components/ErrorDisplay.tsx"],"names":[],"mappings":"AACA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;CACvD;AAED,UAAU,iBAAiB;IACzB,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,cAAc,EAAE,CAAC;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAgBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAuB,EAAE,OAAO,EAAE,EAAE,iBAAiB,2CA8C1F"}
1
+ {"version":3,"file":"ErrorDisplay.d.ts","sourceRoot":"","sources":["../../src/components/ErrorDisplay.tsx"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;CACvD;AAED,UAAU,iBAAiB;IACzB,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,cAAc,EAAE,CAAC;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAgBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAuB,EAAE,OAAO,EAAE,EAAE,iBAAiB,2CAyD1F"}
@@ -2,23 +2,23 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  function parseErrors(error) {
3
3
  if (Array.isArray(error))
4
4
  return error;
5
- if (typeof error === "object")
5
+ if (typeof error === 'object')
6
6
  return [error];
7
7
  // Legacy: semicolon-joined strings from older hook versions
8
- return error.split("; ").map((msg) => ({ message: msg, stage: "compile" }));
8
+ return error.split('; ').map((msg) => ({ message: msg, stage: 'compile' }));
9
9
  }
10
10
  const STAGE_LABELS = {
11
- parse: "Parse",
12
- compile: "Compile",
13
- elaborate: "Elaborate",
14
- simulate: "Simulate",
11
+ parse: 'Parse',
12
+ compile: 'Compile',
13
+ elaborate: 'Elaborate',
14
+ simulate: 'Simulate',
15
15
  };
16
16
  /**
17
17
  * Styled error display for circuit embed components.
18
18
  * Renders structured error messages with optional line/column info.
19
19
  */
20
- export function ErrorDisplay({ error, title = "Circuit Error", onRetry }) {
20
+ export function ErrorDisplay({ error, title = 'Circuit Error', onRetry }) {
21
21
  const errors = parseErrors(error);
22
- return (_jsx("div", { className: "rounded-xl border border-red-800/40 bg-red-950/20 p-4 overflow-hidden", role: "alert", "aria-live": "assertive", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "shrink-0 mt-0.5", children: _jsx("svg", { className: "w-5 h-5 text-red-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" }) }) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("h4", { className: "text-sm font-semibold text-red-300", children: title }), _jsx("div", { className: "mt-2 space-y-1.5", children: errors.map((err, i) => (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("span", { className: "text-[10px] font-mono text-red-400/60 bg-red-900/30 px-1.5 py-0.5 rounded shrink-0 mt-0.5", children: STAGE_LABELS[err.stage] || err.stage }), _jsxs("span", { className: "text-xs font-mono text-red-300/80 break-all", children: [err.message, err.line !== undefined && (_jsxs("span", { className: "text-red-400/50 ml-1", children: ["(line ", err.line, err.column !== undefined ? `:${err.column}` : "", ")"] }))] })] }, i))) }), onRetry && (_jsx("button", { onClick: onRetry, className: "mt-3 px-3 py-1 text-xs font-medium rounded-md bg-red-900/30 hover:bg-red-900/50 text-red-300 transition-colors", children: "Retry" }))] })] }) }));
22
+ return (_jsx("div", { className: "rounded-xl border border-red-800/40 bg-red-950/20 p-4 overflow-hidden", role: "alert", "aria-live": "assertive", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "shrink-0 mt-0.5", children: _jsx("svg", { className: "w-5 h-5 text-red-400", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" }) }) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("h4", { className: "text-sm font-semibold text-red-300", children: title }), _jsx("div", { className: "mt-2 space-y-1.5", children: errors.map((err, i) => (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("span", { className: "text-[10px] font-mono text-red-400/60 bg-red-900/30 px-1.5 py-0.5 rounded shrink-0 mt-0.5", children: STAGE_LABELS[err.stage] || err.stage }), _jsxs("span", { className: "text-xs font-mono text-red-300/80 break-all", children: [err.message, err.line !== undefined && (_jsxs("span", { className: "text-red-400/50 ml-1", children: ["(line ", err.line, err.column !== undefined ? `:${err.column}` : '', ")"] }))] })] }, i))) }), onRetry && (_jsx("button", { onClick: onRetry, className: "mt-3 px-3 py-1 text-xs font-medium rounded-md bg-red-900/30 hover:bg-red-900/50 text-red-300 transition-colors", children: "Retry" }))] })] }) }));
23
23
  }
24
24
  //# sourceMappingURL=ErrorDisplay.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorDisplay.js","sourceRoot":"","sources":["../../src/components/ErrorDisplay.tsx"],"names":[],"mappings":";AAcA,SAAS,WAAW,CAAC,KAAiD;IACpE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9C,4DAA4D;IAC5D,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,SAAkB,EAAE,CAAC,CAAC,CAAC;AACvF,CAAC;AAED,MAAM,YAAY,GAA2B;IAC3C,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;CACrB,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,eAAe,EAAE,OAAO,EAAqB;IACzF,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAElC,OAAO,CACL,cACE,SAAS,EAAC,uEAAuE,EACjF,IAAI,EAAC,OAAO,eACF,WAAW,YAErB,eAAK,SAAS,EAAC,wBAAwB,aACrC,cAAK,SAAS,EAAC,iBAAiB,YAC9B,cAAK,SAAS,EAAC,sBAAsB,EAAC,IAAI,EAAC,MAAM,EAAC,OAAO,EAAC,WAAW,EAAC,MAAM,EAAC,cAAc,EAAC,WAAW,EAAE,CAAC,YACxG,eAAM,aAAa,EAAC,OAAO,EAAC,cAAc,EAAC,OAAO,EAAC,CAAC,EAAC,0EAA0E,GAAG,GAC9H,GACF,EACN,eAAK,SAAS,EAAC,gBAAgB,aAC7B,aAAI,SAAS,EAAC,oCAAoC,YAAE,KAAK,GAAM,EAC/D,cAAK,SAAS,EAAC,kBAAkB,YAC9B,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CACtB,eAAa,SAAS,EAAC,wBAAwB,aAC7C,eAAM,SAAS,EAAC,2FAA2F,YACxG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,KAAK,GAChC,EACP,gBAAM,SAAS,EAAC,6CAA6C,aAC1D,GAAG,CAAC,OAAO,EACX,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,CACzB,gBAAM,SAAS,EAAC,sBAAsB,uBAC7B,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,SAC5D,CACR,IACI,KAXC,CAAC,CAYL,CACP,CAAC,GACE,EACL,OAAO,IAAI,CACV,iBACE,OAAO,EAAE,OAAO,EAChB,SAAS,EAAC,gHAAgH,sBAGnH,CACV,IACG,IACF,GACF,CACP,CAAC;AACJ,CAAC","sourcesContent":["\nexport interface SimulatorError {\n message: string;\n line?: number;\n column?: number;\n stage: \"parse\" | \"compile\" | \"elaborate\" | \"simulate\";\n}\n\ninterface ErrorDisplayProps {\n error: string | SimulatorError | SimulatorError[];\n title?: string;\n onRetry?: () => void;\n}\n\nfunction parseErrors(error: string | SimulatorError | SimulatorError[]): SimulatorError[] {\n if (Array.isArray(error)) return error;\n if (typeof error === \"object\") return [error];\n // Legacy: semicolon-joined strings from older hook versions\n return error.split(\"; \").map((msg) => ({ message: msg, stage: \"compile\" as const }));\n}\n\nconst STAGE_LABELS: Record<string, string> = {\n parse: \"Parse\",\n compile: \"Compile\",\n elaborate: \"Elaborate\",\n simulate: \"Simulate\",\n};\n\n/**\n * Styled error display for circuit embed components.\n * Renders structured error messages with optional line/column info.\n */\nexport function ErrorDisplay({ error, title = \"Circuit Error\", onRetry }: ErrorDisplayProps) {\n const errors = parseErrors(error);\n\n return (\n <div\n className=\"rounded-xl border border-red-800/40 bg-red-950/20 p-4 overflow-hidden\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n <div className=\"flex items-start gap-3\">\n <div className=\"shrink-0 mt-0.5\">\n <svg className=\"w-5 h-5 text-red-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z\" />\n </svg>\n </div>\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"text-sm font-semibold text-red-300\">{title}</h4>\n <div className=\"mt-2 space-y-1.5\">\n {errors.map((err, i) => (\n <div key={i} className=\"flex items-start gap-2\">\n <span className=\"text-[10px] font-mono text-red-400/60 bg-red-900/30 px-1.5 py-0.5 rounded shrink-0 mt-0.5\">\n {STAGE_LABELS[err.stage] || err.stage}\n </span>\n <span className=\"text-xs font-mono text-red-300/80 break-all\">\n {err.message}\n {err.line !== undefined && (\n <span className=\"text-red-400/50 ml-1\">\n (line {err.line}{err.column !== undefined ? `:${err.column}` : \"\"})\n </span>\n )}\n </span>\n </div>\n ))}\n </div>\n {onRetry && (\n <button\n onClick={onRetry}\n className=\"mt-3 px-3 py-1 text-xs font-medium rounded-md bg-red-900/30 hover:bg-red-900/50 text-red-300 transition-colors\"\n >\n Retry\n </button>\n )}\n </div>\n </div>\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"ErrorDisplay.js","sourceRoot":"","sources":["../../src/components/ErrorDisplay.tsx"],"names":[],"mappings":";AAaA,SAAS,WAAW,CAAC,KAAiD;IACpE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9C,4DAA4D;IAC5D,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,SAAkB,EAAE,CAAC,CAAC,CAAC;AACvF,CAAC;AAED,MAAM,YAAY,GAA2B;IAC3C,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;CACrB,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,eAAe,EAAE,OAAO,EAAqB;IACzF,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAElC,OAAO,CACL,cACE,SAAS,EAAC,uEAAuE,EACjF,IAAI,EAAC,OAAO,eACF,WAAW,YAErB,eAAK,SAAS,EAAC,wBAAwB,aACrC,cAAK,SAAS,EAAC,iBAAiB,YAC9B,cACE,SAAS,EAAC,sBAAsB,EAChC,IAAI,EAAC,MAAM,EACX,OAAO,EAAC,WAAW,EACnB,MAAM,EAAC,cAAc,EACrB,WAAW,EAAE,CAAC,YAEd,eACE,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EACtB,CAAC,EAAC,0EAA0E,GAC5E,GACE,GACF,EACN,eAAK,SAAS,EAAC,gBAAgB,aAC7B,aAAI,SAAS,EAAC,oCAAoC,YAAE,KAAK,GAAM,EAC/D,cAAK,SAAS,EAAC,kBAAkB,YAC9B,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CACtB,eAAa,SAAS,EAAC,wBAAwB,aAC7C,eAAM,SAAS,EAAC,2FAA2F,YACxG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,KAAK,GAChC,EACP,gBAAM,SAAS,EAAC,6CAA6C,aAC1D,GAAG,CAAC,OAAO,EACX,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,CACzB,gBAAM,SAAS,EAAC,sBAAsB,uBAC7B,GAAG,CAAC,IAAI,EACd,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,SAC5C,CACR,IACI,KAZC,CAAC,CAaL,CACP,CAAC,GACE,EACL,OAAO,IAAI,CACV,iBACE,OAAO,EAAE,OAAO,EAChB,SAAS,EAAC,gHAAgH,sBAGnH,CACV,IACG,IACF,GACF,CACP,CAAC;AACJ,CAAC","sourcesContent":["export interface SimulatorError {\n message: string;\n line?: number;\n column?: number;\n stage: 'parse' | 'compile' | 'elaborate' | 'simulate';\n}\n\ninterface ErrorDisplayProps {\n error: string | SimulatorError | SimulatorError[];\n title?: string;\n onRetry?: () => void;\n}\n\nfunction parseErrors(error: string | SimulatorError | SimulatorError[]): SimulatorError[] {\n if (Array.isArray(error)) return error;\n if (typeof error === 'object') return [error];\n // Legacy: semicolon-joined strings from older hook versions\n return error.split('; ').map((msg) => ({ message: msg, stage: 'compile' as const }));\n}\n\nconst STAGE_LABELS: Record<string, string> = {\n parse: 'Parse',\n compile: 'Compile',\n elaborate: 'Elaborate',\n simulate: 'Simulate',\n};\n\n/**\n * Styled error display for circuit embed components.\n * Renders structured error messages with optional line/column info.\n */\nexport function ErrorDisplay({ error, title = 'Circuit Error', onRetry }: ErrorDisplayProps) {\n const errors = parseErrors(error);\n\n return (\n <div\n className=\"rounded-xl border border-red-800/40 bg-red-950/20 p-4 overflow-hidden\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n <div className=\"flex items-start gap-3\">\n <div className=\"shrink-0 mt-0.5\">\n <svg\n className=\"w-5 h-5 text-red-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z\"\n />\n </svg>\n </div>\n <div className=\"flex-1 min-w-0\">\n <h4 className=\"text-sm font-semibold text-red-300\">{title}</h4>\n <div className=\"mt-2 space-y-1.5\">\n {errors.map((err, i) => (\n <div key={i} className=\"flex items-start gap-2\">\n <span className=\"text-[10px] font-mono text-red-400/60 bg-red-900/30 px-1.5 py-0.5 rounded shrink-0 mt-0.5\">\n {STAGE_LABELS[err.stage] || err.stage}\n </span>\n <span className=\"text-xs font-mono text-red-300/80 break-all\">\n {err.message}\n {err.line !== undefined && (\n <span className=\"text-red-400/50 ml-1\">\n (line {err.line}\n {err.column !== undefined ? `:${err.column}` : ''})\n </span>\n )}\n </span>\n </div>\n ))}\n </div>\n {onRetry && (\n <button\n onClick={onRetry}\n className=\"mt-3 px-3 py-1 text-xs font-medium rounded-md bg-red-900/30 hover:bg-red-900/50 text-red-300 transition-colors\"\n >\n Retry\n </button>\n )}\n </div>\n </div>\n </div>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"LoadingSkeleton.d.ts","sourceRoot":"","sources":["../../src/components/LoadingSkeleton.tsx"],"names":[],"mappings":"AAGA,UAAU,oBAAoB;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,MAAY,EAAE,EAAE,oBAAoB,2CAmCrE"}
1
+ {"version":3,"file":"LoadingSkeleton.d.ts","sourceRoot":"","sources":["../../src/components/LoadingSkeleton.tsx"],"names":[],"mappings":"AAEA,UAAU,oBAAoB;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,MAAY,EAAE,EAAE,oBAAoB,2CAqDrE"}
@@ -5,6 +5,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
5
  * Respects height to prevent layout shift.
6
6
  */
7
7
  export function LoadingSkeleton({ height = 300 }) {
8
- return (_jsxs("div", { className: "rounded-xl border border-[var(--embed-border)] bg-[var(--embed-bg-primary)] overflow-hidden flex items-center justify-center", style: { height }, role: "status", "aria-label": "Loading circuit", children: [_jsxs("div", { className: "flex items-center gap-8", children: [_jsxs("div", { className: "flex flex-col gap-4", children: [_jsx("div", { className: "w-20 h-14 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse" }), _jsx("div", { className: "w-20 h-14 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse", style: { animationDelay: "150ms" } })] }), _jsxs("div", { className: "flex flex-col gap-6 items-center", children: [_jsx("div", { className: "w-12 h-0.5 bg-[var(--embed-border)]/40 animate-pulse", style: { animationDelay: "300ms" } }), _jsx("div", { className: "w-12 h-0.5 bg-[var(--embed-border)]/40 animate-pulse", style: { animationDelay: "350ms" } })] }), _jsx("div", { className: "w-24 h-20 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse", style: { animationDelay: "200ms" } }), _jsx("div", { className: "w-12 h-0.5 bg-[var(--embed-border)]/40 animate-pulse", style: { animationDelay: "400ms" } }), _jsx("div", { className: "w-20 h-14 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse", style: { animationDelay: "250ms" } })] }), _jsx("span", { className: "sr-only", children: "Compiling and laying out circuit..." })] }));
8
+ return (_jsxs("div", { className: "rounded-xl border border-[var(--embed-border)] bg-[var(--embed-bg-primary)] overflow-hidden flex items-center justify-center", style: { height }, role: "status", "aria-label": "Loading circuit", children: [_jsxs("div", { className: "flex items-center gap-8", children: [_jsxs("div", { className: "flex flex-col gap-4", children: [_jsx("div", { className: "w-20 h-14 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse" }), _jsx("div", { className: "w-20 h-14 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse", style: { animationDelay: '150ms' } })] }), _jsxs("div", { className: "flex flex-col gap-6 items-center", children: [_jsx("div", { className: "w-12 h-0.5 bg-[var(--embed-border)]/40 animate-pulse", style: { animationDelay: '300ms' } }), _jsx("div", { className: "w-12 h-0.5 bg-[var(--embed-border)]/40 animate-pulse", style: { animationDelay: '350ms' } })] }), _jsx("div", { className: "w-24 h-20 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse", style: { animationDelay: '200ms' } }), _jsx("div", { className: "w-12 h-0.5 bg-[var(--embed-border)]/40 animate-pulse", style: { animationDelay: '400ms' } }), _jsx("div", { className: "w-20 h-14 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse", style: { animationDelay: '250ms' } })] }), _jsx("span", { className: "sr-only", children: "Compiling and laying out circuit..." })] }));
9
9
  }
10
10
  //# sourceMappingURL=LoadingSkeleton.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoadingSkeleton.js","sourceRoot":"","sources":["../../src/components/LoadingSkeleton.tsx"],"names":[],"mappings":";AAOA;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,MAAM,GAAG,GAAG,EAAwB;IACpE,OAAO,CACL,eACE,SAAS,EAAC,8HAA8H,EACxI,KAAK,EAAE,EAAE,MAAM,EAAE,EACjB,IAAI,EAAC,QAAQ,gBACF,iBAAiB,aAE5B,eAAK,SAAS,EAAC,yBAAyB,aAEtC,eAAK,SAAS,EAAC,qBAAqB,aAClC,cAAK,SAAS,EAAC,qEAAqE,GAAG,EACvF,cAAK,SAAS,EAAC,qEAAqE,EAAC,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAAI,IACvH,EAGN,eAAK,SAAS,EAAC,kCAAkC,aAC/C,cAAK,SAAS,EAAC,sDAAsD,EAAC,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAAI,EAC5G,cAAK,SAAS,EAAC,sDAAsD,EAAC,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAAI,IACxG,EAGN,cAAK,SAAS,EAAC,qEAAqE,EAAC,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAAI,EAG3H,cAAK,SAAS,EAAC,sDAAsD,EAAC,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAAI,EAG5G,cAAK,SAAS,EAAC,qEAAqE,EAAC,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAAI,IACvH,EAGN,eAAM,SAAS,EAAC,SAAS,oDAA2C,IAChE,CACP,CAAC;AACJ,CAAC","sourcesContent":["\nimport React from \"react\";\n\ninterface LoadingSkeletonProps {\n height?: number | string;\n}\n\n/**\n * Loading skeleton for circuit embeds.\n * Shows fake node placeholders with connecting lines, matching the dark theme.\n * Respects height to prevent layout shift.\n */\nexport function LoadingSkeleton({ height = 300 }: LoadingSkeletonProps) {\n return (\n <div\n className=\"rounded-xl border border-[var(--embed-border)] bg-[var(--embed-bg-primary)] overflow-hidden flex items-center justify-center\"\n style={{ height }}\n role=\"status\"\n aria-label=\"Loading circuit\"\n >\n <div className=\"flex items-center gap-8\">\n {/* Input nodes */}\n <div className=\"flex flex-col gap-4\">\n <div className=\"w-20 h-14 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse\" />\n <div className=\"w-20 h-14 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse\" style={{ animationDelay: \"150ms\" }} />\n </div>\n\n {/* Connecting lines */}\n <div className=\"flex flex-col gap-6 items-center\">\n <div className=\"w-12 h-0.5 bg-[var(--embed-border)]/40 animate-pulse\" style={{ animationDelay: \"300ms\" }} />\n <div className=\"w-12 h-0.5 bg-[var(--embed-border)]/40 animate-pulse\" style={{ animationDelay: \"350ms\" }} />\n </div>\n\n {/* Logic node */}\n <div className=\"w-24 h-20 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse\" style={{ animationDelay: \"200ms\" }} />\n\n {/* Connecting line */}\n <div className=\"w-12 h-0.5 bg-[var(--embed-border)]/40 animate-pulse\" style={{ animationDelay: \"400ms\" }} />\n\n {/* Output node */}\n <div className=\"w-20 h-14 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse\" style={{ animationDelay: \"250ms\" }} />\n </div>\n\n {/* Screen reader text */}\n <span className=\"sr-only\">Compiling and laying out circuit...</span>\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"LoadingSkeleton.js","sourceRoot":"","sources":["../../src/components/LoadingSkeleton.tsx"],"names":[],"mappings":";AAMA;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,EAAE,MAAM,GAAG,GAAG,EAAwB;IACpE,OAAO,CACL,eACE,SAAS,EAAC,8HAA8H,EACxI,KAAK,EAAE,EAAE,MAAM,EAAE,EACjB,IAAI,EAAC,QAAQ,gBACF,iBAAiB,aAE5B,eAAK,SAAS,EAAC,yBAAyB,aAEtC,eAAK,SAAS,EAAC,qBAAqB,aAClC,cAAK,SAAS,EAAC,qEAAqE,GAAG,EACvF,cACE,SAAS,EAAC,qEAAqE,EAC/E,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAClC,IACE,EAGN,eAAK,SAAS,EAAC,kCAAkC,aAC/C,cACE,SAAS,EAAC,sDAAsD,EAChE,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAClC,EACF,cACE,SAAS,EAAC,sDAAsD,EAChE,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAClC,IACE,EAGN,cACE,SAAS,EAAC,qEAAqE,EAC/E,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAClC,EAGF,cACE,SAAS,EAAC,sDAAsD,EAChE,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAClC,EAGF,cACE,SAAS,EAAC,qEAAqE,EAC/E,KAAK,EAAE,EAAE,cAAc,EAAE,OAAO,EAAE,GAClC,IACE,EAGN,eAAM,SAAS,EAAC,SAAS,oDAA2C,IAChE,CACP,CAAC;AACJ,CAAC","sourcesContent":["import React from 'react';\n\ninterface LoadingSkeletonProps {\n height?: number | string;\n}\n\n/**\n * Loading skeleton for circuit embeds.\n * Shows fake node placeholders with connecting lines, matching the dark theme.\n * Respects height to prevent layout shift.\n */\nexport function LoadingSkeleton({ height = 300 }: LoadingSkeletonProps) {\n return (\n <div\n className=\"rounded-xl border border-[var(--embed-border)] bg-[var(--embed-bg-primary)] overflow-hidden flex items-center justify-center\"\n style={{ height }}\n role=\"status\"\n aria-label=\"Loading circuit\"\n >\n <div className=\"flex items-center gap-8\">\n {/* Input nodes */}\n <div className=\"flex flex-col gap-4\">\n <div className=\"w-20 h-14 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse\" />\n <div\n className=\"w-20 h-14 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse\"\n style={{ animationDelay: '150ms' }}\n />\n </div>\n\n {/* Connecting lines */}\n <div className=\"flex flex-col gap-6 items-center\">\n <div\n className=\"w-12 h-0.5 bg-[var(--embed-border)]/40 animate-pulse\"\n style={{ animationDelay: '300ms' }}\n />\n <div\n className=\"w-12 h-0.5 bg-[var(--embed-border)]/40 animate-pulse\"\n style={{ animationDelay: '350ms' }}\n />\n </div>\n\n {/* Logic node */}\n <div\n className=\"w-24 h-20 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse\"\n style={{ animationDelay: '200ms' }}\n />\n\n {/* Connecting line */}\n <div\n className=\"w-12 h-0.5 bg-[var(--embed-border)]/40 animate-pulse\"\n style={{ animationDelay: '400ms' }}\n />\n\n {/* Output node */}\n <div\n className=\"w-20 h-14 rounded-lg bg-[var(--embed-bg-tertiary)]/60 animate-pulse\"\n style={{ animationDelay: '250ms' }}\n />\n </div>\n\n {/* Screen reader text */}\n <span className=\"sr-only\">Compiling and laying out circuit...</span>\n </div>\n );\n}\n"]}
@@ -3,5 +3,5 @@
3
3
  * This allows external consumers to import from @simten/embed/nodes
4
4
  * while the source of truth lives in the ui package.
5
5
  */
6
- export { BaseNode, type PortConfig, type BaseNodeProps, InputNode, OutputNode, LogicGateNode, EmbedConsoleNode, EmbedScreenNode, CompositeBadge, type NodeData, } from "@simten/ui/nodes";
6
+ export { BaseNode, type BaseNodeProps, CompositeBadge, EmbedConsoleNode, EmbedScreenNode, InputNode, LogicGateNode, type NodeData, OutputNode, type PortConfig, } from '@simten/ui/nodes';
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/nodes/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,QAAQ,EACR,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,SAAS,EACT,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,KAAK,QAAQ,GACd,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/nodes/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,QAAQ,EACR,KAAK,aAAa,EAClB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,aAAa,EACb,KAAK,QAAQ,EACb,UAAU,EACV,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAC"}
@@ -3,5 +3,5 @@
3
3
  * This allows external consumers to import from @simten/embed/nodes
4
4
  * while the source of truth lives in the ui package.
5
5
  */
6
- export { BaseNode, InputNode, OutputNode, LogicGateNode, EmbedConsoleNode, EmbedScreenNode, CompositeBadge, } from "@simten/ui/nodes";
6
+ export { BaseNode, CompositeBadge, EmbedConsoleNode, EmbedScreenNode, InputNode, LogicGateNode, OutputNode, } from '@simten/ui/nodes';
7
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/nodes/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,QAAQ,EAGR,SAAS,EACT,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,cAAc,GAEf,MAAM,kBAAkB,CAAC","sourcesContent":["/**\n * Re-export canonical node components from @simten/ui/nodes.\n * This allows external consumers to import from @simten/embed/nodes\n * while the source of truth lives in the ui package.\n */\nexport {\n BaseNode,\n type PortConfig,\n type BaseNodeProps,\n InputNode,\n OutputNode,\n LogicGateNode,\n EmbedConsoleNode,\n EmbedScreenNode,\n CompositeBadge,\n type NodeData,\n} from \"@simten/ui/nodes\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/nodes/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,QAAQ,EAER,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,aAAa,EAEb,UAAU,GAEX,MAAM,kBAAkB,CAAC","sourcesContent":["/**\n * Re-export canonical node components from @simten/ui/nodes.\n * This allows external consumers to import from @simten/embed/nodes\n * while the source of truth lives in the ui package.\n */\nexport {\n BaseNode,\n type BaseNodeProps,\n CompositeBadge,\n EmbedConsoleNode,\n EmbedScreenNode,\n InputNode,\n LogicGateNode,\n type NodeData,\n OutputNode,\n type PortConfig,\n} from '@simten/ui/nodes';\n"]}
@@ -16,9 +16,9 @@
16
16
  *
17
17
  * See: apps/web/content/docs/architecture.mdx → "Runtime topology".
18
18
  */
19
- import { type SimulatorEngine, type CircuitLibrary, type FlatPortValueMap, type FlatSequentialState } from "@simten/core/simulator";
20
- import type { Circuit } from "@simten/core";
21
- import type { BuiltCircuit } from "@simten/core/circuit";
19
+ import type { Circuit } from '@simten/core';
20
+ import type { BuiltCircuit } from '@simten/core/circuit';
21
+ import type { CircuitLibrary, FlatPortValueMap, FlatSequentialState, SimulatorEngine } from '@simten/core/simulator';
22
22
  export interface SimulatorState {
23
23
  outputs: Record<string, boolean | number>;
24
24
  inputs: Record<string, boolean | number>;
@@ -1 +1 @@
1
- {"version":3,"file":"useCircuitSimulator.d.ts","sourceRoot":"","sources":["../../src/hooks/useCircuitSimulator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useCircuitSimulator.d.ts","sourceRoot":"","sources":["../../src/hooks/useCircuitSimulator.ts"],"names":[],"mappings":"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"}
@@ -16,11 +16,11 @@
16
16
  *
17
17
  * See: apps/web/content/docs/architecture.mdx → "Runtime topology".
18
18
  */
19
- import { useState, useEffect, useCallback, useRef, useMemo } from "react";
20
- import { getCircuitEval, autoHarness, isSequentialCircuit } from "@simten/core/circuit";
21
- import { Switch, Button, Led, Input, Output, HexDisplay } from "@simten/core/std";
22
- import { useSandboxContext } from "@simten/ui/sandbox";
23
- const TOP_LEVEL_NODE = "__top__";
19
+ import { autoHarness, getCircuitEval, isSequentialCircuit } from '@simten/core/circuit';
20
+ import { Button, HexDisplay, Input, Led, Output, Switch } from '@simten/core/std';
21
+ import { useSandboxContext } from '@simten/ui/sandbox';
22
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
23
+ const TOP_LEVEL_NODE = '__top__';
24
24
  /**
25
25
  * Extract eval function sources from a BuiltCircuit and its dependencies.
26
26
  * These are serialized and sent to the sandbox, which reconstructs them with new Function().
@@ -72,6 +72,24 @@ export function builtFromIR(circuit, dependencies) {
72
72
  _dependencies: depMap,
73
73
  };
74
74
  }
75
+ /**
76
+ * Resolves once the sandbox iframe reports ready (or the caller cancels).
77
+ * Polls because the sandbox handle exposes readiness as isReady() with no event.
78
+ */
79
+ function waitForSandboxReady(sandbox, cancelled) {
80
+ return new Promise((resolve) => {
81
+ if (sandbox.isReady() || cancelled()) {
82
+ resolve();
83
+ return;
84
+ }
85
+ const id = setInterval(() => {
86
+ if (sandbox.isReady() || cancelled()) {
87
+ clearInterval(id);
88
+ resolve();
89
+ }
90
+ }, 50);
91
+ });
92
+ }
75
93
  /**
76
94
  * Circuit simulator hook — runs simulation in the sandbox iframe.
77
95
  *
@@ -87,8 +105,12 @@ export function useCircuitSimulator(circuit, options) {
87
105
  const circuitMap = new Map();
88
106
  const lib = {
89
107
  resolveCircuit: (name) => circuitMap.get(name),
90
- getAllPrimitiveNames: () => [...circuitMap.entries()].filter(([, c]) => c.implementation.kind === 'primitive').map(([n]) => n),
91
- addCircuit: (c) => { circuitMap.set(c.name, c); },
108
+ getAllPrimitiveNames: () => [...circuitMap.entries()]
109
+ .filter(([, c]) => c.implementation.kind === 'primitive')
110
+ .map(([n]) => n),
111
+ addCircuit: (c) => {
112
+ circuitMap.set(c.name, c);
113
+ },
92
114
  };
93
115
  for (const c of [Switch(), Button(), Led, Input(), Output, HexDisplay]) {
94
116
  lib.addCircuit(c.circuit);
@@ -145,7 +167,9 @@ export function useCircuitSimulator(circuit, options) {
145
167
  // Mirror of inputs in a ref so tick/tickN can snapshot the latest value
146
168
  // synchronously without waiting for setState → re-render.
147
169
  const inputsRef = useRef(inputs);
148
- useEffect(() => { inputsRef.current = inputs; }, [inputs]);
170
+ useEffect(() => {
171
+ inputsRef.current = inputs;
172
+ }, [inputs]);
149
173
  // ── Compile to sandbox on mount / circuit change ──
150
174
  useEffect(() => {
151
175
  if (!circuit || !harnessedCircuit) {
@@ -157,6 +181,14 @@ export function useCircuitSimulator(circuit, options) {
157
181
  async function initSandbox() {
158
182
  if (!circuit || !harnessedCircuit)
159
183
  return;
184
+ // compileIR does not queue — calling it before the sandbox iframe has
185
+ // finished loading returns "Sandbox not ready" with no recovery. Wait for
186
+ // readiness first so consumers mounting a circuit immediately (fresh apps
187
+ // where the SandboxProvider mounts alongside them) don't have to gate on
188
+ // isReady() themselves.
189
+ await waitForSandboxReady(sandbox, () => cancelled);
190
+ if (cancelled)
191
+ return;
160
192
  // Extract eval sources from the BuiltCircuit and its dependencies
161
193
  const evalSources = extractEvalSources(circuit);
162
194
  // Collect all library circuits (stdlib + user).
@@ -212,9 +244,10 @@ export function useCircuitSimulator(circuit, options) {
212
244
  // Seed history with the initial snapshot (if any). Fresh compile means
213
245
  // the previous history (if any) is invalid anyway — sandbox already
214
246
  // cleared its own snapshots on the recompile.
215
- historyRef.current = result.snapshotId !== undefined
216
- ? [{ snapshotId: result.snapshotId, cycle: 0, inputs: { ...defaultInputs } }]
217
- : [];
247
+ historyRef.current =
248
+ result.snapshotId !== undefined
249
+ ? [{ snapshotId: result.snapshotId, cycle: 0, inputs: { ...defaultInputs } }]
250
+ : [];
218
251
  setHistoryIndex(result.snapshotId !== undefined ? 0 : -1);
219
252
  setHistoryLen(historyRef.current.length);
220
253
  setReady(true);
@@ -282,7 +315,9 @@ export function useCircuitSimulator(circuit, options) {
282
315
  // Mirror historyIndex in a ref so the helper above can see its live value
283
316
  // without recompiling on every change (avoids rebuilding every callback).
284
317
  const historyIndexRef = useRef(-1);
285
- useEffect(() => { historyIndexRef.current = historyIndex; }, [historyIndex]);
318
+ useEffect(() => {
319
+ historyIndexRef.current = historyIndex;
320
+ }, [historyIndex]);
286
321
  // ── Actions ──
287
322
  const setNode = useCallback(async (name, value) => {
288
323
  // Input changes (switch toggles, button presses) don't create a new
@@ -307,7 +342,7 @@ export function useCircuitSimulator(circuit, options) {
307
342
  }, [ready, sandbox, slotId]);
308
343
  const toggleInput = useCallback((name) => {
309
344
  const current = inputs[name];
310
- const newValue = typeof current === 'boolean' ? !current : (current === 0 ? 1 : 0);
345
+ const newValue = typeof current === 'boolean' ? !current : current === 0 ? 1 : 0;
311
346
  setNode(name, newValue);
312
347
  }, [inputs, setNode]);
313
348
  const toggleNode = useCallback(async (nodeId) => {
@@ -315,7 +350,7 @@ export function useCircuitSimulator(circuit, options) {
315
350
  return;
316
351
  const outKey = `${nodeId}.out`;
317
352
  const current = portValues.get(outKey);
318
- const newValue = typeof current === 'boolean' ? !current : (current === 1 ? 0 : 1);
353
+ const newValue = typeof current === 'boolean' ? !current : current === 1 ? 0 : 1;
319
354
  // Same reasoning as setNode: no new history entry on input edit.
320
355
  const result = await sandbox.setNode(nodeId, newValue, slotId);
321
356
  if ('error' in result)
@@ -407,7 +442,9 @@ export function useCircuitSimulator(circuit, options) {
407
442
  if (isSequential) {
408
443
  const snap = await sandbox.snapshot(slotId);
409
444
  if (!('error' in snap) && snap.snapshotId !== undefined) {
410
- historyRef.current = [{ snapshotId: snap.snapshotId, cycle: 0, inputs: { ...defaultInputs } }];
445
+ historyRef.current = [
446
+ { snapshotId: snap.snapshotId, cycle: 0, inputs: { ...defaultInputs } },
447
+ ];
411
448
  }
412
449
  }
413
450
  historyIndexRef.current = historyRef.current.length > 0 ? 0 : -1;
@@ -476,14 +513,18 @@ export function useCircuitSimulator(circuit, options) {
476
513
  // bail-early version of tick and never recover, even after the sandbox
477
514
  // becomes ready — the interval would fire forever calling a stale closure.
478
515
  const tickRef = useRef(tick);
479
- useEffect(() => { tickRef.current = tick; }, [tick]);
516
+ useEffect(() => {
517
+ tickRef.current = tick;
518
+ }, [tick]);
480
519
  const startAutoRun = useCallback((ticksPerSecond, _opts) => {
481
520
  if (autoRunRef.current)
482
521
  clearInterval(autoRunRef.current);
483
522
  setSpeedState(ticksPerSecond);
484
523
  setIsRunning(true);
485
524
  const interval = Math.max(1, Math.floor(1000 / ticksPerSecond));
486
- autoRunRef.current = setInterval(() => { tickRef.current(); }, interval);
525
+ autoRunRef.current = setInterval(() => {
526
+ tickRef.current();
527
+ }, interval);
487
528
  }, []);
488
529
  const stopAutoRun = useCallback(() => {
489
530
  if (autoRunRef.current) {
@@ -498,7 +539,9 @@ export function useCircuitSimulator(circuit, options) {
498
539
  // Restart with new speed
499
540
  clearInterval(autoRunRef.current);
500
541
  const interval = Math.max(1, Math.floor(1000 / ticksPerSecond));
501
- autoRunRef.current = setInterval(() => { tickRef.current(); }, interval);
542
+ autoRunRef.current = setInterval(() => {
543
+ tickRef.current();
544
+ }, interval);
502
545
  }
503
546
  }, []);
504
547
  useEffect(() => {
@@ -528,7 +571,9 @@ export function useCircuitSimulator(circuit, options) {
528
571
  // Shadow-typed history for the UI: the consumer only needs a length for
529
572
  // showing the `N/M` counter and the ◀ ▶ enable logic. historyLen drives
530
573
  // re-renders; the array identity is intentionally stable per-slot.
531
- const historyForUi = useMemo(() => historyRef.current.slice(0, historyLen).map(h => ({ engineSnapshot: h.snapshotId, metadata: h.cycle })), [historyLen]);
574
+ const historyForUi = useMemo(() => historyRef.current
575
+ .slice(0, historyLen)
576
+ .map((h) => ({ engineSnapshot: h.snapshotId, metadata: h.cycle })), [historyLen]);
532
577
  return {
533
578
  // State
534
579
  outputs,