@matterfact/embed 0.4.0 → 0.6.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.
Files changed (54) hide show
  1. package/README.md +62 -6
  2. package/dist/{chunk-523BCS2Z.js → chunk-4Q2ROXLR.js} +2 -2
  3. package/dist/chunk-7I37ZFAJ.js +2 -0
  4. package/dist/{chunk-Z4WT3TIZ.js → chunk-AXKXNYRT.js} +39 -38
  5. package/dist/chunk-AXKXNYRT.js.map +1 -0
  6. package/dist/chunk-D7R6WVHG.js +2 -0
  7. package/dist/chunk-D7R6WVHG.js.map +7 -0
  8. package/dist/{chunk-SBNMM3ZV.js → chunk-RS6RMZ77.js} +39 -37
  9. package/dist/chunk-RS6RMZ77.js.map +1 -0
  10. package/dist/{context-432WQST4.js → context-WU2F5CBC.js} +6 -4
  11. package/dist/context-YX2KXFLI.js +3 -0
  12. package/dist/{context-KZAUOIR6.js.map → context-YX2KXFLI.js.map} +1 -1
  13. package/dist/embed.js +1 -1
  14. package/dist/embed.js.map +2 -2
  15. package/dist/index.cjs +58 -50
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +37 -3
  18. package/dist/index.d.ts +37 -3
  19. package/dist/index.js +22 -15
  20. package/dist/index.js.map +1 -1
  21. package/dist/react.cjs +64 -50
  22. package/dist/react.cjs.map +1 -1
  23. package/dist/react.d.cts +35 -1
  24. package/dist/react.d.ts +35 -1
  25. package/dist/react.js +28 -15
  26. package/dist/react.js.map +1 -1
  27. package/dist/{snapshot-SOMSG2OF.js → snapshot-JOGZWESK.js} +2 -2
  28. package/dist/{snapshot-Q3CALMHD.js → snapshot-MUXE7KXX.js} +3 -3
  29. package/dist/{snapshot-Q3CALMHD.js.map → snapshot-MUXE7KXX.js.map} +1 -1
  30. package/examples/README.md +46 -0
  31. package/examples/demo-host/index.html +163 -0
  32. package/examples/demo-host/serve.mjs +62 -0
  33. package/examples/embed-demo/.env.example +24 -0
  34. package/examples/embed-demo/README.md +72 -0
  35. package/examples/embed-demo/index.html +12 -0
  36. package/examples/embed-demo/package.json +25 -0
  37. package/examples/embed-demo/src/App.tsx +239 -0
  38. package/examples/embed-demo/src/config.ts +43 -0
  39. package/examples/embed-demo/src/main.tsx +10 -0
  40. package/examples/embed-demo/src/styles.css +354 -0
  41. package/examples/embed-demo/tsconfig.json +16 -0
  42. package/examples/embed-demo/vite.config.ts +11 -0
  43. package/examples/host-panel.html +259 -0
  44. package/package.json +3 -2
  45. package/dist/chunk-SBNMM3ZV.js.map +0 -1
  46. package/dist/chunk-URIBHOOQ.js +0 -2
  47. package/dist/chunk-XLQ36ZMV.js +0 -2
  48. package/dist/chunk-XLQ36ZMV.js.map +0 -7
  49. package/dist/chunk-Z4WT3TIZ.js.map +0 -1
  50. package/dist/context-KZAUOIR6.js +0 -3
  51. /package/dist/{chunk-523BCS2Z.js.map → chunk-4Q2ROXLR.js.map} +0 -0
  52. /package/dist/{chunk-URIBHOOQ.js.map → chunk-7I37ZFAJ.js.map} +0 -0
  53. /package/dist/{context-432WQST4.js.map → context-WU2F5CBC.js.map} +0 -0
  54. /package/dist/{snapshot-SOMSG2OF.js.map → snapshot-JOGZWESK.js.map} +0 -0
