@june-ai/june-ui 0.1.1 → 0.2.2

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 CHANGED
@@ -1,66 +1,66 @@
1
- # @june-ai/june-ui
2
-
3
- React Generative UI SDK built on [OpenUI](https://github.com/thesysdev/openui). June adds streaming
4
- helpers, themes, safe actions, error recovery, and library validation. OpenUI does all parsing and
5
- rendering.
6
-
7
- ## Install
8
-
9
- ```bash
10
- npm install @june-ai/june-ui
11
- ```
12
-
13
- Import styles once in your app entry:
14
-
15
- ```ts
16
- import "@openuidev/react-ui/components.css"; // OpenUI built-in components
17
- import "@june-ai/june-ui/styles.css"; // June theme variables
18
- ```
19
-
20
- ## Usage
21
-
22
- ```tsx
23
- import { JuneUI } from "@june-ai/june-ui";
24
-
25
- <JuneUI response={response} isStreaming={isStreaming} theme="system" onJuneError={console.error} />
26
- ```
27
-
28
- ### Streaming (works with any backend)
29
-
30
- ```tsx
31
- const stream = useJuneStream();
32
- stream.startFetch("/api/generate", { method: "POST", body, sse: false }); // sse: true for SSE
33
- <JuneUI response={stream.response} isStreaming={stream.isStreaming} />
34
- ```
35
-
36
- ### Custom library
37
-
38
- ```tsx
39
- import { createJuneLibrary } from "@june-ai/june-ui";
40
- const library = createJuneLibrary({ root: "Stack", components: [Stack, Card] }); // module scope
41
- <JuneUI library={library} response={response} />
42
- ```
43
-
44
- ### Actions
45
-
46
- ```tsx
47
- const actions = { submit: defineJuneAction({ schema, sensitive: true, handler }) };
48
- <JuneUI actions={actions} confirmAction={({ name }) => window.confirm(name)} ... />
49
- ```
50
- Model output never executes code. Only actions you registered by name can run, and sensitive
51
- actions are denied unless confirmed.
52
-
53
- ### Lightweight entry
54
-
55
- `@june-ai/june-ui/core` exports `JuneRenderer`, which requires your own `library` and does not
56
- import OpenUI's built-in component library.
57
-
58
- ## OpenUI features
59
-
60
- Tool providers, query loaders, state callbacks, and parse-result callbacks are forwarded to
61
- OpenUI's `Renderer` as props. See OpenUI's docs for their behaviour. Never put API keys in the
62
- browser; do tool/MCP calls in your backend.
63
-
64
- ## Requirements
65
-
1
+ # @june-ai/june-ui
2
+
3
+ React Generative UI SDK built on [OpenUI](https://github.com/thesysdev/openui). June adds streaming
4
+ helpers, themes, safe actions, error recovery, and library validation. OpenUI does all parsing and
5
+ rendering.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @june-ai/june-ui
11
+ ```
12
+
13
+ Import styles once in your app entry:
14
+
15
+ ```ts
16
+ import "@openuidev/react-ui/components.css"; // OpenUI built-in components
17
+ import "@june-ai/june-ui/styles.css"; // June theme variables
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```tsx
23
+ import { JuneUI } from "@june-ai/june-ui";
24
+
25
+ <JuneUI response={response} isStreaming={isStreaming} theme="system" onJuneError={console.error} />
26
+ ```
27
+
28
+ ### Streaming (works with any backend)
29
+
30
+ ```tsx
31
+ const stream = useJuneStream();
32
+ stream.startFetch("/api/generate", { method: "POST", body, sse: false }); // sse: true for SSE
33
+ <JuneUI response={stream.response} isStreaming={stream.isStreaming} />
34
+ ```
35
+
36
+ ### Custom library
37
+
38
+ ```tsx
39
+ import { createJuneLibrary } from "@june-ai/june-ui";
40
+ const library = createJuneLibrary({ root: "Stack", components: [Stack, Card] }); // module scope
41
+ <JuneUI library={library} response={response} />
42
+ ```
43
+
44
+ ### Actions
45
+
46
+ ```tsx
47
+ const actions = { submit: defineJuneAction({ schema, sensitive: true, handler }) };
48
+ <JuneUI actions={actions} confirmAction={({ name }) => window.confirm(name)} ... />
49
+ ```
50
+ Model output never executes code. Only actions you registered by name can run, and sensitive
51
+ actions are denied unless confirmed.
52
+
53
+ ### Lightweight entry
54
+
55
+ `@june-ai/june-ui/core` exports `JuneRenderer`, which requires your own `library` and does not
56
+ import OpenUI's built-in component library.
57
+
58
+ ## OpenUI features
59
+
60
+ Tool providers, query loaders, state callbacks, and parse-result callbacks are forwarded to
61
+ OpenUI's `Renderer` as props. See OpenUI's docs for their behaviour. Never put API keys in the
62
+ browser; do tool/MCP calls in your backend.
63
+
64
+ ## Requirements
65
+
66
66
  React 18.3.1+ or 19, plus the OpenUI peer dependencies listed in package.json.
package/dist/index.cjs CHANGED
@@ -148,26 +148,20 @@ function useJuneTheme() {
148
148
 
149
149
  // src/themes/dark.ts
150
150
  var darkTheme = {
151
- "--june-background": "#0b0f19",
152
151
  "--june-foreground": "#f3f4f6",
153
152
  "--june-muted": "#9ca3af",
154
153
  "--june-border": "#1f2937",
155
154
  "--june-accent": "#818cf8",
156
- "--june-danger": "#f87171",
157
- "--june-radius": "8px",
158
- "--june-font-family": "system-ui, -apple-system, 'Segoe UI', sans-serif"
155
+ "--june-danger": "#f87171"
159
156
  };
160
157
 
161
158
  // src/themes/light.ts
162
159
  var lightTheme = {
163
- "--june-background": "#ffffff",
164
160
  "--june-foreground": "#111827",
165
161
  "--june-muted": "#6b7280",
166
162
  "--june-border": "#e5e7eb",
167
163
  "--june-accent": "#4f46e5",
168
- "--june-danger": "#b91c1c",
169
- "--june-radius": "8px",
170
- "--june-font-family": "system-ui, -apple-system, 'Segoe UI', sans-serif"
164
+ "--june-danger": "#b91c1c"
171
165
  };
172
166
 
173
167
  // src/themes/theme-provider.tsx
@@ -192,23 +186,33 @@ function useResolvedTheme(mode) {
192
186
  return mode === "system" ? system : mode;
193
187
  }
194
188
  function JuneThemeProvider({
195
- mode = "light",
189
+ mode,
196
190
  vars,
197
191
  className,
198
192
  style,
199
193
  children
200
194
  }) {
201
- const resolved = useResolvedTheme(mode);
195
+ const explicit = mode !== void 0;
196
+ const resolved = useResolvedTheme(mode ?? "system");
202
197
  const mergedStyle = (0, import_react2.useMemo)(() => {
203
- const base = resolved === "dark" ? darkTheme : lightTheme;
204
- return { ...base, ...vars, colorScheme: resolved, ...style };
205
- }, [resolved, vars, style]);
206
- const context = (0, import_react2.useMemo)(() => ({ mode, theme: resolved }), [mode, resolved]);
198
+ if (!explicit && !vars && !style) return void 0;
199
+ const base = explicit ? resolved === "dark" ? darkTheme : lightTheme : void 0;
200
+ return {
201
+ ...base,
202
+ ...vars,
203
+ ...explicit ? { colorScheme: resolved } : {},
204
+ ...style
205
+ };
206
+ }, [explicit, resolved, vars, style]);
207
+ const context = (0, import_react2.useMemo)(
208
+ () => ({ mode: mode ?? "system", theme: resolved }),
209
+ [mode, resolved]
210
+ );
207
211
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(JuneContext.Provider, { value: context, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
208
212
  "div",
209
213
  {
210
214
  className: className ? `june-ui-root ${className}` : "june-ui-root",
211
- "data-june-theme": resolved,
215
+ "data-june-theme": explicit ? resolved : void 0,
212
216
  style: mergedStyle,
213
217
  children
214
218
  }
@@ -667,7 +671,7 @@ function JuneRenderer(props) {
667
671
  isStreaming = false,
668
672
  mixedContent = true,
669
673
  renderText,
670
- theme = "light",
674
+ theme,
671
675
  themeVars,
672
676
  className,
673
677
  style,
package/dist/index.d.cts CHANGED
@@ -89,6 +89,7 @@ declare function runAction(event: OpenUIActionEvent, options: RunActionOptions):
89
89
  declare function createActionHandler(options: RunActionOptions): (event: OpenUIActionEvent) => void;
90
90
 
91
91
  type JuneThemeVars = Record<string, string>;
92
+ /** Colors only. June never sets fonts, radii or backgrounds. */
92
93
  declare const lightTheme: JuneThemeVars;
93
94
 
94
95
  interface FallbackArgs {
@@ -149,6 +150,10 @@ declare function JuneRenderer(props: JuneRendererProps): react.JSX.Element;
149
150
 
150
151
  declare function useResolvedTheme(mode: JuneThemeMode): JuneResolvedTheme;
151
152
  interface JuneThemeProviderProps {
153
+ /**
154
+ * Omit to inherit the host app's look: no colors, fonts or color-scheme are applied.
155
+ * "light" | "dark" | "system" opt in to June's text colors.
156
+ */
152
157
  mode?: JuneThemeMode;
153
158
  /** CSS variable overrides, e.g. { "--june-accent": "#0ea5e9" }. */
154
159
  vars?: JuneThemeVars;
package/dist/index.d.ts CHANGED
@@ -89,6 +89,7 @@ declare function runAction(event: OpenUIActionEvent, options: RunActionOptions):
89
89
  declare function createActionHandler(options: RunActionOptions): (event: OpenUIActionEvent) => void;
90
90
 
91
91
  type JuneThemeVars = Record<string, string>;
92
+ /** Colors only. June never sets fonts, radii or backgrounds. */
92
93
  declare const lightTheme: JuneThemeVars;
93
94
 
94
95
  interface FallbackArgs {
@@ -149,6 +150,10 @@ declare function JuneRenderer(props: JuneRendererProps): react.JSX.Element;
149
150
 
150
151
  declare function useResolvedTheme(mode: JuneThemeMode): JuneResolvedTheme;
151
152
  interface JuneThemeProviderProps {
153
+ /**
154
+ * Omit to inherit the host app's look: no colors, fonts or color-scheme are applied.
155
+ * "light" | "dark" | "system" opt in to June's text colors.
156
+ */
152
157
  mode?: JuneThemeMode;
153
158
  /** CSS variable overrides, e.g. { "--june-accent": "#0ea5e9" }. */
154
159
  vars?: JuneThemeVars;
package/dist/index.js CHANGED
@@ -109,26 +109,20 @@ function useJuneTheme() {
109
109
 
110
110
  // src/themes/dark.ts
111
111
  var darkTheme = {
112
- "--june-background": "#0b0f19",
113
112
  "--june-foreground": "#f3f4f6",
114
113
  "--june-muted": "#9ca3af",
115
114
  "--june-border": "#1f2937",
116
115
  "--june-accent": "#818cf8",
117
- "--june-danger": "#f87171",
118
- "--june-radius": "8px",
119
- "--june-font-family": "system-ui, -apple-system, 'Segoe UI', sans-serif"
116
+ "--june-danger": "#f87171"
120
117
  };
121
118
 
122
119
  // src/themes/light.ts
123
120
  var lightTheme = {
124
- "--june-background": "#ffffff",
125
121
  "--june-foreground": "#111827",
126
122
  "--june-muted": "#6b7280",
127
123
  "--june-border": "#e5e7eb",
128
124
  "--june-accent": "#4f46e5",
129
- "--june-danger": "#b91c1c",
130
- "--june-radius": "8px",
131
- "--june-font-family": "system-ui, -apple-system, 'Segoe UI', sans-serif"
125
+ "--june-danger": "#b91c1c"
132
126
  };
133
127
 
134
128
  // src/themes/theme-provider.tsx
@@ -153,23 +147,33 @@ function useResolvedTheme(mode) {
153
147
  return mode === "system" ? system : mode;
154
148
  }
155
149
  function JuneThemeProvider({
156
- mode = "light",
150
+ mode,
157
151
  vars,
158
152
  className,
159
153
  style,
160
154
  children
161
155
  }) {
162
- const resolved = useResolvedTheme(mode);
156
+ const explicit = mode !== void 0;
157
+ const resolved = useResolvedTheme(mode ?? "system");
163
158
  const mergedStyle = useMemo(() => {
164
- const base = resolved === "dark" ? darkTheme : lightTheme;
165
- return { ...base, ...vars, colorScheme: resolved, ...style };
166
- }, [resolved, vars, style]);
167
- const context = useMemo(() => ({ mode, theme: resolved }), [mode, resolved]);
159
+ if (!explicit && !vars && !style) return void 0;
160
+ const base = explicit ? resolved === "dark" ? darkTheme : lightTheme : void 0;
161
+ return {
162
+ ...base,
163
+ ...vars,
164
+ ...explicit ? { colorScheme: resolved } : {},
165
+ ...style
166
+ };
167
+ }, [explicit, resolved, vars, style]);
168
+ const context = useMemo(
169
+ () => ({ mode: mode ?? "system", theme: resolved }),
170
+ [mode, resolved]
171
+ );
168
172
  return /* @__PURE__ */ jsx(JuneContext.Provider, { value: context, children: /* @__PURE__ */ jsx(
169
173
  "div",
170
174
  {
171
175
  className: className ? `june-ui-root ${className}` : "june-ui-root",
172
- "data-june-theme": resolved,
176
+ "data-june-theme": explicit ? resolved : void 0,
173
177
  style: mergedStyle,
174
178
  children
175
179
  }
@@ -628,7 +632,7 @@ function JuneRenderer(props) {
628
632
  isStreaming = false,
629
633
  mixedContent = true,
630
634
  renderText,
631
- theme = "light",
635
+ theme,
632
636
  themeVars,
633
637
  className,
634
638
  style,
package/dist/june.css CHANGED
@@ -1,21 +1,30 @@
1
1
  .june-ui-root {
2
- box-sizing: border-box;
3
- max-width: 100%;
4
- color: var(--june-foreground);
5
- background: var(--june-background);
6
- font-family: var(--june-font-family);
7
- border-radius: var(--june-radius);
8
- }
9
-
10
- .june-ui-root img,
11
- .june-ui-root video {
12
- max-width: 100%;
13
- height: auto;
14
- }
15
-
16
- [data-june-error] {
17
- padding: 12px 16px;
18
- border: 1px solid var(--june-danger);
19
- border-radius: var(--june-radius);
20
- color: var(--june-danger);
21
- }
2
+ box-sizing: border-box;
3
+ max-width: 100%;
4
+ min-width: 0;
5
+ }
6
+
7
+ /* Colors apply only when a theme is explicitly chosen. */
8
+ .june-ui-root[data-june-theme] {
9
+ color: var(--june-foreground);
10
+ }
11
+
12
+ .june-ui-root img,
13
+ .june-ui-root video {
14
+ max-width: 100%;
15
+ height: auto;
16
+ }
17
+
18
+ .june-text {
19
+ margin: 0 0 8px;
20
+ line-height: 1.5;
21
+ overflow-wrap: anywhere;
22
+ white-space: pre-wrap;
23
+ }
24
+
25
+ [data-june-error] {
26
+ padding: 12px 16px;
27
+ border: 1px solid var(--june-danger, #b91c1c);
28
+ border-radius: 8px;
29
+ color: var(--june-danger, #b91c1c);
30
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@june-ai/june-ui",
3
- "version": "0.1.1",
3
+ "version": "0.2.2",
4
4
  "description": "A React Generative UI SDK powered by OpenUI",
5
5
  "license": "MIT",
6
6
  "type": "module",