diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..52f9c88c --- /dev/null +++ b/.babelrc @@ -0,0 +1,34 @@ +{ + "presets": [ + "@babel/preset-env", + "@babel/preset-react", + "@babel/preset-typescript", + ], + "plugins": [ + // Reuse babel's injected headers + // ["@babel/plugin-transform-runtime", { "version": "^7.11.2" }], + + // Handle absolute imports + ["polyfill-corejs3", { + "method": "usage-pure", + }], + + // Handle absolute imports + ["babel-plugin-module-resolver", { + "root": ["."], + "extensions": [".js", ".jsx", ".ts", ".tsx"], + "alias": { + "#components": "./src/components", + "#hooks": "./src/hooks", + "#utils": "./src/utils", + }, + }], + + // Extends javascript support + "@babel/plugin-syntax-dynamic-import", + + // Extends react support + "@babel/plugin-transform-react-constant-elements", + // "@babel/plugin-transform-react-inline-elements", + ] +} diff --git a/.babelrc.js b/.babelrc.js deleted file mode 100644 index 41bf9306..00000000 --- a/.babelrc.js +++ /dev/null @@ -1,66 +0,0 @@ -module.exports = (api) => { - api.cache(false); - return { - /* - 'env': { - 'test': { - 'plugins': [ - require.resolve('babel-plugin-dynamic-import-node'), - ], - }, - }, - */ - 'presets': [ - require.resolve( - '@babel/preset-env', - { - 'useBuiltIns': false, - // 'useBuiltIns': 'usage', - // 'corejs': 3, - // 'debug': true, - } - ), - require.resolve('@babel/preset-react'), - require.resolve('@babel/preset-typescript'), - ], - - 'plugins': [ - // Reuse babel's injected headers - require.resolve('@babel/plugin-transform-runtime'), - [require('babel-plugin-polyfill-corejs3'), { - "method": "usage-pure", - // "targets": { "firefox": 42 } - }], - - require.resolve('@babel/plugin-proposal-do-expressions'), - require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'), - require.resolve('@babel/plugin-proposal-optional-chaining'), - - // Stage 2 - [require.resolve('@babel/plugin-proposal-decorators'), { 'legacy': true }], - require.resolve('@babel/plugin-proposal-function-sent'), - require.resolve('@babel/plugin-proposal-export-namespace-from'), - require.resolve('@babel/plugin-proposal-numeric-separator'), - require.resolve('@babel/plugin-proposal-throw-expressions'), - - // Stage 3 - require.resolve('@babel/plugin-syntax-dynamic-import'), - require.resolve('@babel/plugin-syntax-import-meta'), - [require.resolve('@babel/plugin-proposal-class-properties'), { 'loose': false }], - require.resolve('@babel/plugin-proposal-json-strings'), - - [ - require.resolve('babel-plugin-module-resolver'), - { - 'root': ['.'], - 'extensions': ['.js', '.jsx', '.ts', '.tsx'], - 'alias': { - '#components': './src/components', - '#hooks': './src/hooks', - '#utils': './src/utils', - }, - }, - ], - ], - }; -}; diff --git a/.browserslistrc b/.browserslistrc index d927f315..aedd097c 100644 --- a/.browserslistrc +++ b/.browserslistrc @@ -1,2 +1,2 @@ # Support all browsers with more than 1% market share -> 1% +>= 1% diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..7ee88e2c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,148 @@ +media +postgres-data +redis-data + +production.env + +# Swap files +*.swp + +# Byte-compiled / optimized / DLL files +__pycache__ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env +build +develop-eggs +dist +downloads +eggs +.eggs +lib +lib64 +parts +sdist +var +*.egg-info +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov +.tox +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build + +# PyBuilder +target + +#Ipython Notebook +.ipynb_checkpoints + +# SASS cache +.sass-cache +media_test + +# Rope project settings +.ropeproject + + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules +jspm_packages + +# Typescript v1 declaration files +typings + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env* + +# Sensitive Deploy Files +deploy/eb/ + +# tox +./.tox + +# git +./.git diff --git a/.eslintrc.js b/.eslintrc.js index 3cbf51d7..c1f5a887 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -97,6 +97,10 @@ module.exports = { }], 'react/prop-types': 0, 'react/jsx-props-no-spreading': 0, + 'react/jsx-key': ['warn', { + checkFragmentShorthand: true, + checkKeyMustBeforeSpread: true, + }], // 'react/prop-types': [1, { ignore: [], customValidators: [], skipUndeclared: false }], 'react/no-unused-state': 'warn', 'react/require-default-props': ['warn', { diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..1a7f7ec3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,77 @@ +name: deep ui CI + +on: + pull_request: + push: + branches: + - master + +jobs: + build_test: + name: ๐Ÿšด Build + Lint + Test ๐Ÿšด # Match the name below (8398a7/action-slack). + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: ๐Ÿณ Prepare Docker + id: prep + run: | + TAG=$(echo $GITHUB_SHA | head -c7) + IMAGE="docker.pkg.github.com/the-deep/deep-ui" + echo ::set-output name=tagged_image::${IMAGE}:${TAG} + echo ::set-output name=tag::${TAG} + - name: ๐Ÿณ Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@master + + - name: ๐Ÿณ Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-single-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-single-buildx + + - name: ๐Ÿณ Build image + uses: docker/build-push-action@v2 + with: + context: . + builder: ${{ steps.buildx.outputs.name }} + file: Dockerfile + push: false # This would be set to true in a real world deployment scenario. + load: true + tags: ${{ steps.prep.outputs.tagged_image }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + + - name: ๐Ÿคž Run CSS Lint ๐Ÿงช + env: + DOCKER_IMAGE: ${{ steps.prep.outputs.tagged_image }} + run: | + docker run --rm --workdir="/code/" $DOCKER_IMAGE sh -c 'yarn css-lint' + + - name: ๐Ÿคž Run Lint ๐Ÿงช + env: + DOCKER_IMAGE: ${{ steps.prep.outputs.tagged_image }} + run: | + docker run --rm --workdir="/code/" $DOCKER_IMAGE sh -c 'yarn lint' + + - name: ๐Ÿคž Run Typecheck ๐Ÿงช + env: + DOCKER_IMAGE: ${{ steps.prep.outputs.tagged_image }} + run: | + docker run --rm --workdir="/code/" $DOCKER_IMAGE sh -c 'yarn typecheck' + + - name: ๐Ÿคž Run Build ๐Ÿงช + env: + DOCKER_IMAGE: ${{ steps.prep.outputs.tagged_image }} + run: | + docker run --rm --workdir="/code/" $DOCKER_IMAGE sh -c 'yarn build' + + # Temp fix + # https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md#github-cache + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: ๐Ÿณ Move docker cache (๐Ÿง™ Hack fix) + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.gitignore b/.gitignore index 0bb9e0d5..0f06345a 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ yarn-error.log* build-storybook.log* storybook-static/ + +stats.html diff --git a/.stylelintrc.json b/.stylelintrc.json index 7d7a6560..225de3ec 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1,8 +1,7 @@ { "plugins": [], "extends": [ - "stylelint-config-recommended", - "stylelint-config-concentric" + "stylelint-config-recommended" ], "rules": { "indentation": 4, diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..10a069ac --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM node:lts-alpine + +MAINTAINER togglecorp info@togglecorp.com + +RUN apk update\ + && apk add --no-cache git bash python3 g++ make + +WORKDIR /code + +COPY ./package.json ./yarn.lock /code/ +RUN yarn install --frozen-lockfile + +COPY . /code/ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..8d6ca978 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,8 @@ +version: '3.3' + +services: + js: + build: . + command: sh -c 'yarn install --frozen-lock && yarn watch' + volumes: + - .:/code diff --git a/package.json b/package.json index 19fc4745..c2fd3003 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "prepack": "yarn build", "watch": "rollup -c -w", "typecheck": "tsc", - "lint": "eslint --rule 'import/no-unresolved: 0' 'src/**/*.[tj]s?(x)'", + "lint": "eslint 'src/**/*.[tj]s?(x)' --ignore-pattern 'stories'", + "css-lint": "stylelint 'src/**/*.css' --config .stylelintrc.json", "storybook": "start-storybook -p 6006", "build-storybook": "build-storybook", "chromatic": "npx chromatic --exit-zero-on-changes" @@ -39,39 +40,28 @@ "react-router-dom": "^4.3.1" }, "dependencies": { - "@babel/runtime-corejs3": "^7.11.2", - "@tanem/svg-injector": "^10.1.12", - "@togglecorp/fujs": "^1.9.2-beta.0", - "@types/react-color": "^3.0.5", - "@types/requestidlecallback": "^0.3.1", - "d3-shape": "^2.1.0", + "@tanem/svg-injector": "^10.1.14", + "@togglecorp/fujs": "^1.9.2", + "@types/react-color": "^3.0.6", + "@types/requestidlecallback": "^0.3.4", + "d3-shape": "^3.0.1", "react-color": "^2.19.3", - "react-icons": "^4.2.0", - "react-zoom-pan-pinch": "^1.6.1", + "react-icons": "^4.3.1", + "react-zoom-pan-pinch": "^2.1.3", "resize-observer-polyfill": "^1.5.1" }, "devDependencies": { - "@babel/core": "^7.11.5", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/plugin-proposal-decorators": "^7.10.5", - "@babel/plugin-proposal-do-expressions": "^7.10.4", - "@babel/plugin-proposal-export-namespace-from": "^7.10.4", - "@babel/plugin-proposal-function-sent": "^7.10.4", - "@babel/plugin-proposal-json-strings": "^7.10.4", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", - "@babel/plugin-proposal-numeric-separator": "^7.10.4", - "@babel/plugin-proposal-optional-chaining": "^7.11.0", - "@babel/plugin-proposal-throw-expressions": "^7.10.4", + "@babel/core": "^7.16.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-transform-runtime": "^7.11.5", - "@babel/preset-env": "^7.11.5", - "@babel/preset-react": "^7.10.4", - "@babel/preset-typescript": "^7.10.4", + "@babel/plugin-transform-react-constant-elements": "^7.16.7", + "@babel/preset-env": "^7.16.7", + "@babel/preset-react": "^7.16.7", + "@babel/preset-typescript": "^7.16.7", "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-commonjs": "^15.0.0", + "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-eslint": "^8.0.1", "@rollup/plugin-image": "^2.1.1", - "@rollup/plugin-node-resolve": "^9.0.0", + "@rollup/plugin-node-resolve": "^13.1.2", "@storybook/addon-a11y": "^6.4.9", "@storybook/addon-actions": "^6.4.9", "@storybook/addon-essentials": "^6.4.9", @@ -79,47 +69,45 @@ "@storybook/client-api": "^6.4.9", "@storybook/node-logger": "^6.4.9", "@storybook/react": "^6.4.9", - "@types/d3-shape": "^2.0.0", - "@types/node": "^14.11.2", - "@types/react": "^16.9.49", - "@types/react-dom": "^16.9.8", - "@types/react-router-dom": "^5.1.5", - "@typescript-eslint/eslint-plugin": "^4.2.0", - "@typescript-eslint/parser": "^4.2.0", - "babel-loader": "^8.1.0", - "babel-plugin-dynamic-import-node": "^2.3.3", + "@types/d3-shape": "^3.0.2", + "@types/node": "^17.0.6", + "@types/react": "^17.0.38", + "@types/react-dom": "^17.0.11", + "@types/react-router-dom": "^5.3.2", + "@typescript-eslint/eslint-plugin": "^5.8.1", + "@typescript-eslint/parser": "^5.8.1", + "babel-loader": "^8.2.3", "babel-plugin-module-resolver": "^4.0.0", - "babel-plugin-polyfill-corejs3": "^0.0.5", - "chromatic": "^5.7.0", - "css-loader": "^4.2.2", - "eslint": "^7.9.0", - "eslint-config-airbnb": "^18.2.0", + "babel-plugin-polyfill-corejs3": "^0.5.0", + "chromatic": "^6.3.3", + "css-loader": "^6.5.1", + "eslint": "^8.6.0", + "eslint-config-airbnb": "^19.0.4", "eslint-import-resolver-babel-module": "^5.1.2", - "eslint-plugin-import": "^2.22.0", - "eslint-plugin-jsx-a11y": "^6.3.1", - "eslint-plugin-postcss-modules": "^1.2.0", - "eslint-plugin-react": "^7.20.6", - "eslint-plugin-react-hooks": "^4.1.2", - "eslint-plugin-storybook": "^0.5.3", + "eslint-plugin-import": "^2.25.4", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-postcss-modules": "^2.0.0", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-storybook": "^0.5.5", "install-peers-cli": "^2.2.0", "path": "^0.12.7", - "postcss-loader": "^3.0.0", - "postcss-nested": "^4.2.3", - "postcss-normalize": "^9.0.0", - "postcss-preset-env": "^6.7.0", - "react-is": "^16.13.1", - "rollup": "^2.26.8", - "rollup-plugin-eslint": "^7.0.0", + "postcss": "^8.4.5", + "postcss-loader": "^6.2.1", + "postcss-nested": "^5.0.6", + "postcss-normalize": "^10.0.1", + "postcss-preset-env": "^7.2.0", + "react-is": "^17.0.2", + "rollup": "^2.62.0", "rollup-plugin-filesize": "^9.0.2", - "rollup-plugin-postcss": "^3.1.8", + "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-progress": "^1.1.2", - "rollup-plugin-stylelint": "^1.0.0", + "rollup-plugin-visualizer": "^5.5.2", "storybook-addon-designs": "^6.2.0", "storybook-dark-mode": "^1.0.8", - "style-loader": "^1.2.1", - "stylelint": "^13.7.0", - "stylelint-config-concentric": "^2.0.2", - "stylelint-config-recommended": "^3.0.0", - "typescript": "^4.0.3" + "style-loader": "^3.3.1", + "stylelint": "^14.2.0", + "stylelint-config-recommended": "^6.0.0", + "typescript": "^4.5.4" } } diff --git a/rollup.config.js b/rollup.config.js index 1cb51d36..1c7484d1 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -4,8 +4,8 @@ import commonjs from '@rollup/plugin-commonjs'; import postcss from 'rollup-plugin-postcss'; import filesize from 'rollup-plugin-filesize'; // import autoprefixer from 'autoprefixer'; -import { eslint } from 'rollup-plugin-eslint'; -import stylelint from 'rollup-plugin-stylelint'; +import eslint from '@rollup/plugin-eslint'; +import { visualizer } from 'rollup-plugin-visualizer'; import image from '@rollup/plugin-image'; import postcssPresetEnv from 'postcss-preset-env'; @@ -17,7 +17,6 @@ import pkg from './package.json'; const INPUT_FILE_PATH = 'src/index.tsx'; const PLUGINS = [ - stylelint(), postcss({ extract: true, modules: { @@ -36,7 +35,8 @@ const PLUGINS = [ include: ['**/*.jsx', '**/*.js', '**/*.ts', '**/*.tsx'], }), babel({ - babelHelpers: 'runtime', + // babelHelpers: 'runtime', + babelHelpers: 'bundled', exclude: 'node_modules/**', extensions: ['.jsx', '.js', '.ts', '.tsx'], }), @@ -45,8 +45,9 @@ const PLUGINS = [ extensions: ['.jsx', '.js', '.ts', '.tsx'], }), commonjs(), - filesize(), image(), + filesize(), + visualizer({ template: 'sunburst' }), ]; const OUTPUT_DATA = [ diff --git a/src/components/Actions/index.tsx b/src/components/Actions/index.tsx index 0688ae1d..a8c2e4ca 100644 --- a/src/components/Actions/index.tsx +++ b/src/components/Actions/index.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { _cs } from '@togglecorp/fujs'; import { SpacingTypes } from '../../types'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; const spacingToStyleMap: { @@ -45,4 +46,4 @@ function Actions(props: Props) { ); } -export default Actions; +export default genericMemo(Actions); diff --git a/src/components/Alert/index.tsx b/src/components/Alert/index.tsx index f6f6e049..c1b8e8b1 100644 --- a/src/components/Alert/index.tsx +++ b/src/components/Alert/index.tsx @@ -77,7 +77,6 @@ function Alert(props: Props) { } = props; const alertElementRef = React.useRef(null); - const hideTimeout = React.useRef(); const [hidden, setHidden] = React.useState(false); React.useEffect(() => { @@ -92,10 +91,10 @@ function Alert(props: Props) { }, []); React.useEffect(() => { - window.clearTimeout(hideTimeout.current); + let hideTimeoutId: number | undefined; if (duration > 0 && duration !== Infinity) { - hideTimeout.current = window.setTimeout(() => { + hideTimeoutId = window.setTimeout(() => { setHidden(true); if (onTimeout) { onTimeout(name, TRANSITION_DURATION); @@ -104,7 +103,9 @@ function Alert(props: Props) { } return () => { - window.clearTimeout(hideTimeout.current); + if (hideTimeoutId) { + window.clearTimeout(hideTimeoutId); + } }; }, [duration, setHidden, onTimeout, name]); diff --git a/src/components/AutoSizeTextArea/index.tsx b/src/components/AutoSizeTextArea/index.tsx index 5b010f52..b3e2087e 100644 --- a/src/components/AutoSizeTextArea/index.tsx +++ b/src/components/AutoSizeTextArea/index.tsx @@ -1,5 +1,6 @@ import React, { useLayoutEffect, useRef, useState } from 'react'; import { _cs } from '@togglecorp/fujs'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; @@ -67,4 +68,4 @@ function AutoSizeTextArea(props: AutoSizeTextAreaProps) { ); } -export default AutoSizeTextArea; +export default genericMemo(AutoSizeTextArea); diff --git a/src/components/BodyBackdrop/index.tsx b/src/components/BodyBackdrop/index.tsx index bfb70bea..1a860d9b 100644 --- a/src/components/BodyBackdrop/index.tsx +++ b/src/components/BodyBackdrop/index.tsx @@ -1,6 +1,8 @@ import React from 'react'; import { _cs } from '@togglecorp/fujs'; +import { genericMemo } from '../../utils'; + import Portal from '../Portal'; import styles from './styles.css'; @@ -25,4 +27,4 @@ function BodyBackdrop(props: Props) { ); } -export default BodyBackdrop; +export default genericMemo(BodyBackdrop); diff --git a/src/components/Card/index.tsx b/src/components/Card/index.tsx index f837131d..a8da3b45 100644 --- a/src/components/Card/index.tsx +++ b/src/components/Card/index.tsx @@ -1,6 +1,8 @@ import React from 'react'; import { _cs } from '@togglecorp/fujs'; +import { genericMemo } from '../../utils'; + import styles from './styles.css'; export interface Props { @@ -26,4 +28,4 @@ function Card(props: Props) { ); } -export default Card; +export default genericMemo(Card); diff --git a/src/components/CheckListInput/index.tsx b/src/components/CheckListInput/index.tsx index 975be918..3f760c40 100644 --- a/src/components/CheckListInput/index.tsx +++ b/src/components/CheckListInput/index.tsx @@ -7,7 +7,7 @@ import InputError from '../InputError'; import InputHint from '../InputHint'; import List from '../List'; import Checkbox from '../Checkbox'; - +import { genericMemo } from '../../utils'; import { SpacingTypes } from '../../types'; import styles from './styles.css'; @@ -145,4 +145,4 @@ function CheckListInput< ); } -export default CheckListInput; +export default genericMemo(CheckListInput); diff --git a/src/components/Checkbox/index.tsx b/src/components/Checkbox/index.tsx index 7c138f66..eff1e02c 100644 --- a/src/components/Checkbox/index.tsx +++ b/src/components/Checkbox/index.tsx @@ -1,6 +1,7 @@ import React, { useCallback } from 'react'; import { _cs } from '@togglecorp/fujs'; +import { genericMemo } from '../../utils'; import useUiModeClassName from '../../hooks/useUiModeClassName'; import { UiMode } from '../UiModeContext'; @@ -105,4 +106,4 @@ function Checkbox(props: Props) { ); } -export default Checkbox; +export default genericMemo(Checkbox); diff --git a/src/components/CollapsibleContainer/index.tsx b/src/components/CollapsibleContainer/index.tsx index e13f9ab5..3ca30b7b 100644 --- a/src/components/CollapsibleContainer/index.tsx +++ b/src/components/CollapsibleContainer/index.tsx @@ -10,6 +10,7 @@ import Container, { Props as ContainerProps } from '../Container'; import Button from '../Button'; import QuickActionButton from '../QuickActionButton'; import useBooleanState from '../../hooks/useBooleanState'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; @@ -92,4 +93,4 @@ function CollapsibleContainer(props: Props) { ); } -export default CollapsibleContainer; +export default genericMemo(CollapsibleContainer); diff --git a/src/components/ColorInput/index.tsx b/src/components/ColorInput/index.tsx index 17d3758c..d37a2416 100644 --- a/src/components/ColorInput/index.tsx +++ b/src/components/ColorInput/index.tsx @@ -6,6 +6,7 @@ import { } from 'react-color'; import { useDropdownFeatures } from '../DropdownMenu'; +import { genericMemo } from '../../utils'; import RawButton from '../RawButton'; import Popup from '../Popup'; @@ -70,4 +71,4 @@ function ColorInput(props: Props) { ); } -export default ColorInput; +export default genericMemo(ColorInput); diff --git a/src/components/CompactInformationCard/index.tsx b/src/components/CompactInformationCard/index.tsx index 56740812..20ca1819 100644 --- a/src/components/CompactInformationCard/index.tsx +++ b/src/components/CompactInformationCard/index.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { _cs } from '@togglecorp/fujs'; import NumberOutput from '../NumberOutput'; +import { genericMemo } from '../../utils'; import { SpacingTypes } from '../../types'; import styles from './styles.css'; @@ -59,4 +60,4 @@ function CompactInformationCard(props: Props) { ); } -export default CompactInformationCard; +export default genericMemo(CompactInformationCard); diff --git a/src/components/Container/index.tsx b/src/components/Container/index.tsx index d24818a7..de085f1e 100644 --- a/src/components/Container/index.tsx +++ b/src/components/Container/index.tsx @@ -5,6 +5,7 @@ import Header, { Props as HeaderProps } from '../Header'; import Footer from '../Footer'; import Border, { Props as BorderProps } from '../Border'; import { SpacingTypes } from '../../types'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; @@ -179,4 +180,4 @@ function Container(props: Props) { ); } -export default Container; +export default genericMemo(Container); diff --git a/src/components/ContainerCard/index.tsx b/src/components/ContainerCard/index.tsx index e2a180cb..867a49bd 100644 --- a/src/components/ContainerCard/index.tsx +++ b/src/components/ContainerCard/index.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { _cs } from '@togglecorp/fujs'; import Container, { Props as ContainerProps } from '../Container'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; @@ -23,4 +24,4 @@ function ContainerCard(props: Props) { ); } -export default ContainerCard; +export default genericMemo(ContainerCard); diff --git a/src/components/ControlledExpandableContainer/index.tsx b/src/components/ControlledExpandableContainer/index.tsx index de6ad642..058f8db9 100644 --- a/src/components/ControlledExpandableContainer/index.tsx +++ b/src/components/ControlledExpandableContainer/index.tsx @@ -8,6 +8,7 @@ import { import { SpacingTypes } from '../../types'; import Container, { Props as ContainerProps } from '../Container'; import Button from '../Button'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; @@ -124,4 +125,4 @@ function ControlledExpandableContainer(props: Props) { ); } -export default ControlledExpandableContainer; +export default genericMemo(ControlledExpandableContainer); diff --git a/src/components/Cover/index.tsx b/src/components/Cover/index.tsx index 54b7234e..5ac7d0df 100644 --- a/src/components/Cover/index.tsx +++ b/src/components/Cover/index.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { _cs } from '@togglecorp/fujs'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; interface Props { @@ -50,4 +51,4 @@ function Cover(props: Props) { ); } -export default Cover; +export default genericMemo(Cover); diff --git a/src/components/DateInput/index.tsx b/src/components/DateInput/index.tsx index 6b3a715e..ba3a8099 100644 --- a/src/components/DateInput/index.tsx +++ b/src/components/DateInput/index.tsx @@ -17,7 +17,7 @@ import Button from '../Button'; import Popup from '../Popup'; import Calendar, { Props as CalendarProps } from '../Calendar'; import { Props as CalendarDateProps } from '../Calendar/CalendarDate'; -import { ymdToDateString } from '../../utils'; +import { genericMemo, ymdToDateString } from '../../utils'; import styles from './styles.css'; @@ -208,4 +208,4 @@ function DateInput(props: Props) { ); } -export default DateInput; +export default genericMemo(DateInput); diff --git a/src/components/DateRangeDualInput/index.tsx b/src/components/DateRangeDualInput/index.tsx index 3715729b..bfc4d8d5 100644 --- a/src/components/DateRangeDualInput/index.tsx +++ b/src/components/DateRangeDualInput/index.tsx @@ -7,6 +7,7 @@ import DateRangeInput, { Props as DateRangeInputProps, Value as DateRangeInputValue, } from '../DateRangeInput'; +import { genericMemo } from '../../utils'; type DateRangeProps = Omit, 'onChange' | 'name' | 'value'>; @@ -75,4 +76,4 @@ function DateRangeDualInput(props: Props< ); } -export default DateRangeDualInput; +export default genericMemo(DateRangeDualInput); diff --git a/src/components/DateRangeInput/index.tsx b/src/components/DateRangeInput/index.tsx index 7686d639..1b6e50bd 100644 --- a/src/components/DateRangeInput/index.tsx +++ b/src/components/DateRangeInput/index.tsx @@ -19,7 +19,7 @@ import Button from '../Button'; import Popup from '../Popup'; import Calendar, { Props as CalendarProps } from '../Calendar'; import CalendarDate, { Props as CalendarDateProps } from '../Calendar/CalendarDate'; -import { ymdToDateString, dateStringToDate } from '../../utils'; +import { ymdToDateString, dateStringToDate, genericMemo } from '../../utils'; import { predefinedDateRangeOptions, @@ -47,7 +47,7 @@ interface DateRendererProps extends CalendarDateProps { endDate?: string; } -const DateRenderer = (props: DateRendererProps) => { +function DateRenderer(props: DateRendererProps) { const { className: dateClassName, year, @@ -87,7 +87,7 @@ const DateRenderer = (props: DateRendererProps) => { ghost={ghost} /> ); -}; +} type NameType = string | number | undefined; @@ -421,4 +421,4 @@ function DateRangeInput(props: Props) { ); } -export default DateRangeInput; +export default genericMemo(DateRangeInput); diff --git a/src/components/DismissibleList/index.tsx b/src/components/DismissibleList/index.tsx index 43801164..d2d8b958 100644 --- a/src/components/DismissibleList/index.tsx +++ b/src/components/DismissibleList/index.tsx @@ -3,6 +3,7 @@ import { _cs } from '@togglecorp/fujs'; import { IoClose } from 'react-icons/io5'; import ListView from '../ListView'; +import { genericMemo } from '../../utils'; import Button, { Props as ButtonProps } from '../Button'; import styles from './styles.css'; @@ -128,4 +129,4 @@ function DismissibleList(props: Prop /> ); } -export default DismissibleList; +export default genericMemo(DismissibleList); diff --git a/src/components/DraggableContent/index.tsx b/src/components/DraggableContent/index.tsx index 97151de3..cb00abea 100644 --- a/src/components/DraggableContent/index.tsx +++ b/src/components/DraggableContent/index.tsx @@ -3,6 +3,7 @@ import { _cs } from '@togglecorp/fujs'; import { GrDrag } from 'react-icons/gr'; import Container, { Props as ContainerProps } from '../Container'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; @@ -97,4 +98,4 @@ function DraggableContent(props: Props) { ); } -export default DraggableContent; +export default genericMemo(DraggableContent); diff --git a/src/components/DropContainer/index.tsx b/src/components/DropContainer/index.tsx index b41409b3..86042e83 100644 --- a/src/components/DropContainer/index.tsx +++ b/src/components/DropContainer/index.tsx @@ -7,6 +7,7 @@ import type { Props as DraggableContentProps, SerializableValue, } from '../DraggableContent'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; @@ -107,4 +108,4 @@ function DropContainer(props: Props) { ); } -export default DropContainer; +export default genericMemo(DropContainer); diff --git a/src/components/DropdownMenuItem/index.tsx b/src/components/DropdownMenuItem/index.tsx index 58351e17..8dada50a 100644 --- a/src/components/DropdownMenuItem/index.tsx +++ b/src/components/DropdownMenuItem/index.tsx @@ -30,6 +30,7 @@ const spacingToStyleMap: { loose: styles.looseSpacing, }; +// FIXME: remove this (only used in stories) export function Separator({ className }: { className?: string }) { return (
@@ -59,6 +60,7 @@ function DropdownMenuItem(props: Props childrenContainerClassName, actionsContainerClassName, spacing = 'comfortable', + href, } = props; const className = _cs( @@ -79,17 +81,16 @@ function DropdownMenuItem(props: Props ); - // eslint-disable-next-line react/destructuring-assignment - if (props.href !== undefined) { - const isExternalLink = props.href - && typeof props.href === 'string' - && (isValidUrl(props.href) || props.href.startsWith('mailto:')); + if (href !== undefined) { + const isExternalLink = href + && typeof href === 'string' + && (isValidUrl(href) || href.startsWith('mailto:')); if (isExternalLink) { return ( @@ -101,7 +102,7 @@ function DropdownMenuItem(props: Props return ( {children} diff --git a/src/components/Element/index.tsx b/src/components/Element/index.tsx index c6844671..c9e29adb 100644 --- a/src/components/Element/index.tsx +++ b/src/components/Element/index.tsx @@ -6,6 +6,7 @@ import ElementFragments, { } from '../ElementFragments'; import { SpacingTypes } from '../../types'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; const spacingToStyleMap: { @@ -50,4 +51,4 @@ function Element(props: Props) { ); } -export default Element; +export default genericMemo(Element); diff --git a/src/components/ElementFragments/index.tsx b/src/components/ElementFragments/index.tsx index f0e76457..f5abc778 100644 --- a/src/components/ElementFragments/index.tsx +++ b/src/components/ElementFragments/index.tsx @@ -3,7 +3,7 @@ import { _cs } from '@togglecorp/fujs'; import Icons from '../Icons'; import Actions from '../Actions'; - +import { genericMemo } from '../../utils'; import { SpacingTypes } from '../../types'; import styles from './styles.css'; @@ -82,4 +82,4 @@ function ElementFragments(props: Props) { ); } -export default ElementFragments; +export default genericMemo(ElementFragments); diff --git a/src/components/ExpandableContainer/index.tsx b/src/components/ExpandableContainer/index.tsx index 25b175fb..7f52720d 100644 --- a/src/components/ExpandableContainer/index.tsx +++ b/src/components/ExpandableContainer/index.tsx @@ -3,6 +3,7 @@ import React, { useState } from 'react'; import ControlledExpandableContainer, { Props as ControlledExpandableContainerProps, } from '../ControlledExpandableContainer'; +import { genericMemo } from '../../utils'; export interface Props extends Omit, 'expanded' | 'onExpansionChange' | 'name'>{ defaultVisibility?: boolean; @@ -26,4 +27,4 @@ function ExpandableContainer(props: Props) { ); } -export default ExpandableContainer; +export default genericMemo(ExpandableContainer); diff --git a/src/components/FileInput/index.tsx b/src/components/FileInput/index.tsx index 9720b66b..7a491b87 100644 --- a/src/components/FileInput/index.tsx +++ b/src/components/FileInput/index.tsx @@ -7,6 +7,7 @@ import InputContainer, { Props as InputContainerProps } from '../InputContainer' import RawInput, { Props as RawInputProps } from '../RawInput'; import Button, { useButtonFeatures } from '../Button'; import useDropHandler from '../../hooks/useDropHandler'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; export const isValidFile = (fileName: string, mimeType: string, acceptString?: string) => { @@ -88,6 +89,7 @@ function FileInput(props: Props) { const handleFiles = useCallback( (files: FileList | null) => { + // eslint-disable-next-line react/destructuring-assignment if (!files || !props.onChange) { return; } @@ -98,11 +100,14 @@ function FileInput(props: Props) { return; } + // eslint-disable-next-line react/destructuring-assignment if (!props.multiple) { const [firstFile] = validFiles; + // eslint-disable-next-line react/destructuring-assignment const onChangeFromProps = props.onChange; onChangeFromProps(firstFile, name); } else { + // eslint-disable-next-line react/destructuring-assignment const onChangeFromProps = props.onChange; onChangeFromProps(validFiles, name); } @@ -165,14 +170,17 @@ function FileInput(props: Props) { const handleClear = useCallback( () => { + // eslint-disable-next-line react/destructuring-assignment if (!props.onChange) { return; } - + // eslint-disable-next-line react/destructuring-assignment if (props.multiple) { + // eslint-disable-next-line react/destructuring-assignment const onChangeFromProps = props.onChange; onChangeFromProps([], name); } else { + // eslint-disable-next-line react/destructuring-assignment const onChangeFromProps = props.onChange; onChangeFromProps(undefined, name); } @@ -190,11 +198,14 @@ function FileInput(props: Props) { const status = useMemo( () => { + // eslint-disable-next-line react/destructuring-assignment if (!props.multiple) { + // eslint-disable-next-line react/destructuring-assignment const singleFile = props.value; return singleFile ? singleFile.name : 'No file chosen'; } + // eslint-disable-next-line react/destructuring-assignment const multipleFile = props.value; if (!multipleFile || multipleFile.length === 0) { return 'No file chosen'; @@ -285,4 +296,4 @@ function FileInput(props: Props) { ); } -export default FileInput; +export default genericMemo(FileInput); diff --git a/src/components/Footer/index.tsx b/src/components/Footer/index.tsx index d05ea946..52a884d6 100644 --- a/src/components/Footer/index.tsx +++ b/src/components/Footer/index.tsx @@ -3,6 +3,7 @@ import { _cs } from '@togglecorp/fujs'; import ElementFragments from '../ElementFragments'; import QuickActionGroup from '../QuickActionGroup'; +import { genericMemo } from '../../utils'; import { SpacingTypes } from '../../types'; import styles from './styles.css'; @@ -76,4 +77,4 @@ function Footer(props: Props) { ); } -export default Footer; +export default genericMemo(Footer); diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx index 12730028..427b8d28 100644 --- a/src/components/Header/index.tsx +++ b/src/components/Header/index.tsx @@ -4,6 +4,7 @@ import { _cs } from '@togglecorp/fujs'; import Element from '../Element'; import Heading, { Props as HeadingProps } from '../Heading'; import { SpacingTypes } from '../../types'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; @@ -114,4 +115,4 @@ function Header(props: Props) { ); } -export default Header; +export default genericMemo(Header); diff --git a/src/components/Heading/index.tsx b/src/components/Heading/index.tsx index fbc4d7cc..23902cf0 100644 --- a/src/components/Heading/index.tsx +++ b/src/components/Heading/index.tsx @@ -3,6 +3,7 @@ import { _cs, isNotDefined, } from '@togglecorp/fujs'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; @@ -122,4 +123,4 @@ function Heading(props: Props) { return heading; } -export default Heading; +export default genericMemo(Heading); diff --git a/src/components/Icons/index.tsx b/src/components/Icons/index.tsx index ff286c87..fb816c80 100644 --- a/src/components/Icons/index.tsx +++ b/src/components/Icons/index.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { _cs } from '@togglecorp/fujs'; import { SpacingTypes } from '../../types'; +import { genericMemo } from '../../utils'; import styles from './styles.css'; const spacingToStyleMap: { @@ -45,4 +46,4 @@ function Icons(props: Props) { ); } -export default Icons; +export default genericMemo(Icons); diff --git a/src/components/ImagePreview/index.tsx b/src/components/ImagePreview/index.tsx index e91b0289..485e8dc5 100644 --- a/src/components/ImagePreview/index.tsx +++ b/src/components/ImagePreview/index.tsx @@ -20,7 +20,6 @@ import useBooleanState from '../../hooks/useBooleanState'; import styles from './styles.css'; -type ButtonClickHandler = React.HTMLProps['onClick']; type HTMLImageProps = React.HTMLProps; export interface Props { @@ -66,23 +65,23 @@ function ImagePreview(props: Props) { > {pending && } {({ zoomIn, zoomOut, resetTransform, - }: { - zoomIn: ButtonClickHandler, - zoomOut: ButtonClickHandler, - resetTransform: ButtonClickHandler, }) => ( <> {!hideTools && (
)} - + - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/coffee.svg b/src/components/Kraken/images/coffee.svg old mode 100755 new mode 100644 index ed0bdbf1..93412a33 --- a/src/components/Kraken/images/coffee.svg +++ b/src/components/Kraken/images/coffee.svg @@ -1,106 +1 @@ - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/exercise.svg b/src/components/Kraken/images/exercise.svg index 55f0ad8e..0283e1e1 100644 --- a/src/components/Kraken/images/exercise.svg +++ b/src/components/Kraken/images/exercise.svg @@ -1,116 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/experiment.svg b/src/components/Kraken/images/experiment.svg index 5c8802dc..e4b83297 100644 --- a/src/components/Kraken/images/experiment.svg +++ b/src/components/Kraken/images/experiment.svg @@ -1,126 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/fat.svg b/src/components/Kraken/images/fat.svg old mode 100755 new mode 100644 index 4fd3ee6e..da7f2579 --- a/src/components/Kraken/images/fat.svg +++ b/src/components/Kraken/images/fat.svg @@ -1,113 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/hi.svg b/src/components/Kraken/images/hi.svg index dd108225..4abb3f8a 100644 --- a/src/components/Kraken/images/hi.svg +++ b/src/components/Kraken/images/hi.svg @@ -1,100 +1 @@ - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/move.svg b/src/components/Kraken/images/move.svg old mode 100755 new mode 100644 index 0465e2c6..f4f80799 --- a/src/components/Kraken/images/move.svg +++ b/src/components/Kraken/images/move.svg @@ -1,98 +1 @@ - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/read.svg b/src/components/Kraken/images/read.svg old mode 100755 new mode 100644 index 7324217e..b0894780 --- a/src/components/Kraken/images/read.svg +++ b/src/components/Kraken/images/read.svg @@ -1,94 +1 @@ - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/search.svg b/src/components/Kraken/images/search.svg index 13678d3e..3dd8ad37 100644 --- a/src/components/Kraken/images/search.svg +++ b/src/components/Kraken/images/search.svg @@ -1,139 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/sing.svg b/src/components/Kraken/images/sing.svg old mode 100755 new mode 100644 index d9605eb2..9001b312 --- a/src/components/Kraken/images/sing.svg +++ b/src/components/Kraken/images/sing.svg @@ -1,116 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/skate.svg b/src/components/Kraken/images/skate.svg old mode 100755 new mode 100644 index d806392e..8eaab35c --- a/src/components/Kraken/images/skate.svg +++ b/src/components/Kraken/images/skate.svg @@ -1,106 +1 @@ - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/skydive.svg b/src/components/Kraken/images/skydive.svg index 7b51c5a2..4454eef0 100644 --- a/src/components/Kraken/images/skydive.svg +++ b/src/components/Kraken/images/skydive.svg @@ -1,116 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/sleep.svg b/src/components/Kraken/images/sleep.svg old mode 100755 new mode 100644 index 7bcafade..221ddb1e --- a/src/components/Kraken/images/sleep.svg +++ b/src/components/Kraken/images/sleep.svg @@ -1,149 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/standby.svg b/src/components/Kraken/images/standby.svg old mode 100755 new mode 100644 index 8059e786..fd4300d5 --- a/src/components/Kraken/images/standby.svg +++ b/src/components/Kraken/images/standby.svg @@ -1,81 +1 @@ - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/whip.svg b/src/components/Kraken/images/whip.svg old mode 100755 new mode 100644 index ed9e45d5..f25c0109 --- a/src/components/Kraken/images/whip.svg +++ b/src/components/Kraken/images/whip.svg @@ -1,116 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/images/work.svg b/src/components/Kraken/images/work.svg index 0e3076a8..7ea1a8e2 100644 --- a/src/components/Kraken/images/work.svg +++ b/src/components/Kraken/images/work.svg @@ -1,110 +1 @@ - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/src/components/Kraken/index.tsx b/src/components/Kraken/index.tsx index 2276d45a..a6f0a56b 100644 --- a/src/components/Kraken/index.tsx +++ b/src/components/Kraken/index.tsx @@ -2,6 +2,8 @@ import React from 'react'; import { _cs } from '@togglecorp/fujs'; import Svg from '../Svg'; +import { genericMemo } from '../../utils'; + import ballonSvg from './images/ballon.svg'; import hiSvg from './images/hi.svg'; import workSvg from './images/work.svg'; @@ -82,4 +84,4 @@ function Kraken(props: Props) { ); } -export default Kraken; +export default genericMemo(Kraken); diff --git a/src/components/List.tsx b/src/components/List.tsx index 18152713..7edac80f 100644 --- a/src/components/List.tsx +++ b/src/components/List.tsx @@ -166,6 +166,7 @@ function GroupedList {children} diff --git a/src/components/ListView/index.tsx b/src/components/ListView/index.tsx index 8bc3cebb..86bdfdcc 100644 --- a/src/components/ListView/index.tsx +++ b/src/components/ListView/index.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { _cs } from '@togglecorp/fujs'; +import { genericMemo } from '../../utils'; import List, { Props as ListProps, OptionKey, @@ -125,4 +126,4 @@ function ListView< ); } -export default ListView; +export default genericMemo(ListView); diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx index c7c59f4b..949a97c5 100644 --- a/src/components/Modal/index.tsx +++ b/src/components/Modal/index.tsx @@ -3,6 +3,7 @@ import { _cs } from '@togglecorp/fujs'; import { IoClose } from 'react-icons/io5'; import Header, { Props as HeaderProps } from '../Header'; +import { genericMemo } from '../../utils'; import Footer from '../Footer'; import Button from '../Button'; import BodyBackdrop from '../BodyBackdrop'; @@ -141,6 +142,8 @@ function Modal(props: Props) { !props.hideCloseButton && (