@assistant-ui/react-native 0.1.42 → 0.1.44

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 (228) hide show
  1. package/dist/context/AssistantContext.d.ts +2 -2
  2. package/dist/context/AssistantContext.d.ts.map +1 -0
  3. package/dist/context/providers/AttachmentByIndexProvider.d.ts +2 -2
  4. package/dist/context/providers/AttachmentByIndexProvider.d.ts.map +1 -0
  5. package/dist/context/providers/RuntimeAdapterProvider.d.ts +2 -2
  6. package/dist/context/providers/RuntimeAdapterProvider.d.ts.map +1 -0
  7. package/dist/context/providers/ThreadListItemRuntimeProvider.d.ts +2 -2
  8. package/dist/context/providers/ThreadListItemRuntimeProvider.d.ts.map +1 -0
  9. package/dist/index.d.ts +54 -22
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +5 -4
  12. package/dist/internal.d.ts +4 -3
  13. package/dist/internal.d.ts.map +1 -0
  14. package/dist/primitives/actionBar/ActionBarCopy.d.ts +9 -11
  15. package/dist/primitives/actionBar/ActionBarCopy.d.ts.map +1 -1
  16. package/dist/primitives/actionBar/ActionBarCopy.js +23 -19
  17. package/dist/primitives/actionBar/ActionBarCopy.js.map +1 -1
  18. package/dist/primitives/actionBar/ActionBarEdit.d.ts +7 -7
  19. package/dist/primitives/actionBar/ActionBarEdit.d.ts.map +1 -1
  20. package/dist/primitives/actionBar/ActionBarEdit.js +21 -11
  21. package/dist/primitives/actionBar/ActionBarEdit.js.map +1 -1
  22. package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts +8 -10
  23. package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts.map +1 -1
  24. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js +35 -17
  25. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js.map +1 -1
  26. package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts +8 -10
  27. package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts.map +1 -1
  28. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js +35 -17
  29. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js.map +1 -1
  30. package/dist/primitives/actionBar/ActionBarReload.d.ts +7 -7
  31. package/dist/primitives/actionBar/ActionBarReload.d.ts.map +1 -1
  32. package/dist/primitives/actionBar/ActionBarReload.js +21 -11
  33. package/dist/primitives/actionBar/ActionBarReload.js.map +1 -1
  34. package/dist/primitives/actionBar/ActionBarSpeak.d.ts +12 -0
  35. package/dist/primitives/actionBar/ActionBarSpeak.d.ts.map +1 -0
  36. package/dist/primitives/actionBar/ActionBarSpeak.js +61 -0
  37. package/dist/primitives/actionBar/ActionBarSpeak.js.map +1 -0
  38. package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts +12 -0
  39. package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts.map +1 -0
  40. package/dist/primitives/actionBar/ActionBarStopSpeaking.js +61 -0
  41. package/dist/primitives/actionBar/ActionBarStopSpeaking.js.map +1 -0
  42. package/dist/primitives/actionBar.d.ts +7 -10
  43. package/dist/primitives/actionBar.d.ts.map +1 -1
  44. package/dist/primitives/actionBar.js +6 -2
  45. package/dist/primitives/actionBar.js.map +1 -1
  46. package/dist/primitives/attachment/AttachmentName.d.ts +4 -7
  47. package/dist/primitives/attachment/AttachmentName.d.ts.map +1 -1
  48. package/dist/primitives/attachment/AttachmentRemove.d.ts +4 -7
  49. package/dist/primitives/attachment/AttachmentRemove.d.ts.map +1 -1
  50. package/dist/primitives/attachment/AttachmentRoot.d.ts +5 -8
  51. package/dist/primitives/attachment/AttachmentRoot.d.ts.map +1 -1
  52. package/dist/primitives/attachment/AttachmentThumb.d.ts +4 -7
  53. package/dist/primitives/attachment/AttachmentThumb.d.ts.map +1 -1
  54. package/dist/primitives/attachment.d.ts +4 -9
  55. package/dist/primitives/attachment.d.ts.map +1 -1
  56. package/dist/primitives/branchPicker/BranchPickerCount.d.ts +3 -6
  57. package/dist/primitives/branchPicker/BranchPickerCount.d.ts.map +1 -1
  58. package/dist/primitives/branchPicker/BranchPickerNext.d.ts +7 -7
  59. package/dist/primitives/branchPicker/BranchPickerNext.d.ts.map +1 -1
  60. package/dist/primitives/branchPicker/BranchPickerNext.js +21 -11
  61. package/dist/primitives/branchPicker/BranchPickerNext.js.map +1 -1
  62. package/dist/primitives/branchPicker/BranchPickerNumber.d.ts +3 -6
  63. package/dist/primitives/branchPicker/BranchPickerNumber.d.ts.map +1 -1
  64. package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts +7 -7
  65. package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts.map +1 -1
  66. package/dist/primitives/branchPicker/BranchPickerPrevious.js +21 -11
  67. package/dist/primitives/branchPicker/BranchPickerPrevious.js.map +1 -1
  68. package/dist/primitives/branchPicker.d.ts +4 -9
  69. package/dist/primitives/branchPicker.d.ts.map +1 -1
  70. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts +4 -7
  71. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts.map +1 -1
  72. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts +5 -8
  73. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts.map +1 -1
  74. package/dist/primitives/chainOfThought.d.ts +3 -8
  75. package/dist/primitives/chainOfThought.d.ts.map +1 -1
  76. package/dist/primitives/composer/ComposerAddAttachment.d.ts +4 -7
  77. package/dist/primitives/composer/ComposerAddAttachment.d.ts.map +1 -1
  78. package/dist/primitives/composer/ComposerAttachments.d.ts +5 -8
  79. package/dist/primitives/composer/ComposerAttachments.d.ts.map +1 -1
  80. package/dist/primitives/composer/ComposerCancel.d.ts +4 -7
  81. package/dist/primitives/composer/ComposerCancel.d.ts.map +1 -1
  82. package/dist/primitives/composer/ComposerIf.d.ts +2 -2
  83. package/dist/primitives/composer/ComposerIf.d.ts.map +1 -0
  84. package/dist/primitives/composer/ComposerInput.d.ts +10 -13
  85. package/dist/primitives/composer/ComposerInput.d.ts.map +1 -1
  86. package/dist/primitives/composer/ComposerInput.js +1 -1
  87. package/dist/primitives/composer/ComposerInput.js.map +1 -1
  88. package/dist/primitives/composer/ComposerQueue.d.ts +2 -2
  89. package/dist/primitives/composer/ComposerQueue.d.ts.map +1 -0
  90. package/dist/primitives/composer/ComposerQuote.d.ts +5 -8
  91. package/dist/primitives/composer/ComposerQuote.d.ts.map +1 -1
  92. package/dist/primitives/composer/ComposerQuoteDismiss.d.ts +4 -7
  93. package/dist/primitives/composer/ComposerQuoteDismiss.d.ts.map +1 -1
  94. package/dist/primitives/composer/ComposerQuoteText.d.ts +5 -8
  95. package/dist/primitives/composer/ComposerQuoteText.d.ts.map +1 -1
  96. package/dist/primitives/composer/ComposerRoot.d.ts +5 -8
  97. package/dist/primitives/composer/ComposerRoot.d.ts.map +1 -1
  98. package/dist/primitives/composer/ComposerSend.d.ts +4 -7
  99. package/dist/primitives/composer/ComposerSend.d.ts.map +1 -1
  100. package/dist/primitives/composer.d.ts +11 -16
  101. package/dist/primitives/composer.d.ts.map +1 -1
  102. package/dist/primitives/error/ErrorMessage.d.ts +7 -10
  103. package/dist/primitives/error/ErrorMessage.d.ts.map +1 -1
  104. package/dist/primitives/error/ErrorRoot.d.ts +7 -10
  105. package/dist/primitives/error/ErrorRoot.d.ts.map +1 -1
  106. package/dist/primitives/error/index.d.ts +2 -7
  107. package/dist/primitives/error/index.d.ts.map +1 -1
  108. package/dist/primitives/message/MessageAttachments.d.ts +5 -8
  109. package/dist/primitives/message/MessageAttachments.d.ts.map +1 -1
  110. package/dist/primitives/message/MessageContent.d.ts +47 -49
  111. package/dist/primitives/message/MessageContent.d.ts.map +1 -1
  112. package/dist/primitives/message/MessageContent.js +27 -21
  113. package/dist/primitives/message/MessageContent.js.map +1 -1
  114. package/dist/primitives/message/MessageIf.d.ts +8 -11
  115. package/dist/primitives/message/MessageIf.d.ts.map +1 -1
  116. package/dist/primitives/message/MessageParts.d.ts +6 -8
  117. package/dist/primitives/message/MessageParts.d.ts.map +1 -1
  118. package/dist/primitives/message/MessageRoot.d.ts +5 -8
  119. package/dist/primitives/message/MessageRoot.d.ts.map +1 -1
  120. package/dist/primitives/message.d.ts +6 -11
  121. package/dist/primitives/message.d.ts.map +1 -1
  122. package/dist/primitives/messagePart/MessagePartImage.d.ts +9 -0
  123. package/dist/primitives/messagePart/MessagePartImage.d.ts.map +1 -0
  124. package/dist/primitives/messagePart/MessagePartImage.js +39 -0
  125. package/dist/primitives/messagePart/MessagePartImage.js.map +1 -0
  126. package/dist/primitives/messagePart/MessagePartInProgress.d.ts +2 -0
  127. package/dist/primitives/messagePart/MessagePartInProgress.d.ts.map +1 -0
  128. package/dist/primitives/messagePart/MessagePartInProgress.js +2 -0
  129. package/dist/primitives/messagePart/MessagePartText.d.ts +9 -0
  130. package/dist/primitives/messagePart/MessagePartText.d.ts.map +1 -0
  131. package/dist/primitives/messagePart/MessagePartText.js +32 -0
  132. package/dist/primitives/messagePart/MessagePartText.js.map +1 -0
  133. package/dist/primitives/messagePart.d.ts +5 -0
  134. package/dist/primitives/messagePart.d.ts.map +1 -0
  135. package/dist/primitives/messagePart.js +16 -0
  136. package/dist/primitives/messagePart.js.map +1 -0
  137. package/dist/primitives/queueItem/QueueItemRemove.d.ts +4 -7
  138. package/dist/primitives/queueItem/QueueItemRemove.d.ts.map +1 -1
  139. package/dist/primitives/queueItem/QueueItemSteer.d.ts +4 -7
  140. package/dist/primitives/queueItem/QueueItemSteer.d.ts.map +1 -1
  141. package/dist/primitives/queueItem/QueueItemText.d.ts +5 -8
  142. package/dist/primitives/queueItem/QueueItemText.d.ts.map +1 -1
  143. package/dist/primitives/queueItem.d.ts +3 -8
  144. package/dist/primitives/queueItem.d.ts.map +1 -1
  145. package/dist/primitives/suggestion/SuggestionDescription.d.ts +5 -8
  146. package/dist/primitives/suggestion/SuggestionDescription.d.ts.map +1 -1
  147. package/dist/primitives/suggestion/SuggestionTitle.d.ts +5 -8
  148. package/dist/primitives/suggestion/SuggestionTitle.d.ts.map +1 -1
  149. package/dist/primitives/suggestion/SuggestionTrigger.d.ts +15 -18
  150. package/dist/primitives/suggestion/SuggestionTrigger.d.ts.map +1 -1
  151. package/dist/primitives/suggestion/SuggestionTrigger.js +1 -1
  152. package/dist/primitives/suggestion.d.ts +3 -8
  153. package/dist/primitives/suggestion.d.ts.map +1 -1
  154. package/dist/primitives/thread/ThreadEmpty.d.ts +4 -7
  155. package/dist/primitives/thread/ThreadEmpty.d.ts.map +1 -1
  156. package/dist/primitives/thread/ThreadIf.d.ts +6 -9
  157. package/dist/primitives/thread/ThreadIf.d.ts.map +1 -1
  158. package/dist/primitives/thread/ThreadMessages.d.ts +41 -37
  159. package/dist/primitives/thread/ThreadMessages.d.ts.map +1 -1
  160. package/dist/primitives/thread/ThreadMessages.js +123 -72
  161. package/dist/primitives/thread/ThreadMessages.js.map +1 -1
  162. package/dist/primitives/thread/ThreadRoot.d.ts +5 -8
  163. package/dist/primitives/thread/ThreadRoot.d.ts.map +1 -1
  164. package/dist/primitives/thread/ThreadSuggestion.d.ts +17 -20
  165. package/dist/primitives/thread/ThreadSuggestion.d.ts.map +1 -1
  166. package/dist/primitives/thread.d.ts +8 -11
  167. package/dist/primitives/thread.d.ts.map +1 -1
  168. package/dist/primitives/threadList/ThreadListItems.d.ts +8 -11
  169. package/dist/primitives/threadList/ThreadListItems.d.ts.map +1 -1
  170. package/dist/primitives/threadList/ThreadListItems.js +1 -1
  171. package/dist/primitives/threadList/ThreadListNew.d.ts +7 -10
  172. package/dist/primitives/threadList/ThreadListNew.d.ts.map +1 -1
  173. package/dist/primitives/threadList/ThreadListNew.js +21 -17
  174. package/dist/primitives/threadList/ThreadListNew.js.map +1 -1
  175. package/dist/primitives/threadList/ThreadListRoot.d.ts +5 -8
  176. package/dist/primitives/threadList/ThreadListRoot.d.ts.map +1 -1
  177. package/dist/primitives/threadList.d.ts +3 -8
  178. package/dist/primitives/threadList.d.ts.map +1 -1
  179. package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts +4 -7
  180. package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts.map +1 -1
  181. package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts +4 -7
  182. package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts.map +1 -1
  183. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts +5 -8
  184. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts.map +1 -1
  185. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts +7 -10
  186. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts.map +1 -1
  187. package/dist/primitives/threadListItem/ThreadListItemTrigger.js +21 -17
  188. package/dist/primitives/threadListItem/ThreadListItemTrigger.js.map +1 -1
  189. package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts +4 -7
  190. package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts.map +1 -1
  191. package/dist/primitives/threadListItem.d.ts +6 -11
  192. package/dist/primitives/threadListItem.d.ts.map +1 -1
  193. package/dist/runtimes/useLocalRuntime.d.ts +2 -2
  194. package/dist/runtimes/useLocalRuntime.d.ts.map +1 -0
  195. package/dist/runtimes/useRemoteThreadListRuntime.d.ts +2 -2
  196. package/dist/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -0
  197. package/package.json +13 -12
  198. package/src/index.ts +91 -1
  199. package/src/primitives/accessibilityRole.test.tsx +20 -0
  200. package/src/primitives/actionBar/ActionBar.test.tsx +375 -0
  201. package/src/primitives/actionBar/ActionBarCopy.tsx +8 -3
  202. package/src/primitives/actionBar/ActionBarEdit.tsx +16 -4
  203. package/src/primitives/actionBar/ActionBarFeedbackNegative.tsx +18 -4
  204. package/src/primitives/actionBar/ActionBarFeedbackPositive.tsx +18 -4
  205. package/src/primitives/actionBar/ActionBarReload.tsx +16 -4
  206. package/src/primitives/actionBar/ActionBarSpeak.tsx +42 -0
  207. package/src/primitives/actionBar/ActionBarStopSpeaking.tsx +42 -0
  208. package/src/primitives/actionBar.ts +8 -0
  209. package/src/primitives/branchPicker/BranchPickerNext.test.tsx +52 -3
  210. package/src/primitives/branchPicker/BranchPickerNext.tsx +16 -4
  211. package/src/primitives/branchPicker/BranchPickerPrevious.test.tsx +52 -6
  212. package/src/primitives/branchPicker/BranchPickerPrevious.tsx +16 -4
  213. package/src/primitives/composer/ComposerInput.test.tsx +17 -1
  214. package/src/primitives/composer/ComposerInput.tsx +6 -1
  215. package/src/primitives/message/MessageContent.test.tsx +64 -3
  216. package/src/primitives/message/MessageContent.tsx +5 -3
  217. package/src/primitives/messagePart/MessagePartImage.test.tsx +91 -0
  218. package/src/primitives/messagePart/MessagePartImage.tsx +33 -0
  219. package/src/primitives/messagePart/MessagePartInProgress.ts +1 -0
  220. package/src/primitives/messagePart/MessagePartText.test.tsx +80 -0
  221. package/src/primitives/messagePart/MessagePartText.tsx +36 -0
  222. package/src/primitives/messagePart.ts +10 -0
  223. package/src/primitives/thread/ThreadMessages.test.tsx +190 -6
  224. package/src/primitives/thread/ThreadMessages.tsx +68 -1
  225. package/src/primitives/threadList/ThreadListNew.test.tsx +35 -8
  226. package/src/primitives/threadList/ThreadListNew.tsx +4 -1
  227. package/src/primitives/threadListItem/ThreadListItemTrigger.test.tsx +32 -6
  228. package/src/primitives/threadListItem/ThreadListItemTrigger.tsx +4 -1
