@protolabsai/ui 0.18.0 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protolabsai/ui",
3
- "version": "0.18.0",
3
+ "version": "0.19.1",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"
@@ -22,10 +22,13 @@
22
22
  "./menu": "./src/menu.tsx",
23
23
  "./app-shell": "./src/app-shell.tsx",
24
24
  "./theming": "./src/theming.tsx",
25
- "./styles.css": "./src/styles.css"
25
+ "./styles.css": "./src/styles.css",
26
+ "./plugin-kit.css": "./dist/plugin-kit.css",
27
+ "./plugin-kit.js": "./src/plugin-kit.js"
26
28
  },
27
29
  "files": [
28
- "src"
30
+ "src",
31
+ "dist"
29
32
  ],
30
33
  "dependencies": {
31
34
  "@dnd-kit/core": "^6.3.1",
@@ -54,6 +57,8 @@
54
57
  "vite": "^6.0.0"
55
58
  },
56
59
  "scripts": {
60
+ "build": "node scripts/build-plugin-kit.mjs",
61
+ "build:plugin-kit": "node scripts/build-plugin-kit.mjs",
57
62
  "storybook": "storybook dev -p 6006 --no-open",
58
63
  "build-storybook": "storybook build -o storybook-static",
59
64
  "typecheck": "tsc --noEmit"
@@ -47,7 +47,10 @@ function Sample() {
47
47
  export const LiveEditor: Story = {
48
48
  render: () => (
49
49
  <div style={{ display: "flex", gap: 24, alignItems: "flex-start", padding: 24, flexWrap: "wrap" }}>
50
- <ThemePanel />
50
+ {/* The panel fills its container — the host sizes it (here a 400×560 box). */}
51
+ <div style={{ width: 400, height: 560 }}>
52
+ <ThemePanel />
53
+ </div>
51
54
  <div style={{ flex: "1 1 360px" }}>
52
55
  <Sample />
53
56
  </div>
@@ -0,0 +1,94 @@
1
+ // @protolabsai/ui/plugin-kit — the protoAgent console handshake for plugin iframe
2
+ // pages, wired to the DS. The console (protoAgent ADR 0038 theming bridge) posts a
3
+ // CURATED theme — `{ bg, bgPanel, fg, fgMuted, brand, border }`, read from the
4
+ // console's own CSS vars — NOT the full --pl-* set. This bridges those six keys onto
5
+ // the --pl-* tokens that plugin-kit.css components consume, so the DS components
6
+ // re-skin to the operator's live theme. The rest of the --pl-* tokens keep the kit's
7
+ // (coherent dark) defaults. See protoAgent docs/guides/plugin-views.md +
8
+ // examples/plugins/chat_example.
9
+ //
10
+ // Two ways to use it (no build step for either):
11
+ // 1. <script type="module">: import { initPluginView } from ".../plugin-kit.js"
12
+ // 2. classic <script src=".../plugin-kit.js">: use the window.protoPluginView global
13
+ // Or inline the snippet from docs/how-to/build-a-plugin-view.md.
14
+
15
+ // Curated console key → the --pl-* token(s) the DS components actually read.
16
+ const TOKEN_MAP = {
17
+ bg: ["--pl-color-bg"],
18
+ bgPanel: ["--pl-color-bg-raised", "--pl-color-bg-subtle"],
19
+ fg: ["--pl-color-fg"],
20
+ fgMuted: ["--pl-color-fg-muted"],
21
+ brand: ["--pl-color-accent"], // components key off --pl-color-accent (== brand lavender)
22
+ border: ["--pl-color-border"],
23
+ };
24
+
25
+ let token = null;
26
+ const listeners = new Set();
27
+
28
+ /** Map the console's curated theme onto the DS --pl-* tokens on :root. Also passes
29
+ * through any key already in --pl-* form, so a future console that sends raw tokens
30
+ * Just Works. Unknown keys are ignored — a plugin page can never set an arbitrary
31
+ * CSS property this way. */
32
+ function applyTheme(theme) {
33
+ if (!theme || typeof theme !== "object") return;
34
+ const root = document.documentElement;
35
+ for (const [key, value] of Object.entries(theme)) {
36
+ if (value == null || value === "") continue;
37
+ const v = String(value);
38
+ if (key.startsWith("--pl-")) {
39
+ root.style.setProperty(key, v);
40
+ continue;
41
+ }
42
+ const targets = TOKEN_MAP[key];
43
+ if (targets) for (const cssVar of targets) root.style.setProperty(cssVar, v);
44
+ }
45
+ }
46
+
47
+ function onMessage(e) {
48
+ const d = e && e.data;
49
+ if (!d) return;
50
+ // `protoagent:init` carries token + theme (after iframe load); `protoagent:theme`
51
+ // is the live re-theme on an operator theme switch.
52
+ if (d.type === "protoagent:init") {
53
+ if (d.token) token = d.token;
54
+ applyTheme(d.theme);
55
+ } else if (d.type === "protoagent:theme") {
56
+ applyTheme(d.theme);
57
+ } else {
58
+ return;
59
+ }
60
+ for (const fn of listeners) {
61
+ try {
62
+ fn({ token, theme: d.theme });
63
+ } catch (_) {
64
+ /* a listener throwing must not break the handshake */
65
+ }
66
+ }
67
+ }
68
+
69
+ /** Start listening for the console handshake. Call once on load. `onInit` (optional)
70
+ * fires on the initial bearer+theme AND on every live re-theme. Returns a handle
71
+ * with the current token. */
72
+ export function initPluginView(onInit) {
73
+ if (typeof onInit === "function") listeners.add(onInit);
74
+ window.addEventListener("message", onMessage);
75
+ return { getToken };
76
+ }
77
+
78
+ /** The captured bearer token (null until the handshake delivers one). */
79
+ export function getToken() {
80
+ return token;
81
+ }
82
+
83
+ /** Same-origin fetch with the bearer token attached when present. */
84
+ export function apiFetch(input, init) {
85
+ const opts = init || {};
86
+ const headers = new Headers(opts.headers || {});
87
+ if (token) headers.set("Authorization", "Bearer " + token);
88
+ return fetch(input, { ...opts, headers });
89
+ }
90
+
91
+ // Expose a global for classic <script src> (no-build) pages that can't use imports.
92
+ if (typeof window !== "undefined") {
93
+ window.protoPluginView = { initPluginView, getToken, apiFetch };
94
+ }
@@ -5,7 +5,7 @@
5
5
  display: flex;
6
6
  flex-direction: column;
7
7
  width: 100%;
8
- max-width: 440px;
8
+ height: 100%;
9
9
  color: var(--pl-color-fg);
10
10
  font-size: 13px;
11
11
  background: var(--pl-color-bg-raised);
@@ -71,8 +71,9 @@
71
71
  .pl-theme-panel__groups {
72
72
  display: flex;
73
73
  flex-direction: column;
74
+ flex: 1;
75
+ min-height: 0;
74
76
  gap: var(--pl-space-4);
75
- max-height: 460px;
76
77
  padding: var(--pl-space-3);
77
78
  overflow-y: auto;
78
79
  }