@assistant-ui/react-native 0.1.42 → 0.1.43

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 (167) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.js +2 -1
  3. package/dist/primitives/actionBar/ActionBarCopy.d.ts +3 -3
  4. package/dist/primitives/actionBar/ActionBarCopy.d.ts.map +1 -1
  5. package/dist/primitives/actionBar/ActionBarCopy.js +23 -19
  6. package/dist/primitives/actionBar/ActionBarCopy.js.map +1 -1
  7. package/dist/primitives/actionBar/ActionBarEdit.d.ts +7 -5
  8. package/dist/primitives/actionBar/ActionBarEdit.d.ts.map +1 -1
  9. package/dist/primitives/actionBar/ActionBarEdit.js +21 -11
  10. package/dist/primitives/actionBar/ActionBarEdit.js.map +1 -1
  11. package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts +3 -3
  12. package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts.map +1 -1
  13. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js +26 -16
  14. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js.map +1 -1
  15. package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts +3 -3
  16. package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts.map +1 -1
  17. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js +26 -16
  18. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js.map +1 -1
  19. package/dist/primitives/actionBar/ActionBarReload.d.ts +7 -5
  20. package/dist/primitives/actionBar/ActionBarReload.d.ts.map +1 -1
  21. package/dist/primitives/actionBar/ActionBarReload.js +21 -11
  22. package/dist/primitives/actionBar/ActionBarReload.js.map +1 -1
  23. package/dist/primitives/actionBar/ActionBarSpeak.d.ts +14 -0
  24. package/dist/primitives/actionBar/ActionBarSpeak.d.ts.map +1 -0
  25. package/dist/primitives/actionBar/ActionBarSpeak.js +61 -0
  26. package/dist/primitives/actionBar/ActionBarSpeak.js.map +1 -0
  27. package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts +14 -0
  28. package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts.map +1 -0
  29. package/dist/primitives/actionBar/ActionBarStopSpeaking.js +61 -0
  30. package/dist/primitives/actionBar/ActionBarStopSpeaking.js.map +1 -0
  31. package/dist/primitives/actionBar.d.ts +4 -2
  32. package/dist/primitives/actionBar.js +6 -2
  33. package/dist/primitives/actionBar.js.map +1 -1
  34. package/dist/primitives/attachment/AttachmentName.d.ts +2 -3
  35. package/dist/primitives/attachment/AttachmentName.d.ts.map +1 -1
  36. package/dist/primitives/attachment/AttachmentRemove.d.ts +2 -3
  37. package/dist/primitives/attachment/AttachmentRemove.d.ts.map +1 -1
  38. package/dist/primitives/attachment/AttachmentRoot.d.ts +2 -3
  39. package/dist/primitives/attachment/AttachmentRoot.d.ts.map +1 -1
  40. package/dist/primitives/attachment/AttachmentThumb.d.ts +2 -3
  41. package/dist/primitives/attachment/AttachmentThumb.d.ts.map +1 -1
  42. package/dist/primitives/branchPicker/BranchPickerCount.d.ts +2 -3
  43. package/dist/primitives/branchPicker/BranchPickerCount.d.ts.map +1 -1
  44. package/dist/primitives/branchPicker/BranchPickerNext.d.ts +7 -5
  45. package/dist/primitives/branchPicker/BranchPickerNext.d.ts.map +1 -1
  46. package/dist/primitives/branchPicker/BranchPickerNext.js +21 -11
  47. package/dist/primitives/branchPicker/BranchPickerNext.js.map +1 -1
  48. package/dist/primitives/branchPicker/BranchPickerNumber.d.ts +2 -3
  49. package/dist/primitives/branchPicker/BranchPickerNumber.d.ts.map +1 -1
  50. package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts +7 -5
  51. package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts.map +1 -1
  52. package/dist/primitives/branchPicker/BranchPickerPrevious.js +21 -11
  53. package/dist/primitives/branchPicker/BranchPickerPrevious.js.map +1 -1
  54. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts +2 -3
  55. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts.map +1 -1
  56. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts +2 -3
  57. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts.map +1 -1
  58. package/dist/primitives/composer/ComposerAddAttachment.d.ts +2 -3
  59. package/dist/primitives/composer/ComposerAddAttachment.d.ts.map +1 -1
  60. package/dist/primitives/composer/ComposerAttachments.d.ts +4 -5
  61. package/dist/primitives/composer/ComposerAttachments.d.ts.map +1 -1
  62. package/dist/primitives/composer/ComposerCancel.d.ts +2 -3
  63. package/dist/primitives/composer/ComposerCancel.d.ts.map +1 -1
  64. package/dist/primitives/composer/ComposerInput.d.ts +2 -3
  65. package/dist/primitives/composer/ComposerInput.d.ts.map +1 -1
  66. package/dist/primitives/composer/ComposerQuote.d.ts +2 -3
  67. package/dist/primitives/composer/ComposerQuote.d.ts.map +1 -1
  68. package/dist/primitives/composer/ComposerQuoteDismiss.d.ts +2 -3
  69. package/dist/primitives/composer/ComposerQuoteDismiss.d.ts.map +1 -1
  70. package/dist/primitives/composer/ComposerQuoteText.d.ts +2 -3
  71. package/dist/primitives/composer/ComposerQuoteText.d.ts.map +1 -1
  72. package/dist/primitives/composer/ComposerRoot.d.ts +2 -3
  73. package/dist/primitives/composer/ComposerRoot.d.ts.map +1 -1
  74. package/dist/primitives/composer/ComposerSend.d.ts +2 -3
  75. package/dist/primitives/composer/ComposerSend.d.ts.map +1 -1
  76. package/dist/primitives/error/ErrorMessage.d.ts +2 -3
  77. package/dist/primitives/error/ErrorMessage.d.ts.map +1 -1
  78. package/dist/primitives/error/ErrorRoot.d.ts +2 -3
  79. package/dist/primitives/error/ErrorRoot.d.ts.map +1 -1
  80. package/dist/primitives/message/MessageAttachments.d.ts +4 -5
  81. package/dist/primitives/message/MessageAttachments.d.ts.map +1 -1
  82. package/dist/primitives/message/MessageContent.d.ts +2 -3
  83. package/dist/primitives/message/MessageContent.d.ts.map +1 -1
  84. package/dist/primitives/message/MessageIf.d.ts +2 -3
  85. package/dist/primitives/message/MessageIf.d.ts.map +1 -1
  86. package/dist/primitives/message/MessageParts.d.ts +3 -3
  87. package/dist/primitives/message/MessageParts.d.ts.map +1 -1
  88. package/dist/primitives/message/MessageRoot.d.ts +2 -3
  89. package/dist/primitives/message/MessageRoot.d.ts.map +1 -1
  90. package/dist/primitives/messagePart/MessagePartImage.d.ts +11 -0
  91. package/dist/primitives/messagePart/MessagePartImage.d.ts.map +1 -0
  92. package/dist/primitives/messagePart/MessagePartImage.js +39 -0
  93. package/dist/primitives/messagePart/MessagePartImage.js.map +1 -0
  94. package/dist/primitives/messagePart/MessagePartInProgress.d.ts +2 -0
  95. package/dist/primitives/messagePart/MessagePartInProgress.js +2 -0
  96. package/dist/primitives/messagePart/MessagePartText.d.ts +11 -0
  97. package/dist/primitives/messagePart/MessagePartText.d.ts.map +1 -0
  98. package/dist/primitives/messagePart/MessagePartText.js +32 -0
  99. package/dist/primitives/messagePart/MessagePartText.js.map +1 -0
  100. package/dist/primitives/messagePart.d.ts +10 -0
  101. package/dist/primitives/messagePart.d.ts.map +1 -0
  102. package/dist/primitives/messagePart.js +16 -0
  103. package/dist/primitives/messagePart.js.map +1 -0
  104. package/dist/primitives/queueItem/QueueItemRemove.d.ts +2 -3
  105. package/dist/primitives/queueItem/QueueItemRemove.d.ts.map +1 -1
  106. package/dist/primitives/queueItem/QueueItemSteer.d.ts +2 -3
  107. package/dist/primitives/queueItem/QueueItemSteer.d.ts.map +1 -1
  108. package/dist/primitives/queueItem/QueueItemText.d.ts +2 -3
  109. package/dist/primitives/queueItem/QueueItemText.d.ts.map +1 -1
  110. package/dist/primitives/suggestion/SuggestionDescription.d.ts +2 -3
  111. package/dist/primitives/suggestion/SuggestionDescription.d.ts.map +1 -1
  112. package/dist/primitives/suggestion/SuggestionTitle.d.ts +2 -3
  113. package/dist/primitives/suggestion/SuggestionTitle.d.ts.map +1 -1
  114. package/dist/primitives/suggestion/SuggestionTrigger.d.ts +2 -3
  115. package/dist/primitives/suggestion/SuggestionTrigger.d.ts.map +1 -1
  116. package/dist/primitives/thread/ThreadEmpty.d.ts +2 -3
  117. package/dist/primitives/thread/ThreadEmpty.d.ts.map +1 -1
  118. package/dist/primitives/thread/ThreadIf.d.ts +2 -3
  119. package/dist/primitives/thread/ThreadIf.d.ts.map +1 -1
  120. package/dist/primitives/thread/ThreadMessages.d.ts +9 -5
  121. package/dist/primitives/thread/ThreadMessages.d.ts.map +1 -1
  122. package/dist/primitives/thread/ThreadMessages.js +117 -78
  123. package/dist/primitives/thread/ThreadMessages.js.map +1 -1
  124. package/dist/primitives/thread/ThreadRoot.d.ts +2 -3
  125. package/dist/primitives/thread/ThreadRoot.d.ts.map +1 -1
  126. package/dist/primitives/thread/ThreadSuggestion.d.ts +2 -3
  127. package/dist/primitives/thread/ThreadSuggestion.d.ts.map +1 -1
  128. package/dist/primitives/threadList/ThreadListItems.d.ts +2 -3
  129. package/dist/primitives/threadList/ThreadListItems.d.ts.map +1 -1
  130. package/dist/primitives/threadList/ThreadListNew.d.ts +2 -3
  131. package/dist/primitives/threadList/ThreadListNew.d.ts.map +1 -1
  132. package/dist/primitives/threadList/ThreadListRoot.d.ts +2 -3
  133. package/dist/primitives/threadList/ThreadListRoot.d.ts.map +1 -1
  134. package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts +2 -3
  135. package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts.map +1 -1
  136. package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts +2 -3
  137. package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts.map +1 -1
  138. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts +2 -3
  139. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts.map +1 -1
  140. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts +2 -3
  141. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts.map +1 -1
  142. package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts +2 -3
  143. package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts.map +1 -1
  144. package/package.json +13 -12
  145. package/src/index.ts +1 -0
  146. package/src/primitives/accessibilityRole.test.tsx +20 -0
  147. package/src/primitives/actionBar/ActionBar.test.tsx +299 -0
  148. package/src/primitives/actionBar/ActionBarCopy.tsx +8 -3
  149. package/src/primitives/actionBar/ActionBarEdit.tsx +16 -4
  150. package/src/primitives/actionBar/ActionBarFeedbackNegative.tsx +14 -3
  151. package/src/primitives/actionBar/ActionBarFeedbackPositive.tsx +14 -3
  152. package/src/primitives/actionBar/ActionBarReload.tsx +16 -4
  153. package/src/primitives/actionBar/ActionBarSpeak.tsx +42 -0
  154. package/src/primitives/actionBar/ActionBarStopSpeaking.tsx +42 -0
  155. package/src/primitives/actionBar.ts +8 -0
  156. package/src/primitives/branchPicker/BranchPickerNext.test.tsx +52 -3
  157. package/src/primitives/branchPicker/BranchPickerNext.tsx +16 -4
  158. package/src/primitives/branchPicker/BranchPickerPrevious.test.tsx +52 -6
  159. package/src/primitives/branchPicker/BranchPickerPrevious.tsx +16 -4
  160. package/src/primitives/messagePart/MessagePartImage.test.tsx +91 -0
  161. package/src/primitives/messagePart/MessagePartImage.tsx +33 -0
  162. package/src/primitives/messagePart/MessagePartInProgress.ts +1 -0
  163. package/src/primitives/messagePart/MessagePartText.test.tsx +80 -0
  164. package/src/primitives/messagePart/MessagePartText.tsx +36 -0
  165. package/src/primitives/messagePart.ts +10 -0
  166. package/src/primitives/thread/ThreadMessages.test.tsx +79 -1
  167. package/src/primitives/thread/ThreadMessages.tsx +37 -0
