@toolr/ui-design 0.1.6 → 0.1.8
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.
- package/components/hooks/use-click-outside.ts +10 -3
- package/components/hooks/use-modal-behavior.ts +53 -0
- package/components/hooks/use-navigation-history.ts +7 -2
- package/components/hooks/use-resizable-sidebar.ts +38 -0
- package/components/lib/form-colors.ts +40 -0
- package/components/sections/captured-issues/captured-issues-panel.tsx +3 -3
- package/components/sections/captured-issues/use-captured-issues.ts +9 -3
- package/components/sections/golden-snapshots/file-diff-viewer.tsx +1 -1
- package/components/sections/golden-snapshots/status-overview.tsx +1 -1
- package/components/sections/prompt-editor/file-type-tabbed-prompt-editor.tsx +4 -40
- package/components/sections/prompt-editor/index.ts +0 -7
- package/components/sections/prompt-editor/simulator-prompt-editor.tsx +4 -40
- package/components/sections/prompt-editor/tabbed-prompt-editor.tsx +4 -36
- package/components/sections/snippets-editor/snippets-editor.tsx +6 -39
- package/components/settings/SettingsHeader.tsx +0 -1
- package/components/settings/SettingsTreeNav.tsx +9 -12
- package/components/ui/action-dialog.tsx +19 -55
- package/components/ui/ai-action-button.tsx +2 -4
- package/components/ui/badge.tsx +15 -23
- package/components/ui/breadcrumb.tsx +11 -71
- package/components/ui/checkbox.tsx +19 -27
- package/components/ui/collapsible-section.tsx +4 -41
- package/components/ui/confirm-badge.tsx +14 -23
- package/components/ui/cookie-consent.tsx +18 -2
- package/components/ui/debounce-border-overlay.tsx +31 -0
- package/components/ui/detail-section.tsx +2 -19
- package/components/ui/editor-placeholder-card.tsx +10 -9
- package/components/ui/execution-details-panel.tsx +2 -7
- package/components/ui/extension-list-card.tsx +1 -1
- package/components/ui/file-structure-section.tsx +3 -18
- package/components/ui/file-tree.tsx +6 -18
- package/components/ui/files-panel.tsx +3 -11
- package/components/ui/filter-dropdown.tsx +5 -2
- package/components/ui/form-actions.tsx +11 -8
- package/components/ui/icon-button.tsx +7 -6
- package/components/ui/input.tsx +18 -29
- package/components/ui/label.tsx +7 -17
- package/components/ui/layout-tab-bar.tsx +5 -5
- package/components/ui/modal.tsx +10 -18
- package/components/ui/nav-card.tsx +3 -18
- package/components/ui/navigation-bar.tsx +12 -73
- package/components/ui/number-input.tsx +6 -0
- package/components/ui/registry-browser.tsx +6 -20
- package/components/ui/registry-card.tsx +3 -7
- package/components/ui/resizable-textarea.tsx +13 -35
- package/components/ui/segmented-toggle.tsx +4 -1
- package/components/ui/select.tsx +8 -14
- package/components/ui/selection-grid.tsx +6 -50
- package/components/ui/setting-row.tsx +5 -5
- package/components/ui/settings-card.tsx +2 -2
- package/components/ui/settings-info-box.tsx +6 -24
- package/components/ui/sort-dropdown.tsx +8 -5
- package/components/ui/status-card.tsx +2 -13
- package/components/ui/tab-bar.tsx +17 -33
- package/components/ui/toggle.tsx +22 -30
- package/components/ui/tooltip.tsx +11 -23
- package/dist/index.d.ts +71 -142
- package/dist/index.js +1630 -2436
- package/index.ts +8 -7
- package/package.json +9 -1
- package/components/sections/prompt-editor/use-prompt-editor.ts +0 -131
|
@@ -73,22 +73,25 @@ export function SortDropdown({
|
|
|
73
73
|
return (
|
|
74
74
|
<div className="relative flex items-center" ref={ref} onKeyDown={handleKeyDown}>
|
|
75
75
|
<button
|
|
76
|
+
aria-expanded={isOpen}
|
|
77
|
+
aria-haspopup="listbox"
|
|
76
78
|
onClick={() => setIsOpen(!isOpen)}
|
|
77
79
|
className={`flex items-center gap-1.5 h-7 px-2 rounded-md border ${v.bg} text-sm transition-colors cursor-pointer ${FORM_COLORS[color].border} text-neutral-200 ${FORM_COLORS[color].hover}`}
|
|
78
80
|
>
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
+
<button
|
|
82
|
+
type="button"
|
|
83
|
+
aria-label={ascending ? 'Sort descending' : 'Sort ascending'}
|
|
84
|
+
className={`${FORM_COLORS[color].accent} hover:brightness-125 transition-colors cursor-pointer`}
|
|
81
85
|
onClick={(e) => { e.stopPropagation(); onToggleDirection() }}
|
|
82
|
-
role="button"
|
|
83
86
|
>
|
|
84
87
|
<DirIcon className="w-3 h-3" />
|
|
85
|
-
</
|
|
88
|
+
</button>
|
|
86
89
|
<span className="whitespace-nowrap">{current.label}</span>
|
|
87
90
|
<ChevronDown className={`w-3 h-3 transition-transform ${isOpen ? 'rotate-180' : ''}`} />
|
|
88
91
|
</button>
|
|
89
92
|
|
|
90
93
|
{isOpen && (
|
|
91
|
-
<div ref={menuRef} className={`absolute right-0 top-full z-50 mt-1 min-w-[140px] bg-[var(--popover)] border ${FORM_COLORS[color].border} rounded-lg shadow-
|
|
94
|
+
<div ref={menuRef} role="listbox" className={`absolute right-0 top-full z-50 mt-1 min-w-[140px] bg-[var(--popover)] border ${FORM_COLORS[color].border} rounded-lg shadow-lg overflow-hidden`}>
|
|
92
95
|
{fields.map((f, idx) => (
|
|
93
96
|
<button
|
|
94
97
|
key={f.value}
|
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
/** Status card displaying a list of labeled items with color-coded status indicators. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
Settings, Shield, Database, Globe, Zap, Code, Terminal,
|
|
5
|
-
Star, Cloud, Bell, Heart, Sparkles, Bot, Plug,
|
|
6
|
-
} from 'lucide-react'
|
|
7
|
-
import type { LucideIcon } from 'lucide-react'
|
|
8
|
-
import type { IconName } from './icon-button.tsx'
|
|
3
|
+
import { iconMap, type IconName } from './icon-button.tsx'
|
|
9
4
|
import { cn } from '../lib/cn.ts'
|
|
10
5
|
|
|
11
|
-
const iconSubset: Partial<Record<IconName, LucideIcon>> = {
|
|
12
|
-
settings: Settings, shield: Shield, database: Database, globe: Globe,
|
|
13
|
-
zap: Zap, code: Code, terminal: Terminal, star: Star, cloud: Cloud,
|
|
14
|
-
bell: Bell, heart: Heart, sparkles: Sparkles, bot: Bot, plug: Plug,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
6
|
type StatusType = 'success' | 'warning' | 'error' | 'info' | 'neutral'
|
|
18
7
|
|
|
19
8
|
export interface StatusItem {
|
|
@@ -55,7 +44,7 @@ export function StatusCard({
|
|
|
55
44
|
action,
|
|
56
45
|
className,
|
|
57
46
|
}: StatusCardProps) {
|
|
58
|
-
const Icon = icon ?
|
|
47
|
+
const Icon = icon ? iconMap[icon] : undefined
|
|
59
48
|
|
|
60
49
|
return (
|
|
61
50
|
<div className={cn('rounded-lg border border-neutral-700 bg-neutral-800 overflow-hidden', className)}>
|
|
@@ -1,38 +1,12 @@
|
|
|
1
1
|
/** Tab bar with underline, pill, and card variants, closable tabs, color-coded icons, and auto-collapse to icon-only. */
|
|
2
2
|
|
|
3
3
|
import { useRef, useState, useEffect, useCallback } from 'react'
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
Globe, Star, Users, User, Tag, X,
|
|
7
|
-
Zap, Shield, Sparkles, Eye, Lock, Search, Heart,
|
|
8
|
-
} from 'lucide-react'
|
|
9
|
-
import type { LucideIcon } from 'lucide-react'
|
|
10
|
-
import type { IconName } from './icon-button.tsx'
|
|
4
|
+
import { X } from 'lucide-react'
|
|
5
|
+
import { iconMap, type IconName } from './icon-button.tsx'
|
|
11
6
|
import { Badge, type BadgeColor } from './badge.tsx'
|
|
12
7
|
import { cn } from '../lib/cn.ts'
|
|
13
8
|
import { Tooltip } from './tooltip.tsx'
|
|
14
9
|
|
|
15
|
-
const iconSubset: Partial<Record<IconName, LucideIcon>> = {
|
|
16
|
-
folder: Folder,
|
|
17
|
-
file: File,
|
|
18
|
-
settings: Settings,
|
|
19
|
-
code: Code,
|
|
20
|
-
terminal: Terminal,
|
|
21
|
-
database: Database,
|
|
22
|
-
globe: Globe,
|
|
23
|
-
star: Star,
|
|
24
|
-
users: Users,
|
|
25
|
-
user: User,
|
|
26
|
-
tag: Tag,
|
|
27
|
-
zap: Zap,
|
|
28
|
-
shield: Shield,
|
|
29
|
-
sparkles: Sparkles,
|
|
30
|
-
eye: Eye,
|
|
31
|
-
lock: Lock,
|
|
32
|
-
search: Search,
|
|
33
|
-
heart: Heart,
|
|
34
|
-
}
|
|
35
|
-
|
|
36
10
|
export interface Tab {
|
|
37
11
|
id: string
|
|
38
12
|
label: string
|
|
@@ -102,7 +76,7 @@ function estimateTabsWidth(tabs: Tab[], size: keyof typeof sizeConfig): number {
|
|
|
102
76
|
}
|
|
103
77
|
|
|
104
78
|
function TabIcon({ icon, size, color }: { icon: IconName; size: 'xss' | 'xs' | 'sm' | 'md' | 'lg'; color?: string }) {
|
|
105
|
-
const Icon =
|
|
79
|
+
const Icon = iconMap[icon]
|
|
106
80
|
if (!Icon) return null
|
|
107
81
|
const s = sizeConfig[size]
|
|
108
82
|
const c = getColors(color)
|
|
@@ -114,11 +88,12 @@ function TabBadge({ badge, size, badgeColor }: { badge: number | string; size: '
|
|
|
114
88
|
return <Badge value={badge} color={badgeColor} size={s.badgeSize} className="flex-shrink-0" />
|
|
115
89
|
}
|
|
116
90
|
|
|
117
|
-
function CloseButton({ size, onClick }: { size: 'xss' | 'xs' | 'sm' | 'md' | 'lg'; onClick: () => void }) {
|
|
91
|
+
function CloseButton({ size, onClick, tabLabel }: { size: 'xss' | 'xs' | 'sm' | 'md' | 'lg'; onClick: () => void; tabLabel: string }) {
|
|
118
92
|
const s = sizeConfig[size]
|
|
119
93
|
return (
|
|
120
94
|
<button
|
|
121
95
|
type="button"
|
|
96
|
+
aria-label={`Close ${tabLabel}`}
|
|
122
97
|
onClick={(e) => {
|
|
123
98
|
e.stopPropagation()
|
|
124
99
|
onClick()
|
|
@@ -149,6 +124,8 @@ function CompactTab({
|
|
|
149
124
|
return (
|
|
150
125
|
<button
|
|
151
126
|
type="button"
|
|
127
|
+
role="tab"
|
|
128
|
+
aria-selected={isActive}
|
|
152
129
|
onClick={onSelect}
|
|
153
130
|
className={cn(
|
|
154
131
|
'relative flex items-center justify-center transition-colors cursor-pointer',
|
|
@@ -186,6 +163,8 @@ function UnderlineTab({
|
|
|
186
163
|
return (
|
|
187
164
|
<button
|
|
188
165
|
type="button"
|
|
166
|
+
role="tab"
|
|
167
|
+
aria-selected={isActive}
|
|
189
168
|
onClick={onSelect}
|
|
190
169
|
className={cn(
|
|
191
170
|
'group relative flex items-center whitespace-nowrap transition-colors cursor-pointer',
|
|
@@ -197,7 +176,7 @@ function UnderlineTab({
|
|
|
197
176
|
{tab.icon && <TabIcon icon={tab.icon} size={size} color={isActive ? tab.color : undefined} />}
|
|
198
177
|
<span>{tab.label}</span>
|
|
199
178
|
{tab.badge !== undefined && <TabBadge badge={tab.badge} size={size} badgeColor={tab.badgeColor} />}
|
|
200
|
-
{showClose && <CloseButton size={size} onClick={onClose!} />}
|
|
179
|
+
{showClose && <CloseButton size={size} onClick={onClose!} tabLabel={tab.label} />}
|
|
201
180
|
{isActive && (
|
|
202
181
|
<span className={cn('absolute bottom-0 left-0 right-0 h-0.5 rounded-full', c.indicator)} />
|
|
203
182
|
)}
|
|
@@ -215,6 +194,8 @@ function PillTab({
|
|
|
215
194
|
return (
|
|
216
195
|
<button
|
|
217
196
|
type="button"
|
|
197
|
+
role="tab"
|
|
198
|
+
aria-selected={isActive}
|
|
218
199
|
onClick={onSelect}
|
|
219
200
|
className={cn(
|
|
220
201
|
'group flex items-center whitespace-nowrap rounded-md transition-colors cursor-pointer',
|
|
@@ -228,7 +209,7 @@ function PillTab({
|
|
|
228
209
|
{tab.icon && <TabIcon icon={tab.icon} size={size} color={isActive ? tab.color : undefined} />}
|
|
229
210
|
<span>{tab.label}</span>
|
|
230
211
|
{tab.badge !== undefined && <TabBadge badge={tab.badge} size={size} badgeColor={tab.badgeColor} />}
|
|
231
|
-
{showClose && <CloseButton size={size} onClick={onClose!} />}
|
|
212
|
+
{showClose && <CloseButton size={size} onClick={onClose!} tabLabel={tab.label} />}
|
|
232
213
|
</button>
|
|
233
214
|
)
|
|
234
215
|
}
|
|
@@ -243,6 +224,8 @@ function CardTab({
|
|
|
243
224
|
return (
|
|
244
225
|
<button
|
|
245
226
|
type="button"
|
|
227
|
+
role="tab"
|
|
228
|
+
aria-selected={isActive}
|
|
246
229
|
onClick={onSelect}
|
|
247
230
|
className={cn(
|
|
248
231
|
'group relative flex items-center whitespace-nowrap transition-colors cursor-pointer rounded-t-lg border border-b-0',
|
|
@@ -256,7 +239,7 @@ function CardTab({
|
|
|
256
239
|
{tab.icon && <TabIcon icon={tab.icon} size={size} color={isActive ? tab.color : undefined} />}
|
|
257
240
|
<span>{tab.label}</span>
|
|
258
241
|
{tab.badge !== undefined && <TabBadge badge={tab.badge} size={size} badgeColor={tab.badgeColor} />}
|
|
259
|
-
{showClose && <CloseButton size={size} onClick={onClose!} />}
|
|
242
|
+
{showClose && <CloseButton size={size} onClick={onClose!} tabLabel={tab.label} />}
|
|
260
243
|
{isActive && (
|
|
261
244
|
<span className="absolute -bottom-px left-0 right-0 h-px bg-neutral-800" />
|
|
262
245
|
)}
|
|
@@ -303,6 +286,7 @@ export function TabBar({
|
|
|
303
286
|
return (
|
|
304
287
|
<div
|
|
305
288
|
ref={containerRef}
|
|
289
|
+
role="tablist"
|
|
306
290
|
className={cn(
|
|
307
291
|
'flex items-end',
|
|
308
292
|
variant === 'underline' && 'border-b border-neutral-700',
|
package/components/ui/toggle.tsx
CHANGED
|
@@ -7,22 +7,10 @@
|
|
|
7
7
|
* - List items - inline toggle controls
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
| 'orange'
|
|
15
|
-
| 'cyan'
|
|
16
|
-
| 'yellow'
|
|
17
|
-
| 'purple'
|
|
18
|
-
| 'indigo'
|
|
19
|
-
| 'emerald'
|
|
20
|
-
| 'amber'
|
|
21
|
-
| 'violet'
|
|
22
|
-
| 'neutral'
|
|
23
|
-
| 'sky'
|
|
24
|
-
| 'pink'
|
|
25
|
-
| 'teal'
|
|
10
|
+
import { type AccentColor } from '../lib/form-colors.ts'
|
|
11
|
+
import { cn } from '../lib/cn.ts'
|
|
12
|
+
|
|
13
|
+
export type ToggleColor = AccentColor
|
|
26
14
|
|
|
27
15
|
// Border colors per accent
|
|
28
16
|
const BORDER_COLORS: Record<ToggleColor, { idle: string; active: string }> = {
|
|
@@ -90,8 +78,6 @@ const TOGGLE_SIZES: Record<ToggleSize, { track: string; knob: string; translate:
|
|
|
90
78
|
lg: { track: 'w-14 h-7', knob: 'w-6 h-6', translate: 'translate-x-7' },
|
|
91
79
|
}
|
|
92
80
|
|
|
93
|
-
export type ToggleVariant = 'outline' | 'filled'
|
|
94
|
-
|
|
95
81
|
export interface ToggleProps {
|
|
96
82
|
checked: boolean
|
|
97
83
|
onChange: (checked: boolean) => void
|
|
@@ -99,7 +85,8 @@ export interface ToggleProps {
|
|
|
99
85
|
size?: ToggleSize
|
|
100
86
|
className?: string
|
|
101
87
|
color?: ToggleColor
|
|
102
|
-
|
|
88
|
+
/** Accessible label — required for screen readers */
|
|
89
|
+
'aria-label'?: string
|
|
103
90
|
/** Test ID for E2E testing */
|
|
104
91
|
testId?: string
|
|
105
92
|
}
|
|
@@ -109,8 +96,9 @@ export function Toggle({
|
|
|
109
96
|
onChange,
|
|
110
97
|
disabled = false,
|
|
111
98
|
size = 'sm',
|
|
112
|
-
className
|
|
99
|
+
className,
|
|
113
100
|
color = 'blue',
|
|
101
|
+
'aria-label': ariaLabel,
|
|
114
102
|
testId,
|
|
115
103
|
}: ToggleProps) {
|
|
116
104
|
const s = TOGGLE_SIZES[size]
|
|
@@ -119,23 +107,27 @@ export function Toggle({
|
|
|
119
107
|
return (
|
|
120
108
|
<button
|
|
121
109
|
type="button"
|
|
110
|
+
role="switch"
|
|
111
|
+
aria-checked={checked}
|
|
112
|
+
aria-label={ariaLabel}
|
|
122
113
|
onClick={() => !disabled && onChange(!checked)}
|
|
123
114
|
disabled={disabled}
|
|
124
115
|
data-testid={testId}
|
|
125
116
|
style={{ boxShadow: `inset 0 0 0 1px ${checked ? bc.active : bc.idle}` }}
|
|
126
|
-
className={
|
|
127
|
-
relative
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
117
|
+
className={cn(
|
|
118
|
+
'relative rounded-full transition-all flex-shrink-0 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed',
|
|
119
|
+
s.track,
|
|
120
|
+
checked ? TOGGLE_CHECKED_TRACK[color] : TOGGLE_UNCHECKED_TRACK[color],
|
|
121
|
+
className,
|
|
122
|
+
)}
|
|
132
123
|
>
|
|
133
124
|
<span
|
|
134
125
|
style={{ backgroundColor: checked ? kc.on : kc.off }}
|
|
135
|
-
className={
|
|
136
|
-
block absolute top-0.5 left-0.5
|
|
137
|
-
|
|
138
|
-
|
|
126
|
+
className={cn(
|
|
127
|
+
'block absolute top-0.5 left-0.5 rounded-full transition-transform',
|
|
128
|
+
s.knob,
|
|
129
|
+
checked ? s.translate : 'translate-x-0',
|
|
130
|
+
)}
|
|
139
131
|
/>
|
|
140
132
|
</button>
|
|
141
133
|
)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { useState, useRef, useLayoutEffect, useEffect } from 'react'
|
|
1
|
+
import { useState, useRef, useLayoutEffect, useEffect, useCallback } from 'react'
|
|
2
2
|
import type { ReactNode } from 'react'
|
|
3
3
|
import { createPortal } from 'react-dom'
|
|
4
|
+
import { useClickOutside } from '../hooks/use-click-outside.ts'
|
|
4
5
|
|
|
5
6
|
export interface TooltipContent {
|
|
6
7
|
title?: string
|
|
@@ -201,37 +202,25 @@ export function Tooltip({
|
|
|
201
202
|
}
|
|
202
203
|
|
|
203
204
|
// Click-outside dismissal for click trigger mode
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const handleClickOutside = (e: MouseEvent) => {
|
|
207
|
-
if (
|
|
208
|
-
triggerRef.current && !triggerRef.current.contains(e.target as Node) &&
|
|
209
|
-
tooltipRef.current && !tooltipRef.current.contains(e.target as Node)
|
|
210
|
-
) {
|
|
211
|
-
setIsVisible(false)
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
document.addEventListener('mousedown', handleClickOutside)
|
|
215
|
-
return () => document.removeEventListener('mousedown', handleClickOutside)
|
|
216
|
-
}, [trigger, isVisible])
|
|
205
|
+
const dismissClickTooltip = useCallback(() => setIsVisible(false), [])
|
|
206
|
+
useClickOutside([triggerRef, tooltipRef], isVisible && trigger === 'click', dismissClickTooltip)
|
|
217
207
|
|
|
218
208
|
const updatePosition = () => {
|
|
219
209
|
if (!triggerRef.current) return
|
|
220
210
|
const triggerRect = triggerRef.current.getBoundingClientRect()
|
|
221
211
|
const tooltipEl = tooltipRef.current
|
|
212
|
+
const tooltipRect = tooltipEl?.getBoundingClientRect()
|
|
222
213
|
|
|
223
214
|
let resolvedPosition: ResolvedPosition = position === 'auto' ? 'top' : position
|
|
224
215
|
|
|
225
|
-
if (position === 'auto' &&
|
|
226
|
-
const tooltipRect = tooltipEl.getBoundingClientRect()
|
|
216
|
+
if (position === 'auto' && tooltipRect) {
|
|
227
217
|
resolvedPosition = resolveAutoPosition(triggerRect, tooltipRect)
|
|
228
218
|
setActualPosition(resolvedPosition)
|
|
229
219
|
}
|
|
230
220
|
|
|
231
221
|
let newCoords = calculateBasePosition(triggerRect, resolvedPosition, align)
|
|
232
222
|
|
|
233
|
-
if (
|
|
234
|
-
const tooltipRect = tooltipEl.getBoundingClientRect()
|
|
223
|
+
if (tooltipRect) {
|
|
235
224
|
newCoords = adjustForTooltipSize(newCoords, tooltipRect, resolvedPosition, align)
|
|
236
225
|
newCoords = clampToViewport(newCoords, tooltipRect)
|
|
237
226
|
}
|
|
@@ -258,13 +247,12 @@ export function Tooltip({
|
|
|
258
247
|
const tooltipContent = (
|
|
259
248
|
<div
|
|
260
249
|
ref={tooltipRef}
|
|
261
|
-
|
|
250
|
+
role="tooltip"
|
|
251
|
+
className={`fixed px-3 py-1.5 bg-[var(--popover)] border border-neutral-600 rounded-lg shadow-lg z-[9999] ${interactive || trigger === 'click' ? '' : 'pointer-events-none'} ${multiline ? 'whitespace-pre-line' : 'whitespace-nowrap'}`}
|
|
262
252
|
style={{
|
|
263
253
|
top: coords.top,
|
|
264
254
|
left: coords.left,
|
|
265
|
-
opacity:
|
|
266
|
-
visibility: isVisible ? 'visible' : 'hidden',
|
|
267
|
-
transition: 'opacity 150ms, visibility 150ms',
|
|
255
|
+
opacity: 1,
|
|
268
256
|
...(multiline ? { maxWidth: maxWidth ?? '80vw' } : {}),
|
|
269
257
|
...(maxHeight ? { maxHeight, overflowY: 'auto' as const } : {}),
|
|
270
258
|
}}
|
|
@@ -290,7 +278,7 @@ export function Tooltip({
|
|
|
290
278
|
>
|
|
291
279
|
{children}
|
|
292
280
|
</div>
|
|
293
|
-
{createPortal(tooltipContent, document.body)}
|
|
281
|
+
{isVisible && createPortal(tooltipContent, document.body)}
|
|
294
282
|
</>
|
|
295
283
|
)
|
|
296
284
|
}
|