@@ -7,6 +7,8 @@ import { ActionBarEdit } from "./actionBar/ActionBarEdit";
7
7
  import { ActionBarFeedbackNegative } from "./actionBar/ActionBarFeedbackNegative";
8
8
  import { ActionBarFeedbackPositive } from "./actionBar/ActionBarFeedbackPositive";
9
9
  import { ActionBarReload } from "./actionBar/ActionBarReload";
10
+ import { ActionBarSpeak } from "./actionBar/ActionBarSpeak";
11
+ import { ActionBarStopSpeaking } from "./actionBar/ActionBarStopSpeaking";
10
12
  import { AttachmentRemove } from "./attachment/AttachmentRemove";
11
13
  import { BranchPickerNext } from "./branchPicker/BranchPickerNext";
12
14
  import { BranchPickerPrevious } from "./branchPicker/BranchPickerPrevious";
@@ -64,6 +66,8 @@ vi.mock("@assistant-ui/core/react", () => ({
64
66
  isSubmitted: false,
65
67
  }),
66
68
  useActionBarReload: () => ({ reload: vi.fn(), disabled: false }),
69
+ useActionBarSpeak: () => ({ speak: vi.fn(), disabled: false }),
70
+ useActionBarStopSpeaking: () => ({ stopSpeaking: vi.fn(), disabled: false }),
67
71
  useBranchPickerNext: () => ({ next: vi.fn(), disabled: false }),
68
72
  useBranchPickerPrevious: () => ({ previous: vi.fn(), disabled: false }),
69
73
  useComposerAddAttachment: () => ({ disabled: false }),
@@ -134,6 +138,22 @@ const actionable: ReadonlyArray<{
134
138
  </ActionBarReload>
135
139
  ),
136
140
  },
