@assistant-ui/react 0.14.23 → 0.14.26

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.
Files changed (87) hide show
  1. package/dist/index.d.ts +4 -3
  2. package/dist/index.js +4 -3
  3. package/dist/legacy-runtime/hooks/AttachmentContext.d.ts +12 -12
  4. package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.d.ts +3 -1
  5. package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.d.ts.map +1 -1
  6. package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.js +2 -2
  7. package/dist/legacy-runtime/runtime-cores/assistant-transport/commandQueue.js.map +1 -1
  8. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.d.ts.map +1 -1
  9. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js +6 -2
  10. package/dist/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.js.map +1 -1
  11. package/dist/primitives/composer/ComposerInput.d.ts.map +1 -1
  12. package/dist/primitives/composer/ComposerInput.js +5 -14
  13. package/dist/primitives/composer/ComposerInput.js.map +1 -1
  14. package/dist/primitives/composer/useComposerInputState.d.ts +13 -0
  15. package/dist/primitives/composer/useComposerInputState.d.ts.map +1 -0
  16. package/dist/primitives/composer/useComposerInputState.js +47 -0
  17. package/dist/primitives/composer/useComposerInputState.js.map +1 -0
  18. package/dist/primitives/messagePart/MessagePartText.d.ts +2 -0
  19. package/dist/primitives/messagePart/MessagePartText.d.ts.map +1 -1
  20. package/dist/primitives/messagePart/MessagePartText.js.map +1 -1
  21. package/dist/primitives/thread/ThreadMessages.d.ts +2 -2
  22. package/dist/primitives/thread/ThreadMessages.js +2 -2
  23. package/dist/primitives/thread.d.ts +3 -3
  24. package/dist/primitives/thread.js +3 -2
  25. package/dist/primitives/thread.js.map +1 -1
  26. package/dist/primitives/threadList/ThreadListRoot.d.ts.map +1 -1
  27. package/dist/primitives/threadList/ThreadListRoot.js +10 -3
  28. package/dist/primitives/threadList/ThreadListRoot.js.map +1 -1
  29. package/dist/primitives/threadListFocusGroup.d.ts +26 -0
  30. package/dist/primitives/threadListFocusGroup.d.ts.map +1 -0
  31. package/dist/primitives/threadListFocusGroup.js +15 -0
  32. package/dist/primitives/threadListFocusGroup.js.map +1 -0
  33. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts.map +1 -1
  34. package/dist/primitives/threadListItem/ThreadListItemRoot.js +45 -27
  35. package/dist/primitives/threadListItem/ThreadListItemRoot.js.map +1 -1
  36. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts.map +1 -1
  37. package/dist/primitives/threadListItem/ThreadListItemTrigger.js +26 -2
  38. package/dist/primitives/threadListItem/ThreadListItemTrigger.js.map +1 -1
  39. package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.d.ts.map +1 -1
  40. package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.js +63 -38
  41. package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.js.map +1 -1
  42. package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.d.ts +20 -3
  43. package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.d.ts.map +1 -1
  44. package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.js +95 -14
  45. package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.js.map +1 -1
  46. package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.d.ts.map +1 -1
  47. package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.js +38 -21
  48. package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.js.map +1 -1
  49. package/dist/unstable/useComposerInput.d.ts +84 -0
  50. package/dist/unstable/useComposerInput.d.ts.map +1 -0
  51. package/dist/unstable/useComposerInput.js +78 -0
  52. package/dist/unstable/useComposerInput.js.map +1 -0
  53. package/dist/utils/hooks/useMediaQuery.js +2 -2
  54. package/dist/utils/hooks/useMediaQuery.js.map +1 -1
  55. package/dist/utils/smooth/useSmooth.d.ts +4 -0
  56. package/dist/utils/smooth/useSmooth.d.ts.map +1 -1
  57. package/dist/utils/smooth/useSmooth.js +7 -1
  58. package/dist/utils/smooth/useSmooth.js.map +1 -1
  59. package/dist/utils/useToolArgsFieldStatus.d.ts +2 -2
  60. package/dist/utils/useToolArgsFieldStatus.d.ts.map +1 -1
  61. package/package.json +16 -14
  62. package/src/index.ts +39 -0
  63. package/src/legacy-runtime/runtime-cores/assistant-transport/commandQueue.ts +5 -2
  64. package/src/legacy-runtime/runtime-cores/assistant-transport/transport-scheduling.test.ts +22 -0
  65. package/src/legacy-runtime/runtime-cores/assistant-transport/useAssistantTransportRuntime.ts +12 -2
  66. package/src/primitives/composer/ComposerInput.tsx +9 -20
  67. package/src/primitives/composer/trigger/triggerKeyboardResource.test.ts +18 -22
  68. package/src/primitives/composer/useComposerInputState.ts +34 -0
  69. package/src/primitives/messagePart/MessagePartText.tsx +1 -0
  70. package/src/primitives/thread/ThreadMessages.tsx +1 -0
  71. package/src/primitives/thread.ts +1 -0
  72. package/src/primitives/threadList/ThreadListRoot.tsx +8 -1
  73. package/src/primitives/threadListFocusGroup.ts +24 -0
  74. package/src/primitives/threadListItem/ThreadListItemRoot.tsx +53 -5
  75. package/src/primitives/threadListItem/ThreadListItemTrigger.tsx +45 -0
  76. package/src/primitives/threadListItem/ThreadListKeyboardNav.test.tsx +141 -0
  77. package/src/primitives/threadListItemMore/ThreadListItemMoreContent.tsx +22 -1
  78. package/src/primitives/threadListItemMore/ThreadListItemMoreRoot.tsx +64 -3
  79. package/src/primitives/threadListItemMore/ThreadListItemMoreTrigger.tsx +29 -2
  80. package/src/tests/generative-ui.test.tsx +21 -1
  81. package/src/tests/threadMessageById.test.tsx +224 -0
  82. package/src/unstable/useComposerInput.test.tsx +187 -0
  83. package/src/unstable/useComposerInput.ts +126 -0
  84. package/src/utils/hooks/useMediaQuery.ts +3 -2
  85. package/src/utils/smooth/useSmooth.test.tsx +26 -0
  86. package/src/utils/smooth/useSmooth.ts +7 -1
  87. package/src/primitives/threadListItem/ThreadListItemTrigger.ts +0 -23
