[Editor] Add the ability to make multiple selections (bug 1779582)

- several editors can be selected/unselected using ctrl+click;
- and then they can be copied, pasted, their properties can be changed.
This commit is contained in:
Calixte Denizet 2022-07-21 10:42:15 +02:00
parent 9fe4a667bd
commit d6b9ca48a5
7 changed files with 490 additions and 150 deletions

View File

@ -136,7 +136,7 @@ class AnnotationEditorLayer {
} else {
this.enableClick();
}
this.setActiveEditor(null);
this.#uiManager.unselectAll();
}
addInkEditorIfNeeded(isCommitting) {
@ -210,14 +210,6 @@ class AnnotationEditorLayer {
}
this.#uiManager.setActiveEditor(editor);
if (currentActive && currentActive !== editor) {
currentActive.commitOrRemove();
}
if (editor) {
this.#uiManager.unselectAll();
}
}
enableClick() {
@ -250,11 +242,19 @@ class AnnotationEditorLayer {
this.#uiManager.removeEditor(editor);
this.detach(editor);
this.annotationStorage.removeKey(editor.id);
editor.div.remove();
editor.isAttachedToDOM = false;
if (this.#uiManager.isActive(editor) || this.#editors.size === 0) {
this.setActiveEditor(null);
}
editor.div.style.display = "none";
setTimeout(() => {
// When the div is removed from DOM the focus can move on the
// document.body, so we just slightly postpone the removal in
// order to let an element potentially grab the focus before
// the body.
editor.div.style.display = "";
editor.div.remove();
editor.isAttachedToDOM = false;
if (document.activeElement === document.body) {
this.#uiManager.focusMainContainer();
}
}, 0);
if (!this.#isCleaningUp) {
this.addInkEditorIfNeeded(/* isCommitting = */ false);
@ -271,10 +271,6 @@ class AnnotationEditorLayer {
return;
}
if (this.#uiManager.isActive(editor)) {
editor.parent?.setActiveEditor(null);
}
this.attach(editor);
editor.pageIndex = this.pageIndex;
editor.parent?.detach(editor);
@ -546,6 +542,42 @@ class AnnotationEditorLayer {
return editor;
}
/**
* Set the last selected editor.
* @param {AnnotationEditor} editor
*/
setSelected(editor) {
this.#uiManager.setSelected(editor);
}
/**
* Check if the editor is selected.
* @param {AnnotationEditor} editor
*/
isSelected(editor) {
return this.#uiManager.isSelected(editor);
}
/**
* Unselect an editor.
* @param {AnnotationEditor} editor
*/
unselect(editor) {
this.#uiManager.unselect(editor);
}
get isMultipleSelection() {
return this.#uiManager.isMultipleSelection;
}
/**
* An editor just got a mousedown with ctrl key pressed.
* @param {boolean}} isMultiple
*/
set isMultipleSelection(isMultiple) {
this.#uiManager.isMultipleSelection = isMultiple;
}
/**
* Mouseclick callback.
* @param {MouseEvent} event
@ -662,7 +694,6 @@ class AnnotationEditorLayer {
* @param {Object} parameters
*/
update(parameters) {
this.setActiveEditor(null);
this.viewport = parameters.viewport;
this.setDimensions();
this.updateMode();

View File

@ -16,12 +16,8 @@
// eslint-disable-next-line max-len
/** @typedef {import("./annotation_editor_layer.js").AnnotationEditorLayer} AnnotationEditorLayer */
import {
AnnotationEditorPrefix,
shadow,
unreachable,
} from "../../shared/util.js";
import { bindEvents, ColorManager } from "./tools.js";
import { shadow, unreachable } from "../../shared/util.js";
/**
* @typedef {Object} AnnotationEditorParameters
@ -35,8 +31,20 @@ import { bindEvents, ColorManager } from "./tools.js";
* Base class for editors.
*/
class AnnotationEditor {
#boundFocusin = this.focusin.bind(this);
#boundFocusout = this.focusout.bind(this);
#isEditing = false;
#isFocused = false;
#isInEditMode = false;
#wasSelected = false;
#wasFocused = false;
#zIndex = AnnotationEditor._zIndex++;
static _colorManager = new ColorManager();
@ -88,17 +96,32 @@ class AnnotationEditor {
this.div.style.zIndex = this.#zIndex;
}
#select() {
if (this.#wasSelected) {
this.parent.unselect(this);
this.unselect();
this.#wasSelected = true;
} else {
this.parent.setSelected(this);
this.select();
}
}
/**
* onfocus callback.
*/
focusin(/* event */) {
this.parent.setActiveEditor(this);
focusin(event) {
this.#isFocused =
event.target === this.div ||
!!event.relatedTarget?.closest(`#${this.id}`);
if (event.target === this.div) {
this.#select();
}
}
/**
* onblur callback.
* @param {FocusEvent} event
* @returns {undefined}
*/
focusout(event) {
if (!this.isAttachedToDOM) {
@ -116,10 +139,14 @@ class AnnotationEditor {
event.preventDefault();
this.commitOrRemove();
if (!target?.id?.startsWith(AnnotationEditorPrefix)) {
this.parent.setActiveEditor(null);
this.#isFocused = false;
if (!this.parent.isMultipleSelection) {
this.commitOrRemove();
if (target?.closest(".annotationEditorLayer")) {
// We only unselect the element when another editor (or its parent)
// is grabbing the focus.
this.parent.unselect(this);
}
}
}
@ -228,15 +255,13 @@ class AnnotationEditor {
this.setInForeground();
this.div.addEventListener("focusin", this.#boundFocusin);
this.div.addEventListener("focusout", this.#boundFocusout);
const [tx, ty] = this.getInitialTranslation();
this.translate(tx, ty);
bindEvents(this, this.div, [
"dragstart",
"focusin",
"focusout",
"mousedown",
]);
bindEvents(this, this.div, ["dragstart", "mousedown", "mouseup"]);
return this.div;
}
@ -250,6 +275,23 @@ class AnnotationEditor {
// Avoid to focus this editor because of a non-left click.
event.preventDefault();
}
const isMultipleSelection = (this.parent.isMultipleSelection =
event.ctrlKey || event.shiftKey);
this.#wasSelected = isMultipleSelection && this.parent.isSelected(this);
this.#wasFocused = this.#isFocused;
}
/**
* Onmouseup callback.
* @param {MouseEvent} event
*/
mouseup(event) {
if (this.#wasFocused) {
this.#select();
}
this.parent.isMultipleSelection = false;
this.#wasFocused = false;
}
getRect(tx, ty) {
@ -331,7 +373,6 @@ class AnnotationEditor {
/**
* Enable edit mode.
* @returns {undefined}
*/
enableEditMode() {
this.#isInEditMode = true;
@ -339,7 +380,6 @@ class AnnotationEditor {
/**
* Disable edit mode.
* @returns {undefined}
*/
disableEditMode() {
this.#isInEditMode = false;
@ -374,10 +414,9 @@ class AnnotationEditor {
* Rebuild the editor in case it has been removed on undo.
*
* To implement in subclasses.
* @returns {undefined}
*/
rebuild() {
unreachable("An editor must be rebuildable");
this.div?.addEventListener("focusin", this.#boundFocusin);
}
/**
@ -386,7 +425,6 @@ class AnnotationEditor {
* new annotation to add to the pdf document.
*
* To implement in subclasses.
* @returns {undefined}
*/
serialize() {
unreachable("An editor must be serializable");
@ -423,10 +461,11 @@ class AnnotationEditor {
/**
* Remove this editor.
* It's used on ctrl+backspace action.
*
* @returns {undefined}
*/
remove() {
this.div.removeEventListener("focusin", this.#boundFocusin);
this.div.removeEventListener("focusout", this.#boundFocusout);
if (!this.isEmpty()) {
// The editor is removed but it can be back at some point thanks to
// undo/redo so we must commit it before.
@ -439,18 +478,14 @@ class AnnotationEditor {
* Select this editor.
*/
select() {
if (this.div) {
this.div.classList.add("selectedEditor");
}
this.div?.classList.add("selectedEditor");
}
/**
* Unselect this editor.
*/
unselect() {
if (this.div) {
this.div.classList.remove("selectedEditor");
}
this.div?.classList.remove("selectedEditor");
}
/**
@ -494,6 +529,29 @@ class AnnotationEditor {
get contentDiv() {
return this.div;
}
/**
* If true then the editor is currently edited.
* @type {boolean}
*/
get isEditing() {
return this.#isEditing;
}
/**
* When set to true, it means that this editor is currently edited.
* @param {boolean} value
*/
set isEditing(value) {
this.#isEditing = value;
if (value) {
this.select();
this.parent.setSelected(this);
this.parent.setActiveEditor(this);
} else {
this.parent.setActiveEditor(null);
}
}
}
export { AnnotationEditor };

View File

@ -30,6 +30,10 @@ import { AnnotationEditor } from "./editor.js";
* Basic text editor in order to create a FreeTex annotation.
*/
class FreeTextEditor extends AnnotationEditor {
#boundEditorDivBlur = this.editorDivBlur.bind(this);
#boundEditorDivFocus = this.editorDivFocus.bind(this);
#boundEditorDivKeydown = this.editorDivKeydown.bind(this);
#color;
@ -199,6 +203,7 @@ class FreeTextEditor extends AnnotationEditor {
/** @inheritdoc */
rebuild() {
super.rebuild();
if (this.div === null) {
return;
}
@ -220,6 +225,8 @@ class FreeTextEditor extends AnnotationEditor {
this.div.draggable = false;
this.div.removeAttribute("tabIndex");
this.editorDiv.addEventListener("keydown", this.#boundEditorDivKeydown);
this.editorDiv.addEventListener("focus", this.#boundEditorDivFocus);
this.editorDiv.addEventListener("blur", this.#boundEditorDivBlur);
}
/** @inheritdoc */
@ -231,6 +238,8 @@ class FreeTextEditor extends AnnotationEditor {
this.div.draggable = true;
this.div.tabIndex = 0;
this.editorDiv.removeEventListener("keydown", this.#boundEditorDivKeydown);
this.editorDiv.removeEventListener("focus", this.#boundEditorDivFocus);
this.editorDiv.removeEventListener("blur", this.#boundEditorDivBlur);
}
/** @inheritdoc */
@ -251,6 +260,7 @@ class FreeTextEditor extends AnnotationEditor {
/** @inheritdoc */
remove() {
this.isEditing = false;
this.parent.setEditingState(true);
super.remove();
}
@ -333,6 +343,14 @@ class FreeTextEditor extends AnnotationEditor {
FreeTextEditor._keyboardManager.exec(this, event);
}
editorDivFocus(event) {
this.isEditing = true;
}
editorDivBlur(event) {
this.isEditing = false;
}
/** @inheritdoc */
disableEditing() {
this.editorDiv.setAttribute("role", "comment");

View File

@ -123,8 +123,16 @@ class InkEditor extends AnnotationEditor {
/** @inheritdoc */
get propertiesToUpdate() {
return [
[AnnotationEditorParamsType.INK_THICKNESS, this.thickness],
[AnnotationEditorParamsType.INK_COLOR, this.color],
[
AnnotationEditorParamsType.INK_THICKNESS,
this.thickness || InkEditor._defaultThickness,
],
[
AnnotationEditorParamsType.INK_COLOR,
this.color ||
InkEditor._defaultColor ||
AnnotationEditor._defaultLineColor,
],
];
}
@ -174,6 +182,7 @@ class InkEditor extends AnnotationEditor {
/** @inheritdoc */
rebuild() {
super.rebuild();
if (this.div === null) {
return;
}
@ -284,6 +293,7 @@ class InkEditor extends AnnotationEditor {
* @param {number} y
*/
#startDrawing(x, y) {
this.isEditing = true;
if (!this.#isCanvasInitialized) {
this.#isCanvasInitialized = true;
this.#setCanvasDims();
@ -390,6 +400,7 @@ class InkEditor extends AnnotationEditor {
return;
}
this.isEditing = false;
this.disableEditMode();
// This editor must be on top of the main ink editor.
@ -408,8 +419,8 @@ class InkEditor extends AnnotationEditor {
}
/** @inheritdoc */
focusin(/* event */) {
super.focusin();
focusin(event) {
super.focusin(event);
this.enableEditMode();
}

View File

@ -377,19 +377,19 @@ class AnnotationEditorUIManager {
#currentPageIndex = 0;
#isMultipleSelection = false;
#editorTypes = null;
#eventBus = null;
#idManager = new IdManager();
#isAllSelected = false;
#isEnabled = false;
#mode = AnnotationEditorType.NONE;
#previousActiveEditor = null;
#selectedEditors = new Set();
#boundKeydown = this.keydown.bind(this);
@ -435,6 +435,7 @@ class AnnotationEditorUIManager {
],
AnnotationEditorUIManager.prototype.delete,
],
[["Escape"], AnnotationEditorUIManager.prototype.unselectAll],
]);
constructor(container, eventBus) {
@ -456,6 +457,7 @@ class AnnotationEditorUIManager {
this.#allLayers.clear();
this.#allEditors.clear();
this.#activeEditor = null;
this.#selectedEditors.clear();
this.#clipboardManager.destroy();
this.#commandManager.destroy();
}
@ -470,6 +472,10 @@ class AnnotationEditorUIManager {
layer?.onTextLayerRendered();
}
focusMainContainer() {
this.#container.focus();
}
#addKeyboardManager() {
// The keyboard events are caught at the container level in order to be able
// to execute some callbacks even if the current page doesn't have focus.
@ -631,10 +637,10 @@ class AnnotationEditorUIManager {
* @param {*} value
*/
updateParams(type, value) {
(this.#activeEditor || this.#previousActiveEditor)?.updateParams(
type,
value
);
for (const editor of this.#selectedEditors) {
editor.updateParams(type, value);
}
for (const editorType of this.#editorTypes) {
editorType.updateDefaultParams(type, value);
}
@ -656,6 +662,7 @@ class AnnotationEditorUIManager {
* Disable all the layers.
*/
#disableAll() {
this.unselectAll();
if (this.#isEnabled) {
this.#isEnabled = false;
for (const layer of this.#allLayers.values()) {
@ -702,6 +709,9 @@ class AnnotationEditorUIManager {
*/
removeEditor(editor) {
this.#allEditors.delete(editor.id);
if (this.hasSelection) {
this.#selectedEditors.delete(editor);
}
}
/**
@ -726,24 +736,80 @@ class AnnotationEditorUIManager {
return;
}
this.#previousActiveEditor = this.#activeEditor;
this.#activeEditor = editor;
if (editor) {
this.#dispatchUpdateUI(editor.propertiesToUpdate);
this.#dispatchUpdateStates({ hasSelectedEditor: true });
} else {
this.#dispatchUpdateStates({ hasSelectedEditor: false });
if (this.#previousActiveEditor) {
this.#dispatchUpdateUI(this.#previousActiveEditor.propertiesToUpdate);
} else {
for (const editorType of this.#editorTypes) {
this.#dispatchUpdateUI(editorType.defaultPropertiesToUpdate);
}
}
}
}
/**
* Set the last selected editor.
* @param {AnnotationEditor} editor
*/
setSelected(editor) {
if (!this.#isMultipleSelection) {
if (this.#selectedEditors.has(editor)) {
if (this.#selectedEditors.size > 1) {
for (const ed of this.#selectedEditors) {
if (ed !== editor) {
ed.unselect();
}
}
this.#selectedEditors.clear();
this.#selectedEditors.add(editor);
this.#dispatchUpdateUI(editor.propertiesToUpdate);
}
return;
}
for (const ed of this.#selectedEditors) {
ed.unselect();
}
this.#selectedEditors.clear();
}
this.#selectedEditors.add(editor);
this.#dispatchUpdateUI(editor.propertiesToUpdate);
this.#dispatchUpdateStates({
hasSelectedEditor: this.hasSelection,
});
}
/**
* Check if the editor is selected.
* @param {AnnotationEditor} editor
*/
isSelected(editor) {
return this.#selectedEditors.has(editor);
}
/**
* Unselect an editor.
* @param {AnnotationEditor} editor
*/
unselect(editor) {
editor.unselect();
this.#selectedEditors.delete(editor);
this.#dispatchUpdateStates({
hasSelectedEditor: this.hasSelection,
});
}
get hasSelection() {
return this.#selectedEditors.size !== 0;
}
get isMultipleSelection() {
return this.#isMultipleSelection;
}
/**
* An editor just got a mousedown with ctrl key pressed.
* @param {boolean} isMultiple
*/
set isMultipleSelection(isMultiple) {
this.#isMultipleSelection = isMultiple;
}
/**
* Undo the last command.
*/
@ -795,52 +861,26 @@ class AnnotationEditorUIManager {
return false;
}
/**
* Unselect the current editor.
*/
unselect() {
if (this.#activeEditor) {
this.#activeEditor.parent.setActiveEditor(null);
}
}
/**
* Delete the current editor or all.
*/
delete() {
let cmd, undo;
if (this.#isAllSelected) {
this.#previousActiveEditor = this.#activeEditor = null;
const editors = Array.from(this.#allEditors.values());
cmd = () => {
for (const editor of editors) {
if (!editor.isEmpty()) {
editor.remove();
}
}
};
undo = () => {
for (const editor of editors) {
this.#addEditorToLayer(editor);
}
};
this.addCommands({ cmd, undo, mustExec: true });
} else {
if (!this.#activeEditor) {
return;
}
const editor = this.#activeEditor;
this.#previousActiveEditor = this.#activeEditor = null;
cmd = () => {
editor.remove();
};
undo = () => {
this.#addEditorToLayer(editor);
};
if (!this.hasSelection) {
return;
}
const editors = [...this.#selectedEditors];
const cmd = () => {
for (const editor of editors) {
editor.remove();
}
};
const undo = () => {
for (const editor of editors) {
this.#addEditorToLayer(editor);
}
};
this.addCommands({ cmd, undo, mustExec: true });
}
@ -848,8 +888,8 @@ class AnnotationEditorUIManager {
* Copy the selected editor.
*/
copy() {
if (this.#activeEditor) {
this.#clipboardManager.copy(this.#activeEditor);
if (this.hasSelection) {
this.#clipboardManager.copy([...this.#selectedEditors]);
this.#dispatchUpdateStates({ hasEmptyClipboard: false });
}
}
@ -858,10 +898,8 @@ class AnnotationEditorUIManager {
* Cut the selected editor.
*/
cut() {
if (this.#activeEditor) {
this.#clipboardManager.copy(this.#activeEditor);
this.delete();
}
this.copy();
this.delete();
}
/**
@ -873,42 +911,63 @@ class AnnotationEditorUIManager {
return;
}
this.unselectAll();
const layer = this.#allLayers.get(this.#currentPageIndex);
const newEditors = this.#clipboardManager
.paste()
.map(data => layer.deserialize(data));
const cmd = () => {
newEditors.map(editor => this.#addEditorToLayer(editor));
for (const editor of newEditors) {
this.#addEditorToLayer(editor);
}
this.#selectEditors(newEditors);
};
const undo = () => {
newEditors.map(editor => editor.remove());
for (const editor of newEditors) {
editor.remove();
}
};
this.addCommands({ cmd, undo, mustExec: true });
}
/**
* Select all the editors.
* Select the editors.
* @param {Array<AnnotationEditor>} editors
*/
selectAll() {
this.#isAllSelected = true;
for (const editor of this.#allEditors.values()) {
#selectEditors(editors) {
this.#selectedEditors.clear();
for (const editor of editors) {
if (editor.isEmpty()) {
continue;
}
this.#selectedEditors.add(editor);
editor.select();
}
this.#dispatchUpdateStates({ hasSelectedEditor: true });
}
/**
* Unselect all the editors.
* Select all the editors.
*/
selectAll() {
for (const editor of this.#selectedEditors) {
editor.commit();
}
this.#selectEditors(this.#allEditors.values());
}
/**
* Unselect all the selected editors.
*/
unselectAll() {
this.#isAllSelected = false;
for (const editor of this.#allEditors.values()) {
for (const editor of this.#selectedEditors) {
editor.unselect();
}
this.#selectedEditors.clear();
this.#dispatchUpdateStates({
hasSelectedEditor: this.#activeEditor !== null,
hasSelectedEditor: false,
});
}

View File

@ -252,4 +252,176 @@ describe("Editor", () => {
);
});
});
describe("FreeText (multiselection)", () => {
let pages;
beforeAll(async () => {
pages = await loadAndWait("tracemonkey.pdf", ".annotationEditorLayer");
});
afterAll(async () => {
await closePages(pages);
});
function getSelected(page) {
return page.evaluate(prefix => {
const elements = document.querySelectorAll(".selectedEditor");
const results = [];
for (const element of elements) {
results.push(parseInt(element.id.slice(prefix.length)));
}
results.sort();
return results;
}, editorPrefix.slice(1));
}
it("must select/unselect several editors and check copy, paste and delete operations", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await page.click("#editorFreeText");
const rect = await page.$eval(".annotationEditorLayer", el => {
// With Chrome something is wrong when serializing a DomRect,
// hence we extract the values and just return them.
const { x, y } = el.getBoundingClientRect();
return { x, y };
});
const editorCenters = [];
for (let i = 0; i < 4; i++) {
const data = `FreeText ${i}`;
await page.mouse.click(
rect.x + (i + 1) * 100,
rect.y + (i + 1) * 100
);
await page.type(`${editorPrefix}${i} .internal`, data);
const editorRect = await page.$eval(`${editorPrefix}${i}`, el => {
const { x, y, width, height } = el.getBoundingClientRect();
return {
x,
y,
width,
height,
};
});
editorCenters.push({
x: editorRect.x + editorRect.width / 2,
y: editorRect.y + editorRect.height / 2,
});
// Commit.
await page.mouse.click(
editorRect.x,
editorRect.y + 2 * editorRect.height
);
}
await page.keyboard.down("Control");
await page.keyboard.press("a");
await page.keyboard.up("Control");
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([0, 1, 2, 3]);
await page.keyboard.down("Control");
await page.mouse.click(editorCenters[1].x, editorCenters[1].y);
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([0, 2, 3]);
await page.mouse.click(editorCenters[2].x, editorCenters[2].y);
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([0, 3]);
await page.mouse.click(editorCenters[1].x, editorCenters[1].y);
await page.keyboard.up("Control");
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([0, 1, 3]);
await page.keyboard.down("Control");
await page.keyboard.press("c");
await page.keyboard.up("Control");
await page.keyboard.down("Control");
await page.keyboard.press("v");
await page.keyboard.up("Control");
// 0,1,3 are unselected and new pasted editors are selected.
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([4, 5, 6]);
// No ctrl here, hence all are unselected and 2 is selected.
await page.mouse.click(editorCenters[2].x, editorCenters[2].y);
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([2]);
await page.mouse.click(editorCenters[1].x, editorCenters[1].y);
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([1]);
await page.keyboard.down("Control");
await page.mouse.click(editorCenters[3].x, editorCenters[3].y);
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([1, 3]);
await page.keyboard.up("Control");
// Delete 1 and 3.
await page.keyboard.press("Backspace");
await page.keyboard.down("Control");
await page.keyboard.press("a");
await page.keyboard.up("Control");
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([0, 2, 4, 5, 6]);
// Create an empty editor.
await page.mouse.click(rect.x + 700, rect.y + 100);
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([7]);
// Set the focus to 2 and check that only 2 is selected.
await page.mouse.click(editorCenters[2].x, editorCenters[2].y);
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([2]);
// Create an empty editor.
await page.mouse.click(rect.x + 700, rect.y + 100);
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([8]);
// Dismiss it.
await page.keyboard.press("Escape");
// Select all.
await page.keyboard.down("Control");
await page.keyboard.press("a");
await page.keyboard.up("Control");
// Check that all the editors are correctly selected (and the focus
// didn't move to the body when the empty editor was removed).
expect(await getSelected(page))
.withContext(`In ${browserName}`)
.toEqual([0, 2, 4, 5, 6]);
})
);
});
});
});

View File

@ -47,6 +47,11 @@
transform-origin: 0 0;
}
.annotationEditorLayer .selectedEditor {
outline: var(--focus-outline);
resize: none;
}
.annotationEditorLayer .freeTextEditor {
position: absolute;
background: transparent;
@ -94,21 +99,17 @@
outline: none;
}
.annotationEditorLayer .freeTextEditor:focus-within {
outline: var(--focus-outline);
}
.annotationEditorLayer .inkEditor:not(:focus) {
.annotationEditorLayer .inkEditor.disabled {
resize: none;
}
.annotationEditorLayer .freeTextEditor:hover:not(:focus-within),
.annotationEditorLayer .inkEditor:hover:not(:focus) {
outline: var(--hover-outline);
.annotationEditorLayer .inkEditor.disabled.selectedEditor {
resize: horizontal;
}
.annotationEditorLayer .inkEditor.disabled:focus {
resize: horizontal;
.annotationEditorLayer .freeTextEditor:hover:not(.selectedEditor),
.annotationEditorLayer .inkEditor:hover:not(.selectedEditor) {
outline: var(--hover-outline);
}
.annotationEditorLayer .inkEditor {
@ -123,11 +124,6 @@
cursor: auto;
}
.annotationEditorLayer .inkEditor:focus {
outline: var(--focus-outline);
resize: both;
}
.annotationEditorLayer .inkEditor.editing {
resize: none;
cursor: var(--editorInk-editing-cursor), pointer;
@ -140,8 +136,3 @@
width: 100%;
height: 100%;
}
.annotationEditorLayer .selectedEditor {
outline: var(--focus-outline);
resize: none;
}