Add TypeScript support for React components

This commit is contained in:
MrTimscampi 2021-06-11 14:49:57 +02:00
parent 0dde17fbd7
commit 4d23e79f65
16 changed files with 810 additions and 107 deletions

View file

@ -61,12 +61,22 @@ module.exports = {
settings: {
react: {
version: 'detect'
},
'import/extensions': [
'.js',
'.ts',
'.jsx',
'.tsx'
],
'import/parsers': {
'@typescript-eslint/parser': [ '.ts', '.tsx' ]
}
},
overrides: [
{
files: [
'./src/**/*.js'
'./src/**/*.js',
'./src/**/*.ts'
],
parser: '@babel/eslint-parser',
env: {
@ -197,6 +207,23 @@ module.exports = {
'document.querySelector'
]
}
},
{
files: [
'./src/**/*.ts',
'./src/**/*.tsx'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:import/typescript',
'plugin:@typescript-eslint/recommended',
'plugin:eslint-comments/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended'
]
}
]
};

View file

@ -12,7 +12,14 @@ module.exports = {
corejs: 3
}
],
'@babel/preset-react'
'@babel/preset-react',
[
'@babel/preset-typescript',
{
isTSX: true,
allExtensions: true
}
]
],
plugins: [
'@babel/plugin-proposal-class-properties',

576
package-lock.json generated
View file

@ -1387,6 +1387,23 @@
"@babel/helper-plugin-utils": "^7.14.5"
}
},
"@babel/plugin-syntax-typescript": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz",
"integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.14.5"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz",
"integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==",
"dev": true
}
}
},
"@babel/plugin-transform-arrow-functions": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz",
@ -2030,6 +2047,197 @@
"@babel/helper-plugin-utils": "^7.14.5"
}
},
"@babel/plugin-transform-typescript": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.14.5.tgz",
"integrity": "sha512-cFD5PKp4b8/KkwQ7h71FdPXFvz1RgwTFF9akRZwFldb9G0AHf7CgoPx96c4Q/ZVjh6V81tqQwW5YiHws16OzPg==",
"dev": true,
"requires": {
"@babel/helper-create-class-features-plugin": "^7.14.5",
"@babel/helper-plugin-utils": "^7.14.5",
"@babel/plugin-syntax-typescript": "^7.14.5"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
"integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==",
"dev": true,
"requires": {
"@babel/highlight": "^7.14.5"
}
},
"@babel/generator": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz",
"integrity": "sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==",
"dev": true,
"requires": {
"@babel/types": "^7.14.5",
"jsesc": "^2.5.1",
"source-map": "^0.5.0"
}
},
"@babel/helper-annotate-as-pure": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz",
"integrity": "sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==",
"dev": true,
"requires": {
"@babel/types": "^7.14.5"
}
},
"@babel/helper-create-class-features-plugin": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.5.tgz",
"integrity": "sha512-Uq9z2e7ZtcnDMirRqAGLRaLwJn+Lrh388v5ETrR3pALJnElVh2zqQmdbz4W2RUJYohAPh2mtyPUgyMHMzXMncQ==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.14.5",
"@babel/helper-function-name": "^7.14.5",
"@babel/helper-member-expression-to-functions": "^7.14.5",
"@babel/helper-optimise-call-expression": "^7.14.5",
"@babel/helper-replace-supers": "^7.14.5",
"@babel/helper-split-export-declaration": "^7.14.5"
}
},
"@babel/helper-function-name": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz",
"integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.14.5",
"@babel/template": "^7.14.5",
"@babel/types": "^7.14.5"
}
},
"@babel/helper-get-function-arity": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz",
"integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==",
"dev": true,
"requires": {
"@babel/types": "^7.14.5"
}
},
"@babel/helper-hoist-variables": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz",
"integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==",
"dev": true,
"requires": {
"@babel/types": "^7.14.5"
}
},
"@babel/helper-member-expression-to-functions": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.5.tgz",
"integrity": "sha512-UxUeEYPrqH1Q/k0yRku1JE7dyfyehNwT6SVkMHvYvPDv4+uu627VXBckVj891BO8ruKBkiDoGnZf4qPDD8abDQ==",
"dev": true,
"requires": {
"@babel/types": "^7.14.5"
}
},
"@babel/helper-optimise-call-expression": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz",
"integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==",
"dev": true,
"requires": {
"@babel/types": "^7.14.5"
}
},
"@babel/helper-plugin-utils": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz",
"integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==",
"dev": true
},
"@babel/helper-replace-supers": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz",
"integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==",
"dev": true,
"requires": {
"@babel/helper-member-expression-to-functions": "^7.14.5",
"@babel/helper-optimise-call-expression": "^7.14.5",
"@babel/traverse": "^7.14.5",
"@babel/types": "^7.14.5"
}
},
"@babel/helper-split-export-declaration": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz",
"integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==",
"dev": true,
"requires": {
"@babel/types": "^7.14.5"
}
},
"@babel/helper-validator-identifier": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
"integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
"dev": true
},
"@babel/highlight": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
"integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.14.5",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.5.tgz",
"integrity": "sha512-TM8C+xtH/9n1qzX+JNHi7AN2zHMTiPUtspO0ZdHflW8KaskkALhMmuMHb4bCmNdv9VAPzJX3/bXqkVLnAvsPfg==",
"dev": true
},
"@babel/template": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz",
"integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.14.5",
"@babel/parser": "^7.14.5",
"@babel/types": "^7.14.5"
}
},
"@babel/traverse": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.5.tgz",
"integrity": "sha512-G3BiS15vevepdmFqmUc9X+64y0viZYygubAMO8SvBmKARuF6CPSZtH4Ng9vi/lrWlZFGe3FWdXNy835akH8Glg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.14.5",
"@babel/generator": "^7.14.5",
"@babel/helper-function-name": "^7.14.5",
"@babel/helper-hoist-variables": "^7.14.5",
"@babel/helper-split-export-declaration": "^7.14.5",
"@babel/parser": "^7.14.5",
"@babel/types": "^7.14.5",
"debug": "^4.1.0",
"globals": "^11.1.0"
}
},
"@babel/types": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz",
"integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.14.5",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/plugin-transform-unicode-escapes": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz",
@ -2189,6 +2397,31 @@
}
}
},
"@babel/preset-typescript": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.14.5.tgz",
"integrity": "sha512-u4zO6CdbRKbS9TypMqrlGH7sd2TAJppZwn3c/ZRLeO/wGsbddxgbPDUZVNrie3JWYLQ9vpineKlsrWFvO6Pwkw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.14.5",
"@babel/helper-validator-option": "^7.14.5",
"@babel/plugin-transform-typescript": "^7.14.5"
},
"dependencies": {
"@babel/helper-plugin-utils": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz",
"integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==",
"dev": true
},
"@babel/helper-validator-option": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz",
"integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==",
"dev": true
}
}
},
"@babel/runtime": {
"version": "7.13.10",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz",
@ -2198,6 +2431,16 @@
"regenerator-runtime": "^0.13.4"
}
},
"@babel/runtime-corejs3": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.5.tgz",
"integrity": "sha512-cBbwXj3F2xjnQJ0ERaFRLjxhUSBYsQPXJ7CERz/ecx6q6hzQ99eTflAPFC3ks4q/IG4CWupNVdflc4jlFBJVsg==",
"dev": true,
"requires": {
"core-js-pure": "^3.14.0",
"regenerator-runtime": "^0.13.4"
}
},
"@babel/template": {
"version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz",
@ -2791,6 +3034,156 @@
}
}
},
"@typescript-eslint/eslint-plugin": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.26.1.tgz",
"integrity": "sha512-aoIusj/8CR+xDWmZxARivZjbMBQTT9dImUtdZ8tVCVRXgBUuuZyM5Of5A9D9arQPxbi/0rlJLcuArclz/rCMJw==",
"dev": true,
"requires": {
"@typescript-eslint/experimental-utils": "4.26.1",
"@typescript-eslint/scope-manager": "4.26.1",
"debug": "^4.3.1",
"functional-red-black-tree": "^1.0.1",
"lodash": "^4.17.21",
"regexpp": "^3.1.0",
"semver": "^7.3.5",
"tsutils": "^3.21.0"
},
"dependencies": {
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
}
}
},
"@typescript-eslint/experimental-utils": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.26.1.tgz",
"integrity": "sha512-sQHBugRhrXzRCs9PaGg6rowie4i8s/iD/DpTB+EXte8OMDfdCG5TvO73XlO9Wc/zi0uyN4qOmX9hIjQEyhnbmQ==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.7",
"@typescript-eslint/scope-manager": "4.26.1",
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/typescript-estree": "4.26.1",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0"
},
"dependencies": {
"eslint-utils": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
"integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
"dev": true,
"requires": {
"eslint-visitor-keys": "^2.0.0"
}
},
"eslint-visitor-keys": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
"dev": true
}
}
},
"@typescript-eslint/parser": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.26.1.tgz",
"integrity": "sha512-q7F3zSo/nU6YJpPJvQveVlIIzx9/wu75lr6oDbDzoeIRWxpoc/HQ43G4rmMoCc5my/3uSj2VEpg/D83LYZF5HQ==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "4.26.1",
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/typescript-estree": "4.26.1",
"debug": "^4.3.1"
}
},
"@typescript-eslint/scope-manager": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.26.1.tgz",
"integrity": "sha512-TW1X2p62FQ8Rlne+WEShyd7ac2LA6o27S9i131W4NwDSfyeVlQWhw8ylldNNS8JG6oJB9Ha9Xyc+IUcqipvheQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/visitor-keys": "4.26.1"
}
},
"@typescript-eslint/types": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.26.1.tgz",
"integrity": "sha512-STyMPxR3cS+LaNvS8yK15rb8Y0iL0tFXq0uyl6gY45glyI7w0CsyqyEXl/Fa0JlQy+pVANeK3sbwPneCbWE7yg==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.26.1.tgz",
"integrity": "sha512-l3ZXob+h0NQzz80lBGaykdScYaiEbFqznEs99uwzm8fPHhDjwaBFfQkjUC/slw6Sm7npFL8qrGEAMxcfBsBJUg==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.26.1",
"@typescript-eslint/visitor-keys": "4.26.1",
"debug": "^4.3.1",
"globby": "^11.0.3",
"is-glob": "^4.0.1",
"semver": "^7.3.5",
"tsutils": "^3.21.0"
},
"dependencies": {
"array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true
},
"globby": {
"version": "11.0.3",
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz",
"integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==",
"dev": true,
"requires": {
"array-union": "^2.1.0",
"dir-glob": "^3.0.1",
"fast-glob": "^3.1.1",
"ignore": "^5.1.4",
"merge2": "^1.3.0",
"slash": "^3.0.0"
}
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
}
}
},
"@typescript-eslint/visitor-keys": {
"version": "4.26.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.26.1.tgz",
"integrity": "sha512-IGouNSSd+6x/fHtYRyLOM6/C+QxMDzWlDtN41ea+flWuSF9g02iqcIlX8wM53JkfljoIjP0U+yp7SiTS1onEkw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "4.26.1",
"eslint-visitor-keys": "^2.0.0"
},
"dependencies": {
"eslint-visitor-keys": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
"integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
"dev": true
}
}
},
"@uupaa/dynamic-import-polyfill": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@uupaa/dynamic-import-polyfill/-/dynamic-import-polyfill-1.0.2.tgz",
@ -3080,6 +3473,16 @@
"sprintf-js": "~1.0.2"
}
},
"aria-query": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz",
"integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==",
"dev": true,
"requires": {
"@babel/runtime": "^7.10.2",
"@babel/runtime-corejs3": "^7.10.2"
}
},
"arr-diff": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
@ -3185,6 +3588,12 @@
"integrity": "sha512-tKHdBe8N/Vq2nLAm4YPBVREVZjMux6KrqyPfNQgIbDl0t7HaNSmy8w4OyVHYg/cvyn5BW7o7pVwpjPte89Zhcg==",
"dev": true
},
"ast-types-flow": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
"integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
"dev": true
},
"astral-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
@ -3265,6 +3674,18 @@
}
}
},
"axe-core": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.2.2.tgz",
"integrity": "sha512-OKRkKM4ojMEZRJ5UNJHmq9tht7cEnRnqKG6KyB/trYws00Xtkv12mHtlJ0SK7cmuNbrU8dPUova3ELTuilfBbw==",
"dev": true
},
"axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
"integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==",
"dev": true
},
"babel-loader": {
"version": "8.2.2",
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.2.tgz",
@ -4126,6 +4547,12 @@
}
}
},
"core-js-pure": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.14.0.tgz",
"integrity": "sha512-YVh+LN2FgNU0odThzm61BsdkwrbrchumFq3oztnE9vTKC4KS2fvnPmcx8t6jnqAyOTCTF4ZSiuK8Qhh7SNcL4g==",
"dev": true
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
@ -4538,6 +4965,12 @@
"type": "^1.0.1"
}
},
"damerau-levenshtein": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz",
"integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==",
"dev": true
},
"date-fns": {
"version": "2.22.1",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.22.1.tgz",
@ -5513,6 +5946,33 @@
}
}
},
"eslint-plugin-jsx-a11y": {
"version": "6.4.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz",
"integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==",
"dev": true,
"requires": {
"@babel/runtime": "^7.11.2",
"aria-query": "^4.2.2",
"array-includes": "^3.1.1",
"ast-types-flow": "^0.0.7",
"axe-core": "^4.0.2",
"axobject-query": "^2.2.0",
"damerau-levenshtein": "^1.0.6",
"emoji-regex": "^9.0.0",
"has": "^1.0.3",
"jsx-ast-utils": "^3.1.0",
"language-tags": "^1.0.5"
},
"dependencies": {
"emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true
}
}
},
"eslint-plugin-promise": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.0.tgz",
@ -5617,6 +6077,12 @@
}
}
},
"eslint-plugin-react-hooks": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz",
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==",
"dev": true
},
"eslint-rule-composer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz",
@ -7573,6 +8039,21 @@
"integrity": "sha512-sZLUnTqimCkvkgRS+kbPlYW5o8q5w1cu+uIisKpEWkj31I8mx8kNG162DwRav8Zirkva6N5uoFsm9kzK4mUXjw==",
"dev": true
},
"language-subtag-registry": {
"version": "0.3.21",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
"integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg==",
"dev": true
},
"language-tags": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
"integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=",
"dev": true,
"requires": {
"language-subtag-registry": "~0.3.2"
}
},
"leven": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz",
@ -15489,6 +15970,78 @@
"integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
"dev": true
},
"ts-loader": {
"version": "9.2.3",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.2.3.tgz",
"integrity": "sha512-sEyWiU3JMHBL55CIeC4iqJQadI0U70A5af0kvgbNLHVNz2ACztQg0j/9x10bjjIht8WfFYLKfn4L6tkZ+pu+8Q==",
"dev": true,
"requires": {
"chalk": "^4.1.0",
"enhanced-resolve": "^5.0.0",
"micromatch": "^4.0.0",
"semver": "^7.3.4"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
"dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"tsconfig-paths": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
@ -15518,6 +16071,23 @@
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==",
"dev": true
},
"tsutils": {
"version": "3.21.0",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
"integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
"dev": true,
"requires": {
"tslib": "^1.8.1"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
}
}
},
"type": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
@ -15557,6 +16127,12 @@
"is-typedarray": "^1.0.0"
}
},
"typescript": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz",
"integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==",
"dev": true
},
"unbox-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",

