@assistant-ui/react 0.15.27 → 0.15.28

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ComposerRoot.d.ts","sourceRoot":"","sources":["../../../src/primitives/composer/ComposerRoot.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,iCAA8B;AAClD,OAAO,EACL,KAAK,YAAY,EAGjB,KAAK,wBAAwB,EAI9B,MAAM,OAAO,CAAC;AA0Bf,yBAAiB,qBAAqB,CAAC;IACrC,KAAY,OAAO,GAAG,YAAY,CAAC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;IAC1D;;;OAGG;IACH,KAAY,KAAK,GAAG,wBAAwB,CAAC,OAAO,SAAS,CAAC,IAAI,CAAC,GAAG;QACpE;;;;;;;WAOG;QACH,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;KAC/B,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,qBAAqB;;;;;IAhC9B;;;;;;;OAOG;cACO,OAAO,GAAG,SAAS;mDAkF/B,CAAC"}
1
+ {"version":3,"file":"ComposerRoot.d.ts","sourceRoot":"","sources":["../../../src/primitives/composer/ComposerRoot.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,iCAA8B;AAClD,OAAO,EACL,KAAK,YAAY,EAGjB,KAAK,wBAAwB,EAK9B,MAAM,OAAO,CAAC;AA0Bf,yBAAiB,qBAAqB,CAAC;IACrC,KAAY,OAAO,GAAG,YAAY,CAAC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;IAC1D;;;OAGG;IACH,KAAY,KAAK,GAAG,wBAAwB,CAAC,OAAO,SAAS,CAAC,IAAI,CAAC,GAAG;QACpE;;;;;;;WAOG;QACH,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;KAC/B,CAAC;CACH;AAKD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,qBAAqB;;;;;IAnC9B;;;;;;;OAOG;cACO,OAAO,GAAG,SAAS;mDAwF/B,CAAC"}
@@ -4,7 +4,7 @@ import { useComposerSend } from "./ComposerSend.js";
4
4
  import { ComposerCompactContext } from "./ComposerCompactContext.js";
5
5
  import { COMPOSER_INPUT_SELECTOR, CONTENT_EDITABLE_SELECTOR } from "./composerInputSelector.js";
6
6
  import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
7
- import { forwardRef, useState } from "@assistant-ui/tap/react-shim";
7
+ import { forwardRef, useState, version } from "@assistant-ui/tap/react-shim";
8
8
  import { useAuiState } from "@assistant-ui/store";
9
9
  import { jsx } from "react/jsx-runtime";
10
10
  import { composeEventHandlers } from "radix-ui/internal";
@@ -25,6 +25,7 @@ const INTERACTIVE_ELEMENT_SELECTOR = [
25
25
  CONTENT_EDITABLE_SELECTOR,
26
26
  "[tabindex]"
27
27
  ].join(", ");
28
+ const isReact18 = version.startsWith("18.");
28
29
  /**
29
30
  * The root form container for message composition.
30
31
  *
@@ -46,96 +47,103 @@ const INTERACTIVE_ELEMENT_SELECTOR = [
46
47
  * ```
47
48
  */
48
49
  const ComposerPrimitiveRoot = forwardRef((t0, forwardedRef) => {
49
- const $ = c(25);
50
+ const $ = c(27);
50
51
  let compact;
52
+ let inert;
51
53
  let onMouseDown;
52
54
  let onSubmit;
53
55
  let rest;
54
56
  if ($[0] !== t0) {
55
- ({onSubmit, onMouseDown, compact, ...rest} = t0);
57
+ ({onSubmit, onMouseDown, compact, inert, ...rest} = t0);
56
58
  $[0] = t0;
57
59
  $[1] = compact;
58
- $[2] = onMouseDown;
59
- $[3] = onSubmit;
60
- $[4] = rest;
60
+ $[2] = inert;
61
+ $[3] = onMouseDown;
62
+ $[4] = onSubmit;
63
+ $[5] = rest;
61
64
  } else {
62
65
  compact = $[1];
63
- onMouseDown = $[2];
64
- onSubmit = $[3];
65
- rest = $[4];
66
+ inert = $[2];
67
+ onMouseDown = $[3];
68
+ onSubmit = $[4];
69
+ rest = $[5];
66
70
  }
67
71
  const send = useComposerSend();
68
72
  const composerType = useAuiState(_temp);
69
73
  const [multiline, setMultiline] = useState(false);
70
74
  let t1;
71
- if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
75
+ if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
72
76
  t1 = { setMultiline };
73
- $[5] = t1;
74
- } else t1 = $[5];
77
+ $[6] = t1;
78
+ } else t1 = $[6];
75
79
  const compactContext = t1;
76
80
  let t2;
77
- if ($[6] !== compact) {
81
+ if ($[7] !== compact) {
78
82
  t2 = (s_0) => compact ? s_0.composer.attachments.length === 0 && s_0.composer.quote == null && s_0.composer.queue.length === 0 && s_0.composer.dictation == null && !s_0.composer.text.includes("\n") : false;
79
- $[6] = compact;
80
- $[7] = t2;
81
- } else t2 = $[7];
83
+ $[7] = compact;
84
+ $[8] = t2;
85
+ } else t2 = $[8];
82
86
  const isCompact = useAuiState(t2) && !multiline;
87
+ const inertAttribute = isReact18 && typeof inert === "boolean" ? inert ? "" : void 0 : inert;
83
88
  let t3;
84
- if ($[8] !== send) {
89
+ if ($[9] !== send) {
85
90
  t3 = (e) => {
86
91
  e.preventDefault();
87
92
  if (!send) return;
88
93
  send();
89
94
  };
90
- $[8] = send;
91
- $[9] = t3;
92
- } else t3 = $[9];
95
+ $[9] = send;
96
+ $[10] = t3;
97
+ } else t3 = $[10];
93
98
  const handleSubmit = t3;
94
99
  const handleMouseDown = _temp2;
95
100
  const t4 = compact ? compactContext : null;
96
- const t5 = isCompact ? "" : void 0;
97
- let t6;
98
- if ($[10] !== handleSubmit || $[11] !== onSubmit) {
99
- t6 = composeEventHandlers(onSubmit, handleSubmit);
100
- $[10] = handleSubmit;
101
- $[11] = onSubmit;
102
- $[12] = t6;
103
- } else t6 = $[12];
101
+ const t5 = inertAttribute;
102
+ const t6 = isCompact ? "" : void 0;
104
103
  let t7;
105
- if ($[13] !== onMouseDown) {
106
- t7 = composeEventHandlers(onMouseDown, handleMouseDown);
107
- $[13] = onMouseDown;
108
- $[14] = t7;
109
- } else t7 = $[14];
104
+ if ($[11] !== handleSubmit || $[12] !== onSubmit) {
105
+ t7 = composeEventHandlers(onSubmit, handleSubmit);
106
+ $[11] = handleSubmit;
107
+ $[12] = onSubmit;
108
+ $[13] = t7;
109
+ } else t7 = $[13];
110
110
  let t8;
111
- if ($[15] !== composerType || $[16] !== forwardedRef || $[17] !== rest || $[18] !== t5 || $[19] !== t6 || $[20] !== t7) {
112
- t8 = /* @__PURE__ */ jsx(Primitive$1.form, {
111
+ if ($[14] !== onMouseDown) {
112
+ t8 = composeEventHandlers(onMouseDown, handleMouseDown);
113
+ $[14] = onMouseDown;
114
+ $[15] = t8;
115
+ } else t8 = $[15];
116
+ let t9;
117
+ if ($[16] !== composerType || $[17] !== forwardedRef || $[18] !== rest || $[19] !== t5 || $[20] !== t6 || $[21] !== t7 || $[22] !== t8) {
118
+ t9 = /* @__PURE__ */ jsx(Primitive$1.form, {
113
119
  ...rest,
120
+ inert: t5,
114
121
  "data-aui-composer-type": composerType,
115
- "data-compact": t5,
122
+ "data-compact": t6,
116
123
  ref: forwardedRef,
117
- onSubmit: t6,
118
- onMouseDown: t7
124
+ onSubmit: t7,
125
+ onMouseDown: t8
119
126
  });
120
- $[15] = composerType;
121
- $[16] = forwardedRef;
122
- $[17] = rest;
123
- $[18] = t5;
124
- $[19] = t6;
125
- $[20] = t7;
126
- $[21] = t8;
127
- } else t8 = $[21];
128
- let t9;
129
- if ($[22] !== t4 || $[23] !== t8) {
130
- t9 = /* @__PURE__ */ jsx(ComposerCompactContext.Provider, {
127
+ $[16] = composerType;
128
+ $[17] = forwardedRef;
129
+ $[18] = rest;
130
+ $[19] = t5;
131
+ $[20] = t6;
132
+ $[21] = t7;
133
+ $[22] = t8;
134
+ $[23] = t9;
135
+ } else t9 = $[23];
136
+ let t10;
137
+ if ($[24] !== t4 || $[25] !== t9) {
138
+ t10 = /* @__PURE__ */ jsx(ComposerCompactContext.Provider, {
131
139
  value: t4,
132
- children: t8
140
+ children: t9
133
141
  });
134
- $[22] = t4;
135
- $[23] = t8;
136
- $[24] = t9;
137
- } else t9 = $[24];
138
- return t9;
142
+ $[24] = t4;
143
+ $[25] = t9;
144
+ $[26] = t10;
145
+ } else t10 = $[26];
146
+ return t10;
139
147
  });
140
148
  ComposerPrimitiveRoot.displayName = "ComposerPrimitive.Root";
141
149
  function _temp(s) {
@@ -1 +1 @@
1
- {"version":3,"file":"ComposerRoot.js","names":["c","_c","composeEventHandlers","useAuiState","Primitive","ComponentRef","FormEvent","forwardRef","ComponentPropsWithoutRef","MouseEvent","useMemo","useState","useComposerSend","ComposerCompactContext","COMPOSER_INPUT_SELECTOR","CONTENT_EDITABLE_SELECTOR","INTERACTIVE_ELEMENT_SELECTOR","join","ComposerPrimitiveRoot","Element","form","Props","compact","t0","forwardedRef","$","onMouseDown","onSubmit","rest","send","composerType","_temp","multiline","setMultiline","t1","Symbol","for","compactContext","t2","s_0","s","composer","attachments","length","quote","queue","dictation","text","includes","stateAllowsCompact","isCompact","t3","e","preventDefault","handleSubmit","handleMouseDown","_temp2","t4","t5","undefined","t6","t7","t8","t9","displayName","type","e_0","button","target","currentTarget","contains","interactive","closest","input","querySelector","focus","_c","Primitive"],"sources":["../../../src/primitives/composer/ComposerRoot.tsx"],"sourcesContent":["\"use client\";\n\nimport { composeEventHandlers } from \"radix-ui/internal\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport { Primitive } from \"../../utils/Primitive\";\nimport {\n type ComponentRef,\n type FormEvent,\n forwardRef,\n type ComponentPropsWithoutRef,\n type MouseEvent,\n useMemo,\n useState,\n} from \"react\";\nimport { useComposerSend } from \"./ComposerSend\";\nimport { ComposerCompactContext } from \"./ComposerCompactContext\";\nimport {\n COMPOSER_INPUT_SELECTOR,\n CONTENT_EDITABLE_SELECTOR,\n} from \"./composerInputSelector\";\n\n// Keeps tabindex=\"-1\": roving-tabindex widgets click-focus items at -1.\nconst INTERACTIVE_ELEMENT_SELECTOR = [\n \"a\",\n \"audio[controls]\",\n \"button\",\n \"details\",\n \"embed\",\n \"iframe\",\n \"input\",\n \"label\",\n \"select\",\n \"summary\",\n \"textarea\",\n \"video[controls]\",\n CONTENT_EDITABLE_SELECTOR,\n \"[tabindex]\",\n].join(\", \");\n\nexport namespace ComposerPrimitiveRoot {\n export type Element = ComponentRef<typeof Primitive.form>;\n /**\n * Props for the ComposerPrimitive.Root component.\n * Accepts all standard form element props.\n */\n export type Props = ComponentPropsWithoutRef<typeof Primitive.form> & {\n /**\n * Opt the composer into compact mode. While the input holds at most a single\n * line of text and there are no attachments, quote, queued messages, or\n * active dictation, the root renders a `data-compact` attribute so styles\n * can collapse the composer into a single row. It expands automatically\n * when any of those conditions stop holding.\n * @default false\n */\n compact?: boolean | undefined;\n };\n}\n\n/**\n * The root form container for message composition.\n *\n * This component provides a form wrapper that handles message submission when the form\n * is submitted (e.g., via Enter key or submit button). It automatically prevents the\n * default form submission and triggers the composer's send functionality.\n *\n * Clicking blank form space focuses the composer input (the first textarea or\n * contenteditable inside the form). Text selection cannot start from blank\n * areas; descendants that need native mousedown defaults can call\n * `stopPropagation()` in their own `onMouseDown`.\n *\n * @example\n * ```tsx\n * <ComposerPrimitive.Root>\n * <ComposerPrimitive.Input placeholder=\"Type your message...\" />\n * <ComposerPrimitive.Send>Send</ComposerPrimitive.Send>\n * </ComposerPrimitive.Root>\n * ```\n */\nexport const ComposerPrimitiveRoot = forwardRef<\n ComposerPrimitiveRoot.Element,\n ComposerPrimitiveRoot.Props\n>(({ onSubmit, onMouseDown, compact, ...rest }, forwardedRef) => {\n const send = useComposerSend();\n const composerType = useAuiState((s) => s.composer.type);\n\n const [multiline, setMultiline] = useState(false);\n const compactContext = useMemo(() => ({ setMultiline }), []);\n const stateAllowsCompact = useAuiState((s) =>\n compact\n ? s.composer.attachments.length === 0 &&\n s.composer.quote == null &&\n s.composer.queue.length === 0 &&\n s.composer.dictation == null &&\n !s.composer.text.includes(\"\\n\")\n : false,\n );\n const isCompact = stateAllowsCompact && !multiline;\n\n const handleSubmit = (e: FormEvent) => {\n e.preventDefault();\n\n if (!send) return;\n send();\n };\n\n const handleMouseDown = (e: MouseEvent<HTMLFormElement>) => {\n if (e.button !== 0) return;\n const target = e.target;\n // Portaled descendants (e.g. a dialog overlay) propagate mousedown through\n // the React tree while their DOM nodes live outside the form.\n if (!(target instanceof Element) || !e.currentTarget.contains(target))\n return;\n // Bound the ancestor walk to the form: hosts like AssistantModal render\n // the composer inside a wrapper carrying tabindex=\"-1\" (Radix FocusScope).\n const interactive = target.closest(INTERACTIVE_ELEMENT_SELECTOR);\n if (interactive && e.currentTarget.contains(interactive)) return;\n const input = e.currentTarget.querySelector<HTMLElement>(\n COMPOSER_INPUT_SELECTOR,\n );\n if (!input) return;\n e.preventDefault();\n input.focus();\n };\n\n return (\n <ComposerCompactContext.Provider value={compact ? compactContext : null}>\n <Primitive.form\n {...rest}\n data-aui-composer-type={composerType}\n data-compact={isCompact ? \"\" : undefined}\n ref={forwardedRef}\n onSubmit={composeEventHandlers(onSubmit, handleSubmit)}\n onMouseDown={composeEventHandlers(onMouseDown, handleMouseDown)}\n />\n </ComposerCompactContext.Provider>\n );\n});\n\nComposerPrimitiveRoot.displayName = \"ComposerPrimitive.Root\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"ComposerRoot.js","names":["c","_c","composeEventHandlers","useAuiState","Primitive","ComponentRef","FormEvent","forwardRef","ComponentPropsWithoutRef","MouseEvent","useMemo","useState","version","useComposerSend","ComposerCompactContext","COMPOSER_INPUT_SELECTOR","CONTENT_EDITABLE_SELECTOR","INTERACTIVE_ELEMENT_SELECTOR","join","ComposerPrimitiveRoot","Element","form","Props","compact","isReact18","startsWith","t0","forwardedRef","$","inert","onMouseDown","onSubmit","rest","send","composerType","_temp","multiline","setMultiline","t1","Symbol","for","compactContext","t2","s_0","s","composer","attachments","length","quote","queue","dictation","text","includes","stateAllowsCompact","isCompact","inertAttribute","undefined","t3","e","preventDefault","handleSubmit","handleMouseDown","_temp2","t4","t5","t6","t7","t8","t9","t10","displayName","type","e_0","button","target","currentTarget","contains","interactive","closest","input","querySelector","focus","_c","Primitive"],"sources":["../../../src/primitives/composer/ComposerRoot.tsx"],"sourcesContent":["\"use client\";\n\nimport { composeEventHandlers } from \"radix-ui/internal\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport { Primitive } from \"../../utils/Primitive\";\nimport {\n type ComponentRef,\n type FormEvent,\n forwardRef,\n type ComponentPropsWithoutRef,\n type MouseEvent,\n useMemo,\n useState,\n version,\n} from \"react\";\nimport { useComposerSend } from \"./ComposerSend\";\nimport { ComposerCompactContext } from \"./ComposerCompactContext\";\nimport {\n COMPOSER_INPUT_SELECTOR,\n CONTENT_EDITABLE_SELECTOR,\n} from \"./composerInputSelector\";\n\n// Keeps tabindex=\"-1\": roving-tabindex widgets click-focus items at -1.\nconst INTERACTIVE_ELEMENT_SELECTOR = [\n \"a\",\n \"audio[controls]\",\n \"button\",\n \"details\",\n \"embed\",\n \"iframe\",\n \"input\",\n \"label\",\n \"select\",\n \"summary\",\n \"textarea\",\n \"video[controls]\",\n CONTENT_EDITABLE_SELECTOR,\n \"[tabindex]\",\n].join(\", \");\n\nexport namespace ComposerPrimitiveRoot {\n export type Element = ComponentRef<typeof Primitive.form>;\n /**\n * Props for the ComposerPrimitive.Root component.\n * Accepts all standard form element props.\n */\n export type Props = ComponentPropsWithoutRef<typeof Primitive.form> & {\n /**\n * Opt the composer into compact mode. While the input holds at most a single\n * line of text and there are no attachments, quote, queued messages, or\n * active dictation, the root renders a `data-compact` attribute so styles\n * can collapse the composer into a single row. It expands automatically\n * when any of those conditions stop holding.\n * @default false\n */\n compact?: boolean | undefined;\n };\n}\n\n// React 18 drops a boolean `inert`, so it receives the attribute's string form.\nconst isReact18 = version.startsWith(\"18.\");\n\n/**\n * The root form container for message composition.\n *\n * This component provides a form wrapper that handles message submission when the form\n * is submitted (e.g., via Enter key or submit button). It automatically prevents the\n * default form submission and triggers the composer's send functionality.\n *\n * Clicking blank form space focuses the composer input (the first textarea or\n * contenteditable inside the form). Text selection cannot start from blank\n * areas; descendants that need native mousedown defaults can call\n * `stopPropagation()` in their own `onMouseDown`.\n *\n * @example\n * ```tsx\n * <ComposerPrimitive.Root>\n * <ComposerPrimitive.Input placeholder=\"Type your message...\" />\n * <ComposerPrimitive.Send>Send</ComposerPrimitive.Send>\n * </ComposerPrimitive.Root>\n * ```\n */\nexport const ComposerPrimitiveRoot = forwardRef<\n ComposerPrimitiveRoot.Element,\n ComposerPrimitiveRoot.Props\n>(({ onSubmit, onMouseDown, compact, inert, ...rest }, forwardedRef) => {\n const send = useComposerSend();\n const composerType = useAuiState((s) => s.composer.type);\n\n const [multiline, setMultiline] = useState(false);\n const compactContext = useMemo(() => ({ setMultiline }), []);\n const stateAllowsCompact = useAuiState((s) =>\n compact\n ? s.composer.attachments.length === 0 &&\n s.composer.quote == null &&\n s.composer.queue.length === 0 &&\n s.composer.dictation == null &&\n !s.composer.text.includes(\"\\n\")\n : false,\n );\n const isCompact = stateAllowsCompact && !multiline;\n const inertAttribute =\n isReact18 && typeof inert === \"boolean\" ? (inert ? \"\" : undefined) : inert;\n\n const handleSubmit = (e: FormEvent) => {\n e.preventDefault();\n\n if (!send) return;\n send();\n };\n\n const handleMouseDown = (e: MouseEvent<HTMLFormElement>) => {\n if (e.button !== 0) return;\n const target = e.target;\n // Portaled descendants (e.g. a dialog overlay) propagate mousedown through\n // the React tree while their DOM nodes live outside the form.\n if (!(target instanceof Element) || !e.currentTarget.contains(target))\n return;\n // Bound the ancestor walk to the form: hosts like AssistantModal render\n // the composer inside a wrapper carrying tabindex=\"-1\" (Radix FocusScope).\n const interactive = target.closest(INTERACTIVE_ELEMENT_SELECTOR);\n if (interactive && e.currentTarget.contains(interactive)) return;\n const input = e.currentTarget.querySelector<HTMLElement>(\n COMPOSER_INPUT_SELECTOR,\n );\n if (!input) return;\n e.preventDefault();\n input.focus();\n };\n\n return (\n <ComposerCompactContext.Provider value={compact ? compactContext : null}>\n <Primitive.form\n {...rest}\n inert={inertAttribute as boolean | undefined}\n data-aui-composer-type={composerType}\n data-compact={isCompact ? \"\" : undefined}\n ref={forwardedRef}\n onSubmit={composeEventHandlers(onSubmit, handleSubmit)}\n onMouseDown={composeEventHandlers(onMouseDown, handleMouseDown)}\n />\n </ComposerCompactContext.Provider>\n );\n});\n\nComposerPrimitiveRoot.displayName = \"ComposerPrimitive.Root\";\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react",
3
- "version": "0.15.27",
3
+ "version": "0.15.28",
4
4
  "description": "Open-source TypeScript/React library for building production-grade AI chat experiences",
5
5
  "keywords": [
6
6
  "ai",
@@ -55,14 +55,14 @@
55
55
  ],
56
56
  "sideEffects": false,
57
57
  "dependencies": {
58
- "@assistant-ui/core": "^0.3.26",
58
+ "@assistant-ui/core": "^0.3.27",
59
59
  "@assistant-ui/store": "^0.3.19",
60
- "@assistant-ui/tap": "^0.9.22",
60
+ "@assistant-ui/tap": "^0.9.23",
61
61
  "assistant-cloud": "^0.2.7",
62
- "assistant-stream": "^0.3.49",
62
+ "assistant-stream": "^0.3.50",
63
63
  "radix-ui": "^1.7.0",
64
64
  "react-textarea-autosize": "^8.5.9",
65
- "safe-content-frame": "^0.0.33",
65
+ "safe-content-frame": "^0.0.34",
66
66
  "zod": "^4.6.5",
67
67
  "zustand": "^5.0.15"
68
68
  },
@@ -1,5 +1,5 @@
1
1
  /** @vitest-environment jsdom */
2
- import { act } from "react";
2
+ import { act, version } from "react";
3
3
  import type { MouseEvent, ReactNode } from "react";
4
4
  import { createPortal } from "react-dom";
5
5
  import { createRoot } from "react-dom/client";
@@ -12,6 +12,8 @@ import { useComposerCompactContextOptional } from "./ComposerCompactContext";
12
12
  import type { ComposerCompactContextValue } from "./ComposerCompactContext";
13
13
  import { ComposerPrimitiveRoot } from "./ComposerRoot";
14
14
 
15
+ const onReact18 = version.startsWith("18.");
16
+
15
17
  type StoreState = {
16
18
  composer: {
17
19
  attachments: object[];
@@ -77,6 +79,24 @@ describe("ComposerPrimitiveRoot click-to-focus", () => {
77
79
  };
78
80
  };
79
81
 
82
+ it("forwards the inert attribute and removes it when disabled", () => {
83
+ const { container, rerender } = render(<ComposerPrimitiveRoot inert />);
84
+ const form = container.querySelector("form");
85
+
86
+ expect(form?.hasAttribute("inert")).toBe(true);
87
+
88
+ rerender(<ComposerPrimitiveRoot inert={false} />);
89
+ expect(form?.hasAttribute("inert")).toBe(false);
90
+ });
91
+
92
+ it.skipIf(!onReact18)("keeps a string inert on React 18", () => {
93
+ const { container } = render(
94
+ <ComposerPrimitiveRoot inert={"" as unknown as boolean} />,
95
+ );
96
+
97
+ expect(container.querySelector("form")?.hasAttribute("inert")).toBe(true);
98
+ });
99
+
80
100
  it("focuses the textarea when primary-button mousedown starts on blank form space", () => {
81
101
  const { blankSpace, textarea } = setupComposer();
82
102
 
@@ -11,6 +11,7 @@ import {
11
11
  type MouseEvent,
12
12
  useMemo,
13
13
  useState,
14
+ version,
14
15
  } from "react";
15
16
  import { useComposerSend } from "./ComposerSend";
16
17
  import { ComposerCompactContext } from "./ComposerCompactContext";
@@ -56,6 +57,9 @@ export namespace ComposerPrimitiveRoot {
56
57
  };
57
58
  }
58
59
 
60
+ // React 18 drops a boolean `inert`, so it receives the attribute's string form.
61
+ const isReact18 = version.startsWith("18.");
62
+
59
63
  /**
60
64
  * The root form container for message composition.
61
65
  *
@@ -79,7 +83,7 @@ export namespace ComposerPrimitiveRoot {
79
83
  export const ComposerPrimitiveRoot = forwardRef<
80
84
  ComposerPrimitiveRoot.Element,
81
85
  ComposerPrimitiveRoot.Props
82
- >(({ onSubmit, onMouseDown, compact, ...rest }, forwardedRef) => {
86
+ >(({ onSubmit, onMouseDown, compact, inert, ...rest }, forwardedRef) => {
83
87
  const send = useComposerSend();
84
88
  const composerType = useAuiState((s) => s.composer.type);
85
89
 
@@ -95,6 +99,8 @@ export const ComposerPrimitiveRoot = forwardRef<
95
99
  : false,
96
100
  );
97
101
  const isCompact = stateAllowsCompact && !multiline;
102
+ const inertAttribute =
103
+ isReact18 && typeof inert === "boolean" ? (inert ? "" : undefined) : inert;
98
104
 
99
105
  const handleSubmit = (e: FormEvent) => {
100
106
  e.preventDefault();
@@ -126,6 +132,7 @@ export const ComposerPrimitiveRoot = forwardRef<
126
132
  <ComposerCompactContext.Provider value={compact ? compactContext : null}>
127
133
  <Primitive.form
128
134
  {...rest}
135
+ inert={inertAttribute as boolean | undefined}
129
136
  data-aui-composer-type={composerType}
130
137
  data-compact={isCompact ? "" : undefined}
131
138
  ref={forwardedRef}