diff --git a/client/package.json b/client/package.json index 9b0af9ccdc..fc57f22997 100644 --- a/client/package.json +++ b/client/package.json @@ -98,12 +98,9 @@ "@babel/preset-typescript": "^7.10.1", "@babel/runtime-corejs3": "^7.10.3", "@coralproject/rte": "^2.2.4", - "@emotion/cache": "^10.0.29", - "@emotion/core": "^10.1.1", "@fluent/react": "^0.12.0", "@giphy/js-fetch-api": "^4.1.2", "@giphy/js-types": "^5.0.0", - "@giphy/react-components": "^5.4.0", "@graphql-codegen/cli": "^1.20.0", "@graphql-codegen/introspection": "^1.18.1", "@intervolga/optimize-cssnano-plugin": "^1.0.6", diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml index a69218d2e3..d3c506e28a 100644 --- a/client/pnpm-lock.yaml +++ b/client/pnpm-lock.yaml @@ -122,12 +122,6 @@ devDependencies: '@coralproject/rte': specifier: ^2.2.4 version: 2.2.4(react-dom@18.2.0)(react@18.2.0) - '@emotion/cache': - specifier: ^10.0.29 - version: 10.0.29 - '@emotion/core': - specifier: ^10.1.1 - version: 10.1.1(react@18.2.0) '@fluent/react': specifier: ^0.12.0 version: 0.12.0(@fluent/bundle@0.15.1)(react@18.2.0) @@ -137,9 +131,6 @@ devDependencies: '@giphy/js-types': specifier: ^5.0.0 version: 5.0.0 - '@giphy/react-components': - specifier: ^5.4.0 - version: 5.4.0(react-dom@18.2.0)(react@18.2.0) '@graphql-codegen/cli': specifier: ^1.20.0 version: 1.21.8(@types/node@12.12.34)(graphql@14.6.0)(typescript@3.9.10) @@ -2049,107 +2040,6 @@ packages: kuler: 2.0.0 dev: false - /@emotion/cache@10.0.29: - resolution: {integrity: sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==} - dependencies: - '@emotion/sheet': 0.9.4 - '@emotion/stylis': 0.8.5 - '@emotion/utils': 0.11.3 - '@emotion/weak-memoize': 0.2.5 - dev: true - - /@emotion/core@10.1.1(react@18.2.0): - resolution: {integrity: sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA==} - peerDependencies: - react: '>=16.3.0' - dependencies: - '@babel/runtime': 7.23.8 - '@emotion/cache': 10.0.29 - '@emotion/css': 10.0.27 - '@emotion/serialize': 0.11.16 - '@emotion/sheet': 0.9.4 - '@emotion/utils': 0.11.3 - react: 18.2.0 - dev: true - - /@emotion/css@10.0.27: - resolution: {integrity: sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==} - dependencies: - '@emotion/serialize': 0.11.16 - '@emotion/utils': 0.11.3 - babel-plugin-emotion: 10.0.29 - dev: true - - /@emotion/hash@0.8.0: - resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} - dev: true - - /@emotion/is-prop-valid@0.8.8: - resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} - dependencies: - '@emotion/memoize': 0.7.4 - dev: true - - /@emotion/memoize@0.7.4: - resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==} - dev: true - - /@emotion/serialize@0.11.16: - resolution: {integrity: sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==} - dependencies: - '@emotion/hash': 0.8.0 - '@emotion/memoize': 0.7.4 - '@emotion/unitless': 0.7.5 - '@emotion/utils': 0.11.3 - csstype: 2.6.9 - dev: true - - /@emotion/sheet@0.9.4: - resolution: {integrity: sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==} - dev: true - - /@emotion/styled-base@10.0.31(@emotion/core@10.1.1)(react@18.2.0): - resolution: {integrity: sha512-wTOE1NcXmqMWlyrtwdkqg87Mu6Rj1MaukEoEmEkHirO5IoHDJ8LgCQL4MjJODgxWxXibGR3opGp1p7YvkNEdXQ==} - peerDependencies: - '@emotion/core': ^10.0.28 - react: '>=16.3.0' - dependencies: - '@babel/runtime': 7.23.8 - '@emotion/core': 10.1.1(react@18.2.0) - '@emotion/is-prop-valid': 0.8.8 - '@emotion/serialize': 0.11.16 - '@emotion/utils': 0.11.3 - react: 18.2.0 - dev: true - - /@emotion/styled@10.0.27(@emotion/core@10.1.1)(react@18.2.0): - resolution: {integrity: sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q==} - peerDependencies: - '@emotion/core': ^10.0.27 - react: '>=16.3.0' - dependencies: - '@emotion/core': 10.1.1(react@18.2.0) - '@emotion/styled-base': 10.0.31(@emotion/core@10.1.1)(react@18.2.0) - babel-plugin-emotion: 10.0.29 - react: 18.2.0 - dev: true - - /@emotion/stylis@0.8.5: - resolution: {integrity: sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==} - dev: true - - /@emotion/unitless@0.7.5: - resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} - dev: true - - /@emotion/utils@0.11.3: - resolution: {integrity: sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==} - dev: true - - /@emotion/weak-memoize@0.2.5: - resolution: {integrity: sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==} - dev: true - /@endemolshinegroup/cosmiconfig-typescript-loader@3.0.2(cosmiconfig@7.0.0)(typescript@3.9.10): resolution: {integrity: sha512-QRVtqJuS1mcT56oHpVegkKBlgtWjXw/gHNWO3eL9oyB5Sc7HBoc2OLG/nYpVfT/Jejvo3NUrD0Udk7XgoyDKkA==} engines: {node: '>=10.0.0'} @@ -2244,21 +2134,6 @@ packages: '@fluent/bundle': 0.15.1 dev: true - /@giphy/js-analytics@4.0.7: - resolution: {integrity: sha512-s4+GUXWwyxJVm6i7GHiQvQlMaXkHGCkh4uqjpisX5IiHxTNheSDMHHX0SyRLpTL5rdnvBkiBxlH8iOv9w3pNwg==} - dependencies: - '@giphy/js-types': 4.1.0 - '@giphy/js-util': 4.0.1 - append-query: 2.1.1 - throttle-debounce: 3.0.1 - dev: true - - /@giphy/js-brand@2.0.4: - resolution: {integrity: sha512-q2iRyRWmKpCLAt1G7LzcHjw8s/cvSSoA1SfoQL47Tx0/yGwo8xCiFcFPFZJZsCcVMLCwA7/UmxTkdRydQVhCNw==} - dependencies: - emotion: 10.0.27 - dev: true - /@giphy/js-fetch-api@4.1.2: resolution: {integrity: sha512-wDfDQu8HiVkLb+YXcZf8QFbznmMHWbg86ZBydYmnp2mfuHyaHKsz9n9PnxdH3RorMS9YM/Ca/zqAM5y89Qj+Hw==} dependencies: @@ -2283,27 +2158,6 @@ packages: uuid: 8.3.2 dev: true - /@giphy/react-components@5.4.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-n8BhFzVZoETPsdYVDBuqXc1yCzsX0lypEkNQAIuouY4VEoGfb4yvRT507O79FPLwYLAXxGWiGE9S2h/0TLJvLw==} - peerDependencies: - react: 16.10.2 - 17 - dependencies: - '@emotion/core': 10.1.1(react@18.2.0) - '@emotion/styled': 10.0.27(@emotion/core@10.1.1)(react@18.2.0) - '@giphy/js-analytics': 4.0.7 - '@giphy/js-brand': 2.0.4 - '@giphy/js-fetch-api': 4.1.2 - '@giphy/js-types': 4.1.0 - '@giphy/js-util': 4.0.1 - emotion-theming: 10.0.27(@emotion/core@10.1.1)(react@18.2.0) - intersection-observer: 0.11.0 - react: 18.2.0 - react-use: 17.2.4(react-dom@18.2.0)(react@18.2.0) - throttle-debounce: 3.0.1 - transitivePeerDependencies: - - react-dom - dev: true - /@graphql-codegen/cli@1.21.8(@types/node@12.12.34)(graphql@14.6.0)(typescript@3.9.10): resolution: {integrity: sha512-sxKUIvT2dGerFyvs6SsQpkHDyOnk+MRwqsnmsF22eAWHUbNLd429PKC71E26egXzT2BhHabUIfMV7xk9mkgWNg==} hasBin: true @@ -4790,12 +4644,6 @@ packages: buffer-equal: 1.0.0 dev: true - /append-query@2.1.1: - resolution: {integrity: sha512-adm0E8o1o7ay+HbkWvGIpNNeciLB/rxJ0heThHuzSSVq5zcdQ5/ZubFnUoY0imFmk6gZVghSpwoubLVtwi9EHQ==} - dependencies: - extend: 3.0.2 - dev: true - /aproba@1.2.0: resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} dev: true @@ -5375,21 +5223,6 @@ packages: object.assign: 4.1.5 dev: true - /babel-plugin-emotion@10.0.29: - resolution: {integrity: sha512-7Jpi1OCxjyz0k163lKtqP+LHMg5z3S6A7vMBfHnF06l2unmtsOmFDzZBpGf0CWo1G4m8UACfVcDJiSiRuu/cSw==} - dependencies: - '@babel/helper-module-imports': 7.16.0 - '@emotion/hash': 0.8.0 - '@emotion/memoize': 0.7.4 - '@emotion/serialize': 0.11.16 - babel-plugin-macros: 2.0.0 - babel-plugin-syntax-jsx: 6.18.0 - convert-source-map: 1.7.0 - escape-string-regexp: 1.0.5 - find-root: 1.1.0 - source-map: 0.5.7 - dev: true - /babel-plugin-istanbul@6.0.0: resolution: {integrity: sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==} engines: {node: '>=8'} @@ -5457,10 +5290,6 @@ packages: resolution: {integrity: sha512-Z/flU+T9ta0aIEKl1tGEmN/pZiI1uXmCiGFRegKacQfEJzp7iNsKloZmyJlQr+75FCJtiFfGIK03SiCvCt9cPQ==} dev: true - /babel-plugin-syntax-jsx@6.18.0: - resolution: {integrity: sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==} - dev: true - /babel-plugin-syntax-trailing-function-commas@6.22.0: resolution: {integrity: sha512-Gx9CH3Q/3GKbhs07Bszw5fPTlU+ygrOGfAhEt7W2JICwufpC4SuO0mG0+4NykPBSYPMJhqvVlDBU17qB1D+hMQ==} dev: true @@ -7197,15 +7026,6 @@ packages: elliptic: 6.5.3 dev: true - /create-emotion@10.0.27: - resolution: {integrity: sha512-fIK73w82HPPn/RsAij7+Zt8eCE8SptcJ3WoRMfxMtjteYxud8GDTKKld7MYwAX2TVhrw29uR1N/bVGxeStHILg==} - dependencies: - '@emotion/cache': 10.0.29 - '@emotion/serialize': 0.11.16 - '@emotion/sheet': 0.9.4 - '@emotion/utils': 0.11.3 - dev: true - /create-hash@1.2.0: resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} dependencies: @@ -8310,26 +8130,6 @@ packages: engines: {node: '>= 4'} dev: true - /emotion-theming@10.0.27(@emotion/core@10.1.1)(react@18.2.0): - resolution: {integrity: sha512-MlF1yu/gYh8u+sLUqA0YuA9JX0P4Hb69WlKc/9OLo+WCXuX6sy/KoIa+qJimgmr2dWqnypYKYPX37esjDBbhdw==} - peerDependencies: - '@emotion/core': ^10.0.27 - react: '>=16.3.0' - dependencies: - '@babel/runtime': 7.23.8 - '@emotion/core': 10.1.1(react@18.2.0) - '@emotion/weak-memoize': 0.2.5 - hoist-non-react-statics: 3.3.2 - react: 18.2.0 - dev: true - - /emotion@10.0.27: - resolution: {integrity: sha512-2xdDzdWWzue8R8lu4G76uWX5WhyQuzATon9LmNeCy/2BHVC6dsEpfhN1a0qhELgtDVdjyEA6J8Y/VlI5ZnaH0g==} - dependencies: - babel-plugin-emotion: 10.0.29 - create-emotion: 10.0.27 - dev: true - /enabled@2.0.0: resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} dev: false @@ -9318,10 +9118,6 @@ packages: pkg-dir: 4.2.0 dev: true - /find-root@1.1.0: - resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} - dev: true - /find-up@1.1.2: resolution: {integrity: sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==} engines: {node: '>=0.10.0'} @@ -10848,10 +10644,6 @@ packages: engines: {node: '>= 0.10'} dev: true - /intersection-observer@0.11.0: - resolution: {integrity: sha512-KZArj2QVnmdud9zTpKf279m2bbGfG+4/kn16UU0NL3pTVl52ZHiJ9IRNSsnn6jaHrL9EGLFM5eWjTx2fz/+zoQ==} - dev: true - /intersection-observer@0.7.0: resolution: {integrity: sha512-Id0Fij0HsB/vKWGeBe9PxeY45ttRiBmhFyyt/geBdDHBYNctMRTE3dC1U3ujzz3lap+hVXlEcVaB56kZP/eEUg==} dev: true @@ -15821,30 +15613,6 @@ packages: tslib: 2.6.2 dev: true - /react-use@17.2.4(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-vQGpsAM0F5UIlshw5UI8ULGPS4yn5rm7/qvn3T1Gnkrz7YRMEEMh+ynKcmRloOyiIeLvKWiQjMiwRGtdbgs5qQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - dependencies: - '@types/js-cookie': 2.2.6 - '@xobotyi/scrollbar-width': 1.9.5 - copy-to-clipboard: 3.3.1 - fast-deep-equal: 3.1.3 - fast-shallow-equal: 1.0.0 - js-cookie: 2.2.1 - nano-css: 5.3.5(react-dom@18.2.0)(react@18.2.0) - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-universal-interface: 0.6.2(react@18.2.0)(tslib@2.6.2) - resize-observer-polyfill: 1.5.1 - screenfull: 5.2.0 - set-harmonic-interval: 1.0.1 - throttle-debounce: 3.0.1 - ts-easing: 0.2.0 - tslib: 2.6.2 - dev: true - /react-use@17.4.0(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-TgbNTCA33Wl7xzIJegn1HndB4qTS9u03QUwyNycUnXaweZkE4Kq2SB+Yoxx8qbshkZGYBDvUXbXWRUmQDcZZ/Q==} peerDependencies: diff --git a/client/src/core/client/stream/shadow/EmotionShadowRoot.tsx b/client/src/core/client/stream/shadow/EmotionShadowRoot.tsx deleted file mode 100644 index f094519db4..0000000000 --- a/client/src/core/client/stream/shadow/EmotionShadowRoot.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import createCache from "@emotion/cache"; -import { CacheProvider } from "@emotion/core"; -import React from "react"; -import * as ReactShadow from "react-shadow"; - -const cache = new WeakMap(); -const createProxy = (ReactShadow as any).createProxy; - -/** - * Creates a ReactShadow proxy with telling emotions to insert its styles into the shadow root - * This is only needed because of @giphy/react-components - * - * TODO: (cvle) Currently some styles still slip into light dom. - * TODO: (cvle) Replace giphy components? - */ -export default createProxy( - {}, - "emotion", - ({ root, children }: { root: any; children: any }) => { - const options = - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - cache.get(root) || - (() => { - const opts = createCache({ - container: root, - key: "react-shadow", - }); - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - cache.set(root, opts); - return opts; - })(); - - return ( - - <>{children} - - ); - } -); diff --git a/client/src/core/client/stream/shadow/index.ts b/client/src/core/client/stream/shadow/index.ts deleted file mode 100644 index 59570923b2..0000000000 --- a/client/src/core/client/stream/shadow/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as EmotionShadowRoot } from "./EmotionShadowRoot"; diff --git a/client/src/core/client/stream/stream.tsx b/client/src/core/client/stream/stream.tsx index aa1dccd5f2..77e93fcc46 100644 --- a/client/src/core/client/stream/stream.tsx +++ b/client/src/core/client/stream/stream.tsx @@ -28,7 +28,6 @@ import AppContainer from "./App"; import CSSLoadError from "./CSSLoadError"; import { createInitLocalState } from "./local"; import localesData from "./locales"; -import { EmotionShadowRoot } from "./shadow"; // Import css variables. import { ACCESS_TOKEN_KEY } from "coral-framework/lib/auth"; @@ -232,7 +231,6 @@ export async function attach(options: AttachOptions) { const encapsulationContext = useMemo( () => ({ - ReactShadowRoot: EmotionShadowRoot, containerClassName: options.containerClassName, cssAssets: shadowCSSAssets, customCSSAssets: customShadowCSSAssets, diff --git a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css b/client/src/core/client/stream/tabs/Comments/GifGrid/GifGrid.css similarity index 96% rename from client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css rename to client/src/core/client/stream/tabs/Comments/GifGrid/GifGrid.css index 458806cd34..c76c047304 100644 --- a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.css +++ b/client/src/core/client/stream/tabs/Comments/GifGrid/GifGrid.css @@ -22,7 +22,7 @@ } .gridItem { - width: 85px; + width: 124px; background: var(--palette-background-body); border-style: none; padding: 2px; diff --git a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.tsx b/client/src/core/client/stream/tabs/Comments/GifGrid/GifGrid.tsx similarity index 87% rename from client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.tsx rename to client/src/core/client/stream/tabs/Comments/GifGrid/GifGrid.tsx index a12bc4642a..fb58517a11 100644 --- a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorGrid.tsx +++ b/client/src/core/client/stream/tabs/Comments/GifGrid/GifGrid.tsx @@ -11,16 +11,21 @@ import React, { import { useCoralContext } from "coral-framework/lib/bootstrap"; import { Button } from "coral-ui/components/v2"; -import { GifResult } from "./TenorInput"; +import styles from "./GifGrid.css"; -import styles from "./TenorGrid.css"; +export interface GifResult { + id: string; + url: string; + preview: string; + title?: string; +} interface GridItemProps { gif: GifResult; onSelect: (gif: GifResult) => void; } -const TenorGridItem: FunctionComponent = ({ gif, onSelect }) => { +const GifGridItem: FunctionComponent = ({ gif, onSelect }) => { const onClick = useCallback(() => { onSelect(gif); }, [gif, onSelect]); @@ -38,7 +43,7 @@ interface GridColumnsProps { numColumns: number; } -const TenorGridColumns: FunctionComponent = ({ +const GifGridColumns: FunctionComponent = ({ gifs, onSelectGif, numColumns, @@ -71,13 +76,13 @@ const TenorGridColumns: FunctionComponent = ({ {columns.map((colGifs, colIndex) => { return (
{colGifs && colGifs.map((gif, index) => { return ( - = ({ interface Props { gifs: GifResult[]; showLoadMore?: boolean; - onSelectGif: (gif: GifResult) => void; onLoadMore: () => void; } -const TenorGrid: FunctionComponent = ({ +const GifGrid: FunctionComponent = ({ gifs, showLoadMore, onSelectGif, @@ -117,7 +121,7 @@ const TenorGrid: FunctionComponent = ({ } const rect = gridRef.current.getBoundingClientRect(); - const numCols = rect.width / 90; + const numCols = rect.width / 125; setCols(numCols); }, [gridRef, setCols]); @@ -136,7 +140,7 @@ const TenorGrid: FunctionComponent = ({ return (
{gifs && cols > 0 && ( - = ({ ); }; -export default TenorGrid; +export default GifGrid; diff --git a/client/src/core/client/stream/tabs/Comments/GifGrid/index.ts b/client/src/core/client/stream/tabs/Comments/GifGrid/index.ts new file mode 100644 index 0000000000..a468483fb2 --- /dev/null +++ b/client/src/core/client/stream/tabs/Comments/GifGrid/index.ts @@ -0,0 +1 @@ +export { default as GifGrid, GifResult } from "./GifGrid"; diff --git a/client/src/core/client/stream/tabs/Comments/GifSearchInput/GifSearchInput.tsx b/client/src/core/client/stream/tabs/Comments/GifSearchInput/GifSearchInput.tsx index b9f12e4d59..4bd9e203d6 100644 --- a/client/src/core/client/stream/tabs/Comments/GifSearchInput/GifSearchInput.tsx +++ b/client/src/core/client/stream/tabs/Comments/GifSearchInput/GifSearchInput.tsx @@ -16,6 +16,7 @@ interface GifSearchInputProps { onChange: React.ChangeEventHandler; onKeyPress: (e: KeyboardEvent) => void; inputRef: React.RefObject; + onClickSearch?: () => Promise; } export const GifSearchInput: FunctionComponent = ({ @@ -23,6 +24,7 @@ export const GifSearchInput: FunctionComponent = ({ onChange, onKeyPress, inputRef, + onClickSearch, }) => { return ( @@ -49,6 +51,7 @@ export const GifSearchInput: FunctionComponent = ({ color="stream" className={styles.searchButton} aria-label="Search" + onClick={onClickSearch} > diff --git a/client/src/core/client/stream/tabs/Comments/GiphyInput/GiphyInput.tsx b/client/src/core/client/stream/tabs/Comments/GiphyInput/GiphyInput.tsx index 7d9721a614..5b92e78290 100644 --- a/client/src/core/client/stream/tabs/Comments/GiphyInput/GiphyInput.tsx +++ b/client/src/core/client/stream/tabs/Comments/GiphyInput/GiphyInput.tsx @@ -1,7 +1,5 @@ -import { Localized } from "@fluent/react/compat"; import { GiphyFetch, SearchOptions } from "@giphy/js-fetch-api"; import { IGif } from "@giphy/js-types"; -import { Grid } from "@giphy/react-components"; import React, { ChangeEventHandler, FunctionComponent, @@ -13,20 +11,21 @@ import React, { useRef, useState, } from "react"; -import useDebounce from "react-use/lib/useDebounce"; import useResizeObserver from "use-resize-observer"; +import { useDebounce } from "coral-framework/hooks"; import { HorizontalGutter } from "coral-ui/components/v2"; +import { GifGrid, GifResult } from "../GifGrid"; import { GifSearchInput } from "../GifSearchInput/GifSearchInput"; import GiphyAttribution from "./GiphyAttribution"; import styles from "./GiphyInput.css"; -const APPROX_COL_WIDTH = 120; +const DEBOUNCE_DELAY_MS = 1250; interface Props { - onSelect: (gif: IGif) => void; + onSelect: (gif: GifResult) => void; forwardRef?: Ref; apiKey: string; maxRating: string; @@ -38,34 +37,88 @@ const GiphyInput: FunctionComponent = ({ maxRating, }) => { const [query, setQuery] = useState(""); + const [gifs, setGifs] = useState([]); + const [offset, setOffset] = useState(0); + const [isNext, setIsNext] = useState(false); const inputRef = useRef(null); - const { ref, width = 1 } = useResizeObserver(); + const { ref } = useResizeObserver(); const client = useMemo(() => new GiphyFetch(apiKey), [apiKey]); - const fetchGifs = useCallback( - async (offset: number) => - client.search(query, { - offset, - limit: 10, - rating: maxRating as SearchOptions["rating"], - sort: "relevant", - }), - [client, maxRating, query] - ); - - // Instead of updating the query with every keystroke, debounce the change to - // that state parameter. - const [debouncedQuery, setDebouncedQuery] = useState(""); - const [, cancelDebounce] = useDebounce(() => setQuery(debouncedQuery), 500, [ - debouncedQuery, - ]); - const onChange: ChangeEventHandler = useCallback((e) => { - setDebouncedQuery(e.target.value); + useEffect(() => { + setOffset(0); + }, [query]); + + const fetchGifs = useCallback(async () => { + const response = await client.search(query, { + offset, + limit: 10, + rating: maxRating as SearchOptions["rating"], + sort: "relevant", + }); + if (!response) { + return null; + } + return response; + }, [client, maxRating, query, offset]); + + const mapGifs = useCallback((response: { data: IGif[] }) => { + return response.data.map((gif) => { + return { + id: gif.id as string, + preview: gif.images.preview_gif.url, + title: gif.title, + url: gif.images.original.url, + }; + }); }, []); + const loadGifs = useCallback(async () => { + const response = await fetchGifs(); + if (!response) { + return; + } + + const mappedResponse = mapGifs(response); + + setGifs(mappedResponse); + setOffset( + response.pagination.count + response.pagination.offset + 1 ?? null + ); + setIsNext( + response.pagination.total_count > response.pagination.count + offset + ); + }, [fetchGifs, offset, mapGifs]); + + const loadMoreGifs = useCallback(async () => { + const response = await fetchGifs(); + if (!response) { + return; + } + + const mappedResponse = mapGifs(response); + + setGifs([...gifs, ...mappedResponse]); + setOffset( + response.pagination.count + response.pagination.offset + 1 ?? null + ); + setIsNext( + response.pagination.total_count > response.pagination.count + offset + ); + }, [fetchGifs, gifs, offset, mapGifs]); + + const debounceFetchGifs = useDebounce(loadGifs, DEBOUNCE_DELAY_MS); + + const onChange: ChangeEventHandler = useCallback( + async (e) => { + setQuery(e.target.value); + setTimeout(debounceFetchGifs, 300); + }, + [debounceFetchGifs, setQuery] + ); + // Focus on the input as soon as the input is available. useEffect(() => { if (inputRef.current) { @@ -73,63 +126,50 @@ const GiphyInput: FunctionComponent = ({ } }, []); - const onKeyPress = useCallback((e: KeyboardEvent) => { - if (e.key !== "Enter") { - return; - } + const onKeyPress = useCallback( + async (e: KeyboardEvent) => { + if (e.key !== "Enter") { + return; + } - e.preventDefault(); - }, []); + debounceFetchGifs(); - const gridColumns = useMemo(() => { - if (width < APPROX_COL_WIDTH * 2) { - return 2; - } - return Math.floor(width / APPROX_COL_WIDTH); - }, [width]); + e.preventDefault(); + }, + [debounceFetchGifs] + ); + + const onLoadMore = useCallback(async () => { + await loadMoreGifs(); + }, [loadMoreGifs]); const onGifClick = useCallback( - (gif: IGif) => { + (gif: GifResult) => { // Cancel any active timers that might cause the query to be changed. - cancelDebounce(); setQuery(""); onSelect(gif); }, - [cancelDebounce, onSelect] + [onSelect] ); return (
- {query && ( - -

- No results found for "{query}"{" "} -

- - } - key={query} - width={width} - onGifClick={onGifClick} - /> - )} + 0 && query?.length > 0) + } + onSelectGif={onGifClick} + onLoadMore={onLoadMore} + />
diff --git a/client/src/core/client/stream/tabs/Comments/Stream/CommentForm/MediaField.tsx b/client/src/core/client/stream/tabs/Comments/Stream/CommentForm/MediaField.tsx index fb3b2663ab..94d393b124 100644 --- a/client/src/core/client/stream/tabs/Comments/Stream/CommentForm/MediaField.tsx +++ b/client/src/core/client/stream/tabs/Comments/Stream/CommentForm/MediaField.tsx @@ -1,4 +1,3 @@ -import { IGif } from "@giphy/js-types"; import React, { FunctionComponent, useCallback, useEffect } from "react"; import { useField } from "react-final-form"; @@ -17,9 +16,10 @@ import { MediaPreview, } from "../../Comment/MediaConfirmation"; import ExternalImageInput from "../../ExternalImageInput"; +import { GifResult } from "../../GifGrid"; import GiphyInput, { GifPreview } from "../../GiphyInput"; import { getMediaValidators } from "../../helpers"; -import TenorInput, { GifResult } from "../../TenorInput/TenorInput"; +import TenorInput from "../../TenorInput/TenorInput"; export type Widget = "gifs" | "external" | null; @@ -63,11 +63,11 @@ const MediaField: FunctionComponent = ({ }); const onGiphySelect = useCallback( - (gif: IGif) => { + (gif: GifResult) => { onChange({ type: "giphy", id: gif.id, - url: gif.images.original.url, + url: gif.url, }); setWidget(null); }, diff --git a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorInput.tsx b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorInput.tsx index 5d0f62e6fd..1d052bb62c 100644 --- a/client/src/core/client/stream/tabs/Comments/TenorInput/TenorInput.tsx +++ b/client/src/core/client/stream/tabs/Comments/TenorInput/TenorInput.tsx @@ -1,4 +1,3 @@ -import { Localized } from "@fluent/react/compat"; import React, { ChangeEventHandler, FunctionComponent, @@ -14,11 +13,11 @@ import useResizeObserver from "use-resize-observer"; import { useDebounce } from "coral-framework/hooks"; import { useCoralContext } from "coral-framework/lib/bootstrap"; import useFetchWithAuth from "coral-stream/common/useFetchWithAuth"; -import { ButtonSvgIcon, SearchIcon } from "coral-ui/components/icons"; -import { Button, HorizontalGutter, TextField } from "coral-ui/components/v2"; +import { HorizontalGutter } from "coral-ui/components/v2"; +import { GifGrid, GifResult } from "../GifGrid"; +import { GifSearchInput } from "../GifSearchInput/GifSearchInput"; import TenorAttribution from "./TenorAttribution"; -import TenorGrid from "./TenorGrid"; import styles from "./TenorInput.css"; @@ -29,13 +28,6 @@ interface Props { forwardRef?: Ref; } -export interface GifResult { - id: string; - url: string; - preview: string; - title?: string; -} - export interface SearchPayload { results: GifResult[]; next?: string; @@ -157,32 +149,14 @@ const TenorInput: FunctionComponent = ({ onSelect }) => { return (
- - - - } - ref={inputRef} + inputRef={inputRef} /> - 0 && query?.length > 0)