141
+ {
142
+ name: "ActionBarSpeak",
143
+ render: (e) => (
144
+ <ActionBarSpeak testID="t" {...e}>
145
+ x
146
+ </ActionBarSpeak>
147
+ ),
148
+ },
149
+ {
150
+ name: "ActionBarStopSpeaking",
151
+ render: (e) => (
152
+ <ActionBarStopSpeaking testID="t" {...e}>
153
+ x
154
+ </ActionBarStopSpeaking>
155
+ ),
156
+ },
137
157
  {
138
158
  name: "AttachmentRemove",
139
159
  render: (e) => (
@@ -0,0 +1,375 @@
1
+ import { act, type ReactNode } from "react";
2
+ import { createRoot, type Root } from "react-dom/client";
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { ActionBarCopy } from "./ActionBarCopy";
5
+ import { ActionBarEdit } from "./ActionBarEdit";
6
+ import { ActionBarFeedbackNegative } from "./ActionBarFeedbackNegative";
7
+ import { ActionBarFeedbackPositive } from "./ActionBarFeedbackPositive";
8
+ import { ActionBarReload } from "./ActionBarReload";
9
+ import { ActionBarSpeak } from "./ActionBarSpeak";
10
+ import { ActionBarStopSpeaking } from "./ActionBarStopSpeaking";
11
+
12
+ const h = vi.hoisted(() => ({
13
+ copy: vi.fn<() => void>(),
14
+ edit: vi.fn<() => void>(),
15
+ feedbackNegative: vi.fn<() => void>(),
16
+ feedbackPositive: vi.fn<() => void>(),
17
+ reload: vi.fn<() => void>(),
18
+ speak: vi.fn<() => Promise<void>>(),
19
+ stopSpeaking: vi.fn<() => void>(),
20
+ platform: { os: "web" },
21
+ state: {
22
+ copy: { disabled: false, isCopied: false },
23
+ edit: { disabled: false },
24
+ feedbackNegative: { isSubmitted: false },
25
+ feedbackPositive: { isSubmitted: false },
26
+ reload: { disabled: false },
27
+ speak: { disabled: false },
28
+ stopSpeaking: { disabled: false },
29
+ },
30
+ }));
31
+
32
+ vi.mock("@assistant-ui/core/react", async (importOriginal) => {
33
+ const actual =
34
+ await importOriginal<typeof import("@assistant-ui/core/react")>();
35
+ return {
36
+ ...actual,
37
+ useActionBarCopy: () => ({
38
+ copy: h.copy,
39
+ disabled: h.state.copy.disabled,
40
+ isCopied: h.state.copy.isCopied,
41
+ }),
42
+ useActionBarEdit: () => ({ edit: h.edit, disabled: h.state.edit.disabled }),
43
+ useActionBarFeedbackNegative: () => ({
44
+ submit: h.feedbackNegative,
45
+ isSubmitted: h.state.feedbackNegative.isSubmitted,
46
+ }),
47
+ useActionBarFeedbackPositive: () => ({
48
+ submit: h.feedbackPositive,
49
+ isSubmitted: h.state.feedbackPositive.isSubmitted,
50
+ }),
51
+ useActionBarReload: () => ({
52
+ reload: h.reload,
53
+ disabled: h.state.reload.disabled,
54
+ }),
55
+ useActionBarSpeak: () => ({
56
+ speak: h.speak,
57
+ disabled: h.state.speak.disabled,
58
+ }),
59
+ useActionBarStopSpeaking: () => ({
60
+ stopSpeaking: h.stopSpeaking,
61
+ disabled: h.state.stopSpeaking.disabled,
62
+ }),
63
+ };
64
+ });
65
+
66
+ vi.mock("react-native", async (importOriginal) => {
67
+ const actual = (await importOriginal()) as Record<string, unknown> & {
68
+ Platform: Record<string, unknown>;
69
+ };
70
+ return {
71
+ ...actual,
72
+ Platform: {
73
+ ...actual.Platform,
74
+ get OS() {
75
+ return h.platform.os;
76
+ },
77
+ },
78
+ };
79
+ });
80
+
81
+ (globalThis as Record<string, unknown>).IS_REACT_ACT_ENVIRONMENT = true;
82
+
83
+ const click = (el: Element) =>
84
+ el.dispatchEvent(
85
+ new MouseEvent("click", { bubbles: true, cancelable: true }),
86
+ );
87
+
88
+ type DisabledChildren = (state: { disabled: boolean }) => ReactNode;
89
+
90
+ type ActionBarTestCase = {
91
+ name: string;
92
+ disabledState?: { disabled: boolean };
93
+ render: (
94
+ children: ReactNode | DisabledChildren,
95
+ disabled?: boolean,
96
+ ) => ReactNode;
97
+ };
98
+
99
+ const actionBars: ActionBarTestCase[] = [
100
+ {
101
+ name: "ActionBarCopy",
102
+ disabledState: h.state.copy,
103
+ render: (children, disabled) => (
104
+ <ActionBarCopy
105
+ testID="t"
106
+ {...(disabled === undefined ? {} : { disabled })}
107
+ >
108
+ {children}
109
+ </ActionBarCopy>
110
+ ),
111
+ },
112
+ {
113
+ name: "ActionBarEdit",
114
+ disabledState: h.state.edit,
115
+ render: (children, disabled) => (
116
+ <ActionBarEdit
117
+ testID="t"
118
+ {...(disabled === undefined ? {} : { disabled })}
119
+ >
120
+ {children}
121
+ </ActionBarEdit>
122
+ ),
123
+ },
124
+ {
125
+ name: "ActionBarFeedbackNegative",
126
+ render: (children, disabled) => (
127
+ <ActionBarFeedbackNegative
128
+ testID="t"
129
+ {...(disabled === undefined ? {} : { disabled })}
130
+ >
131
+ {children}
132
+ </ActionBarFeedbackNegative>
133
+ ),
134
+ },
135
+ {
136
+ name: "ActionBarFeedbackPositive",
137
+ render: (children, disabled) => (
138
+ <ActionBarFeedbackPositive
139
+ testID="t"
140
+ {...(disabled === undefined ? {} : { disabled })}
141
+ >
142
+ {children}
143
+ </ActionBarFeedbackPositive>
144
+ ),
145
+ },
146
+ {
147
+ name: "ActionBarReload",
148
+ disabledState: h.state.reload,
149
+ render: (children, disabled) => (
150
+ <ActionBarReload
151
+ testID="t"
152
+ {...(disabled === undefined ? {} : { disabled })}
153
+ >
154
+ {children}
155
+ </ActionBarReload>
156
+ ),
157
+ },
158
+ {
159
+ name: "ActionBarSpeak",
160
+ disabledState: h.state.speak,
161
+ render: (children, disabled) => (
162
+ <ActionBarSpeak
163
+ testID="t"
164
+ {...(disabled === undefined ? {} : { disabled })}
165
+ >
166
+ {children}
167
+ </ActionBarSpeak>
168
+ ),
169
+ },
170
+ {
171
+ name: "ActionBarStopSpeaking",
172
+ disabledState: h.state.stopSpeaking,
173
+ render: (children, disabled) => (
174
+ <ActionBarStopSpeaking
175
+ testID="t"
176
+ {...(disabled === undefined ? {} : { disabled })}
177
+ >
178
+ {children}
179
+ </ActionBarStopSpeaking>
180
+ ),
181
+ },
182
+ ];
183
+
184
+ describe("ActionBar", () => {
185
+ let container: HTMLDivElement;
186
+ let root: Root;
187
+
188
+ beforeEach(() => {
189
+ h.copy.mockReset();
190
+ h.edit.mockReset();
191
+ h.feedbackNegative.mockReset();
192
+ h.feedbackPositive.mockReset();
193
+ h.reload.mockReset();
194
+ h.speak.mockReset();
195
+ h.stopSpeaking.mockReset();
196
+ h.platform.os = "web";
197
+ h.state.copy.disabled = false;
198
+ h.state.copy.isCopied = false;
199
+ h.state.edit.disabled = false;
200
+ h.state.feedbackNegative.isSubmitted = false;
201
+ h.state.feedbackPositive.isSubmitted = false;
202
+ h.state.reload.disabled = false;
203
+ h.state.speak.disabled = false;
204
+ h.state.stopSpeaking.disabled = false;
205
+
206
+ container = document.createElement("div");
207
+ document.body.appendChild(container);
208
+ root = createRoot(container);
209
+ });
210
+
211
+ afterEach(async () => {
212
+ await act(async () => {
213
+ root.unmount();
214
+ });
215
+ container.remove();
216
+ });
217
+
218
+ const mount = async (node: ReactNode) => {
219
+ await act(async () => {
220
+ root.render(node);
221
+ });
222
+ return container.querySelector('[data-testid="t"]') as HTMLElement;
223
+ };
224
+
225
+ for (const actionBar of actionBars) {
226
+ describe(actionBar.name, () => {
227
+ it("passes the effective disabled state to render children", async () => {
228
+ if (actionBar.disabledState) {
229
+ actionBar.disabledState.disabled = true;
230
+ }
231
+
232
+ let initialState: { disabled: boolean } | null = null;
233
+ const initialEl = await mount(
234
+ actionBar.render((state) => {
235
+ initialState = state;
236
+ return state.disabled ? "disabled" : "enabled";
237
+ }),
238
+ );
239
+
240
+ expect(initialEl.textContent).toBe(
241
+ actionBar.disabledState ? "disabled" : "enabled",
242
+ );
243
+ expect(initialState).toMatchObject({
244
+ disabled: actionBar.disabledState ? true : false,
245
+ });
246
+
247
+ let propState: { disabled: boolean } | null = null;
248
+ const propEl = await mount(
249
+ actionBar.render((state) => {
250
+ propState = state;
251
+ return state.disabled ? "disabled" : "enabled";
252
+ }, !actionBar.disabledState),
253
+ );
254
+
255
+ expect(propEl.textContent).toBe(
256
+ actionBar.disabledState ? "enabled" : "disabled",
257
+ );
258
+ expect(propState).toMatchObject({
259
+ disabled: !actionBar.disabledState,
260
+ });
261
+ });
262
+
263
+ it("renders plain children", async () => {
264
+ const el = await mount(actionBar.render("label"));
265
+
266
+ expect(el.textContent).toBe("label");
267
+ });
268
+ });
269
+ }
270
+
271
+ const feedbackActionBars = [
272
+ {
273
+ name: "ActionBarFeedbackNegative",
274
+ state: h.state.feedbackNegative,
275
+ render: (extra: { "aria-selected"?: boolean }) => (
276
+ <ActionBarFeedbackNegative testID="t" {...extra}>
277
+ x
278
+ </ActionBarFeedbackNegative>
279
+ ),
280
+ },
281
+ {
282
+ name: "ActionBarFeedbackPositive",
283
+ state: h.state.feedbackPositive,
284
+ render: (extra: { "aria-selected"?: boolean }) => (
285
+ <ActionBarFeedbackPositive testID="t" {...extra}>
286
+ x
287
+ </ActionBarFeedbackPositive>
288
+ ),
289
+ },
290
+ ];
291
+
292
+ for (const { name, state, render } of feedbackActionBars) {
293
+ describe(name, () => {
294
+ it("marks submitted feedback pressed on the web", async () => {
295
+ state.isSubmitted = true;
296
+
297
+ const el = await mount(render({}));
298
+
299
+ expect(el.getAttribute("aria-pressed")).toBe("true");
300
+ expect(el.hasAttribute("aria-selected")).toBe(false);
301
+ });
302
+
303
+ it("does not mark unsubmitted feedback pressed on the web", async () => {
304
+ const el = await mount(render({}));
305
+
306
+ expect(el.getAttribute("aria-pressed")).toBe("false");
307
+ });
308
+
309
+ it("marks submitted feedback selected on native", async () => {
310
+ h.platform.os = "ios";
311
+ state.isSubmitted = true;
312
+
313
+ const el = await mount(render({}));
314
+
315
+ expect(el.getAttribute("aria-selected")).toBe("true");
316
+ expect(el.hasAttribute("aria-pressed")).toBe(false);
317
+ });
318
+
319
+ it("keeps a caller selected override on native", async () => {
320
+ h.platform.os = "ios";
321
+ state.isSubmitted = true;
322
+
323
+ const el = await mount(render({ "aria-selected": false }));
324
+
325
+ expect(el.getAttribute("aria-selected")).toBe("false");
326
+ });
327
+ });
328
+ }
329
+
330
+ it("calls speak on press", async () => {
331
+ const el = await mount(<ActionBarSpeak testID="t">speak</ActionBarSpeak>);
332
+
333
+ await act(async () => {
334
+ click(el);
335
+ });
336
+
337
+ expect(h.speak).toHaveBeenCalledTimes(1);
338
+ });
339
+
340
+ it("does not call speak while the hook disables it", async () => {
341
+ h.state.speak.disabled = true;
342
+ const el = await mount(<ActionBarSpeak testID="t">speak</ActionBarSpeak>);
343
+
344
+ await act(async () => {
345
+ click(el);
346
+ });
347
+
348
+ expect(h.speak).not.toHaveBeenCalled();
349
+ });
350
+
351
+ it("calls stopSpeaking on press", async () => {
352
+ const el = await mount(
353
+ <ActionBarStopSpeaking testID="t">stop</ActionBarStopSpeaking>,
354
+ );
355
+
356
+ await act(async () => {
357
+ click(el);
358
+ });
359
+
360
+ expect(h.stopSpeaking).toHaveBeenCalledTimes(1);
361
+ });
362
+
363
+ it("does not call stopSpeaking while the hook disables it", async () => {
364
+ h.state.stopSpeaking.disabled = true;
365
+ const el = await mount(
366
+ <ActionBarStopSpeaking testID="t">stop</ActionBarStopSpeaking>,
367
+ );
368
+
369
+ await act(async () => {
370
+ click(el);
371
+ });
372
+
373
+ expect(h.stopSpeaking).not.toHaveBeenCalled();
374
+ });
375
+ });
@@ -7,7 +7,9 @@ import {
7
7
 
8
8
  export type ActionBarCopyProps = Omit<PressableProps, "onPress" | "children"> &
9
9
  UseActionBarCopyOptions & {
10
- children: ReactNode | ((props: { isCopied: boolean }) => ReactNode);
10
+ children:
11
+ | ReactNode
12
+ | ((props: { isCopied: boolean; disabled: boolean }) => ReactNode);
11
13
  };
12
14
 
13
15
  export const ActionBarCopy = ({
@@ -21,15 +23,18 @@ export const ActionBarCopy = ({
21
23
  copiedDuration,
22
24
  copyToClipboard,
23
25
  });
26
+ const isDisabled = disabledProp ?? disabled;
24
27
 
25
28
  return (
26
29
  <Pressable
27
30
  onPress={copy}
28
- disabled={disabledProp ?? disabled}
31
+ disabled={isDisabled}
29
32
  accessibilityRole="button"
30
33
  {...pressableProps}
31
34
  >
32
- {typeof children === "function" ? children({ isCopied }) : children}
35
+ {typeof children === "function"
36
+ ? children({ isCopied, disabled: isDisabled })
37
+ : children}
33
38
  </Pressable>
34
39
  );
35
40
  };
@@ -1,11 +1,20 @@
1
- import { Pressable, type PressableProps } from "react-native";
1
+ import type { ReactNode } from "react";
2
+ import {
3
+ Pressable,
4
+ type PressableProps,
5
+ type PressableStateCallbackType,
6
+ } from "react-native";
2
7
  import { useActionBarEdit } from "@assistant-ui/core/react";
3
8
 
4
9
  export type ActionBarEditProps = Omit<
5
10
  PressableProps,
6
11
  "onPress" | "children"
7
12
  > & {
8
- children: PressableProps["children"];
13
+ children:
14
+ | ReactNode
15
+ | ((
16
+ state: PressableStateCallbackType & { disabled: boolean },
17
+ ) => ReactNode);
9
18
  };
10
19
 
11
20
  export const ActionBarEdit = ({
@@ -14,15 +23,18 @@ export const ActionBarEdit = ({
14
23
  ...pressableProps
15
24
  }: ActionBarEditProps) => {
16
25
  const { edit, disabled } = useActionBarEdit();
26
+ const isDisabled = disabledProp ?? disabled;
17
27
 
18
28
  return (
19
29
  <Pressable
20
30
  onPress={edit}
21
- disabled={disabledProp ?? disabled}
31
+ disabled={isDisabled}
22
32
  accessibilityRole="button"
23
33
  {...pressableProps}
24
34
  >
25
- {children}
35
+ {typeof children === "function"
36
+ ? (state) => children({ ...state, disabled: isDisabled })
37
+ : children}
26
38
  </Pressable>
27
39
  );
28
40
  };
@@ -1,23 +1,37 @@
1
1
  import type { ReactNode } from "react";
2
- import { Pressable, type PressableProps } from "react-native";
2
+ import { Platform, Pressable, type PressableProps } from "react-native";
3
3
  import { useActionBarFeedbackNegative } from "@assistant-ui/core/react";
4
4
 
5
5
  export type ActionBarFeedbackNegativeProps = Omit<
6
6
  PressableProps,
7
7
  "onPress" | "children"
8
8
  > & {
9
- children: ReactNode | ((props: { isSubmitted: boolean }) => ReactNode);
9
+ children:
10
+ | ReactNode
11
+ | ((props: { isSubmitted: boolean; disabled: boolean }) => ReactNode);
10
12
  };
11
13
 
12
14
  export const ActionBarFeedbackNegative = ({
13
15
  children,
16
+ disabled: disabledProp,
14
17
  ...pressableProps
15
18
  }: ActionBarFeedbackNegativeProps) => {
16
19
  const { submit, isSubmitted } = useActionBarFeedbackNegative();
20
+ const disabled = disabledProp ?? false;
17
21
 
18
22
  return (
19
- <Pressable onPress={submit} accessibilityRole="button" {...pressableProps}>
20
- {typeof children === "function" ? children({ isSubmitted }) : children}
23
+ <Pressable
24
+ onPress={submit}
25
+ disabled={disabledProp}
26
+ accessibilityRole="button"
27
+ {...(Platform.OS === "web"
28
+ ? { "aria-pressed": isSubmitted }
29
+ : { "aria-selected": isSubmitted })}
30
+ {...pressableProps}
31
+ >
32
+ {typeof children === "function"
33
+ ? children({ isSubmitted, disabled })
34
+ : children}
21
35
  </Pressable>
22
36
  );
23
37
  };
@@ -1,23 +1,37 @@
1
1
  import type { ReactNode } from "react";
2
- import { Pressable, type PressableProps } from "react-native";
2
+ import { Platform, Pressable, type PressableProps } from "react-native";
3
3
  import { useActionBarFeedbackPositive } from "@assistant-ui/core/react";
4
4
 
5
5
  export type ActionBarFeedbackPositiveProps = Omit<
6
6
  PressableProps,
7
7
  "onPress" | "children"
8
8
  > & {
9
- children: ReactNode | ((props: { isSubmitted: boolean }) => ReactNode);
9
+ children:
10
+ | ReactNode
11
+ | ((props: { isSubmitted: boolean; disabled: boolean }) => ReactNode);
10
12
  };
11
13
 
12
14
  export const ActionBarFeedbackPositive = ({
13
15
  children,
16
+ disabled: disabledProp,
14
17
  ...pressableProps
15
18
  }: ActionBarFeedbackPositiveProps) => {
16
19
  const { submit, isSubmitted } = useActionBarFeedbackPositive();
20
+ const disabled = disabledProp ?? false;
17
21
 
18
22
  return (
19
- <Pressable onPress={submit} accessibilityRole="button" {...pressableProps}>
20
- {typeof children === "function" ? children({ isSubmitted }) : children}
23
+ <Pressable
24
+ onPress={submit}
25
+ disabled={disabledProp}
26
+ accessibilityRole="button"
27
+ {...(Platform.OS === "web"
28
+ ? { "aria-pressed": isSubmitted }
29
+ : { "aria-selected": isSubmitted })}
30
+ {...pressableProps}
31
+ >
32
+ {typeof children === "function"
33
+ ? children({ isSubmitted, disabled })
34
+ : children}
21
35
  </Pressable>
22
36
  );
23
37
  };
@@ -1,11 +1,20 @@
1
- import { Pressable, type PressableProps } from "react-native";
1
+ import type { ReactNode } from "react";
2
+ import {
3
+ Pressable,
4
+ type PressableProps,
5
+ type PressableStateCallbackType,
6
+ } from "react-native";
2
7
  import { useActionBarReload } from "@assistant-ui/core/react";
3
8
 
4
9
  export type ActionBarReloadProps = Omit<
5
10
  PressableProps,
6
11
  "onPress" | "children"
7
12
  > & {
8
- children: PressableProps["children"];
13
+ children:
14
+ | ReactNode
15
+ | ((
16
+ state: PressableStateCallbackType & { disabled: boolean },
17
+ ) => ReactNode);
9
18
  };
10
19
 
11
20
  export const ActionBarReload = ({
@@ -14,15 +23,18 @@ export const ActionBarReload = ({
14
23
  ...pressableProps
15
24
  }: ActionBarReloadProps) => {
16
25
  const { reload, disabled } = useActionBarReload();
26
+ const isDisabled = disabledProp ?? disabled;
17
27
 
18
28
  return (
19
29
  <Pressable
20
30
  onPress={reload}
21
- disabled={disabledProp ?? disabled}
31
+ disabled={isDisabled}
22
32
  accessibilityRole="button"
23
33
  {...pressableProps}
24
34
  >
25
- {children}
35
+ {typeof children === "function"
36
+ ? (state) => children({ ...state, disabled: isDisabled })
37
+ : children}
26
38
  </Pressable>
27
39
  );
28
40
  };
@@ -0,0 +1,42 @@
1
+ import type { ReactNode } from "react";
2
+ import {
3
+ Pressable,
4
+ type PressableProps,
5
+ type PressableStateCallbackType,
6
+ } from "react-native";
7
+ import { useActionBarSpeak } from "@assistant-ui/core/react";
8
+
9
+ export type ActionBarSpeakProps = Omit<
10
+ PressableProps,
11
+ "children" | "onPress"
12
+ > & {
13
+ children:
14
+ | ReactNode
15
+ | ((
16
+ state: PressableStateCallbackType & { disabled: boolean },
17
+ ) => ReactNode);
18
+ };
19
+
20
+ export const ActionBarSpeak = ({
21
+ children,
22
+ disabled: disabledProp,
23
+ ...pressableProps
24
+ }: ActionBarSpeakProps) => {
25
+ const { speak, disabled } = useActionBarSpeak();
26
+ const isDisabled = disabledProp ?? disabled;
27
+
28
+ return (
29
+ <Pressable
30
+ onPress={() => void speak()}
31
+ disabled={isDisabled}
32
+ accessibilityRole="button"
33
+ {...pressableProps}
34
+ >
35
+ {typeof children === "function"
36
+ ? (state) => children({ ...state, disabled: isDisabled })
37
+ : children}
38
+ </Pressable>
39
+ );
40
+ };
41
+
42
+ ActionBarSpeak.displayName = "ActionBarPrimitive.Speak";