From 69e8045081c212a1c02835fa7770da7480646c85 Mon Sep 17 00:00:00 2001 From: Rene Haas Date: Fri, 11 Nov 2022 18:06:25 +0100 Subject: [PATCH] add overlayscrollbars-solid --- package-lock.json | 581 ++++++++++++++++++ package.json | 2 + packages/overlayscrollbars-solid/.gitignore | 8 + packages/overlayscrollbars-solid/CHANGELOG.md | 6 + packages/overlayscrollbars-solid/README.md | 167 +++++ packages/overlayscrollbars-solid/logo.svg | 1 + packages/overlayscrollbars-solid/package.json | 49 ++ .../src/OverlayScrollbarsComponent.tsx | 100 +++ .../src/createOverlayScrollbars.ts | 70 +++ .../src/overlayscrollbars-solid.ts | 2 + .../test/OverlayScrollbarsComponent.test.tsx | 395 ++++++++++++ .../test/createOverlayScrollbars.test.tsx | 186 ++++++ .../overlayscrollbars-solid/tsconfig.json | 18 + .../tsconfig.types.json | 9 + .../overlayscrollbars-solid/vite.config.js | 62 ++ .../overlayscrollbars-solid/vitest.config.js | 20 + .../test/OverlayScrollbarsComponent.test.ts | 2 +- 17 files changed, 1677 insertions(+), 1 deletion(-) create mode 100644 packages/overlayscrollbars-solid/.gitignore create mode 100644 packages/overlayscrollbars-solid/CHANGELOG.md create mode 100644 packages/overlayscrollbars-solid/README.md create mode 100644 packages/overlayscrollbars-solid/logo.svg create mode 100644 packages/overlayscrollbars-solid/package.json create mode 100644 packages/overlayscrollbars-solid/src/OverlayScrollbarsComponent.tsx create mode 100644 packages/overlayscrollbars-solid/src/createOverlayScrollbars.ts create mode 100644 packages/overlayscrollbars-solid/src/overlayscrollbars-solid.ts create mode 100644 packages/overlayscrollbars-solid/test/OverlayScrollbarsComponent.test.tsx create mode 100644 packages/overlayscrollbars-solid/test/createOverlayScrollbars.test.tsx create mode 100644 packages/overlayscrollbars-solid/tsconfig.json create mode 100644 packages/overlayscrollbars-solid/tsconfig.types.json create mode 100644 packages/overlayscrollbars-solid/vite.config.js create mode 100644 packages/overlayscrollbars-solid/vitest.config.js diff --git a/package-lock.json b/package-lock.json index 70ce929..805293e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7320,6 +7320,39 @@ "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/babel-plugin-jsx-dom-expressions": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.35.4.tgz", + "integrity": "sha512-Ab8W+36+XcNpyb644K537MtuhZRssgE3hmZD/08a1Z99Xfnd38tR2BZaDl7yEQvvHrb46N+eje2YjIg4VGAfVQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "7.16.0", + "@babel/plugin-syntax-jsx": "^7.16.5", + "@babel/types": "^7.16.0", + "html-entities": "2.3.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-plugin-jsx-dom-expressions/node_modules/@babel/helper-module-imports": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz", + "integrity": "sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/babel-plugin-jsx-dom-expressions/node_modules/html-entities": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", + "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==", + "dev": true + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", @@ -7407,6 +7440,18 @@ "@babel/core": "^7.0.0" } }, + "node_modules/babel-preset-solid": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/babel-preset-solid/-/babel-preset-solid-1.6.1.tgz", + "integrity": "sha512-Ji/cvYUE2BROsA3zOhaqKjuAEo6YAkmw8ZE11QsMtSEcWJ1rCFC829qWb5FLPl3UymVxh68+dpScPDtyyr/rdA==", + "dev": true, + "dependencies": { + "babel-plugin-jsx-dom-expressions": "^0.35.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -17636,6 +17681,34 @@ "node": ">= 0.10.0" } }, + "node_modules/merge-anything": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-5.0.4.tgz", + "integrity": "sha512-YFsDeY5A9SLXhL21Qn15wCWewRUW6wMTxQF4SuPe9bNdr1wsjiE44Rp8FQUTCtwO0WLdlKiFzhAVE5tlf857Tg==", + "dev": true, + "dependencies": { + "is-what": "^4.1.7", + "ts-toolbelt": "^9.6.0" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/merge-anything/node_modules/is-what": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.7.tgz", + "integrity": "sha512-DBVOQNiPKnGMxRMLIYSwERAS5MVY1B7xYiGnpgctsOFvVDz9f9PFXXxMcTOHuoqYp4NK9qFYQaIC1NRRxLMpBQ==", + "dev": true, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -19278,6 +19351,10 @@ "resolved": "packages/overlayscrollbars-react", "link": true }, + "node_modules/overlayscrollbars-solid": { + "resolved": "packages/overlayscrollbars-solid", + "link": true + }, "node_modules/overlayscrollbars-svelte": { "resolved": "packages/overlayscrollbars-svelte", "link": true @@ -24369,6 +24446,200 @@ } } }, + "node_modules/solid-js": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.6.1.tgz", + "integrity": "sha512-i8OmR419Hr0918Or6sm1ET/cgmxTtAB7Bdz/UwhZ7G2THixrvVSO3jd+C7YqMKKfVwmf8PJ2gUSbKE8NKv28GA==", + "dev": true, + "dependencies": { + "csstype": "^3.1.0" + } + }, + "node_modules/solid-refresh": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/solid-refresh/-/solid-refresh-0.4.1.tgz", + "integrity": "sha512-v3tD/OXQcUyXLrWjPW1dXZyeWwP7/+GQNs8YTL09GBq+5FguA6IejJWUvJDrLIA4M0ho9/5zK2e9n+uy+4488g==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.18.2", + "@babel/helper-module-imports": "^7.16.7", + "@babel/types": "^7.18.4" + }, + "peerDependencies": { + "solid-js": "^1.3" + } + }, + "node_modules/solid-testing-library": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/solid-testing-library/-/solid-testing-library-0.5.0.tgz", + "integrity": "sha512-vr4Ke9Dq3bUFLaXOcN8/IVn2e9Q37w4vdmoIOmFBIPs7iCJX9IxuC0IdQqK8nzBZMQqceijkfyCE3Qc407KmaA==", + "dev": true, + "dependencies": { + "@testing-library/dom": "^8.19.0" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "solid-js": ">=1.0.0" + } + }, + "node_modules/solid-testing-library/node_modules/@testing-library/dom": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.19.0.tgz", + "integrity": "sha512-6YWYPPpxG3e/xOo6HIWwB/58HukkwIVTOaZ0VwdMVjhRUX/01E4FtQbck9GazOOj7MXHc5RBzMrU86iBJHbI+A==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^5.0.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.4.4", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/solid-testing-library/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/solid-testing-library/node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/solid-testing-library/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/solid-testing-library/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/solid-testing-library/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/solid-testing-library/node_modules/deep-equal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz", + "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/solid-testing-library/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/solid-testing-library/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/solid-testing-library/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/solid-testing-library/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/solid-testing-library/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/sorcery": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.10.0.tgz", @@ -25924,6 +26195,12 @@ "tree-kill": "cli.js" } }, + "node_modules/ts-toolbelt": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz", + "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==", + "dev": true + }, "node_modules/tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -26445,6 +26722,24 @@ } } }, + "node_modules/vite-plugin-solid": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/vite-plugin-solid/-/vite-plugin-solid-2.4.0.tgz", + "integrity": "sha512-Rr+t2sr9TWIvH16yzBZzx6O9YSpYAvcwKUMPqbi/4iU3mRumXQ4O10i1XGtQIynC7U3XwJsMzAJigDFGbiJBiw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "babel-preset-solid": "^1.4.6", + "merge-anything": "^5.0.2", + "solid-refresh": "^0.4.1", + "vitefu": "^0.1.1" + }, + "peerDependencies": { + "solid-js": "^1.3.17", + "vite": "^3.0.0" + } + }, "node_modules/vite/node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -26477,6 +26772,20 @@ "fsevents": "~2.3.2" } }, + "node_modules/vitefu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.1.1.tgz", + "integrity": "sha512-HClD14fjMJ+NQgXBqT3dC3RdO/+Chayil+cCPYZKY3kT+KcJomKzrdgzfCHJkIL2L0OAY+VPvrSW615iPtc7ag==", + "dev": true, + "peerDependencies": { + "vite": "^3.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, "node_modules/vitest": { "version": "0.24.3", "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.24.3.tgz", @@ -29548,6 +29857,26 @@ "resolved": "packages/overlayscrollbars/dist", "link": true }, + "packages/overlayscrollbars-solid": { + "version": "0.4.0", + "license": "MIT", + "devDependencies": { + "overlayscrollbars": "file:./../overlayscrollbars/dist", + "solid-js": "^1.5.1", + "solid-testing-library": "^0.5.0", + "typescript": "^4.8.2", + "vite": "^3.0.9", + "vite-plugin-solid": "^2.3.0" + }, + "peerDependencies": { + "overlayscrollbars": "^2.0.0", + "solid-js": "^1.5.1" + } + }, + "packages/overlayscrollbars-solid/node_modules/overlayscrollbars": { + "resolved": "packages/overlayscrollbars/dist", + "link": true + }, "packages/overlayscrollbars-svelte": { "version": "0.4.0", "devDependencies": { @@ -35174,6 +35503,35 @@ "@types/babel__traverse": "^7.0.6" } }, + "babel-plugin-jsx-dom-expressions": { + "version": "0.35.4", + "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.35.4.tgz", + "integrity": "sha512-Ab8W+36+XcNpyb644K537MtuhZRssgE3hmZD/08a1Z99Xfnd38tR2BZaDl7yEQvvHrb46N+eje2YjIg4VGAfVQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "7.16.0", + "@babel/plugin-syntax-jsx": "^7.16.5", + "@babel/types": "^7.16.0", + "html-entities": "2.3.2" + }, + "dependencies": { + "@babel/helper-module-imports": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz", + "integrity": "sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.0" + } + }, + "html-entities": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", + "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==", + "dev": true + } + } + }, "babel-plugin-polyfill-corejs2": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", @@ -35242,6 +35600,15 @@ "babel-preset-current-node-syntax": "^1.0.0" } }, + "babel-preset-solid": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/babel-preset-solid/-/babel-preset-solid-1.6.1.tgz", + "integrity": "sha512-Ji/cvYUE2BROsA3zOhaqKjuAEo6YAkmw8ZE11QsMtSEcWJ1rCFC829qWb5FLPl3UymVxh68+dpScPDtyyr/rdA==", + "dev": true, + "requires": { + "babel-plugin-jsx-dom-expressions": "^0.35.2" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -42945,6 +43312,24 @@ "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", "dev": true }, + "merge-anything": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-5.0.4.tgz", + "integrity": "sha512-YFsDeY5A9SLXhL21Qn15wCWewRUW6wMTxQF4SuPe9bNdr1wsjiE44Rp8FQUTCtwO0WLdlKiFzhAVE5tlf857Tg==", + "dev": true, + "requires": { + "is-what": "^4.1.7", + "ts-toolbelt": "^9.6.0" + }, + "dependencies": { + "is-what": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.7.tgz", + "integrity": "sha512-DBVOQNiPKnGMxRMLIYSwERAS5MVY1B7xYiGnpgctsOFvVDz9f9PFXXxMcTOHuoqYp4NK9qFYQaIC1NRRxLMpBQ==", + "dev": true + } + } + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -45346,6 +45731,22 @@ } } }, + "overlayscrollbars-solid": { + "version": "file:packages/overlayscrollbars-solid", + "requires": { + "overlayscrollbars": "file:../overlayscrollbars/dist", + "solid-js": "^1.5.1", + "solid-testing-library": "^0.5.0", + "typescript": "^4.8.2", + "vite": "^3.0.9", + "vite-plugin-solid": "^2.3.0" + }, + "dependencies": { + "overlayscrollbars": { + "version": "file:packages/overlayscrollbars/dist" + } + } + }, "overlayscrollbars-svelte": { "version": "file:packages/overlayscrollbars-svelte", "requires": { @@ -49296,6 +49697,159 @@ } } }, + "solid-js": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.6.1.tgz", + "integrity": "sha512-i8OmR419Hr0918Or6sm1ET/cgmxTtAB7Bdz/UwhZ7G2THixrvVSO3jd+C7YqMKKfVwmf8PJ2gUSbKE8NKv28GA==", + "dev": true, + "requires": { + "csstype": "^3.1.0" + } + }, + "solid-refresh": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/solid-refresh/-/solid-refresh-0.4.1.tgz", + "integrity": "sha512-v3tD/OXQcUyXLrWjPW1dXZyeWwP7/+GQNs8YTL09GBq+5FguA6IejJWUvJDrLIA4M0ho9/5zK2e9n+uy+4488g==", + "dev": true, + "requires": { + "@babel/generator": "^7.18.2", + "@babel/helper-module-imports": "^7.16.7", + "@babel/types": "^7.18.4" + } + }, + "solid-testing-library": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/solid-testing-library/-/solid-testing-library-0.5.0.tgz", + "integrity": "sha512-vr4Ke9Dq3bUFLaXOcN8/IVn2e9Q37w4vdmoIOmFBIPs7iCJX9IxuC0IdQqK8nzBZMQqceijkfyCE3Qc407KmaA==", + "dev": true, + "requires": { + "@testing-library/dom": "^8.19.0" + }, + "dependencies": { + "@testing-library/dom": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.19.0.tgz", + "integrity": "sha512-6YWYPPpxG3e/xOo6HIWwB/58HukkwIVTOaZ0VwdMVjhRUX/01E4FtQbck9GazOOj7MXHc5RBzMrU86iBJHbI+A==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^5.0.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.4.4", + "pretty-format": "^27.0.2" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "requires": { + "deep-equal": "^2.0.5" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "deep-equal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz", + "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.8" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "sorcery": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.10.0.tgz", @@ -50461,6 +51015,12 @@ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true }, + "ts-toolbelt": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz", + "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==", + "dev": true + }, "tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -50863,6 +51423,27 @@ } } }, + "vite-plugin-solid": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/vite-plugin-solid/-/vite-plugin-solid-2.4.0.tgz", + "integrity": "sha512-Rr+t2sr9TWIvH16yzBZzx6O9YSpYAvcwKUMPqbi/4iU3mRumXQ4O10i1XGtQIynC7U3XwJsMzAJigDFGbiJBiw==", + "dev": true, + "requires": { + "@babel/core": "^7.18.6", + "@babel/preset-typescript": "^7.18.6", + "babel-preset-solid": "^1.4.6", + "merge-anything": "^5.0.2", + "solid-refresh": "^0.4.1", + "vitefu": "^0.1.1" + } + }, + "vitefu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.1.1.tgz", + "integrity": "sha512-HClD14fjMJ+NQgXBqT3dC3RdO/+Chayil+cCPYZKY3kT+KcJomKzrdgzfCHJkIL2L0OAY+VPvrSW615iPtc7ag==", + "dev": true, + "requires": {} + }, "vitest": { "version": "0.24.3", "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.24.3.tgz", diff --git a/package.json b/package.json index 0ca554e..3818256 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "test:vue": "npm run test --workspace=overlayscrollbars-vue", "test:ngx": "npm run test --workspace=overlayscrollbars-ngx", "test:svelte": "npm run test --workspace=overlayscrollbars-svelte", + "test:solid": "npm run test --workspace=overlayscrollbars-solid", "e2e": "run-s e2e:*", "e2e:os": "npm run e2e --workspace=overlayscrollbars", "e2e:os:dev": "npm run e2e:dev --workspace=overlayscrollbars", @@ -77,6 +78,7 @@ "build:vue": "npm run build --workspace=overlayscrollbars-vue", "build:ngx": "npm run build --workspace=overlayscrollbars-ngx", "build:svelte": "npm run build --workspace=overlayscrollbars-svelte", + "build:solid": "npm run build --workspace=overlayscrollbars-solid", "example:react": "npm run build:react && cd examples/react && npm i && npm run start", "example:vue": "npm run build:vue && cd examples/vue && npm i && npm run dev", "example:ngx": "npm run build:ngx && cd examples/angular && npm i && npm run start", diff --git a/packages/overlayscrollbars-solid/.gitignore b/packages/overlayscrollbars-solid/.gitignore new file mode 100644 index 0000000..6c8bc50 --- /dev/null +++ b/packages/overlayscrollbars-solid/.gitignore @@ -0,0 +1,8 @@ +# Compiled output +/dist + +# Node +/node_modules + +# Miscellaneous +/.coverage diff --git a/packages/overlayscrollbars-solid/CHANGELOG.md b/packages/overlayscrollbars-solid/CHANGELOG.md new file mode 100644 index 0000000..a21d9a6 --- /dev/null +++ b/packages/overlayscrollbars-solid/CHANGELOG.md @@ -0,0 +1,6 @@ +# Changelog + +## 0.4.0 + +The component was created. +Depends on `OverlayScrollbars` version `^2.0.0` and `Solid` version `^1.5.1`. diff --git a/packages/overlayscrollbars-solid/README.md b/packages/overlayscrollbars-solid/README.md new file mode 100644 index 0000000..4a94f4e --- /dev/null +++ b/packages/overlayscrollbars-solid/README.md @@ -0,0 +1,167 @@ +
+ OverlayScrollbars + Vue +
+
+
+ + [![OverlayScrollbars](https://img.shields.io/badge/OverlayScrollbars-%5E2.0.0-338EFF?style=flat-square)](https://github.com/KingSora/OverlayScrollbars) + [![Solid](https://img.shields.io/badge/Solid-%5E1.5.1-2C4F7C?style=flat-square&logo=solid)](https://github.com/solidjs/solid) + [![Downloads](https://img.shields.io/npm/dt/overlayscrollbars-solid.svg?style=flat-square)](https://www.npmjs.com/package/overlayscrollbars-solid) + [![Version](https://img.shields.io/npm/v/overlayscrollbars-solid.svg?style=flat-square)](https://www.npmjs.com/package/overlayscrollbars-solid) + [![License](https://img.shields.io/github/license/kingsora/overlayscrollbars.svg?style=flat-square)](#) + +
+ +# OverlayScrollbars for Solid + +This is the official OverlayScrollbars Solid wrapper. + +## Installation + +```sh +npm install overlayscrollbars-solid +``` + +## Peer Dependencies + +OverlayScrollbars for Solid has the following **peer dependencies**: + +- The vanilla JavaScript library: [overlayscrollbars](https://www.npmjs.com/package/overlayscrollbars) + +``` +npm install overlayscrollbars +``` + +- The Solid framework: [solid-js](https://www.npmjs.com/package/solid-js) + +``` +npm install solid-js +``` + +## Usage + +The first step is to import the CSS file into your app: +```ts +import 'overlayscrollbars/overlayscrollbars.css'; +``` + +> __Note__: In older node versions use `'overlayscrollbars/styles/overlayscrollbars.css'` as the import path for the CSS file. + +## Component + +The main entry point is the `OverlayScrollbarsComponent` which can be used in your application as a component: + +```jsx +import { OverlayScrollbarsComponent } from "overlayscrollbars-solid"; + +// ... + + + example content + +``` + +### Properties + +It has three optional properties: `element`, `options` and `events`. + +- `element`: accepts a `string` which represents the tag of the root element. +- `options`: accepts an `object` which represents the OverlayScrollbars options. +- `events`: accepts an `object` which represents the OverlayScrollbars events. + +```jsx +// example usage + { /* ... */ } }} +/> +``` + +### Ref + +The `ref` of the `OverlayScrollbarsComponent` will give you an object with which you can access the OverlayScrollbars `instance` and the root `element` of the component. +The ref object has two properties: + +- `osInstance`: a function which returns the OverlayScrollbars instance. +- `getElement`: a function which returns the root element. + +```jsx +// example usage +import type { OverlayScrollbarsComponentRef } from 'overlayscrollbars-solid'; + +const Component = () => { + let ref: OverlayScrollbarsComponentRef | undefined; + + return (ref = r)} /> +} +``` + +## Primitive + +In case the `OverlayScrollbarsComponent` is not enough, you can also use the `createOverlayScrollbars` primitive: + +```jsx +import { createOverlayScrollbars } from "overlayscrollbars-solid"; + +// example usage +const Component = () => { + let div; + const [params, setParams] = createStore({ options, events }); + const [initialize, instance] = useOverlayScrollbars(params); + + /** + * or: + * + * const [params, setParams] = createSignal<{ + * options?: PartialOptions; + * events?: EventListeners; + * }>({}); + * const [initialize, instance] = createOverlayScrollbars(params); + * + * or: + * + * const [options, setOptions] = createSignal(); + * const [events, setEvents] = createSignal(); + * const [initialize, instance] = createOverlayScrollbars({ + * options, + * events, + * }); + * + */ + + onMount(() => { + initialize({ target: div }); + }); + + onCleanup(() => { + instance().destroy(); + }); + + return
+} +``` + +The primitive is for advanced usage and lets you control the whole initialization process. This is useful if you want to integrate it with other plugins. + +### Parameters + +Parameters are optional and similar to the `OverlayScrollbarsComponent`. +Its an `object` with two optional properties: + +- `options`: accepts an `object` which represents the OverlayScrollbars options. +- `events`: accepts an `object` which represents the OverlayScrollbars events. + +> __Note__: The object can be a normal, `store` or `signal` object. This also applies to the `options` and `events` fields. + +### Return + +The `createOverlayScrollbars` primitive returns a `tuple` with two values: + +- The first value is the `initialization` function, it takes one argument which is the `InitializationTarget` and returns the OverlayScrollbars instance. +- The second value is a function which returns the current OverlayScrollbars instance or `null` if not initialized. + +## License + +MIT diff --git a/packages/overlayscrollbars-solid/logo.svg b/packages/overlayscrollbars-solid/logo.svg new file mode 100644 index 0000000..025aa30 --- /dev/null +++ b/packages/overlayscrollbars-solid/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/overlayscrollbars-solid/package.json b/packages/overlayscrollbars-solid/package.json new file mode 100644 index 0000000..64f2159 --- /dev/null +++ b/packages/overlayscrollbars-solid/package.json @@ -0,0 +1,49 @@ +{ + "name": "overlayscrollbars-solid", + "private": true, + "version": "0.4.0", + "description": "OverlayScrollbars for Solid.", + "author": "Rene Haas | KingSora", + "license": "MIT", + "homepage": "https://kingsora.github.io/OverlayScrollbars", + "bugs": "https://github.com/KingSora/OverlayScrollbars/issues", + "repository": { + "type": "git", + "url": "https://github.com/KingSora/OverlayScrollbars.git", + "directory": "packages/overlayscrollbars-solid" + }, + "keywords": [ + "overlayscrollbars", + "solid", + "solidjs", + "component", + "hook", + "hooks", + "primitive", + "styleable", + "scrollbar", + "scrollbars", + "scroll" + ], + "main": "./src/overlayscrollbars-solid.ts", + "module": "./src/overlayscrollbars-solid.ts", + "types": "./src/overlayscrollbars-solid.ts", + "peerDependencies": { + "overlayscrollbars": "^2.0.0", + "solid-js": "^1.5.1" + }, + "devDependencies": { + "overlayscrollbars": "file:./../overlayscrollbars/dist", + "solid-js": "^1.5.1", + "solid-testing-library": "^0.5.0", + "typescript": "^4.8.2", + "vite": "^3.0.9", + "vite-plugin-solid": "^2.3.0" + }, + "scripts": { + "build": "run-p build-js build-types", + "test": "vitest run --coverage", + "build-js": "vite build", + "build-types": "vue-tsc --emitDeclarationOnly -p tsconfig.types.json --composite false" + } +} diff --git a/packages/overlayscrollbars-solid/src/OverlayScrollbarsComponent.tsx b/packages/overlayscrollbars-solid/src/OverlayScrollbarsComponent.tsx new file mode 100644 index 0000000..01e9c80 --- /dev/null +++ b/packages/overlayscrollbars-solid/src/OverlayScrollbarsComponent.tsx @@ -0,0 +1,100 @@ +import { + mergeProps, + splitProps, + children, + onCleanup, + createEffect, + createRenderEffect, + createSignal, +} from 'solid-js'; +import { Dynamic } from 'solid-js/web'; +import type { JSX, ParentProps, ComponentProps, Ref } from 'solid-js'; +import type { OverlayScrollbars, PartialOptions, EventListeners } from 'overlayscrollbars'; +import { createOverlayScrollbars } from './createOverlayScrollbars'; + +type InferGeneric = T extends JSX.HTMLAttributes ? G : never; + +export type OverlayScrollbarsComponentProps = Omit< + ComponentProps, + 'ref' +> & + ParentProps<{ + /** Tag of the root element. */ + element?: T; + /** OverlayScrollbars options. */ + options?: PartialOptions | false | null; + /** OverlayScrollbars events. */ + events?: EventListeners | false | null; + /** OverlayScrollbarsComponent ref. */ + ref?: Exclude, OverlayScrollbarsComponentRef>; + }>; + +export interface OverlayScrollbarsComponentRef { + /** Returns the OverlayScrollbars instance or null if not initialized. */ + osInstance(): OverlayScrollbars | null; + /** Returns the root element. */ + getElement(): InferGeneric | null; +} + +export const OverlayScrollbarsComponent = ( + props: OverlayScrollbarsComponentProps +) => { + const [finalProps, other] = splitProps( + mergeProps({ element: 'div' }, props as OverlayScrollbarsComponentProps), + ['element', 'options', 'events', 'ref', 'children'] + ); + const [elementRef, setElementRef] = createSignal(); + const [childrenRef, setChildrenRef] = createSignal(); + const [initialize, instance] = createOverlayScrollbars(finalProps); + + createEffect(() => { + const currElement = elementRef(); + const currChildrenElement = childrenRef(); + + if (currElement && currChildrenElement) { + const osInstance = initialize({ + target: currElement, + elements: { + viewport: currChildrenElement, + content: currChildrenElement, + }, + }); + + onCleanup(() => { + osInstance.destroy(); + }); + } + }); + + createRenderEffect(() => { + finalProps.ref?.({ + osInstance: instance, + getElement: () => + /* c8 ignore next */ + elementRef() || null, + }); + }); + + onCleanup(() => { + instance()?.destroy(); + }); + + return ( + { + setElementRef(ref); + }} + {...other} + > +
{ + setChildrenRef(ref); + }} + > + {children(() => finalProps.children)} +
+
+ ); +}; diff --git a/packages/overlayscrollbars-solid/src/createOverlayScrollbars.ts b/packages/overlayscrollbars-solid/src/createOverlayScrollbars.ts new file mode 100644 index 0000000..3293511 --- /dev/null +++ b/packages/overlayscrollbars-solid/src/createOverlayScrollbars.ts @@ -0,0 +1,70 @@ +import { createRenderEffect } from 'solid-js'; +import { OverlayScrollbars } from 'overlayscrollbars'; +import type { Accessor } from 'solid-js'; +import type { Store } from 'solid-js/store'; +import type { InitializationTarget } from 'overlayscrollbars'; +import type { + OverlayScrollbarsComponentProps, + OverlayScrollbarsComponentRef, +} from './OverlayScrollbarsComponent'; + +export interface CreateOverlayScrollbarsParams { + /** OverlayScrollbars options. */ + options?: + | OverlayScrollbarsComponentProps['options'] + | Accessor; + /** OverlayScrollbars events. */ + events?: + | OverlayScrollbarsComponentProps['events'] + | Accessor; +} + +export type CreateOverlayScrollbarsInitialization = ( + target: InitializationTarget +) => OverlayScrollbars; + +export type CreateOverlayScrollbarsInstance = () => ReturnType< + OverlayScrollbarsComponentRef['osInstance'] +>; + +const isAccessor = (obj: any): obj is Accessor => typeof obj === 'function'; +const unwrapAccessor = (obj: Accessor | T): T => (isAccessor(obj) ? obj() : obj); + +export const createOverlayScrollbars = ( + params?: + | CreateOverlayScrollbarsParams + | Accessor + | Store +): [CreateOverlayScrollbarsInitialization, CreateOverlayScrollbarsInstance] => { + let instance: OverlayScrollbars | null = null; + let options: OverlayScrollbarsComponentProps['options']; + let events: OverlayScrollbarsComponentProps['events']; + + createRenderEffect(() => { + options = unwrapAccessor(unwrapAccessor(params)?.options); + + if (OverlayScrollbars.valid(instance)) { + instance.options(options || {}, true); + } + }); + + createRenderEffect(() => { + events = unwrapAccessor(unwrapAccessor(params)?.events); + + if (OverlayScrollbars.valid(instance)) { + instance.on(events || {}, true); + } + }); + + return [ + (target: InitializationTarget): OverlayScrollbars => { + // if already initialized return the current instance + if (OverlayScrollbars.valid(instance)) { + return instance; + } + + return (instance = OverlayScrollbars(target, options || {}, events || {})); + }, + () => instance, + ]; +}; diff --git a/packages/overlayscrollbars-solid/src/overlayscrollbars-solid.ts b/packages/overlayscrollbars-solid/src/overlayscrollbars-solid.ts new file mode 100644 index 0000000..5a2961e --- /dev/null +++ b/packages/overlayscrollbars-solid/src/overlayscrollbars-solid.ts @@ -0,0 +1,2 @@ +export * from './OverlayScrollbarsComponent'; +export * from './createOverlayScrollbars'; diff --git a/packages/overlayscrollbars-solid/test/OverlayScrollbarsComponent.test.tsx b/packages/overlayscrollbars-solid/test/OverlayScrollbarsComponent.test.tsx new file mode 100644 index 0000000..587c9cb --- /dev/null +++ b/packages/overlayscrollbars-solid/test/OverlayScrollbarsComponent.test.tsx @@ -0,0 +1,395 @@ +import { describe, test, afterEach, expect, vitest } from 'vitest'; +import { createSignal, createEffect } from 'solid-js'; +import { render, screen, cleanup, fireEvent } from 'solid-testing-library'; +import userEvent from '@testing-library/user-event'; +import { OverlayScrollbars } from 'overlayscrollbars'; +import { OverlayScrollbarsComponent } from '~/overlayscrollbars-solid'; +import type { OverlayScrollbarsComponentRef } from '~/overlayscrollbars-solid'; + +const createTestComponent = + (props: any = {}) => + () => { + let ref: OverlayScrollbarsComponentRef | undefined; + const [element, setElement]: any = createSignal(props.element || 'div'); + const [options, setOptions]: any = createSignal(props.options); + const [events, setEvents]: any = createSignal(props.events); + const [className, setClassName]: any = createSignal(props.className); + const [style, setStyle]: any = createSignal(props.style); + + createEffect(() => { + props?.getRef?.(ref); + }); + + return ( + <> + (ref = r)} + /> + + + ); + }; + +/** + * rerender doesn't exist... so I am faking it with custom event... + */ +describe('OverlayScrollbarsComponent', () => { + afterEach(() => cleanup()); + + describe('correct rendering', () => { + test('correct root element with instance', () => { + const elementA = 'code'; + const elementB = 'span'; + let osInstance; + const { container } = render(createTestComponent()); + + expect(container).not.toBeEmptyDOMElement(); + expect(container.querySelector('div')).toBe(container.firstElementChild); // default is div + + expect(OverlayScrollbars.valid(osInstance)).toBe(false); + osInstance = OverlayScrollbars(container.firstElementChild as HTMLElement); + expect(osInstance).toBeDefined(); + expect(OverlayScrollbars.valid(osInstance)).toBe(true); + + fireEvent( + screen.getByText('props'), + new CustomEvent('osProps', { + detail: { element: elementA }, + }) + ); + + expect(container.querySelector(elementA)).toBe(container.firstElementChild); + + expect(OverlayScrollbars.valid(osInstance)).toBe(false); // prev instance is destroyed + osInstance = OverlayScrollbars(container.firstElementChild as HTMLElement); + expect(osInstance).toBeDefined(); + expect(OverlayScrollbars.valid(osInstance)).toBe(true); + + fireEvent( + screen.getByText('props'), + new CustomEvent('osProps', { + detail: { element: elementB }, + }) + ); + + expect(container.querySelector(elementB)).toBe(container.firstElementChild); + + expect(OverlayScrollbars.valid(osInstance)).toBe(false); // prev instance is destroyed + osInstance = OverlayScrollbars(container.firstElementChild as HTMLElement); + expect(osInstance).toBeDefined(); + expect(OverlayScrollbars.valid(osInstance)).toBe(true); + }); + + test('data-overlayscrollbars-initialize', async () => { + const { container } = render(() => ); + + expect(container.querySelector('[data-overlayscrollbars-initialize]')).toBeTruthy(); + }); + + test('children', () => { + const { container } = render(() => ( + + hello solid + + )); + expect(screen.getByText(/hello/)).toBeInTheDocument(); + expect(screen.getByText(/solid/)).toBeInTheDocument(); + expect(screen.getByText(/solid/).parentElement).not.toBe(container.firstElementChild); + }); + + test('dynamic children', async () => { + render(() => { + const [elements, setElements] = createSignal(1); + return ( + <> + + {elements() === 0 ? 'empty' : null} + {[...Array(elements()).keys()].map((i) => ( + {i} + ))} + + + + + ); + }); + + const addBtn = screen.getByText('add'); + const removeBtn = screen.getByText('remove'); + const initialElement = screen.getByText('0'); + expect(initialElement).toBeInTheDocument(); + + const initialElementParent = initialElement.parentElement; + expect(initialElementParent).toBeInTheDocument(); + + userEvent.click(addBtn); + expect((await screen.findByText('1')).parentElement).toBe(initialElementParent); + + userEvent.click(removeBtn); + userEvent.click(removeBtn); + expect(await screen.findByText('empty')).toBe(initialElementParent); + }); + + test('className', () => { + const { container } = render( + createTestComponent({ + className: 'overlay scrollbars', + }) + ); + + expect(container.firstElementChild).toHaveClass('overlay', 'scrollbars'); + + fireEvent( + screen.getByText('props'), + new CustomEvent('osProps', { + detail: { className: 'overlay scrollbars solid' }, + }) + ); + + expect(container.firstElementChild).toHaveClass('overlay', 'scrollbars', 'solid'); + }); + + test('style', () => { + const { container } = render( + createTestComponent({ + style: { width: '22px' }, + }) + ); + + expect(container.firstElementChild).toHaveStyle({ width: '22px' }); + + fireEvent( + screen.getByText('props'), + new CustomEvent('osProps', { + detail: { style: { height: '33px' } }, + }) + ); + + expect(container.firstElementChild).toHaveStyle({ height: '33px' }); + }); + }); + + test('ref', () => { + let osRef: OverlayScrollbarsComponentRef | undefined; + const { container } = render( + createTestComponent({ + getRef(ref: any) { + osRef = ref; + }, + }) + ); + + expect(osRef).toBeTruthy(); + + const { osInstance, getElement } = osRef!; + expect(osInstance).toBeTypeOf('function'); + expect(getElement).toBeTypeOf('function'); + expect(OverlayScrollbars.valid(osInstance())).toBe(true); + expect(getElement()).toBe(container.firstElementChild); + }); + + test('options', () => { + let osRef: OverlayScrollbarsComponentRef | undefined; + render( + createTestComponent({ + options: { paddingAbsolute: true, overflow: { y: 'hidden' } }, + getRef(ref: any) { + osRef = ref; + }, + }) + ); + + const instance = osRef!.osInstance()!; + + const opts = instance.options(); + expect(opts.paddingAbsolute).toBe(true); + expect(opts.overflow.y).toBe('hidden'); + + fireEvent( + screen.getByText('props'), + new CustomEvent('osProps', { + detail: { + options: { overflow: { x: 'hidden' } }, + }, + }) + ); + + const newOpts = instance.options(); + expect(newOpts.paddingAbsolute).toBe(false); //switches back to default because its not specified in the new options + expect(newOpts.overflow.x).toBe('hidden'); + expect(newOpts.overflow.y).toBe('scroll'); //switches back to default because its not specified in the new options + + // instance didn't change + expect(instance).toBe(osRef!.osInstance()); + + fireEvent( + screen.getByText('props'), + new CustomEvent('osProps', { + detail: { + element: 'span', + options: { overflow: { x: 'hidden', y: 'hidden' } }, + }, + }) + ); + + const newElementInstance = osRef!.osInstance()!; + const newElementNewOpts = newElementInstance.options(); + expect(newElementInstance).not.toBe(instance); + expect(newElementNewOpts.paddingAbsolute).toBe(false); + expect(newElementNewOpts.overflow.x).toBe('hidden'); + expect(newElementNewOpts.overflow.y).toBe('hidden'); + + // reset options with `undefined`, `null`, `false` or `{}` + fireEvent( + screen.getByText('props'), + new CustomEvent('osProps', { + detail: { + options: undefined, + }, + }) + ); + + const clearedOpts = newElementInstance.options(); + expect(osRef!.osInstance()).toBe(newElementInstance); + expect(clearedOpts.paddingAbsolute).toBe(false); + expect(clearedOpts.overflow.x).toBe('scroll'); + expect(clearedOpts.overflow.y).toBe('scroll'); + }); + + test('events', () => { + const onUpdatedInitial = vitest.fn(); + const onUpdated = vitest.fn(); + let osRef: OverlayScrollbarsComponentRef | undefined; + render( + createTestComponent({ + events: { updated: onUpdatedInitial }, + getRef: (ref: any) => { + osRef = ref; + }, + }) + ); + + const instance = osRef!.osInstance()!; + + expect(onUpdatedInitial).toHaveBeenCalledTimes(1); + + fireEvent( + screen.getByText('props'), + new CustomEvent('osProps', { + detail: { + events: { updated: onUpdated }, + }, + }) + ); + expect(onUpdated).not.toHaveBeenCalled(); + + instance.update(true); + expect(onUpdatedInitial).toHaveBeenCalledTimes(1); + expect(onUpdated).toHaveBeenCalledTimes(1); + + fireEvent( + screen.getByText('props'), + new CustomEvent('osProps', { + detail: { + events: { updated: [onUpdated, onUpdatedInitial] }, + }, + }) + ); + + instance.update(true); + expect(onUpdatedInitial).toHaveBeenCalledTimes(2); + expect(onUpdated).toHaveBeenCalledTimes(2); + + // unregister with `[]`, `null` or `undefined` + fireEvent( + screen.getByText('props'), + new CustomEvent('osProps', { + detail: { + events: { updated: null }, + }, + }) + ); + + instance.update(true); + expect(onUpdatedInitial).toHaveBeenCalledTimes(2); + expect(onUpdated).toHaveBeenCalledTimes(2); + + // instance didn't change + expect(instance).toBe(osRef!.osInstance()); + + fireEvent( + screen.getByText('props'), + new CustomEvent('osProps', { + detail: { element: 'span', events: { updated: [onUpdated, onUpdatedInitial] } }, + }) + ); + + const newElementInstance = osRef!.osInstance()!; + expect(newElementInstance).not.toBe(instance); + expect(onUpdatedInitial).toHaveBeenCalledTimes(3); + expect(onUpdated).toHaveBeenCalledTimes(3); + + // reset events with `undefined`, `null`, `false` or `{}` + fireEvent( + screen.getByText('props'), + new CustomEvent('osProps', { + detail: { element: 'span', events: undefined }, + }) + ); + + newElementInstance.update(true); + expect(newElementInstance).toBe(osRef!.osInstance()); + expect(onUpdatedInitial).toHaveBeenCalledTimes(3); + expect(onUpdated).toHaveBeenCalledTimes(3); + }); + + test('destroy', () => { + let osRef: OverlayScrollbarsComponentRef | undefined; + const { unmount } = render( + createTestComponent({ + getRef(ref: any) { + osRef = ref; + }, + }) + ); + const { osInstance } = osRef!; + + expect(OverlayScrollbars.valid(osInstance())).toBe(true); + + unmount(); + + expect(osInstance()).toBeDefined(); + expect(OverlayScrollbars.valid(osInstance())).toBe(false); + }); +}); diff --git a/packages/overlayscrollbars-solid/test/createOverlayScrollbars.test.tsx b/packages/overlayscrollbars-solid/test/createOverlayScrollbars.test.tsx new file mode 100644 index 0000000..65be463 --- /dev/null +++ b/packages/overlayscrollbars-solid/test/createOverlayScrollbars.test.tsx @@ -0,0 +1,186 @@ +import { describe, test, afterEach, expect, vitest } from 'vitest'; +import { createSignal, createEffect, onMount } from 'solid-js'; +import { createStore } from 'solid-js/store'; +import { render, screen, cleanup } from 'solid-testing-library'; +import userEvent from '@testing-library/user-event'; +import { createOverlayScrollbars } from '~/overlayscrollbars-solid'; +import type { OverlayScrollbars, PartialOptions, EventListeners } from 'overlayscrollbars'; + +describe('OverlayScrollbarsComponent', () => { + afterEach(() => cleanup()); + + test('re-initialization', () => { + const Test = () => { + let instanceRef: OverlayScrollbars | null = null; + const [initialize, instance] = createOverlayScrollbars(); + return ( + <> + + + ); + }; + + render(Test); + + const initializeBtn = screen.getByRole('button'); + userEvent.click(initializeBtn); + // taking snapshot here wouldn't be equal because of "tabindex" attribute of the viewport element + userEvent.click(initializeBtn); + const snapshot = initializeBtn.innerHTML; + userEvent.click(initializeBtn); + + expect(snapshot).toBe(initializeBtn.innerHTML); + }); + + test('params store', () => { + let osInstance: OverlayScrollbars; + const onUpdated = vitest.fn(); + render(() => { + let div: HTMLDivElement; + const [params, setParams] = createStore<{ + options?: PartialOptions; + events?: EventListeners; + }>({}); + const [initialize, instance] = createOverlayScrollbars(params); + + onMount(() => { + osInstance = initialize({ target: div! }); + }); + + createEffect(() => { + if (params.events?.updated) { + instance()?.update(true); + } + }); + + return () => ( + <> +
+ + + ); + }); + + expect(onUpdated).not.toHaveBeenCalled(); + + const triggerBtn = screen.getByRole('button'); + userEvent.click(triggerBtn); + + expect(onUpdated).toHaveBeenCalledTimes(1); + expect(osInstance!.options().paddingAbsolute).toBe(true); + }); + + test('params signal', () => { + let osInstance: OverlayScrollbars; + const onUpdated = vitest.fn(); + render(() => { + let div: HTMLDivElement; + const [params, setParams] = createSignal<{ + options?: PartialOptions; + events?: EventListeners; + }>({}); + const [initialize, instance] = createOverlayScrollbars(params); + + onMount(() => { + osInstance = initialize({ target: div! }); + }); + + createEffect(() => { + if (params().events?.updated) { + instance()?.update(true); + } + }); + + return () => ( + <> +
+ + + ); + }); + + expect(onUpdated).not.toHaveBeenCalled(); + + const triggerBtn = screen.getByRole('button'); + userEvent.click(triggerBtn); + + expect(onUpdated).toHaveBeenCalledTimes(1); + expect(osInstance!.options().paddingAbsolute).toBe(true); + }); + + test('params fields signal', async () => { + let osInstance: OverlayScrollbars; + const onUpdated = vitest.fn(); + render(() => { + let div: HTMLDivElement; + const [options, setOptions] = createSignal(); + const [events, setEvents] = createSignal(); + const [initialize, instance] = createOverlayScrollbars({ + options, + events, + }); + + onMount(() => { + osInstance = initialize({ target: div! }); + }); + + createEffect(() => { + if (events()?.updated) { + instance()?.update(true); + } + }); + + return () => ( + <> +
+ + + ); + }); + + expect(onUpdated).not.toHaveBeenCalled(); + + const triggerBtn = screen.getByRole('button'); + userEvent.click(triggerBtn); + + expect(onUpdated).toHaveBeenCalledTimes(1); + expect(osInstance!.options().paddingAbsolute).toBe(true); + }); +}); diff --git a/packages/overlayscrollbars-solid/tsconfig.json b/packages/overlayscrollbars-solid/tsconfig.json new file mode 100644 index 0000000..3f6ca9d --- /dev/null +++ b/packages/overlayscrollbars-solid/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "@~local/tsconfig", + "compilerOptions": { + "strict": true, + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "types": ["vite/client", "jest", "@testing-library/jest-dom"], + "isolatedModules": true, + "paths": { + "~/*": ["./src/*"] + } + } +} diff --git a/packages/overlayscrollbars-solid/tsconfig.types.json b/packages/overlayscrollbars-solid/tsconfig.types.json new file mode 100644 index 0000000..aeec63a --- /dev/null +++ b/packages/overlayscrollbars-solid/tsconfig.types.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src/", + "outDir": "./dist/types", + "declaration": true + }, + "include": ["src/**/*"] +} \ No newline at end of file diff --git a/packages/overlayscrollbars-solid/vite.config.js b/packages/overlayscrollbars-solid/vite.config.js new file mode 100644 index 0000000..643b825 --- /dev/null +++ b/packages/overlayscrollbars-solid/vite.config.js @@ -0,0 +1,62 @@ +import { resolve } from 'node:path'; +import { defineConfig } from 'vite'; +import { esbuildResolve } from 'rollup-plugin-esbuild-resolve'; +import solidPlugin from 'vite-plugin-solid'; +import rollupPluginPackageJson from '@~local/rollup/plugin/packageJson'; +import rollupPluginCopy from '@~local/rollup/plugin/copy'; + +export default defineConfig({ + build: { + sourcemap: true, + outDir: 'dist', + lib: { + formats: ['es', 'cjs'], + entry: resolve(__dirname, 'src/overlayscrollbars-solid.ts'), + name: 'OverlayScrollbarsSolid', + fileName: (format) => `overlayscrollbars-solid.${format}.js`, + }, + rollupOptions: { + external: ['solid-js', 'solid-js/web', 'solid-js/store', 'overlayscrollbars'], + output: { + globals: { + overlayscrollbars: 'OverlayScrollbarsGlobal', + }, + }, + plugins: [ + rollupPluginCopy({ paths: ['README.md', 'CHANGELOG.md'] }), + rollupPluginPackageJson({ + json: ({ + name, + version, + description, + author, + license, + homepage, + bugs, + repository, + keywords, + peerDependencies, + }) => { + return { + name, + version, + description, + author, + license, + homepage, + bugs, + repository, + keywords, + main: 'overlayscrollbars-vue.cjs.js', + module: 'overlayscrollbars-vue.es.js', + types: 'types/overlayscrollbars-vue.d.ts', + peerDependencies, + sideEffects: false, + }; + }, + }), + ], + }, + }, + plugins: [esbuildResolve(), solidPlugin()], +}); diff --git a/packages/overlayscrollbars-solid/vitest.config.js b/packages/overlayscrollbars-solid/vitest.config.js new file mode 100644 index 0000000..bb12a57 --- /dev/null +++ b/packages/overlayscrollbars-solid/vitest.config.js @@ -0,0 +1,20 @@ +import { mergeConfig } from 'vite'; +import vitestConfig from '@~local/config/vitest'; +import viteConfig from './vite.config'; + +export default mergeConfig( + { + ...viteConfig, + resolve: { + conditions: ['development', 'browser'], + }, + }, + { + test: { + ...vitestConfig.test, + deps: { + inline: [/solid-testing-library/], + }, + }, + } +); diff --git a/packages/overlayscrollbars-svelte/test/OverlayScrollbarsComponent.test.ts b/packages/overlayscrollbars-svelte/test/OverlayScrollbarsComponent.test.ts index 25ff18f..d5e01d3 100644 --- a/packages/overlayscrollbars-svelte/test/OverlayScrollbarsComponent.test.ts +++ b/packages/overlayscrollbars-svelte/test/OverlayScrollbarsComponent.test.ts @@ -3,7 +3,7 @@ import { cleanup, render, screen, fireEvent } from '@testing-library/svelte'; import userEvent from '@testing-library/user-event'; import { OverlayScrollbars } from 'overlayscrollbars'; import { OverlayScrollbarsComponent } from '~/index'; // eslint-disable-line import/named -import type { OverlayScrollbarsComponentRef } from '~/index'; // eslint-disable-line import/named +import type { OverlayScrollbarsComponentRef } from '~/OverlayScrollbarsComponent.types'; // eslint-disable-line import/named import Test from './Test.svelte'; /**