@@ -0,0 +1,354 @@
1
+ :root {
2
+ --bg: #f4f6f9;
3
+ --surface: #fff;
4
+ --surface-2: #f0f3f7;
5
+ --line: #dfe4ec;
6
+ --ink: #131722;
7
+ --muted: #616b7c;
8
+ --accent: #2f5fe0;
9
+ --pos: #128a5b;
10
+ --neg: #c2453d;
11
+ --panel-w: 420px;
12
+ --sans:
13
+ -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial,
14
+ sans-serif;
15
+ --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
16
+ }
17
+ @media (prefers-color-scheme: dark) {
18
+ :root {
19
+ --bg: #0f1419;
20
+ --surface: #161c24;
21
+ --surface-2: #1d2530;
22
+ --line: #28303c;
23
+ --ink: #e7ecf2;
24
+ --muted: #8b97a6;
25
+ --accent: #6b93ff;
26
+ --pos: #4ea88a;
27
+ --neg: #d1706a;
28
+ }
29
+ }
30
+ * {
31
+ box-sizing: border-box;
32
+ }
33
+ html,
34
+ body,
35
+ #root {
36
+ height: 100%;
37
+ margin: 0;
38
+ }
39
+ body {
40
+ background: var(--bg);
41
+ color: var(--ink);
42
+ font-family: var(--sans);
43
+ }
44
+
45
+ .app {
46
+ display: grid;
47
+ grid-template-rows: auto 1fr;
48
+ height: 100vh;
49
+ overflow: hidden;
50
+ }
51
+
52
+ header {
53
+ display: flex;
54
+ align-items: center;
55
+ gap: 16px;
56
+ padding: 0 20px;
57
+ height: 56px;
58
+ border-bottom: 1px solid var(--line);
59
+ background: var(--surface);
60
+ }
61
+ .brand {
62
+ display: flex;
63
+ align-items: center;
64
+ gap: 10px;
65
+ font-weight: 700;
66
+ letter-spacing: -0.01em;
67
+ }
68
+ .brand .mark {
69
+ width: 26px;
70
+ height: 26px;
71
+ border-radius: 7px;
72
+ background: linear-gradient(135deg, var(--accent), #1b3fa8);
73
+ display: grid;
74
+ place-items: center;
75
+ color: #fff;
76
+ font-weight: 800;
77
+ font-size: 15px;
78
+ }
79
+ .brand small {
80
+ color: var(--muted);
81
+ font-weight: 500;
82
+ margin-left: 2px;
83
+ }
84
+ nav {
85
+ display: flex;
86
+ gap: 4px;
87
+ margin-left: 12px;
88
+ }
89
+ nav a {
90
+ color: var(--muted);
91
+ text-decoration: none;
92
+ font-size: 13.5px;
93
+ font-weight: 500;
94
+ padding: 6px 11px;
95
+ border-radius: 7px;
96
+ }
97
+ nav a.active {
98
+ color: var(--ink);
99
+ background: var(--surface-2);
100
+ }
101
+ .spacer {
102
+ flex: 1;
103
+ }
104
+ .env-chip {
105
+ font-family: var(--mono);
106
+ font-size: 11.5px;
107
+ color: var(--muted);
108
+ border: 1px solid var(--line);
109
+ border-radius: 999px;
110
+ padding: 4px 10px;
111
+ }
112
+ .toggle {
113
+ display: flex;
114
+ align-items: center;
115
+ gap: 8px;
116
+ cursor: pointer;
117
+ background: var(--surface-2);
118
+ color: var(--ink);
119
+ border: 1px solid var(--line);
120
+ border-radius: 8px;
121
+ padding: 7px 12px;
122
+ font: inherit;
123
+ font-size: 13px;
124
+ font-weight: 600;
125
+ }
126
+ .toggle:hover {
127
+ border-color: var(--accent);
128
+ }
129
+ .toggle .dot {
130
+ width: 7px;
131
+ height: 7px;
132
+ border-radius: 50%;
133
+ background: var(--pos);
134
+ }
135
+
136
+ .layout {
137
+ display: grid;
138
+ grid-template-columns: 1fr var(--panel-w);
139
+ min-height: 0;
140
+ }
141
+ .app[data-panel='closed'] .layout {
142
+ grid-template-columns: 1fr 0;
143
+ }
144
+
145
+ main {
146
+ overflow-y: auto;
147
+ padding: 28px 32px 40px;
148
+ min-width: 0;
149
+ }
150
+ .eyebrow {
151
+ font-family: var(--mono);
152
+ font-size: 11.5px;
153
+ letter-spacing: 0.08em;
154
+ text-transform: uppercase;
155
+ color: var(--muted);
156
+ }
157
+ h1 {
158
+ font-size: 26px;
159
+ letter-spacing: -0.02em;
160
+ margin: 6px 0 2px;
161
+ }
162
+ .sub {
163
+ color: var(--muted);
164
+ font-size: 14px;
165
+ margin-bottom: 26px;
166
+ }
167
+
168
+ .kpis {
169
+ display: grid;
170
+ grid-template-columns: repeat(4, 1fr);
171
+ gap: 12px;
172
+ margin-bottom: 26px;
173
+ }
174
+ .kpi {
175
+ background: var(--surface);
176
+ border: 1px solid var(--line);
177
+ border-radius: 12px;
178
+ padding: 14px 16px;
179
+ }
180
+ .kpi .label {
181
+ font-size: 11.5px;
182
+ color: var(--muted);
183
+ text-transform: uppercase;
184
+ letter-spacing: 0.05em;
185
+ }
186
+ .kpi .val {
187
+ font-size: 22px;
188
+ font-weight: 700;
189
+ margin-top: 6px;
190
+ font-variant-numeric: tabular-nums;
191
+ }
192
+ .kpi .val.pos {
193
+ color: var(--pos);
194
+ }
195
+ .kpi .val.neg {
196
+ color: var(--neg);
197
+ }
198
+
199
+ .section-title {
200
+ font-size: 13px;
201
+ font-weight: 700;
202
+ color: var(--muted);
203
+ text-transform: uppercase;
204
+ letter-spacing: 0.05em;
205
+ margin: 4px 0 12px;
206
+ }
207
+
208
+ .artifact-frame {
209
+ position: relative;
210
+ width: 100%;
211
+ height: 360px;
212
+ border: 1px solid var(--line);
213
+ border-radius: 12px;
214
+ background: var(--surface-2);
215
+ margin-bottom: 8px;
216
+ overflow: hidden;
217
+ }
218
+ .artifact-badge {
219
+ position: absolute;
220
+ top: 12px;
221
+ left: 12px;
222
+ z-index: 2;
223
+ display: flex;
224
+ align-items: center;
225
+ gap: 7px;
226
+ background: color-mix(in srgb, var(--surface) 82%, transparent);
227
+ backdrop-filter: blur(4px);
228
+ border: 1px solid var(--line);
229
+ border-radius: 999px;
230
+ padding: 5px 11px;
231
+ font-size: 11.5px;
232
+ color: var(--muted);
233
+ }
234
+ .artifact-badge .mf {
235
+ color: var(--accent);
236
+ }
237
+ .artifact-badge code {
238
+ color: var(--ink);
239
+ font-family: var(--mono);
240
+ font-size: 11px;
241
+ }
242
+ .artifact-caption {
243
+ font-size: 12.5px;
244
+ color: var(--muted);
245
+ margin: 0 0 26px;
246
+ }
247
+ .artifact-caption strong {
248
+ color: var(--ink);
249
+ font-weight: 600;
250
+ }
251
+
252
+ table {
253
+ width: 100%;
254
+ border-collapse: collapse;
255
+ font-size: 13.5px;
256
+ }
257
+ th {
258
+ text-align: left;
259
+ color: var(--muted);
260
+ font-weight: 600;
261
+ font-size: 11.5px;
262
+ text-transform: uppercase;
263
+ letter-spacing: 0.04em;
264
+ padding: 8px 10px;
265
+ border-bottom: 1px solid var(--line);
266
+ }
267
+ td {
268
+ padding: 11px 10px;
269
+ border-bottom: 1px solid var(--line);
270
+ font-variant-numeric: tabular-nums;
271
+ }
272
+ td.tick {
273
+ font-weight: 700;
274
+ }
275
+ td.pos {
276
+ color: var(--pos);
277
+ }
278
+ td.neg {
279
+ color: var(--neg);
280
+ }
281
+
282
+ aside {
283
+ border-left: 1px solid var(--line);
284
+ background: var(--surface);
285
+ display: flex;
286
+ flex-direction: column;
287
+ min-width: 0;
288
+ overflow: hidden;
289
+ }
290
+ .panel-head {
291
+ display: flex;
292
+ align-items: center;
293
+ gap: 8px;
294
+ height: 44px;
295
+ padding: 0 14px;
296
+ border-bottom: 1px solid var(--line);
297
+ font-size: 12.5px;
298
+ font-weight: 700;
299
+ color: var(--muted);
300
+ text-transform: uppercase;
301
+ letter-spacing: 0.05em;
302
+ }
303
+ .panel-head .mf {
304
+ color: var(--accent);
305
+ }
306
+ .agent-slot {
307
+ flex: 1;
308
+ min-height: 0;
309
+ }
310
+
311
+ .setup {
312
+ display: grid;
313
+ place-items: center;
314
+ height: 100vh;
315
+ padding: 24px;
316
+ }
317
+ .setup .box {
318
+ max-width: 580px;
319
+ background: var(--surface);
320
+ border: 1px solid var(--line);
321
+ border-radius: 14px;
322
+ padding: 28px 30px;
323
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.12);
324
+ }
325
+ .setup h2 {
326
+ margin: 0 0 6px;
327
+ font-size: 18px;
328
+ }
329
+ .setup p {
330
+ color: var(--muted);
331
+ font-size: 14px;
332
+ line-height: 1.55;
333
+ margin: 10px 0;
334
+ }
335
+ .setup code {
336
+ font-family: var(--mono);
337
+ font-size: 12.5px;
338
+ background: var(--surface-2);
339
+ padding: 2px 6px;
340
+ border-radius: 5px;
341
+ color: var(--ink);
342
+ margin: 0 2px;
343
+ }
344
+ .setup ul {
345
+ margin: 8px 0 0;
346
+ padding-left: 18px;
347
+ }
348
+ .setup li {
349
+ font-size: 13.5px;
350
+ line-height: 1.7;
351
+ }
352
+ .setup li.bad {
353
+ color: var(--neg);
354
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "jsx": "react-jsx",
8
+ "strict": true,
9
+ "noUnusedLocals": true,
10
+ "noUnusedParameters": true,
11
+ "skipLibCheck": true,
12
+ "esModuleInterop": true,
13
+ "types": ["vite/client"]
14
+ },
15
+ "include": ["src", "vite.config.ts"]
16
+ }
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+
4
+ // The dev server runs on localhost:8000 — that exact origin must be registered
5
+ // as an allowed origin on your publishable key. strictPort so it never silently
6
+ // drifts to a different (unregistered) port.
7
+ export default defineConfig({
8
+ plugins: [react()],
9
+ server: { host: 'localhost', port: 8000, strictPort: true },
10
+ preview: { host: 'localhost', port: 8000, strictPort: true },
11
+ });
@@ -0,0 +1,259 @@
1
+ <!doctype html>
2
+ <!--
3
+ Example: the matterfact agent rendered INLINE, in a host app's own side panel
4
+ (not the floating corner bubble). A made-up investment tool, "ActivistHub", with the
5
+ agent living in its right rail via `data-container`.
6
+
7
+ Shows: inline placement · pull-based page context (window.matterfact.getPageContext) ·
8
+ artifact awareness (an embedded matterfact artifact the agent can read) · the host
9
+ owning open/close (the "Assistant" toggle) · ?mfdev=1 to inspect what the agent sees.
10
+
11
+ This uses the <script> loader so it opens as a plain file. React apps use
12
+ <MatterfactAgent inline> from @matterfact/embed instead (see the tag at the bottom).
13
+ Replace the placeholder key/origin with your own before it will connect.
14
+ -->
15
+ <html lang="en" class="light">
16
+ <head>
17
+ <meta charset="utf-8" />
18
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
19
+ <title>ActivistHub — matterfact embed showcase</title>
20
+ <style>
21
+ /* A stand-in "customer app": deliberately NOT matterfact's own palette, so the
22
+ embedded agent visibly reads as a guest inside someone else's product. */
23
+ :root {
24
+ --bg: #0f1419;
25
+ --surface: #161c24;
26
+ --surface-2: #1d2530;
27
+ --line: #28303c;
28
+ --ink: #e7ecf2;
29
+ --muted: #8b97a6;
30
+ --accent: #e0b341; /* ActivistHub gold — a customer brand, not ours */
31
+ --pos: #4ea88a;
32
+ --neg: #d1706a;
33
+ --panel-w: 400px;
34
+ --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
35
+ --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
36
+ }
37
+ * { box-sizing: border-box; }
38
+ html, body { height: 100%; margin: 0; }
39
+ body {
40
+ background: var(--bg); color: var(--ink); font-family: var(--sans);
41
+ display: grid; grid-template-rows: auto 1fr; height: 100vh; overflow: hidden;
42
+ }
43
+
44
+ header {
45
+ display: flex; align-items: center; gap: 16px;
46
+ padding: 0 20px; height: 56px; border-bottom: 1px solid var(--line);
47
+ background: var(--surface);
48
+ }
49
+ .brand { display: flex; align-items: center; gap: 10px; font-weight: 700; letter-spacing: -0.01em; }
50
+ .brand .mark {
51
+ width: 26px; height: 26px; border-radius: 7px;
52
+ background: linear-gradient(135deg, var(--accent), #b98a1e);
53
+ display: grid; place-items: center; color: #201a08; font-weight: 800; font-size: 15px;
54
+ }
55
+ .brand small { color: var(--muted); font-weight: 500; margin-left: 2px; }
56
+ nav { display: flex; gap: 4px; margin-left: 12px; }
57
+ nav a {
58
+ color: var(--muted); text-decoration: none; font-size: 13.5px; font-weight: 500;
59
+ padding: 6px 11px; border-radius: 7px;
60
+ }
61
+ nav a.active { color: var(--ink); background: var(--surface-2); }
62
+ .spacer { flex: 1; }
63
+ .panel-toggle {
64
+ display: flex; align-items: center; gap: 8px; cursor: pointer;
65
+ background: var(--surface-2); color: var(--ink); border: 1px solid var(--line);
66
+ border-radius: 8px; padding: 7px 12px; font-size: 13px; font-weight: 600;
67
+ }
68
+ .panel-toggle:hover { border-color: #3a4453; }
69
+ .panel-toggle .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--pos); }
70
+
71
+ .layout { display: grid; grid-template-columns: 1fr var(--panel-w); min-height: 0; }
72
+ .layout[data-panel="hidden"] { grid-template-columns: 1fr 0; }
73
+
74
+ main { overflow-y: auto; padding: 28px 32px 60px; min-width: 0; }
75
+ .eyebrow { font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
76
+ h1 { font-size: 26px; letter-spacing: -0.02em; margin: 6px 0 2px; }
77
+ .sub { color: var(--muted); font-size: 14px; margin-bottom: 26px; }
78
+
79
+ .kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 26px; }
80
+ .kpi { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px; }
81
+ .kpi .label { font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
82
+ .kpi .val { font-size: 22px; font-weight: 700; margin-top: 6px; font-variant-numeric: tabular-nums; }
83
+ .kpi .val.pos { color: var(--pos); } .kpi .val.neg { color: var(--neg); }
84
+
85
+ .section-title { font-size: 13px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; margin: 4px 0 12px; }
86
+
87
+ /* The embedded matterfact ARTIFACT — a cross-origin iframe on our page. The agent
88
+ recognises it by origin and can pull the real data behind it. */
89
+ .artifact-frame {
90
+ position: relative;
91
+ width: 100%; height: 260px; border: 1px solid var(--line); border-radius: 12px;
92
+ background: var(--surface-2); margin-bottom: 8px; overflow: hidden;
93
+ }
94
+ .artifact-frame iframe { width: 100%; height: 100%; border: 0; }
95
+ .artifact-badge {
96
+ position: absolute; top: 12px; left: 12px; z-index: 2;
97
+ display: flex; align-items: center; gap: 7px;
98
+ background: rgba(15,20,25,0.82); backdrop-filter: blur(4px);
99
+ border: 1px solid var(--line); border-radius: 999px; padding: 5px 11px;
100
+ font-size: 11.5px; color: var(--muted);
101
+ }
102
+ .artifact-badge .mf { color: var(--accent); }
103
+ .artifact-badge code { color: var(--ink); font-family: var(--mono); font-size: 11px; }
104
+ .artifact-caption { font-size: 12.5px; color: var(--muted); margin: 0 0 26px; }
105
+ .artifact-caption strong { color: var(--ink); font-weight: 600; }
106
+
107
+ table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
108
+ th { text-align: left; color: var(--muted); font-weight: 600; font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.04em; padding: 8px 10px; border-bottom: 1px solid var(--line); }
109
+ td { padding: 11px 10px; border-bottom: 1px solid var(--line); font-variant-numeric: tabular-nums; }
110
+ td.tick { font-weight: 700; }
111
+ td.pos { color: var(--pos); } td.neg { color: var(--neg); }
112
+
113
+ /* THE PANEL. This box is the HOST's. The agent renders inside it, sized by this CSS. */
114
+ aside {
115
+ border-left: 1px solid var(--line); background: var(--surface);
116
+ display: flex; flex-direction: column; min-width: 0; overflow: hidden;
117
+ }
118
+ aside .panel-head {
119
+ display: flex; align-items: center; gap: 8px; height: 44px; padding: 0 14px;
120
+ border-bottom: 1px solid var(--line); font-size: 12.5px; font-weight: 700;
121
+ color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em;
122
+ }
123
+ aside .panel-head .mf { color: var(--accent); }
124
+ #agent-panel { flex: 1; min-height: 0; }
125
+
126
+ footer {
127
+ position: fixed; bottom: 0; left: 0; right: var(--panel-w);
128
+ background: var(--surface-2); border-top: 1px solid var(--line);
129
+ padding: 8px 16px; font-size: 12px; color: var(--muted); font-family: var(--mono);
130
+ }
131
+ footer code { color: var(--accent); }
132
+ </style>
133
+ </head>
134
+ <body>
135
+ <header>
136
+ <div class="brand">
137
+ <span class="mark">A</span> ActivistHub <small>· Elliott</small>
138
+ </div>
139
+ <nav>
140
+ <a href="#">Positions</a>
141
+ <a href="#" class="active">Growth Sleeve</a>
142
+ <a href="#">Research</a>
143
+ </nav>
144
+ <div class="spacer"></div>
145
+ <button class="panel-toggle" id="toggle">
146
+ <span class="dot"></span> Assistant
147
+ </button>
148
+ </header>
149
+
150
+ <div class="layout" id="layout" data-panel="shown">
151
+ <main>
152
+ <div class="eyebrow">Portfolio</div>
153
+ <h1>Growth Sleeve</h1>
154
+ <div class="sub">12 holdings · rebalanced 3 days ago · benchmark S&amp;P 500</div>
155
+
156
+ <div class="kpis">
157
+ <div class="kpi"><div class="label">Market value</div><div class="val">$48.2M</div></div>
158
+ <div class="kpi"><div class="label">Day change</div><div class="val pos">+1.34%</div></div>
159
+ <div class="kpi"><div class="label">YTD</div><div class="val pos">+18.7%</div></div>
160
+ <div class="kpi"><div class="label">vs benchmark</div><div class="val neg">−2.1%</div></div>
161
+ </div>
162
+
163
+ <div class="section-title">Q3 revenue model</div>
164
+ <div class="artifact-frame">
165
+ <div class="artifact-badge"><span class="mf">✦</span> matterfact artifact · <code>art_growth_q3</code></div>
166
+ <!-- A matterfact artifact embedded in the customer's page. The agent spots it by
167
+ origin and reads the data behind it — ask "summarise the Q3 model". (This id
168
+ isn't seeded in local dev, so the frame is empty here; the agent detects it
169
+ from the URL regardless — it never reads the rendered pixels.) -->
170
+ <iframe src="https://app.matterfact.com/artifacts/art_growth_q3" title="Q3 Revenue Model"></iframe>
171
+ </div>
172
+ <p class="artifact-caption">
173
+ <strong>Artifact-aware:</strong> the assistant detects this embedded artifact by
174
+ its origin and can pull the real data behind it — no scraping the page.
175
+ </p>
176
+
177
+ <div class="section-title">Holdings</div>
178
+ <!-- Click a row to select it — a state change with NO url navigation. getPageContext
179
+ (below) reflects the selection, and the widget pulls it fresh each turn. -->
180
+ <table>
181
+ <thead><tr><th>Ticker</th><th>Weight</th><th>Day</th><th>YTD</th><th>Thesis</th></tr></thead>
182
+ <tbody id="holdings">
183
+ <tr data-ticker="NVDA" style="cursor:pointer"><td class="tick">NVDA</td><td>9.4%</td><td class="pos">+2.8%</td><td class="pos">+41%</td><td>AI datacenter demand</td></tr>
184
+ <tr data-ticker="MSFT" style="cursor:pointer"><td class="tick">MSFT</td><td>8.1%</td><td class="pos">+0.9%</td><td class="pos">+22%</td><td>Copilot attach</td></tr>
185
+ <tr data-ticker="UNH" style="cursor:pointer"><td class="tick">UNH</td><td>6.7%</td><td class="neg">−1.2%</td><td class="neg">−8%</td><td>MLR pressure</td></tr>
186
+ <tr data-ticker="V" style="cursor:pointer"><td class="tick">V</td><td>5.9%</td><td class="pos">+0.4%</td><td class="pos">+11%</td><td>Cross-border recovery</td></tr>
187
+ <tr data-ticker="LLY" style="cursor:pointer"><td class="tick">LLY</td><td>5.2%</td><td class="pos">+1.7%</td><td class="pos">+34%</td><td>GLP-1 ramp</td></tr>
188
+ </tbody>
189
+ </table>
190
+ </main>
191
+
192
+ <aside id="aside">
193
+ <div class="panel-head"><span class="mf">✦</span> matterfact assistant</div>
194
+ <!-- The agent mounts HERE, into the host's own box. No launcher, no floating bubble. -->
195
+ <div id="agent-panel"></div>
196
+ </aside>
197
+ </div>
198
+
199
+ <footer>
200
+ inline placement via <code>data-container="#agent-panel"</code> — add
201
+ <code>?mfdev=1</code> to this URL to see what the agent sees
202
+ </footer>
203
+
204
+ <script>
205
+ // What the user has selected — a state change with no URL navigation. This is exactly
206
+ // the case a STATIC window.matterfact.context can't express: it'd be read once and go
207
+ // stale the moment you click a row.
208
+ let selectedTicker = null;
209
+
210
+ // PULL-BASED context (the script-tag counterpart to the React `getPageContext` prop).
211
+ // The widget calls this at the start of every turn, so the current selection always
212
+ // rides along — no navigation needed to flush it. (A host with fully static context can
213
+ // still use `window.matterfact = { context: {...} }` instead; this supersedes it.)
214
+ window.matterfact = {
215
+ getPageContext: () => ({
216
+ route: '/portfolios/growth-sleeve',
217
+ description:
218
+ 'Growth Sleeve portfolio — 12 holdings, $48.2M, +18.7% YTD, 2.1% behind the ' +
219
+ 'S&P 500.' + (selectedTicker ? ` The user has selected ${selectedTicker}.` : ''),
220
+ entities: [
221
+ { kind: 'x:ticker', id: 'NVDA', label: 'NVDA', data: { weight: 0.094 } },
222
+ { kind: 'x:ticker', id: 'MSFT', label: 'MSFT', data: { weight: 0.081 } },
223
+ { kind: 'x:ticker', id: 'LLY', label: 'LLY', data: { weight: 0.052 } },
224
+ ],
225
+ data: { selectedHolding: selectedTicker },
226
+ }),
227
+ };
228
+
229
+ // Row selection: set the state and highlight. No navigation — the next turn still
230
+ // learns about it because getPageContext is pulled fresh.
231
+ document.getElementById('holdings').addEventListener('click', (e) => {
232
+ const row = e.target.closest('tr[data-ticker]');
233
+ if (!row) return;
234
+ selectedTicker = row.dataset.ticker === selectedTicker ? null : row.dataset.ticker;
235
+ for (const tr of document.querySelectorAll('#holdings tr')) {
236
+ tr.style.background = tr.dataset.ticker === selectedTicker ? 'var(--surface-2)' : '';
237
+ }
238
+ });
239
+
240
+ // Host owns visibility: this button IS the open/close control. The agent draws none.
241
+ const layout = document.getElementById('layout');
242
+ document.getElementById('toggle').addEventListener('click', () => {
243
+ layout.dataset.panel = layout.dataset.panel === 'shown' ? 'hidden' : 'shown';
244
+ });
245
+ </script>
246
+
247
+ <!-- The one line a host adds. data-container puts the agent in THEIR panel.
248
+ Swap in your own publishable key and, for a single-tenant deployment, your
249
+ widget origin. In a React app the equivalent is:
250
+ import { MatterfactAgent } from '@matterfact/embed/react';
251
+ <MatterfactAgent inline publishableKey="pk_live_…" /> -->
252
+ <script type="module"
253
+ src="https://app.matterfact.com/embed/embed.js"
254
+ data-key="pk_live_yourapp_XXXXXXXX"
255
+ data-origin="https://app.matterfact.com"
256
+ data-container="#agent-panel"
257
+ data-surface="growth-sleeve"></script>
258
+ </body>
259
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matterfact/embed",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "The matterfact embeddable agent: mount the chat in a cross-origin iframe (a <script> loader for any site, or a <MatterfactAgent> React component), give the agent eyes on the host page, and embed matterfact artifacts inline with <MatterfactArtifact>.",
5
5
  "license": "Apache-2.0",
6
6
  "private": false,
@@ -9,7 +9,8 @@
9
9
  "access": "public"
10
10
  },
11
11
  "files": [
12
- "dist"
12
+ "dist",
13
+ "examples"
13
14
  ],
14
15
  "exports": {
15
16
  ".": {