diff --git a/.eslintrc.js b/.eslintrc.js
index 3e78ec5..76d441a 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,8 +1,12 @@
const resolve = require('./resolve.config');
-const browserRollupConfig = require('./config/jest-puppeteer.rollup.config.js');
module.exports = {
- extends: ['plugin:jest-playwright/recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react/recommended', 'airbnb', 'prettier'],
+ extends: [
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:react/recommended',
+ 'airbnb',
+ 'prettier',
+ ],
env: {
browser: true,
es2020: true,
@@ -43,6 +47,13 @@ module.exports = {
'consistent-return': 'off',
'import/prefer-default-export': 'off',
'import/no-extraneous-dependencies': 'off',
+ 'import/no-unresolved': [
+ 'error',
+ {
+ ignore: [`^@/.*`],
+ },
+ ],
+ '@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
@@ -54,12 +65,6 @@ module.exports = {
allowedNames: ['self', '_self'], // Allow `const self = this`; `[]` by default
},
],
- 'import/no-unresolved': [
- 'error',
- {
- ignore: [`^@/.*`],
- },
- ],
'import/extensions': [
'error',
'ignorePackages',
@@ -73,8 +78,10 @@ module.exports = {
},
overrides: [
{
- files: ['*.test.*', `*${browserRollupConfig.js.input}.*`],
+ files: ['*.test.*', '**/tests/**'],
rules: {
+ 'no-shadow': 'off',
+ 'no-use-before-define': 'off',
'no-restricted-syntax': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-empty-function': 'off',
@@ -87,16 +94,10 @@ module.exports = {
'no-void': 'off',
'no-empty-function': 'off',
'no-new-func': 'off',
- 'import/no-unresolved': [
- 'error',
- {
- ignore: [`\\./${browserRollupConfig.build}/${browserRollupConfig.html.output}$`, `^@/.*`],
- },
- ],
},
},
{
- files: ['rollup.config.*'],
+ files: ['*rollup*'],
rules: {
'no-console': 'off',
'global-require': 'off',
diff --git a/.prettierrc b/.prettierrc
index a324b31..9b0f0c6 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,5 +1,5 @@
{
- "printWidth": 150,
+ "printWidth": 100,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "es5",
diff --git a/babel.config.base.js b/babel.config.base.js
index 7247b49..b077b0d 100644
--- a/babel.config.base.js
+++ b/babel.config.base.js
@@ -1,21 +1,13 @@
module.exports = function (api) {
api.cache.using(() => process.env.NODE_ENV);
- const isRollup = api.caller((caller) => !!(caller && caller.name === 'babel-rollup-build'));
const isJest = api.caller((caller) => !!(caller && caller.name === 'babel-jest'));
- if (isRollup) {
- return {
- plugins: [
- '@babel/plugin-transform-runtime',
- '@babel/plugin-proposal-class-properties',
- ['@babel/plugin-proposal-private-methods', { loose: false }],
- ],
- };
- }
-
if (isJest) {
return {
- plugins: ['@babel/plugin-transform-modules-commonjs', ['@babel/plugin-proposal-private-methods', { loose: false }]],
+ plugins: [
+ '@babel/plugin-transform-modules-commonjs',
+ ['@babel/plugin-proposal-private-methods', { loose: false }],
+ ],
presets: [
[
'@babel/preset-env',
diff --git a/config/jest-browser.env.js b/config/jest-browser.env.js
deleted file mode 100644
index da645ee..0000000
--- a/config/jest-browser.env.js
+++ /dev/null
@@ -1,32 +0,0 @@
-const PlaywrightEnvironment = require('jest-playwright-preset/lib/PlaywrightEnvironment').default;
-const { setupRollupTest, cleanupRollupTest } = require('./jest-browser.rollup.js');
-
-const buildTests = [];
-
-class BrowserRollupEnvironment extends PlaywrightEnvironment {
- constructor(envConfig, envContext) {
- super(envConfig, envContext);
-
- this.watch = (envConfig.displayName.name || '').includes('-dev');
- this.ctx = envContext;
- this.cfg = envConfig;
- }
-
- async setup() {
- const { testPath } = this.ctx;
-
- if (!buildTests.includes(testPath)) {
- await cleanupRollupTest(testPath, this.cfg.cache);
- await setupRollupTest(this.cfg.rootDir, this.ctx.testPath, this.cfg.cache && this.cfg.cacheDirectory, this.watch);
- buildTests.push(testPath);
- }
-
- await super.setup();
- }
-
- async teardown() {
- await super.teardown();
- }
-}
-
-module.exports = BrowserRollupEnvironment;
diff --git a/config/jest-browser.globalSetup.js b/config/jest-browser.globalSetup.js
deleted file mode 100644
index af775c0..0000000
--- a/config/jest-browser.globalSetup.js
+++ /dev/null
@@ -1,5 +0,0 @@
-const { globalSetup } = require('jest-playwright-preset');
-
-module.exports = async (jestConfig) => {
- await globalSetup(jestConfig);
-};
diff --git a/config/jest-browser.globalTeardown.js b/config/jest-browser.globalTeardown.js
deleted file mode 100644
index f88db2c..0000000
--- a/config/jest-browser.globalTeardown.js
+++ /dev/null
@@ -1,36 +0,0 @@
-const fs = require('fs');
-const path = require('path');
-const { execSync } = require('child_process');
-const del = require('del');
-const { globalTeardown } = require('jest-playwright-preset');
-
-const coverageTempDir = './.nyc_output';
-const coverageTempDirFile = 'coverage.json';
-const reportDir = './.coverage/browser';
-
-module.exports = async (jestConfig) => {
- await globalTeardown(jestConfig);
-
- const { rootDir } = jestConfig;
- const coverageTempDirPath = path.resolve(rootDir, coverageTempDir);
- const coverageTempFilePath = path.resolve(coverageTempDirPath, coverageTempDirFile);
- const reportDirPath = path.resolve(rootDir, reportDir);
-
- if (fs.existsSync(coverageTempFilePath)) {
- const coverageReportText = ' COVERAGE ';
-
- console.log('');
- console.log(`\x1b[1m\x1b[44m${coverageReportText}\x1b[0m`);
- console.log(`Reporting from: "${path.relative(rootDir, coverageTempFilePath)}" in "${path.relative(rootDir, reportDirPath)}"`);
-
- del.sync(reportDirPath);
- execSync(`npx nyc report --reporter=lcov --report-dir=${reportDir}`, {
- cwd: rootDir,
- });
-
- const [deletedTempDir] = del.sync(coverageTempDirPath);
- if (deletedTempDir) {
- console.log('Deleted:', path.relative(rootDir, deletedTempDir));
- }
- }
-};
diff --git a/config/jest-browser.rollup.config.js b/config/jest-browser.rollup.config.js
deleted file mode 100644
index 177cf2b..0000000
--- a/config/jest-browser.rollup.config.js
+++ /dev/null
@@ -1,19 +0,0 @@
-const path = require('path');
-
-module.exports = {
- port: 8080,
- root: path.join(__dirname, '../'),
- build: '.build',
- html: {
- input: 'index.html',
- output: 'build.html',
- },
- js: {
- input: 'index.browser',
- output: 'build',
- },
- dev: {
- servePort: 18080,
- livereloadPort: 28080,
- },
-};
diff --git a/config/jest-browser.rollup.js b/config/jest-browser.rollup.js
deleted file mode 100644
index 75b8e04..0000000
--- a/config/jest-browser.rollup.js
+++ /dev/null
@@ -1,337 +0,0 @@
-const fs = require('fs');
-const crypto = require('crypto');
-const path = require('path');
-const del = require('del');
-const chalk = require('chalk');
-const readline = require('readline');
-const rollup = require('rollup');
-const rollupPluginHtml = require('@rollup/plugin-html');
-const rollupPluginStyles = require('rollup-plugin-styles');
-const rollupPluginServe = require('rollup-plugin-serve');
-const rollupPluginLivereload = require('rollup-plugin-livereload');
-const deploymentConfig = require('./jest-browser.rollup.config.js');
-
-const rollupConfigName = 'rollup.config.js';
-const cacheFilePrefix = 'jest-browser-overlayscrollbars-cache-';
-const cacheEncoding = 'utf8';
-const cacheHash = 'md5';
-
-const rollupAdditionalWatchFiles = (files) => ({
- buildStart() {
- if (files) {
- files.forEach((file) => {
- if (fs.existsSync(file)) {
- this.addWatchFile(file);
- }
- });
- }
- },
-});
-
-const makeHtmlAttributes = (attributes) => {
- if (!attributes) {
- return '';
- }
-
- const keys = Object.keys(attributes);
- // eslint-disable-next-line no-param-reassign
- // eslint-disable-next-line no-return-assign
- return keys.reduce((result, key) => (result += ` ${key}="${attributes[key]}"`), '');
-};
-
-const genHtmlTemplateFunc = (contentOrContentFn) => ({ attributes, files, meta, publicPath, title }) => {
- const scripts = (files.js || [])
- .map(({ fileName }) => ``)
- .join('\n');
-
- const links = (files.css || [])
- .map(({ fileName }) => ``)
- .join('\n');
-
- const metas = meta.map((input) => ``).join('\n');
-
- return `
-
-
- ${metas}
- ${title}
-
- ${links}
-
-
- ${(typeof contentOrContentFn === 'function' ? contentOrContentFn() : contentOrContentFn) || ''}
- ${scripts}
-
-
-`;
-};
-
-const getAllFilesFrom = (dir, except) => {
- const result = [];
- fs.readdirSync(dir).forEach((dirOrFile) => {
- if (!except.includes(dirOrFile)) {
- const dirOrFileResolved = path.resolve(dir, dirOrFile);
- if (fs.statSync(dirOrFileResolved).isDirectory()) {
- result.push(...getAllFilesFrom(dirOrFileResolved));
- }
- result.push(dirOrFileResolved);
- }
- });
- return result;
-};
-
-const createCacheObj = (testPath) => {
- const testFileName = path.basename(testPath);
- const testFiles = getAllFilesFrom(path.dirname(testPath), [deploymentConfig.build, testFileName]);
- const obj = {};
-
- testFiles.forEach((dir) => {
- obj[dir] = crypto.createHash(cacheHash).update(fs.readFileSync(dir, cacheEncoding), cacheEncoding).digest('hex');
- });
-
- return obj;
-};
-
-const filesChanged = (testPath, cacheDir) => {
- let result = true;
- const cacheObjString = JSON.stringify(createCacheObj(testPath));
- const getCacheFile = path.resolve(cacheDir, cacheFilePrefix + crypto.createHash(cacheHash).update(testPath, cacheEncoding).digest('hex'));
- if (fs.existsSync(getCacheFile)) {
- result = cacheObjString !== fs.readFileSync(getCacheFile, cacheEncoding);
- }
-
- if (result) {
- fs.writeFileSync(getCacheFile, cacheObjString);
- }
-
- return result;
-};
-
-const setupRollupTest = async (rootDir, testPath, cacheDir, watch) => {
- const rollupWatchers = [];
- const rollupServers = [];
- const testDir = path.dirname(testPath);
- const testName = path.basename(testDir);
- const changed = cacheDir && !watch ? filesChanged(testPath, cacheDir) : true;
- const buildFolderExists = fs.existsSync(path.resolve(testDir, deploymentConfig.build));
-
- if (changed || !buildFolderExists) {
- const rollupConfigPath = path.resolve(rootDir, rollupConfigName);
-
- if (fs.existsSync(rollupConfigPath)) {
- const rollupConfig = require(rollupConfigPath); // eslint-disable-line
-
- if (typeof rollupConfig === 'function') {
- try {
- const htmlFilePath = path.resolve(testDir, deploymentConfig.html.input);
- const dist = path.resolve(testDir, deploymentConfig.build);
- const getHtmlFileContent = () => (fs.existsSync(htmlFilePath) ? fs.readFileSync(htmlFilePath, 'utf8') : null);
- const logBuilding = (re) => {
- const text = re ? ' RE-BUILDING ' : ' BUILDING ';
- console.log(`${chalk.bgBlue.bold.whiteBright(text)} ${chalk.blackBright(testPath)}`); // eslint-disable-line
- };
- const logBundleFinish = (duration) => {
- if (duration) {
- console.log(`Bundle finished after ${Math.round(duration / 1000)} seconds.`); // eslint-disable-line
- } else {
- console.log(`Bundle finished.`); // eslint-disable-line
- }
- };
-
- let rollupConfigObj = rollupConfig(undefined, {
- project: rootDir,
- overwrite: ({ defaultConfig }) => {
- return {
- dist,
- input: path.resolve(testDir, deploymentConfig.js.input),
- file: deploymentConfig.js.output,
- types: null,
- minVersions: false,
- esmBuild: false,
- sourcemap: true,
- name: testName,
- pipeline: [
- rollupPluginStyles(),
- ...defaultConfig.pipeline,
- rollupPluginHtml({
- title: `Jest-Browser: ${testName}`,
- fileName: deploymentConfig.html.output,
- template: genHtmlTemplateFunc(getHtmlFileContent),
- meta: [{ charset: 'utf-8' }, { 'http-equiv': 'X-UA-Compatible', content: 'IE=edge' }],
- }),
- ...(watch
- ? [
- rollupAdditionalWatchFiles([htmlFilePath]),
- rollupPluginServe({
- contentBase: dist,
- historyApiFallback: `/${deploymentConfig.html.output}`,
- port: deploymentConfig.dev.servePort,
- onListening(server) {
- rollupServers.push(server);
- },
- }),
- rollupPluginLivereload({
- watch: dist,
- port: deploymentConfig.dev.livereloadPort,
- }),
- ]
- : []),
- ],
- };
- },
- silent: true,
- fast: true,
- });
-
- if (!Array.isArray(rollupConfigObj)) {
- rollupConfigObj = [rollupConfigObj];
- }
-
- for (let i = 0; i < rollupConfigObj.length; i++) {
- const inputConfig = rollupConfigObj[i];
- let { output } = inputConfig;
-
- if (!Array.isArray(output)) {
- output = [output];
- }
-
- if (watch) {
- let firstWatch = true;
- const rollupWatcher = rollup.watch({
- ...inputConfig,
- output,
- });
-
- // eslint-disable-next-line no-await-in-loop
- await new Promise((resolve) => {
- rollupWatcher.on('event', ({ code, duration, error, result }) => {
- if (code === 'ERROR') {
- console.log('Error:', error); // eslint-disable-line
- }
- if (code === 'START') {
- if (firstWatch) {
- console.log(''); // eslint-disable-line
- }
- logBuilding(!firstWatch);
- }
- if (code === 'BUNDLE_END') {
- logBundleFinish(duration);
- if (result && result.close) {
- result.close();
- }
- }
- if (code === 'END') {
- console.log('Watching for changes, press ENTER to continue.'); // eslint-disable-line
- console.log(''); // eslint-disable-line
- if (firstWatch) {
- firstWatch = false;
- resolve();
- }
- }
- });
- });
-
- rollupWatchers.push(rollupWatcher);
- } else {
- console.log(''); // eslint-disable-line
- logBuilding();
- const startTime = Date.now();
- // eslint-disable-next-line no-await-in-loop
- const bundle = await rollup.rollup(inputConfig);
-
- for (let v = 0; v < output.length; v++) {
- const outputConfig = output[i];
- // eslint-disable-next-line no-await-in-loop
- await bundle.write(outputConfig);
-
- const endTime = Date.now();
- logBundleFinish(endTime - startTime);
- }
-
- console.log(''); // eslint-disable-line
- }
- }
-
- if (watch) {
- const rl = readline.createInterface({
- input: process.stdin,
- output: process.stdout,
- });
-
- await new Promise((resolve) => {
- rl.on('line', () => {
- resolve();
- });
- rl.on('close', () => {
- resolve();
- });
- });
-
- rl.close();
- rollupWatchers.forEach((watcher) => {
- watcher.close();
- });
- rollupServers.forEach((server) => {
- server.close();
- });
- if (rollupPluginLivereload && global.PLUGIN_LIVERELOAD && global.PLUGIN_LIVERELOAD.server) {
- global.PLUGIN_LIVERELOAD.server.close();
- global.PLUGIN_LIVERELOAD.server = null;
- }
- }
- } catch (e) {
- console.warn(e);
- }
- }
- }
- }
-};
-
-const cleanupRollupTest = async (testPath, cache) => {
- if (!cache) {
- await del(path.resolve(path.dirname(testPath), deploymentConfig.build));
- }
-};
-
-module.exports = { setupRollupTest, cleanupRollupTest };
diff --git a/config/jest-browser.setupAfterEnv.js b/config/jest-browser.setupAfterEnv.js
deleted file mode 100644
index 6e64826..0000000
--- a/config/jest-browser.setupAfterEnv.js
+++ /dev/null
@@ -1,2 +0,0 @@
-jest.setTimeout(60000 * 5);
-context.setDefaultTimeout(60000 * 5);
diff --git a/config/jest-test-server.js b/config/jest-test-server.js
deleted file mode 100644
index eca1c8b..0000000
--- a/config/jest-test-server.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const express = require('express');
-const deploymentConfig = require('./jest-browser.rollup.config.js');
-
-const app = express();
-
-app.use(express.static(deploymentConfig.root));
-app.listen(deploymentConfig.port);
diff --git a/config/jest-test-server.loader.js b/config/jest-test-server.loader.js
deleted file mode 100644
index 326a743..0000000
--- a/config/jest-test-server.loader.js
+++ /dev/null
@@ -1,10 +0,0 @@
-const path = require('path');
-const deploymentConfig = require('./jest-browser.rollup.config.js');
-
-module.exports = {
- process: (src, filePath) => {
- const deploymentPath = path.relative(deploymentConfig.root, filePath);
- const split = deploymentPath.split(path.sep);
- return `module.exports = ${JSON.stringify(`http://127.0.0.1:${deploymentConfig.port}/${path.posix.join(...split)}`)}`;
- },
-};
diff --git a/config/jest-jsdom.setup.js b/config/jest/jest.setup.js
similarity index 100%
rename from config/jest-jsdom.setup.js
rename to config/jest/jest.setup.js
diff --git a/config/playwright/rollup.config.js b/config/playwright/rollup.config.js
new file mode 100644
index 0000000..863422d
--- /dev/null
+++ b/config/playwright/rollup.config.js
@@ -0,0 +1,73 @@
+const fs = require('fs');
+const path = require('path');
+const rollupPluginStyles = require('rollup-plugin-styles');
+const rollupPluginServe = require('rollup-plugin-serve');
+const rollupPluginLivereload = require('rollup-plugin-livereload');
+
+const createRollupConfig = require('../rollup/rollup.config');
+const rollupPluginHtml = require('./rollup.pluginHtml');
+const rollupAdditionalWatchFiles = require('./rollup.pluginAdditionalWatchFiles');
+
+const portRange = {
+ min: 20000,
+ max: 60000,
+};
+
+const meta = {
+ dist: './.build',
+ html: './index.html',
+ input: './index.browser',
+};
+
+module.exports = (testDir, onListening = null) => {
+ const name = path.basename(testDir);
+ const htmlFilePath = path.resolve(testDir, meta.html);
+ const dist = path.resolve(testDir, meta.dist);
+ const htmlName = `${name}.html`;
+ const { min, max } = portRange;
+ const port = Math.floor(Math.random() * (max - min + 1) + min);
+
+ return createRollupConfig({
+ project: name,
+ mode: 'dev',
+ paths: {
+ dist,
+ src: path.resolve(testDir, './'),
+ },
+ versions: {
+ minified: false,
+ module: false,
+ },
+ rollup: {
+ input: path.resolve(testDir, meta.input),
+ context: 'this',
+ moduleContext: () => 'this',
+ output: {
+ sourcemap: true,
+ },
+ plugins: [
+ rollupPluginStyles(),
+ rollupPluginHtml(`Playwright: ${name}`, htmlName, () =>
+ fs.existsSync(htmlFilePath) ? fs.readFileSync(htmlFilePath, 'utf8') : null
+ ),
+ ...(onListening
+ ? [
+ rollupAdditionalWatchFiles([htmlFilePath]),
+ rollupPluginServe({
+ contentBase: dist,
+ historyApiFallback: `/${htmlName}`,
+ host: '127.0.0.1',
+ port,
+ onListening,
+ }),
+ rollupPluginLivereload({
+ watch: dist,
+ port: port - 1,
+ verbose: false,
+ }),
+ ]
+ : []),
+ ],
+ },
+ });
+};
diff --git a/config/playwright/rollup.pluginAdditionalWatchFiles.js b/config/playwright/rollup.pluginAdditionalWatchFiles.js
new file mode 100644
index 0000000..24097e5
--- /dev/null
+++ b/config/playwright/rollup.pluginAdditionalWatchFiles.js
@@ -0,0 +1,13 @@
+const fs = require('fs');
+
+module.exports = (files) => ({
+ buildStart() {
+ if (files) {
+ files.forEach((file) => {
+ if (fs.existsSync(file)) {
+ this.addWatchFile(file);
+ }
+ });
+ }
+ },
+});
diff --git a/config/playwright/rollup.pluginHtml.js b/config/playwright/rollup.pluginHtml.js
new file mode 100644
index 0000000..601e348
--- /dev/null
+++ b/config/playwright/rollup.pluginHtml.js
@@ -0,0 +1,102 @@
+const rollupPluginHtml = require('@rollup/plugin-html');
+
+const makeHtmlAttributes = (attributes) => {
+ if (!attributes) {
+ return '';
+ }
+
+ const keys = Object.keys(attributes);
+ // eslint-disable-next-line no-param-reassign
+ // eslint-disable-next-line no-return-assign
+ return keys.reduce((result, key) => (result += ` ${key}="${attributes[key]}"`), '');
+};
+
+const genHtmlTemplateFunc = (contentOrContentFn) => ({
+ attributes,
+ files,
+ meta,
+ publicPath,
+ title,
+}) => {
+ const scripts = (files.js || [])
+ .map(
+ ({ fileName }) =>
+ ``
+ )
+ .join('\n');
+
+ const links = (files.css || [])
+ .map(
+ ({ fileName }) =>
+ ``
+ )
+ .join('\n');
+
+ const metas = meta.map((input) => ``).join('\n');
+
+ return `
+
+
+ ${metas}
+ ${title}
+
+ ${links}
+
+
+ ${(typeof contentOrContentFn === 'function' ? contentOrContentFn() : contentOrContentFn) || ''}
+ ${scripts}
+
+
+`;
+};
+
+module.exports = (title, fileName, getHtmlContent) =>
+ rollupPluginHtml({
+ title,
+ fileName,
+ template: genHtmlTemplateFunc(getHtmlContent),
+ meta: [{ charset: 'utf-8' }, { 'http-equiv': 'X-UA-Compatible', content: 'IE=edge' }],
+ });
diff --git a/config/rollup/babel.config.esm.js b/config/rollup/babel.config.esm.js
new file mode 100644
index 0000000..d401820
--- /dev/null
+++ b/config/rollup/babel.config.esm.js
@@ -0,0 +1,14 @@
+module.exports = {
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ loose: true,
+ bugfixes: true,
+ targets: {
+ esmodules: true,
+ },
+ },
+ ],
+ ],
+};
diff --git a/config/rollup/babel.config.umd.js b/config/rollup/babel.config.umd.js
new file mode 100644
index 0000000..30d30f0
--- /dev/null
+++ b/config/rollup/babel.config.umd.js
@@ -0,0 +1,13 @@
+module.exports = {
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ loose: true,
+ targets: {
+ ie: '11',
+ },
+ },
+ ],
+ ],
+};
diff --git a/config/rollup/defaultOptions.js b/config/rollup/defaultOptions.js
new file mode 100644
index 0000000..c1e46ed
--- /dev/null
+++ b/config/rollup/defaultOptions.js
@@ -0,0 +1,21 @@
+module.exports = {
+ project: null,
+ mode: 'build',
+ paths: {
+ src: './src',
+ dist: './dist',
+ types: './types',
+ },
+ versions: {
+ minified: true,
+ module: true,
+ },
+ alias: {},
+ rollup: {
+ input: './src/index',
+ output: {
+ sourcemap: true,
+ exports: 'auto',
+ },
+ },
+};
diff --git a/config/rollup/pipeline.build.js b/config/rollup/pipeline.build.js
new file mode 100644
index 0000000..bdc3e56
--- /dev/null
+++ b/config/rollup/pipeline.build.js
@@ -0,0 +1,107 @@
+const path = require('path');
+const { babel: rollupBabelInputPlugin } = require('@rollup/plugin-babel');
+const { terser: rollupTerser } = require('rollup-plugin-terser');
+const rollupTs = require('rollup-plugin-ts');
+
+const babelConfigUmd = require('./babel.config.umd');
+const babelConfigEsm = require('./babel.config.esm');
+const { rollupCommonjs, rollupResolve, rollupAlias } = require('./pipeline.common.plugins');
+const { extensions } = require('../../resolve.config.json');
+
+const createOutputWithMinifiedVersion = (output, esm, buildMinifiedVersion) =>
+ [output].concat(
+ buildMinifiedVersion
+ ? [
+ {
+ ...output,
+ compact: true,
+ file: output.file.replace('.js', '.min.js'),
+ sourcemap: false,
+ plugins: [
+ ...(output.plugins || []),
+ rollupTerser({
+ ecma: esm ? 2015 : 5,
+ safari10: true,
+ mangle: {
+ safari10: true,
+ properties: {
+ regex: /^_/,
+ },
+ },
+ compress: {
+ evaluate: false,
+ },
+ }),
+ ],
+ },
+ ]
+ : []
+ );
+
+module.exports = (esm, options, declarationFiles = false) => {
+ const { rollup, paths, versions, alias } = options;
+ const { output: rollupOutput, input, plugins = [], ...rollupOptions } = rollup;
+ const { name, file, globals, exports, sourcemap: rawSourcemap, ...outputConfig } = rollupOutput;
+ const { minified: buildMinifiedVersion } = versions;
+ const { src: srcPath, dist: distPath, types: typesPath } = paths;
+ const sourcemap = rawSourcemap;
+
+ const output = createOutputWithMinifiedVersion(
+ {
+ ...outputConfig,
+ ...(!esm && {
+ name,
+ globals,
+ exports,
+ }),
+ sourcemap,
+ format: esm ? 'esm' : 'umd',
+ generatedCode: esm ? 'es2015' : 'es5',
+ file: path.resolve(distPath, `${file}${esm ? '.esm' : ''}.js`),
+ },
+ esm,
+ buildMinifiedVersion
+ );
+
+ return {
+ input,
+ output,
+ ...rollupOptions,
+ plugins: [
+ rollupAlias(alias),
+ rollupTs({
+ tsconfig: (resolvedConfig) => ({
+ ...resolvedConfig,
+ declaration: declarationFiles,
+ declarationDir: typesPath,
+ }),
+ include: ['*.ts+(|x)', '**/*.ts+(|x)'],
+ exclude: ['node_modules', '**/node_modules/*'],
+ }),
+ rollupResolve(srcPath),
+ rollupCommonjs(sourcemap),
+ rollupBabelInputPlugin({
+ ...(esm ? babelConfigEsm : babelConfigUmd),
+ assumptions: {
+ iterableIsArray: true,
+ noNewArrows: true,
+ noClassCalls: true,
+ ignoreToPrimitiveHint: true,
+ ignoreFunctionLength: true,
+ },
+ plugins: [
+ '@babel/plugin-transform-runtime',
+ ['@babel/plugin-proposal-class-properties', { loose: true }],
+ ['@babel/plugin-proposal-private-methods', { loose: true }],
+ ],
+ babelHelpers: 'runtime',
+ shouldPrintComment: () => false,
+ caller: {
+ name: 'babel-rollup-build',
+ },
+ extensions,
+ }),
+ ...plugins,
+ ],
+ };
+};
diff --git a/config/rollup/pipeline.common.plugins.js b/config/rollup/pipeline.common.plugins.js
new file mode 100644
index 0000000..1dfcfc2
--- /dev/null
+++ b/config/rollup/pipeline.common.plugins.js
@@ -0,0 +1,23 @@
+const { nodeResolve: rollupPluginResolve } = require('@rollup/plugin-node-resolve');
+const rollupPluginCommonjs = require('@rollup/plugin-commonjs');
+const rollupPluginAlias = require('@rollup/plugin-alias');
+const { extensions, directories } = require('../../resolve.config.json');
+
+module.exports = {
+ rollupAlias: (aliasEntries) =>
+ rollupPluginAlias({
+ entries: aliasEntries,
+ }),
+ rollupCommonjs: (sourcemap) =>
+ rollupPluginCommonjs({
+ sourceMap: sourcemap,
+ extensions,
+ }),
+ rollupResolve: (srcPath) =>
+ rollupPluginResolve({
+ mainFields: ['browser', 'umd:main', 'module', 'main'],
+ rootDir: srcPath,
+ moduleDirectories: directories,
+ extensions,
+ }),
+};
diff --git a/config/rollup/pipeline.dev.js b/config/rollup/pipeline.dev.js
new file mode 100644
index 0000000..6d4ebb5
--- /dev/null
+++ b/config/rollup/pipeline.dev.js
@@ -0,0 +1,37 @@
+const path = require('path');
+const { default: rollupEsBuild } = require('rollup-plugin-esbuild');
+const { rollupCommonjs, rollupResolve, rollupAlias } = require('./pipeline.common.plugins');
+
+module.exports = (options) => {
+ const { rollup, paths, alias } = options;
+ const { output: rollupOutput, input, plugins = [], ...rollupOptions } = rollup;
+ const { file, sourcemap: rawSourcemap, ...outputConfig } = rollupOutput;
+ const { src: srcPath, dist: distPath } = paths;
+ const sourcemap = rawSourcemap;
+
+ const output = {
+ ...outputConfig,
+ sourcemap: true,
+ format: 'esm',
+ generatedCode: 'es2015',
+ file: path.resolve(distPath, `${file}.js`),
+ };
+
+ return {
+ input,
+ output,
+ ...rollupOptions,
+ plugins: [
+ rollupAlias(alias),
+ rollupResolve(srcPath),
+ rollupEsBuild({
+ include: /\.[jt]sx?$/,
+ sourceMap: true,
+ target: 'es6',
+ tsconfig: './tsconfig.json',
+ }),
+ rollupCommonjs(sourcemap),
+ ...plugins,
+ ],
+ };
+};
diff --git a/config/rollup/rollup.config.js b/config/rollup/rollup.config.js
new file mode 100644
index 0000000..343a7af
--- /dev/null
+++ b/config/rollup/rollup.config.js
@@ -0,0 +1,107 @@
+const fs = require('fs');
+const path = require('path');
+const glob = require('glob');
+const resolve = require('../../resolve.config.json');
+const pkg = require('../../package.json');
+
+const defaultOptions = require('./defaultOptions');
+const pipelineBuild = require('./pipeline.build');
+const pipelineDev = require('./pipeline.dev');
+
+const repoRoot = path.resolve(__dirname, '../../');
+
+const appendExtension = (file) =>
+ path.extname(file) === '' ? file + resolve.extensions.find((ext) => fs.existsSync(path.resolve(`${file}${ext}`))) : file;
+
+const normalizePath = (pathName) => (pathName ? pathName.split(path.sep).join(path.posix.sep) : pathName);
+
+const resolvePath = (basePath, pathToResolve, appendExt) => {
+ const result = pathToResolve ? (path.isAbsolute(pathToResolve) ? pathToResolve : path.resolve(basePath, pathToResolve)) : null;
+ return normalizePath(result && appendExt ? appendExtension(result) : result);
+};
+
+const getWorkspaceAliases = () =>
+ pkg.workspaces
+ .map((pattern) => glob.sync(pattern, { cwd: repoRoot }))
+ .flat()
+ .reduce((obj, resolvedPath) => {
+ let projTsConfig;
+ const absolutePath = path.resolve(repoRoot, resolvedPath);
+ try {
+ projTsConfig = require(`${path.resolve(repoRoot, resolvedPath)}/tsconfig.json`);
+ } catch {}
+
+ obj[`@/${path.basename(absolutePath)}`] = `${normalizePath(
+ path.resolve(absolutePath, projTsConfig?.compilerOptions?.baseUrl || defaultOptions.paths.src)
+ )}`;
+ return obj;
+ }, {});
+
+const mergeAndResolveOptions = (userOptions) => {
+ const { mode: defaultMode, paths: defaultPaths, versions: defaultVersions, alias: defaultAlias, rollup: defaultRollup } = defaultOptions;
+ const { project, mode: rawMode, paths: rawPaths = {}, versions: rawVersions = {}, alias: rawAlias = {}, rollup: rawRollup = {} } = userOptions;
+ const projectPath = process.cwd();
+ const mergedOptions = {
+ project: project || path.basename(projectPath),
+ mode: rawMode || defaultMode,
+ repoRoot,
+ paths: {
+ ...defaultPaths,
+ ...rawPaths,
+ },
+ versions: {
+ ...defaultVersions,
+ ...rawVersions,
+ },
+ alias: {
+ ...getWorkspaceAliases(),
+ ...defaultAlias,
+ ...rawAlias,
+ },
+ rollup: {
+ ...defaultRollup,
+ ...rawRollup,
+ output: {
+ ...defaultRollup.output,
+ ...(rawRollup.output || {}),
+ },
+ },
+ };
+ const { src, dist, types, tests } = mergedOptions.paths;
+
+ mergedOptions.paths.src = resolvePath(projectPath, src);
+ mergedOptions.paths.dist = resolvePath(projectPath, dist);
+ mergedOptions.paths.types = resolvePath(projectPath, types);
+ mergedOptions.paths.tests = resolvePath(projectPath, tests);
+
+ mergedOptions.rollup.input = resolvePath(projectPath, mergedOptions.rollup.input, true);
+ mergedOptions.rollup.output = {
+ ...(mergedOptions.rollup.output || {}),
+ name: mergedOptions.rollup.output?.name || mergedOptions.project,
+ file: mergedOptions.rollup.output?.file || mergedOptions.project.toLocaleLowerCase(),
+ };
+
+ return mergedOptions;
+};
+
+const createConfig = (userOptions = {}) => {
+ const options = mergeAndResolveOptions(userOptions);
+ const { project, mode, versions } = options;
+ const { module: buildModuleVersion } = versions;
+ const isBuild = mode === 'build';
+
+ if (isBuild) {
+ console.log('');
+ console.log('PROJECT : ', project);
+ console.log('OPTIONS : ', options);
+
+ const umd = pipelineBuild(false, options, true);
+ const esm = buildModuleVersion ? pipelineBuild(true, options) : null;
+
+ return [umd, esm].filter((build) => !!build);
+ }
+
+ return pipelineDev(options);
+};
+
+module.exports = createConfig;
diff --git a/jest-playwright.config.base.js b/jest-playwright.config.base.js
deleted file mode 100644
index 504f9ce..0000000
--- a/jest-playwright.config.base.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const path = require('path');
-
-const deploymentConfig = path.resolve(__dirname, './config/jest-browser.rollup.config.js');
-const testServerPath = path.resolve(__dirname, './config/jest-test-server.js');
-
-module.exports = {
- browsers: ['chromium', 'firefox', 'webkit'],
- collectCoverage: true,
- launchType: 'LAUNCH',
- launchOptions: {
- headless: false,
- },
- serverOptions: {
- command: `node ${testServerPath}`,
- port: deploymentConfig.port,
- launchTimeout: 10000,
- },
-};
diff --git a/jest.config.base.js b/jest.config.base.js
index 76279b4..d03a6b1 100644
--- a/jest.config.base.js
+++ b/jest.config.base.js
@@ -1,64 +1,17 @@
const path = require('path');
const resolve = require('./resolve.config');
-const browserRollupConfig = require('./config/jest-browser.rollup.config.js');
-
-const testServerLoaderPath = path.resolve(__dirname, './config/jest-test-server.loader.js');
-const jsdomSetupFile = path.resolve(__dirname, './config/jest-jsdom.setup.js');
-const browserGlobalSetupPath = path.resolve(__dirname, './config/jest-browser.globalSetup.js');
-const browserGlobalTeardownPath = path.resolve(__dirname, './config/jest-browser.globalTeardown.js');
-const browserTestEnvironmentPath = path.resolve(__dirname, './config/jest-browser.env.js');
-const browserSetupAfterEnvFile = path.resolve(__dirname, './config/jest-browser.setupAfterEnv.js');
// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html
-const base = {
+module.exports = {
clearMocks: true,
- coverageDirectory: './.coverage/jsdom',
+ coverageDirectory: './.coverage/jest',
testEnvironment: 'jsdom',
moduleDirectories: resolve.directories,
moduleFileExtensions: resolve.extensions.map((ext) => ext.replace(/\./, '')),
testPathIgnorePatterns: ['\\\\node_modules\\\\'],
-};
-
-const browserBase = {
- ...base,
- collectCoverage: false,
- preset: 'jest-playwright-preset',
- globalSetup: browserGlobalSetupPath,
- globalTeardown: browserGlobalTeardownPath,
- testEnvironment: browserTestEnvironmentPath,
- setupFilesAfterEnv: [browserSetupAfterEnvFile],
- testMatch: ['**/tests/browser/**/*.test.[jt]s?(x)'],
- coveragePathIgnorePatterns: ['/node_modules/', `/${browserRollupConfig.build}/`],
- transform: {
- '^.+\\.[jt]sx?$': 'babel-jest',
- [`^.+${browserRollupConfig.build}.+${browserRollupConfig.html.output}?$`]: testServerLoaderPath,
- },
-};
-
-module.exports = {
- ...base,
- projects: [
- {
- ...base,
- displayName: 'jsdom',
- setupFilesAfterEnv: [jsdomSetupFile],
- testMatch: ['**/tests/jsdom/**/*.test.[jt]s?(x)'],
- },
- {
- ...browserBase,
- displayName: {
- name: 'browser',
- color: 'white',
- },
- },
- {
- ...browserBase,
- displayName: {
- name: 'browser-dev',
- color: 'white',
- },
- },
- ],
+ displayName: 'jest',
+ setupFilesAfterEnv: [path.resolve(__dirname, './config/jest/jest.setup.js')],
+ testMatch: ['**/tests/jest/**/*.test.[jt]s?(x)'],
};
diff --git a/package.json b/package.json
index 2dcb6fa..8886549 100644
--- a/package.json
+++ b/package.json
@@ -4,66 +4,58 @@
"packages/*"
],
"devDependencies": {
- "@babel/core": "^7.14.6",
- "@babel/plugin-transform-runtime": "^7.14.5",
- "@babel/preset-env": "^7.14.7",
- "@babel/preset-typescript": "^7.14.5",
- "@rollup/plugin-babel": "^5.3.0",
- "@rollup/plugin-commonjs": "^17.0.0",
+ "@babel/core": "^7.18.2",
+ "@babel/plugin-transform-runtime": "^7.18.2",
+ "@babel/preset-env": "^7.18.2",
+ "@babel/preset-typescript": "^7.17.12",
+ "@babel/runtime": "^7.18.2",
+ "@playwright/test": "^1.22.2",
+ "@rollup/plugin-alias": "^3.1.9",
+ "@rollup/plugin-babel": "^5.3.1",
+ "@rollup/plugin-commonjs": "^22.0.0",
"@rollup/plugin-html": "^0.2.0",
- "@rollup/plugin-inject": "^4.0.2",
- "@rollup/plugin-node-resolve": "^11.0.1",
- "@rollup/plugin-typescript": "^5.0.2",
+ "@rollup/plugin-node-resolve": "^13.3.0",
"@testing-library/dom": "^7.26.3",
"@types/jest": "^26.0.24",
"@typescript-eslint/eslint-plugin": "^3.7.0",
"@typescript-eslint/parser": "^3.7.0",
- "babel-jest": "^27.0.6",
- "babel-plugin-istanbul": "^6.0.0",
+ "babel-jest": "^28.1.1",
"bufferutil": "^4.0.1",
"canvas": "^2.6.1",
"chalk": "^4.1.0",
"core-js": "^3.6.5",
"del": "^5.1.0",
+ "esbuild": "^0.14.42",
"eslint": "^7.5.0",
"eslint-config-airbnb": "^18.2.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jest": "^24.3.6",
- "eslint-plugin-jest-playwright": "^0.4.1",
"eslint-plugin-json": "^2.1.2",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-react": "^7.20.3",
"eslint-plugin-react-hooks": "^4.0.8",
- "expect-playwright": "^0.3.4",
- "express": "^4.17.1",
"glob": "^7.1.6",
- "jest": "^27.0.6",
- "jest-circus": "^27.0.6",
- "jest-dev-server": "^4.4.0",
- "jest-environment-node": "^27.0.6",
- "jest-playwright-preset": "^1.7.0",
- "jest-runner": "^27.0.6",
- "mkdirp": "^1.0.4",
- "node-sass": "^4.14.1",
- "playwright": "^1.12.3",
- "playwright-chromium": "^1.12.3",
- "playwright-core": "^1.12.3",
- "playwright-firefox": "^1.12.3",
- "playwright-webkit": "1.12.3",
+ "jest": "^28.1.1",
+ "node-sass": "^7.0.1",
+ "playwright": "^1.22.2",
+ "playwright-chromium": "^1.22.2",
+ "playwright-core": "^1.22.2",
+ "playwright-firefox": "^1.22.2",
+ "playwright-webkit": "^1.22.2",
"prettier": "^2.0.5",
"prettier-eslint": "^11.0.0",
- "rollup": "^2.36.1",
+ "rollup": "^2.75.5",
+ "rollup-plugin-esbuild": "^4.9.1",
"rollup-plugin-livereload": "^2.0.0",
- "rollup-plugin-prettier": "^2.1.0",
"rollup-plugin-serve": "^1.1.0",
"rollup-plugin-styles": "^3.10.0",
"rollup-plugin-terser": "^6.1.0",
- "rollup-plugin-typescript2": "^0.27.1",
+ "rollup-plugin-ts": "^3.0.1",
"should": "^13.2.3",
- "tslib": "^2.2.0",
- "typescript": "^4.3.2",
+ "tslib": "^2.4.0",
+ "typescript": "^4.7.3",
"utf-8-validate": "^5.0.2"
},
"scripts": {
@@ -72,6 +64,7 @@
"test:browser": "yarn workspaces run test:browser",
"test:browser:quick": "yarn workspaces run test:browser:quick",
"test:browser-dev": "yarn workspaces run test:browser-dev",
+ "test:playwright": "yarn workspaces run test:playwright",
"build": "yarn workspaces run build",
"lint": "npx eslint --fix ."
}
diff --git a/packages/overlayscrollbars-example/.gitignore b/packages/overlayscrollbars-example/.gitignore
new file mode 100644
index 0000000..a547bf3
--- /dev/null
+++ b/packages/overlayscrollbars-example/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/packages/overlayscrollbars-example/favicon.svg b/packages/overlayscrollbars-example/favicon.svg
new file mode 100644
index 0000000..de4aedd
--- /dev/null
+++ b/packages/overlayscrollbars-example/favicon.svg
@@ -0,0 +1,15 @@
+
diff --git a/packages/overlayscrollbars-example/index.html b/packages/overlayscrollbars-example/index.html
new file mode 100644
index 0000000..3a37503
--- /dev/null
+++ b/packages/overlayscrollbars-example/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ OverlayScrollbars example
+
+
+
+
+
+
diff --git a/packages/overlayscrollbars-example/package.json b/packages/overlayscrollbars-example/package.json
new file mode 100644
index 0000000..2496d7c
--- /dev/null
+++ b/packages/overlayscrollbars-example/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "overlayscrollbars-example",
+ "private": true,
+ "version": "0.0.0",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview"
+ },
+ "devDependencies": {
+ "typescript": "^4.5.4",
+ "vite": "^2.9.9"
+ },
+ "dependencies": {
+ "overlayscrollbars": "file:./../overlayscrollbars"
+ }
+}
\ No newline at end of file
diff --git a/packages/overlayscrollbars-example/src/main.ts b/packages/overlayscrollbars-example/src/main.ts
new file mode 100644
index 0000000..77ce734
--- /dev/null
+++ b/packages/overlayscrollbars-example/src/main.ts
@@ -0,0 +1,8 @@
+import './style.css';
+
+const app = document.querySelector('#app')!;
+
+app.innerHTML = `
+ Hello Vite!
+ Documentation
+`;
diff --git a/packages/overlayscrollbars-example/src/style.css b/packages/overlayscrollbars-example/src/style.css
new file mode 100644
index 0000000..852de7a
--- /dev/null
+++ b/packages/overlayscrollbars-example/src/style.css
@@ -0,0 +1,8 @@
+#app {
+ font-family: Avenir, Helvetica, Arial, sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ text-align: center;
+ color: #2c3e50;
+ margin-top: 60px;
+}
diff --git a/packages/overlayscrollbars-example/src/vite-env.d.ts b/packages/overlayscrollbars-example/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/packages/overlayscrollbars-example/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/packages/overlayscrollbars-example/tsconfig.json b/packages/overlayscrollbars-example/tsconfig.json
new file mode 100644
index 0000000..fbd0225
--- /dev/null
+++ b/packages/overlayscrollbars-example/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": ["ESNext", "DOM"],
+ "moduleResolution": "Node",
+ "strict": true,
+ "sourceMap": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "esModuleInterop": true,
+ "noEmit": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noImplicitReturns": true,
+ "skipLibCheck": true
+ },
+ "include": ["src"]
+}
diff --git a/packages/overlayscrollbars/dist/overlayscrollbars.esm.js b/packages/overlayscrollbars/dist/overlayscrollbars.esm.js
index fcbd70c..f40c408 100644
--- a/packages/overlayscrollbars/dist/overlayscrollbars.esm.js
+++ b/packages/overlayscrollbars/dist/overlayscrollbars.esm.js
@@ -1,5 +1,9 @@
const createCache = (update, options) => {
- const { _equal, _initialValue, _alwaysUpdateValues } = options || {};
+ const {
+ _initialValue,
+ _equal,
+ _alwaysUpdateValues
+ } = options || {};
let _value = _initialValue;
let _previous;
@@ -14,38 +18,25 @@ const createCache = (update, options) => {
_previous = curr;
}
- return {
- _value,
- _previous,
- _changed: changed,
- };
+ return [_value, changed, _previous];
};
- return {
- _update: cacheUpdate,
- _current: (force) => ({
- _value,
- _previous,
- _changed: !!force,
- }),
- };
+ return [cacheUpdate, force => [_value, !!force, _previous]];
};
const ElementNodeType = Node.ELEMENT_NODE;
-const { toString, hasOwnProperty } = Object.prototype;
+const {
+ toString,
+ hasOwnProperty: hasOwnProperty$1
+} = Object.prototype;
function isUndefined(obj) {
return obj === undefined;
}
function isNull(obj) {
return obj === null;
}
-const type = (obj) => {
- return isUndefined(obj) || isNull(obj)
- ? `${obj}`
- : toString
- .call(obj)
- .replace(/^\[object (.+)\]$/, '$1')
- .toLowerCase();
+const type = obj => {
+ return isUndefined(obj) || isNull(obj) ? `${obj}` : toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();
};
function isNumber(obj) {
return typeof obj === 'number';
@@ -68,7 +59,7 @@ function isObject(obj) {
function isArrayLike(obj) {
const length = !!obj && obj.length;
const lengthCorrectFormat = isNumber(length) && length > -1 && length % 1 == 0;
- return isArray(obj) || (!isFunction(obj) && lengthCorrectFormat) ? (length > 0 && isObject(obj) ? length - 1 in obj : true) : false;
+ return isArray(obj) || !isFunction(obj) && lengthCorrectFormat ? length > 0 && isObject(obj) ? length - 1 in obj : true : false;
}
function isPlainObject(obj) {
if (!obj || !isObject(obj) || type(obj) !== 'object') return false;
@@ -76,25 +67,24 @@ function isPlainObject(obj) {
const cstr = 'constructor';
const ctor = obj[cstr];
const ctorProto = ctor && ctor.prototype;
- const hasOwnConstructor = hasOwnProperty.call(obj, cstr);
- const hasIsPrototypeOf = ctorProto && hasOwnProperty.call(ctorProto, 'isPrototypeOf');
+ const hasOwnConstructor = hasOwnProperty$1.call(obj, cstr);
+ const hasIsPrototypeOf = ctorProto && hasOwnProperty$1.call(ctorProto, 'isPrototypeOf');
if (ctor && !hasOwnConstructor && !hasIsPrototypeOf) {
return false;
}
- for (key in obj) {
- }
+ for (key in obj) {}
- return isUndefined(key) || hasOwnProperty.call(obj, key);
+ return isUndefined(key) || hasOwnProperty$1.call(obj, key);
}
function isHTMLElement(obj) {
const instanceofObj = window.HTMLElement;
- return obj ? (instanceofObj ? obj instanceof instanceofObj : obj.nodeType === ElementNodeType) : false;
+ return obj ? instanceofObj ? obj instanceof instanceofObj : obj.nodeType === ElementNodeType : false;
}
function isElement(obj) {
const instanceofObj = window.Element;
- return obj ? (instanceofObj ? obj instanceof instanceofObj : obj.nodeType === ElementNodeType) : false;
+ return obj ? instanceofObj ? obj instanceof instanceofObj : obj.nodeType === ElementNodeType : false;
}
function each(source, callback) {
@@ -105,7 +95,7 @@ function each(source, callback) {
}
}
} else if (source) {
- each(Object.keys(source), (key) => callback(source[key], key, source));
+ each(Object.keys(source), key => callback(source[key], key, source));
}
return source;
@@ -115,20 +105,20 @@ const push = (array, items, arrayIsSingleItem) => {
!arrayIsSingleItem && !isString(items) && isArrayLike(items) ? Array.prototype.push.apply(array, items) : array.push(items);
return array;
};
-const from = (arr) => {
+const from = arr => {
if (Array.from) {
return Array.from(arr);
}
const result = [];
- each(arr, (elm) => {
+ each(arr, elm => {
push(result, elm);
});
return result;
};
-const isEmptyArray = (array) => array && array.length === 0;
+const isEmptyArray = array => array && array.length === 0;
const runEach = (arr, p1) => {
- const runFn = (fn) => fn && fn(p1);
+ const runFn = fn => fn && fn(p1);
if (arr instanceof Set) {
arr.forEach(runFn);
@@ -137,8 +127,8 @@ const runEach = (arr, p1) => {
}
};
-const hasOwnProperty$1 = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
-const keys = (obj) => (obj ? Object.keys(obj) : []);
+const hasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
+const keys = obj => obj ? Object.keys(obj) : [];
function assignDeep(target, object1, object2, object3, object4, object5, object6) {
const sources = [object1, object2, object3, object4, object5, object6];
@@ -146,8 +136,8 @@ function assignDeep(target, object1, object2, object3, object4, object5, object6
target = {};
}
- each(sources, (source) => {
- each(keys(source), (key) => {
+ each(sources, source => {
+ each(keys(source), key => {
const copy = source[key];
if (target === copy) {
@@ -209,7 +199,7 @@ const elmPrototype = Element.prototype;
const find = (selector, elm) => {
const arr = [];
- const rootElm = elm ? (isElement(elm) ? elm : null) : document;
+ const rootElm = elm ? isElement(elm) ? elm : null : document;
return rootElm ? push(arr, rootElm.querySelectorAll(selector)) : arr;
};
@@ -222,9 +212,9 @@ const is = (elm, selector) => {
return false;
};
-const contents = (elm) => (elm ? from(elm.childNodes) : []);
+const contents = elm => elm ? from(elm.childNodes) : [];
-const parent = (elm) => (elm ? elm.parentElement : null);
+const parent = elm => elm ? elm.parentElement : null;
const before = (parentElm, preferredAnchor, insertedElms) => {
if (insertedElms) {
@@ -234,7 +224,7 @@ const before = (parentElm, preferredAnchor, insertedElms) => {
if (parentElm) {
if (isArrayLike(insertedElms)) {
fragment = document.createDocumentFragment();
- each(insertedElms, (insertedElm) => {
+ each(insertedElms, insertedElm => {
if (insertedElm === anchor) {
anchor = insertedElm.previousSibling;
}
@@ -270,9 +260,9 @@ const insertBefore = (node, insertedNodes) => {
const insertAfter = (node, insertedNodes) => {
before(parent(node), node && node.nextSibling, insertedNodes);
};
-const removeElements = (nodes) => {
+const removeElements = nodes => {
if (isArrayLike(nodes)) {
- each(from(nodes), (e) => removeElements(e));
+ each(from(nodes), e => removeElements(e));
} else if (nodes) {
const parentElm = parent(nodes);
@@ -282,7 +272,7 @@ const removeElements = (nodes) => {
}
};
-const createDiv = (classNames) => {
+const createDiv = classNames => {
const div = document.createElement('div');
if (classNames) {
@@ -291,13 +281,13 @@ const createDiv = (classNames) => {
return div;
};
-const createDOM = (html) => {
+const createDOM = html => {
const createdDiv = createDiv();
createdDiv.innerHTML = html.trim();
- return each(contents(createdDiv), (elm) => removeElements(elm));
+ return each(contents(createdDiv), elm => removeElements(elm));
};
-const firstLetterToUpper = (str) => str.charAt(0).toUpperCase() + str.slice(1);
+const firstLetterToUpper = str => str.charAt(0).toUpperCase() + str.slice(1);
const getDummyStyle = () => createDiv().style;
@@ -305,30 +295,30 @@ const cssPrefixes = ['-webkit-', '-moz-', '-o-', '-ms-'];
const jsPrefixes = ['WebKit', 'Moz', 'O', 'MS', 'webkit', 'moz', 'o', 'ms'];
const jsCache = {};
const cssCache = {};
-const cssProperty = (name) => {
+const cssProperty = name => {
let result = cssCache[name];
- if (hasOwnProperty$1(cssCache, name)) {
+ if (hasOwnProperty(cssCache, name)) {
return result;
}
const uppercasedName = firstLetterToUpper(name);
const elmStyle = getDummyStyle();
- each(cssPrefixes, (prefix) => {
+ each(cssPrefixes, prefix => {
const prefixWithoutDashes = prefix.replace(/-/g, '');
const resultPossibilities = [name, prefix + name, prefixWithoutDashes + uppercasedName, firstLetterToUpper(prefixWithoutDashes) + uppercasedName];
- return !(result = resultPossibilities.find((resultPossibility) => elmStyle[resultPossibility] !== undefined));
+ return !(result = resultPossibilities.find(resultPossibility => elmStyle[resultPossibility] !== undefined));
});
- return (cssCache[name] = result || '');
+ return cssCache[name] = result || '';
};
-const jsAPI = (name) => {
+const jsAPI = name => {
let result = jsCache[name] || window[name];
- if (hasOwnProperty$1(jsCache, name)) {
+ if (hasOwnProperty(jsCache, name)) {
return result;
}
- each(jsPrefixes, (prefix) => {
+ each(jsPrefixes, prefix => {
result = result || window[prefix + firstLetterToUpper(name)];
return !result;
});
@@ -353,7 +343,7 @@ const classListAction = (elm, className, action) => {
const classes = className.match(rnothtmlwhite) || [];
result = classes.length > 0;
- while ((clazz = classes[i++])) {
+ while (clazz = classes[i++]) {
result = !!action(elm.classList, clazz) && result;
}
}
@@ -370,10 +360,10 @@ const diffClass = (classNameA, classNameB) => {
const classNameASplit = classNameA && classNameA.split(' ');
const classNameBSplit = classNameB && classNameB.split(' ');
const tempObj = {};
- each(classNameASplit, (className) => {
+ each(classNameASplit, className => {
tempObj[className] = 1;
});
- each(classNameBSplit, (className) => {
+ each(classNameBSplit, className => {
if (tempObj[className]) {
delete tempObj[className];
} else {
@@ -383,36 +373,27 @@ const diffClass = (classNameA, classNameB) => {
return keys(tempObj);
};
-const zeroObj = {
+const zeroObj$1 = {
w: 0,
- h: 0,
+ h: 0
};
const windowSize = () => ({
w: window.innerWidth,
- h: window.innerHeight,
+ h: window.innerHeight
});
-const offsetSize = (elm) =>
- elm
- ? {
- w: elm.offsetWidth,
- h: elm.offsetHeight,
- }
- : zeroObj;
-const clientSize = (elm) =>
- elm
- ? {
- w: elm.clientWidth,
- h: elm.clientHeight,
- }
- : zeroObj;
-const scrollSize = (elm) =>
- elm
- ? {
- w: elm.scrollWidth,
- h: elm.scrollHeight,
- }
- : zeroObj;
-const getBoundingClientRect = (elm) => elm.getBoundingClientRect();
+const offsetSize = elm => elm ? {
+ w: elm.offsetWidth,
+ h: elm.offsetHeight
+} : zeroObj$1;
+const clientSize = elm => elm ? {
+ w: elm.clientWidth,
+ h: elm.clientHeight
+} : zeroObj$1;
+const scrollSize = elm => elm ? {
+ w: elm.scrollWidth,
+ h: elm.scrollHeight
+} : zeroObj$1;
+const getBoundingClientRect = elm => elm.getBoundingClientRect();
let passiveEventsSupport;
@@ -421,60 +402,52 @@ const supportPassiveEvents = () => {
passiveEventsSupport = false;
try {
- window.addEventListener(
- 'test',
- null,
- Object.defineProperty({}, 'passive', {
- get: function () {
- passiveEventsSupport = true;
- },
- })
- );
+ window.addEventListener('test', null, Object.defineProperty({}, 'passive', {
+ get: function () {
+ passiveEventsSupport = true;
+ }
+ }));
} catch (e) {}
}
return passiveEventsSupport;
};
-const splitEventNames = (eventNames) => eventNames.split(' ');
+const splitEventNames = eventNames => eventNames.split(' ');
const off = (target, eventNames, listener, capture) => {
- each(splitEventNames(eventNames), (eventName) => {
+ each(splitEventNames(eventNames), eventName => {
target.removeEventListener(eventName, listener, capture);
});
};
const on = (target, eventNames, listener, options) => {
const doSupportPassiveEvents = supportPassiveEvents();
- const passive = (doSupportPassiveEvents && options && options._passive) || false;
- const capture = (options && options._capture) || false;
- const once = (options && options._once) || false;
+ const passive = doSupportPassiveEvents && options && options._passive || false;
+ const capture = options && options._capture || false;
+ const once = options && options._once || false;
const offListeners = [];
- const nativeOptions = doSupportPassiveEvents
- ? {
- passive,
- capture,
- }
- : capture;
- each(splitEventNames(eventNames), (eventName) => {
- const finalListener = once
- ? (evt) => {
- target.removeEventListener(eventName, finalListener, capture);
- listener && listener(evt);
- }
- : listener;
+ const nativeOptions = doSupportPassiveEvents ? {
+ passive,
+ capture
+ } : capture;
+ each(splitEventNames(eventNames), eventName => {
+ const finalListener = once ? evt => {
+ target.removeEventListener(eventName, finalListener, capture);
+ listener && listener(evt);
+ } : listener;
push(offListeners, off.bind(null, target, eventName, finalListener, capture));
target.addEventListener(eventName, finalListener, nativeOptions);
});
return runEach.bind(0, offListeners);
};
-const stopPropagation = (evt) => evt.stopPropagation();
-const preventDefault = (evt) => evt.preventDefault();
-const stopAndPrevent = (evt) => stopPropagation(evt) || preventDefault(evt);
+const stopPropagation = evt => evt.stopPropagation();
+const preventDefault = evt => evt.preventDefault();
+const stopAndPrevent = evt => stopPropagation(evt) || preventDefault(evt);
const equal = (a, b, props, propMutation) => {
if (a && b) {
let result = true;
- each(props, (prop) => {
+ each(props, prop => {
const compareA = propMutation ? propMutation(a[prop]) : a[prop];
const compareB = propMutation ? propMutation(b[prop]) : b[prop];
@@ -489,11 +462,11 @@ const equal = (a, b, props, propMutation) => {
};
const equalWH = (a, b) => equal(a, b, ['w', 'h']);
const equalTRBL = (a, b) => equal(a, b, ['t', 'r', 'b', 'l']);
-const equalBCRWH = (a, b, round) => equal(a, b, ['width', 'height'], round && ((value) => Math.round(value)));
+const equalBCRWH = (a, b, round) => equal(a, b, ['width', 'height'], round && (value => Math.round(value)));
const setT = window.setTimeout;
-const clearTimeouts = (id) => {
+const clearTimeouts = id => {
id && window.clearTimeout(id);
id && cAF(id);
};
@@ -504,7 +477,11 @@ const debounce = (functionToDebounce, options) => {
let maxTimeoutId;
let prevArguments;
let latestArguments;
- const { _timeout, _maxDelay, _mergeParams } = options;
+ const {
+ _timeout,
+ _maxDelay,
+ _mergeParams
+ } = options;
const invokeFunctionToDebounce = function invokeFunctionToDebounce(args) {
clearTimeouts(timeoutId);
@@ -513,7 +490,7 @@ const debounce = (functionToDebounce, options) => {
functionToDebounce.apply(this, args);
};
- const mergeParms = (curr) => (_mergeParams && prevArguments ? _mergeParams(prevArguments, curr) : curr);
+ const mergeParms = curr => _mergeParams && prevArguments ? _mergeParams(prevArguments, curr) : curr;
const flush = () => {
if (timeoutId) {
@@ -557,7 +534,7 @@ const debounce = (functionToDebounce, options) => {
const cssNumber = {
opacity: 1,
- zindex: 1,
+ zindex: 1
};
const parseToZeroOrNumber = (value, toFloat) => {
@@ -565,15 +542,16 @@ const parseToZeroOrNumber = (value, toFloat) => {
return Number.isNaN(num) ? 0 : num;
};
-const adaptCSSVal = (prop, val) => (!cssNumber[prop.toLowerCase()] && isNumber(val) ? `${val}px` : val);
+const adaptCSSVal = (prop, val) => !cssNumber[prop.toLowerCase()] && isNumber(val) ? `${val}px` : val;
-const getCSSVal = (elm, computedStyle, prop) =>
- computedStyle != null ? computedStyle[prop] || computedStyle.getPropertyValue(prop) : elm.style[prop];
+const getCSSVal = (elm, computedStyle, prop) => computedStyle != null ? computedStyle[prop] || computedStyle.getPropertyValue(prop) : elm.style[prop];
const setCSSVal = (elm, prop, val) => {
try {
if (elm) {
- const { style } = elm;
+ const {
+ style
+ } = elm;
if (!isUndefined(style[prop])) {
style[prop] = adaptCSSVal(prop, val);
@@ -593,18 +571,16 @@ function style(elm, styles) {
if (elm) {
const computedStyle = window.getComputedStyle(elm, null);
- getStylesResult = getSingleStyle
- ? getCSSVal(elm, computedStyle, styles)
- : styles.reduce((result, key) => {
- result[key] = getCSSVal(elm, computedStyle, key);
- return result;
- }, getStylesResult);
+ getStylesResult = getSingleStyle ? getCSSVal(elm, computedStyle, styles) : styles.reduce((result, key) => {
+ result[key] = getCSSVal(elm, computedStyle, key);
+ return result;
+ }, getStylesResult);
}
return getStylesResult;
}
- each(keys(styles), (key) => setCSSVal(elm, key, styles[key]));
+ each(keys(styles), key => setCSSVal(elm, key, styles[key]));
}
const topRightBottomLeft = (elm, propertyPrefix, propertySuffix) => {
const finalPrefix = propertyPrefix ? `${propertyPrefix}-` : '';
@@ -618,54 +594,54 @@ const topRightBottomLeft = (elm, propertyPrefix, propertySuffix) => {
t: parseToZeroOrNumber(result[top]),
r: parseToZeroOrNumber(result[right]),
b: parseToZeroOrNumber(result[bottom]),
- l: parseToZeroOrNumber(result[left]),
+ l: parseToZeroOrNumber(result[left])
};
};
-const zeroObj$1 = {
+const zeroObj = {
x: 0,
- y: 0,
+ y: 0
};
-const absoluteCoordinates = (elm) => {
+const absoluteCoordinates = elm => {
const rect = elm ? getBoundingClientRect(elm) : 0;
- return rect
- ? {
- x: rect.left + window.pageYOffset,
- y: rect.top + window.pageXOffset,
- }
- : zeroObj$1;
+ return rect ? {
+ x: rect.left + window.pageYOffset,
+ y: rect.top + window.pageXOffset
+ } : zeroObj;
};
-function createCommonjsModule(fn) {
- var module = { exports: {} };
- return fn(module, module.exports), module.exports;
+function getDefaultExportFromCjs (x) {
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
-var _extends_1 = createCommonjsModule(function (module) {
- function _extends() {
- module.exports = _extends =
- Object.assign ||
- function (target) {
- for (var i = 1; i < arguments.length; i++) {
- var source = arguments[i];
+var _extends$1 = {exports: {}};
- for (var key in source) {
- if (Object.prototype.hasOwnProperty.call(source, key)) {
- target[key] = source[key];
- }
+(function (module) {
+ function _extends() {
+ module.exports = _extends = Object.assign ? Object.assign.bind() : function (target) {
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i];
+
+ for (var key in source) {
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
+ target[key] = source[key];
}
}
+ }
- return target;
- };
-
+ return target;
+ }, module.exports.__esModule = true, module.exports["default"] = module.exports;
return _extends.apply(this, arguments);
}
- module.exports = _extends;
-});
+ module.exports = _extends, module.exports.__esModule = true, module.exports["default"] = module.exports;
+})(_extends$1);
-const { stringify } = JSON;
+const _extends = getDefaultExportFromCjs(_extends$1.exports);
+
+const {
+ stringify
+} = JSON;
const templateTypePrefixSuffix = ['__TPL_', '_TYPE__'];
const optionsTemplateTypes = ['boolean', 'number', 'string', 'array', 'object', 'function', 'null'].reduce((result, item) => {
result[item] = templateTypePrefixSuffix[0] + item + templateTypePrefixSuffix[1];
@@ -675,10 +651,10 @@ const optionsTemplateTypes = ['boolean', 'number', 'string', 'array', 'object',
const validateRecursive = (options, template, optionsDiff, doWriteErrors, propPath) => {
const validatedOptions = {};
- const optionsCopy = _extends_1({}, options);
+ const optionsCopy = _extends({}, options);
- const props = keys(template).filter((prop) => hasOwnProperty$1(options, prop));
- each(props, (prop) => {
+ const props = keys(template).filter(prop => hasOwnProperty(options, prop));
+ each(props, prop => {
const optionsDiffValue = isUndefined(optionsDiff[prop]) ? {} : optionsDiff[prop];
const optionsValue = options[prop];
const templateValue = template[prop];
@@ -689,7 +665,7 @@ const validateRecursive = (options, template, optionsDiff, doWriteErrors, propPa
const validatedResult = validateRecursive(optionsValue, templateValue, optionsDiffValue, doWriteErrors, propPrefix + prop);
validatedOptions[prop] = validatedResult._validated;
optionsCopy[prop] = validatedResult._foreign;
- each([optionsCopy, validatedOptions], (value) => {
+ each([optionsCopy, validatedOptions], value => {
if (isEmptyObject(value[prop])) {
delete value[prop];
}
@@ -700,7 +676,7 @@ const validateRecursive = (options, template, optionsDiff, doWriteErrors, propPa
const errorPossibleTypes = [];
const optionsValueType = type(optionsValue);
const templateValueArr = !isArray(templateValue) ? [templateValue] : templateValue;
- each(templateValueArr, (currTemplateType) => {
+ each(templateValueArr, currTemplateType => {
let typeString;
each(optionsTemplateTypes, (value, key) => {
if (value === currTemplateType) {
@@ -711,7 +687,7 @@ const validateRecursive = (options, template, optionsDiff, doWriteErrors, propPa
if (isEnumString && isString(optionsValue)) {
const enumStringSplit = currTemplateType.split(' ');
- isValid = !!enumStringSplit.find((possibility) => possibility === optionsValue);
+ isValid = !!enumStringSplit.find(possibility => possibility === optionsValue);
push(errorEnumStrings, enumStringSplit);
} else {
isValid = optionsTemplateTypes[optionsValueType] === currTemplateType;
@@ -722,18 +698,14 @@ const validateRecursive = (options, template, optionsDiff, doWriteErrors, propPa
});
if (isValid) {
- const doStringifyComparison = isArray(optionsValue) || isPlainObject(optionsValue);
+ const isPrimitiveArr = isArray(optionsValue) && !optionsValue.some(val => !isNumber(val) && !isString(val) && !isBoolean(val));
+ const doStringifyComparison = isPrimitiveArr || isPlainObject(optionsValue);
if (doStringifyComparison ? stringify(optionsValue) !== stringify(optionsDiffValue) : optionsValue !== optionsDiffValue) {
validatedOptions[prop] = optionsValue;
}
} else if (doWriteErrors) {
- console.warn(
- `${
- `The option "${propPrefix}${prop}" wasn't set, because it doesn't accept the type [ ${optionsValueType.toUpperCase()} ] with the value of "${optionsValue}".\r\n` +
- `Accepted types are: [ ${errorPossibleTypes.join(', ').toUpperCase()} ].\r\n`
- }${errorEnumStrings.length > 0 ? `\r\nValid strings are: [ ${errorEnumStrings.join(', ')} ].` : ''}`
- );
+ console.warn(`${`The option "${propPrefix}${prop}" wasn't set, because it doesn't accept the type [ ${optionsValueType.toUpperCase()} ] with the value of "${optionsValue}".\r\n` + `Accepted types are: [ ${errorPossibleTypes.join(', ').toUpperCase()} ].\r\n`}${errorEnumStrings.length > 0 ? `\r\nValid strings are: [ ${errorEnumStrings.join(', ')} ].` : ''}`);
}
delete optionsCopy[prop];
@@ -741,7 +713,7 @@ const validateRecursive = (options, template, optionsDiff, doWriteErrors, propPa
});
return {
_foreign: optionsCopy,
- _validated: validatedOptions,
+ _validated: validatedOptions
};
};
@@ -749,12 +721,12 @@ const validateOptions = (options, template, optionsDiff, doWriteErrors) => {
return validateRecursive(options, template, optionsDiff || {}, doWriteErrors || false);
};
-const transformOptions = (optionsWithOptionsTemplate) => {
+const transformOptions = optionsWithOptionsTemplate => {
const result = {
_template: {},
- _options: {},
+ _options: {}
};
- each(keys(optionsWithOptionsTemplate), (key) => {
+ each(keys(optionsWithOptionsTemplate), key => {
const val = optionsWithOptionsTemplate[key];
if (isArray(val)) {
@@ -785,6 +757,11 @@ const classNameSizeObserverListenerScroll = `${classNameSizeObserverListener}-sc
const classNameSizeObserverListenerItem = `${classNameSizeObserverListener}-item`;
const classNameSizeObserverListenerItemFinal = `${classNameSizeObserverListenerItem}-final`;
const classNameTrinsicObserver = 'os-trinsic-observer';
+const classNameScrollbar = 'os-scrollbar';
+const classNameScrollbarHorizontal = `${classNameScrollbar}-horizontal`;
+const classNameScrollbarVertical = `${classNameScrollbar}-vertical`;
+const classNameScrollbarTrack = 'os-scrollbar-track';
+const classNameScrollbarHandle = 'os-scrollbar-handle';
const numberAllowedValues = optionsTemplateTypes.number;
const arrayNullValues = [optionsTemplateTypes.array, optionsTemplateTypes.null];
@@ -801,14 +778,11 @@ const defaultOptionsWithTemplate = {
updating: {
elementEvents: [[['img', 'load']], arrayNullValues],
attributes: [null, arrayNullValues],
- debounce: [
- [0, 33],
- [optionsTemplateTypes.number, optionsTemplateTypes.array, optionsTemplateTypes.null],
- ],
+ debounce: [[0, 33], [optionsTemplateTypes.number, optionsTemplateTypes.array, optionsTemplateTypes.null]]
},
overflow: {
x: ['scroll', overflowAllowedValues],
- y: ['scroll', overflowAllowedValues],
+ y: ['scroll', overflowAllowedValues]
},
scrollbars: {
visibility: ['auto', scrollbarsVisibilityAllowedValues],
@@ -816,29 +790,35 @@ const defaultOptionsWithTemplate = {
autoHideDelay: [800, numberAllowedValues],
dragScroll: booleanTrueTemplate,
clickScroll: booleanFalseTemplate,
- touch: booleanTrueTemplate,
+ touch: booleanTrueTemplate
},
textarea: {
dynWidth: booleanFalseTemplate,
dynHeight: booleanFalseTemplate,
- inheritedAttrs: [['style', 'class'], stringArrayNullAllowedValues],
+ inheritedAttrs: [['style', 'class'], stringArrayNullAllowedValues]
},
nativeScrollbarsOverlaid: {
show: booleanFalseTemplate,
- initialize: booleanFalseTemplate,
+ initialize: booleanFalseTemplate
},
callbacks: {
- onUpdated: [null, [optionsTemplateTypes.function, optionsTemplateTypes.null]],
- },
+ onUpdated: [null, [optionsTemplateTypes.function, optionsTemplateTypes.null]]
+ }
};
-const { _template: optionsTemplate, _options: defaultOptions } = transformOptions(defaultOptionsWithTemplate);
+const {
+ _template: optionsTemplate,
+ _options: defaultOptions
+} = transformOptions(defaultOptionsWithTemplate);
let environmentInstance;
-const { abs, round } = Math;
+const {
+ abs: abs$1,
+ round: round$1
+} = Math;
const diffBiggerThanOne = (valOne, valTwo) => {
- const absValOne = abs(valOne);
- const absValTwo = abs(valTwo);
+ const absValOne = abs$1(valOne);
+ const absValTwo = abs$1(valTwo);
return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);
};
@@ -848,18 +828,16 @@ const getNativeScrollbarSize = (body, measureElm) => {
const oSize = offsetSize(measureElm);
return {
x: oSize.h - cSize.h,
- y: oSize.w - cSize.w,
+ y: oSize.w - cSize.w
};
};
-const getNativeScrollbarStyling = (testElm) => {
+const getNativeScrollbarStyling = testElm => {
let result = false;
addClass(testElm, classNameViewportScrollbarStyling);
try {
- result =
- style(testElm, cssProperty('scrollbar-width')) === 'none' ||
- window.getComputedStyle(testElm, '::-webkit-scrollbar').getPropertyValue('display') === 'none';
+ result = style(testElm, cssProperty('scrollbar-width')) === 'none' || window.getComputedStyle(testElm, '::-webkit-scrollbar').getPropertyValue('display') === 'none';
} catch (ex) {}
return result;
@@ -870,7 +848,7 @@ const getRtlScrollBehavior = (parentElm, childElm) => {
style(parentElm, {
overflowX: strHidden,
overflowY: strHidden,
- direction: 'rtl',
+ direction: 'rtl'
});
scrollLeft(parentElm, 0);
const parentOffset = absoluteCoordinates(parentElm);
@@ -879,7 +857,7 @@ const getRtlScrollBehavior = (parentElm, childElm) => {
const childOffsetAfterScroll = absoluteCoordinates(childElm);
return {
i: parentOffset.x === childOffset.x,
- n: childOffset.x !== childOffsetAfterScroll.x,
+ n: childOffset.x !== childOffsetAfterScroll.x
};
};
@@ -901,13 +879,18 @@ const getWindowDPR = () => {
return window.devicePixelRatio || dDPI / sDPI;
};
-const getDefaultInitializationStrategy = (nativeScrollbarStyling) => ({
- _padding: !nativeScrollbarStyling,
- _content: false,
+const getDefaultInitializationStrategy = nativeScrollbarStyling => ({
+ _host: null,
+ _viewport: null,
+ _padding: null,
+ _content: null,
+ _scrollbarsSlot: null
});
const createEnvironment = () => {
- const { body } = document;
+ const {
+ body
+ } = document;
const envDOM = createDOM(``);
const envElm = envDOM[0];
const envChildElm = envElm.firstChild;
@@ -916,9 +899,9 @@ const createEnvironment = () => {
const nativeScrollbarStyling = getNativeScrollbarStyling(envElm);
const nativeScrollbarIsOverlaid = {
x: nativeScrollbarSize.x === 0,
- y: nativeScrollbarSize.y === 0,
+ y: nativeScrollbarSize.y === 0
};
- const defaultInitializationStrategy = getDefaultInitializationStrategy(nativeScrollbarStyling);
+ const defaultInitializationStrategy = getDefaultInitializationStrategy();
let initializationStrategy = defaultInitializationStrategy;
let defaultDefaultOptions = defaultOptions;
const env = {
@@ -937,20 +920,20 @@ const createEnvironment = () => {
onChangedListener.delete(listener);
},
- _getInitializationStrategy: () => _extends_1({}, initializationStrategy),
+ _getInitializationStrategy: () => _extends({}, initializationStrategy),
_setInitializationStrategy(newInitializationStrategy) {
initializationStrategy = assignDeep({}, initializationStrategy, newInitializationStrategy);
},
- _getDefaultOptions: () => _extends_1({}, defaultDefaultOptions),
+ _getDefaultOptions: () => _extends({}, defaultDefaultOptions),
_setDefaultOptions(newDefaultOptions) {
defaultDefaultOptions = assignDeep({}, defaultDefaultOptions, newDefaultOptions);
},
_defaultInitializationStrategy: defaultInitializationStrategy,
- _defaultDefaultOptions: defaultDefaultOptions,
+ _defaultDefaultOptions: defaultDefaultOptions
};
removeAttr(envElm, 'style');
removeElements(envElm);
@@ -964,16 +947,16 @@ const createEnvironment = () => {
const sizeNew = windowSize();
const deltaSize = {
w: sizeNew.w - size.w,
- h: sizeNew.h - size.h,
+ h: sizeNew.h - size.h
};
if (deltaSize.w === 0 && deltaSize.h === 0) return;
const deltaAbsSize = {
- w: abs(deltaSize.w),
- h: abs(deltaSize.h),
+ w: abs$1(deltaSize.w),
+ h: abs$1(deltaSize.h)
};
const deltaAbsRatio = {
- w: abs(round(sizeNew.w / (size.w / 100.0))),
- h: abs(round(sizeNew.h / (size.h / 100.0))),
+ w: abs$1(round$1(sizeNew.w / (size.w / 100.0))),
+ h: abs$1(round$1(sizeNew.h / (size.h / 100.0)))
};
const dprNew = getWindowDPR();
const deltaIsBigger = deltaAbsSize.w > 2 && deltaAbsSize.h > 2;
@@ -982,7 +965,7 @@ const createEnvironment = () => {
const isZoom = deltaIsBigger && difference && dprChanged;
if (isZoom) {
- const newScrollbarSize = (environmentInstance._nativeScrollbarSize = getNativeScrollbarSize(body, envElm));
+ const newScrollbarSize = environmentInstance._nativeScrollbarSize = getNativeScrollbarSize(body, envElm);
removeElements(envElm);
if (scrollbarSize.x !== newScrollbarSize.x || scrollbarSize.y !== newScrollbarSize.y) {
@@ -1009,66 +992,103 @@ const getEnvironment = () => {
return environmentInstance;
};
-const unwrap = (elm) => {
+let contentArrangeCounter = 0;
+
+const unwrap = elm => {
appendChildren(parent(elm), contents(elm));
removeElements(elm);
};
-let contentArrangeCounter = 0;
-
const createUniqueViewportArrangeElement = () => {
- const elm = document.createElement('style');
- attr(elm, 'id', `${classNameViewportArrange}-${contentArrangeCounter}`);
- contentArrangeCounter++;
- return elm;
-};
+ const {
+ _nativeScrollbarStyling,
+ _nativeScrollbarIsOverlaid,
+ _cssCustomProperties
+ } = getEnvironment();
+ const create = !_cssCustomProperties && !_nativeScrollbarStyling && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);
+ const result = create ? document.createElement('style') : false;
-const evaluateCreationFromStrategy = (initializationValue, strategy) => {
- const isBooleanValue = isBoolean(initializationValue);
-
- if (isBooleanValue || isUndefined(initializationValue)) {
- return (isBooleanValue ? initializationValue : strategy) && undefined;
+ if (result) {
+ attr(result, 'id', `${classNameViewportArrange}-${contentArrangeCounter}`);
+ contentArrangeCounter++;
}
- return initializationValue;
+ return result;
};
-const createStructureSetup = (target) => {
- const { _getInitializationStrategy, _nativeScrollbarStyling, _nativeScrollbarIsOverlaid, _cssCustomProperties } = getEnvironment();
+const staticCreationFromStrategy = (target, initializationValue, strategy, elementClass) => {
+ const result = initializationValue ? initializationValue : isFunction(strategy) ? strategy(target) : strategy;
+ return result ? result : createDiv(elementClass);
+};
- const { _padding: paddingNeeded, _content: contentNeeded } = _getInitializationStrategy();
+const dynamicCreationFromStrategy = (target, initializationValue, strategy, elementClass, defaultValue) => {
+ const takeInitializationValue = isBoolean(initializationValue) || initializationValue;
+ const result = takeInitializationValue ? initializationValue : isFunction(strategy) ? strategy(target) : strategy;
+
+ if (result === null) {
+ return defaultValue ? createDiv(elementClass) : false;
+ }
+
+ return result === true ? createDiv(elementClass) : result;
+};
+
+const createStructureSetup = target => {
+ const {
+ _getInitializationStrategy,
+ _nativeScrollbarStyling
+ } = getEnvironment();
+
+ const {
+ _host: hostInitializationStrategy,
+ _viewport: viewportInitializationStrategy,
+ _padding: paddingInitializationStrategy,
+ _content: contentInitializationStrategy
+ } = _getInitializationStrategy();
const targetIsElm = isHTMLElement(target);
- const osTargetObj = targetIsElm
- ? {}
- : {
- _host: target.host,
- _target: target.target,
- _viewport: target.viewport,
- _padding: evaluateCreationFromStrategy(target.padding, paddingNeeded),
- _content: evaluateCreationFromStrategy(target.content, contentNeeded),
- };
+ const targetStructureInitialization = target;
+ const targetElement = targetIsElm ? target : targetStructureInitialization.target;
+ const isTextarea = is(targetElement, 'textarea');
+ const isBody = !isTextarea && is(targetElement, 'body');
+ const ownerDocument = targetElement.ownerDocument;
+ const bodyElm = ownerDocument.body;
+ const wnd = ownerDocument.defaultView;
+ const evaluatedTargetObj = {
+ _target: targetElement,
+ _host: isTextarea ? staticCreationFromStrategy(targetElement, targetStructureInitialization.host, hostInitializationStrategy, classNameHost) : targetElement,
+ _viewport: staticCreationFromStrategy(targetElement, targetStructureInitialization.viewport, viewportInitializationStrategy, classNameViewport),
+ _padding: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.padding, paddingInitializationStrategy, classNamePadding, !_nativeScrollbarStyling),
+ _content: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.content, contentInitializationStrategy, classNameContent, false),
+ _viewportArrange: createUniqueViewportArrangeElement()
+ };
+ const ctx = {
+ _windowElm: wnd,
+ _documentElm: ownerDocument,
+ _htmlElm: parent(bodyElm),
+ _bodyElm: bodyElm,
+ _isTextarea: isTextarea,
+ _isBody: isBody,
+ _targetIsElm: targetIsElm
+ };
+ const generatedElements = keys(evaluatedTargetObj).reduce((arr, key) => {
+ const value = evaluatedTargetObj[key];
+ return push(arr, value && !parent(value) ? value : false);
+ }, []);
- if (targetIsElm) {
- const viewport = createDiv(classNameViewport);
- const padding = paddingNeeded && createDiv(classNamePadding);
- const content = contentNeeded && createDiv(classNameContent);
- osTargetObj._target = target;
- osTargetObj._padding = padding;
- osTargetObj._viewport = viewport;
- osTargetObj._content = content;
- }
+ const elementIsGenerated = elm => elm ? indexOf(generatedElements, elm) > -1 : null;
- let { _target, _padding, _viewport, _content } = osTargetObj;
+ const {
+ _target,
+ _host,
+ _padding,
+ _viewport,
+ _content,
+ _viewportArrange
+ } = evaluatedTargetObj;
const destroyFns = [];
- const isTextarea = is(_target, 'textarea');
- const isBody = !isTextarea && is(_target, 'body');
-
- const _host = isTextarea ? osTargetObj._host || createDiv() : _target;
-
- const getTargetContents = (contentSlot) => (isTextarea ? _target : contents(contentSlot));
-
- const isTextareaHostGenerated = isTextarea && _host !== osTargetObj._host;
+ const isTextareaHostGenerated = isTextarea && elementIsGenerated(_host);
+ const targetContents = isTextarea ? _target : contents([_content, _viewport, _padding, _host, _target].find(elm => elementIsGenerated(elm) === false));
+ const contentSlot = _content || _viewport;
if (isTextareaHostGenerated) {
insertAfter(_target, _host);
@@ -1078,41 +1098,29 @@ const createStructureSetup = (target) => {
});
}
- if (targetIsElm) {
- const contentSlot = _content || _viewport;
- appendChildren(contentSlot, getTargetContents(_target));
- appendChildren(_host, _padding);
- appendChildren(_padding || _host, _viewport);
- appendChildren(_viewport, _content);
- push(destroyFns, () => {
+ appendChildren(contentSlot, targetContents);
+ appendChildren(_host, _padding);
+ appendChildren(_padding || _host, _viewport);
+ appendChildren(_viewport, _content);
+ addClass(_host, classNameHost);
+ addClass(_padding, classNamePadding);
+ addClass(_viewport, classNameViewport);
+ addClass(_content, classNameContent);
+ push(destroyFns, () => {
+ if (targetIsElm) {
appendChildren(_host, contents(contentSlot));
removeElements(_padding || _viewport);
removeClass(_host, classNameHost);
- });
- } else {
- const contentContainingElm = _content || _viewport || _padding || _host;
- const createPadding = isUndefined(_padding);
- const createViewport = isUndefined(_viewport);
- const createContent = isUndefined(_content);
- const targetContents = getTargetContents(contentContainingElm);
- _padding = osTargetObj._padding = createPadding ? createDiv() : _padding;
- _viewport = osTargetObj._viewport = createViewport ? createDiv() : _viewport;
- _content = osTargetObj._content = createContent ? createDiv() : _content;
- appendChildren(_host, _padding);
- appendChildren(_padding || _host, _viewport);
- appendChildren(_viewport, _content);
- const contentSlot = _content || _viewport;
- appendChildren(contentSlot, targetContents);
- push(destroyFns, () => {
- if (createContent) {
+ } else {
+ if (elementIsGenerated(_content)) {
unwrap(_content);
}
- if (createViewport) {
+ if (elementIsGenerated(_viewport)) {
unwrap(_viewport);
}
- if (createPadding) {
+ if (elementIsGenerated(_padding)) {
unwrap(_padding);
}
@@ -1120,44 +1128,79 @@ const createStructureSetup = (target) => {
removeClass(_padding, classNamePadding);
removeClass(_viewport, classNameViewport);
removeClass(_content, classNameContent);
- });
- }
-
- addClass(_host, classNameHost);
- addClass(_padding, classNamePadding);
- addClass(_viewport, classNameViewport);
- addClass(_content, classNameContent);
- const ownerDocument = _target.ownerDocument;
- const bodyElm = ownerDocument.body;
- const wnd = ownerDocument.defaultView;
- const ctx = {
- _windowElm: wnd,
- _documentElm: ownerDocument,
- _htmlElm: parent(bodyElm),
- _bodyElm: bodyElm,
- _isTextarea: isTextarea,
- _isBody: isBody,
- };
-
- const obj = _extends_1({}, osTargetObj, {
- _host,
+ }
});
if (_nativeScrollbarStyling) {
push(destroyFns, removeClass.bind(0, _viewport, classNameViewportScrollbarStyling));
- } else if (!_cssCustomProperties && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y)) {
- const viewportArrangeElm = createUniqueViewportArrangeElement();
- insertBefore(_viewport, viewportArrangeElm);
- push(destroyFns, removeElements.bind(0, viewportArrangeElm));
- obj._viewportArrange = viewportArrangeElm;
+ }
+
+ if (_viewportArrange) {
+ insertBefore(_viewport, _viewportArrange);
+ push(destroyFns, removeElements.bind(0, _viewportArrange));
}
return {
- _targetObj: obj,
+ _targetObj: evaluatedTargetObj,
_targetCtx: ctx,
_destroy: () => {
runEach(destroyFns);
- },
+ }
+ };
+};
+
+const generateScrollbarDOM = scrollbarClassName => {
+ const scrollbar = createDiv(`${classNameScrollbar} ${scrollbarClassName}`);
+ const track = createDiv(classNameScrollbarTrack);
+ const handle = createDiv(classNameScrollbarHandle);
+ appendChildren(scrollbar, track);
+ appendChildren(track, handle);
+ return {
+ _scrollbar: scrollbar,
+ _track: track,
+ _handle: handle
+ };
+};
+
+const createScrollbarsSetup = (target, structureSetup) => {
+ const {
+ _getInitializationStrategy
+ } = getEnvironment();
+
+ const {
+ _scrollbarsSlot: environmentScrollbarSlot
+ } = _getInitializationStrategy();
+
+ const {
+ _targetObj,
+ _targetCtx
+ } = structureSetup;
+ const {
+ _target,
+ _host,
+ _viewport
+ } = _targetObj;
+ const initializationScrollbarSlot = !_targetCtx._targetIsElm && target.scrollbarsSlot;
+ const initializationScrollbarSlotResult = isFunction(initializationScrollbarSlot) ? initializationScrollbarSlot(_target, _host, _viewport) : initializationScrollbarSlot;
+ const evaluatedScrollbarSlot = initializationScrollbarSlotResult || (isFunction(environmentScrollbarSlot) ? environmentScrollbarSlot(_target, _host, _viewport) : environmentScrollbarSlot) || _host;
+ const horizontalScrollbarStructure = generateScrollbarDOM(classNameScrollbarHorizontal);
+ const verticalScrollbarStructure = generateScrollbarDOM(classNameScrollbarVertical);
+ const {
+ _scrollbar: horizontalScrollbar
+ } = horizontalScrollbarStructure;
+ const {
+ _scrollbar: verticalScrollbar
+ } = verticalScrollbarStructure;
+ appendChildren(evaluatedScrollbarSlot, horizontalScrollbar);
+ appendChildren(evaluatedScrollbarSlot, verticalScrollbar);
+ return {
+ _horizontalScrollbarStructure: horizontalScrollbarStructure,
+ _verticalScrollbarStructure: verticalScrollbarStructure,
+
+ _destroy() {
+ removeElements([horizontalScrollbar, verticalScrollbar]);
+ }
+
};
};
@@ -1165,43 +1208,51 @@ const animationStartEventName = 'animationstart';
const scrollEventName = 'scroll';
const scrollAmount = 3333333;
-const directionIsRTL = (elm) => style(elm, 'direction') === 'rtl';
+const getElmDirectionIsRTL = elm => style(elm, 'direction') === 'rtl';
-const domRectHasDimensions = (rect) => rect && (rect.height || rect.width);
+const domRectHasDimensions = rect => rect && (rect.height || rect.width);
const createSizeObserver = (target, onSizeChangedCallback, options) => {
- const { _direction: observeDirectionChange = false, _appear: observeAppearChange = false } = options || {};
- const { _rtlScrollBehavior: rtlScrollBehavior } = getEnvironment();
+ const {
+ _direction: observeDirectionChange = false,
+ _appear: observeAppearChange = false
+ } = options || {};
+ const {
+ _rtlScrollBehavior: rtlScrollBehavior
+ } = getEnvironment();
const baseElements = createDOM(``);
const sizeObserver = baseElements[0];
const listenerElement = sizeObserver.firstChild;
- const { _update: updateResizeObserverContentRectCache } = createCache(0, {
+ const getIsDirectionRTL = getElmDirectionIsRTL.bind(0, sizeObserver);
+ const [updateResizeObserverContentRectCache] = createCache(0, {
+ _initialValue: undefined,
_alwaysUpdateValues: true,
- _equal: (currVal, newVal) => !(!currVal || (!domRectHasDimensions(currVal) && domRectHasDimensions(newVal))),
+ _equal: (currVal, newVal) => !(!currVal || !domRectHasDimensions(currVal) && domRectHasDimensions(newVal))
});
- const onSizeChangedCallbackProxy = (sizeChangedContext) => {
- const hasDirectionCache = sizeChangedContext && isBoolean(sizeChangedContext._value);
+ const onSizeChangedCallbackProxy = sizeChangedContext => {
+ const isResizeObserverCall = isArray(sizeChangedContext) && sizeChangedContext.length > 0 && isObject(sizeChangedContext[0]);
+ const hasDirectionCache = !isResizeObserverCall && isBoolean(sizeChangedContext[0]);
let skip = false;
let appear = false;
let doDirectionScroll = true;
- if (isArray(sizeChangedContext) && sizeChangedContext.length > 0) {
- const { _previous, _value } = updateResizeObserverContentRectCache(0, sizeChangedContext.pop().contentRect);
- const hasDimensions = domRectHasDimensions(_value);
- const hadDimensions = domRectHasDimensions(_previous);
- skip = !_previous || !hasDimensions;
+ if (isResizeObserverCall) {
+ const [currRContentRect,, prevContentRect] = updateResizeObserverContentRectCache(0, sizeChangedContext.pop().contentRect);
+ const hasDimensions = domRectHasDimensions(currRContentRect);
+ const hadDimensions = domRectHasDimensions(prevContentRect);
+ skip = !prevContentRect || !hasDimensions;
appear = !hadDimensions && hasDimensions;
doDirectionScroll = !skip;
} else if (hasDirectionCache) {
- doDirectionScroll = sizeChangedContext._changed;
+ [, doDirectionScroll] = sizeChangedContext;
} else {
appear = sizeChangedContext === true;
}
if (observeDirectionChange && doDirectionScroll) {
- const rtl = hasDirectionCache ? sizeChangedContext._value : directionIsRTL(sizeObserver);
- scrollLeft(sizeObserver, rtl ? (rtlScrollBehavior.n ? -scrollAmount : rtlScrollBehavior.i ? 0 : scrollAmount) : scrollAmount);
+ const rtl = hasDirectionCache ? sizeChangedContext[0] : getElmDirectionIsRTL(sizeObserver);
+ scrollLeft(sizeObserver, rtl ? rtlScrollBehavior.n ? -scrollAmount : rtlScrollBehavior.i ? 0 : scrollAmount : scrollAmount);
scrollTop(sizeObserver, scrollAmount);
}
@@ -1209,7 +1260,7 @@ const createSizeObserver = (target, onSizeChangedCallback, options) => {
onSizeChangedCallback({
_sizeChanged: !hasDirectionCache,
_directionIsRTLCache: hasDirectionCache ? sizeChangedContext : undefined,
- _appear: !!appear,
+ _appear: !!appear
});
}
};
@@ -1225,9 +1276,7 @@ const createSizeObserver = (target, onSizeChangedCallback, options) => {
resizeObserverInstance.disconnect();
});
} else {
- const observerElementChildren = createDOM(
- ``
- );
+ const observerElementChildren = createDOM(``);
appendChildren(listenerElement, observerElementChildren);
addClass(listenerElement, classNameSizeObserverListenerScroll);
const observerElementChildrenRoot = observerElementChildren[0];
@@ -1246,7 +1295,7 @@ const createSizeObserver = (target, onSizeChangedCallback, options) => {
scrollTop(shrinkElement, scrollAmount);
};
- const onResized = (appear) => {
+ const onResized = appear => {
rAFId = 0;
if (isDirty) {
@@ -1255,7 +1304,7 @@ const createSizeObserver = (target, onSizeChangedCallback, options) => {
}
};
- const onScroll = (scrollEvent) => {
+ const onScroll = scrollEvent => {
currSize = offsetSize(observerElementChildrenRoot);
isDirty = !scrollEvent || !equalWH(currSize, cacheSize);
@@ -1276,46 +1325,42 @@ const createSizeObserver = (target, onSizeChangedCallback, options) => {
push(offListeners, [on(expandElement, scrollEventName, onScroll), on(shrinkElement, scrollEventName, onScroll)]);
style(expandElementChild, {
width: scrollAmount,
- height: scrollAmount,
+ height: scrollAmount
});
reset();
appearCallback = observeAppearChange ? onScroll.bind(0, false) : reset;
}
if (observeDirectionChange) {
- directionIsRTLCache = createCache(directionIsRTL.bind(0, sizeObserver));
- const { _update: updateDirectionIsRTLCache } = directionIsRTLCache;
- push(
- offListeners,
- on(sizeObserver, scrollEventName, (event) => {
- const directionIsRTLCacheValues = updateDirectionIsRTLCache();
- const { _value, _changed } = directionIsRTLCacheValues;
+ directionIsRTLCache = createCache(getIsDirectionRTL, {
+ _initialValue: !getIsDirectionRTL()
+ });
+ const [updateDirectionIsRTLCache] = directionIsRTLCache;
+ push(offListeners, on(sizeObserver, scrollEventName, event => {
+ const directionIsRTLCacheValues = updateDirectionIsRTLCache();
+ const [directionIsRTL, directionIsRTLChanged] = directionIsRTLCacheValues;
- if (_changed) {
- removeClass(listenerElement, 'ltr rtl');
+ if (directionIsRTLChanged) {
+ removeClass(listenerElement, 'ltr rtl');
- if (_value) {
- addClass(listenerElement, 'rtl');
- } else {
- addClass(listenerElement, 'ltr');
- }
-
- onSizeChangedCallbackProxy(directionIsRTLCacheValues);
+ if (directionIsRTL) {
+ addClass(listenerElement, 'rtl');
+ } else {
+ addClass(listenerElement, 'ltr');
}
- stopAndPrevent(event);
- })
- );
+ onSizeChangedCallbackProxy(directionIsRTLCacheValues);
+ }
+
+ stopAndPrevent(event);
+ }));
}
if (appearCallback) {
addClass(sizeObserver, classNameSizeObserverAppear);
- push(
- offListeners,
- on(sizeObserver, animationStartEventName, appearCallback, {
- _once: !!ResizeObserverConstructor,
- })
- );
+ push(offListeners, on(sizeObserver, animationStartEventName, appearCallback, {
+ _once: !!ResizeObserverConstructor
+ }));
}
prependChildren(target, sizeObserver);
@@ -1327,47 +1372,39 @@ const createSizeObserver = (target, onSizeChangedCallback, options) => {
_getCurrentCacheValues(force) {
return {
- _directionIsRTL: directionIsRTLCache
- ? directionIsRTLCache._current(force)
- : {
- _value: false,
- _previous: false,
- _changed: false,
- },
+ _directionIsRTL: directionIsRTLCache ? directionIsRTLCache[1](force) : [false, false, false]
};
- },
+ }
+
};
};
const createTrinsicObserver = (target, onTrinsicChangedCallback) => {
const trinsicObserver = createDiv(classNameTrinsicObserver);
const offListeners = [];
- const { _update: updateHeightIntrinsicCache, _current: getCurrentHeightIntrinsicCache } = createCache(
- (ioEntryOrSize) => ioEntryOrSize.h === 0 || ioEntryOrSize.isIntersecting || ioEntryOrSize.intersectionRatio > 0,
- {
- _initialValue: false,
+ const [updateHeightIntrinsicCache, getCurrentHeightIntrinsicCache] = createCache(ioEntryOrSize => ioEntryOrSize.h === 0 || ioEntryOrSize.isIntersecting || ioEntryOrSize.intersectionRatio > 0, {
+ _initialValue: false
+ });
+
+ const triggerOnTrinsicChangedCallback = updateValue => {
+ if (updateValue) {
+ const heightIntrinsic = updateHeightIntrinsicCache(0, updateValue);
+ const [, heightIntrinsicChanged] = heightIntrinsic;
+
+ if (heightIntrinsicChanged) {
+ onTrinsicChangedCallback(heightIntrinsic);
+ }
}
- );
+ };
if (IntersectionObserverConstructor) {
- const intersectionObserverInstance = new IntersectionObserverConstructor(
- (entries) => {
- if (entries && entries.length > 0) {
- const last = entries.pop();
-
- if (last) {
- const heightIntrinsic = updateHeightIntrinsicCache(0, last);
-
- if (heightIntrinsic._changed) {
- onTrinsicChangedCallback(heightIntrinsic);
- }
- }
- }
- },
- {
- root: target,
+ const intersectionObserverInstance = new IntersectionObserverConstructor(entries => {
+ if (entries && entries.length > 0) {
+ triggerOnTrinsicChangedCallback(entries.pop());
}
- );
+ }, {
+ root: target
+ });
intersectionObserverInstance.observe(trinsicObserver);
push(offListeners, () => {
intersectionObserverInstance.disconnect();
@@ -1375,11 +1412,7 @@ const createTrinsicObserver = (target, onTrinsicChangedCallback) => {
} else {
const onSizeChanged = () => {
const newSize = offsetSize(trinsicObserver);
- const heightIntrinsicCache = updateHeightIntrinsicCache(0, newSize);
-
- if (heightIntrinsicCache._changed) {
- onTrinsicChangedCallback(heightIntrinsicCache);
- }
+ triggerOnTrinsicChangedCallback(newSize);
};
push(offListeners, createSizeObserver(trinsicObserver, onSizeChanged)._destroy);
@@ -1395,26 +1428,23 @@ const createTrinsicObserver = (target, onTrinsicChangedCallback) => {
_getCurrentCacheValues(force) {
return {
- _heightIntrinsic: getCurrentHeightIntrinsicCache(force),
+ _heightIntrinsic: getCurrentHeightIntrinsicCache(force)
};
- },
+ }
+
};
};
-const createEventContentChange = (target, eventContentChange, callback) => {
+const createEventContentChange = (target, callback, eventContentChange) => {
let map;
+ let destroyed = false;
const _destroy = () => {
- if (map) {
- map.forEach((eventName, elm) => {
- off(elm, eventName, callback);
- });
- map.clear();
- }
+ destroyed = true;
};
- const _updateElements = (getElements) => {
- if (map && eventContentChange) {
+ const _updateElements = getElements => {
+ if (eventContentChange) {
const eventElmList = eventContentChange.reduce((arr, item) => {
if (item) {
const selector = item[0];
@@ -1428,36 +1458,41 @@ const createEventContentChange = (target, eventContentChange, callback) => {
return arr;
}, []);
- each(eventElmList, (item) =>
- each(item[0], (elm) => {
- const eventNames = item[1];
- const registredEventNames = map.get(elm);
- const newEntry = isUndefined(registredEventNames);
- const changingExistingEntry = !newEntry && eventNames !== registredEventNames;
- const finalEventNames = changingExistingEntry ? `${registredEventNames} ${eventNames}` : eventNames;
+ each(eventElmList, item => each(item[0], elm => {
+ const eventNames = item[1];
+ const entry = map.get(elm);
- if (changingExistingEntry) {
- off(elm, registredEventNames, callback);
+ if (entry) {
+ const entryEventNames = entry[0];
+ const entryOff = entry[1];
+
+ if (entryEventNames === eventNames) {
+ entryOff();
}
+ }
- map.set(elm, finalEventNames);
- on(elm, finalEventNames, callback);
- })
- );
+ const off = on(elm, eventNames, event => {
+ if (destroyed) {
+ off();
+ map.delete(elm);
+ } else {
+ callback(event);
+ }
+ });
+ map.set(elm, [eventNames, off]);
+ }));
}
};
if (eventContentChange) {
- map = map || new Map();
-
- _destroy();
+ map = new WeakMap();
_updateElements();
}
return {
_destroy,
- _updateElements,
+ _updateElements
};
};
@@ -1470,28 +1505,24 @@ const createDOMObserver = (target, isContentObserver, callback, options) => {
_nestedTargetSelector,
_ignoreTargetChange,
_ignoreNestedTargetChange,
- _ignoreContentChange,
+ _ignoreContentChange
} = options || {};
- const { _destroy: destroyEventContentChange, _updateElements: updateEventContentChangeElements } = createEventContentChange(
- target,
- isContentObserver && _eventContentChange,
- debounce(
- () => {
- if (isConnected) {
- callback(true);
- }
- },
- {
- _timeout: 33,
- _maxDelay: 99,
- }
- )
- );
+ const {
+ _destroy: destroyEventContentChange,
+ _updateElements: updateEventContentChangeElements
+ } = createEventContentChange(target, debounce(() => {
+ if (isConnected) {
+ callback(true);
+ }
+ }, {
+ _timeout: 33,
+ _maxDelay: 99
+ }), _eventContentChange);
const finalAttributes = _attributes || [];
const finalStyleChangingAttributes = _styleChangingAttributes || [];
const observedAttributes = finalAttributes.concat(finalStyleChangingAttributes);
- const observerCallback = (mutations) => {
+ const observerCallback = mutations => {
const ignoreTargetChange = (isContentObserver ? _ignoreNestedTargetChange : _ignoreTargetChange) || noop;
const ignoreContentChange = _ignoreContentChange || noop;
const targetChangedAttrs = [];
@@ -1499,8 +1530,14 @@ const createDOMObserver = (target, isContentObserver, callback, options) => {
let targetStyleChanged = false;
let contentChanged = false;
let childListChanged = false;
- each(mutations, (mutation) => {
- const { attributeName, target: mutationTarget, type, oldValue, addedNodes } = mutation;
+ each(mutations, mutation => {
+ const {
+ attributeName,
+ target: mutationTarget,
+ type,
+ oldValue,
+ addedNodes
+ } = mutation;
const isAttributesType = type === 'attributes';
const isChildListType = type === 'childList';
const targetIsMutationTarget = target === mutationTarget;
@@ -1512,33 +1549,24 @@ const createDOMObserver = (target, isContentObserver, callback, options) => {
const notOnlyAttrChanged = !isAttributesType;
const contentAttrChanged = isAttributesType && styleChangingAttrChanged;
const isNestedTarget = contentAttrChanged && _nestedTargetSelector && is(mutationTarget, _nestedTargetSelector);
- const baseAssertion = isNestedTarget
- ? !ignoreTargetChange(mutationTarget, attributeName, oldValue, attributeValue)
- : notOnlyAttrChanged || contentAttrChanged;
+ const baseAssertion = isNestedTarget ? !ignoreTargetChange(mutationTarget, attributeName, oldValue, attributeValue) : notOnlyAttrChanged || contentAttrChanged;
const contentFinalChanged = baseAssertion && !ignoreContentChange(mutation, !!isNestedTarget, target, options);
push(totalAddedNodes, addedNodes);
contentChanged = contentChanged || contentFinalChanged;
childListChanged = childListChanged || isChildListType;
}
- if (
- !isContentObserver &&
- targetIsMutationTarget &&
- attributeChanged &&
- !ignoreTargetChange(mutationTarget, attributeName, oldValue, attributeValue)
- ) {
+ if (!isContentObserver && targetIsMutationTarget && attributeChanged && !ignoreTargetChange(mutationTarget, attributeName, oldValue, attributeValue)) {
push(targetChangedAttrs, attributeName);
targetStyleChanged = targetStyleChanged || styleChangingAttrChanged;
}
});
if (childListChanged && !isEmptyArray(totalAddedNodes)) {
- updateEventContentChangeElements((selector) =>
- totalAddedNodes.reduce((arr, node) => {
- push(arr, find(selector, node));
- return is(node, selector) ? push(arr, node) : arr;
- }, [])
- );
+ updateEventContentChangeElements(selector => totalAddedNodes.reduce((arr, node) => {
+ push(arr, find(selector, node));
+ return is(node, selector) ? push(arr, node) : arr;
+ }, []));
}
if (isContentObserver) {
@@ -1555,7 +1583,7 @@ const createDOMObserver = (target, isContentObserver, callback, options) => {
attributeFilter: observedAttributes,
subtree: isContentObserver,
childList: isContentObserver,
- characterData: isContentObserver,
+ characterData: isContentObserver
});
isConnected = true;
return {
@@ -1570,7 +1598,7 @@ const createDOMObserver = (target, isContentObserver, callback, options) => {
if (isConnected) {
observerCallback(mutationObserver.takeRecords());
}
- },
+ }
};
};
@@ -1582,7 +1610,7 @@ const baseStyleChangingAttrs = ['id', 'class', 'style', 'open'];
const ignoreTargetChange = (target, attrName, oldValue, newValue) => {
if (attrName === 'class' && oldValue && newValue) {
const diff = diffClass(oldValue, newValue);
- return !!diff.find((addedOrRemovedClass) => addedOrRemovedClass.indexOf(ignorePrefix) !== 0);
+ return !!diff.find(addedOrRemovedClass => addedOrRemovedClass.indexOf(ignorePrefix) !== 0);
}
return false;
@@ -1592,32 +1620,53 @@ const lifecycleHubOservers = (instance, updateLifecycles) => {
let debounceTimeout;
let debounceMaxDelay;
let contentMutationObserver;
- const { _structureSetup } = instance;
- const { _targetObj, _targetCtx } = _structureSetup;
- const { _host, _viewport, _content } = _targetObj;
- const { _isTextarea } = _targetCtx;
- const { _nativeScrollbarStyling, _flexboxGlue } = getEnvironment();
+ const {
+ _structureSetup
+ } = instance;
+ const {
+ _targetObj,
+ _targetCtx
+ } = _structureSetup;
+ const {
+ _host,
+ _viewport,
+ _content
+ } = _targetObj;
+ const {
+ _isTextarea
+ } = _targetCtx;
+ const {
+ _nativeScrollbarStyling,
+ _flexboxGlue
+ } = getEnvironment();
const contentMutationObserverAttr = _isTextarea ? baseStyleChangingAttrsTextarea : baseStyleChangingAttrs.concat(baseStyleChangingAttrsTextarea);
const updateLifecyclesWithDebouncedAdaptiveUpdateHints = debounce(updateLifecycles, {
_timeout: () => debounceTimeout,
_maxDelay: () => debounceMaxDelay,
_mergeParams(prev, curr) {
- const { _sizeChanged: prevSizeChanged, _hostMutation: prevHostMutation, _contentMutation: prevContentMutation } = prev[0];
- const { _sizeChanged: currSizeChanged, _hostMutation: currvHostMutation, _contentMutation: currContentMutation } = curr[0];
- const merged = [
- {
- _sizeChanged: prevSizeChanged || currSizeChanged,
- _hostMutation: prevHostMutation || currvHostMutation,
- _contentMutation: prevContentMutation || currContentMutation,
- },
- ];
+ const {
+ _sizeChanged: prevSizeChanged,
+ _hostMutation: prevHostMutation,
+ _contentMutation: prevContentMutation
+ } = prev[0];
+ const {
+ _sizeChanged: currSizeChanged,
+ _hostMutation: currvHostMutation,
+ _contentMutation: currContentMutation
+ } = curr[0];
+ const merged = [{
+ _sizeChanged: prevSizeChanged || currSizeChanged,
+ _hostMutation: prevHostMutation || currvHostMutation,
+ _contentMutation: prevContentMutation || currContentMutation
+ }];
return merged;
- },
+ }
+
});
- const updateViewportAttrsFromHost = (attributes) => {
- each(attributes || viewportAttrsFromTarget, (attribute) => {
+ const updateViewportAttrsFromHost = attributes => {
+ each(attributes || viewportAttrsFromTarget, attribute => {
if (indexOf(viewportAttrsFromTarget, attribute) > -1) {
const hostAttr = attr(_host, attribute);
@@ -1630,31 +1679,35 @@ const lifecycleHubOservers = (instance, updateLifecycles) => {
});
};
- const onTrinsicChanged = (heightIntrinsic) => {
+ const onTrinsicChanged = heightIntrinsic => {
updateLifecycles({
- _heightIntrinsic: heightIntrinsic,
+ _heightIntrinsic: heightIntrinsic
});
};
- const onSizeChanged = ({ _sizeChanged, _directionIsRTLCache, _appear }) => {
+ const onSizeChanged = ({
+ _sizeChanged,
+ _directionIsRTLCache,
+ _appear
+ }) => {
const updateFn = !_sizeChanged || _appear ? updateLifecycles : updateLifecyclesWithDebouncedAdaptiveUpdateHints;
updateFn({
_sizeChanged,
- _directionIsRTL: _directionIsRTLCache,
+ _directionIsRTL: _directionIsRTLCache
});
};
- const onContentMutation = (contentChangedTroughEvent) => {
+ const onContentMutation = contentChangedTroughEvent => {
const updateFn = contentChangedTroughEvent ? updateLifecycles : updateLifecyclesWithDebouncedAdaptiveUpdateHints;
updateFn({
- _contentMutation: true,
+ _contentMutation: true
});
};
const onHostMutation = (targetChangedAttrs, targetStyleChanged) => {
if (targetStyleChanged) {
updateLifecyclesWithDebouncedAdaptiveUpdateHints({
- _hostMutation: true,
+ _hostMutation: true
});
} else {
updateViewportAttrsFromHost(targetChangedAttrs);
@@ -1664,18 +1717,18 @@ const lifecycleHubOservers = (instance, updateLifecycles) => {
const trinsicObserver = (_content || !_flexboxGlue) && createTrinsicObserver(_host, onTrinsicChanged);
const sizeObserver = createSizeObserver(_host, onSizeChanged, {
_appear: true,
- _direction: !_nativeScrollbarStyling,
+ _direction: !_nativeScrollbarStyling
});
const hostMutationObserver = createDOMObserver(_host, false, onHostMutation, {
_styleChangingAttributes: baseStyleChangingAttrs,
_attributes: baseStyleChangingAttrs.concat(viewportAttrsFromTarget),
- _ignoreTargetChange: ignoreTargetChange,
+ _ignoreTargetChange: ignoreTargetChange
});
- const updateOptions = (checkOption) => {
- const { _value: elementEvents, _changed: elementEventsChanged } = checkOption('updating.elementEvents');
- const { _value: attributes, _changed: attributesChanged } = checkOption('updating.attributes');
- const { _value: debounce, _changed: debounceChanged } = checkOption('updating.debounce');
+ const updateOptions = checkOption => {
+ const [elementEvents, elementEventsChanged] = checkOption('updating.elementEvents');
+ const [attributes, attributesChanged] = checkOption('updating.attributes');
+ const [debounceValue, debounceChanged] = checkOption('updating.debounce');
const updateContentMutationObserver = elementEventsChanged || attributesChanged;
if (updateContentMutationObserver) {
@@ -1689,20 +1742,20 @@ const lifecycleHubOservers = (instance, updateLifecycles) => {
_styleChangingAttributes: contentMutationObserverAttr.concat(attributes || []),
_attributes: contentMutationObserverAttr.concat(attributes || []),
_eventContentChange: elementEvents,
- _ignoreNestedTargetChange: ignoreTargetChange,
+ _ignoreNestedTargetChange: ignoreTargetChange
});
}
if (debounceChanged) {
updateLifecyclesWithDebouncedAdaptiveUpdateHints._flush();
- if (isArray(debounce)) {
- const timeout = debounce[0];
- const maxWait = debounce[1];
+ if (isArray(debounceValue)) {
+ const timeout = debounceValue[0];
+ const maxWait = debounceValue[1];
debounceTimeout = isNumber(timeout) ? timeout : false;
debounceMaxDelay = isNumber(maxWait) ? maxWait : false;
- } else if (isNumber(debounce)) {
- debounceTimeout = debounce;
+ } else if (isNumber(debounceValue)) {
+ debounceTimeout = debounceValue;
debounceMaxDelay = false;
} else {
debounceTimeout = false;
@@ -1724,54 +1777,75 @@ const lifecycleHubOservers = (instance, updateLifecycles) => {
sizeObserver._destroy();
hostMutationObserver._destroy();
- },
+ }
+
};
};
-const createTrinsicLifecycle = (lifecycleHub) => {
- const { _structureSetup } = lifecycleHub;
- const { _content } = _structureSetup._targetObj;
- return (updateHints) => {
- const { _heightIntrinsic } = updateHints;
- const { _value: heightIntrinsic, _changed: heightIntrinsicChanged } = _heightIntrinsic;
+const createTrinsicLifecycle = lifecycleHub => {
+ const {
+ _structureSetup
+ } = lifecycleHub;
+ const {
+ _content
+ } = _structureSetup._targetObj;
+ return updateHints => {
+ const {
+ _heightIntrinsic
+ } = updateHints;
+ const [heightIntrinsic, heightIntrinsicChanged] = _heightIntrinsic;
if (heightIntrinsicChanged) {
style(_content, {
height: heightIntrinsic ? '' : '100%',
- display: heightIntrinsic ? '' : 'inline',
+ display: heightIntrinsic ? '' : 'inline'
});
}
return {
_sizeChanged: heightIntrinsicChanged,
- _contentMutation: heightIntrinsicChanged,
+ _contentMutation: heightIntrinsicChanged
};
};
};
-const createPaddingLifecycle = (lifecycleHub) => {
- const { _structureSetup, _setLifecycleCommunication } = lifecycleHub;
- const { _host, _padding, _viewport } = _structureSetup._targetObj;
- const { _update: updatePaddingCache, _current: currentPaddingCache } = createCache(topRightBottomLeft.bind(0, _host, 'padding'), {
+const createPaddingLifecycle = lifecycleHub => {
+ const {
+ _structureSetup,
+ _setLifecycleCommunication
+ } = lifecycleHub;
+ const {
+ _host,
+ _padding,
+ _viewport
+ } = _structureSetup._targetObj;
+ const [updatePaddingCache, currentPaddingCache] = createCache(topRightBottomLeft.bind(0, _host, 'padding'), {
_equal: equalTRBL,
- _initialValue: topRightBottomLeft(),
+ _initialValue: topRightBottomLeft()
});
return (updateHints, checkOption, force) => {
- let { _value: padding, _changed: paddingChanged } = currentPaddingCache(force);
- const { _nativeScrollbarStyling, _flexboxGlue } = getEnvironment();
- const { _sizeChanged, _directionIsRTL, _contentMutation } = updateHints;
- const { _value: directionIsRTL, _changed: directionChanged } = _directionIsRTL;
- const { _value: paddingAbsolute, _changed: paddingAbsoluteChanged } = checkOption('paddingAbsolute');
+ let [padding, paddingChanged] = currentPaddingCache(force);
+ const {
+ _nativeScrollbarStyling,
+ _flexboxGlue
+ } = getEnvironment();
+ const {
+ _sizeChanged,
+ _directionIsRTL,
+ _contentMutation
+ } = updateHints;
+ const [directionIsRTL, directionChanged] = _directionIsRTL;
+ const [paddingAbsolute, paddingAbsoluteChanged] = checkOption('paddingAbsolute');
const contentMutation = !_flexboxGlue && _contentMutation;
if (_sizeChanged || paddingChanged || contentMutation) {
- ({ _value: padding, _changed: paddingChanged } = updatePaddingCache(force));
+ [padding, paddingChanged] = updatePaddingCache(force);
}
const paddingStyleChanged = paddingAbsoluteChanged || directionChanged || paddingChanged;
if (paddingStyleChanged) {
- const paddingRelative = !paddingAbsolute || (!_padding && !_nativeScrollbarStyling);
+ const paddingRelative = !paddingAbsolute || !_padding && !_nativeScrollbarStyling;
const paddingHorizontal = padding.r + padding.l;
const paddingVertical = padding.t + padding.b;
const paddingStyle = {
@@ -1779,15 +1853,15 @@ const createPaddingLifecycle = (lifecycleHub) => {
marginBottom: paddingRelative ? -paddingVertical : 0,
marginLeft: paddingRelative && directionIsRTL ? -paddingHorizontal : 0,
top: paddingRelative ? -padding.t : 0,
- right: paddingRelative ? (directionIsRTL ? -padding.r : 'auto') : 0,
- left: paddingRelative ? (directionIsRTL ? 'auto' : -padding.l) : 0,
- width: paddingRelative ? `calc(100% + ${paddingHorizontal}px)` : '',
+ right: paddingRelative ? directionIsRTL ? -padding.r : 'auto' : 0,
+ left: paddingRelative ? directionIsRTL ? 'auto' : -padding.l : 0,
+ width: paddingRelative ? `calc(100% + ${paddingHorizontal}px)` : ''
};
const viewportStyle = {
paddingTop: paddingRelative ? padding.t : 0,
paddingRight: paddingRelative ? padding.r : 0,
paddingBottom: paddingRelative ? padding.b : 0,
- paddingLeft: paddingRelative ? padding.l : 0,
+ paddingLeft: paddingRelative ? padding.l : 0
};
style(_padding || _viewport, paddingStyle);
style(_viewport, viewportStyle);
@@ -1795,38 +1869,42 @@ const createPaddingLifecycle = (lifecycleHub) => {
_setLifecycleCommunication({
_paddingInfo: {
_absolute: !paddingRelative,
- _padding: padding,
+ _padding: padding
},
- _viewportPaddingStyle: _padding ? viewportStyle : _extends_1({}, paddingStyle, viewportStyle),
+ _viewportPaddingStyle: _padding ? viewportStyle : _extends({}, paddingStyle, viewportStyle)
});
}
return {
- _paddingStyleChanged: paddingStyleChanged,
+ _paddingStyleChanged: paddingStyleChanged
};
};
};
-const { max, abs: abs$1, round: round$1 } = Math;
+const {
+ max,
+ abs,
+ round
+} = Math;
const overlaidScrollbarsHideOffset = 42;
const whCacheOptions = {
_equal: equalWH,
_initialValue: {
w: 0,
- h: 0,
- },
+ h: 0
+ }
};
-const sizeFraction = (elm) => {
+const sizeFraction = elm => {
const viewportOffsetSize = offsetSize(elm);
const viewportRect = getBoundingClientRect(elm);
return {
w: viewportRect.width - viewportOffsetSize.w,
- h: viewportRect.height - viewportOffsetSize.h,
+ h: viewportRect.height - viewportOffsetSize.h
};
};
-const fractionalPixelRatioTollerance = () => (window.devicePixelRatio % 1 === 0 ? 0 : 1);
+const fractionalPixelRatioTollerance = () => window.devicePixelRatio % 1 === 0 ? 0 : 1;
const setAxisOverflowStyle = (horizontal, overflowAmount, behavior, styleObj) => {
const overflowKey = horizontal ? 'overflowX' : 'overflowY';
@@ -1845,81 +1923,104 @@ const setAxisOverflowStyle = (horizontal, overflowAmount, behavior, styleObj) =>
return {
_visible: behaviorIsVisible,
- _behavior: behaviorIsVisibleHidden ? 'hidden' : 'scroll',
+ _behavior: behaviorIsVisibleHidden ? 'hidden' : 'scroll'
};
};
-const createOverflowLifecycle = (lifecycleHub) => {
- const { _structureSetup, _doViewportArrange, _getLifecycleCommunication, _setLifecycleCommunication } = lifecycleHub;
- const { _host, _viewport, _viewportArrange } = _structureSetup._targetObj;
- const { _update: updateViewportSizeFraction, _current: getCurrentViewportSizeFraction } = createCache(
- sizeFraction.bind(0, _viewport),
- whCacheOptions
- );
- const { _update: updateViewportScrollSizeCache, _current: getCurrentViewportScrollSizeCache } = createCache(
- scrollSize.bind(0, _viewport),
- whCacheOptions
- );
- const { _update: updateOverflowAmountCache, _current: getCurrentOverflowAmountCache } = createCache(
- ({ _viewportScrollSize, _viewportClientSize, _viewportSizeFraction }) => ({
- w: max(
- 0,
- round$1(max(0, _viewportScrollSize.w - _viewportClientSize.w) - (fractionalPixelRatioTollerance() || max(0, _viewportSizeFraction.w)))
- ),
- h: max(
- 0,
- round$1(max(0, _viewportScrollSize.h - _viewportClientSize.h) - (fractionalPixelRatioTollerance() || max(0, _viewportSizeFraction.h)))
- ),
- }),
- whCacheOptions
- );
+const createOverflowLifecycle = lifecycleHub => {
+ const {
+ _structureSetup,
+ _doViewportArrange,
+ _getLifecycleCommunication,
+ _setLifecycleCommunication
+ } = lifecycleHub;
+ const {
+ _host,
+ _viewport,
+ _viewportArrange
+ } = _structureSetup._targetObj;
+ const [updateViewportSizeFraction, getCurrentViewportSizeFraction] = createCache(sizeFraction.bind(0, _viewport), whCacheOptions);
+ const [updateViewportScrollSizeCache, getCurrentViewportScrollSizeCache] = createCache(scrollSize.bind(0, _viewport), whCacheOptions);
+ const [updateOverflowAmountCache, getCurrentOverflowAmountCache] = createCache(({
+ _viewportScrollSize,
+ _viewportClientSize,
+ _viewportSizeFraction
+ }) => ({
+ w: max(0, round(max(0, _viewportScrollSize.w - _viewportClientSize.w) - (fractionalPixelRatioTollerance() || max(0, _viewportSizeFraction.w)))),
+ h: max(0, round(max(0, _viewportScrollSize.h - _viewportClientSize.h) - (fractionalPixelRatioTollerance() || max(0, _viewportSizeFraction.h))))
+ }), whCacheOptions);
const fixFlexboxGlue = (viewportOverflowState, heightIntrinsic) => {
style(_viewport, {
- height: '',
+ height: ''
});
if (heightIntrinsic) {
- const { _absolute: paddingAbsolute, _padding: padding } = _getLifecycleCommunication()._paddingInfo;
+ const {
+ _nativeScrollbarIsOverlaid
+ } = getEnvironment();
- const { _overflowScroll, _scrollbarsHideOffset } = viewportOverflowState;
+ const {
+ _absolute: paddingAbsolute,
+ _padding: padding
+ } = _getLifecycleCommunication()._paddingInfo;
+
+ const {
+ _overflowScroll,
+ _scrollbarsHideOffset
+ } = viewportOverflowState;
const hostSizeFraction = sizeFraction(_host);
const hostClientSize = clientSize(_host);
- const paddingVertical = paddingAbsolute || style(_viewport, 'boxSizing') === 'content-box' ? padding.b + padding.t : 0;
- const fractionalClientHeight = hostClientSize.h + (abs$1(hostSizeFraction.h) < 1 ? hostSizeFraction.h : 0);
+ const isContentBox = style(_viewport, 'boxSizing') === 'content-box';
+ const paddingVertical = paddingAbsolute || isContentBox ? padding.b + padding.t : 0;
+ const fractionalClientHeight = hostClientSize.h + (abs(hostSizeFraction.h) < 1 ? hostSizeFraction.h : 0);
+ const subtractXScrollbar = !(_nativeScrollbarIsOverlaid.x && isContentBox);
style(_viewport, {
- height: fractionalClientHeight + (_overflowScroll.x ? _scrollbarsHideOffset.x : 0) - paddingVertical,
+ height: fractionalClientHeight + (_overflowScroll.x && subtractXScrollbar ? _scrollbarsHideOffset.x : 0) - paddingVertical
});
}
};
const getViewportOverflowState = (showNativeOverlaidScrollbars, viewportStyleObj) => {
- const { _nativeScrollbarSize, _nativeScrollbarIsOverlaid, _nativeScrollbarStyling } = getEnvironment();
- const { x: overlaidX, y: overlaidY } = _nativeScrollbarIsOverlaid;
+ const {
+ _nativeScrollbarSize,
+ _nativeScrollbarIsOverlaid,
+ _nativeScrollbarStyling
+ } = getEnvironment();
+ const {
+ x: overlaidX,
+ y: overlaidY
+ } = _nativeScrollbarIsOverlaid;
const determineOverflow = !viewportStyleObj;
const arrangeHideOffset = !_nativeScrollbarStyling && !showNativeOverlaidScrollbars ? overlaidScrollbarsHideOffset : 0;
const styleObj = determineOverflow ? style(_viewport, ['overflowX', 'overflowY']) : viewportStyleObj;
const scroll = {
x: styleObj.overflowX === 'scroll',
- y: styleObj.overflowY === 'scroll',
+ y: styleObj.overflowY === 'scroll'
};
const scrollbarsHideOffset = {
- x: scroll.x && !_nativeScrollbarStyling ? (overlaidX ? arrangeHideOffset : _nativeScrollbarSize.x) : 0,
- y: scroll.y && !_nativeScrollbarStyling ? (overlaidY ? arrangeHideOffset : _nativeScrollbarSize.y) : 0,
+ x: scroll.x && !_nativeScrollbarStyling ? overlaidX ? arrangeHideOffset : _nativeScrollbarSize.x : 0,
+ y: scroll.y && !_nativeScrollbarStyling ? overlaidY ? arrangeHideOffset : _nativeScrollbarSize.y : 0
};
return {
_overflowScroll: scroll,
_scrollbarsHideOffsetArrange: {
x: overlaidX && !!arrangeHideOffset,
- y: overlaidY && !!arrangeHideOffset,
+ y: overlaidY && !!arrangeHideOffset
},
- _scrollbarsHideOffset: scrollbarsHideOffset,
+ _scrollbarsHideOffset: scrollbarsHideOffset
};
};
const setViewportOverflowState = (showNativeOverlaidScrollbars, overflowAmount, overflow, viewportStyleObj) => {
- const { _visible: xVisible, _behavior: xVisibleBehavior } = setAxisOverflowStyle(true, overflowAmount.w, overflow.x, viewportStyleObj);
- const { _visible: yVisible, _behavior: yVisibleBehavior } = setAxisOverflowStyle(false, overflowAmount.h, overflow.y, viewportStyleObj);
+ const {
+ _visible: xVisible,
+ _behavior: xVisibleBehavior
+ } = setAxisOverflowStyle(true, overflowAmount.w, overflow.x, viewportStyleObj);
+ const {
+ _visible: yVisible,
+ _behavior: yVisibleBehavior
+ } = setAxisOverflowStyle(false, overflowAmount.h, overflow.y, viewportStyleObj);
if (xVisible && !yVisible) {
viewportStyleObj.overflowX = xVisibleBehavior;
@@ -1934,27 +2035,42 @@ const createOverflowLifecycle = (lifecycleHub) => {
const arrangeViewport = (viewportOverflowState, viewportScrollSize, viewportSizeFraction, directionIsRTL) => {
if (_doViewportArrange) {
- const { _scrollbarsHideOffset, _scrollbarsHideOffsetArrange } = viewportOverflowState;
- const { x: arrangeX, y: arrangeY } = _scrollbarsHideOffsetArrange;
- const { x: hideOffsetX, y: hideOffsetY } = _scrollbarsHideOffset;
+ const {
+ _scrollbarsHideOffset,
+ _scrollbarsHideOffsetArrange
+ } = viewportOverflowState;
+ const {
+ x: arrangeX,
+ y: arrangeY
+ } = _scrollbarsHideOffsetArrange;
+ const {
+ x: hideOffsetX,
+ y: hideOffsetY
+ } = _scrollbarsHideOffset;
- const { _viewportPaddingStyle: viewportPaddingStyle } = _getLifecycleCommunication();
+ const {
+ _viewportPaddingStyle: viewportPaddingStyle
+ } = _getLifecycleCommunication();
const viewportArrangeHorizontalPaddingKey = directionIsRTL ? 'paddingRight' : 'paddingLeft';
const viewportArrangeHorizontalPaddingValue = viewportPaddingStyle[viewportArrangeHorizontalPaddingKey];
const viewportArrangeVerticalPaddingValue = viewportPaddingStyle.paddingTop;
- const fractionalContentWidth = viewportScrollSize.w + (abs$1(viewportSizeFraction.w) < 1 ? viewportSizeFraction.w : 0);
- const fractionalContenHeight = viewportScrollSize.h + (abs$1(viewportSizeFraction.h) < 1 ? viewportSizeFraction.h : 0);
+ const fractionalContentWidth = viewportScrollSize.w + (abs(viewportSizeFraction.w) < 1 ? viewportSizeFraction.w : 0);
+ const fractionalContenHeight = viewportScrollSize.h + (abs(viewportSizeFraction.h) < 1 ? viewportSizeFraction.h : 0);
const arrangeSize = {
w: hideOffsetY && arrangeY ? `${hideOffsetY + fractionalContentWidth - viewportArrangeHorizontalPaddingValue}px` : '',
- h: hideOffsetX && arrangeX ? `${hideOffsetX + fractionalContenHeight - viewportArrangeVerticalPaddingValue}px` : '',
+ h: hideOffsetX && arrangeX ? `${hideOffsetX + fractionalContenHeight - viewportArrangeVerticalPaddingValue}px` : ''
};
if (_viewportArrange) {
- const { sheet } = _viewportArrange;
+ const {
+ sheet
+ } = _viewportArrange;
if (sheet) {
- const { cssRules } = sheet;
+ const {
+ cssRules
+ } = sheet;
if (cssRules) {
if (!cssRules.length) {
@@ -1969,7 +2085,7 @@ const createOverflowLifecycle = (lifecycleHub) => {
} else {
style(_viewport, {
'--os-vaw': arrangeSize.w,
- '--os-vah': arrangeSize.h,
+ '--os-vah': arrangeSize.h
});
}
}
@@ -1978,11 +2094,22 @@ const createOverflowLifecycle = (lifecycleHub) => {
};
const hideNativeScrollbars = (viewportOverflowState, directionIsRTL, viewportArrange, viewportStyleObj) => {
- const { _scrollbarsHideOffset, _scrollbarsHideOffsetArrange } = viewportOverflowState;
- const { x: arrangeX, y: arrangeY } = _scrollbarsHideOffsetArrange;
- const { x: hideOffsetX, y: hideOffsetY } = _scrollbarsHideOffset;
+ const {
+ _scrollbarsHideOffset,
+ _scrollbarsHideOffsetArrange
+ } = viewportOverflowState;
+ const {
+ x: arrangeX,
+ y: arrangeY
+ } = _scrollbarsHideOffsetArrange;
+ const {
+ x: hideOffsetX,
+ y: hideOffsetY
+ } = _scrollbarsHideOffset;
- const { _viewportPaddingStyle: viewportPaddingStyle } = _getLifecycleCommunication();
+ const {
+ _viewportPaddingStyle: viewportPaddingStyle
+ } = _getLifecycleCommunication();
const horizontalMarginKey = directionIsRTL ? 'marginLeft' : 'marginRight';
const viewportHorizontalPaddingKey = directionIsRTL ? 'paddingLeft' : 'paddingRight';
@@ -2004,17 +2131,25 @@ const createOverflowLifecycle = (lifecycleHub) => {
if (_doViewportArrange) {
const finalViewportOverflowState = viewportOverflowState || getViewportOverflowState(showNativeOverlaidScrollbars);
- const { _viewportPaddingStyle: viewportPaddingStyle } = _getLifecycleCommunication();
+ const {
+ _viewportPaddingStyle: viewportPaddingStyle
+ } = _getLifecycleCommunication();
- const { _flexboxGlue } = getEnvironment();
- const { _scrollbarsHideOffsetArrange } = finalViewportOverflowState;
- const { x: arrangeX, y: arrangeY } = _scrollbarsHideOffsetArrange;
+ const {
+ _flexboxGlue
+ } = getEnvironment();
+ const {
+ _scrollbarsHideOffsetArrange
+ } = finalViewportOverflowState;
+ const {
+ x: arrangeX,
+ y: arrangeY
+ } = _scrollbarsHideOffsetArrange;
const finalPaddingStyle = {};
- const assignProps = (props) =>
- each(props.split(' '), (prop) => {
- finalPaddingStyle[prop] = viewportPaddingStyle[prop];
- });
+ const assignProps = props => each(props.split(' '), prop => {
+ finalPaddingStyle[prop] = viewportPaddingStyle[prop];
+ });
if (!_flexboxGlue) {
finalPaddingStyle.height = '';
@@ -2037,26 +2172,34 @@ const createOverflowLifecycle = (lifecycleHub) => {
style(_viewport, prevStyle);
addClass(_viewport, classNameViewportArrange);
},
- _viewportOverflowState: finalViewportOverflowState,
+ _viewportOverflowState: finalViewportOverflowState
};
}
return {
- _redoViewportArrange: noop,
+ _redoViewportArrange: noop
};
};
return (updateHints, checkOption, force) => {
- const { _directionIsRTL, _heightIntrinsic, _sizeChanged, _hostMutation, _contentMutation, _paddingStyleChanged } = updateHints;
- const { _flexboxGlue, _nativeScrollbarStyling, _nativeScrollbarIsOverlaid } = getEnvironment();
- const { _value: heightIntrinsic, _changed: heightIntrinsicChanged } = _heightIntrinsic;
- const { _value: directionIsRTL, _changed: directionChanged } = _directionIsRTL;
- const { _value: showNativeOverlaidScrollbarsOption, _changed: showNativeOverlaidScrollbarsChanged } = checkOption(
- 'nativeScrollbarsOverlaid.show'
- );
+ const {
+ _directionIsRTL,
+ _heightIntrinsic,
+ _sizeChanged,
+ _hostMutation,
+ _contentMutation,
+ _paddingStyleChanged
+ } = updateHints;
+ const {
+ _flexboxGlue,
+ _nativeScrollbarStyling,
+ _nativeScrollbarIsOverlaid
+ } = getEnvironment();
+ const [heightIntrinsic, heightIntrinsicChanged] = _heightIntrinsic;
+ const [directionIsRTL, directionChanged] = _directionIsRTL;
+ const [showNativeOverlaidScrollbarsOption, showNativeOverlaidScrollbarsChanged] = checkOption('nativeScrollbarsOverlaid.show');
const showNativeOverlaidScrollbars = showNativeOverlaidScrollbarsOption && _nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y;
- const adjustFlexboxGlue =
- !_flexboxGlue && (_sizeChanged || _contentMutation || _hostMutation || showNativeOverlaidScrollbarsChanged || heightIntrinsicChanged);
+ const adjustFlexboxGlue = !_flexboxGlue && (_sizeChanged || _contentMutation || _hostMutation || showNativeOverlaidScrollbarsChanged || heightIntrinsicChanged);
let viewportSizeFractionCache = getCurrentViewportSizeFraction(force);
let viewportScrollSizeCache = getCurrentViewportScrollSizeCache(force);
let overflowAmuntCache = getCurrentOverflowAmountCache(force);
@@ -2076,27 +2219,19 @@ const createOverflowLifecycle = (lifecycleHub) => {
}
if (_sizeChanged || _paddingStyleChanged || _contentMutation || showNativeOverlaidScrollbarsChanged || directionChanged) {
- const { _redoViewportArrange, _viewportOverflowState: undoViewportArrangeOverflowState } = undoViewportArrange(
- showNativeOverlaidScrollbars,
- directionIsRTL,
- preMeasureViewportOverflowState
- );
- const { _value: _viewportSizeFraction2, _changed: viewportSizeFractionCahnged } = (viewportSizeFractionCache = updateViewportSizeFraction(
- force
- ));
- const { _value: _viewportScrollSize2, _changed: _viewportScrollSizeChanged } = (viewportScrollSizeCache = updateViewportScrollSizeCache(force));
+ const {
+ _redoViewportArrange,
+ _viewportOverflowState: undoViewportArrangeOverflowState
+ } = undoViewportArrange(showNativeOverlaidScrollbars, directionIsRTL, preMeasureViewportOverflowState);
+ const [_viewportSizeFraction2, viewportSizeFractionCahnged] = viewportSizeFractionCache = updateViewportSizeFraction(force);
+ const [_viewportScrollSize2, _viewportScrollSizeChanged] = viewportScrollSizeCache = updateViewportScrollSizeCache(force);
const viewportContentSize = clientSize(_viewport);
let arrangedViewportScrollSize = _viewportScrollSize2;
let arrangedViewportClientSize = viewportContentSize;
_redoViewportArrange();
- if (
- (_viewportScrollSizeChanged || viewportSizeFractionCahnged || showNativeOverlaidScrollbarsChanged) &&
- undoViewportArrangeOverflowState &&
- !showNativeOverlaidScrollbars &&
- arrangeViewport(undoViewportArrangeOverflowState, _viewportScrollSize2, _viewportSizeFraction2, directionIsRTL)
- ) {
+ if ((_viewportScrollSizeChanged || viewportSizeFractionCahnged || showNativeOverlaidScrollbarsChanged) && undoViewportArrangeOverflowState && !showNativeOverlaidScrollbars && arrangeViewport(undoViewportArrangeOverflowState, _viewportScrollSize2, _viewportSizeFraction2, directionIsRTL)) {
arrangedViewportClientSize = clientSize(_viewport);
arrangedViewportScrollSize = scrollSize(_viewport);
}
@@ -2105,37 +2240,28 @@ const createOverflowLifecycle = (lifecycleHub) => {
_viewportSizeFraction: _viewportSizeFraction2,
_viewportScrollSize: {
w: max(_viewportScrollSize2.w, arrangedViewportScrollSize.w),
- h: max(_viewportScrollSize2.h, arrangedViewportScrollSize.h),
+ h: max(_viewportScrollSize2.h, arrangedViewportScrollSize.h)
},
_viewportClientSize: {
w: arrangedViewportClientSize.w + max(0, viewportContentSize.w - _viewportScrollSize2.w),
- h: arrangedViewportClientSize.h + max(0, viewportContentSize.h - _viewportScrollSize2.h),
- },
+ h: arrangedViewportClientSize.h + max(0, viewportContentSize.h - _viewportScrollSize2.h)
+ }
});
}
- const { _value: viewportSizeFraction, _changed: viewportSizeFractionChanged } = viewportSizeFractionCache;
- const { _value: viewportScrollSize, _changed: viewportScrollSizeChanged } = viewportScrollSizeCache;
- const { _value: overflowAmount, _changed: overflowAmountChanged } = overflowAmuntCache;
- const { _value: overflow, _changed: overflowChanged } = checkOption('overflow');
+ const [viewportSizeFraction, viewportSizeFractionChanged] = viewportSizeFractionCache;
+ const [viewportScrollSize, viewportScrollSizeChanged] = viewportScrollSizeCache;
+ const [overflowAmount, overflowAmountChanged] = overflowAmuntCache;
+ const [overflow, overflowChanged] = checkOption('overflow');
- if (
- _paddingStyleChanged ||
- viewportSizeFractionChanged ||
- viewportScrollSizeChanged ||
- overflowAmountChanged ||
- overflowChanged ||
- showNativeOverlaidScrollbarsChanged ||
- directionChanged ||
- adjustFlexboxGlue
- ) {
+ if (_paddingStyleChanged || viewportSizeFractionChanged || viewportScrollSizeChanged || overflowAmountChanged || overflowChanged || showNativeOverlaidScrollbarsChanged || directionChanged || adjustFlexboxGlue) {
const viewportStyle = {
marginRight: 0,
marginBottom: 0,
marginLeft: 0,
width: '',
overflowY: '',
- overflowX: '',
+ overflowX: ''
};
const viewportOverflowState = setViewportOverflowState(showNativeOverlaidScrollbars, overflowAmount, overflow, viewportStyle);
const viewportArranged = arrangeViewport(viewportOverflowState, viewportScrollSize, viewportSizeFraction, directionIsRTL);
@@ -2149,20 +2275,15 @@ const createOverflowLifecycle = (lifecycleHub) => {
_setLifecycleCommunication({
_viewportOverflowScroll: viewportOverflowState._overflowScroll,
- _viewportOverflowAmount: overflowAmount,
+ _viewportOverflowAmount: overflowAmount
});
}
};
};
-const getPropByPath = (obj, path) =>
- obj ? path.split('.').reduce((o, prop) => (o && hasOwnProperty$1(o, prop) ? o[prop] : undefined), obj) : undefined;
+const getPropByPath = (obj, path) => obj ? path.split('.').reduce((o, prop) => o && hasOwnProperty(o, prop) ? o[prop] : undefined, obj) : undefined;
-const booleanCacheValuesFallback = {
- _value: false,
- _previous: false,
- _changed: false,
-};
+const booleanCacheValuesFallback = [false, false, false];
const lifecycleCommunicationFallback = {
_paddingInfo: {
_absolute: false,
@@ -2170,16 +2291,16 @@ const lifecycleCommunicationFallback = {
t: 0,
r: 0,
b: 0,
- l: 0,
- },
+ l: 0
+ }
},
_viewportOverflowScroll: {
x: false,
- y: false,
+ y: false
},
_viewportOverflowAmount: {
w: 0,
- h: 0,
+ h: 0
},
_viewportPaddingStyle: {
marginRight: 0,
@@ -2188,18 +2309,20 @@ const lifecycleCommunicationFallback = {
paddingTop: 0,
paddingRight: 0,
paddingBottom: 0,
- paddingLeft: 0,
- },
+ paddingLeft: 0
+ }
};
-const createLifecycleHub = (options, structureSetup) => {
+const createLifecycleHub = (options, structureSetup, scrollbarsSetup) => {
let lifecycleCommunication = lifecycleCommunicationFallback;
- const { _viewport } = structureSetup._targetObj;
+ const {
+ _viewport
+ } = structureSetup._targetObj;
const {
_nativeScrollbarStyling,
_nativeScrollbarIsOverlaid,
_flexboxGlue,
_addListener: addEnvironmentListener,
- _removeListener: removeEnvironmentListener,
+ _removeListener: removeEnvironmentListener
} = getEnvironment();
const doViewportArrange = !_nativeScrollbarStyling && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);
const instance = {
@@ -2210,7 +2333,8 @@ const createLifecycleHub = (options, structureSetup) => {
_setLifecycleCommunication(newLifecycleCommunication) {
lifecycleCommunication = assignDeep({}, lifecycleCommunication, newLifecycleCommunication);
- },
+ }
+
};
const lifecycles = [createTrinsicLifecycle(instance), createPaddingLifecycle(instance), createOverflowLifecycle(instance)];
@@ -2221,17 +2345,12 @@ const createLifecycleHub = (options, structureSetup) => {
_sizeChanged = force || false,
_hostMutation = force || false,
_contentMutation = force || false,
- _paddingStyleChanged = force || false,
+ _paddingStyleChanged = force || false
} = updateHints || {};
- const finalDirectionIsRTL =
- _directionIsRTL || (_sizeObserver ? _sizeObserver._getCurrentCacheValues(force)._directionIsRTL : booleanCacheValuesFallback);
- const finalHeightIntrinsic =
- _heightIntrinsic || (_trinsicObserver ? _trinsicObserver._getCurrentCacheValues(force)._heightIntrinsic : booleanCacheValuesFallback);
+ const finalDirectionIsRTL = _directionIsRTL || (_sizeObserver ? _sizeObserver._getCurrentCacheValues(force)._directionIsRTL : booleanCacheValuesFallback);
+ const finalHeightIntrinsic = _heightIntrinsic || (_trinsicObserver ? _trinsicObserver._getCurrentCacheValues(force)._heightIntrinsic : booleanCacheValuesFallback);
- const checkOption = (path) => ({
- _value: getPropByPath(options, path),
- _changed: force || getPropByPath(changedOptions, path) !== undefined,
- });
+ const checkOption = path => [getPropByPath(options, path), force || getPropByPath(changedOptions, path) !== undefined];
const adjustScrollOffset = doViewportArrange || !_flexboxGlue;
const scrollOffsetX = adjustScrollOffset && scrollLeft(_viewport);
@@ -2241,25 +2360,20 @@ const createLifecycleHub = (options, structureSetup) => {
_updateObserverOptions(checkOption);
}
- each(lifecycles, (lifecycle) => {
+ each(lifecycles, lifecycle => {
const {
_sizeChanged: adaptiveSizeChanged,
_hostMutation: adaptiveHostMutation,
_contentMutation: adaptiveContentMutation,
- _paddingStyleChanged: adaptivePaddingStyleChanged,
- } =
- lifecycle(
- {
- _directionIsRTL: finalDirectionIsRTL,
- _heightIntrinsic: finalHeightIntrinsic,
- _sizeChanged,
- _hostMutation,
- _contentMutation,
- _paddingStyleChanged,
- },
- checkOption,
- !!force
- ) || {};
+ _paddingStyleChanged: adaptivePaddingStyleChanged
+ } = lifecycle({
+ _directionIsRTL: finalDirectionIsRTL,
+ _heightIntrinsic: finalHeightIntrinsic,
+ _sizeChanged,
+ _hostMutation,
+ _contentMutation,
+ _paddingStyleChanged
+ }, checkOption, !!force) || {};
_sizeChanged = adaptiveSizeChanged || _sizeChanged;
_hostMutation = adaptiveHostMutation || _hostMutation;
_contentMutation = adaptiveContentMutation || _contentMutation;
@@ -2279,7 +2393,12 @@ const createLifecycleHub = (options, structureSetup) => {
}
};
- const { _sizeObserver, _trinsicObserver, _updateObserverOptions, _destroy: destroyObservers } = lifecycleHubOservers(instance, updateLifecycles);
+ const {
+ _sizeObserver,
+ _trinsicObserver,
+ _updateObserverOptions,
+ _destroy: destroyObservers
+ } = lifecycleHubOservers(instance, updateLifecycles);
const update = (changedOptions, force) => updateLifecycles(null, changedOptions, force);
@@ -2289,25 +2408,35 @@ const createLifecycleHub = (options, structureSetup) => {
return {
_update: update,
_state: () => ({
- _overflowAmount: lifecycleCommunication._viewportOverflowAmount,
+ _overflowAmount: lifecycleCommunication._viewportOverflowAmount
}),
_destroy() {
destroyObservers();
removeEnvironmentListener(envUpdateListener);
- },
+
+ structureSetup._destroy();
+
+ scrollbarsSetup._destroy();
+ }
+
};
};
const OverlayScrollbars = (target, options, extensions) => {
- const { _getDefaultOptions } = getEnvironment();
+ const {
+ _getDefaultOptions
+ } = getEnvironment();
const currentOptions = assignDeep({}, _getDefaultOptions(), validateOptions(options || {}, optionsTemplate, null, true)._validated);
const structureSetup = createStructureSetup(target);
- const lifecycleHub = createLifecycleHub(currentOptions, structureSetup);
+ const scrollbarsSetup = createScrollbarsSetup(target, structureSetup);
+ const lifecycleHub = createLifecycleHub(currentOptions, structureSetup, scrollbarsSetup);
const instance = {
options(newOptions) {
if (newOptions) {
- const { _validated: _changedOptions } = validateOptions(newOptions, optionsTemplate, currentOptions, true);
+ const {
+ _validated: _changedOptions
+ } = validateOptions(newOptions, optionsTemplate, currentOptions, true);
if (!isEmptyObject(_changedOptions)) {
assignDeep(currentOptions, _changedOptions);
@@ -2324,10 +2453,12 @@ const OverlayScrollbars = (target, options, extensions) => {
update(force) {
lifecycleHub._update(null, force);
},
+
+ destroy: () => lifecycleHub._destroy()
};
instance.update(true);
return instance;
};
-export default OverlayScrollbars;
+export { OverlayScrollbars as default };
//# sourceMappingURL=overlayscrollbars.esm.js.map
diff --git a/packages/overlayscrollbars/dist/overlayscrollbars.esm.js.map b/packages/overlayscrollbars/dist/overlayscrollbars.esm.js.map
index 4e20aaf..d99b4d2 100644
--- a/packages/overlayscrollbars/dist/overlayscrollbars.esm.js.map
+++ b/packages/overlayscrollbars/dist/overlayscrollbars.esm.js.map
@@ -1 +1 @@
-{"version":3,"file":"overlayscrollbars.esm.js","sources":["../src/support/cache/cache.ts","../src/support/utils/types.ts","../src/support/utils/array.ts","../src/support/utils/object.ts","../src/support/dom/attribute.ts","../src/support/dom/traversal.ts","../src/support/dom/manipulation.ts","../src/support/dom/create.ts","../src/support/compatibility/vendors.ts","../src/support/compatibility/apis.ts","../src/support/dom/class.ts","../src/support/dom/dimensions.ts","../src/support/dom/events.ts","../src/support/utils/equal.ts","../src/support/utils/function.ts","../src/support/dom/style.ts","../src/support/dom/offset.ts","../../../node_modules/@babel/runtime/helpers/extends.js","../src/support/options/validation.ts","../src/support/options/transformation.ts","../src/classnames.ts","../src/options.ts","../src/environment.ts","../src/setups/structureSetup.ts","../src/observers/sizeObserver.ts","../src/observers/trinsicObserver.ts","../src/observers/domObserver.ts","../src/lifecycles/lifecycleHubObservers.ts","../src/lifecycles/trinsicLifecycle.ts","../src/lifecycles/paddingLifecycle.ts","../src/lifecycles/overflowLifecycle.ts","../src/lifecycles/lifecycleHub.ts","../src/overlayscrollbars.ts"],"sourcesContent":["export interface CacheValues {\r\n readonly _value?: T;\r\n readonly _previous?: T;\r\n _changed: boolean;\r\n}\r\n\r\nexport interface CacheOptions {\r\n // Custom comparison function if shallow compare isn't enough. Returns true if nothing changed.\r\n _equal?: EqualCachePropFunction;\r\n // Initial value for _value\r\n _initialValue?: T;\r\n // If true updates always _value and _previous, otherwise they update only when changed\r\n _alwaysUpdateValues?: boolean;\r\n}\r\n\r\nexport interface Cache {\r\n _current: (force?: boolean) => CacheValues;\r\n _update: CacheUpdate;\r\n}\r\n\r\nexport type CacheUpdate = undefined extends C\r\n ? (force?: boolean | 0, context?: C) => CacheValues\r\n : (force: boolean | 0, context: C) => CacheValues;\r\n\r\nexport type UpdateCachePropFunction = undefined extends C\r\n ? (context?: C, current?: T, previous?: T) => T\r\n : C extends T\r\n ? ((context: C, current?: T, previous?: T) => T) | 0\r\n : (context: C, current?: T, previous?: T) => T;\r\n\r\nexport type EqualCachePropFunction = (currentVal?: T, newVal?: T) => boolean;\r\n\r\nexport const createCache = (update: UpdateCachePropFunction, options?: CacheOptions): Cache => {\r\n const { _equal, _initialValue, _alwaysUpdateValues } = options || {};\r\n let _value: T | undefined = _initialValue;\r\n let _previous: T | undefined;\r\n\r\n const cacheUpdate = ((force?: boolean | 0, context?: C) => {\r\n const curr = _value;\r\n // @ts-ignore\r\n // update can only not be a function if C extends T as described in \"UpdateCachePropFunction\" type definition\r\n // if C extends T the cast (context as T) is perfectly valid\r\n const newVal = update ? update(context, _value, _previous) : (context as T);\r\n const changed = force || (_equal ? !_equal(curr, newVal) : curr !== newVal);\r\n\r\n if (changed || _alwaysUpdateValues) {\r\n _value = newVal;\r\n _previous = curr;\r\n }\r\n\r\n return {\r\n _value,\r\n _previous,\r\n _changed: changed,\r\n };\r\n }) as CacheUpdate;\r\n\r\n return {\r\n _update: cacheUpdate,\r\n _current: (force?: boolean) => ({\r\n _value,\r\n _previous,\r\n _changed: !!force,\r\n }),\r\n };\r\n};\r\n","import { PlainObject } from 'typings';\r\n\r\nconst ElementNodeType = Node.ELEMENT_NODE;\r\nconst { toString, hasOwnProperty } = Object.prototype;\r\n\r\nexport function isUndefined(obj: any): obj is undefined {\r\n return obj === undefined;\r\n}\r\n\r\nexport function isNull(obj: any): obj is null {\r\n return obj === null;\r\n}\r\n\r\nexport const type: (obj: any) => string = (obj) => {\r\n return isUndefined(obj) || isNull(obj)\r\n ? `${obj}`\r\n : toString\r\n .call(obj)\r\n .replace(/^\\[object (.+)\\]$/, '$1')\r\n .toLowerCase();\r\n};\r\n\r\nexport function isNumber(obj: any): obj is number {\r\n return typeof obj === 'number';\r\n}\r\n\r\nexport function isString(obj: any): obj is string {\r\n return typeof obj === 'string';\r\n}\r\n\r\nexport function isBoolean(obj: any): obj is boolean {\r\n return typeof obj === 'boolean';\r\n}\r\n\r\nexport function isFunction(obj: any): obj is (...args: Array) => unknown {\r\n return typeof obj === 'function';\r\n}\r\n\r\nexport function isArray(obj: any): obj is Array {\r\n return Array.isArray(obj);\r\n}\r\n\r\nexport function isObject(obj: any): boolean {\r\n return typeof obj === 'object' && !isArray(obj) && !isNull(obj);\r\n}\r\n\r\n/**\r\n * Returns true if the given object is array like, false otherwise.\r\n * @param obj The Object\r\n */\r\nexport function isArrayLike(obj: any): obj is ArrayLike {\r\n const length = !!obj && obj.length;\r\n const lengthCorrectFormat = isNumber(length) && length > -1 && length % 1 == 0; // eslint-disable-line eqeqeq\r\n\r\n return isArray(obj) || (!isFunction(obj) && lengthCorrectFormat) ? (length > 0 && isObject(obj) ? length - 1 in obj : true) : false;\r\n}\r\n\r\n/**\r\n * Returns true if the given object is a \"plain\" (e.g. { key: value }) object, false otherwise.\r\n * @param obj The Object.\r\n */\r\nexport function isPlainObject(obj: any): obj is PlainObject {\r\n if (!obj || !isObject(obj) || type(obj) !== 'object') return false;\r\n\r\n let key;\r\n const cstr = 'constructor';\r\n const ctor = obj[cstr];\r\n const ctorProto = ctor && ctor.prototype;\r\n const hasOwnConstructor = hasOwnProperty.call(obj, cstr);\r\n const hasIsPrototypeOf = ctorProto && hasOwnProperty.call(ctorProto, 'isPrototypeOf');\r\n\r\n if (ctor && !hasOwnConstructor && !hasIsPrototypeOf) {\r\n return false;\r\n }\r\n\r\n /* eslint-disable no-restricted-syntax */\r\n for (key in obj) {\r\n /**/\r\n }\r\n /* eslint-enable */\r\n\r\n return isUndefined(key) || hasOwnProperty.call(obj, key);\r\n}\r\n\r\n/**\r\n * Checks whether the given object is a HTMLElement.\r\n * @param obj The object which shall be checked.\r\n */\r\nexport function isHTMLElement(obj: any): obj is HTMLElement {\r\n const instanceofObj = window.HTMLElement;\r\n return obj ? (instanceofObj ? obj instanceof instanceofObj : obj.nodeType === ElementNodeType) : false;\r\n}\r\n\r\n/**\r\n * Checks whether the given object is a Element.\r\n * @param obj The object which shall be checked.\r\n */\r\nexport function isElement(obj: any): obj is Element {\r\n const instanceofObj = window.Element;\r\n return obj ? (instanceofObj ? obj instanceof instanceofObj : obj.nodeType === ElementNodeType) : false;\r\n}\r\n","import { isArrayLike, isString } from 'support/utils/types';\r\nimport { PlainObject } from 'typings';\r\n\r\ntype RunEachItem = ((...args: any) => any | any[]) | null | undefined;\r\n\r\n/**\r\n * Iterates through a array or object\r\n * @param arrayLikeOrObject The array or object through which shall be iterated.\r\n * @param callback The function which is responsible for the iteration.\r\n * If the function returns true its treated like a \"continue\" statement.\r\n * If the function returns false its treated like a \"break\" statement.\r\n */\r\nexport function each(\r\n array: Array | ReadonlyArray,\r\n callback: (value: T, indexOrKey: number, source: Array) => boolean | unknown\r\n): Array | ReadonlyArray;\r\nexport function each(\r\n array: Array | ReadonlyArray | null | undefined,\r\n callback: (value: T, indexOrKey: number, source: Array) => boolean | unknown\r\n): Array | ReadonlyArray | null | undefined;\r\nexport function each(\r\n arrayLikeObject: ArrayLike,\r\n callback: (value: T, indexOrKey: number, source: ArrayLike) => boolean | unknown\r\n): ArrayLike;\r\nexport function each(\r\n arrayLikeObject: ArrayLike | null | undefined,\r\n callback: (value: T, indexOrKey: number, source: ArrayLike) => boolean | unknown\r\n): ArrayLike | null | undefined;\r\nexport function each(obj: PlainObject, callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | unknown): PlainObject;\r\nexport function each(\r\n obj: PlainObject | null | undefined,\r\n callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | unknown\r\n): PlainObject | null | undefined;\r\nexport function each(\r\n source: ArrayLike | PlainObject | null | undefined,\r\n callback: (value: T, indexOrKey: any, source: any) => boolean | unknown\r\n): Array | ReadonlyArray | ArrayLike | PlainObject | null | undefined {\r\n if (isArrayLike(source)) {\r\n for (let i = 0; i < source.length; i++) {\r\n if (callback(source[i], i, source) === false) {\r\n break;\r\n }\r\n }\r\n } else if (source) {\r\n each(Object.keys(source), (key) => callback(source[key], key, source));\r\n }\r\n return source;\r\n}\r\n\r\n/**\r\n * Returns the index of the given inside the given array or -1 if the given item isn't part of the given array.\r\n * @param arr The array.\r\n * @param item The item.\r\n * @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0.\r\n */\r\nexport const indexOf = (arr: Array, item: T, fromIndex?: number): number => arr.indexOf(item, fromIndex);\r\n\r\n/**\r\n * Pushesh all given items into the given array and returns it.\r\n * @param array The array the items shall be pushed into.\r\n * @param items The items which shall be pushed into the array.\r\n */\r\nexport const push = (array: Array, items: T | ArrayLike, arrayIsSingleItem?: boolean): Array => {\r\n !arrayIsSingleItem && !isString(items) && isArrayLike(items) ? Array.prototype.push.apply(array, items as Array) : array.push(items as T);\r\n return array;\r\n};\r\n\r\n/**\r\n * Creates a shallow-copied Array instance from an array-like or iterable object.\r\n * @param arr The object from which the array instance shall be created.\r\n */\r\nexport const from = (arr: ArrayLike) => {\r\n if (Array.from) {\r\n return Array.from(arr);\r\n }\r\n const result: Array = [];\r\n\r\n each(arr, (elm) => {\r\n push(result, elm);\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Check whether the passed array is empty.\r\n * @param array The array which shall be checked.\r\n */\r\nexport const isEmptyArray = (array: Array | null | undefined) => array && array.length === 0;\r\n\r\n/**\r\n * Calls all functions in the passed array/set of functions.\r\n * @param arr The array filled with function which shall be called.\r\n * @param p1 The first param.\r\n */\r\nexport const runEach = (arr: ArrayLike | Set, p1?: unknown): void => {\r\n const runFn = (fn: RunEachItem) => fn && fn(p1);\r\n if (arr instanceof Set) {\r\n arr.forEach(runFn);\r\n } else {\r\n each(arr, runFn);\r\n }\r\n};\r\n","import { isArray, isFunction, isPlainObject, isNull } from 'support/utils/types';\r\nimport { each } from 'support/utils/array';\r\n\r\n/**\r\n * Determines whether the passed object has a property with the passed name.\r\n * @param obj The object.\r\n * @param prop The name of the property.\r\n */\r\nexport const hasOwnProperty = (obj: any, prop: string | number | symbol): boolean => Object.prototype.hasOwnProperty.call(obj, prop);\r\n\r\n/**\r\n * Returns the names of the enumerable string properties and methods of an object.\r\n * @param obj The object of which the properties shall be returned.\r\n */\r\nexport const keys = (obj: any): Array => (obj ? Object.keys(obj) : []);\r\n\r\n// https://github.com/jquery/jquery/blob/master/src/core.js#L116\r\nexport function assignDeep(target: T, object1: U): T & U;\r\nexport function assignDeep(target: T, object1: U, object2: V): T & U & V;\r\nexport function assignDeep(target: T, object1: U, object2: V, object3: W): T & U & V & W;\r\nexport function assignDeep(target: T, object1: U, object2: V, object3: W, object4: X): T & U & V & W & X;\r\nexport function assignDeep(target: T, object1: U, object2: V, object3: W, object4: X, object5: Y): T & U & V & W & X & Y;\r\nexport function assignDeep(\r\n target: T,\r\n object1?: U,\r\n object2?: V,\r\n object3?: W,\r\n object4?: X,\r\n object5?: Y,\r\n object6?: Z\r\n): T & U & V & W & X & Y & Z {\r\n const sources: Array = [object1, object2, object3, object4, object5, object6];\r\n\r\n // Handle case when target is a string or something (possible in deep copy)\r\n if ((typeof target !== 'object' || isNull(target)) && !isFunction(target)) {\r\n target = {} as T;\r\n }\r\n\r\n each(sources, (source) => {\r\n // Extend the base object\r\n each(keys(source), (key) => {\r\n const copy: any = source[key];\r\n\r\n // Prevent Object.prototype pollution\r\n // Prevent never-ending loop\r\n if (target === copy) {\r\n return true;\r\n }\r\n\r\n const copyIsArray = isArray(copy);\r\n\r\n // Recurse if we're merging plain objects or arrays\r\n if (copy && (isPlainObject(copy) || copyIsArray)) {\r\n const src = target[key];\r\n let clone: any = src;\r\n\r\n // Ensure proper type for the source value\r\n if (copyIsArray && !isArray(src)) {\r\n clone = [];\r\n } else if (!copyIsArray && !isPlainObject(src)) {\r\n clone = {};\r\n }\r\n\r\n // Never move original objects, clone them\r\n target[key] = assignDeep(clone, copy) as any;\r\n } else {\r\n target[key] = copy;\r\n }\r\n });\r\n });\r\n\r\n // Return the modified object\r\n return target as any;\r\n}\r\n\r\n/**\r\n * Returns true if the given object is empty, false otherwise.\r\n * @param obj The Object.\r\n */\r\nexport function isEmptyObject(obj: any): boolean {\r\n /* eslint-disable no-restricted-syntax, guard-for-in */\r\n for (const name in obj) return false;\r\n return true;\r\n /* eslint-enable */\r\n}\r\n","import { isUndefined } from 'support/utils/types';\r\n\r\ntype GetSetPropName = 'scrollLeft' | 'scrollTop' | 'value';\r\n\r\nfunction getSetProp(\r\n topLeft: GetSetPropName,\r\n fallback: number | string,\r\n elm: HTMLElement | HTMLInputElement | null,\r\n value?: number | string\r\n): number | string | void {\r\n if (isUndefined(value)) {\r\n return elm ? elm[topLeft] : fallback;\r\n }\r\n elm && (elm[topLeft] = value);\r\n}\r\n\r\n/**\r\n * Gets or sets a attribute with the given attribute of the given element depending whether the value attribute is given.\r\n * Returns null if the element has no attribute with the given name.\r\n * @param elm The element of which the attribute shall be get or set.\r\n * @param attrName The attribute name which shall be get or set.\r\n * @param value The value of the attribute which shall be set.\r\n */\r\nexport function attr(elm: HTMLElement | null, attrName: string): string | null;\r\nexport function attr(elm: HTMLElement | null, attrName: string, value: string): void;\r\nexport function attr(elm: HTMLElement | null, attrName: string, value?: string): string | null | void {\r\n if (isUndefined(value)) {\r\n return elm ? elm.getAttribute(attrName) : null;\r\n }\r\n elm && elm.setAttribute(attrName, value);\r\n}\r\n\r\n/**\r\n * Removes the given attribute from the given element.\r\n * @param elm The element of which the attribute shall be removed.\r\n * @param attrName The attribute name.\r\n */\r\nexport const removeAttr = (elm: Element | null, attrName: string): void => {\r\n elm && elm.removeAttribute(attrName);\r\n};\r\n\r\n/**\r\n * Gets or sets the scrollLeft value of the given element depending whether the value attribute is given.\r\n * @param elm The element of which the scrollLeft value shall be get or set.\r\n * @param value The scrollLeft value which shall be set.\r\n */\r\nexport function scrollLeft(elm: HTMLElement | null): number;\r\nexport function scrollLeft(elm: HTMLElement | null, value: number): void;\r\nexport function scrollLeft(elm: HTMLElement | null, value?: number): number | void {\r\n return getSetProp('scrollLeft', 0, elm, value) as number;\r\n}\r\n\r\n/**\r\n * Gets or sets the scrollTop value of the given element depending whether the value attribute is given.\r\n * @param elm The element of which the scrollTop value shall be get or set.\r\n * @param value The scrollTop value which shall be set.\r\n */\r\nexport function scrollTop(elm: HTMLElement | null): number;\r\nexport function scrollTop(elm: HTMLElement | null, value: number): void;\r\nexport function scrollTop(elm: HTMLElement | null, value?: number): number | void {\r\n return getSetProp('scrollTop', 0, elm, value) as number;\r\n}\r\n\r\n/**\r\n * Gets or sets the value of the given input element depending whether the value attribute is given.\r\n * @param elm The input element of which the value shall be get or set.\r\n * @param value The value which shall be set.\r\n */\r\nexport function val(elm: HTMLInputElement | null): string;\r\nexport function val(elm: HTMLInputElement | null, value: string): void;\r\nexport function val(elm: HTMLInputElement | null, value?: string): string | void {\r\n return getSetProp('value', '', elm, value) as string;\r\n}\r\n","import { isElement } from 'support/utils/types';\r\nimport { push, from } from 'support/utils/array';\r\n\r\ntype InputElementType = Element | Node | false | null | undefined;\r\ntype OutputElementType = Element | null;\r\n\r\nconst elmPrototype = Element.prototype;\r\n\r\n/**\r\n * Find all elements with the passed selector, outgoing (and including) the passed element or the document if no element was provided.\r\n * @param selector The selector which has to be searched by.\r\n * @param elm The element from which the search shall be outgoing.\r\n */\r\nconst find = (selector: string, elm?: InputElementType): Element[] => {\r\n const arr: Array = [];\r\n const rootElm = elm ? (isElement(elm) ? elm : null) : document;\r\n\r\n return rootElm ? push(arr, rootElm.querySelectorAll(selector)) : arr;\r\n};\r\n\r\n/**\r\n * Find the first element with the passed selector, outgoing (and including) the passed element or the document if no element was provided.\r\n * @param selector The selector which has to be searched by.\r\n * @param elm The element from which the search shall be outgoing.\r\n */\r\nconst findFirst = (selector: string, elm?: InputElementType): OutputElementType => {\r\n const rootElm = elm ? (isElement(elm) ? elm : null) : document;\r\n\r\n return rootElm ? rootElm.querySelector(selector) : null;\r\n};\r\n\r\n/**\r\n * Determines whether the passed element is matching with the passed selector.\r\n * @param elm The element which has to be compared with the passed selector.\r\n * @param selector The selector which has to be compared with the passed element. Additional selectors: ':visible' and ':hidden'.\r\n */\r\nconst is = (elm: InputElementType, selector: string): boolean => {\r\n if (isElement(elm)) {\r\n /* istanbul ignore next */\r\n // eslint-disable-next-line\r\n // @ts-ignore\r\n const fn: (...args: any) => boolean = elmPrototype.matches || elmPrototype.msMatchesSelector;\r\n return fn.call(elm, selector);\r\n }\r\n return false;\r\n};\r\n\r\n/**\r\n * Returns the children (no text-nodes or comments) of the passed element which are matching the passed selector. An empty array is returned if the passed element is null.\r\n * @param elm The element of which the children shall be returned.\r\n * @param selector The selector which must match with the children elements.\r\n */\r\nconst children = (elm: InputElementType, selector?: string): ReadonlyArray => {\r\n const childs: Array = [];\r\n\r\n return isElement(elm)\r\n ? push(\r\n childs,\r\n from(elm.children).filter((child) => (selector ? is(child, selector) : child))\r\n )\r\n : childs;\r\n};\r\n\r\n/**\r\n * Returns the childNodes (incl. text-nodes or comments etc.) of the passed element. An empty array is returned if the passed element is null.\r\n * @param elm The element of which the childNodes shall be returned.\r\n */\r\nconst contents = (elm: InputElementType): ReadonlyArray => (elm ? from(elm.childNodes) : []);\r\n\r\n/**\r\n * Returns the parent element of the passed element, or null if the passed element is null.\r\n * @param elm The element of which the parent element shall be returned.\r\n */\r\nconst parent = (elm: InputElementType): OutputElementType => (elm ? elm.parentElement : null);\r\n\r\nconst closest = (elm: InputElementType, selector: string): OutputElementType => {\r\n if (isElement(elm)) {\r\n const closestFn = elmPrototype.closest;\r\n if (closestFn) {\r\n return closestFn.call(elm, selector);\r\n }\r\n\r\n do {\r\n if (is(elm, selector)) {\r\n return elm as Element;\r\n }\r\n elm = parent(elm);\r\n } while (elm);\r\n }\r\n\r\n return null;\r\n};\r\n\r\n/**\r\n * Determines whether the given element lies between two selectors in the DOM.\r\n * @param elm The element.\r\n * @param highBoundarySelector The high boundary selector.\r\n * @param deepBoundarySelector The deep boundary selector.\r\n */\r\nconst liesBetween = (elm: InputElementType, highBoundarySelector: string, deepBoundarySelector: string): boolean => {\r\n const closestHighBoundaryElm = elm && closest(elm, highBoundarySelector);\r\n const closestDeepBoundaryElm = elm && findFirst(deepBoundarySelector, closestHighBoundaryElm);\r\n\r\n return closestHighBoundaryElm && closestDeepBoundaryElm\r\n ? closestHighBoundaryElm === elm ||\r\n closestDeepBoundaryElm === elm ||\r\n closest(closest(elm, deepBoundarySelector), highBoundarySelector) !== closestHighBoundaryElm\r\n : false;\r\n};\r\n\r\nexport { find, findFirst, is, children, contents, parent, liesBetween };\r\n","import { isArrayLike } from 'support/utils/types';\r\nimport { each, from } from 'support/utils/array';\r\nimport { parent } from 'support/dom/traversal';\r\n\r\ntype NodeCollection = ArrayLike | Node | false | null | undefined;\r\n\r\n/**\r\n * Inserts Nodes before the given preferredAnchor element.\r\n * @param parentElm The parent of the preferredAnchor element or the element which shall be the parent of the inserted Nodes.\r\n * @param preferredAnchor The element before which the Nodes shall be inserted or null if the elements shall be appended at the end.\r\n * @param insertedElms The Nodes which shall be inserted.\r\n */\r\nconst before = (parentElm: Node | false | null | undefined, preferredAnchor: Node | null | undefined, insertedElms: NodeCollection): void => {\r\n if (insertedElms) {\r\n let anchor: Node | null | undefined = preferredAnchor;\r\n let fragment: DocumentFragment | Node | null | undefined;\r\n\r\n // parent must be defined\r\n if (parentElm) {\r\n if (isArrayLike(insertedElms)) {\r\n fragment = document.createDocumentFragment();\r\n\r\n // append all insertedElms to the fragment and if one of these is the anchor, change the anchor\r\n each(insertedElms, (insertedElm) => {\r\n if (insertedElm === anchor) {\r\n anchor = insertedElm.previousSibling;\r\n }\r\n fragment!.appendChild(insertedElm);\r\n });\r\n } else {\r\n fragment = insertedElms;\r\n }\r\n\r\n // if the preferred anchor isn't null set it to a valid anchor\r\n if (preferredAnchor) {\r\n if (!anchor) {\r\n anchor = parentElm.firstChild;\r\n } else if (anchor !== preferredAnchor) {\r\n anchor = anchor.nextSibling;\r\n }\r\n }\r\n\r\n parentElm.insertBefore(fragment, anchor || null);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Appends the given children at the end of the given Node.\r\n * @param node The Node to which the children shall be appended.\r\n * @param children The Nodes which shall be appended.\r\n */\r\nexport const appendChildren = (node: Node | null | undefined, children: NodeCollection): void => {\r\n before(node, null, children);\r\n};\r\n\r\n/**\r\n * Prepends the given children at the start of the given Node.\r\n * @param node The Node to which the children shall be prepended.\r\n * @param children The Nodes which shall be prepended.\r\n */\r\nexport const prependChildren = (node: Node | null | undefined, children: NodeCollection): void => {\r\n before(node, node && node.firstChild, children);\r\n};\r\n\r\n/**\r\n * Inserts the given Nodes before the given Node.\r\n * @param node The Node before which the given Nodes shall be inserted.\r\n * @param insertedNodes The Nodes which shall be inserted.\r\n */\r\nexport const insertBefore = (node: Node | null | undefined, insertedNodes: NodeCollection): void => {\r\n before(parent(node), node, insertedNodes);\r\n};\r\n\r\n/**\r\n * Inserts the given Nodes after the given Node.\r\n * @param node The Node after which the given Nodes shall be inserted.\r\n * @param insertedNodes The Nodes which shall be inserted.\r\n */\r\nexport const insertAfter = (node: Node | null | undefined, insertedNodes: NodeCollection): void => {\r\n before(parent(node), node && node.nextSibling, insertedNodes);\r\n};\r\n\r\n/**\r\n * Removes the given Nodes from their parent.\r\n * @param nodes The Nodes which shall be removed.\r\n */\r\nexport const removeElements = (nodes: NodeCollection): void => {\r\n if (isArrayLike(nodes)) {\r\n each(from(nodes), (e) => removeElements(e));\r\n } else if (nodes) {\r\n const parentElm = parent(nodes);\r\n if (parentElm) {\r\n parentElm.removeChild(nodes);\r\n }\r\n }\r\n};\r\n","import { each } from 'support/utils/array';\r\nimport { attr } from 'support/dom/attribute';\r\nimport { contents } from 'support/dom/traversal';\r\nimport { removeElements } from 'support/dom/manipulation';\r\n\r\n/**\r\n * Creates a div DOM node.\r\n */\r\nexport const createDiv = (classNames?: string): HTMLDivElement => {\r\n const div = document.createElement('div');\r\n if (classNames) {\r\n attr(div, 'class', classNames);\r\n }\r\n return div;\r\n};\r\n\r\n/**\r\n * Creates DOM nodes modeled after the passed html string and returns the root dom nodes as a array.\r\n * @param html The html string after which the DOM nodes shall be created.\r\n */\r\nexport const createDOM = (html: string): ReadonlyArray => {\r\n const createdDiv = createDiv();\r\n createdDiv.innerHTML = html.trim();\r\n\r\n return each(contents(createdDiv), (elm) => removeElements(elm));\r\n};\r\n","import { each } from 'support/utils/array';\r\nimport { hasOwnProperty } from 'support/utils/object';\r\nimport { createDiv } from 'support/dom/create';\r\n\r\nconst firstLetterToUpper = (str: string): string => str.charAt(0).toUpperCase() + str.slice(1);\r\nconst getDummyStyle = (): CSSStyleDeclaration => createDiv().style;\r\n\r\n// https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix\r\n\r\nexport const cssPrefixes: ReadonlyArray = ['-webkit-', '-moz-', '-o-', '-ms-'];\r\nexport const jsPrefixes: ReadonlyArray = ['WebKit', 'Moz', 'O', 'MS', 'webkit', 'moz', 'o', 'ms'];\r\n\r\nexport const jsCache: { [key: string]: any } = {};\r\nexport const cssCache: { [key: string]: string } = {};\r\n\r\n/**\r\n * Gets the name of the given CSS property with vendor prefix if it isn't supported without it, or and empty string if unsupported.\r\n * @param name The name of the CSS property which shall be get.\r\n */\r\nexport const cssProperty = (name: string): string => {\r\n let result: string | undefined = cssCache[name];\r\n\r\n if (hasOwnProperty(cssCache, name)) {\r\n return result;\r\n }\r\n\r\n const uppercasedName: string = firstLetterToUpper(name);\r\n const elmStyle: CSSStyleDeclaration = getDummyStyle();\r\n\r\n each(cssPrefixes, (prefix: string) => {\r\n const prefixWithoutDashes: string = prefix.replace(/-/g, '');\r\n const resultPossibilities: Array = [\r\n name, // transition\r\n prefix + name, // -webkit-transition\r\n prefixWithoutDashes + uppercasedName, // webkitTransition\r\n firstLetterToUpper(prefixWithoutDashes) + uppercasedName, // WebkitTransition\r\n ];\r\n return !(result = resultPossibilities.find((resultPossibility: string) => elmStyle[resultPossibility] !== undefined));\r\n });\r\n\r\n return (cssCache[name] = result || '');\r\n};\r\n\r\n/**\r\n * Get the name of the given CSS property value(s), with vendor prefix if it isn't supported without it, or an empty string if no value is supported.\r\n * @param property The CSS property to which the CSS property value(s) belong.\r\n * @param values The value(s) separated by spaces which shall be get.\r\n * @param suffix A suffix which is added to each value in case the value is a function or something else more advanced.\r\n */\r\nexport const cssPropertyValue = (property: string, values: string, suffix?: string): string => {\r\n const name = `${property} ${values}`;\r\n let result: string | undefined = cssCache[name];\r\n\r\n if (hasOwnProperty(cssCache, name)) {\r\n return result;\r\n }\r\n\r\n const dummyStyle: CSSStyleDeclaration = getDummyStyle();\r\n const possbleValues: Array = values.split(' ');\r\n const preparedSuffix: string = suffix || '';\r\n const cssPrefixesWithFirstEmpty = [''].concat(cssPrefixes);\r\n\r\n each(possbleValues, (possibleValue: string) => {\r\n each(cssPrefixesWithFirstEmpty, (prefix: string) => {\r\n const prop = prefix + possibleValue;\r\n dummyStyle.cssText = `${property}:${prop}${preparedSuffix}`;\r\n if (dummyStyle.length) {\r\n result = prop;\r\n return false;\r\n }\r\n });\r\n return !result;\r\n });\r\n\r\n return (cssCache[name] = result || '');\r\n};\r\n\r\n/**\r\n * Get the requested JS function, object or constructor with vendor prefix if it isn't supported without or undefined if unsupported.\r\n * @param name The name of the JS function, object or constructor.\r\n */\r\nexport const jsAPI = (name: string): T | undefined => {\r\n let result: any = jsCache[name] || window[name];\r\n\r\n if (hasOwnProperty(jsCache, name)) {\r\n return result;\r\n }\r\n\r\n each(jsPrefixes, (prefix: string) => {\r\n result = result || window[prefix + firstLetterToUpper(name)];\r\n return !result;\r\n });\r\n\r\n jsCache[name] = result;\r\n return result;\r\n};\r\n","import { jsAPI } from 'support/compatibility/vendors';\r\n\r\nexport const MutationObserverConstructor = jsAPI('MutationObserver');\r\nexport const IntersectionObserverConstructor = jsAPI('IntersectionObserver');\r\nexport const ResizeObserverConstructor = jsAPI('ResizeObserver');\r\nexport const cAF = jsAPI('cancelAnimationFrame');\r\nexport const rAF = jsAPI('requestAnimationFrame');\r\n","import { isString } from 'support/utils/types';\r\nimport { each } from 'support/utils/array';\r\nimport { keys } from 'support/utils/object';\r\n\r\nconst rnothtmlwhite = /[^\\x20\\t\\r\\n\\f]+/g;\r\nconst classListAction = (\r\n elm: Element | false | null | undefined,\r\n className: string,\r\n action: (elmClassList: DOMTokenList, clazz: string) => boolean | void\r\n): boolean => {\r\n let clazz: string;\r\n let i = 0;\r\n let result = false;\r\n\r\n if (elm && isString(className)) {\r\n const classes: Array = className.match(rnothtmlwhite) || [];\r\n result = classes.length > 0;\r\n while ((clazz = classes[i++])) {\r\n result = !!action(elm.classList, clazz) && result;\r\n }\r\n }\r\n return result;\r\n};\r\n\r\n/**\r\n * Check whether the given element has the given class name(s).\r\n * @param elm The element.\r\n * @param className The class name(s).\r\n */\r\nexport const hasClass = (elm: Element | false | null | undefined, className: string): boolean =>\r\n classListAction(elm, className, (classList, clazz) => classList.contains(clazz));\r\n\r\n/**\r\n * Adds the given class name(s) to the given element.\r\n * @param elm The element.\r\n * @param className The class name(s) which shall be added. (separated by spaces)\r\n */\r\nexport const addClass = (elm: Element | false | null | undefined, className: string): void => {\r\n classListAction(elm, className, (classList, clazz) => classList.add(clazz));\r\n};\r\n\r\n/**\r\n * Removes the given class name(s) from the given element.\r\n * @param elm The element.\r\n * @param className The class name(s) which shall be removed. (separated by spaces)\r\n */\r\nexport const removeClass = (elm: Element | false | null | undefined, className: string): void => {\r\n classListAction(elm, className, (classList, clazz) => classList.remove(clazz));\r\n};\r\n\r\n/**\r\n * Takes two className strings, compares them and returns the difference as array.\r\n * @param classNameA ClassName A.\r\n * @param classNameB ClassName B.\r\n */\r\nexport const diffClass = (classNameA: string | null | undefined, classNameB: string | null | undefined) => {\r\n const classNameASplit = classNameA && classNameA.split(' ');\r\n const classNameBSplit = classNameB && classNameB.split(' ');\r\n const tempObj = {};\r\n\r\n each(classNameASplit, (className) => {\r\n tempObj[className] = 1;\r\n });\r\n each(classNameBSplit, (className) => {\r\n if (tempObj[className]) {\r\n delete tempObj[className];\r\n } else {\r\n tempObj[className] = 1;\r\n }\r\n });\r\n\r\n return keys(tempObj);\r\n};\r\n","export interface WH {\r\n w: T;\r\n h: T;\r\n}\r\n\r\nconst elementHasDimensions = (elm: HTMLElement): boolean => !!(elm.offsetWidth || elm.offsetHeight || elm.getClientRects().length);\r\nconst zeroObj: WH = {\r\n w: 0,\r\n h: 0,\r\n};\r\n\r\n/**\r\n * Returns the window inner- width and height.\r\n */\r\nexport const windowSize = (): WH => ({\r\n w: window.innerWidth,\r\n h: window.innerHeight,\r\n});\r\n\r\n/**\r\n * Returns the scroll- width and height of the passed element. If the element is null the width and height values are 0.\r\n * @param elm The element of which the scroll- width and height shall be returned.\r\n */\r\nexport const offsetSize = (elm: HTMLElement | null | undefined): WH =>\r\n elm\r\n ? {\r\n w: elm.offsetWidth,\r\n h: elm.offsetHeight,\r\n }\r\n : zeroObj;\r\n\r\n/**\r\n * Returns the client- width and height of the passed element. If the element is null the width and height values are 0.\r\n * @param elm The element of which the client- width and height shall be returned.\r\n */\r\nexport const clientSize = (elm: HTMLElement | null | undefined): WH =>\r\n elm\r\n ? {\r\n w: elm.clientWidth,\r\n h: elm.clientHeight,\r\n }\r\n : zeroObj;\r\n\r\n/**\r\n * Returns the client- width and height of the passed element. If the element is null the width and height values are 0.\r\n * @param elm The element of which the client- width and height shall be returned.\r\n */\r\nexport const scrollSize = (elm: HTMLElement | null | undefined): WH =>\r\n elm\r\n ? {\r\n w: elm.scrollWidth,\r\n h: elm.scrollHeight,\r\n }\r\n : zeroObj;\r\n\r\n/**\r\n * Returns the BoundingClientRect of the passed element.\r\n * @param elm The element of which the BoundingClientRect shall be returned.\r\n */\r\nexport const getBoundingClientRect = (elm: HTMLElement): DOMRect => elm.getBoundingClientRect();\r\n\r\n/**\r\n * Determines whether the passed element has any dimensions.\r\n * @param elm The element.\r\n */\r\nexport const hasDimensions = (elm: HTMLElement | null | undefined): boolean => (elm ? elementHasDimensions(elm as HTMLElement) : false);\r\n","import { isUndefined } from 'support/utils/types';\r\nimport { each, push, runEach } from 'support/utils/array';\r\n\r\nlet passiveEventsSupport: boolean;\r\nconst supportPassiveEvents = (): boolean => {\r\n if (isUndefined(passiveEventsSupport)) {\r\n passiveEventsSupport = false;\r\n try {\r\n /* eslint-disable */\r\n // @ts-ignore\r\n window.addEventListener(\r\n 'test',\r\n null,\r\n Object.defineProperty({}, 'passive', {\r\n get: function () {\r\n passiveEventsSupport = true;\r\n },\r\n })\r\n );\r\n /* eslint-enable */\r\n } catch (e) {}\r\n }\r\n return passiveEventsSupport;\r\n};\r\nconst splitEventNames = (eventNames: string) => eventNames.split(' ');\r\n\r\nexport interface OnOptions {\r\n _capture?: boolean;\r\n _passive?: boolean;\r\n _once?: boolean;\r\n}\r\n\r\n/**\r\n * Removes the passed event listener for the passed events with the passed options.\r\n * @param target The element from which the listener shall be removed.\r\n * @param eventNames The eventsnames for which the listener shall be removed.\r\n * @param listener The listener which shall be removed.\r\n * @param capture The options of the removed listener.\r\n */\r\nexport const off = (target: EventTarget, eventNames: string, listener: (event: T) => any, capture?: boolean): void => {\r\n each(splitEventNames(eventNames), (eventName) => {\r\n target.removeEventListener(eventName, listener as EventListener, capture);\r\n });\r\n};\r\n\r\n/**\r\n * Adds the passed event listener for the passed eventnames with the passed options.\r\n * @param target The element to which the listener shall be added.\r\n * @param eventNames The eventsnames for which the listener shall be called.\r\n * @param listener The listener which is called on the eventnames.\r\n * @param options The options of the added listener.\r\n */\r\nexport const on = (\r\n target: EventTarget,\r\n eventNames: string,\r\n listener: (event: T) => any,\r\n options?: OnOptions\r\n): (() => void) => {\r\n const doSupportPassiveEvents = supportPassiveEvents();\r\n const passive = (doSupportPassiveEvents && options && options._passive) || false;\r\n const capture = (options && options._capture) || false;\r\n const once = (options && options._once) || false;\r\n const offListeners: (() => void)[] = [];\r\n const nativeOptions: AddEventListenerOptions | boolean = doSupportPassiveEvents\r\n ? {\r\n passive,\r\n capture,\r\n }\r\n : capture;\r\n\r\n each(splitEventNames(eventNames), (eventName) => {\r\n const finalListener = (once\r\n ? (evt: T) => {\r\n target.removeEventListener(eventName, finalListener, capture);\r\n listener && listener(evt);\r\n }\r\n : listener) as EventListener;\r\n\r\n push(offListeners, off.bind(null, target, eventName, finalListener, capture));\r\n target.addEventListener(eventName, finalListener, nativeOptions);\r\n });\r\n\r\n return runEach.bind(0, offListeners);\r\n};\r\n\r\n/**\r\n * Shorthand for the stopPropagation event Method.\r\n * @param evt The event of which the stopPropagation method shall be called.\r\n */\r\nexport const stopPropagation = (evt: Event): void => evt.stopPropagation();\r\n\r\n/**\r\n * Shorthand for the preventDefault event Method.\r\n * @param evt The event of which the preventDefault method shall be called.\r\n */\r\nexport const preventDefault = (evt: Event): void => evt.preventDefault();\r\n\r\n/**\r\n * Shorthand for the stopPropagation and preventDefault event Method.\r\n * @param evt The event of which the stopPropagation and preventDefault methods shall be called.\r\n */\r\nexport const stopAndPrevent = (evt: Event): void => (stopPropagation(evt) as undefined) || (preventDefault(evt) as undefined);\r\n","import { each } from 'support/utils/array';\r\nimport { WH, XY, TRBL } from 'support/dom';\r\nimport { PlainObject } from 'typings';\r\n\r\n/**\r\n * Compares two objects and returns true if all values of the passed prop names are identical, false otherwise or if one of the two object is falsy.\r\n * @param a Object a.\r\n * @param b Object b.\r\n * @param props The props which shall be compared.\r\n */\r\nexport const equal = (\r\n a: T | undefined,\r\n b: T | undefined,\r\n props: Array,\r\n propMutation?: ((value: any) => any) | null | false\r\n): boolean => {\r\n if (a && b) {\r\n let result = true;\r\n each(props, (prop) => {\r\n const compareA = propMutation ? propMutation(a[prop]) : a[prop];\r\n const compareB = propMutation ? propMutation(b[prop]) : b[prop];\r\n if (compareA !== compareB) {\r\n result = false;\r\n }\r\n });\r\n return result;\r\n }\r\n return false;\r\n};\r\n\r\n/**\r\n * Compares object a with object b and returns true if both have the same property values, false otherwise.\r\n * Also returns false if one of the objects is undefined or null.\r\n * @param a Object a.\r\n * @param b Object b.\r\n */\r\nexport const equalWH = (a?: WH, b?: WH) => equal(a, b, ['w', 'h']);\r\n\r\n/**\r\n * Compares object a with object b and returns true if both have the same property values, false otherwise.\r\n * Also returns false if one of the objects is undefined or null.\r\n * @param a Object a.\r\n * @param b Object b.\r\n */\r\nexport const equalXY = (a?: XY, b?: XY) => equal(a, b, ['x', 'y']);\r\n\r\n/**\r\n * Compares object a with object b and returns true if both have the same property values, false otherwise.\r\n * Also returns false if one of the objects is undefined or null.\r\n * @param a Object a.\r\n * @param b Object b.\r\n */\r\nexport const equalTRBL = (a?: TRBL, b?: TRBL) => equal(a, b, ['t', 'r', 'b', 'l']);\r\n\r\n/**\r\n * Compares two DOM Rects for their equality of their width and height properties\r\n * Also returns false if one of the DOM Rects is undefined or null.\r\n * @param a DOM Rect a.\r\n * @param b DOM Rect b.\r\n * @param round Whether the values should be rounded.\r\n */\r\nexport const equalBCRWH = (a?: DOMRect, b?: DOMRect, round?: boolean) =>\r\n equal(a, b, ['width', 'height'], round && ((value) => Math.round(value)));\r\n","import { isNumber, isFunction } from 'support/utils/types';\r\nimport { rAF, cAF } from 'support/compatibility/apis';\r\n\r\nconst setT = window.setTimeout;\r\nconst clearTimeouts = (id: number | undefined) => {\r\n id && window.clearTimeout(id);\r\n id && cAF!(id);\r\n};\r\n\r\ntype DebounceTiming = number | false | null | undefined;\r\n\r\nexport interface DebounceOptions any> {\r\n /**\r\n * The timeout for debouncing. If null, no debounce is applied.\r\n */\r\n _timeout?: DebounceTiming | (() => DebounceTiming);\r\n /**\r\n * A maximum amount of ms. before the function will be called even with debounce.\r\n */\r\n _maxDelay?: DebounceTiming | (() => DebounceTiming);\r\n /**\r\n * Function which merges parameters for each canceled debounce.\r\n * If parameters can't be merged the function will return null, otherwise it returns the merged parameters.\r\n */\r\n _mergeParams?: (\r\n prev: Parameters,\r\n curr: Parameters\r\n ) => Parameters | false | null | undefined;\r\n}\r\n\r\nexport interface Debounced any> {\r\n (...args: Parameters): ReturnType;\r\n _flush(): void;\r\n}\r\n\r\nexport const noop = () => {}; // eslint-disable-line\r\n\r\n/**\r\n * Debounces the given function either with a timeout or a animation frame.\r\n * @param functionToDebounce The function which shall be debounced.\r\n * @param options Options for debouncing.\r\n */\r\nexport const debounce = any>(\r\n functionToDebounce: FunctionToDebounce,\r\n options: DebounceOptions\r\n): Debounced => {\r\n let timeoutId: number | undefined;\r\n let maxTimeoutId: number | undefined;\r\n let prevArguments: Parameters | null | undefined;\r\n let latestArguments: Parameters | null | undefined;\r\n const { _timeout, _maxDelay, _mergeParams } = options;\r\n\r\n const invokeFunctionToDebounce = function (args: IArguments) {\r\n clearTimeouts(timeoutId);\r\n clearTimeouts(maxTimeoutId);\r\n maxTimeoutId = timeoutId = prevArguments = undefined;\r\n // eslint-disable-next-line\r\n // @ts-ignore\r\n functionToDebounce.apply(this, args);\r\n };\r\n\r\n const mergeParms = (curr: Parameters): Parameters | false | null | undefined =>\r\n _mergeParams && prevArguments ? _mergeParams(prevArguments, curr) : curr;\r\n\r\n const flush = () => {\r\n if (timeoutId) {\r\n invokeFunctionToDebounce(mergeParms(latestArguments!) || latestArguments!);\r\n }\r\n };\r\n\r\n const debouncedFn = function () {\r\n const args: Parameters = arguments as Parameters;\r\n const finalTimeout = isFunction(_timeout) ? _timeout() : _timeout;\r\n const hasTimeout = isNumber(finalTimeout) && finalTimeout >= 0;\r\n\r\n if (hasTimeout) {\r\n const finalMaxWait = isFunction(_maxDelay) ? _maxDelay() : _maxDelay;\r\n const hasMaxWait = isNumber(finalMaxWait) && finalMaxWait >= 0;\r\n const setTimeoutFn = finalTimeout! > 0 ? setT : rAF!;\r\n const mergeParamsResult = mergeParms(args);\r\n const invokedArgs = mergeParamsResult || args;\r\n const boundInvoke = invokeFunctionToDebounce.bind(0, invokedArgs);\r\n\r\n if (!mergeParamsResult) {\r\n invokeFunctionToDebounce(prevArguments || args);\r\n }\r\n\r\n clearTimeouts(timeoutId);\r\n timeoutId = setTimeoutFn(boundInvoke, finalTimeout as number) as number;\r\n\r\n if (hasMaxWait && !maxTimeoutId) {\r\n maxTimeoutId = setT(flush, finalMaxWait as number);\r\n }\r\n\r\n prevArguments = latestArguments = invokedArgs;\r\n } else {\r\n invokeFunctionToDebounce(args);\r\n }\r\n };\r\n debouncedFn._flush = flush;\r\n\r\n return debouncedFn as Debounced;\r\n};\r\n","import { each, keys } from 'support/utils';\r\nimport { isString, isNumber, isArray, isUndefined } from 'support/utils/types';\r\nimport { PlainObject, StyleObject } from 'typings';\r\n\r\nexport interface TRBL {\r\n t: number;\r\n r: number;\r\n b: number;\r\n l: number;\r\n}\r\n\r\nconst cssNumber = {\r\n //animationiterationcount: 1,\r\n //columncount: 1,\r\n //fillopacity: 1,\r\n //flexgrow: 1,\r\n //flexshrink: 1,\r\n //fontweight: 1,\r\n //lineheight: 1,\r\n opacity: 1,\r\n //order: 1,\r\n //orphans: 1,\r\n //widows: 1,\r\n zindex: 1,\r\n //zoom: 1,\r\n};\r\n\r\nconst parseToZeroOrNumber = (value: string, toFloat?: boolean): number => {\r\n /* istanbul ignore next */\r\n const num = toFloat ? parseFloat(value) : parseInt(value, 10);\r\n /* istanbul ignore next */\r\n return Number.isNaN(num) ? 0 : num;\r\n};\r\nconst adaptCSSVal = (prop: string, val: string | number): string | number => (!cssNumber[prop.toLowerCase()] && isNumber(val) ? `${val}px` : val);\r\nconst getCSSVal = (elm: HTMLElement, computedStyle: CSSStyleDeclaration, prop: string): string =>\r\n /* istanbul ignore next */\r\n computedStyle != null ? computedStyle[prop] || computedStyle.getPropertyValue(prop) : elm.style[prop];\r\nconst setCSSVal = (elm: HTMLElement | false | null | undefined, prop: string, val: string | number): void => {\r\n try {\r\n if (elm) {\r\n const { style } = elm;\r\n if (!isUndefined(style[prop])) {\r\n style[prop] = adaptCSSVal(prop, val);\r\n } else {\r\n style.setProperty(prop, val as string);\r\n }\r\n }\r\n } catch (e) {}\r\n};\r\n\r\n/**\r\n * Gets or sets the passed styles to the passed element.\r\n * @param elm The element to which the styles shall be applied to / be read from.\r\n * @param styles The styles which shall be set or read.\r\n */\r\nexport function style(elm: HTMLElement | false | null | undefined, styles: StyleObject): void;\r\nexport function style(elm: HTMLElement | false | null | undefined, styles: string): string;\r\nexport function style(elm: HTMLElement | false | null | undefined, styles: Array | string): { [key: string]: string };\r\nexport function style(\r\n elm: HTMLElement | false | null | undefined,\r\n styles: StyleObject | Array | string\r\n): { [key: string]: string } | string | void {\r\n const getSingleStyle = isString(styles);\r\n const getStyles = isArray(styles) || getSingleStyle;\r\n\r\n if (getStyles) {\r\n let getStylesResult: string | PlainObject = getSingleStyle ? '' : {};\r\n if (elm) {\r\n const computedStyle: CSSStyleDeclaration = window.getComputedStyle(elm, null);\r\n getStylesResult = getSingleStyle\r\n ? getCSSVal(elm, computedStyle, styles as string)\r\n : (styles as Array).reduce((result, key) => {\r\n result[key] = getCSSVal(elm, computedStyle, key as string);\r\n return result;\r\n }, getStylesResult);\r\n }\r\n return getStylesResult;\r\n }\r\n each(keys(styles), (key) => setCSSVal(elm, key, styles[key]));\r\n}\r\n\r\n/**\r\n * Hides the passed element (display: none).\r\n * @param elm The element which shall be hidden.\r\n */\r\nexport const hide = (elm: HTMLElement | false | null | undefined): void => {\r\n style(elm, { display: 'none' });\r\n};\r\n\r\n/**\r\n * Shows the passed element (display: block).\r\n * @param elm The element which shall be shown.\r\n */\r\nexport const show = (elm: HTMLElement | false | null | undefined): void => {\r\n style(elm, { display: 'block' });\r\n};\r\n\r\n/**\r\n * Returns the top right bottom left values of the passed css property.\r\n * @param elm The element of which the values shall be returned.\r\n * @param propertyPrefix The css property prefix. (e.g. \"border\")\r\n * @param propertySuffix The css property suffix. (e.g. \"width\")\r\n */\r\nexport const topRightBottomLeft = (elm?: HTMLElement | false | null | undefined, propertyPrefix?: string, propertySuffix?: string): TRBL => {\r\n const finalPrefix = propertyPrefix ? `${propertyPrefix}-` : '';\r\n const finalSuffix = propertySuffix ? `-${propertySuffix}` : '';\r\n const top = `${finalPrefix}top${finalSuffix}`;\r\n const right = `${finalPrefix}right${finalSuffix}`;\r\n const bottom = `${finalPrefix}bottom${finalSuffix}`;\r\n const left = `${finalPrefix}left${finalSuffix}`;\r\n const result = style(elm, [top, right, bottom, left]);\r\n return {\r\n t: parseToZeroOrNumber(result[top]),\r\n r: parseToZeroOrNumber(result[right]),\r\n b: parseToZeroOrNumber(result[bottom]),\r\n l: parseToZeroOrNumber(result[left]),\r\n };\r\n};\r\n","import { getBoundingClientRect } from 'support/dom/dimensions';\r\n\r\nexport interface XY {\r\n x: T;\r\n y: T;\r\n}\r\n\r\nconst zeroObj: XY = {\r\n x: 0,\r\n y: 0,\r\n};\r\n\r\n/**\r\n * Returns the offset- left and top coordinates of the passed element relative to the document. If the element is null the top and left values are 0.\r\n * @param elm The element of which the offset- top and left coordinates shall be returned.\r\n */\r\nexport const absoluteCoordinates = (elm: HTMLElement | null | undefined): XY => {\r\n const rect = elm ? getBoundingClientRect(elm) : 0;\r\n return rect\r\n ? {\r\n x: rect.left + window.pageYOffset,\r\n y: rect.top + window.pageXOffset,\r\n }\r\n : zeroObj;\r\n};\r\n\r\n/**\r\n * Returns the offset- left and top coordinates of the passed element. If the element is null the top and left values are 0.\r\n * @param elm The element of which the offset- top and left coordinates shall be returned.\r\n */\r\nexport const offsetCoordinates = (elm: HTMLElement | null | undefined): XY =>\r\n elm\r\n ? {\r\n x: elm.offsetLeft,\r\n y: elm.offsetTop,\r\n }\r\n : zeroObj;\r\n","function _extends() {\n module.exports = _extends = Object.assign || function (target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i];\n\n for (var key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n\n return target;\n };\n\n return _extends.apply(this, arguments);\n}\n\nmodule.exports = _extends;","import { each, hasOwnProperty, keys, push, isEmptyObject } from 'support/utils';\r\nimport { type, isArray, isUndefined, isPlainObject, isString } from 'support/utils/types';\r\nimport { PlainObject } from 'typings';\r\n\r\nexport type OptionsObjectType = Record;\r\nexport type OptionsFunctionType = (this: unknown, ...args: unknown[]) => unknown;\r\nexport type OptionsTemplateType = ExtractPropsKey;\r\nexport type OptionsTemplateTypes = keyof OptionsTemplateTypeMap;\r\nexport type OptionsTemplateNativeTypes = OptionsTemplateTypeMap[keyof OptionsTemplateTypeMap];\r\n\r\nexport type OptionsTemplateValue = T extends string\r\n ? string extends T\r\n ? OptionsTemplateValueNonEnum\r\n : string\r\n : OptionsTemplateValueNonEnum;\r\n\r\nexport type OptionsTemplate = {\r\n [P in keyof T]: T[P] extends OptionsObjectType\r\n ? OptionsTemplate\r\n : T[P] extends OptionsTemplateNativeTypes\r\n ? OptionsTemplateValue\r\n : never;\r\n};\r\n\r\nexport type OptionsValidationResult = {\r\n readonly _foreign: Record;\r\n readonly _validated: PartialOptions;\r\n};\r\n\r\nexport type PartialOptions = {\r\n [P in keyof T]?: T[P] extends OptionsObjectType ? PartialOptions : T[P];\r\n};\r\n\r\ntype OptionsTemplateTypeMap = {\r\n __TPL_boolean_TYPE__: boolean;\r\n __TPL_number_TYPE__: number;\r\n __TPL_string_TYPE__: string;\r\n __TPL_array_TYPE__: Array | ReadonlyArray;\r\n __TPL_function_TYPE__: OptionsFunctionType;\r\n __TPL_null_TYPE__: null;\r\n __TPL_object_TYPE__: OptionsObjectType;\r\n};\r\n\r\ntype OptionsTemplateValueNonEnum =\r\n | OptionsTemplateType\r\n | [OptionsTemplateType, ...Array];\r\n\r\ntype ExtractPropsKey = {\r\n [P in keyof T]: TProps extends T[P] ? P : never;\r\n}[keyof T];\r\n\r\ntype OptionsTemplateTypesDictionary = {\r\n readonly boolean: OptionsTemplateType;\r\n readonly number: OptionsTemplateType;\r\n readonly string: OptionsTemplateType;\r\n readonly array: OptionsTemplateType>;\r\n readonly object: OptionsTemplateType;\r\n readonly function: OptionsTemplateType;\r\n readonly null: OptionsTemplateType;\r\n};\r\n\r\nconst { stringify } = JSON;\r\n\r\n/**\r\n * A prefix and suffix tuple which serves as recognition pattern for template types.\r\n */\r\nconst templateTypePrefixSuffix: readonly [string, string] = ['__TPL_', '_TYPE__'];\r\n\r\n/**\r\n * A object which serves as a mapping for \"normal\" types and template types.\r\n * Key = normal type string\r\n * value = template type string\r\n */\r\nconst optionsTemplateTypes: OptionsTemplateTypesDictionary = ['boolean', 'number', 'string', 'array', 'object', 'function', 'null'].reduce(\r\n (result, item) => {\r\n result[item] = templateTypePrefixSuffix[0] + item + templateTypePrefixSuffix[1];\r\n return result;\r\n },\r\n {} as OptionsTemplateTypesDictionary\r\n);\r\n\r\n/**\r\n * Validates the given options object according to the given template object and returns a object which looks like:\r\n * {\r\n * foreign : a object which consists of properties which aren't defined inside the template. (foreign properties)\r\n * validated : a object which consists only of valid properties. (property name is inside the template and value has a correct type)\r\n * }\r\n * @param options The options object which shall be validated.\r\n * @param template The template according to which the options object shall be validated.\r\n * @param optionsDiff When provided the returned validated object will only have properties which are different to this objects properties.\r\n * Example (assume all properties are valid to the template):\r\n * Options object : { a: 'a', b: 'b', c: 'c' }\r\n * optionsDiff object : { a: 'a', b: 'b', c: undefined }\r\n * Returned validated object : { c: 'c' }\r\n * Because the value of the properties a and b didn't change, they aren't included in the returned object.\r\n * Without the optionsDiff object the returned validated object would be: { a: 'a', b: 'b', c: 'c' }\r\n * @param doWriteErrors True if errors shall be logged into the console, false otherwise.\r\n * @param propPath The propertyPath which lead to this object. (used for error logging)\r\n */\r\nconst validateRecursive = (\r\n options: PartialOptions,\r\n template: OptionsTemplate,\r\n optionsDiff: T,\r\n doWriteErrors?: boolean,\r\n propPath?: string\r\n): OptionsValidationResult => {\r\n const validatedOptions: PartialOptions = {};\r\n const optionsCopy: PartialOptions = { ...options };\r\n const props = keys(template).filter((prop) => hasOwnProperty(options, prop));\r\n\r\n each(props, (prop: Extract) => {\r\n const optionsDiffValue: any = isUndefined(optionsDiff[prop]) ? {} : optionsDiff[prop];\r\n const optionsValue: any = options[prop];\r\n const templateValue: PlainObject | string | OptionsTemplateTypes | Array = template[prop];\r\n const templateIsComplex = isPlainObject(templateValue);\r\n const propPrefix = propPath ? `${propPath}.` : '';\r\n\r\n // if the template has a object as value, it means that the options are complex (verschachtelt)\r\n if (templateIsComplex && isPlainObject(optionsValue)) {\r\n const validatedResult = validateRecursive(optionsValue, templateValue as T, optionsDiffValue, doWriteErrors, propPrefix + prop);\r\n validatedOptions[prop] = validatedResult._validated as any;\r\n optionsCopy[prop] = validatedResult._foreign as any;\r\n\r\n each([optionsCopy, validatedOptions], (value) => {\r\n if (isEmptyObject(value[prop])) {\r\n delete value[prop];\r\n }\r\n });\r\n } else if (!templateIsComplex) {\r\n let isValid = false;\r\n const errorEnumStrings: Array = [];\r\n const errorPossibleTypes: Array = [];\r\n const optionsValueType = type(optionsValue);\r\n const templateValueArr: Array = !isArray(templateValue)\r\n ? [templateValue as string | OptionsTemplateTypes]\r\n : (templateValue as Array);\r\n\r\n each(templateValueArr, (currTemplateType) => {\r\n // if currType value isn't inside possibleTemplateTypes we assume its a enum string value\r\n let typeString: string | undefined;\r\n each(optionsTemplateTypes, (value: string, key: string) => {\r\n if (value === currTemplateType) {\r\n typeString = key;\r\n }\r\n });\r\n const isEnumString = isUndefined(typeString);\r\n if (isEnumString && isString(optionsValue)) {\r\n // split it into a array which contains all possible values for example: [\"yes\", \"no\", \"maybe\"]\r\n const enumStringSplit = currTemplateType.split(' ');\r\n isValid = !!enumStringSplit.find((possibility) => possibility === optionsValue);\r\n\r\n // build error message\r\n push(errorEnumStrings, enumStringSplit);\r\n } else {\r\n isValid = optionsTemplateTypes[optionsValueType] === currTemplateType;\r\n }\r\n\r\n // build error message\r\n push(errorPossibleTypes, isEnumString ? optionsTemplateTypes.string : typeString!);\r\n\r\n // continue if invalid, break if valid\r\n return !isValid;\r\n });\r\n\r\n if (isValid) {\r\n const doStringifyComparison = isArray(optionsValue) || isPlainObject(optionsValue);\r\n if (doStringifyComparison ? stringify(optionsValue) !== stringify(optionsDiffValue) : optionsValue !== optionsDiffValue) {\r\n validatedOptions[prop] = optionsValue;\r\n }\r\n } else if (doWriteErrors) {\r\n console.warn(\r\n `${\r\n `The option \"${propPrefix}${prop}\" wasn't set, because it doesn't accept the type [ ${optionsValueType.toUpperCase()} ] with the value of \"${optionsValue}\".\\r\\n` +\r\n `Accepted types are: [ ${errorPossibleTypes.join(', ').toUpperCase()} ].\\r\\n`\r\n }${errorEnumStrings.length > 0 ? `\\r\\nValid strings are: [ ${errorEnumStrings.join(', ')} ].` : ''}`\r\n );\r\n }\r\n\r\n delete optionsCopy[prop];\r\n }\r\n });\r\n\r\n return {\r\n _foreign: optionsCopy,\r\n _validated: validatedOptions,\r\n };\r\n};\r\n\r\n/**\r\n * Validates the given options object according to the given template object and returns a object which looks like:\r\n * {\r\n * foreign : a object which consists of properties which aren't defined inside the template. (foreign properties)\r\n * validated : a object which consists only of valid properties. (property name is inside the template and value has a correct type)\r\n * }\r\n * @param options The options object which shall be validated.\r\n * @param template The template according to which the options object shall be validated.\r\n * @param optionsDiff When provided the returned validated object will only have properties which are different to this objects properties.\r\n * Example (assume all properties are valid to the template):\r\n * Options object : { a: 'a', b: 'b', c: 'c' }\r\n * optionsDiff object : { a: 'a', b: 'b', c: undefined }\r\n * Returned validated object : { c: 'c' }\r\n * Because the value of the properties a and b didn't change, they aren't included in the returned object.\r\n * Without the optionsDiff object the returned validated object would be: { a: 'a', b: 'b', c: 'c' }\r\n * @param doWriteErrors True if errors shall be logged into the console, false otherwise.\r\n */\r\nconst validateOptions = (\r\n options: PartialOptions,\r\n template: OptionsTemplate,\r\n optionsDiff?: T | null,\r\n doWriteErrors?: boolean\r\n): OptionsValidationResult => {\r\n /*\r\n if (!isEmptyObject(foreign) && doWriteErrors)\r\n console.warn(`The following options are discarded due to invalidity:\\r\\n ${window.JSON.stringify(foreign, null, 2)}`);\r\n\r\n //add values, which aren't specified in the template, to the finished validated object to prevent them from being discarded\r\n if (keepForeignProps) {\r\n Object.assign(result.validated, foreign);\r\n }\r\n */\r\n return validateRecursive(options, template, optionsDiff || ({} as T), doWriteErrors || false);\r\n};\r\n\r\nexport { validateOptions, optionsTemplateTypes };\r\n","import {\r\n OptionsTemplate,\r\n OptionsObjectType,\r\n OptionsTemplateNativeTypes,\r\n OptionsTemplateTypes,\r\n OptionsTemplateValue,\r\n} from 'support/options/validation';\r\nimport { PlainObject } from 'typings';\r\nimport { isArray } from 'support/utils/types';\r\nimport { each, keys } from 'support/utils';\r\n\r\nexport interface OptionsWithOptionsTemplateTransformation {\r\n _template: OptionsTemplate;\r\n _options: T;\r\n}\r\n\r\nexport type OptionsWithOptionsTemplateValue = [T, OptionsTemplateValue];\r\n\r\nexport type OptionsWithOptionsTemplate = {\r\n [P in keyof T]: T[P] extends OptionsObjectType\r\n ? OptionsWithOptionsTemplate\r\n : T[P] extends OptionsTemplateNativeTypes\r\n ? OptionsWithOptionsTemplateValue\r\n : never;\r\n};\r\n\r\n/**\r\n * Transforms the given OptionsWithOptionsTemplate object to its corresponding generic (T) Object or its corresponding Template object.\r\n * @param optionsWithOptionsTemplate The OptionsWithOptionsTemplate object which shall be converted.\r\n * @param toTemplate True if the given OptionsWithOptionsTemplate shall be converted to its corresponding Template object.\r\n */\r\nexport const transformOptions = (optionsWithOptionsTemplate: OptionsWithOptionsTemplate): OptionsWithOptionsTemplateTransformation => {\r\n const result: any = {\r\n _template: {},\r\n _options: {},\r\n };\r\n\r\n each(keys(optionsWithOptionsTemplate), (key: Extract) => {\r\n const val: PlainObject | OptionsTemplateTypes | Array = optionsWithOptionsTemplate[key];\r\n\r\n if (isArray(val)) {\r\n result._template[key] = val[1];\r\n result._options[key] = val[0];\r\n } else {\r\n // if (isObject(val))\r\n const tmpResult = transformOptions(val as OptionsWithOptionsTemplate);\r\n result._template[key] = tmpResult._template;\r\n result._options[key] = tmpResult._options;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n","export const classNameEnvironment = 'os-environment';\r\nexport const classNameEnvironmentFlexboxGlue = `${classNameEnvironment}-flexbox-glue`;\r\nexport const classNameEnvironmentFlexboxGlueMax = `${classNameEnvironmentFlexboxGlue}-max`;\r\n\r\nexport const classNameHost = 'os-host';\r\nexport const classNamePadding = 'os-padding';\r\nexport const classNameViewport = 'os-viewport';\r\nexport const classNameViewportArrange = `${classNameViewport}-arrange`;\r\nexport const classNameContent = 'os-content';\r\nexport const classNameViewportScrollbarStyling = `${classNameViewport}-scrollbar-styled`;\r\n\r\nexport const classNameSizeObserver = 'os-size-observer';\r\nexport const classNameSizeObserverAppear = `${classNameSizeObserver}-appear`;\r\nexport const classNameSizeObserverListener = `${classNameSizeObserver}-listener`;\r\nexport const classNameSizeObserverListenerScroll = `${classNameSizeObserverListener}-scroll`;\r\nexport const classNameSizeObserverListenerItem = `${classNameSizeObserverListener}-item`;\r\nexport const classNameSizeObserverListenerItemFinal = `${classNameSizeObserverListenerItem}-final`;\r\n\r\nexport const classNameTrinsicObserver = 'os-trinsic-observer';\r\n","import {\r\n optionsTemplateTypes as oTypes,\r\n transformOptions,\r\n OptionsTemplateValue,\r\n OptionsWithOptionsTemplateValue,\r\n OptionsWithOptionsTemplate,\r\n} from 'support/options';\r\n\r\nexport type ResizeBehavior = 'none' | 'both' | 'horizontal' | 'vertical';\r\n\r\nexport type OverflowBehavior = 'hidden' | 'scroll' | 'visible' | 'visible-hidden';\r\n\r\nexport type VisibilityBehavior = 'visible' | 'hidden' | 'auto';\r\n\r\nexport type AutoHideBehavior = 'never' | 'scroll' | 'leave' | 'move';\r\n\r\nexport type ScrollBehavior = 'always' | 'ifneeded' | 'never';\r\n\r\nexport type BasicEventCallback = (this: any) => void;\r\n\r\nexport type ScrollEventCallback = (this: any, args?: UIEvent) => void;\r\n\r\nexport type OverflowChangedCallback = (this: any, args?: OverflowChangedArgs) => void;\r\n\r\nexport type OverflowAmountChangedCallback = (this: any, args?: OverflowAmountChangedArgs) => void;\r\n\r\nexport type DirectionChangedCallback = (this: any, args?: DirectionChangedArgs) => void;\r\n\r\nexport type SizeChangedCallback = (this: any, args?: SizeChangedArgs) => void;\r\n\r\nexport type UpdatedCallback = (this: any, args?: UpdatedArgs) => void;\r\n\r\nexport interface OSOptions {\r\n resize: ResizeBehavior;\r\n paddingAbsolute: boolean;\r\n updating: {\r\n elementEvents: Array<[string, string]> | null;\r\n attributes: string[] | null;\r\n debounce: number | [number, number] | null;\r\n };\r\n overflow: {\r\n x: OverflowBehavior;\r\n y: OverflowBehavior;\r\n };\r\n scrollbars: {\r\n visibility: VisibilityBehavior;\r\n autoHide: AutoHideBehavior;\r\n autoHideDelay: number;\r\n dragScroll: boolean;\r\n clickScroll: boolean;\r\n touch: boolean;\r\n };\r\n textarea: {\r\n dynWidth: boolean;\r\n dynHeight: boolean;\r\n inheritedAttrs: string | Array | null;\r\n };\r\n nativeScrollbarsOverlaid: {\r\n show: boolean;\r\n initialize: boolean;\r\n };\r\n callbacks: {\r\n onUpdated: (() => any) | null;\r\n };\r\n /*\r\n callbacks?: {\r\n onInitialized?: BasicEventCallback | null;\r\n onInitializationWithdrawn?: BasicEventCallback | null;\r\n onDestroyed?: BasicEventCallback | null;\r\n onScrollStart?: ScrollEventCallback | null;\r\n onScroll?: ScrollEventCallback | null;\r\n onScrollStop?: ScrollEventCallback | null;\r\n onOverflowChanged?: OverflowChangedCallback | null;\r\n onOverflowAmountChanged?: OverflowAmountChangedCallback | null;\r\n onDirectionChanged?: DirectionChangedCallback | null;\r\n onContentSizeChanged?: SizeChangedCallback | null;\r\n onHostSizeChanged?: SizeChangedCallback | null;\r\n onUpdated?: UpdatedCallback | null;\r\n };\r\n */\r\n}\r\n\r\nexport interface OverflowChangedArgs {\r\n x: boolean;\r\n y: boolean;\r\n xScrollable: boolean;\r\n yScrollable: boolean;\r\n clipped: boolean;\r\n}\r\n\r\nexport interface OverflowAmountChangedArgs {\r\n x: number;\r\n y: number;\r\n}\r\n\r\nexport interface DirectionChangedArgs {\r\n isRTL: number;\r\n dir: string;\r\n}\r\n\r\nexport interface SizeChangedArgs {\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport interface UpdatedArgs {\r\n forced: boolean;\r\n}\r\n\r\nconst numberAllowedValues: OptionsTemplateValue = oTypes.number;\r\nconst arrayNullValues: OptionsTemplateValue | null> = [oTypes.array, oTypes.null];\r\nconst stringArrayNullAllowedValues: OptionsTemplateValue | null> = [oTypes.string, oTypes.array, oTypes.null];\r\nconst booleanTrueTemplate: OptionsWithOptionsTemplateValue = [true, oTypes.boolean];\r\nconst booleanFalseTemplate: OptionsWithOptionsTemplateValue = [false, oTypes.boolean];\r\n// const callbackTemplate: OptionsWithOptionsTemplateValue = [null, [oTypes.function, oTypes.null]];\r\nconst resizeAllowedValues: OptionsTemplateValue = 'none both horizontal vertical';\r\nconst overflowAllowedValues: OptionsTemplateValue = 'hidden scroll visible visible-hidden';\r\nconst scrollbarsVisibilityAllowedValues: OptionsTemplateValue = 'visible hidden auto';\r\nconst scrollbarsAutoHideAllowedValues: OptionsTemplateValue = 'never scroll leavemove';\r\n\r\n/**\r\n * A object which serves as \"default options object\" and \"options template object\".\r\n * I combined these two into one object so that I don't have to define two separate big objects, instead I define one big object.\r\n *\r\n * The property value is a tuple:\r\n * the first value is the default value\r\n * the second value is the template value\r\n * Example:\r\n * {\r\n * a: ['default', [Type.string, Type.null]],\r\n * b: [250, Type.number]\r\n * }\r\n * Property \"a\" has a default value of 'default' and it can be a string or null\r\n * Property \"b\" has a default value of 250 and it can be number\r\n */\r\nconst defaultOptionsWithTemplate: OptionsWithOptionsTemplate = {\r\n resize: ['none', resizeAllowedValues], // none || both || horizontal || vertical || n || b || h || v\r\n paddingAbsolute: booleanFalseTemplate, // true || false\r\n updating: {\r\n elementEvents: [[['img', 'load']], arrayNullValues], // array of tuples || null\r\n attributes: [null, arrayNullValues],\r\n debounce: [\r\n [0, 33],\r\n [oTypes.number, oTypes.array, oTypes.null],\r\n ], // number || number array || null\r\n },\r\n overflow: {\r\n x: ['scroll', overflowAllowedValues], // visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s\r\n y: ['scroll', overflowAllowedValues], // visible-hidden || visible-scroll || hidden || scroll || v-h || v-s || h || s\r\n },\r\n scrollbars: {\r\n visibility: ['auto', scrollbarsVisibilityAllowedValues], // visible || hidden || auto || v || h || a\r\n autoHide: ['never', scrollbarsAutoHideAllowedValues], // never || scroll || leave || move || n || s || l || m\r\n autoHideDelay: [800, numberAllowedValues], // number\r\n dragScroll: booleanTrueTemplate, // true || false\r\n clickScroll: booleanFalseTemplate, // true || false\r\n touch: booleanTrueTemplate, // true || false\r\n },\r\n textarea: {\r\n dynWidth: booleanFalseTemplate, // true || false\r\n dynHeight: booleanFalseTemplate, // true || false\r\n inheritedAttrs: [['style', 'class'], stringArrayNullAllowedValues], // string || array || null\r\n },\r\n nativeScrollbarsOverlaid: {\r\n show: booleanFalseTemplate, // true || false\r\n initialize: booleanFalseTemplate, // true || false\r\n },\r\n callbacks: {\r\n onUpdated: [null, [oTypes.function, oTypes.null]],\r\n },\r\n /*\r\n callbacks: {\r\n onInitialized: callbackTemplate, // null || function\r\n onInitializationWithdrawn: callbackTemplate, // null || function\r\n onDestroyed: callbackTemplate, // null || function\r\n onScrollStart: callbackTemplate, // null || function\r\n onScroll: callbackTemplate, // null || function\r\n onScrollStop: callbackTemplate, // null || function\r\n onOverflowChanged: callbackTemplate, // null || function\r\n onOverflowAmountChanged: callbackTemplate, // null || function\r\n onDirectionChanged: callbackTemplate, // null || function\r\n onContentSizeChanged: callbackTemplate, // null || function\r\n onHostSizeChanged: callbackTemplate, // null || function\r\n onUpdated: callbackTemplate, // null || function\r\n },\r\n */\r\n};\r\n\r\nexport const { _template: optionsTemplate, _options: defaultOptions } = transformOptions(defaultOptionsWithTemplate);\r\n","import {\r\n createDOM,\r\n addClass,\r\n style,\r\n appendChildren,\r\n clientSize,\r\n absoluteCoordinates,\r\n offsetSize,\r\n scrollLeft,\r\n XY,\r\n removeAttr,\r\n removeElements,\r\n windowSize,\r\n runEach,\r\n equalBCRWH,\r\n getBoundingClientRect,\r\n assignDeep,\r\n cssProperty,\r\n PartialOptions,\r\n} from 'support';\r\nimport {\r\n classNameEnvironment,\r\n classNameEnvironmentFlexboxGlue,\r\n classNameEnvironmentFlexboxGlueMax,\r\n classNameViewportScrollbarStyling,\r\n} from 'classnames';\r\nimport { OSOptions, defaultOptions } from 'options';\r\n\r\nexport interface InitializationStrategy {\r\n _padding: boolean;\r\n _content: boolean;\r\n}\r\n\r\nexport type OnEnvironmentChanged = (env: Environment) => void;\r\nexport interface Environment {\r\n _nativeScrollbarSize: XY;\r\n _nativeScrollbarIsOverlaid: XY;\r\n _nativeScrollbarStyling: boolean;\r\n _rtlScrollBehavior: { n: boolean; i: boolean };\r\n _flexboxGlue: boolean;\r\n _cssCustomProperties: boolean;\r\n _addListener(listener: OnEnvironmentChanged): void;\r\n _removeListener(listener: OnEnvironmentChanged): void;\r\n _getInitializationStrategy(): InitializationStrategy;\r\n _setInitializationStrategy(newInitializationStrategy: Partial): void;\r\n _getDefaultOptions(): OSOptions;\r\n _setDefaultOptions(newDefaultOptions: PartialOptions): void;\r\n _defaultInitializationStrategy: InitializationStrategy;\r\n _defaultDefaultOptions: OSOptions;\r\n}\r\n\r\nlet environmentInstance: Environment;\r\nconst { abs, round } = Math;\r\n\r\nconst diffBiggerThanOne = (valOne: number, valTwo: number): boolean => {\r\n const absValOne = abs(valOne);\r\n const absValTwo = abs(valTwo);\r\n return !(absValOne === absValTwo || absValOne + 1 === absValTwo || absValOne - 1 === absValTwo);\r\n};\r\n\r\nconst getNativeScrollbarSize = (body: HTMLElement, measureElm: HTMLElement): XY => {\r\n appendChildren(body, measureElm);\r\n const cSize = clientSize(measureElm);\r\n const oSize = offsetSize(measureElm);\r\n\r\n return {\r\n x: oSize.h - cSize.h,\r\n y: oSize.w - cSize.w,\r\n };\r\n};\r\n\r\nconst getNativeScrollbarStyling = (testElm: HTMLElement): boolean => {\r\n let result = false;\r\n addClass(testElm, classNameViewportScrollbarStyling);\r\n try {\r\n result =\r\n style(testElm, cssProperty('scrollbar-width')) === 'none' ||\r\n window.getComputedStyle(testElm, '::-webkit-scrollbar').getPropertyValue('display') === 'none';\r\n } catch (ex) {}\r\n\r\n return result;\r\n};\r\n\r\nconst getRtlScrollBehavior = (parentElm: HTMLElement, childElm: HTMLElement): { i: boolean; n: boolean } => {\r\n const strHidden = 'hidden';\r\n style(parentElm, { overflowX: strHidden, overflowY: strHidden, direction: 'rtl' });\r\n scrollLeft(parentElm, 0);\r\n\r\n const parentOffset = absoluteCoordinates(parentElm);\r\n const childOffset = absoluteCoordinates(childElm);\r\n scrollLeft(parentElm, -999); // https://github.com/KingSora/OverlayScrollbars/issues/187\r\n const childOffsetAfterScroll = absoluteCoordinates(childElm);\r\n return {\r\n /**\r\n * origin direction = determines if the zero scroll position is on the left or right side\r\n * 'i' means 'invert' (i === true means that the axis must be inverted to be correct)\r\n * true = on the left side\r\n * false = on the right side\r\n */\r\n i: parentOffset.x === childOffset.x,\r\n /**\r\n * negative = determines if the maximum scroll is positive or negative\r\n * 'n' means 'negate' (n === true means that the axis must be negated to be correct)\r\n * true = negative\r\n * false = positive\r\n */\r\n n: childOffset.x !== childOffsetAfterScroll.x,\r\n };\r\n};\r\n\r\nconst getFlexboxGlue = (parentElm: HTMLElement, childElm: HTMLElement): boolean => {\r\n addClass(parentElm, classNameEnvironmentFlexboxGlue);\r\n const minOffsetsizeParent = getBoundingClientRect(parentElm);\r\n const minOffsetsize = getBoundingClientRect(childElm);\r\n const supportsMin = equalBCRWH(minOffsetsize, minOffsetsizeParent, true);\r\n\r\n addClass(parentElm, classNameEnvironmentFlexboxGlueMax);\r\n const maxOffsetsizeParent = getBoundingClientRect(parentElm);\r\n const maxOffsetsize = getBoundingClientRect(childElm);\r\n const supportsMax = equalBCRWH(maxOffsetsize, maxOffsetsizeParent, true);\r\n\r\n return supportsMin && supportsMax;\r\n};\r\n\r\nconst getWindowDPR = (): number => {\r\n // eslint-disable-next-line\r\n // @ts-ignore\r\n const dDPI = window.screen.deviceXDPI || 0;\r\n // eslint-disable-next-line\r\n // @ts-ignore\r\n const sDPI = window.screen.logicalXDPI || 1;\r\n return window.devicePixelRatio || dDPI / sDPI;\r\n};\r\n\r\nconst getDefaultInitializationStrategy = (nativeScrollbarStyling: boolean): InitializationStrategy => ({\r\n _padding: !nativeScrollbarStyling,\r\n _content: false,\r\n});\r\n\r\nconst createEnvironment = (): Environment => {\r\n const { body } = document;\r\n const envDOM = createDOM(``);\r\n const envElm = envDOM[0] as HTMLElement;\r\n const envChildElm = envElm.firstChild as HTMLElement;\r\n const onChangedListener: Set = new Set();\r\n const nativeScrollbarSize = getNativeScrollbarSize(body, envElm);\r\n const nativeScrollbarStyling = getNativeScrollbarStyling(envElm);\r\n const nativeScrollbarIsOverlaid = {\r\n x: nativeScrollbarSize.x === 0,\r\n y: nativeScrollbarSize.y === 0,\r\n };\r\n const defaultInitializationStrategy = getDefaultInitializationStrategy(nativeScrollbarStyling);\r\n let initializationStrategy = defaultInitializationStrategy;\r\n let defaultDefaultOptions = defaultOptions;\r\n\r\n const env: Environment = {\r\n _nativeScrollbarSize: nativeScrollbarSize,\r\n _nativeScrollbarIsOverlaid: nativeScrollbarIsOverlaid,\r\n _nativeScrollbarStyling: nativeScrollbarStyling,\r\n _cssCustomProperties: style(envElm, 'zIndex') === '-1',\r\n _rtlScrollBehavior: getRtlScrollBehavior(envElm, envChildElm),\r\n _flexboxGlue: getFlexboxGlue(envElm, envChildElm),\r\n _addListener(listener: OnEnvironmentChanged): void {\r\n onChangedListener.add(listener);\r\n },\r\n _removeListener(listener: OnEnvironmentChanged): void {\r\n onChangedListener.delete(listener);\r\n },\r\n _getInitializationStrategy: () => ({ ...initializationStrategy }),\r\n _setInitializationStrategy(newInitializationStrategy) {\r\n initializationStrategy = assignDeep({}, initializationStrategy, newInitializationStrategy);\r\n },\r\n _getDefaultOptions: () => ({ ...defaultDefaultOptions }),\r\n _setDefaultOptions(newDefaultOptions) {\r\n defaultDefaultOptions = assignDeep({}, defaultDefaultOptions, newDefaultOptions);\r\n },\r\n _defaultInitializationStrategy: defaultInitializationStrategy,\r\n _defaultDefaultOptions: defaultDefaultOptions,\r\n };\r\n\r\n removeAttr(envElm, 'style');\r\n removeElements(envElm);\r\n\r\n if (!nativeScrollbarStyling && (!nativeScrollbarIsOverlaid.x || !nativeScrollbarIsOverlaid.y)) {\r\n let size = windowSize();\r\n let dpr = getWindowDPR();\r\n let scrollbarSize = nativeScrollbarSize;\r\n\r\n window.addEventListener('resize', () => {\r\n if (onChangedListener.size) {\r\n const sizeNew = windowSize();\r\n const deltaSize = {\r\n w: sizeNew.w - size.w,\r\n h: sizeNew.h - size.h,\r\n };\r\n\r\n if (deltaSize.w === 0 && deltaSize.h === 0) return;\r\n\r\n const deltaAbsSize = {\r\n w: abs(deltaSize.w),\r\n h: abs(deltaSize.h),\r\n };\r\n const deltaAbsRatio = {\r\n w: abs(round(sizeNew.w / (size.w / 100.0))),\r\n h: abs(round(sizeNew.h / (size.h / 100.0))),\r\n };\r\n const dprNew = getWindowDPR();\r\n const deltaIsBigger = deltaAbsSize.w > 2 && deltaAbsSize.h > 2;\r\n const difference = !diffBiggerThanOne(deltaAbsRatio.w, deltaAbsRatio.h);\r\n const dprChanged = dprNew !== dpr && dpr > 0;\r\n const isZoom = deltaIsBigger && difference && dprChanged;\r\n\r\n if (isZoom) {\r\n const newScrollbarSize = (environmentInstance._nativeScrollbarSize = getNativeScrollbarSize(body, envElm));\r\n removeElements(envElm);\r\n\r\n if (scrollbarSize.x !== newScrollbarSize.x || scrollbarSize.y !== newScrollbarSize.y) {\r\n runEach(onChangedListener);\r\n }\r\n\r\n scrollbarSize = newScrollbarSize;\r\n }\r\n\r\n size = sizeNew;\r\n dpr = dprNew;\r\n }\r\n });\r\n }\r\n\r\n return env;\r\n};\r\n\r\nexport const getEnvironment = (): Environment => {\r\n if (!environmentInstance) {\r\n environmentInstance = createEnvironment();\r\n }\r\n return environmentInstance;\r\n};\r\n","import {\r\n isHTMLElement,\r\n appendChildren,\r\n is,\r\n createDiv,\r\n contents,\r\n insertAfter,\r\n addClass,\r\n parent,\r\n isUndefined,\r\n removeElements,\r\n removeClass,\r\n push,\r\n runEach,\r\n insertBefore,\r\n attr,\r\n isBoolean,\r\n} from 'support';\r\nimport {\r\n classNameHost,\r\n classNamePadding,\r\n classNameViewport,\r\n classNameViewportArrange,\r\n classNameContent,\r\n classNameViewportScrollbarStyling,\r\n} from 'classnames';\r\nimport { getEnvironment } from 'environment';\r\nimport { OSTarget, OSTargetObject, OSTargetElement } from 'typings';\r\n\r\nexport interface OSTargetContext {\r\n _isTextarea: boolean;\r\n _isBody: boolean;\r\n _htmlElm: HTMLHtmlElement;\r\n _bodyElm: HTMLBodyElement;\r\n _windowElm: Window;\r\n _documentElm: HTMLDocument;\r\n}\r\n\r\nexport interface PreparedOSTargetObject {\r\n _target: OSTargetElement;\r\n _host: HTMLElement;\r\n _viewport: HTMLElement;\r\n _padding: HTMLElement | false | null;\r\n _content: HTMLElement | false | null;\r\n _viewportArrange: HTMLStyleElement | false | null;\r\n}\r\n\r\nexport interface StructureSetup {\r\n _targetObj: PreparedOSTargetObject;\r\n _targetCtx: OSTargetContext;\r\n _destroy: () => void;\r\n}\r\n\r\nconst unwrap = (elm: HTMLElement | false | null | undefined) => {\r\n appendChildren(parent(elm), contents(elm));\r\n removeElements(elm);\r\n};\r\n\r\nlet contentArrangeCounter = 0;\r\nconst createUniqueViewportArrangeElement = (): HTMLStyleElement => {\r\n const elm = document.createElement('style');\r\n\r\n attr(elm, 'id', `${classNameViewportArrange}-${contentArrangeCounter}`);\r\n contentArrangeCounter++;\r\n\r\n return elm;\r\n};\r\nconst evaluateCreationFromStrategy = (initializationValue: HTMLElement | boolean | undefined, strategy: boolean): HTMLElement | false | undefined => {\r\n const isBooleanValue = isBoolean(initializationValue);\r\n if (isBooleanValue || isUndefined(initializationValue)) {\r\n return (isBooleanValue ? initializationValue : strategy) && undefined;\r\n }\r\n return initializationValue as HTMLElement;\r\n};\r\n\r\nexport const createStructureSetup = (target: OSTarget | OSTargetObject): StructureSetup => {\r\n const { _getInitializationStrategy, _nativeScrollbarStyling, _nativeScrollbarIsOverlaid, _cssCustomProperties } = getEnvironment();\r\n const { _padding: paddingNeeded, _content: contentNeeded } = _getInitializationStrategy();\r\n const targetIsElm = isHTMLElement(target);\r\n const osTargetObj: Partial = targetIsElm\r\n ? ({} as Partial)\r\n : {\r\n _host: (target as OSTargetObject).host,\r\n _target: (target as OSTargetObject).target,\r\n _viewport: (target as OSTargetObject).viewport,\r\n _padding: evaluateCreationFromStrategy((target as OSTargetObject).padding, paddingNeeded),\r\n _content: evaluateCreationFromStrategy((target as OSTargetObject).content, contentNeeded),\r\n };\r\n\r\n if (targetIsElm) {\r\n const viewport = createDiv(classNameViewport);\r\n const padding = paddingNeeded && createDiv(classNamePadding);\r\n const content = contentNeeded && createDiv(classNameContent);\r\n\r\n osTargetObj._target = target as OSTargetElement;\r\n osTargetObj._padding = padding;\r\n osTargetObj._viewport = viewport;\r\n osTargetObj._content = content;\r\n }\r\n\r\n let { _target, _padding, _viewport, _content } = osTargetObj;\r\n const destroyFns: (() => any)[] = [];\r\n const isTextarea = is(_target, 'textarea');\r\n const isBody = !isTextarea && is(_target, 'body');\r\n const _host = (isTextarea ? osTargetObj._host || createDiv() : _target) as HTMLElement;\r\n const getTargetContents = (contentSlot: HTMLElement) => (isTextarea ? (_target as HTMLTextAreaElement) : contents(contentSlot as HTMLElement));\r\n const isTextareaHostGenerated = isTextarea && _host !== osTargetObj._host;\r\n\r\n // only insert host for textarea after target if it was generated\r\n if (isTextareaHostGenerated) {\r\n insertAfter(_target, _host);\r\n\r\n push(destroyFns, () => {\r\n insertAfter(_host, _target);\r\n removeElements(_host);\r\n });\r\n }\r\n\r\n if (targetIsElm) {\r\n const contentSlot = _content || _viewport;\r\n appendChildren(contentSlot, getTargetContents(_target!));\r\n appendChildren(_host, _padding);\r\n appendChildren(_padding || _host, _viewport);\r\n appendChildren(_viewport, _content);\r\n\r\n push(destroyFns, () => {\r\n appendChildren(_host, contents(contentSlot));\r\n removeElements(_padding || _viewport);\r\n removeClass(_host, classNameHost);\r\n });\r\n } else {\r\n const contentContainingElm = _content || _viewport || _padding || _host;\r\n const createPadding = isUndefined(_padding);\r\n const createViewport = isUndefined(_viewport);\r\n const createContent = isUndefined(_content);\r\n const targetContents = getTargetContents(contentContainingElm);\r\n\r\n _padding = osTargetObj._padding = createPadding ? createDiv() : _padding;\r\n _viewport = osTargetObj._viewport = createViewport ? createDiv() : _viewport;\r\n _content = osTargetObj._content = createContent ? createDiv() : _content;\r\n\r\n appendChildren(_host, _padding);\r\n appendChildren(_padding || _host, _viewport);\r\n appendChildren(_viewport, _content);\r\n\r\n const contentSlot = _content || _viewport;\r\n appendChildren(contentSlot, targetContents);\r\n\r\n push(destroyFns, () => {\r\n if (createContent) {\r\n unwrap(_content);\r\n }\r\n if (createViewport) {\r\n unwrap(_viewport);\r\n }\r\n if (createPadding) {\r\n unwrap(_padding);\r\n }\r\n removeClass(_host, classNameHost);\r\n removeClass(_padding, classNamePadding);\r\n removeClass(_viewport, classNameViewport);\r\n removeClass(_content, classNameContent);\r\n });\r\n }\r\n\r\n addClass(_host, classNameHost);\r\n addClass(_padding, classNamePadding);\r\n addClass(_viewport, classNameViewport);\r\n addClass(_content, classNameContent);\r\n\r\n const ownerDocument: HTMLDocument = _target!.ownerDocument;\r\n const bodyElm = ownerDocument.body as HTMLBodyElement;\r\n const wnd = ownerDocument.defaultView as Window;\r\n const ctx: OSTargetContext = {\r\n _windowElm: wnd,\r\n _documentElm: ownerDocument,\r\n _htmlElm: parent(bodyElm) as HTMLHtmlElement,\r\n _bodyElm: bodyElm,\r\n _isTextarea: isTextarea,\r\n _isBody: isBody,\r\n };\r\n // @ts-ignore\r\n const obj: PreparedOSTargetObject = {\r\n ...osTargetObj,\r\n _host,\r\n };\r\n\r\n if (_nativeScrollbarStyling) {\r\n push(destroyFns, removeClass.bind(0, _viewport, classNameViewportScrollbarStyling));\r\n } else if (!_cssCustomProperties && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y)) {\r\n const viewportArrangeElm = createUniqueViewportArrangeElement();\r\n\r\n insertBefore(_viewport, viewportArrangeElm);\r\n push(destroyFns, removeElements.bind(0, viewportArrangeElm));\r\n\r\n obj._viewportArrange = viewportArrangeElm;\r\n }\r\n\r\n return {\r\n _targetObj: obj,\r\n _targetCtx: ctx,\r\n _destroy: () => {\r\n runEach(destroyFns);\r\n },\r\n };\r\n};\r\n","import {\r\n Cache,\r\n CacheValues,\r\n createCache,\r\n createDOM,\r\n style,\r\n appendChildren,\r\n offsetSize,\r\n scrollLeft,\r\n scrollTop,\r\n runEach,\r\n prependChildren,\r\n removeElements,\r\n on,\r\n stopAndPrevent,\r\n addClass,\r\n equalWH,\r\n push,\r\n cAF,\r\n rAF,\r\n ResizeObserverConstructor,\r\n isArray,\r\n isBoolean,\r\n removeClass,\r\n} from 'support';\r\nimport { getEnvironment } from 'environment';\r\nimport {\r\n classNameSizeObserver,\r\n classNameSizeObserverAppear,\r\n classNameSizeObserverListener,\r\n classNameSizeObserverListenerScroll,\r\n classNameSizeObserverListenerItem,\r\n classNameSizeObserverListenerItemFinal,\r\n} from 'classnames';\r\n\r\nexport interface SizeObserverOptions {\r\n _direction?: boolean;\r\n _appear?: boolean;\r\n}\r\n\r\nexport interface SizeObserverCallbackParams {\r\n _sizeChanged: boolean;\r\n _directionIsRTLCache?: CacheValues;\r\n _appear?: boolean;\r\n}\r\n\r\nexport interface SizeObserver {\r\n _destroy(): void;\r\n _getCurrentCacheValues(\r\n force?: boolean\r\n ): {\r\n _directionIsRTL: CacheValues;\r\n };\r\n}\r\n\r\n/*\r\nconst directionIsRTLMap = {\r\n direction: ['rtl'],\r\n 'writing-mode': ['sideways-rl', 'tb', 'tb-rl', 'vertical-rl'],\r\n};\r\nconst directionIsRTL = (elm: HTMLElement): boolean => {\r\n let isRTL = false;\r\n const styles = style(elm, ['direction', 'writing-mode']);\r\n each(styles, (value, key) => {\r\n isRTL = isRTL || indexOf(directionIsRTLMap[key], value) > -1;\r\n });\r\n return isRTL;\r\n};\r\n*/\r\nconst animationStartEventName = 'animationstart';\r\nconst scrollEventName = 'scroll';\r\nconst scrollAmount = 3333333;\r\nconst directionIsRTL = (elm: HTMLElement): boolean => style(elm, 'direction') === 'rtl';\r\nconst domRectHasDimensions = (rect?: DOMRectReadOnly) => rect && (rect.height || rect.width);\r\n\r\n/**\r\n * Creates a size observer which observes any size, padding, border, margin and box-sizing changes of the target element. Depending on the options also direction and appear can be observed.\r\n * @param target The target element which shall be observed.\r\n * @param onSizeChangedCallback The callback which gets called after a size change was detected.\r\n * @param options The options for size detection, whether to observe also direction and appear.\r\n * @returns A object which represents the instance of the size observer.\r\n */\r\nexport const createSizeObserver = (\r\n target: HTMLElement,\r\n onSizeChangedCallback: (params: SizeObserverCallbackParams) => any,\r\n options?: SizeObserverOptions\r\n): SizeObserver => {\r\n const { _direction: observeDirectionChange = false, _appear: observeAppearChange = false } = options || {};\r\n const { _rtlScrollBehavior: rtlScrollBehavior } = getEnvironment();\r\n const baseElements = createDOM(``);\r\n const sizeObserver = baseElements[0] as HTMLElement;\r\n const listenerElement = sizeObserver.firstChild as HTMLElement;\r\n const { _update: updateResizeObserverContentRectCache } = createCache(0, {\r\n _alwaysUpdateValues: true,\r\n _equal: (currVal, newVal) =>\r\n !(\r\n !currVal || // if no initial value\r\n // if from display: none to display: block\r\n (!domRectHasDimensions(currVal) && domRectHasDimensions(newVal))\r\n ),\r\n });\r\n const onSizeChangedCallbackProxy = (sizeChangedContext?: CacheValues | ResizeObserverEntry[] | Event | boolean) => {\r\n const hasDirectionCache = sizeChangedContext && isBoolean((sizeChangedContext as CacheValues)._value);\r\n\r\n let skip = false;\r\n let appear: boolean | number | undefined = false;\r\n let doDirectionScroll = true; // always true if sizeChangedContext is Event (appear callback or RO. Polyfill)\r\n\r\n // if triggered from RO.\r\n if (isArray(sizeChangedContext) && sizeChangedContext.length > 0) {\r\n const { _previous, _value } = updateResizeObserverContentRectCache(0, sizeChangedContext.pop()!.contentRect);\r\n const hasDimensions = domRectHasDimensions(_value);\r\n const hadDimensions = domRectHasDimensions(_previous);\r\n skip = !_previous || !hasDimensions; // skip on initial RO. call or if display is none\r\n appear = !hadDimensions && hasDimensions;\r\n\r\n doDirectionScroll = !skip; // direction scroll when not skipping\r\n }\r\n // else if its triggered with DirectionCache\r\n else if (hasDirectionCache) {\r\n doDirectionScroll = (sizeChangedContext as CacheValues)._changed; // direction scroll when DirectionCache changed, false otherwise\r\n }\r\n // else if it triggered with appear from polyfill\r\n else {\r\n appear = sizeChangedContext === true;\r\n }\r\n\r\n if (observeDirectionChange && doDirectionScroll) {\r\n const rtl = hasDirectionCache ? (sizeChangedContext as CacheValues)._value : directionIsRTL(sizeObserver);\r\n scrollLeft(sizeObserver, rtl ? (rtlScrollBehavior.n ? -scrollAmount : rtlScrollBehavior.i ? 0 : scrollAmount) : scrollAmount);\r\n scrollTop(sizeObserver, scrollAmount);\r\n }\r\n\r\n if (!skip) {\r\n onSizeChangedCallback({\r\n _sizeChanged: !hasDirectionCache,\r\n _directionIsRTLCache: hasDirectionCache ? (sizeChangedContext as CacheValues) : undefined,\r\n _appear: !!appear,\r\n });\r\n }\r\n };\r\n const offListeners: (() => void)[] = [];\r\n let appearCallback: ((...args: any) => any) | false = observeAppearChange ? onSizeChangedCallbackProxy : false;\r\n let directionIsRTLCache: Cache | undefined;\r\n\r\n if (ResizeObserverConstructor) {\r\n const resizeObserverInstance = new ResizeObserverConstructor(onSizeChangedCallbackProxy);\r\n resizeObserverInstance.observe(listenerElement);\r\n push(offListeners, () => {\r\n resizeObserverInstance.disconnect();\r\n });\r\n } else {\r\n const observerElementChildren = createDOM(\r\n ``\r\n );\r\n appendChildren(listenerElement, observerElementChildren);\r\n addClass(listenerElement, classNameSizeObserverListenerScroll);\r\n const observerElementChildrenRoot = observerElementChildren[0] as HTMLElement;\r\n const shrinkElement = observerElementChildrenRoot.lastChild as HTMLElement;\r\n const expandElement = observerElementChildrenRoot.firstChild as HTMLElement;\r\n const expandElementChild = expandElement?.firstChild as HTMLElement;\r\n\r\n let cacheSize = offsetSize(observerElementChildrenRoot);\r\n let currSize = cacheSize;\r\n let isDirty = false;\r\n let rAFId: number;\r\n\r\n const reset = () => {\r\n scrollLeft(expandElement, scrollAmount);\r\n scrollTop(expandElement, scrollAmount);\r\n scrollLeft(shrinkElement, scrollAmount);\r\n scrollTop(shrinkElement, scrollAmount);\r\n };\r\n const onResized = (appear?: unknown) => {\r\n rAFId = 0;\r\n if (isDirty) {\r\n cacheSize = currSize;\r\n onSizeChangedCallbackProxy(appear === true);\r\n }\r\n };\r\n const onScroll = (scrollEvent?: Event | false) => {\r\n currSize = offsetSize(observerElementChildrenRoot);\r\n isDirty = !scrollEvent || !equalWH(currSize, cacheSize);\r\n\r\n if (scrollEvent) {\r\n stopAndPrevent(scrollEvent);\r\n\r\n if (isDirty && !rAFId) {\r\n cAF!(rAFId);\r\n rAFId = rAF!(onResized);\r\n }\r\n } else {\r\n onResized(scrollEvent === false);\r\n }\r\n\r\n reset();\r\n };\r\n\r\n push(offListeners, [on(expandElement, scrollEventName, onScroll), on(shrinkElement, scrollEventName, onScroll)]);\r\n\r\n // lets assume that the divs will never be that large and a constant value is enough\r\n style(expandElementChild, {\r\n width: scrollAmount,\r\n height: scrollAmount,\r\n });\r\n\r\n reset();\r\n\r\n appearCallback = observeAppearChange ? onScroll.bind(0, false) : reset;\r\n }\r\n\r\n if (observeDirectionChange) {\r\n directionIsRTLCache = createCache(directionIsRTL.bind(0, sizeObserver));\r\n const { _update: updateDirectionIsRTLCache } = directionIsRTLCache;\r\n push(\r\n offListeners,\r\n on(sizeObserver, scrollEventName, (event: Event) => {\r\n const directionIsRTLCacheValues = updateDirectionIsRTLCache();\r\n console.log;\r\n const { _value, _changed } = directionIsRTLCacheValues;\r\n if (_changed) {\r\n removeClass(listenerElement, 'ltr rtl');\r\n if (_value) {\r\n addClass(listenerElement, 'rtl');\r\n } else {\r\n addClass(listenerElement, 'ltr');\r\n }\r\n onSizeChangedCallbackProxy(directionIsRTLCacheValues);\r\n }\r\n\r\n stopAndPrevent(event);\r\n })\r\n );\r\n }\r\n\r\n // appearCallback is always needed on scroll-observer strategy to reset it\r\n if (appearCallback) {\r\n addClass(sizeObserver, classNameSizeObserverAppear);\r\n push(\r\n offListeners,\r\n on(sizeObserver, animationStartEventName, appearCallback, {\r\n // Fire only once for \"CSS is ready\" event if ResizeObserver strategy is used\r\n _once: !!ResizeObserverConstructor,\r\n })\r\n );\r\n }\r\n\r\n prependChildren(target, sizeObserver);\r\n\r\n return {\r\n _destroy() {\r\n runEach(offListeners);\r\n removeElements(sizeObserver);\r\n },\r\n _getCurrentCacheValues(force?: boolean) {\r\n return {\r\n _directionIsRTL: directionIsRTLCache\r\n ? directionIsRTLCache._current(force)\r\n : {\r\n _value: false,\r\n _previous: false,\r\n _changed: false,\r\n },\r\n };\r\n },\r\n };\r\n};\r\n","import {\r\n WH,\r\n CacheValues,\r\n createDiv,\r\n offsetSize,\r\n runEach,\r\n prependChildren,\r\n removeElements,\r\n createCache,\r\n push,\r\n IntersectionObserverConstructor,\r\n} from 'support';\r\nimport { createSizeObserver } from 'observers/sizeObserver';\r\nimport { classNameTrinsicObserver } from 'classnames';\r\n\r\nexport interface TrinsicObserver {\r\n _destroy(): void;\r\n _getCurrentCacheValues(\r\n force?: boolean\r\n ): {\r\n _heightIntrinsic: CacheValues;\r\n };\r\n}\r\n\r\n/**\r\n * Creates a trinsic observer which observes changes to intrinsic or extrinsic sizing for the height of the target element.\r\n * @param target The element which shall be observed.\r\n * @param onTrinsicChangedCallback The callback which gets called after a change was detected.\r\n * @returns A object which represents the instance of the trinsic observer.\r\n */\r\nexport const createTrinsicObserver = (\r\n target: HTMLElement,\r\n onTrinsicChangedCallback: (heightIntrinsic: CacheValues) => any\r\n): TrinsicObserver => {\r\n const trinsicObserver = createDiv(classNameTrinsicObserver);\r\n const offListeners: (() => void)[] = [];\r\n const { _update: updateHeightIntrinsicCache, _current: getCurrentHeightIntrinsicCache } = createCache<\r\n boolean,\r\n IntersectionObserverEntry | WH\r\n >(\r\n (ioEntryOrSize: IntersectionObserverEntry | WH) =>\r\n (ioEntryOrSize! as WH).h === 0 ||\r\n (ioEntryOrSize! as IntersectionObserverEntry).isIntersecting ||\r\n (ioEntryOrSize! as IntersectionObserverEntry).intersectionRatio > 0,\r\n {\r\n _initialValue: false,\r\n }\r\n );\r\n\r\n if (IntersectionObserverConstructor) {\r\n const intersectionObserverInstance: IntersectionObserver = new IntersectionObserverConstructor(\r\n (entries: IntersectionObserverEntry[]) => {\r\n if (entries && entries.length > 0) {\r\n const last = entries.pop();\r\n if (last) {\r\n const heightIntrinsic = updateHeightIntrinsicCache(0, last);\r\n\r\n if (heightIntrinsic._changed) {\r\n onTrinsicChangedCallback(heightIntrinsic);\r\n }\r\n }\r\n }\r\n },\r\n { root: target }\r\n );\r\n intersectionObserverInstance.observe(trinsicObserver);\r\n push(offListeners, () => {\r\n intersectionObserverInstance.disconnect();\r\n });\r\n } else {\r\n const onSizeChanged = () => {\r\n const newSize = offsetSize(trinsicObserver);\r\n const heightIntrinsicCache = updateHeightIntrinsicCache(0, newSize);\r\n if (heightIntrinsicCache._changed) {\r\n onTrinsicChangedCallback(heightIntrinsicCache);\r\n }\r\n };\r\n push(offListeners, createSizeObserver(trinsicObserver, onSizeChanged)._destroy);\r\n onSizeChanged();\r\n }\r\n\r\n prependChildren(target, trinsicObserver);\r\n\r\n return {\r\n _destroy() {\r\n runEach(offListeners);\r\n removeElements(trinsicObserver);\r\n },\r\n _getCurrentCacheValues(force?: boolean) {\r\n return {\r\n _heightIntrinsic: getCurrentHeightIntrinsicCache(force),\r\n };\r\n },\r\n };\r\n};\r\n","import {\r\n each,\r\n noop,\r\n debounce,\r\n indexOf,\r\n isString,\r\n MutationObserverConstructor,\r\n isEmptyArray,\r\n on,\r\n off,\r\n attr,\r\n is,\r\n find,\r\n push,\r\n isUndefined,\r\n} from 'support';\r\n\r\ntype StringNullUndefined = string | null | undefined;\r\n\r\ntype DOMContentObserverCallback = (contentChangedTroughEvent: boolean) => any;\r\n\r\ntype DOMTargetObserverCallback = (targetChangedAttrs: string[], targetStyleChanged: boolean) => any;\r\n\r\ninterface DOMObserverOptionsBase {\r\n _attributes?: string[];\r\n _styleChangingAttributes?: string[];\r\n}\r\n\r\ninterface DOMContentObserverOptions extends DOMObserverOptionsBase {\r\n _eventContentChange?: DOMObserverEventContentChange; // [selector, eventname(s) | function returning eventname(s)] -> eventnames divided by whitespaces\r\n _nestedTargetSelector?: string;\r\n _ignoreContentChange?: DOMObserverIgnoreContentChange; // function which will prevent marking certain dom changes as content change if it returns true\r\n _ignoreNestedTargetChange?: DOMObserverIgnoreTargetChange; // a function which will prevent marking certain attributes as changed on nested targets if it returns true\r\n}\r\n\r\ninterface DOMTargetObserverOptions extends DOMObserverOptionsBase {\r\n _ignoreTargetChange?: DOMObserverIgnoreTargetChange; // a function which will prevent marking certain attributes as changed if it returns true\r\n}\r\n\r\ntype ContentChangeArrayItem = [StringNullUndefined, StringNullUndefined] | null | undefined;\r\n\r\nexport type DOMObserverEventContentChange = Array | false | null | undefined;\r\n\r\nexport type DOMObserverIgnoreContentChange = (\r\n mutation: MutationRecord,\r\n isNestedTarget: boolean,\r\n domObserverTarget: HTMLElement,\r\n domObserverOptions?: DOMContentObserverOptions\r\n) => boolean;\r\n\r\nexport type DOMObserverIgnoreTargetChange = (\r\n target: Node,\r\n attributeName: string,\r\n oldAttributeValue: string | null,\r\n newAttributeValue: string | null\r\n) => boolean;\r\n\r\nexport type DOMObserverCallback = ContentObserver extends true\r\n ? DOMContentObserverCallback\r\n : DOMTargetObserverCallback;\r\n\r\nexport type DOMObserverOptions = ContentObserver extends true ? DOMContentObserverOptions : DOMTargetObserverOptions;\r\n\r\nexport interface DOMObserver {\r\n _destroy: () => void;\r\n _update: () => void;\r\n}\r\n\r\n/**\r\n * Creates a set of helper functions to observe events of elements inside the target element.\r\n * @param target The target element of which the children elements shall be observed. (not only direct children but also nested ones)\r\n * @param eventContentChange The event content change array. (array of tuples: selector and eventname(s))\r\n * @param callback Callback which is called if one of the elements emits the corresponding event.\r\n * @returns A object which contains a set of helper functions to destroy and update the observation of elements.\r\n */\r\nconst createEventContentChange = (target: Element, eventContentChange: DOMObserverEventContentChange, callback: (...args: any) => any) => {\r\n let map: Map | undefined;\r\n const _destroy = () => {\r\n if (map) {\r\n map.forEach((eventName: string, elm: Node) => {\r\n off(elm, eventName, callback);\r\n });\r\n map.clear();\r\n }\r\n };\r\n const _updateElements = (getElements?: (selector: string) => Node[]) => {\r\n if (map && eventContentChange) {\r\n const eventElmList = eventContentChange.reduce>((arr, item) => {\r\n if (item) {\r\n const selector = item[0];\r\n const eventNames = item[1];\r\n const elements = eventNames && selector && (getElements ? getElements(selector) : find(selector, target));\r\n\r\n if (elements && elements.length && eventNames && isString(eventNames)) {\r\n push(arr, [elements, eventNames.trim()], true);\r\n }\r\n }\r\n return arr;\r\n }, []);\r\n\r\n each(eventElmList, (item) =>\r\n each(item[0], (elm) => {\r\n const eventNames = item[1];\r\n const registredEventNames = map!.get(elm);\r\n const newEntry = isUndefined(registredEventNames);\r\n const changingExistingEntry = !newEntry && eventNames !== registredEventNames;\r\n const finalEventNames = changingExistingEntry ? `${registredEventNames} ${eventNames}` : eventNames;\r\n\r\n if (changingExistingEntry) {\r\n off(elm, registredEventNames!, callback);\r\n }\r\n\r\n map!.set(elm, finalEventNames);\r\n on(elm, finalEventNames, callback);\r\n })\r\n );\r\n }\r\n };\r\n\r\n if (eventContentChange) {\r\n map = map || new Map();\r\n _destroy();\r\n _updateElements();\r\n }\r\n\r\n return {\r\n _destroy,\r\n _updateElements,\r\n };\r\n};\r\n\r\n/**\r\n * Creates a DOM observer which observes DOM changes to either the target element or its children.\r\n * @param target The element which shall be observed.\r\n * @param isContentObserver Whether this observer is just observing the target or just the targets children. (not only direct children but also nested ones)\r\n * @param callback The callback which gets called if a change was detected.\r\n * @param options The options for DOM change detection.\r\n * @returns A object which represents the instance of the DOM observer.\r\n */\r\nexport const createDOMObserver = (\r\n target: HTMLElement,\r\n isContentObserver: ContentObserver,\r\n callback: DOMObserverCallback,\r\n options?: DOMObserverOptions\r\n): DOMObserver => {\r\n let isConnected = false;\r\n const {\r\n _attributes,\r\n _styleChangingAttributes,\r\n _eventContentChange,\r\n _nestedTargetSelector,\r\n _ignoreTargetChange,\r\n _ignoreNestedTargetChange,\r\n _ignoreContentChange,\r\n } = (options as DOMContentObserverOptions & DOMTargetObserverOptions) || {};\r\n const { _destroy: destroyEventContentChange, _updateElements: updateEventContentChangeElements } = createEventContentChange(\r\n target,\r\n isContentObserver && _eventContentChange,\r\n debounce(\r\n () => {\r\n if (isConnected) {\r\n (callback as DOMContentObserverCallback)(true);\r\n }\r\n },\r\n { _timeout: 33, _maxDelay: 99 }\r\n )\r\n );\r\n\r\n // MutationObserver\r\n const finalAttributes = _attributes || [];\r\n const finalStyleChangingAttributes = _styleChangingAttributes || [];\r\n const observedAttributes = finalAttributes.concat(finalStyleChangingAttributes);\r\n const observerCallback = (mutations: MutationRecord[]) => {\r\n const ignoreTargetChange = (isContentObserver ? _ignoreNestedTargetChange : _ignoreTargetChange) || noop;\r\n const ignoreContentChange = _ignoreContentChange || noop;\r\n const targetChangedAttrs: string[] = [];\r\n const totalAddedNodes: Node[] = [];\r\n let targetStyleChanged = false;\r\n let contentChanged = false;\r\n let childListChanged = false;\r\n each(mutations, (mutation) => {\r\n const { attributeName, target: mutationTarget, type, oldValue, addedNodes } = mutation;\r\n const isAttributesType = type === 'attributes';\r\n const isChildListType = type === 'childList';\r\n const targetIsMutationTarget = target === mutationTarget;\r\n const attributeValue = isAttributesType && isString(attributeName) ? attr(mutationTarget as HTMLElement, attributeName!) : 0;\r\n const attributeChanged = attributeValue !== 0 && oldValue !== attributeValue;\r\n const styleChangingAttrChanged = indexOf(finalStyleChangingAttributes, attributeName) > -1 && attributeChanged;\r\n\r\n // if is content observer and something changed in children\r\n if (isContentObserver && !targetIsMutationTarget) {\r\n const notOnlyAttrChanged = !isAttributesType;\r\n const contentAttrChanged = isAttributesType && styleChangingAttrChanged;\r\n const isNestedTarget = contentAttrChanged && _nestedTargetSelector && is(mutationTarget, _nestedTargetSelector);\r\n const baseAssertion = isNestedTarget\r\n ? !ignoreTargetChange(mutationTarget, attributeName!, oldValue, attributeValue as string | null)\r\n : notOnlyAttrChanged || contentAttrChanged;\r\n const contentFinalChanged = baseAssertion && !ignoreContentChange(mutation, !!isNestedTarget, target, options);\r\n\r\n push(totalAddedNodes, addedNodes);\r\n\r\n contentChanged = contentChanged || contentFinalChanged;\r\n childListChanged = childListChanged || isChildListType;\r\n }\r\n // if is target observer and target attr changed\r\n if (\r\n !isContentObserver &&\r\n targetIsMutationTarget &&\r\n attributeChanged &&\r\n !ignoreTargetChange(mutationTarget, attributeName!, oldValue, attributeValue as string | null)\r\n ) {\r\n push(targetChangedAttrs, attributeName!);\r\n targetStyleChanged = targetStyleChanged || styleChangingAttrChanged;\r\n }\r\n });\r\n\r\n if (childListChanged && !isEmptyArray(totalAddedNodes)) {\r\n // adds / removes the new elements from the event content change\r\n updateEventContentChangeElements((selector) =>\r\n totalAddedNodes.reduce((arr, node) => {\r\n push(arr, find(selector, node));\r\n return is(node, selector) ? push(arr, node) : arr;\r\n }, [])\r\n );\r\n }\r\n\r\n if (isContentObserver) {\r\n contentChanged && (callback as DOMContentObserverCallback)(false);\r\n } else if (!isEmptyArray(targetChangedAttrs) || targetStyleChanged) {\r\n (callback as DOMTargetObserverCallback)(targetChangedAttrs, targetStyleChanged);\r\n }\r\n };\r\n const mutationObserver: MutationObserver = new MutationObserverConstructor!(observerCallback);\r\n\r\n // Connect\r\n mutationObserver.observe(target, {\r\n attributes: true,\r\n attributeOldValue: true,\r\n attributeFilter: observedAttributes,\r\n subtree: isContentObserver,\r\n childList: isContentObserver,\r\n characterData: isContentObserver,\r\n });\r\n isConnected = true;\r\n\r\n return {\r\n _destroy: () => {\r\n if (isConnected) {\r\n destroyEventContentChange();\r\n mutationObserver.disconnect();\r\n isConnected = false;\r\n }\r\n },\r\n _update: () => {\r\n if (isConnected) {\r\n observerCallback(mutationObserver.takeRecords());\r\n }\r\n },\r\n };\r\n};\r\n","import { CacheValues, diffClass, debounce, isArray, isNumber, each, indexOf, isString, attr, removeAttr } from 'support';\r\nimport { getEnvironment } from 'environment';\r\nimport { createSizeObserver, SizeObserverCallbackParams } from 'observers/sizeObserver';\r\nimport { createTrinsicObserver } from 'observers/trinsicObserver';\r\nimport { createDOMObserver, DOMObserver } from 'observers/domObserver';\r\nimport { LifecycleHub, LifecycleCheckOption, LifecycleUpdateHints } from 'lifecycles/lifecycleHub';\r\n\r\n//const hostSelector = `.${classNameHost}`;\r\n\r\n// TODO: observer textarea attrs if textarea\r\n// TODO: test _ignoreContentChange & _ignoreNestedTargetChange for content dom observer\r\n// TODO: test _ignoreTargetChange for target dom observer\r\n\r\n//const viewportSelector = `.${classNameViewport}`;\r\n//const contentSelector = `.${classNameContent}`;\r\nconst ignorePrefix = 'os-';\r\nconst viewportAttrsFromTarget = ['tabindex'];\r\nconst baseStyleChangingAttrsTextarea = ['wrap', 'cols', 'rows'];\r\nconst baseStyleChangingAttrs = ['id', 'class', 'style', 'open'];\r\n\r\nconst ignoreTargetChange = (target: Node, attrName: string, oldValue: string | null, newValue: string | null) => {\r\n if (attrName === 'class' && oldValue && newValue) {\r\n const diff = diffClass(oldValue, newValue);\r\n return !!diff.find((addedOrRemovedClass) => addedOrRemovedClass.indexOf(ignorePrefix) !== 0);\r\n }\r\n return false;\r\n};\r\n\r\nexport const lifecycleHubOservers = (instance: LifecycleHub, updateLifecycles: (updateHints?: Partial | null) => unknown) => {\r\n let debounceTimeout: number | false | undefined;\r\n let debounceMaxDelay: number | false | undefined;\r\n let contentMutationObserver: DOMObserver | undefined;\r\n const { _structureSetup } = instance;\r\n const { _targetObj, _targetCtx } = _structureSetup;\r\n const { _host, _viewport, _content } = _targetObj;\r\n const { _isTextarea } = _targetCtx;\r\n const { _nativeScrollbarStyling, _flexboxGlue } = getEnvironment();\r\n const contentMutationObserverAttr = _isTextarea ? baseStyleChangingAttrsTextarea : baseStyleChangingAttrs.concat(baseStyleChangingAttrsTextarea);\r\n const updateLifecyclesWithDebouncedAdaptiveUpdateHints = debounce(updateLifecycles as (updateHints: Partial) => any, {\r\n _timeout: () => debounceTimeout,\r\n _maxDelay: () => debounceMaxDelay,\r\n _mergeParams(prev, curr) {\r\n const { _sizeChanged: prevSizeChanged, _hostMutation: prevHostMutation, _contentMutation: prevContentMutation } = prev[0];\r\n const { _sizeChanged: currSizeChanged, _hostMutation: currvHostMutation, _contentMutation: currContentMutation } = curr[0];\r\n const merged: [Partial] = [\r\n {\r\n _sizeChanged: prevSizeChanged || currSizeChanged,\r\n _hostMutation: prevHostMutation || currvHostMutation,\r\n _contentMutation: prevContentMutation || currContentMutation,\r\n },\r\n ];\r\n\r\n return merged;\r\n },\r\n });\r\n\r\n const updateViewportAttrsFromHost = (attributes?: string[]) => {\r\n each(attributes || viewportAttrsFromTarget, (attribute) => {\r\n if (indexOf(viewportAttrsFromTarget, attribute) > -1) {\r\n const hostAttr = attr(_host, attribute);\r\n if (isString(hostAttr)) {\r\n attr(_viewport, attribute, hostAttr);\r\n } else {\r\n removeAttr(_viewport, attribute);\r\n }\r\n }\r\n });\r\n };\r\n const onTrinsicChanged = (heightIntrinsic: CacheValues) => {\r\n updateLifecycles({\r\n _heightIntrinsic: heightIntrinsic,\r\n });\r\n };\r\n const onSizeChanged = ({ _sizeChanged, _directionIsRTLCache, _appear }: SizeObserverCallbackParams) => {\r\n const updateFn = !_sizeChanged || _appear ? updateLifecycles : updateLifecyclesWithDebouncedAdaptiveUpdateHints;\r\n updateFn({\r\n _sizeChanged,\r\n _directionIsRTL: _directionIsRTLCache,\r\n });\r\n };\r\n const onContentMutation = (contentChangedTroughEvent: boolean) => {\r\n // if contentChangedTroughEvent is true its already debounced\r\n const updateFn = contentChangedTroughEvent ? updateLifecycles : updateLifecyclesWithDebouncedAdaptiveUpdateHints;\r\n updateFn({\r\n _contentMutation: true,\r\n });\r\n };\r\n const onHostMutation = (targetChangedAttrs: string[], targetStyleChanged: boolean) => {\r\n if (targetStyleChanged) {\r\n updateLifecyclesWithDebouncedAdaptiveUpdateHints({\r\n _hostMutation: true,\r\n });\r\n } else {\r\n updateViewportAttrsFromHost(targetChangedAttrs);\r\n }\r\n };\r\n\r\n const trinsicObserver = (_content || !_flexboxGlue) && createTrinsicObserver(_host, onTrinsicChanged);\r\n const sizeObserver = createSizeObserver(_host, onSizeChanged, { _appear: true, _direction: !_nativeScrollbarStyling });\r\n const hostMutationObserver = createDOMObserver(_host, false, onHostMutation, {\r\n _styleChangingAttributes: baseStyleChangingAttrs,\r\n _attributes: baseStyleChangingAttrs.concat(viewportAttrsFromTarget),\r\n _ignoreTargetChange: ignoreTargetChange,\r\n });\r\n\r\n const updateOptions = (checkOption: LifecycleCheckOption) => {\r\n const { _value: elementEvents, _changed: elementEventsChanged } = checkOption | null>('updating.elementEvents');\r\n const { _value: attributes, _changed: attributesChanged } = checkOption('updating.attributes');\r\n const { _value: debounce, _changed: debounceChanged } = checkOption | number | null>('updating.debounce');\r\n const updateContentMutationObserver = elementEventsChanged || attributesChanged;\r\n\r\n if (updateContentMutationObserver) {\r\n if (contentMutationObserver) {\r\n contentMutationObserver._update();\r\n contentMutationObserver._destroy();\r\n }\r\n contentMutationObserver = createDOMObserver(_content || _viewport, true, onContentMutation, {\r\n _styleChangingAttributes: contentMutationObserverAttr.concat(attributes || []),\r\n _attributes: contentMutationObserverAttr.concat(attributes || []),\r\n _eventContentChange: elementEvents,\r\n _ignoreNestedTargetChange: ignoreTargetChange,\r\n //_nestedTargetSelector: hostSelector,\r\n /*\r\n _ignoreContentChange: (mutation, isNestedTarget) => {\r\n const { target, attributeName } = mutation;\r\n return isNestedTarget\r\n ? false\r\n : attributeName\r\n ? liesBetween(target as Element, hostSelector, viewportSelector) || liesBetween(target as Element, hostSelector, contentSelector)\r\n : false;\r\n },\r\n */\r\n });\r\n }\r\n\r\n if (debounceChanged) {\r\n updateLifecyclesWithDebouncedAdaptiveUpdateHints._flush();\r\n if (isArray(debounce)) {\r\n const timeout = debounce[0];\r\n const maxWait = debounce[1];\r\n debounceTimeout = isNumber(timeout) ? timeout : false;\r\n debounceMaxDelay = isNumber(maxWait) ? maxWait : false;\r\n } else if (isNumber(debounce)) {\r\n debounceTimeout = debounce;\r\n debounceMaxDelay = false;\r\n } else {\r\n debounceTimeout = false;\r\n debounceMaxDelay = false;\r\n }\r\n }\r\n };\r\n\r\n updateViewportAttrsFromHost();\r\n\r\n return {\r\n _trinsicObserver: trinsicObserver,\r\n _sizeObserver: sizeObserver,\r\n _updateObserverOptions: updateOptions,\r\n _destroy() {\r\n contentMutationObserver && contentMutationObserver._destroy();\r\n trinsicObserver && trinsicObserver._destroy();\r\n sizeObserver._destroy();\r\n hostMutationObserver._destroy();\r\n },\r\n };\r\n};\r\n","import { style } from 'support';\r\nimport { LifecycleHub, Lifecycle } from 'lifecycles/lifecycleHub';\r\n\r\n/**\r\n * Lifecycle with the responsibility to adjust the trinsic behavior of the content element.\r\n * @param lifecycleHub\r\n * @returns\r\n */\r\nexport const createTrinsicLifecycle = (lifecycleHub: LifecycleHub): Lifecycle => {\r\n const { _structureSetup } = lifecycleHub;\r\n const { _content } = _structureSetup._targetObj;\r\n\r\n return (updateHints) => {\r\n const { _heightIntrinsic } = updateHints;\r\n const { _value: heightIntrinsic, _changed: heightIntrinsicChanged } = _heightIntrinsic;\r\n\r\n if (heightIntrinsicChanged) {\r\n style(_content, {\r\n height: heightIntrinsic ? '' : '100%',\r\n display: heightIntrinsic ? '' : 'inline',\r\n });\r\n }\r\n\r\n return {\r\n _sizeChanged: heightIntrinsicChanged,\r\n _contentMutation: heightIntrinsicChanged,\r\n };\r\n };\r\n};\r\n","import { createCache, topRightBottomLeft, equalTRBL, style, TRBL } from 'support';\r\nimport { LifecycleHub, Lifecycle } from 'lifecycles/lifecycleHub';\r\nimport { StyleObject } from 'typings';\r\nimport { getEnvironment } from 'environment';\r\n\r\n/**\r\n * Lifecycle with the responsibility to adjust the padding styling of the padding and viewport element.\r\n * @param lifecycleHub\r\n * @returns\r\n */\r\nexport const createPaddingLifecycle = (lifecycleHub: LifecycleHub): Lifecycle => {\r\n const { _structureSetup, _setLifecycleCommunication } = lifecycleHub;\r\n const { _host, _padding, _viewport } = _structureSetup._targetObj;\r\n const { _update: updatePaddingCache, _current: currentPaddingCache } = createCache(topRightBottomLeft.bind(0, _host, 'padding'), {\r\n _equal: equalTRBL,\r\n _initialValue: topRightBottomLeft(),\r\n });\r\n\r\n return (updateHints, checkOption, force) => {\r\n let { _value: padding, _changed: paddingChanged } = currentPaddingCache(force);\r\n const { _nativeScrollbarStyling, _flexboxGlue } = getEnvironment();\r\n const { _sizeChanged, _directionIsRTL, _contentMutation } = updateHints;\r\n const { _value: directionIsRTL, _changed: directionChanged } = _directionIsRTL;\r\n const { _value: paddingAbsolute, _changed: paddingAbsoluteChanged } = checkOption('paddingAbsolute');\r\n const contentMutation = !_flexboxGlue && _contentMutation;\r\n\r\n if (_sizeChanged || paddingChanged || contentMutation) {\r\n ({ _value: padding, _changed: paddingChanged } = updatePaddingCache(force));\r\n }\r\n\r\n const paddingStyleChanged = paddingAbsoluteChanged || directionChanged || paddingChanged;\r\n\r\n if (paddingStyleChanged) {\r\n // if there is no padding element and no scrollbar styling, paddingAbsolute isn't supported\r\n const paddingRelative = !paddingAbsolute || (!_padding && !_nativeScrollbarStyling);\r\n const paddingHorizontal = padding!.r + padding!.l;\r\n const paddingVertical = padding!.t + padding!.b;\r\n\r\n const paddingStyle: StyleObject = {\r\n marginRight: paddingRelative && !directionIsRTL ? -paddingHorizontal : 0,\r\n marginBottom: paddingRelative ? -paddingVertical : 0,\r\n marginLeft: paddingRelative && directionIsRTL ? -paddingHorizontal : 0,\r\n top: paddingRelative ? -padding!.t : 0,\r\n right: paddingRelative ? (directionIsRTL ? -padding!.r : 'auto') : 0,\r\n left: paddingRelative ? (directionIsRTL ? 'auto' : -padding!.l) : 0,\r\n width: paddingRelative ? `calc(100% + ${paddingHorizontal}px)` : '',\r\n };\r\n const viewportStyle: StyleObject = {\r\n paddingTop: paddingRelative ? padding!.t : 0,\r\n paddingRight: paddingRelative ? padding!.r : 0,\r\n paddingBottom: paddingRelative ? padding!.b : 0,\r\n paddingLeft: paddingRelative ? padding!.l : 0,\r\n };\r\n\r\n // if there is no padding element apply the style to the viewport element instead\r\n style(_padding || _viewport, paddingStyle);\r\n style(_viewport, viewportStyle);\r\n\r\n _setLifecycleCommunication({\r\n _paddingInfo: {\r\n _absolute: !paddingRelative,\r\n _padding: padding!,\r\n },\r\n _viewportPaddingStyle: _padding\r\n ? viewportStyle\r\n : {\r\n ...paddingStyle,\r\n ...viewportStyle,\r\n },\r\n });\r\n }\r\n\r\n return {\r\n _paddingStyleChanged: paddingStyleChanged,\r\n };\r\n };\r\n};\r\n","import {\r\n createCache,\r\n keys,\r\n attr,\r\n WH,\r\n XY,\r\n style,\r\n scrollSize,\r\n CacheValues,\r\n equalWH,\r\n addClass,\r\n removeClass,\r\n clientSize,\r\n offsetSize,\r\n getBoundingClientRect,\r\n noop,\r\n each,\r\n} from 'support';\r\nimport { LifecycleHub, Lifecycle } from 'lifecycles/lifecycleHub';\r\nimport { getEnvironment } from 'environment';\r\nimport { OverflowBehavior } from 'options';\r\nimport { StyleObject } from 'typings';\r\nimport { classNameViewportArrange, classNameViewportScrollbarStyling } from 'classnames';\r\n\r\ninterface OverflowAmountCacheContext {\r\n _viewportScrollSize: WH;\r\n _viewportClientSize: WH;\r\n _viewportSizeFraction: WH;\r\n}\r\n\r\ninterface ViewportOverflowState {\r\n _scrollbarsHideOffset: XY;\r\n _scrollbarsHideOffsetArrange: XY;\r\n _overflowScroll: XY;\r\n}\r\n\r\ninterface UndoViewportArrangeResult {\r\n _redoViewportArrange: () => void;\r\n _viewportOverflowState?: ViewportOverflowState;\r\n}\r\n\r\ninterface OverflowOption {\r\n x: OverflowBehavior;\r\n y: OverflowBehavior;\r\n}\r\n\r\nconst { max, abs, round } = Math;\r\nconst overlaidScrollbarsHideOffset = 42;\r\nconst whCacheOptions = {\r\n _equal: equalWH,\r\n _initialValue: { w: 0, h: 0 },\r\n};\r\nconst sizeFraction = (elm: HTMLElement): WH => {\r\n const viewportOffsetSize = offsetSize(elm);\r\n const viewportRect = getBoundingClientRect(elm);\r\n return {\r\n w: viewportRect.width - viewportOffsetSize.w,\r\n h: viewportRect.height - viewportOffsetSize.h,\r\n };\r\n};\r\nconst fractionalPixelRatioTollerance = () => (window.devicePixelRatio % 1 === 0 ? 0 : 1);\r\nconst setAxisOverflowStyle = (horizontal: boolean, overflowAmount: number, behavior: OverflowBehavior, styleObj: StyleObject) => {\r\n const overflowKey: keyof StyleObject = horizontal ? 'overflowX' : 'overflowY';\r\n const behaviorIsVisible = behavior.indexOf('visible') === 0;\r\n const behaviorIsVisibleHidden = behavior === 'visible-hidden';\r\n const behaviorIsScroll = behavior === 'scroll';\r\n const hasOverflow = overflowAmount > 0;\r\n\r\n if (behaviorIsVisible) {\r\n styleObj[overflowKey] = 'visible';\r\n }\r\n if (behaviorIsScroll && hasOverflow) {\r\n styleObj[overflowKey] = behavior;\r\n }\r\n\r\n return {\r\n _visible: behaviorIsVisible,\r\n _behavior: behaviorIsVisibleHidden ? 'hidden' : 'scroll',\r\n };\r\n};\r\n\r\n/**\r\n * Lifecycle with the responsibility to set the correct overflow and scrollbar hiding styles of the viewport element.\r\n * @param lifecycleHub\r\n * @returns\r\n */\r\nexport const createOverflowLifecycle = (lifecycleHub: LifecycleHub): Lifecycle => {\r\n const { _structureSetup, _doViewportArrange, _getLifecycleCommunication, _setLifecycleCommunication } = lifecycleHub;\r\n const { _host, _viewport, _viewportArrange } = _structureSetup._targetObj;\r\n const { _update: updateViewportSizeFraction, _current: getCurrentViewportSizeFraction } = createCache>(\r\n sizeFraction.bind(0, _viewport),\r\n whCacheOptions\r\n );\r\n const { _update: updateViewportScrollSizeCache, _current: getCurrentViewportScrollSizeCache } = createCache>(\r\n scrollSize.bind(0, _viewport),\r\n whCacheOptions\r\n );\r\n const { _update: updateOverflowAmountCache, _current: getCurrentOverflowAmountCache } = createCache, OverflowAmountCacheContext>(\r\n ({ _viewportScrollSize, _viewportClientSize, _viewportSizeFraction }) => ({\r\n w: max(0, round(max(0, _viewportScrollSize.w - _viewportClientSize.w) - (fractionalPixelRatioTollerance() || max(0, _viewportSizeFraction.w)))),\r\n h: max(0, round(max(0, _viewportScrollSize.h - _viewportClientSize.h) - (fractionalPixelRatioTollerance() || max(0, _viewportSizeFraction.h)))),\r\n }),\r\n whCacheOptions\r\n );\r\n\r\n /**\r\n * Applies a fixed height to the viewport so it can't overflow or underflow the host element.\r\n * @param viewportOverflowState The current overflow state.\r\n * @param heightIntrinsic Whether the host height is intrinsic or not.\r\n */\r\n const fixFlexboxGlue = (viewportOverflowState: ViewportOverflowState, heightIntrinsic: boolean) => {\r\n style(_viewport, {\r\n height: '',\r\n });\r\n\r\n if (heightIntrinsic) {\r\n const { _absolute: paddingAbsolute, _padding: padding } = _getLifecycleCommunication()._paddingInfo;\r\n const { _overflowScroll, _scrollbarsHideOffset } = viewportOverflowState;\r\n const hostSizeFraction = sizeFraction(_host);\r\n const hostClientSize = clientSize(_host);\r\n // padding subtraction is only needed if padding is absolute or if viewport is content-box\r\n const paddingVertical = paddingAbsolute || style(_viewport, 'boxSizing') === 'content-box' ? padding.b + padding.t : 0;\r\n const fractionalClientHeight = hostClientSize.h + (abs(hostSizeFraction.h) < 1 ? hostSizeFraction.h : 0);\r\n\r\n style(_viewport, {\r\n height: fractionalClientHeight + (_overflowScroll.x ? _scrollbarsHideOffset.x : 0) - paddingVertical,\r\n });\r\n }\r\n };\r\n\r\n /**\r\n * Gets the current overflow state of the viewport.\r\n * @param showNativeOverlaidScrollbars Whether native overlaid scrollbars are shown instead of hidden.\r\n * @param viewportStyleObj The viewport style object where the overflow scroll property can be read of, or undefined if shall be determined.\r\n * @returns A object which contains informations about the current overflow state.\r\n */\r\n const getViewportOverflowState = (showNativeOverlaidScrollbars: boolean, viewportStyleObj?: StyleObject): ViewportOverflowState => {\r\n const { _nativeScrollbarSize, _nativeScrollbarIsOverlaid, _nativeScrollbarStyling } = getEnvironment();\r\n const { x: overlaidX, y: overlaidY } = _nativeScrollbarIsOverlaid;\r\n const determineOverflow = !viewportStyleObj;\r\n const arrangeHideOffset = !_nativeScrollbarStyling && !showNativeOverlaidScrollbars ? overlaidScrollbarsHideOffset : 0;\r\n const styleObj = determineOverflow ? style(_viewport, ['overflowX', 'overflowY']) : viewportStyleObj;\r\n const scroll = {\r\n x: styleObj!.overflowX === 'scroll',\r\n y: styleObj!.overflowY === 'scroll',\r\n };\r\n const scrollbarsHideOffset = {\r\n x: scroll.x && !_nativeScrollbarStyling ? (overlaidX ? arrangeHideOffset : _nativeScrollbarSize.x) : 0,\r\n y: scroll.y && !_nativeScrollbarStyling ? (overlaidY ? arrangeHideOffset : _nativeScrollbarSize.y) : 0,\r\n };\r\n\r\n return {\r\n _overflowScroll: scroll,\r\n _scrollbarsHideOffsetArrange: {\r\n x: overlaidX && !!arrangeHideOffset,\r\n y: overlaidY && !!arrangeHideOffset,\r\n },\r\n _scrollbarsHideOffset: scrollbarsHideOffset,\r\n };\r\n };\r\n\r\n /**\r\n * Sets the overflow property of the viewport and calculates the a overflow state according to the new parameters.\r\n * @param showNativeOverlaidScrollbars Whether to show natively overlaid scrollbars.\r\n * @param overflowAmount The overflow amount.\r\n * @param overflow The overflow behavior according to the options.\r\n * @param viewportStyleObj The viewport style object to which the overflow style shall be applied.\r\n * @returns A object which represents the newly set overflow state.\r\n */\r\n const setViewportOverflowState = (\r\n showNativeOverlaidScrollbars: boolean,\r\n overflowAmount: WH,\r\n overflow: OverflowOption,\r\n viewportStyleObj: StyleObject\r\n ): ViewportOverflowState => {\r\n const { _visible: xVisible, _behavior: xVisibleBehavior } = setAxisOverflowStyle(true, overflowAmount!.w, overflow.x, viewportStyleObj);\r\n const { _visible: yVisible, _behavior: yVisibleBehavior } = setAxisOverflowStyle(false, overflowAmount!.h, overflow.y, viewportStyleObj);\r\n\r\n if (xVisible && !yVisible) {\r\n viewportStyleObj.overflowX = xVisibleBehavior;\r\n }\r\n if (yVisible && !xVisible) {\r\n viewportStyleObj.overflowY = yVisibleBehavior;\r\n }\r\n\r\n return getViewportOverflowState(showNativeOverlaidScrollbars, viewportStyleObj);\r\n };\r\n\r\n /**\r\n * Sets the styles of the viewport arrange element.\r\n * @param viewportOverflowState The viewport overflow state according to which the scrollbars shall be hidden.\r\n * @param viewportScrollSize The content scroll size.\r\n * @param directionIsRTL Whether the direction is RTL or not.\r\n * @returns A boolean which indicates whether the viewport arrange element was adjusted.\r\n */\r\n const arrangeViewport = (\r\n viewportOverflowState: ViewportOverflowState,\r\n viewportScrollSize: WH,\r\n viewportSizeFraction: WH,\r\n directionIsRTL: boolean\r\n ) => {\r\n if (_doViewportArrange) {\r\n const { _scrollbarsHideOffset, _scrollbarsHideOffsetArrange } = viewportOverflowState;\r\n const { x: arrangeX, y: arrangeY } = _scrollbarsHideOffsetArrange;\r\n const { x: hideOffsetX, y: hideOffsetY } = _scrollbarsHideOffset;\r\n const { _viewportPaddingStyle: viewportPaddingStyle } = _getLifecycleCommunication();\r\n const viewportArrangeHorizontalPaddingKey: keyof StyleObject = directionIsRTL ? 'paddingRight' : 'paddingLeft';\r\n const viewportArrangeHorizontalPaddingValue = viewportPaddingStyle[viewportArrangeHorizontalPaddingKey] as number;\r\n const viewportArrangeVerticalPaddingValue = viewportPaddingStyle.paddingTop as number;\r\n const fractionalContentWidth = viewportScrollSize.w + (abs(viewportSizeFraction.w) < 1 ? viewportSizeFraction.w : 0);\r\n const fractionalContenHeight = viewportScrollSize.h + (abs(viewportSizeFraction.h) < 1 ? viewportSizeFraction.h : 0);\r\n const arrangeSize = {\r\n w: hideOffsetY && arrangeY ? `${hideOffsetY + fractionalContentWidth - viewportArrangeHorizontalPaddingValue}px` : '',\r\n h: hideOffsetX && arrangeX ? `${hideOffsetX + fractionalContenHeight - viewportArrangeVerticalPaddingValue}px` : '',\r\n };\r\n\r\n // adjust content arrange / before element\r\n if (_viewportArrange) {\r\n const { sheet } = _viewportArrange;\r\n if (sheet) {\r\n const { cssRules } = sheet;\r\n if (cssRules) {\r\n if (!cssRules.length) {\r\n sheet.insertRule(`#${attr(_viewportArrange, 'id')} + .${classNameViewportArrange}::before {}`, 0);\r\n }\r\n\r\n // @ts-ignore\r\n const ruleStyle = cssRules[0].style;\r\n\r\n ruleStyle.width = arrangeSize.w;\r\n ruleStyle.height = arrangeSize.h;\r\n }\r\n }\r\n } else {\r\n style<'--os-vaw' | '--os-vah'>(_viewport, {\r\n '--os-vaw': arrangeSize.w,\r\n '--os-vah': arrangeSize.h,\r\n });\r\n }\r\n }\r\n\r\n return _doViewportArrange;\r\n };\r\n\r\n /**\r\n * Hides the native scrollbars according to the passed parameters.\r\n * @param viewportOverflowState The viewport overflow state.\r\n * @param directionIsRTL Whether the direction is RTL or not.\r\n * @param viewportArrange Whether special styles related to the viewport arrange strategy shall be applied.\r\n * @param viewportStyleObj The viewport style object to which the needed styles shall be applied.\r\n */\r\n const hideNativeScrollbars = (\r\n viewportOverflowState: ViewportOverflowState,\r\n directionIsRTL: boolean,\r\n viewportArrange: boolean,\r\n viewportStyleObj: StyleObject\r\n ) => {\r\n const { _scrollbarsHideOffset, _scrollbarsHideOffsetArrange } = viewportOverflowState;\r\n const { x: arrangeX, y: arrangeY } = _scrollbarsHideOffsetArrange;\r\n const { x: hideOffsetX, y: hideOffsetY } = _scrollbarsHideOffset;\r\n const { _viewportPaddingStyle: viewportPaddingStyle } = _getLifecycleCommunication();\r\n const horizontalMarginKey: keyof StyleObject = directionIsRTL ? 'marginLeft' : 'marginRight';\r\n const viewportHorizontalPaddingKey: keyof StyleObject = directionIsRTL ? 'paddingLeft' : 'paddingRight';\r\n const horizontalMarginValue = viewportPaddingStyle[horizontalMarginKey] as number;\r\n const verticalMarginValue = viewportPaddingStyle.marginBottom as number;\r\n const horizontalPaddingValue = viewportPaddingStyle[viewportHorizontalPaddingKey] as number;\r\n const verticalPaddingValue = viewportPaddingStyle.paddingBottom as number;\r\n\r\n // horizontal\r\n viewportStyleObj.width = `calc(100% + ${hideOffsetY + horizontalMarginValue * -1}px)`;\r\n viewportStyleObj[horizontalMarginKey] = -hideOffsetY + horizontalMarginValue;\r\n\r\n // vertical\r\n viewportStyleObj.marginBottom = -hideOffsetX + verticalMarginValue;\r\n\r\n // viewport arrange additional styles\r\n if (viewportArrange) {\r\n viewportStyleObj[viewportHorizontalPaddingKey] = horizontalPaddingValue + (arrangeY ? hideOffsetY : 0);\r\n viewportStyleObj.paddingBottom = verticalPaddingValue + (arrangeX ? hideOffsetX : 0);\r\n }\r\n };\r\n\r\n /**\r\n * Removes all styles applied because of the viewport arrange strategy.\r\n * @param showNativeOverlaidScrollbars Whether native overlaid scrollbars are shown instead of hidden.\r\n * @param directionIsRTL Whether the direction is RTL or not.\r\n * @param viewportOverflowState The currentviewport overflow state or undefined if it has to be determined.\r\n * @returns A object with a function which applies all the removed styles and the determined viewport vverflow state.\r\n */\r\n const undoViewportArrange = (\r\n showNativeOverlaidScrollbars: boolean,\r\n directionIsRTL: boolean,\r\n viewportOverflowState?: ViewportOverflowState\r\n ): UndoViewportArrangeResult => {\r\n if (_doViewportArrange) {\r\n const finalViewportOverflowState = viewportOverflowState || getViewportOverflowState(showNativeOverlaidScrollbars);\r\n const { _viewportPaddingStyle: viewportPaddingStyle } = _getLifecycleCommunication();\r\n const { _flexboxGlue } = getEnvironment();\r\n const { _scrollbarsHideOffsetArrange } = finalViewportOverflowState;\r\n const { x: arrangeX, y: arrangeY } = _scrollbarsHideOffsetArrange;\r\n const finalPaddingStyle: StyleObject = {};\r\n const assignProps = (props: string) =>\r\n each(props.split(' '), (prop) => {\r\n finalPaddingStyle[prop] = viewportPaddingStyle[prop];\r\n });\r\n\r\n if (!_flexboxGlue) {\r\n finalPaddingStyle.height = '';\r\n }\r\n\r\n if (arrangeX) {\r\n assignProps('marginBottom paddingTop paddingBottom');\r\n }\r\n\r\n if (arrangeY) {\r\n assignProps('marginLeft marginRight paddingLeft paddingRight');\r\n }\r\n\r\n const prevStyle = style(_viewport, keys(finalPaddingStyle));\r\n removeClass(_viewport, classNameViewportArrange);\r\n style(_viewport, finalPaddingStyle);\r\n\r\n return {\r\n _redoViewportArrange: () => {\r\n hideNativeScrollbars(finalViewportOverflowState, directionIsRTL, _doViewportArrange, prevStyle);\r\n style(_viewport, prevStyle);\r\n addClass(_viewport, classNameViewportArrange);\r\n },\r\n _viewportOverflowState: finalViewportOverflowState,\r\n };\r\n }\r\n return {\r\n _redoViewportArrange: noop,\r\n };\r\n };\r\n\r\n return (updateHints, checkOption, force) => {\r\n const { _directionIsRTL, _heightIntrinsic, _sizeChanged, _hostMutation, _contentMutation, _paddingStyleChanged } = updateHints;\r\n const { _flexboxGlue, _nativeScrollbarStyling, _nativeScrollbarIsOverlaid } = getEnvironment();\r\n const { _value: heightIntrinsic, _changed: heightIntrinsicChanged } = _heightIntrinsic;\r\n const { _value: directionIsRTL, _changed: directionChanged } = _directionIsRTL;\r\n const { _value: showNativeOverlaidScrollbarsOption, _changed: showNativeOverlaidScrollbarsChanged } = checkOption(\r\n 'nativeScrollbarsOverlaid.show'\r\n );\r\n const showNativeOverlaidScrollbars = showNativeOverlaidScrollbarsOption && _nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y;\r\n const adjustFlexboxGlue =\r\n !_flexboxGlue && (_sizeChanged || _contentMutation || _hostMutation || showNativeOverlaidScrollbarsChanged || heightIntrinsicChanged);\r\n let viewportSizeFractionCache: CacheValues> = getCurrentViewportSizeFraction(force);\r\n let viewportScrollSizeCache: CacheValues> = getCurrentViewportScrollSizeCache(force);\r\n let overflowAmuntCache: CacheValues> = getCurrentOverflowAmountCache(force);\r\n let preMeasureViewportOverflowState: ViewportOverflowState | undefined;\r\n\r\n if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarStyling) {\r\n if (showNativeOverlaidScrollbars) {\r\n removeClass(_viewport, classNameViewportScrollbarStyling);\r\n } else {\r\n addClass(_viewport, classNameViewportScrollbarStyling);\r\n }\r\n }\r\n\r\n if (adjustFlexboxGlue) {\r\n preMeasureViewportOverflowState = getViewportOverflowState(showNativeOverlaidScrollbars);\r\n fixFlexboxGlue(preMeasureViewportOverflowState, !!heightIntrinsic);\r\n }\r\n\r\n if (_sizeChanged || _paddingStyleChanged || _contentMutation || showNativeOverlaidScrollbarsChanged || directionChanged) {\r\n const { _redoViewportArrange, _viewportOverflowState: undoViewportArrangeOverflowState } = undoViewportArrange(\r\n showNativeOverlaidScrollbars,\r\n directionIsRTL!,\r\n preMeasureViewportOverflowState\r\n );\r\n const { _value: viewportSizeFraction, _changed: viewportSizeFractionCahnged } = (viewportSizeFractionCache = updateViewportSizeFraction(force));\r\n const { _value: viewportScrollSize, _changed: viewportScrollSizeChanged } = (viewportScrollSizeCache = updateViewportScrollSizeCache(force));\r\n const viewportContentSize = clientSize(_viewport);\r\n let arrangedViewportScrollSize = viewportScrollSize!;\r\n let arrangedViewportClientSize = viewportContentSize;\r\n\r\n _redoViewportArrange();\r\n\r\n // if re measure is required (only required if content arrange strategy is used)\r\n if (\r\n (viewportScrollSizeChanged || viewportSizeFractionCahnged || showNativeOverlaidScrollbarsChanged) &&\r\n undoViewportArrangeOverflowState &&\r\n !showNativeOverlaidScrollbars &&\r\n arrangeViewport(undoViewportArrangeOverflowState, viewportScrollSize!, viewportSizeFraction!, directionIsRTL!)\r\n ) {\r\n arrangedViewportClientSize = clientSize(_viewport);\r\n arrangedViewportScrollSize = scrollSize(_viewport);\r\n }\r\n\r\n overflowAmuntCache = updateOverflowAmountCache(force, {\r\n _viewportSizeFraction: viewportSizeFraction!,\r\n _viewportScrollSize: {\r\n w: max(viewportScrollSize!.w, arrangedViewportScrollSize.w),\r\n h: max(viewportScrollSize!.h, arrangedViewportScrollSize.h),\r\n },\r\n _viewportClientSize: {\r\n w: arrangedViewportClientSize.w + max(0, viewportContentSize.w - viewportScrollSize!.w),\r\n h: arrangedViewportClientSize.h + max(0, viewportContentSize.h - viewportScrollSize!.h),\r\n },\r\n });\r\n }\r\n\r\n const { _value: viewportSizeFraction, _changed: viewportSizeFractionChanged } = viewportSizeFractionCache;\r\n const { _value: viewportScrollSize, _changed: viewportScrollSizeChanged } = viewportScrollSizeCache;\r\n const { _value: overflowAmount, _changed: overflowAmountChanged } = overflowAmuntCache;\r\n const { _value: overflow, _changed: overflowChanged } = checkOption('overflow');\r\n\r\n if (\r\n _paddingStyleChanged ||\r\n viewportSizeFractionChanged ||\r\n viewportScrollSizeChanged ||\r\n overflowAmountChanged ||\r\n overflowChanged ||\r\n showNativeOverlaidScrollbarsChanged ||\r\n directionChanged ||\r\n adjustFlexboxGlue\r\n ) {\r\n const viewportStyle: StyleObject = {\r\n marginRight: 0,\r\n marginBottom: 0,\r\n marginLeft: 0,\r\n width: '',\r\n overflowY: '',\r\n overflowX: '',\r\n };\r\n\r\n const viewportOverflowState = setViewportOverflowState(showNativeOverlaidScrollbars, overflowAmount!, overflow, viewportStyle);\r\n const viewportArranged = arrangeViewport(viewportOverflowState, viewportScrollSize!, viewportSizeFraction!, directionIsRTL!);\r\n hideNativeScrollbars(viewportOverflowState, directionIsRTL!, viewportArranged, viewportStyle);\r\n\r\n if (adjustFlexboxGlue) {\r\n fixFlexboxGlue(viewportOverflowState, !!heightIntrinsic);\r\n }\r\n\r\n // TODO: hide host overflow if scroll x or y and no padding element there\r\n // TODO: Test without content\r\n // TODO: Test without padding\r\n // TODO: overflow: visible on padding / host if overflow visible on both axis\r\n\r\n style(_viewport, viewportStyle);\r\n\r\n _setLifecycleCommunication({\r\n _viewportOverflowScroll: viewportOverflowState._overflowScroll,\r\n _viewportOverflowAmount: overflowAmount,\r\n });\r\n }\r\n };\r\n};\r\n","import { XY, WH, TRBL, CacheValues, PartialOptions, each, hasOwnProperty, isNumber, scrollLeft, scrollTop, assignDeep } from 'support';\r\nimport { OSOptions } from 'options';\r\nimport { getEnvironment } from 'environment';\r\nimport { StructureSetup } from 'setups/structureSetup';\r\nimport { lifecycleHubOservers } from 'lifecycles/lifecycleHubObservers';\r\nimport { createTrinsicLifecycle } from 'lifecycles/trinsicLifecycle';\r\nimport { createPaddingLifecycle } from 'lifecycles/paddingLifecycle';\r\nimport { createOverflowLifecycle } from 'lifecycles/overflowLifecycle';\r\nimport { StyleObject } from 'typings';\r\n\r\nexport type LifecycleCheckOption = (path: string) => LifecycleOptionInfo;\r\n\r\nexport type Lifecycle = (\r\n updateHints: LifecycleUpdateHints,\r\n checkOption: LifecycleCheckOption,\r\n force: boolean\r\n) => Partial