From 695dcc6ca84ee86090b2b68d1d47ff1cc49cb304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Tue, 28 Nov 2023 18:47:55 +0100 Subject: [PATCH] [Glitch] Converted app/javascript/flavours/glitch/utils/ folder to TypeScript Port 1142f4c79e3eaf4450ed727de0f480e300e8b9a2 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/utils/config.js | 10 ----- .../flavours/glitch/utils/config.ts | 13 ++++++ app/javascript/flavours/glitch/utils/html.js | 6 --- app/javascript/flavours/glitch/utils/html.ts | 9 +++++ .../glitch/utils/{icons.jsx => icons.tsx} | 14 ++++++- .../glitch/utils/{log_out.js => log_out.ts} | 0 .../flavours/glitch/utils/notifications.js | 30 -------------- .../flavours/glitch/utils/notifications.ts | 13 ++++++ .../{react_router.jsx => react_router.tsx} | 40 +++++++++++-------- .../utils/{scrollbar.js => scrollbar.ts} | 17 ++++---- 10 files changed, 77 insertions(+), 75 deletions(-) delete mode 100644 app/javascript/flavours/glitch/utils/config.js create mode 100644 app/javascript/flavours/glitch/utils/config.ts delete mode 100644 app/javascript/flavours/glitch/utils/html.js create mode 100644 app/javascript/flavours/glitch/utils/html.ts rename app/javascript/flavours/glitch/utils/{icons.jsx => icons.tsx} (69%) rename app/javascript/flavours/glitch/utils/{log_out.js => log_out.ts} (100%) delete mode 100644 app/javascript/flavours/glitch/utils/notifications.js create mode 100644 app/javascript/flavours/glitch/utils/notifications.ts rename app/javascript/flavours/glitch/utils/{react_router.jsx => react_router.tsx} (53%) rename app/javascript/flavours/glitch/utils/{scrollbar.js => scrollbar.ts} (72%) diff --git a/app/javascript/flavours/glitch/utils/config.js b/app/javascript/flavours/glitch/utils/config.js deleted file mode 100644 index 932cd0cbf5..0000000000 --- a/app/javascript/flavours/glitch/utils/config.js +++ /dev/null @@ -1,10 +0,0 @@ -import ready from '../ready'; - -export let assetHost = ''; - -ready(() => { - const cdnHost = document.querySelector('meta[name=cdn-host]'); - if (cdnHost) { - assetHost = cdnHost.content || ''; - } -}); diff --git a/app/javascript/flavours/glitch/utils/config.ts b/app/javascript/flavours/glitch/utils/config.ts new file mode 100644 index 0000000000..9222c89d1b --- /dev/null +++ b/app/javascript/flavours/glitch/utils/config.ts @@ -0,0 +1,13 @@ +import ready from '../ready'; + +export let assetHost = ''; + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +ready(() => { + const cdnHost = document.querySelector( + 'meta[name=cdn-host]', + ); + if (cdnHost) { + assetHost = cdnHost.content || ''; + } +}); diff --git a/app/javascript/flavours/glitch/utils/html.js b/app/javascript/flavours/glitch/utils/html.js deleted file mode 100644 index 247e98c88a..0000000000 --- a/app/javascript/flavours/glitch/utils/html.js +++ /dev/null @@ -1,6 +0,0 @@ -// NB: This function can still return unsafe HTML -export const unescapeHTML = (html) => { - const wrapper = document.createElement('div'); - wrapper.innerHTML = html.replace(//g, '\n').replace(/<\/p>

/g, '\n\n').replace(/<[^>]*>/g, ''); - return wrapper.textContent; -}; diff --git a/app/javascript/flavours/glitch/utils/html.ts b/app/javascript/flavours/glitch/utils/html.ts new file mode 100644 index 0000000000..0145a04551 --- /dev/null +++ b/app/javascript/flavours/glitch/utils/html.ts @@ -0,0 +1,9 @@ +// NB: This function can still return unsafe HTML +export const unescapeHTML = (html: string) => { + const wrapper = document.createElement('div'); + wrapper.innerHTML = html + .replace(//g, '\n') + .replace(/<\/p>

