mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-16 08:06:24 +03:00
Fix live page editable focus handling (#256)
This commit is contained in:
@@ -6489,10 +6489,13 @@
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (isPageEditableElement(deepActive) && !isInlineEditActive(deepActive)) {
|
||||
return;
|
||||
}
|
||||
// While a contenteditable text-leaf is focused, let the browser handle
|
||||
// all keys except Escape. Escape cancels the current edit (restores
|
||||
// original text) and blurs without saving, staying in CONFIGURING.
|
||||
if (e.target.isContentEditable && inlineEditRows.some((r) => r.el === e.target)) {
|
||||
if (e.target.isContentEditable && isInlineEditActive(e.target)) {
|
||||
if (e.key !== 'Escape') return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -8312,6 +8315,21 @@ void main() {
|
||||
&& !steerLocked;
|
||||
}
|
||||
|
||||
function isPageEditableElement(el) {
|
||||
if (!el || own(el)) return false;
|
||||
if (/^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName || '')) return true;
|
||||
return !!el.isContentEditable;
|
||||
}
|
||||
|
||||
function isInlineEditActive(el) {
|
||||
return !!el && inlineEditRows.some((r) => r.el === el);
|
||||
}
|
||||
|
||||
function isPageEditableActive() {
|
||||
const active = activeElementDeep();
|
||||
return isPageEditableElement(active) && !isInlineEditActive(active);
|
||||
}
|
||||
|
||||
function pageHasHostTextSelection() {
|
||||
const sel = window.getSelection?.();
|
||||
if (!sel || sel.isCollapsed) return false;
|
||||
@@ -8325,6 +8343,7 @@ void main() {
|
||||
function shouldSteerAutoFocus() {
|
||||
return shouldFocusSteerChat()
|
||||
&& !steerFocusSuspended
|
||||
&& !isPageEditableActive()
|
||||
&& performance.now() >= steerFocusPauseUntil;
|
||||
}
|
||||
|
||||
|
||||
@@ -154,6 +154,24 @@ describe('live-browser.js regression guards', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('does not autofocus the steering chat while a page editable is focused', () => {
|
||||
assert.match(
|
||||
SOURCE,
|
||||
/function isPageEditableElement\(el\) \{[\s\S]{0,160}?own\(el\)[\s\S]{0,160}?\^\(INPUT\|TEXTAREA\|SELECT\)\$[\s\S]{0,80}?el\.isContentEditable/,
|
||||
'page-owned inputs, textareas, selects, and contenteditables must be recognized before steer focus recovery runs',
|
||||
);
|
||||
assert.match(
|
||||
SOURCE,
|
||||
/function isPageEditableActive\(\) \{[\s\S]{0,120}?activeElementDeep\(\)[\s\S]{0,120}?isPageEditableElement\(active\) && !isInlineEditActive\(active\)/,
|
||||
'auto-focus recovery must check the deep active element instead of only host text selection',
|
||||
);
|
||||
assert.match(
|
||||
SOURCE,
|
||||
/function shouldSteerAutoFocus\(\) \{[\s\S]{0,160}?&& !isPageEditableActive\(\)/,
|
||||
'steer chat auto-focus must back off while the page owns an editable caret',
|
||||
);
|
||||
});
|
||||
|
||||
it('pins edit badge button metrics instead of inheriting host button chrome', () => {
|
||||
const start = SOURCE.indexOf('const calloutStyle = (color, borderColor) => ({');
|
||||
const end = SOURCE.indexOf(' });', start);
|
||||
@@ -345,6 +363,22 @@ describe('live-browser.js regression guards', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('lets page editables keep Enter and arrow keydown events', () => {
|
||||
const start = SOURCE.indexOf('function handleKeyDown(e)');
|
||||
const pendingApplyStart = SOURCE.indexOf('if (pendingApplyInFlight)', start);
|
||||
const guardSource = SOURCE.slice(start, pendingApplyStart);
|
||||
assert.match(
|
||||
guardSource,
|
||||
/isPageEditableElement\(deepActive\) && !isInlineEditActive\(deepActive\)[\s\S]{0,40}?return;/,
|
||||
'page-owned editables must short-circuit global key handling before variant navigation or accept handling',
|
||||
);
|
||||
assert.match(
|
||||
guardSource,
|
||||
/e\.target\.isContentEditable && isInlineEditActive\(e\.target\)/,
|
||||
'impeccable inline edit rows must keep their existing Escape-cancel path',
|
||||
);
|
||||
});
|
||||
|
||||
it('configure input Escape tears down annotation overlay before returning to picking', () => {
|
||||
// The configure prompt auto-focuses. While focused, the global keydown
|
||||
// handler bails on own() inputs, so this local Escape path must hide the
|
||||
|
||||
Reference in New Issue
Block a user