@parallelworks/ui 0.40.1 → 0.42.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 (289) hide show
  1. package/README.md +25 -0
  2. package/dist/ai/adapter/memoryStore.js +7 -0
  3. package/dist/ai/adapter/mock/mockAdapter.js +52 -17
  4. package/dist/ai/adapter/openai/createOpenAIStream.js +1 -1
  5. package/dist/ai/adapter/openai/index.d.ts +1 -1
  6. package/dist/ai/adapter/openai/sse.d.ts +8 -2
  7. package/dist/ai/adapter/openai/sse.js +40 -4
  8. package/dist/ai/adapter/openai/wire.d.ts +6 -0
  9. package/dist/ai/components/AllocationSelector.d.ts +3 -4
  10. package/dist/ai/components/AllocationSelector.js +37 -33
  11. package/dist/ai/components/AttachmentManager.js +7 -7
  12. package/dist/ai/components/AttachmentUpload.js +5 -5
  13. package/dist/ai/components/BranchNavigator.js +1 -1
  14. package/dist/ai/components/ChatEmptyState.js +2 -2
  15. package/dist/ai/components/ChatInput.js +10 -8
  16. package/dist/ai/components/ChatLayout.js +4 -5
  17. package/dist/ai/components/ChatMessage.js +12 -12
  18. package/dist/ai/components/ChatMessageList.js +9 -9
  19. package/dist/ai/components/ChatSidebar.js +8 -9
  20. package/dist/ai/components/ChatThread.js +4 -4
  21. package/dist/ai/components/ComposerChrome.d.ts +2 -2
  22. package/dist/ai/components/ComposerChrome.js +3 -6
  23. package/dist/ai/components/DragOverlay.js +2 -2
  24. package/dist/ai/components/ModelSelector.d.ts +5 -3
  25. package/dist/ai/components/ModelSelector.js +102 -339
  26. package/dist/ai/components/PastedText.js +11 -11
  27. package/dist/ai/components/ProviderIssueBanner.d.ts +2 -0
  28. package/dist/ai/components/ProviderIssueBanner.js +34 -16
  29. package/dist/ai/components/Reasoning.js +4 -4
  30. package/dist/ai/components/ShareDialog.js +43 -35
  31. package/dist/ai/components/SlashMenu.d.ts +12 -2
  32. package/dist/ai/components/SlashMenu.js +29 -13
  33. package/dist/ai/components/agent/ActivityLine.js +3 -3
  34. package/dist/ai/components/agent/AgentMessageParts.js +20 -20
  35. package/dist/ai/components/agent/PermissionPicker.js +13 -11
  36. package/dist/ai/components/conversationActions.d.ts +4 -6
  37. package/dist/ai/components/conversationActions.js +9 -13
  38. package/dist/ai/core/ChatProvider.js +4 -4
  39. package/dist/ai/core/config.js +1 -1
  40. package/dist/ai/core/parts.d.ts +5 -0
  41. package/dist/ai/core/parts.js +28 -1
  42. package/dist/ai/core/providerIssues.d.ts +7 -0
  43. package/dist/ai/core/providerIssues.js +9 -1
  44. package/dist/ai/core/useKeyboardShortcuts.d.ts +4 -0
  45. package/dist/ai/core/useKeyboardShortcuts.js +8 -2
  46. package/dist/ai/index.d.ts +0 -1
  47. package/dist/ai/index.js +1 -2
  48. package/dist/ai/strings.d.ts +19 -0
  49. package/dist/ai/strings.js +18 -1
  50. package/dist/ai/ui/Avatar.js +5 -5
  51. package/dist/ai/ui/ConversationSidebar.d.ts +0 -1
  52. package/dist/ai/ui/ConversationSidebar.js +6 -7
  53. package/dist/ai/ui/Markdown.js +3 -3
  54. package/dist/ai/ui/Notice.js +6 -6
  55. package/dist/ai/ui/chip.d.ts +4 -0
  56. package/dist/ai/ui/chip.js +8 -0
  57. package/dist/ai/ui/sidebar.d.ts +6 -5
  58. package/dist/ai/ui/sidebar.js +39 -43
  59. package/dist/components/ActionMenu.d.ts +13 -0
  60. package/dist/components/ActionMenu.js +30 -0
  61. package/dist/components/Avatar.js +6 -6
  62. package/dist/components/Breadcrumbs.js +1 -1
  63. package/dist/components/Button.js +10 -10
  64. package/dist/components/Callout.js +2 -2
  65. package/dist/components/Card.js +3 -3
  66. package/dist/components/Combobox.d.ts +66 -0
  67. package/dist/components/Combobox.js +393 -0
  68. package/dist/components/ConfirmModal.js +11 -11
  69. package/dist/components/ContextMenu.d.ts +23 -0
  70. package/dist/components/ContextMenu.js +89 -0
  71. package/dist/components/CopyToClipboard.js +2 -2
  72. package/dist/components/CreateModal.d.ts +17 -36
  73. package/dist/components/CreateModal.js +97 -259
  74. package/dist/components/DescriptionList.js +8 -8
  75. package/dist/components/Filter.js +2 -2
  76. package/dist/components/FilterPill.js +2 -2
  77. package/dist/components/HoverCard.d.ts +14 -0
  78. package/dist/components/HoverCard.js +33 -0
  79. package/dist/components/IconButton.d.ts +5 -5
  80. package/dist/components/IconButton.js +18 -22
  81. package/dist/components/InfoTip.d.ts +15 -0
  82. package/dist/components/InfoTip.js +60 -0
  83. package/dist/components/Input.js +5 -5
  84. package/dist/components/LetterBadge.js +2 -2
  85. package/dist/components/Loader.js +3 -3
  86. package/dist/components/Markdown.js +1 -1
  87. package/dist/components/MarkdownImpl.js +2 -2
  88. package/dist/components/Menu.d.ts +33 -0
  89. package/dist/components/Menu.js +86 -0
  90. package/dist/components/MenuEntries.d.ts +56 -0
  91. package/dist/components/MenuEntries.js +123 -0
  92. package/dist/components/Modal.d.ts +29 -0
  93. package/dist/components/Modal.js +47 -0
  94. package/dist/components/Overview.js +11 -10
  95. package/dist/components/PageHeader.d.ts +10 -16
  96. package/dist/components/PageHeader.js +69 -95
  97. package/dist/components/Pagination.js +5 -5
  98. package/dist/components/Provider.d.ts +5 -11
  99. package/dist/components/Provider.js +11 -14
  100. package/dist/components/Radio.d.ts +8 -0
  101. package/dist/components/Radio.js +16 -0
  102. package/dist/components/SectionHeader.js +2 -2
  103. package/dist/components/SegmentedControl.d.ts +6 -5
  104. package/dist/components/SegmentedControl.js +34 -30
  105. package/dist/components/Select.d.ts +27 -0
  106. package/dist/components/Select.js +78 -0
  107. package/dist/components/SettingModeOption.d.ts +5 -8
  108. package/dist/components/SettingModeOption.js +10 -12
  109. package/dist/components/SettingRow.js +4 -4
  110. package/dist/components/SettingsCard.js +4 -4
  111. package/dist/components/SettingsGroup.js +2 -2
  112. package/dist/components/Sort.js +1 -1
  113. package/dist/components/StatusBadge.js +7 -7
  114. package/dist/components/StatusIcons.js +4 -4
  115. package/dist/components/Switch.d.ts +22 -0
  116. package/dist/components/Switch.js +28 -0
  117. package/dist/components/Table.js +11 -11
  118. package/dist/components/Tooltip.d.ts +24 -20
  119. package/dist/components/Tooltip.js +58 -76
  120. package/dist/components/floating.d.ts +14 -0
  121. package/dist/components/floating.js +21 -0
  122. package/dist/components/search.d.ts +2 -0
  123. package/dist/components/search.js +14 -0
  124. package/dist/editor/Editor.js +1 -1
  125. package/dist/editor/EditorField.js +16 -21
  126. package/dist/editor/FormCodePanel.js +19 -19
  127. package/dist/editor/Monaco.js +3 -3
  128. package/dist/file-explorer/FileExplorer.js +77 -81
  129. package/dist/file-explorer/FileExplorerContext.js +2 -2
  130. package/dist/file-explorer/FilePreview/CodePreviewEditor.js +1 -1
  131. package/dist/file-explorer/FilePreview/Inline.js +1 -1
  132. package/dist/file-explorer/FilePreview/StreamedBadge.js +5 -6
  133. package/dist/file-explorer/FilePreview/Viewer.js +8 -8
  134. package/dist/file-explorer/FilePreview/index.d.ts +1 -1
  135. package/dist/file-explorer/FilePreview/index.js +49 -83
  136. package/dist/file-explorer/FileRow.d.ts +4 -3
  137. package/dist/file-explorer/FileRow.js +32 -38
  138. package/dist/file-explorer/FileRowsWindow.d.ts +3 -2
  139. package/dist/file-explorer/FileRowsWindow.js +4 -4
  140. package/dist/file-explorer/FileTable.d.ts +3 -2
  141. package/dist/file-explorer/FileTable.js +3 -3
  142. package/dist/file-explorer/LoadMoreRow.js +1 -1
  143. package/dist/file-explorer/TreeView.js +11 -16
  144. package/dist/file-explorer/helpers.js +11 -12
  145. package/dist/file-explorer/toasts.js +11 -11
  146. package/dist/form/FieldGroup.d.ts +11 -0
  147. package/dist/form/FieldGroup.js +36 -0
  148. package/dist/form/FieldWrapper.js +4 -4
  149. package/dist/form/Fields/BooleanField.js +23 -33
  150. package/dist/form/Fields/CheckboxGroupField.d.ts +1 -1
  151. package/dist/form/Fields/CheckboxGroupField.js +9 -13
  152. package/dist/form/Fields/ColorField.d.ts +1 -2
  153. package/dist/form/Fields/ColorField.js +6 -11
  154. package/dist/form/Fields/DropdownField.d.ts +3 -13
  155. package/dist/form/Fields/DropdownField.js +40 -27
  156. package/dist/form/Fields/DurationField.d.ts +1 -2
  157. package/dist/form/Fields/DurationField.js +25 -32
  158. package/dist/form/Fields/LabelField.js +2 -2
  159. package/dist/form/Fields/MultiDropdownField.d.ts +6 -12
  160. package/dist/form/Fields/MultiDropdownField.js +31 -22
  161. package/dist/form/Fields/NumberField.d.ts +1 -1
  162. package/dist/form/Fields/NumberField.js +65 -35
  163. package/dist/form/Fields/ObjectField.d.ts +1 -1
  164. package/dist/form/Fields/ObjectField.js +12 -43
  165. package/dist/form/Fields/RadioField.d.ts +1 -1
  166. package/dist/form/Fields/RadioField.js +30 -41
  167. package/dist/form/Fields/RangeField.d.ts +1 -2
  168. package/dist/form/Fields/RangeField.js +23 -16
  169. package/dist/form/Fields/StringField.d.ts +1 -2
  170. package/dist/form/Fields/StringField.js +58 -26
  171. package/dist/form/Fields/TextAreaField.js +12 -10
  172. package/dist/form/Form.d.ts +30 -48
  173. package/dist/form/Form.js +306 -412
  174. package/dist/form/FormLayout.js +9 -9
  175. package/dist/form/Wizard/WizardContainer.d.ts +1 -4
  176. package/dist/form/Wizard/WizardContainer.js +40 -56
  177. package/dist/form/Wizard/WizardNavigation.js +1 -1
  178. package/dist/form/Wizard/WizardStepContent.d.ts +1 -5
  179. package/dist/form/Wizard/WizardStepContent.js +11 -16
  180. package/dist/form/Wizard/WizardStepIndicator.js +6 -6
  181. package/dist/form/Wizard/types.d.ts +0 -14
  182. package/dist/form/fieldRegistry.d.ts +1 -1
  183. package/dist/form/fieldRegistry.js +6 -6
  184. package/dist/form/formEditing.js +1 -1
  185. package/dist/form/index.d.ts +5 -4
  186. package/dist/form/index.js +6 -7
  187. package/dist/form/types/fieldComponentTypes.d.ts +8 -10
  188. package/dist/form/useChoiceField.d.ts +20 -0
  189. package/dist/form/useChoiceField.js +49 -0
  190. package/dist/form/useFieldValue.d.ts +7 -0
  191. package/dist/form/useFieldValue.js +20 -0
  192. package/dist/form/useParsedOpts.d.ts +3 -1
  193. package/dist/form/useParsedOpts.js +12 -17
  194. package/dist/form/utils/dependentOptions.d.ts +8 -4
  195. package/dist/form/utils/dependentOptions.js +25 -17
  196. package/dist/form/utils/fieldItems.d.ts +10 -0
  197. package/dist/form/utils/fieldItems.js +11 -0
  198. package/dist/form/utils/fieldPath.d.ts +10 -0
  199. package/dist/form/utils/fieldPath.js +20 -0
  200. package/dist/form/utils/shareEqual.d.ts +6 -0
  201. package/dist/form/utils/shareEqual.js +38 -0
  202. package/dist/graph/AnnotationBanner.js +8 -8
  203. package/dist/graph/Collapse.d.ts +1 -0
  204. package/dist/graph/Collapse.js +6 -27
  205. package/dist/graph/Connectors.js +5 -5
  206. package/dist/graph/DependencyGraph.js +20 -19
  207. package/dist/graph/GraphEditor.js +30 -41
  208. package/dist/graph/GraphEditorDialogs.js +17 -17
  209. package/dist/graph/GraphNode.js +1 -1
  210. package/dist/graph/InputDialog.js +19 -22
  211. package/dist/graph/InputsEditor.js +58 -66
  212. package/dist/graph/JobSummary.js +42 -39
  213. package/dist/graph/MatrixGroup.js +1 -1
  214. package/dist/graph/ProblemsButton.js +18 -19
  215. package/dist/graph/Reveal.js +1 -1
  216. package/dist/graph/ShortcutsButton.js +15 -18
  217. package/dist/graph/SuggestionInput.d.ts +5 -10
  218. package/dist/graph/SuggestionInput.js +14 -18
  219. package/dist/graph/ToolbarPopover.d.ts +11 -6
  220. package/dist/graph/ToolbarPopover.js +35 -67
  221. package/dist/graph/TreeView.js +24 -37
  222. package/dist/graph/WorkflowSettingsDialog.js +4 -4
  223. package/dist/graph/editorChrome.js +13 -12
  224. package/dist/graph/editorFields.js +29 -29
  225. package/dist/graph/editorPrimitives.d.ts +1 -1
  226. package/dist/graph/editorPrimitives.js +10 -7
  227. package/dist/graph/editorRows.js +103 -97
  228. package/dist/graph/fieldProblems.js +2 -2
  229. package/dist/graph/graphEditorState.d.ts +4 -3
  230. package/dist/graph/inputRefs.js +9 -9
  231. package/dist/graph/settingsViews.js +6 -7
  232. package/dist/graph/stepWith.js +6 -6
  233. package/dist/index.d.ts +14 -15
  234. package/dist/index.js +15 -14
  235. package/dist/list/ActionToolbar.d.ts +6 -14
  236. package/dist/list/ActionToolbar.js +48 -96
  237. package/dist/list/ListPage.d.ts +6 -12
  238. package/dist/list/ListPage.js +46 -29
  239. package/dist/list/ListPager.js +4 -4
  240. package/dist/list/ListTable.js +5 -5
  241. package/dist/list/ListViewControls.d.ts +5 -4
  242. package/dist/list/ListViewControls.js +177 -267
  243. package/dist/list/UserHoverCard.d.ts +3 -17
  244. package/dist/list/UserHoverCard.js +21 -45
  245. package/dist/list/index.d.ts +3 -4
  246. package/dist/list/index.js +3 -4
  247. package/dist/list/listSearch.js +12 -11
  248. package/dist/list/rowMenu.d.ts +63 -0
  249. package/dist/list/rowMenu.js +134 -0
  250. package/dist/logviewer/LogViewer.js +26 -26
  251. package/dist/styles.css +1 -1
  252. package/package.json +7 -13
  253. package/dist/ai/ui/Dropdown.d.ts +0 -31
  254. package/dist/ai/ui/Dropdown.js +0 -110
  255. package/dist/components/AddMenu.d.ts +0 -18
  256. package/dist/components/AddMenu.js +0 -46
  257. package/dist/components/BareModal.d.ts +0 -17
  258. package/dist/components/BareModal.js +0 -77
  259. package/dist/components/CollapsiblePanel.d.ts +0 -27
  260. package/dist/components/CollapsiblePanel.js +0 -77
  261. package/dist/components/Dropdown.d.ts +0 -28
  262. package/dist/components/Dropdown.js +0 -355
  263. package/dist/components/Listbox.d.ts +0 -21
  264. package/dist/components/Listbox.js +0 -119
  265. package/dist/components/MultiSelect.d.ts +0 -22
  266. package/dist/components/MultiSelect.js +0 -168
  267. package/dist/components/SwitchToggle.d.ts +0 -15
  268. package/dist/components/SwitchToggle.js +0 -57
  269. package/dist/components/SwitchToggleSmall.d.ts +0 -6
  270. package/dist/components/SwitchToggleSmall.js +0 -14
  271. package/dist/components/Toggle.d.ts +0 -6
  272. package/dist/components/Toggle.js +0 -20
  273. package/dist/components/dropdownUtils.d.ts +0 -37
  274. package/dist/components/dropdownUtils.js +0 -99
  275. package/dist/form/SpecialTypes/DropdownWrapper.d.ts +0 -25
  276. package/dist/form/SpecialTypes/DropdownWrapper.js +0 -28
  277. package/dist/form/SpecialTypes/FormikCustomDropdown.d.ts +0 -51
  278. package/dist/form/SpecialTypes/FormikCustomDropdown.js +0 -119
  279. package/dist/form/SpecialTypes/FormikCustomInput.d.ts +0 -19
  280. package/dist/form/SpecialTypes/FormikCustomInput.js +0 -121
  281. package/dist/form/SpecialTypes/FormikMultiSelectDropdown.d.ts +0 -13
  282. package/dist/form/SpecialTypes/FormikMultiSelectDropdown.js +0 -31
  283. package/dist/form/SpecialTypes/FormikNumericInput.d.ts +0 -9
  284. package/dist/form/SpecialTypes/FormikNumericInput.js +0 -60
  285. package/dist/form/SpecialTypes/index.d.ts +0 -3
  286. package/dist/list/HoverCard.d.ts +0 -24
  287. package/dist/list/HoverCard.js +0 -73
  288. package/dist/list/RowContextMenu.d.ts +0 -127
  289. package/dist/list/RowContextMenu.js +0 -515
