improve clipboard handling (#596)

* improve clipboard handling

* fix regression of not defocusing tool icons
This commit is contained in:
David Luzar 2020-01-27 22:14:35 +01:00 committed by GitHub
parent de68561df5
commit 26048ee469
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 21 deletions

View File

@ -37,7 +37,7 @@ export class ActionManager implements ActionsManagerInterface {
action => action.keyTest && action.keyTest(event, elements, appState), action => action.keyTest && action.keyTest(event, elements, appState),
); );
if (data.length === 0) return {}; if (data.length === 0) return null;
event.preventDefault(); event.preventDefault();
return data[0].perform(elements, appState, null); return data[0].perform(elements, appState, null);

View File

@ -45,7 +45,7 @@ export interface ActionsManagerInterface {
event: KeyboardEvent, event: KeyboardEvent,
elements: readonly ExcalidrawElement[], elements: readonly ExcalidrawElement[],
appState: AppState, appState: AppState,
) => ActionResult | {}; ) => ActionResult | null;
getContextMenuItems: ( getContextMenuItems: (
elements: readonly ExcalidrawElement[], elements: readonly ExcalidrawElement[],
appState: AppState, appState: AppState,

View File

@ -307,11 +307,15 @@ export class App extends React.Component<any, AppState> {
} }
if (isInputLike(event.target)) return; if (isInputLike(event.target)) return;
const data = this.actionManager.handleKeyDown(event, elements, this.state); const actionResult = this.actionManager.handleKeyDown(
this.syncActionResult(data); event,
elements,
this.state,
);
if (data.elements !== undefined || data.appState !== undefined) { if (actionResult) {
return; this.syncActionResult(actionResult);
if (actionResult) return;
} }
const shape = findShapeByKey(event.key); const shape = findShapeByKey(event.key);
@ -371,18 +375,20 @@ export class App extends React.Component<any, AppState> {
private removeWheelEventListener: (() => void) | undefined; private removeWheelEventListener: (() => void) | undefined;
private copyToClipboard = () => { private copyToClipboard = () => {
if (navigator.clipboard) { const text = JSON.stringify(
const text = JSON.stringify( elements
elements .filter(element => element.isSelected)
.filter(element => element.isSelected) .map(({ shape, ...el }) => el),
.map(({ shape, ...el }) => el), );
); if ("clipboard" in navigator && "writeText" in navigator.clipboard) {
navigator.clipboard.writeText(text); navigator.clipboard.writeText(text);
} else {
document.execCommand("copy");
} }
}; };
private pasteFromClipboard = () => { private pasteFromClipboard = () => {
if (navigator.clipboard) { if ("clipboard" in navigator && "readText" in navigator.clipboard) {
navigator.clipboard navigator.clipboard
.readText() .readText()
.then(text => this.addElementsFromPaste(text)); .then(text => this.addElementsFromPaste(text));
@ -790,9 +796,9 @@ export class App extends React.Component<any, AppState> {
// fixes mousemove causing selection of UI texts #32 // fixes mousemove causing selection of UI texts #32
e.preventDefault(); e.preventDefault();
// Preventing the event above disables default behavior // Preventing the event above disables default behavior
// of defocusing potentially focused input, which is what we want // of defocusing potentially focused element, which is what we
// when clicking inside the canvas. // want when clicking inside the canvas.
if (isInputLike(document.activeElement)) { if (document.activeElement instanceof HTMLElement) {
document.activeElement.blur(); document.activeElement.blur();
} }

View File

@ -14,14 +14,25 @@ export function capitalizeString(str: string) {
return str.charAt(0).toUpperCase() + str.slice(1); return str.charAt(0).toUpperCase() + str.slice(1);
} }
export function isToolIcon(
target: Element | EventTarget | null,
): target is HTMLElement {
return target instanceof HTMLElement && target.className.includes("ToolIcon");
}
export function isInputLike( export function isInputLike(
target: Element | EventTarget | null, target: Element | EventTarget | null,
): target is HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement { ): target is
| HTMLInputElement
| HTMLTextAreaElement
| HTMLSelectElement
| HTMLDivElement {
return ( return (
(target instanceof HTMLElement && target.dataset.type === "wysiwyg") || ((target instanceof HTMLElement && target.dataset.type === "wysiwyg") ||
target instanceof HTMLInputElement || target instanceof HTMLInputElement ||
target instanceof HTMLTextAreaElement || target instanceof HTMLTextAreaElement ||
target instanceof HTMLSelectElement target instanceof HTMLSelectElement) &&
!isToolIcon(target)
); );
} }