@parallelworks/ui 0.33.0 → 0.34.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.
@@ -2,12 +2,31 @@ import { type ReactNode } from 'react';
2
2
  /** Where the conversation list goes: beside the thread, in a drawer over it,
3
3
  * or whichever fits the width the chat is given. */
4
4
  export type SidebarMode = 'inline' | 'drawer' | 'auto';
5
- export declare const DRAWER_BELOW_PX = 768;
5
+ /** The list at its default width beside the narrowest thread that still
6
+ * reads comfortably; narrower than that, 'auto' moves the list to a drawer. */
7
+ export declare const DRAWER_BELOW_PX: number;
6
8
  /** Put on the element the thread and composer sit in: their shared column
7
9
  * grows with it, from 50rem to 64rem, instead of staying 50rem on a wide
8
10
  * screen. */
9
11
  export declare const CHAT_COLUMN_SCOPE = "@container [--chat-column:clamp(50rem,60cqi,64rem)]";
10
- export default function ChatLayout({ children, sidebarActions, sidebarTop, sidebarMode, drawerBelowPx, drawerToggle, }: {
12
+ /** A conversation list beside a thread, or in a drawer over it when the
13
+ * space is narrow. The list reads where it goes from `useChat`
14
+ * (`sidebarPresentation`, `drawerOpen`); `ChatLayout` is this with the chat
15
+ * list, and a host with its own list uses it directly. Must be mounted
16
+ * inside a ChatProvider. */
17
+ export declare function ConversationLayout({ sidebar, children, sidebarMode, drawerBelowPx, drawerToggle, drawerBar, }: {
18
+ sidebar: ReactNode;
19
+ children: ReactNode;
20
+ sidebarMode?: SidebarMode;
21
+ /** The width under which 'auto' shows the drawer. */
22
+ drawerBelowPx?: number;
23
+ /** False when the host's own header opens the drawer. */
24
+ drawerToggle?: boolean;
25
+ /** Beside the drawer's toggle, while the list is a drawer: what the top of
26
+ * the list would otherwise keep in view. */
27
+ drawerBar?: ReactNode;
28
+ }): import("react").JSX.Element;
29
+ export default function ChatLayout({ children, sidebarActions, sidebarTop, sidebarMode, drawerBelowPx, drawerToggle, drawerBar, }: {
11
30
  children: ReactNode;
12
31
  sidebarActions?: boolean;
13
32
  /** Above the conversation list, given whether it is collapsed to the rail. */
@@ -19,4 +38,6 @@ export default function ChatLayout({ children, sidebarActions, sidebarTop, sideb
19
38
  drawerBelowPx?: number;
20
39
  /** False when the host's own header opens the drawer. */
21
40
  drawerToggle?: boolean;
41
+ /** Beside the drawer's toggle, while the list is a drawer. */
42
+ drawerBar?: ReactNode;
22
43
  }): import("react").JSX.Element;
@@ -8,7 +8,9 @@ import cx from "classnames";
8
8
  import { useLayoutEffect, useRef, useState } from "react";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
10
  //#region src/ai/components/ChatLayout.tsx
11
- var DRAWER_BELOW_PX = 768;
11
+ /** The list at its default width beside the narrowest thread that still
12
+ * reads comfortably; narrower than that, 'auto' moves the list to a drawer. */
13
+ var DRAWER_BELOW_PX = 896;
12
14
  /** Put on the element the thread and composer sit in: their shared column
13
15
  * grows with it, from 50rem to 64rem, instead of staying 50rem on a wide
14
16
  * screen. */
@@ -37,34 +39,49 @@ function useSidebarPresentation(ref, mode, drawerBelowPx) {
37
39
  useLayoutEffect(() => () => report("inline"), [report]);
38
40
  return presentation;
39
41
  }
40
- function ChatLayout({ children, sidebarActions = true, sidebarTop, sidebarMode = "inline", drawerBelowPx = 768, drawerToggle = true }) {
42
+ /** A conversation list beside a thread, or in a drawer over it when the
43
+ * space is narrow. The list reads where it goes from `useChat`
44
+ * (`sidebarPresentation`, `drawerOpen`); `ChatLayout` is this with the chat
45
+ * list, and a host with its own list uses it directly. Must be mounted
46
+ * inside a ChatProvider. */
47
+ function ConversationLayout({ sidebar, children, sidebarMode = "inline", drawerBelowPx = DRAWER_BELOW_PX, drawerToggle = true, drawerBar }) {
41
48
  const ref = useRef(null);
42
49
  const drawer = useSidebarPresentation(ref, sidebarMode, drawerBelowPx) === "drawer";
43
50
  const { drawerOpen, toggleSidebar } = useChat();
44
51
  const { strings } = useChatConfig();
45
- return /* @__PURE__ */ jsx(KeyboardShortcutsProvider, { children: /* @__PURE__ */ jsxs("div", {
52
+ return /* @__PURE__ */ jsxs("div", {
46
53
  ref,
47
54
  className: cx("flex h-full", drawer && "relative overflow-hidden"),
48
- children: [/* @__PURE__ */ jsx(ChatSidebar, {
49
- actions: sidebarActions,
50
- top: sidebarTop
51
- }), /* @__PURE__ */ jsxs("main", {
55
+ children: [sidebar, /* @__PURE__ */ jsxs("main", {
52
56
  inert: drawer && drawerOpen,
53
57
  className: cx("flex min-w-0 flex-1 flex-col", CHAT_COLUMN_SCOPE),
54
- children: [drawer && drawerToggle && /* @__PURE__ */ jsx("div", {
55
- className: "flex shrink-0 items-center bg-(--theme-panel-bg) px-2 pt-2",
56
- children: /* @__PURE__ */ jsx(SidebarToggle, {
58
+ children: [drawer && (drawerToggle || drawerBar) && /* @__PURE__ */ jsxs("div", {
59
+ className: "flex shrink-0 items-center gap-2 bg-(--theme-panel-bg) px-2 pt-2",
60
+ children: [drawerToggle && /* @__PURE__ */ jsx(SidebarToggle, {
57
61
  collapsed: !drawerOpen,
58
62
  onToggle: toggleSidebar,
59
63
  openLabel: strings.sidebar.openSidebar,
60
64
  closeLabel: strings.sidebar.closeSidebar
61
- })
65
+ }), drawerBar]
62
66
  }), /* @__PURE__ */ jsx("div", {
63
67
  className: "flex min-h-0 flex-1 flex-col",
64
68
  children
65
69
  })]
66
70
  })]
71
+ });
72
+ }
73
+ function ChatLayout({ children, sidebarActions = true, sidebarTop, sidebarMode = "inline", drawerBelowPx = DRAWER_BELOW_PX, drawerToggle = true, drawerBar }) {
74
+ return /* @__PURE__ */ jsx(KeyboardShortcutsProvider, { children: /* @__PURE__ */ jsx(ConversationLayout, {
75
+ sidebar: /* @__PURE__ */ jsx(ChatSidebar, {
76
+ actions: sidebarActions,
77
+ top: sidebarTop
78
+ }),
79
+ sidebarMode,
80
+ drawerBelowPx,
81
+ drawerToggle,
82
+ drawerBar,
83
+ children
67
84
  }) });
68
85
  }
69
86
  //#endregion
70
- export { CHAT_COLUMN_SCOPE, DRAWER_BELOW_PX, ChatLayout as default };
87
+ export { CHAT_COLUMN_SCOPE, ConversationLayout, DRAWER_BELOW_PX, ChatLayout as default };
@@ -11,7 +11,7 @@ import { useRowMenu } from "../../list/RowContextMenu.js";
11
11
  import { useChatConfig } from "../core/config.js";
12
12
  import { useChat } from "../core/ChatProvider.js";
13
13
  import { FOCUS_SIDEBAR_SEARCH_EVENT } from "../core/events.js";
14
- import { SidebarDrawer, SidebarRow, useRowDialogs } from "../ui/sidebar.js";
14
+ import { SidebarRow, useRowDialogs } from "../ui/sidebar.js";
15
15
  import { conversationToMarkdown, downloadText, exportFilename } from "../core/exportConversation.js";
16
16
  import { ConversationSidebar } from "../ui/ConversationSidebar.js";
17
17
  import ShareDialog from "./ShareDialog.js";
@@ -170,7 +170,12 @@ function ChatSidebar({ actions = true, top }) {
170
170
  };
171
171
  const list = /* @__PURE__ */ jsx(ConversationSidebar, {
172
172
  collapsed: sidebarCollapsed,
173
- fill: drawer,
173
+ drawer: drawer ? {
174
+ open: drawerOpen,
175
+ onClose: closeDrawer,
176
+ label: tSidebar.drawerLabel,
177
+ closeLabel: tSidebar.closeSidebar
178
+ } : void 0,
174
179
  onToggle: toggleSidebar,
175
180
  toggleLabels: {
176
181
  open: tSidebar.openSidebar,
@@ -262,13 +267,7 @@ function ChatSidebar({ actions = true, top }) {
262
267
  })
263
268
  });
264
269
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [
265
- drawer ? /* @__PURE__ */ jsx(SidebarDrawer, {
266
- open: drawerOpen,
267
- onClose: closeDrawer,
268
- label: tSidebar.drawerLabel,
269
- closeLabel: tSidebar.closeSidebar,
270
- children: list
271
- }) : sidebar !== "hidden" && list,
270
+ (drawer || sidebar !== "hidden") && list,
272
271
  contextMenu,
273
272
  dialogs,
274
273
  conversationToShare && /* @__PURE__ */ jsx(ShareDialog, {
@@ -11,7 +11,7 @@ export { default as BlockedGroupBanner } from './components/BlockedGroupBanner.j
11
11
  export { default as BranchNavigator } from './components/BranchNavigator.js';
12
12
  export { default as ChatEmptyState } from './components/ChatEmptyState.js';
13
13
  export { type ChatInputHandle, default as ChatInput, } from './components/ChatInput.js';
14
- export { CHAT_COLUMN_SCOPE, DRAWER_BELOW_PX, default as ChatLayout, type SidebarMode, } from './components/ChatLayout.js';
14
+ export { CHAT_COLUMN_SCOPE, ConversationLayout, DRAWER_BELOW_PX, default as ChatLayout, type SidebarMode, } from './components/ChatLayout.js';
15
15
  export { default as ChatMessageView } from './components/ChatMessage.js';
16
16
  export { default as ChatMessageList } from './components/ChatMessageList.js';
17
17
  export { default as ChatSidebar } from './components/ChatSidebar.js';
package/dist/ai/index.js CHANGED
@@ -39,10 +39,10 @@ import { RenameDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, Sidebar
39
39
  import { ConversationSidebar, useResizableSidebarWidth } from "./ui/ConversationSidebar.js";
40
40
  import ShareDialog, { ShareButton } from "./components/ShareDialog.js";
41
41
  import ChatSidebar from "./components/ChatSidebar.js";
42
- import ChatLayout, { CHAT_COLUMN_SCOPE, DRAWER_BELOW_PX } from "./components/ChatLayout.js";
42
+ import ChatLayout, { CHAT_COLUMN_SCOPE, ConversationLayout, DRAWER_BELOW_PX } from "./components/ChatLayout.js";
43
43
  import ChatMessage_default from "./components/ChatMessage.js";
44
44
  import ChatMessageList from "./components/ChatMessageList.js";
45
45
  import ChatThread from "./components/ChatThread.js";
46
46
  import ComposerFrame from "./components/ComposerFrame.js";
47
47
  import { NoticeBar, NoticeCard, OutputCard } from "./ui/Notice.js";
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, ChatThread, ComposerContext, ComposerControls, ComposerFrame, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, Dropdown, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarRailItem, SidebarRow, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, compactCount, computeEditDiff, computeWriteRows, defaultChatStrings, durationToAbsHumanDuration, editSummary, finalizeParts, firstNonEmptyLine, formatElapsed, formatFileSize, fullToolArgs, getGreeting, getProviderKeyFromModelId, 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, 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, ChatThread, ComposerContext, ComposerControls, ComposerFrame, 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, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarRailItem, SidebarRow, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, compactCount, computeEditDiff, computeWriteRows, defaultChatStrings, durationToAbsHumanDuration, editSummary, finalizeParts, firstNonEmptyLine, formatElapsed, formatFileSize, fullToolArgs, getGreeting, getProviderKeyFromModelId, 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, useDragDrop, useKeyboardShortcuts, useResizableSidebarWidth, useRowDialogs, wordEmphasisRanges };
@@ -19,7 +19,7 @@ export interface ConversationSidebarGroup<T> {
19
19
  /** A list of conversations beside the thread: headed groups of rows that
20
20
  * collapse to a rail, with an optional drag handle for the width. The host
21
21
  * decides what is listed, how it is grouped and how each row reads. */
22
- export declare function ConversationSidebar<T>({ label, collapsed: collapsedProp, onToggle, toggleLabels, resize, fill, groups, getKey, renderRow, loading, placeholder, top, rail, footer, cycle, groupTestId, children, }: {
22
+ export declare function ConversationSidebar<T>({ label, collapsed: collapsedProp, onToggle, toggleLabels, resize, fill: fillProp, drawer, groups, getKey, renderRow, loading, placeholder, top, rail, footer, cycle, groupTestId, children, }: {
23
23
  label?: string;
24
24
  collapsed: boolean;
25
25
  onToggle: () => void;
@@ -36,6 +36,14 @@ export declare function ConversationSidebar<T>({ label, collapsed: collapsedProp
36
36
  /** Takes the width of its container, as inside a drawer, with no rail and
37
37
  * no drag handle. */
38
38
  fill?: boolean;
39
+ /** Shows the list in a drawer over the page instead of beside it; it fills
40
+ * the drawer. */
41
+ drawer?: {
42
+ open: boolean;
43
+ onClose: () => void;
44
+ label: string;
45
+ closeLabel: string;
46
+ } | undefined;
39
47
  groups: ConversationSidebarGroup<T>[];
40
48
  getKey: (item: T) => string;
41
49
  /** One `SidebarRow`. */
@@ -1,5 +1,5 @@
1
1
  import { positionKeys } from "../../components/keys.js";
2
- import { SidebarGroupHeading, SidebarPanel, SidebarToggle } from "./sidebar.js";
2
+ import { SidebarDrawer, SidebarGroupHeading, SidebarPanel, SidebarToggle } from "./sidebar.js";
3
3
  import cx from "classnames";
4
4
  import { Fragment, useEffect, useRef, useState } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -90,12 +90,13 @@ function useItemCycling(ordered, cycle) {
90
90
  /** A list of conversations beside the thread: headed groups of rows that
91
91
  * collapse to a rail, with an optional drag handle for the width. The host
92
92
  * decides what is listed, how it is grouped and how each row reads. */
93
- function ConversationSidebar({ label, collapsed: collapsedProp, onToggle, toggleLabels, resize, fill = false, groups, getKey, renderRow, loading = false, placeholder, top, rail, footer, cycle, groupTestId, children }) {
93
+ function ConversationSidebar({ label, collapsed: collapsedProp, onToggle, toggleLabels, resize, fill: fillProp = false, drawer, groups, getKey, renderRow, loading = false, placeholder, top, rail, footer, cycle, groupTestId, children }) {
94
94
  const sized = useResizableSidebarWidth(resize?.storageKey ?? "");
95
95
  useItemCycling(groups.flatMap((g) => g.items), cycle);
96
+ const fill = fillProp || !!drawer;
96
97
  const collapsed = collapsedProp && !fill;
97
98
  const resizable = resize && !fill;
98
- return /* @__PURE__ */ jsxs(SidebarPanel, {
99
+ const panel = /* @__PURE__ */ jsxs(SidebarPanel, {
99
100
  collapsed,
100
101
  label,
101
102
  ...resizable ? {
@@ -160,6 +161,13 @@ function ConversationSidebar({ label, collapsed: collapsedProp, onToggle, toggle
160
161
  children
161
162
  ]
162
163
  });
164
+ return drawer ? /* @__PURE__ */ jsx(SidebarDrawer, {
165
+ open: drawer.open,
166
+ onClose: drawer.onClose,
167
+ label: drawer.label,
168
+ closeLabel: drawer.closeLabel,
169
+ children: panel
170
+ }) : panel;
163
171
  }
164
172
  //#endregion
165
173
  export { ConversationSidebar, useResizableSidebarWidth };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parallelworks/ui",
3
- "version": "0.33.0",
3
+ "version": "0.34.0",
4
4
  "description": "React UI components: a theme contract, icons, primitives, lists, forms, a job graph, a code editor, a log viewer, a file explorer and an AI chat, each on its own subpath",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {