diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index fa2daba006..0000000000 --- a/.eslintrc +++ /dev/null @@ -1,26 +0,0 @@ -{ - "parserOptions": { - "ecmaVersion": 2018 - }, - - "env": { - "browser": true, - "node": true - }, - - "ignores": ["./spec/support/"], - - "rules": { - "semi": "error", - "use-isnan": "error", - "no-unsafe-negation": "error", - "no-cond-assign": "error", - - "no-console": "warn", - "no-var": "warn", - "no-extra-semi": "warn", - "no-unused-vars": "warn", - "no-new-object": "warn", - "no-undef": "error" - } -} diff --git a/.prettierrc b/.prettierrc index 82005a82ac..b9c6c9de98 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,6 @@ { "printWidth": 100, - "parser": "flow", + "parser": "typescript", "tabWidth": 2, "useTabs": false, "semi": true, diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000000..ad4eefa539 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,35 @@ +import typescriptEslint from 'typescript-eslint'; +import prettierPlugin from 'eslint-plugin-prettier'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default [ + { + files: ['src/**/*.{ts,js,mjs}'], + ignores: ['dist', 'node_modules'] + }, + ...typescriptEslint.configs.recommended, + { + plugins: { + prettier: prettierPlugin + }, + rules: { + ...prettierPlugin.configs.recommended.rules, + ...eslintConfigPrettier.rules, + + // TODO: to improve because the basic rules cause + // thousands of errors, for this reason, they have been marked as WARN + 'prettier/prettier': 'error', + + 'prefer-const': 'warn', + 'prefer-rest-params': 'warn', + 'no-var': 'warn', + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/no-unused-expressions': 'warn', + '@typescript-eslint/no-this-alias': 'warn', + '@typescript-eslint/no-empty-object-type': 'warn', + '@typescript-eslint/no-require-imports': 'warn', + '@typescript-eslint/no-unsafe-function-type': 'warn' + } + } +]; diff --git a/package-lock.json b/package-lock.json index 74059a46e3..83167d01b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,9 +23,13 @@ "@rollup/plugin-typescript": "^11.1.6", "@types/node": "^20.5.2", "archiver": "^7.0.1", + "eslint": "^9.10.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.2.1", "jasmine": "^5.1.0", "jasmine-browser-runner": "^2.5.0", "jasmine-core": "^5.2.0", + "prettier": "^3.3.3", "rollup": "^4.20.0", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-dts": "^6.1.1", @@ -33,7 +37,8 @@ "rollup-plugin-zip": "^1.0.3", "sass": "^1.77.8", "tslib": "^2.6.3", - "typescript": "^5.4.3" + "typescript": "^5.4.3", + "typescript-eslint": "^8.6.0" } }, "node_modules/@babel/code-frame": { @@ -144,6 +149,181 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.10.0.tgz", + "integrity": "sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.1.0.tgz", + "integrity": "sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==", + "dev": true, + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -332,6 +512,18 @@ "node": ">=14" } }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@rollup/plugin-terser": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", @@ -672,6 +864,293 @@ "undici-types": "~5.26.4" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz", + "integrity": "sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/type-utils": "8.6.0", + "@typescript-eslint/utils": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.6.0.tgz", + "integrity": "sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/typescript-estree": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.6.0.tgz", + "integrity": "sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.6.0.tgz", + "integrity": "sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "8.6.0", + "@typescript-eslint/utils": "8.6.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/@typescript-eslint/types": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.6.0.tgz", + "integrity": "sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.6.0.tgz", + "integrity": "sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/visitor-keys": "8.6.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.6.0.tgz", + "integrity": "sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.6.0", + "@typescript-eslint/types": "8.6.0", + "@typescript-eslint/typescript-estree": "8.6.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.6.0.tgz", + "integrity": "sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.6.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -699,9 +1178,9 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -710,6 +1189,31 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -855,6 +1359,12 @@ "node": ">=8.0.0" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -1091,6 +1601,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1332,6 +1851,12 @@ "ms": "2.0.0" } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -1446,6 +1971,232 @@ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "dev": true }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.10.0.tgz", + "integrity": "sha512-Y4D0IgtBZfOcOUAIQTSXBKoNGfY0REGqHJG6+Q81vNippW5YlKjHFj4soMxamKK1NXHUWuBZTLdU3Km+L/pcHw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.10.0", + "@eslint/plugin-kit": "^0.1.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", + "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/espree": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "dev": true, + "dependencies": { + "acorn": "^8.12.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -1453,6 +2204,15 @@ "dev": true, "license": "MIT" }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -1594,6 +2354,18 @@ ], "license": "MIT" }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, "node_modules/fast-fifo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", @@ -1618,6 +2390,18 @@ "node": ">=8.6.0" } }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -1627,6 +2411,18 @@ "reusify": "^1.0.4" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -1673,6 +2469,41 @@ "node": ">=8" } }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -1803,6 +2634,18 @@ "node": ">= 6" } }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globby": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", @@ -1841,6 +2684,12 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1952,6 +2801,31 @@ "dev": true, "license": "MIT" }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2033,6 +2907,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -2095,19 +2978,6 @@ "node": ">=10" } }, - "node_modules/jake/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/jasmine": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.1.0.tgz", @@ -2270,6 +3140,36 @@ "dev": true, "optional": true }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -2319,6 +3219,15 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/lazystream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", @@ -2358,6 +3267,19 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lie": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", @@ -2368,6 +3290,21 @@ "immediate": "~3.0.5" } }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -2375,6 +3312,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "node_modules/magic-string": { "version": "0.30.11", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", @@ -2471,9 +3414,9 @@ } }, "node_modules/minimatch": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -2498,6 +3441,12 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -2534,6 +3483,53 @@ "wrappy": "1" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", @@ -2548,6 +3544,18 @@ "dev": true, "license": "(MIT AND Zlib)" }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -2557,6 +3565,15 @@ "node": ">= 0.8" } }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -2643,6 +3660,42 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -2673,6 +3726,15 @@ "node": ">= 0.10" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -2826,6 +3888,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -3059,6 +4130,18 @@ } } }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -3365,6 +4448,18 @@ "node": ">=8" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3390,6 +4485,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/tar-stream": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", @@ -3436,6 +4547,12 @@ "b4a": "^1.6.4" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", @@ -3468,6 +4585,18 @@ "node": ">=0.6" } }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", @@ -3475,6 +4604,18 @@ "dev": true, "license": "0BSD" }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -3502,6 +4643,29 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.6.0.tgz", + "integrity": "sha512-eEhhlxCEpCd4helh3AO1hk0UP2MvbRi9CtIAJTVPQjuSXOOO2jsEacNi4UdcJzZJbeuVg1gMhtZ8UYb+NFYPrA==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.6.0", + "@typescript-eslint/parser": "8.6.0", + "@typescript-eslint/utils": "8.6.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -3528,6 +4692,15 @@ "node": ">= 0.8" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -3568,6 +4741,15 @@ "node": ">= 8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", @@ -3664,6 +4846,18 @@ "buffer-crc32": "~0.2.3" } }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zip-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", diff --git a/package.json b/package.json index c9a832bbcf..ff05c239eb 100644 --- a/package.json +++ b/package.json @@ -32,10 +32,11 @@ } ], "scripts": { + "lint": "eslint .", "test": "npx jasmine-browser-runner runSpecs", "build": "rollup --config rollup.config.ts --configPlugin @rollup/plugin-typescript", - "release": " npm run build && node ci/compress.js", - "preversion": "npm test", + "release": "npm run lint && npm run build && node ci/compress.js", + "preversion": "npm run lint && npm test", "version": "npm run build && node ci/compress.js && git add -A dist src/index.ts" }, "lint-staged": { @@ -56,9 +57,13 @@ "@rollup/plugin-typescript": "^11.1.6", "@types/node": "^20.5.2", "archiver": "^7.0.1", + "eslint": "^9.10.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.2.1", "jasmine": "^5.1.0", "jasmine-browser-runner": "^2.5.0", "jasmine-core": "^5.2.0", + "prettier": "^3.3.3", "rollup": "^4.20.0", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-dts": "^6.1.1", @@ -66,7 +71,8 @@ "rollup-plugin-zip": "^1.0.3", "sass": "^1.77.8", "tslib": "^2.6.3", - "typescript": "^5.4.3" + "typescript": "^5.4.3", + "typescript-eslint": "^8.6.0" }, "files": [ "dist", diff --git a/src/autocomplete.ts b/src/autocomplete.ts index e07ee62335..bbb4092456 100644 --- a/src/autocomplete.ts +++ b/src/autocomplete.ts @@ -1,9 +1,9 @@ -import { Utils } from "./utils"; -import { Dropdown, DropdownOptions } from "./dropdown"; -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Utils } from './utils'; +import { Dropdown, DropdownOptions } from './dropdown'; +import { Component, BaseOptions, InitElements, MElement } from './component'; export interface AutocompleteData { - /** + /** * A primitive value that can be converted to string. * If "text" is not provided, it will also be used as "option text" as well */ @@ -66,7 +66,7 @@ export interface AutocompleteOptions extends BaseOptions { * @default {} */ dropdownOptions: Partial; -}; +} let _defaults: AutocompleteOptions = { data: [], // Autocomplete data set @@ -82,9 +82,10 @@ let _defaults: AutocompleteOptions = { onSearch: (text: string, autocomplete: Autocomplete) => { const normSearch = text.toLocaleLowerCase(); autocomplete.setMenuItems( - autocomplete.options.data.filter((option) => - option.id.toString().toLocaleLowerCase().includes(normSearch) - || option.text?.toLocaleLowerCase().includes(normSearch) + autocomplete.options.data.filter( + (option) => + option.id.toString().toLocaleLowerCase().includes(normSearch) || + option.text?.toLocaleLowerCase().includes(normSearch) ) ); }, @@ -101,7 +102,7 @@ export class Autocomplete extends Component { /** Index of the current selected option. */ activeIndex: number; private oldVal: string; - private $active: HTMLElement|null; + private $active: HTMLElement | null; private _mousedown: boolean; container: HTMLElement; /** Instance of the dropdown plugin for this autocomplete. */ @@ -118,11 +119,11 @@ export class Autocomplete extends Component { ...Autocomplete.defaults, ...options }; - + this.isOpen = false; this.count = 0; this.activeIndex = -1; - this.oldVal = ""; + this.oldVal = ''; this.selectedValues = []; this.menuItems = this.options.data || []; this.$active = null; @@ -146,13 +147,19 @@ export class Autocomplete extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: InitElements, options?: Partial): Autocomplete[]; + static init( + els: InitElements, + options?: Partial + ): Autocomplete[]; /** * Initializes instances of Autocomplete. * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLInputElement | InitElements, options: Partial = {}): Autocomplete | Autocomplete[] { + static init( + els: HTMLInputElement | InitElements, + options: Partial = {} + ): Autocomplete | Autocomplete[] { return super.init(els, options, Autocomplete); } @@ -172,16 +179,10 @@ export class Autocomplete extends Component { this.el.addEventListener('focus', this._handleInputKeyupAndFocus); this.el.addEventListener('keydown', this._handleInputKeydown); this.el.addEventListener('click', this._handleInputClick); - this.container.addEventListener( - 'mousedown', - this._handleContainerMousedownAndTouchstart - ); + this.container.addEventListener('mousedown', this._handleContainerMousedownAndTouchstart); this.container.addEventListener('mouseup', this._handleContainerMouseupAndTouchend); if (typeof window.ontouchstart !== 'undefined') { - this.container.addEventListener( - 'touchstart', - this._handleContainerMousedownAndTouchstart - ); + this.container.addEventListener('touchstart', this._handleContainerMousedownAndTouchstart); this.container.addEventListener('touchend', this._handleContainerMouseupAndTouchend); } } @@ -192,21 +193,12 @@ export class Autocomplete extends Component { this.el.removeEventListener('focus', this._handleInputKeyupAndFocus); this.el.removeEventListener('keydown', this._handleInputKeydown); this.el.removeEventListener('click', this._handleInputClick); - this.container.removeEventListener( - 'mousedown', - this._handleContainerMousedownAndTouchstart - ); + this.container.removeEventListener('mousedown', this._handleContainerMousedownAndTouchstart); this.container.removeEventListener('mouseup', this._handleContainerMouseupAndTouchend); if (typeof window.ontouchstart !== 'undefined') { - this.container.removeEventListener( - 'touchstart', - this._handleContainerMousedownAndTouchstart - ); - this.container.removeEventListener( - 'touchend', - this._handleContainerMouseupAndTouchend - ); + this.container.removeEventListener('touchstart', this._handleContainerMousedownAndTouchstart); + this.container.removeEventListener('touchend', this._handleContainerMouseupAndTouchend); } } @@ -217,7 +209,7 @@ export class Autocomplete extends Component { this.container.classList.add('autocomplete-content', 'dropdown-content'); this.el.setAttribute('data-target', this.container.id); - this.menuItems.forEach(menuItem => { + this.menuItems.forEach((menuItem) => { const itemElement = this._createDropdownItem(menuItem); this.container.append(itemElement); }); @@ -268,14 +260,19 @@ export class Autocomplete extends Component { this.close(); this._resetAutocomplete(); } - } + }; _handleInputKeyupAndFocus = (e: KeyboardEvent) => { if (e.type === 'keyup') Autocomplete._keydown = false; this.count = 0; const actualValue = this.el.value.toLocaleLowerCase(); // Don't capture enter or arrow key usage. - if (Utils.keys.ENTER.includes(e.key) || Utils.keys.ARROW_UP.includes(e.key) || Utils.keys.ARROW_DOWN.includes(e.key)) return; + if ( + Utils.keys.ENTER.includes(e.key) || + Utils.keys.ARROW_UP.includes(e.key) || + Utils.keys.ARROW_DOWN.includes(e.key) + ) + return; // Check if the input isn't empty // Check if focus triggered by tab if (this.oldVal !== actualValue && (Utils.tabPressed || e.type !== 'focus')) { @@ -292,7 +289,7 @@ export class Autocomplete extends Component { this._triggerChanged(); } this.oldVal = actualValue; - } + }; _handleInputKeydown = (e: KeyboardEvent) => { Autocomplete._keydown = true; @@ -311,7 +308,8 @@ export class Autocomplete extends Component { if (Utils.keys.ARROW_UP.includes(e.key) || Utils.keys.ARROW_DOWN.includes(e.key)) { e.preventDefault(); if (Utils.keys.ARROW_UP.includes(e.key) && this.activeIndex > 0) this.activeIndex--; - if (Utils.keys.ARROW_DOWN.includes(e.key) && this.activeIndex < numItems - 1) this.activeIndex++; + if (Utils.keys.ARROW_DOWN.includes(e.key) && this.activeIndex < numItems - 1) + this.activeIndex++; this.$active?.classList.remove('active'); if (this.activeIndex >= 0) { this.$active = this.container.querySelectorAll('li')[this.activeIndex]; @@ -324,19 +322,19 @@ export class Autocomplete extends Component { }); } } - } + }; _handleInputClick = () => { this.open(); - } + }; _handleContainerMousedownAndTouchstart = () => { this._mousedown = true; - } + }; _handleContainerMouseupAndTouchend = () => { this._mousedown = false; - } + }; _resetCurrentElementPosition() { this.activeIndex = -1; @@ -409,7 +407,10 @@ export class Autocomplete extends Component { item.appendChild(itemText); item.querySelector('.item-text').appendChild(div); // Description - if (typeof entry.description === 'string' || (typeof entry.description === 'number' && !isNaN(entry.description))) { + if ( + typeof entry.description === 'string' || + (typeof entry.description === 'number' && !isNaN(entry.description)) + ) { const description = document.createElement('small'); description.setAttribute( 'style', @@ -444,9 +445,8 @@ export class Autocomplete extends Component { } _setStatusLoading() { - this.el.parentElement.querySelector( - '.status-info' - ).innerHTML = `
+ this.el.parentElement.querySelector('.status-info').innerHTML = + `
@@ -456,7 +456,8 @@ export class Autocomplete extends Component { _updateSelectedInfo() { const statusElement = this.el.parentElement.querySelector('.status-info'); if (statusElement) { - if (this.options.isMultiSelect) statusElement.innerHTML = this.selectedValues.length.toString(); + if (this.options.isMultiSelect) + statusElement.innerHTML = this.selectedValues.length.toString(); else statusElement.innerHTML = ''; } } @@ -490,16 +491,15 @@ export class Autocomplete extends Component { setTimeout(() => { this.dropdown.open(); }, 0); // TODO: why? - } - else this.dropdown.recalculateDimensions(); // Recalculate dropdown when its already open - } + } else this.dropdown.recalculateDimensions(); // Recalculate dropdown when its already open + }; /** * Hide autocomplete. */ close = () => { this.dropdown.close(); - } + }; /** * Updates the visible or selectable items shown in the menu. @@ -532,10 +532,10 @@ export class Autocomplete extends Component { const entry = this.menuItems.find((item) => item.id == id); if (!entry) return; // Toggle Checkbox - const li = this.container.querySelector('li[data-id="'+id+'"]'); + const li = this.container.querySelector('li[data-id="' + id + '"]'); if (!li) return; if (this.options.isMultiSelect) { - const checkbox = li.querySelector('input[type="checkbox"]'); + const checkbox = li.querySelector('input[type="checkbox"]'); checkbox.checked = !checkbox.checked; if (checkbox.checked) this.selectedValues.push(entry); else diff --git a/src/buttons.ts b/src/buttons.ts index 3d4a6a5853..ad294e69ed 100644 --- a/src/buttons.ts +++ b/src/buttons.ts @@ -1,11 +1,11 @@ -import { Component, BaseOptions, InitElements, MElement, Openable } from "./component"; +import { Component, BaseOptions, InitElements, MElement, Openable } from './component'; export interface FloatingActionButtonOptions extends BaseOptions { /** * Direction FAB menu opens. * @default "top" */ - direction: "top" | "right" | "bottom" | "left"; + direction: 'top' | 'right' | 'bottom' | 'left'; /** * true: FAB menu appears on hover, false: FAB menu appears on click. * @default true @@ -16,7 +16,7 @@ export interface FloatingActionButtonOptions extends BaseOptions { * @default false */ toolbarEnabled: boolean; -}; +} let _defaults: FloatingActionButtonOptions = { direction: 'top', @@ -24,14 +24,17 @@ let _defaults: FloatingActionButtonOptions = { toolbarEnabled: false }; -export class FloatingActionButton extends Component implements Openable { +export class FloatingActionButton + extends Component + implements Openable +{ /** * Describes open/close state of FAB. */ isOpen: boolean; private _anchor: HTMLAnchorElement; - private _menu: HTMLElement|null; + private _menu: HTMLElement | null; private _floatingBtns: HTMLElement[]; private _floatingBtnsReverse: HTMLElement[]; @@ -59,14 +62,10 @@ export class FloatingActionButton extends Component this.offsetX = 0; this.el.classList.add(`direction-${this.options.direction}`); - if (this.options.direction === 'top') - this.offsetY = 40; - else if (this.options.direction === 'right') - this.offsetX = -40; - else if (this.options.direction === 'bottom') - this.offsetY = -40; - else - this.offsetX = 40; + if (this.options.direction === 'top') this.offsetY = 40; + else if (this.options.direction === 'right') this.offsetX = -40; + else if (this.options.direction === 'bottom') this.offsetY = -40; + else this.offsetX = 40; this._setupEventHandlers(); } @@ -79,19 +78,28 @@ export class FloatingActionButton extends Component * @param el HTML element. * @param options Component options. */ - static init(el: HTMLElement, options?: Partial): FloatingActionButton + static init( + el: HTMLElement, + options?: Partial + ): FloatingActionButton; /** * Initializes instances of FloatingActionButton. * @param els HTML elements. * @param options Component options. */ - static init(els: InitElements, options?: Partial): FloatingActionButton[]; + static init( + els: InitElements, + options?: Partial + ): FloatingActionButton[]; /** * Initializes instances of FloatingActionButton. * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): FloatingActionButton | FloatingActionButton[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): FloatingActionButton | FloatingActionButton[] { return super.init(els, options, FloatingActionButton); } @@ -128,24 +136,22 @@ export class FloatingActionButton extends Component } else { this.open(); } - } + }; _handleDocumentClick = (e: MouseEvent) => { const elem = e.target; if (elem !== this._menu) this.close; - } + }; /** * Open FAB. */ open = (): void => { if (this.isOpen) return; - if (this.options.toolbarEnabled) - this._animateInToolbar(); - else - this._animateInFAB(); + if (this.options.toolbarEnabled) this._animateInToolbar(); + else this._animateInFAB(); this.isOpen = true; - } + }; /** * Close FAB. @@ -155,18 +161,17 @@ export class FloatingActionButton extends Component if (this.options.toolbarEnabled) { window.removeEventListener('scroll', this.close, true); document.body.removeEventListener('click', this._handleDocumentClick, true); - } - else { + } else { this._animateOutFAB(); } this.isOpen = false; - } + }; _animateInFAB() { this.el.classList.add('active'); const delayIncrement = 40; const duration = 275; - + this._floatingBtnsReverse.forEach((el, index) => { const delay = delayIncrement * index; el.style.transition = 'none'; @@ -203,7 +208,7 @@ export class FloatingActionButton extends Component let windowHeight = window.innerHeight; let btnRect = this.el.getBoundingClientRect(); - const backdrop = document.createElement('div'); + const backdrop = document.createElement('div'); backdrop.classList.add('fab-backdrop'); // $('
'); const fabColor = getComputedStyle(this._anchor).backgroundColor; // css('background-color'); @@ -233,7 +238,8 @@ export class FloatingActionButton extends Component setTimeout(() => { this.el.style.transform = ''; - this.el.style.transition = 'transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s'; + this.el.style.transition = + 'transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s'; this._anchor.style.overflow = 'visible'; this._anchor.style.transform = ''; @@ -246,7 +252,9 @@ export class FloatingActionButton extends Component backdrop.style.transform = 'scale(' + scaleFactor + ')'; backdrop.style.transition = 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)'; - this._menu.querySelectorAll('li > a').forEach((a: HTMLAnchorElement) => a.style.opacity = '1'); + this._menu + .querySelectorAll('li > a') + .forEach((a: HTMLAnchorElement) => (a.style.opacity = '1')); // Scroll to close. window.addEventListener('scroll', this.close, true); diff --git a/src/cards.ts b/src/cards.ts index b11660e16d..a06400ab62 100644 --- a/src/cards.ts +++ b/src/cards.ts @@ -1,45 +1,45 @@ export class Cards { - static Init() { - if (typeof document !== 'undefined') document.addEventListener("DOMContentLoaded", () => { - document.body.addEventListener('click', e => { - const trigger = e.target; - - const card: HTMLElement = trigger.closest('.card'); - if (!card) return; + if (typeof document !== 'undefined') + document.addEventListener('DOMContentLoaded', () => { + document.body.addEventListener('click', (e) => { + const trigger = e.target; - const cardReveal = Array.from(card.children).find(elem => elem.classList.contains('card-reveal')); - if (!cardReveal) return; - const initialOverflow = getComputedStyle(card).overflow; + const card: HTMLElement = trigger.closest('.card'); + if (!card) return; - // Close Card - const closeArea = cardReveal.querySelector('.card-reveal .card-title'); - if (trigger === closeArea || closeArea.contains(trigger)) { - const duration = 225; - cardReveal.style.transition = `transform ${duration}ms ease`; //easeInOutQuad - cardReveal.style.transform = 'translateY(0)'; - setTimeout(() => { - cardReveal.style.display = 'none'; - card.style.overflow = initialOverflow; - }, duration); - }; + const cardReveal = ( + Array.from(card.children).find((elem) => elem.classList.contains('card-reveal')) + ); + if (!cardReveal) return; + const initialOverflow = getComputedStyle(card).overflow; - // Reveal Card - const activators = card.querySelectorAll('.activator'); - activators.forEach(activator => { - if (trigger === activator || activator.contains(trigger)) { - card.style.overflow = 'hidden'; - cardReveal.style.display = 'block'; + // Close Card + const closeArea = cardReveal.querySelector('.card-reveal .card-title'); + if (trigger === closeArea || closeArea.contains(trigger)) { + const duration = 225; + cardReveal.style.transition = `transform ${duration}ms ease`; //easeInOutQuad + cardReveal.style.transform = 'translateY(0)'; setTimeout(() => { - const duration = 300; - cardReveal.style.transition = `transform ${duration}ms ease`; //easeInOutQuad - cardReveal.style.transform = 'translateY(-100%)'; - }, 1); + cardReveal.style.display = 'none'; + card.style.overflow = initialOverflow; + }, duration); } - }); + // Reveal Card + const activators = card.querySelectorAll('.activator'); + activators.forEach((activator) => { + if (trigger === activator || activator.contains(trigger)) { + card.style.overflow = 'hidden'; + cardReveal.style.display = 'block'; + setTimeout(() => { + const duration = 300; + cardReveal.style.transition = `transform ${duration}ms ease`; //easeInOutQuad + cardReveal.style.transform = 'translateY(-100%)'; + }, 1); + } + }); + }); }); - }); - } } diff --git a/src/carousel.ts b/src/carousel.ts index afdffd2705..7a9a5ff341 100644 --- a/src/carousel.ts +++ b/src/carousel.ts @@ -1,7 +1,7 @@ -import { Utils } from "./utils"; -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Utils } from './utils'; +import { Component, BaseOptions, InitElements, MElement } from './component'; -export interface CarouselOptions extends BaseOptions{ +export interface CarouselOptions extends BaseOptions { /** * Transition duration in milliseconds. * @default 200 @@ -140,8 +140,7 @@ export class Carousel extends Component { } }); - if (this.showIndicators) - this.el.appendChild(this._indicators); + if (this.showIndicators) this.el.appendChild(this._indicators); this.count = this.images.length; @@ -184,7 +183,10 @@ export class Carousel extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): Carousel | Carousel[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): Carousel | Carousel[] { return super.init(els, options, Carousel); } @@ -236,7 +238,13 @@ export class Carousel extends Component { window.removeEventListener('resize', this._handleThrottledResize); } - _handleThrottledResize: () => void = Utils.throttle(function(){ this._handleResize(); }, 200, null).bind(this); + _handleThrottledResize: () => void = Utils.throttle( + function () { + this._handleResize(); + }, + 200, + null + ).bind(this); _handleCarouselTap = (e: MouseEvent | TouchEvent) => { // Fixes firefox draggable image bug @@ -254,7 +262,7 @@ export class Carousel extends Component { this.timestamp = Date.now(); clearInterval(this.ticker); this.ticker = setInterval(this._track, 100); - } + }; _handleCarouselDrag = (e: MouseEvent | TouchEvent) => { let x: number, y: number, delta: number, deltaY: number; @@ -286,7 +294,7 @@ export class Carousel extends Component { e.stopPropagation(); return false; } - } + }; _handleCarouselRelease = (e: MouseEvent | TouchEvent) => { if (this.pressed) { @@ -317,7 +325,7 @@ export class Carousel extends Component { e.stopPropagation(); } return false; - } + }; _handleCarouselClick = (e: MouseEvent | TouchEvent) => { // Disable clicks if carousel was dragged. @@ -325,8 +333,7 @@ export class Carousel extends Component { e.preventDefault(); e.stopPropagation(); return false; - } - else if (!this.options.fullWidth) { + } else if (!this.options.fullWidth) { const clickedElem = (e.target).closest('.carousel-item'); if (!clickedElem) return; const clickedIndex = [...clickedElem.parentNode.children].indexOf(clickedElem); @@ -339,7 +346,10 @@ export class Carousel extends Component { // fixes https://github.com/materializecss/materialize/issues/180 if (clickedIndex < 0) { // relative X position > center of carousel = clicked at the right part of the carousel - if ((e as MouseEvent).clientX - (e.target as HTMLElement).getBoundingClientRect().left > this.el.clientWidth / 2) { + if ( + (e as MouseEvent).clientX - (e.target as HTMLElement).getBoundingClientRect().left > + this.el.clientWidth / 2 + ) { this.next(); } else { this.prev(); @@ -348,7 +358,7 @@ export class Carousel extends Component { this._cycleTo(clickedIndex); } } - } + }; _handleIndicatorClick = (e: Event) => { e.stopPropagation(); @@ -357,7 +367,7 @@ export class Carousel extends Component { const index = [...indicator.parentNode.children].indexOf(indicator); this._cycleTo(index); } - } + }; _handleResize = () => { if (this.options.fullWidth) { @@ -367,11 +377,10 @@ export class Carousel extends Component { this.offset = this.center * 2 * this.itemWidth; this.target = this.offset; this._setCarouselHeight(true); - } - else { + } else { this._scroll(); } - } + }; _setCarouselHeight(imageOnly: boolean = false) { const firstSlide = this.el.querySelector('.carousel-item.active') @@ -384,31 +393,29 @@ export class Carousel extends Component { // If image won't trigger the load event const imageHeight = firstImage.clientHeight; if (imageHeight > 0) { - this.el.style.height = imageHeight+'px'; - } - else { + this.el.style.height = imageHeight + 'px'; + } else { // If image still has no height, use the natural dimensions to calculate const naturalWidth = firstImage.naturalWidth; const naturalHeight = firstImage.naturalHeight; const adjustedHeight = (this.el.clientWidth / naturalWidth) * naturalHeight; - this.el.style.height = adjustedHeight+'px'; + this.el.style.height = adjustedHeight + 'px'; } } else { // Get height when image is loaded normally firstImage.addEventListener('load', () => { - this.el.style.height = firstImage.offsetHeight+'px'; + this.el.style.height = firstImage.offsetHeight + 'px'; }); } - } - else if (!imageOnly) { + } else if (!imageOnly) { const slideHeight = firstSlide.clientHeight; - this.el.style.height = slideHeight+'px'; + this.el.style.height = slideHeight + 'px'; } } _xpos(e: MouseEvent | TouchEvent) { // touch event - if (e.type.startsWith("touch") && (e as TouchEvent).targetTouches.length >= 1) { + if (e.type.startsWith('touch') && (e as TouchEvent).targetTouches.length >= 1) { return (e as TouchEvent).targetTouches[0].clientX; } // mouse event @@ -417,7 +424,7 @@ export class Carousel extends Component { _ypos(e: MouseEvent | TouchEvent) { // touch event - if (e.type.startsWith("touch") && (e as TouchEvent).targetTouches.length >= 1) { + if (e.type.startsWith('touch') && (e as TouchEvent).targetTouches.length >= 1) { return (e as TouchEvent).targetTouches[0].clientY; } // mouse event @@ -425,11 +432,7 @@ export class Carousel extends Component { } _wrap(x: number) { - return x >= this.count - ? x % this.count - : x < 0 - ? this._wrap(this.count + (x % this.count)) - : x; + return x >= this.count ? x % this.count : x < 0 ? this._wrap(this.count + (x % this.count)) : x; } _track = () => { @@ -441,7 +444,7 @@ export class Carousel extends Component { this.frame = this.offset; v = (1000 * delta) / (1 + elapsed); this.velocity = 0.8 * v + 0.2 * this.velocity; - } + }; _autoScroll = () => { let elapsed: number, delta: number; @@ -455,7 +458,7 @@ export class Carousel extends Component { this._scroll(this.target); } } - } + }; _scroll(x: number = 0) { // Track scrolling state @@ -494,8 +497,7 @@ export class Carousel extends Component { if (this.options.fullWidth) { alignment = 'translateX(0)'; centerTweenedOpacity = 1; - } - else { + } else { alignment = 'translateX(' + (this.el.clientWidth - this.itemWidth) / 2 + 'px) '; alignment += 'translateY(' + (this.el.clientHeight - this.itemHeight) / 2 + 'px)'; centerTweenedOpacity = 1 - numVisibleOffset * tween; @@ -505,7 +507,9 @@ export class Carousel extends Component { if (this.showIndicators) { const diff = this.center % this.count; const activeIndicator = this._indicators.querySelector('.indicator-item.active'); - const activeIndicatorIndex = [...activeIndicator.parentNode.children].indexOf(activeIndicator); + const activeIndicatorIndex = [...activeIndicator.parentNode.children].indexOf( + activeIndicator + ); if (activeIndicatorIndex !== diff) { activeIndicator.classList.remove('active'); const pos = diff < 0 ? this.count + diff : diff; @@ -524,10 +528,9 @@ export class Carousel extends Component { el.classList.add('active'); } - let transformString = `${alignment} translateX(${-delta / 2}px) translateX(${dir * - this.options.shift * - tween * - i}px) translateZ(${this.options.dist * tween}px)`; + let transformString = `${alignment} translateX(${-delta / 2}px) translateX(${ + dir * this.options.shift * tween * i + }px) translateZ(${this.options.dist * tween}px)`; this._updateItemStyle(el, centerTweenedOpacity, 0, transformString); } @@ -543,8 +546,9 @@ export class Carousel extends Component { // Don't show wrapped items. if (!this.noWrap || this.center + i < this.count) { el = this.images[this._wrap(this.center + i)]; - let transformString = `${alignment} translateX(${this.options.shift + - (this.dim * i - delta) / 2}px) translateZ(${zTranslation}px)`; + let transformString = `${alignment} translateX(${ + this.options.shift + (this.dim * i - delta) / 2 + }px) translateZ(${zTranslation}px)`; this._updateItemStyle(el, tweenedOpacity, -i, transformString); } // left side @@ -558,8 +562,9 @@ export class Carousel extends Component { // Don't show wrapped items. if (!this.noWrap || this.center - i >= 0) { el = this.images[this._wrap(this.center - i)]; - let transformString = `${alignment} translateX(${-this.options.shift + - (-this.dim * i - delta) / 2}px) translateZ(${zTranslation}px)`; + let transformString = `${alignment} translateX(${ + -this.options.shift + (-this.dim * i - delta) / 2 + }px) translateZ(${zTranslation}px)`; this._updateItemStyle(el, tweenedOpacity, -i, transformString); } } @@ -567,9 +572,9 @@ export class Carousel extends Component { // Don't show wrapped items. if (!this.noWrap || (this.center >= 0 && this.center < this.count)) { el = this.images[this._wrap(this.center)]; - let transformString = `${alignment} translateX(${-delta / 2}px) translateX(${dir * - this.options.shift * - tween}px) translateZ(${this.options.dist * tween}px)`; + let transformString = `${alignment} translateX(${-delta / 2}px) translateX(${ + dir * this.options.shift * tween + }px) translateZ(${this.options.dist * tween}px)`; this._updateItemStyle(el, centerTweenedOpacity, 0, transformString); } // onCycleTo callback @@ -592,7 +597,7 @@ export class Carousel extends Component { el.style.visibility = 'visible'; } - _cycleTo(n: number, callback: CarouselOptions["onCycleTo"] = null) { + _cycleTo(n: number, callback: CarouselOptions['onCycleTo'] = null) { let diff = (this.center % this.count) - n; // Account for wraparound. if (!this.noWrap) { @@ -663,7 +668,7 @@ export class Carousel extends Component { * @param n Index of slide. * @param callback "onCycleTo" optional callback. */ - set(n: number, callback?: CarouselOptions["onCycleTo"]) { + set(n: number, callback?: CarouselOptions['onCycleTo']) { if (n === undefined || isNaN(n)) { n = 0; } diff --git a/src/characterCounter.ts b/src/characterCounter.ts index 450e815b9c..f33b7a43aa 100644 --- a/src/characterCounter.ts +++ b/src/characterCounter.ts @@ -1,13 +1,12 @@ -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Component, BaseOptions, InitElements, MElement } from './component'; -export interface CharacterCounterOptions extends BaseOptions {}; +export interface CharacterCounterOptions extends BaseOptions {} const _defaults = Object.freeze({}); type InputElement = HTMLInputElement | HTMLTextAreaElement; export class CharacterCounter extends Component<{}> { - declare el: InputElement; /** Stores the reference to the counter HTML element. */ counterEl: HTMLSpanElement; @@ -16,7 +15,10 @@ export class CharacterCounter extends Component<{}> { /** Specifies whether the input text has valid length or not. */ isValidLength: boolean; - constructor(el: HTMLInputElement | HTMLTextAreaElement, options: Partial) { + constructor( + el: HTMLInputElement | HTMLTextAreaElement, + options: Partial + ) { super(el, {}, CharacterCounter); (this.el as any).M_CharacterCounter = this; @@ -27,7 +29,7 @@ export class CharacterCounter extends Component<{}> { this.isInvalid = false; this.isValidLength = false; - + this._setupCounter(); this._setupEventHandlers(); } @@ -47,13 +49,19 @@ export class CharacterCounter extends Component<{}> { * @param els HTML elements. * @param options Component options. */ - static init(els: InitElements, options?: Partial): CharacterCounter[]; + static init( + els: InitElements, + options?: Partial + ): CharacterCounter[]; /** * Initializes instances of CharacterCounter. * @param els HTML elements. * @param options Component options. */ - static init(els: InputElement | InitElements, options: Partial = {}): CharacterCounter | CharacterCounter[] { + static init( + els: InputElement | InitElements, + options: Partial = {} + ): CharacterCounter | CharacterCounter[] { return super.init(els, options, CharacterCounter); } @@ -101,14 +109,13 @@ export class CharacterCounter extends Component<{}> { this._validateInput(); } this.counterEl.innerHTML = counterString; - } + }; _validateInput() { if (this.isValidLength && this.isInvalid) { this.isInvalid = false; this.el.classList.remove('invalid'); - } - else if (!this.isValidLength && !this.isInvalid) { + } else if (!this.isValidLength && !this.isInvalid) { this.isInvalid = true; this.el.classList.remove('valid'); this.el.classList.add('invalid'); diff --git a/src/chips.ts b/src/chips.ts index 9680f59ec8..92020c46d9 100644 --- a/src/chips.ts +++ b/src/chips.ts @@ -1,12 +1,12 @@ -import { Utils } from "./utils"; -import { Autocomplete, AutocompleteOptions } from "./autocomplete"; -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Utils } from './utils'; +import { Autocomplete, AutocompleteOptions } from './autocomplete'; +import { Component, BaseOptions, InitElements, MElement } from './component'; export interface ChipData { /** * Unique identifier. */ - id: number|string; + id: number | string; /** * Chip text. If not specified, "id" will be used. */ @@ -17,7 +17,7 @@ export interface ChipData { image?: string; } -export interface ChipsOptions extends BaseOptions{ +export interface ChipsOptions extends BaseOptions { /** * Set the chip data. * @default [] @@ -116,8 +116,7 @@ export class Chips extends Component { this.hasAutocomplete = Object.keys(this.options.autocompleteOptions).length > 0; // Set input id - if (!this._input.getAttribute('id')) - this._input.setAttribute('id', Utils.guid()); + if (!this._input.getAttribute('id')) this._input.setAttribute('id', Utils.guid()); // Render initial chips if (this.options.data.length) { @@ -152,7 +151,10 @@ export class Chips extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): Chips | Chips[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): Chips | Chips[] { return super.init(els, options, Chips); } @@ -166,7 +168,7 @@ export class Chips extends Component { destroy() { this._removeEventHandlers(); - this._chips.forEach(c => c.remove()); + this._chips.forEach((c) => c.remove()); this._chips = []; (this.el as any).M_Chips = undefined; } @@ -199,16 +201,14 @@ export class Chips extends Component { if (clickedClose) { this.deleteChip(index); this._input.focus(); - } - else { + } else { this.selectChip(index); } // Default handle click to focus on input - } - else { + } else { this._input.focus(); } - } + }; static _handleChipsKeydown(e: KeyboardEvent) { Chips._keydown = true; @@ -231,25 +231,19 @@ export class Chips extends Component { // Make sure selectIndex doesn't go negative selectIndex = Math.max(index - 1, 0); } - if (currChips.chipsData.length) - currChips.selectChip(selectIndex); - else - currChips._input.focus(); - } - else if (Utils.keys.ARROW_LEFT.includes(e.key)) { + if (currChips.chipsData.length) currChips.selectChip(selectIndex); + else currChips._input.focus(); + } else if (Utils.keys.ARROW_LEFT.includes(e.key)) { if (currChips._selectedChip) { const selectIndex = gGetIndex(currChips._selectedChip) - 1; if (selectIndex < 0) return; currChips.selectChip(selectIndex); } - } - else if (Utils.keys.ARROW_RIGHT.includes(e.key)) { + } else if (Utils.keys.ARROW_RIGHT.includes(e.key)) { if (currChips._selectedChip) { const selectIndex = gGetIndex(currChips._selectedChip) + 1; - if (selectIndex >= currChips.chipsData.length) - currChips._input.focus(); - else - currChips.selectChip(selectIndex); + if (selectIndex >= currChips.chipsData.length) currChips._input.focus(); + else currChips.selectChip(selectIndex); } } } @@ -268,11 +262,11 @@ export class Chips extends Component { _handleInputFocus = () => { this.el.classList.add('focus'); - } + }; _handleInputBlur = () => { this.el.classList.remove('focus'); - } + }; _handleInputKeydown = (e: KeyboardEvent) => { Chips._keydown = true; @@ -283,11 +277,10 @@ export class Chips extends Component { } e.preventDefault(); if (!this.hasAutocomplete || (this.hasAutocomplete && !this.options.autocompleteOnly)) { - this.addChip({id: this._input.value}); + this.addChip({ id: this._input.value }); } this._input.value = ''; - } - else if ( + } else if ( (Utils.keys.BACKSPACE.includes(e.key) || Utils.keys.ARROW_LEFT.includes(e.key)) && this._input.value === '' && this.chipsData.length @@ -295,14 +288,14 @@ export class Chips extends Component { e.preventDefault(); this.selectChip(this.chipsData.length - 1); } - } + }; _renderChip(chip: ChipData): HTMLDivElement { if (!chip.id) return; const renderedChip = document.createElement('div'); renderedChip.classList.add('chip'); renderedChip.innerText = chip.text || chip.id; - renderedChip.setAttribute('tabindex', "0"); + renderedChip.setAttribute('tabindex', '0'); const closeIcon = document.createElement('i'); closeIcon.classList.add(this.options.closeIconClass, 'close'); closeIcon.innerText = 'close'; @@ -329,11 +322,12 @@ export class Chips extends Component { _setupAutocomplete() { this.options.autocompleteOptions.onAutocomplete = (items) => { - if (items.length > 0) this.addChip({ - id: items[0].id, - text: items[0].text, - image: items[0].image - }); + if (items.length > 0) + this.addChip({ + id: items[0].id, + text: items[0].text, + image: items[0].image + }); this._input.value = ''; this._input.focus(); }; @@ -357,8 +351,7 @@ export class Chips extends Component { _setPlaceholder() { if (this.chipsData !== undefined && !this.chipsData.length && this.options.placeholder) { this._input.placeholder = this.options.placeholder; - } - else if ( + } else if ( (this.chipsData === undefined || !!this.chipsData.length) && this.options.secondaryPlaceholder ) { @@ -368,7 +361,7 @@ export class Chips extends Component { _isValidAndNotExist(chip: ChipData) { const isValid = !!chip.id; - const doesNotExist = !this.chipsData.some(item => item.id == chip.id); + const doesNotExist = !this.chipsData.some((item) => item.id == chip.id); return isValid && doesNotExist; } @@ -420,18 +413,18 @@ export class Chips extends Component { } } - static Init(){ + static Init() { if (typeof document !== 'undefined') - document.addEventListener("DOMContentLoaded", () => { - // Handle removal of static chips. - document.body.addEventListener('click', e => { - if ((e.target).closest('.chip .close')) { - const chips = (e.target).closest('.chips'); - if (chips && (chips as any).M_Chips == undefined) return; - (e.target).closest('.chip').remove(); - } + document.addEventListener('DOMContentLoaded', () => { + // Handle removal of static chips. + document.body.addEventListener('click', (e) => { + if ((e.target).closest('.chip .close')) { + const chips = (e.target).closest('.chips'); + if (chips && (chips as any).M_Chips == undefined) return; + (e.target).closest('.chip').remove(); + } + }); }); - }); } static { diff --git a/src/collapsible.ts b/src/collapsible.ts index 4e46f5ae98..2e4aaa86ec 100644 --- a/src/collapsible.ts +++ b/src/collapsible.ts @@ -1,5 +1,5 @@ -import { Utils } from "./utils"; -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Utils } from './utils'; +import { Component, BaseOptions, InitElements, MElement } from './component'; export interface CollapsibleOptions extends BaseOptions { /** @@ -43,7 +43,7 @@ const _defaults: CollapsibleOptions = { accordion: true, onOpenStart: null, onOpenEnd: null, - onCloseStart: null, + onCloseStart: null, onCloseEnd: null, inDuration: 300, outDuration: 300 @@ -63,11 +63,13 @@ export class Collapsible extends Component { // Setup tab indices this._headers = Array.from(this.el.querySelectorAll('li > .collapsible-header')); - this._headers.forEach(el => el.tabIndex = 0); + this._headers.forEach((el) => (el.tabIndex = 0)); this._setupEventHandlers(); // Open active - const activeBodies: HTMLElement[] = Array.from(this.el.querySelectorAll('li.active > .collapsible-body')); + const activeBodies: HTMLElement[] = Array.from( + this.el.querySelectorAll('li.active > .collapsible-body') + ); if (this.options.accordion) { if (activeBodies.length > 0) { // Accordion => open first active only @@ -75,7 +77,7 @@ export class Collapsible extends Component { } } else { // Expandables => all active - activeBodies.forEach(el => this._setExpanded(el)); + activeBodies.forEach((el) => this._setExpanded(el)); } } @@ -100,7 +102,10 @@ export class Collapsible extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): Collapsible | Collapsible[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): Collapsible | Collapsible[] { return super.init(els, options, Collapsible); } @@ -115,12 +120,16 @@ export class Collapsible extends Component { _setupEventHandlers() { this.el.addEventListener('click', this._handleCollapsibleClick); - this._headers.forEach(header => header.addEventListener('keydown', this._handleCollapsibleKeydown)); + this._headers.forEach((header) => + header.addEventListener('keydown', this._handleCollapsibleKeydown) + ); } _removeEventHandlers() { this.el.removeEventListener('click', this._handleCollapsibleClick); - this._headers.forEach(header => header.removeEventListener('keydown', this._handleCollapsibleKeydown)); + this._headers.forEach((header) => + header.removeEventListener('keydown', this._handleCollapsibleKeydown) + ); } _handleCollapsibleClick = (e: MouseEvent | KeyboardEvent) => { @@ -133,21 +142,19 @@ export class Collapsible extends Component { const isActive = li.classList.contains('active'); const index = [...li.parentNode.children].indexOf(li); - if (isActive) - this.close(index); - else - this.open(index); + if (isActive) this.close(index); + else this.open(index); } - } + }; _handleCollapsibleKeydown = (e: KeyboardEvent) => { if (Utils.keys.ENTER.includes(e.key)) { this._handleCollapsibleClick(e); } - } + }; private _setExpanded(li: HTMLElement): void { - li.style.maxHeight = li.scrollHeight + "px"; + li.style.maxHeight = li.scrollHeight + 'px'; } _animateIn(index: number) { @@ -170,7 +177,7 @@ export class Collapsible extends Component { const body: HTMLElement = li.querySelector('.collapsible-body'); const duration = this.options.outDuration; // easeInOutCubic body.style.transition = `max-height ${duration}ms ease-out`; - body.style.maxHeight = "0"; + body.style.maxHeight = '0'; setTimeout(() => { if (typeof this.options.onCloseEnd === 'function') { this.options.onCloseEnd.call(this, li); @@ -183,7 +190,7 @@ export class Collapsible extends Component { * @param n Nth section to open. */ open = (index: number) => { - const listItems = Array.from(this.el.children).filter(c => c.tagName === 'LI'); + const listItems = Array.from(this.el.children).filter((c) => c.tagName === 'LI'); const li = listItems[index]; if (li && !li.classList.contains('active')) { // onOpenStart callback @@ -192,8 +199,8 @@ export class Collapsible extends Component { } // Handle accordion behavior if (this.options.accordion) { - const activeLis = listItems.filter(li => li.classList.contains('active')); - activeLis.forEach(activeLi => { + const activeLis = listItems.filter((li) => li.classList.contains('active')); + activeLis.forEach((activeLi) => { const index = listItems.indexOf(activeLi); this.close(index); }); @@ -202,14 +209,14 @@ export class Collapsible extends Component { li.classList.add('active'); this._animateIn(index); } - } + }; /** * Close collapsible section. * @param n Nth section to close. */ close = (index: number) => { - const li = Array.from(this.el.children).filter(c => c.tagName === 'LI')[index]; + const li = Array.from(this.el.children).filter((c) => c.tagName === 'LI')[index]; if (li && li.classList.contains('active')) { // onCloseStart callback if (typeof this.options.onCloseStart === 'function') { @@ -219,5 +226,5 @@ export class Collapsible extends Component { li.classList.remove('active'); this._animateOut(index); } - } + }; } diff --git a/src/component.ts b/src/component.ts index 2abc34959c..13e412dea7 100644 --- a/src/component.ts +++ b/src/component.ts @@ -1,14 +1,15 @@ /** * Base options for component initialization. */ -export interface BaseOptions {}; +export interface BaseOptions {} export type MElement = HTMLElement | Element; export type InitElements = NodeListOf | HTMLCollectionOf; type ComponentConstructor, O extends BaseOptions> = { - new (el: HTMLElement, options: Partial): T + new (el: HTMLElement, options: Partial): T; }; -type ComponentType, O extends BaseOptions> = ComponentConstructor & typeof Component; +type ComponentType, O extends BaseOptions> = ComponentConstructor & + typeof Component; export interface I18nOptions { cancel: string; @@ -20,12 +21,12 @@ export interface Openable { isOpen: boolean; open(): void; close(): void; -}; +} /** * Base class implementation for Materialize components. */ -export class Component{ +export class Component { /** * The DOM element the plugin was initialized with. */ @@ -38,7 +39,7 @@ export class Component{ /** * Constructs component instance and set everything up. */ - constructor(el: HTMLElement, options: Partial, classDef: ComponentType, O>){ + constructor(el: HTMLElement, options: Partial, classDef: ComponentType, O>) { // Display error if el is not a valid HTML Element if (!(el instanceof HTMLElement)) { console.error(Error(el + ' is not an HTML Element')); @@ -57,41 +58,48 @@ export class Component{ * @param options Component options. * @param classDef Class definition. */ - protected static init< - I extends HTMLElement, O extends BaseOptions, C extends Component - >(el: I, options: O, classDef: ComponentType): C; + protected static init>( + el: I, + options: O, + classDef: ComponentType + ): C; /** * Initializes component instances. * @param els HTML elements. * @param options Component options. * @param classDef Class definition. */ - protected static init< - I extends MElement, O extends BaseOptions, C extends Component - >(els: InitElements, options: Partial, classDef: ComponentType): C[]; + protected static init>( + els: InitElements, + options: Partial, + classDef: ComponentType + ): C[]; /** * Initializes component instances. * @param els HTML elements. * @param options Component options. * @param classDef Class definition. */ - protected static init< - I extends MElement, O extends BaseOptions, C extends Component - >(els: I | InitElements, options: Partial, classDef: ComponentType): C | C[]; + protected static init>( + els: I | InitElements, + options: Partial, + classDef: ComponentType + ): C | C[]; /** * Initializes component instances. * @param els HTML elements. * @param options Component options. * @param classDef Class definition. */ - protected static init< - I extends MElement, O extends BaseOptions, C extends Component - >(els: I | InitElements, options: Partial, classDef: ComponentType): C | C[] { + protected static init>( + els: I | InitElements, + options: Partial, + classDef: ComponentType + ): C | C[] { let instances = null; if (els instanceof Element) { instances = new classDef(els, options); - } - else if (!!els && els.length) { + } else if (!!els && els.length) { instances = []; for (let i = 0; i < els.length; i++) { instances.push(new classDef(els[i], options)); @@ -103,18 +111,22 @@ export class Component{ /** * @returns default options for component instance. */ - static get defaults(): BaseOptions{ return {}; } + static get defaults(): BaseOptions { + return {}; + } /** * Retrieves component instance for the given element. * @param el Associated HTML Element. */ static getInstance(el: HTMLElement): Component { - throw new Error("This method must be implemented."); + throw new Error('This method must be implemented.'); } /** * Destroy plugin instance and teardown. */ - destroy(): void { throw new Error("This method must be implemented."); } + destroy(): void { + throw new Error('This method must be implemented.'); + } } diff --git a/src/datepicker.ts b/src/datepicker.ts index 8e1662719b..bfb00b1bdf 100644 --- a/src/datepicker.ts +++ b/src/datepicker.ts @@ -1,7 +1,7 @@ -import { Modal } from "./modal"; -import { Utils } from "./utils"; -import { FormSelect } from "./select"; -import { BaseOptions, Component, InitElements, MElement, I18nOptions } from "./component"; +import { Modal } from './modal'; +import { Utils } from './utils'; +import { FormSelect } from './select'; +import { BaseOptions, Component, InitElements, MElement, I18nOptions } from './component'; export interface DateI18nOptions extends I18nOptions { previousMonth: string; @@ -11,7 +11,7 @@ export interface DateI18nOptions extends I18nOptions { weekdays: string[]; weekdaysShort: string[]; weekdaysAbbrev: string[]; -}; +} export interface DatepickerOptions extends BaseOptions { /** @@ -236,7 +236,7 @@ let _defaults: DatepickerOptions = { }; export class Datepicker extends Component { - declare el: HTMLInputElement + declare el: HTMLInputElement; id: string; /** If the picker is open. */ isOpen: boolean; @@ -269,7 +269,7 @@ export class Datepicker extends Component { // make sure i18n defaults are not lost when only few i18n option properties are passed if (!!options && options.hasOwnProperty('i18n') && typeof options.i18n === 'object') { - this.options.i18n = {...Datepicker.defaults.i18n, ...options.i18n}; + this.options.i18n = { ...Datepicker.defaults.i18n, ...options.i18n }; } // Remove time component from minDate and maxDate options @@ -292,12 +292,10 @@ export class Datepicker extends Component { if (this.options.setDefaultDate) { this.setDate(defDate, true); this.setInputValue(); - } - else { + } else { this.gotoDate(defDate); } - } - else { + } else { this.gotoDate(new Date()); } this.isOpen = false; @@ -318,13 +316,19 @@ export class Datepicker extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: InitElements, options?: Partial): Datepicker[]; + static init( + els: InitElements, + options?: Partial + ): Datepicker[]; /** * Initializes instances of Datepicker. * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLInputElement | InitElements, options: Partial = {}): Datepicker | Datepicker[] { + static init( + els: HTMLInputElement | InitElements, + options: Partial = {} + ): Datepicker | Datepicker[] { return super.init(els, options, Datepicker); } @@ -391,10 +395,9 @@ export class Datepicker extends Component { if (this.options.container) { const optEl = this.options.container; this.options.container = - optEl instanceof HTMLElement ? optEl : document.querySelector(optEl) as HTMLElement; + optEl instanceof HTMLElement ? optEl : (document.querySelector(optEl) as HTMLElement); this.options.container.append(this.modalEl); - } - else { + } else { //this.modalEl.before(this.el); this.el.parentElement.appendChild(this.modalEl); } @@ -419,7 +422,7 @@ export class Datepicker extends Component { // String Format const formatArray = format.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g); const formattedDate = formatArray - .map(label => this.formats[label] ? this.formats[label]() : label) + .map((label) => (this.formats[label] ? this.formats[label]() : label)) .join(''); return formattedDate; } @@ -445,8 +448,7 @@ export class Datepicker extends Component { max = this.options.maxDate; if (Datepicker._isDate(min) && date < min) { date = min; - } - else if (Datepicker._isDate(max) && date > max) { + } else if (Datepicker._isDate(max) && date > max) { date = max; } this.date = new Date(date.getTime()); @@ -463,7 +465,14 @@ export class Datepicker extends Component { */ setInputValue() { this.el.value = this.toString(); - this.el.dispatchEvent(new CustomEvent('change', {bubbles:true, cancelable:true, composed:true, detail: {firedBy: this}})); + this.el.dispatchEvent( + new CustomEvent('change', { + bubbles: true, + cancelable: true, + composed: true, + detail: { firedBy: this } + }) + ); } _renderDateDisplay() { @@ -735,13 +744,15 @@ export class Datepicker extends Component { ); } - monthHtml = ''; + monthHtml = + ''; if (Array.isArray(opts.yearRange)) { i = opts.yearRange[0]; j = opts.yearRange[1] + 1; - } - else { + } else { i = year - opts.yearRange; j = 1 + year + opts.yearRange; } @@ -927,18 +938,18 @@ export class Datepicker extends Component { _handleInputClick = () => { this.open(); - } + }; _handleInputKeydown = (e: KeyboardEvent) => { if (Utils.keys.ENTER.includes(e.key)) { e.preventDefault(); this.open(); } - } + }; _handleCalendarClick = (e) => { if (!this.isOpen) return; - const target = (e.target); + const target = e.target; if (!target.classList.contains('is-disabled')) { if ( target.classList.contains('datepicker-day-button') && @@ -955,29 +966,27 @@ export class Datepicker extends Component { if (this.options.autoClose) { this._finishSelection(); } - } - else if (target.closest('.month-prev')) { + } else if (target.closest('.month-prev')) { this.prevMonth(); - } - else if (target.closest('.month-next')) { + } else if (target.closest('.month-next')) { this.nextMonth(); } } - } + }; _handleClearClick = () => { this.date = null; this.setInputValue(); this.close(); - } + }; _handleMonthChange = (e) => { this.gotoMonth(e.target.value); - } + }; _handleYearChange = (e) => { this.gotoYear(e.target.value); - } + }; // change view to a specific month (zero-index, e.g. 0: January) gotoMonth(month) { @@ -1000,16 +1009,17 @@ export class Datepicker extends Component { // Prevent change event from being fired when triggered by the plugin if (e['detail']?.firedBy === this) return; if (this.options.parse) { - date = this.options.parse(this.el.value, - typeof this.options.format === "function" + date = this.options.parse( + this.el.value, + typeof this.options.format === 'function' ? this.options.format(new Date(this.el.value)) - : this.options.format); - } - else { + : this.options.format + ); + } else { date = new Date(Date.parse(this.el.value)); } if (Datepicker._isDate(date)) this.setDate(date); - } + }; renderDayName(opts, day, abbr: boolean = false) { day += opts.firstDay; @@ -1023,7 +1033,7 @@ export class Datepicker extends Component { _finishSelection = () => { this.setInputValue(); this.close(); - } + }; /** * Open datepicker. @@ -1037,7 +1047,7 @@ export class Datepicker extends Component { this.draw(); this.modal.open(undefined); return this; - } + }; /** * Close datepicker. @@ -1050,7 +1060,7 @@ export class Datepicker extends Component { } this.modal.close(); return this; - } + }; static { Datepicker._template = ` diff --git a/src/dropdown.ts b/src/dropdown.ts index 83b5d334ee..962270c029 100644 --- a/src/dropdown.ts +++ b/src/dropdown.ts @@ -1,5 +1,5 @@ -import { Utils } from "./utils"; -import { Component, BaseOptions, InitElements, MElement, Openable } from "./component"; +import { Utils } from './utils'; +import { Component, BaseOptions, InitElements, MElement, Openable } from './component'; export interface DropdownOptions extends BaseOptions { /** @@ -72,7 +72,7 @@ export interface DropdownOptions extends BaseOptions { * @default null */ onItemClick: (el: HTMLLIElement) => void; -}; +} const _defaults: DropdownOptions = { alignment: 'left', @@ -153,7 +153,10 @@ export class Dropdown extends Component implements Openable { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): Dropdown | Dropdown[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): Dropdown | Dropdown[] { return super.init(els, options, Dropdown); } @@ -213,15 +216,15 @@ export class Dropdown extends Component implements Openable { _handleClick = (e: MouseEvent) => { e.preventDefault(); if (this.isOpen) { - this.close(); + this.close(); } else { - this.open(); + this.open(); } - } + }; _handleMouseEnter = () => { this.open(); - } + }; _handleMouseLeave = (e: MouseEvent) => { const toEl = e.relatedTarget as HTMLElement; @@ -239,21 +242,14 @@ export class Dropdown extends Component implements Openable { if (!leaveToActiveDropdownTrigger && !leaveToDropdownContent) { this.close(); } - } + }; _handleDocumentClick = (e: MouseEvent) => { const target = e.target; - if ( - this.options.closeOnClick && - target.closest('.dropdown-content') && - !this.isTouchMoving - ) { + if (this.options.closeOnClick && target.closest('.dropdown-content') && !this.isTouchMoving) { // isTouchMoving to check if scrolling on mobile. this.close(); - } - else if ( - !target.closest('.dropdown-content') - ) { + } else if (!target.closest('.dropdown-content')) { // Do this one frame later so that if the element clicked also triggers _handleClick // For example, if a label for a select was clicked, that we don't close/open the dropdown setTimeout(() => { @@ -263,23 +259,24 @@ export class Dropdown extends Component implements Openable { }, 0); } this.isTouchMoving = false; - } + }; _handleTriggerKeydown = (e: KeyboardEvent) => { // ARROW DOWN OR ENTER WHEN SELECT IS CLOSED - open Dropdown - const arrowDownOrEnter = Utils.keys.ARROW_DOWN.includes(e.key) || Utils.keys.ENTER.includes(e.key); + const arrowDownOrEnter = + Utils.keys.ARROW_DOWN.includes(e.key) || Utils.keys.ENTER.includes(e.key); if (arrowDownOrEnter && !this.isOpen) { e.preventDefault(); this.open(); } - } + }; _handleDocumentTouchmove = (e: TouchEvent) => { const target = e.target; if (target.closest('.dropdown-content')) { this.isTouchMoving = true; } - } + }; _handleDropdownClick = (e: MouseEvent) => { // onItemClick callback @@ -287,10 +284,11 @@ export class Dropdown extends Component implements Openable { const itemEl = (e.target).closest('li'); this.options.onItemClick.call(this, itemEl); } - } + }; _handleDropdownKeydown = (e: KeyboardEvent) => { - const arrowUpOrDown = Utils.keys.ARROW_DOWN.includes(e.key) || Utils.keys.ARROW_UP.includes(e.key); + const arrowUpOrDown = + Utils.keys.ARROW_DOWN.includes(e.key) || Utils.keys.ARROW_UP.includes(e.key); if (Utils.keys.TAB.includes(e.key)) { e.preventDefault(); this.close(); @@ -328,8 +326,7 @@ export class Dropdown extends Component implements Openable { // Click a or button tag if exists, otherwise click li tag if (!!activatableElement) { activatableElement.click(); - } - else if (!!focusedElement) { + } else if (!!focusedElement) { if (focusedElement instanceof HTMLElement) { focusedElement.click(); } @@ -344,19 +341,26 @@ export class Dropdown extends Component implements Openable { // CASE WHEN USER TYPE LTTERS const keyText = e.key.toLowerCase(); const isLetter = /[a-zA-Z0-9-_]/.test(keyText); - const specialKeys = [...Utils.keys.ARROW_DOWN, ...Utils.keys.ARROW_UP, ...Utils.keys.ENTER, ...Utils.keys.ESC, ...Utils.keys.TAB]; + const specialKeys = [ + ...Utils.keys.ARROW_DOWN, + ...Utils.keys.ARROW_UP, + ...Utils.keys.ENTER, + ...Utils.keys.ESC, + ...Utils.keys.TAB + ]; if (isLetter && !specialKeys.includes(e.key)) { this.filterQuery.push(keyText); const string = this.filterQuery.join(''); - const newOptionEl = Array.from(this.dropdownEl.querySelectorAll('li')) - .find((el) => el.innerText.toLowerCase().indexOf(string) === 0); + const newOptionEl = Array.from(this.dropdownEl.querySelectorAll('li')).find( + (el) => el.innerText.toLowerCase().indexOf(string) === 0 + ); if (newOptionEl) { this.focusedIndex = [...newOptionEl.parentNode.children].indexOf(newOptionEl); this._focusFocusedItem(); } } this.filterTimeout = setTimeout(this._resetFilterQuery, 1000); - } + }; _handleWindowResize = (e: Event) => { // Only re-place the dropdown if it's still visible @@ -364,12 +368,11 @@ export class Dropdown extends Component implements Openable { if (this.el.offsetParent) { this.recalculateDimensions(); } - } - + }; _resetFilterQuery = () => { this.filterQuery = []; - } + }; _resetDropdownStyles() { this.dropdownEl.style.display = ''; @@ -386,26 +389,23 @@ export class Dropdown extends Component implements Openable { _moveDropdown(containerEl: HTMLElement = null) { if (!!this.options.container) { this.options.container.append(this.dropdownEl); - } - else if (containerEl) { + } else if (containerEl) { if (!containerEl.contains(this.dropdownEl)) { containerEl.append(this.dropdownEl); } - } - else { + } else { this.el.after(this.dropdownEl); } } _makeDropdownFocusable() { if (!this.dropdownEl) return; - this.dropdownEl.popover = ""; + this.dropdownEl.popover = ''; // Needed for arrow key navigation this.dropdownEl.tabIndex = 0; // Only set tabindex if it hasn't been set by user - Array.from(this.dropdownEl.children).forEach((el)=> { - if (!el.getAttribute('tabindex')) - el.setAttribute('tabindex', '0'); + Array.from(this.dropdownEl.children).forEach((el) => { + if (!el.getAttribute('tabindex')) el.setAttribute('tabindex', '0'); }); } @@ -523,28 +523,29 @@ export class Dropdown extends Component implements Openable { this.dropdownEl.style.opacity = '0'; this.dropdownEl.style.transform = 'scale(0.3, 0.3)'; setTimeout(() => { - // easeOutQuad (opacity) & easeOutQuint + // easeOutQuad (opacity) & easeOutQuint this.dropdownEl.style.transition = `opacity ${duration}ms ease, transform ${duration}ms ease`; // to this.dropdownEl.style.opacity = '1'; this.dropdownEl.style.transform = 'scale(1, 1)'; - }, 1); + }, 1); setTimeout(() => { if (this.options.autoFocus) this.dropdownEl.focus(); - if (typeof this.options.onOpenEnd === 'function') this.options.onOpenEnd.call(this, this.el); + if (typeof this.options.onOpenEnd === 'function') this.options.onOpenEnd.call(this, this.el); }, duration); } _animateOut() { const duration = this.options.outDuration; - // easeOutQuad (opacity) & easeOutQuint + // easeOutQuad (opacity) & easeOutQuint this.dropdownEl.style.transition = `opacity ${duration}ms ease, transform ${duration}ms ease`; // to this.dropdownEl.style.opacity = '0'; - this.dropdownEl.style.transform = 'scale(0.3, 0.3)'; + this.dropdownEl.style.transform = 'scale(0.3, 0.3)'; setTimeout(() => { this._resetDropdownStyles(); - if (typeof this.options.onCloseEnd === 'function') this.options.onCloseEnd.call(this, this.el); + if (typeof this.options.onCloseEnd === 'function') + this.options.onCloseEnd.call(this, this.el); }, duration); } @@ -557,18 +558,24 @@ export class Dropdown extends Component implements Openable { ancestor = ancestor.parentElement; } return null; - }; + } _placeDropdown() { // Container here will be closest ancestor with overflow: hidden - let closestOverflowParent: HTMLElement = this._getClosestAncestor(this.dropdownEl, (ancestor: HTMLElement) => { - return !['HTML','BODY'].includes(ancestor.tagName) && getComputedStyle(ancestor).overflow !== 'visible'; - }); + let closestOverflowParent: HTMLElement = this._getClosestAncestor( + this.dropdownEl, + (ancestor: HTMLElement) => { + return ( + !['HTML', 'BODY'].includes(ancestor.tagName) && + getComputedStyle(ancestor).overflow !== 'visible' + ); + } + ); // Fallback if (!closestOverflowParent) { - closestOverflowParent = (!!this.dropdownEl.offsetParent - ? this.dropdownEl.offsetParent - : this.dropdownEl.parentNode); + closestOverflowParent = ( + (!!this.dropdownEl.offsetParent ? this.dropdownEl.offsetParent : this.dropdownEl.parentNode) + ); } if (getComputedStyle(closestOverflowParent).position === 'static') @@ -610,7 +617,7 @@ export class Dropdown extends Component implements Openable { // Do this one frame later so that we don't bind an event handler that's immediately // called when the event bubbles up to the document and closes the dropdown setTimeout(() => this._setupTemporaryEventHandlers(), 0); - } + }; /** * Close dropdown. @@ -628,7 +635,7 @@ export class Dropdown extends Component implements Openable { if (this.options.autoFocus) { this.el.focus(); } - } + }; /** * While dropdown is open, you can recalculate its dimensions if its contents have changed. @@ -642,6 +649,5 @@ export class Dropdown extends Component implements Openable { this.dropdownEl.style.transformOrigin = ''; this._placeDropdown(); } - } - + }; } diff --git a/src/forms.ts b/src/forms.ts index d85e6b6934..4565b4b914 100644 --- a/src/forms.ts +++ b/src/forms.ts @@ -1,13 +1,12 @@ -import { Utils } from "./utils"; +import { Utils } from './utils'; export class Forms { - /** * Resizes the given TextArea after updating the * value content dynamically. * @param textarea TextArea to be resized */ - static textareaAutoResize(textarea: HTMLTextAreaElement){ + static textareaAutoResize(textarea: HTMLTextAreaElement) { if (!textarea) { console.error('No textarea element found'); return; @@ -44,7 +43,7 @@ export class Forms { if (textarea.getAttribute('wrap') === 'off') { hiddenDiv.style.overflowWrap = 'normal'; // ('overflow-wrap', 'normal') - hiddenDiv.style.whiteSpace = 'pre'; //.css('white-space', 'pre'); + hiddenDiv.style.whiteSpace = 'pre'; //.css('white-space', 'pre'); } hiddenDiv.innerText = textarea.value + '\n'; @@ -55,10 +54,9 @@ export class Forms { // When textarea is hidden, width goes crazy. // Approximate with half of window size if (textarea.offsetWidth > 0 && textarea.offsetHeight > 0) { - hiddenDiv.style.width = textarea.getBoundingClientRect().width +'px'; // ('width', textarea.width() + 'px'); - } - else { - hiddenDiv.style.width = (window.innerWidth / 2)+'px' //css('width', window.innerWidth / 2 + 'px'); + hiddenDiv.style.width = textarea.getBoundingClientRect().width + 'px'; // ('width', textarea.width() + 'px'); + } else { + hiddenDiv.style.width = window.innerWidth / 2 + 'px'; //css('width', window.innerWidth / 2 + 'px'); } // Resize if the new height is greater than the @@ -67,66 +65,71 @@ export class Forms { const prevLength = parseInt(textarea.getAttribute('previous-length')); if (isNaN(originalHeight)) return; if (originalHeight <= hiddenDiv.clientHeight) { - textarea.style.height = hiddenDiv.clientHeight+'px'; //css('height', hiddenDiv.innerHeight() + 'px'); - } - else if (textarea.value.length < prevLength) { - // In case the new height is less than original height, it - // means the textarea has less text than before - // So we set the height to the original one - textarea.style.height = originalHeight+'px'; + textarea.style.height = hiddenDiv.clientHeight + 'px'; //css('height', hiddenDiv.innerHeight() + 'px'); + } else if (textarea.value.length < prevLength) { + // In case the new height is less than original height, it + // means the textarea has less text than before + // So we set the height to the original one + textarea.style.height = originalHeight + 'px'; } textarea.setAttribute('previous-length', textarea.value.length.toString()); - }; + } - static Init(){ - if (typeof document !== 'undefined') - document?.addEventListener("DOMContentLoaded", () => { + static Init() { + if (typeof document !== 'undefined') + document?.addEventListener('DOMContentLoaded', () => { document.addEventListener('keyup', (e: KeyboardEvent) => { const target = e.target; // Radio and Checkbox focus class - if (target instanceof HTMLInputElement && ['radio','checkbox'].includes(target.type)) { + if (target instanceof HTMLInputElement && ['radio', 'checkbox'].includes(target.type)) { // TAB, check if tabbing to radio or checkbox. if (Utils.keys.TAB.includes(e.key)) { target.classList.add('tabbed'); - target.addEventListener('blur', e => target.classList.remove('tabbed'), {once: true}); + target.addEventListener('blur', (e) => target.classList.remove('tabbed'), { + once: true + }); } } }); - document.querySelectorAll('.materialize-textarea').forEach((textArea: HTMLTextAreaElement) => { + document + .querySelectorAll('.materialize-textarea') + .forEach((textArea: HTMLTextAreaElement) => { Forms.InitTextarea(textArea); - }); + }); // File Input Path - document.querySelectorAll('.file-field input[type="file"]').forEach((fileInput: HTMLInputElement) => { + document + .querySelectorAll('.file-field input[type="file"]') + .forEach((fileInput: HTMLInputElement) => { Forms.InitFileInputPath(fileInput); - }); - + }); }); } - static InitTextarea(textarea: HTMLTextAreaElement){ - // Save Data in Element - textarea.setAttribute('original-height', textarea.getBoundingClientRect().height.toString()); - textarea.setAttribute('previous-length', textarea.value.length.toString()); - Forms.textareaAutoResize(textarea); + static InitTextarea(textarea: HTMLTextAreaElement) { + // Save Data in Element + textarea.setAttribute('original-height', textarea.getBoundingClientRect().height.toString()); + textarea.setAttribute('previous-length', textarea.value.length.toString()); + Forms.textareaAutoResize(textarea); - textarea.addEventListener('keyup', e => Forms.textareaAutoResize(textarea)); - textarea.addEventListener('keydown', e => Forms.textareaAutoResize(textarea)); + textarea.addEventListener('keyup', (e) => Forms.textareaAutoResize(textarea)); + textarea.addEventListener('keydown', (e) => Forms.textareaAutoResize(textarea)); } - static InitFileInputPath(fileInput: HTMLInputElement){ - fileInput.addEventListener('change', e => { - const fileField = fileInput.closest('.file-field'); - const pathInput = fileField.querySelector('input.file-path'); - const files = fileInput.files; - const filenames = []; - for (let i = 0; i < files.length; i++) { - filenames.push(files[i].name); - } - pathInput.value = filenames.join(', '); - pathInput.dispatchEvent(new Event('change',{bubbles:true, cancelable:true, composed:true})); - }); + static InitFileInputPath(fileInput: HTMLInputElement) { + fileInput.addEventListener('change', (e) => { + const fileField = fileInput.closest('.file-field'); + const pathInput = fileField.querySelector('input.file-path'); + const files = fileInput.files; + const filenames = []; + for (let i = 0; i < files.length; i++) { + filenames.push(files[i].name); + } + pathInput.value = filenames.join(', '); + pathInput.dispatchEvent( + new Event('change', { bubbles: true, cancelable: true, composed: true }) + ); + }); } - } diff --git a/src/materialbox.ts b/src/materialbox.ts index cecda59aed..8dccd2217f 100644 --- a/src/materialbox.ts +++ b/src/materialbox.ts @@ -1,5 +1,5 @@ -import { Utils } from "./utils"; -import { BaseOptions, Component, InitElements, MElement } from "./component"; +import { Utils } from './utils'; +import { BaseOptions, Component, InitElements, MElement } from './component'; export interface MaterialboxOptions extends BaseOptions { /** @@ -74,7 +74,7 @@ export class Materialbox extends Component { ...Materialbox.defaults, ...options }; - + this.overlayActive = false; this.doneAnimating = true; this.placeholder = document.createElement('div'); @@ -110,7 +110,10 @@ export class Materialbox extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): Materialbox | Materialbox[]{ + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): Materialbox | Materialbox[] { return super.init(els, options, Materialbox); } @@ -137,23 +140,21 @@ export class Materialbox extends Component { private _handleMaterialboxClick = () => { // If already modal, return to original - if (this.doneAnimating === false || (this.overlayActive && this.doneAnimating)) - this.close(); - else - this.open(); - } + if (this.doneAnimating === false || (this.overlayActive && this.doneAnimating)) this.close(); + else this.open(); + }; private _handleWindowScroll = () => { if (this.overlayActive) this.close(); - } + }; private _handleWindowResize = () => { if (this.overlayActive) this.close(); - } + }; private _handleWindowEscape = (e: KeyboardEvent) => { if (Utils.keys.ESC.includes(e.key) && this.doneAnimating && this.overlayActive) this.close(); - } + }; private _makeAncestorsOverflowVisible() { this._changedAncestorList = []; @@ -201,15 +202,19 @@ export class Materialbox extends Component { // to this.el.style.height = this.newHeight + 'px'; this.el.style.width = this.newWidth + 'px'; - this.el.style.left = (Utils.getDocumentScrollLeft() + + this.el.style.left = + Utils.getDocumentScrollLeft() + this.windowWidth / 2 - this._offset(this.placeholder).left - - this.newWidth / 2) + 'px'; + this.newWidth / 2 + + 'px'; - this.el.style.top = (Utils.getDocumentScrollTop() + + this.el.style.top = + Utils.getDocumentScrollTop() + this.windowHeight / 2 - this._offset(this.placeholder).top - - this.newHeight / 2) + 'px'; + this.newHeight / 2 + + 'px'; }, 1); setTimeout(() => { @@ -270,9 +275,10 @@ export class Materialbox extends Component { this.el.classList.remove('active'); this.doneAnimating = true; // Remove overflow overrides on ancestors - this._changedAncestorList.forEach(anchestor => anchestor.style.overflow = ''); + this._changedAncestorList.forEach((anchestor) => (anchestor.style.overflow = '')); // onCloseEnd callback - if (typeof this.options.onCloseEnd === 'function') this.options.onCloseEnd.call(this, this.el); + if (typeof this.options.onCloseEnd === 'function') + this.options.onCloseEnd.call(this, this.el); }, duration); } @@ -285,7 +291,7 @@ export class Materialbox extends Component { this._photoCaption.style.display = 'inline'; // Animate this._photoCaption.style.transition = 'none'; - this._photoCaption.style.opacity = '0' + this._photoCaption.style.opacity = '0'; const duration = this.options.inDuration; setTimeout(() => { this._photoCaption.style.transition = `opacity ${duration}ms ease`; @@ -305,9 +311,13 @@ export class Materialbox extends Component { private _addOverlay(): void { this._overlay = document.createElement('div'); this._overlay.id = 'materialbox-overlay'; - this._overlay.addEventListener('click', e => { - if (this.doneAnimating) this.close(); - }, {once: true}); + this._overlay.addEventListener( + 'click', + (e) => { + if (this.doneAnimating) this.close(); + }, + { once: true } + ); // Put before in origin image to preserve z-index layering. this.el.before(this._overlay); @@ -321,7 +331,7 @@ export class Materialbox extends Component { // Animate this._overlay.style.transition = 'none'; - this._overlay.style.opacity = '0' + this._overlay.style.opacity = '0'; const duration = this.options.inDuration; setTimeout(() => { this._overlay.style.transition = `opacity ${duration}ms ease`; @@ -350,7 +360,8 @@ export class Materialbox extends Component { this.el.classList.add('active'); this.overlayActive = true; // onOpenStart callback - if (typeof this.options.onOpenStart === 'function') this.options.onOpenStart.call(this, this.el); + if (typeof this.options.onOpenStart === 'function') + this.options.onOpenStart.call(this, this.el); // Set positioning for placeholder this.placeholder.style.width = this.placeholder.getBoundingClientRect().width + 'px'; this.placeholder.style.height = this.placeholder.getBoundingClientRect().height + 'px'; @@ -366,11 +377,11 @@ export class Materialbox extends Component { this.attrWidth = this.el.getAttribute('width'); this.attrHeight = this.el.getAttribute('height'); if (this.attrWidth) { - this.el.style.width = this.attrWidth+'px'; + this.el.style.width = this.attrWidth + 'px'; this.el.removeAttribute('width'); } if (this.attrHeight) { - this.el.style.width = this.attrHeight+'px'; + this.el.style.width = this.attrHeight + 'px'; this.el.removeAttribute('height'); } this._addOverlay(); @@ -386,8 +397,7 @@ export class Materialbox extends Component { const ratio = this.originalHeight / this.originalWidth; this.newWidth = this.windowWidth * 0.9; this.newHeight = this.windowWidth * 0.9 * ratio; - } - else { + } else { // Height first const ratio = this.originalWidth / this.originalHeight; this.newWidth = this.windowHeight * 0.9 * ratio; @@ -398,7 +408,7 @@ export class Materialbox extends Component { window.addEventListener('scroll', this._handleWindowScroll); window.addEventListener('resize', this._handleWindowResize); window.addEventListener('keyup', this._handleWindowEscape); - } + }; /** * Close materialbox. @@ -407,7 +417,8 @@ export class Materialbox extends Component { this._updateVars(); this.doneAnimating = false; // onCloseStart callback - if (typeof this.options.onCloseStart === 'function') this.options.onCloseStart.call(this, this.el); + if (typeof this.options.onCloseStart === 'function') + this.options.onCloseStart.call(this, this.el); //anim.remove(this.el); //anim.remove(this._overlay); //if (this.caption !== '') anim.remove(this._photoCaption); @@ -418,5 +429,5 @@ export class Materialbox extends Component { this._removeOverlay(); this._animateImageOut(); if (this.caption !== '') this._removeCaption(); - } + }; } diff --git a/src/modal.ts b/src/modal.ts index 5cd1265890..21512819be 100644 --- a/src/modal.ts +++ b/src/modal.ts @@ -1,5 +1,5 @@ -import { Utils } from "./utils"; -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Utils } from './utils'; +import { Component, BaseOptions, InitElements, MElement } from './component'; export interface ModalOptions extends BaseOptions { /** @@ -74,10 +74,9 @@ const _defaults = { }; export class Modal extends Component { - static _modalsOpen: number; static _count: number; - + /** * ID of the modal element. */ @@ -86,7 +85,7 @@ export class Modal extends Component { * If the modal is open. */ isOpen: boolean; - + private _openingTrigger: any; private _overlay: HTMLDivElement; private _nthModalOpened: number; @@ -99,7 +98,7 @@ export class Modal extends Component { ...Modal.defaults, ...options }; - + this.isOpen = false; this.id = this.el.id; this._openingTrigger = undefined; @@ -135,7 +134,10 @@ export class Modal extends Component { * @param options Component options. * @returns {Modal | Modal[]} */ - static init(els: HTMLElement | InitElements, options: Partial = {}): Modal | Modal[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): Modal | Modal[] { return super.init(els, options, Modal); } @@ -174,33 +176,33 @@ export class Modal extends Component { const modalInstance = (document.getElementById(modalId) as any).M_Modal; if (modalInstance) modalInstance.open(trigger); e.preventDefault(); - } + }; _handleOverlayClick = () => { if (this.options.dismissible) this.close(); - } + }; _handleModalCloseClick = (e: MouseEvent) => { const closeTrigger = (e.target as HTMLElement).closest('.modal-close'); if (closeTrigger) this.close(); - } + }; _handleKeydown = (e: KeyboardEvent) => { if (Utils.keys.ESC.includes(e.key) && this.options.dismissible) this.close(); - } + }; _handleFocus = (e: FocusEvent) => { // Only trap focus if this modal is the last model opened (prevents loops in nested modals). if (!this.el.contains(e.target as HTMLElement) && this._nthModalOpened === Modal._modalsOpen) { this.el.focus(); } - } + }; _animateIn() { // Set initial styles this._overlay.style.display = 'block'; this._overlay.style.opacity = '0'; - this.el.style.display = 'block'; + this.el.style.display = 'block'; this.el.style.opacity = '0'; const duration = this.options.inDuration; @@ -225,9 +227,8 @@ export class Modal extends Component { this.el.style.opacity = '1'; if (isBottomSheet) { this.el.style.bottom = '0'; - } - else { - this.el.style.top = this.options.endingTop; + } else { + this.el.style.top = this.options.endingTop; this.el.style.transform = 'scaleX(1) scaleY(1)'; } setTimeout(() => { @@ -261,9 +262,8 @@ export class Modal extends Component { this.el.style.opacity = '0'; if (isBottomSheet) { this.el.style.bottom = '-100%'; - } - else { - this.el.style.top = this.options.startingTop; + } else { + this.el.style.top = this.options.startingTop; this.el.style.transform = 'scaleX(0.9) scaleY(0.9)'; } setTimeout(() => { @@ -294,10 +294,11 @@ export class Modal extends Component { this.options.onOpenStart.call(this, this.el, this._openingTrigger); } if (this.options.preventScrolling) { - const hasVerticalScrollBar = document.documentElement.scrollHeight > document.documentElement.clientHeight + const hasVerticalScrollBar = + document.documentElement.scrollHeight > document.documentElement.clientHeight; if (hasVerticalScrollBar) { const scrollTop = document.documentElement.scrollTop; - document.documentElement.style.top = '-' + scrollTop + "px"; + document.documentElement.style.top = '-' + scrollTop + 'px'; document.documentElement.classList.add('noscroll'); } } @@ -311,7 +312,7 @@ export class Modal extends Component { // Focus modal this.el.focus(); return this; - } + }; /** * Close modal. @@ -329,7 +330,7 @@ export class Modal extends Component { // Enable body scrolling only if there are no more modals open. if (Modal._modalsOpen === 0) { const scrollTop = -parseInt(document.documentElement.style.top); - document.documentElement.style.removeProperty("top"); + document.documentElement.style.removeProperty('top'); document.documentElement.classList.remove('noscroll'); document.documentElement.scrollTop = scrollTop; } @@ -339,7 +340,7 @@ export class Modal extends Component { } this._animateOut(); return this; - } + }; // Experimental! // also note: https://stackoverflow.com/a/35385518/8830502 @@ -355,7 +356,7 @@ export class Modal extends Component { `; } - static{ + static { Modal._modalsOpen = 0; Modal._count = 0; } diff --git a/src/parallax.ts b/src/parallax.ts index 1662674aa3..653e23e41e 100644 --- a/src/parallax.ts +++ b/src/parallax.ts @@ -1,5 +1,5 @@ -import { Utils } from "./utils"; -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Utils } from './utils'; +import { Component, BaseOptions, InitElements, MElement } from './component'; export interface ParallaxOptions extends BaseOptions { /** @@ -28,7 +28,7 @@ export class Parallax extends Component { ...Parallax.defaults, ...options }; - + this._enabled = window.innerWidth > this.options.responsiveThreshold; this._img = this.el.querySelector('img'); this._updateParallax(); @@ -58,7 +58,10 @@ export class Parallax extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): Parallax | Parallax[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): Parallax | Parallax[] { return super.init(els, options, Parallax); } @@ -83,18 +86,17 @@ export class Parallax extends Component { static _handleWindowResize() { for (let i = 0; i < Parallax._parallaxes.length; i++) { let parallaxInstance = Parallax._parallaxes[i]; - parallaxInstance._enabled = - window.innerWidth > parallaxInstance.options.responsiveThreshold; + parallaxInstance._enabled = window.innerWidth > parallaxInstance.options.responsiveThreshold; } } _setupEventHandlers() { this._img.addEventListener('load', this._handleImageLoad); if (Parallax._parallaxes.length === 0) { - if (!Parallax._handleScrollThrottled){ + if (!Parallax._handleScrollThrottled) { Parallax._handleScrollThrottled = Utils.throttle(Parallax._handleScroll, 5); } - if (!Parallax._handleWindowResizeThrottled){ + if (!Parallax._handleWindowResizeThrottled) { Parallax._handleWindowResizeThrottled = Utils.throttle(Parallax._handleWindowResize, 5); } window.addEventListener('scroll', Parallax._handleScrollThrottled); @@ -116,7 +118,7 @@ export class Parallax extends Component { _handleImageLoad = () => { this._updateParallax(); - } + }; private _offset(el: Element) { const box = el.getBoundingClientRect(); @@ -128,7 +130,8 @@ export class Parallax extends Component { } _updateParallax() { - const containerHeight = this.el.getBoundingClientRect().height > 0 ? (this.el.parentNode as any).offsetHeight : 500; + const containerHeight = + this.el.getBoundingClientRect().height > 0 ? (this.el.parentNode as any).offsetHeight : 500; const imgHeight = this._img.offsetHeight; const parallaxDist = imgHeight - containerHeight; const bottom = this._offset(this.el).top + containerHeight; @@ -141,8 +144,7 @@ export class Parallax extends Component { if (!this._enabled) { this._img.style.transform = ''; - } - else if (bottom > scrollTop && top < scrollTop + windowHeight) { + } else if (bottom > scrollTop && top < scrollTop + windowHeight) { this._img.style.transform = `translate3D(-50%, ${parallax}px, 0)`; } } diff --git a/src/pushpin.ts b/src/pushpin.ts index 5a17e16ea6..64e137d0dc 100644 --- a/src/pushpin.ts +++ b/src/pushpin.ts @@ -1,5 +1,5 @@ -import { Utils } from "./utils"; -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Utils } from './utils'; +import { Component, BaseOptions, InitElements, MElement } from './component'; export interface PushpinOptions extends BaseOptions { /** @@ -24,7 +24,7 @@ export interface PushpinOptions extends BaseOptions { * You are provided with a position string. * @default null */ - onPositionChange: (position: "pinned" | "pin-top" | "pin-bottom") => void; + onPositionChange: (position: 'pinned' | 'pin-top' | 'pin-bottom') => void; } let _defaults = { @@ -74,7 +74,10 @@ export class Pushpin extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): Pushpin | Pushpin[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): Pushpin | Pushpin[] { return super.init(els, options, Pushpin); } diff --git a/src/range.ts b/src/range.ts index 46ed147ef6..161df244e2 100644 --- a/src/range.ts +++ b/src/range.ts @@ -1,6 +1,6 @@ -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Component, BaseOptions, InitElements, MElement } from './component'; -export interface RangeOptions extends BaseOptions {}; +export interface RangeOptions extends BaseOptions {} const _defaults: RangeOptions = {}; @@ -41,13 +41,19 @@ export class Range extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: InitElements, options?: Partial): Range[]; + static init( + els: InitElements, + options?: Partial + ): Range[]; /** * Initializes instances of Range. * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLInputElement | InitElements, options: Partial = {}): Range | Range[] { + static init( + els: HTMLInputElement | InitElements, + options: Partial = {} + ): Range | Range[] { return super.init(els, options, Range); } @@ -96,8 +102,8 @@ export class Range extends Component { } const offsetLeft = this._calcRangeOffset(); this.thumb.classList.add('active'); - this.thumb.style.left = offsetLeft+'px'; - } + this.thumb.style.left = offsetLeft + 'px'; + }; _handleRangeMousedownTouchstart = (e: MouseEvent | TouchEvent) => { // Set indicator value @@ -110,9 +116,9 @@ export class Range extends Component { if (e.type !== 'input') { const offsetLeft = this._calcRangeOffset(); this.thumb.classList.add('active'); - this.thumb.style.left = offsetLeft+'px'; + this.thumb.style.left = offsetLeft + 'px'; } - } + }; _handleRangeInputMousemoveTouchmove = () => { if (this._mousedown) { @@ -121,15 +127,15 @@ export class Range extends Component { } const offsetLeft = this._calcRangeOffset(); this.thumb.classList.add('active'); - this.thumb.style.left = offsetLeft+'px'; + this.thumb.style.left = offsetLeft + 'px'; this.value.innerHTML = this.el.value; } - } + }; _handleRangeMouseupTouchend = () => { this._mousedown = false; this.el.classList.remove('active'); - } + }; _handleRangeBlurMouseoutTouchleave = () => { if (!this._mousedown) { @@ -146,7 +152,7 @@ export class Range extends Component { top ${duration}ms ease, margin ${duration}ms ease `; - // to + // to this.thumb.style.height = '0'; this.thumb.style.width = '0'; this.thumb.style.top = '0'; @@ -155,7 +161,7 @@ export class Range extends Component { } this.thumb.classList.remove('active'); } - } + }; _setupThumb() { this.thumb = document.createElement('span'); @@ -199,8 +205,11 @@ export class Range extends Component { /** * Initializes every range input in the current document. */ - static Init(){ - if (typeof document !== 'undefined') - Range.init((document?.querySelectorAll('input[type=range]')) as NodeListOf, {}); + static Init() { + if (typeof document !== 'undefined') + Range.init( + document?.querySelectorAll('input[type=range]') as NodeListOf, + {} + ); } } diff --git a/src/scrollspy.ts b/src/scrollspy.ts index 143420310b..47beb06077 100644 --- a/src/scrollspy.ts +++ b/src/scrollspy.ts @@ -1,5 +1,5 @@ -import { Utils } from "./utils"; -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Utils } from './utils'; +import { Component, BaseOptions, InitElements, MElement } from './component'; export interface ScrollSpyOptions extends BaseOptions { /** @@ -22,13 +22,15 @@ export interface ScrollSpyOptions extends BaseOptions { * @default id => 'a[href="#' + id + '"]' */ getActiveElement: (id: string) => string; -}; +} let _defaults: ScrollSpyOptions = { throttle: 100, scrollOffset: 200, // offset - 200 allows elements near bottom of page to scroll activeClass: 'active', - getActiveElement: (id: string): string => { return 'a[href="#'+id+'"]'; } + getActiveElement: (id: string): string => { + return 'a[href="#' + id + '"]'; + } }; export class ScrollSpy extends Component { @@ -80,7 +82,10 @@ export class ScrollSpy extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): ScrollSpy | ScrollSpy[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): ScrollSpy | ScrollSpy[] { return super.init(els, options, ScrollSpy); } @@ -115,20 +120,22 @@ export class ScrollSpy extends Component { } } - _handleThrottledResize: () => void = Utils.throttle(function(){ this._handleWindowScroll(); }, 200).bind(this); + _handleThrottledResize: () => void = Utils.throttle(function () { + this._handleWindowScroll(); + }, 200).bind(this); _handleTriggerClick = (e: MouseEvent) => { const trigger = e.target; for (let i = ScrollSpy._elements.length - 1; i >= 0; i--) { const scrollspy = ScrollSpy._elements[i]; - const x = document.querySelector('a[href="#'+scrollspy.el.id+'"]'); + const x = document.querySelector('a[href="#' + scrollspy.el.id + '"]'); if (trigger === x) { e.preventDefault(); - scrollspy.el.scrollIntoView({behavior: 'smooth'}); + scrollspy.el.scrollIntoView({ behavior: 'smooth' }); break; } } - } + }; _handleWindowScroll = () => { // unique tick id @@ -165,7 +172,7 @@ export class ScrollSpy extends Component { } // remember elements in view for next tick ScrollSpy._elementsInView = intersections; - } + }; static _offset(el) { const box = el.getBoundingClientRect(); @@ -204,20 +211,25 @@ export class ScrollSpy extends Component { } _enter() { - ScrollSpy._visibleElements = ScrollSpy._visibleElements.filter(value => value.getBoundingClientRect().height !== 0); + ScrollSpy._visibleElements = ScrollSpy._visibleElements.filter( + (value) => value.getBoundingClientRect().height !== 0 + ); if (ScrollSpy._visibleElements[0]) { - const actElem = document.querySelector(this.options.getActiveElement(ScrollSpy._visibleElements[0].id)); + const actElem = document.querySelector( + this.options.getActiveElement(ScrollSpy._visibleElements[0].id) + ); actElem?.classList.remove(this.options.activeClass); - if (ScrollSpy._visibleElements[0].M_ScrollSpy && this.id < ScrollSpy._visibleElements[0].M_ScrollSpy.id) { + if ( + ScrollSpy._visibleElements[0].M_ScrollSpy && + this.id < ScrollSpy._visibleElements[0].M_ScrollSpy.id + ) { ScrollSpy._visibleElements.unshift(this.el); - } - else { + } else { ScrollSpy._visibleElements.push(this.el); } - } - else { + } else { ScrollSpy._visibleElements.push(this.el); } const selector = this.options.getActiveElement(ScrollSpy._visibleElements[0].id); @@ -225,10 +237,14 @@ export class ScrollSpy extends Component { } _exit() { - ScrollSpy._visibleElements = ScrollSpy._visibleElements.filter(value => value.getBoundingClientRect().height !== 0); + ScrollSpy._visibleElements = ScrollSpy._visibleElements.filter( + (value) => value.getBoundingClientRect().height !== 0 + ); if (ScrollSpy._visibleElements[0]) { - const actElem = document.querySelector(this.options.getActiveElement(ScrollSpy._visibleElements[0].id)); + const actElem = document.querySelector( + this.options.getActiveElement(ScrollSpy._visibleElements[0].id) + ); actElem?.classList.remove(this.options.activeClass); ScrollSpy._visibleElements = ScrollSpy._visibleElements.filter((x) => x.id != this.el.id); diff --git a/src/select.ts b/src/select.ts index 5e1124120a..088c5c5e3b 100644 --- a/src/select.ts +++ b/src/select.ts @@ -1,6 +1,6 @@ -import { Utils } from "./utils"; -import { Dropdown, DropdownOptions } from "./dropdown"; -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Utils } from './utils'; +import { Dropdown, DropdownOptions } from './dropdown'; +import { Component, BaseOptions, InitElements, MElement } from './component'; export interface FormSelectOptions extends BaseOptions { /** @@ -21,9 +21,9 @@ let _defaults: FormSelectOptions = { }; type ValueStruct = { - el: HTMLOptionElement, - optionEl: HTMLElement, -} + el: HTMLOptionElement; + optionEl: HTMLElement; +}; export class FormSelect extends Component { declare el: HTMLSelectElement; @@ -42,7 +42,7 @@ export class FormSelect extends Component { dropdown: Dropdown; /** The select wrapper element. */ wrapper: HTMLDivElement; - selectOptions: (HTMLOptionElement|HTMLOptGroupElement)[]; + selectOptions: (HTMLOptionElement | HTMLOptGroupElement)[]; private _values: ValueStruct[]; constructor(el: HTMLSelectElement, options: FormSelectOptions) { @@ -54,7 +54,7 @@ export class FormSelect extends Component { ...FormSelect.defaults, ...options }; - + this.isMultiple = this.el.multiple; this.el.tabIndex = -1; this._values = []; @@ -77,13 +77,19 @@ export class FormSelect extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: InitElements, options?: Partial): FormSelect[]; + static init( + els: InitElements, + options?: Partial + ): FormSelect[]; /** * Initializes instances of FormSelect. * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLSelectElement | InitElements, options: Partial = {}): FormSelect | FormSelect[] { + static init( + els: HTMLSelectElement | InitElements, + options: Partial = {} + ): FormSelect | FormSelect[] { return super.init(els, options, FormSelect); } @@ -101,7 +107,7 @@ export class FormSelect extends Component { this.dropdownOptions.querySelectorAll('li:not(.optgroup)').forEach((el) => { el.addEventListener('click', this._handleOptionClick); el.addEventListener('keydown', (e: KeyboardEvent) => { - if (e.key === " " || e.key === "Enter") this._handleOptionClick(e); + if (e.key === ' ' || e.key === 'Enter') this._handleOptionClick(e); }); }); this.el.addEventListener('change', this._handleSelectChange); @@ -118,16 +124,16 @@ export class FormSelect extends Component { _handleSelectChange = () => { this._setValueToInput(); - } + }; _handleOptionClick = (e: MouseEvent | KeyboardEvent) => { e.preventDefault(); const virtualOption = (e.target as HTMLLIElement).closest('li'); this._selectOptionElement(virtualOption); e.stopPropagation(); - } + }; - _arraysEqual(a: T[], b: (E|T)[]) { + _arraysEqual(a: T[], b: (E | T)[]) { if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; @@ -136,14 +142,16 @@ export class FormSelect extends Component { } _selectOptionElement(virtualOption: HTMLElement) { - if (!virtualOption.classList.contains('disabled') && !virtualOption.classList.contains('optgroup')) { + if ( + !virtualOption.classList.contains('disabled') && + !virtualOption.classList.contains('optgroup') + ) { const value = this._values.find((value) => value.optionEl === virtualOption); const previousSelectedValues = this.getSelectedValues(); if (this.isMultiple) { // Multi-Select this._toggleEntryFromArray(value); - } - else { + } else { // Single-Select this._deselectAll(); this._selectValue(value); @@ -152,11 +160,11 @@ export class FormSelect extends Component { this._setValueToInput(); // Trigger Change-Event only when data is different const actualSelectedValues = this.getSelectedValues(); - const selectionHasChanged = !this._arraysEqual( - previousSelectedValues, - actualSelectedValues - ); - if (selectionHasChanged) this.el.dispatchEvent(new Event('change',{bubbles:true, cancelable:true, composed:true})); // trigger('change'); + const selectionHasChanged = !this._arraysEqual(previousSelectedValues, actualSelectedValues); + if (selectionHasChanged) + this.el.dispatchEvent( + new Event('change', { bubbles: true, cancelable: true, composed: true }) + ); // trigger('change'); } if (!this.isMultiple) this.dropdown.close(); } @@ -166,10 +174,10 @@ export class FormSelect extends Component { this._setValueToInput(); this._setSelectedStates(); } - } + }; _setupDropdown() { - this.labelEl = document.querySelector('[for="'+this.el.id+'"]'); + this.labelEl = document.querySelector('[for="' + this.el.id + '"]'); if (this.labelEl) this.labelEl.style.display = 'none'; this.wrapper = document.createElement('div'); @@ -187,7 +195,9 @@ export class FormSelect extends Component { if (this.el.disabled) this.wrapper.classList.add('disabled'); - this.selectOptions = <(HTMLOptGroupElement|HTMLOptionElement)[]>Array.from(this.el.children).filter(el => ['OPTION','OPTGROUP'].includes(el.tagName)); + this.selectOptions = <(HTMLOptGroupElement | HTMLOptionElement)[]>( + Array.from(this.el.children).filter((el) => ['OPTION', 'OPTGROUP'].includes(el.tagName)) + ); // Create dropdown this.dropdownOptions = document.createElement('ul'); @@ -202,12 +212,14 @@ export class FormSelect extends Component { this.selectOptions.forEach((realOption) => { if (realOption.tagName === 'OPTION') { // Option - const virtualOption = this._createAndAppendOptionWithIcon(realOption, this.isMultiple ? 'multiple' : undefined); + const virtualOption = this._createAndAppendOptionWithIcon( + realOption, + this.isMultiple ? 'multiple' : undefined + ); this._addOptionToValues(realOption as HTMLOptionElement, virtualOption); - } - else if (realOption.tagName === 'OPTGROUP') { + } else if (realOption.tagName === 'OPTGROUP') { // Optgroup - const groupId = "opt-group-"+Utils.guid(); + const groupId = 'opt-group-' + Utils.guid(); const groupParent = document.createElement('li'); groupParent.classList.add('optgroup'); groupParent.tabIndex = -1; @@ -217,15 +229,20 @@ export class FormSelect extends Component { this.dropdownOptions.append(groupParent); const groupChildren = []; - const selectOptions = Array.from(realOption.children).filter(el => el.tagName === 'OPTION'); - selectOptions.forEach(realOption => { - const virtualOption = this._createAndAppendOptionWithIcon(realOption, 'optgroup-option'); - const childId = "opt-child-"+Utils.guid(); + const selectOptions = ( + Array.from(realOption.children).filter((el) => el.tagName === 'OPTION') + ); + selectOptions.forEach((realOption) => { + const virtualOption = this._createAndAppendOptionWithIcon( + realOption, + 'optgroup-option' + ); + const childId = 'opt-child-' + Utils.guid(); virtualOption.id = childId; groupChildren.push(childId); this._addOptionToValues(realOption, virtualOption); }); - groupParent.setAttribute("aria-owns", groupChildren.join(" ")); + groupParent.setAttribute('aria-owns', groupChildren.join(' ')); } }); } @@ -233,28 +250,27 @@ export class FormSelect extends Component { // Add input dropdown this.input = document.createElement('input'); - this.input.id = "m_select-input-" + Utils.guid(); + this.input.id = 'm_select-input-' + Utils.guid(); this.input.classList.add('select-dropdown', 'dropdown-trigger'); this.input.type = 'text'; this.input.readOnly = true; this.input.setAttribute('data-target', this.dropdownOptions.id); this.input.ariaReadOnly = 'true'; - this.input.ariaRequired = this.el.hasAttribute("required").toString(); //setAttribute("aria-required", this.el.hasAttribute("required")); + this.input.ariaRequired = this.el.hasAttribute('required').toString(); //setAttribute("aria-required", this.el.hasAttribute("required")); if (this.el.disabled) this.input.disabled = true; // 'true'); const attrs = this.el.attributes; - for (let i = 0; i < attrs.length; ++i){ + for (let i = 0; i < attrs.length; ++i) { const attr = attrs[i]; - if (attr.name.startsWith("aria-")) - this.input.setAttribute(attr.name, attr.value); + if (attr.name.startsWith('aria-')) this.input.setAttribute(attr.name, attr.value); } // Adds aria-attributes to input element this.input.setAttribute('role', 'combobox'); this.input.ariaExpanded = 'false'; - this.input.setAttribute("aria-owns", this.dropdownOptions.id); - this.input.setAttribute("aria-controls", this.dropdownOptions.id); - this.input.placeholder = " "; + this.input.setAttribute('aria-owns', this.dropdownOptions.id); + this.input.setAttribute('aria-controls', this.dropdownOptions.id); + this.input.placeholder = ' '; this.wrapper.prepend(this.input); this._setValueToInput(); @@ -271,7 +287,7 @@ export class FormSelect extends Component { // Initialize dropdown if (!this.el.disabled) { - const dropdownOptions = {...this.options.dropdownOptions}; // TODO: + const dropdownOptions = { ...this.options.dropdownOptions }; // TODO: dropdownOptions.coverTrigger = false; const userOnOpenEnd = dropdownOptions.onOpenEnd; const userOnCloseEnd = dropdownOptions.onCloseEnd; @@ -281,7 +297,9 @@ export class FormSelect extends Component { if (selectedOption) { // Focus selected option in dropdown Utils.keyDown = true; - this.dropdown.focusedIndex = [...selectedOption.parentNode.children].indexOf(selectedOption); + this.dropdown.focusedIndex = [...selectedOption.parentNode.children].indexOf( + selectedOption + ); this.dropdown._focusFocusedItem(); Utils.keyDown = false; // Handle scrolling to selected option @@ -333,10 +351,13 @@ export class FormSelect extends Component { this.wrapper.remove(); } - _createAndAppendOptionWithIcon(realOption: HTMLOptionElement|HTMLOptGroupElement, type: string) { + _createAndAppendOptionWithIcon( + realOption: HTMLOptionElement | HTMLOptGroupElement, + type: string + ) { const li = document.createElement('li'); li.setAttribute('role', 'option'); - if (realOption.disabled){ + if (realOption.disabled) { li.classList.add('disabled'); li.ariaDisabled = 'true'; } @@ -382,7 +403,7 @@ export class FormSelect extends Component { } _deselectAll() { - this._values.forEach(value => this._deselectValue(value)); + this._values.forEach((value) => this._deselectValue(value)); } _isValueSelected(value: ValueStruct) { @@ -391,23 +412,28 @@ export class FormSelect extends Component { } _toggleEntryFromArray(value: ValueStruct) { - if (this._isValueSelected(value)) - this._deselectValue(value); - else - this._selectValue(value); + if (this._isValueSelected(value)) this._deselectValue(value); + else this._selectValue(value); } _getSelectedOptions(): HTMLOptionElement[] { // remove null, false, ... values - return Array.prototype.filter.call(this.el.selectedOptions, (realOption: HTMLOptionElement) => realOption); + return Array.prototype.filter.call( + this.el.selectedOptions, + (realOption: HTMLOptionElement) => realOption + ); } _setValueToInput() { const selectedRealOptions = this._getSelectedOptions(); - const selectedOptionPairs = this._values.filter((value) => selectedRealOptions.indexOf(value.el) >= 0); + const selectedOptionPairs = this._values.filter( + (value) => selectedRealOptions.indexOf(value.el) >= 0 + ); // Filter not disabled - const notDisabledOptionPairs = selectedOptionPairs.filter(op => !op.el.disabled); - const texts = notDisabledOptionPairs.map((value) => value.optionEl.querySelector('span').innerText.trim()); + const notDisabledOptionPairs = selectedOptionPairs.filter((op) => !op.el.disabled); + const texts = notDisabledOptionPairs.map((value) => + value.optionEl.querySelector('span').innerText.trim() + ); // Set input-text to first Option with empty value which indicates a description like "choose your option" if (texts.length === 0) { const firstDisabledOption = this.el.querySelector('option:disabled'); @@ -426,8 +452,7 @@ export class FormSelect extends Component { if (cb) cb.checked = optionIsSelected; if (optionIsSelected) { this._activateOption(this.dropdownOptions, value.optionEl); - } - else { + } else { value.optionEl.classList.remove('selected'); value.optionEl.ariaSelected = 'false'; // attr("aria-selected", 'false'); } @@ -436,7 +461,8 @@ export class FormSelect extends Component { _activateOption(ul: HTMLElement, li: HTMLElement) { if (!li) return; - if (!this.isMultiple) ul.querySelectorAll('li.selected').forEach(li => li.classList.remove('selected')); + if (!this.isMultiple) + ul.querySelectorAll('li.selected').forEach((li) => li.classList.remove('selected')); li.classList.add('selected'); li.ariaSelected = 'true'; } diff --git a/src/sidenav.ts b/src/sidenav.ts index 122faff759..59fc3aee99 100644 --- a/src/sidenav.ts +++ b/src/sidenav.ts @@ -1,5 +1,5 @@ -import { Utils } from "./utils"; -import { Component, BaseOptions, InitElements, MElement, Openable } from "./component"; +import { Utils } from './utils'; +import { Component, BaseOptions, InitElements, MElement, Openable } from './component'; export interface SidenavOptions extends BaseOptions { /** @@ -131,7 +131,10 @@ export class Sidenav extends Component implements Openable { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): Sidenav | Sidenav[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): Sidenav | Sidenav[] { return super.init(els, options, Sidenav); } @@ -269,7 +272,7 @@ export class Sidenav extends Component implements Openable { // Set transform and opacity styles this.el.style.transform = `${transformPrefix} translateX(${transformX}px)`; this._overlay.style.opacity = this.percentOpen.toString(); - } + }; private _handleDragTargetRelease = () => { if (this.isDragged) { @@ -281,7 +284,7 @@ export class Sidenav extends Component implements Openable { this.isDragged = false; this._verticallyScrolling = false; } - } + }; private _handleCloseDrag = (e) => { if (this.isOpen) { @@ -314,7 +317,7 @@ export class Sidenav extends Component implements Openable { this.el.style.transform = `translateX(${transformX}px)`; this._overlay.style.opacity = this.percentOpen.toString(); } - } + }; private _handleCloseRelease = () => { if (this.isOpen && this.isDragged) { @@ -326,7 +329,7 @@ export class Sidenav extends Component implements Openable { this.isDragged = false; this._verticallyScrolling = false; } - } + }; // Handles closing of Sidenav when element with class .sidenav-close private _handleCloseTriggerClick = (e) => { @@ -334,7 +337,7 @@ export class Sidenav extends Component implements Openable { if (closeTrigger && !this._isCurrentlyFixed()) { this.close(); } - } + }; private _handleWindowResize = () => { // Only handle horizontal resizes @@ -347,7 +350,7 @@ export class Sidenav extends Component implements Openable { } this.lastWindowWidth = window.innerWidth; this.lastWindowHeight = window.innerHeight; - } + }; private _setupClasses() { if (this.options.edge === 'right') { @@ -407,7 +410,7 @@ export class Sidenav extends Component implements Openable { if (this.options.preventScrolling) this._preventBodyScrolling(); if (!this.isDragged || this.percentOpen != 1) this._animateIn(); } - } + }; /** * Closes Sidenav. @@ -433,7 +436,7 @@ export class Sidenav extends Component implements Openable { this._overlay.style.display = 'none'; } } - } + }; private _animateIn() { this._animateSidenavIn(); @@ -456,7 +459,7 @@ export class Sidenav extends Component implements Openable { const duration = this.options.inDuration; // from this.el.style.transition = 'none'; - this.el.style.transform = 'translateX(' + (slideOutPercent * 100) + '%)'; + this.el.style.transform = 'translateX(' + slideOutPercent * 100 + '%)'; setTimeout(() => { this.el.style.transition = `transform ${duration}ms ease`; // easeOutQuad // to @@ -480,18 +483,17 @@ export class Sidenav extends Component implements Openable { const duration = this.options.outDuration; this.el.style.transition = `transform ${duration}ms ease`; // easeOutQuad // to - this.el.style.transform = 'translateX(' + (endPercent * 100) + '%)'; + this.el.style.transform = 'translateX(' + endPercent * 100 + '%)'; setTimeout(() => { - if (typeof this.options.onCloseEnd === 'function') this.options.onCloseEnd.call(this, this.el); + if (typeof this.options.onCloseEnd === 'function') + this.options.onCloseEnd.call(this, this.el); }, duration); } private _animateOverlayIn() { let start = 0; - if (this.isDragged) - start = this.percentOpen; - else - this._overlay.style.display = 'block'; + if (this.isDragged) start = this.percentOpen; + else this._overlay.style.display = 'block'; // Animation const duration = this.options.inDuration; // from @@ -501,7 +503,7 @@ export class Sidenav extends Component implements Openable { setTimeout(() => { this._overlay.style.transition = `opacity ${duration}ms ease`; // to - this._overlay.style.opacity = '1'; + this._overlay.style.opacity = '1'; }, 1); } @@ -510,13 +512,13 @@ export class Sidenav extends Component implements Openable { // easeOutQuad this._overlay.style.transition = `opacity ${duration}ms ease`; // to - this._overlay.style.opacity = '0'; + this._overlay.style.opacity = '0'; setTimeout(() => { this._overlay.style.display = 'none'; }, duration); } - static { + static { Sidenav._sidenavs = []; } } diff --git a/src/slider.ts b/src/slider.ts index 880a4a3230..c58fb998bb 100644 --- a/src/slider.ts +++ b/src/slider.ts @@ -1,5 +1,5 @@ -import { Utils } from "./utils"; -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Utils } from './utils'; +import { Component, BaseOptions, InitElements, MElement } from './component'; export interface SliderOptions extends BaseOptions { /** @@ -39,7 +39,7 @@ export interface SliderOptions extends BaseOptions { * @returns a string to be used as label indicator. * @default null */ - indicatorLabelFunc: (index: number, current: boolean) => string + indicatorLabelFunc: (index: number, current: boolean) => string; } let _defaults: SliderOptions = { @@ -85,7 +85,7 @@ export class Slider extends Component { // setup this._slider = this.el.querySelector('.slides'); this._slides = Array.from(this._slider.querySelectorAll('li')); - this.activeIndex = this._slides.findIndex(li => li.classList.contains('active')); + this.activeIndex = this._slides.findIndex((li) => li.classList.contains('active')); if (this.activeIndex !== -1) { this._activeSlide = this._slides[this.activeIndex]; @@ -94,16 +94,16 @@ export class Slider extends Component { this._setSliderHeight(); // Sets element id if it does not have one - if (this._slider.hasAttribute('id')) - this._sliderId = this._slider.getAttribute('id'); + if (this._slider.hasAttribute('id')) this._sliderId = this._slider.getAttribute('id'); else { this._sliderId = 'slider-' + Utils.guid(); this._slider.setAttribute('id', this._sliderId); } - const placeholderBase64 = 'data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; + const placeholderBase64 = + 'data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; // Set initial positions of captions - this._slides.forEach(slide => { + this._slides.forEach((slide) => { // Caption //const caption = slide.querySelector('.caption'); //if (caption) this._animateCaptionIn(caption, 0); @@ -111,13 +111,12 @@ export class Slider extends Component { const img = slide.querySelector('img'); if (img) { if (img.src !== placeholderBase64) { - img.style.backgroundImage = 'url('+ img.src +')'; + img.style.backgroundImage = 'url(' + img.src + ')'; img.src = placeholderBase64; } } // Sets slide as focusable by code - if (!slide.hasAttribute('tabindex')) - slide.setAttribute('tabindex', '-1'); + if (!slide.hasAttribute('tabindex')) slide.setAttribute('tabindex', '-1'); // Removes initial visibility from "inactive" slides slide.style.visibility = 'hidden'; }); @@ -128,8 +127,7 @@ export class Slider extends Component { if (this._activeSlide) { this._activeSlide.style.display = 'block'; this._activeSlide.style.visibility = 'visible'; - } - else { + } else { this.activeIndex = 0; this._slides[0].classList.add('active'); this._slides[0].style.visibility = 'visible'; @@ -166,7 +164,10 @@ export class Slider extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): Slider | Slider[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): Slider | Slider[] { return super.init(els, options, Slider); } @@ -218,48 +219,48 @@ export class Slider extends Component { const currIndex = [...el.parentNode.children].indexOf(el); this._focusCurrent = true; this.set(currIndex); - } + }; private _handleAutoPauseHover = () => { this._hovered = true; if (this.interval != null) { this._pause(true); } - } + }; private _handleAutoPauseFocus = () => { this._focused = true; if (this.interval != null) { this._pause(true); } - } + }; private _handleAutoStartHover = () => { this._hovered = false; if (!(this.options.pauseOnFocus && this._focused) && this.eventPause) { this.start(); } - } + }; private _handleAutoStartFocus = () => { this._focused = false; if (!(this.options.pauseOnHover && this._hovered) && this.eventPause) { this.start(); } - } + }; private _handleInterval = () => { const activeElem = this._slider.querySelector('.active'); let newActiveIndex = [...activeElem.parentNode.children].indexOf(activeElem); if (this._slides.length === newActiveIndex + 1) newActiveIndex = 0; // loop to start - else - newActiveIndex += 1; + else newActiveIndex += 1; this.set(newActiveIndex); - } + }; private _animateSlide(slide: HTMLElement, isDirectionIn: boolean): void { - let dx = 0, dy = 0; + let dx = 0, + dy = 0; // from slide.style.opacity = isDirectionIn ? '0' : '1'; setTimeout(() => { @@ -289,9 +290,8 @@ export class Slider extends Component { if (!this.el.classList.contains('fullscreen')) { if (this.options.indicators) { // Add height if indicators are present - this.el.style.height = (this.options.height + 40)+'px'; //.css('height', this.options.height + 40 + 'px'); - } - else { + this.el.style.height = this.options.height + 40 + 'px'; //.css('height', this.options.height + 40 + 'px'); + } else { this.el.style.height = this.options.height + 'px'; } this._slider.style.height = this.options.height + 'px'; @@ -333,23 +333,22 @@ export class Slider extends Component { if (this.activeIndex === index) return; this._activeSlide = this._slides[this.activeIndex]; - const _caption = this._activeSlide.querySelector('.caption'); + const _caption = this._activeSlide.querySelector('.caption'); this._activeSlide.classList.remove('active'); // Enables every slide - this._slides.forEach(slide => slide.style.visibility = 'visible'); + this._slides.forEach((slide) => (slide.style.visibility = 'visible')); //--- Hide active Slide + Caption this._activeSlide.style.opacity = '0'; setTimeout(() => { - this._slides.forEach(slide => { + this._slides.forEach((slide) => { if (slide.classList.contains('active')) return; slide.style.opacity = '0'; slide.style.transform = 'translate(0, 0)'; // Disables invisible slides (for assistive technologies) slide.style.visibility = 'hidden'; }); - }, this.options.duration); // Hide active Caption @@ -362,8 +361,12 @@ export class Slider extends Component { const nextIndicator = this._indicators[index].children[0]; activeIndicator.classList.remove('active'); nextIndicator.classList.add('active'); - if (typeof this.options.indicatorLabelFunc === "function"){ - activeIndicator.ariaLabel = this.options.indicatorLabelFunc.call(this, this.activeIndex, false); + if (typeof this.options.indicatorLabelFunc === 'function') { + activeIndicator.ariaLabel = this.options.indicatorLabelFunc.call( + this, + this.activeIndex, + false + ); nextIndicator.ariaLabel = this.options.indicatorLabelFunc.call(this, index, true); } } @@ -391,7 +394,7 @@ export class Slider extends Component { */ pause = () => { this._pause(false); - } + }; /** * Start slider autoslide. @@ -403,7 +406,7 @@ export class Slider extends Component { this.options.duration + this.options.interval ); this.eventPause = false; - } + }; /** * Move to next slider. @@ -414,7 +417,7 @@ export class Slider extends Component { if (newIndex >= this._slides.length) newIndex = 0; else if (newIndex < 0) newIndex = this._slides.length - 1; this.set(newIndex); - } + }; /** * Move to prev slider. @@ -425,5 +428,5 @@ export class Slider extends Component { if (newIndex >= this._slides.length) newIndex = 0; else if (newIndex < 0) newIndex = this._slides.length - 1; this.set(newIndex); - } + }; } diff --git a/src/tabs.ts b/src/tabs.ts index 5708ca1967..60c69628c4 100644 --- a/src/tabs.ts +++ b/src/tabs.ts @@ -1,5 +1,5 @@ -import { Carousel } from "./carousel"; -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Carousel } from './carousel'; +import { Component, BaseOptions, InitElements, MElement } from './component'; export interface TabsOptions extends BaseOptions { /** @@ -24,7 +24,7 @@ export interface TabsOptions extends BaseOptions { * @default infinity */ responsiveThreshold: number; -}; +} let _defaults: TabsOptions = { duration: 300, @@ -87,7 +87,10 @@ export class Tabs extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): Tabs | Tabs[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): Tabs | Tabs[] { return super.init(els, options, Tabs); } @@ -100,8 +103,7 @@ export class Tabs extends Component { this._indicator.parentNode.removeChild(this._indicator); if (this.options.swipeable) { this._teardownSwipeableTabs(); - } - else { + } else { this._teardownNormalTabs(); } (this.el as any).M_Tabs = undefined; @@ -110,7 +112,9 @@ export class Tabs extends Component { /** * The index of tab that is currently shown. */ - get index(){ return this._index; } + get index() { + return this._index; + } _setupEventHandlers() { window.addEventListener('resize', this._handleWindowResize); @@ -125,10 +129,10 @@ export class Tabs extends Component { _handleWindowResize = () => { this._setTabsAndTabWidth(); if (this._tabWidth !== 0 && this._tabsWidth !== 0) { - this._indicator.style.left = this._calcLeftPos(this._activeTabLink)+'px'; - this._indicator.style.right = this._calcRightPos(this._activeTabLink)+'px'; + this._indicator.style.left = this._calcLeftPos(this._activeTabLink) + 'px'; + this._indicator.style.right = this._calcRightPos(this._activeTabLink) + 'px'; } - } + }; _handleTabClick = (e: MouseEvent) => { const tabLink = e.target as HTMLAnchorElement; @@ -147,14 +151,13 @@ export class Tabs extends Component { const _oldContent = this._content; // Update the variables with the new link and content - this._activeTabLink = tabLink; - if (tabLink.hash) - this._content = document.querySelector(tabLink.hash); - this._tabLinks = this.el.querySelectorAll('li.tab > a'); - // Make the tab active - this._activeTabLink.classList.add('active'); - const prevIndex = this._index; - this._index = Math.max(Array.from(this._tabLinks).indexOf(tabLink), 0); + this._activeTabLink = tabLink; + if (tabLink.hash) this._content = document.querySelector(tabLink.hash); + this._tabLinks = this.el.querySelectorAll('li.tab > a'); + // Make the tab active + this._activeTabLink.classList.add('active'); + const prevIndex = this._index; + this._index = Math.max(Array.from(this._tabLinks).indexOf(tabLink), 0); // Swap content if (this.options.swipeable) { @@ -180,20 +183,22 @@ export class Tabs extends Component { this._setTabsAndTabWidth(); this._animateIndicator(prevIndex); e.preventDefault(); - } + }; _createIndicator() { const indicator = document.createElement('li'); indicator.classList.add('indicator'); this.el.appendChild(indicator); this._indicator = indicator; - this._indicator.style.left = this._calcLeftPos(this._activeTabLink)+'px'; - this._indicator.style.right = this._calcRightPos(this._activeTabLink)+'px'; + this._indicator.style.left = this._calcLeftPos(this._activeTabLink) + 'px'; + this._indicator.style.right = this._calcRightPos(this._activeTabLink) + 'px'; } _setupActiveTabLink() { // If the location.hash matches one of the links, use that as the active tab. - this._activeTabLink = Array.from(this._tabLinks).find((a: HTMLAnchorElement) => a.getAttribute('href') === location.hash); + this._activeTabLink = Array.from(this._tabLinks).find( + (a: HTMLAnchorElement) => a.getAttribute('href') === location.hash + ); // If no match is found, use the first link or any with class 'active' as the initial active tab. if (!this._activeTabLink) { this._activeTabLink = this.el.querySelector('li.tab a.active'); @@ -204,27 +209,25 @@ export class Tabs extends Component { Array.from(this._tabLinks).forEach((a: HTMLAnchorElement) => a.classList.remove('active')); this._activeTabLink.classList.add('active'); - this._index = Math.max(Array.from(this._tabLinks).indexOf(this._activeTabLink), 0); - if (this._activeTabLink && this._activeTabLink.hash) { - this._content = document.querySelector(this._activeTabLink.hash); - if (this._content) - this._content.classList.add('active'); - } + this._index = Math.max(Array.from(this._tabLinks).indexOf(this._activeTabLink), 0); + if (this._activeTabLink && this._activeTabLink.hash) { + this._content = document.querySelector(this._activeTabLink.hash); + if (this._content) this._content.classList.add('active'); } + } _setupSwipeableTabs() { // Change swipeable according to responsive threshold - if (window.innerWidth > this.options.responsiveThreshold) - this.options.swipeable = false; - - const tabsContent = []; - this._tabLinks.forEach(a => { - if (a.hash) { - const currContent = document.querySelector(a.hash); - currContent.classList.add('carousel-item'); - tabsContent.push(currContent); - } - }); + if (window.innerWidth > this.options.responsiveThreshold) this.options.swipeable = false; + + const tabsContent = []; + this._tabLinks.forEach((a) => { + if (a.hash) { + const currContent = document.querySelector(a.hash); + currContent.classList.add('carousel-item'); + tabsContent.push(currContent); + } + }); // Create Carousel-Wrapper around Tab-Contents const tabsWrapper = document.createElement('div'); @@ -232,7 +235,7 @@ export class Tabs extends Component { // Wrap around tabsContent[0].parentElement.insertBefore(tabsWrapper, tabsContent[0]); - tabsContent.forEach(tabContent => { + tabsContent.forEach((tabContent) => { tabsWrapper.appendChild(tabContent); tabContent.style.display = ''; }); @@ -311,13 +314,12 @@ export class Tabs extends Component { } _animateIndicator(prevIndex) { - let leftDelay = 0, rightDelay = 0; + let leftDelay = 0, + rightDelay = 0; - const isMovingLeftOrStaying = (this._index - prevIndex >= 0); - if (isMovingLeftOrStaying) - leftDelay = 90; - else - rightDelay = 90; + const isMovingLeftOrStaying = this._index - prevIndex >= 0; + if (isMovingLeftOrStaying) leftDelay = 90; + else rightDelay = 90; // in v1: easeOutQuad this._indicator.style.transition = ` @@ -333,7 +335,9 @@ export class Tabs extends Component { * @param tabId The id of the tab that you want to switch to. */ select(tabId: string) { - const tab = Array.from(this._tabLinks).find((a: HTMLAnchorElement) => a.getAttribute('href') === '#'+tabId); + const tab = Array.from(this._tabLinks).find( + (a: HTMLAnchorElement) => a.getAttribute('href') === '#' + tabId + ); if (tab) (tab).click(); } } diff --git a/src/tapTarget.ts b/src/tapTarget.ts index c938b8595a..e7188e9086 100644 --- a/src/tapTarget.ts +++ b/src/tapTarget.ts @@ -1,5 +1,5 @@ -import { Utils } from "./utils"; -import { Component, BaseOptions, InitElements, MElement, Openable } from "./component"; +import { Utils } from './utils'; +import { Component, BaseOptions, InitElements, MElement, Openable } from './component'; export interface TapTargetOptions extends BaseOptions { /** @@ -12,7 +12,7 @@ export interface TapTargetOptions extends BaseOptions { * @default null */ onClose: (origin: HTMLElement) => void; -}; +} let _defaults: TapTargetOptions = { onOpen: null, @@ -69,7 +69,10 @@ export class TapTarget extends Component implements Openable { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): TapTarget | TapTarget[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): TapTarget | TapTarget[] { return super.init(els, options, TapTarget); } @@ -95,19 +98,21 @@ export class TapTarget extends Component implements Openable { window.removeEventListener('resize', this._handleThrottledResize); } - _handleThrottledResize: () => void = Utils.throttle(function(){ this._handleResize(); }, 200).bind(this); + _handleThrottledResize: () => void = Utils.throttle(function () { + this._handleResize(); + }, 200).bind(this); _handleTargetClick = () => { this.open(); - } + }; _handleOriginClick = () => { this.close(); - } + }; _handleResize = () => { this._calculatePositioning(); - } + }; _handleDocumentClick = (e: MouseEvent | TouchEvent) => { if (!(e.target as HTMLElement).closest('.tap-target-wrapper')) { @@ -115,7 +120,7 @@ export class TapTarget extends Component implements Openable { e.preventDefault(); e.stopPropagation(); } - } + }; _setup() { // Creating tap target @@ -165,7 +170,6 @@ export class TapTarget extends Component implements Openable { // Element or parent is fixed position? let isFixed = getComputedStyle(this._origin).position === 'fixed'; if (!isFixed) { - let currentElem: any = this._origin; const parents = []; while ((currentElem = currentElem.parentNode) && currentElem !== document) @@ -179,8 +183,12 @@ export class TapTarget extends Component implements Openable { // Calculating origin const originWidth = this._origin.offsetWidth; const originHeight = this._origin.offsetHeight; - const originTop = isFixed ? this._offset(this._origin).top - Utils.getDocumentScrollTop() : this._offset(this._origin).top; - const originLeft = isFixed ? this._offset(this._origin).left - Utils.getDocumentScrollLeft() : this._offset(this._origin).left; + const originTop = isFixed + ? this._offset(this._origin).top - Utils.getDocumentScrollTop() + : this._offset(this._origin).top; + const originLeft = isFixed + ? this._offset(this._origin).left - Utils.getDocumentScrollLeft() + : this._offset(this._origin).left; // Calculating screen const windowWidth = window.innerWidth; @@ -219,8 +227,12 @@ export class TapTarget extends Component implements Openable { // Setting tap target this.wrapper.style.top = isTop ? tapTargetTop + 'px' : ''; - this.wrapper.style.right = isRight ? windowWidth - tapTargetLeft - tapTargetWidth - scrollBarWidth + 'px' : ''; - this.wrapper.style.bottom = isBottom ? windowHeight - tapTargetTop - tapTargetHeight + 'px' : ''; + this.wrapper.style.right = isRight + ? windowWidth - tapTargetLeft - tapTargetWidth - scrollBarWidth + 'px' + : ''; + this.wrapper.style.bottom = isBottom + ? windowHeight - tapTargetTop - tapTargetHeight + 'px' + : ''; this.wrapper.style.left = isLeft ? tapTargetLeft + 'px' : ''; this.wrapper.style.position = tapTargetPosition; @@ -235,10 +247,10 @@ export class TapTarget extends Component implements Openable { this.contentEl.style.verticalAlign = tapTargetTextAlign; // Setting wave - this.waveEl.style.top = tapTargetWaveTop+'px'; - this.waveEl.style.left = tapTargetWaveLeft+'px'; - this.waveEl.style.width = tapTargetWaveWidth+'px'; - this.waveEl.style.height = tapTargetWaveHeight+'px'; + this.waveEl.style.top = tapTargetWaveTop + 'px'; + this.waveEl.style.left = tapTargetWaveLeft + 'px'; + this.waveEl.style.width = tapTargetWaveWidth + 'px'; + this.waveEl.style.height = tapTargetWaveHeight + 'px'; } /** diff --git a/src/timepicker.ts b/src/timepicker.ts index 663abfa7ce..567a6ace8f 100644 --- a/src/timepicker.ts +++ b/src/timepicker.ts @@ -1,8 +1,8 @@ -import { Modal } from "./modal"; -import { Utils } from "./utils"; -import { Component, BaseOptions, InitElements, MElement, I18nOptions } from "./component"; +import { Modal } from './modal'; +import { Utils } from './utils'; +import { Component, BaseOptions, InitElements, MElement, I18nOptions } from './component'; -export type Views = "hours" | "minutes"; +export type Views = 'hours' | 'minutes'; export interface TimepickerOptions extends BaseOptions { /** @@ -125,8 +125,8 @@ let _defaults: TimepickerOptions = { }; type Point = { - x: number, - y: number + x: number; + y: number; }; export class Timepicker extends Component { @@ -158,12 +158,12 @@ export class Timepicker extends Component { * If the time is AM or PM on twelve-hour clock. * @default 'PM' */ - amOrPm: "AM" | "PM"; + amOrPm: 'AM' | 'PM'; static _template: any; /** If the picker is open. */ isOpen: boolean; /** Vibrate device when dragging clock hand. */ - vibrate: "vibrate" | "webkitVibrate" | null; + vibrate: 'vibrate' | 'webkitVibrate' | null; _canvas: HTMLElement; hoursView: any; spanAmPm: HTMLSpanElement; @@ -210,13 +210,19 @@ export class Timepicker extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: InitElements, options?: Partial): Timepicker[]; + static init( + els: InitElements, + options?: Partial + ): Timepicker[]; /** * Initializes instances of Timepicker. * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLInputElement | InitElements, options: Partial = {}): Timepicker | Timepicker[] { + static init( + els: HTMLInputElement | InitElements, + options: Partial = {} + ): Timepicker | Timepicker[] { return super.init(els, options, Timepicker); } @@ -230,8 +236,11 @@ export class Timepicker extends Component { } static _Pos(e: TouchEvent | MouseEvent): Point { - if (e.type.startsWith("touch") && (e as TouchEvent).targetTouches.length >= 1) { - return { x: (e as TouchEvent).targetTouches[0].clientX, y: (e as TouchEvent).targetTouches[0].clientY }; + if (e.type.startsWith('touch') && (e as TouchEvent).targetTouches.length >= 1) { + return { + x: (e as TouchEvent).targetTouches[0].clientX, + y: (e as TouchEvent).targetTouches[0].clientY + }; } // mouse event return { x: (e as MouseEvent).clientX, y: (e as MouseEvent).clientY }; @@ -265,21 +274,21 @@ export class Timepicker extends Component { _handleInputClick = () => { this.open(); - } + }; _handleInputKeydown = (e: KeyboardEvent) => { if (Utils.keys.ENTER.includes(e.key)) { e.preventDefault(); this.open(); } - } + }; _handleTimeInputEnterKey = (e: KeyboardEvent) => { if (Utils.keys.ENTER.includes(e.key)) { e.preventDefault(); this._inputFromTextField(); } - } + }; _handleClockClickStart = (e) => { e.preventDefault(); @@ -301,7 +310,7 @@ export class Timepicker extends Component { // Mouseup on document document.addEventListener('mouseup', this._handleDocumentClickEnd); document.addEventListener('touchend', this._handleDocumentClickEnd); - } + }; _handleDocumentClickMove = (e) => { e.preventDefault(); @@ -310,7 +319,7 @@ export class Timepicker extends Component { let y = clickPos.y - this.y0; this.moved = true; this.setHand(x, y, false); - } + }; _handleDocumentClickEnd = (e) => { e.preventDefault(); @@ -324,8 +333,7 @@ export class Timepicker extends Component { } if (this.currentView === 'hours') { this.showView('minutes', this.options.duration / 2); - } - else if (this.options.autoClose) { + } else if (this.options.autoClose) { this.minutesView.classList.add('timepicker-dial-out'); setTimeout(() => { this.done(); @@ -337,7 +345,7 @@ export class Timepicker extends Component { // Unbind mousemove event document.removeEventListener('mousemove', this._handleDocumentClickMove); document.removeEventListener('touchmove', this._handleDocumentClickMove); - } + }; _insertHTMLIntoDOM() { const template = document.createElement('template'); @@ -351,8 +359,7 @@ export class Timepicker extends Component { if (this.options.container && !!containerEl) { containerEl.append(this.modalEl); - } - else { + } else { this.el.parentElement.appendChild(this.modalEl); } } @@ -376,8 +383,8 @@ export class Timepicker extends Component { this.vibrate = navigator.vibrate ? 'vibrate' : (navigator as any).webkitVibrate - ? 'webkitVibrate' - : null; + ? 'webkitVibrate' + : null; this._canvas = this.modalEl.querySelector('.timepicker-canvas'); this.plate = this.modalEl.querySelector('.timepicker-plate'); this.digitalClock = this.modalEl.querySelector('.timepicker-display-column'); @@ -401,7 +408,10 @@ export class Timepicker extends Component { } _pickerSetup() { - const clearButton = this._createButton(this.options.i18n.clear, this.options.showClearBtn ? '' : 'hidden'); + const clearButton = this._createButton( + this.options.i18n.clear, + this.options.showClearBtn ? '' : 'hidden' + ); clearButton.classList.add('timepicker-clear'); clearButton.addEventListener('click', this.clear); this.footer.appendChild(clearButton); @@ -483,21 +493,24 @@ export class Timepicker extends Component { const tick = $tick.cloneNode(true); const radian = (i / 6) * Math.PI; const radius = this.options.outerRadius; - tick.style.left = this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + 'px'; - tick.style.top = this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + 'px'; + tick.style.left = + this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + 'px'; + tick.style.top = + this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + 'px'; tick.innerHTML = i === 0 ? '00' : i.toString(); this.hoursView.appendChild(tick); // tick.on(mousedownEvent, mousedown); } - } - else { + } else { for (let i = 0; i < 24; i += 1) { const tick = $tick.cloneNode(true); const radian = (i / 6) * Math.PI; const inner = i > 0 && i < 13; const radius = inner ? this.options.innerRadius : this.options.outerRadius; - tick.style.left = this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + 'px'; - tick.style.top = this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + 'px'; + tick.style.left = + this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + 'px'; + tick.style.top = + this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + 'px'; tick.innerHTML = i === 0 ? '00' : i.toString(); this.hoursView.appendChild(tick); // tick.on(mousedownEvent, mousedown); @@ -518,10 +531,10 @@ export class Timepicker extends Component { this.options.tickRadius + 'px'; tick.style.top = - this.options.dialRadius - - Math.cos(radian) * this.options.outerRadius - - this.options.tickRadius + - 'px'; + this.options.dialRadius - + Math.cos(radian) * this.options.outerRadius - + this.options.tickRadius + + 'px'; tick.innerHTML = Timepicker._addLeadingZero(i); this.minutesView.appendChild(tick); } @@ -531,15 +544,14 @@ export class Timepicker extends Component { const btnClicked = e.target; this.amOrPm = btnClicked.classList.contains('am-btn') ? 'AM' : 'PM'; this._updateAmPmView(); - } + }; _updateAmPmView() { if (this.options.twelveHour) { if (this.amOrPm === 'PM') { this._amBtn.classList.remove('text-primary'); this._pmBtn.classList.add('text-primary'); - } - else if (this.amOrPm === 'AM') { + } else if (this.amOrPm === 'AM') { this._amBtn.classList.add('text-primary'); this._pmBtn.classList.remove('text-primary'); } @@ -588,8 +600,7 @@ export class Timepicker extends Component { if (isHours) { this.inputHours.classList.add('text-primary'); this.inputMinutes.classList.remove('text-primary'); - } - else { + } else { this.inputHours.classList.remove('text-primary'); this.inputMinutes.classList.add('text-primary'); } @@ -607,7 +618,7 @@ export class Timepicker extends Component { this.toggleViewTimer = setTimeout(() => { hideView.style.visibility = 'hidden'; }, this.options.duration); - } + }; resetClock(delay) { let view = this.currentView, @@ -627,8 +638,7 @@ export class Timepicker extends Component { self.canvas?.classList.remove('timepicker-canvas-out'); self.setHand(x, y); }, delay); - } - else { + } else { this.setHand(x, y); } } @@ -642,26 +652,23 @@ export class Timepicker extends Component { this.showView('minutes', this.options.duration / 2); this.hours = value; this.inputMinutes.focus(); - } - else { + } else { const hour = new Date().getHours(); this.inputHours.value = (hour % 12).toString(); } - } - else { + } else { const value = parseInt(this.inputMinutes.value); if (value >= 0 && value < 60) { this.inputMinutes.value = Timepicker._addLeadingZero(value); this.drawClockFromTimeInput(value, isHours); this.minutes = value; (this.modalEl.querySelector('.confirmation-btns :nth-child(2)')).focus(); - } - else { + } else { const minutes = new Date().getMinutes(); this.inputMinutes.value = Timepicker._addLeadingZero(minutes); } } - } + }; drawClockFromTimeInput(value, isHours) { const unit = Math.PI / (isHours ? 6 : 30); @@ -743,8 +750,7 @@ export class Timepicker extends Component { this[this.currentView] = value; if (isHours) { this.inputHours.value = value.toString(); - } - else { + } else { this.inputMinutes.value = Timepicker._addLeadingZero(value); } @@ -768,7 +774,7 @@ export class Timepicker extends Component { this._updateTimeFromInput(); this.showView('hours'); this.modal.open(undefined); - } + }; /** * Close timepicker. @@ -777,7 +783,7 @@ export class Timepicker extends Component { if (!this.isOpen) return; this.isOpen = false; this.modal.close(); - } + }; done = (e = null, clearValue = null) => { // Set input value @@ -792,15 +798,17 @@ export class Timepicker extends Component { this.el.value = value; // Trigger change event if (value !== last) { - this.el.dispatchEvent(new Event('change',{bubbles:true, cancelable:true, composed:true})); + this.el.dispatchEvent( + new Event('change', { bubbles: true, cancelable: true, composed: true }) + ); } this.close(); this.el.focus(); - } + }; clear = () => { this.done(null, true); - } + }; static { Timepicker._template = ` diff --git a/src/toasts.ts b/src/toasts.ts index bf823a6c44..ef1f3511ed 100644 --- a/src/toasts.ts +++ b/src/toasts.ts @@ -1,4 +1,4 @@ -import { BaseOptions } from "./component"; +import { BaseOptions } from './component'; export interface ToastOptions extends BaseOptions { /** @@ -174,8 +174,7 @@ export class Toast { toast.wasSwiped = true; toast.dismiss(); // Animate toast back to original position - } - else { + } else { toast.el.style.transition = 'transform .2s, opacity .2s'; toast.el.style.transform = ''; toast.el.style.opacity = ''; @@ -185,7 +184,7 @@ export class Toast { } static _xPos(e: TouchEvent | MouseEvent) { - if (e.type.startsWith("touch") && (e as TouchEvent).targetTouches.length >= 1) { + if (e.type.startsWith('touch') && (e as TouchEvent).targetTouches.length >= 1) { return (e as TouchEvent).targetTouches[0].clientX; } // mouse event @@ -202,13 +201,13 @@ export class Toast { } _createToast() { - let toast: HTMLElement = this.options.toastId + let toast: HTMLElement = this.options.toastId ? document.getElementById(this.options.toastId) : document.createElement('div'); - if (toast instanceof HTMLTemplateElement) { + if (toast instanceof HTMLTemplateElement) { const node = (toast as HTMLTemplateElement).content.cloneNode(true); - toast = ((node as HTMLElement).firstElementChild as HTMLElement); - } + toast = (node as HTMLElement).firstElementChild as HTMLElement; + } toast.classList.add('toast'); toast.setAttribute('role', 'alert'); toast.setAttribute('aria-live', 'assertive'); @@ -224,7 +223,7 @@ export class Toast { _animateIn() { // Animate toast in - this.el.style.display = ""; + this.el.style.display = ''; this.el.style.opacity = '0'; // easeOutCubic this.el.style.transition = ` @@ -233,8 +232,8 @@ export class Toast { `; setTimeout(() => { this.el.style.top = '0'; - this.el.style.opacity = '1'; - }, 1); + this.el.style.opacity = '1'; + }, 1); } /** @@ -276,7 +275,7 @@ export class Toast { setTimeout(() => { this.el.style.opacity = '0'; - this.el.style.marginTop = '-40px'; + this.el.style.marginTop = '-40px'; }, 1); setTimeout(() => { @@ -300,4 +299,4 @@ export class Toast { Toast._container = null; Toast._draggedToast = null; } -} \ No newline at end of file +} diff --git a/src/tooltip.ts b/src/tooltip.ts index e54bd91211..164112a1d7 100644 --- a/src/tooltip.ts +++ b/src/tooltip.ts @@ -1,6 +1,6 @@ -import { Utils } from "./utils"; -import { Bounding } from "./bounding"; -import { Component, BaseOptions, InitElements, MElement } from "./component"; +import { Utils } from './utils'; +import { Bounding } from './bounding'; +import { Component, BaseOptions, InitElements, MElement } from './component'; export type TooltipPosition = 'top' | 'right' | 'bottom' | 'left'; @@ -98,7 +98,7 @@ export class Tooltip extends Component { ...this._getAttributeOptions(), ...options }; - + this.isOpen = false; this.isHovered = false; this.isFocused = false; @@ -127,7 +127,10 @@ export class Tooltip extends Component { * @param els HTML elements. * @param options Component options. */ - static init(els: HTMLElement | InitElements, options: Partial = {}): Tooltip | Tooltip[] { + static init( + els: HTMLElement | InitElements, + options: Partial = {} + ): Tooltip | Tooltip[] { return super.init(els, options, Tooltip); } @@ -145,12 +148,12 @@ export class Tooltip extends Component { this.tooltipEl = document.createElement('div'); this.tooltipEl.classList.add('material-tooltip'); - const tooltipContentEl = this.options.tooltipId + const tooltipContentEl = this.options.tooltipId ? document.getElementById(this.options.tooltipId) : document.createElement('div'); - this.tooltipEl.append( tooltipContentEl); - tooltipContentEl.style.display = ""; - + this.tooltipEl.append(tooltipContentEl); + tooltipContentEl.style.display = ''; + tooltipContentEl.classList.add('tooltip-content'); this._setTooltipContent(tooltipContentEl); this.tooltipEl.appendChild(tooltipContentEl); @@ -158,9 +161,8 @@ export class Tooltip extends Component { } _setTooltipContent(tooltipContentEl: HTMLElement) { - if (this.options.tooltipId) - return; - tooltipContentEl.innerText = this.options.text; + if (this.options.tooltipId) return; + tooltipContentEl.innerText = this.options.text; } _updateTooltipContent() { @@ -189,11 +191,11 @@ export class Tooltip extends Component { isManual = isManual === undefined ? true : undefined; // Default value true this.isOpen = true; // Update tooltip content with HTML attribute options - this.options = {...this.options, ...this._getAttributeOptions()}; + this.options = { ...this.options, ...this._getAttributeOptions() }; this._updateTooltipContent(); this._setEnterDelayTimeout(isManual); - } - + }; + /** * Hide tooltip. */ @@ -203,7 +205,7 @@ export class Tooltip extends Component { this.isFocused = false; this.isOpen = false; this._setExitDelayTimeout(); - } + }; _setExitDelayTimeout() { clearTimeout(this._exitDelayTimeout); @@ -223,7 +225,7 @@ export class Tooltip extends Component { _positionTooltip() { const tooltip: HTMLElement = this.tooltipEl; - const origin = (this.el as HTMLElement), + const origin = this.el as HTMLElement, originHeight = origin.offsetHeight, originWidth = origin.offsetWidth, tooltipHeight = tooltip.offsetHeight, @@ -259,8 +261,8 @@ export class Tooltip extends Component { tooltipHeight ); - tooltip.style.top = newCoordinates.y+'px'; - tooltip.style.left = newCoordinates.x+'px'; + tooltip.style.top = newCoordinates.y + 'px'; + tooltip.style.left = newCoordinates.x + 'px'; } _repositionWithinScreen(x: number, y: number, width: number, height: number) { @@ -335,28 +337,28 @@ export class Tooltip extends Component { this.isHovered = true; this.isFocused = false; // Allows close of tooltip when opened by focus. this.open(false); - } + }; _handleMouseLeave = () => { this.isHovered = false; this.isFocused = false; // Allows close of tooltip when opened by focus. this.close(); - } + }; _handleFocus = () => { if (Utils.tabPressed) { this.isFocused = true; this.open(false); } - } + }; _handleBlur = () => { this.isFocused = false; this.close(); - } + }; - _getAttributeOptions(): Partial { - let attributeOptions: Partial = { }; + _getAttributeOptions(): Partial { + let attributeOptions: Partial = {}; const tooltipTextOption = this.el.getAttribute('data-tooltip'); const tooltipId = this.el.getAttribute('data-tooltip-id'); const positionOption = this.el.getAttribute('data-position'); diff --git a/src/utils.ts b/src/utils.ts index bbcca5d7d6..c6ce21555c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -22,7 +22,7 @@ export class Utils { ARROW_DOWN: ['ArrowDown', 'Down'], ARROW_LEFT: ['ArrowLeft', 'Left'], ARROW_RIGHT: ['ArrowRight', 'Right'], - DELETE: ['Delete', 'Del'], + DELETE: ['Delete', 'Del'] }; /** @@ -73,7 +73,7 @@ export class Utils { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); - } + }; return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); } @@ -137,16 +137,21 @@ export class Utils { * @param bounding Bounding rect. * @param offset Element offset. */ - static checkPossibleAlignments(el: HTMLElement, container: HTMLElement, bounding: Bounding, offset: number) { + static checkPossibleAlignments( + el: HTMLElement, + container: HTMLElement, + bounding: Bounding, + offset: number + ) { let canAlign: { - top: boolean, - right: boolean, - bottom: boolean, - left: boolean, - spaceOnTop: number, - spaceOnRight: number, - spaceOnBottom: number - spaceOnLeft: number + top: boolean; + right: boolean; + bottom: boolean; + left: boolean; + spaceOnTop: number; + spaceOnRight: number; + spaceOnBottom: number; + spaceOnLeft: number; } = { top: true, right: true, @@ -224,7 +229,7 @@ export class Utils { */ static getDocumentScrollTop(): number { return window.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0; - }; + } /** * Retrieves document scroll postion from left. @@ -239,18 +244,22 @@ export class Utils { * @param wait Wait time. * @param options Additional options. */ - static throttle(func: Function, wait: number, options: Partial<{leading:boolean,trailing:boolean}> = null) { + static throttle( + func: Function, + wait: number, + options: Partial<{ leading: boolean; trailing: boolean }> = null + ) { let context: object, args: IArguments, result: any; let timeout = null; let previous = 0; options || (options = {}); - let later = function() { + let later = function () { previous = options.leading === false ? 0 : new Date().getTime(); timeout = null; result = func.apply(context, args); context = args = null; }; - return function() { + return function () { let now = new Date().getTime(); if (!previous && options.leading === false) previous = now; let remaining = wait - (now - previous); @@ -268,4 +277,4 @@ export class Utils { return result; }; } -} \ No newline at end of file +} diff --git a/src/waves.ts b/src/waves.ts index a8eb13d2de..cf285b83b3 100644 --- a/src/waves.ts +++ b/src/waves.ts @@ -1,16 +1,15 @@ type RGBColor = { - r: number, - g: number, - b: number, -} + r: number; + g: number; + b: number; +}; type Position = { - x: number, - y: number, -} + x: number; + y: number; +}; export class Waves { - private static _offset(el: HTMLElement) { const box = el.getBoundingClientRect(); const docElem = document.documentElement; @@ -22,24 +21,38 @@ export class Waves { // https://phoenix-dx.com/css-techniques-for-material-ripple-effect/ - static renderWaveEffect(targetElement: HTMLElement, position: Position|null = null, color: RGBColor|null = null): void { + static renderWaveEffect( + targetElement: HTMLElement, + position: Position | null = null, + color: RGBColor | null = null + ): void { const isCentered = position === null; const duration = 500; let animationFrame: number, animationStart: number; - const animationStep = function(timestamp: number) { + const animationStep = function (timestamp: number) { if (!animationStart) { animationStart = timestamp; } const frame = timestamp - animationStart; if (frame < duration) { - const easing = (frame/duration) * (2 - (frame/duration)); - const circle = isCentered ? 'circle at 50% 50%' : `circle at ${position.x}px ${position.y}px`; - const waveColor = `rgba(${color?.r || 0}, ${color?.g || 0}, ${color?.b || 0}, ${ 0.3 * (1-easing) })`; - const stop = 90 * easing + "%"; - targetElement.style.backgroundImage = "radial-gradient("+circle+", "+waveColor+" "+stop+", transparent "+stop+")"; + const easing = (frame / duration) * (2 - frame / duration); + const circle = isCentered + ? 'circle at 50% 50%' + : `circle at ${position.x}px ${position.y}px`; + const waveColor = `rgba(${color?.r || 0}, ${color?.g || 0}, ${color?.b || 0}, ${0.3 * (1 - easing)})`; + const stop = 90 * easing + '%'; + targetElement.style.backgroundImage = + 'radial-gradient(' + + circle + + ', ' + + waveColor + + ' ' + + stop + + ', transparent ' + + stop + + ')'; animationFrame = window.requestAnimationFrame(animationStep); - } - else { + } else { targetElement.style.backgroundImage = 'none'; window.cancelAnimationFrame(animationFrame); } @@ -48,9 +61,9 @@ export class Waves { } static Init() { - if (typeof document !== 'undefined') - document?.addEventListener("DOMContentLoaded", () => { - document.body.addEventListener('click', e => { + if (typeof document !== 'undefined') + document?.addEventListener('DOMContentLoaded', () => { + document.body.addEventListener('click', (e) => { const trigger = e.target; const el = trigger.closest('.waves-effect'); if (el && el.contains(trigger)) { @@ -59,12 +72,11 @@ export class Waves { const y = e.pageY - Waves._offset(el).top; let color = null; - if (el.classList.contains('waves-light')) - color = {r:255, g:255, b:255}; + if (el.classList.contains('waves-light')) color = { r: 255, g: 255, b: 255 }; - Waves.renderWaveEffect(el, isCircular ? null : {x, y}, color); + Waves.renderWaveEffect(el, isCircular ? null : { x, y }, color); } }); }); } -} \ No newline at end of file +}