@@ -0,0 +1,187 @@
1
+ /** @vitest-environment jsdom */
2
+ import { render } from "@testing-library/react";
3
+ import { beforeEach, describe, expect, it, vi } from "vitest";
4
+
5
+ type ComposerState = { isEditing: boolean; text: string };
6
+
7
+ const fixture = {
8
+ composer: { isEditing: true, text: "hello" } as ComposerState,
9
+ threadDisabled: false,
10
+ dictationInputDisabled: undefined as boolean | undefined,
11
+ sendDisabled: false,
12
+ activeAria: null as { popoverId: string; highlightedItemId?: string } | null,
13
+ };
14
+
15
+ const composerSetText = vi.fn();
16
+ const composerSend = vi.fn();
17
+ const flushTapSync = vi.fn((fn: () => void) => fn());
18
+
19
+ vi.mock("@assistant-ui/store", () => ({
20
+ useAui: () => ({
21
+ composer: () => ({
22
+ getState: () => ({ isEditing: fixture.composer.isEditing }),
23
+ setText: composerSetText,
24
+ send: composerSend,
25
+ }),
26
+ }),
27
+ useAuiState: (selector: (s: unknown) => unknown) =>
28
+ selector({
29
+ composer: {
30
+ isEditing: fixture.composer.isEditing,
31
+ text: fixture.composer.text,
32
+ dictation: fixture.dictationInputDisabled
33
+ ? { inputDisabled: fixture.dictationInputDisabled }
34
+ : undefined,
35
+ },
36
+ thread: { isDisabled: fixture.threadDisabled },
37
+ }),
38
+ }));
39
+ vi.mock("@assistant-ui/tap", () => ({
40
+ flushTapSync: (fn: () => void) => flushTapSync(fn),
41
+ }));
42
+ vi.mock("@assistant-ui/core/react", () => ({
43
+ useComposerSend: () => ({
44
+ send: composerSend,
45
+ disabled: fixture.sendDisabled,
46
+ }),
47
+ }));
48
+ vi.mock("../primitives/composer/trigger/TriggerPopoverRootContext", () => ({
49
+ useTriggerPopoverActiveAriaOptional: () => fixture.activeAria,
50
+ }));
51
+
52
+ import {
53
+ unstable_useComposerInput,
54
+ unstable_useTriggerPopoverAriaProps,
55
+ type Unstable_ComposerInput,
56
+ type Unstable_TriggerPopoverAriaProps,
57
+ } from "./useComposerInput";
58
+
59
+ const renderInput = (options?: { disabled?: boolean }) => {
60
+ let result!: Unstable_ComposerInput;
61
+ function Harness() {
62
+ result = unstable_useComposerInput(options);
63
+ return null;
64
+ }
65
+ render(<Harness />);
66
+ return () => result;
67
+ };
68
+
69
+ const renderAria = () => {
70
+ let result!: Unstable_TriggerPopoverAriaProps;
71
+ function Harness() {
72
+ result = unstable_useTriggerPopoverAriaProps();
73
+ return null;
74
+ }
75
+ render(<Harness />);
76
+ return () => result;
77
+ };
78
+
79
+ beforeEach(() => {
80
+ fixture.composer = { isEditing: true, text: "hello" };
81
+ fixture.threadDisabled = false;
82
+ fixture.dictationInputDisabled = undefined;
83
+ fixture.sendDisabled = false;
84
+ fixture.activeAria = null;
85
+ composerSetText.mockClear();
86
+ composerSend.mockClear();
87
+ flushTapSync.mockClear();
88
+ });
89
+
90
+ describe("unstable_useComposerInput", () => {
91
+ it("exposes the composer text while editing", () => {
92
+ expect(renderInput()().value).toBe("hello");
93
+ });
94
+
95
+ it("reports an empty value when the composer is not editing", () => {
96
+ fixture.composer = { isEditing: false, text: "stale" };
97
+ expect(renderInput()().value).toBe("");
98
+ });
99
+
100
+ it("writes text via flushTapSync when editing", () => {
101
+ renderInput()().setText("world");
102
+ expect(flushTapSync).toHaveBeenCalledTimes(1);
103
+ expect(composerSetText).toHaveBeenCalledWith("world");
104
+ });
105
+
106
+ it("ignores setText when the composer is not editing (editing guard)", () => {
107
+ fixture.composer = { isEditing: false, text: "" };
108
+ renderInput()().setText("world");
109
+ expect(composerSetText).not.toHaveBeenCalled();
110
+ });
111
+
112
+ it("combines the disabled option with composer disabled sources", () => {
113
+ expect(renderInput()().isDisabled).toBe(false);
114
+ expect(renderInput({ disabled: true })().isDisabled).toBe(true);
115
+
116
+ fixture.threadDisabled = true;
117
+ expect(renderInput()().isDisabled).toBe(true);
118
+
119
+ fixture.threadDisabled = false;
120
+ fixture.dictationInputDisabled = true;
121
+ expect(renderInput()().isDisabled).toBe(true);
122
+ });
123
+
124
+ it("derives canSend from send gating and disabled state", () => {
125
+ expect(renderInput()().canSend).toBe(true);
126
+
127
+ fixture.sendDisabled = true;
128
+ expect(renderInput()().canSend).toBe(false);
129
+
130
+ fixture.sendDisabled = false;
131
+ expect(renderInput({ disabled: true })().canSend).toBe(false);
132
+
133
+ fixture.threadDisabled = true;
134
+ expect(renderInput()().canSend).toBe(false);
135
+
136
+ fixture.threadDisabled = false;
137
+ fixture.dictationInputDisabled = true;
138
+ expect(renderInput()().canSend).toBe(false);
139
+ });
140
+
141
+ it("forwards send options to the composer action", () => {
142
+ renderInput()().send({ steer: true });
143
+ expect(composerSend).toHaveBeenCalledWith({ steer: true });
144
+ });
145
+
146
+ it("does not send while send is unavailable or the input is disabled", () => {
147
+ fixture.sendDisabled = true;
148
+ renderInput()().send();
149
+ expect(composerSend).not.toHaveBeenCalled();
150
+
151
+ fixture.sendDisabled = false;
152
+ renderInput({ disabled: true })().send();
153
+ expect(composerSend).not.toHaveBeenCalled();
154
+
155
+ fixture.threadDisabled = true;
156
+ renderInput()().send();
157
+ expect(composerSend).not.toHaveBeenCalled();
158
+
159
+ fixture.threadDisabled = false;
160
+ fixture.dictationInputDisabled = true;
161
+ renderInput()().send();
162
+ expect(composerSend).not.toHaveBeenCalled();
163
+ });
164
+ });
165
+
166
+ describe("unstable_useTriggerPopoverAriaProps", () => {
167
+ it("is empty when no popover is active", () => {
168
+ expect(renderAria()()).toEqual({});
169
+ });
170
+
171
+ it("describes the active popover combobox relationship", () => {
172
+ fixture.activeAria = { popoverId: "pop-1", highlightedItemId: "item-2" };
173
+ expect(renderAria()()).toEqual({
174
+ "aria-controls": "pop-1",
175
+ "aria-expanded": true,
176
+ "aria-haspopup": "listbox",
177
+ "aria-activedescendant": "item-2",
178
+ });
179
+ });
180
+
181
+ it("emits an undefined aria-activedescendant when nothing is highlighted", () => {
182
+ fixture.activeAria = { popoverId: "pop-1" };
183
+ const props = renderAria()();
184
+ expect(props).toHaveProperty("aria-activedescendant", undefined);
185
+ expect(props["aria-controls"]).toBe("pop-1");
186
+ });
187
+ });
@@ -0,0 +1,126 @@
1
+ "use client";
2
+
3
+ import { useCallback } from "react";
4
+ import { useAui } from "@assistant-ui/store";
5
+ import { flushTapSync } from "@assistant-ui/tap";
6
+ import { useComposerSend } from "@assistant-ui/core/react";
7
+ import type { ComposerSendOptions } from "@assistant-ui/core/store";
8
+ import {
9
+ type TriggerPopoverAriaProps,
10
+ useComposerInputDisabled,
11
+ useComposerInputValue,
12
+ useTriggerPopoverAriaProps,
13
+ } from "../primitives/composer/useComposerInputState";
14
+
15
+ export type Unstable_UseComposerInputOptions = {
16
+ /**
17
+ * Disables the input in addition to the composer's own disabled sources
18
+ * (thread disabled, active dictation). When disabled, `isDisabled` is `true`
19
+ * and `canSend` is `false`.
20
+ */
21
+ disabled?: boolean | undefined;
22
+ };
23
+
24
+ export type Unstable_ComposerInput = {
25
+ /** Current composer text, or `""` when the composer is not editing. */
26
+ value: string;
27
+ /**
28
+ * Writes `text` into the composer, mirroring `ComposerPrimitive.Input`:
29
+ * a no-op unless the composer is editing, committed via `flushTapSync` so the
30
+ * controlled value stays in sync within the same tick.
31
+ */
32
+ setText(text: string): void;
33
+ /**
34
+ * Sends the current message when `canSend` is `true`; otherwise a no-op.
35
+ * Accepts the same options as the composer send action.
36
+ */
37
+ send(options?: ComposerSendOptions): void;
38
+ /**
39
+ * Whether the input is disabled, combining the `disabled` option with the
40
+ * composer's own disabled sources (thread disabled, active dictation).
41
+ */
42
+ isDisabled: boolean;
43
+ /**
44
+ * Whether a send is currently available. Matches `ComposerPrimitive.Send`
45
+ * gating (non-empty editing composer, not running without queue support) and
46
+ * is additionally `false` while `isDisabled`.
47
+ */
48
+ canSend: boolean;
49
+ };
50
+
51
+ /**
52
+ * @deprecated Under active development and might change without notice.
53
+ *
54
+ * Headless bridge to the composer's text value and send action, for building a
55
+ * custom composer input without `ComposerPrimitive.Input`. It is a thin bridge,
56
+ * not a second input: it does not own keyboard behavior, autosize, IME or
57
+ * contentEditable sync, paste/drop attachments, focus management, or rich-text
58
+ * state. Spread `unstable_useTriggerPopoverAriaProps()` onto your element for
59
+ * trigger-popover combobox semantics.
60
+ *
61
+ * @example
62
+ * ```tsx
63
+ * const { value, setText, send, isDisabled, canSend } = unstable_useComposerInput();
64
+ * <textarea
65
+ * value={value}
66
+ * disabled={isDisabled}
67
+ * onChange={(e) => setText(e.target.value)}
68
+ * onKeyDown={(e) => {
69
+ * if (e.key === "Enter" && !e.shiftKey && canSend) {
70
+ * e.preventDefault();
71
+ * send();
72
+ * }
73
+ * }}
74
+ * />
75
+ * ```
76
+ */
77
+ export function unstable_useComposerInput(
78
+ options?: Unstable_UseComposerInputOptions,
79
+ ): Unstable_ComposerInput {
80
+ const aui = useAui();
81
+ const value = useComposerInputValue();
82
+ const isDisabled = useComposerInputDisabled(options?.disabled);
83
+
84
+ const setText = useCallback(
85
+ (text: string) => {
86
+ if (!aui.composer().getState().isEditing) return;
87
+ flushTapSync(() => {
88
+ aui.composer().setText(text);
89
+ });
90
+ },
91
+ [aui],
92
+ );
93
+
94
+ const { send: rawSend, disabled: sendDisabled } = useComposerSend();
95
+ const canSend = !sendDisabled && !isDisabled;
96
+ const send = useCallback(
97
+ (sendOptions?: ComposerSendOptions) => {
98
+ if (!canSend) return;
99
+ rawSend(sendOptions);
100
+ },
101
+ [canSend, rawSend],
102
+ );
103
+
104
+ return { value, setText, send, isDisabled, canSend };
105
+ }
106
+
107
+ export type Unstable_TriggerPopoverAriaProps = TriggerPopoverAriaProps;
108
+
109
+ /**
110
+ * @deprecated Under active development and might change without notice.
111
+ *
112
+ * ARIA combobox attributes for the focused element (typically the composer
113
+ * input) describing the open trigger popover, per the WAI-ARIA editable
114
+ * combobox pattern. Returns an empty object outside a `TriggerPopoverRoot` or
115
+ * when no popover is open. Spread these last so they take precedence over any
116
+ * matching ARIA props you set yourself, mirroring `ComposerPrimitive.Input`.
117
+ *
118
+ * @example
119
+ * ```tsx
120
+ * const aria = unstable_useTriggerPopoverAriaProps();
121
+ * <textarea {...aria} />
122
+ * ```
123
+ */
124
+ export function unstable_useTriggerPopoverAriaProps(): Unstable_TriggerPopoverAriaProps {
125
+ return useTriggerPopoverAriaProps();
126
+ }
@@ -8,7 +8,7 @@ const noopUnsubscribe = () => {};
8
8
  export const useMediaQuery = (query: string | null): boolean => {
9
9
  const subscribe = useCallback(
10
10
  (callback: () => void) => {
11
- if (typeof window === "undefined" || query === null)
11
+ if (typeof window === "undefined" || query === null || !window.matchMedia)
12
12
  return noopUnsubscribe;
13
13
  const mql = window.matchMedia(query);
14
14
  mql.addEventListener("change", callback);
@@ -18,7 +18,8 @@ export const useMediaQuery = (query: string | null): boolean => {
18
18
  );
19
19
 
20
20
  const getSnapshot = useCallback(() => {
21
- if (typeof window === "undefined" || query === null) return false;
21
+ if (typeof window === "undefined" || query === null || !window.matchMedia)
22
+ return false;
22
23
  return window.matchMedia(query).matches;
23
24
  }, [query]);
24
25
 
@@ -39,6 +39,23 @@ const runningState = (text: string) =>
39
39
  status: { type: "running" },
40
40
  }) as MessagePartState & TextMessagePart;
41
41
 
42
+ const setReducedMotion = (matches: boolean) => {
43
+ Object.defineProperty(window, "matchMedia", {
44
+ writable: true,
45
+ configurable: true,
46
+ value: (query: string) => ({
47
+ matches,
48
+ media: query,
49
+ onchange: null,
50
+ addEventListener: () => {},
51
+ removeEventListener: () => {},
52
+ addListener: () => {},
53
+ removeListener: () => {},
54
+ dispatchEvent: () => false,
55
+ }),
56
+ });
57
+ };
58
+
42
59
  const driveAndCount = (minCommitMs: number) => {
43
60
  const raf: FrameRequestCallback[] = [];
44
61
  const rafSpy = vi
@@ -85,6 +102,7 @@ const driveAndCount = (minCommitMs: number) => {
85
102
  describe("useSmooth", () => {
86
103
  afterEach(() => {
87
104
  vi.restoreAllMocks();
105
+ Reflect.deleteProperty(window, "matchMedia");
88
106
  });
89
107
 
90
108
  it("returns the input state unchanged when disabled", () => {
@@ -115,6 +133,14 @@ describe("useSmooth", () => {
115
133
  expect(result.current).toBe(state);
116
134
  });
117
135
 
136
+ it("disables the reveal under prefers-reduced-motion", () => {
137
+ setReducedMotion(true);
138
+ const state = runningState("streaming");
139
+ const { result } = renderHook(() => useSmooth(state, true));
140
+ expect(result.current).toBe(state);
141
+ expect(result.current.text).toBe("streaming");
142
+ });
143
+
118
144
  it("starts from an empty reveal for running parts when enabled", () => {
119
145
  const state = {
120
146
  type: "text",
@@ -9,6 +9,7 @@ import type {
9
9
  MessagePartState,
10
10
  } from "@assistant-ui/core";
11
11
  import { useCallbackRef } from "@radix-ui/react-use-callback-ref";
12
+ import { useMediaQuery } from "../hooks/useMediaQuery";
12
13
  import { useSmoothStatusStore } from "./SmoothContext";
13
14
  import { writableStore } from "../../context/ReadonlyStore";
14
15
 
@@ -134,6 +135,10 @@ const positiveOr = (value: number | undefined, fallback: number): number =>
134
135
  * the reveal. Returns the part state with `text` replaced by the revealed
135
136
  * prefix and `status` reporting `running` until the reveal catches up.
136
137
  *
138
+ * The reveal auto-disables under `prefers-reduced-motion: reduce`,
139
+ * committing the full text immediately; this takes precedence over an
140
+ * explicit `smooth={true}`.
141
+ *
137
142
  * @example
138
143
  * ```tsx
139
144
  * const { text, status } = useSmooth(useMessagePartText(), {
@@ -147,9 +152,10 @@ export const useSmooth = (
147
152
  smooth: boolean | SmoothOptions = false,
148
153
  ): MessagePartState & (TextMessagePart | ReasoningMessagePart) => {
149
154
  const { text } = state;
155
+ const reduceMotion = useMediaQuery("(prefers-reduced-motion: reduce)");
150
156
  const options =
151
157
  typeof smooth === "object" && smooth !== null ? smooth : undefined;
152
- const enabled = smooth !== false && smooth !== null;
158
+ const enabled = smooth !== false && smooth !== null && !reduceMotion;
153
159
  const drainMs = positiveOr(options?.drainMs, DEFAULT_DRAIN_MS);
154
160
  const maxCharIntervalMs = positiveOr(
155
161
  options?.maxCharIntervalMs,
@@ -1,23 +0,0 @@
1
- "use client";
2
-
3
- import {
4
- type ActionButtonElement,
5
- type ActionButtonProps,
6
- createActionButton,
7
- } from "../../utils/createActionButton";
8
- import { useThreadListItemTrigger as useThreadListItemTriggerBehavior } from "@assistant-ui/core/react";
9
-
10
- const useThreadListItemTrigger = () => {
11
- const { switchTo } = useThreadListItemTriggerBehavior();
12
- return switchTo;
13
- };
14
-
15
- export namespace ThreadListItemPrimitiveTrigger {
16
- export type Element = ActionButtonElement;
17
- export type Props = ActionButtonProps<typeof useThreadListItemTrigger>;
18
- }
19
-
20
- export const ThreadListItemPrimitiveTrigger = createActionButton(
21
- "ThreadListItemPrimitive.Trigger",
22
- useThreadListItemTrigger,
23
- );