@toolr/ui-design 0.1.10 → 0.1.12
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/agent-rules.json +1 -1
- package/components/lib/theme-engine.ts +1 -5
- package/components/ui/input.tsx +1 -1
- package/components/ui/tooltip.tsx +23 -0
- package/dist/index.d.ts +1 -6
- package/dist/index.js +19 -0
- package/dist/tokens/semantic.css +1 -1
- package/package.json +1 -1
- package/tokens/semantic.css +1 -1
package/agent-rules.json
CHANGED
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"color": "#fb923c",
|
|
55
55
|
"rules": [
|
|
56
56
|
{ "type": "do", "text": "Select, Tooltip, Modal all render via createPortal to document.body — parent overflow:hidden and z-index don't affect them" },
|
|
57
|
-
{ "type": "do", "text": "Popover background is rgba(0,0,0,0.
|
|
57
|
+
{ "type": "do", "text": "Popover background is rgba(0,0,0,0.9) — semi-transparent by design, which is why body background matters" },
|
|
58
58
|
{ "type": "dont", "text": "Never wrap portal components in overflow:hidden expecting to clip them — they escape to document.body" }
|
|
59
59
|
]
|
|
60
60
|
},
|
|
@@ -140,11 +140,6 @@ export function isLightTheme(themeId: ThemeId): boolean {
|
|
|
140
140
|
/**
|
|
141
141
|
* Apply a theme to the document by setting CSS custom properties on the root element.
|
|
142
142
|
*
|
|
143
|
-
* IMPORTANT — body background: Portal-based components (Select, Tooltip) render at
|
|
144
|
-
* document.body via createPortal. Their backgrounds use --popover which is semi-transparent
|
|
145
|
-
* (rgba(0,0,0,0.8)). If <body> has no background-color, the browser default (white) bleeds
|
|
146
|
-
* through, making dropdowns/tooltips appear gray instead of dark.
|
|
147
|
-
*
|
|
148
143
|
* Consuming apps MUST set: body { background-color: var(--background); }
|
|
149
144
|
*/
|
|
150
145
|
export function applyTheme(themeId: ThemeId, accentHue: number | null, dims: Record<SurfaceKey, number> = DEFAULT_DIMS, outline: number = DEFAULT_OUTLINE, root: HTMLElement = document.documentElement): void {
|
|
@@ -186,4 +181,5 @@ export function applyTheme(themeId: ThemeId, accentHue: number | null, dims: Rec
|
|
|
186
181
|
root.style.setProperty('--surface-hover', `${glassBase}${alphaToHex(10 / 100)}`)
|
|
187
182
|
}
|
|
188
183
|
|
|
184
|
+
|
|
189
185
|
}
|
package/components/ui/input.tsx
CHANGED
|
@@ -26,7 +26,7 @@ import { useAccentColor } from '../lib/accent-context.ts'
|
|
|
26
26
|
export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'size' | 'type'> {
|
|
27
27
|
value: string
|
|
28
28
|
onChange: (value: string) => void
|
|
29
|
-
type?: 'text' | 'search' | 'password'
|
|
29
|
+
type?: 'text' | 'search' | 'password' | 'email'
|
|
30
30
|
debounceMs?: number
|
|
31
31
|
error?: boolean | string
|
|
32
32
|
variant?: 'filled' | 'outline'
|
|
@@ -247,6 +247,29 @@ export function Tooltip({
|
|
|
247
247
|
return () => window.removeEventListener('scroll', handleScroll, true)
|
|
248
248
|
}, [trigger, isVisible, position, align])
|
|
249
249
|
|
|
250
|
+
// Dismiss hover tooltips on scroll, keyboard, click elsewhere, or window blur to prevent orphans
|
|
251
|
+
useEffect(() => {
|
|
252
|
+
if (trigger !== 'hover' || !isVisible) return
|
|
253
|
+
const dismiss = () => setIsVisible(false)
|
|
254
|
+
window.addEventListener('scroll', dismiss, true)
|
|
255
|
+
window.addEventListener('keydown', dismiss)
|
|
256
|
+
window.addEventListener('pointerdown', dismiss)
|
|
257
|
+
window.addEventListener('blur', dismiss)
|
|
258
|
+
return () => {
|
|
259
|
+
window.removeEventListener('scroll', dismiss, true)
|
|
260
|
+
window.removeEventListener('keydown', dismiss)
|
|
261
|
+
window.removeEventListener('pointerdown', dismiss)
|
|
262
|
+
window.removeEventListener('blur', dismiss)
|
|
263
|
+
}
|
|
264
|
+
}, [trigger, isVisible])
|
|
265
|
+
|
|
266
|
+
// Clear pending hide timeout on unmount
|
|
267
|
+
useEffect(() => {
|
|
268
|
+
return () => {
|
|
269
|
+
if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current)
|
|
270
|
+
}
|
|
271
|
+
}, [])
|
|
272
|
+
|
|
250
273
|
const resolvedPos = position === 'auto' ? actualPosition : position
|
|
251
274
|
const arrowClasses = getArrowClasses(resolvedPos, align)
|
|
252
275
|
|
package/dist/index.d.ts
CHANGED
|
@@ -58,11 +58,6 @@ declare function isLightTheme(themeId: ThemeId): boolean;
|
|
|
58
58
|
/**
|
|
59
59
|
* Apply a theme to the document by setting CSS custom properties on the root element.
|
|
60
60
|
*
|
|
61
|
-
* IMPORTANT — body background: Portal-based components (Select, Tooltip) render at
|
|
62
|
-
* document.body via createPortal. Their backgrounds use --popover which is semi-transparent
|
|
63
|
-
* (rgba(0,0,0,0.8)). If <body> has no background-color, the browser default (white) bleeds
|
|
64
|
-
* through, making dropdowns/tooltips appear gray instead of dark.
|
|
65
|
-
*
|
|
66
61
|
* Consuming apps MUST set: body { background-color: var(--background); }
|
|
67
62
|
*/
|
|
68
63
|
declare function applyTheme(themeId: ThemeId, accentHue: number | null, dims?: Record<SurfaceKey, number>, outline?: number, root?: HTMLElement): void;
|
|
@@ -400,7 +395,7 @@ declare function Toggle({ checked, onChange, disabled, size, className, accentCo
|
|
|
400
395
|
interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'size' | 'type'> {
|
|
401
396
|
value: string;
|
|
402
397
|
onChange: (value: string) => void;
|
|
403
|
-
type?: 'text' | 'search' | 'password';
|
|
398
|
+
type?: 'text' | 'search' | 'password' | 'email';
|
|
404
399
|
debounceMs?: number;
|
|
405
400
|
error?: boolean | string;
|
|
406
401
|
variant?: 'filled' | 'outline';
|
package/dist/index.js
CHANGED
|
@@ -566,6 +566,25 @@ function Tooltip({
|
|
|
566
566
|
window.addEventListener("scroll", handleScroll, true);
|
|
567
567
|
return () => window.removeEventListener("scroll", handleScroll, true);
|
|
568
568
|
}, [trigger, isVisible, position, align]);
|
|
569
|
+
useEffect2(() => {
|
|
570
|
+
if (trigger !== "hover" || !isVisible) return;
|
|
571
|
+
const dismiss = () => setIsVisible(false);
|
|
572
|
+
window.addEventListener("scroll", dismiss, true);
|
|
573
|
+
window.addEventListener("keydown", dismiss);
|
|
574
|
+
window.addEventListener("pointerdown", dismiss);
|
|
575
|
+
window.addEventListener("blur", dismiss);
|
|
576
|
+
return () => {
|
|
577
|
+
window.removeEventListener("scroll", dismiss, true);
|
|
578
|
+
window.removeEventListener("keydown", dismiss);
|
|
579
|
+
window.removeEventListener("pointerdown", dismiss);
|
|
580
|
+
window.removeEventListener("blur", dismiss);
|
|
581
|
+
};
|
|
582
|
+
}, [trigger, isVisible]);
|
|
583
|
+
useEffect2(() => {
|
|
584
|
+
return () => {
|
|
585
|
+
if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
|
|
586
|
+
};
|
|
587
|
+
}, []);
|
|
569
588
|
const resolvedPos = position === "auto" ? actualPosition : position;
|
|
570
589
|
const arrowClasses = getArrowClasses(resolvedPos, align);
|
|
571
590
|
const tooltipContent = /* @__PURE__ */ jsxs3(
|
package/dist/tokens/semantic.css
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
--dialog-backdrop: rgba(0, 0, 0, 0.95);
|
|
25
25
|
|
|
26
26
|
/* Popover: floating panels, dropdown menus */
|
|
27
|
-
--popover: rgba(0, 0, 0, 0.
|
|
27
|
+
--popover: rgba(0, 0, 0, 0.9);
|
|
28
28
|
--popover-foreground: rgba(255, 255, 255, 0.83);
|
|
29
29
|
|
|
30
30
|
/* Muted: subdued elements, disabled states */
|
package/package.json
CHANGED
package/tokens/semantic.css
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
--dialog-backdrop: rgba(0, 0, 0, 0.95);
|
|
25
25
|
|
|
26
26
|
/* Popover: floating panels, dropdown menus */
|
|
27
|
-
--popover: rgba(0, 0, 0, 0.
|
|
27
|
+
--popover: rgba(0, 0, 0, 0.9);
|
|
28
28
|
--popover-foreground: rgba(255, 255, 255, 0.83);
|
|
29
29
|
|
|
30
30
|
/* Muted: subdued elements, disabled states */
|