@@ -1,10 +1,9 @@
1
1
  import { ViewProps } from "react-native";
2
2
  import { ReactNode } from "react";
3
3
  //#region src/primitives/threadListItem/ThreadListItemRoot.d.ts
4
- type ThreadListItemRootProps = ViewProps & {
4
+ export type ThreadListItemRootProps = ViewProps & {
5
5
  children: ReactNode;
6
6
  };
7
- declare const ThreadListItemRoot: ({ children, ...viewProps }: ThreadListItemRootProps) => import("react").JSX.Element;
7
+ export declare const ThreadListItemRoot: ({ children, ...viewProps }: ThreadListItemRootProps) => import("react").JSX.Element;
8
8
  //#endregion
9
- export { ThreadListItemRoot, ThreadListItemRootProps };
10
9
  //# sourceMappingURL=ThreadListItemRoot.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadListItemRoot.d.ts","names":[],"sources":["../../../src/primitives/threadListItem/ThreadListItemRoot.tsx"],"mappings":";;;KAGY,0BAA0B;EACpC,UAAU;;cAGC,uBAAsB,aAAA,aAGhC,4CAAuB,IAAA"}
1
+ {"version":3,"file":"ThreadListItemRoot.d.ts","names":[],"sources":["../../../src/primitives/threadListItem/ThreadListItemRoot.tsx"],"mappings":";;;YAGY,0BAA0B;EACpC,UAAU;;qBAGC,uBAAsB,aAAA,aAGhC,4CAAuB,IAAA"}
@@ -1,12 +1,11 @@
1
1
  import { PressableProps, PressableStateCallbackType } from "react-native";
2
2
  import { ReactNode } from "react";
3
3
  //#region src/primitives/threadListItem/ThreadListItemTrigger.d.ts
4
- type ThreadListItemTriggerProps = Omit<PressableProps, "onPress" | "children"> & {
4
+ export type ThreadListItemTriggerProps = Omit<PressableProps, "onPress" | "children"> & {
5
5
  children: ReactNode | ((state: PressableStateCallbackType & {
6
6
  isActive: boolean;
7
7
  }) => ReactNode);
8
8
  };
9
- declare const ThreadListItemTrigger: ({ children, accessibilityState, ...pressableProps }: ThreadListItemTriggerProps) => import("react").JSX.Element;
9
+ export declare const ThreadListItemTrigger: ({ children, accessibilityState, ...pressableProps }: ThreadListItemTriggerProps) => import("react").JSX.Element;
10
10
  //#endregion
11
- export { ThreadListItemTrigger, ThreadListItemTriggerProps };
12
11
  //# sourceMappingURL=ThreadListItemTrigger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadListItemTrigger.d.ts","names":[],"sources":["../../../src/primitives/threadListItem/ThreadListItemTrigger.tsx"],"mappings":";;;KASY,6BAA6B,KACvC;EAGA,UACI,cAEE,OAAO;IAA+B;QACnC;;cAGE,0BAAyB,UAAA,uBAAA,kBAInC,+CAA0B,IAAA"}
1
+ {"version":3,"file":"ThreadListItemTrigger.d.ts","names":[],"sources":["../../../src/primitives/threadListItem/ThreadListItemTrigger.tsx"],"mappings":";;;YASY,6BAA6B,KACvC;EAGA,UACI,cAEE,OAAO;IAA+B;QACnC;;qBAGE,0BAAyB,UAAA,uBAAA,kBAInC,+CAA0B,IAAA"}
@@ -1,9 +1,8 @@
1
1
  import { PressableProps } from "react-native";
2
2
  //#region src/primitives/threadListItem/ThreadListItemUnarchive.d.ts
3
- type ThreadListItemUnarchiveProps = Omit<PressableProps, "onPress" | "children"> & {
3
+ export type ThreadListItemUnarchiveProps = Omit<PressableProps, "onPress" | "children"> & {
4
4
  children: PressableProps["children"];
5
5
  };
6
- declare const ThreadListItemUnarchive: ({ children, ...pressableProps }: ThreadListItemUnarchiveProps) => import("react").JSX.Element;
6
+ export declare const ThreadListItemUnarchive: ({ children, ...pressableProps }: ThreadListItemUnarchiveProps) => import("react").JSX.Element;
7
7
  //#endregion
8
- export { ThreadListItemUnarchive, ThreadListItemUnarchiveProps };
9
8
  //# sourceMappingURL=ThreadListItemUnarchive.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadListItemUnarchive.d.ts","names":[],"sources":["../../../src/primitives/threadListItem/ThreadListItemUnarchive.tsx"],"mappings":";;KAGY,+BAA+B,KACzC;EAGA,UAAU;;cAGC,4BAA2B,aAAA,kBAGrC,iDAA4B,IAAA"}
1
+ {"version":3,"file":"ThreadListItemUnarchive.d.ts","names":[],"sources":["../../../src/primitives/threadListItem/ThreadListItemUnarchive.tsx"],"mappings":";;YAGY,+BAA+B,KACzC;EAGA,UAAU;;qBAGC,4BAA2B,aAAA,kBAGrC,iDAA4B,IAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-native",
3
- "version": "0.1.42",
3
+ "version": "0.1.43",
4
4
  "description": "React Native bindings for assistant-ui",
5
5
  "keywords": [
6
6
  "assistant",
@@ -31,11 +31,11 @@
31
31
  ],
32
32
  "sideEffects": false,
33
33
  "dependencies": {
34
- "@assistant-ui/core": "^0.3.19",
35
- "@assistant-ui/store": "^0.3.13",
36
- "@assistant-ui/tap": "^0.9.17",
37
- "assistant-cloud": "^0.2.1",
38
- "assistant-stream": "^0.3.43"
34
+ "@assistant-ui/core": "^0.3.20",
35
+ "@assistant-ui/store": "^0.3.14",
36
+ "@assistant-ui/tap": "^0.9.18",
37
+ "assistant-cloud": "^0.2.2",
38
+ "assistant-stream": "^0.3.44"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "@types/react": "*",
@@ -48,16 +48,16 @@
48
48
  }
49
49
  },
50
50
  "devDependencies": {
51
- "@assistant-ui/x-buildutils": "0.0.27",
51
+ "@assistant-ui/x-buildutils": "0.0.28",
52
52
  "@babel/core": "^7.29.7",
53
- "@types/react": "^19.2.18",
54
- "@types/react-dom": "^19.2.7",
53
+ "@types/react": "^19.3.0",
54
+ "@types/react-dom": "^19.3.0",
55
55
  "jsdom": "^30.0.1",
56
- "react": "^19.2.8",
57
- "react-dom": "^19.2.8",
56
+ "react": "^19.3.0",
57
+ "react-dom": "^19.3.0",
58
58
  "react-native": "^0.87.1",
59
59
  "react-native-web": "^0.21.2",
60
- "vitest": "^5.0.0"
60
+ "vitest": "^5.0.1"
61
61
  },
62
62
  "publishConfig": {
63
63
  "access": "public",
@@ -75,6 +75,7 @@
75
75
  "scripts": {
76
76
  "build": "aui-build",
77
77
  "test": "vitest run",
78
+ "typecheck": "tsc --noEmit",
78
79
  "test:watch": "vitest"
79
80
  }
80
81
  }
package/src/index.ts CHANGED
@@ -162,6 +162,7 @@ export * as ThreadPrimitive from "./primitives/thread";
162
162
  export * as ComposerPrimitive from "./primitives/composer";
163
163
  export * as QueueItemPrimitive from "./primitives/queueItem";
164
164
  export * as MessagePrimitive from "./primitives/message";
165
+ export * as MessagePartPrimitive from "./primitives/messagePart";
165
166
  export * as ThreadListPrimitive from "./primitives/threadList";
166
167
  export * as ActionBarPrimitive from "./primitives/actionBar";
167
168
  export * as BranchPickerPrimitive from "./primitives/branchPicker";
@@ -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,299 @@
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
+ state: {
21
+ copy: { disabled: false, isCopied: false },
22
+ edit: { disabled: false },
23
+ feedbackNegative: { isSubmitted: false },
24
+ feedbackPositive: { isSubmitted: false },
25
+ reload: { disabled: false },
26
+ speak: { disabled: false },
27
+ stopSpeaking: { disabled: false },
28
+ },
29
+ }));
30
+
31
+ vi.mock("@assistant-ui/core/react", async (importOriginal) => {
32
+ const actual =
33
+ await importOriginal<typeof import("@assistant-ui/core/react")>();
34
+ return {
35
+ ...actual,
36
+ useActionBarCopy: () => ({
37
+ copy: h.copy,
38
+ disabled: h.state.copy.disabled,
39
+ isCopied: h.state.copy.isCopied,
40
+ }),
41
+ useActionBarEdit: () => ({ edit: h.edit, disabled: h.state.edit.disabled }),
42
+ useActionBarFeedbackNegative: () => ({
43
+ submit: h.feedbackNegative,
44
+ isSubmitted: h.state.feedbackNegative.isSubmitted,
45
+ }),
46
+ useActionBarFeedbackPositive: () => ({
47
+ submit: h.feedbackPositive,
48
+ isSubmitted: h.state.feedbackPositive.isSubmitted,
49
+ }),
50
+ useActionBarReload: () => ({
51
+ reload: h.reload,
52
+ disabled: h.state.reload.disabled,
53
+ }),
54
+ useActionBarSpeak: () => ({
55
+ speak: h.speak,
56
+ disabled: h.state.speak.disabled,
57
+ }),
58
+ useActionBarStopSpeaking: () => ({
59
+ stopSpeaking: h.stopSpeaking,
60
+ disabled: h.state.stopSpeaking.disabled,
61
+ }),
62
+ };
63
+ });
64
+
65
+ (globalThis as Record<string, unknown>).IS_REACT_ACT_ENVIRONMENT = true;
66
+
67
+ const click = (el: Element) =>
68
+ el.dispatchEvent(
69
+ new MouseEvent("click", { bubbles: true, cancelable: true }),
70
+ );
71
+
72
+ type DisabledChildren = (state: { disabled: boolean }) => ReactNode;
73
+
74
+ type ActionBarTestCase = {
75
+ name: string;
76
+ disabledState?: { disabled: boolean };
77
+ render: (
78
+ children: ReactNode | DisabledChildren,
79
+ disabled?: boolean,
80
+ ) => ReactNode;
81
+ };
82
+
83
+ const actionBars: ActionBarTestCase[] = [
84
+ {
85
+ name: "ActionBarCopy",
86
+ disabledState: h.state.copy,
87
+ render: (children, disabled) => (
88
+ <ActionBarCopy
89
+ testID="t"
90
+ {...(disabled === undefined ? {} : { disabled })}
91
+ >
92
+ {children}
93
+ </ActionBarCopy>
94
+ ),
95
+ },
96
+ {
97
+ name: "ActionBarEdit",
98
+ disabledState: h.state.edit,
99
+ render: (children, disabled) => (
100
+ <ActionBarEdit
101
+ testID="t"
102
+ {...(disabled === undefined ? {} : { disabled })}
103
+ >
104
+ {children}
105
+ </ActionBarEdit>
106
+ ),
107
+ },
108
+ {
109
+ name: "ActionBarFeedbackNegative",
110
+ render: (children, disabled) => (
111
+ <ActionBarFeedbackNegative
112
+ testID="t"
113
+ {...(disabled === undefined ? {} : { disabled })}
114
+ >
115
+ {children}
116
+ </ActionBarFeedbackNegative>
117
+ ),
118
+ },
119
+ {
120
+ name: "ActionBarFeedbackPositive",
121
+ render: (children, disabled) => (
122
+ <ActionBarFeedbackPositive
123
+ testID="t"
124
+ {...(disabled === undefined ? {} : { disabled })}
125
+ >
126
+ {children}
127
+ </ActionBarFeedbackPositive>
128
+ ),
129
+ },
130
+ {
131
+ name: "ActionBarReload",
132
+ disabledState: h.state.reload,
133
+ render: (children, disabled) => (
134
+ <ActionBarReload
135
+ testID="t"
136
+ {...(disabled === undefined ? {} : { disabled })}
137
+ >
138
+ {children}
139
+ </ActionBarReload>
140
+ ),
141
+ },
142
+ {
143
+ name: "ActionBarSpeak",
144
+ disabledState: h.state.speak,
145
+ render: (children, disabled) => (
146
+ <ActionBarSpeak
147
+ testID="t"
148
+ {...(disabled === undefined ? {} : { disabled })}
149
+ >
150
+ {children}
151
+ </ActionBarSpeak>
152
+ ),
153
+ },
154
+ {
155
+ name: "ActionBarStopSpeaking",
156
+ disabledState: h.state.stopSpeaking,
157
+ render: (children, disabled) => (
158
+ <ActionBarStopSpeaking
159
+ testID="t"
160
+ {...(disabled === undefined ? {} : { disabled })}
161
+ >
162
+ {children}
163
+ </ActionBarStopSpeaking>
164
+ ),
165
+ },
166
+ ];
167
+
168
+ describe("ActionBar", () => {
169
+ let container: HTMLDivElement;
170
+ let root: Root;
171
+
172
+ beforeEach(() => {
173
+ h.copy.mockReset();
174
+ h.edit.mockReset();
175
+ h.feedbackNegative.mockReset();
176
+ h.feedbackPositive.mockReset();
177
+ h.reload.mockReset();
178
+ h.speak.mockReset();
179
+ h.stopSpeaking.mockReset();
180
+ h.state.copy.disabled = false;
181
+ h.state.copy.isCopied = false;
182
+ h.state.edit.disabled = false;
183
+ h.state.feedbackNegative.isSubmitted = false;
184
+ h.state.feedbackPositive.isSubmitted = false;
185
+ h.state.reload.disabled = false;
186
+ h.state.speak.disabled = false;
187
+ h.state.stopSpeaking.disabled = false;
188
+
189
+ container = document.createElement("div");
190
+ document.body.appendChild(container);
191
+ root = createRoot(container);
192
+ });
193
+
194
+ afterEach(async () => {
195
+ await act(async () => {
196
+ root.unmount();
197
+ });
198
+ container.remove();
199
+ });
200
+
201
+ const mount = async (node: ReactNode) => {
202
+ await act(async () => {
203
+ root.render(node);
204
+ });
205
+ return container.querySelector('[data-testid="t"]') as HTMLElement;
206
+ };
207
+
208
+ for (const actionBar of actionBars) {
209
+ describe(actionBar.name, () => {
210
+ it("passes the effective disabled state to render children", async () => {
211
+ if (actionBar.disabledState) {
212
+ actionBar.disabledState.disabled = true;
213
+ }
214
+
215
+ let initialState: { disabled: boolean } | null = null;
216
+ const initialEl = await mount(
217
+ actionBar.render((state) => {
218
+ initialState = state;
219
+ return state.disabled ? "disabled" : "enabled";
220
+ }),
221
+ );
222
+
223
+ expect(initialEl.textContent).toBe(
224
+ actionBar.disabledState ? "disabled" : "enabled",
225
+ );
226
+ expect(initialState).toMatchObject({
227
+ disabled: actionBar.disabledState ? true : false,
228
+ });
229
+
230
+ let propState: { disabled: boolean } | null = null;
231
+ const propEl = await mount(
232
+ actionBar.render((state) => {
233
+ propState = state;
234
+ return state.disabled ? "disabled" : "enabled";
235
+ }, !actionBar.disabledState),
236
+ );
237
+
238
+ expect(propEl.textContent).toBe(
239
+ actionBar.disabledState ? "enabled" : "disabled",
240
+ );
241
+ expect(propState).toMatchObject({
242
+ disabled: !actionBar.disabledState,
243
+ });
244
+ });
245
+
246
+ it("renders plain children", async () => {
247
+ const el = await mount(actionBar.render("label"));
248
+
249
+ expect(el.textContent).toBe("label");
250
+ });
251
+ });
252
+ }
253
+
254
+ it("calls speak on press", async () => {
255
+ const el = await mount(<ActionBarSpeak testID="t">speak</ActionBarSpeak>);
256
+
257
+ await act(async () => {
258
+ click(el);
259
+ });
260
+
261
+ expect(h.speak).toHaveBeenCalledTimes(1);
262
+ });
263
+
264
+ it("does not call speak while the hook disables it", async () => {
265
+ h.state.speak.disabled = true;
266
+ const el = await mount(<ActionBarSpeak testID="t">speak</ActionBarSpeak>);
267
+
268
+ await act(async () => {
269
+ click(el);
270
+ });
271
+
272
+ expect(h.speak).not.toHaveBeenCalled();
273
+ });
274
+
275
+ it("calls stopSpeaking on press", async () => {
276
+ const el = await mount(
277
+ <ActionBarStopSpeaking testID="t">stop</ActionBarStopSpeaking>,
278
+ );
279
+
280
+ await act(async () => {
281
+ click(el);
282
+ });
283
+
284
+ expect(h.stopSpeaking).toHaveBeenCalledTimes(1);
285
+ });
286
+
287
+ it("does not call stopSpeaking while the hook disables it", async () => {
288
+ h.state.stopSpeaking.disabled = true;
289
+ const el = await mount(
290
+ <ActionBarStopSpeaking testID="t">stop</ActionBarStopSpeaking>,
291
+ );
292
+
293
+ await act(async () => {
294
+ click(el);
295
+ });
296
+
297
+ expect(h.stopSpeaking).not.toHaveBeenCalled();
298
+ });
299
+ });
@@ -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
  };
@@ -6,18 +6,29 @@ 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
+ {...pressableProps}
28
+ >
29
+ {typeof children === "function"
30
+ ? children({ isSubmitted, disabled })
31
+ : children}
21
32
  </Pressable>
22
33
  );
23
34
  };
@@ -6,18 +6,29 @@ 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
+ {...pressableProps}
28
+ >
29
+ {typeof children === "function"
30
+ ? children({ isSubmitted, disabled })
31
+ : children}
21
32
  </Pressable>
22
33
  );
23
34
  };
@@ -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
  };