@@ -90,6 +90,33 @@ function applyPartDelta(parts, delta) {
90
90
  function isStreamedText(part) {
91
91
  return part?.kind === "text" || part?.kind === "reasoning";
92
92
  }
93
+ /** The wire history for an assistant turn whose tool calls the gateway ran:
94
+ * the calls, each result, then the answer. A turn with no finished tool
95
+ * calls comes back as the answer alone. */
96
+ function toolTurnMessages(parts, answer) {
97
+ const calls = (parts ?? []).filter((p) => p.kind === "tool_call" && p.status !== "running" && p.result !== void 0);
98
+ if (calls.length === 0) return [answer];
99
+ return [
100
+ {
101
+ role: "assistant",
102
+ content: null,
103
+ tool_calls: calls.map((c) => ({
104
+ id: c.id,
105
+ type: "function",
106
+ function: {
107
+ name: c.name,
108
+ arguments: c.args
109
+ }
110
+ }))
111
+ },
112
+ ...calls.map((c) => ({
113
+ role: "tool",
114
+ tool_call_id: c.id,
115
+ content: c.result
116
+ })),
117
+ ...answer.content ? [answer] : []
118
+ ];
119
+ }
93
120
  /** A turn can end (completed or stopped) with tool calls still marked
94
121
  * running — the transport died before their tool_end arrived. A stored
95
122
  * message must not spin forever, so close them out as interrupted. */
@@ -101,4 +128,4 @@ function finalizeParts(parts) {
101
128
  } : p);
