Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add clipboard hooks - first approach #85

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/web-api-hooks/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { EventArgs, EventMap, JSONArray, JSONObject, JSONValue } from './types';

export { default as useClipboard } from './useClipboard';
export { default as useDeviceMotion } from './useDeviceMotion';
export { default as useDeviceOrientation } from './useDeviceOrientation';
export { default as useDocumentReadiness } from './useDocumentReadiness';
Expand Down
72 changes: 72 additions & 0 deletions packages/web-api-hooks/src/useClipboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
export default function useClipboard() {
const checkForPermission = (type: PermissionName): Promise<string> => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function may be put outside of the useClipboard function (just above it), in order to avoid re-instantiating it on every render.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a second thought, checkForPermission may be moved to 'utils.ts', in order to be reused by useDeviceMotion.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved.

return new Promise((resolve, reject) => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please prefer using async/await.

if (!navigator.permissions) {
resolve('Permission granted.');
} else {
navigator.permissions
.query({
name: type,
})
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be put on a single line to improve legibility.


/* Permission API is still a working draft, and Typescript types for it
are still not correct, hence 'any' type as an argument. Similar situation
in lines where checkForPermission function is invoked. */
.then((permissionStatus: any) => {
// Will be 'granted', 'denied' or 'prompt':
if (permissionStatus.state === 'granted') {
resolve('Permission granted.');
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the resolved value should be a boolean, returning false on failure.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes total sense.

} else {
reject('Permission deined'); // eslint-disable-line
}
})
.catch(error => reject(error));
}
});
};

const cut = (element: HTMLInputElement) => {
checkForPermission('clipboard-write' as PermissionName)
.then(() => {
element.select();
document.execCommand('cut');
element.value = '';
element.blur();
})
.catch((error: string) => console.error(error));
};

const paste = (element: HTMLInputElement) => {
checkForPermission('clipboard-read' as PermissionName)
.then(() => {
element.focus();
document.execCommand('paste');
})
.catch((error: string) => console.error(error));
};

const copy = (text: string) => {
checkForPermission('clipboard-write' as PermissionName)
.then(() => {
if (navigator.clipboard) {
navigator.clipboard.writeText(text);
} else {
const tempInput = document.createElement('input');
document.body.appendChild(tempInput);
tempInput.setAttribute('id', 'temp-input');
(document.getElementById(
'temp-input',
) as HTMLInputElement).value = text;
tempInput.select();
document.execCommand('copy');
document.body.removeChild(tempInput);
}
})
.catch((error: string) => console.error(error));
};
Copy link
Owner

@kripod kripod Oct 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please prefer using async/await and add an optional errorCallback parameter instead of printing on the console.

return {
copy,
cut,
paste,
};
}