View file

@ -13,6 +13,9 @@
"@babel/plugin-transform-modules-umd": "^7.14.5",
"@babel/preset-env": "^7.14.5",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.14.5",
"@typescript-eslint/eslint-plugin": "^4.26.1",
"@typescript-eslint/parser": "^4.26.1",
"@uupaa/dynamic-import-polyfill": "^1.0.2",
"autoprefixer": "^10.2.6",
"babel-loader": "^8.2.2",
@ -26,8 +29,10 @@
"eslint-plugin-compat": "^3.9.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0",
"expose-loader": "^3.0.0",
"file-loader": "^6.2.0",
"html-loader": "^2.1.2",
@ -44,6 +49,8 @@
"stylelint-no-browser-hacks": "^1.2.1",
"stylelint-order": "^4.1.0",
"stylelint-scss": "^3.19.0",
"ts-loader": "^9.2.3",
"typescript": "^4.3.2",
"webpack": "^5.39.0",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2",

View file

@ -1,10 +1,15 @@
import PropTypes from 'prop-types';
import React, { useEffect, useRef, useState } from 'react';
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
import AlphaPicker from './alphaPicker';
type AlphaPickerProps = {
onAlphaPicked: () => void
};
// React compatibility wrapper component for alphaPicker.js
const AlphaPickerComponent = ({ onAlphaPicked = () => {} }) => {
// eslint-disable-next-line @typescript-eslint/no-empty-function
const AlphaPickerComponent: FunctionComponent<AlphaPickerProps> = ({ onAlphaPicked = () => {} }) => {
const [ alphaPicker, setAlphaPicker ] = useState(null);
const element = useRef(null);
@ -19,6 +24,7 @@ const AlphaPickerComponent = ({ onAlphaPicked = () => {} }) => {
return () => {
alphaPicker?.destroy();
};
// eslint-disable-next-line react-hooks/exhaustive-deps -- Disabled for wrapper components
}, []);
return (

View file

@ -15,6 +15,10 @@ function setLayout(instance, layout, selectedLayout) {
}
class LayoutManager {
tv = false;
mobile = false;
desktop = false;
setLayout(layout, save) {
if (!layout || layout === 'auto') {
this.autoLayout();

View file

@ -1,12 +1,18 @@
import PropTypes from 'prop-types';
import React, { useState } from 'react';
import React, { FunctionComponent, useState } from 'react';
import SearchFields from '../search/SearchFields';
import SearchResults from '../search/SearchResults';
import SearchSuggestions from '../search/SearchSuggestions';
import LiveTVSearchResults from '../search/LiveTVSearchResults';
const SearchPage = ({ serverId, parentId, collectionType }) => {
type SearchProps = {
serverId: string,
parentId: string,
collectionType: string
};
const SearchPage: FunctionComponent<SearchProps> = ({ serverId, parentId, collectionType }: SearchProps) => {
const [ query, setQuery ] = useState(null);
return (
@ -14,18 +20,18 @@ const SearchPage = ({ serverId, parentId, collectionType }) => {
<SearchFields onSearch={setQuery} />
{!query &&
<SearchSuggestions
serverId={serverId || ApiClient.serverId()}
serverId={serverId || window.ApiClient.serverId()}
parentId={parentId}
/>
}
<SearchResults
serverId={serverId || ApiClient.serverId()}
serverId={serverId || window.ApiClient.serverId()}
parentId={parentId}
collectionType={collectionType}
query={query}
/>
<LiveTVSearchResults
serverId={serverId || ApiClient.serverId()}
serverId={serverId || window.ApiClient.serverId()}
parentId={parentId}
collectionType={collectionType}
query={query}

View file

@ -1,6 +1,6 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React, { useEffect, useState } from 'react';
import React, { FunctionComponent, useEffect, useState } from 'react';
import globalize from '../../scripts/globalize';
import ServerConnections from '../ServerConnections';
@ -18,10 +18,17 @@ const CARD_OPTIONS = {
showChannelName: true
};
type LiveTVSearchResultsProps = {
serverId: string;
parentId: string;
collectionType: string;
query: string;
}
/*
* React component to display search result rows for live tv library search
*/
const LiveTVSearchResults = ({ serverId, parentId, collectionType, query }) => {
const LiveTVSearchResults: FunctionComponent<LiveTVSearchResultsProps> = ({ serverId, parentId, collectionType, query }) => {
const [ movies, setMovies ] = useState([]);
const [ episodes, setEpisodes ] = useState([]);
const [ sports, setSports ] = useState([]);
@ -30,34 +37,32 @@ const LiveTVSearchResults = ({ serverId, parentId, collectionType, query }) => {
const [ programs, setPrograms ] = useState([]);
const [ channels, setChannels ] = useState([]);
const getDefaultParameters = () => ({
ParentId: parentId,
searchTerm: query,
Limit: 24,
Fields: 'PrimaryImageAspectRatio,CanDelete,BasicSyncInfo,MediaSourceCount',
Recursive: true,
EnableTotalRecordCount: false,
ImageTypeLimit: 1,
IncludePeople: false,
IncludeMedia: false,
IncludeGenres: false,
IncludeStudios: false,
IncludeArtists: false
});
// FIXME: This query does not support Live TV filters
const fetchItems = (apiClient, params = {}) => apiClient?.getItems(
apiClient?.getCurrentUserId(),
{
...getDefaultParameters(),
IncludeMedia: true,
...params
}
);
const isLiveTV = () => collectionType === 'livetv';
useEffect(() => {
const getDefaultParameters = () => ({
ParentId: parentId,
searchTerm: query,
Limit: 24,
Fields: 'PrimaryImageAspectRatio,CanDelete,BasicSyncInfo,MediaSourceCount',
Recursive: true,
EnableTotalRecordCount: false,
ImageTypeLimit: 1,
IncludePeople: false,
IncludeMedia: false,
IncludeGenres: false,
IncludeStudios: false,
IncludeArtists: false
});
// FIXME: This query does not support Live TV filters
const fetchItems = (apiClient, params = {}) => apiClient?.getItems(
apiClient?.getCurrentUserId(),
{
...getDefaultParameters(),
IncludeMedia: true,
...params
}
);
// Reset state
setMovies([]);
setEpisodes([]);
@ -67,8 +72,9 @@ const LiveTVSearchResults = ({ serverId, parentId, collectionType, query }) => {
setPrograms([]);
setChannels([]);
if (query && isLiveTV()) {
const apiClient = ServerConnections.getApiClient(serverId);
if (query && collectionType === 'livetv') {
// TODO: Remove type casting once we're using a properly typed API client
const apiClient = (ServerConnections as any).getApiClient(serverId);
// Movies row
fetchItems(apiClient, {
@ -128,7 +134,7 @@ const LiveTVSearchResults = ({ serverId, parentId, collectionType, query }) => {
fetchItems(apiClient, { IncludeItemTypes: 'TvChannel' })
.then(result => setChannels(result.Items));
}
}, [ query ]);
}, [collectionType, parentId, query, serverId]);
return (
<div
@ -136,7 +142,7 @@ const LiveTVSearchResults = ({ serverId, parentId, collectionType, query }) => {
'searchResults',
'padded-bottom-page',
'padded-top',
{ 'hide': !query || !isLiveTV() }
{ 'hide': !query || !(collectionType === 'livetv') }
)}
>
<SearchResultsRow

View file

@ -1,6 +1,6 @@
import debounce from 'lodash-es/debounce';
import PropTypes from 'prop-types';
import React, { useEffect, useMemo, useRef } from 'react';
import React, { FunctionComponent, useEffect, useMemo, useRef } from 'react';
import AlphaPicker from '../alphaPicker/AlphaPickerComponent';
import globalize from '../../scripts/globalize';
@ -31,12 +31,17 @@ const createInputElement = () => ({
const normalizeInput = (value = '') => value.trim();
const SearchFields = ({ onSearch = () => {} }) => {
type SearchFieldsProps = {
onSearch: () => void
};
// eslint-disable-next-line @typescript-eslint/no-empty-function
const SearchFields: FunctionComponent<SearchFieldsProps> = ({ onSearch = () => {} }) => {
const element = useRef(null);
const getSearchInput = () => element?.current?.querySelector('.searchfields-txtSearch');
const debouncedOnSearch = useMemo(() => debounce(onSearch, 400), []);
const debouncedOnSearch = useMemo(() => debounce(onSearch, 400), [onSearch]);
useEffect(() => {
getSearchInput()?.addEventListener('input', e => {
@ -47,7 +52,7 @@ const SearchFields = ({ onSearch = () => {} }) => {
return () => {
debouncedOnSearch.cancel();
};
}, []);
}, [debouncedOnSearch]);
const onAlphaPicked = e => {
const value = e.detail.value;

View file

@ -1,15 +1,22 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React, { useEffect, useState } from 'react';
import React, { FunctionComponent, useEffect, useState } from 'react';
import globalize from '../../scripts/globalize';
import ServerConnections from '../ServerConnections';
import SearchResultsRow from './SearchResultsRow';
type SearchResultsProps = {
serverId: string;
parentId: string;
collectionType: string;
query: string;
}
/*
* React component to display search result rows for global search and non-live tv library search
*/
const SearchResults = ({ serverId, parentId, collectionType, query }) => {
const SearchResults: FunctionComponent<SearchResultsProps> = ({ serverId, parentId, collectionType, query }) => {
const [ movies, setMovies ] = useState([]);
const [ shows, setShows ] = useState([]);
const [ episodes, setEpisodes ] = useState([]);
@ -26,55 +33,55 @@ const SearchResults = ({ serverId, parentId, collectionType, query }) => {
const [ books, setBooks ] = useState([]);
const [ people, setPeople ] = useState([]);
const getDefaultParameters = () => ({
ParentId: parentId,
searchTerm: query,
Limit: 24,
Fields: 'PrimaryImageAspectRatio,CanDelete,BasicSyncInfo,MediaSourceCount',
Recursive: true,
EnableTotalRecordCount: false,
ImageTypeLimit: 1,
IncludePeople: false,
IncludeMedia: false,
IncludeGenres: false,
IncludeStudios: false,
IncludeArtists: false
});
const fetchArtists = (apiClient, params = {}) => apiClient?.getArtists(
apiClient?.getCurrentUserId(),
{
...getDefaultParameters(),
IncludeArtists: true,
...params
}
);
const fetchItems = (apiClient, params = {}) => apiClient?.getItems(
apiClient?.getCurrentUserId(),
{
...getDefaultParameters(),
IncludeMedia: true,
...params
}
);
const fetchPeople = (apiClient, params = {}) => apiClient?.getPeople(
apiClient?.getCurrentUserId(),
{
...getDefaultParameters(),
IncludePeople: true,
...params
}
);
const isMovies = () => collectionType === 'movies';
const isMusic = () => collectionType === 'music';
const isTVShows = () => collectionType === 'tvshows' || collectionType === 'tv';
useEffect(() => {
const getDefaultParameters = () => ({
ParentId: parentId,
searchTerm: query,
Limit: 24,
Fields: 'PrimaryImageAspectRatio,CanDelete,BasicSyncInfo,MediaSourceCount',
Recursive: true,
EnableTotalRecordCount: false,
ImageTypeLimit: 1,
IncludePeople: false,
IncludeMedia: false,
IncludeGenres: false,
IncludeStudios: false,
IncludeArtists: false
});
const fetchArtists = (apiClient, params = {}) => apiClient?.getArtists(
apiClient?.getCurrentUserId(),
{
...getDefaultParameters(),
IncludeArtists: true,
...params
}
);
const fetchItems = (apiClient, params = {}) => apiClient?.getItems(
apiClient?.getCurrentUserId(),
{
...getDefaultParameters(),
IncludeMedia: true,
...params
}
);
const fetchPeople = (apiClient, params = {}) => apiClient?.getPeople(
apiClient?.getCurrentUserId(),
{
...getDefaultParameters(),
IncludePeople: true,
...params
}
);
const isMovies = () => collectionType === 'movies';
const isMusic = () => collectionType === 'music';
const isTVShows = () => collectionType === 'tvshows' || collectionType === 'tv';
// Reset state
setMovies([]);
setShows([]);
@ -93,7 +100,8 @@ const SearchResults = ({ serverId, parentId, collectionType, query }) => {
setPeople([]);
if (query) {
const apiClient = ServerConnections.getApiClient(serverId);
// TODO: Remove type casting once we're using a properly typed API client
const apiClient = (ServerConnections as any).getApiClient(serverId);
// Movie libraries
if (!collectionType || isMovies()) {
@ -160,7 +168,7 @@ const SearchResults = ({ serverId, parentId, collectionType, query }) => {
.then(results => setBooks(results.Items));
}
}
}, [ query ]);
}, [collectionType, parentId, query, serverId]);
return (
<div

View file

@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
import React, { useEffect, useRef } from 'react';
import React, { FunctionComponent, useEffect, useRef } from 'react';
import cardBuilder from '../cardbuilder/cardBuilder';
@ -16,7 +16,13 @@ const createScroller = ({ title = '' }) => ({
</div>`
});
const SearchResultsRow = ({ title, items = [], cardOptions = {} }) => {
type SearchResultsRowProps = {
title: string;
items: Array<any>; // TODO: Should be Array<BaseItemDto> once we have a typed API client
cardOptions: Record<string, any>;
}
const SearchResultsRow: FunctionComponent<SearchResultsRowProps> = ({ title, items = [], cardOptions = {} }) => {
const element = useRef(null);
useEffect(() => {
@ -31,7 +37,7 @@ const SearchResultsRow = ({ title, items = [], cardOptions = {} }) => {
allowBottomPadding: false,
...cardOptions
});
}, [ items ]);
}, [cardOptions, items]);
return (
<div

View file

@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
import React, { useEffect, useState } from 'react';
import React, { FunctionComponent, useEffect, useState } from 'react';
import { appRouter } from '../appRouter';
import globalize from '../../scripts/globalize';
@ -19,11 +19,17 @@ const createSuggestionLink = ({name, href}) => ({
>${name}</a>`
});
const SearchSuggestions = ({ serverId, parentId }) => {
type SearchSuggestionsProps = {
serverId: string;
parentId: string;
}
const SearchSuggestions: FunctionComponent<SearchSuggestionsProps> = ({ serverId, parentId }) => {
const [ suggestions, setSuggestions ] = useState([]);
useEffect(() => {
const apiClient = ServerConnections.getApiClient(serverId);
// TODO: Remove type casting once we're using a properly typed API client
const apiClient = (ServerConnections as any).getApiClient(serverId);
apiClient.getItems(apiClient.getCurrentUserId(), {
SortBy: 'IsFavoriteOrLiked,Random',
@ -35,7 +41,7 @@ const SearchSuggestions = ({ serverId, parentId }) => {
ParentId: parentId,
EnableTotalRecordCount: false
}).then(result => setSuggestions(result.Items));
}, []);
}, [parentId, serverId]);
return (
<div

5
src/global.d.ts vendored Normal file
View file

@ -0,0 +1,5 @@
export declare global {
interface Window {
ApiClient: any;
}
}

21
tsconfig.json Normal file
View file

@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ES5",
"lib": ["DOM", "ES2015"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"noImplicitAny": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"module": "ESNext",
"moduleResolution": "node",
"outDir": "./dist/",
"checkJs": false,
"strictNullChecks": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}

View file

@ -24,6 +24,7 @@ module.exports = {
context: path.resolve(__dirname, 'src'),
target: 'browserslist',
resolve: {
extensions: ['.tsx', '.ts', '.js'],
modules: [
path.resolve(__dirname, 'node_modules')
]
@ -87,12 +88,19 @@ module.exports = {
}
},
{
test: /\.js$/,
test: /\.(js|jsx)$/,
exclude: /node_modules[\\/](?!@uupaa[\\/]dynamic-import-polyfill|date-fns|epubjs|flv.js|libarchive.js)/,
use: [{
loader: 'babel-loader'
}]
},
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
use: [{
loader: 'ts-loader'
}]
},
/* modules that Babel breaks when transforming to ESM */
{
test: /node_modules[\\/](pdfjs-dist|xmldom)[\\/].*\.js$/,

View file

@ -11,7 +11,12 @@ module.exports = merge(common, {
module: {
rules: [
{
test: /\.js$/,
test: /\.(js|jsx)$/,
enforce: 'pre',
use: ['source-map-loader']
},
{
test: /\.(ts|tsx)$/,
enforce: 'pre',
use: ['source-map-loader']
}