102
129
  }
103
130
  //#endregion
104
- export { applyPartDelta, finalizeParts };
131
+ export { applyPartDelta, finalizeParts, toolTurnMessages };
@@ -1,2 +1,9 @@
1
+ import type { ChatStrings } from '../strings.js';
1
2
  import type { ChatModel, ProviderIssue } from '../types.js';
2
3
  export declare function providerIssueFor(issues: ProviderIssue[], model: Pick<ChatModel, 'provider_name' | 'provider_owner'> | undefined): ProviderIssue | undefined;
4
+ type IssueStrings = ChatStrings['providerIssue'];
5
+ /** A short name for what went wrong, such as beside the provider's heading. */
6
+ export declare function issueLabel(t: IssueStrings, issue: ProviderIssue): string;
7
+ /** What went wrong and what to do about it: the provider's own message when it sent one. */
8
+ export declare function issueDetail(t: IssueStrings, issue: ProviderIssue): string;
9
+ export {};
@@ -3,5 +3,13 @@ function providerIssueFor(issues, model) {
3
3
  if (!model?.provider_name) return;
4
4
  return issues.find((issue) => issue.provider_name === model.provider_name && (issue.provider_owner ?? "") === (model.provider_owner ?? ""));
5
5
  }
6
+ /** A short name for what went wrong, such as beside the provider's heading. */
7
+ function issueLabel(t, issue) {
8
+ return issue.status === "unauthorized" ? t.keyRejected : t.unreachable;
9
+ }
10
+ /** What went wrong and what to do about it: the provider's own message when it sent one. */
11
+ function issueDetail(t, issue) {
12
+ return issue.message || (issue.status === "unauthorized" ? t.keyRejectedHint : t.unreachableHint);
13
+ }
6
14
  //#endregion
