@signalcore/ui 0.1.0 → 1.0.0-beta.1

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 (611) hide show
  1. package/README.md +896 -513
  2. package/dist/AgentAbout.d.ts +186 -0
  3. package/dist/AgentAbout.js +1020 -0
  4. package/dist/AgentAbout.js.map +1 -0
  5. package/dist/AgentCard.d.ts +49 -0
  6. package/dist/AgentCard.js +77 -0
  7. package/dist/AgentCard.js.map +1 -0
  8. package/dist/AgentChat.d.ts +233 -0
  9. package/dist/AgentChat.js +1127 -0
  10. package/dist/AgentChat.js.map +1 -0
  11. package/dist/AgentSpace.d.ts +112 -0
  12. package/dist/AgentSpace.js +339 -0
  13. package/dist/AgentSpace.js.map +1 -0
  14. package/dist/AgentTasks.d.ts +48 -0
  15. package/dist/AgentTasks.js +120 -0
  16. package/dist/AgentTasks.js.map +1 -0
  17. package/dist/BrowserView.d.ts +52 -0
  18. package/dist/BrowserView.js +328 -0
  19. package/dist/BrowserView.js.map +1 -0
  20. package/dist/FileView.d.ts +63 -0
  21. package/dist/FileView.js +449 -0
  22. package/dist/FileView.js.map +1 -0
  23. package/dist/Modes.d.ts +13 -0
  24. package/dist/Modes.js +75 -0
  25. package/dist/Modes.js.map +1 -0
  26. package/dist/VoiceCall.d.ts +91 -0
  27. package/dist/VoiceCall.js +302 -0
  28. package/dist/VoiceCall.js.map +1 -0
  29. package/dist/about.d.ts +212 -0
  30. package/dist/about.js +136 -0
  31. package/dist/about.js.map +1 -0
  32. package/dist/agentIcons.d.ts +33 -0
  33. package/dist/agentIcons.js +36 -0
  34. package/dist/agentIcons.js.map +1 -0
  35. package/dist/automation/Automation.d.ts +35 -0
  36. package/dist/automation/Automation.js +268 -0
  37. package/dist/automation/Automation.js.map +1 -0
  38. package/dist/automation/RunView.d.ts +25 -0
  39. package/dist/automation/RunView.js +187 -0
  40. package/dist/automation/RunView.js.map +1 -0
  41. package/dist/automation/cron.d.ts +41 -0
  42. package/dist/automation/cron.js +169 -0
  43. package/dist/automation/cron.js.map +1 -0
  44. package/dist/automation/marks.js +121 -0
  45. package/dist/automation/marks.js.map +1 -0
  46. package/dist/automation/messages.d.ts +113 -0
  47. package/dist/automation/messages.js +113 -0
  48. package/dist/automation/messages.js.map +1 -0
  49. package/dist/automation/record.d.ts +47 -0
  50. package/dist/automation/record.js +177 -0
  51. package/dist/automation/record.js.map +1 -0
  52. package/dist/automation/types.d.ts +143 -0
  53. package/dist/automation/when.d.ts +36 -0
  54. package/dist/automation/when.js +168 -0
  55. package/dist/automation/when.js.map +1 -0
  56. package/dist/blocks.d.ts +185 -0
  57. package/dist/browser.js +292 -0
  58. package/dist/browser.js.map +1 -0
  59. package/dist/call.d.ts +89 -0
  60. package/dist/call.js +218 -0
  61. package/dist/call.js.map +1 -0
  62. package/dist/channelParts.js +26 -0
  63. package/dist/channelParts.js.map +1 -0
  64. package/dist/classes.js +8 -3
  65. package/dist/classes.js.map +1 -0
  66. package/dist/client.d.ts +146 -54
  67. package/dist/client.js +204 -1
  68. package/dist/client.js.map +1 -0
  69. package/dist/conversationFiles.js +46 -0
  70. package/dist/conversationFiles.js.map +1 -0
  71. package/dist/credentials.d.ts +45 -0
  72. package/dist/credentials.js +98 -0
  73. package/dist/credentials.js.map +1 -0
  74. package/dist/dev.js +17 -0
  75. package/dist/dev.js.map +1 -0
  76. package/dist/es.d.ts +17 -0
  77. package/dist/es.js +382 -0
  78. package/dist/es.js.map +1 -0
  79. package/dist/files.d.ts +21 -0
  80. package/dist/files.js +214 -0
  81. package/dist/files.js.map +1 -0
  82. package/dist/frames.d.ts +115 -0
  83. package/dist/frames.js +219 -0
  84. package/dist/frames.js.map +1 -0
  85. package/dist/icons.js +29 -0
  86. package/dist/icons.js.map +1 -0
  87. package/dist/index.d.ts +63 -60
  88. package/dist/index.js +59 -45
  89. package/dist/kit/AudioPlayer.d.ts +20 -0
  90. package/dist/kit/AudioPlayer.js +116 -0
  91. package/dist/kit/AudioPlayer.js.map +1 -0
  92. package/dist/kit/Button.d.ts +29 -0
  93. package/dist/kit/Button.js +59 -0
  94. package/dist/kit/Button.js.map +1 -0
  95. package/dist/kit/Card.d.ts +16 -0
  96. package/dist/kit/Card.js +36 -0
  97. package/dist/kit/Card.js.map +1 -0
  98. package/dist/kit/Chart.js +152 -0
  99. package/dist/kit/Chart.js.map +1 -0
  100. package/dist/kit/Choices.d.ts +21 -0
  101. package/dist/kit/Choices.js +99 -0
  102. package/dist/kit/Choices.js.map +1 -0
  103. package/dist/kit/Combobox.d.ts +26 -0
  104. package/dist/kit/Combobox.js +190 -0
  105. package/dist/kit/Combobox.js.map +1 -0
  106. package/dist/kit/DateField.d.ts +17 -0
  107. package/dist/kit/DateField.js +133 -0
  108. package/dist/kit/DateField.js.map +1 -0
  109. package/dist/kit/Field.d.ts +40 -0
  110. package/dist/kit/Field.js +98 -0
  111. package/dist/kit/Field.js.map +1 -0
  112. package/dist/kit/FileField.d.ts +113 -0
  113. package/dist/kit/FileField.js +341 -0
  114. package/dist/kit/FileField.js.map +1 -0
  115. package/dist/kit/FileMark.d.ts +15 -0
  116. package/dist/kit/FileMark.js +39 -0
  117. package/dist/kit/FileMark.js.map +1 -0
  118. package/dist/kit/Inputs.d.ts +59 -0
  119. package/dist/kit/Inputs.js +205 -0
  120. package/dist/kit/Inputs.js.map +1 -0
  121. package/dist/kit/List.d.ts +47 -0
  122. package/dist/kit/List.js +85 -0
  123. package/dist/kit/List.js.map +1 -0
  124. package/dist/kit/Mark.d.ts +30 -0
  125. package/dist/kit/Mark.js +27 -0
  126. package/dist/kit/Mark.js.map +1 -0
  127. package/dist/kit/MarkStack.d.ts +15 -0
  128. package/dist/kit/MarkStack.js +26 -0
  129. package/dist/kit/MarkStack.js.map +1 -0
  130. package/dist/kit/Note.d.ts +11 -0
  131. package/dist/kit/Note.js +31 -0
  132. package/dist/kit/Note.js.map +1 -0
  133. package/dist/kit/Popover.js +90 -0
  134. package/dist/kit/Popover.js.map +1 -0
  135. package/dist/kit/RangeField.d.ts +14 -0
  136. package/dist/kit/RangeField.js +47 -0
  137. package/dist/kit/RangeField.js.map +1 -0
  138. package/dist/kit/RatingField.d.ts +14 -0
  139. package/dist/kit/RatingField.js +50 -0
  140. package/dist/kit/RatingField.js.map +1 -0
  141. package/dist/kit/Stat.d.ts +26 -0
  142. package/dist/kit/Stat.js +46 -0
  143. package/dist/kit/Stat.js.map +1 -0
  144. package/dist/kit/Switch.d.ts +14 -0
  145. package/dist/kit/Switch.js +21 -0
  146. package/dist/kit/Switch.js.map +1 -0
  147. package/dist/kit/Tag.d.ts +16 -0
  148. package/dist/kit/Tag.js +20 -0
  149. package/dist/kit/Tag.js.map +1 -0
  150. package/dist/kit/Tile.d.ts +34 -0
  151. package/dist/kit/Tile.js +52 -0
  152. package/dist/kit/Tile.js.map +1 -0
  153. package/dist/kit/TimeField.d.ts +31 -0
  154. package/dist/kit/TimeField.js +109 -0
  155. package/dist/kit/TimeField.js.map +1 -0
  156. package/dist/kit/context.d.ts +22 -0
  157. package/dist/kit/context.js +46 -0
  158. package/dist/kit/context.js.map +1 -0
  159. package/dist/kit/dates.d.ts +14 -0
  160. package/dist/kit/dates.js +129 -0
  161. package/dist/kit/dates.js.map +1 -0
  162. package/dist/kit/messages.d.ts +99 -0
  163. package/dist/kit/messages.js +66 -0
  164. package/dist/kit/messages.js.map +1 -0
  165. package/dist/kit/numbers.d.ts +12 -0
  166. package/dist/kit/numbers.js +40 -0
  167. package/dist/kit/numbers.js.map +1 -0
  168. package/dist/kit/options.d.ts +10 -0
  169. package/dist/kit/options.js +23 -0
  170. package/dist/kit/options.js.map +1 -0
  171. package/dist/kit/uploads.d.ts +42 -0
  172. package/dist/kit/uploads.js +165 -0
  173. package/dist/kit/uploads.js.map +1 -0
  174. package/dist/kit/waveform.js +76 -0
  175. package/dist/kit/waveform.js.map +1 -0
  176. package/dist/locale.d.ts +1 -0
  177. package/dist/locale.js +1 -0
  178. package/dist/markdown.js +84 -0
  179. package/dist/markdown.js.map +1 -0
  180. package/dist/marks.js +217 -0
  181. package/dist/marks.js.map +1 -0
  182. package/dist/reveal.js +48 -0
  183. package/dist/reveal.js.map +1 -0
  184. package/dist/stepGlyphs.js +62 -0
  185. package/dist/stepGlyphs.js.map +1 -0
  186. package/dist/surface/Form.js +264 -0
  187. package/dist/surface/Form.js.map +1 -0
  188. package/dist/surface/Markdown.js +42 -0
  189. package/dist/surface/Markdown.js.map +1 -0
  190. package/dist/surface/Surface.d.ts +31 -17
  191. package/dist/surface/Surface.js +480 -57
  192. package/dist/surface/Surface.js.map +1 -0
  193. package/dist/surface/scope.d.ts +32 -0
  194. package/dist/surface/scope.js +23 -0
  195. package/dist/surface/scope.js.map +1 -0
  196. package/dist/surface/values.d.ts +44 -0
  197. package/dist/surface/values.js +237 -0
  198. package/dist/surface/values.js.map +1 -0
  199. package/dist/tint.d.ts +10 -0
  200. package/dist/tint.js +19 -0
  201. package/dist/tint.js.map +1 -0
  202. package/dist/types.d.ts +541 -0
  203. package/dist/types.js +16 -0
  204. package/dist/types.js.map +1 -0
  205. package/dist/useAgentFace.d.ts +18 -0
  206. package/dist/useAgentFace.js +45 -0
  207. package/dist/useAgentFace.js.map +1 -0
  208. package/dist/useCall.d.ts +39 -0
  209. package/dist/useCall.js +273 -0
  210. package/dist/useCall.js.map +1 -0
  211. package/dist/useConversation.d.ts +77 -0
  212. package/dist/useConversation.js +523 -0
  213. package/dist/useConversation.js.map +1 -0
  214. package/dist/useDictation.d.ts +17 -0
  215. package/dist/useDictation.js +68 -0
  216. package/dist/useDictation.js.map +1 -0
  217. package/dist/useLive.d.ts +26 -0
  218. package/dist/useLive.js +88 -0
  219. package/dist/useLive.js.map +1 -0
  220. package/dist/usePolled.js +68 -0
  221. package/dist/usePolled.js.map +1 -0
  222. package/dist/voice/Orb.d.ts +10 -9
  223. package/dist/voice/Orb.js +43 -39
  224. package/dist/voice/Orb.js.map +1 -0
  225. package/dist/voice/StillOrb.js +33 -0
  226. package/dist/voice/StillOrb.js.map +1 -0
  227. package/dist/voice/WebGLOrb.js +98 -0
  228. package/dist/voice/WebGLOrb.js.map +1 -0
  229. package/dist/voice/fluidDots.js +161 -0
  230. package/dist/voice/fluidDots.js.map +1 -0
  231. package/dist/voice/motion.js +84 -0
  232. package/dist/voice/motion.js.map +1 -0
  233. package/dist/voice/orbs.d.ts +32 -0
  234. package/dist/voice/orbs.js +16 -0
  235. package/dist/voice/orbs.js.map +1 -0
  236. package/dist/voice/useReducedMotion.js +16 -16
  237. package/dist/voice/useReducedMotion.js.map +1 -0
  238. package/dist/voice/wave.js +116 -0
  239. package/dist/voice/wave.js.map +1 -0
  240. package/dist/voice/webgl.js +177 -0
  241. package/dist/voice/webgl.js.map +1 -0
  242. package/dist/widget.js +284 -8
  243. package/package.json +49 -39
  244. package/src/AgentAbout.tsx +1621 -0
  245. package/src/AgentCard.tsx +123 -0
  246. package/src/AgentChat.tsx +1812 -0
  247. package/src/AgentSpace.tsx +540 -0
  248. package/src/AgentTasks.tsx +163 -0
  249. package/src/BrowserView.tsx +442 -0
  250. package/src/FileView.tsx +620 -0
  251. package/src/Modes.tsx +112 -0
  252. package/src/VoiceCall.tsx +411 -0
  253. package/src/about.ts +355 -0
  254. package/src/agentIcons.ts +56 -0
  255. package/src/automation/Automation.tsx +308 -0
  256. package/src/automation/RunView.tsx +213 -0
  257. package/src/automation/cron.ts +196 -0
  258. package/src/automation/marks.tsx +144 -0
  259. package/src/automation/messages.ts +231 -0
  260. package/src/automation/record.ts +206 -0
  261. package/src/automation/types.ts +146 -0
  262. package/src/automation/when.ts +195 -0
  263. package/src/blocks.ts +249 -0
  264. package/src/browser.ts +334 -0
  265. package/src/call.ts +300 -0
  266. package/src/channelParts.ts +17 -0
  267. package/src/classes.ts +10 -0
  268. package/src/client.ts +397 -0
  269. package/src/conversationFiles.ts +54 -0
  270. package/src/credentials.ts +158 -0
  271. package/src/dev.ts +20 -0
  272. package/src/es.ts +423 -0
  273. package/src/files.ts +238 -0
  274. package/src/frames.ts +291 -0
  275. package/src/icons.tsx +49 -0
  276. package/src/index.ts +271 -0
  277. package/src/kit/AudioPlayer.tsx +129 -0
  278. package/src/kit/Button.tsx +97 -0
  279. package/src/kit/Card.tsx +47 -0
  280. package/src/kit/Chart.tsx +129 -0
  281. package/src/kit/Choices.tsx +131 -0
  282. package/src/kit/Combobox.tsx +247 -0
  283. package/src/kit/DateField.tsx +156 -0
  284. package/src/kit/Field.tsx +137 -0
  285. package/src/kit/FileField.tsx +492 -0
  286. package/src/kit/FileMark.tsx +56 -0
  287. package/src/kit/Inputs.tsx +250 -0
  288. package/src/kit/List.tsx +135 -0
  289. package/src/kit/Mark.tsx +64 -0
  290. package/src/kit/MarkStack.tsx +29 -0
  291. package/src/kit/Note.tsx +42 -0
  292. package/src/kit/Popover.tsx +121 -0
  293. package/src/kit/RangeField.tsx +53 -0
  294. package/src/kit/RatingField.tsx +62 -0
  295. package/src/kit/Stat.tsx +60 -0
  296. package/src/kit/Switch.tsx +28 -0
  297. package/src/kit/Tag.tsx +32 -0
  298. package/src/kit/Tile.tsx +74 -0
  299. package/src/kit/TimeField.tsx +157 -0
  300. package/src/kit/context.tsx +246 -0
  301. package/src/kit/dates.ts +150 -0
  302. package/src/kit/messages.ts +160 -0
  303. package/src/kit/numbers.ts +44 -0
  304. package/src/kit/options.ts +30 -0
  305. package/src/kit/uploads.ts +244 -0
  306. package/src/kit/waveform.ts +84 -0
  307. package/src/locale.ts +6 -0
  308. package/src/markdown.ts +69 -0
  309. package/src/marks.tsx +328 -0
  310. package/src/reveal.ts +52 -0
  311. package/src/stepGlyphs.ts +83 -0
  312. package/src/styles.css +6970 -0
  313. package/src/surface/Form.tsx +299 -0
  314. package/src/surface/Markdown.tsx +55 -0
  315. package/src/surface/Surface.tsx +605 -0
  316. package/src/surface/scope.ts +82 -0
  317. package/src/surface/values.ts +361 -0
  318. package/src/tint.ts +14 -0
  319. package/src/types.ts +604 -0
  320. package/src/useAgentFace.ts +47 -0
  321. package/src/useCall.ts +292 -0
  322. package/src/useConversation.ts +627 -0
  323. package/src/useDictation.ts +83 -0
  324. package/src/useLive.ts +115 -0
  325. package/src/usePolled.ts +60 -0
  326. package/src/voice/Orb.tsx +45 -0
  327. package/src/voice/StillOrb.tsx +29 -0
  328. package/src/voice/WebGLOrb.tsx +98 -0
  329. package/src/voice/fluidDots.tsx +171 -0
  330. package/src/voice/motion.ts +112 -0
  331. package/src/voice/orbs.ts +39 -0
  332. package/src/voice/useReducedMotion.ts +24 -0
  333. package/src/voice/wave.tsx +129 -0
  334. package/src/voice/webgl.ts +209 -0
  335. package/src/widget/css.d.ts +5 -0
  336. package/src/widget/element.tsx +535 -0
  337. package/src/widget/index.ts +10 -0
  338. package/src/widget/mount.ts +27 -0
  339. package/src/widget/widget.css +253 -0
  340. package/dist/SignalcoreProvider.d.ts +0 -113
  341. package/dist/SignalcoreProvider.js +0 -84
  342. package/dist/automations/AppMarks.d.ts +0 -11
  343. package/dist/automations/AppMarks.js +0 -18
  344. package/dist/automations/AutomationCard.d.ts +0 -27
  345. package/dist/automations/AutomationCard.js +0 -53
  346. package/dist/automations/AutomationsWindow.d.ts +0 -38
  347. package/dist/automations/AutomationsWindow.js +0 -57
  348. package/dist/automations/Card.d.ts +0 -46
  349. package/dist/automations/Card.js +0 -45
  350. package/dist/automations/ScheduleMarks.d.ts +0 -13
  351. package/dist/automations/ScheduleMarks.js +0 -24
  352. package/dist/automations/presentationIcons.d.ts +0 -7
  353. package/dist/automations/presentationIcons.js +0 -67
  354. package/dist/automations/schedule.d.ts +0 -25
  355. package/dist/automations/schedule.js +0 -59
  356. package/dist/automations/time.d.ts +0 -3
  357. package/dist/automations/time.js +0 -25
  358. package/dist/browser/BrowserView.d.ts +0 -43
  359. package/dist/browser/BrowserView.js +0 -94
  360. package/dist/browser/room.d.ts +0 -21
  361. package/dist/browser/room.js +0 -33
  362. package/dist/browser/useBrowserSession.d.ts +0 -17
  363. package/dist/browser/useBrowserSession.js +0 -67
  364. package/dist/builder/BuilderChat.d.ts +0 -32
  365. package/dist/builder/BuilderChat.js +0 -41
  366. package/dist/builder/BuilderTranscript.d.ts +0 -49
  367. package/dist/builder/BuilderTranscript.js +0 -62
  368. package/dist/builder/StatusLine.d.ts +0 -8
  369. package/dist/builder/StatusLine.js +0 -17
  370. package/dist/builder/answer.d.ts +0 -7
  371. package/dist/builder/answer.js +0 -8
  372. package/dist/builder/blocks.d.ts +0 -31
  373. package/dist/builder/blocks.js +0 -74
  374. package/dist/builder/items.d.ts +0 -15
  375. package/dist/builder/items.js +0 -21
  376. package/dist/builder/steps.d.ts +0 -20
  377. package/dist/builder/steps.js +0 -120
  378. package/dist/builder/time.d.ts +0 -4
  379. package/dist/builder/time.js +0 -24
  380. package/dist/builder/useBuildSession.d.ts +0 -36
  381. package/dist/builder/useBuildSession.js +0 -130
  382. package/dist/builder/workingOn.d.ts +0 -7
  383. package/dist/builder/workingOn.js +0 -15
  384. package/dist/chat/AgentChat.d.ts +0 -37
  385. package/dist/chat/AgentChat.js +0 -21
  386. package/dist/chat/ChatView.d.ts +0 -25
  387. package/dist/chat/ChatView.js +0 -34
  388. package/dist/chat/Composer.d.ts +0 -20
  389. package/dist/chat/Composer.js +0 -22
  390. package/dist/chat/MessageRow.d.ts +0 -22
  391. package/dist/chat/MessageRow.js +0 -32
  392. package/dist/chat/arrival.d.ts +0 -15
  393. package/dist/chat/arrival.js +0 -25
  394. package/dist/chat/history.d.ts +0 -24
  395. package/dist/chat/history.js +0 -45
  396. package/dist/chat/moments.d.ts +0 -25
  397. package/dist/chat/moments.js +0 -72
  398. package/dist/chat/types.d.ts +0 -12
  399. package/dist/chat/types.js +0 -1
  400. package/dist/chat/useComposer.d.ts +0 -46
  401. package/dist/chat/useComposer.js +0 -62
  402. package/dist/chat/useConversation.d.ts +0 -35
  403. package/dist/chat/useConversation.js +0 -71
  404. package/dist/chat/useStickToBottom.d.ts +0 -9
  405. package/dist/chat/useStickToBottom.js +0 -33
  406. package/dist/chat/useTurns.d.ts +0 -49
  407. package/dist/chat/useTurns.js +0 -111
  408. package/dist/classes.d.ts +0 -2
  409. package/dist/development.d.ts +0 -5
  410. package/dist/development.js +0 -8
  411. package/dist/flow/FlowWindow.d.ts +0 -42
  412. package/dist/flow/FlowWindow.js +0 -126
  413. package/dist/flow/index.d.ts +0 -16
  414. package/dist/flow/index.js +0 -16
  415. package/dist/flow/kinds.d.ts +0 -23
  416. package/dist/flow/kinds.js +0 -48
  417. package/dist/flow/map.d.ts +0 -44
  418. package/dist/flow/map.js +0 -225
  419. package/dist/flow/nodePaths.d.ts +0 -7
  420. package/dist/flow/nodePaths.js +0 -17
  421. package/dist/flow/relations.d.ts +0 -42
  422. package/dist/flow/relations.js +0 -174
  423. package/dist/host.d.ts +0 -124
  424. package/dist/host.js +0 -1
  425. package/dist/live/LiveView.d.ts +0 -28
  426. package/dist/live/LiveView.js +0 -55
  427. package/dist/live/capture.d.ts +0 -20
  428. package/dist/live/capture.js +0 -100
  429. package/dist/live/follow.d.ts +0 -26
  430. package/dist/live/follow.js +0 -72
  431. package/dist/live/paint.d.ts +0 -13
  432. package/dist/live/paint.js +0 -77
  433. package/dist/live/useLiveStream.d.ts +0 -16
  434. package/dist/live/useLiveStream.js +0 -57
  435. package/dist/look.d.ts +0 -33
  436. package/dist/look.js +0 -241
  437. package/dist/messages/en.d.ts +0 -3
  438. package/dist/messages/en.js +0 -251
  439. package/dist/messages/es.d.ts +0 -3
  440. package/dist/messages/es.js +0 -251
  441. package/dist/messages/index.d.ts +0 -16
  442. package/dist/messages/index.js +0 -33
  443. package/dist/messages/types.d.ts +0 -246
  444. package/dist/messages/types.js +0 -1
  445. package/dist/parts/Button.d.ts +0 -18
  446. package/dist/parts/Button.js +0 -17
  447. package/dist/parts/Icon.d.ts +0 -39
  448. package/dist/parts/Icon.js +0 -37
  449. package/dist/parts/Input.d.ts +0 -6
  450. package/dist/parts/Input.js +0 -11
  451. package/dist/parts/Spinner.d.ts +0 -2
  452. package/dist/parts/Spinner.js +0 -7
  453. package/dist/patterns.d.ts +0 -15
  454. package/dist/patterns.js +0 -5
  455. package/dist/presets.d.ts +0 -82
  456. package/dist/presets.js +0 -81
  457. package/dist/primitives.d.ts +0 -22
  458. package/dist/primitives.js +0 -58
  459. package/dist/request/RequestCard.d.ts +0 -34
  460. package/dist/request/RequestCard.js +0 -101
  461. package/dist/request/approval/ApprovalPreview.d.ts +0 -5
  462. package/dist/request/approval/ApprovalPreview.js +0 -27
  463. package/dist/request/approval/shapes.d.ts +0 -32
  464. package/dist/request/approval/shapes.js +0 -68
  465. package/dist/request/apps.d.ts +0 -11
  466. package/dist/request/apps.js +0 -27
  467. package/dist/request/cards.d.ts +0 -12
  468. package/dist/request/cards.js +0 -24
  469. package/dist/request/deliver.d.ts +0 -12
  470. package/dist/request/deliver.js +0 -21
  471. package/dist/request/handOver.d.ts +0 -18
  472. package/dist/request/handOver.js +0 -33
  473. package/dist/request/kinds/Approval.d.ts +0 -3
  474. package/dist/request/kinds/Approval.js +0 -9
  475. package/dist/request/kinds/Choice.d.ts +0 -3
  476. package/dist/request/kinds/Choice.js +0 -8
  477. package/dist/request/kinds/Connect.d.ts +0 -9
  478. package/dist/request/kinds/Connect.js +0 -119
  479. package/dist/request/kinds/FreeText.d.ts +0 -3
  480. package/dist/request/kinds/FreeText.js +0 -20
  481. package/dist/request/kinds/HandOver.d.ts +0 -13
  482. package/dist/request/kinds/HandOver.js +0 -20
  483. package/dist/request/kinds/Secret.d.ts +0 -7
  484. package/dist/request/kinds/Secret.js +0 -49
  485. package/dist/request/kinds/Upload.d.ts +0 -6
  486. package/dist/request/kinds/Upload.js +0 -47
  487. package/dist/request/types.d.ts +0 -83
  488. package/dist/request/types.js +0 -1
  489. package/dist/safeUrl.d.ts +0 -6
  490. package/dist/safeUrl.js +0 -8
  491. package/dist/stream/builder.d.ts +0 -176
  492. package/dist/stream/builder.js +0 -202
  493. package/dist/stream/reduce.d.ts +0 -51
  494. package/dist/stream/reduce.js +0 -58
  495. package/dist/stream/untilAborted.d.ts +0 -7
  496. package/dist/stream/untilAborted.js +0 -32
  497. package/dist/stream/useRunStream.d.ts +0 -26
  498. package/dist/stream/useRunStream.js +0 -137
  499. package/dist/styles.css +0 -2318
  500. package/dist/surface/HostNode.d.ts +0 -14
  501. package/dist/surface/HostNode.js +0 -30
  502. package/dist/surface/Node.d.ts +0 -7
  503. package/dist/surface/Node.js +0 -49
  504. package/dist/surface/SurfaceBoundary.d.ts +0 -26
  505. package/dist/surface/SurfaceBoundary.js +0 -20
  506. package/dist/surface/bindings.d.ts +0 -14
  507. package/dist/surface/bindings.js +0 -37
  508. package/dist/surface/check.d.ts +0 -27
  509. package/dist/surface/check.js +0 -102
  510. package/dist/surface/format.d.ts +0 -10
  511. package/dist/surface/format.js +0 -32
  512. package/dist/surface/hosts.d.ts +0 -6
  513. package/dist/surface/hosts.js +0 -11
  514. package/dist/surface/scene.d.ts +0 -21
  515. package/dist/surface/scene.js +0 -8
  516. package/dist/surface/templates/Browser.d.ts +0 -6
  517. package/dist/surface/templates/Browser.js +0 -11
  518. package/dist/surface/templates/Chart.d.ts +0 -6
  519. package/dist/surface/templates/Chart.js +0 -13
  520. package/dist/surface/templates/Choices.d.ts +0 -3
  521. package/dist/surface/templates/Choices.js +0 -12
  522. package/dist/surface/templates/Form.d.ts +0 -3
  523. package/dist/surface/templates/Form.js +0 -44
  524. package/dist/surface/templates/KeyValue.d.ts +0 -3
  525. package/dist/surface/templates/KeyValue.js +0 -7
  526. package/dist/surface/templates/Layout.d.ts +0 -5
  527. package/dist/surface/templates/Layout.js +0 -16
  528. package/dist/surface/templates/Live.d.ts +0 -6
  529. package/dist/surface/templates/Live.js +0 -9
  530. package/dist/surface/templates/Media.d.ts +0 -5
  531. package/dist/surface/templates/Media.js +0 -13
  532. package/dist/surface/templates/Slots.d.ts +0 -3
  533. package/dist/surface/templates/Slots.js +0 -19
  534. package/dist/surface/templates/Table.d.ts +0 -3
  535. package/dist/surface/templates/Table.js +0 -12
  536. package/dist/surface/templates/Text.d.ts +0 -4
  537. package/dist/surface/templates/Text.js +0 -15
  538. package/dist/surface/templates/index.d.ts +0 -7
  539. package/dist/surface/templates/index.js +0 -32
  540. package/dist/surface/types.d.ts +0 -68
  541. package/dist/surface/types.js +0 -6
  542. package/dist/theme.d.ts +0 -62
  543. package/dist/theme.js +0 -9
  544. package/dist/useTokens.d.ts +0 -7
  545. package/dist/useTokens.js +0 -41
  546. package/dist/voice/VoiceWindow.d.ts +0 -18
  547. package/dist/voice/VoiceWindow.js +0 -35
  548. package/dist/voice/index.d.ts +0 -13
  549. package/dist/voice/index.js +0 -12
  550. package/dist/voice/meter.d.ts +0 -16
  551. package/dist/voice/meter.js +0 -52
  552. package/dist/voice/orbColors.d.ts +0 -16
  553. package/dist/voice/orbColors.js +0 -75
  554. package/dist/voice/pushable.d.ts +0 -16
  555. package/dist/voice/pushable.js +0 -56
  556. package/dist/voice/useDictation.d.ts +0 -24
  557. package/dist/voice/useDictation.js +0 -60
  558. package/dist/voice/useReducedMotion.d.ts +0 -5
  559. package/dist/voice/useVoice.d.ts +0 -70
  560. package/dist/voice/useVoice.js +0 -197
  561. package/dist/voice/useVoicePrimitives.d.ts +0 -7
  562. package/dist/voice/useVoicePrimitives.js +0 -11
  563. package/dist/voice/voice.d.ts +0 -55
  564. package/dist/voice/voice.js +0 -9
  565. package/dist/voice/webSpeech.d.ts +0 -33
  566. package/dist/voice/webSpeech.js +0 -258
  567. package/dist/widget.js.map +0 -1
  568. package/dist/windows/AgentSpace.d.ts +0 -78
  569. package/dist/windows/AgentSpace.js +0 -135
  570. package/dist/windows/Captions.d.ts +0 -13
  571. package/dist/windows/Captions.js +0 -22
  572. package/dist/windows/Dock.d.ts +0 -37
  573. package/dist/windows/Dock.js +0 -22
  574. package/dist/windows/Journal.d.ts +0 -15
  575. package/dist/windows/Journal.js +0 -19
  576. package/dist/windows/KindMark.d.ts +0 -7
  577. package/dist/windows/KindMark.js +0 -31
  578. package/dist/windows/Pending.d.ts +0 -8
  579. package/dist/windows/Pending.js +0 -17
  580. package/dist/windows/Stage.d.ts +0 -18
  581. package/dist/windows/Stage.js +0 -21
  582. package/dist/windows/StatusLabel.d.ts +0 -9
  583. package/dist/windows/StatusLabel.js +0 -7
  584. package/dist/windows/Strip.d.ts +0 -17
  585. package/dist/windows/Strip.js +0 -42
  586. package/dist/windows/SurfaceWindow.d.ts +0 -20
  587. package/dist/windows/SurfaceWindow.js +0 -12
  588. package/dist/windows/WindowFrame.d.ts +0 -23
  589. package/dist/windows/WindowFrame.js +0 -22
  590. package/dist/windows/hearing.d.ts +0 -11
  591. package/dist/windows/hearing.js +0 -26
  592. package/dist/windows/kinds.d.ts +0 -47
  593. package/dist/windows/kinds.js +0 -28
  594. package/dist/windows/reduce.d.ts +0 -98
  595. package/dist/windows/reduce.js +0 -151
  596. package/dist/windows/registry.d.ts +0 -18
  597. package/dist/windows/registry.js +0 -61
  598. package/dist/windows/reveal.d.ts +0 -9
  599. package/dist/windows/reveal.js +0 -6
  600. package/dist/windows/space.d.ts +0 -21
  601. package/dist/windows/space.js +0 -6
  602. package/dist/windows/status.d.ts +0 -11
  603. package/dist/windows/status.js +0 -30
  604. package/dist/windows/types.d.ts +0 -15
  605. package/dist/windows/types.js +0 -1
  606. package/dist/windows/useLoaded.d.ts +0 -44
  607. package/dist/windows/useLoaded.js +0 -58
  608. package/dist/windows/useUnread.d.ts +0 -7
  609. package/dist/windows/useUnread.js +0 -21
  610. package/dist/windows/useWindows.d.ts +0 -70
  611. package/dist/windows/useWindows.js +0 -60
