@gravity-platform/unoverse-react 0.0.2 → 0.0.4

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/dist/index.d.cts CHANGED
@@ -86,8 +86,14 @@ interface UnoverseComponentProps {
86
86
  * (e.g. the workbench's light/dark toggle); swap it to restyle, zero def changes.
87
87
  */
88
88
  theme?: ResolvedTheme;
89
+ /**
90
+ * Render inside a Shadow DOM for full CSS isolation (default true). The SDK owns the
91
+ * isolation boundary so every consumer is protected identically; the canvas/channel no
92
+ * longer wrap it themselves. Set false only for a host that manages its own isolation.
93
+ */
94
+ isolate?: boolean;
89
95
  }
90
- declare function UnoverseComponent({ client, uri, data, onAction, theme }: UnoverseComponentProps): react.JSX.Element;
96
+ declare function UnoverseComponent({ client, uri, data, onAction, theme, isolate }: UnoverseComponentProps): react.JSX.Element;
91
97
 
92
98
  /** Subscribe to a component instance in the store (re-renders on merge). */
93
99
  declare function useUnoverseInstance(store: ComponentStore, chatId: string, nodeId: string): {
@@ -118,14 +124,20 @@ interface StreamedUnoverseTemplateProps {
118
124
  /** Channel overrides for the template's declared props (e.g. per-tenant logoUrl/brandName).
119
125
  * Merged OVER the definition's own `props` defaults into the root data scope. */
120
126
  props?: Record<string, unknown>;
127
+ /** Render inside a Shadow DOM for full CSS isolation (default true). See UnoverseComponent. */
128
+ isolate?: boolean;
121
129
  }
122
130
  /** Resolve a ComponentSlot's `select` against the store → ordered pointers. Exported for testing. */
123
131
  declare function selectPointers(store: ComponentStore, node: UnoverseNode): string[];
124
- declare function StreamedUnoverseTemplate({ client, store, uri, onAction, theme: themeProp, props }: StreamedUnoverseTemplateProps): react.JSX.Element;
132
+ declare function StreamedUnoverseTemplate({ client, store, uri, onAction, theme: themeProp, props, isolate }: StreamedUnoverseTemplateProps): react.JSX.Element;
125
133
 
126
134
  /** Returns the resolved theme (null until the first fetch resolves). */
127
135
  declare function useUnoverseTheme(client: UnoverseClient, name?: string): ResolvedTheme | null;
128
136
 
137
+ declare function IsolatedRoot({ children }: {
138
+ children: ReactNode;
139
+ }): react.JSX.Element;
140
+
129
141
  interface UnoverseConnectionConfig {
130
142
  /** Gravity API base, e.g. "http://localhost:4100". REST execute lives here. */
131
143
  apiUrl: string;
@@ -163,4 +175,4 @@ declare function useUnoverseConnection(config: UnoverseConnectionConfig, session
163
175
  enabled?: boolean;
164
176
  }): UnoverseConnection;
165
177
 
166
- export { type ActionHandler, type SlotResolver, StreamedUnoverseComponent, type StreamedUnoverseComponentProps, StreamedUnoverseTemplate, type StreamedUnoverseTemplateProps, UnoverseComponent, type UnoverseComponentProps, type UnoverseConnection, type UnoverseConnectionConfig, type UnoverseSessionParams, keyframesCss, renderNode, selectPointers, styleToCss, useUnoverseConnection, useUnoverseInstance, useUnoverseTheme };
178
+ export { type ActionHandler, IsolatedRoot, type SlotResolver, StreamedUnoverseComponent, type StreamedUnoverseComponentProps, StreamedUnoverseTemplate, type StreamedUnoverseTemplateProps, UnoverseComponent, type UnoverseComponentProps, type UnoverseConnection, type UnoverseConnectionConfig, type UnoverseSessionParams, keyframesCss, renderNode, selectPointers, styleToCss, useUnoverseConnection, useUnoverseInstance, useUnoverseTheme };
package/dist/index.d.ts CHANGED
@@ -86,8 +86,14 @@ interface UnoverseComponentProps {
86
86
  * (e.g. the workbench's light/dark toggle); swap it to restyle, zero def changes.
87
87
  */
88
88
  theme?: ResolvedTheme;
89
+ /**
90
+ * Render inside a Shadow DOM for full CSS isolation (default true). The SDK owns the
91
+ * isolation boundary so every consumer is protected identically; the canvas/channel no
92
+ * longer wrap it themselves. Set false only for a host that manages its own isolation.
93
+ */
94
+ isolate?: boolean;
89
95
  }
90
- declare function UnoverseComponent({ client, uri, data, onAction, theme }: UnoverseComponentProps): react.JSX.Element;
96
+ declare function UnoverseComponent({ client, uri, data, onAction, theme, isolate }: UnoverseComponentProps): react.JSX.Element;
91
97
 
92
98
  /** Subscribe to a component instance in the store (re-renders on merge). */
93
99
  declare function useUnoverseInstance(store: ComponentStore, chatId: string, nodeId: string): {
@@ -118,14 +124,20 @@ interface StreamedUnoverseTemplateProps {
118
124
  /** Channel overrides for the template's declared props (e.g. per-tenant logoUrl/brandName).
119
125
  * Merged OVER the definition's own `props` defaults into the root data scope. */
120
126
  props?: Record<string, unknown>;
127
+ /** Render inside a Shadow DOM for full CSS isolation (default true). See UnoverseComponent. */
128
+ isolate?: boolean;
121
129
  }
122
130
  /** Resolve a ComponentSlot's `select` against the store → ordered pointers. Exported for testing. */
123
131
  declare function selectPointers(store: ComponentStore, node: UnoverseNode): string[];
124
- declare function StreamedUnoverseTemplate({ client, store, uri, onAction, theme: themeProp, props }: StreamedUnoverseTemplateProps): react.JSX.Element;
132
+ declare function StreamedUnoverseTemplate({ client, store, uri, onAction, theme: themeProp, props, isolate }: StreamedUnoverseTemplateProps): react.JSX.Element;
125
133
 
126
134
  /** Returns the resolved theme (null until the first fetch resolves). */
127
135
  declare function useUnoverseTheme(client: UnoverseClient, name?: string): ResolvedTheme | null;
128
136
 
137
+ declare function IsolatedRoot({ children }: {
138
+ children: ReactNode;
139
+ }): react.JSX.Element;
140
+
129
141
  interface UnoverseConnectionConfig {
130
142
  /** Gravity API base, e.g. "http://localhost:4100". REST execute lives here. */
131
143
  apiUrl: string;
@@ -163,4 +175,4 @@ declare function useUnoverseConnection(config: UnoverseConnectionConfig, session
163
175
  enabled?: boolean;
164
176
  }): UnoverseConnection;
165
177
 
166
- export { type ActionHandler, type SlotResolver, StreamedUnoverseComponent, type StreamedUnoverseComponentProps, StreamedUnoverseTemplate, type StreamedUnoverseTemplateProps, UnoverseComponent, type UnoverseComponentProps, type UnoverseConnection, type UnoverseConnectionConfig, type UnoverseSessionParams, keyframesCss, renderNode, selectPointers, styleToCss, useUnoverseConnection, useUnoverseInstance, useUnoverseTheme };
178
+ export { type ActionHandler, IsolatedRoot, type SlotResolver, StreamedUnoverseComponent, type StreamedUnoverseComponentProps, StreamedUnoverseTemplate, type StreamedUnoverseTemplateProps, UnoverseComponent, type UnoverseComponentProps, type UnoverseConnection, type UnoverseConnectionConfig, type UnoverseSessionParams, keyframesCss, renderNode, selectPointers, styleToCss, useUnoverseConnection, useUnoverseInstance, useUnoverseTheme };
package/dist/index.js CHANGED
@@ -6885,7 +6885,7 @@ var require_dist = __commonJS({
6885
6885
  });
6886
6886
 
6887
6887
  // src/UnoverseComponent.tsx
6888
- import { useEffect as useEffect2, useState as useState3 } from "react";
6888
+ import { useEffect as useEffect3, useState as useState4 } from "react";
6889
6889
 
6890
6890
  // src/primitives.tsx
6891
6891
  import { createElement, useMemo, useState } from "react";
@@ -7192,14 +7192,43 @@ function useUnoverseTheme(client, name = "light") {
7192
7192
  return theme;
7193
7193
  }
7194
7194
 
7195
- // src/UnoverseComponent.tsx
7195
+ // src/isolate.tsx
7196
+ import { useEffect as useEffect2, useRef, useState as useState3 } from "react";
7197
+ import { createPortal } from "react-dom";
7196
7198
  import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
7197
- function UnoverseComponent({ client, uri, data, onAction, theme }) {
7198
- const [def, setDef] = useState3(null);
7199
- const [error2, setError] = useState3(null);
7199
+ var RESET_CSS = `
7200
+ :host { all: initial; display: contents; }
7201
+ .uno-isolate-root { box-sizing: border-box; }
7202
+ .uno-isolate-root *, .uno-isolate-root *::before, .uno-isolate-root *::after { box-sizing: border-box; }
7203
+ .uno-isolate-root button, .uno-isolate-root input, .uno-isolate-root textarea, .uno-isolate-root select {
7204
+ font: inherit; letter-spacing: inherit; color: inherit; margin: 0;
7205
+ }
7206
+ `;
7207
+ function IsolatedRoot({ children }) {
7208
+ const hostRef = useRef(null);
7209
+ const [shadow, setShadow] = useState3(null);
7210
+ useEffect2(() => {
7211
+ const host = hostRef.current;
7212
+ if (!host) return;
7213
+ setShadow(host.shadowRoot ?? host.attachShadow({ mode: "open" }));
7214
+ }, []);
7215
+ return /* @__PURE__ */ jsx3("div", { ref: hostRef, style: { display: "contents" }, children: shadow && createPortal(
7216
+ /* @__PURE__ */ jsxs2(Fragment, { children: [
7217
+ /* @__PURE__ */ jsx3("style", { children: RESET_CSS }),
7218
+ /* @__PURE__ */ jsx3("div", { className: "uno-isolate-root", children })
7219
+ ] }),
7220
+ shadow
7221
+ ) });
7222
+ }
7223
+
7224
+ // src/UnoverseComponent.tsx
7225
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
7226
+ function UnoverseComponent({ client, uri, data, onAction, theme, isolate = true }) {
7227
+ const [def, setDef] = useState4(null);
7228
+ const [error2, setError] = useState4(null);
7200
7229
  const fetched = useUnoverseTheme(client, "light");
7201
7230
  const activeTheme = theme ?? fetched;
7202
- useEffect2(() => {
7231
+ useEffect3(() => {
7203
7232
  let alive = true;
7204
7233
  setDef(null);
7205
7234
  setError(null);
@@ -7208,11 +7237,11 @@ function UnoverseComponent({ client, uri, data, onAction, theme }) {
7208
7237
  alive = false;
7209
7238
  };
7210
7239
  }, [client, uri]);
7211
- if (error2) return /* @__PURE__ */ jsxs2("div", { children: [
7240
+ if (error2) return /* @__PURE__ */ jsxs3("div", { children: [
7212
7241
  "Unoverse error: ",
7213
7242
  error2
7214
7243
  ] });
7215
- if (!def || !activeTheme) return /* @__PURE__ */ jsxs2("div", { children: [
7244
+ if (!def || !activeTheme) return /* @__PURE__ */ jsxs3("div", { children: [
7216
7245
  "Loading ",
7217
7246
  uri,
7218
7247
  "\u2026"
@@ -7220,17 +7249,18 @@ function UnoverseComponent({ client, uri, data, onAction, theme }) {
7220
7249
  const propDefaults2 = Object.fromEntries(
7221
7250
  Object.entries(def.props ?? {}).map(([k, v]) => [k, v?.default])
7222
7251
  );
7223
- const merged = { ...propDefaults2, ...data ?? {} };
7224
- return /* @__PURE__ */ jsxs2(Fragment, { children: [
7225
- /* @__PURE__ */ jsx3("style", { children: keyframesCss(activeTheme) }),
7226
- /* @__PURE__ */ jsx3("div", { style: { display: "contents", ...activeTheme.root }, children: renderNode(def.root, merged, onAction, activeTheme) })
7252
+ const merged = data ?? propDefaults2;
7253
+ const body = /* @__PURE__ */ jsxs3(Fragment2, { children: [
7254
+ /* @__PURE__ */ jsx4("style", { children: keyframesCss(activeTheme) }),
7255
+ /* @__PURE__ */ jsx4("div", { style: { display: "contents", ...activeTheme.root }, children: renderNode(def.root, merged, onAction, activeTheme) })
7227
7256
  ] });
7257
+ return isolate ? /* @__PURE__ */ jsx4(IsolatedRoot, { children: body }) : body;
7228
7258
  }
7229
7259
 
7230
7260
  // src/streamed.tsx
7231
7261
  import { useCallback, useMemo as useMemo2, useSyncExternalStore } from "react";
7232
7262
  import { dispatchAction } from "@gravity-platform/unoverse-core";
7233
- import { jsx as jsx4 } from "react/jsx-runtime";
7263
+ import { jsx as jsx5 } from "react/jsx-runtime";
7234
7264
  function useUnoverseInstance(store, chatId, nodeId) {
7235
7265
  const subscribe = useCallback((cb) => store.subscribe(cb), [store]);
7236
7266
  const getVersion = useCallback(() => store.getVersion(), [store]);
@@ -7248,14 +7278,14 @@ function StreamedUnoverseComponent({ client, store, chatId, nodeId, onAction, th
7248
7278
  }),
7249
7279
  [store, chatId, nodeId, onAction]
7250
7280
  );
7251
- if (!type) return /* @__PURE__ */ jsx4("div", { children: "waiting for COMPONENT_INIT\u2026" });
7281
+ if (!type) return /* @__PURE__ */ jsx5("div", { children: "waiting for COMPONENT_INIT\u2026" });
7252
7282
  const merged = extraData ? { ...data, ...extraData } : data;
7253
- return /* @__PURE__ */ jsx4(UnoverseComponent, { client, uri: `unoverse://components/${type}`, data: merged, onAction: handleAction, theme });
7283
+ return /* @__PURE__ */ jsx5(UnoverseComponent, { client, uri: `unoverse://components/${type}`, data: merged, onAction: handleAction, theme });
7254
7284
  }
7255
7285
 
7256
7286
  // src/template.tsx
7257
- import { useEffect as useEffect3, useState as useState4, useSyncExternalStore as useSyncExternalStore2 } from "react";
7258
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
7287
+ import { useEffect as useEffect4, useState as useState5, useSyncExternalStore as useSyncExternalStore2 } from "react";
7288
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
7259
7289
  function propDefaults(props) {
7260
7290
  const out = {};
7261
7291
  for (const [k, v] of Object.entries(props ?? {})) {
@@ -7286,16 +7316,16 @@ function selectPointers(store, node) {
7286
7316
  if (sel.limit != null) pointers = pointers.slice(0, sel.limit);
7287
7317
  return pointers;
7288
7318
  }
7289
- function StreamedUnoverseTemplate({ client, store, uri, onAction, theme: themeProp, props }) {
7290
- const [def, setDef] = useState4(null);
7291
- const [error2, setError] = useState4(null);
7319
+ function StreamedUnoverseTemplate({ client, store, uri, onAction, theme: themeProp, props, isolate = true }) {
7320
+ const [def, setDef] = useState5(null);
7321
+ const [error2, setError] = useState5(null);
7292
7322
  const fetched = useUnoverseTheme(client, "light");
7293
7323
  const theme = themeProp ?? fetched;
7294
7324
  useSyncExternalStore2(
7295
7325
  (cb) => store.subscribe(cb),
7296
7326
  () => store.getVersion()
7297
7327
  );
7298
- useEffect3(() => {
7328
+ useEffect4(() => {
7299
7329
  let alive = true;
7300
7330
  setDef(null);
7301
7331
  setError(null);
@@ -7304,18 +7334,18 @@ function StreamedUnoverseTemplate({ client, store, uri, onAction, theme: themePr
7304
7334
  alive = false;
7305
7335
  };
7306
7336
  }, [client, uri]);
7307
- if (error2) return /* @__PURE__ */ jsxs3("div", { children: [
7337
+ if (error2) return /* @__PURE__ */ jsxs4("div", { children: [
7308
7338
  "Unoverse error: ",
7309
7339
  error2
7310
7340
  ] });
7311
- if (!def || !theme) return /* @__PURE__ */ jsxs3("div", { children: [
7341
+ if (!def || !theme) return /* @__PURE__ */ jsxs4("div", { children: [
7312
7342
  "Loading ",
7313
7343
  uri,
7314
7344
  "\u2026"
7315
7345
  ] });
7316
7346
  const leaf = (pointer, extraData) => {
7317
7347
  const { chatId, nodeId } = store.split(pointer);
7318
- return /* @__PURE__ */ jsx5(StreamedUnoverseComponent, { client, store, chatId, nodeId, onAction, theme, extraData }, pointer);
7348
+ return /* @__PURE__ */ jsx6(StreamedUnoverseComponent, { client, store, chatId, nodeId, onAction, theme, extraData }, pointer);
7319
7349
  };
7320
7350
  const resolveSlot = (node, key) => {
7321
7351
  const pointers = selectPointers(store, node);
@@ -7325,7 +7355,7 @@ function StreamedUnoverseTemplate({ client, store, uri, onAction, theme: themePr
7325
7355
  return pointers.map((p) => leaf(p));
7326
7356
  };
7327
7357
  const resolveTimeline = (node, key) => {
7328
- return /* @__PURE__ */ jsx5("div", { style: styleToCss(node.style, theme), children: store.getTimeline().map((turn) => {
7358
+ return /* @__PURE__ */ jsx6("div", { style: styleToCss(node.style, theme), children: store.getTimeline().map((turn) => {
7329
7359
  const sub = turn.role === "user" ? node.user : node.assistant;
7330
7360
  if (!sub) return null;
7331
7361
  const turnSlot = (slotNode, k) => {
@@ -7364,14 +7394,15 @@ function StreamedUnoverseTemplate({ client, store, uri, onAction, theme: themePr
7364
7394
  // button submits it. Lives in the store (shared state), not locally in Input.
7365
7395
  draft: store.getDraft()
7366
7396
  };
7367
- return /* @__PURE__ */ jsxs3(Fragment2, { children: [
7368
- /* @__PURE__ */ jsx5("style", { children: keyframesCss(theme) }),
7369
- /* @__PURE__ */ jsx5("div", { style: { display: "contents", ...theme.root }, children: renderNode(def.root, rootData, onAction, theme, void 0, resolve) })
7397
+ const body = /* @__PURE__ */ jsxs4(Fragment3, { children: [
7398
+ /* @__PURE__ */ jsx6("style", { children: keyframesCss(theme) }),
7399
+ /* @__PURE__ */ jsx6("div", { style: { display: "contents", ...theme.root }, children: renderNode(def.root, rootData, onAction, theme, void 0, resolve) })
7370
7400
  ] });
7401
+ return isolate ? /* @__PURE__ */ jsx6(IsolatedRoot, { children: body }) : body;
7371
7402
  }
7372
7403
 
7373
7404
  // src/connection.tsx
7374
- import { useCallback as useCallback2, useEffect as useEffect4, useRef, useState as useState5, useSyncExternalStore as useSyncExternalStore3 } from "react";
7405
+ import { useCallback as useCallback2, useEffect as useEffect5, useRef as useRef2, useState as useState6, useSyncExternalStore as useSyncExternalStore3 } from "react";
7375
7406
  import { applyServerMessage } from "@gravity-platform/unoverse-core";
7376
7407
 
7377
7408
  // ../node_modules/zod/v4/core/core.js
@@ -17596,11 +17627,11 @@ function useUnoverseConnection(config2, session, store, options = {}) {
17596
17627
  const { apiUrl, streamUrl, getAccessToken } = config2;
17597
17628
  const { workflowId, targetTriggerNode, userId, conversationId } = session;
17598
17629
  const chatId = session.chatId ?? conversationId;
17599
- const [isConnected, setIsConnected] = useState5(false);
17600
- const [isReady, setIsReady] = useState5(false);
17601
- const clientRef = useRef(null);
17602
- const seenRef = useRef(/* @__PURE__ */ new Set());
17603
- useEffect4(() => {
17630
+ const [isConnected, setIsConnected] = useState6(false);
17631
+ const [isReady, setIsReady] = useState6(false);
17632
+ const clientRef = useRef2(null);
17633
+ const seenRef = useRef2(/* @__PURE__ */ new Set());
17634
+ useEffect5(() => {
17604
17635
  if (!enabled) return;
17605
17636
  if (!workflowId || !userId || !conversationId) {
17606
17637
  console.warn("[unoverse] connection missing workflowId/userId/conversationId");
@@ -17700,6 +17731,7 @@ function useUnoverseConnection(config2, session, store, options = {}) {
17700
17731
  return { isConnected, isReady, sendMessage, trigger, sendAction, activeTemplate };
17701
17732
  }
17702
17733
  export {
17734
+ IsolatedRoot,
17703
17735
  StreamedUnoverseComponent,
17704
17736
  StreamedUnoverseTemplate,
17705
17737
  UnoverseComponent,