7
- export { providerIssueFor };
15
+ export { issueDetail, issueLabel, providerIssueFor };
@@ -11,4 +11,8 @@ export declare function useKeyboardShortcuts(options?: UseKeyboardShortcutsOptio
11
11
  handleCopyLastResponse: () => Promise<void>;
12
12
  handleStopGeneration: () => void;
13
13
  };
14
+ /** Escape pressed in a dialog, a drawer, a menu or an open list closes that
15
+ * layer and nothing else. Those layers dismiss from a listener on the
16
+ * document too, so stopping propagation can't keep the event from here. */
17
+ export declare function escapeClosesLayer(target: EventTarget | null): boolean;
14
18
  export {};
@@ -36,7 +36,7 @@ function useKeyboardShortcuts(options = {}) {
36
36
  const handleKeyDown = (e) => {
37
37
  const cmdKey = isMac() ? e.metaKey : e.ctrlKey;
38
38
  if (e.key === "Escape") {
39
- handleStopGeneration();
39
+ if (!escapeClosesLayer(e.target)) handleStopGeneration();
40
40
  return;
41
41
  }
42
42
  if (cmdKey && e.shiftKey && e.key === "O") {
@@ -71,5 +71,11 @@ function useKeyboardShortcuts(options = {}) {
71
71
  handleStopGeneration
72
72
  };
73
73
  }
74
+ /** Escape pressed in a dialog, a drawer, a menu or an open list closes that
75
+ * layer and nothing else. Those layers dismiss from a listener on the
76
+ * document too, so stopping propagation can't keep the event from here. */
77
+ function escapeClosesLayer(target) {
78
+ return target instanceof Element && (target.matches("[aria-expanded=\"true\"]") || !!target.closest("[role=\"dialog\"], [role=\"alertdialog\"], [role=\"menu\"]"));
79
+ }
74
80
  //#endregion
75
- export { lastAssistantContent, lastUserMessage, useKeyboardShortcuts };
81
+ export { escapeClosesLayer, lastAssistantContent, lastUserMessage, useKeyboardShortcuts };
@@ -41,7 +41,6 @@ export { useKeyboardShortcuts } from './core/useKeyboardShortcuts.js';
41
41
  export { type ChatStrings, defaultChatStrings } from './strings.js';
42
42
  export * from './types.js';
43
43
  export { ConversationSidebar, type ConversationSidebarGroup, useResizableSidebarWidth, } from './ui/ConversationSidebar.js';
44
- export { type DropdownOption, default as Dropdown } from './ui/Dropdown.js';
45
44
  export { NoticeBar, NoticeCard, type NoticeTone, OutputCard } from './ui/Notice.js';
46
45
  export { RenameDialog, type RowDialogStrings, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, useRowDialogs, } from './ui/sidebar.js';
47
46
  export { formatFileSize, isMac, isOrgModel } from './utils.js';
package/dist/ai/index.js CHANGED
@@ -12,7 +12,6 @@ import { defaultChatStrings } from "./strings.js";
12
12
  import { resolveChatConfig, useChatConfig } from "./core/config.js";
13
13
  import { providerIssueFor } from "./core/providerIssues.js";
14
14
  import { ChatProvider, useChat } from "./core/ChatProvider.js";
15
- import Dropdown from "./ui/Dropdown.js";
16
15
  import { formatFileSize, isMac, isOrgModel } from "./utils.js";
17
16
  import AllocationSelector from "./components/AllocationSelector.js";
18
17
  import AttachmentManager from "./components/AttachmentManager.js";
@@ -46,4 +45,4 @@ import ChatLayout, { CHAT_COLUMN_SCOPE, ConversationLayout, DRAWER_BELOW_PX } fr
46
45
  import ChatMessage_default from "./components/ChatMessage.js";
47
46
  import ChatMessageList from "./components/ChatMessageList.js";
48
47
  import ChatThread from "./components/ChatThread.js";
49
- export { AGENT_COLOR_NAMES, ActivityLine, AgentMessageParts, AllocationSelector, ApprovalBlock, AttachmentManager, AttachmentUpload, BlockedGroupBanner, BranchNavigator, CHAT_COLUMN_SCOPE, ChatAdapterError, ChatEmptyState, ChatInput, ChatLayout, ChatMessageList, ChatMessage_default as ChatMessageView, ChatProvider, ChatSidebar, ChatStage, ChatThread, ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationLayout, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, Dropdown, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ManageProvidersLink, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, compactCount, computeEditDiff, computeWriteRows, defaultChatStrings, durationToAbsHumanDuration, editSummary, finalizeParts, firstNonEmptyLine, formatElapsed, formatFileSize, fullToolArgs, getGreeting, getProviderKeyFromModelId, groupConversationsByDate, hiddenTranscriptTool, initialState, interruptionNotice, isEditDiffTool, isGroupableTool, isMac, isNamedPermissionMode, isOrgModel, languageForPath, lineDelta, parseEditArgs, parseSubagentNotice, pasteInlineMaxBytes, permissionModesUpTo, planFromArgs, plural, providerIssueFor, resolveChatConfig, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, slashMatches, subagentDeliveryLine, summarizeToolArgs, taskCallFromArgs, thinkingHeading, tokenizeDiffLines, toolHeaderFor, toolSummary, useChat, useChatConfig, useConversationActions, useDragDrop, useKeyboardShortcuts, useResizableSidebarWidth, useRowDialogs, wordEmphasisRanges };
48
+ export { AGENT_COLOR_NAMES, ActivityLine, AgentMessageParts, AllocationSelector, ApprovalBlock, AttachmentManager, AttachmentUpload, BlockedGroupBanner, BranchNavigator, CHAT_COLUMN_SCOPE, ChatAdapterError, ChatEmptyState, ChatInput, ChatLayout, ChatMessageList, ChatMessage_default as ChatMessageView, ChatProvider, ChatSidebar, ChatStage, ChatThread, ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationLayout, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ManageProvidersLink, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarPlaceholder, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, compactCount, computeEditDiff, computeWriteRows, defaultChatStrings, durationToAbsHumanDuration, editSummary, finalizeParts, firstNonEmptyLine, formatElapsed, formatFileSize, fullToolArgs, getGreeting, getProviderKeyFromModelId, groupConversationsByDate, hiddenTranscriptTool, initialState, interruptionNotice, isEditDiffTool, isGroupableTool, isMac, isNamedPermissionMode, isOrgModel, languageForPath, lineDelta, parseEditArgs, parseSubagentNotice, pasteInlineMaxBytes, permissionModesUpTo, planFromArgs, plural, providerIssueFor, resolveChatConfig, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, slashMatches, subagentDeliveryLine, summarizeToolArgs, taskCallFromArgs, thinkingHeading, tokenizeDiffLines, toolHeaderFor, toolSummary, useChat, useChatConfig, useConversationActions, useDragDrop, useKeyboardShortcuts, useResizableSidebarWidth, useRowDialogs, wordEmphasisRanges };
@@ -34,8 +34,27 @@ export interface ChatStrings {
34
34
  bannerUnreachable: (provider: string) => string;
35
35
  };
36
36
  modelPicker: {
37
+ /** Names the picker for assistive technology. */
38
+ choose: string;
39
+ select: string;
40
+ search: string;
41
+ loading: string;
42
+ failed: string;
43
+ retry: string;
44
+ none: string;
37
45
  /** Beside a provider another user registered and shared with the reader. */
38
46
  sharedBy: (owner: string) => string;
47
+ /** Beside a session whose models are still loading. */
48
+ connecting: string;
49
+ /** Beside a session whose service did not answer. */
50
+ notResponding: string;
51
+ /** Links the provider's settings from its issue banner, for its owner. */
52
+ manageProvider: string;
53
+ };
54
+ allocationPicker: {
55
+ choose: string;
56
+ placeholder: string;
57
+ usage: (used: string, total: string) => string;
39
58
  };
40
59
  queue: {
41
60
  remove: string;
@@ -47,7 +47,24 @@ var defaultChatStrings = {
47
47
  bannerKeyRejected: (provider) => `API key rejected for \u201c${provider}\u201d`,
48
48
  bannerUnreachable: (provider) => `\u201c${provider}\u201d is unreachable`
49
49
  },
50
- modelPicker: { sharedBy: (owner) => `Shared by ${owner}` },
50
+ modelPicker: {
51
+ choose: "Model",
52
+ select: "Select a model",
53
+ search: "Search models…",
54
+ loading: "Loading models…",
55
+ failed: "Failed to load models",
56
+ retry: "Retry",
57
+ none: "No models available",
58
+ sharedBy: (owner) => `Shared by ${owner}`,
59
+ connecting: "Connecting…",
60
+ notResponding: "Not responding",
61
+ manageProvider: "Manage provider"
62
+ },
63
+ allocationPicker: {
64
+ choose: "Allocation",
65
+ placeholder: "Select allocation",
66
+ usage: (used, total) => `${used} / ${total}`
67
+ },
51
68
  activity: {
52
69
  tokens: (input, output) => `↑${input} ↓${output} tokens`,
53
70
  stop: "Stop"
@@ -1,22 +1,22 @@
1
1
  import { avatarInitials } from "../../components/Avatar.js";
2
- import cx from "classnames";
3
- import { useState } from "react";
2
+ import { clsx } from "clsx";
4
3
  import { jsx } from "react/jsx-runtime";
4
+ import { useState } from "react";
5
5
  //#region src/ai/ui/Avatar.tsx
6
6
  var SIZE_CLASSES = "w-6 h-6 text-xs";
7
7
  function Avatar({ src, name, className }) {
8
8
  const [erroredUrl, setErroredUrl] = useState(null);
9
9
  const errored = erroredUrl !== null && erroredUrl === src;
10
10
  return /* @__PURE__ */ jsx("div", {
11
- className: cx("relative inline-flex", className),
11
+ className: clsx("relative inline-flex", className),
12
12
  children: !src || errored ? /* @__PURE__ */ jsx("div", {
13
- className: cx("rounded-full flex items-center justify-center font-medium", "bg-(--theme-element,#3b82f6) text-(--theme-element-text,#ffffff)", SIZE_CLASSES),
13
+ className: clsx("rounded-full flex items-center justify-center font-medium", "bg-(--theme-element,#3b82f6) text-(--theme-element-text,#ffffff)", SIZE_CLASSES),
14
14
  children: avatarInitials(name)
15
15
  }) : /* @__PURE__ */ jsx("img", {
16
16
  src,
17
17
  alt: name || "User avatar",
18
18
  onError: () => setErroredUrl(src),
19
- className: cx("rounded-full object-cover", SIZE_CLASSES)
19
+ className: clsx("rounded-full object-cover", SIZE_CLASSES)
20
20
  })
21
21
  });
22
22
  }
@@ -43,7 +43,6 @@ export declare function ConversationSidebar<T>({ label, collapsed: collapsedProp
43
43
  open: boolean;
44
44
  onClose: () => void;
45
45
  label: string;
46
- closeLabel: string;
47
46
  } | undefined;
48
47
  groups: ConversationSidebarGroup<T>[];
49
48
  getKey: (item: T) => string;
@@ -1,8 +1,8 @@
1
1
  import { positionKeys } from "../../components/keys.js";
2
2
  import { SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarToggle } from "./sidebar.js";
3
- import cx from "classnames";
4
- import { Fragment, useEffect, useRef, useState } from "react";
3
+ import { clsx } from "clsx";
5
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { Fragment as Fragment$1, useEffect, useRef, useState } from "react";
6
6
  var SHARED_WIDTH_STORAGE_KEY = "aiChatSidebarWidth";
7
7
  function clampSidebarWidth(width) {
8
8
  return Math.min(480, Math.max(200, width));
@@ -121,14 +121,14 @@ function ConversationSidebar({ label, collapsed: collapsedProp, onToggle, toggle
121
121
  if (e.key === "ArrowLeft") sized.nudge(-16);
122
122
  else if (e.key === "ArrowRight") sized.nudge(16);
123
123
  },
124
- className: cx("absolute inset-y-0 right-0 z-10 w-1 cursor-col-resize touch-none", sized.resizing ? "bg-(--theme-element)" : "hover:bg-(--theme-border)")
124
+ className: clsx("absolute inset-y-0 right-0 z-10 w-1 cursor-col-resize touch-none", sized.resizing ? "bg-(--theme-element)" : "hover:bg-(--theme-border)")
125
125
  }),
126
126
  top,
127
127
  collapsed && rail ? /* @__PURE__ */ jsx("ul", {
128
128
  className: "flex min-h-0 flex-1 flex-col items-center gap-1 overflow-y-auto py-1",
129
129
  children: rail
130
130
  }) : /* @__PURE__ */ jsx("div", {
131
- className: cx("min-h-0 flex-1 overflow-y-auto px-2 pb-2 transition-opacity duration-200", collapsed ? "pointer-events-none opacity-0" : "opacity-100"),
131
+ className: clsx("min-h-0 flex-1 overflow-y-auto px-2 pb-2 transition-opacity duration-200", collapsed ? "pointer-events-none opacity-0" : "opacity-100"),
132
132
  children: loading ? /* @__PURE__ */ jsx("div", {
133
133
  className: "space-y-3 px-2 pt-2",
134
134
  children: positionKeys(5, "skeleton").map((key, i) => /* @__PURE__ */ jsx("div", {
@@ -146,12 +146,12 @@ function ConversationSidebar({ label, collapsed: collapsedProp, onToggle, toggle
146
146
  children: group.label
147
147
  }), /* @__PURE__ */ jsx("ul", {
148
148
  className: "space-y-0.5",
149
- children: group.items.map((item) => /* @__PURE__ */ jsx(Fragment, { children: renderRow(item) }, getKey(item)))
149
+ children: group.items.map((item) => /* @__PURE__ */ jsx(Fragment$1, { children: renderRow(item) }, getKey(item)))
150
150
  })]
151
151
  }, group.key))
152
152
  }),
153
153
  /* @__PURE__ */ jsxs("div", {
154
- className: cx("flex shrink-0 items-center gap-1 p-1.5", collapsed ? "justify-center" : footer ? "justify-between" : "justify-end"),
154
+ className: clsx("flex shrink-0 items-center gap-1 p-1.5", collapsed ? "justify-center" : footer ? "justify-between" : "justify-end"),
155
155
  children: [!collapsed && footer, /* @__PURE__ */ jsx(SidebarToggle, {
156
156
  collapsed,
157
157
  onToggle,
@@ -166,7 +166,6 @@ function ConversationSidebar({ label, collapsed: collapsedProp, onToggle, toggle
166
166
  open: drawer.open,
167
167
  onClose: drawer.onClose,
168
168
  label: drawer.label,
169
- closeLabel: drawer.closeLabel,
170
169
  children: panel
171
170
  }) : panel;
172
171
  }
@@ -1,8 +1,8 @@
1
1
  import { useChatConfig } from "../core/config.js";
2
2
  import { rehypeCodeBreaks } from "./codeBreaks.js";
3
- import cx from "classnames";
4
- import { useEffect, useState } from "react";
3
+ import { clsx } from "clsx";
5
4
  import { jsx } from "react/jsx-runtime";
5
+ import { useEffect, useState } from "react";
6
6
  import { code } from "@streamdown/code";
7
7
  import { math } from "@streamdown/math";
8
8
  import { Streamdown, defaultRehypePlugins } from "streamdown";
@@ -67,7 +67,7 @@ function Markdown({ children, isStreaming }) {
67
67
  components: {
68
68
  a: ({ node, ...props }) => /* @__PURE__ */ jsx("a", {
69
69
  ...props,
70
- className: cx("link wrap-break-word", props.className),
70
+ className: clsx("link wrap-break-word", props.className),
71
71
  target: "_blank",
72
72
  rel: "noopener noreferrer"
73
73
  }),
@@ -1,7 +1,7 @@
1
1
  import { FiAlertCircle } from "../../icons/fi/FiAlertCircle.js";
2
2
  import { IoMdClose } from "../../icons/io/IoMdClose.js";
3
3
  import { IoInformationCircleOutline } from "../../icons/io5/IoInformationCircleOutline.js";
4
- import cx from "classnames";
4
+ import { clsx } from "clsx";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/ai/ui/Notice.tsx
7
7
  var barTone = {
@@ -34,13 +34,13 @@ function NoticeBar({ tone, title, children, action, onAction, testId }) {
34
34
  const Icon = tone === "danger" || tone === "warning" ? FiAlertCircle : IoInformationCircleOutline;
35
35
  return /* @__PURE__ */ jsxs("div", {
36
36
  "data-testid": testId,
37
- className: cx("flex shrink-0 items-start gap-3 border-b px-6 py-3", barTone[tone]),
37
+ className: clsx("flex shrink-0 items-start gap-3 border-b px-6 py-3", barTone[tone]),
38
38
  children: [
39
- /* @__PURE__ */ jsx(Icon, { className: cx("mt-0.5 h-4 w-4 shrink-0", iconTone[tone]) }),
39
+ /* @__PURE__ */ jsx(Icon, { className: clsx("mt-0.5 h-4 w-4 shrink-0", iconTone[tone]) }),
40
40
  /* @__PURE__ */ jsxs("div", {
41
41
  className: "min-w-0 flex-1",
42
42
  children: [/* @__PURE__ */ jsx("p", {
43
- className: cx("text-sm font-medium", titleTone[tone]),
43
+ className: clsx("text-sm font-medium", titleTone[tone]),
44
44
  children: title
45
45
  }), children && /* @__PURE__ */ jsx("p", {
46
46
  className: "mt-0.5 text-xs theme-muted-text",
@@ -64,7 +64,7 @@ function OutputCard({ title, text, onDismiss, dismissLabel, testId }) {
64
64
  className: "relative my-3 rounded-lg border theme-border theme-muted-panel px-3 py-2",
65
65
  children: [
66
66
  /* @__PURE__ */ jsx("p", {
67
- className: cx("font-mono text-[11px] theme-muted-text", onDismiss && "pr-6"),
67
+ className: clsx("font-mono text-[11px] theme-muted-text", onDismiss && "pr-6"),
68
68
  children: title
69
69
  }),
70
70
  /* @__PURE__ */ jsx("pre", {
@@ -87,7 +87,7 @@ function OutputCard({ title, text, onDismiss, dismissLabel, testId }) {
87
87
  function NoticeCard({ tone = "neutral", children, onDismiss, dismissLabel, testId }) {
88
88
  return /* @__PURE__ */ jsxs("div", {
89
89
  "data-testid": testId,
90
- className: cx("flex items-start gap-2 rounded-lg border px-3 py-2 text-xs", cardTone[tone]),
90
+ className: clsx("flex items-start gap-2 rounded-lg border px-3 py-2 text-xs", cardTone[tone]),
91
91
  children: [/* @__PURE__ */ jsx("span", {
92
92
  className: "flex-1",
93
93
  children
@@ -0,0 +1,4 @@
1
+ /** A picker under the composer, beside send. */
2
+ export declare const chipClassName = "inline-flex min-w-0 items-center cursor-pointer outline-none transition-colors theme-muted-text hover:theme-text focus-visible:ring-1 focus-visible:ring-(--theme-element) disabled:cursor-not-allowed disabled:opacity-50 h-8 max-w-[280px] gap-1.5 rounded-full px-2.5 text-[13px] hover:chat-tint";
3
+ /** A smaller picker for secondary settings, such as the agent's permissions. */
4
+ export declare const smallChipClassName = "inline-flex min-w-0 items-center cursor-pointer outline-none transition-colors theme-muted-text hover:theme-text focus-visible:ring-1 focus-visible:ring-(--theme-element) disabled:cursor-not-allowed disabled:opacity-50 gap-1 rounded-md px-1.5 py-0.5 text-[11px] hover:theme-muted-panel";
@@ -0,0 +1,8 @@
1
+ //#region src/ai/ui/chip.ts
2
+ var chipBase = "inline-flex min-w-0 items-center cursor-pointer outline-none transition-colors theme-muted-text hover:theme-text focus-visible:ring-1 focus-visible:ring-(--theme-element) disabled:cursor-not-allowed disabled:opacity-50";
3
+ /** A picker under the composer, beside send. */
4
+ var chipClassName = `${chipBase} h-8 max-w-[280px] gap-1.5 rounded-full px-2.5 text-[13px] hover:chat-tint`;
5
+ /** A smaller picker for secondary settings, such as the agent's permissions. */
6
+ var smallChipClassName = `${chipBase} gap-1 rounded-md px-1.5 py-0.5 text-[11px] hover:theme-muted-panel`;
7
+ //#endregion
8
+ export { chipClassName, smallChipClassName };
@@ -1,5 +1,6 @@
1
1
  import { type CSSProperties, type ReactNode } from 'react';
2
- import { type OpenMenu, type RowMenuItem } from '../../list/index.js';
2
+ import type { OpenMenu } from '../../components/ContextMenu.js';
3
+ import type { MenuEntry } from '../../components/MenuEntries.js';
3
4
  export declare const SIDEBAR_DEFAULT_WIDTH_PX = 256;
4
5
  /** The column a conversation list lives in: it animates between its width
5
6
  * and a rail, unless a drag is setting the width right now. */
@@ -16,12 +17,12 @@ export declare function SidebarPanel({ collapsed, width, railWidth, resizing, la
16
17
  /** The list over the content of a layout too narrow to keep it beside the
17
18
  * content. Place it in a positioned container: the drawer covers that
18
19
  * container, not the window, so an embedded chat keeps to its own panel.
19
- * Tapping outside or Escape closes it, and focus returns where it was. */
20
- export declare function SidebarDrawer({ open, onClose, label, closeLabel, children, }: {
20
+ * A tap outside, Escape or a swipe to the left closes it, and focus returns
21
+ * where it was. */
22
+ export declare function SidebarDrawer({ open, onClose, label, children, }: {
21
23
  open: boolean;
22
24
  onClose: () => void;
23
25
  label: string;
24
- closeLabel: string;
25
26
  children: ReactNode;
26
27
  }): import("react").JSX.Element;
27
28
  export declare function SidebarToggle({ collapsed, onToggle, openLabel, closeLabel, className, }: {
@@ -53,7 +54,7 @@ export declare function SidebarRowTitle({ children, time, }: {
53
54
  * while its menu is up, and the menu opens from its button or a right-click. */
54
55
  export declare function SidebarRow({ selected, menuItems, openMenu, className, children, }: {
55
56
  selected: boolean;
56
- menuItems: RowMenuItem[];
57
+ menuItems: MenuEntry[];
57
58
  openMenu: OpenMenu;
58
59
  className?: string;
59
60
  children: ReactNode;
@@ -1,10 +1,11 @@
1
1
  import { TbLayoutSidebar } from "../../icons/tb/TbLayoutSidebar.js";
2
2
  import { ConfirmModal } from "../../components/ConfirmModal.js";
3
+ import { MoreButton, rowContextMenuProps, useRowMenuActive } from "../../list/rowMenu.js";
3
4
  import { focusOnMount } from "../../components/focus.js";
4
- import { MoreButton, rowContextMenuProps, useRowMenuActive } from "../../list/RowContextMenu.js";
5
- import cx from "classnames";
6
- import { useEffect, useRef, useState } from "react";
7
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
+ import { clsx } from "clsx";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ import { useRef, useState } from "react";
8
+ import { Drawer } from "@base-ui/react/drawer";
8
9
  //#region src/ai/ui/sidebar.tsx
9
10
  var SIDEBAR_RAIL_WIDTH_PX = 48;
10
11
  var HIGHLIGHT_SELECTED = "bg-[color-mix(in_oklab,var(--theme-accent)_12%,transparent)]";
@@ -14,7 +15,7 @@ var HIGHLIGHT_HOVER = "hover:bg-[color-mix(in_oklab,var(--theme-panel)_5%,transp
14
15
  function SidebarPanel({ collapsed, width = 256, railWidth = SIDEBAR_RAIL_WIDTH_PX, resizing = false, label, className, style, children }) {
15
16
  return /* @__PURE__ */ jsx("aside", {
16
17
  "aria-label": label,
17
- className: cx("relative h-full flex shrink-0 flex-col bg-(--theme-muted-panel-bg) overflow-hidden", !resizing && "transition-[width] duration-300 ease-in-out", className),
18
+ className: clsx("relative h-full flex shrink-0 flex-col bg-(--theme-muted-panel-bg) overflow-hidden", !resizing && "transition-[width] duration-300 ease-in-out", className),
18
19
  style: {
19
20
  width: collapsed ? railWidth : width,
20
21
  ...style
@@ -25,37 +26,32 @@ function SidebarPanel({ collapsed, width = 256, railWidth = SIDEBAR_RAIL_WIDTH_P
25
26
  /** The list over the content of a layout too narrow to keep it beside the
26
27
  * content. Place it in a positioned container: the drawer covers that
27
28
  * container, not the window, so an embedded chat keeps to its own panel.
28
- * Tapping outside or Escape closes it, and focus returns where it was. */
29
- function SidebarDrawer({ open, onClose, label, closeLabel, children }) {
30
- const panelRef = useRef(null);
31
- useEffect(() => {
32
- if (!open) return;
33
- const returnTo = document.activeElement instanceof HTMLElement ? document.activeElement : null;
34
- panelRef.current?.focus();
35
- return () => returnTo?.focus();
36
- }, [open]);
37
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
38
- type: "button",
39
- tabIndex: -1,
40
- "aria-label": closeLabel,
41
- onClick: onClose,
42
- className: cx("absolute inset-0 z-20 bg-black/40 transition-opacity duration-300", open ? "opacity-100" : "pointer-events-none opacity-0")
43
- }), /* @__PURE__ */ jsx("div", {
44
- ref: panelRef,
45
- role: "dialog",
46
- "aria-modal": "true",
47
- "aria-label": label,
48
- tabIndex: -1,
49
- inert: !open,
50
- onKeyDown: (e) => {
51
- if (e.key === "Escape") {
52
- e.stopPropagation();
53
- onClose();
54
- }
55
- },
56
- className: cx("absolute inset-y-0 left-0 z-30 flex w-[min(20rem,85%)] shadow-xl transition-transform duration-300 ease-in-out focus:outline-none", open ? "translate-x-0" : "-translate-x-full"),
57
- children
58
- })] });
29
+ * A tap outside, Escape or a swipe to the left closes it, and focus returns
30
+ * where it was. */
31
+ function SidebarDrawer({ open, onClose, label, children }) {
32
+ const container = useRef(null);
33
+ return /* @__PURE__ */ jsxs(Drawer.Root, {
34
+ open,
35
+ onOpenChange: (next) => !next && onClose(),
36
+ swipeDirection: "left",
37
+ modal: "trap-focus",
38
+ children: [/* @__PURE__ */ jsx("div", {
39
+ ref: container,
40
+ className: "contents"
41
+ }), /* @__PURE__ */ jsxs(Drawer.Portal, {
42
+ container,
43
+ keepMounted: true,
44
+ className: "contents",
45
+ children: [/* @__PURE__ */ jsx(Drawer.Backdrop, { className: "absolute inset-0 z-20 bg-black/40 opacity-[calc(1-var(--drawer-swipe-progress))] transition-opacity duration-300 data-ending-style:opacity-0 data-starting-style:opacity-0 data-swiping:duration-0" }), /* @__PURE__ */ jsx(Drawer.Viewport, {
46
+ className: "absolute inset-y-0 left-0 z-30 flex w-[min(20rem,85%)]",
47
+ children: /* @__PURE__ */ jsx(Drawer.Popup, {
48
+ "aria-label": label,
49
+ className: "flex w-full shadow-xl outline-none [transform:translateX(var(--drawer-swipe-movement-x))] transition-transform duration-300 ease-in-out data-ending-style:[transform:translateX(-100%)] data-starting-style:[transform:translateX(-100%)] data-swiping:select-none data-swiping:duration-0",
50
+ children
51
+ })
52
+ })]
53
+ })]
54
+ });
59
55
  }
60
56
  function SidebarToggle({ collapsed, onToggle, openLabel, closeLabel, className }) {
61
57
  const label = collapsed ? openLabel : closeLabel;
@@ -65,14 +61,14 @@ function SidebarToggle({ collapsed, onToggle, openLabel, closeLabel, className }
65
61
  title: label,
66
62
  "aria-label": label,
67
63
  "aria-expanded": !collapsed,
68
- className: cx("flex h-7 w-7 items-center justify-center rounded-md theme-muted-text transition-colors hover:theme-muted-panel hover:theme-text", className),
64
+ className: clsx("flex h-7 w-7 items-center justify-center rounded-md theme-muted-text transition-colors hover:theme-muted-panel hover:theme-text", className),
69
65
  children: /* @__PURE__ */ jsx(TbLayoutSidebar, { className: "h-4 w-4" })
70
66
  });
71
67
  }
72
68
  function SidebarGroupHeading({ children, tone = "default", testId }) {
73
69
  return /* @__PURE__ */ jsx("h4", {
74
70
  "data-testid": testId,
75
- className: cx("mt-5 mb-1 whitespace-nowrap px-2 text-xs font-medium", tone === "attention" ? "text-amber-700 dark:text-amber-300" : "theme-muted-text"),
71
+ className: clsx("mt-5 mb-1 whitespace-nowrap px-2 text-xs font-medium", tone === "attention" ? "text-amber-700 dark:text-amber-300" : "theme-muted-text"),
76
72
  children
77
73
  });
78
74
  }
@@ -104,11 +100,11 @@ function SidebarRowTitle({ children, time }) {
104
100
  function SidebarRow({ selected, menuItems, openMenu, className, children }) {
105
101
  const { active, openMenu: openRowMenu } = useRowMenuActive(openMenu);
106
102
  return /* @__PURE__ */ jsxs("li", {
107
- className: cx("group relative flex items-center justify-between rounded-lg px-2 py-[3px] transition-colors duration-150", selected || active ? HIGHLIGHT_SELECTED : HIGHLIGHT_HOVER, className),
103
+ className: clsx("group relative flex items-center justify-between rounded-lg px-2 py-[3px] transition-colors duration-150", selected || active ? HIGHLIGHT_SELECTED : HIGHLIGHT_HOVER, className),
108
104
  ...rowContextMenuProps(openRowMenu, menuItems),
109
105
  children: [children, /* @__PURE__ */ jsx(MoreButton, {
110
- active,
111
- onOpen: (x, y) => openRowMenu(x, y, menuItems)
106
+ open: active,
107
+ onOpen: (button) => openRowMenu(button, menuItems)
112
108
  })]
113
109
  });
114
110
  }
@@ -122,7 +118,7 @@ function SidebarRailItem({ selected, label, onSelect, testId, tooltipProps, chil
122
118
  "aria-current": selected ? "page" : void 0,
123
119
  onClick: onSelect,
124
120
  ...tooltipProps,
125
- className: cx("flex h-7 w-7 items-center justify-center rounded-md transition-colors", HIGHLIGHT_HOVER, selected && HIGHLIGHT_SELECTED),
121
+ className: clsx("flex h-7 w-7 items-center justify-center rounded-md transition-colors", HIGHLIGHT_HOVER, selected && HIGHLIGHT_SELECTED),
126
122
  children
127
123
  }) });
128
124
  }
@@ -181,7 +177,7 @@ function useRowDialogs({ strings, nameOf, onDelete, onRename }) {
181
177
  setName(nameOf(item));
182
178
  setToRename(item);
183
179
  },
184
- dialogs: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ConfirmModal, {
180
+ dialogs: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ConfirmModal, {
185
181
  open: toDelete !== null,
186
182
  onClose: () => setToDelete(null),
187
183
  align: "center",
@@ -0,0 +1,13 @@
1
+ import type { ReactNode } from 'react';
2
+ import { type MenuEntry, type MenuSearch } from './MenuEntries.js';
3
+ /** A trigger that opens a menu, such as a header's "New" or "…" button. */
4
+ export declare function ActionMenu({ items, label, search, align, triggerClassName, children, }: {
5
+ items: MenuEntry[];
6
+ /** Names the trigger, which usually shows only an icon, and labels its tooltip. */
7
+ label: string;
8
+ search?: MenuSearch | undefined;
9
+ align?: 'start' | 'center' | 'end';
10
+ triggerClassName?: string | undefined;
11
+ /** The trigger's content. */
12
+ children: ReactNode;
13
+ }): import("react").JSX.Element;
@@ -0,0 +1,30 @@
1
+ import { MenuPopup } from "./Menu.js";
2
+ import { Tooltip } from "./Tooltip.js";
3
+ import { MenuEntries, MenuFilter } from "./MenuEntries.js";
4
+ import { Menu } from "@base-ui/react/menu";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/ActionMenu.tsx
7
+ /** A trigger that opens a menu, such as a header's "New" or "…" button. */
8
+ function ActionMenu({ items, label, search, align, triggerClassName, children }) {
9
+ return /* @__PURE__ */ jsx(MenuFilter, {
10
+ search,
11
+ children: (query) => /* @__PURE__ */ jsxs(Menu.Root, { children: [/* @__PURE__ */ jsx(Tooltip, {
12
+ content: label,
13
+ children: /* @__PURE__ */ jsx(Menu.Trigger, {
14
+ "aria-label": label,
15
+ className: triggerClassName,
16
+ children
17
+ })
18
+ }), /* @__PURE__ */ jsx(MenuPopup, {
19
+ align,
20
+ className: "min-w-52",
21
+ children: /* @__PURE__ */ jsx(MenuEntries, {
22
+ entries: items,
23
+ search,
24
+ query
25
+ })
26
+ })] })
27
+ });
28
+ }
29
+ //#endregion
30
+ export { ActionMenu };
@@ -1,7 +1,7 @@
1
1
  import { useStrings } from "./Provider.js";
2
- import cx from "classnames";
3
- import { useState } from "react";
2
+ import { clsx } from "clsx";
4
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { useState } from "react";
5
5
  //#region src/components/Avatar.tsx
6
6
  var SIZE_CLASSES = {
7
7
  xs: "w-4 h-4 text-[9px]",
@@ -30,19 +30,19 @@ function Avatar({ src, name, size = "md", status, className }) {
30
30
  const [erroredUrl, setErroredUrl] = useState(null);
31
31
  const showImage = !!src && erroredUrl !== src;
32
32
  return /* @__PURE__ */ jsxs("div", {
33
- className: cx("relative inline-flex", className),
33
+ className: clsx("relative inline-flex", className),
34
34
  children: [showImage ? /* @__PURE__ */ jsx("img", {
35
35
  src,
36
36
  alt: name || strings.common.userAvatar,
37
37
  loading: "lazy",
38
38
  onError: () => setErroredUrl(src),
39
- className: cx("rounded-full object-cover", SIZE_CLASSES[size])
39
+ className: clsx("rounded-full object-cover", SIZE_CLASSES[size])
40
40
  }) : /* @__PURE__ */ jsx("div", {
41
- className: cx("rounded-full flex items-center justify-center font-medium", "bg-gradient-to-br from-[var(--gradient-start,var(--theme-element))] to-[var(--gradient-mid,var(--theme-link))] text-white", SIZE_CLASSES[size]),
41
+ className: clsx("rounded-full flex items-center justify-center font-medium", "bg-gradient-to-br from-[var(--gradient-start,var(--theme-element))] to-[var(--gradient-mid,var(--theme-link))] text-white", SIZE_CLASSES[size]),
42
42
  children: size === "xs" ? avatarInitials(name).charAt(0) : avatarInitials(name)
43
43
  }), status && /* @__PURE__ */ jsx("span", {
44
44
  "data-testid": "online-indicator",
45
- className: cx("absolute bottom-0 right-0 block rounded-full ring-2 ring-(--theme-app-bg)", STATUS_CLASSES[status], size === "xs" || size === "sm" ? "w-1.5 h-1.5" : "w-2.5 h-2.5")
45
+ className: clsx("absolute bottom-0 right-0 block rounded-full ring-2 ring-(--theme-app-bg)", STATUS_CLASSES[status], size === "xs" || size === "sm" ? "w-1.5 h-1.5" : "w-2.5 h-2.5")
46
46
  })]
47
47
  });
48
48
  }
@@ -1,5 +1,5 @@
1
- import React, { createContext, useContext, useEffect, useLayoutEffect, useMemo } from "react";
2
1
  import { jsx } from "react/jsx-runtime";
2
+ import React, { createContext, useContext, useEffect, useLayoutEffect, useMemo } from "react";
3
3
  //#region src/components/Breadcrumbs.tsx
4
4
  var BreadcrumbContext = createContext({
5
5
  breadcrumbs: [],