/g, '\n\n') + .replace(/<[^>]*>/g, ''); + return wrapper.textContent; +}; diff --git a/app/javascript/flavours/glitch/utils/icons.jsx b/app/javascript/flavours/glitch/utils/icons.tsx similarity index 69% rename from app/javascript/flavours/glitch/utils/icons.jsx rename to app/javascript/flavours/glitch/utils/icons.tsx index be566032e0..6e432e32fa 100644 --- a/app/javascript/flavours/glitch/utils/icons.jsx +++ b/app/javascript/flavours/glitch/utils/icons.tsx @@ -1,13 +1,23 @@ // Copied from emoji-mart for consistency with emoji picker and since // they don't export the icons in the package export const loupeIcon = ( - + ); export const deleteIcon = ( - + ); diff --git a/app/javascript/flavours/glitch/utils/log_out.js b/app/javascript/flavours/glitch/utils/log_out.ts similarity index 100% rename from app/javascript/flavours/glitch/utils/log_out.js rename to app/javascript/flavours/glitch/utils/log_out.ts diff --git a/app/javascript/flavours/glitch/utils/notifications.js b/app/javascript/flavours/glitch/utils/notifications.js deleted file mode 100644 index 42623ac7c6..0000000000 --- a/app/javascript/flavours/glitch/utils/notifications.js +++ /dev/null @@ -1,30 +0,0 @@ -// Handles browser quirks, based on -// https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API/Using_the_Notifications_API - -const checkNotificationPromise = () => { - try { - // eslint-disable-next-line promise/valid-params, promise/catch-or-return - Notification.requestPermission().then(); - } catch(e) { - return false; - } - - return true; -}; - -const handlePermission = (permission, callback) => { - // Whatever the user answers, we make sure Chrome stores the information - if(!('permission' in Notification)) { - Notification.permission = permission; - } - - callback(Notification.permission); -}; - -export const requestNotificationPermission = (callback) => { - if (checkNotificationPromise()) { - Notification.requestPermission().then((permission) => handlePermission(permission, callback)).catch(console.warn); - } else { - Notification.requestPermission((permission) => handlePermission(permission, callback)); - } -}; diff --git a/app/javascript/flavours/glitch/utils/notifications.ts b/app/javascript/flavours/glitch/utils/notifications.ts new file mode 100644 index 0000000000..08f677f8fe --- /dev/null +++ b/app/javascript/flavours/glitch/utils/notifications.ts @@ -0,0 +1,13 @@ +/** + * Tries Notification.requestPermission, console warning instead of rejecting on error. + * @param callback Runs with the permission result on completion. + */ +export const requestNotificationPermission = async ( + callback: NotificationPermissionCallback, +) => { + try { + callback(await Notification.requestPermission()); + } catch (error) { + console.warn(error); + } +}; diff --git a/app/javascript/flavours/glitch/utils/react_router.jsx b/app/javascript/flavours/glitch/utils/react_router.tsx similarity index 53% rename from app/javascript/flavours/glitch/utils/react_router.jsx rename to app/javascript/flavours/glitch/utils/react_router.tsx index fa8f0db2b5..0682fee554 100644 --- a/app/javascript/flavours/glitch/utils/react_router.jsx +++ b/app/javascript/flavours/glitch/utils/react_router.tsx @@ -1,8 +1,8 @@ -import PropTypes from "prop-types"; +import PropTypes from 'prop-types'; -import { __RouterContext } from "react-router"; +import { __RouterContext } from 'react-router'; -import hoistStatics from "hoist-non-react-statics"; +import hoistStatics from 'hoist-non-react-statics'; export const WithRouterPropTypes = { match: PropTypes.object.isRequired, @@ -16,31 +16,37 @@ export const WithOptionalRouterPropTypes = { history: PropTypes.object, }; +export interface OptionalRouterProps { + ref: unknown; + wrappedComponentRef: unknown; +} + // This is copied from https://github.com/remix-run/react-router/blob/v5.3.4/packages/react-router/modules/withRouter.js // but does not fail if called outside of a React Router context -export function withOptionalRouter(Component) { - const displayName = `withRouter(${Component.displayName || Component.name})`; - const C = props => { +export function withOptionalRouter< + ComponentType extends React.ComponentType, +>(Component: ComponentType) { + const displayName = `withRouter(${Component.displayName ?? Component.name})`; + const C = (props: React.ComponentProps) => { const { wrappedComponentRef, ...remainingProps } = props; return ( <__RouterContext.Consumer> - {context => { - if(context) + {(context) => { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (context) { return ( + // @ts-expect-error - Dynamic covariant generic components are tough to type. ); - else - return ( - - ); + } else { + // @ts-expect-error - Dynamic covariant generic components are tough to type. + return ; + } }} ); @@ -53,8 +59,8 @@ export function withOptionalRouter(Component) { wrappedComponentRef: PropTypes.oneOfType([ PropTypes.string, PropTypes.func, - PropTypes.object - ]) + PropTypes.object, + ]), }; return hoistStatics(C, Component); diff --git a/app/javascript/flavours/glitch/utils/scrollbar.js b/app/javascript/flavours/glitch/utils/scrollbar.ts similarity index 72% rename from app/javascript/flavours/glitch/utils/scrollbar.js rename to app/javascript/flavours/glitch/utils/scrollbar.ts index b3f543ffb3..d505df1244 100644 --- a/app/javascript/flavours/glitch/utils/scrollbar.js +++ b/app/javascript/flavours/glitch/utils/scrollbar.ts @@ -1,9 +1,7 @@ -/** @type {number | null} */ -let cachedScrollbarWidth = null; +import { isMobile } from '../is_mobile'; + +let cachedScrollbarWidth: number | null = null; -/** - * @returns {number} - */ const getActualScrollbarWidth = () => { const outer = document.createElement('div'); outer.style.visibility = 'hidden'; @@ -14,20 +12,19 @@ const getActualScrollbarWidth = () => { outer.appendChild(inner); const scrollbarWidth = outer.offsetWidth - inner.offsetWidth; - outer.parentNode.removeChild(outer); + outer.remove(); return scrollbarWidth; }; -/** - * @returns {number} - */ export const getScrollbarWidth = () => { if (cachedScrollbarWidth !== null) { return cachedScrollbarWidth; } - const scrollbarWidth = getActualScrollbarWidth(); + const scrollbarWidth = isMobile(window.innerWidth) + ? 0 + : getActualScrollbarWidth(); cachedScrollbarWidth = scrollbarWidth; return scrollbarWidth;