@oxy.so/bloom 3.2.0 → 3.3.0

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 (496) hide show
  1. package/docs/adoption-matrix.mdx +3 -3
  2. package/docs/ai-chat.mdx +31 -3
  3. package/docs/composer-panel.mdx +23 -6
  4. package/lib/commonjs/agent-limits-card/AgentLimitsCard.js +25 -23
  5. package/lib/commonjs/agent-limits-card/AgentLimitsCard.js.map +1 -1
  6. package/lib/commonjs/ai-chat/AiChatContainer.js +122 -14
  7. package/lib/commonjs/ai-chat/AiChatContainer.js.map +1 -1
  8. package/lib/commonjs/ai-chat/AiChatShell.js +46 -6
  9. package/lib/commonjs/ai-chat/AiChatShell.js.map +1 -1
  10. package/lib/commonjs/ai-chat/context.js +5 -1
  11. package/lib/commonjs/ai-chat/context.js.map +1 -1
  12. package/lib/commonjs/ai-chat/index.js +7 -0
  13. package/lib/commonjs/ai-chat/index.js.map +1 -1
  14. package/lib/commonjs/ai-chat/index.web.js +7 -0
  15. package/lib/commonjs/ai-chat/index.web.js.map +1 -1
  16. package/lib/commonjs/app-shell/AppShellHeader.js +5 -4
  17. package/lib/commonjs/app-shell/AppShellHeader.js.map +1 -1
  18. package/lib/commonjs/app-shell/AppShellMenuButton.js +3 -2
  19. package/lib/commonjs/app-shell/AppShellMenuButton.js.map +1 -1
  20. package/lib/commonjs/app-shell/NotificationBell.js +6 -6
  21. package/lib/commonjs/app-shell/NotificationBell.js.map +1 -1
  22. package/lib/commonjs/auth-card/AuthCard.js +20 -20
  23. package/lib/commonjs/auth-card/AuthCard.js.map +1 -1
  24. package/lib/commonjs/calendar/CalendarViewEventDetails.js +27 -22
  25. package/lib/commonjs/calendar/CalendarViewEventDetails.js.map +1 -1
  26. package/lib/commonjs/calendar/CalendarViewHeader.js +6 -5
  27. package/lib/commonjs/calendar/CalendarViewHeader.js.map +1 -1
  28. package/lib/commonjs/calendar/CalendarViewInboxMenu.js +9 -7
  29. package/lib/commonjs/calendar/CalendarViewInboxMenu.js.map +1 -1
  30. package/lib/commonjs/carousel/Carousel.js +4 -3
  31. package/lib/commonjs/carousel/Carousel.js.map +1 -1
  32. package/lib/commonjs/chart-cards/BarListCard.js +10 -10
  33. package/lib/commonjs/chart-cards/BarListCard.js.map +1 -1
  34. package/lib/commonjs/chart-cards/primitives/ChartRangePill.js +10 -8
  35. package/lib/commonjs/chart-cards/primitives/ChartRangePill.js.map +1 -1
  36. package/lib/commonjs/chat-indicators/MessageStatus.js +8 -5
  37. package/lib/commonjs/chat-indicators/MessageStatus.js.map +1 -1
  38. package/lib/commonjs/composer-panel/ComposerControls.js +61 -0
  39. package/lib/commonjs/composer-panel/ComposerControls.js.map +1 -1
  40. package/lib/commonjs/composer-panel/ComposerPanelBase.js +12 -4
  41. package/lib/commonjs/composer-panel/ComposerPanelBase.js.map +1 -1
  42. package/lib/commonjs/composer-panel/ComposerPillBase.js +114 -79
  43. package/lib/commonjs/composer-panel/ComposerPillBase.js.map +1 -1
  44. package/lib/commonjs/composer-panel/EffortSlider.js +24 -15
  45. package/lib/commonjs/composer-panel/EffortSlider.js.map +1 -1
  46. package/lib/commonjs/composer-panel/ModelPickerBase.js +15 -4
  47. package/lib/commonjs/composer-panel/ModelPickerBase.js.map +1 -1
  48. package/lib/commonjs/data-table/DataTableRowActions.js +2 -2
  49. package/lib/commonjs/data-table/DataTableRowActions.js.map +1 -1
  50. package/lib/commonjs/data-table/DataTableSearch.js +8 -8
  51. package/lib/commonjs/data-table/DataTableSearch.js.map +1 -1
  52. package/lib/commonjs/date-picker/MeetingScheduler.js +23 -21
  53. package/lib/commonjs/date-picker/MeetingScheduler.js.map +1 -1
  54. package/lib/commonjs/date-picker/PickerShell.js +2 -2
  55. package/lib/commonjs/date-picker/PickerShell.js.map +1 -1
  56. package/lib/commonjs/dialog/DialogHeader.js +25 -17
  57. package/lib/commonjs/dialog/DialogHeader.js.map +1 -1
  58. package/lib/commonjs/eviction/EvictionReportCard.js +27 -20
  59. package/lib/commonjs/eviction/EvictionReportCard.js.map +1 -1
  60. package/lib/commonjs/eviction/constants.js +16 -9
  61. package/lib/commonjs/eviction/constants.js.map +1 -1
  62. package/lib/commonjs/file-upload/FileUpload.js +14 -11
  63. package/lib/commonjs/file-upload/FileUpload.js.map +1 -1
  64. package/lib/commonjs/floating/menu-rows.js +2 -2
  65. package/lib/commonjs/floating/menu-rows.js.map +1 -1
  66. package/lib/commonjs/floating/menu-sub-flyout.js +2 -2
  67. package/lib/commonjs/floating/menu-sub-flyout.js.map +1 -1
  68. package/lib/commonjs/floating/menu-sub-inline.js +3 -2
  69. package/lib/commonjs/floating/menu-sub-inline.js.map +1 -1
  70. package/lib/commonjs/listing-card/ListingCard.js +29 -28
  71. package/lib/commonjs/listing-card/ListingCard.js.map +1 -1
  72. package/lib/commonjs/listing-details/ContactCard.js +21 -17
  73. package/lib/commonjs/listing-details/ContactCard.js.map +1 -1
  74. package/lib/commonjs/listing-details/FloorPlan.js +5 -5
  75. package/lib/commonjs/listing-details/FloorPlan.js.map +1 -1
  76. package/lib/commonjs/listing-details/ListingPhotoGrid.js +4 -4
  77. package/lib/commonjs/listing-details/ListingPhotoGrid.js.map +1 -1
  78. package/lib/commonjs/listing-details/ReviewCard.js +13 -13
  79. package/lib/commonjs/listing-details/ReviewCard.js.map +1 -1
  80. package/lib/commonjs/listing-details/ReviewSummary.js +7 -7
  81. package/lib/commonjs/listing-details/ReviewSummary.js.map +1 -1
  82. package/lib/commonjs/message-bubble/CallSummaryRow.js +10 -7
  83. package/lib/commonjs/message-bubble/CallSummaryRow.js.map +1 -1
  84. package/lib/commonjs/message-bubble/SwipeToReply.js +2 -2
  85. package/lib/commonjs/message-bubble/SwipeToReply.js.map +1 -1
  86. package/lib/commonjs/message-bubble/parts.js +20 -17
  87. package/lib/commonjs/message-bubble/parts.js.map +1 -1
  88. package/lib/commonjs/notification-center/NotificationCenter.js +24 -20
  89. package/lib/commonjs/notification-center/NotificationCenter.js.map +1 -1
  90. package/lib/commonjs/page-header/PageHeader.js +9 -9
  91. package/lib/commonjs/page-header/PageHeader.js.map +1 -1
  92. package/lib/commonjs/place-reviews/PlaceReviewCard.js +20 -15
  93. package/lib/commonjs/place-reviews/PlaceReviewCard.js.map +1 -1
  94. package/lib/commonjs/place-reviews/PlaceReviewSummary.js +6 -5
  95. package/lib/commonjs/place-reviews/PlaceReviewSummary.js.map +1 -1
  96. package/lib/commonjs/place-reviews/WriteReviewPrompt.js +9 -7
  97. package/lib/commonjs/place-reviews/WriteReviewPrompt.js.map +1 -1
  98. package/lib/commonjs/property-insights/EnergyBadge.js +5 -5
  99. package/lib/commonjs/property-insights/EnergyBadge.js.map +1 -1
  100. package/lib/commonjs/property-insights/EnergyLabel.js +10 -10
  101. package/lib/commonjs/property-insights/EnergyLabel.js.map +1 -1
  102. package/lib/commonjs/property-insights/NearbyPlaces.js +6 -6
  103. package/lib/commonjs/property-insights/NearbyPlaces.js.map +1 -1
  104. package/lib/commonjs/property-insights/PriceEstimate.js +17 -16
  105. package/lib/commonjs/property-insights/PriceEstimate.js.map +1 -1
  106. package/lib/commonjs/property-insights/PriceHistoryChart.js +7 -7
  107. package/lib/commonjs/property-insights/PriceHistoryChart.js.map +1 -1
  108. package/lib/commonjs/property-insights/RentHistoryList.js +7 -7
  109. package/lib/commonjs/property-insights/RentHistoryList.js.map +1 -1
  110. package/lib/commonjs/recent-hires-card/RecentHiresCard.js +10 -9
  111. package/lib/commonjs/recent-hires-card/RecentHiresCard.js.map +1 -1
  112. package/lib/commonjs/select/Select.js +2 -2
  113. package/lib/commonjs/select/Select.js.map +1 -1
  114. package/lib/commonjs/select/Select.web.js +2 -2
  115. package/lib/commonjs/select/Select.web.js.map +1 -1
  116. package/lib/commonjs/select/shared.js +3 -2
  117. package/lib/commonjs/select/shared.js.map +1 -1
  118. package/lib/commonjs/settings-modal/SettingsFields.js +8 -8
  119. package/lib/commonjs/settings-modal/SettingsFields.js.map +1 -1
  120. package/lib/commonjs/settings-modal/SettingsModal.js +17 -14
  121. package/lib/commonjs/settings-modal/SettingsModal.js.map +1 -1
  122. package/lib/commonjs/settings-modal/SettingsStorage.js +30 -22
  123. package/lib/commonjs/settings-modal/SettingsStorage.js.map +1 -1
  124. package/lib/commonjs/settings-modal/SettingsTools.js +18 -17
  125. package/lib/commonjs/settings-modal/SettingsTools.js.map +1 -1
  126. package/lib/commonjs/sidebar/Sidebar.js +19 -17
  127. package/lib/commonjs/sidebar/Sidebar.js.map +1 -1
  128. package/lib/commonjs/sidebar/SidebarFolder.js +7 -6
  129. package/lib/commonjs/sidebar/SidebarFolder.js.map +1 -1
  130. package/lib/commonjs/sidebar/SidebarUserMenu.js +8 -7
  131. package/lib/commonjs/sidebar/SidebarUserMenu.js.map +1 -1
  132. package/lib/commonjs/task-list/TaskList.js +6 -6
  133. package/lib/commonjs/task-list/TaskList.js.map +1 -1
  134. package/lib/commonjs/tenancy/DocumentList.js +10 -8
  135. package/lib/commonjs/tenancy/DocumentList.js.map +1 -1
  136. package/lib/commonjs/tenancy/MaintenanceRequestCard.js +9 -9
  137. package/lib/commonjs/tenancy/MaintenanceRequestCard.js.map +1 -1
  138. package/lib/commonjs/tenancy/RentPaymentList.js +19 -19
  139. package/lib/commonjs/tenancy/RentPaymentList.js.map +1 -1
  140. package/lib/commonjs/tenancy/constants.js +18 -10
  141. package/lib/commonjs/tenancy/constants.js.map +1 -1
  142. package/lib/commonjs/text-field/TextField.js +11 -11
  143. package/lib/commonjs/text-field/TextField.js.map +1 -1
  144. package/lib/commonjs/theme-toggle/ThemeToggle.js +7 -6
  145. package/lib/commonjs/theme-toggle/ThemeToggle.js.map +1 -1
  146. package/lib/commonjs/web-search/WebSearch.js +8 -8
  147. package/lib/commonjs/web-search/WebSearch.js.map +1 -1
  148. package/lib/commonjs/zoomable-media-gallery/ZoomableMediaGallery.js +19 -14
  149. package/lib/commonjs/zoomable-media-gallery/ZoomableMediaGallery.js.map +1 -1
  150. package/lib/module/agent-limits-card/AgentLimitsCard.js +3 -1
  151. package/lib/module/agent-limits-card/AgentLimitsCard.js.map +1 -1
  152. package/lib/module/ai-chat/AiChatContainer.js +122 -14
  153. package/lib/module/ai-chat/AiChatContainer.js.map +1 -1
  154. package/lib/module/ai-chat/AiChatShell.js +46 -6
  155. package/lib/module/ai-chat/AiChatShell.js.map +1 -1
  156. package/lib/module/ai-chat/context.js +5 -1
  157. package/lib/module/ai-chat/context.js.map +1 -1
  158. package/lib/module/ai-chat/index.js +1 -0
  159. package/lib/module/ai-chat/index.js.map +1 -1
  160. package/lib/module/ai-chat/index.web.js +1 -0
  161. package/lib/module/ai-chat/index.web.js.map +1 -1
  162. package/lib/module/app-shell/AppShellHeader.js +2 -1
  163. package/lib/module/app-shell/AppShellHeader.js.map +1 -1
  164. package/lib/module/app-shell/AppShellMenuButton.js +2 -1
  165. package/lib/module/app-shell/AppShellMenuButton.js.map +1 -1
  166. package/lib/module/app-shell/NotificationBell.js +1 -1
  167. package/lib/module/app-shell/NotificationBell.js.map +1 -1
  168. package/lib/module/auth-card/AuthCard.js +1 -1
  169. package/lib/module/auth-card/AuthCard.js.map +1 -1
  170. package/lib/module/calendar/CalendarViewEventDetails.js +6 -1
  171. package/lib/module/calendar/CalendarViewEventDetails.js.map +1 -1
  172. package/lib/module/calendar/CalendarViewHeader.js +2 -1
  173. package/lib/module/calendar/CalendarViewHeader.js.map +1 -1
  174. package/lib/module/calendar/CalendarViewInboxMenu.js +3 -1
  175. package/lib/module/calendar/CalendarViewInboxMenu.js.map +1 -1
  176. package/lib/module/carousel/Carousel.js +2 -1
  177. package/lib/module/carousel/Carousel.js.map +1 -1
  178. package/lib/module/chart-cards/BarListCard.js +1 -1
  179. package/lib/module/chart-cards/BarListCard.js.map +1 -1
  180. package/lib/module/chart-cards/primitives/ChartRangePill.js +3 -1
  181. package/lib/module/chart-cards/primitives/ChartRangePill.js.map +1 -1
  182. package/lib/module/chat-indicators/MessageStatus.js +4 -1
  183. package/lib/module/chat-indicators/MessageStatus.js.map +1 -1
  184. package/lib/module/composer-panel/ComposerControls.js +60 -0
  185. package/lib/module/composer-panel/ComposerControls.js.map +1 -1
  186. package/lib/module/composer-panel/ComposerPanelBase.js +13 -5
  187. package/lib/module/composer-panel/ComposerPanelBase.js.map +1 -1
  188. package/lib/module/composer-panel/ComposerPillBase.js +115 -80
  189. package/lib/module/composer-panel/ComposerPillBase.js.map +1 -1
  190. package/lib/module/composer-panel/EffortSlider.js +24 -15
  191. package/lib/module/composer-panel/EffortSlider.js.map +1 -1
  192. package/lib/module/composer-panel/ModelPickerBase.js +15 -4
  193. package/lib/module/composer-panel/ModelPickerBase.js.map +1 -1
  194. package/lib/module/data-table/DataTableRowActions.js +1 -1
  195. package/lib/module/data-table/DataTableRowActions.js.map +1 -1
  196. package/lib/module/data-table/DataTableSearch.js +1 -1
  197. package/lib/module/data-table/DataTableSearch.js.map +1 -1
  198. package/lib/module/date-picker/MeetingScheduler.js +3 -1
  199. package/lib/module/date-picker/MeetingScheduler.js.map +1 -1
  200. package/lib/module/date-picker/PickerShell.js +1 -1
  201. package/lib/module/date-picker/PickerShell.js.map +1 -1
  202. package/lib/module/dialog/DialogHeader.js +9 -1
  203. package/lib/module/dialog/DialogHeader.js.map +1 -1
  204. package/lib/module/eviction/EvictionReportCard.js +8 -1
  205. package/lib/module/eviction/EvictionReportCard.js.map +1 -1
  206. package/lib/module/eviction/constants.js +8 -1
  207. package/lib/module/eviction/constants.js.map +1 -1
  208. package/lib/module/file-upload/FileUpload.js +4 -1
  209. package/lib/module/file-upload/FileUpload.js.map +1 -1
  210. package/lib/module/floating/menu-rows.js +1 -1
  211. package/lib/module/floating/menu-rows.js.map +1 -1
  212. package/lib/module/floating/menu-sub-flyout.js +1 -1
  213. package/lib/module/floating/menu-sub-flyout.js.map +1 -1
  214. package/lib/module/floating/menu-sub-inline.js +2 -1
  215. package/lib/module/floating/menu-sub-inline.js.map +1 -1
  216. package/lib/module/listing-card/ListingCard.js +2 -1
  217. package/lib/module/listing-card/ListingCard.js.map +1 -1
  218. package/lib/module/listing-details/ContactCard.js +5 -1
  219. package/lib/module/listing-details/ContactCard.js.map +1 -1
  220. package/lib/module/listing-details/FloorPlan.js +1 -1
  221. package/lib/module/listing-details/FloorPlan.js.map +1 -1
  222. package/lib/module/listing-details/ListingPhotoGrid.js +1 -1
  223. package/lib/module/listing-details/ListingPhotoGrid.js.map +1 -1
  224. package/lib/module/listing-details/ReviewCard.js +1 -1
  225. package/lib/module/listing-details/ReviewCard.js.map +1 -1
  226. package/lib/module/listing-details/ReviewSummary.js +1 -1
  227. package/lib/module/listing-details/ReviewSummary.js.map +1 -1
  228. package/lib/module/message-bubble/CallSummaryRow.js +4 -1
  229. package/lib/module/message-bubble/CallSummaryRow.js.map +1 -1
  230. package/lib/module/message-bubble/SwipeToReply.js +1 -1
  231. package/lib/module/message-bubble/SwipeToReply.js.map +1 -1
  232. package/lib/module/message-bubble/parts.js +4 -1
  233. package/lib/module/message-bubble/parts.js.map +1 -1
  234. package/lib/module/notification-center/NotificationCenter.js +5 -1
  235. package/lib/module/notification-center/NotificationCenter.js.map +1 -1
  236. package/lib/module/page-header/PageHeader.js +1 -1
  237. package/lib/module/page-header/PageHeader.js.map +1 -1
  238. package/lib/module/place-reviews/PlaceReviewCard.js +6 -1
  239. package/lib/module/place-reviews/PlaceReviewCard.js.map +1 -1
  240. package/lib/module/place-reviews/PlaceReviewSummary.js +2 -1
  241. package/lib/module/place-reviews/PlaceReviewSummary.js.map +1 -1
  242. package/lib/module/place-reviews/WriteReviewPrompt.js +3 -1
  243. package/lib/module/place-reviews/WriteReviewPrompt.js.map +1 -1
  244. package/lib/module/property-insights/EnergyBadge.js +1 -1
  245. package/lib/module/property-insights/EnergyBadge.js.map +1 -1
  246. package/lib/module/property-insights/EnergyLabel.js +1 -1
  247. package/lib/module/property-insights/EnergyLabel.js.map +1 -1
  248. package/lib/module/property-insights/NearbyPlaces.js +1 -1
  249. package/lib/module/property-insights/NearbyPlaces.js.map +1 -1
  250. package/lib/module/property-insights/PriceEstimate.js +2 -1
  251. package/lib/module/property-insights/PriceEstimate.js.map +1 -1
  252. package/lib/module/property-insights/PriceHistoryChart.js +1 -1
  253. package/lib/module/property-insights/PriceHistoryChart.js.map +1 -1
  254. package/lib/module/property-insights/RentHistoryList.js +1 -1
  255. package/lib/module/property-insights/RentHistoryList.js.map +1 -1
  256. package/lib/module/recent-hires-card/RecentHiresCard.js +2 -1
  257. package/lib/module/recent-hires-card/RecentHiresCard.js.map +1 -1
  258. package/lib/module/select/Select.js +1 -1
  259. package/lib/module/select/Select.js.map +1 -1
  260. package/lib/module/select/Select.web.js +1 -1
  261. package/lib/module/select/Select.web.js.map +1 -1
  262. package/lib/module/select/shared.js +2 -1
  263. package/lib/module/select/shared.js.map +1 -1
  264. package/lib/module/settings-modal/SettingsFields.js +1 -1
  265. package/lib/module/settings-modal/SettingsFields.js.map +1 -1
  266. package/lib/module/settings-modal/SettingsModal.js +4 -1
  267. package/lib/module/settings-modal/SettingsModal.js.map +1 -1
  268. package/lib/module/settings-modal/SettingsStorage.js +9 -1
  269. package/lib/module/settings-modal/SettingsStorage.js.map +1 -1
  270. package/lib/module/settings-modal/SettingsTools.js +2 -1
  271. package/lib/module/settings-modal/SettingsTools.js.map +1 -1
  272. package/lib/module/sidebar/Sidebar.js +3 -1
  273. package/lib/module/sidebar/Sidebar.js.map +1 -1
  274. package/lib/module/sidebar/SidebarFolder.js +2 -1
  275. package/lib/module/sidebar/SidebarFolder.js.map +1 -1
  276. package/lib/module/sidebar/SidebarUserMenu.js +2 -1
  277. package/lib/module/sidebar/SidebarUserMenu.js.map +1 -1
  278. package/lib/module/task-list/TaskList.js +1 -1
  279. package/lib/module/task-list/TaskList.js.map +1 -1
  280. package/lib/module/tenancy/DocumentList.js +3 -1
  281. package/lib/module/tenancy/DocumentList.js.map +1 -1
  282. package/lib/module/tenancy/MaintenanceRequestCard.js +1 -1
  283. package/lib/module/tenancy/MaintenanceRequestCard.js.map +1 -1
  284. package/lib/module/tenancy/RentPaymentList.js +1 -1
  285. package/lib/module/tenancy/RentPaymentList.js.map +1 -1
  286. package/lib/module/tenancy/constants.js +9 -1
  287. package/lib/module/tenancy/constants.js.map +1 -1
  288. package/lib/module/text-field/TextField.js +1 -1
  289. package/lib/module/text-field/TextField.js.map +1 -1
  290. package/lib/module/theme-toggle/ThemeToggle.js +2 -1
  291. package/lib/module/theme-toggle/ThemeToggle.js.map +1 -1
  292. package/lib/module/web-search/WebSearch.js +1 -1
  293. package/lib/module/web-search/WebSearch.js.map +1 -1
  294. package/lib/module/zoomable-media-gallery/ZoomableMediaGallery.js +5 -1
  295. package/lib/module/zoomable-media-gallery/ZoomableMediaGallery.js.map +1 -1
  296. package/lib/typescript/commonjs/agent-limits-card/AgentLimitsCard.d.ts.map +1 -1
  297. package/lib/typescript/commonjs/ai-chat/AiChatContainer.d.ts +28 -5
  298. package/lib/typescript/commonjs/ai-chat/AiChatContainer.d.ts.map +1 -1
  299. package/lib/typescript/commonjs/ai-chat/AiChatShell.d.ts +11 -2
  300. package/lib/typescript/commonjs/ai-chat/AiChatShell.d.ts.map +1 -1
  301. package/lib/typescript/commonjs/ai-chat/context.d.ts +19 -1
  302. package/lib/typescript/commonjs/ai-chat/context.d.ts.map +1 -1
  303. package/lib/typescript/commonjs/ai-chat/index.d.ts +3 -1
  304. package/lib/typescript/commonjs/ai-chat/index.d.ts.map +1 -1
  305. package/lib/typescript/commonjs/ai-chat/index.web.d.ts +3 -1
  306. package/lib/typescript/commonjs/ai-chat/index.web.d.ts.map +1 -1
  307. package/lib/typescript/commonjs/ai-chat/types.d.ts +101 -3
  308. package/lib/typescript/commonjs/ai-chat/types.d.ts.map +1 -1
  309. package/lib/typescript/commonjs/app-shell/AppShellHeader.d.ts.map +1 -1
  310. package/lib/typescript/commonjs/app-shell/AppShellMenuButton.d.ts.map +1 -1
  311. package/lib/typescript/commonjs/calendar/CalendarViewEventDetails.d.ts.map +1 -1
  312. package/lib/typescript/commonjs/calendar/CalendarViewHeader.d.ts.map +1 -1
  313. package/lib/typescript/commonjs/calendar/CalendarViewInboxMenu.d.ts.map +1 -1
  314. package/lib/typescript/commonjs/carousel/Carousel.d.ts.map +1 -1
  315. package/lib/typescript/commonjs/chart-cards/primitives/ChartRangePill.d.ts.map +1 -1
  316. package/lib/typescript/commonjs/chat-indicators/MessageStatus.d.ts.map +1 -1
  317. package/lib/typescript/commonjs/composer-panel/ComposerControls.d.ts +14 -0
  318. package/lib/typescript/commonjs/composer-panel/ComposerControls.d.ts.map +1 -1
  319. package/lib/typescript/commonjs/composer-panel/ComposerPanelBase.d.ts +3 -2
  320. package/lib/typescript/commonjs/composer-panel/ComposerPanelBase.d.ts.map +1 -1
  321. package/lib/typescript/commonjs/composer-panel/ComposerPillBase.d.ts +3 -2
  322. package/lib/typescript/commonjs/composer-panel/ComposerPillBase.d.ts.map +1 -1
  323. package/lib/typescript/commonjs/composer-panel/EffortSlider.d.ts +10 -2
  324. package/lib/typescript/commonjs/composer-panel/EffortSlider.d.ts.map +1 -1
  325. package/lib/typescript/commonjs/composer-panel/ModelPickerBase.d.ts.map +1 -1
  326. package/lib/typescript/commonjs/composer-panel/types.d.ts +61 -20
  327. package/lib/typescript/commonjs/composer-panel/types.d.ts.map +1 -1
  328. package/lib/typescript/commonjs/date-picker/MeetingScheduler.d.ts.map +1 -1
  329. package/lib/typescript/commonjs/dialog/DialogHeader.d.ts.map +1 -1
  330. package/lib/typescript/commonjs/eviction/EvictionReportCard.d.ts.map +1 -1
  331. package/lib/typescript/commonjs/eviction/constants.d.ts.map +1 -1
  332. package/lib/typescript/commonjs/file-upload/FileUpload.d.ts.map +1 -1
  333. package/lib/typescript/commonjs/floating/menu-sub-inline.d.ts.map +1 -1
  334. package/lib/typescript/commonjs/listing-card/ListingCard.d.ts.map +1 -1
  335. package/lib/typescript/commonjs/listing-details/ContactCard.d.ts.map +1 -1
  336. package/lib/typescript/commonjs/message-bubble/CallSummaryRow.d.ts.map +1 -1
  337. package/lib/typescript/commonjs/message-bubble/parts.d.ts.map +1 -1
  338. package/lib/typescript/commonjs/notification-center/NotificationCenter.d.ts.map +1 -1
  339. package/lib/typescript/commonjs/place-reviews/PlaceReviewCard.d.ts.map +1 -1
  340. package/lib/typescript/commonjs/place-reviews/PlaceReviewSummary.d.ts.map +1 -1
  341. package/lib/typescript/commonjs/place-reviews/WriteReviewPrompt.d.ts.map +1 -1
  342. package/lib/typescript/commonjs/property-insights/PriceEstimate.d.ts.map +1 -1
  343. package/lib/typescript/commonjs/recent-hires-card/RecentHiresCard.d.ts.map +1 -1
  344. package/lib/typescript/commonjs/select/shared.d.ts.map +1 -1
  345. package/lib/typescript/commonjs/settings-modal/SettingsModal.d.ts.map +1 -1
  346. package/lib/typescript/commonjs/settings-modal/SettingsStorage.d.ts.map +1 -1
  347. package/lib/typescript/commonjs/settings-modal/SettingsTools.d.ts.map +1 -1
  348. package/lib/typescript/commonjs/sidebar/Sidebar.d.ts.map +1 -1
  349. package/lib/typescript/commonjs/sidebar/SidebarFolder.d.ts.map +1 -1
  350. package/lib/typescript/commonjs/sidebar/SidebarUserMenu.d.ts.map +1 -1
  351. package/lib/typescript/commonjs/tenancy/DocumentList.d.ts.map +1 -1
  352. package/lib/typescript/commonjs/tenancy/constants.d.ts.map +1 -1
  353. package/lib/typescript/commonjs/theme-toggle/ThemeToggle.d.ts.map +1 -1
  354. package/lib/typescript/module/agent-limits-card/AgentLimitsCard.d.ts.map +1 -1
  355. package/lib/typescript/module/ai-chat/AiChatContainer.d.ts +28 -5
  356. package/lib/typescript/module/ai-chat/AiChatContainer.d.ts.map +1 -1
  357. package/lib/typescript/module/ai-chat/AiChatShell.d.ts +11 -2
  358. package/lib/typescript/module/ai-chat/AiChatShell.d.ts.map +1 -1
  359. package/lib/typescript/module/ai-chat/context.d.ts +19 -1
  360. package/lib/typescript/module/ai-chat/context.d.ts.map +1 -1
  361. package/lib/typescript/module/ai-chat/index.d.ts +3 -1
  362. package/lib/typescript/module/ai-chat/index.d.ts.map +1 -1
  363. package/lib/typescript/module/ai-chat/index.web.d.ts +3 -1
  364. package/lib/typescript/module/ai-chat/index.web.d.ts.map +1 -1
  365. package/lib/typescript/module/ai-chat/types.d.ts +101 -3
  366. package/lib/typescript/module/ai-chat/types.d.ts.map +1 -1
  367. package/lib/typescript/module/app-shell/AppShellHeader.d.ts.map +1 -1
  368. package/lib/typescript/module/app-shell/AppShellMenuButton.d.ts.map +1 -1
  369. package/lib/typescript/module/calendar/CalendarViewEventDetails.d.ts.map +1 -1
  370. package/lib/typescript/module/calendar/CalendarViewHeader.d.ts.map +1 -1
  371. package/lib/typescript/module/calendar/CalendarViewInboxMenu.d.ts.map +1 -1
  372. package/lib/typescript/module/carousel/Carousel.d.ts.map +1 -1
  373. package/lib/typescript/module/chart-cards/primitives/ChartRangePill.d.ts.map +1 -1
  374. package/lib/typescript/module/chat-indicators/MessageStatus.d.ts.map +1 -1
  375. package/lib/typescript/module/composer-panel/ComposerControls.d.ts +14 -0
  376. package/lib/typescript/module/composer-panel/ComposerControls.d.ts.map +1 -1
  377. package/lib/typescript/module/composer-panel/ComposerPanelBase.d.ts +3 -2
  378. package/lib/typescript/module/composer-panel/ComposerPanelBase.d.ts.map +1 -1
  379. package/lib/typescript/module/composer-panel/ComposerPillBase.d.ts +3 -2
  380. package/lib/typescript/module/composer-panel/ComposerPillBase.d.ts.map +1 -1
  381. package/lib/typescript/module/composer-panel/EffortSlider.d.ts +10 -2
  382. package/lib/typescript/module/composer-panel/EffortSlider.d.ts.map +1 -1
  383. package/lib/typescript/module/composer-panel/ModelPickerBase.d.ts.map +1 -1
  384. package/lib/typescript/module/composer-panel/types.d.ts +61 -20
  385. package/lib/typescript/module/composer-panel/types.d.ts.map +1 -1
  386. package/lib/typescript/module/date-picker/MeetingScheduler.d.ts.map +1 -1
  387. package/lib/typescript/module/dialog/DialogHeader.d.ts.map +1 -1
  388. package/lib/typescript/module/eviction/EvictionReportCard.d.ts.map +1 -1
  389. package/lib/typescript/module/eviction/constants.d.ts.map +1 -1
  390. package/lib/typescript/module/file-upload/FileUpload.d.ts.map +1 -1
  391. package/lib/typescript/module/floating/menu-sub-inline.d.ts.map +1 -1
  392. package/lib/typescript/module/listing-card/ListingCard.d.ts.map +1 -1
  393. package/lib/typescript/module/listing-details/ContactCard.d.ts.map +1 -1
  394. package/lib/typescript/module/message-bubble/CallSummaryRow.d.ts.map +1 -1
  395. package/lib/typescript/module/message-bubble/parts.d.ts.map +1 -1
  396. package/lib/typescript/module/notification-center/NotificationCenter.d.ts.map +1 -1
  397. package/lib/typescript/module/place-reviews/PlaceReviewCard.d.ts.map +1 -1
  398. package/lib/typescript/module/place-reviews/PlaceReviewSummary.d.ts.map +1 -1
  399. package/lib/typescript/module/place-reviews/WriteReviewPrompt.d.ts.map +1 -1
  400. package/lib/typescript/module/property-insights/PriceEstimate.d.ts.map +1 -1
  401. package/lib/typescript/module/recent-hires-card/RecentHiresCard.d.ts.map +1 -1
  402. package/lib/typescript/module/select/shared.d.ts.map +1 -1
  403. package/lib/typescript/module/settings-modal/SettingsModal.d.ts.map +1 -1
  404. package/lib/typescript/module/settings-modal/SettingsStorage.d.ts.map +1 -1
  405. package/lib/typescript/module/settings-modal/SettingsTools.d.ts.map +1 -1
  406. package/lib/typescript/module/sidebar/Sidebar.d.ts.map +1 -1
  407. package/lib/typescript/module/sidebar/SidebarFolder.d.ts.map +1 -1
  408. package/lib/typescript/module/sidebar/SidebarUserMenu.d.ts.map +1 -1
  409. package/lib/typescript/module/tenancy/DocumentList.d.ts.map +1 -1
  410. package/lib/typescript/module/tenancy/constants.d.ts.map +1 -1
  411. package/lib/typescript/module/theme-toggle/ThemeToggle.d.ts.map +1 -1
  412. package/package.json +1 -1
  413. package/src/__tests__/support/adoption-matrix.ts +664 -0
  414. package/src/__tests__/support/collision-fixture-barrel.ts +20 -0
  415. package/src/__tests__/support/composite.ts +68 -0
  416. package/src/__tests__/support/constructed-style-sheets.ts +68 -0
  417. package/src/__tests__/support/press-host.ts +30 -0
  418. package/src/__tests__/support/rendered-style.ts +99 -0
  419. package/src/__tests__/support/unread-hook-fixture.ts +33 -0
  420. package/src/agent-limits-card/AgentLimitsCard.tsx +3 -1
  421. package/src/ai-chat/AiChatContainer.tsx +137 -16
  422. package/src/ai-chat/AiChatShell.tsx +59 -5
  423. package/src/ai-chat/context.ts +19 -1
  424. package/src/ai-chat/index.ts +3 -0
  425. package/src/ai-chat/index.web.ts +3 -0
  426. package/src/ai-chat/types.ts +104 -3
  427. package/src/app-shell/AppShellHeader.tsx +2 -1
  428. package/src/app-shell/AppShellMenuButton.tsx +2 -1
  429. package/src/app-shell/NotificationBell.tsx +1 -1
  430. package/src/auth-card/AuthCard.tsx +1 -1
  431. package/src/calendar/CalendarViewEventDetails.tsx +6 -8
  432. package/src/calendar/CalendarViewHeader.tsx +2 -1
  433. package/src/calendar/CalendarViewInboxMenu.tsx +3 -1
  434. package/src/carousel/Carousel.tsx +2 -1
  435. package/src/chart-cards/BarListCard.tsx +1 -1
  436. package/src/chart-cards/primitives/ChartRangePill.tsx +3 -1
  437. package/src/chat-indicators/MessageStatus.tsx +4 -6
  438. package/src/composer-panel/ComposerControls.tsx +54 -0
  439. package/src/composer-panel/ComposerPanelBase.tsx +13 -5
  440. package/src/composer-panel/ComposerPillBase.tsx +101 -59
  441. package/src/composer-panel/EffortSlider.tsx +38 -18
  442. package/src/composer-panel/ModelPickerBase.tsx +23 -7
  443. package/src/composer-panel/types.ts +61 -20
  444. package/src/data-table/DataTableRowActions.tsx +1 -1
  445. package/src/data-table/DataTableSearch.tsx +1 -1
  446. package/src/date-picker/MeetingScheduler.tsx +3 -1
  447. package/src/date-picker/PickerShell.tsx +1 -1
  448. package/src/dialog/DialogHeader.tsx +8 -5
  449. package/src/eviction/EvictionReportCard.tsx +8 -10
  450. package/src/eviction/constants.ts +8 -10
  451. package/src/file-upload/FileUpload.tsx +4 -6
  452. package/src/floating/menu-rows.tsx +1 -1
  453. package/src/floating/menu-sub-flyout.tsx +1 -1
  454. package/src/floating/menu-sub-inline.tsx +2 -4
  455. package/src/listing-card/ListingCard.tsx +2 -1
  456. package/src/listing-details/ContactCard.tsx +5 -1
  457. package/src/listing-details/FloorPlan.tsx +1 -1
  458. package/src/listing-details/ListingPhotoGrid.tsx +1 -1
  459. package/src/listing-details/ReviewCard.tsx +1 -1
  460. package/src/listing-details/ReviewSummary.tsx +1 -1
  461. package/src/message-bubble/CallSummaryRow.tsx +4 -6
  462. package/src/message-bubble/SwipeToReply.tsx +1 -1
  463. package/src/message-bubble/parts.tsx +4 -1
  464. package/src/notification-center/NotificationCenter.tsx +5 -7
  465. package/src/page-header/PageHeader.tsx +1 -1
  466. package/src/place-reviews/PlaceReviewCard.tsx +6 -8
  467. package/src/place-reviews/PlaceReviewSummary.tsx +2 -1
  468. package/src/place-reviews/WriteReviewPrompt.tsx +3 -1
  469. package/src/property-insights/EnergyBadge.tsx +1 -1
  470. package/src/property-insights/EnergyLabel.tsx +1 -1
  471. package/src/property-insights/NearbyPlaces.tsx +1 -1
  472. package/src/property-insights/PriceEstimate.tsx +2 -1
  473. package/src/property-insights/PriceHistoryChart.tsx +1 -1
  474. package/src/property-insights/RentHistoryList.tsx +1 -1
  475. package/src/recent-hires-card/RecentHiresCard.tsx +2 -1
  476. package/src/select/Select.tsx +1 -1
  477. package/src/select/Select.web.tsx +1 -1
  478. package/src/select/shared.tsx +2 -4
  479. package/src/settings-modal/SettingsFields.tsx +1 -1
  480. package/src/settings-modal/SettingsModal.tsx +4 -1
  481. package/src/settings-modal/SettingsStorage.tsx +9 -11
  482. package/src/settings-modal/SettingsTools.tsx +2 -1
  483. package/src/sidebar/Sidebar.tsx +3 -1
  484. package/src/sidebar/SidebarFolder.tsx +2 -1
  485. package/src/sidebar/SidebarUserMenu.tsx +2 -1
  486. package/src/task-list/TaskList.tsx +1 -1
  487. package/src/tenancy/DocumentList.tsx +3 -1
  488. package/src/tenancy/MaintenanceRequestCard.tsx +1 -1
  489. package/src/tenancy/RentPaymentList.tsx +1 -1
  490. package/src/tenancy/constants.ts +9 -11
  491. package/src/text-field/TextField.tsx +1 -1
  492. package/src/theme/__tests__/__fixtures__/golden-resolved-tokens.json +7682 -0
  493. package/src/theme/__tests__/fixtures/color-engine-golden.json +1 -0
  494. package/src/theme-toggle/ThemeToggle.tsx +2 -1
  495. package/src/web-search/WebSearch.tsx +1 -1
  496. package/src/zoomable-media-gallery/ZoomableMediaGallery.tsx +5 -5
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Compositing and WCAG maths for suites that measure a TRANSLUCENT surface.
3
+ *
4
+ * A pane you can see through has no colour of its own to read off a style prop:
5
+ * what a label lands on is the fill flattened onto whatever is behind it. Every
6
+ * gate on a glass material therefore needs the same four functions, and they
7
+ * are here so a new one does not start by copying them — which is how two
8
+ * copies of a luminance formula end up disagreeing about the sRGB knee.
9
+ *
10
+ * `theme/__tests__/glass-colors.test.ts` keeps its OWN copies, deliberately and
11
+ * with its own reasons written down; this is for everything since.
12
+ */
13
+
14
+ export interface Rgba {
15
+ r: number;
16
+ g: number;
17
+ b: number;
18
+ a: number;
19
+ }
20
+
21
+ /** Parse `#rgb`, `#rrggbb`, `rgb(...)` or `rgba(...)`. Throws on anything else. */
22
+ export function parseColor(value: string): Rgba {
23
+ const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(value.trim());
24
+ if (hex?.[1] !== undefined) {
25
+ const h = hex[1].length === 3 ? hex[1].replace(/./g, (c) => c + c) : hex[1];
26
+ return {
27
+ r: parseInt(h.slice(0, 2), 16),
28
+ g: parseInt(h.slice(2, 4), 16),
29
+ b: parseInt(h.slice(4, 6), 16),
30
+ a: 1,
31
+ };
32
+ }
33
+ const fn = /^rgba?\(([^)]*)\)$/.exec(value.trim());
34
+ if (!fn?.[1]) throw new Error(`unparseable colour: ${JSON.stringify(value)}`);
35
+ const parts = fn[1].split(/[\s,/]+/).filter(Boolean).map(Number);
36
+ if (parts.length < 3 || parts.some((n) => Number.isNaN(n))) {
37
+ throw new Error(`unparseable colour: ${JSON.stringify(value)}`);
38
+ }
39
+ return { r: parts[0] ?? 0, g: parts[1] ?? 0, b: parts[2] ?? 0, a: parts[3] ?? 1 };
40
+ }
41
+
42
+ /** Flatten a translucent colour onto an opaque one — source-over. */
43
+ export function over(top: Rgba, bottom: Rgba): Rgba {
44
+ return {
45
+ r: top.r * top.a + bottom.r * (1 - top.a),
46
+ g: top.g * top.a + bottom.g * (1 - top.a),
47
+ b: top.b * top.a + bottom.b * (1 - top.a),
48
+ a: 1,
49
+ };
50
+ }
51
+
52
+ /** WCAG relative luminance. */
53
+ export function luminance({ r, g, b }: Rgba): number {
54
+ const channel = (v: number): number => {
55
+ const c = v / 255;
56
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
57
+ };
58
+ return 0.2126 * channel(r) + 0.7152 * channel(g) + 0.0722 * channel(b);
59
+ }
60
+
61
+ /** WCAG contrast ratio, order-independent. */
62
+ export function contrastRatio(a: Rgba, b: Rgba): number {
63
+ const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x) as [number, number];
64
+ return (hi + 0.05) / (lo + 0.05);
65
+ }
66
+
67
+ export const WHITE: Rgba = { r: 255, g: 255, b: 255, a: 1 };
68
+ export const BLACK: Rgba = { r: 0, g: 0, b: 0, a: 1 };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * A spec-shaped stand-in for constructed stylesheets, for the jsdom suites.
3
+ *
4
+ * jsdom 26 ships the `CSSStyleSheet` CONSTRUCTOR but neither `replaceSync` nor
5
+ * `document.adoptedStyleSheets`, so every jsdom test takes Bloom's `<style>`
6
+ * fallback. That makes the whole CSP-safe path — the reason
7
+ * `styles/adopt-style-sheet.ts` exists — invisible to jest unless a test
8
+ * installs the API itself. Without this, a mutation that deleted the adoption
9
+ * branch entirely would leave the suite green.
10
+ *
11
+ * Not collected as a suite: jest's `testMatch` wants `*.test.ts` / `*.spec.ts`.
12
+ */
13
+
14
+ export interface FakeStyleSheet {
15
+ /** The CSS most recently handed to `replaceSync`. */
16
+ cssText: string;
17
+ /** How many times the sheet has been re-parsed, so a test can prove it wasn't. */
18
+ replaceSyncCalls: number;
19
+ replaceSync(css: string): void;
20
+ }
21
+
22
+ export interface ConstructedStyleSheetsHarness {
23
+ /** The document's adopted sheets, read live (the code reassigns the array). */
24
+ adopted(): readonly FakeStyleSheet[];
25
+ /** Drop the API again, restoring jsdom's own `CSSStyleSheet`. */
26
+ uninstall(): void;
27
+ }
28
+
29
+ export function installConstructedStyleSheets(): ConstructedStyleSheetsHarness {
30
+ class FakeCSSStyleSheet implements FakeStyleSheet {
31
+ cssText = '';
32
+ replaceSyncCalls = 0;
33
+
34
+ replaceSync(css: string): void {
35
+ this.cssText = css;
36
+ this.replaceSyncCalls += 1;
37
+ }
38
+ }
39
+
40
+ const previousConstructor = Object.getOwnPropertyDescriptor(
41
+ globalThis,
42
+ 'CSSStyleSheet',
43
+ );
44
+
45
+ Object.defineProperty(globalThis, 'CSSStyleSheet', {
46
+ value: FakeCSSStyleSheet,
47
+ writable: true,
48
+ configurable: true,
49
+ });
50
+ Object.defineProperty(document, 'adoptedStyleSheets', {
51
+ value: [],
52
+ writable: true,
53
+ configurable: true,
54
+ });
55
+
56
+ return {
57
+ adopted: () =>
58
+ document.adoptedStyleSheets as unknown as readonly FakeStyleSheet[],
59
+ uninstall: () => {
60
+ Reflect.deleteProperty(document, 'adoptedStyleSheets');
61
+ if (previousConstructor) {
62
+ Object.defineProperty(globalThis, 'CSSStyleSheet', previousConstructor);
63
+ } else {
64
+ Reflect.deleteProperty(globalThis, 'CSSStyleSheet');
65
+ }
66
+ },
67
+ };
68
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Pressing a component's OWN host node, and proving the component is what
3
+ * installed the handler being measured.
4
+ *
5
+ * `fireEvent.press` walks UP from the element it is handed to the nearest
6
+ * ancestor carrying an `onPress` prop, and it does not stop at host nodes — a
7
+ * COMPOSITE counts, because `getEventHandler` only reads `element.props`. So
8
+ * `<Thing onPress={fn}>` written in a test's own JSX catches the press itself.
9
+ * Measured on a (since removed) card component: with the handler deleted from the
10
+ * component the card rendered as an inert `View`, and the test still reported exactly one
11
+ * call. Green, and measuring nothing. Nine suites had the same shape.
12
+ *
13
+ * Asserting the host node's own `onPress` FIRST closes both halves:
14
+ *
15
+ * - a component that installs no handler at all fails here, and
16
+ * - a component that installs one which drops the caller's fails on the call
17
+ * count, because `fireEvent` now finds a handler AT the node and never walks
18
+ * past it to the test's own JSX.
19
+ *
20
+ * `host` must therefore be the node the component itself made pressable — the
21
+ * one carrying its `testID` / `accessibilityLabel` — not a `Text` deep inside
22
+ * it, or the walk-up is back and so is the hole.
23
+ */
24
+ import { fireEvent } from '@testing-library/react-native';
25
+ import type { ReactTestInstance } from 'react-test-renderer';
26
+
27
+ export function pressHost(host: ReactTestInstance): void {
28
+ expect(typeof host.props.onPress).toBe('function');
29
+ fireEvent.press(host);
30
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Reading what actually landed on a rendered node — shared by every suite that
3
+ * asserts the "className lands on the node the parent lays out" rule.
4
+ *
5
+ * Three components had the same two-node defect (`Button`, then `Fab` and
6
+ * `FrostedIconButton`), and asserting it needs the same two things each time:
7
+ * the HOST tree (composites do not appear in `toJSON()`, so a wrapper is only
8
+ * visible there) and a deep flatten of the `style` prop, because react-native-css
9
+ * merges a caller's class in as a `{ $$css: true, className }` descriptor
10
+ * ALONGSIDE the style objects rather than in a prop of its own.
11
+ */
12
+ import type { ReactTestRendererJSON } from 'react-test-renderer';
13
+
14
+ export type StyleEntry = Record<string, unknown>;
15
+
16
+ export interface HostNode {
17
+ type: string;
18
+ props: Record<string, unknown>;
19
+ children: Array<HostNode | string> | null;
20
+ }
21
+
22
+ /**
23
+ * Deep-flatten an RN `style` prop (nested arrays, `false`/`null` holes) into the
24
+ * list of style objects that actually reached the node.
25
+ */
26
+ export function styleEntries(style: unknown, out: StyleEntry[] = []): StyleEntry[] {
27
+ if (!style || typeof style !== 'object') return out;
28
+ if (Array.isArray(style)) {
29
+ for (const entry of style) styleEntries(entry, out);
30
+ return out;
31
+ }
32
+ out.push(style as StyleEntry);
33
+ return out;
34
+ }
35
+
36
+ /** Every style key/value that landed on a node, later entries winning. */
37
+ export function resolvedStyle(style: unknown): StyleEntry {
38
+ return Object.assign({}, ...styleEntries(style)) as StyleEntry;
39
+ }
40
+
41
+ /** The class tokens react-native-css accepted for a node, in arrival order. */
42
+ export function classNamesOn(style: unknown): string[] {
43
+ return styleEntries(style)
44
+ .filter((entry) => entry.$$css === true && typeof entry.className === 'string')
45
+ .map((entry) => String(entry.className));
46
+ }
47
+
48
+ export function isHostNode(value: unknown): value is HostNode {
49
+ return (
50
+ typeof value === 'object' && value !== null && typeof (value as HostNode).type === 'string'
51
+ );
52
+ }
53
+
54
+ /** Walk the HOST tree (composites are absent from `toJSON()`) for a testID. */
55
+ export function findHost(
56
+ node: ReactTestRendererJSON | ReactTestRendererJSON[] | unknown,
57
+ testID: string,
58
+ ): HostNode | null {
59
+ if (Array.isArray(node)) {
60
+ for (const child of node) {
61
+ const hit = findHost(child, testID);
62
+ if (hit) return hit;
63
+ }
64
+ return null;
65
+ }
66
+ if (!isHostNode(node)) return null;
67
+ if (node.props.testID === testID) return node;
68
+ return findHost(node.children, testID);
69
+ }
70
+
71
+ /**
72
+ * Every host node in a rendered tree, in document order.
73
+ *
74
+ * The reason to walk `toJSON()` rather than `UNSAFE_root.findAll` is that the
75
+ * latter yields COMPOSITE instances too, so a `memo(fn)` component contributes
76
+ * two matches for one rendered element and every count is silently doubled —
77
+ * which reads as "the component rendered the thing twice", not as an artefact
78
+ * of the query.
79
+ */
80
+ export function hostNodes(tree: unknown, out: HostNode[] = []): HostNode[] {
81
+ if (Array.isArray(tree)) {
82
+ for (const child of tree) hostNodes(child, out);
83
+ return out;
84
+ }
85
+ if (!isHostNode(tree)) return out;
86
+ out.push(tree);
87
+ return hostNodes(tree.children, out);
88
+ }
89
+
90
+ /**
91
+ * The host nodes a parent laid out. Callers assert the LENGTH themselves —
92
+ * "exactly one" is the property, and a helper that returned only the first would
93
+ * hide the second.
94
+ */
95
+ export function renderedChildren(tree: unknown, hostTestID: string): HostNode[] {
96
+ const host = findHost(tree, hostTestID);
97
+ if (host === null) throw new Error(`no host rendered for testID "${hostTestID}"`);
98
+ return (host.children ?? []).filter(isHostNode);
99
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * A module that DELIBERATELY throws away one of the values a hook hands back, so
3
+ * `hook-subscriptions-are-read.test.ts` can prove its detector fires. It carries
4
+ * both halves of the control: `unreadFlag` is bound and never read, which the
5
+ * detector must report, and `readFlag` is bound and read, which it must stay
6
+ * quiet about — otherwise the cheapest way to green the gate would be deleting a
7
+ * binding that is doing its job.
8
+ *
9
+ * Nothing imports this at runtime. bob's `exclude` keeps it out of `lib/`, and
10
+ * `files: ["src", …]` does ship it inside the tarball's `src/` like the other
11
+ * 137 test files there — but no entry point reaches it, so no bundler links it.
12
+ * It is a plain `.ts` with no React import because the
13
+ * detector reads source, never types: a call named `use…` bound to a name is all
14
+ * the shape there is.
15
+ *
16
+ * The destructuring RENAMES, which is not decoration — it reproduces the shipped
17
+ * shape (`const { state: pressed, onIn: onPressIn } = useInteractionState()`) and
18
+ * it is what keeps the control honest. A hook declared in the same file as its
19
+ * caller mentions its own property names in its return type and its return
20
+ * object, and the detector counts every occurrence of a spelling as a possible
21
+ * read, so an unrenamed fixture would be silently unreportable for a reason no
22
+ * real call site has.
23
+ */
24
+
25
+ /** Stands in for a real subscription — a hook by name, with two return values. */
26
+ function useFixtureInteractionState(): { first: boolean; second: boolean } {
27
+ return { first: false, second: false };
28
+ }
29
+
30
+ export function fixtureComponentBody(): boolean {
31
+ const { first: readFlag, second: unreadFlag } = useFixtureInteractionState();
32
+ return readFlag;
33
+ }
@@ -19,7 +19,9 @@ import Animated, {
19
19
  } from 'react-native-reanimated';
20
20
 
21
21
  import { ACCENT_TABLE, colorRamp, mixColor, resolveButtonRamps } from '../button/shared';
22
- import { RiArrowDownSLine, RiArrowRightLine, RiArrowRightSLine } from '../icons/remix';
22
+ import { RiArrowDownSLine } from '../icons/remix/RiArrowDownSLine';
23
+ import { RiArrowRightLine } from '../icons/remix/RiArrowRightLine';
24
+ import { RiArrowRightSLine } from '../icons/remix/RiArrowRightSLine';
23
25
  import { Text, TYPE_SCALE } from '../typography';
24
26
  import { useControllableState } from '../hooks/use-controllable-state';
25
27
  import { adoptStyleSheet } from '../styles/adopt-style-sheet';
@@ -1,5 +1,11 @@
1
- import React, { useCallback, useMemo, useRef } from 'react';
2
- import { ScrollView, View } from 'react-native';
1
+ import React, { forwardRef, useCallback, useImperativeHandle, useMemo, useRef } from 'react';
2
+ import {
3
+ ScrollView,
4
+ View,
5
+ type LayoutChangeEvent,
6
+ type NativeScrollEvent,
7
+ type NativeSyntheticEvent,
8
+ } from 'react-native';
3
9
 
4
10
  import { AgentThinking } from '../agent-thinking';
5
11
  import { Breadcrumb, BreadcrumbItem } from '../breadcrumb';
@@ -8,7 +14,7 @@ import { RiMoreFill } from '../icons/remix/RiMoreFill';
8
14
  import { RiShare2Line } from '../icons/remix/RiShare2Line';
9
15
  import { GlyphAction } from './AiChatControls';
10
16
  import { CONTAINER_RADIUS, dataHook, IS_WEB, useAiChatPalette, useAiChatWebCss } from './shared';
11
- import type { AiChatContainerProps, AiChatThreadProps } from './types';
17
+ import type { AiChatContainerProps, AiChatThreadHandle, AiChatThreadProps } from './types';
12
18
 
13
19
  const DEFAULT_LABELS = {
14
20
  breadcrumb: 'Chat location',
@@ -20,6 +26,9 @@ const DEFAULT_LABELS = {
20
26
  * The AI chat's centre column: the centre column of the AI chat template.
21
27
  *
22
28
  * section fills its parent, radius 24, background-secondary, clipped
29
+ * layer the `background` slot, filling the section above its own paint
30
+ * and below everything else, clipped to the same radius;
31
+ * `surface={false}` drops that paint
23
32
  * header px 16 / pt 16, gap 8: the project › chat breadcrumb (flex 1) and
24
33
  * the 16px share / more glyphs, 8 apart
25
34
  * thread the `children` — usually an `AiChatThread`
@@ -27,6 +36,9 @@ const DEFAULT_LABELS = {
27
36
  * while `working`, then the `composer`
28
37
  *
29
38
  * `header` renders above all of it: the shell's `AiChatMobileHeader`.
39
+ *
40
+ * `project` is optional: without one the breadcrumb is the chat's own crumb
41
+ * alone, since a chat that belongs to nothing must not have to invent a folder.
30
42
  */
31
43
  export function AiChatContainer({
32
44
  project,
@@ -40,6 +52,8 @@ export function AiChatContainer({
40
52
  composer,
41
53
  working = false,
42
54
  workingLabel,
55
+ background,
56
+ surface = true,
43
57
  labels,
44
58
  style,
45
59
  testID,
@@ -58,10 +72,15 @@ export function AiChatContainer({
58
72
  flexDirection: 'column',
59
73
  overflow: 'hidden',
60
74
  borderRadius: CONTAINER_RADIUS,
61
- backgroundColor: palette.secondary,
75
+ backgroundColor: surface ? palette.secondary : 'transparent',
62
76
  },
63
77
  style,
64
78
  ]}>
79
+ {background ? (
80
+ <View pointerEvents="none" style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}>
81
+ {background}
82
+ </View>
83
+ ) : null}
65
84
  {header}
66
85
  <View
67
86
  style={{
@@ -76,9 +95,11 @@ export function AiChatContainer({
76
95
  }}>
77
96
  <View style={{ minWidth: 0, flex: 1 }}>
78
97
  <Breadcrumb accessibilityLabel={l.breadcrumb}>
79
- <BreadcrumbItem icon={projectIcon} onPress={onProjectPress}>
80
- {project}
81
- </BreadcrumbItem>
98
+ {project === undefined ? null : (
99
+ <BreadcrumbItem icon={projectIcon} onPress={onProjectPress}>
100
+ {project}
101
+ </BreadcrumbItem>
102
+ )}
82
103
  <BreadcrumbItem current>{title}</BreadcrumbItem>
83
104
  </Breadcrumb>
84
105
  </View>
@@ -101,24 +122,124 @@ export function AiChatContainer({
101
122
  /**
102
123
  * The thread: the scrolling conversation, anchored to the bottom
103
124
  * so a short exchange sits just above the composer and grows upward — px 16 /
104
- * pt 16, turns 12 apart, a thin scrollbar. It follows the newest turn with a
105
- * smooth scroll whenever the content grows.
125
+ * pt 16, turns 12 apart, a thin scrollbar.
126
+ *
127
+ * It follows the newest turn with a smooth scroll whenever the content grows.
128
+ * That is the default and nothing else changes it; the timeline props are the
129
+ * ones a host with history needs and are each off unless asked for:
130
+ *
131
+ * autoFollow / followAnimated / followThreshold whether, how, and from how
132
+ * close to the bottom the follow happens
133
+ * onStartReached a chat pages UPWARD; this
134
+ * fires near the TOP, once per approach, re-arming when the reader leaves
135
+ * maintainStartPosition the growth that answers an
136
+ * `onStartReached` is added to the offset, so a page landing above the
137
+ * reader does not move the turn they are reading
138
+ * ref (`AiChatThreadHandle`) scrollToEnd /
139
+ * scrollToOffset / the ScrollView, for a cursor jump or a restore
140
+ *
141
+ * There is no virtualization and no `scrollToIndex`: a host jumping to a turn
142
+ * measures its row (`onLayout`) and calls `scrollToOffset`.
106
143
  */
107
- export function AiChatThread({ children, style, testID }: AiChatThreadProps) {
144
+ export const AiChatThread = forwardRef<AiChatThreadHandle, AiChatThreadProps>(function AiChatThread(
145
+ {
146
+ children,
147
+ autoFollow = true,
148
+ followAnimated = true,
149
+ followThreshold,
150
+ onStartReached,
151
+ onStartReachedThreshold = 300,
152
+ maintainStartPosition = false,
153
+ onScroll,
154
+ scrollEventThrottle = 16,
155
+ style,
156
+ testID,
157
+ },
158
+ ref,
159
+ ) {
108
160
  const scrollRef = useRef<ScrollView>(null);
109
161
  const lastHeight = useRef(0);
110
- const onContentSizeChange = useCallback((_width: number, height: number) => {
111
- const grew = height > lastHeight.current + 0.5;
112
- const first = lastHeight.current === 0;
113
- lastHeight.current = height;
114
- if (grew && !first) scrollRef.current?.scrollToEnd({ animated: true });
162
+ const offset = useRef(0);
163
+ const viewport = useRef(0);
164
+ /** An `onStartReached` is out and its page has not landed yet. */
165
+ const pageOut = useRef(false);
166
+ /** The reader has left the top zone, so the next approach may fire again. */
167
+ const startArmed = useRef(true);
168
+
169
+ useImperativeHandle(
170
+ ref,
171
+ (): AiChatThreadHandle => ({
172
+ scrollToEnd: (options) => scrollRef.current?.scrollToEnd({ animated: options?.animated ?? true }),
173
+ scrollToOffset: ({ offset: y, animated = false }) => scrollRef.current?.scrollTo({ y, animated }),
174
+ getScrollView: () => scrollRef.current,
175
+ }),
176
+ [],
177
+ );
178
+
179
+ const listening = !!onScroll || !!onStartReached || followThreshold !== undefined || maintainStartPosition;
180
+
181
+ const handleScroll = useCallback(
182
+ (event: NativeSyntheticEvent<NativeScrollEvent>) => {
183
+ const { contentOffset, layoutMeasurement } = event.nativeEvent;
184
+ offset.current = contentOffset.y;
185
+ viewport.current = layoutMeasurement.height;
186
+ if (onStartReached) {
187
+ if (contentOffset.y <= onStartReachedThreshold) {
188
+ if (startArmed.current) {
189
+ startArmed.current = false;
190
+ pageOut.current = true;
191
+ onStartReached();
192
+ }
193
+ } else {
194
+ startArmed.current = true;
195
+ }
196
+ }
197
+ onScroll?.(event);
198
+ },
199
+ [onScroll, onStartReached, onStartReachedThreshold],
200
+ );
201
+
202
+ const onLayout = useCallback((event: LayoutChangeEvent) => {
203
+ viewport.current = event.nativeEvent.layout.height;
115
204
  }, []);
205
+
206
+ const onContentSizeChange = useCallback(
207
+ (_width: number, height: number) => {
208
+ const previous = lastHeight.current;
209
+ const grew = height > previous + 0.5;
210
+ const first = previous === 0;
211
+ lastHeight.current = height;
212
+ if (!grew || first) return;
213
+
214
+ // A page landing above the reader: keep the turn they are on where it is.
215
+ if (maintainStartPosition && pageOut.current) {
216
+ pageOut.current = false;
217
+ scrollRef.current?.scrollTo({ y: offset.current + (height - previous), animated: false });
218
+ return;
219
+ }
220
+ pageOut.current = false;
221
+
222
+ if (!autoFollow) return;
223
+ if (followThreshold !== undefined) {
224
+ // Measured against the height BEFORE the growth: was the reader near
225
+ // the bottom when this arrived?
226
+ const fromBottom = previous - offset.current - viewport.current;
227
+ if (fromBottom > followThreshold) return;
228
+ }
229
+ scrollRef.current?.scrollToEnd({ animated: followAnimated });
230
+ },
231
+ [autoFollow, followAnimated, followThreshold, maintainStartPosition],
232
+ );
233
+
116
234
  return (
117
235
  <ScrollView
118
236
  ref={scrollRef}
119
237
  testID={testID}
120
238
  {...dataHook('bloomAiChatScroll', 'thin')}
121
239
  onContentSizeChange={onContentSizeChange}
240
+ onLayout={onLayout}
241
+ onScroll={listening ? handleScroll : undefined}
242
+ scrollEventThrottle={listening ? scrollEventThrottle : undefined}
122
243
  style={[{ minHeight: 0, width: '100%', flex: 1 }, style]}
123
244
  contentContainerStyle={{
124
245
  // react-native-web gives every view `min-height: 0`, so a growing
@@ -135,4 +256,4 @@ export function AiChatThread({ children, style, testID }: AiChatThreadProps) {
135
256
  {children}
136
257
  </ScrollView>
137
258
  );
138
- }
259
+ });
@@ -39,6 +39,8 @@ const REVEAL_MS = 325;
39
39
  const REVEAL_OFFSET = 272;
40
40
  const DRAWER_EASE = Easing.bezier(0.4, 0, 0.2, 1);
41
41
  const DRAWER_MS = 300;
42
+ /** An icon-only rail: one 36px control plus its 10px gutters. */
43
+ const COLLAPSED_SIDEBAR_WIDTH = 56;
42
44
 
43
45
  const DEFAULT_LABELS = {
44
46
  openNavigation: 'Open navigation',
@@ -257,7 +259,9 @@ export function AiChatMobileHeader({ title, style, testID }: AiChatMobileHeaderP
257
259
  * The AI chat shell: the full AI chat
258
260
  * screen on background-full with a 12px frame.
259
261
  *
260
- * lg and up the floating `sidebar` in flow, 16 from the workspace
262
+ * lg and up the floating `sidebar` in flow, 16 from the workspace, at
263
+ * `sidebarWidth` (or its own width) — `sidebarCollapsed` narrows
264
+ * the column to `collapsedSidebarWidth` (56) for an icon rail
261
265
  * workspace the chat container flexing, then (xl and up) the `panel` 12 to
262
266
  * its right at `panelWidth`; the resize grip on the chat's right
263
267
  * edge trades width between them, clamped 320–560
@@ -272,9 +276,19 @@ export function AiChatMobileHeader({ title, style, testID }: AiChatMobileHeaderP
272
276
  * over the workspace closes it
273
277
  *
274
278
  * The chat container reads the drawer controls through `AiChatMobileHeader`.
279
+ * Everything the shell knows — including `navPresented`, which says whether the
280
+ * nav is on screen at all — is published to any descendant through
281
+ * `useAiChatShell()`.
282
+ *
283
+ * `background` is a layer drawn above the shell's own paint and below all of
284
+ * it; with `surface={false}` neither the root nor the workspace paints, so the
285
+ * layer reaches the chat.
275
286
  */
276
287
  export function AiChatShell({
277
288
  sidebar,
289
+ sidebarWidth,
290
+ sidebarCollapsed = false,
291
+ collapsedSidebarWidth = COLLAPSED_SIDEBAR_WIDTH,
278
292
  mobileSidebar,
279
293
  children,
280
294
  panel,
@@ -287,6 +301,8 @@ export function AiChatShell({
287
301
  onNavOpenChange,
288
302
  panelOpen: panelOpenProp,
289
303
  onPanelOpenChange,
304
+ background,
305
+ surface = true,
290
306
  labels,
291
307
  style,
292
308
  testID,
@@ -368,10 +384,14 @@ export function AiChatShell({
368
384
  navCollapsed: !navInFlow,
369
385
  hasNav: !!mobileSidebar,
370
386
  hasPanel: !!panel,
387
+ // In flow it is always on screen; as a drawer, only while it is open.
388
+ navPresented: navInFlow ? !!sidebar : navOpen,
389
+ sidebarCollapsed,
371
390
  openNav: () => {
372
391
  setPanelOpen(false);
373
392
  setNavOpen(true);
374
393
  },
394
+ closeNav: () => setNavOpen(false),
375
395
  openPanel: () => {
376
396
  setNavOpen(false);
377
397
  setPanelOpen(true);
@@ -380,7 +400,20 @@ export function AiChatShell({
380
400
  panelIcon,
381
401
  labels: { openNavigation: l.openNavigation, openPanel: l.openPanel },
382
402
  }),
383
- [wide, navInFlow, mobileSidebar, panel, setPanelOpen, setNavOpen, panelLabel, panelIcon, l],
403
+ [
404
+ wide,
405
+ navInFlow,
406
+ navOpen,
407
+ sidebar,
408
+ sidebarCollapsed,
409
+ mobileSidebar,
410
+ panel,
411
+ setPanelOpen,
412
+ setNavOpen,
413
+ panelLabel,
414
+ panelIcon,
415
+ l,
416
+ ],
384
417
  );
385
418
 
386
419
  const rootStyle: WebCssStyle = {
@@ -391,7 +424,7 @@ export function AiChatShell({
391
424
  gap: 16,
392
425
  overflow: 'hidden',
393
426
  padding: 12,
394
- backgroundColor: palette.full,
427
+ backgroundColor: surface ? palette.full : 'transparent',
395
428
  };
396
429
 
397
430
  const veil = palette.isDark ? 'rgba(255, 255, 255, 0.05)' : 'rgba(0, 0, 0, 0.1)';
@@ -403,6 +436,11 @@ export function AiChatShell({
403
436
  testID={testID}
404
437
  onLayout={(event: LayoutChangeEvent) => setShellWidth(event.nativeEvent.layout.width)}
405
438
  style={[rootStyle, style]}>
439
+ {background ? (
440
+ <View pointerEvents="none" style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}>
441
+ {background}
442
+ </View>
443
+ ) : null}
406
444
  {!navInFlow && mobileSidebar ? (
407
445
  <View
408
446
  aria-hidden={!navOpen}
@@ -416,7 +454,23 @@ export function AiChatShell({
416
454
  </View>
417
455
  ) : null}
418
456
 
419
- {navInFlow ? <View style={{ position: 'relative', zIndex: 10, height: '100%' }}>{sidebar}</View> : null}
457
+ {navInFlow ? (
458
+ <View
459
+ style={{
460
+ position: 'relative',
461
+ zIndex: 10,
462
+ height: '100%',
463
+ // Untouched unless the host asked for a width: the sidebar has
464
+ // always sized itself.
465
+ ...(sidebarCollapsed
466
+ ? { width: collapsedSidebarWidth, flexShrink: 0, overflow: 'hidden' }
467
+ : sidebarWidth !== undefined
468
+ ? { width: sidebarWidth, flexShrink: 0 }
469
+ : null),
470
+ }}>
471
+ {sidebar}
472
+ </View>
473
+ ) : null}
420
474
 
421
475
  <Animated.View
422
476
  style={[
@@ -428,7 +482,7 @@ export function AiChatShell({
428
482
  flexDirection: 'column',
429
483
  gap: 8,
430
484
  overflow: 'hidden',
431
- backgroundColor: palette.full,
485
+ backgroundColor: surface ? palette.full : 'transparent',
432
486
  },
433
487
  navInFlow ? null : workspaceStyle,
434
488
  ]}>