@sqlrooms/ui 0.29.0-rc.5 → 0.29.0-rc.7

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.
@@ -21,6 +21,21 @@ function useTabStripContext() {
21
21
  }
22
22
  return context;
23
23
  }
24
+ function useOptionalTabStripContext() {
25
+ return useContext(TabStripContext);
26
+ }
27
+ function getFontSizeStyle(fontSize) {
28
+ return fontSize === undefined
29
+ ? undefined
30
+ : { fontSize };
31
+ }
32
+ function mergeFontSizeStyle(fontSize, style) {
33
+ if (fontSize === undefined)
34
+ return style;
35
+ if (style === undefined)
36
+ return { fontSize };
37
+ return { ...style, fontSize: style?.fontSize ?? fontSize };
38
+ }
24
39
  const DEFAULT_TAB_DRAG_KIND = 'sqlrooms.tab';
25
40
  const TAB_STRIP_BUTTON_CLASSNAMES = [
26
41
  'flex h-full min-w-0 min-h-7 items-center',
@@ -30,7 +45,7 @@ const TAB_STRIP_BUTTON_CLASSNAMES = [
30
45
  /**
31
46
  * A single sortable tab item.
32
47
  */
33
- function SortableTab({ tab, sortableId, tabClassName, editingTabId, closeable = true, onClose, onStartEditing, onStopEditing, onInlineRename, renderTabTitle, renderTabMenu, renderTabLabel, dndScopeId, getTabDragData, }) {
48
+ function SortableTab({ tab, sortableId, tabClassName, editingTabId, closeable = true, onClose, onActivate, onStartEditing, onStopEditing, onInlineRename, renderTabMenu, renderTabLabel, dndScopeId, getTabDragData, fontSize, }) {
34
49
  const tabDragData = getTabDragData?.(tab);
35
50
  const isEditing = editingTabId === tab.id;
36
51
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
@@ -52,16 +67,17 @@ function SortableTab({ tab, sortableId, tabClassName, editingTabId, closeable =
52
67
  opacity: isDragging ? 0.5 : 1,
53
68
  };
54
69
  const menuContent = renderTabMenu?.(tab);
55
- return (_jsx("div", { ref: setNodeRef, className: "h-full shrink-0", style: style, "data-tab-id": tab.id, ...(isEditing ? {} : attributes), ...(isEditing ? {} : listeners), tabIndex: -1, children: _jsx("div", { "data-state": isEditing ? 'editing' : undefined, className: cn('data-[state=inactive]:hover:bg-primary/5', 'group flex h-full max-w-[200px] min-w-[100px] shrink-0 cursor-grab', 'items-center justify-between gap-1 overflow-hidden rounded-b-none', 'py-0 pr-1 pl-4 font-normal data-[state=active]:shadow-none', tabClassName, isEditing && 'focus-visible:ring-0'), children: _jsxs("div", { className: "relative flex h-full min-w-0 flex-1 items-center", children: [_jsx(TabsTrigger, { value: tab.id, tabIndex: isEditing ? -1 : undefined, "data-editing": isEditing ? '' : undefined, className: cn(...TAB_STRIP_BUTTON_CLASSNAMES, 'flex-1 justify-start gap-1', 'data-[state=active]:bg-primary/10 data-[state=active]:text-foreground data-[state=active]:shadow-none', isEditing && 'focus-visible:ring-0'), onDoubleClick: () => onStartEditing(tab.id), children: !isEditing ? (_jsx("div", { className: "truncate text-sm", children: renderTabLabel ? renderTabLabel(tab) : tab.name })) : (_jsx(EditableText, { value: tab.name, onChange: (newName) => onInlineRename(tab.id, newName), className: "h-6 min-w-0 flex-1 truncate text-sm shadow-none", isEditing: true, autoFocus: true, selectOnFocus: true, allowTabFocusWhenNotEditing: false, onEditingChange: (isEditing) => {
70
+ const fontSizeStyle = getFontSizeStyle(fontSize);
71
+ return (_jsx("div", { ref: setNodeRef, className: "h-full shrink-0", style: style, "data-tab-id": tab.id, ...(isEditing ? {} : attributes), ...(isEditing ? {} : listeners), tabIndex: -1, children: _jsx("div", { "data-state": isEditing ? 'editing' : undefined, className: cn('data-[state=inactive]:hover:bg-primary/5', 'group/tab flex h-full max-w-[200px] min-w-[100px] shrink-0 cursor-grab', 'items-center justify-between gap-1 overflow-hidden rounded-b-none', 'py-0 pr-1 font-normal data-[state=active]:shadow-none', tabClassName, isEditing && 'focus-visible:ring-0'), children: _jsxs("div", { className: "relative flex h-full min-w-0 flex-1 items-center", children: [_jsx(TabsTrigger, { value: tab.id, tabIndex: isEditing ? -1 : undefined, "data-editing": isEditing ? '' : undefined, className: cn(...TAB_STRIP_BUTTON_CLASSNAMES, 'flex-1 gap-1', isEditing ? 'justify-start' : 'justify-center text-center', 'data-[state=active]:bg-primary/10 data-[state=active]:text-foreground data-[state=active]:shadow-none', isEditing && 'focus-visible:ring-0'), style: fontSizeStyle, onClick: () => onActivate(tab.id), onDoubleClick: () => onStartEditing(tab.id), children: !isEditing ? (_jsx("div", { className: "min-w-0 flex-1 truncate text-center", children: renderTabLabel ? renderTabLabel(tab) : tab.name })) : (_jsx(EditableText, { value: tab.name, onChange: (newName) => onInlineRename(tab.id, newName), className: "h-6 min-w-0 flex-1 truncate shadow-none", style: fontSizeStyle, isEditing: true, autoFocus: true, selectOnFocus: true, allowTabFocusWhenNotEditing: false, onEditingChange: (isEditing) => {
56
72
  if (!isEditing) {
57
73
  onStopEditing();
58
74
  }
59
- } })) }), _jsxs("div", { className: "flex shrink-0 items-center", children: [menuContent && (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": "Tab options", className: "hover:bg-primary/10 focus-visible:bg-primary/10 focus-visible:ring-ring absolute top-1/2 left-1 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded p-1 opacity-0 outline-hidden group-hover:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-offset-0 data-[state=open]:opacity-100", onMouseDown: (event) => {
75
+ } })) }), _jsxs("div", { className: "flex shrink-0 items-center", children: [menuContent && (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": "Tab options", className: "hover:bg-primary/10 focus-visible:bg-primary/10 focus-visible:ring-ring absolute top-1/2 left-1 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded p-1 opacity-0 outline-hidden group-hover/tab:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-offset-0 data-[state=open]:opacity-100", onMouseDown: (event) => {
60
76
  event.stopPropagation();
61
77
  event.preventDefault();
62
78
  }, onClick: (event) => {
63
79
  event.stopPropagation();
64
- }, children: _jsx(EllipsisVerticalIcon, { className: "h-3 w-3" }) }) }), _jsx(DropdownMenuContent, { align: "start", children: menuContent })] })), closeable && (_jsx("button", { type: "button", "aria-label": "Close tab", className: "hover:bg-primary/10 focus-visible:bg-primary/10 focus-visible:ring-ring absolute top-1/2 right-1 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded p-1 opacity-0 outline-hidden group-hover:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-offset-0", onMouseDown: (event) => {
80
+ }, children: _jsx(EllipsisVerticalIcon, { className: "h-3 w-3" }) }) }), _jsx(DropdownMenuContent, { align: "start", style: fontSizeStyle, children: menuContent })] })), closeable && (_jsx("button", { type: "button", "aria-label": "Close tab", className: "hover:bg-primary/10 focus-visible:bg-primary/10 focus-visible:ring-ring absolute top-1/2 right-1 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded p-1 opacity-0 outline-hidden group-hover/tab:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-offset-0", onMouseDown: (event) => {
65
81
  event.stopPropagation();
66
82
  event.preventDefault();
67
83
  }, onClick: (event) => {
@@ -74,10 +90,11 @@ function SortableTab({ tab, sortableId, tabClassName, editingTabId, closeable =
74
90
  * A menu item for the tab's dropdown menu.
75
91
  */
76
92
  function TabStripMenuItem({ children, onClick, variant = 'default', className, disabled, }) {
93
+ const { fontSize } = useTabStripContext();
77
94
  return (_jsx(DropdownMenuItem, { disabled: disabled, onClick: (event) => {
78
95
  event.stopPropagation();
79
96
  onClick?.();
80
- }, className: cn(variant === 'destructive' && 'text-destructive focus:text-destructive', className), children: children }));
97
+ }, className: cn(variant === 'destructive' && 'text-destructive focus:text-destructive', className), style: getFontSizeStyle(fontSize), children: children }));
81
98
  }
82
99
  /**
83
100
  * A separator for the tab's dropdown menu.
@@ -98,7 +115,7 @@ function TabStripSearchItemAction({ icon, onClick, 'aria-label': ariaLabel, clas
98
115
  * Renders the scrollable row of open tabs with drag-to-reorder support.
99
116
  */
100
117
  function TabStripTabs({ className, tabClassName }) {
101
- const { openTabItems, editingTabId, scrollContainerRef, onOpenTabsChange, dndMode, dndScopeId, getTabDragData, renderTabTitle, renderTabMenu, renderTabLabel, preventCloseLastTab, closeable, handleStartEditing, handleStopEditing, handleInlineRename, handleClose, } = useTabStripContext();
118
+ const { openTabItems, editingTabId, scrollContainerRef, onOpenTabsChange, dndMode, dndScopeId, getTabDragData, renderTabMenu, renderTabLabel, preventCloseLastTab, closeable, fontSize, handleStartEditing, handleStopEditing, handleInlineRename, handleClose, onActivate, } = useTabStripContext();
102
119
  const sensors = useSensors(useSensor(PointerSensor, {
103
120
  activationConstraint: {
104
121
  distance: 5, // 5px movement before drag starts (allows clicks)
@@ -153,12 +170,12 @@ function TabStripTabs({ className, tabClassName }) {
153
170
  const tabIds = useMemo(() => openTabItems.map((t) => getSortableId(t.id)),
154
171
  // eslint-disable-next-line react-hooks/exhaustive-deps
155
172
  [openTabItems, dndMode, dndScopeId]);
156
- const content = (_jsx(SortableContext, { items: tabIds, strategy: horizontalListSortingStrategy, children: _jsx(ScrollableRow, { className: "h-full min-w-0 shrink overflow-hidden", scrollRef: scrollContainerRef, scrollClassName: cn('flex h-full min-w-0 items-center gap-1 overflow-x-auto overflow-y-visible', 'pl-1 pr-1 scroll-pl-7 scroll-pr-7 [&::-webkit-scrollbar]:hidden', className), arrowVisibility: "always", arrowClassName: "w-7", arrowIconClassName: "h-4 w-4 opacity-60", children: openTabItems.map((tab) => (_jsx(SortableTab, { tab: tab, sortableId: getSortableId(tab.id), tabClassName: tabClassName, editingTabId: editingTabId, closeable: closeable && !(preventCloseLastTab && openTabItems.length === 1), onClose: handleClose, onStartEditing: handleStartEditing, onStopEditing: handleStopEditing, onInlineRename: handleInlineRename, renderTabTitle: renderTabTitle, renderTabMenu: renderTabMenu, renderTabLabel: renderTabLabel, dndScopeId: dndScopeId, getTabDragData: getTabDragData }, tab.id))) }) }));
173
+ const content = (_jsx(SortableContext, { items: tabIds, strategy: horizontalListSortingStrategy, children: _jsx(ScrollableRow, { className: "h-full min-w-0 shrink overflow-hidden", scrollRef: scrollContainerRef, scrollClassName: cn('flex h-full min-w-0 items-center gap-1 overflow-x-auto overflow-y-visible', 'pl-1 pr-1 scroll-pl-7 scroll-pr-7 [&::-webkit-scrollbar]:hidden', className), arrowVisibility: "always", arrowClassName: "w-7", arrowIconClassName: "h-4 w-4 opacity-60", children: openTabItems.map((tab) => (_jsx(SortableTab, { tab: tab, sortableId: getSortableId(tab.id), tabClassName: tabClassName, editingTabId: editingTabId, closeable: closeable && !(preventCloseLastTab && openTabItems.length === 1), onClose: handleClose, onActivate: onActivate ?? (() => undefined), onStartEditing: handleStartEditing, onStopEditing: handleStopEditing, onInlineRename: handleInlineRename, renderTabMenu: renderTabMenu, renderTabLabel: renderTabLabel, dndScopeId: dndScopeId, getTabDragData: getTabDragData, fontSize: fontSize }, tab.id))) }) }));
157
174
  if (dndMode === 'shared') {
158
175
  const activeDraggedTab = activeDraggedTabId
159
176
  ? openTabItems.find((tab) => tab.id === activeDraggedTabId)
160
177
  : undefined;
161
- return (_jsxs(_Fragment, { children: [_jsx(SharedTabStripDndMonitor, { dndScopeId: dndScopeId, handleDragEnd: handleDragEnd, setActiveDraggedTabId: setActiveDraggedTabId, setHideSharedDragOverlay: setHideSharedDragOverlay, shouldHideSharedDragOverlay: shouldHideSharedDragOverlay }), content, _jsx(DragOverlay, { dropAnimation: null, children: activeDraggedTab && !hideSharedDragOverlay ? (_jsx(TabDragOverlay, { tab: activeDraggedTab, renderTabLabel: renderTabLabel })) : null })] }));
178
+ return (_jsxs(_Fragment, { children: [_jsx(SharedTabStripDndMonitor, { dndScopeId: dndScopeId, handleDragEnd: handleDragEnd, setActiveDraggedTabId: setActiveDraggedTabId, setHideSharedDragOverlay: setHideSharedDragOverlay, shouldHideSharedDragOverlay: shouldHideSharedDragOverlay }), content, _jsx(DragOverlay, { dropAnimation: null, children: activeDraggedTab && !hideSharedDragOverlay ? (_jsx(TabDragOverlay, { tab: activeDraggedTab, renderTabLabel: renderTabLabel, fontSize: fontSize })) : null })] }));
162
179
  }
163
180
  return (_jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, modifiers: DRAG_MODIFIERS, autoScroll: true, onDragEnd: handleDragEnd, children: content }));
164
181
  }
@@ -197,15 +214,16 @@ function SharedTabStripDndMonitor({ dndScopeId, handleDragEnd, setActiveDraggedT
197
214
  });
198
215
  return null;
199
216
  }
200
- function TabDragOverlay({ tab, renderTabLabel, }) {
201
- return (_jsx("div", { className: cn('bg-primary/15 text-foreground border-primary/50 flex h-7 max-w-[200px] min-w-[100px]', 'cursor-grabbing items-center justify-center gap-1 overflow-hidden rounded-md border px-6 py-1', 'text-sm shadow-lg'), children: _jsx("div", { className: "truncate text-center", children: renderTabLabel ? renderTabLabel(tab) : tab.name }) }));
217
+ function TabDragOverlay({ tab, renderTabLabel, fontSize, }) {
218
+ return (_jsx("div", { className: cn('bg-primary/15 text-foreground border-primary/50 flex h-7 max-w-[200px] min-w-[100px]', 'cursor-grabbing items-center justify-center gap-1 overflow-hidden rounded-md border px-6 py-1', 'text-sm shadow-lg'), style: getFontSizeStyle(fontSize), children: _jsx("div", { className: "truncate text-center", children: renderTabLabel ? renderTabLabel(tab) : tab.name }) }));
202
219
  }
203
220
  /**
204
221
  * Renders the dropdown with search for browsing tabs.
205
222
  * Shows open tabs first and closed tabs second (dimmed). When searching, shows all matching tabs.
206
223
  */
207
224
  function TabStripSearchDropdown({ className, triggerClassName, autoFocus = true, tooltip, triggerIcon, emptyMessage = 'No tabs', searchEmptyMessage = 'No matching tabs', closedTabsLabel = 'Recently closed', sortSearchItems = 'recent', getTabLastOpenedAt, }) {
208
- const { openTabItems, search, setSearch, closedTabs, filteredTabs, closedTabIds, openTabs, preventCloseLastTab, onOpenTabsChange, onSelect, renderSearchItemActions, getLastOpenedAt, handleClose, } = useTabStripContext();
225
+ const { openTabItems, search, setSearch, closedTabs, filteredTabs, closedTabIds, openTabs, preventCloseLastTab, onOpenTabsChange, onSelect, renderSearchItemActions, renderSearchItemLabel, getLastOpenedAt, handleClose, fontSize, } = useTabStripContext();
226
+ const fontSizeStyle = getFontSizeStyle(fontSize);
209
227
  const [isOpen, setIsOpen] = useState(false);
210
228
  const isSearching = search.trim().length > 0;
211
229
  const handleOpenChange = (open) => {
@@ -256,8 +274,8 @@ function TabStripSearchDropdown({ className, triggerClassName, autoFocus = true,
256
274
  const disableClose = preventCloseLastTab && (openTabsList.length ?? 0) <= 1;
257
275
  return (_jsxs(_Fragment, { children: [renderSearchItemActions?.(tab), _jsx(TabStripSearchItemAction, { icon: _jsx(XIcon, { className: "h-3 w-3" }), "aria-label": `Close ${tab.name}`, onClick: disableClose ? undefined : () => handleClose(tab.id), className: cn(disableClose && 'pointer-events-none opacity-40') })] }));
258
276
  };
259
- const triggerButton = (_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", "aria-label": "Browse tabs", size: "icon", className: cn(...TAB_STRIP_BUTTON_CLASSNAMES, triggerClassName), children: triggerIcon ?? _jsx(ListCollapseIcon, { className: "h-4 w-4" }) }) }));
260
- return (_jsxs(DropdownMenu, { open: isOpen, onOpenChange: handleOpenChange, children: [tooltip ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: triggerButton }), _jsx(TooltipContent, { children: tooltip })] }) })) : (triggerButton), _jsxs(DropdownMenuContent, { align: "start", onCloseAutoFocus: (event) => event.preventDefault(), className: cn('flex max-h-[400px] max-w-[240px] flex-col overflow-x-hidden', className), children: [_jsxs("div", { className: "flex shrink-0 items-center gap-1 px-2", children: [_jsx(SearchIcon, { className: "text-muted-foreground", size: 14 }), _jsx(Input, { value: search, onChange: (event) => setSearch(event.target.value), onKeyDown: (event) => {
277
+ const triggerButton = (_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", "aria-label": "Browse tabs", size: "icon", className: cn(...TAB_STRIP_BUTTON_CLASSNAMES, triggerClassName), style: fontSizeStyle, children: triggerIcon ?? _jsx(ListCollapseIcon, { className: "h-4 w-4" }) }) }));
278
+ return (_jsxs(DropdownMenu, { open: isOpen, onOpenChange: handleOpenChange, children: [tooltip ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: triggerButton }), _jsx(TooltipContent, { children: tooltip })] }) })) : (triggerButton), _jsxs(DropdownMenuContent, { align: "start", onCloseAutoFocus: (event) => event.preventDefault(), className: cn('flex max-h-[400px] max-w-[240px] flex-col overflow-x-hidden', className), style: fontSizeStyle, children: [_jsxs("div", { className: "flex shrink-0 items-center gap-1 px-2", children: [_jsx(SearchIcon, { className: "text-muted-foreground", size: 14 }), _jsx(Input, { value: search, onChange: (event) => setSearch(event.target.value), onKeyDown: (event) => {
261
279
  if (event.key === 'ArrowDown' || event.key === 'Tab') {
262
280
  event.preventDefault();
263
281
  const firstItem = event.currentTarget
@@ -268,32 +286,35 @@ function TabStripSearchDropdown({ className, triggerClassName, autoFocus = true,
268
286
  else {
269
287
  event.stopPropagation();
270
288
  }
271
- }, onKeyUp: (event) => event.stopPropagation(), className: "border-none text-xs shadow-none focus-visible:ring-0", placeholder: "Search...", "aria-label": "Search", autoFocus: autoFocus })] }), _jsx(DropdownMenuSeparator, { className: "shrink-0" }), _jsx("div", { className: "overflow-x-hidden overflow-y-auto", children: isSearching ? (filteredTabs.length === 0 ? (_jsx(DropdownTabItems, { tabs: filteredTabs, emptyMessage: searchEmptyMessage, onTabClick: handleTabClick, renderActions: renderSearchItemActions })) : (_jsxs(_Fragment, { children: [_jsx(DropdownTabItems, { tabs: filteredOpenTabs, onTabClick: handleTabClick, renderActions: renderOpenTabActions }), filteredClosedTabs.length > 0 && (_jsxs(_Fragment, { children: [filteredOpenTabs.length > 0 && _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { className: "text-muted-foreground py-1 text-xs font-medium", children: closedTabsLabel }), _jsx(DropdownTabItems, { tabs: filteredClosedTabs, onTabClick: handleTabClick, renderActions: renderSearchItemActions, getItemClassName: () => 'text-muted-foreground' })] }))] }))) : (_jsx(_Fragment, { children: hasAnyTabs ? (_jsxs(_Fragment, { children: [_jsx(DropdownTabItems, { tabs: openTabsList, onTabClick: handleTabClick, renderActions: renderOpenTabActions }), closedTabsList.length > 0 && (_jsxs(_Fragment, { children: [openTabsList.length > 0 && _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { className: "text-muted-foreground py-1 text-xs font-medium", children: closedTabsLabel }), _jsx(DropdownTabItems, { tabs: closedTabsList, onTabClick: handleTabClick, renderActions: renderSearchItemActions, getItemClassName: () => 'text-muted-foreground' })] }))] })) : (_jsx(DropdownTabItems, { tabs: [], emptyMessage: emptyMessage, onTabClick: handleTabClick, renderActions: renderSearchItemActions })) })) })] })] }));
289
+ }, onKeyUp: (event) => event.stopPropagation(), className: "border-none text-xs shadow-none focus-visible:ring-0", style: fontSizeStyle, placeholder: "Search...", "aria-label": "Search", autoFocus: autoFocus })] }), _jsx(DropdownMenuSeparator, { className: "shrink-0" }), _jsx("div", { className: "overflow-x-hidden overflow-y-auto", children: isSearching ? (filteredTabs.length === 0 ? (_jsx(DropdownTabItems, { tabs: filteredTabs, emptyMessage: searchEmptyMessage, onTabClick: handleTabClick, renderLabel: renderSearchItemLabel, renderActions: renderSearchItemActions })) : (_jsxs(_Fragment, { children: [_jsx(DropdownTabItems, { tabs: filteredOpenTabs, onTabClick: handleTabClick, renderLabel: renderSearchItemLabel, renderActions: renderOpenTabActions }), filteredClosedTabs.length > 0 && (_jsxs(_Fragment, { children: [filteredOpenTabs.length > 0 && _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { className: "text-muted-foreground py-1 text-xs font-medium", style: fontSizeStyle, children: closedTabsLabel }), _jsx(DropdownTabItems, { tabs: filteredClosedTabs, onTabClick: handleTabClick, renderLabel: renderSearchItemLabel, renderActions: renderSearchItemActions, getItemClassName: () => 'text-muted-foreground' })] }))] }))) : (_jsx(_Fragment, { children: hasAnyTabs ? (_jsxs(_Fragment, { children: [_jsx(DropdownTabItems, { tabs: openTabsList, onTabClick: handleTabClick, renderLabel: renderSearchItemLabel, renderActions: renderOpenTabActions }), closedTabsList.length > 0 && (_jsxs(_Fragment, { children: [openTabsList.length > 0 && _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { className: "text-muted-foreground py-1 text-xs font-medium", style: fontSizeStyle, children: closedTabsLabel }), _jsx(DropdownTabItems, { tabs: closedTabsList, onTabClick: handleTabClick, renderLabel: renderSearchItemLabel, renderActions: renderSearchItemActions, getItemClassName: () => 'text-muted-foreground' })] }))] })) : (_jsx(DropdownTabItems, { tabs: [], emptyMessage: emptyMessage, onTabClick: handleTabClick, renderLabel: renderSearchItemLabel, renderActions: renderSearchItemActions })) })) })] })] }));
272
290
  }
273
- function DropdownTabItems({ tabs, emptyMessage, onTabClick, renderActions, getItemClassName, }) {
291
+ function DropdownTabItems({ tabs, emptyMessage, onTabClick, renderLabel, renderActions, getItemClassName, }) {
292
+ const { fontSize } = useTabStripContext();
293
+ const fontSizeStyle = getFontSizeStyle(fontSize);
274
294
  if (tabs.length === 0) {
275
295
  if (!emptyMessage)
276
296
  return null;
277
- return (_jsx(DropdownMenuLabel, { className: "items-center justify-center text-xs", children: emptyMessage }));
297
+ return (_jsx(DropdownMenuLabel, { className: "items-center justify-center text-xs", style: fontSizeStyle, children: emptyMessage }));
278
298
  }
279
- return (_jsx(_Fragment, { children: tabs.map((tab) => (_jsxs(DropdownMenuItem, { onClick: () => onTabClick?.(tab.id), className: cn('flex h-7 cursor-pointer items-center justify-between truncate', getItemClassName?.(tab)), children: [_jsx("span", { className: "xs truncate pl-1", children: tab.name }), renderActions && (_jsx("div", { className: "flex items-center gap-2", children: renderActions(tab) }))] }, tab.id))) }));
299
+ return (_jsx(_Fragment, { children: tabs.map((tab) => (_jsxs(DropdownMenuItem, { onClick: () => onTabClick?.(tab.id), className: cn('flex h-7 cursor-pointer items-center justify-between truncate', getItemClassName?.(tab)), style: fontSizeStyle, children: [_jsx("div", { className: "min-w-0 truncate pl-1 text-xs", style: fontSizeStyle, children: renderLabel ? renderLabel(tab) : tab.name }), renderActions && (_jsx("div", { className: "flex items-center gap-2", children: renderActions(tab) }))] }, tab.id))) }));
280
300
  }
281
301
  /**
282
302
  * A general-purpose button for the tab strip.
283
303
  */
284
- const TabStripButton = React.forwardRef(({ className, ...props }, ref) => {
285
- return (_jsx(Button, { ref: ref, size: "icon", variant: "ghost", className: cn(...TAB_STRIP_BUTTON_CLASSNAMES, 'h-full shrink-0', className), ...props }));
304
+ const TabStripButton = React.forwardRef(function TabStripButtonComponent({ className, style, ...props }, ref) {
305
+ const context = useOptionalTabStripContext();
306
+ return (_jsx(Button, { ref: ref, size: "icon", variant: "ghost", style: mergeFontSizeStyle(context?.fontSize, style), className: cn(...TAB_STRIP_BUTTON_CLASSNAMES, 'h-full shrink-0', className), ...props }));
286
307
  });
287
308
  TabStripButton.displayName = 'TabStripButton';
288
309
  /**
289
310
  * Renders a button to create a new tab.
290
311
  */
291
312
  function TabStripNewButton({ tooltip, ...props }) {
292
- const { onCreate } = useTabStripContext();
313
+ const { onCreate, fontSize } = useTabStripContext();
293
314
  if (!onCreate) {
294
315
  return null;
295
316
  }
296
- const button = (_jsx(TabStripButton, { ...props, "aria-label": props['aria-label'] || 'Create new tab', onClick: (e) => {
317
+ const button = (_jsx(TabStripButton, { ...props, style: mergeFontSizeStyle(fontSize, props.style), "aria-label": props['aria-label'] || 'Create new tab', onClick: (e) => {
297
318
  onCreate();
298
319
  props.onClick?.(e);
299
320
  }, children: _jsx(PlusIcon, { className: "h-4 w-4" }) }));
@@ -323,7 +344,7 @@ function TabStripNewButton({ tooltip, ...props }) {
323
344
  * <TabStrip.NewButton />
324
345
  * </TabStrip>
325
346
  */
326
- function TabStripRoot({ className, tabsListClassName, children, tabs, openTabs, selectedTabId, preventCloseLastTab = false, closeable = true, onClose, onOpenTabsChange, onSelect, onCreate, onRename, renderTabTitle, renderTabMenu, renderSearchItemActions, renderTabLabel, dndMode = 'internal', dndScopeId, getTabDragData, }) {
347
+ function TabStripRoot({ className, tabsListClassName, children, tabs, openTabs, selectedTabId, preventCloseLastTab = false, closeable = true, onClose, onOpenTabsChange, onSelect, onActivate, onCreate, onRename, renderTabMenu, renderSearchItemActions, renderSearchItemLabel, renderTabLabel, fontSize, dndMode = 'internal', dndScopeId, getTabDragData, }) {
327
348
  const generatedDndScopeId = useId();
328
349
  const actualDndScopeId = dndScopeId ?? generatedDndScopeId;
329
350
  const [search, setSearch] = useState('');
@@ -471,13 +492,15 @@ function TabStripRoot({ className, tabsListClassName, children, tabs, openTabs,
471
492
  dndMode,
472
493
  dndScopeId: actualDndScopeId,
473
494
  getTabDragData,
495
+ fontSize,
474
496
  onOpenTabsChange,
475
497
  onSelect,
498
+ onActivate,
476
499
  onCreate,
477
500
  onRename,
478
- renderTabTitle,
479
501
  renderTabMenu,
480
502
  renderSearchItemActions,
503
+ renderSearchItemLabel,
481
504
  renderTabLabel,
482
505
  setSearch,
483
506
  handleStartEditing,
@@ -488,7 +511,7 @@ function TabStripRoot({ className, tabsListClassName, children, tabs, openTabs,
488
511
  const handleValueChange = (value) => {
489
512
  onSelect?.(value);
490
513
  };
491
- return (_jsx(Tabs, { value: selectedTabId ?? undefined, onValueChange: handleValueChange, activationMode: "manual", className: cn('bg-muted w-full min-w-0', className), children: _jsx(TabStripContext.Provider, { value: contextValue, children: _jsx(TabsList, { className: cn('flex h-9 w-full min-w-0 items-center justify-start gap-2 overflow-visible bg-transparent p-1', tabsListClassName), children: children ?? (_jsxs(_Fragment, { children: [_jsx(TabStripSearchDropdown, {}), _jsx(TabStripTabs, {}), _jsx(TabStripNewButton, {})] })) }) }) }));
514
+ return (_jsx(Tabs, { value: selectedTabId ?? undefined, onValueChange: handleValueChange, activationMode: "manual", className: cn('bg-muted w-full min-w-0', className), style: getFontSizeStyle(fontSize), children: _jsx(TabStripContext.Provider, { value: contextValue, children: _jsx(TabsList, { className: cn('flex h-9 w-full min-w-0 items-center justify-start gap-2 overflow-visible bg-transparent p-1', tabsListClassName), children: children ?? (_jsxs(_Fragment, { children: [_jsx(TabStripSearchDropdown, {}), _jsx(TabStripTabs, {}), _jsx(TabStripNewButton, {})] })) }) }) }));
492
515
  }
493
516
  // Attach subcomponents
494
517
  export const TabStrip = Object.assign(TabStripRoot, {
@@ -1 +1 @@
1
- {"version":3,"file":"tab-strip.js","sourceRoot":"","sources":["../../src/components/tab-strip.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n DndContext,\n DragEndEvent,\n DragMoveEvent,\n DragOverEvent,\n DragStartEvent,\n DragOverlay,\n PointerSensor,\n closestCenter,\n useDndMonitor,\n useSensor,\n useSensors,\n} from '@dnd-kit/core';\nimport {\n restrictToHorizontalAxis,\n restrictToParentElement,\n} from '@dnd-kit/modifiers';\nimport {\n SortableContext,\n arrayMove,\n horizontalListSortingStrategy,\n useSortable,\n} from '@dnd-kit/sortable';\nimport {\n EllipsisVerticalIcon,\n ListCollapseIcon,\n PlusIcon,\n SearchIcon,\n XIcon,\n} from 'lucide-react';\nimport React, {\n createContext,\n useContext,\n useEffect,\n useLayoutEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nconst DRAG_MODIFIERS = [restrictToHorizontalAxis, restrictToParentElement];\n\nimport {cn} from '../lib/utils';\nimport {Button, ButtonProps} from './button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from './dropdown-menu';\nimport {EditableText} from './editable-text';\nimport {Input} from './input';\nimport {ScrollableRow} from './scrollable-row';\nimport {Tabs, TabsList, TabsTrigger} from './tabs';\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from './tooltip';\n\nexport interface TabDescriptor {\n id: string;\n name: string;\n [key: string]: unknown;\n}\n\nexport type TabStripDndMode = 'internal' | 'shared';\n\n/**\n * Extra payload attached to tab drags. `TabStrip` always preserves `tabId` and\n * `tabStripId`; callers may intentionally override `kind` for cross-component\n * drags such as artifact tabs.\n */\nexport type TabStripDragData = Record<string, unknown>;\n\n// -----------------------------------------------------------------------------\n// Context\n// -----------------------------------------------------------------------------\n\ninterface TabStripContextValue {\n // Data\n openTabItems: TabDescriptor[];\n closedTabs: TabDescriptor[];\n closedTabIds: Set<string>;\n filteredTabs: TabDescriptor[];\n editingTabId: string | null;\n search: string;\n scrollContainerRef: React.RefObject<HTMLDivElement>;\n selectedTabId?: string | null;\n openTabs?: string[];\n preventCloseLastTab: boolean;\n closeable: boolean;\n getLastOpenedAt: (tabId: string) => number | undefined;\n dndMode: TabStripDndMode;\n dndScopeId: string;\n getTabDragData?: (tab: TabDescriptor) => TabStripDragData | undefined;\n\n // Callbacks\n onOpenTabsChange?: (tabIds: string[]) => void;\n onSelect?: (tabId: string) => void;\n onCreate?: () => void;\n onRename?: (tabId: string, newName: string) => void;\n renderTabTitle?: (tab: TabDescriptor) => React.ReactNode;\n renderTabMenu?: (tab: TabDescriptor) => React.ReactNode;\n renderSearchItemActions?: (tab: TabDescriptor) => React.ReactNode;\n renderTabLabel?: (tab: TabDescriptor) => React.ReactNode;\n\n // Internal handlers\n setSearch: (value: string) => void;\n handleStartEditing: (tabId: string) => void;\n handleStopEditing: () => void;\n handleInlineRename: (tabId: string, newName: string) => void;\n handleClose: (tabId: string) => void;\n}\n\nconst TabStripContext = createContext<TabStripContextValue | null>(null);\n\nfunction useTabStripContext() {\n const context = useContext(TabStripContext);\n if (!context) {\n throw new Error('TabStrip subcomponents must be used within a TabStrip');\n }\n return context;\n}\n\n// -----------------------------------------------------------------------------\n// Subcomponents\n// -----------------------------------------------------------------------------\n\ninterface TabStripTabsProps {\n className?: string;\n /** Custom className for individual tab triggers. */\n tabClassName?: string;\n}\n\ninterface SortableTabProps {\n tab: TabDescriptor;\n sortableId: string;\n tabClassName?: string;\n editingTabId: string | null;\n closeable?: boolean;\n onClose: (tabId: string) => void;\n onStartEditing: (tabId: string) => void;\n onStopEditing: () => void;\n onInlineRename: (tabId: string, newName: string) => void;\n renderTabTitle?: (tab: TabDescriptor) => React.ReactNode;\n renderTabMenu?: (tab: TabDescriptor) => React.ReactNode;\n renderTabLabel?: (tab: TabDescriptor) => React.ReactNode;\n dndScopeId: string;\n getTabDragData?: (tab: TabDescriptor) => TabStripDragData | undefined;\n}\n\nconst DEFAULT_TAB_DRAG_KIND = 'sqlrooms.tab';\n\nconst TAB_STRIP_BUTTON_CLASSNAMES = [\n 'flex h-full min-w-0 min-h-7 items-center',\n 'hover:bg-primary/10 overflow-hidden px-6 py-1 font-normal',\n 'focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:ring-inset',\n];\n\n/**\n * A single sortable tab item.\n */\nfunction SortableTab({\n tab,\n sortableId,\n tabClassName,\n editingTabId,\n closeable = true,\n onClose,\n onStartEditing,\n onStopEditing,\n onInlineRename,\n renderTabTitle,\n renderTabMenu,\n renderTabLabel,\n dndScopeId,\n getTabDragData,\n}: SortableTabProps) {\n const tabDragData = getTabDragData?.(tab);\n const isEditing = editingTabId === tab.id;\n const {attributes, listeners, setNodeRef, transform, transition, isDragging} =\n useSortable({\n id: sortableId,\n disabled: isEditing,\n data: {\n kind: DEFAULT_TAB_DRAG_KIND,\n ...tabDragData,\n tabId: tab.id,\n tabStripId: dndScopeId,\n },\n });\n\n const style: React.CSSProperties = {\n // Use Translate instead of Transform to avoid scale changes that squeeze the tab\n transform: transform\n ? `translate3d(${transform.x}px, ${transform.y}px, 0)`\n : undefined,\n transition,\n opacity: isDragging ? 0.5 : 1,\n };\n\n const menuContent = renderTabMenu?.(tab);\n\n return (\n <div\n ref={setNodeRef}\n className=\"h-full shrink-0\"\n style={style}\n data-tab-id={tab.id}\n {...(isEditing ? {} : attributes)}\n {...(isEditing ? {} : listeners)}\n tabIndex={-1}\n >\n <div\n data-state={isEditing ? 'editing' : undefined}\n className={cn(\n 'data-[state=inactive]:hover:bg-primary/5',\n 'group flex h-full max-w-[200px] min-w-[100px] shrink-0 cursor-grab',\n 'items-center justify-between gap-1 overflow-hidden rounded-b-none',\n 'py-0 pr-1 pl-4 font-normal data-[state=active]:shadow-none',\n tabClassName,\n isEditing && 'focus-visible:ring-0',\n )}\n >\n <div className=\"relative flex h-full min-w-0 flex-1 items-center\">\n <TabsTrigger\n value={tab.id}\n tabIndex={isEditing ? -1 : undefined}\n data-editing={isEditing ? '' : undefined}\n className={cn(\n ...TAB_STRIP_BUTTON_CLASSNAMES,\n 'flex-1 justify-start gap-1',\n 'data-[state=active]:bg-primary/10 data-[state=active]:text-foreground data-[state=active]:shadow-none',\n isEditing && 'focus-visible:ring-0',\n )}\n onDoubleClick={() => onStartEditing(tab.id)}\n >\n {!isEditing ? (\n <div className=\"truncate text-sm\">\n {renderTabLabel ? renderTabLabel(tab) : tab.name}\n </div>\n ) : (\n <EditableText\n value={tab.name}\n onChange={(newName) => onInlineRename(tab.id, newName)}\n className=\"h-6 min-w-0 flex-1 truncate text-sm shadow-none\"\n isEditing\n autoFocus\n selectOnFocus\n allowTabFocusWhenNotEditing={false}\n onEditingChange={(isEditing) => {\n if (!isEditing) {\n onStopEditing();\n }\n }}\n />\n )}\n </TabsTrigger>\n\n <div className=\"flex shrink-0 items-center\">\n {menuContent && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n aria-label=\"Tab options\"\n className=\"hover:bg-primary/10 focus-visible:bg-primary/10 focus-visible:ring-ring absolute top-1/2 left-1 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded p-1 opacity-0 outline-hidden group-hover:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-offset-0 data-[state=open]:opacity-100\"\n onMouseDown={(event) => {\n event.stopPropagation();\n event.preventDefault();\n }}\n onClick={(event) => {\n event.stopPropagation();\n }}\n >\n <EllipsisVerticalIcon className=\"h-3 w-3\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {menuContent}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n\n {closeable && (\n <button\n type=\"button\"\n aria-label=\"Close tab\"\n className=\"hover:bg-primary/10 focus-visible:bg-primary/10 focus-visible:ring-ring absolute top-1/2 right-1 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded p-1 opacity-0 outline-hidden group-hover:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-offset-0\"\n onMouseDown={(event) => {\n event.stopPropagation();\n event.preventDefault();\n }}\n onClick={(event) => {\n event.stopPropagation();\n event.preventDefault();\n onClose(tab.id);\n }}\n >\n <XIcon className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\n// -----------------------------------------------------------------------------\n// Tab Menu Components (for use with renderTabMenu)\n// -----------------------------------------------------------------------------\n\ninterface TabStripMenuItemProps {\n children: React.ReactNode;\n onClick?: () => void;\n variant?: 'default' | 'destructive';\n className?: string;\n disabled?: boolean;\n}\n\n/**\n * A menu item for the tab's dropdown menu.\n */\nfunction TabStripMenuItem({\n children,\n onClick,\n variant = 'default',\n className,\n disabled,\n}: TabStripMenuItemProps) {\n return (\n <DropdownMenuItem\n disabled={disabled}\n onClick={(event) => {\n event.stopPropagation();\n onClick?.();\n }}\n className={cn(\n variant === 'destructive' && 'text-destructive focus:text-destructive',\n className,\n )}\n >\n {children}\n </DropdownMenuItem>\n );\n}\n\ninterface TabStripMenuSeparatorProps {\n className?: string;\n}\n\n/**\n * A separator for the tab's dropdown menu.\n */\nfunction TabStripMenuSeparator({className}: TabStripMenuSeparatorProps) {\n return <DropdownMenuSeparator className={className} />;\n}\n\ninterface TabStripSearchItemActionProps {\n icon: React.ReactNode;\n onClick?: () => void;\n 'aria-label': string;\n className?: string;\n}\n\n/**\n * An action button for search dropdown items.\n */\nfunction TabStripSearchItemAction({\n icon,\n onClick,\n 'aria-label': ariaLabel,\n className,\n}: TabStripSearchItemActionProps) {\n return (\n <span\n role=\"button\"\n tabIndex={-1}\n aria-label={ariaLabel}\n className={cn(\n 'text-muted-foreground hover:text-foreground flex h-4 w-4 cursor-pointer items-center justify-center rounded',\n className,\n )}\n onClick={(event) => {\n event.stopPropagation();\n onClick?.();\n }}\n >\n {icon}\n </span>\n );\n}\n\n/**\n * Renders the scrollable row of open tabs with drag-to-reorder support.\n */\nfunction TabStripTabs({className, tabClassName}: TabStripTabsProps) {\n const {\n openTabItems,\n editingTabId,\n scrollContainerRef,\n onOpenTabsChange,\n dndMode,\n dndScopeId,\n getTabDragData,\n renderTabTitle,\n renderTabMenu,\n renderTabLabel,\n preventCloseLastTab,\n closeable,\n handleStartEditing,\n handleStopEditing,\n handleInlineRename,\n handleClose,\n } = useTabStripContext();\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {\n distance: 5, // 5px movement before drag starts (allows clicks)\n },\n }),\n );\n const [activeDraggedTabId, setActiveDraggedTabId] = useState<string | null>(\n null,\n );\n const [hideSharedDragOverlay, setHideSharedDragOverlay] = useState(false);\n\n const isDragInsideTabStrip = (\n event: DragMoveEvent | DragOverEvent | DragStartEvent,\n ) => {\n const rect =\n event.active.rect.current.translated ?? event.active.rect.current.initial;\n const tabStripRect = scrollContainerRef.current?.getBoundingClientRect();\n if (!rect || !tabStripRect) return false;\n\n const centerX = rect.left + rect.width / 2;\n const centerY = rect.top + rect.height / 2;\n\n return (\n centerX >= tabStripRect.left &&\n centerX <= tabStripRect.right &&\n centerY >= tabStripRect.top &&\n centerY <= tabStripRect.bottom\n );\n };\n\n const shouldHideSharedDragOverlay = (\n event: DragMoveEvent | DragOverEvent | DragStartEvent,\n ) => {\n if (isDragInsideTabStrip(event)) {\n return true;\n }\n if ('over' in event) {\n return event.over?.data.current?.tabStripId === dndScopeId;\n }\n return false;\n };\n\n const handleDragEnd = (event: DragEndEvent) => {\n const {active, over} = event;\n if (!over || active.id === over.id || !onOpenTabsChange) return;\n\n const activeData = active.data.current;\n const overData = over.data.current;\n const activeTabId =\n typeof activeData?.tabId === 'string'\n ? activeData.tabId\n : String(active.id);\n const overTabId =\n typeof overData?.tabId === 'string' ? overData.tabId : String(over.id);\n\n if (\n dndMode === 'shared' &&\n (activeData?.tabStripId !== dndScopeId ||\n overData?.tabStripId !== dndScopeId)\n ) {\n return;\n }\n\n const oldIndex = openTabItems.findIndex((tab) => tab.id === activeTabId);\n const newIndex = openTabItems.findIndex((tab) => tab.id === overTabId);\n\n if (oldIndex !== -1 && newIndex !== -1) {\n const newOrder = arrayMove(\n openTabItems.map((t) => t.id),\n oldIndex,\n newIndex,\n );\n onOpenTabsChange(newOrder);\n }\n };\n\n const getSortableId = (tabId: string) =>\n dndMode === 'shared' ? `${dndScopeId}:${tabId}` : tabId;\n\n const tabIds = useMemo(\n () => openTabItems.map((t) => getSortableId(t.id)),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [openTabItems, dndMode, dndScopeId],\n );\n\n const content = (\n <SortableContext items={tabIds} strategy={horizontalListSortingStrategy}>\n <ScrollableRow\n className=\"h-full min-w-0 shrink overflow-hidden\"\n scrollRef={scrollContainerRef}\n scrollClassName={cn(\n 'flex h-full min-w-0 items-center gap-1 overflow-x-auto overflow-y-visible',\n 'pl-1 pr-1 scroll-pl-7 scroll-pr-7 [&::-webkit-scrollbar]:hidden',\n className,\n )}\n arrowVisibility=\"always\"\n arrowClassName=\"w-7\"\n arrowIconClassName=\"h-4 w-4 opacity-60\"\n >\n {openTabItems.map((tab) => (\n <SortableTab\n key={tab.id}\n tab={tab}\n sortableId={getSortableId(tab.id)}\n tabClassName={tabClassName}\n editingTabId={editingTabId}\n closeable={\n closeable && !(preventCloseLastTab && openTabItems.length === 1)\n }\n onClose={handleClose}\n onStartEditing={handleStartEditing}\n onStopEditing={handleStopEditing}\n onInlineRename={handleInlineRename}\n renderTabTitle={renderTabTitle}\n renderTabMenu={renderTabMenu}\n renderTabLabel={renderTabLabel}\n dndScopeId={dndScopeId}\n getTabDragData={getTabDragData}\n />\n ))}\n </ScrollableRow>\n </SortableContext>\n );\n\n if (dndMode === 'shared') {\n const activeDraggedTab = activeDraggedTabId\n ? openTabItems.find((tab) => tab.id === activeDraggedTabId)\n : undefined;\n\n return (\n <>\n <SharedTabStripDndMonitor\n dndScopeId={dndScopeId}\n handleDragEnd={handleDragEnd}\n setActiveDraggedTabId={setActiveDraggedTabId}\n setHideSharedDragOverlay={setHideSharedDragOverlay}\n shouldHideSharedDragOverlay={shouldHideSharedDragOverlay}\n />\n {content}\n <DragOverlay dropAnimation={null}>\n {activeDraggedTab && !hideSharedDragOverlay ? (\n <TabDragOverlay\n tab={activeDraggedTab}\n renderTabLabel={renderTabLabel}\n />\n ) : null}\n </DragOverlay>\n </>\n );\n }\n\n return (\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n modifiers={DRAG_MODIFIERS}\n autoScroll={true}\n onDragEnd={handleDragEnd}\n >\n {content}\n </DndContext>\n );\n}\n\nfunction SharedTabStripDndMonitor({\n dndScopeId,\n handleDragEnd,\n setActiveDraggedTabId,\n setHideSharedDragOverlay,\n shouldHideSharedDragOverlay,\n}: {\n dndScopeId: string;\n handleDragEnd: (event: DragEndEvent) => void;\n setActiveDraggedTabId: React.Dispatch<React.SetStateAction<string | null>>;\n setHideSharedDragOverlay: React.Dispatch<React.SetStateAction<boolean>>;\n shouldHideSharedDragOverlay: (\n event: DragMoveEvent | DragOverEvent | DragStartEvent,\n ) => boolean;\n}) {\n const isOwnTabDrag = (\n event: DragStartEvent | DragMoveEvent | DragOverEvent | DragEndEvent,\n ) => event.active.data.current?.tabStripId === dndScopeId;\n\n useDndMonitor({\n onDragStart: (event) => {\n const activeData = event.active.data.current;\n if (!isOwnTabDrag(event)) {\n return;\n }\n setActiveDraggedTabId(\n typeof activeData?.tabId === 'string' ? activeData.tabId : null,\n );\n setHideSharedDragOverlay(true);\n },\n onDragMove: (event) => {\n if (!isOwnTabDrag(event)) return;\n setHideSharedDragOverlay(shouldHideSharedDragOverlay(event));\n },\n onDragOver: (event) => {\n if (!isOwnTabDrag(event)) return;\n setHideSharedDragOverlay(shouldHideSharedDragOverlay(event));\n },\n onDragEnd: (event) => {\n if (!isOwnTabDrag(event)) return;\n handleDragEnd(event);\n setActiveDraggedTabId(null);\n setHideSharedDragOverlay(false);\n },\n onDragCancel: () => {\n setActiveDraggedTabId(null);\n setHideSharedDragOverlay(false);\n },\n });\n\n return null;\n}\n\nfunction TabDragOverlay({\n tab,\n renderTabLabel,\n}: {\n tab: TabDescriptor;\n renderTabLabel?: (tab: TabDescriptor) => React.ReactNode;\n}) {\n return (\n <div\n className={cn(\n 'bg-primary/15 text-foreground border-primary/50 flex h-7 max-w-[200px] min-w-[100px]',\n 'cursor-grabbing items-center justify-center gap-1 overflow-hidden rounded-md border px-6 py-1',\n 'text-sm shadow-lg',\n )}\n >\n <div className=\"truncate text-center\">\n {renderTabLabel ? renderTabLabel(tab) : tab.name}\n </div>\n </div>\n );\n}\n\ninterface TabStripSearchDropdownProps {\n className?: string;\n triggerClassName?: string;\n /** Whether to auto-focus the search input when dropdown opens. Defaults to true. */\n autoFocus?: boolean;\n /** Optional tooltip content for the trigger button. */\n tooltip?: React.ReactNode;\n /** Optional custom icon for the trigger button. */\n triggerIcon?: React.ReactNode;\n /** Message shown when there are no tabs at all. */\n emptyMessage?: React.ReactNode;\n /** Message shown when searching and there are no matching tabs. */\n searchEmptyMessage?: React.ReactNode;\n /** Label for the closed tabs group. */\n closedTabsLabel?: React.ReactNode;\n /** Sorting mode for search dropdown items. */\n sortSearchItems?: 'none' | 'recent';\n /** Optional accessor for tab recency timestamps. */\n getTabLastOpenedAt?: (tab: TabDescriptor) => number | undefined;\n}\n\n/**\n * Renders the dropdown with search for browsing tabs.\n * Shows open tabs first and closed tabs second (dimmed). When searching, shows all matching tabs.\n */\nfunction TabStripSearchDropdown({\n className,\n triggerClassName,\n autoFocus = true,\n tooltip,\n triggerIcon,\n emptyMessage = 'No tabs',\n searchEmptyMessage = 'No matching tabs',\n closedTabsLabel = 'Recently closed',\n sortSearchItems = 'recent',\n getTabLastOpenedAt,\n}: TabStripSearchDropdownProps) {\n const {\n openTabItems,\n search,\n setSearch,\n closedTabs,\n filteredTabs,\n closedTabIds,\n openTabs,\n preventCloseLastTab,\n onOpenTabsChange,\n onSelect,\n renderSearchItemActions,\n getLastOpenedAt,\n handleClose,\n } = useTabStripContext();\n\n const [isOpen, setIsOpen] = useState(false);\n\n const isSearching = search.trim().length > 0;\n\n const handleOpenChange = (open: boolean) => {\n setIsOpen(open);\n if (!open) {\n setSearch('');\n }\n };\n\n const handleTabClick = (tabId: string) => {\n if (closedTabIds.has(tabId)) {\n // Opening a closed tab: add to openTabs and select it\n onOpenTabsChange?.([...(openTabs ?? []), tabId]);\n onSelect?.(tabId);\n } else {\n // Already open: just select it\n onSelect?.(tabId);\n }\n setIsOpen(false);\n };\n\n const sortByRecency = (tabsToSort: TabDescriptor[]) => {\n if (sortSearchItems !== 'recent') {\n return tabsToSort;\n }\n\n const withIndex = tabsToSort.map((tab, index) => ({\n tab,\n index,\n ts: getTabLastOpenedAt?.(tab) ?? getLastOpenedAt(tab.id),\n }));\n\n return withIndex\n .slice()\n .sort((a, b) => {\n const aTs = a.ts ?? -1;\n const bTs = b.ts ?? -1;\n if (aTs === bTs) {\n return a.index - b.index;\n }\n return bTs - aTs;\n })\n .map((item) => item.tab);\n };\n\n const openTabsList = sortByRecency(openTabItems);\n const closedTabsList = sortByRecency(closedTabs);\n const hasAnyTabs = openTabsList.length + closedTabsList.length > 0;\n\n const filteredOpenTabs = sortByRecency(\n filteredTabs.filter((tab) => !closedTabIds.has(tab.id)),\n );\n const filteredClosedTabs = sortByRecency(\n filteredTabs.filter((tab) => closedTabIds.has(tab.id)),\n );\n\n const renderOpenTabActions = (tab: TabDescriptor) => {\n const disableClose = preventCloseLastTab && (openTabsList.length ?? 0) <= 1;\n return (\n <>\n {renderSearchItemActions?.(tab)}\n <TabStripSearchItemAction\n icon={<XIcon className=\"h-3 w-3\" />}\n aria-label={`Close ${tab.name}`}\n onClick={disableClose ? undefined : () => handleClose(tab.id)}\n className={cn(disableClose && 'pointer-events-none opacity-40')}\n />\n </>\n );\n };\n\n const triggerButton = (\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n aria-label=\"Browse tabs\"\n size=\"icon\"\n className={cn(...TAB_STRIP_BUTTON_CLASSNAMES, triggerClassName)}\n >\n {triggerIcon ?? <ListCollapseIcon className=\"h-4 w-4\" />}\n </Button>\n </DropdownMenuTrigger>\n );\n\n return (\n <DropdownMenu open={isOpen} onOpenChange={handleOpenChange}>\n {tooltip ? (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>{triggerButton}</TooltipTrigger>\n <TooltipContent>{tooltip}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n ) : (\n triggerButton\n )}\n\n <DropdownMenuContent\n align=\"start\"\n onCloseAutoFocus={(event) => event.preventDefault()}\n className={cn(\n 'flex max-h-[400px] max-w-[240px] flex-col overflow-x-hidden',\n className,\n )}\n >\n <div className=\"flex shrink-0 items-center gap-1 px-2\">\n <SearchIcon className=\"text-muted-foreground\" size={14} />\n <Input\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'ArrowDown' || event.key === 'Tab') {\n event.preventDefault();\n const firstItem = event.currentTarget\n .closest('[role=\"menu\"]')\n ?.querySelector<HTMLElement>(\n '[role=\"menuitem\"]:not([disabled])',\n );\n firstItem?.focus();\n } else {\n event.stopPropagation();\n }\n }}\n onKeyUp={(event) => event.stopPropagation()}\n className=\"border-none text-xs shadow-none focus-visible:ring-0\"\n placeholder=\"Search...\"\n aria-label=\"Search\"\n autoFocus={autoFocus}\n />\n </div>\n <DropdownMenuSeparator className=\"shrink-0\" />\n\n <div className=\"overflow-x-hidden overflow-y-auto\">\n {isSearching ? (\n filteredTabs.length === 0 ? (\n <DropdownTabItems\n tabs={filteredTabs}\n emptyMessage={searchEmptyMessage}\n onTabClick={handleTabClick}\n renderActions={renderSearchItemActions}\n />\n ) : (\n <>\n <DropdownTabItems\n tabs={filteredOpenTabs}\n onTabClick={handleTabClick}\n renderActions={renderOpenTabActions}\n />\n {filteredClosedTabs.length > 0 && (\n <>\n {filteredOpenTabs.length > 0 && <DropdownMenuSeparator />}\n <DropdownMenuLabel className=\"text-muted-foreground py-1 text-xs font-medium\">\n {closedTabsLabel}\n </DropdownMenuLabel>\n <DropdownTabItems\n tabs={filteredClosedTabs}\n onTabClick={handleTabClick}\n renderActions={renderSearchItemActions}\n getItemClassName={() => 'text-muted-foreground'}\n />\n </>\n )}\n </>\n )\n ) : (\n <>\n {hasAnyTabs ? (\n <>\n <DropdownTabItems\n tabs={openTabsList}\n onTabClick={handleTabClick}\n renderActions={renderOpenTabActions}\n />\n {closedTabsList.length > 0 && (\n <>\n {openTabsList.length > 0 && <DropdownMenuSeparator />}\n <DropdownMenuLabel className=\"text-muted-foreground py-1 text-xs font-medium\">\n {closedTabsLabel}\n </DropdownMenuLabel>\n <DropdownTabItems\n tabs={closedTabsList}\n onTabClick={handleTabClick}\n renderActions={renderSearchItemActions}\n getItemClassName={() => 'text-muted-foreground'}\n />\n </>\n )}\n </>\n ) : (\n <DropdownTabItems\n tabs={[]}\n emptyMessage={emptyMessage}\n onTabClick={handleTabClick}\n renderActions={renderSearchItemActions}\n />\n )}\n </>\n )}\n </div>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\ninterface DropdownTabItemsProps {\n tabs: TabDescriptor[];\n emptyMessage?: React.ReactNode;\n onTabClick?: (tabId: string) => void;\n renderActions?: (tab: TabDescriptor) => React.ReactNode;\n getItemClassName?: (tab: TabDescriptor) => string | undefined;\n}\n\nfunction DropdownTabItems({\n tabs,\n emptyMessage,\n onTabClick,\n renderActions,\n getItemClassName,\n}: DropdownTabItemsProps) {\n if (tabs.length === 0) {\n if (!emptyMessage) return null;\n return (\n <DropdownMenuLabel className=\"items-center justify-center text-xs\">\n {emptyMessage}\n </DropdownMenuLabel>\n );\n }\n\n return (\n <>\n {tabs.map((tab) => (\n <DropdownMenuItem\n key={tab.id}\n onClick={() => onTabClick?.(tab.id)}\n className={cn(\n 'flex h-7 cursor-pointer items-center justify-between truncate',\n getItemClassName?.(tab),\n )}\n >\n <span className=\"xs truncate pl-1\">{tab.name}</span>\n {renderActions && (\n <div className=\"flex items-center gap-2\">{renderActions(tab)}</div>\n )}\n </DropdownMenuItem>\n ))}\n </>\n );\n}\n\n/**\n * A general-purpose button for the tab strip.\n */\nconst TabStripButton = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({className, ...props}, ref) => {\n return (\n <Button\n ref={ref}\n size=\"icon\"\n variant=\"ghost\"\n className={cn(\n ...TAB_STRIP_BUTTON_CLASSNAMES,\n 'h-full shrink-0',\n className,\n )}\n {...props}\n />\n );\n },\n);\nTabStripButton.displayName = 'TabStripButton';\ntype TabStripNewButtonProps = ButtonProps & {\n /** Optional tooltip content for the button. */\n tooltip?: React.ReactNode;\n};\n\n/**\n * Renders a button to create a new tab.\n */\nfunction TabStripNewButton({tooltip, ...props}: TabStripNewButtonProps) {\n const {onCreate} = useTabStripContext();\n\n if (!onCreate) {\n return null;\n }\n\n const button = (\n <TabStripButton\n {...props}\n aria-label={props['aria-label'] || 'Create new tab'}\n onClick={(e) => {\n onCreate();\n props.onClick?.(e);\n }}\n >\n <PlusIcon className=\"h-4 w-4\" />\n </TabStripButton>\n );\n\n if (tooltip) {\n return (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>{button}</TooltipTrigger>\n <TooltipContent>{tooltip}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n }\n\n return button;\n}\n\n// -----------------------------------------------------------------------------\n// Main Component\n// -----------------------------------------------------------------------------\n\nexport interface TabStripProps {\n className?: string;\n tabsListClassName?: string;\n children?: React.ReactNode;\n /** All available tabs. */\n tabs: TabDescriptor[];\n /** IDs of tabs that are currently open. */\n openTabs?: string[];\n /** ID of the currently selected tab. */\n selectedTabId?: string | null;\n /** If true, hides the close button when only one tab remains open. */\n preventCloseLastTab?: boolean;\n /** Whether tabs can be closed. Defaults to true. */\n closeable?: boolean;\n /** Called when a tab is closed (hidden, can be reopened). */\n onClose?: (tabId: string) => void;\n /** Called when the list of open tabs changes (open from dropdown or reorder). */\n onOpenTabsChange?: (tabIds: string[]) => void;\n /** Called when a tab is selected. */\n onSelect?: (tabId: string) => void;\n /** Called when a new tab should be created. */\n onCreate?: () => void;\n /** Called when a tab is renamed inline. */\n onRename?: (tabId: string, newName: string) => void;\n /** Render function for the tab's title. */\n renderTabTitle?: (tab: TabDescriptor) => React.ReactNode;\n /** Render function for the tab's dropdown menu. Use TabStrip.MenuItem and TabStrip.MenuSeparator. */\n renderTabMenu?: (tab: TabDescriptor) => React.ReactNode;\n /** Render function for search dropdown item actions. Use TabStrip.SearchItemAction. */\n renderSearchItemActions?: (tab: TabDescriptor) => React.ReactNode;\n /** Render function for custom tab content. Receives the tab and returns the content to display. */\n renderTabLabel?: (tab: TabDescriptor) => React.ReactNode;\n /** Whether this tab strip owns its dnd context or participates in a shared parent context. */\n dndMode?: TabStripDndMode;\n /** Unique scope for shared dnd tab ids. Defaults to a generated component id. */\n dndScopeId?: string;\n /** Extra drag payload attached to tab drags; may intentionally override `kind`. */\n getTabDragData?: (tab: TabDescriptor) => TabStripDragData | undefined;\n}\n\n/**\n * A composable tab strip component with search dropdown and tab management.\n *\n * @example\n * // Default layout\n * <TabStrip\n * tabs={tabs}\n * openTabs={openTabs}\n * onClose={closeTab}\n * onOpen={openTab}\n * onCreate={createTab}\n * />\n *\n * @example\n * // Custom layout with subcomponents\n * <TabStrip tabs={tabs} openTabs={openTabs} onClose={closeTab}>\n * <TabStrip.Tabs className=\"flex-1\" />\n * <TabStrip.SearchDropdown />\n * <TabStrip.NewButton />\n * </TabStrip>\n */\nfunction TabStripRoot({\n className,\n tabsListClassName,\n children,\n tabs,\n openTabs,\n selectedTabId,\n preventCloseLastTab = false,\n closeable = true,\n onClose,\n onOpenTabsChange,\n onSelect,\n onCreate,\n onRename,\n renderTabTitle,\n renderTabMenu,\n renderSearchItemActions,\n renderTabLabel,\n dndMode = 'internal',\n dndScopeId,\n getTabDragData,\n}: TabStripProps) {\n const generatedDndScopeId = useId();\n const actualDndScopeId = dndScopeId ?? generatedDndScopeId;\n const [search, setSearch] = useState('');\n const [editingTabId, setEditingTabId] = useState<string | null>(null);\n const scrollContainerRef = useRef<HTMLDivElement>(null!);\n const prevSelectedIdRef = useRef<string | null>(null);\n const prevOpenTabIdsRef = useRef<Set<string>>(new Set());\n const lastOpenedAtRef = useRef<Map<string, number>>(new Map());\n\n const openTabsSet = useMemo(() => new Set(openTabs), [openTabs]);\n\n // Build openTabItems in the order of openTabs (for drag-to-reorder)\n const openTabItems = useMemo(() => {\n const tabsById = new Map(tabs.map((tab) => [tab.id, tab]));\n return (openTabs ?? [])\n .map((id) => tabsById.get(id))\n .filter((tab): tab is TabDescriptor => tab !== undefined);\n }, [tabs, openTabs]);\n\n const closedTabs = useMemo(\n () => tabs.filter((tab) => !openTabsSet.has(tab.id)),\n [tabs, openTabsSet],\n );\n\n const closedTabIds = useMemo(\n () => new Set(closedTabs.map((tab) => tab.id)),\n [closedTabs],\n );\n\n const trimmedSearch = search.trim().toLowerCase();\n\n const filteredTabs = useMemo(\n () =>\n trimmedSearch\n ? tabs.filter((tab) => tab.name.toLowerCase().includes(trimmedSearch))\n : [],\n [tabs, trimmedSearch],\n );\n\n useEffect(() => {\n if (!selectedTabId) return;\n lastOpenedAtRef.current.set(selectedTabId, Date.now());\n }, [selectedTabId]);\n\n useEffect(() => {\n const ids = new Set(tabs.map((tab) => tab.id));\n const next = new Map<string, number>();\n for (const [id, ts] of lastOpenedAtRef.current.entries()) {\n if (ids.has(id)) {\n next.set(id, ts);\n }\n }\n lastOpenedAtRef.current = next;\n }, [tabs]);\n\n // Auto-scroll to selected tab\n useLayoutEffect(() => {\n if (!selectedTabId) return;\n if (prevSelectedIdRef.current === selectedTabId) return;\n prevSelectedIdRef.current = selectedTabId;\n\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const isOpen = openTabItems.some((tab) => tab.id === selectedTabId);\n if (!isOpen) return;\n\n // Use queueMicrotask to defer scroll until after Radix UI updates the DOM\n queueMicrotask(() => {\n const activeTab = container.querySelector<HTMLElement>(\n '[data-state=\"active\"]',\n );\n if (!activeTab) return;\n\n activeTab.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'nearest',\n // @ts-expect-error - scrollMode is not standardized yet\n scrollMode: 'if-needed',\n });\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedTabId]);\n\n // Auto-scroll to newly added tab\n useLayoutEffect(() => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n // Find newly added tabs (in openTabs but not in prevOpenTabIdsRef)\n const newTabIds = (openTabs ?? []).filter(\n (id) => !prevOpenTabIdsRef.current.has(id),\n );\n\n // Update ref for next comparison\n prevOpenTabIdsRef.current = new Set(openTabs);\n\n if (newTabIds.length > 0) {\n const now = Date.now();\n for (const id of newTabIds) {\n lastOpenedAtRef.current.set(id, now);\n }\n }\n\n // Skip scroll on initial render (when ref was empty, all tabs appear \"new\")\n if (newTabIds.length === (openTabs?.length ?? 0)) return;\n\n // If there are new tabs, scroll to the last one added\n if (newTabIds.length === 0) return;\n const newTabId = newTabIds[newTabIds.length - 1];\n\n queueMicrotask(() => {\n const newTabElement = container.querySelector<HTMLElement>(\n `[data-tab-id=\"${newTabId}\"]`,\n );\n if (!newTabElement) return;\n\n newTabElement.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'nearest',\n });\n });\n }, [openTabs]);\n\n const handleInlineRename = (tabId: string, newName: string) => {\n if (!onRename) return;\n const tab = tabs.find((t) => t.id === tabId);\n const trimmed = newName.trim();\n if (!trimmed || trimmed === tab?.name) {\n setEditingTabId(null);\n return;\n }\n onRename(tabId, trimmed);\n setEditingTabId(null);\n };\n\n const handleStartEditing = (tabId: string) => {\n if (!onRename) return;\n setEditingTabId(tabId);\n };\n\n const handleStopEditing = () => {\n setEditingTabId(null);\n };\n\n const handleClose = (tabId: string) => {\n // If closing the selected tab, select the one to the left (or right if leftmost)\n if (selectedTabId === tabId && openTabItems.length > 1) {\n const closingIndex = openTabItems.findIndex((t) => t.id === tabId);\n // If closing the leftmost, select the next; otherwise select the previous\n const newIndex = closingIndex === 0 ? 1 : closingIndex - 1;\n const newSelectedId = openTabItems[newIndex]?.id;\n if (newSelectedId) {\n onSelect?.(newSelectedId);\n }\n }\n onClose?.(tabId);\n };\n\n const contextValue: TabStripContextValue = {\n openTabItems,\n closedTabs,\n closedTabIds,\n filteredTabs,\n editingTabId,\n search,\n scrollContainerRef,\n selectedTabId,\n openTabs,\n preventCloseLastTab,\n closeable,\n getLastOpenedAt: (tabId) => lastOpenedAtRef.current.get(tabId),\n dndMode,\n dndScopeId: actualDndScopeId,\n getTabDragData,\n onOpenTabsChange,\n onSelect,\n onCreate,\n onRename,\n renderTabTitle,\n renderTabMenu,\n renderSearchItemActions,\n renderTabLabel,\n setSearch,\n handleStartEditing,\n handleStopEditing,\n handleInlineRename,\n handleClose,\n };\n\n const handleValueChange = (value: string) => {\n onSelect?.(value);\n };\n\n return (\n <Tabs\n value={selectedTabId ?? undefined}\n onValueChange={handleValueChange}\n activationMode=\"manual\"\n className={cn('bg-muted w-full min-w-0', className)}\n >\n <TabStripContext.Provider value={contextValue}>\n <TabsList\n className={cn(\n 'flex h-9 w-full min-w-0 items-center justify-start gap-2 overflow-visible bg-transparent p-1',\n tabsListClassName,\n )}\n >\n {children ?? (\n <>\n <TabStripSearchDropdown />\n <TabStripTabs />\n <TabStripNewButton />\n </>\n )}\n </TabsList>\n </TabStripContext.Provider>\n </Tabs>\n );\n}\n\n// Attach subcomponents\nexport const TabStrip = Object.assign(TabStripRoot, {\n Tabs: TabStripTabs,\n SearchDropdown: TabStripSearchDropdown,\n Button: TabStripButton,\n NewButton: TabStripNewButton,\n MenuItem: TabStripMenuItem,\n MenuSeparator: TabStripMenuSeparator,\n SearchItemAction: TabStripSearchItemAction,\n});\n\nexport type {\n TabStripMenuItemProps,\n TabStripMenuSeparatorProps,\n TabStripNewButtonProps,\n TabStripSearchDropdownProps,\n TabStripSearchItemActionProps,\n TabStripTabsProps,\n};\n"]}
1
+ {"version":3,"file":"tab-strip.js","sourceRoot":"","sources":["../../src/components/tab-strip.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n DndContext,\n DragEndEvent,\n DragMoveEvent,\n DragOverEvent,\n DragStartEvent,\n DragOverlay,\n PointerSensor,\n closestCenter,\n useDndMonitor,\n useSensor,\n useSensors,\n} from '@dnd-kit/core';\nimport {\n restrictToHorizontalAxis,\n restrictToParentElement,\n} from '@dnd-kit/modifiers';\nimport {\n SortableContext,\n arrayMove,\n horizontalListSortingStrategy,\n useSortable,\n} from '@dnd-kit/sortable';\nimport {\n EllipsisVerticalIcon,\n ListCollapseIcon,\n PlusIcon,\n SearchIcon,\n XIcon,\n} from 'lucide-react';\nimport React, {\n createContext,\n useContext,\n useEffect,\n useLayoutEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nconst DRAG_MODIFIERS = [restrictToHorizontalAxis, restrictToParentElement];\n\nimport {cn} from '../lib/utils';\nimport {Button, ButtonProps} from './button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from './dropdown-menu';\nimport {EditableText} from './editable-text';\nimport {Input} from './input';\nimport {ScrollableRow} from './scrollable-row';\nimport {Tabs, TabsList, TabsTrigger} from './tabs';\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from './tooltip';\n\nexport interface TabDescriptor {\n id: string;\n name: string;\n [key: string]: unknown;\n}\n\nexport type TabStripDndMode = 'internal' | 'shared';\n\n/**\n * Extra payload attached to tab drags. `TabStrip` always preserves `tabId` and\n * `tabStripId`; callers may intentionally override `kind` for cross-component\n * drags such as artifact tabs.\n */\nexport type TabStripDragData = Record<string, unknown>;\n\n// -----------------------------------------------------------------------------\n// Context\n// -----------------------------------------------------------------------------\n\ninterface TabStripContextValue {\n // Data\n openTabItems: TabDescriptor[];\n closedTabs: TabDescriptor[];\n closedTabIds: Set<string>;\n filteredTabs: TabDescriptor[];\n editingTabId: string | null;\n search: string;\n scrollContainerRef: React.RefObject<HTMLDivElement>;\n selectedTabId?: string | null;\n openTabs?: string[];\n preventCloseLastTab: boolean;\n closeable: boolean;\n getLastOpenedAt: (tabId: string) => number | undefined;\n dndMode: TabStripDndMode;\n dndScopeId: string;\n getTabDragData?: (tab: TabDescriptor) => TabStripDragData | undefined;\n fontSize?: React.CSSProperties['fontSize'];\n\n // Callbacks\n onOpenTabsChange?: (tabIds: string[]) => void;\n onSelect?: (tabId: string) => void;\n onActivate?: (tabId: string) => void;\n onCreate?: () => void;\n onRename?: (tabId: string, newName: string) => void;\n renderTabMenu?: (tab: TabDescriptor) => React.ReactNode;\n renderSearchItemActions?: (tab: TabDescriptor) => React.ReactNode;\n renderSearchItemLabel?: (tab: TabDescriptor) => React.ReactNode;\n renderTabLabel?: (tab: TabDescriptor) => React.ReactNode;\n\n // Internal handlers\n setSearch: (value: string) => void;\n handleStartEditing: (tabId: string) => void;\n handleStopEditing: () => void;\n handleInlineRename: (tabId: string, newName: string) => void;\n handleClose: (tabId: string) => void;\n}\n\nconst TabStripContext = createContext<TabStripContextValue | null>(null);\n\nfunction useTabStripContext() {\n const context = useContext(TabStripContext);\n if (!context) {\n throw new Error('TabStrip subcomponents must be used within a TabStrip');\n }\n return context;\n}\n\nfunction useOptionalTabStripContext() {\n return useContext(TabStripContext);\n}\n\nfunction getFontSizeStyle(fontSize?: React.CSSProperties['fontSize']) {\n return fontSize === undefined\n ? undefined\n : ({fontSize} as React.CSSProperties);\n}\n\nfunction mergeFontSizeStyle(\n fontSize: React.CSSProperties['fontSize'] | undefined,\n style: React.CSSProperties | undefined,\n) {\n if (fontSize === undefined) return style;\n if (style === undefined) return {fontSize};\n return {...style, fontSize: style?.fontSize ?? fontSize};\n}\n\n// -----------------------------------------------------------------------------\n// Subcomponents\n// -----------------------------------------------------------------------------\n\ninterface TabStripTabsProps {\n className?: string;\n /** Custom className for individual tab triggers. */\n tabClassName?: string;\n}\n\ninterface SortableTabProps {\n tab: TabDescriptor;\n sortableId: string;\n tabClassName?: string;\n editingTabId: string | null;\n closeable?: boolean;\n onClose: (tabId: string) => void;\n onActivate: (tabId: string) => void;\n onStartEditing: (tabId: string) => void;\n onStopEditing: () => void;\n onInlineRename: (tabId: string, newName: string) => void;\n renderTabMenu?: (tab: TabDescriptor) => React.ReactNode;\n renderTabLabel?: (tab: TabDescriptor) => React.ReactNode;\n dndScopeId: string;\n getTabDragData?: (tab: TabDescriptor) => TabStripDragData | undefined;\n fontSize?: React.CSSProperties['fontSize'];\n}\n\nconst DEFAULT_TAB_DRAG_KIND = 'sqlrooms.tab';\n\nconst TAB_STRIP_BUTTON_CLASSNAMES = [\n 'flex h-full min-w-0 min-h-7 items-center',\n 'hover:bg-primary/10 overflow-hidden px-6 py-1 font-normal',\n 'focus-visible:ring-2 focus-visible:ring-offset-0 focus-visible:ring-inset',\n];\n\n/**\n * A single sortable tab item.\n */\nfunction SortableTab({\n tab,\n sortableId,\n tabClassName,\n editingTabId,\n closeable = true,\n onClose,\n onActivate,\n onStartEditing,\n onStopEditing,\n onInlineRename,\n renderTabMenu,\n renderTabLabel,\n dndScopeId,\n getTabDragData,\n fontSize,\n}: SortableTabProps) {\n const tabDragData = getTabDragData?.(tab);\n const isEditing = editingTabId === tab.id;\n const {attributes, listeners, setNodeRef, transform, transition, isDragging} =\n useSortable({\n id: sortableId,\n disabled: isEditing,\n data: {\n kind: DEFAULT_TAB_DRAG_KIND,\n ...tabDragData,\n tabId: tab.id,\n tabStripId: dndScopeId,\n },\n });\n\n const style: React.CSSProperties = {\n // Use Translate instead of Transform to avoid scale changes that squeeze the tab\n transform: transform\n ? `translate3d(${transform.x}px, ${transform.y}px, 0)`\n : undefined,\n transition,\n opacity: isDragging ? 0.5 : 1,\n };\n\n const menuContent = renderTabMenu?.(tab);\n const fontSizeStyle = getFontSizeStyle(fontSize);\n\n return (\n <div\n ref={setNodeRef}\n className=\"h-full shrink-0\"\n style={style}\n data-tab-id={tab.id}\n {...(isEditing ? {} : attributes)}\n {...(isEditing ? {} : listeners)}\n tabIndex={-1}\n >\n <div\n data-state={isEditing ? 'editing' : undefined}\n className={cn(\n 'data-[state=inactive]:hover:bg-primary/5',\n 'group/tab flex h-full max-w-[200px] min-w-[100px] shrink-0 cursor-grab',\n 'items-center justify-between gap-1 overflow-hidden rounded-b-none',\n 'py-0 pr-1 font-normal data-[state=active]:shadow-none',\n tabClassName,\n isEditing && 'focus-visible:ring-0',\n )}\n >\n <div className=\"relative flex h-full min-w-0 flex-1 items-center\">\n <TabsTrigger\n value={tab.id}\n tabIndex={isEditing ? -1 : undefined}\n data-editing={isEditing ? '' : undefined}\n className={cn(\n ...TAB_STRIP_BUTTON_CLASSNAMES,\n 'flex-1 gap-1',\n isEditing ? 'justify-start' : 'justify-center text-center',\n 'data-[state=active]:bg-primary/10 data-[state=active]:text-foreground data-[state=active]:shadow-none',\n isEditing && 'focus-visible:ring-0',\n )}\n style={fontSizeStyle}\n onClick={() => onActivate(tab.id)}\n onDoubleClick={() => onStartEditing(tab.id)}\n >\n {!isEditing ? (\n <div className=\"min-w-0 flex-1 truncate text-center\">\n {renderTabLabel ? renderTabLabel(tab) : tab.name}\n </div>\n ) : (\n <EditableText\n value={tab.name}\n onChange={(newName) => onInlineRename(tab.id, newName)}\n className=\"h-6 min-w-0 flex-1 truncate shadow-none\"\n style={fontSizeStyle}\n isEditing\n autoFocus\n selectOnFocus\n allowTabFocusWhenNotEditing={false}\n onEditingChange={(isEditing) => {\n if (!isEditing) {\n onStopEditing();\n }\n }}\n />\n )}\n </TabsTrigger>\n\n <div className=\"flex shrink-0 items-center\">\n {menuContent && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n aria-label=\"Tab options\"\n className=\"hover:bg-primary/10 focus-visible:bg-primary/10 focus-visible:ring-ring absolute top-1/2 left-1 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded p-1 opacity-0 outline-hidden group-hover/tab:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-offset-0 data-[state=open]:opacity-100\"\n onMouseDown={(event) => {\n event.stopPropagation();\n event.preventDefault();\n }}\n onClick={(event) => {\n event.stopPropagation();\n }}\n >\n <EllipsisVerticalIcon className=\"h-3 w-3\" />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" style={fontSizeStyle}>\n {menuContent}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n\n {closeable && (\n <button\n type=\"button\"\n aria-label=\"Close tab\"\n className=\"hover:bg-primary/10 focus-visible:bg-primary/10 focus-visible:ring-ring absolute top-1/2 right-1 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded p-1 opacity-0 outline-hidden group-hover/tab:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-offset-0\"\n onMouseDown={(event) => {\n event.stopPropagation();\n event.preventDefault();\n }}\n onClick={(event) => {\n event.stopPropagation();\n event.preventDefault();\n onClose(tab.id);\n }}\n >\n <XIcon className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\n// -----------------------------------------------------------------------------\n// Tab Menu Components (for use with renderTabMenu)\n// -----------------------------------------------------------------------------\n\ninterface TabStripMenuItemProps {\n children: React.ReactNode;\n onClick?: () => void;\n variant?: 'default' | 'destructive';\n className?: string;\n disabled?: boolean;\n}\n\n/**\n * A menu item for the tab's dropdown menu.\n */\nfunction TabStripMenuItem({\n children,\n onClick,\n variant = 'default',\n className,\n disabled,\n}: TabStripMenuItemProps) {\n const {fontSize} = useTabStripContext();\n\n return (\n <DropdownMenuItem\n disabled={disabled}\n onClick={(event) => {\n event.stopPropagation();\n onClick?.();\n }}\n className={cn(\n variant === 'destructive' && 'text-destructive focus:text-destructive',\n className,\n )}\n style={getFontSizeStyle(fontSize)}\n >\n {children}\n </DropdownMenuItem>\n );\n}\n\ninterface TabStripMenuSeparatorProps {\n className?: string;\n}\n\n/**\n * A separator for the tab's dropdown menu.\n */\nfunction TabStripMenuSeparator({className}: TabStripMenuSeparatorProps) {\n return <DropdownMenuSeparator className={className} />;\n}\n\ninterface TabStripSearchItemActionProps {\n icon: React.ReactNode;\n onClick?: () => void;\n 'aria-label': string;\n className?: string;\n}\n\n/**\n * An action button for search dropdown items.\n */\nfunction TabStripSearchItemAction({\n icon,\n onClick,\n 'aria-label': ariaLabel,\n className,\n}: TabStripSearchItemActionProps) {\n return (\n <span\n role=\"button\"\n tabIndex={-1}\n aria-label={ariaLabel}\n className={cn(\n 'text-muted-foreground hover:text-foreground flex h-4 w-4 cursor-pointer items-center justify-center rounded',\n className,\n )}\n onClick={(event) => {\n event.stopPropagation();\n onClick?.();\n }}\n >\n {icon}\n </span>\n );\n}\n\n/**\n * Renders the scrollable row of open tabs with drag-to-reorder support.\n */\nfunction TabStripTabs({className, tabClassName}: TabStripTabsProps) {\n const {\n openTabItems,\n editingTabId,\n scrollContainerRef,\n onOpenTabsChange,\n dndMode,\n dndScopeId,\n getTabDragData,\n renderTabMenu,\n renderTabLabel,\n preventCloseLastTab,\n closeable,\n fontSize,\n handleStartEditing,\n handleStopEditing,\n handleInlineRename,\n handleClose,\n onActivate,\n } = useTabStripContext();\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {\n distance: 5, // 5px movement before drag starts (allows clicks)\n },\n }),\n );\n const [activeDraggedTabId, setActiveDraggedTabId] = useState<string | null>(\n null,\n );\n const [hideSharedDragOverlay, setHideSharedDragOverlay] = useState(false);\n\n const isDragInsideTabStrip = (\n event: DragMoveEvent | DragOverEvent | DragStartEvent,\n ) => {\n const rect =\n event.active.rect.current.translated ?? event.active.rect.current.initial;\n const tabStripRect = scrollContainerRef.current?.getBoundingClientRect();\n if (!rect || !tabStripRect) return false;\n\n const centerX = rect.left + rect.width / 2;\n const centerY = rect.top + rect.height / 2;\n\n return (\n centerX >= tabStripRect.left &&\n centerX <= tabStripRect.right &&\n centerY >= tabStripRect.top &&\n centerY <= tabStripRect.bottom\n );\n };\n\n const shouldHideSharedDragOverlay = (\n event: DragMoveEvent | DragOverEvent | DragStartEvent,\n ) => {\n if (isDragInsideTabStrip(event)) {\n return true;\n }\n if ('over' in event) {\n return event.over?.data.current?.tabStripId === dndScopeId;\n }\n return false;\n };\n\n const handleDragEnd = (event: DragEndEvent) => {\n const {active, over} = event;\n if (!over || active.id === over.id || !onOpenTabsChange) return;\n\n const activeData = active.data.current;\n const overData = over.data.current;\n const activeTabId =\n typeof activeData?.tabId === 'string'\n ? activeData.tabId\n : String(active.id);\n const overTabId =\n typeof overData?.tabId === 'string' ? overData.tabId : String(over.id);\n\n if (\n dndMode === 'shared' &&\n (activeData?.tabStripId !== dndScopeId ||\n overData?.tabStripId !== dndScopeId)\n ) {\n return;\n }\n\n const oldIndex = openTabItems.findIndex((tab) => tab.id === activeTabId);\n const newIndex = openTabItems.findIndex((tab) => tab.id === overTabId);\n\n if (oldIndex !== -1 && newIndex !== -1) {\n const newOrder = arrayMove(\n openTabItems.map((t) => t.id),\n oldIndex,\n newIndex,\n );\n onOpenTabsChange(newOrder);\n }\n };\n\n const getSortableId = (tabId: string) =>\n dndMode === 'shared' ? `${dndScopeId}:${tabId}` : tabId;\n\n const tabIds = useMemo(\n () => openTabItems.map((t) => getSortableId(t.id)),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [openTabItems, dndMode, dndScopeId],\n );\n\n const content = (\n <SortableContext items={tabIds} strategy={horizontalListSortingStrategy}>\n <ScrollableRow\n className=\"h-full min-w-0 shrink overflow-hidden\"\n scrollRef={scrollContainerRef}\n scrollClassName={cn(\n 'flex h-full min-w-0 items-center gap-1 overflow-x-auto overflow-y-visible',\n 'pl-1 pr-1 scroll-pl-7 scroll-pr-7 [&::-webkit-scrollbar]:hidden',\n className,\n )}\n arrowVisibility=\"always\"\n arrowClassName=\"w-7\"\n arrowIconClassName=\"h-4 w-4 opacity-60\"\n >\n {openTabItems.map((tab) => (\n <SortableTab\n key={tab.id}\n tab={tab}\n sortableId={getSortableId(tab.id)}\n tabClassName={tabClassName}\n editingTabId={editingTabId}\n closeable={\n closeable && !(preventCloseLastTab && openTabItems.length === 1)\n }\n onClose={handleClose}\n onActivate={onActivate ?? (() => undefined)}\n onStartEditing={handleStartEditing}\n onStopEditing={handleStopEditing}\n onInlineRename={handleInlineRename}\n renderTabMenu={renderTabMenu}\n renderTabLabel={renderTabLabel}\n dndScopeId={dndScopeId}\n getTabDragData={getTabDragData}\n fontSize={fontSize}\n />\n ))}\n </ScrollableRow>\n </SortableContext>\n );\n\n if (dndMode === 'shared') {\n const activeDraggedTab = activeDraggedTabId\n ? openTabItems.find((tab) => tab.id === activeDraggedTabId)\n : undefined;\n\n return (\n <>\n <SharedTabStripDndMonitor\n dndScopeId={dndScopeId}\n handleDragEnd={handleDragEnd}\n setActiveDraggedTabId={setActiveDraggedTabId}\n setHideSharedDragOverlay={setHideSharedDragOverlay}\n shouldHideSharedDragOverlay={shouldHideSharedDragOverlay}\n />\n {content}\n <DragOverlay dropAnimation={null}>\n {activeDraggedTab && !hideSharedDragOverlay ? (\n <TabDragOverlay\n tab={activeDraggedTab}\n renderTabLabel={renderTabLabel}\n fontSize={fontSize}\n />\n ) : null}\n </DragOverlay>\n </>\n );\n }\n\n return (\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n modifiers={DRAG_MODIFIERS}\n autoScroll={true}\n onDragEnd={handleDragEnd}\n >\n {content}\n </DndContext>\n );\n}\n\nfunction SharedTabStripDndMonitor({\n dndScopeId,\n handleDragEnd,\n setActiveDraggedTabId,\n setHideSharedDragOverlay,\n shouldHideSharedDragOverlay,\n}: {\n dndScopeId: string;\n handleDragEnd: (event: DragEndEvent) => void;\n setActiveDraggedTabId: React.Dispatch<React.SetStateAction<string | null>>;\n setHideSharedDragOverlay: React.Dispatch<React.SetStateAction<boolean>>;\n shouldHideSharedDragOverlay: (\n event: DragMoveEvent | DragOverEvent | DragStartEvent,\n ) => boolean;\n}) {\n const isOwnTabDrag = (\n event: DragStartEvent | DragMoveEvent | DragOverEvent | DragEndEvent,\n ) => event.active.data.current?.tabStripId === dndScopeId;\n\n useDndMonitor({\n onDragStart: (event) => {\n const activeData = event.active.data.current;\n if (!isOwnTabDrag(event)) {\n return;\n }\n setActiveDraggedTabId(\n typeof activeData?.tabId === 'string' ? activeData.tabId : null,\n );\n setHideSharedDragOverlay(true);\n },\n onDragMove: (event) => {\n if (!isOwnTabDrag(event)) return;\n setHideSharedDragOverlay(shouldHideSharedDragOverlay(event));\n },\n onDragOver: (event) => {\n if (!isOwnTabDrag(event)) return;\n setHideSharedDragOverlay(shouldHideSharedDragOverlay(event));\n },\n onDragEnd: (event) => {\n if (!isOwnTabDrag(event)) return;\n handleDragEnd(event);\n setActiveDraggedTabId(null);\n setHideSharedDragOverlay(false);\n },\n onDragCancel: () => {\n setActiveDraggedTabId(null);\n setHideSharedDragOverlay(false);\n },\n });\n\n return null;\n}\n\nfunction TabDragOverlay({\n tab,\n renderTabLabel,\n fontSize,\n}: {\n tab: TabDescriptor;\n renderTabLabel?: (tab: TabDescriptor) => React.ReactNode;\n fontSize?: React.CSSProperties['fontSize'];\n}) {\n return (\n <div\n className={cn(\n 'bg-primary/15 text-foreground border-primary/50 flex h-7 max-w-[200px] min-w-[100px]',\n 'cursor-grabbing items-center justify-center gap-1 overflow-hidden rounded-md border px-6 py-1',\n 'text-sm shadow-lg',\n )}\n style={getFontSizeStyle(fontSize)}\n >\n <div className=\"truncate text-center\">\n {renderTabLabel ? renderTabLabel(tab) : tab.name}\n </div>\n </div>\n );\n}\n\ninterface TabStripSearchDropdownProps {\n className?: string;\n triggerClassName?: string;\n /** Whether to auto-focus the search input when dropdown opens. Defaults to true. */\n autoFocus?: boolean;\n /** Optional tooltip content for the trigger button. */\n tooltip?: React.ReactNode;\n /** Optional custom icon for the trigger button. */\n triggerIcon?: React.ReactNode;\n /** Message shown when there are no tabs at all. */\n emptyMessage?: React.ReactNode;\n /** Message shown when searching and there are no matching tabs. */\n searchEmptyMessage?: React.ReactNode;\n /** Label for the closed tabs group. */\n closedTabsLabel?: React.ReactNode;\n /** Sorting mode for search dropdown items. */\n sortSearchItems?: 'none' | 'recent';\n /** Optional accessor for tab recency timestamps. */\n getTabLastOpenedAt?: (tab: TabDescriptor) => number | undefined;\n}\n\n/**\n * Renders the dropdown with search for browsing tabs.\n * Shows open tabs first and closed tabs second (dimmed). When searching, shows all matching tabs.\n */\nfunction TabStripSearchDropdown({\n className,\n triggerClassName,\n autoFocus = true,\n tooltip,\n triggerIcon,\n emptyMessage = 'No tabs',\n searchEmptyMessage = 'No matching tabs',\n closedTabsLabel = 'Recently closed',\n sortSearchItems = 'recent',\n getTabLastOpenedAt,\n}: TabStripSearchDropdownProps) {\n const {\n openTabItems,\n search,\n setSearch,\n closedTabs,\n filteredTabs,\n closedTabIds,\n openTabs,\n preventCloseLastTab,\n onOpenTabsChange,\n onSelect,\n renderSearchItemActions,\n renderSearchItemLabel,\n getLastOpenedAt,\n handleClose,\n fontSize,\n } = useTabStripContext();\n const fontSizeStyle = getFontSizeStyle(fontSize);\n\n const [isOpen, setIsOpen] = useState(false);\n\n const isSearching = search.trim().length > 0;\n\n const handleOpenChange = (open: boolean) => {\n setIsOpen(open);\n if (!open) {\n setSearch('');\n }\n };\n\n const handleTabClick = (tabId: string) => {\n if (closedTabIds.has(tabId)) {\n // Opening a closed tab: add to openTabs and select it\n onOpenTabsChange?.([...(openTabs ?? []), tabId]);\n onSelect?.(tabId);\n } else {\n // Already open: just select it\n onSelect?.(tabId);\n }\n setIsOpen(false);\n };\n\n const sortByRecency = (tabsToSort: TabDescriptor[]) => {\n if (sortSearchItems !== 'recent') {\n return tabsToSort;\n }\n\n const withIndex = tabsToSort.map((tab, index) => ({\n tab,\n index,\n ts: getTabLastOpenedAt?.(tab) ?? getLastOpenedAt(tab.id),\n }));\n\n return withIndex\n .slice()\n .sort((a, b) => {\n const aTs = a.ts ?? -1;\n const bTs = b.ts ?? -1;\n if (aTs === bTs) {\n return a.index - b.index;\n }\n return bTs - aTs;\n })\n .map((item) => item.tab);\n };\n\n const openTabsList = sortByRecency(openTabItems);\n const closedTabsList = sortByRecency(closedTabs);\n const hasAnyTabs = openTabsList.length + closedTabsList.length > 0;\n\n const filteredOpenTabs = sortByRecency(\n filteredTabs.filter((tab) => !closedTabIds.has(tab.id)),\n );\n const filteredClosedTabs = sortByRecency(\n filteredTabs.filter((tab) => closedTabIds.has(tab.id)),\n );\n\n const renderOpenTabActions = (tab: TabDescriptor) => {\n const disableClose = preventCloseLastTab && (openTabsList.length ?? 0) <= 1;\n return (\n <>\n {renderSearchItemActions?.(tab)}\n <TabStripSearchItemAction\n icon={<XIcon className=\"h-3 w-3\" />}\n aria-label={`Close ${tab.name}`}\n onClick={disableClose ? undefined : () => handleClose(tab.id)}\n className={cn(disableClose && 'pointer-events-none opacity-40')}\n />\n </>\n );\n };\n\n const triggerButton = (\n <DropdownMenuTrigger asChild>\n <Button\n variant=\"ghost\"\n aria-label=\"Browse tabs\"\n size=\"icon\"\n className={cn(...TAB_STRIP_BUTTON_CLASSNAMES, triggerClassName)}\n style={fontSizeStyle}\n >\n {triggerIcon ?? <ListCollapseIcon className=\"h-4 w-4\" />}\n </Button>\n </DropdownMenuTrigger>\n );\n\n return (\n <DropdownMenu open={isOpen} onOpenChange={handleOpenChange}>\n {tooltip ? (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>{triggerButton}</TooltipTrigger>\n <TooltipContent>{tooltip}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n ) : (\n triggerButton\n )}\n\n <DropdownMenuContent\n align=\"start\"\n onCloseAutoFocus={(event) => event.preventDefault()}\n className={cn(\n 'flex max-h-[400px] max-w-[240px] flex-col overflow-x-hidden',\n className,\n )}\n style={fontSizeStyle}\n >\n <div className=\"flex shrink-0 items-center gap-1 px-2\">\n <SearchIcon className=\"text-muted-foreground\" size={14} />\n <Input\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'ArrowDown' || event.key === 'Tab') {\n event.preventDefault();\n const firstItem = event.currentTarget\n .closest('[role=\"menu\"]')\n ?.querySelector<HTMLElement>(\n '[role=\"menuitem\"]:not([disabled])',\n );\n firstItem?.focus();\n } else {\n event.stopPropagation();\n }\n }}\n onKeyUp={(event) => event.stopPropagation()}\n className=\"border-none text-xs shadow-none focus-visible:ring-0\"\n style={fontSizeStyle}\n placeholder=\"Search...\"\n aria-label=\"Search\"\n autoFocus={autoFocus}\n />\n </div>\n <DropdownMenuSeparator className=\"shrink-0\" />\n\n <div className=\"overflow-x-hidden overflow-y-auto\">\n {isSearching ? (\n filteredTabs.length === 0 ? (\n <DropdownTabItems\n tabs={filteredTabs}\n emptyMessage={searchEmptyMessage}\n onTabClick={handleTabClick}\n renderLabel={renderSearchItemLabel}\n renderActions={renderSearchItemActions}\n />\n ) : (\n <>\n <DropdownTabItems\n tabs={filteredOpenTabs}\n onTabClick={handleTabClick}\n renderLabel={renderSearchItemLabel}\n renderActions={renderOpenTabActions}\n />\n {filteredClosedTabs.length > 0 && (\n <>\n {filteredOpenTabs.length > 0 && <DropdownMenuSeparator />}\n <DropdownMenuLabel\n className=\"text-muted-foreground py-1 text-xs font-medium\"\n style={fontSizeStyle}\n >\n {closedTabsLabel}\n </DropdownMenuLabel>\n <DropdownTabItems\n tabs={filteredClosedTabs}\n onTabClick={handleTabClick}\n renderLabel={renderSearchItemLabel}\n renderActions={renderSearchItemActions}\n getItemClassName={() => 'text-muted-foreground'}\n />\n </>\n )}\n </>\n )\n ) : (\n <>\n {hasAnyTabs ? (\n <>\n <DropdownTabItems\n tabs={openTabsList}\n onTabClick={handleTabClick}\n renderLabel={renderSearchItemLabel}\n renderActions={renderOpenTabActions}\n />\n {closedTabsList.length > 0 && (\n <>\n {openTabsList.length > 0 && <DropdownMenuSeparator />}\n <DropdownMenuLabel\n className=\"text-muted-foreground py-1 text-xs font-medium\"\n style={fontSizeStyle}\n >\n {closedTabsLabel}\n </DropdownMenuLabel>\n <DropdownTabItems\n tabs={closedTabsList}\n onTabClick={handleTabClick}\n renderLabel={renderSearchItemLabel}\n renderActions={renderSearchItemActions}\n getItemClassName={() => 'text-muted-foreground'}\n />\n </>\n )}\n </>\n ) : (\n <DropdownTabItems\n tabs={[]}\n emptyMessage={emptyMessage}\n onTabClick={handleTabClick}\n renderLabel={renderSearchItemLabel}\n renderActions={renderSearchItemActions}\n />\n )}\n </>\n )}\n </div>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\ninterface DropdownTabItemsProps {\n tabs: TabDescriptor[];\n emptyMessage?: React.ReactNode;\n onTabClick?: (tabId: string) => void;\n renderLabel?: (tab: TabDescriptor) => React.ReactNode;\n renderActions?: (tab: TabDescriptor) => React.ReactNode;\n getItemClassName?: (tab: TabDescriptor) => string | undefined;\n}\n\nfunction DropdownTabItems({\n tabs,\n emptyMessage,\n onTabClick,\n renderLabel,\n renderActions,\n getItemClassName,\n}: DropdownTabItemsProps) {\n const {fontSize} = useTabStripContext();\n const fontSizeStyle = getFontSizeStyle(fontSize);\n\n if (tabs.length === 0) {\n if (!emptyMessage) return null;\n return (\n <DropdownMenuLabel\n className=\"items-center justify-center text-xs\"\n style={fontSizeStyle}\n >\n {emptyMessage}\n </DropdownMenuLabel>\n );\n }\n\n return (\n <>\n {tabs.map((tab) => (\n <DropdownMenuItem\n key={tab.id}\n onClick={() => onTabClick?.(tab.id)}\n className={cn(\n 'flex h-7 cursor-pointer items-center justify-between truncate',\n getItemClassName?.(tab),\n )}\n style={fontSizeStyle}\n >\n <div className=\"min-w-0 truncate pl-1 text-xs\" style={fontSizeStyle}>\n {renderLabel ? renderLabel(tab) : tab.name}\n </div>\n {renderActions && (\n <div className=\"flex items-center gap-2\">{renderActions(tab)}</div>\n )}\n </DropdownMenuItem>\n ))}\n </>\n );\n}\n\n/**\n * A general-purpose button for the tab strip.\n */\nconst TabStripButton = React.forwardRef<HTMLButtonElement, ButtonProps>(\n function TabStripButtonComponent({className, style, ...props}, ref) {\n const context = useOptionalTabStripContext();\n\n return (\n <Button\n ref={ref}\n size=\"icon\"\n variant=\"ghost\"\n style={mergeFontSizeStyle(context?.fontSize, style)}\n className={cn(\n ...TAB_STRIP_BUTTON_CLASSNAMES,\n 'h-full shrink-0',\n className,\n )}\n {...props}\n />\n );\n },\n);\nTabStripButton.displayName = 'TabStripButton';\ntype TabStripNewButtonProps = ButtonProps & {\n /** Optional tooltip content for the button. */\n tooltip?: React.ReactNode;\n};\n\n/**\n * Renders a button to create a new tab.\n */\nfunction TabStripNewButton({tooltip, ...props}: TabStripNewButtonProps) {\n const {onCreate, fontSize} = useTabStripContext();\n\n if (!onCreate) {\n return null;\n }\n\n const button = (\n <TabStripButton\n {...props}\n style={mergeFontSizeStyle(fontSize, props.style)}\n aria-label={props['aria-label'] || 'Create new tab'}\n onClick={(e) => {\n onCreate();\n props.onClick?.(e);\n }}\n >\n <PlusIcon className=\"h-4 w-4\" />\n </TabStripButton>\n );\n\n if (tooltip) {\n return (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>{button}</TooltipTrigger>\n <TooltipContent>{tooltip}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n }\n\n return button;\n}\n\n// -----------------------------------------------------------------------------\n// Main Component\n// -----------------------------------------------------------------------------\n\nexport interface TabStripProps {\n className?: string;\n tabsListClassName?: string;\n children?: React.ReactNode;\n /** All available tabs. */\n tabs: TabDescriptor[];\n /** IDs of tabs that are currently open. */\n openTabs?: string[];\n /** ID of the currently selected tab. */\n selectedTabId?: string | null;\n /** If true, hides the close button when only one tab remains open. */\n preventCloseLastTab?: boolean;\n /** Whether tabs can be closed. Defaults to true. */\n closeable?: boolean;\n /** Called when a tab is closed (hidden, can be reopened). */\n onClose?: (tabId: string) => void;\n /** Called when the list of open tabs changes (open from dropdown or reorder). */\n onOpenTabsChange?: (tabIds: string[]) => void;\n /** Called when a tab is selected. */\n onSelect?: (tabId: string) => void;\n /** Called when a tab trigger is clicked, including the already-selected tab. */\n onActivate?: (tabId: string) => void;\n /** Called when a new tab should be created. */\n onCreate?: () => void;\n /** Called when a tab is renamed inline. */\n onRename?: (tabId: string, newName: string) => void;\n /** Render function for the tab's dropdown menu. Use TabStrip.MenuItem and TabStrip.MenuSeparator. */\n renderTabMenu?: (tab: TabDescriptor) => React.ReactNode;\n /** Render function for search dropdown item actions. Use TabStrip.SearchItemAction. */\n renderSearchItemActions?: (tab: TabDescriptor) => React.ReactNode;\n /** Render function for custom search dropdown item labels. */\n renderSearchItemLabel?: (tab: TabDescriptor) => React.ReactNode;\n /** Render function for custom tab content. Receives the tab and returns the content to display. */\n renderTabLabel?: (tab: TabDescriptor) => React.ReactNode;\n /** Font size applied to tab labels, inline editing, and TabStrip subcomponents. */\n fontSize?: React.CSSProperties['fontSize'];\n /** Whether this tab strip owns its dnd context or participates in a shared parent context. */\n dndMode?: TabStripDndMode;\n /** Unique scope for shared dnd tab ids. Defaults to a generated component id. */\n dndScopeId?: string;\n /** Extra drag payload attached to tab drags; may intentionally override `kind`. */\n getTabDragData?: (tab: TabDescriptor) => TabStripDragData | undefined;\n}\n\n/**\n * A composable tab strip component with search dropdown and tab management.\n *\n * @example\n * // Default layout\n * <TabStrip\n * tabs={tabs}\n * openTabs={openTabs}\n * onClose={closeTab}\n * onOpen={openTab}\n * onCreate={createTab}\n * />\n *\n * @example\n * // Custom layout with subcomponents\n * <TabStrip tabs={tabs} openTabs={openTabs} onClose={closeTab}>\n * <TabStrip.Tabs className=\"flex-1\" />\n * <TabStrip.SearchDropdown />\n * <TabStrip.NewButton />\n * </TabStrip>\n */\nfunction TabStripRoot({\n className,\n tabsListClassName,\n children,\n tabs,\n openTabs,\n selectedTabId,\n preventCloseLastTab = false,\n closeable = true,\n onClose,\n onOpenTabsChange,\n onSelect,\n onActivate,\n onCreate,\n onRename,\n renderTabMenu,\n renderSearchItemActions,\n renderSearchItemLabel,\n renderTabLabel,\n fontSize,\n dndMode = 'internal',\n dndScopeId,\n getTabDragData,\n}: TabStripProps) {\n const generatedDndScopeId = useId();\n const actualDndScopeId = dndScopeId ?? generatedDndScopeId;\n const [search, setSearch] = useState('');\n const [editingTabId, setEditingTabId] = useState<string | null>(null);\n const scrollContainerRef = useRef<HTMLDivElement>(null!);\n const prevSelectedIdRef = useRef<string | null>(null);\n const prevOpenTabIdsRef = useRef<Set<string>>(new Set());\n const lastOpenedAtRef = useRef<Map<string, number>>(new Map());\n\n const openTabsSet = useMemo(() => new Set(openTabs), [openTabs]);\n\n // Build openTabItems in the order of openTabs (for drag-to-reorder)\n const openTabItems = useMemo(() => {\n const tabsById = new Map(tabs.map((tab) => [tab.id, tab]));\n return (openTabs ?? [])\n .map((id) => tabsById.get(id))\n .filter((tab): tab is TabDescriptor => tab !== undefined);\n }, [tabs, openTabs]);\n\n const closedTabs = useMemo(\n () => tabs.filter((tab) => !openTabsSet.has(tab.id)),\n [tabs, openTabsSet],\n );\n\n const closedTabIds = useMemo(\n () => new Set(closedTabs.map((tab) => tab.id)),\n [closedTabs],\n );\n\n const trimmedSearch = search.trim().toLowerCase();\n\n const filteredTabs = useMemo(\n () =>\n trimmedSearch\n ? tabs.filter((tab) => tab.name.toLowerCase().includes(trimmedSearch))\n : [],\n [tabs, trimmedSearch],\n );\n\n useEffect(() => {\n if (!selectedTabId) return;\n lastOpenedAtRef.current.set(selectedTabId, Date.now());\n }, [selectedTabId]);\n\n useEffect(() => {\n const ids = new Set(tabs.map((tab) => tab.id));\n const next = new Map<string, number>();\n for (const [id, ts] of lastOpenedAtRef.current.entries()) {\n if (ids.has(id)) {\n next.set(id, ts);\n }\n }\n lastOpenedAtRef.current = next;\n }, [tabs]);\n\n // Auto-scroll to selected tab\n useLayoutEffect(() => {\n if (!selectedTabId) return;\n if (prevSelectedIdRef.current === selectedTabId) return;\n prevSelectedIdRef.current = selectedTabId;\n\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const isOpen = openTabItems.some((tab) => tab.id === selectedTabId);\n if (!isOpen) return;\n\n // Use queueMicrotask to defer scroll until after Radix UI updates the DOM\n queueMicrotask(() => {\n const activeTab = container.querySelector<HTMLElement>(\n '[data-state=\"active\"]',\n );\n if (!activeTab) return;\n\n activeTab.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'nearest',\n // @ts-expect-error - scrollMode is not standardized yet\n scrollMode: 'if-needed',\n });\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedTabId]);\n\n // Auto-scroll to newly added tab\n useLayoutEffect(() => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n // Find newly added tabs (in openTabs but not in prevOpenTabIdsRef)\n const newTabIds = (openTabs ?? []).filter(\n (id) => !prevOpenTabIdsRef.current.has(id),\n );\n\n // Update ref for next comparison\n prevOpenTabIdsRef.current = new Set(openTabs);\n\n if (newTabIds.length > 0) {\n const now = Date.now();\n for (const id of newTabIds) {\n lastOpenedAtRef.current.set(id, now);\n }\n }\n\n // Skip scroll on initial render (when ref was empty, all tabs appear \"new\")\n if (newTabIds.length === (openTabs?.length ?? 0)) return;\n\n // If there are new tabs, scroll to the last one added\n if (newTabIds.length === 0) return;\n const newTabId = newTabIds[newTabIds.length - 1];\n\n queueMicrotask(() => {\n const newTabElement = container.querySelector<HTMLElement>(\n `[data-tab-id=\"${newTabId}\"]`,\n );\n if (!newTabElement) return;\n\n newTabElement.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'nearest',\n });\n });\n }, [openTabs]);\n\n const handleInlineRename = (tabId: string, newName: string) => {\n if (!onRename) return;\n const tab = tabs.find((t) => t.id === tabId);\n const trimmed = newName.trim();\n if (!trimmed || trimmed === tab?.name) {\n setEditingTabId(null);\n return;\n }\n onRename(tabId, trimmed);\n setEditingTabId(null);\n };\n\n const handleStartEditing = (tabId: string) => {\n if (!onRename) return;\n setEditingTabId(tabId);\n };\n\n const handleStopEditing = () => {\n setEditingTabId(null);\n };\n\n const handleClose = (tabId: string) => {\n // If closing the selected tab, select the one to the left (or right if leftmost)\n if (selectedTabId === tabId && openTabItems.length > 1) {\n const closingIndex = openTabItems.findIndex((t) => t.id === tabId);\n // If closing the leftmost, select the next; otherwise select the previous\n const newIndex = closingIndex === 0 ? 1 : closingIndex - 1;\n const newSelectedId = openTabItems[newIndex]?.id;\n if (newSelectedId) {\n onSelect?.(newSelectedId);\n }\n }\n onClose?.(tabId);\n };\n\n const contextValue: TabStripContextValue = {\n openTabItems,\n closedTabs,\n closedTabIds,\n filteredTabs,\n editingTabId,\n search,\n scrollContainerRef,\n selectedTabId,\n openTabs,\n preventCloseLastTab,\n closeable,\n getLastOpenedAt: (tabId) => lastOpenedAtRef.current.get(tabId),\n dndMode,\n dndScopeId: actualDndScopeId,\n getTabDragData,\n fontSize,\n onOpenTabsChange,\n onSelect,\n onActivate,\n onCreate,\n onRename,\n renderTabMenu,\n renderSearchItemActions,\n renderSearchItemLabel,\n renderTabLabel,\n setSearch,\n handleStartEditing,\n handleStopEditing,\n handleInlineRename,\n handleClose,\n };\n\n const handleValueChange = (value: string) => {\n onSelect?.(value);\n };\n\n return (\n <Tabs\n value={selectedTabId ?? undefined}\n onValueChange={handleValueChange}\n activationMode=\"manual\"\n className={cn('bg-muted w-full min-w-0', className)}\n style={getFontSizeStyle(fontSize)}\n >\n <TabStripContext.Provider value={contextValue}>\n <TabsList\n className={cn(\n 'flex h-9 w-full min-w-0 items-center justify-start gap-2 overflow-visible bg-transparent p-1',\n tabsListClassName,\n )}\n >\n {children ?? (\n <>\n <TabStripSearchDropdown />\n <TabStripTabs />\n <TabStripNewButton />\n </>\n )}\n </TabsList>\n </TabStripContext.Provider>\n </Tabs>\n );\n}\n\n// Attach subcomponents\nexport const TabStrip = Object.assign(TabStripRoot, {\n Tabs: TabStripTabs,\n SearchDropdown: TabStripSearchDropdown,\n Button: TabStripButton,\n NewButton: TabStripNewButton,\n MenuItem: TabStripMenuItem,\n MenuSeparator: TabStripMenuSeparator,\n SearchItemAction: TabStripSearchItemAction,\n});\n\nexport type {\n TabStripMenuItemProps,\n TabStripMenuSeparatorProps,\n TabStripNewButtonProps,\n TabStripSearchDropdownProps,\n TabStripSearchItemActionProps,\n TabStripTabsProps,\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../src/components/tree.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAMtC,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,CAAC,CAAC;IACV,QAAQ,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,KAAK,SAAS,CAAC,CAAC,IAAI;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC1B,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;CAC5C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,YAAY,CAO/D;AAED,KAAK,aAAa,CAAC,CAAC,IAAI;IACtB,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC1B,UAAU,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,KAAK,KAAK,CAAC,SAAS,CAAC;CACzE,CAAC"}
1
+ {"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../src/components/tree.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAQtC,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,CAAC,CAAC;IACV,QAAQ,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,KAAK,SAAS,CAAC,CAAC,IAAI;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC1B,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;CAC5C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,YAAY,CAO/D;AAED,KAAK,aAAa,CAAC,CAAC,IAAI;IACtB,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC1B,UAAU,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,KAAK,KAAK,CAAC,SAAS,CAAC;CACzE,CAAC"}
@@ -5,6 +5,7 @@ import { useState } from 'react';
5
5
  import { ChevronRightIcon } from 'lucide-react';
6
6
  import { cn } from '../lib/utils';
7
7
  import { CollapsibleTrigger } from './collapsible';
8
+ const DROPDOWN_ICON_PLACEHOLDER_WIDTH = '18px';
8
9
  /**
9
10
  * Component that renders a generic tree.
10
11
  * @param treeData - The tree data.
@@ -23,11 +24,11 @@ function TreeNode(props) {
23
24
  const hasChildren = Boolean(children?.length);
24
25
  const [isOpen, setIsOpen] = useState(Boolean(treeData.isInitialOpen));
25
26
  if (!hasChildren) {
26
- return _jsx("div", { className: "pl-4", children: renderNode(treeData, isOpen) });
27
+ return (_jsxs("div", { className: "flex w-full items-center space-x-1", children: [_jsx("div", { className: "shrink-0", style: { width: DROPDOWN_ICON_PLACEHOLDER_WIDTH } }), renderNode(treeData, isOpen)] }));
27
28
  }
28
29
  return (_jsxs(Collapsible, { open: isOpen, onOpenChange: setIsOpen, children: [_jsx(CollapsibleTrigger, { className: "w-full", asChild: true, children: _jsxs("div", { className: "flex w-full cursor-pointer items-center space-x-1", children: [_jsx(ChevronRightIcon, { className: cn('shrink-0 text-gray-500', {
29
30
  'rotate-90 transform': isOpen,
30
- }), size: "18px" }), renderNode(treeData, isOpen)] }) }), _jsx(CollapsibleContent, { className: "pl-4", children: isOpen
31
+ }), size: DROPDOWN_ICON_PLACEHOLDER_WIDTH }), renderNode(treeData, isOpen)] }) }), _jsx(CollapsibleContent, { className: "pl-4", children: isOpen
31
32
  ? children?.map((child) => (_jsx(TreeNode, { treeData: child, renderNode: renderNode }, child.key)))
32
33
  : null })] }));
33
34
  }