ai-design-system 0.1.110 → 0.1.112

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.
@@ -17,33 +17,82 @@ import {
17
17
  PopoverTrigger,
18
18
  } from "@/components/primitives/Popover"
19
19
 
20
- export interface Project {
20
+ export interface ProjectSwitcherItem {
21
21
  id: string
22
22
  name: string
23
+ [key: string]: unknown
23
24
  }
24
25
 
26
+ // Backwards compatibility alias
27
+ export type Project = ProjectSwitcherItem
28
+
25
29
  export interface ProjectSwitcherProps {
26
- projects: Project[]
30
+ /** List of projects / channels / workspaces to switch between */
31
+ projects?: ProjectSwitcherItem[]
32
+ /** Generic alias for projects */
33
+ items?: ProjectSwitcherItem[]
34
+ /** ID of the currently selected item */
27
35
  selectedProjectId?: string | null
28
- onSelectProject: (id: string) => void
29
- onCreateProject: () => void
36
+ /** Generic alias for selectedProjectId */
37
+ selectedId?: string | null
38
+ /** Callback fired when an item is selected */
39
+ onSelectProject?: (id: string) => void
40
+ /** Generic alias for onSelectProject */
41
+ onSelect?: (id: string) => void
42
+ /** Callback fired when creating a new item */
43
+ onCreateProject?: () => void
44
+ /** Generic alias for onCreateProject */
45
+ onCreate?: () => void
46
+ /** Custom CSS class names */
30
47
  className?: string
48
+ /**
49
+ * Domain entity name used to automatically derive labels (e.g. "Project", "Channel", "Workspace").
50
+ * @default "Project"
51
+ */
52
+ entityName?: string
53
+ /** Placeholder when nothing is selected. Defaults to "Select <entityName>..." */
54
+ placeholder?: string
55
+ /** Search input placeholder. Defaults to "Find <entityName>..." */
56
+ searchPlaceholder?: string
57
+ /** Empty state message. Defaults to "No <entityName.toLowerCase()>s, yet!" */
58
+ emptyMessage?: string
59
+ /** Create button label. Defaults to "Create <entityName>" */
60
+ createButtonText?: string
31
61
  }
32
62
 
33
63
  export const ProjectSwitcher = React.memo<ProjectSwitcherProps>(
34
64
  ({
35
- projects = [],
65
+ projects,
66
+ items,
36
67
  selectedProjectId,
37
- onSelectProject = () => {},
38
- onCreateProject = () => {},
68
+ selectedId,
69
+ onSelectProject,
70
+ onSelect,
71
+ onCreateProject,
72
+ onCreate,
39
73
  className,
74
+ entityName = "Project",
75
+ placeholder,
76
+ searchPlaceholder,
77
+ emptyMessage,
78
+ createButtonText,
40
79
  }) => {
41
80
  const [open, setOpen] = React.useState(false)
42
81
 
43
- const selectedProject = projects.find((p) => String(p.id) === String(selectedProjectId))
44
- const displayLabel = selectedProject ? selectedProject.name : "Select Project..."
82
+ const list = items ?? projects ?? []
83
+ const activeId = selectedId !== undefined ? selectedId : selectedProjectId
84
+ const handleSelect = onSelect ?? onSelectProject ?? (() => {})
85
+ const handleCreate = onCreate ?? onCreateProject ?? (() => {})
86
+
87
+ const resolvedPlaceholder = placeholder ?? `Select ${entityName}...`
88
+ const resolvedSearchPlaceholder = searchPlaceholder ?? `Find ${entityName}...`
89
+ const resolvedEmptyMessage = emptyMessage ?? `No ${entityName.toLowerCase()}s, yet!`
90
+ const resolvedCreateButtonText = createButtonText ?? `Create ${entityName}`
91
+
92
+ const selectedItem = list.find((p) => String(p.id) === String(activeId))
93
+ const displayLabel = selectedItem ? selectedItem.name : resolvedPlaceholder
45
94
 
46
- const defaultValue = selectedProject ? `${selectedProject.name}-${selectedProject.id}` : undefined
95
+ const defaultValue = selectedItem ? `${selectedItem.name}-${selectedItem.id}` : undefined
47
96
 
48
97
  return (
49
98
  <Popover open={open} onOpenChange={setOpen}>
@@ -64,7 +113,7 @@ export const ProjectSwitcher = React.memo<ProjectSwitcherProps>(
64
113
  <Command defaultValue={defaultValue}>
65
114
  <div className="flex items-center justify-between border-b border-neutral-600 px-3" cmdk-input-wrapper="">
66
115
  <CommandPrimitive.Input
67
- placeholder="Find Project..."
116
+ placeholder={resolvedSearchPlaceholder}
68
117
  className="flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
69
118
  />
70
119
  <kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-neutral-700 bg-neutral-800 px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100">Esc</kbd>
@@ -72,27 +121,28 @@ export const ProjectSwitcher = React.memo<ProjectSwitcherProps>(
72
121
  <CommandList className="max-h-[300px]">
73
122
  <CommandEmpty>
74
123
  <div className="flex flex-col items-center justify-center p-6 text-center text-sm text-muted-foreground">
75
- No projects, yet!
124
+ {resolvedEmptyMessage}
76
125
  </div>
77
126
  </CommandEmpty>
78
- {projects.length > 0 && (
127
+ {list.length > 0 && (
79
128
  <CommandGroup>
80
- {projects.map((project) => (
129
+ {list.map((item) => (
81
130
  <CommandItem
82
- key={project.id}
83
- value={`${project.name}-${project.id}`}
131
+ key={item.id}
132
+ value={`${item.name}-${item.id}`}
84
133
  onSelect={() => {
85
- onSelectProject(project.id)
134
+ handleSelect(item.id)
86
135
  setOpen(false)
87
136
  }}
88
137
  className="mb-1 last:mb-0 cursor-pointer flex items-center justify-between"
89
138
  >
90
139
  <div className="flex items-center">
91
- {project.name}
140
+ {item.name}
92
141
  </div>
93
- <Icon name="check"
142
+ <Icon
143
+ name="check"
94
144
  className={`h-4 w-4 ${
95
- String(selectedProjectId) === String(project.id) ? "opacity-100" : "opacity-0"
145
+ String(activeId) === String(item.id) ? "opacity-100" : "opacity-0"
96
146
  }`}
97
147
  />
98
148
  </CommandItem>
@@ -107,11 +157,11 @@ export const ProjectSwitcher = React.memo<ProjectSwitcherProps>(
107
157
  className="w-full justify-start text-sm font-normal"
108
158
  onClick={() => {
109
159
  setOpen(false)
110
- onCreateProject()
160
+ handleCreate()
111
161
  }}
112
162
  >
113
163
  <Icon name="plus" size="sm" className="mr-2 h-4 w-4" />
114
- Create Project
164
+ {resolvedCreateButtonText}
115
165
  </Button>
116
166
  </div>
117
167
  </Command>
@@ -28,6 +28,8 @@ export interface SessionHeaderProps extends React.HTMLAttributes<HTMLDivElement>
28
28
  onSelectSession?: (id: string) => void;
29
29
  onDownloadSession?: () => Promise<FileDownloadResult | undefined>;
30
30
  showActions?: boolean;
31
+ showNewSession?: boolean;
32
+ showDownloadSession?: boolean;
31
33
  }
32
34
 
33
35
  /**
@@ -37,7 +39,7 @@ export interface SessionHeaderProps extends React.HTMLAttributes<HTMLDivElement>
37
39
  * and a dropdown history of past sessions.
38
40
  */
39
41
  export const SessionHeader = React.forwardRef<HTMLDivElement, SessionHeaderProps>(
40
- ({ title, sessions, activeSessionId, onNewSession, onCloseSession, onSelectSession, onDownloadSession, showActions = true, className, ...props }, ref) => {
42
+ ({ title, sessions, activeSessionId, onNewSession, onCloseSession, onSelectSession, onDownloadSession, showActions = true, showNewSession = true, showDownloadSession = true, className, ...props }, ref) => {
41
43
  const activeSession = sessions?.find(s => s.id === activeSessionId);
42
44
  const downloadRef = React.useRef<HTMLAnchorElement>(null);
43
45
 
@@ -72,14 +74,16 @@ export const SessionHeader = React.forwardRef<HTMLDivElement, SessionHeaderProps
72
74
  </div>
73
75
  {showActions && (
74
76
  <div className="flex items-center space-x-1 flex-none">
75
- {onDownloadSession && (
77
+ {Boolean(onDownloadSession && showDownloadSession) && (
76
78
  <Button variant="ghost" size="icon" onClick={handleDownloadClick} className="h-8 w-8" title="Download Chat History">
77
79
  <Icon name="download" className="h-4 w-4" />
78
80
  </Button>
79
81
  )}
80
- <Button variant="ghost" size="icon" onClick={onNewSession} className="h-8 w-8" title="New Session">
81
- <Icon name="plus" className="h-4 w-4" />
82
- </Button>
82
+ {Boolean(onNewSession && showNewSession) && (
83
+ <Button variant="ghost" size="icon" onClick={onNewSession} className="h-8 w-8" title="New Session">
84
+ <Icon name="plus" className="h-4 w-4" />
85
+ </Button>
86
+ )}
83
87
 
84
88
  <DropdownMenu>
85
89
  <DropdownMenuTrigger asChild>
@@ -196,7 +196,7 @@ export type { EmptyStateProps } from './EmptyState'
196
196
 
197
197
  // ProjectSwitcher Composite
198
198
  export { ProjectSwitcher } from './ProjectSwitcher'
199
- export type { ProjectSwitcherProps, Project } from './ProjectSwitcher'
199
+ export type { ProjectSwitcherProps, ProjectSwitcherItem, Project } from './ProjectSwitcher'
200
200
 
201
201
  // DashboardChart Composite
202
202
  export { DashboardChart } from './DashboardChart'
@@ -225,6 +225,16 @@ export interface ChatPanelProps {
225
225
  * @default true
226
226
  */
227
227
  showSessionActions?: boolean;
228
+ /**
229
+ * Whether to show the new session (+) action in the session header
230
+ * @default true
231
+ */
232
+ showNewSession?: boolean;
233
+ /**
234
+ * Whether to show the download session action in the session header
235
+ * @default true
236
+ */
237
+ showDownloadSession?: boolean;
228
238
  /**
229
239
  * Presentation variant for ChatPanel:
230
240
  * - "default": standard full flex-1 panel (default)
@@ -286,6 +296,8 @@ export const ChatPanel = React.memo<ChatPanelProps>(
286
296
  showHeader = true,
287
297
  sessionTitle,
288
298
  showSessionActions = true,
299
+ showNewSession = true,
300
+ showDownloadSession = true,
289
301
  variant = "default",
290
302
  onClose,
291
303
  }) => {
@@ -446,6 +458,8 @@ export const ChatPanel = React.memo<ChatPanelProps>(
446
458
  <SessionHeader
447
459
  title={sessionTitle}
448
460
  showActions={showSessionActions}
461
+ showNewSession={showNewSession}
462
+ showDownloadSession={showDownloadSession}
449
463
  sessions={sessions}
450
464
  activeSessionId={activeSessionId}
451
465
  onNewSession={onNewSession}
@@ -54,6 +54,7 @@ export type {
54
54
  ActionRequest,
55
55
  ReviewConfig,
56
56
  ProjectSwitcherProps,
57
+ ProjectSwitcherItem,
57
58
  Project,
58
59
  FormReportsDrawerFormProps,
59
60
  SessionHeaderProps,
package/dist/index.cjs CHANGED
@@ -2832,18 +2832,36 @@ var Popover2 = (props) => {
2832
2832
  Popover2.displayName = "Popover";
2833
2833
  var ProjectSwitcher = React3__namespace.memo(
2834
2834
  ({
2835
- projects = [],
2835
+ projects,
2836
+ items,
2836
2837
  selectedProjectId,
2837
- onSelectProject = () => {
2838
- },
2839
- onCreateProject = () => {
2840
- },
2841
- className
2838
+ selectedId,
2839
+ onSelectProject,
2840
+ onSelect,
2841
+ onCreateProject,
2842
+ onCreate,
2843
+ className,
2844
+ entityName = "Project",
2845
+ placeholder,
2846
+ searchPlaceholder,
2847
+ emptyMessage,
2848
+ createButtonText
2842
2849
  }) => {
2850
+ var _a, _b, _c;
2843
2851
  const [open, setOpen] = React3__namespace.useState(false);
2844
- const selectedProject = projects.find((p) => String(p.id) === String(selectedProjectId));
2845
- const displayLabel = selectedProject ? selectedProject.name : "Select Project...";
2846
- const defaultValue = selectedProject ? `${selectedProject.name}-${selectedProject.id}` : void 0;
2852
+ const list = (_a = items != null ? items : projects) != null ? _a : [];
2853
+ const activeId = selectedId !== void 0 ? selectedId : selectedProjectId;
2854
+ const handleSelect = (_b = onSelect != null ? onSelect : onSelectProject) != null ? _b : (() => {
2855
+ });
2856
+ const handleCreate = (_c = onCreate != null ? onCreate : onCreateProject) != null ? _c : (() => {
2857
+ });
2858
+ const resolvedPlaceholder = placeholder != null ? placeholder : `Select ${entityName}...`;
2859
+ const resolvedSearchPlaceholder = searchPlaceholder != null ? searchPlaceholder : `Find ${entityName}...`;
2860
+ const resolvedEmptyMessage = emptyMessage != null ? emptyMessage : `No ${entityName.toLowerCase()}s, yet!`;
2861
+ const resolvedCreateButtonText = createButtonText != null ? createButtonText : `Create ${entityName}`;
2862
+ const selectedItem = list.find((p) => String(p.id) === String(activeId));
2863
+ const displayLabel = selectedItem ? selectedItem.name : resolvedPlaceholder;
2864
+ const defaultValue = selectedItem ? `${selectedItem.name}-${selectedItem.id}` : void 0;
2847
2865
  return /* @__PURE__ */ jsxRuntime.jsxs(Popover2, { open, onOpenChange: setOpen, children: [
2848
2866
  /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
2849
2867
  Button2,
@@ -2863,35 +2881,35 @@ var ProjectSwitcher = React3__namespace.memo(
2863
2881
  /* @__PURE__ */ jsxRuntime.jsx(
2864
2882
  cmdk.Command.Input,
2865
2883
  {
2866
- placeholder: "Find Project...",
2884
+ placeholder: resolvedSearchPlaceholder,
2867
2885
  className: "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
2868
2886
  }
2869
2887
  ),
2870
2888
  /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-neutral-700 bg-neutral-800 px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100", children: "Esc" })
2871
2889
  ] }),
2872
2890
  /* @__PURE__ */ jsxRuntime.jsxs(CommandList2, { className: "max-h-[300px]", children: [
2873
- /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty2, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-center justify-center p-6 text-center text-sm text-muted-foreground", children: "No projects, yet!" }) }),
2874
- projects.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(CommandGroup2, { children: projects.map((project) => /* @__PURE__ */ jsxRuntime.jsxs(
2891
+ /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty2, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-center justify-center p-6 text-center text-sm text-muted-foreground", children: resolvedEmptyMessage }) }),
2892
+ list.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(CommandGroup2, { children: list.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
2875
2893
  CommandItem2,
2876
2894
  {
2877
- value: `${project.name}-${project.id}`,
2895
+ value: `${item.name}-${item.id}`,
2878
2896
  onSelect: () => {
2879
- onSelectProject(project.id);
2897
+ handleSelect(item.id);
2880
2898
  setOpen(false);
2881
2899
  },
2882
2900
  className: "mb-1 last:mb-0 cursor-pointer flex items-center justify-between",
2883
2901
  children: [
2884
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: project.name }),
2902
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: item.name }),
2885
2903
  /* @__PURE__ */ jsxRuntime.jsx(
2886
2904
  Icon,
2887
2905
  {
2888
2906
  name: "check",
2889
- className: `h-4 w-4 ${String(selectedProjectId) === String(project.id) ? "opacity-100" : "opacity-0"}`
2907
+ className: `h-4 w-4 ${String(activeId) === String(item.id) ? "opacity-100" : "opacity-0"}`
2890
2908
  }
2891
2909
  )
2892
2910
  ]
2893
2911
  },
2894
- project.id
2912
+ item.id
2895
2913
  )) })
2896
2914
  ] }),
2897
2915
  /* @__PURE__ */ jsxRuntime.jsx(CommandSeparator2, {}),
@@ -2902,11 +2920,11 @@ var ProjectSwitcher = React3__namespace.memo(
2902
2920
  className: "w-full justify-start text-sm font-normal",
2903
2921
  onClick: () => {
2904
2922
  setOpen(false);
2905
- onCreateProject();
2923
+ handleCreate();
2906
2924
  },
2907
2925
  children: [
2908
2926
  /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "plus", size: "sm", className: "mr-2 h-4 w-4" }),
2909
- "Create Project"
2927
+ resolvedCreateButtonText
2910
2928
  ]
2911
2929
  }
2912
2930
  ) })
@@ -7921,7 +7939,7 @@ var ApprovalCard = React3__namespace.memo(
7921
7939
  ApprovalCard.displayName = "ApprovalCard";
7922
7940
  var SessionHeader = React3__namespace.forwardRef(
7923
7941
  (_a, ref) => {
7924
- var _b = _a, { title, sessions, activeSessionId, onNewSession, onCloseSession, onSelectSession, onDownloadSession, showActions = true, className } = _b, props = __objRest(_b, ["title", "sessions", "activeSessionId", "onNewSession", "onCloseSession", "onSelectSession", "onDownloadSession", "showActions", "className"]);
7942
+ var _b = _a, { title, sessions, activeSessionId, onNewSession, onCloseSession, onSelectSession, onDownloadSession, showActions = true, showNewSession = true, showDownloadSession = true, className } = _b, props = __objRest(_b, ["title", "sessions", "activeSessionId", "onNewSession", "onCloseSession", "onSelectSession", "onDownloadSession", "showActions", "showNewSession", "showDownloadSession", "className"]);
7925
7943
  const activeSession = sessions == null ? void 0 : sessions.find((s) => s.id === activeSessionId);
7926
7944
  const downloadRef = React3__namespace.useRef(null);
7927
7945
  const handleDownloadClick = React3__namespace.useCallback(async () => {
@@ -7947,8 +7965,8 @@ var SessionHeader = React3__namespace.forwardRef(
7947
7965
  children: [
7948
7966
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center space-x-2 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium truncate", children: displayTitle }) }),
7949
7967
  showActions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-1 flex-none", children: [
7950
- onDownloadSession && /* @__PURE__ */ jsxRuntime.jsx(Button2, { variant: "ghost", size: "icon", onClick: handleDownloadClick, className: "h-8 w-8", title: "Download Chat History", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "download", className: "h-4 w-4" }) }),
7951
- /* @__PURE__ */ jsxRuntime.jsx(Button2, { variant: "ghost", size: "icon", onClick: onNewSession, className: "h-8 w-8", title: "New Session", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "plus", className: "h-4 w-4" }) }),
7968
+ Boolean(onDownloadSession && showDownloadSession) && /* @__PURE__ */ jsxRuntime.jsx(Button2, { variant: "ghost", size: "icon", onClick: handleDownloadClick, className: "h-8 w-8", title: "Download Chat History", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "download", className: "h-4 w-4" }) }),
7969
+ Boolean(onNewSession && showNewSession) && /* @__PURE__ */ jsxRuntime.jsx(Button2, { variant: "ghost", size: "icon", onClick: onNewSession, className: "h-8 w-8", title: "New Session", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "plus", className: "h-4 w-4" }) }),
7952
7970
  /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu2, { children: [
7953
7971
  /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button2, { variant: "ghost", size: "icon", className: "h-8 w-8", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "clock", className: "h-4 w-4" }) }) }),
7954
7972
  /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuContent, { align: "end", className: "w-64 max-h-80 overflow-y-auto", children: [
@@ -8180,6 +8198,8 @@ var ChatPanel = React3__namespace.memo(
8180
8198
  showHeader = true,
8181
8199
  sessionTitle,
8182
8200
  showSessionActions = true,
8201
+ showNewSession = true,
8202
+ showDownloadSession = true,
8183
8203
  variant = "default",
8184
8204
  onClose
8185
8205
  }) => {
@@ -8305,6 +8325,8 @@ var ChatPanel = React3__namespace.memo(
8305
8325
  {
8306
8326
  title: sessionTitle,
8307
8327
  showActions: showSessionActions,
8328
+ showNewSession,
8329
+ showDownloadSession,
8308
8330
  sessions,
8309
8331
  activeSessionId,
8310
8332
  onNewSession,