feat(scenes): rich scene descriptions and control viewer window
Add TipTap editing in the editor and an Electron window on the control panel to read the current scene description. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -13,6 +13,12 @@
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
.disabledTipHost {
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.buttonPrimary {
|
||||
border: 1px solid var(--accent-border);
|
||||
background: var(--accent-fill-solid);
|
||||
|
||||
@@ -12,4 +12,5 @@ void test('Button: тултип через портал (title), не тольк
|
||||
assert.ok(src.includes('role="tooltip"'));
|
||||
assert.ok(src.includes('onMouseEnter={showTip}'));
|
||||
assert.ok(src.includes('document.body'));
|
||||
assert.ok(src.includes('disabledTipHost'), 'disabled + title → хост для hover-тултипа');
|
||||
});
|
||||
|
||||
@@ -28,11 +28,12 @@ export function Button({
|
||||
tooltipPlacement = 'top',
|
||||
}: ButtonProps) {
|
||||
const btnRef = useRef<HTMLButtonElement | null>(null);
|
||||
const hostRef = useRef<HTMLSpanElement | null>(null);
|
||||
const [tipPos, setTipPos] = useState<{ x: number; y: number } | null>(null);
|
||||
|
||||
const showTip = useCallback(() => {
|
||||
if (disabled || !title) return;
|
||||
const el = btnRef.current;
|
||||
if (!title) return;
|
||||
const el = disabled ? hostRef.current : btnRef.current;
|
||||
if (!el) return;
|
||||
const r = el.getBoundingClientRect();
|
||||
if (tooltipPlacement === 'bottom-left') {
|
||||
@@ -66,22 +67,38 @@ export function Button({
|
||||
)
|
||||
: null;
|
||||
|
||||
const button = (
|
||||
<button
|
||||
ref={btnRef}
|
||||
type="button"
|
||||
className={btnClass}
|
||||
disabled={disabled}
|
||||
aria-label={ariaLabel}
|
||||
onClick={disabled ? undefined : onClick}
|
||||
onMouseEnter={disabled ? undefined : showTip}
|
||||
onMouseLeave={disabled ? undefined : hideTip}
|
||||
onFocus={showTip}
|
||||
onBlur={hideTip}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
|
||||
// Disabled buttons don't receive mouse events — host span keeps tooltip usable.
|
||||
if (disabled && title) {
|
||||
return (
|
||||
<>
|
||||
<span ref={hostRef} className={styles.disabledTipHost} onMouseEnter={showTip} onMouseLeave={hideTip}>
|
||||
{button}
|
||||
</span>
|
||||
{tip}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
ref={btnRef}
|
||||
type="button"
|
||||
className={btnClass}
|
||||
disabled={disabled}
|
||||
aria-label={ariaLabel}
|
||||
onClick={disabled ? undefined : onClick}
|
||||
onMouseEnter={showTip}
|
||||
onMouseLeave={hideTip}
|
||||
onFocus={showTip}
|
||||
onBlur={hideTip}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
{button}
|
||||
{tip}
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user