@assistant-ui/react-native 0.1.34 → 0.1.36

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.
@@ -86,6 +86,7 @@ const ComposerInput = (t0) => {
86
86
  if ($[11] !== aui || $[12] !== onKeyPressProp || $[13] !== submitMode) {
87
87
  t5 = (e) => {
88
88
  onKeyPressProp?.(e);
89
+ if (e.isDefaultPrevented()) return;
89
90
  if (Platform.OS !== "web") return;
90
91
  if (submitMode !== "enter") return;
91
92
  const nativeEvent = e.nativeEvent;
@@ -1 +1 @@
1
- {"version":3,"file":"ComposerInput.js","names":["useCallback","useEffect","useRef","Platform","TextInput","NativeSyntheticEvent","TextInputKeyPressEventData","TextInputProps","useAui","useAuiState","flushTapSync","ComposerInputProps","Omit","submitMode","getWebTextareaMaxHeight","el","HTMLTextAreaElement","computedMaxHeight","globalThis","getComputedStyle","maxHeight","parsedComputedMaxHeight","Number","parseFloat","isFinite","inlineMaxHeight","style","adjustWebTextareaHeight","ref","React","RefObject","OS","current","rows","overflowX","overflowY","height","scrollHeight","needsScrollbar","nextHeight","Math","min","ComposerInput","t0","$","_c","numberOfLines","onKeyPressProp","props","t1","onKeyPress","undefined","aui","text","_temp","inputRef","t2","value","composer","setText","onChangeText","t3","Symbol","for","t4","t5","e","nativeEvent","shiftKey","isComposing","keyCode","key","Event","preventDefault","send","t6","t7","s"],"sources":["../../../src/primitives/composer/ComposerInput.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport {\n Platform,\n TextInput,\n type NativeSyntheticEvent,\n type TextInputKeyPressEventData,\n type TextInputProps,\n} from \"react-native\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport { flushTapSync } from \"@assistant-ui/tap\";\n\nexport type ComposerInputProps = Omit<\n TextInputProps,\n \"value\" | \"onChangeText\"\n> & {\n /**\n * Controls how the Enter key submits messages (web only).\n * - \"enter\": Plain Enter submits (Shift+Enter for newline)\n * - \"none\": Enter inserts newline (no keyboard submission)\n * @default \"enter\"\n */\n submitMode?: \"enter\" | \"none\";\n};\n\nconst getWebTextareaMaxHeight = (el: HTMLTextAreaElement) => {\n const computedMaxHeight = globalThis.getComputedStyle?.(el).maxHeight;\n const parsedComputedMaxHeight = Number.parseFloat(computedMaxHeight ?? \"\");\n if (Number.isFinite(parsedComputedMaxHeight)) return parsedComputedMaxHeight;\n\n const inlineMaxHeight = Number.parseFloat(el.style.maxHeight);\n return Number.isFinite(inlineMaxHeight) ? inlineMaxHeight : null;\n};\n\nconst adjustWebTextareaHeight = (ref: React.RefObject<TextInput | null>) => {\n if (Platform.OS !== \"web\") return;\n // On web, the TextInput ref IS the DOM element\n const el = ref.current as unknown as HTMLTextAreaElement | null;\n if (!el) return;\n // Ensure rows=1 so scrollHeight reflects actual content\n if (el.rows !== 1) el.rows = 1;\n\n el.style.overflowX = \"hidden\";\n el.style.overflowY = \"hidden\";\n el.style.height = \"auto\";\n\n const scrollHeight = el.scrollHeight;\n const maxHeight = getWebTextareaMaxHeight(el);\n const needsScrollbar = maxHeight !== null && scrollHeight > maxHeight;\n const nextHeight =\n maxHeight === null ? scrollHeight : Math.min(scrollHeight, maxHeight);\n\n el.style.overflowY = needsScrollbar ? \"auto\" : \"hidden\";\n el.style.height = `${nextHeight}px`;\n};\n\nexport const ComposerInput = ({\n submitMode = \"enter\",\n onKeyPress: onKeyPressProp,\n numberOfLines,\n style,\n ...props\n}: ComposerInputProps) => {\n const aui = useAui();\n const text = useAuiState((s) => s.composer.text);\n const inputRef = useRef<TextInput>(null);\n\n const onChangeText = useCallback(\n (value: string) => {\n if (Platform.OS === \"web\") {\n // Keep the controlled value in sync mid-IME so react-dom does not reset the textarea to a stale value\n flushTapSync(() => {\n aui.composer.setText(value);\n });\n return;\n }\n aui.composer.setText(value);\n },\n [aui],\n );\n\n // Auto-resize textarea on web when text changes\n useEffect(() => {\n void text; // trigger re-run when text changes\n adjustWebTextareaHeight(inputRef);\n }, [text]);\n\n const onKeyPress = useCallback(\n (e: NativeSyntheticEvent<TextInputKeyPressEventData>) => {\n onKeyPressProp?.(e);\n\n if (Platform.OS !== \"web\") return;\n if (submitMode !== \"enter\") return;\n\n const nativeEvent = e.nativeEvent as TextInputKeyPressEventData & {\n shiftKey?: boolean;\n isComposing?: boolean;\n keyCode?: number;\n };\n // react-native-web forwards the raw DOM keydown before its own composition guard, so re-check it here (mirrors isEventComposing)\n if (nativeEvent.isComposing || nativeEvent.keyCode === 229) return;\n if (nativeEvent.key === \"Enter\" && !nativeEvent.shiftKey) {\n (e as unknown as Event).preventDefault?.();\n aui.composer.send();\n }\n },\n [aui, submitMode, onKeyPressProp],\n );\n\n return (\n <TextInput\n ref={inputRef}\n value={text}\n onChangeText={onChangeText}\n onKeyPress={onKeyPress}\n numberOfLines={numberOfLines ?? (Platform.OS === \"web\" ? 1 : undefined)}\n style={style}\n {...props}\n />\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ComposerInput.js","names":["useCallback","useEffect","useRef","Platform","TextInput","NativeSyntheticEvent","TextInputKeyPressEventData","TextInputProps","useAui","useAuiState","flushTapSync","ComposerInputProps","Omit","submitMode","getWebTextareaMaxHeight","el","HTMLTextAreaElement","computedMaxHeight","globalThis","getComputedStyle","maxHeight","parsedComputedMaxHeight","Number","parseFloat","isFinite","inlineMaxHeight","style","adjustWebTextareaHeight","ref","React","RefObject","OS","current","rows","overflowX","overflowY","height","scrollHeight","needsScrollbar","nextHeight","Math","min","ComposerInput","t0","$","_c","numberOfLines","onKeyPressProp","props","t1","onKeyPress","undefined","aui","text","_temp","inputRef","t2","value","composer","setText","onChangeText","t3","Symbol","for","t4","t5","e","isDefaultPrevented","nativeEvent","shiftKey","isComposing","keyCode","key","Event","preventDefault","send","t6","t7","s"],"sources":["../../../src/primitives/composer/ComposerInput.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport {\n Platform,\n TextInput,\n type NativeSyntheticEvent,\n type TextInputKeyPressEventData,\n type TextInputProps,\n} from \"react-native\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport { flushTapSync } from \"@assistant-ui/tap\";\n\nexport type ComposerInputProps = Omit<\n TextInputProps,\n \"value\" | \"onChangeText\"\n> & {\n /**\n * Controls how the Enter key submits messages (web only).\n * - \"enter\": Plain Enter submits (Shift+Enter for newline)\n * - \"none\": Enter inserts newline (no keyboard submission)\n * @default \"enter\"\n */\n submitMode?: \"enter\" | \"none\";\n};\n\nconst getWebTextareaMaxHeight = (el: HTMLTextAreaElement) => {\n const computedMaxHeight = globalThis.getComputedStyle?.(el).maxHeight;\n const parsedComputedMaxHeight = Number.parseFloat(computedMaxHeight ?? \"\");\n if (Number.isFinite(parsedComputedMaxHeight)) return parsedComputedMaxHeight;\n\n const inlineMaxHeight = Number.parseFloat(el.style.maxHeight);\n return Number.isFinite(inlineMaxHeight) ? inlineMaxHeight : null;\n};\n\nconst adjustWebTextareaHeight = (ref: React.RefObject<TextInput | null>) => {\n if (Platform.OS !== \"web\") return;\n // On web, the TextInput ref IS the DOM element\n const el = ref.current as unknown as HTMLTextAreaElement | null;\n if (!el) return;\n // Ensure rows=1 so scrollHeight reflects actual content\n if (el.rows !== 1) el.rows = 1;\n\n el.style.overflowX = \"hidden\";\n el.style.overflowY = \"hidden\";\n el.style.height = \"auto\";\n\n const scrollHeight = el.scrollHeight;\n const maxHeight = getWebTextareaMaxHeight(el);\n const needsScrollbar = maxHeight !== null && scrollHeight > maxHeight;\n const nextHeight =\n maxHeight === null ? scrollHeight : Math.min(scrollHeight, maxHeight);\n\n el.style.overflowY = needsScrollbar ? \"auto\" : \"hidden\";\n el.style.height = `${nextHeight}px`;\n};\n\nexport const ComposerInput = ({\n submitMode = \"enter\",\n onKeyPress: onKeyPressProp,\n numberOfLines,\n style,\n ...props\n}: ComposerInputProps) => {\n const aui = useAui();\n const text = useAuiState((s) => s.composer.text);\n const inputRef = useRef<TextInput>(null);\n\n const onChangeText = useCallback(\n (value: string) => {\n if (Platform.OS === \"web\") {\n // Keep the controlled value in sync mid-IME so react-dom does not reset the textarea to a stale value\n flushTapSync(() => {\n aui.composer.setText(value);\n });\n return;\n }\n aui.composer.setText(value);\n },\n [aui],\n );\n\n // Auto-resize textarea on web when text changes\n useEffect(() => {\n void text; // trigger re-run when text changes\n adjustWebTextareaHeight(inputRef);\n }, [text]);\n\n const onKeyPress = useCallback(\n (e: NativeSyntheticEvent<TextInputKeyPressEventData>) => {\n onKeyPressProp?.(e);\n if (e.isDefaultPrevented()) return;\n\n if (Platform.OS !== \"web\") return;\n if (submitMode !== \"enter\") return;\n\n const nativeEvent = e.nativeEvent as TextInputKeyPressEventData & {\n shiftKey?: boolean;\n isComposing?: boolean;\n keyCode?: number;\n };\n // react-native-web forwards the raw DOM keydown before its own composition guard, so re-check it here (mirrors isEventComposing)\n if (nativeEvent.isComposing || nativeEvent.keyCode === 229) return;\n if (nativeEvent.key === \"Enter\" && !nativeEvent.shiftKey) {\n (e as unknown as Event).preventDefault?.();\n aui.composer.send();\n }\n },\n [aui, submitMode, onKeyPressProp],\n );\n\n return (\n <TextInput\n ref={inputRef}\n value={text}\n onChangeText={onChangeText}\n onKeyPress={onKeyPress}\n numberOfLines={numberOfLines ?? (Platform.OS === \"web\" ? 1 : undefined)}\n style={style}\n {...props}\n />\n );\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-native",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "description": "React Native bindings for assistant-ui",
5
5
  "keywords": [
6
6
  "assistant",
@@ -31,10 +31,10 @@
31
31
  ],
32
32
  "sideEffects": false,
33
33
  "dependencies": {
34
- "@assistant-ui/core": "^0.3.6",
35
- "@assistant-ui/store": "^0.3.4",
36
- "@assistant-ui/tap": "^0.9.10",
37
- "assistant-stream": "^0.3.34",
34
+ "@assistant-ui/core": "^0.3.13",
35
+ "@assistant-ui/store": "^0.3.9",
36
+ "@assistant-ui/tap": "^0.9.12",
37
+ "assistant-stream": "^0.3.36",
38
38
  "zustand": "^5.0.14"
39
39
  },
40
40
  "peerDependencies": {
@@ -48,15 +48,15 @@
48
48
  }
49
49
  },
50
50
  "devDependencies": {
51
- "@types/react": "^19.2.17",
52
- "@types/react-dom": "^19.2.3",
53
- "jsdom": "^29.1.1",
51
+ "@types/react": "^19.2.18",
52
+ "@types/react-dom": "^19.2.4",
53
+ "jsdom": "^30.0.1",
54
54
  "react": "^19.2.8",
55
55
  "react-dom": "^19.2.8",
56
- "react-native": "^0.86.0",
56
+ "react-native": "^0.86.2",
57
57
  "react-native-web": "^0.21.2",
58
58
  "vitest": "^4.1.10",
59
- "@assistant-ui/x-buildutils": "0.0.21"
59
+ "@assistant-ui/x-buildutils": "0.0.22"
60
60
  },
61
61
  "publishConfig": {
62
62
  "access": "public",
@@ -315,6 +315,18 @@ describe("ComposerInput", () => {
315
315
 
316
316
  expect(onKeyPress).toHaveBeenCalledTimes(2);
317
317
  });
318
+
319
+ it("does not submit when the consumer prevents the key event", async () => {
320
+ const input = await mount({
321
+ onKeyPress: (event) => event.preventDefault(),
322
+ });
323
+
324
+ await act(async () => {
325
+ fireKeyDown(input, { key: "Enter" });
326
+ });
327
+
328
+ expect(h.sendSpy).not.toHaveBeenCalled();
329
+ });
318
330
  });
319
331
 
320
332
  describe("native", () => {
@@ -87,6 +87,7 @@ export const ComposerInput = ({
87
87
  const onKeyPress = useCallback(
88
88
  (e: NativeSyntheticEvent<TextInputKeyPressEventData>) => {
89
89
  onKeyPressProp?.(e);
90
+ if (e.isDefaultPrevented()) return;
90
91
 
91
92
  if (Platform.OS !== "web") return;
92
93
  if (submitMode !== "enter") return;
@@ -74,11 +74,9 @@ describe("MessageContent", () => {
74
74
 
75
75
  it("prefers a provided renderText over the default renderer", async () => {
76
76
  h.state.message.content = [{ type: "text", text: "raw" }];
77
- const renderText = vi.fn(
78
- ({ part, index }): ReactElement => (
79
- <span data-testid={`text-${index}`}>custom:{part.text}</span>
80
- ),
81
- );
77
+ const renderText = vi.fn(({ part, index }): ReactElement => (
78
+ <span data-testid={`text-${index}`}>custom:{part.text}</span>
79
+ ));
82
80
  await mount({ renderText });
83
81
 
84
82
  expect(renderText).toHaveBeenCalledTimes(1);
@@ -115,18 +113,18 @@ describe("MessageContent", () => {
115
113
  { type: "source", sourceType: "url", id: "1", url: "u" },
116
114
  { type: "file", filename: "f" },
117
115
  ];
118
- const renderImage = vi.fn(
119
- ({ index }): ReactElement => <span>image-{index}</span>,
120
- );
121
- const renderReasoning = vi.fn(
122
- ({ index }): ReactElement => <span>reasoning-{index}</span>,
123
- );
124
- const renderSource = vi.fn(
125
- ({ index }): ReactElement => <span>source-{index}</span>,
126
- );
127
- const renderFile = vi.fn(
128
- ({ index }): ReactElement => <span>file-{index}</span>,
129
- );
116
+ const renderImage = vi.fn(({ index }): ReactElement => (
117
+ <span>image-{index}</span>
118
+ ));
119
+ const renderReasoning = vi.fn(({ index }): ReactElement => (
120
+ <span>reasoning-{index}</span>
121
+ ));
122
+ const renderSource = vi.fn(({ index }): ReactElement => (
123
+ <span>source-{index}</span>
124
+ ));
125
+ const renderFile = vi.fn(({ index }): ReactElement => (
126
+ <span>file-{index}</span>
127
+ ));
130
128
  await mount({ renderImage, renderReasoning, renderSource, renderFile });
131
129
 
132
130
  expect(container.textContent).toBe("image-0reasoning-1source-2file-3");
@@ -183,13 +181,11 @@ describe("MessageContent", () => {
183
181
  h.state.message.content = [
184
182
  { type: "tool-call", toolName: "search", toolCallId: "c1" },
185
183
  ];
186
- const renderToolCall = vi.fn(
187
- ({ part, index }): ReactElement => (
188
- <span data-testid="fallback">
189
- fallback:{String(part.toolName)}:{index}
190
- </span>
191
- ),
192
- );
184
+ const renderToolCall = vi.fn(({ part, index }): ReactElement => (
185
+ <span data-testid="fallback">
186
+ fallback:{String(part.toolName)}:{index}
187
+ </span>
188
+ ));
193
189
  await mount({ renderToolCall });
194
190
 
195
191
  const el = container.querySelector('[data-testid="fallback"]');
@@ -239,13 +235,11 @@ describe("MessageContent", () => {
239
235
 
240
236
  it("falls back to renderData when no renderer is registered", async () => {
241
237
  h.state.message.content = [{ type: "data", name: "chart", data: {} }];
242
- const renderData = vi.fn(
243
- ({ part, index }): ReactElement => (
244
- <span data-testid="dfallback">
245
- fallback:{String(part.name)}:{index}
246
- </span>
247
- ),
248
- );
238
+ const renderData = vi.fn(({ part, index }): ReactElement => (
239
+ <span data-testid="dfallback">
240
+ fallback:{String(part.name)}:{index}
241
+ </span>
242
+ ));
249
243
  await mount({ renderData });
250
244
 
251
245
  const el = container.querySelector('[data-testid="dfallback"]');