equilibria-react 0.1.0
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.
- package/README.md +136 -0
- package/dist/EquilibriaCard.d.ts +9 -0
- package/dist/EquilibriaChart.d.ts +11 -0
- package/dist/equilibria-react.cjs.js +1 -0
- package/dist/equilibria-react.es.js +140 -0
- package/dist/index.d.ts +6 -0
- package/dist/style.css +1 -0
- package/dist/types.d.ts +41 -0
- package/dist/useEquilibria.d.ts +25 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# equilibria-react
|
|
2
|
+
|
|
3
|
+
React components for the [Equilibria Engine](https://github.com/Kinetonomics-Equilibria/KGJS-Equilibria) — styled, drop-in chart cards with lifecycle management, error handling, and responsive sizing.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install equilibria-react equilibria-engine-js
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Required CSS
|
|
12
|
+
|
|
13
|
+
Import the engine and component styles in your app's entry point:
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import "equilibria-engine-js/dist/style.css"; // Engine theme
|
|
17
|
+
import "katex/dist/katex.min.css"; // Math typography
|
|
18
|
+
import "equilibria-react/dist/style.css"; // Card styles
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### `<EquilibriaCard />` — Drop-in styled card
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { EquilibriaCard } from 'equilibria-react';
|
|
27
|
+
|
|
28
|
+
const config = {
|
|
29
|
+
params: [{ name: "price", value: 10, min: 0, max: 20, round: 0.1 }],
|
|
30
|
+
calcs: { revenue: "price * 5" },
|
|
31
|
+
layout: {
|
|
32
|
+
OneGraph: {
|
|
33
|
+
graph: {
|
|
34
|
+
xAxis: { title: "Quantity", min: 0, max: 20 },
|
|
35
|
+
yAxis: { title: "Price ($)", min: 0, max: 20 },
|
|
36
|
+
objects: [
|
|
37
|
+
{ type: "Point", def: { x: "10", y: "price", color: "blue", draggable: true } }
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
function App() {
|
|
45
|
+
return (
|
|
46
|
+
<EquilibriaCard
|
|
47
|
+
config={config}
|
|
48
|
+
title="Interactive Pricing"
|
|
49
|
+
description="Drag the point to adjust price"
|
|
50
|
+
variant="elevated"
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### `<EquilibriaChart />` — Minimal (no card chrome)
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { EquilibriaChart } from 'equilibria-react';
|
|
60
|
+
|
|
61
|
+
function App() {
|
|
62
|
+
return (
|
|
63
|
+
<EquilibriaChart
|
|
64
|
+
config={config}
|
|
65
|
+
style={{ width: '100%', maxWidth: 600 }}
|
|
66
|
+
onReady={() => console.log('Chart rendered')}
|
|
67
|
+
onError={(err) => console.error(err)}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### `useEquilibria()` — Full control hook
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
import { useEquilibria } from 'equilibria-react';
|
|
77
|
+
|
|
78
|
+
function CustomChart({ config }) {
|
|
79
|
+
const { containerRef, isReady, error, retry } = useEquilibria(config);
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div>
|
|
83
|
+
{!isReady && !error && <p>Loading...</p>}
|
|
84
|
+
{error && <button onClick={retry}>Retry</button>}
|
|
85
|
+
<div ref={containerRef} style={{ width: '100%' }} />
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## API Reference
|
|
92
|
+
|
|
93
|
+
### `<EquilibriaCard />` Props
|
|
94
|
+
|
|
95
|
+
| Prop | Type | Default | Description |
|
|
96
|
+
|------|------|---------|-------------|
|
|
97
|
+
| `config` | `object` | **required** | Engine config (JSON/parsed YAML) |
|
|
98
|
+
| `options` | `KineticGraphOptions` | `{}` | Engine constructor options |
|
|
99
|
+
| `title` | `string` | — | Card title |
|
|
100
|
+
| `description` | `string` | — | Subtitle text |
|
|
101
|
+
| `footer` | `ReactNode` | — | Footer content slot |
|
|
102
|
+
| `variant` | `'elevated' \| 'outlined' \| 'flat'` | `'elevated'` | Visual style |
|
|
103
|
+
| `loading` | `boolean` | auto | Override loading state |
|
|
104
|
+
| `errorFallback` | `ReactNode \| (err) => ReactNode` | built-in | Custom error UI |
|
|
105
|
+
| `className` | `string` | — | Additional CSS class |
|
|
106
|
+
| `style` | `CSSProperties` | — | Inline styles |
|
|
107
|
+
| `onError` | `(err) => void` | — | Error callback |
|
|
108
|
+
| `onReady` | `() => void` | — | Fires after mount |
|
|
109
|
+
|
|
110
|
+
### `<EquilibriaChart />` Props
|
|
111
|
+
|
|
112
|
+
All of the above **except** `title`, `description`, `footer`, `variant`, `loading`, and `errorFallback`.
|
|
113
|
+
|
|
114
|
+
## Theming
|
|
115
|
+
|
|
116
|
+
Override CSS custom properties to match your design system:
|
|
117
|
+
|
|
118
|
+
```css
|
|
119
|
+
:root {
|
|
120
|
+
--eq-card-bg: #1a1a2e;
|
|
121
|
+
--eq-card-border: #2d2d44;
|
|
122
|
+
--eq-card-radius: 16px;
|
|
123
|
+
--eq-card-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
|
124
|
+
--eq-title-color: #e0e0e0;
|
|
125
|
+
--eq-description-color: #9090a0;
|
|
126
|
+
--eq-error-bg: #2d1b1b;
|
|
127
|
+
--eq-error-color: #ff6b6b;
|
|
128
|
+
--eq-skeleton-color: #2d2d44;
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
These properties are scoped to the `equilibria-react` components and won't affect the engine's own `--kg-*` variables.
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EquilibriaCardProps } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Styled card component wrapping the Equilibria engine.
|
|
5
|
+
* Includes title, description, loading skeleton, error state, and footer slot.
|
|
6
|
+
*
|
|
7
|
+
* This is the recommended "drop-in" component for rendering charts.
|
|
8
|
+
*/
|
|
9
|
+
export declare function EquilibriaCard({ config, options, className, style, onError: _onError, onReady: _onReady, title, description, footer, loading: loadingOverride, errorFallback, variant, }: EquilibriaCardProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { EquilibriaChartProps } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal chart component — mounts the Equilibria engine into a div container
|
|
5
|
+
* with no additional chrome. Use this when you want full control over the
|
|
6
|
+
* surrounding UI and only need the graph itself.
|
|
7
|
+
*
|
|
8
|
+
* For a styled wrapper with title, description, loading state, and error
|
|
9
|
+
* handling, use `<EquilibriaCard />` instead.
|
|
10
|
+
*/
|
|
11
|
+
export declare function EquilibriaChart({ config, options, className, style, onError, onReady, }: EquilibriaChartProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require("equilibria-engine-js/dist/style.css");require("katex/dist/katex.min.css");const n=require("react/jsx-runtime"),a=require("react"),N=require("equilibria-engine-js");function y(d,m){const h=a.useRef(null),s=a.useRef(null),[f,i]=a.useState(null),[u,t]=a.useState(null),[l,o]=a.useState(!1),c=a.useCallback(()=>{if(s.current){try{s.current.destroy()}catch{}s.current=null,i(null),o(!1)}t(null);const k=h.current;if(!(!k||!d))try{const r=new N.KineticGraph(d,m);r.on("error",_=>{t(_ instanceof Error?_:new Error(String(_)))}),r.mount(k),s.current=r,i(r),o(!0)}catch(r){const _=r instanceof Error?r:new Error(String(r));t(_),o(!1)}},[d,m]);a.useEffect(()=>(c(),()=>{if(s.current){try{s.current.destroy()}catch{}s.current=null,i(null),o(!1)}}),[c]);const C=a.useCallback(()=>{c()},[c]);return{containerRef:h,instance:f,error:u,isReady:l,retry:C}}const g="_chartContainer_k1m9p_61",x="_chartContainerLoading_k1m9p_69",q="_chartContainerReady_k1m9p_75",v="_card_k1m9p_83",b="_header_k1m9p_130",S="_title_k1m9p_134",B="_description_k1m9p_144",I="_chartArea_k1m9p_153",L="_skeleton_k1m9p_163",M="_skeletonHidden_k1m9p_175",P="_skeletonPulse_k1m9p_180",$="_errorContainer_k1m9p_202",A="_errorIcon_k1m9p_226",H="_errorMessage_k1m9p_233",w="_retryButton_k1m9p_243",G="_footer_k1m9p_271",e={chartContainer:g,chartContainerLoading:x,chartContainerReady:q,card:v,"card--elevated":"_card--elevated_k1m9p_98","card--outlined":"_card--outlined_k1m9p_106","card--flat":"_card--flat_k1m9p_117",header:b,title:S,description:B,chartArea:I,skeleton:L,skeletonHidden:M,skeletonPulse:P,"eq-shimmer":"_eq-shimmer_k1m9p_1",errorContainer:$,"fade-in":"_fade-in_k1m9p_1",errorIcon:A,errorMessage:H,retryButton:w,footer:G};function J({config:d,options:m,className:h,style:s,onError:f,onReady:i}){const{containerRef:u,error:t,isReady:l}=y(d,m);a.useEffect(()=>{t&&f&&f(t)},[t,f]),a.useEffect(()=>{l&&i&&i()},[l,i]);const o=[e.chartContainer,!l||t?e.chartContainerLoading:e.chartContainerReady,h].filter(Boolean).join(" ");return n.jsx("div",{ref:u,className:o,style:s})}function K({config:d,options:m,className:h,style:s,onError:f,onReady:i,title:u,description:t,footer:l,loading:o,errorFallback:c,variant:C="elevated"}){const{containerRef:k,error:r,isReady:_,retry:R}=y(d,m),j=o!==void 0?o:!_&&!r,E=[e.card,e[`card--${C}`],h].filter(Boolean).join(" ");let p=null;return r&&(c?p=typeof c=="function"?c(r):c:p=n.jsxs("div",{className:e.errorContainer,children:[n.jsx("div",{className:e.errorIcon,children:"⚠"}),n.jsx("p",{className:e.errorMessage,children:r.message||"Failed to render chart"}),n.jsx("button",{className:e.retryButton,onClick:R,children:"Retry"})]})),n.jsxs("div",{className:E,style:s,children:[(u||t)&&n.jsxs("div",{className:e.header,children:[u&&n.jsx("h3",{className:e.title,children:u}),t&&n.jsx("p",{className:e.description,children:t})]}),n.jsxs("div",{className:e.chartArea,children:[n.jsx("div",{className:`${e.skeleton} ${!j||r?e.skeletonHidden:""}`,children:n.jsx("div",{className:e.skeletonPulse})}),r&&p,n.jsx("div",{ref:k,className:`${e.chartContainer} ${j||r?e.chartContainerLoading:e.chartContainerReady}`})]}),l&&n.jsx("div",{className:e.footer,children:l})]})}exports.EquilibriaCard=K;exports.EquilibriaChart=J;exports.useEquilibria=y;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import "equilibria-engine-js/dist/style.css";
|
|
2
|
+
import "katex/dist/katex.min.css";
|
|
3
|
+
import { jsx as a, jsxs as k } from "react/jsx-runtime";
|
|
4
|
+
import { useRef as v, useState as y, useCallback as g, useEffect as N } from "react";
|
|
5
|
+
import { KineticGraph as L } from "equilibria-engine-js";
|
|
6
|
+
function E(l, m) {
|
|
7
|
+
const u = v(null), t = v(null), [h, c] = y(null), [d, n] = y(null), [i, o] = y(!1), s = g(() => {
|
|
8
|
+
if (t.current) {
|
|
9
|
+
try {
|
|
10
|
+
t.current.destroy();
|
|
11
|
+
} catch {
|
|
12
|
+
}
|
|
13
|
+
t.current = null, c(null), o(!1);
|
|
14
|
+
}
|
|
15
|
+
n(null);
|
|
16
|
+
const f = u.current;
|
|
17
|
+
if (!(!f || !l))
|
|
18
|
+
try {
|
|
19
|
+
const r = new L(l, m);
|
|
20
|
+
r.on("error", (_) => {
|
|
21
|
+
n(_ instanceof Error ? _ : new Error(String(_)));
|
|
22
|
+
}), r.mount(f), t.current = r, c(r), o(!0);
|
|
23
|
+
} catch (r) {
|
|
24
|
+
const _ = r instanceof Error ? r : new Error(String(r));
|
|
25
|
+
n(_), o(!1);
|
|
26
|
+
}
|
|
27
|
+
}, [l, m]);
|
|
28
|
+
N(() => (s(), () => {
|
|
29
|
+
if (t.current) {
|
|
30
|
+
try {
|
|
31
|
+
t.current.destroy();
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
t.current = null, c(null), o(!1);
|
|
35
|
+
}
|
|
36
|
+
}), [s]);
|
|
37
|
+
const p = g(() => {
|
|
38
|
+
s();
|
|
39
|
+
}, [s]);
|
|
40
|
+
return { containerRef: u, instance: h, error: d, isReady: i, retry: p };
|
|
41
|
+
}
|
|
42
|
+
const q = "_chartContainer_k1m9p_61", $ = "_chartContainerLoading_k1m9p_69", j = "_chartContainerReady_k1m9p_75", A = "_card_k1m9p_83", H = "_header_k1m9p_130", M = "_title_k1m9p_134", P = "_description_k1m9p_144", w = "_chartArea_k1m9p_153", x = "_skeleton_k1m9p_163", S = "_skeletonHidden_k1m9p_175", b = "_skeletonPulse_k1m9p_180", G = "_errorContainer_k1m9p_202", K = "_errorIcon_k1m9p_226", z = "_errorMessage_k1m9p_233", D = "_retryButton_k1m9p_243", J = "_footer_k1m9p_271", e = {
|
|
43
|
+
chartContainer: q,
|
|
44
|
+
chartContainerLoading: $,
|
|
45
|
+
chartContainerReady: j,
|
|
46
|
+
card: A,
|
|
47
|
+
"card--elevated": "_card--elevated_k1m9p_98",
|
|
48
|
+
"card--outlined": "_card--outlined_k1m9p_106",
|
|
49
|
+
"card--flat": "_card--flat_k1m9p_117",
|
|
50
|
+
header: H,
|
|
51
|
+
title: M,
|
|
52
|
+
description: P,
|
|
53
|
+
chartArea: w,
|
|
54
|
+
skeleton: x,
|
|
55
|
+
skeletonHidden: S,
|
|
56
|
+
skeletonPulse: b,
|
|
57
|
+
"eq-shimmer": "_eq-shimmer_k1m9p_1",
|
|
58
|
+
errorContainer: G,
|
|
59
|
+
"fade-in": "_fade-in_k1m9p_1",
|
|
60
|
+
errorIcon: K,
|
|
61
|
+
errorMessage: z,
|
|
62
|
+
retryButton: D,
|
|
63
|
+
footer: J
|
|
64
|
+
};
|
|
65
|
+
function X({
|
|
66
|
+
config: l,
|
|
67
|
+
options: m,
|
|
68
|
+
className: u,
|
|
69
|
+
style: t,
|
|
70
|
+
onError: h,
|
|
71
|
+
onReady: c
|
|
72
|
+
}) {
|
|
73
|
+
const { containerRef: d, error: n, isReady: i } = E(l, m);
|
|
74
|
+
N(() => {
|
|
75
|
+
n && h && h(n);
|
|
76
|
+
}, [n, h]), N(() => {
|
|
77
|
+
i && c && c();
|
|
78
|
+
}, [i, c]);
|
|
79
|
+
const o = [
|
|
80
|
+
e.chartContainer,
|
|
81
|
+
!i || n ? e.chartContainerLoading : e.chartContainerReady,
|
|
82
|
+
u
|
|
83
|
+
].filter(Boolean).join(" ");
|
|
84
|
+
return /* @__PURE__ */ a(
|
|
85
|
+
"div",
|
|
86
|
+
{
|
|
87
|
+
ref: d,
|
|
88
|
+
className: o,
|
|
89
|
+
style: t
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
function Y({
|
|
94
|
+
config: l,
|
|
95
|
+
options: m,
|
|
96
|
+
className: u,
|
|
97
|
+
style: t,
|
|
98
|
+
onError: h,
|
|
99
|
+
onReady: c,
|
|
100
|
+
title: d,
|
|
101
|
+
description: n,
|
|
102
|
+
footer: i,
|
|
103
|
+
loading: o,
|
|
104
|
+
errorFallback: s,
|
|
105
|
+
variant: p = "elevated"
|
|
106
|
+
}) {
|
|
107
|
+
const { containerRef: f, error: r, isReady: _, retry: B } = E(l, m), R = o !== void 0 ? o : !_ && !r, I = [
|
|
108
|
+
e.card,
|
|
109
|
+
e[`card--${p}`],
|
|
110
|
+
u
|
|
111
|
+
].filter(Boolean).join(" ");
|
|
112
|
+
let C = null;
|
|
113
|
+
return r && (s ? C = typeof s == "function" ? s(r) : s : C = /* @__PURE__ */ k("div", { className: e.errorContainer, children: [
|
|
114
|
+
/* @__PURE__ */ a("div", { className: e.errorIcon, children: "⚠" }),
|
|
115
|
+
/* @__PURE__ */ a("p", { className: e.errorMessage, children: r.message || "Failed to render chart" }),
|
|
116
|
+
/* @__PURE__ */ a("button", { className: e.retryButton, onClick: B, children: "Retry" })
|
|
117
|
+
] })), /* @__PURE__ */ k("div", { className: I, style: t, children: [
|
|
118
|
+
(d || n) && /* @__PURE__ */ k("div", { className: e.header, children: [
|
|
119
|
+
d && /* @__PURE__ */ a("h3", { className: e.title, children: d }),
|
|
120
|
+
n && /* @__PURE__ */ a("p", { className: e.description, children: n })
|
|
121
|
+
] }),
|
|
122
|
+
/* @__PURE__ */ k("div", { className: e.chartArea, children: [
|
|
123
|
+
/* @__PURE__ */ a("div", { className: `${e.skeleton} ${!R || r ? e.skeletonHidden : ""}`, children: /* @__PURE__ */ a("div", { className: e.skeletonPulse }) }),
|
|
124
|
+
r && C,
|
|
125
|
+
/* @__PURE__ */ a(
|
|
126
|
+
"div",
|
|
127
|
+
{
|
|
128
|
+
ref: f,
|
|
129
|
+
className: `${e.chartContainer} ${R || r ? e.chartContainerLoading : e.chartContainerReady}`
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
] }),
|
|
133
|
+
i && /* @__PURE__ */ a("div", { className: e.footer, children: i })
|
|
134
|
+
] });
|
|
135
|
+
}
|
|
136
|
+
export {
|
|
137
|
+
Y as EquilibriaCard,
|
|
138
|
+
X as EquilibriaChart,
|
|
139
|
+
E as useEquilibria
|
|
140
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
|
|
2
|
+
export { EquilibriaChart } from './EquilibriaChart';
|
|
3
|
+
export { EquilibriaCard } from './EquilibriaCard';
|
|
4
|
+
export { useEquilibria } from './useEquilibria';
|
|
5
|
+
export type { EquilibriaChartProps, EquilibriaCardProps, CardVariant } from './types';
|
|
6
|
+
export type { UseEquilibriaReturn, UseEquilibriaOptions } from './useEquilibria';
|
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--eq-card-bg: rgba(255, 255, 255, .75);--eq-card-border: rgba(255, 255, 255, .5);--eq-card-shadow-color: rgba(99, 102, 241, .08);--eq-card-shadow: 0 8px 32px var(--eq-card-shadow-color), inset 0 0 0 1px var(--eq-card-border);--eq-card-shadow-hover: 0 14px 48px rgba(99, 102, 241, .15), inset 0 0 0 1px var(--eq-card-border);--eq-card-blur: 16px;--eq-card-radius: 20px;--eq-card-padding: 1.75rem;--eq-font-family: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--eq-title-color: #0f172a;--eq-title-size: 1.2rem;--eq-title-weight: 600;--eq-description-color: #475569;--eq-description-size: .95rem;--eq-error-bg: rgba(254, 226, 226, .8);--eq-error-color: #991b1b;--eq-error-border: rgba(248, 113, 113, .3);--eq-skeleton-bg: rgba(241, 245, 249, .6);--eq-skeleton-color-1: rgba(99, 102, 241, .08);--eq-skeleton-color-2: rgba(168, 85, 247, .08);--eq-skeleton-color-3: rgba(236, 72, 153, .08)}@media (prefers-color-scheme: dark){:root{--eq-card-bg: rgba(15, 23, 42, .65);--eq-card-border: rgba(255, 255, 255, .06);--eq-card-shadow-color: rgba(0, 0, 0, .4);--eq-card-shadow: 0 8px 32px var(--eq-card-shadow-color), inset 0 0 0 1px var(--eq-card-border);--eq-card-shadow-hover: 0 14px 48px rgba(0, 0, 0, .6), inset 0 0 0 1px rgba(255, 255, 255, .12);--eq-title-color: #f8fafc;--eq-description-color: #94a3b8;--eq-error-bg: rgba(127, 29, 29, .4);--eq-error-color: #fca5a5;--eq-error-border: rgba(248, 113, 113, .2);--eq-skeleton-bg: rgba(30, 41, 59, .5);--eq-skeleton-color-1: rgba(99, 102, 241, .15);--eq-skeleton-color-2: rgba(168, 85, 247, .15);--eq-skeleton-color-3: rgba(236, 72, 153, .15)}}._chartContainer_k1m9p_61{width:100%;min-height:120px;position:relative;transition:opacity .8s cubic-bezier(.16,1,.3,1),filter .8s cubic-bezier(.16,1,.3,1)}._chartContainerLoading_k1m9p_69{opacity:0!important;filter:blur(8px)!important;pointer-events:none!important}._chartContainerReady_k1m9p_75{opacity:1!important;filter:blur(0)!important;pointer-events:auto!important}._card_k1m9p_83{font-family:var(--eq-font-family);background:var(--eq-card-bg);backdrop-filter:blur(var(--eq-card-blur));-webkit-backdrop-filter:blur(var(--eq-card-blur));border-radius:var(--eq-card-radius);overflow:hidden;transition:box-shadow .4s cubic-bezier(.16,1,.3,1),transform .4s cubic-bezier(.16,1,.3,1)}._card_k1m9p_83:hover{transform:translateY(-2px)}._card--elevated_k1m9p_98{box-shadow:var(--eq-card-shadow)}._card--elevated_k1m9p_98:hover{box-shadow:var(--eq-card-shadow-hover)}._card--outlined_k1m9p_106{box-shadow:inset 0 0 0 1px var(--eq-card-border);background:transparent;backdrop-filter:none;-webkit-backdrop-filter:none}._card--outlined_k1m9p_106:hover{box-shadow:inset 0 0 0 1px #6366f180}._card--flat_k1m9p_117{box-shadow:none;background:transparent;backdrop-filter:none;-webkit-backdrop-filter:none}._card--flat_k1m9p_117:hover{transform:none}._header_k1m9p_130{padding:var(--eq-card-padding) var(--eq-card-padding) 0}._title_k1m9p_134{margin:0;font-family:var(--eq-font-family);font-size:var(--eq-title-size);font-weight:var(--eq-title-weight);color:var(--eq-title-color);line-height:1.4;letter-spacing:-.02em}._description_k1m9p_144{margin:.4rem 0 0;font-size:var(--eq-description-size);color:var(--eq-description-color);line-height:1.6}._chartArea_k1m9p_153{position:relative;padding:var(--eq-card-padding);min-height:200px;display:flex;flex-direction:column}._skeleton_k1m9p_163{position:absolute;inset:var(--eq-card-padding);border-radius:12px;overflow:hidden;background:var(--eq-skeleton-bg);opacity:1;transition:opacity .6s cubic-bezier(.16,1,.3,1),transform .6s cubic-bezier(.16,1,.3,1);z-index:2;pointer-events:none}._skeletonHidden_k1m9p_175{opacity:0;transform:scale(.98)}._skeletonPulse_k1m9p_180{width:100%;height:100%;background:linear-gradient(100deg,transparent 20%,var(--eq-skeleton-color-1) 35%,var(--eq-skeleton-color-2) 50%,var(--eq-skeleton-color-3) 65%,transparent 80%);background-size:300% 100%;animation:_eq-shimmer_k1m9p_1 2.5s cubic-bezier(.4,0,.2,1) infinite}@keyframes _eq-shimmer_k1m9p_1{0%{background-position:200% 0}to{background-position:-100% 0}}._errorContainer_k1m9p_202{position:absolute;inset:var(--eq-card-padding);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1rem;padding:2rem 1.5rem;background:var(--eq-error-bg);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);border:1px solid var(--eq-error-border);border-radius:12px;text-align:center;z-index:3;animation:_fade-in_k1m9p_1 .4s ease-out}@keyframes _fade-in_k1m9p_1{0%{opacity:0;transform:translateY(5px)}to{opacity:1;transform:translateY(0)}}._errorIcon_k1m9p_226{font-size:2rem;line-height:1;color:var(--eq-error-color);filter:drop-shadow(0 0 8px rgba(248,113,113,.4))}._errorMessage_k1m9p_233{margin:0;font-family:var(--eq-font-family);font-size:.95rem;color:var(--eq-error-color);max-width:320px;word-break:break-word;font-weight:500}._retryButton_k1m9p_243{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:var(--eq-error-color);color:#fff;font-family:var(--eq-font-family);font-size:.85rem;font-weight:600;padding:.5rem 1.2rem;border:none;border-radius:8px;cursor:pointer;box-shadow:0 4px 12px #991b1b33;transition:transform .2s ease,box-shadow .2s ease,background .2s ease}._retryButton_k1m9p_243:hover{background:#7f1d1d;transform:translateY(-1px);box-shadow:0 6px 16px #991b1b4d}._retryButton_k1m9p_243:active{transform:translateY(1px);box-shadow:0 2px 8px #991b1b33}._footer_k1m9p_271{padding:0 var(--eq-card-padding) var(--eq-card-padding);font-family:var(--eq-font-family);font-size:var(--eq-description-size);color:var(--eq-description-color);border-top:1px solid var(--eq-card-border);margin-top:0;padding-top:var(--eq-card-padding)}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
import { KineticGraphOptions } from 'equilibria-engine-js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Props for the minimal EquilibriaChart component.
|
|
6
|
+
*/
|
|
7
|
+
export interface EquilibriaChartProps {
|
|
8
|
+
/** Engine configuration object (parsed JSON/YAML). */
|
|
9
|
+
config: Record<string, unknown>;
|
|
10
|
+
/** Engine options passed to the KineticGraph constructor. */
|
|
11
|
+
options?: KineticGraphOptions;
|
|
12
|
+
/** Additional CSS class name applied to the chart container. */
|
|
13
|
+
className?: string;
|
|
14
|
+
/** Inline styles applied to the chart container. */
|
|
15
|
+
style?: CSSProperties;
|
|
16
|
+
/** Callback fired when the engine encounters an error during mount. */
|
|
17
|
+
onError?: (error: Error) => void;
|
|
18
|
+
/** Callback fired after the engine successfully mounts and renders. */
|
|
19
|
+
onReady?: () => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Card style variants.
|
|
23
|
+
*/
|
|
24
|
+
export type CardVariant = 'elevated' | 'outlined' | 'flat';
|
|
25
|
+
/**
|
|
26
|
+
* Props for the styled EquilibriaCard component.
|
|
27
|
+
*/
|
|
28
|
+
export interface EquilibriaCardProps extends EquilibriaChartProps {
|
|
29
|
+
/** Card title displayed above the chart. */
|
|
30
|
+
title?: string;
|
|
31
|
+
/** Subtitle / description displayed below the title. */
|
|
32
|
+
description?: string;
|
|
33
|
+
/** Footer content rendered below the chart. */
|
|
34
|
+
footer?: ReactNode;
|
|
35
|
+
/** Override the loading state (auto-detected by default). */
|
|
36
|
+
loading?: boolean;
|
|
37
|
+
/** Custom error UI. Can be a ReactNode or a render function receiving the error. */
|
|
38
|
+
errorFallback?: ReactNode | ((error: Error) => ReactNode);
|
|
39
|
+
/** Card container style variant. Default: 'elevated'. */
|
|
40
|
+
variant?: CardVariant;
|
|
41
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { KineticGraph, KineticGraphOptions } from 'equilibria-engine-js';
|
|
2
|
+
|
|
3
|
+
export interface UseEquilibriaOptions extends KineticGraphOptions {
|
|
4
|
+
}
|
|
5
|
+
export interface UseEquilibriaReturn {
|
|
6
|
+
/** Ref to attach to the container div element. */
|
|
7
|
+
containerRef: React.RefObject<HTMLDivElement>;
|
|
8
|
+
/** The KineticGraph instance (null until mounted). */
|
|
9
|
+
instance: KineticGraph | null;
|
|
10
|
+
/** Error caught during mount, if any. */
|
|
11
|
+
error: Error | null;
|
|
12
|
+
/** Whether the engine has successfully mounted. */
|
|
13
|
+
isReady: boolean;
|
|
14
|
+
/** Manually retry mounting after an error. */
|
|
15
|
+
retry: () => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Core hook that manages the KineticGraph lifecycle.
|
|
19
|
+
*
|
|
20
|
+
* - Creates and mounts the engine when the ref is attached
|
|
21
|
+
* - Destroys the engine on unmount
|
|
22
|
+
* - Re-mounts when the config identity changes
|
|
23
|
+
* - Surfaces errors and loading state
|
|
24
|
+
*/
|
|
25
|
+
export declare function useEquilibria(config: Record<string, unknown>, options?: UseEquilibriaOptions): UseEquilibriaReturn;
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "equilibria-react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React components for the Equilibria Engine — styled, drop-in chart cards with lifecycle management",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/equilibria-react.cjs.js",
|
|
7
|
+
"module": "dist/equilibria-react.es.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/equilibria-react.es.js",
|
|
12
|
+
"require": "./dist/equilibria-react.cjs.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
},
|
|
15
|
+
"./dist/style.css": "./dist/style.css"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"dev": "vite",
|
|
19
|
+
"build": "vite build",
|
|
20
|
+
"preview": "vite preview"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
24
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
25
|
+
"equilibria-engine-js": "^1.0.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/react": "^18.2.0",
|
|
29
|
+
"@types/react-dom": "^18.2.0",
|
|
30
|
+
"react": "^18.2.0",
|
|
31
|
+
"react-dom": "^18.2.0",
|
|
32
|
+
"equilibria-engine-js": "file:../equilibria-engine-js",
|
|
33
|
+
"typescript": "^5.2.2",
|
|
34
|
+
"vite": "^4.4.9",
|
|
35
|
+
"vite-plugin-dts": "^3.5.3"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"README.md"
|
|
40
|
+
],
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/Kinetonomics-Equilibria/equilibria-react.git"
|
|
44
|
+
},
|
|
45
|
+
"author": "Jarryd Bentley",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"keywords": [
|
|
48
|
+
"equilibria",
|
|
49
|
+
"react",
|
|
50
|
+
"charts",
|
|
51
|
+
"economics",
|
|
52
|
+
"graphs",
|
|
53
|
+
"d3",
|
|
54
|
+
"interactive"
|
|
55
|
+
]
|
|
56
|
+
}
|