@@ -0,0 +1,449 @@
1
+ import { formatSize } from "./kit/numbers.js";
2
+ import { classes } from "./classes.js";
3
+ import { KitProvider } from "./kit/context.js";
4
+ import { Button } from "./kit/Button.js";
5
+ import { baseName, cleanDocument, extensionOf, pretty, previewOf, tableOf, typedFor } from "./files.js";
6
+ import { FileMark } from "./kit/FileMark.js";
7
+ import { AudioPlayer } from "./kit/AudioPlayer.js";
8
+ import { Markdown } from "./surface/Markdown.js";
9
+ import { useEffect, useMemo, useState } from "react";
10
+ import { DownloadSimpleIcon } from "@phosphor-icons/react";
11
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
+ //#region src/FileView.tsx
13
+ const FILE_MESSAGES = {
14
+ download: "Download",
15
+ noPreview: "This file can't be previewed here.",
16
+ noPreviewHint: "Download it to open it on your device.",
17
+ truncated: "Only the beginning is shown. Download it to see it whole.",
18
+ file: "File",
19
+ size: (bytes) => formatSize(bytes),
20
+ pages: (count) => count === 1 ? "1 page" : `${count} pages`,
21
+ sheets: "Sheets",
22
+ rows: (shown, total) => `The first ${shown} of ${total} rows`,
23
+ emptySheet: "This sheet is empty.",
24
+ slide: (number) => `Slide ${number}`,
25
+ notes: "Notes"
26
+ };
27
+ /** The most of a file read as words: a longer one shows its beginning. */
28
+ const TEXT_LIMIT = 262144;
29
+ /** The most rows a table draws. */
30
+ const ROW_LIMIT = 500;
31
+ /**
32
+ * One file, to see and to save, whatever its kind: a bar with its kind, its size (a PDF's pages)
33
+ * and the button that saves it under its name, over the file as it reads. A PDF in the browser's
34
+ * own viewer; a spreadsheet as a grid, its header kept in view, its sheets as tabs at its foot; a
35
+ * Word file as a document at a reading measure; a deck as its slides one under another, their
36
+ * notes under each; Markdown drawn, plain words as written, a source in the mono face, wrapped,
37
+ * never run; a picture whole, a video and a sound in the browser's own players; any other kind
38
+ * says it can't be shown, and is saved. What it can't read alone (a sheet, a document, slides)
39
+ * it draws from `preview`. It fills the height it is given (a dialog's body), and scrolls inside.
40
+ * The addresses it makes for the bytes are let go when it goes.
41
+ */
42
+ function FileView(props) {
43
+ return /* @__PURE__ */ jsx(KitProvider, {
44
+ classNames: props.classNames,
45
+ children: /* @__PURE__ */ jsx(View, { ...props })
46
+ });
47
+ }
48
+ function View({ blob, name, preview, messages, classNames }) {
49
+ const words = {
50
+ ...FILE_MESSAGES,
51
+ ...messages
52
+ };
53
+ const extension = extensionOf(name);
54
+ const save = useObjectUrl(useMemo(() => new Blob([blob], { type: "application/octet-stream" }), [blob]));
55
+ const pages = preview?.kind === "pdf" ? preview.pages : null;
56
+ return /* @__PURE__ */ jsxs("div", {
57
+ className: `sc ${classes(classNames, "sc-file")}`,
58
+ children: [/* @__PURE__ */ jsxs("div", {
59
+ className: classes(classNames, "sc-file__bar"),
60
+ children: [
61
+ /* @__PURE__ */ jsx(FileMark, {
62
+ name,
63
+ size: 24
64
+ }),
65
+ /* @__PURE__ */ jsxs("span", {
66
+ className: classes(classNames, "sc-file__meta"),
67
+ children: [
68
+ /* @__PURE__ */ jsx("span", { children: extension === "" ? words.file : extension.toUpperCase() }),
69
+ /* @__PURE__ */ jsx("span", { children: words.size(blob.size) }),
70
+ pages !== null && /* @__PURE__ */ jsx("span", { children: words.pages(pages) })
71
+ ]
72
+ }),
73
+ save !== null && /* @__PURE__ */ jsx(Button, {
74
+ size: "sm",
75
+ icon: DownloadSimpleIcon,
76
+ href: save,
77
+ download: baseName(name),
78
+ children: words.download
79
+ })
80
+ ]
81
+ }), /* @__PURE__ */ jsx("div", {
82
+ className: classes(classNames, "sc-file__body"),
83
+ children: preview === void 0 ? /* @__PURE__ */ jsx(Read, {
84
+ blob,
85
+ name,
86
+ words,
87
+ classNames
88
+ }) : /* @__PURE__ */ jsx(Previewed, {
89
+ preview,
90
+ blob,
91
+ name,
92
+ words,
93
+ classNames
94
+ })
95
+ })]
96
+ });
97
+ }
98
+ /** Under a file shown only in part: the words that say so. */
99
+ function Cut({ shown, words, classNames }) {
100
+ return shown ? /* @__PURE__ */ jsx("p", {
101
+ className: classes(classNames, "sc-file__note"),
102
+ children: words.truncated
103
+ }) : null;
104
+ }
105
+ /** The file as the API made it to draw, by its kind. */
106
+ function Previewed({ preview, blob, name, words, classNames }) {
107
+ switch (preview.kind) {
108
+ case "pdf": return /* @__PURE__ */ jsx(Pdf, {
109
+ blob,
110
+ name,
111
+ classNames
112
+ });
113
+ case "image": return preview.media_type.includes("svg") ? /* @__PURE__ */ jsx(Svg, {
114
+ blob,
115
+ name,
116
+ classNames
117
+ }) : /* @__PURE__ */ jsx(Media, {
118
+ blob,
119
+ type: preview.media_type,
120
+ name,
121
+ classNames,
122
+ kind: "image"
123
+ });
124
+ case "video":
125
+ case "audio": return /* @__PURE__ */ jsx(Media, {
126
+ blob,
127
+ type: preview.media_type,
128
+ name,
129
+ classNames,
130
+ kind: preview.kind
131
+ });
132
+ case "sheet": return /* @__PURE__ */ jsx(Sheets, {
133
+ sheets: preview.sheets,
134
+ truncated: preview.truncated,
135
+ words,
136
+ classNames
137
+ });
138
+ case "document": return /* @__PURE__ */ jsx(Document, {
139
+ html: preview.html,
140
+ truncated: preview.truncated,
141
+ words,
142
+ classNames
143
+ });
144
+ case "slides": return /* @__PURE__ */ jsx(Slides, {
145
+ slides: preview.slides,
146
+ truncated: preview.truncated,
147
+ words,
148
+ classNames
149
+ });
150
+ case "markdown":
151
+ case "text": return /* @__PURE__ */ jsx(Words, {
152
+ text: preview.text,
153
+ markdown: preview.kind === "markdown",
154
+ truncated: preview.truncated,
155
+ words,
156
+ classNames
157
+ });
158
+ case "code":
159
+ case "json": return /* @__PURE__ */ jsx(Source, {
160
+ text: preview.kind === "json" && !preview.truncated ? pretty(preview.text) : preview.text,
161
+ truncated: preview.truncated,
162
+ words,
163
+ classNames
164
+ });
165
+ case "unknown": return /* @__PURE__ */ jsx(None, {
166
+ name,
167
+ words,
168
+ classNames
169
+ });
170
+ }
171
+ }
172
+ /** The file as the browser reads its bytes alone, by its name and type. */
173
+ function Read({ blob, name, words, classNames }) {
174
+ const preview = previewOf(name, blob.type);
175
+ const svg = extensionOf(name) === "svg";
176
+ const text = useText(blob, preview === "markdown" || preview === "text" || preview === "code" || preview === "table", TEXT_LIMIT);
177
+ const cut = blob.size > TEXT_LIMIT;
178
+ if (preview === "image") return svg ? /* @__PURE__ */ jsx(Svg, {
179
+ blob,
180
+ name,
181
+ classNames
182
+ }) : /* @__PURE__ */ jsx(Media, {
183
+ blob: typedFor(blob, name),
184
+ name,
185
+ classNames,
186
+ kind: "image"
187
+ });
188
+ if (preview === "pdf") return /* @__PURE__ */ jsx(Pdf, {
189
+ blob,
190
+ name,
191
+ classNames
192
+ });
193
+ if (preview === "none") return /* @__PURE__ */ jsx(None, {
194
+ name,
195
+ words,
196
+ classNames
197
+ });
198
+ if (text === null) return null;
199
+ const rows = preview === "table" ? tableOf(text) : null;
200
+ if (rows !== null) {
201
+ const [columns = [], ...body] = rows;
202
+ return /* @__PURE__ */ jsx(Sheets, {
203
+ sheets: [{
204
+ name: baseName(name),
205
+ columns,
206
+ rows: body,
207
+ total_rows: body.length
208
+ }],
209
+ truncated: cut,
210
+ words,
211
+ classNames
212
+ });
213
+ }
214
+ if (preview === "markdown" || preview === "text") return /* @__PURE__ */ jsx(Words, {
215
+ text,
216
+ markdown: preview === "markdown",
217
+ truncated: cut,
218
+ words,
219
+ classNames
220
+ });
221
+ return /* @__PURE__ */ jsx(Source, {
222
+ text: extensionOf(name) === "json" && !cut ? pretty(text) : text,
223
+ truncated: cut,
224
+ words,
225
+ classNames
226
+ });
227
+ }
228
+ /** A PDF in the browser's own viewer. */
229
+ function Pdf({ blob, name, classNames }) {
230
+ const view = useObjectUrl(useMemo(() => typedFor(blob, name), [blob, name]));
231
+ return view !== null && /* @__PURE__ */ jsx("iframe", {
232
+ src: view,
233
+ title: baseName(name),
234
+ className: classes(classNames, "sc-file__frame")
235
+ });
236
+ }
237
+ /**
238
+ * An SVG, from its words as a data address: one of the page's own (a blob's) would run its
239
+ * scripts as the page if it were opened apart.
240
+ */
241
+ function Svg({ blob, name, classNames }) {
242
+ const text = useText(blob, true, Infinity);
243
+ return text !== null && /* @__PURE__ */ jsx("div", {
244
+ className: classes(classNames, "sc-file__image"),
245
+ children: /* @__PURE__ */ jsx("img", {
246
+ src: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(text)}`,
247
+ alt: baseName(name)
248
+ })
249
+ });
250
+ }
251
+ /** A picture whole, a video or a sound in the browser's own player, from its bytes typed. */
252
+ function Media({ blob, type, name, kind, classNames }) {
253
+ const src = useObjectUrl(useMemo(() => type === void 0 || blob.type === type ? blob : new Blob([blob], { type }), [blob, type]));
254
+ if (src === null) return null;
255
+ if (kind === "image") return /* @__PURE__ */ jsx("div", {
256
+ className: classes(classNames, "sc-file__image"),
257
+ children: /* @__PURE__ */ jsx("img", {
258
+ src,
259
+ alt: baseName(name)
260
+ })
261
+ });
262
+ return /* @__PURE__ */ jsx("div", {
263
+ className: classes(classNames, "sc-file__media"),
264
+ "data-kind": kind,
265
+ children: kind === "video" ? /* @__PURE__ */ jsx("video", {
266
+ src,
267
+ controls: true,
268
+ playsInline: true,
269
+ preload: "metadata",
270
+ "aria-label": baseName(name)
271
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(FileMark, {
272
+ name,
273
+ size: 44
274
+ }), /* @__PURE__ */ jsx(AudioPlayer, {
275
+ src,
276
+ label: baseName(name)
277
+ })] })
278
+ });
279
+ }
280
+ /**
281
+ * A spreadsheet: one sheet at a time as a grid, its columns over it kept in view as it scrolls;
282
+ * its sheets as tabs at its foot, as a spreadsheet has them. Under a
283
+ * sheet shown in part, how many of its rows are.
284
+ */
285
+ function Sheets({ sheets, truncated, words, classNames }) {
286
+ const [at, setAt] = useState(0);
287
+ const sheet = sheets[at] ?? sheets[0];
288
+ if (sheet === void 0) return /* @__PURE__ */ jsx(None, {
289
+ name: "",
290
+ words,
291
+ classNames
292
+ });
293
+ const rows = sheet.rows.slice(0, ROW_LIMIT);
294
+ const width = Math.max(sheet.columns?.length ?? 0, ...rows.map((row) => row.length));
295
+ const several = sheets.length > 1;
296
+ return /* @__PURE__ */ jsxs("div", {
297
+ className: classes(classNames, "sc-file__sheet"),
298
+ children: [/* @__PURE__ */ jsxs("div", {
299
+ role: several ? "tabpanel" : void 0,
300
+ className: classes(classNames, "sc-file__table"),
301
+ children: [sheet.columns === null ? /* @__PURE__ */ jsx("p", {
302
+ className: classes(classNames, "sc-file__note"),
303
+ children: words.emptySheet
304
+ }) : /* @__PURE__ */ jsxs("table", { children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: pad(sheet.columns, width).map((cell, index) => /* @__PURE__ */ jsx("th", {
305
+ scope: "col",
306
+ children: cell
307
+ }, index)) }) }), /* @__PURE__ */ jsx("tbody", { children: rows.map((row, index) => /* @__PURE__ */ jsx("tr", { children: pad(row, width).map((cell, column) => /* @__PURE__ */ jsx("td", {
308
+ title: cell.length > 36 ? cell : void 0,
309
+ children: cell
310
+ }, column)) }, index)) })] }), sheet.total_rows > rows.length ? /* @__PURE__ */ jsx("p", {
311
+ className: classes(classNames, "sc-file__note"),
312
+ children: words.rows(rows.length, sheet.total_rows)
313
+ }) : /* @__PURE__ */ jsx(Cut, {
314
+ shown: truncated,
315
+ words,
316
+ classNames
317
+ })]
318
+ }, at), several && /* @__PURE__ */ jsx("div", {
319
+ role: "tablist",
320
+ "aria-label": words.sheets,
321
+ className: classes(classNames, "sc-file__tabs"),
322
+ children: sheets.map((each, index) => /* @__PURE__ */ jsx("button", {
323
+ type: "button",
324
+ role: "tab",
325
+ "aria-selected": index === at,
326
+ onClick: () => {
327
+ setAt(index);
328
+ },
329
+ className: classes(classNames, "sc-file__tab"),
330
+ children: each.name
331
+ }, index))
332
+ })]
333
+ });
334
+ }
335
+ /** A row as wide as the widest, its missing cells empty. */
336
+ const pad = (cells, width) => cells.length >= width ? [...cells] : [...cells, ...Array(width - cells.length).fill("")];
337
+ /**
338
+ * A Word file as its HTML at a reading measure: headings, paragraphs, lists, tables, pictures,
339
+ * kept to what a viewer draws (`cleanDocument`), again here after the API.
340
+ */
341
+ function Document({ html, truncated, words, classNames }) {
342
+ const clean = useMemo(() => cleanDocument(html), [html]);
343
+ return /* @__PURE__ */ jsxs("div", {
344
+ className: classes(classNames, "sc-file__text"),
345
+ children: [/* @__PURE__ */ jsx("div", {
346
+ className: classes(classNames, "sc-file__document"),
347
+ dangerouslySetInnerHTML: { __html: clean }
348
+ }), /* @__PURE__ */ jsx(Cut, {
349
+ shown: truncated,
350
+ words,
351
+ classNames
352
+ })]
353
+ });
354
+ }
355
+ /** A deck: its slides one under another, each a card with its number, its words, its notes. */
356
+ function Slides({ slides, truncated, words, classNames }) {
357
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("ol", {
358
+ className: classes(classNames, "sc-file__slides"),
359
+ children: slides.map((slide, index) => /* @__PURE__ */ jsxs("li", {
360
+ className: classes(classNames, "sc-file__slide"),
361
+ children: [
362
+ /* @__PURE__ */ jsx("span", { children: words.slide(index + 1) }),
363
+ slide.title !== null && slide.title !== "" && /* @__PURE__ */ jsx("h3", { children: slide.title }),
364
+ slide.text !== "" && /* @__PURE__ */ jsx("p", { children: slide.text }),
365
+ slide.notes !== null && slide.notes !== "" && /* @__PURE__ */ jsxs("div", {
366
+ className: classes(classNames, "sc-file__notes"),
367
+ children: [/* @__PURE__ */ jsx("span", { children: words.notes }), /* @__PURE__ */ jsx("p", { children: slide.notes })]
368
+ })
369
+ ]
370
+ }, index))
371
+ }), /* @__PURE__ */ jsx(Cut, {
372
+ shown: truncated,
373
+ words,
374
+ classNames
375
+ })] });
376
+ }
377
+ /** Words at a reading measure: Markdown drawn, plain words as written. */
378
+ function Words({ text, markdown, truncated, words, classNames }) {
379
+ return /* @__PURE__ */ jsxs("div", {
380
+ className: classes(classNames, "sc-file__text"),
381
+ children: [markdown ? /* @__PURE__ */ jsx(Markdown, { text }) : /* @__PURE__ */ jsx("p", {
382
+ className: classes(classNames, "sc-file__plain"),
383
+ children: text
384
+ }), /* @__PURE__ */ jsx(Cut, {
385
+ shown: truncated,
386
+ words,
387
+ classNames
388
+ })]
389
+ });
390
+ }
391
+ /** A source as written, in the mono face, its long lines wrapped; never run. */
392
+ function Source({ text, truncated, words, classNames }) {
393
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("pre", {
394
+ className: classes(classNames, "sc-file__code"),
395
+ children: /* @__PURE__ */ jsx("code", { children: text })
396
+ }), /* @__PURE__ */ jsx(Cut, {
397
+ shown: truncated,
398
+ words,
399
+ classNames
400
+ })] });
401
+ }
402
+ /** A kind that can't be shown: its mark, the line that says so, and what to do instead. */
403
+ function None({ name, words, classNames }) {
404
+ return /* @__PURE__ */ jsxs("div", {
405
+ className: classes(classNames, "sc-file__none"),
406
+ children: [/* @__PURE__ */ jsx(FileMark, {
407
+ name,
408
+ size: 44
409
+ }), /* @__PURE__ */ jsxs("p", { children: [/* @__PURE__ */ jsx("strong", { children: words.noPreview }), /* @__PURE__ */ jsx("span", { children: words.noPreviewHint })] })]
410
+ });
411
+ }
412
+ /** The first `limit` bytes of a blob as words, once read; null while reading, or when not wanted. */
413
+ function useText(blob, wanted, limit) {
414
+ const [text, setText] = useState(null);
415
+ useEffect(() => {
416
+ if (!wanted) return;
417
+ let live = true;
418
+ (blob.size > limit ? blob.slice(0, limit) : blob).text().then((read) => {
419
+ if (live) setText(read);
420
+ });
421
+ return () => {
422
+ live = false;
423
+ setText(null);
424
+ };
425
+ }, [
426
+ blob,
427
+ wanted,
428
+ limit
429
+ ]);
430
+ return text;
431
+ }
432
+ /** An address for a blob while it is shown, let go when it changes or goes. */
433
+ function useObjectUrl(blob) {
434
+ const [url, setUrl] = useState(null);
435
+ useEffect(() => {
436
+ if (blob === null) return;
437
+ const made = URL.createObjectURL(blob);
438
+ setUrl(made);
439
+ return () => {
440
+ URL.revokeObjectURL(made);
441
+ setUrl(null);
442
+ };
443
+ }, [blob]);
444
+ return url;
445
+ }
446
+ //#endregion
447
+ export { FILE_MESSAGES, FileView };
448
+
449
+ //# sourceMappingURL=FileView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileView.js","names":[],"sources":["../src/FileView.tsx"],"sourcesContent":["import { DownloadSimpleIcon } from \"@phosphor-icons/react\";\nimport { useEffect, useMemo, useState, type ReactNode } from \"react\";\n\nimport { formatSize } from \"./about\";\nimport { classes } from \"./classes\";\nimport {\n baseName,\n cleanDocument,\n extensionOf,\n pretty,\n previewOf,\n tableOf,\n typedFor,\n type Preview,\n} from \"./files\";\nimport { AudioPlayer } from \"./kit/AudioPlayer\";\nimport { Button } from \"./kit/Button\";\nimport { KitProvider, type KitClassNames, type KitPart } from \"./kit/context\";\nimport { FileMark } from \"./kit/FileMark\";\nimport { Markdown } from \"./surface/Markdown\";\nimport type { FilePreview, PreviewSheet, PreviewSlide } from \"./types\";\n\n/** The words a file's view says; a host gives its own, in its language. */\nexport interface FileMessages {\n /** The button that saves the file under its name. */\n download: string;\n /** In the preview's place, for a kind that can't be shown here. */\n noPreview: string;\n /** Under it: what to do instead. */\n noPreviewHint: string;\n /** Under a long file shown only in part. */\n truncated: string;\n /** In the bar, for a file whose name has no extension. */\n file: string;\n /** A file's size, as the host's people read it. */\n size: (bytes: number) => string;\n /** A PDF's pages, in the bar. */\n pages: (count: number) => string;\n /** The tabs of a spreadsheet's sheets, for screen readers. */\n sheets: string;\n /** Under a sheet shown in part: its first rows of how many. */\n rows: (shown: number, total: number) => string;\n /** In place of a sheet with nothing in it. */\n emptySheet: string;\n /** Over a slide: its number. */\n slide: (number: number) => string;\n /** Over a slide's speaker notes. */\n notes: string;\n}\n\nexport const FILE_MESSAGES: FileMessages = {\n download: \"Download\",\n noPreview: \"This file can't be previewed here.\",\n noPreviewHint: \"Download it to open it on your device.\",\n truncated: \"Only the beginning is shown. Download it to see it whole.\",\n file: \"File\",\n size: (bytes) => formatSize(bytes),\n pages: (count) => (count === 1 ? \"1 page\" : `${count} pages`),\n sheets: \"Sheets\",\n rows: (shown, total) => `The first ${shown} of ${total} rows`,\n emptySheet: \"This sheet is empty.\",\n slide: (number) => `Slide ${number}`,\n notes: \"Notes\",\n};\n\n/** The parts, by the class each carries; `classNames` adds a host's own under the same keys. */\nexport type FilePart =\n | \"sc-file\"\n | \"sc-file__bar\"\n | \"sc-file__meta\"\n | \"sc-file__body\"\n | \"sc-file__text\"\n | \"sc-file__plain\"\n | \"sc-file__code\"\n | \"sc-file__table\"\n | \"sc-file__sheet\"\n | \"sc-file__tabs\"\n | \"sc-file__tab\"\n | \"sc-file__document\"\n | \"sc-file__slides\"\n | \"sc-file__slide\"\n | \"sc-file__notes\"\n | \"sc-file__frame\"\n | \"sc-file__image\"\n | \"sc-file__media\"\n | \"sc-file__none\"\n | \"sc-file__note\";\n\ntype ClassNames = Partial<Record<FilePart | KitPart, string>> | undefined;\n\nexport interface FileViewProps {\n /** The file's bytes, as the API answers them (`Response.blob()`). */\n blob: Blob;\n /** Its name or path, with its extension: how it is read, and what it is saved as. */\n name: string;\n /**\n * What the API made of it to draw (`client.files.preview`): a spreadsheet's sheets, a Word\n * file as a document, a deck's slides, the words of a text, how a picture, a video or a sound\n * is typed. Without it, what the browser can read of the bytes alone.\n */\n preview?: FilePreview | undefined;\n messages?: Partial<FileMessages> | undefined;\n classNames?: ClassNames;\n}\n\n/** The most of a file read as words: a longer one shows its beginning. */\nconst TEXT_LIMIT = 256 * 1024;\n/** The most rows a table draws. */\nconst ROW_LIMIT = 500;\n\n/**\n * One file, to see and to save, whatever its kind: a bar with its kind, its size (a PDF's pages)\n * and the button that saves it under its name, over the file as it reads. A PDF in the browser's\n * own viewer; a spreadsheet as a grid, its header kept in view, its sheets as tabs at its foot; a\n * Word file as a document at a reading measure; a deck as its slides one under another, their\n * notes under each; Markdown drawn, plain words as written, a source in the mono face, wrapped,\n * never run; a picture whole, a video and a sound in the browser's own players; any other kind\n * says it can't be shown, and is saved. What it can't read alone (a sheet, a document, slides)\n * it draws from `preview`. It fills the height it is given (a dialog's body), and scrolls inside.\n * The addresses it makes for the bytes are let go when it goes.\n */\nexport function FileView(props: FileViewProps) {\n return (\n <KitProvider classNames={props.classNames as KitClassNames}>\n <View {...props} />\n </KitProvider>\n );\n}\n\nfunction View({ blob, name, preview, messages, classNames }: FileViewProps) {\n const words = { ...FILE_MESSAGES, ...messages };\n const extension = extensionOf(name);\n // What is saved is plain bytes, so opening its address shows nothing, it only downloads.\n const saved = useMemo(() => new Blob([blob], { type: \"application/octet-stream\" }), [blob]);\n const save = useObjectUrl(saved);\n const pages = preview?.kind === \"pdf\" ? preview.pages : null;\n\n return (\n <div className={`sc ${classes(classNames, \"sc-file\")}`}>\n <div className={classes(classNames, \"sc-file__bar\")}>\n <FileMark name={name} size={24} />\n <span className={classes(classNames, \"sc-file__meta\")}>\n <span>{extension === \"\" ? words.file : extension.toUpperCase()}</span>\n <span>{words.size(blob.size)}</span>\n {pages !== null && <span>{words.pages(pages)}</span>}\n </span>\n {save !== null && (\n <Button size=\"sm\" icon={DownloadSimpleIcon} href={save} download={baseName(name)}>\n {words.download}\n </Button>\n )}\n </div>\n <div className={classes(classNames, \"sc-file__body\")}>\n {preview === undefined ? (\n <Read blob={blob} name={name} words={words} classNames={classNames} />\n ) : (\n <Previewed\n preview={preview}\n blob={blob}\n name={name}\n words={words}\n classNames={classNames}\n />\n )}\n </div>\n </div>\n );\n}\n\ninterface Drawn {\n name: string;\n words: FileMessages;\n classNames: ClassNames;\n}\n\n/** Under a file shown only in part: the words that say so. */\nfunction Cut({\n shown,\n words,\n classNames,\n}: { shown: boolean; words: FileMessages } & Pick<Drawn, \"classNames\">) {\n return shown ? <p className={classes(classNames, \"sc-file__note\")}>{words.truncated}</p> : null;\n}\n\n/** The file as the API made it to draw, by its kind. */\nfunction Previewed({\n preview,\n blob,\n name,\n words,\n classNames,\n}: Drawn & { preview: FilePreview; blob: Blob }) {\n switch (preview.kind) {\n case \"pdf\":\n return <Pdf blob={blob} name={name} classNames={classNames} />;\n case \"image\":\n return preview.media_type.includes(\"svg\") ? (\n <Svg blob={blob} name={name} classNames={classNames} />\n ) : (\n <Media\n blob={blob}\n type={preview.media_type}\n name={name}\n classNames={classNames}\n kind=\"image\"\n />\n );\n case \"video\":\n case \"audio\":\n return (\n <Media\n blob={blob}\n type={preview.media_type}\n name={name}\n classNames={classNames}\n kind={preview.kind}\n />\n );\n case \"sheet\":\n return (\n <Sheets\n sheets={preview.sheets}\n truncated={preview.truncated}\n words={words}\n classNames={classNames}\n />\n );\n case \"document\":\n return (\n <Document\n html={preview.html}\n truncated={preview.truncated}\n words={words}\n classNames={classNames}\n />\n );\n case \"slides\":\n return (\n <Slides\n slides={preview.slides}\n truncated={preview.truncated}\n words={words}\n classNames={classNames}\n />\n );\n case \"markdown\":\n case \"text\":\n return (\n <Words\n text={preview.text}\n markdown={preview.kind === \"markdown\"}\n truncated={preview.truncated}\n words={words}\n classNames={classNames}\n />\n );\n case \"code\":\n case \"json\":\n return (\n <Source\n text={preview.kind === \"json\" && !preview.truncated ? pretty(preview.text) : preview.text}\n truncated={preview.truncated}\n words={words}\n classNames={classNames}\n />\n );\n case \"unknown\":\n return <None name={name} words={words} classNames={classNames} />;\n }\n}\n\n/** The file as the browser reads its bytes alone, by its name and type. */\nfunction Read({ blob, name, words, classNames }: Drawn & { blob: Blob }) {\n const preview: Preview = previewOf(name, blob.type);\n const svg = extensionOf(name) === \"svg\";\n const reads = preview === \"markdown\" || preview === \"text\" || preview === \"code\";\n const text = useText(blob, reads || preview === \"table\", TEXT_LIMIT);\n const cut = blob.size > TEXT_LIMIT;\n\n if (preview === \"image\") {\n return svg ? (\n <Svg blob={blob} name={name} classNames={classNames} />\n ) : (\n <Media blob={typedFor(blob, name)} name={name} classNames={classNames} kind=\"image\" />\n );\n }\n if (preview === \"pdf\") return <Pdf blob={blob} name={name} classNames={classNames} />;\n if (preview === \"none\") return <None name={name} words={words} classNames={classNames} />;\n if (text === null) return null;\n\n const rows = preview === \"table\" ? tableOf(text) : null;\n if (rows !== null) {\n const [columns = [], ...body] = rows;\n return (\n <Sheets\n sheets={[{ name: baseName(name), columns, rows: body, total_rows: body.length }]}\n truncated={cut}\n words={words}\n classNames={classNames}\n />\n );\n }\n if (preview === \"markdown\" || preview === \"text\") {\n return (\n <Words\n text={text}\n markdown={preview === \"markdown\"}\n truncated={cut}\n words={words}\n classNames={classNames}\n />\n );\n }\n // A source, or a CSV not simple enough for a table: as written, in the mono face.\n return (\n <Source\n text={extensionOf(name) === \"json\" && !cut ? pretty(text) : text}\n truncated={cut}\n words={words}\n classNames={classNames}\n />\n );\n}\n\n/** A PDF in the browser's own viewer. */\nfunction Pdf({ blob, name, classNames }: { blob: Blob; name: string; classNames: ClassNames }) {\n const typed = useMemo(() => typedFor(blob, name), [blob, name]);\n const view = useObjectUrl(typed);\n return (\n view !== null && (\n <iframe src={view} title={baseName(name)} className={classes(classNames, \"sc-file__frame\")} />\n )\n );\n}\n\n/**\n * An SVG, from its words as a data address: one of the page's own (a blob's) would run its\n * scripts as the page if it were opened apart.\n */\nfunction Svg({ blob, name, classNames }: { blob: Blob; name: string; classNames: ClassNames }) {\n const text = useText(blob, true, Infinity);\n return (\n text !== null && (\n <div className={classes(classNames, \"sc-file__image\")}>\n <img\n src={`data:image/svg+xml;charset=utf-8,${encodeURIComponent(text)}`}\n alt={baseName(name)}\n />\n </div>\n )\n );\n}\n\n/** A picture whole, a video or a sound in the browser's own player, from its bytes typed. */\nfunction Media({\n blob,\n type,\n name,\n kind,\n classNames,\n}: {\n blob: Blob;\n /** The type it plays as; none: the one the bytes came with. */\n type?: string | undefined;\n name: string;\n kind: \"image\" | \"video\" | \"audio\";\n classNames: ClassNames;\n}) {\n const typed = useMemo(\n () => (type === undefined || blob.type === type ? blob : new Blob([blob], { type })),\n [blob, type],\n );\n const src = useObjectUrl(typed);\n if (src === null) return null;\n if (kind === \"image\") {\n return (\n <div className={classes(classNames, \"sc-file__image\")}>\n <img src={src} alt={baseName(name)} />\n </div>\n );\n }\n return (\n <div className={classes(classNames, \"sc-file__media\")} data-kind={kind}>\n {kind === \"video\" ? (\n <video src={src} controls playsInline preload=\"metadata\" aria-label={baseName(name)} />\n ) : (\n <>\n <FileMark name={name} size={44} />\n <AudioPlayer src={src} label={baseName(name)} />\n </>\n )}\n </div>\n );\n}\n\n/**\n * A spreadsheet: one sheet at a time as a grid, its columns over it kept in view as it scrolls;\n * its sheets as tabs at its foot, as a spreadsheet has them. Under a\n * sheet shown in part, how many of its rows are.\n */\nfunction Sheets({\n sheets,\n truncated,\n words,\n classNames,\n}: {\n sheets: readonly PreviewSheet[];\n truncated: boolean;\n} & Omit<Drawn, \"name\">) {\n const [at, setAt] = useState(0);\n const sheet = sheets[at] ?? sheets[0];\n if (sheet === undefined) return <None name=\"\" words={words} classNames={classNames} />;\n const rows = sheet.rows.slice(0, ROW_LIMIT);\n const width = Math.max(sheet.columns?.length ?? 0, ...rows.map((row) => row.length));\n const several = sheets.length > 1;\n return (\n <div className={classes(classNames, \"sc-file__sheet\")}>\n {/* Another sheet opens at its top-left corner. */}\n <div\n key={at}\n role={several ? \"tabpanel\" : undefined}\n className={classes(classNames, \"sc-file__table\")}\n >\n {sheet.columns === null ? (\n <p className={classes(classNames, \"sc-file__note\")}>{words.emptySheet}</p>\n ) : (\n <table>\n <thead>\n <tr>\n {pad(sheet.columns, width).map((cell, index) => (\n <th key={index} scope=\"col\">\n {cell}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.map((row, index) => (\n <tr key={index}>\n {pad(row, width).map((cell, column) => (\n <td key={column} title={cell.length > 36 ? cell : undefined}>\n {cell}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n )}\n {sheet.total_rows > rows.length ? (\n <p className={classes(classNames, \"sc-file__note\")}>\n {words.rows(rows.length, sheet.total_rows)}\n </p>\n ) : (\n <Cut shown={truncated} words={words} classNames={classNames} />\n )}\n </div>\n {several && (\n <div\n role=\"tablist\"\n aria-label={words.sheets}\n className={classes(classNames, \"sc-file__tabs\")}\n >\n {sheets.map((each, index) => (\n <button\n key={index}\n type=\"button\"\n role=\"tab\"\n aria-selected={index === at}\n onClick={() => {\n setAt(index);\n }}\n className={classes(classNames, \"sc-file__tab\")}\n >\n {each.name}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/** A row as wide as the widest, its missing cells empty. */\nconst pad = (cells: readonly string[], width: number): string[] =>\n cells.length >= width ? [...cells] : [...cells, ...Array<string>(width - cells.length).fill(\"\")];\n\n/**\n * A Word file as its HTML at a reading measure: headings, paragraphs, lists, tables, pictures,\n * kept to what a viewer draws (`cleanDocument`), again here after the API.\n */\nfunction Document({\n html,\n truncated,\n words,\n classNames,\n}: { html: string; truncated: boolean } & Omit<Drawn, \"name\">) {\n const clean = useMemo(() => cleanDocument(html), [html]);\n return (\n <div className={classes(classNames, \"sc-file__text\")}>\n <div\n className={classes(classNames, \"sc-file__document\")}\n // Kept to the API's allow-list, by the API and again by `cleanDocument`.\n dangerouslySetInnerHTML={{ __html: clean }}\n />\n <Cut shown={truncated} words={words} classNames={classNames} />\n </div>\n );\n}\n\n/** A deck: its slides one under another, each a card with its number, its words, its notes. */\nfunction Slides({\n slides,\n truncated,\n words,\n classNames,\n}: { slides: readonly PreviewSlide[]; truncated: boolean } & Omit<Drawn, \"name\">) {\n return (\n <>\n <ol className={classes(classNames, \"sc-file__slides\")}>\n {slides.map((slide, index) => (\n <li key={index} className={classes(classNames, \"sc-file__slide\")}>\n <span>{words.slide(index + 1)}</span>\n {slide.title !== null && slide.title !== \"\" && <h3>{slide.title}</h3>}\n {slide.text !== \"\" && <p>{slide.text}</p>}\n {slide.notes !== null && slide.notes !== \"\" && (\n <div className={classes(classNames, \"sc-file__notes\")}>\n <span>{words.notes}</span>\n <p>{slide.notes}</p>\n </div>\n )}\n </li>\n ))}\n </ol>\n <Cut shown={truncated} words={words} classNames={classNames} />\n </>\n );\n}\n\n/** Words at a reading measure: Markdown drawn, plain words as written. */\nfunction Words({\n text,\n markdown,\n truncated,\n words,\n classNames,\n}: { text: string; markdown: boolean; truncated: boolean } & Omit<Drawn, \"name\">) {\n return (\n <div className={classes(classNames, \"sc-file__text\")}>\n {markdown ? (\n <Markdown text={text} />\n ) : (\n <p className={classes(classNames, \"sc-file__plain\")}>{text}</p>\n )}\n <Cut shown={truncated} words={words} classNames={classNames} />\n </div>\n );\n}\n\n/** A source as written, in the mono face, its long lines wrapped; never run. */\nfunction Source({\n text,\n truncated,\n words,\n classNames,\n}: { text: string; truncated: boolean } & Omit<Drawn, \"name\">) {\n return (\n <>\n <pre className={classes(classNames, \"sc-file__code\")}>\n <code>{text}</code>\n </pre>\n <Cut shown={truncated} words={words} classNames={classNames} />\n </>\n );\n}\n\n/** A kind that can't be shown: its mark, the line that says so, and what to do instead. */\nfunction None({ name, words, classNames }: Drawn): ReactNode {\n return (\n <div className={classes(classNames, \"sc-file__none\")}>\n <FileMark name={name} size={44} />\n <p>\n <strong>{words.noPreview}</strong>\n <span>{words.noPreviewHint}</span>\n </p>\n </div>\n );\n}\n\n/** The first `limit` bytes of a blob as words, once read; null while reading, or when not wanted. */\nfunction useText(blob: Blob, wanted: boolean, limit: number): string | null {\n const [text, setText] = useState<string | null>(null);\n useEffect(() => {\n if (!wanted) return;\n let live = true;\n void (blob.size > limit ? blob.slice(0, limit) : blob).text().then((read) => {\n if (live) setText(read);\n });\n return () => {\n live = false;\n setText(null);\n };\n }, [blob, wanted, limit]);\n return text;\n}\n\n/** An address for a blob while it is shown, let go when it changes or goes. */\nfunction useObjectUrl(blob: Blob | null): string | null {\n const [url, setUrl] = useState<string | null>(null);\n useEffect(() => {\n if (blob === null) return;\n const made = URL.createObjectURL(blob);\n setUrl(made);\n return () => {\n URL.revokeObjectURL(made);\n setUrl(null);\n };\n }, [blob]);\n return url;\n}\n"],"mappings":";;;;;;;;;;;;AAkDA,MAAa,gBAA8B;CACzC,UAAU;CACV,WAAW;CACX,eAAe;CACf,WAAW;CACX,MAAM;CACN,OAAO,UAAU,WAAW,KAAK;CACjC,QAAQ,UAAW,UAAU,IAAI,WAAW,GAAG,MAAM;CACrD,QAAQ;CACR,OAAO,OAAO,UAAU,aAAa,MAAM,MAAM,MAAM;CACvD,YAAY;CACZ,QAAQ,WAAW,SAAS;CAC5B,OAAO;AACT;;AA2CA,MAAM,aAAa;;AAEnB,MAAM,YAAY;;;;;;;;;;;;AAalB,SAAgB,SAAS,OAAsB;CAC7C,OACE,oBAAC,aAAD;EAAa,YAAY,MAAM;EAC7B,UAAA,oBAAC,MAAD,EAAM,GAAI,MAAQ,CAAA;CACP,CAAA;AAEjB;AAEA,SAAS,KAAK,EAAE,MAAM,MAAM,SAAS,UAAU,cAA6B;CAC1E,MAAM,QAAQ;EAAE,GAAG;EAAe,GAAG;CAAS;CAC9C,MAAM,YAAY,YAAY,IAAI;CAGlC,MAAM,OAAO,aADC,cAAc,IAAI,KAAK,CAAC,IAAI,GAAG,EAAE,MAAM,2BAA2B,CAAC,GAAG,CAAC,IAAI,CAC3D,CAAC;CAC/B,MAAM,QAAQ,SAAS,SAAS,QAAQ,QAAQ,QAAQ;CAExD,OACE,qBAAC,OAAD;EAAK,WAAW,MAAM,QAAQ,YAAY,SAAS;EAAnD,UAAA,CACE,qBAAC,OAAD;GAAK,WAAW,QAAQ,YAAY,cAAc;GAAlD,UAAA;IACE,oBAAC,UAAD;KAAgB;KAAM,MAAM;IAAK,CAAA;IACjC,qBAAC,QAAD;KAAM,WAAW,QAAQ,YAAY,eAAe;KAApD,UAAA;MACE,oBAAC,QAAD,EAAA,UAAO,cAAc,KAAK,MAAM,OAAO,UAAU,YAAY,EAAQ,CAAA;MACrE,oBAAC,QAAD,EAAA,UAAO,MAAM,KAAK,KAAK,IAAI,EAAQ,CAAA;MAClC,UAAU,QAAQ,oBAAC,QAAD,EAAA,UAAO,MAAM,MAAM,KAAK,EAAQ,CAAA;KAC/C;;IACL,SAAS,QACR,oBAAC,QAAD;KAAQ,MAAK;KAAK,MAAM;KAAoB,MAAM;KAAM,UAAU,SAAS,IAAI;KAC5E,UAAA,MAAM;IACD,CAAA;GAEP;EACL,CAAA,GAAA,oBAAC,OAAD;GAAK,WAAW,QAAQ,YAAY,eAAe;GAChD,UAAA,YAAY,KAAA,IACX,oBAAC,MAAD;IAAY;IAAY;IAAa;IAAmB;GAAa,CAAA,IAErE,oBAAC,WAAD;IACW;IACH;IACA;IACC;IACK;GACb,CAAA;EAEA,CAAA,CACF;;AAET;;AASA,SAAS,IAAI,EACX,OACA,OACA,cACsE;CACtE,OAAO,QAAQ,oBAAC,KAAD;EAAG,WAAW,QAAQ,YAAY,eAAe;EAAI,UAAA,MAAM;CAAa,CAAA,IAAI;AAC7F;;AAGA,SAAS,UAAU,EACjB,SACA,MACA,MACA,OACA,cAC+C;CAC/C,QAAQ,QAAQ,MAAhB;EACE,KAAK,OACH,OAAO,oBAAC,KAAD;GAAW;GAAY;GAAkB;EAAa,CAAA;EAC/D,KAAK,SACH,OAAO,QAAQ,WAAW,SAAS,KAAK,IACtC,oBAAC,KAAD;GAAW;GAAY;GAAkB;EAAa,CAAA,IAEtD,oBAAC,OAAD;GACQ;GACN,MAAM,QAAQ;GACR;GACM;GACZ,MAAK;EACN,CAAA;EAEL,KAAK;EACL,KAAK,SACH,OACE,oBAAC,OAAD;GACQ;GACN,MAAM,QAAQ;GACR;GACM;GACZ,MAAM,QAAQ;EACf,CAAA;EAEL,KAAK,SACH,OACE,oBAAC,QAAD;GACE,QAAQ,QAAQ;GAChB,WAAW,QAAQ;GACZ;GACK;EACb,CAAA;EAEL,KAAK,YACH,OACE,oBAAC,UAAD;GACE,MAAM,QAAQ;GACd,WAAW,QAAQ;GACZ;GACK;EACb,CAAA;EAEL,KAAK,UACH,OACE,oBAAC,QAAD;GACE,QAAQ,QAAQ;GAChB,WAAW,QAAQ;GACZ;GACK;EACb,CAAA;EAEL,KAAK;EACL,KAAK,QACH,OACE,oBAAC,OAAD;GACE,MAAM,QAAQ;GACd,UAAU,QAAQ,SAAS;GAC3B,WAAW,QAAQ;GACZ;GACK;EACb,CAAA;EAEL,KAAK;EACL,KAAK,QACH,OACE,oBAAC,QAAD;GACE,MAAM,QAAQ,SAAS,UAAU,CAAC,QAAQ,YAAY,OAAO,QAAQ,IAAI,IAAI,QAAQ;GACrF,WAAW,QAAQ;GACZ;GACK;EACb,CAAA;EAEL,KAAK,WACH,OAAO,oBAAC,MAAD;GAAY;GAAa;GAAmB;EAAa,CAAA;CACpE;AACF;;AAGA,SAAS,KAAK,EAAE,MAAM,MAAM,OAAO,cAAsC;CACvE,MAAM,UAAmB,UAAU,MAAM,KAAK,IAAI;CAClD,MAAM,MAAM,YAAY,IAAI,MAAM;CAElC,MAAM,OAAO,QAAQ,MADP,YAAY,cAAc,YAAY,UAAU,YAAY,UACtC,YAAY,SAAS,UAAU;CACnE,MAAM,MAAM,KAAK,OAAO;CAExB,IAAI,YAAY,SACd,OAAO,MACL,oBAAC,KAAD;EAAW;EAAY;EAAkB;CAAa,CAAA,IAEtD,oBAAC,OAAD;EAAO,MAAM,SAAS,MAAM,IAAI;EAAS;EAAkB;EAAY,MAAK;CAAS,CAAA;CAGzF,IAAI,YAAY,OAAO,OAAO,oBAAC,KAAD;EAAW;EAAY;EAAkB;CAAa,CAAA;CACpF,IAAI,YAAY,QAAQ,OAAO,oBAAC,MAAD;EAAY;EAAa;EAAmB;CAAa,CAAA;CACxF,IAAI,SAAS,MAAM,OAAO;CAE1B,MAAM,OAAO,YAAY,UAAU,QAAQ,IAAI,IAAI;CACnD,IAAI,SAAS,MAAM;EACjB,MAAM,CAAC,UAAU,CAAC,GAAG,GAAG,QAAQ;EAChC,OACE,oBAAC,QAAD;GACE,QAAQ,CAAC;IAAE,MAAM,SAAS,IAAI;IAAG;IAAS,MAAM;IAAM,YAAY,KAAK;GAAO,CAAC;GAC/E,WAAW;GACJ;GACK;EACb,CAAA;CAEL;CACA,IAAI,YAAY,cAAc,YAAY,QACxC,OACE,oBAAC,OAAD;EACQ;EACN,UAAU,YAAY;EACtB,WAAW;EACJ;EACK;CACb,CAAA;CAIL,OACE,oBAAC,QAAD;EACE,MAAM,YAAY,IAAI,MAAM,UAAU,CAAC,MAAM,OAAO,IAAI,IAAI;EAC5D,WAAW;EACJ;EACK;CACb,CAAA;AAEL;;AAGA,SAAS,IAAI,EAAE,MAAM,MAAM,cAAoE;CAE7F,MAAM,OAAO,aADC,cAAc,SAAS,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAC/B,CAAC;CAC/B,OACE,SAAS,QACP,oBAAC,UAAD;EAAQ,KAAK;EAAM,OAAO,SAAS,IAAI;EAAG,WAAW,QAAQ,YAAY,gBAAgB;CAAI,CAAA;AAGnG;;;;;AAMA,SAAS,IAAI,EAAE,MAAM,MAAM,cAAoE;CAC7F,MAAM,OAAO,QAAQ,MAAM,MAAM,QAAQ;CACzC,OACE,SAAS,QACP,oBAAC,OAAD;EAAK,WAAW,QAAQ,YAAY,gBAAgB;EAClD,UAAA,oBAAC,OAAD;GACE,KAAK,oCAAoC,mBAAmB,IAAI;GAChE,KAAK,SAAS,IAAI;EACnB,CAAA;CACE,CAAA;AAGX;;AAGA,SAAS,MAAM,EACb,MACA,MACA,MACA,MACA,cAQC;CAKD,MAAM,MAAM,aAJE,cACL,SAAS,KAAA,KAAa,KAAK,SAAS,OAAO,OAAO,IAAI,KAAK,CAAC,IAAI,GAAG,EAAE,KAAK,CAAC,GAClF,CAAC,MAAM,IAAI,CAEgB,CAAC;CAC9B,IAAI,QAAQ,MAAM,OAAO;CACzB,IAAI,SAAS,SACX,OACE,oBAAC,OAAD;EAAK,WAAW,QAAQ,YAAY,gBAAgB;EAClD,UAAA,oBAAC,OAAD;GAAU;GAAK,KAAK,SAAS,IAAI;EAAI,CAAA;CAClC,CAAA;CAGT,OACE,oBAAC,OAAD;EAAK,WAAW,QAAQ,YAAY,gBAAgB;EAAG,aAAW;EAC/D,UAAA,SAAS,UACR,oBAAC,SAAD;GAAY;GAAK,UAAA;GAAS,aAAA;GAAY,SAAQ;GAAW,cAAY,SAAS,IAAI;EAAI,CAAA,IAEtF,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,UAAD;GAAgB;GAAM,MAAM;EAAK,CAAA,GACjC,oBAAC,aAAD;GAAkB;GAAK,OAAO,SAAS,IAAI;EAAI,CAAA,CAC/C,EAAA,CAAA;CAED,CAAA;AAET;;;;;;AAOA,SAAS,OAAO,EACd,QACA,WACA,OACA,cAIuB;CACvB,MAAM,CAAC,IAAI,SAAS,SAAS,CAAC;CAC9B,MAAM,QAAQ,OAAO,OAAO,OAAO;CACnC,IAAI,UAAU,KAAA,GAAW,OAAO,oBAAC,MAAD;EAAM,MAAK;EAAU;EAAmB;CAAa,CAAA;CACrF,MAAM,OAAO,MAAM,KAAK,MAAM,GAAG,SAAS;CAC1C,MAAM,QAAQ,KAAK,IAAI,MAAM,SAAS,UAAU,GAAG,GAAG,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC;CACnF,MAAM,UAAU,OAAO,SAAS;CAChC,OACE,qBAAC,OAAD;EAAK,WAAW,QAAQ,YAAY,gBAAgB;EAApD,UAAA,CAEE,qBAAC,OAAD;GAEE,MAAM,UAAU,aAAa,KAAA;GAC7B,WAAW,QAAQ,YAAY,gBAAgB;GAHjD,UAAA,CAKG,MAAM,YAAY,OACjB,oBAAC,KAAD;IAAG,WAAW,QAAQ,YAAY,eAAe;IAAI,UAAA,MAAM;GAAc,CAAA,IAEzE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,SAAD,EAAA,UACE,oBAAC,MAAD,EAAA,UACG,IAAI,MAAM,SAAS,KAAK,CAAC,CAAC,KAAK,MAAM,UACpC,oBAAC,MAAD;IAAgB,OAAM;IACnB,UAAA;GACC,GAFK,KAEL,CACL,EACC,CAAA,EACC,CAAA,GACP,oBAAC,SAAD,EAAA,UACG,KAAK,KAAK,KAAK,UACd,oBAAC,MAAD,EAAA,UACG,IAAI,KAAK,KAAK,CAAC,CAAC,KAAK,MAAM,WAC1B,oBAAC,MAAD;IAAiB,OAAO,KAAK,SAAS,KAAK,OAAO,KAAA;IAC/C,UAAA;GACC,GAFK,MAEL,CACL,EACC,GANK,KAML,CACL,EACI,CAAA,CACF,EAAA,CAAA,GAER,MAAM,aAAa,KAAK,SACvB,oBAAC,KAAD;IAAG,WAAW,QAAQ,YAAY,eAAe;IAC9C,UAAA,MAAM,KAAK,KAAK,QAAQ,MAAM,UAAU;GACxC,CAAA,IAEH,oBAAC,KAAD;IAAK,OAAO;IAAkB;IAAmB;GAAa,CAAA,CAE7D;EArCE,GAAA,EAqCF,GACJ,WACC,oBAAC,OAAD;GACE,MAAK;GACL,cAAY,MAAM;GAClB,WAAW,QAAQ,YAAY,eAAe;GAE7C,UAAA,OAAO,KAAK,MAAM,UACjB,oBAAC,UAAD;IAEE,MAAK;IACL,MAAK;IACL,iBAAe,UAAU;IACzB,eAAe;KACb,MAAM,KAAK;IACb;IACA,WAAW,QAAQ,YAAY,cAAc;IAE5C,UAAA,KAAK;GACA,GAVD,KAUC,CACT;EACE,CAAA,CAEJ;;AAET;;AAGA,MAAM,OAAO,OAA0B,UACrC,MAAM,UAAU,QAAQ,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,OAAO,GAAG,MAAc,QAAQ,MAAM,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;;;;;AAMjG,SAAS,SAAS,EAChB,MACA,WACA,OACA,cAC6D;CAC7D,MAAM,QAAQ,cAAc,cAAc,IAAI,GAAG,CAAC,IAAI,CAAC;CACvD,OACE,qBAAC,OAAD;EAAK,WAAW,QAAQ,YAAY,eAAe;EAAnD,UAAA,CACE,oBAAC,OAAD;GACE,WAAW,QAAQ,YAAY,mBAAmB;GAElD,yBAAyB,EAAE,QAAQ,MAAM;EAC1C,CAAA,GACD,oBAAC,KAAD;GAAK,OAAO;GAAkB;GAAmB;EAAa,CAAA,CAC3D;;AAET;;AAGA,SAAS,OAAO,EACd,QACA,WACA,OACA,cACgF;CAChF,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,MAAD;EAAI,WAAW,QAAQ,YAAY,iBAAiB;EACjD,UAAA,OAAO,KAAK,OAAO,UAClB,qBAAC,MAAD;GAAgB,WAAW,QAAQ,YAAY,gBAAgB;GAA/D,UAAA;IACE,oBAAC,QAAD,EAAA,UAAO,MAAM,MAAM,QAAQ,CAAC,EAAQ,CAAA;IACnC,MAAM,UAAU,QAAQ,MAAM,UAAU,MAAM,oBAAC,MAAD,EAAA,UAAK,MAAM,MAAU,CAAA;IACnE,MAAM,SAAS,MAAM,oBAAC,KAAD,EAAA,UAAI,MAAM,KAAQ,CAAA;IACvC,MAAM,UAAU,QAAQ,MAAM,UAAU,MACvC,qBAAC,OAAD;KAAK,WAAW,QAAQ,YAAY,gBAAgB;KAApD,UAAA,CACE,oBAAC,QAAD,EAAA,UAAO,MAAM,MAAY,CAAA,GACzB,oBAAC,KAAD,EAAA,UAAI,MAAM,MAAS,CAAA,CAChB;;GAEL;EAVK,GAAA,KAUL,CACL;CACC,CAAA,GACJ,oBAAC,KAAD;EAAK,OAAO;EAAkB;EAAmB;CAAa,CAAA,CAC9D,EAAA,CAAA;AAEN;;AAGA,SAAS,MAAM,EACb,MACA,UACA,WACA,OACA,cACgF;CAChF,OACE,qBAAC,OAAD;EAAK,WAAW,QAAQ,YAAY,eAAe;EAAnD,UAAA,CACG,WACC,oBAAC,UAAD,EAAgB,KAAO,CAAA,IAEvB,oBAAC,KAAD;GAAG,WAAW,QAAQ,YAAY,gBAAgB;GAAI,UAAA;EAAQ,CAAA,GAEhE,oBAAC,KAAD;GAAK,OAAO;GAAkB;GAAmB;EAAa,CAAA,CAC3D;;AAET;;AAGA,SAAS,OAAO,EACd,MACA,WACA,OACA,cAC6D;CAC7D,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,OAAD;EAAK,WAAW,QAAQ,YAAY,eAAe;EACjD,UAAA,oBAAC,QAAD,EAAA,UAAO,KAAW,CAAA;CACf,CAAA,GACL,oBAAC,KAAD;EAAK,OAAO;EAAkB;EAAmB;CAAa,CAAA,CAC9D,EAAA,CAAA;AAEN;;AAGA,SAAS,KAAK,EAAE,MAAM,OAAO,cAAgC;CAC3D,OACE,qBAAC,OAAD;EAAK,WAAW,QAAQ,YAAY,eAAe;EAAnD,UAAA,CACE,oBAAC,UAAD;GAAgB;GAAM,MAAM;EAAK,CAAA,GACjC,qBAAC,KAAD,EAAA,UAAA,CACE,oBAAC,UAAD,EAAA,UAAS,MAAM,UAAkB,CAAA,GACjC,oBAAC,QAAD,EAAA,UAAO,MAAM,cAAoB,CAAA,CAChC,EAAA,CAAA,CACA;;AAET;;AAGA,SAAS,QAAQ,MAAY,QAAiB,OAA8B;CAC1E,MAAM,CAAC,MAAM,WAAW,SAAwB,IAAI;CACpD,gBAAgB;EACd,IAAI,CAAC,QAAQ;EACb,IAAI,OAAO;EACX,CAAM,KAAK,OAAO,QAAQ,KAAK,MAAM,GAAG,KAAK,IAAI,KAAA,CAAM,KAAK,CAAC,CAAC,MAAM,SAAS;GAC3E,IAAI,MAAM,QAAQ,IAAI;EACxB,CAAC;EACD,aAAa;GACX,OAAO;GACP,QAAQ,IAAI;EACd;CACF,GAAG;EAAC;EAAM;EAAQ;CAAK,CAAC;CACxB,OAAO;AACT;;AAGA,SAAS,aAAa,MAAkC;CACtD,MAAM,CAAC,KAAK,UAAU,SAAwB,IAAI;CAClD,gBAAgB;EACd,IAAI,SAAS,MAAM;EACnB,MAAM,OAAO,IAAI,gBAAgB,IAAI;EACrC,OAAO,IAAI;EACX,aAAa;GACX,IAAI,gBAAgB,IAAI;GACxB,OAAO,IAAI;EACb;CACF,GAAG,CAAC,IAAI,CAAC;CACT,OAAO;AACT"}
@@ -0,0 +1,13 @@
1
+ //#region src/Modes.d.ts
2
+ /** How the person talks to the agent in its space: writing, or on a call. */
3
+ export type SpaceMode = "text" | "voice";
4
+ /** The modes' words: the group's name for screen readers, and each mode's. */
5
+ export interface ModeMessages {
6
+ label: string;
7
+ text: string;
8
+ voice: string;
9
+ }
10
+ /** The modes' parts, by the class each carries. */
11
+ export type ModePart = "sc-space__modes" | "sc-space__mode" | "sc-space__mode--text" | "sc-space__mode--voice";
12
+ //#endregion
13
+ //# sourceMappingURL=Modes.d.ts.map
package/dist/Modes.js ADDED
@@ -0,0 +1,75 @@
1
+ import { classes } from "./classes.js";
2
+ import { useEffect, useRef } from "react";
3
+ import { ChatCircleTextIcon, WaveformIcon } from "@phosphor-icons/react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/Modes.tsx
6
+ const MODES = [{
7
+ mode: "text",
8
+ glyph: ChatCircleTextIcon
9
+ }, {
10
+ mode: "voice",
11
+ glyph: WaveformIcon
12
+ }];
13
+ /** Where an arrow key moves among the modes, by how many; Home and End go to either end. */
14
+ const STEPS = {
15
+ ArrowRight: 1,
16
+ ArrowDown: 1,
17
+ ArrowLeft: -1,
18
+ ArrowUp: -1
19
+ };
20
+ /**
21
+ * The two ways to talk, side by side in one small segmented control: a radio group, the mode on
22
+ * reachable by Tab and the arrows moving to the other and choosing it (Home and End too), each
23
+ * named by its glyph and its word. `focus` takes the keyboard as it is drawn, for a control drawn
24
+ * anew after a switch made from it (the chat's and the call's are two).
25
+ */
26
+ function Modes({ mode, onChange, words, classNames, focus = false }) {
27
+ const buttons = useRef([]);
28
+ const on = MODES.findIndex((each) => each.mode === mode);
29
+ useEffect(() => {
30
+ if (focus) buttons.current[on]?.focus();
31
+ }, []);
32
+ const onKeyDown = (event, index) => {
33
+ const step = STEPS[event.key];
34
+ const to = event.key === "Home" ? 0 : event.key === "End" ? MODES.length - 1 : step === void 0 ? null : (index + step + MODES.length) % MODES.length;
35
+ if (to === null) return;
36
+ event.preventDefault();
37
+ buttons.current[to]?.focus();
38
+ const next = MODES[to];
39
+ if (next && next.mode !== mode) onChange(next.mode);
40
+ };
41
+ return /* @__PURE__ */ jsx("div", {
42
+ role: "radiogroup",
43
+ "aria-label": words.label,
44
+ part: "modes",
45
+ className: classes(classNames, "sc-space__modes"),
46
+ children: MODES.map(({ mode: each, glyph: Glyph }, index) => {
47
+ const chosen = index === on;
48
+ return /* @__PURE__ */ jsxs("button", {
49
+ ref: (button) => {
50
+ buttons.current[index] = button;
51
+ },
52
+ type: "button",
53
+ role: "radio",
54
+ "aria-checked": chosen,
55
+ tabIndex: chosen ? 0 : -1,
56
+ onClick: () => {
57
+ if (!chosen) onChange(each);
58
+ },
59
+ onKeyDown: (event) => {
60
+ onKeyDown(event, index);
61
+ },
62
+ part: chosen ? `mode mode-${each} mode-selected` : `mode mode-${each}`,
63
+ className: classes(classNames, "sc-space__mode", `sc-space__mode--${each}`),
64
+ children: [/* @__PURE__ */ jsx(Glyph, {
65
+ "aria-hidden": true,
66
+ weight: chosen ? "fill" : "regular"
67
+ }), /* @__PURE__ */ jsx("span", { children: words[each] })]
68
+ }, each);
69
+ })
70
+ });
71
+ }
72
+ //#endregion
73
+ export { Modes };
74
+
75
+ //# sourceMappingURL=Modes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Modes.js","names":[],"sources":["../src/Modes.tsx"],"sourcesContent":["import { ChatCircleTextIcon, WaveformIcon, type Icon } from \"@phosphor-icons/react\";\nimport { useEffect, useRef, type KeyboardEvent } from \"react\";\n\nimport { classes } from \"./classes\";\n\n/** How the person talks to the agent in its space: writing, or on a call. */\nexport type SpaceMode = \"text\" | \"voice\";\n\n/** The modes' words: the group's name for screen readers, and each mode's. */\nexport interface ModeMessages {\n label: string;\n text: string;\n voice: string;\n}\n\n/** The modes' parts, by the class each carries. */\nexport type ModePart =\n \"sc-space__modes\" | \"sc-space__mode\" | \"sc-space__mode--text\" | \"sc-space__mode--voice\";\n\nconst MODES: readonly { mode: SpaceMode; glyph: Icon }[] = [\n { mode: \"text\", glyph: ChatCircleTextIcon },\n { mode: \"voice\", glyph: WaveformIcon },\n];\n\n/** Where an arrow key moves among the modes, by how many; Home and End go to either end. */\nconst STEPS: Readonly<Record<string, number>> = {\n ArrowRight: 1,\n ArrowDown: 1,\n ArrowLeft: -1,\n ArrowUp: -1,\n};\n\n/**\n * The two ways to talk, side by side in one small segmented control: a radio group, the mode on\n * reachable by Tab and the arrows moving to the other and choosing it (Home and End too), each\n * named by its glyph and its word. `focus` takes the keyboard as it is drawn, for a control drawn\n * anew after a switch made from it (the chat's and the call's are two).\n */\nexport function Modes({\n mode,\n onChange,\n words,\n classNames,\n focus = false,\n}: {\n mode: SpaceMode;\n onChange: (mode: SpaceMode) => void;\n words: ModeMessages;\n classNames?: Partial<Record<ModePart, string>> | undefined;\n focus?: boolean | undefined;\n}) {\n const buttons = useRef<(HTMLButtonElement | null)[]>([]);\n const on = MODES.findIndex((each) => each.mode === mode);\n\n useEffect(() => {\n if (focus) buttons.current[on]?.focus();\n // Only as it is drawn: a mode chosen later keeps the focus where the keys put it.\n }, []);\n\n const onKeyDown = (event: KeyboardEvent<HTMLButtonElement>, index: number) => {\n const step = STEPS[event.key];\n const to =\n event.key === \"Home\"\n ? 0\n : event.key === \"End\"\n ? MODES.length - 1\n : step === undefined\n ? null\n : (index + step + MODES.length) % MODES.length;\n if (to === null) return;\n event.preventDefault();\n buttons.current[to]?.focus();\n const next = MODES[to];\n if (next && next.mode !== mode) onChange(next.mode);\n };\n\n return (\n <div\n role=\"radiogroup\"\n aria-label={words.label}\n part=\"modes\"\n className={classes(classNames, \"sc-space__modes\")}\n >\n {MODES.map(({ mode: each, glyph: Glyph }, index) => {\n const chosen = index === on;\n return (\n <button\n key={each}\n ref={(button) => {\n buttons.current[index] = button;\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={chosen}\n tabIndex={chosen ? 0 : -1}\n onClick={() => {\n if (!chosen) onChange(each);\n }}\n onKeyDown={(event) => {\n onKeyDown(event, index);\n }}\n part={chosen ? `mode mode-${each} mode-selected` : `mode mode-${each}`}\n className={classes(classNames, \"sc-space__mode\", `sc-space__mode--${each}`)}\n >\n <Glyph aria-hidden weight={chosen ? \"fill\" : \"regular\"} />\n <span>{words[each]}</span>\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;AAmBA,MAAM,QAAqD,CACzD;CAAE,MAAM;CAAQ,OAAO;AAAmB,GAC1C;CAAE,MAAM;CAAS,OAAO;AAAa,CACvC;;AAGA,MAAM,QAA0C;CAC9C,YAAY;CACZ,WAAW;CACX,WAAW;CACX,SAAS;AACX;;;;;;;AAQA,SAAgB,MAAM,EACpB,MACA,UACA,OACA,YACA,QAAQ,SAOP;CACD,MAAM,UAAU,OAAqC,CAAC,CAAC;CACvD,MAAM,KAAK,MAAM,WAAW,SAAS,KAAK,SAAS,IAAI;CAEvD,gBAAgB;EACd,IAAI,OAAO,QAAQ,QAAQ,GAAG,EAAE,MAAM;CAExC,GAAG,CAAC,CAAC;CAEL,MAAM,aAAa,OAAyC,UAAkB;EAC5E,MAAM,OAAO,MAAM,MAAM;EACzB,MAAM,KACJ,MAAM,QAAQ,SACV,IACA,MAAM,QAAQ,QACZ,MAAM,SAAS,IACf,SAAS,KAAA,IACP,QACC,QAAQ,OAAO,MAAM,UAAU,MAAM;EAChD,IAAI,OAAO,MAAM;EACjB,MAAM,eAAe;EACrB,QAAQ,QAAQ,GAAG,EAAE,MAAM;EAC3B,MAAM,OAAO,MAAM;EACnB,IAAI,QAAQ,KAAK,SAAS,MAAM,SAAS,KAAK,IAAI;CACpD;CAEA,OACE,oBAAC,OAAD;EACE,MAAK;EACL,cAAY,MAAM;EAClB,MAAK;EACL,WAAW,QAAQ,YAAY,iBAAiB;EAE/C,UAAA,MAAM,KAAK,EAAE,MAAM,MAAM,OAAO,SAAS,UAAU;GAClD,MAAM,SAAS,UAAU;GACzB,OACE,qBAAC,UAAD;IAEE,MAAM,WAAW;KACf,QAAQ,QAAQ,SAAS;IAC3B;IACA,MAAK;IACL,MAAK;IACL,gBAAc;IACd,UAAU,SAAS,IAAI;IACvB,eAAe;KACb,IAAI,CAAC,QAAQ,SAAS,IAAI;IAC5B;IACA,YAAY,UAAU;KACpB,UAAU,OAAO,KAAK;IACxB;IACA,MAAM,SAAS,aAAa,KAAK,kBAAkB,aAAa;IAChE,WAAW,QAAQ,YAAY,kBAAkB,mBAAmB,MAAM;IAhB5E,UAAA,CAkBE,oBAAC,OAAD;KAAO,eAAA;KAAY,QAAQ,SAAS,SAAS;IAAY,CAAA,GACzD,oBAAC,QAAD,EAAA,UAAO,MAAM,MAAY,CAAA,CACnB;GAnBD,GAAA,IAmBC;EAEZ,CAAC;CACE,CAAA;AAET"}