├── .nvmrc ├── packages ├── website │ ├── README.md │ ├── .prettierignore │ ├── src │ │ ├── images │ │ │ ├── browserstack.png │ │ │ ├── users │ │ │ │ ├── zulip.svg │ │ │ │ ├── twitch.svg │ │ │ │ └── storybook.svg │ │ │ └── favicon.svg │ │ ├── components │ │ │ ├── List.js │ │ │ ├── SEO.js │ │ │ ├── Playground.js │ │ │ └── Layout.js │ │ ├── pages │ │ │ ├── 404.js │ │ │ ├── examples.js │ │ │ └── index.js │ │ ├── theme.js │ │ ├── html.js │ │ └── demo.css │ ├── gatsby-node.js │ ├── .prettierrc │ ├── gatsby-ssr.js │ ├── gatsby-config.js │ ├── gatsby-browser.js │ ├── LICENSE │ ├── .gitignore │ └── package.json ├── examples │ ├── .gitignore │ ├── .eslintrc.json │ ├── index.js │ ├── .babelrc │ ├── public │ │ ├── index.html │ │ └── css │ │ │ └── demo.css │ ├── bundle.js.LICENSE.txt │ ├── webpack.config.js │ ├── package.json │ └── Playground.js ├── simplebar │ ├── .gitignore │ ├── .env │ ├── jest-unit.config.js │ ├── .babelrc.json │ ├── tests │ │ └── simplebar.test.js │ ├── package.json │ └── rollup.config.mjs ├── simplebar-core │ ├── .gitignore │ ├── global-teardown.js │ ├── jest-unit.config.js │ ├── .babelrc.json │ ├── jest-e2e.config.js │ ├── README.md │ ├── global-setup.js │ ├── src │ │ ├── scrollbar-width.ts │ │ ├── helpers.ts │ │ └── simplebar.css │ ├── rollup.config.mjs │ ├── jest-puppeteer.config.js │ ├── package.json │ └── tests │ │ ├── simplebar.test.e2e.js │ │ └── simplebar.test.ts ├── simplebar-react │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── jest.config.js │ ├── rollup.config.mjs │ ├── package.json │ ├── tests │ │ ├── index.test.tsx │ │ └── __snapshots__ │ │ │ └── index.test.tsx.snap │ ├── index.tsx │ └── README.md ├── simplebar-vue │ ├── index.ts │ ├── tsconfig.json │ ├── utils.ts │ ├── tests │ │ ├── test-utils.ts │ │ ├── __snapshots__ │ │ │ └── index.test.ts.snap │ │ └── index.test.ts │ ├── jest.config.js │ ├── rollup.config.mjs │ ├── package.json │ ├── simplebar-vue.d.ts │ ├── scripts │ │ └── swap-vue.js │ └── README.md └── simplebar-angular │ ├── src │ ├── lib │ │ ├── simplebar-angular.component.scss │ │ ├── simplebar-angular.module.ts │ │ ├── simplebar-angular.component.html │ │ ├── simplebar-angular.component.spec.ts │ │ └── simplebar-angular.component.ts │ └── public-api.ts │ ├── ng-package.json │ ├── tsconfig.spec.json │ ├── tsconfig.lib.json │ ├── tsconfig.lib.prod.json │ ├── .editorconfig │ ├── test-setup.ts │ ├── .gitignore │ ├── tsconfig.json │ ├── karma.conf.js │ ├── angular.json │ ├── package.json │ ├── tslint.json │ └── README.md ├── .prettierrc ├── jest-setup.ts ├── logo.eps ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── questions.md │ ├── bug_report.md │ └── feature_request.md └── ISSUE_TEMPLATE.md ├── web.sketch ├── examples ├── vue-2.7 │ ├── .babelrc │ ├── src │ │ ├── main.js │ │ └── App.vue │ ├── README.md │ ├── public │ │ └── index.html │ └── package.json ├── vue-3 │ ├── .babelrc │ ├── src │ │ ├── main.js │ │ └── App.vue │ ├── README.md │ ├── public │ │ └── index.html │ └── package.json ├── react │ ├── src │ │ ├── index.css │ │ ├── index.js │ │ ├── App.test.js │ │ ├── App.css │ │ ├── App.js │ │ ├── logo.svg │ │ └── registerServiceWorker.js │ ├── public │ │ ├── favicon.ico │ │ ├── manifest.json │ │ └── index.html │ ├── .gitignore │ └── package.json ├── angular │ ├── src │ │ ├── styles.css │ │ ├── app │ │ │ ├── app.routes.ts │ │ │ ├── app.component.css │ │ │ ├── app.config.ts │ │ │ ├── app.component.ts │ │ │ ├── app.component.spec.ts │ │ │ └── app.component.html │ │ ├── main.ts │ │ └── index.html │ ├── public │ │ └── favicon.ico │ ├── .vscode │ │ ├── extensions.json │ │ ├── launch.json │ │ └── tasks.json │ ├── .editorconfig │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ ├── .gitignore │ ├── tsconfig.json │ ├── README.md │ ├── package.json │ └── angular.json └── jquery │ └── index.html ├── .gitignore ├── lerna.json ├── .editorconfig ├── tsconfig.json ├── .travis.yml ├── .eslintrc.json ├── rollup.config.mjs ├── LICENSE ├── package.json └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 20.11.1 2 | -------------------------------------------------------------------------------- /packages/website/README.md: -------------------------------------------------------------------------------- 1 | ../../README.md -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /jest-setup.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | -------------------------------------------------------------------------------- /logo.eps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Grsmto/simplebar/HEAD/logo.eps -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: grsmto 2 | buy_me_a_coffee: adriendenat 3 | -------------------------------------------------------------------------------- /packages/examples/.gitignore: -------------------------------------------------------------------------------- 1 | bundle.js 2 | bundle.js.map 3 | .env 4 | -------------------------------------------------------------------------------- /packages/simplebar/.gitignore: -------------------------------------------------------------------------------- 1 | bundle.js 2 | bundle.js.map 3 | .env 4 | -------------------------------------------------------------------------------- /web.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Grsmto/simplebar/HEAD/web.sketch -------------------------------------------------------------------------------- /examples/vue-2.7/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "vue" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /examples/vue-3/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "vue" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/simplebar-core/.gitignore: -------------------------------------------------------------------------------- 1 | bundle.js 2 | bundle.js.map 3 | .env 4 | -------------------------------------------------------------------------------- /packages/simplebar/.env: -------------------------------------------------------------------------------- 1 | BROWSERSTACK_USERNAME= 2 | BROWSERSTACK_ACCESS_KEY= 3 | -------------------------------------------------------------------------------- /packages/examples/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:react/recommended"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/website/.prettierignore: -------------------------------------------------------------------------------- 1 | .cache 2 | package.json 3 | package-lock.json 4 | public 5 | -------------------------------------------------------------------------------- /packages/simplebar-react/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:react/recommended"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/simplebar-vue/index.ts: -------------------------------------------------------------------------------- 1 | import simplebar from './component'; 2 | 3 | export default simplebar; 4 | -------------------------------------------------------------------------------- /examples/react/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /examples/angular/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /examples/react/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Grsmto/simplebar/HEAD/examples/react/public/favicon.ico -------------------------------------------------------------------------------- /packages/simplebar-angular/src/lib/simplebar-angular.component.scss: -------------------------------------------------------------------------------- 1 | ngx-simplebar { 2 | display: block; 3 | } 4 | -------------------------------------------------------------------------------- /examples/angular/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Grsmto/simplebar/HEAD/examples/angular/public/favicon.ico -------------------------------------------------------------------------------- /examples/angular/src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | export const routes: Routes = []; 4 | -------------------------------------------------------------------------------- /examples/vue-3/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | 4 | createApp(App).mount('#app'); 5 | -------------------------------------------------------------------------------- /packages/website/src/images/browserstack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Grsmto/simplebar/HEAD/packages/website/src/images/browserstack.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .temp 4 | dist 5 | yarn-error.log 6 | .next 7 | .env 8 | .idea 9 | yalc.lock 10 | .yalc 11 | local.log 12 | -------------------------------------------------------------------------------- /packages/website/gatsby-node.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Node APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/node-apis/ 5 | */ 6 | -------------------------------------------------------------------------------- /packages/simplebar-vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["**/*.ts", "**/*.tsx", "**/*.js", "../../jest-setup.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/website/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /examples/angular/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "2.11.0", 3 | "version": "independent", 4 | "npmClient": "yarn", 5 | "useWorkspaces": true, 6 | "ignoreChanges": ["**/demo/**", "**/*.md"] 7 | } 8 | -------------------------------------------------------------------------------- /examples/vue-2.7/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | 4 | Vue.config.productionTip = false; 5 | 6 | new Vue({ 7 | render: h => h(App) 8 | }).$mount('#app'); 9 | -------------------------------------------------------------------------------- /packages/simplebar-angular/src/public-api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of simplebar-angular 3 | */ 4 | 5 | export * from './lib/simplebar-angular.component'; 6 | export * from './lib/simplebar-angular.module'; 7 | -------------------------------------------------------------------------------- /packages/simplebar-react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": ["**/*.ts", "**/*.tsx", "**/*.js", "../../jest-setup.ts"], 4 | "compilerOptions": { 5 | "jsx": "react" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/simplebar-vue/utils.ts: -------------------------------------------------------------------------------- 1 | import { isVue3 } from 'vue-demi'; 2 | 3 | export const lifecycleEventNames = { 4 | beforeUnmount: isVue3 ? 'beforeUnmount' : 'beforeDestroy', 5 | unmount: isVue3 ? 'unmount' : 'destroy', 6 | }; 7 | -------------------------------------------------------------------------------- /packages/website/gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's SSR (Server Side Rendering) APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/ssr-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /packages/examples/index.js: -------------------------------------------------------------------------------- 1 | import 'core-js/stable'; 2 | import React from 'react'; 3 | import { createRoot } from 'react-dom/client'; 4 | 5 | import Demo from './Demo'; 6 | 7 | const root = createRoot(document.getElementById('root')); 8 | root.render(); 9 | -------------------------------------------------------------------------------- /packages/simplebar-angular/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "./dist", 4 | "lib": { 5 | "entryFile": "src/public-api.ts" 6 | }, 7 | "allowedNonPeerDependencies": ["simplebar-core"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/simplebar-angular/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": ["jasmine"] 6 | }, 7 | "files": ["test-setup.ts"], 8 | "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | indent_style = space 9 | 10 | [**.js] 11 | indent_size = 2 12 | 13 | [**.css] 14 | indent_size = 2 15 | 16 | [**.html] 17 | indent_size = 2 18 | -------------------------------------------------------------------------------- /examples/angular/src/main.ts: -------------------------------------------------------------------------------- 1 | import { bootstrapApplication } from '@angular/platform-browser'; 2 | import { appConfig } from './app/app.config'; 3 | import { AppComponent } from './app/app.component'; 4 | 5 | bootstrapApplication(AppComponent, appConfig).catch((err) => 6 | console.error(err) 7 | ); 8 | -------------------------------------------------------------------------------- /examples/react/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | registerServiceWorker(); 9 | -------------------------------------------------------------------------------- /examples/react/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /examples/angular/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | .container { 2 | border-radius: 6px; 3 | width: 200px; 4 | height: 200px; 5 | position: absolute; 6 | top: 0; 7 | left: 0; 8 | right: 0; 9 | bottom: 0; 10 | border: 1px dashed; 11 | margin: auto; 12 | } 13 | 14 | ngx-simplebar { 15 | height: 100%; 16 | } 17 | -------------------------------------------------------------------------------- /packages/simplebar-angular/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/lib", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "exclude": ["src/test.ts", "**/*.spec.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /packages/simplebar-angular/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.lib.json", 4 | "compilerOptions": { 5 | "declarationMap": false 6 | }, 7 | "angularCompilerOptions": { 8 | "compilationMode": "partial" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/website/src/components/List.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { jsx } from "theme-ui" 3 | 4 | const List = ({ children, ...otherProps }) => ( 5 |
    12 | {children} 13 |
14 | ) 15 | 16 | export default List 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts", "**/*.tsx", "**/*.js"], 3 | "compilerOptions": { 4 | "strict": true, 5 | "esModuleInterop": true, 6 | "skipLibCheck": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "outDir": "dist", 9 | "declaration": true, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/simplebar-angular/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /packages/simplebar/jest-unit.config.js: -------------------------------------------------------------------------------- 1 | const { defaults: tsjPreset } = require('ts-jest/presets'); 2 | 3 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 4 | module.exports = { 5 | preset: 'ts-jest', 6 | transform: { 7 | ...tsjPreset.transform, 8 | '^.+\\.js?$': 'babel-jest', 9 | }, 10 | testEnvironment: 'jsdom', 11 | }; 12 | -------------------------------------------------------------------------------- /examples/angular/src/app/app.config.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; 2 | import { provideRouter } from '@angular/router'; 3 | 4 | import { routes } from './app.routes'; 5 | 6 | export const appConfig: ApplicationConfig = { 7 | providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)] 8 | }; 9 | -------------------------------------------------------------------------------- /examples/angular/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /examples/angular/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | angular 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/simplebar-core/global-teardown.js: -------------------------------------------------------------------------------- 1 | const { teardown: teardownPuppeteer } = require('jest-environment-puppeteer'); 2 | 3 | module.exports = async function globalTeardown(globalConfig) { 4 | await new Promise((resolve) => { 5 | globalThis.__BROWSERSTACK_LOCAL__.stop(() => { 6 | resolve(); 7 | }); 8 | }); 9 | await teardownPuppeteer(globalConfig); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/simplebar-angular/src/lib/simplebar-angular.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { SimplebarAngularComponent } from './simplebar-angular.component'; 3 | 4 | @NgModule({ 5 | declarations: [SimplebarAngularComponent], 6 | imports: [], 7 | exports: [SimplebarAngularComponent], 8 | schemas: [], 9 | }) 10 | export class SimplebarAngularModule {} 11 | -------------------------------------------------------------------------------- /examples/react/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /packages/simplebar-angular/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'zone.js'; // Included with Angular CLI. 2 | import { TestBed } from '@angular/core/testing'; 3 | import { 4 | BrowserDynamicTestingModule, 5 | platformBrowserDynamicTesting, 6 | } from '@angular/platform-browser-dynamic/testing'; 7 | 8 | TestBed.initTestEnvironment( 9 | BrowserDynamicTestingModule, 10 | platformBrowserDynamicTesting() 11 | ); 12 | -------------------------------------------------------------------------------- /packages/simplebar/.babelrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": ["transform-class-properties"], 4 | "env": { 5 | "test": { 6 | "presets": [ 7 | [ 8 | "@babel/preset-env", 9 | { 10 | "targets": { 11 | "node": "current" 12 | } 13 | } 14 | ] 15 | ] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/simplebar-react/jest.config.js: -------------------------------------------------------------------------------- 1 | const { defaults: tsjPreset } = require('ts-jest/presets'); 2 | 3 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 4 | module.exports = { 5 | preset: 'ts-jest', 6 | transform: { 7 | ...tsjPreset.transform, 8 | '^.+\\.js?$': 'babel-jest', 9 | }, 10 | testEnvironment: 'jsdom', 11 | setupFilesAfterEnv: ['/../../jest-setup.ts'], 12 | }; 13 | -------------------------------------------------------------------------------- /packages/website/src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | import Layout from "../components/Layout" 4 | import SEO from "../components/SEO" 5 | 6 | const NotFoundPage = () => ( 7 | 8 | 9 |

NOT FOUND

10 |

You just hit a route that doesn't exist... the sadness.

11 |
12 | ) 13 | 14 | export default NotFoundPage 15 | -------------------------------------------------------------------------------- /examples/react/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /examples/vue-3/README.md: -------------------------------------------------------------------------------- 1 | # SimpleBar Vue Example 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Run your tests 19 | ``` 20 | npm run test 21 | ``` 22 | 23 | ### Lints and fixes files 24 | ``` 25 | npm run lint 26 | ``` 27 | -------------------------------------------------------------------------------- /examples/vue-2.7/README.md: -------------------------------------------------------------------------------- 1 | # SimpleBar Vue Example 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Run your tests 19 | ``` 20 | npm run test 21 | ``` 22 | 23 | ### Lints and fixes files 24 | ``` 25 | npm run lint 26 | ``` 27 | -------------------------------------------------------------------------------- /packages/simplebar-core/jest-unit.config.js: -------------------------------------------------------------------------------- 1 | const { defaults: tsjPreset } = require('ts-jest/presets'); 2 | 3 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 4 | module.exports = { 5 | preset: 'ts-jest', 6 | transform: { 7 | ...tsjPreset.transform, 8 | '^.+\\.js?$': 'babel-jest', 9 | }, 10 | moduleNameMapper: { 11 | '^lodash-es/*(.*)$': 'lodash/$1', 12 | }, 13 | testEnvironment: 'jsdom', 14 | }; 15 | -------------------------------------------------------------------------------- /packages/simplebar-core/.babelrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-typescript"], 3 | "plugins": ["transform-class-properties"], 4 | "env": { 5 | "test": { 6 | "presets": [ 7 | [ 8 | "@babel/preset-env", 9 | { 10 | "targets": { 11 | "node": "current" 12 | } 13 | } 14 | ] 15 | ] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^16.4.1", 7 | "react-dom": "^16.4.1", 8 | "react-scripts": "latest", 9 | "simplebar-react": "latest" 10 | }, 11 | "scripts": { 12 | "start": "react-scripts start", 13 | "build": "react-scripts build", 14 | "test": "react-scripts test --env=jsdom", 15 | "eject": "react-scripts eject" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/questions.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Questions / Help 3 | about: If you have questions, please read full readme first 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## 💬 Questions and Help 11 | 12 | Please before asking your question: 13 | 14 | - Read carefully the README of the project 15 | - Search if your answer has already been answered in old issues 16 | 17 | After you can submit your question and we will be happy to help you! 18 | -------------------------------------------------------------------------------- /packages/simplebar-core/jest-e2e.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'jest-puppeteer', 3 | testRegex: '^.+\\.test\\.e2e\\.js$', 4 | transform: { 5 | '^.+\\.js?$': 'babel-jest', 6 | }, 7 | transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$'], 8 | moduleFileExtensions: ['js'], 9 | moduleNameMapper: { 10 | '^lodash-es$': 'lodash', 11 | }, 12 | ...(process.env.CI === 'true' && { maxWorkers: 2, testTimeout: 15000 }), 13 | globalSetup: './global-setup.js', 14 | }; 15 | -------------------------------------------------------------------------------- /examples/angular/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "extends": "./tsconfig.json", 5 | "compilerOptions": { 6 | "outDir": "./out-tsc/app", 7 | "types": [] 8 | }, 9 | "files": [ 10 | "src/main.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/simplebar-vue/tests/test-utils.ts: -------------------------------------------------------------------------------- 1 | import { isVue3 } from 'vue-demi'; 2 | import { lifecycleEventNames } from '../utils'; 3 | 4 | export const vtu = isVue3 5 | ? require('@vue/test-utils') 6 | : require('@vue/test-utils-vue2'); 7 | 8 | const { config } = vtu; 9 | 10 | if (isVue3) { 11 | config.global.renderStubDefaultSlot = true; 12 | } 13 | 14 | export function destroyWrapper(wrapper: any) { 15 | if (wrapper) wrapper[lifecycleEventNames.unmount](); 16 | } 17 | 18 | export const { shallowMount } = vtu; 19 | -------------------------------------------------------------------------------- /examples/angular/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "extends": "./tsconfig.json", 5 | "compilerOptions": { 6 | "outDir": "./out-tsc/spec", 7 | "types": [ 8 | "jasmine" 9 | ] 10 | }, 11 | "include": [ 12 | "src/**/*.spec.ts", 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /examples/react/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 80px; 8 | } 9 | 10 | .App-header { 11 | background-color: #222; 12 | height: 150px; 13 | padding: 20px; 14 | color: white; 15 | } 16 | 17 | .App-title { 18 | font-size: 1.5em; 19 | } 20 | 21 | .App-intro { 22 | font-size: large; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { transform: rotate(0deg); } 27 | to { transform: rotate(360deg); } 28 | } 29 | -------------------------------------------------------------------------------- /packages/simplebar-core/README.md: -------------------------------------------------------------------------------- 1 | # SimpleBar Core 2 | 3 | - **🐦 Follow me on [Twitter!](https://twitter.com/adriendenat) or [Mastodon!](https://mas.to/@adrien)** 4 | - **👨‍💻 I'm available for hire! [Reach out to me!](https://adriendenat.com/)** 5 | - **🚧 Check out my new project [Scroll Snap Carousel](https://github.com/Grsmto/scroll-snap-carousel)!** 6 | 7 | ### This is the core library. You should not use it directly. If you want the vanilla plugin, see [SimpleBar](https://github.com/Grsmto/simplebar/tree/master/packages/simplebar). 8 | -------------------------------------------------------------------------------- /packages/examples/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@babel/preset-env", { 3 | "useBuiltIns": "entry", 4 | "corejs": "3.27", 5 | "debug": true 6 | }], "@babel/preset-react"], 7 | "plugins": ["transform-class-properties"], 8 | "env": { 9 | "test": { 10 | "presets": [ 11 | [ 12 | "@babel/preset-env", 13 | { 14 | "targets": { 15 | "node": "current" 16 | } 17 | } 18 | ], 19 | "@babel/preset-react" 20 | ] 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/angular/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /examples/vue-3/src/App.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 13 | 14 | 24 | -------------------------------------------------------------------------------- /examples/vue-3/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | SimpleBar Vue Example 8 | 9 | 10 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/vue-2.7/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | SimpleBar Vue Example 8 | 9 | 10 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/angular/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { RouterOutlet } from '@angular/router'; 3 | import { NgFor } from '@angular/common'; 4 | import { SimplebarAngularModule } from 'simplebar-angular'; 5 | 6 | @Component({ 7 | selector: 'app-root', 8 | standalone: true, 9 | imports: [RouterOutlet, SimplebarAngularModule, NgFor], 10 | templateUrl: './app.component.html', 11 | styleUrl: './app.component.css', 12 | }) 13 | export class AppComponent { 14 | title = 'angular'; 15 | numbers = Array(50).fill(0); 16 | options = { autoHide: false }; 17 | } 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: yarn 3 | 4 | before_install: 5 | - npm i -g lerna 6 | 7 | install: 8 | - yarn 9 | 10 | script: 11 | - yarn build 12 | - yarn test 13 | 14 | deploy: 15 | provider: script 16 | skip_cleanup: true 17 | script: cd packages/website/ && yarn deploy 18 | on: 19 | branch: master 20 | 21 | addons: 22 | chrome: stable 23 | browserstack: 24 | username: 'adriengrsmto' 25 | access_key: 26 | secure: 'HUmCxQG5gsOak0EFqAHTlIBlPL2lLjbKTaYQ0rAEFMu0E4WknH5z1qqZdw9ntAo201u+Pk/jC+YmPqSF3TjpxE5vOqeVCU27YSoUhZid1iI43z7uquuiXXsBlsaQZ0o2PNDSRoWTJ9G5Dfn+YgOIyEnFYEucAIii+tLo2lZVhlY=' 27 | -------------------------------------------------------------------------------- /examples/vue-2.7/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | 25 | 30 | -------------------------------------------------------------------------------- /packages/website/src/pages/examples.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { jsx } from "theme-ui" 3 | 4 | import Layout from "../components/Layout" 5 | import SEO from "../components/SEO" 6 | import Demo from "../../../examples/Demo" 7 | 8 | import "../demo.css" 9 | 10 | const ExamplePage = () => { 11 | return ( 12 | 13 | 14 |
20 |

25 | Simplebar examples 26 |

27 | 28 |
29 |
30 | ) 31 | } 32 | 33 | export default ExamplePage 34 | -------------------------------------------------------------------------------- /packages/simplebar-vue/jest.config.js: -------------------------------------------------------------------------------- 1 | const { defaults: tsjPreset } = require('ts-jest/presets'); 2 | const { isVue3 } = require('vue-demi'); 3 | 4 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 5 | module.exports = { 6 | preset: 'ts-jest', 7 | transform: { 8 | ...tsjPreset.transform, 9 | '^.+\\.js?$': 'babel-jest', 10 | '^.+\\.vue$': isVue3 ? 'vue-jest' : 'vue-jest2', 11 | }, 12 | moduleNameMapper: { 13 | '^@/(.*)$': '/src/$1', 14 | }, 15 | testEnvironment: 'jsdom', 16 | snapshotSerializers: ['jest-serializer-vue'], 17 | testEnvironmentOptions: { 18 | url: 'http://localhost/', 19 | customExportConditions: ['node', 'node-addons'], // See https://github.com/vuejs/vue-jest/issues/479 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /packages/simplebar-angular/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /examples/angular/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /packages/simplebar-core/global-setup.js: -------------------------------------------------------------------------------- 1 | const BrowserStackLocal = require('browserstack-local'); 2 | const { setup: setupPuppeteer } = require('jest-environment-puppeteer'); 3 | 4 | const bsLocal = new BrowserStackLocal.Local(); 5 | 6 | globalThis.__BROWSERSTACK_LOCAL__ = bsLocal; 7 | 8 | const BS_LOCAL_ARGS = { 9 | key: process.env.BROWSERSTACK_ACCESS_KEY, 10 | }; 11 | 12 | // Starts the Local instance with the required arguments 13 | 14 | module.exports = async function globalSetup(globalConfig) { 15 | await new Promise((resolve) => { 16 | bsLocal.start(BS_LOCAL_ARGS, () => { 17 | // Check if BrowserStack local instance is running 18 | console.log(`BrowserStackLocal running: ${bsLocal.isRunning()}`); 19 | resolve(); 20 | }); 21 | }); 22 | await setupPuppeteer(globalConfig); 23 | }; 24 | -------------------------------------------------------------------------------- /packages/simplebar-angular/src/lib/simplebar-angular.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /packages/website/gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | pathPrefix: "/simplebar", 3 | siteMetadata: { 4 | title: `SimpleBar · Custom scrollbars made simple.`, 5 | description: `SimpleBar does only one thing: replace the browser's default scrollbar with a custom CSS-styled one without losing performances. For React, Vue, Angular or VanillaJS!`, 6 | author: `@adriendenat`, 7 | }, 8 | plugins: [ 9 | `gatsby-plugin-react-helmet`, 10 | { 11 | resolve: `gatsby-source-filesystem`, 12 | options: { 13 | name: `images`, 14 | path: `${__dirname}/src/images`, 15 | }, 16 | }, 17 | { 18 | resolve: `gatsby-source-filesystem`, 19 | options: { 20 | name: `markdown`, 21 | path: `${__dirname}/README.md`, 22 | }, 23 | }, 24 | `gatsby-transformer-remark`, 25 | ], 26 | } 27 | -------------------------------------------------------------------------------- /packages/website/gatsby-browser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Browser APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/browser-apis/ 5 | */ 6 | 7 | export const onClientEntry = () => { 8 | return new Promise((resolve, reject) => { 9 | // Polyfill.io stuff 10 | window.__polyfillio__ = () => { 11 | resolve() 12 | } 13 | 14 | const features = [] 15 | 16 | if (!("fetch" in window)) { 17 | features.push("fetch") 18 | } 19 | 20 | if (features.length) { 21 | const s = document.createElement("script") 22 | s.src = `https://cdn.polyfill.io/v3/polyfill.min.js?features=${features.join( 23 | "," 24 | )}&callback=__polyfillio__` 25 | s.async = true 26 | s.onerror = reject 27 | document.head.appendChild(s) 28 | } else { 29 | resolve() 30 | } 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Reproducible example** 24 | 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | 29 | **Your environment** 30 | 31 | | Software | Version(s) | 32 | | ---------------- | ---------- | 33 | | SimpleBar | 34 | | Browser | 35 | | npm/Yarn | 36 | | Operating System | 37 | -------------------------------------------------------------------------------- /examples/react/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import SimpleBar from 'simplebar-react'; 3 | 4 | import 'simplebar-react/dist/simplebar.min.css'; 5 | import logo from './logo.svg'; 6 | import './App.css'; 7 | 8 | class App extends Component { 9 | render() { 10 | return ( 11 |
12 |
13 | logo 14 |

Welcome to React

15 |
16 |

17 | To get started, edit src/App.js and save to reload. 18 |

19 | 20 | {[...Array(50)].map((x, i) => 21 |

Some content

22 | )} 23 |
24 |
25 | ); 26 | } 27 | } 28 | 29 | export default App; 30 | -------------------------------------------------------------------------------- /packages/examples/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SimpleBar demo 6 | 7 | 8 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": [ 4 | "eslint:recommended" 5 | ], 6 | "env": { 7 | "browser": true, 8 | "node": true, 9 | "es2020": true 10 | }, 11 | "parserOptions": { 12 | "sourceType": "module", 13 | "ecmaVersion": 2018 14 | }, 15 | "overrides": [ 16 | { 17 | "files": ["**/*.ts", "**/*.tsx"], 18 | "parser": "@typescript-eslint/parser", 19 | "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], 20 | "plugins": ["@typescript-eslint"] 21 | }, 22 | { 23 | "files": ["**/*.test?(.*).ts", "**/*.test?(.*).tsx", "**/*.test?(.*).js"], 24 | "env": { 25 | "jest": true, 26 | "jest/globals": true 27 | }, 28 | "globals": { 29 | "page": true, 30 | "browser": true, 31 | "context": true, 32 | "jestPuppeteer": true 33 | }, 34 | "plugins": ["jest"] 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | SimpleBar's mission statement is to keep things simple and stick to the native scroll behaviour as much as possible. However if you have a suggestion that falls within this approach that hasn't already been proposed, we'd love to hear it! 11 | 12 | **Is your feature request related to a problem? Please describe.** 13 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 14 | 15 | **Describe the solution you'd like** 16 | A clear and concise description of what you want to happen. 17 | 18 | **Describe alternatives you've considered** 19 | A clear and concise description of any alternative solutions or features you've considered. 20 | 21 | **Additional context** 22 | Add any other context or screenshots about the feature request here. 23 | -------------------------------------------------------------------------------- /packages/examples/bundle.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | object-assign 3 | (c) Sindre Sorhus 4 | @license MIT 5 | */ 6 | 7 | /** @license React v0.19.1 8 | * scheduler.production.min.js 9 | * 10 | * Copyright (c) Facebook, Inc. and its affiliates. 11 | * 12 | * This source code is licensed under the MIT license found in the 13 | * LICENSE file in the root directory of this source tree. 14 | */ 15 | 16 | /** @license React v16.14.0 17 | * react-dom.production.min.js 18 | * 19 | * Copyright (c) Facebook, Inc. and its affiliates. 20 | * 21 | * This source code is licensed under the MIT license found in the 22 | * LICENSE file in the root directory of this source tree. 23 | */ 24 | 25 | /** @license React v16.14.0 26 | * react.production.min.js 27 | * 28 | * Copyright (c) Facebook, Inc. and its affiliates. 29 | * 30 | * This source code is licensed under the MIT license found in the 31 | * LICENSE file in the root directory of this source tree. 32 | */ 33 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | export const getExternals = (pkg) => (id) => { 2 | if ( 3 | Object.keys(pkg.dependencies).find((dep) => id === dep) || 4 | Object.keys(pkg.peerDependencies || {}).find((dep) => id === dep) || 5 | id.match(/(lodash).+/) || 6 | id.match(/(lodash-es).+/) || 7 | id.match(/(core-js).+/) || 8 | id.match(/(@babel).+/) 9 | ) { 10 | return true; 11 | } 12 | 13 | return false; 14 | }; 15 | 16 | export const getBanner = (pkg) => ({ 17 | banner: ` 18 | ${pkg.name} - v${pkg.version} 19 | ${pkg.description} 20 | ${pkg.homepage} 21 | 22 | Made by ${pkg.author} 23 | Under ${pkg.license} License 24 | `, 25 | }); 26 | 27 | export const babelConfig = { 28 | extensions: ['.js', '.ts'], 29 | exclude: ['**/node_modules/**'], 30 | babelHelpers: 'runtime', 31 | }; 32 | 33 | export const tsConfig = { 34 | outDir: 'dist', 35 | tsconfig: '../../tsconfig.json', 36 | exclude: ['**/*.test.ts', '**/*.test.tsx', 'tests/*'], 37 | }; 38 | -------------------------------------------------------------------------------- /examples/jquery/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 25 | 26 | 27 |
28 |

↓Scrollable!↓

29 |

↓Scrollable!↓

30 |

↓Scrollable!↓

31 |

↓Scrollable!↓

32 |

↓Scrollable!↓

33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /packages/simplebar-core/src/scrollbar-width.ts: -------------------------------------------------------------------------------- 1 | import { canUseDOM } from './helpers'; 2 | 3 | let cachedScrollbarWidth: number | null = null; 4 | let cachedDevicePixelRatio: number | null = null; 5 | 6 | if (canUseDOM) { 7 | window.addEventListener('resize', () => { 8 | if (cachedDevicePixelRatio !== window.devicePixelRatio) { 9 | cachedDevicePixelRatio = window.devicePixelRatio; 10 | cachedScrollbarWidth = null; 11 | } 12 | }); 13 | } 14 | 15 | export default function scrollbarWidth() { 16 | if (cachedScrollbarWidth === null) { 17 | if (typeof document === 'undefined') { 18 | cachedScrollbarWidth = 0; 19 | return cachedScrollbarWidth; 20 | } 21 | 22 | const body = document.body; 23 | const box = document.createElement('div'); 24 | 25 | box.classList.add('simplebar-hide-scrollbar'); 26 | 27 | body.appendChild(box); 28 | 29 | const width = box.getBoundingClientRect().right; 30 | 31 | body.removeChild(box); 32 | 33 | cachedScrollbarWidth = width; 34 | } 35 | 36 | return cachedScrollbarWidth; 37 | } 38 | -------------------------------------------------------------------------------- /examples/angular/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async () => { 6 | await TestBed.configureTestingModule({ 7 | imports: [AppComponent], 8 | }).compileComponents(); 9 | }); 10 | 11 | it('should create the app', () => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.componentInstance; 14 | expect(app).toBeTruthy(); 15 | }); 16 | 17 | it(`should have the 'angular' title`, () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app.title).toEqual('angular'); 21 | }); 22 | 23 | it('should render title', () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | fixture.detectChanges(); 26 | const compiled = fixture.nativeElement as HTMLElement; 27 | expect(compiled.querySelector('h1')?.textContent).toContain( 28 | 'Hello, angular' 29 | ); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /examples/vue-2.7/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-simplebar-example", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "babel-preset-vue": "^2.0.2", 12 | "simplebar-vue": "file:../../packages/simplebar-vue", 13 | "vue": "2.7.14" 14 | }, 15 | "devDependencies": { 16 | "@vue/cli-plugin-babel": "^3.0.5", 17 | "@vue/cli-plugin-eslint": "^3.0.5", 18 | "@vue/cli-service": "^3.0.5", 19 | "vue-template-compiler": "2.7.14" 20 | }, 21 | "eslintConfig": { 22 | "root": true, 23 | "env": { 24 | "node": true 25 | }, 26 | "extends": [ 27 | "plugin:vue/essential", 28 | "eslint:recommended" 29 | ], 30 | "rules": {}, 31 | "parserOptions": { 32 | "parser": "babel-eslint" 33 | } 34 | }, 35 | "postcss": { 36 | "plugins": { 37 | "autoprefixer": {} 38 | } 39 | }, 40 | "browserslist": [ 41 | "> 1%", 42 | "last 2 versions", 43 | "not ie <= 8" 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /packages/website/src/theme.js: -------------------------------------------------------------------------------- 1 | import baseTheme from "@theme-ui/preset-base" 2 | 3 | const theme = { 4 | ...baseTheme, 5 | colors: { 6 | body: "#2e2e2e", 7 | background: "#fff", 8 | primary: "#DC8D37", 9 | }, 10 | fonts: { 11 | body: '"Nunito", sans-serif', 12 | }, 13 | fontWeights: { 14 | body: 500, 15 | bold: 700, 16 | heading: 800, 17 | }, 18 | fontSizes: { 19 | 0: "1rem", // 10px 20 | 1: "1.2rem", // 12px 21 | 2: "1.4rem", // 14px 22 | 3: "1.6rem", // 16px 23 | 4: "1.9rem", // 19px 24 | 5: "2.3rem", // 23px 25 | 6: "2.8rem", // 28px 26 | 7: "3.8rem", // 38px 27 | 8: "4.8rem", // 48px 28 | 9: "7rem", // 70px 29 | 10: "9rem", // 90px 30 | }, 31 | styles: { 32 | root: { 33 | h1: { 34 | display: "none", 35 | }, 36 | h3: { 37 | mt: 4, 38 | }, 39 | h4: { 40 | mt: 4, 41 | mb: 0, 42 | fontSize: 4, 43 | }, 44 | "p:first-of-type": { 45 | mt: 0, 46 | }, 47 | }, 48 | }, 49 | } 50 | 51 | theme.fontSizes.body = theme.fontSizes[3] 52 | 53 | export default theme 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jonathan Nicol 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /examples/angular/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /examples/vue-3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-v3-simplebar-example", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "babel-preset-vue": "^2.0.2", 12 | "simplebar-vue": "../../packages/simplebar-vue", 13 | "vue": "^3.2.45" 14 | }, 15 | "devDependencies": { 16 | "@vue/cli-plugin-babel": "^5.0.8", 17 | "@vue/cli-plugin-eslint": "^5.0.8", 18 | "@vue/cli-service": "^5.0.8", 19 | "eslint-plugin-vue": "^9.8.0", 20 | "vue-template-compiler": "^2.7.14" 21 | }, 22 | "eslintConfig": { 23 | "root": true, 24 | "env": { 25 | "node": true 26 | }, 27 | "extends": [ 28 | "plugin:vue/essential", 29 | "eslint:recommended" 30 | ], 31 | "rules": {}, 32 | "parserOptions": { 33 | "parser": "babel-eslint" 34 | } 35 | }, 36 | "postcss": { 37 | "plugins": { 38 | "autoprefixer": {} 39 | } 40 | }, 41 | "browserslist": [ 42 | "> 1%", 43 | "last 2 versions", 44 | "not ie <= 8" 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /packages/website/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 gatsbyjs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /examples/angular/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "compileOnSave": false, 5 | "compilerOptions": { 6 | "outDir": "./dist/out-tsc", 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "skipLibCheck": true, 13 | "esModuleInterop": true, 14 | "sourceMap": true, 15 | "declaration": false, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "bundler", 18 | "importHelpers": true, 19 | "target": "ES2022", 20 | "module": "ES2022", 21 | "useDefineForClassFields": false, 22 | "lib": [ 23 | "ES2022", 24 | "dom" 25 | ] 26 | }, 27 | "angularCompilerOptions": { 28 | "enableI18nLegacyMessageIdFormat": false, 29 | "strictInjectionParameters": true, 30 | "strictInputAccessModifiers": true, 31 | "strictTemplates": true 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/angular/README.md: -------------------------------------------------------------------------------- 1 | # angular 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 18.0.4. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. 28 | -------------------------------------------------------------------------------- /packages/simplebar-angular/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "ES2015", 20 | "module": "es2020", 21 | "lib": ["ES2015", "dom"], 22 | "useDefineForClassFields": false, 23 | "paths": { 24 | "simplebar-angular": ["dist/simplebar-angular"], 25 | "simplebar-angular/*": ["dist/simplebar-angular/*"] 26 | } 27 | }, 28 | "angularCompilerOptions": { 29 | "enableI18nLegacyMessageIdFormat": false, 30 | "strictInjectionParameters": true, 31 | "strictInputAccessModifiers": true, 32 | "strictTemplates": true 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/simplebar-angular/src/lib/simplebar-angular.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SimplebarAngularComponent } from './simplebar-angular.component'; 4 | 5 | describe('SimplebarAngularComponent', () => { 6 | let component: SimplebarAngularComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [SimplebarAngularComponent], 12 | }).compileComponents(); 13 | 14 | fixture = TestBed.createComponent(SimplebarAngularComponent); 15 | component = fixture.componentInstance; 16 | fixture.detectChanges(); 17 | }); 18 | 19 | it('should create', () => { 20 | expect(component).toBeTruthy(); 21 | }); 22 | 23 | it('should create with options', () => { 24 | component.options = { clickOnTrack: false }; 25 | expect(component).toBeTruthy(); 26 | }); 27 | 28 | it('should define simplebar instance', () => { 29 | expect(component.SimpleBar).toBeDefined(); 30 | }); 31 | 32 | it('should unmount', () => { 33 | fixture.destroy(); 34 | expect(component.SimpleBar).toBeNull(); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/examples/webpack.config.js: -------------------------------------------------------------------------------- 1 | const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); 2 | 3 | module.exports = (env, argv) => { 4 | const isDevelopment = argv.mode === 'development'; 5 | 6 | return { 7 | entry: './index.js', 8 | devtool: 'cheap-module-source-map', 9 | output: { 10 | filename: 'dist/bundle.js', 11 | }, 12 | performance: { 13 | hints: false, 14 | }, 15 | devServer: { 16 | port: 8090, 17 | hot: isDevelopment && true, 18 | }, 19 | module: { 20 | rules: [ 21 | { 22 | test: /\.js?$/, 23 | exclude: /node_modules/, 24 | use: [ 25 | { 26 | loader: require.resolve('babel-loader'), 27 | options: { 28 | plugins: [ 29 | isDevelopment && require.resolve('react-refresh/babel'), 30 | ].filter(Boolean), 31 | }, 32 | }, 33 | ], 34 | }, 35 | { 36 | test: /\.css$/, 37 | use: ['style-loader', 'css-loader'], 38 | }, 39 | ], 40 | }, 41 | plugins: [isDevelopment && new ReactRefreshWebpackPlugin()].filter(Boolean), 42 | }; 43 | }; 44 | -------------------------------------------------------------------------------- /packages/simplebar/tests/simplebar.test.js: -------------------------------------------------------------------------------- 1 | import { waitFor, waitForElementToBeRemoved } from '@testing-library/dom'; 2 | 3 | let SimpleBar; 4 | 5 | beforeEach(() => { 6 | jest.isolateModules(() => { 7 | SimpleBar = require('../src').default; 8 | }); 9 | 10 | // Set up our document body 11 | document.body.innerHTML = 12 | '
'; 13 | }); 14 | 15 | test('should return the element options', async () => { 16 | const simpleBar = new SimpleBar(document.getElementById('simplebar')); 17 | await new Promise(process.nextTick); 18 | expect(SimpleBar.getOptions(simpleBar.el.attributes)).toEqual({ 19 | autoHide: true, 20 | }); 21 | }); 22 | 23 | test('unmount on node removed from DOM', async () => { 24 | const simpleBar = new SimpleBar(document.getElementById('simplebar')); 25 | 26 | await waitFor(() => 27 | expect( 28 | document.getElementById('simplebar').getAttribute('data-simplebar') 29 | ).toEqual('init') 30 | ); 31 | 32 | waitForElementToBeRemoved(document.getElementById('simplebar')).then(() => { 33 | expect(SimpleBar.instances.get(simpleBar.el)).toBeUndefined(); 34 | }); 35 | 36 | document.getElementById('simplebar').remove(); 37 | }); 38 | -------------------------------------------------------------------------------- /examples/angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "^18.0.0", 14 | "@angular/common": "^18.0.0", 15 | "@angular/compiler": "^18.0.0", 16 | "@angular/core": "^18.0.0", 17 | "@angular/forms": "^18.0.0", 18 | "@angular/platform-browser": "^18.0.0", 19 | "@angular/platform-browser-dynamic": "^18.0.0", 20 | "@angular/router": "^18.0.0", 21 | "rxjs": "~7.8.0", 22 | "simplebar-angular": "latest", 23 | "tslib": "^2.3.0", 24 | "zone.js": "~0.14.3" 25 | }, 26 | "devDependencies": { 27 | "@angular-devkit/build-angular": "^18.0.4", 28 | "@angular/cli": "^18.0.4", 29 | "@angular/compiler-cli": "^18.0.3", 30 | "@types/jasmine": "~5.1.4", 31 | "jasmine-core": "~5.1.0", 32 | "karma": "~6.4.3", 33 | "karma-chrome-launcher": "~3.2.0", 34 | "karma-coverage": "~2.2.1", 35 | "karma-jasmine": "~5.1.0", 36 | "karma-jasmine-html-reporter": "~2.1.0", 37 | "typescript": "~5.4.2" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/simplebar-angular/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | process.env.CHROME_BIN = require('puppeteer').executablePath(); 5 | 6 | module.exports = function (config) { 7 | config.set({ 8 | basePath: '', 9 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 10 | plugins: [ 11 | require('karma-jasmine'), 12 | require('karma-chrome-launcher'), 13 | require('karma-jasmine-html-reporter'), 14 | require('karma-coverage'), 15 | require('@angular-devkit/build-angular/plugins/karma'), 16 | ], 17 | browsers: ['Chrome'], 18 | customLaunchers: { 19 | ChromeNoSandBox: { 20 | base: 'Chrome', 21 | flags: ['--no-sandbox'], 22 | }, 23 | HeadlessChrome: { 24 | base: 'ChromeHeadless', 25 | flags: ['--no-sandbox', '--headless'], 26 | }, 27 | }, 28 | singleRun: true, 29 | restartOnFileChange: true, 30 | failOnEmptyTestSuite: false, 31 | }); 32 | 33 | if (process.env.TRAVIS) { 34 | config.browsers = ['ChromeHeadless']; 35 | config.singleRun = true; 36 | config.browserDisconnectTimeout = 10000; 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /packages/simplebar-vue/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'node:module'; 2 | import resolve from '@rollup/plugin-node-resolve'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | import typescript from '@rollup/plugin-typescript'; 5 | import license from 'rollup-plugin-license'; 6 | import { getBanner, getExternals, tsConfig } from '../../rollup.config.mjs'; 7 | 8 | const require = createRequire(import.meta.url); 9 | const pkg = require('./package.json'); 10 | 11 | const globals = { 12 | 'simplebar-core': 'SimpleBar', 13 | }; 14 | 15 | export default [ 16 | { 17 | input: 'index.ts', 18 | output: { 19 | name: 'SimpleBarVue', 20 | file: pkg.main, 21 | globals: globals, 22 | format: 'umd', 23 | sourcemap: true, 24 | }, 25 | external: getExternals(pkg), 26 | plugins: [ 27 | resolve(), // so Rollup can find dependencies 28 | commonjs(), // so Rollup can convert dependencies to an ES module 29 | typescript(tsConfig), 30 | license(getBanner(pkg)), 31 | ], 32 | }, 33 | { 34 | input: 'index.ts', 35 | external: getExternals(pkg), 36 | output: { 37 | file: pkg.module, 38 | format: 'esm', 39 | }, 40 | plugins: [typescript(tsConfig), license(getBanner(pkg))], 41 | }, 42 | ]; 43 | -------------------------------------------------------------------------------- /packages/simplebar-core/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'node:module'; 2 | import typescript from '@rollup/plugin-typescript'; 3 | import license from 'rollup-plugin-license'; 4 | import { getExternals, getBanner, tsConfig } from '../../rollup.config.mjs'; 5 | 6 | const require = createRequire(import.meta.url); 7 | const pkg = require('./package.json'); 8 | 9 | export default [ 10 | // ES module (for bundlers) build 11 | { 12 | input: 'src/index.ts', 13 | external: getExternals(pkg), 14 | output: [ 15 | { 16 | file: pkg.module, 17 | format: 'esm', 18 | sourcemap: true, 19 | }, 20 | ], 21 | plugins: [typescript(tsConfig), license(getBanner(pkg))], 22 | }, 23 | // CommonJS (for Node) 24 | { 25 | input: 'src/index.ts', 26 | external: getExternals(pkg), 27 | output: [ 28 | { 29 | name: 'SimpleBarCore', 30 | file: pkg.main, 31 | format: 'umd', 32 | sourcemap: true, 33 | globals: { 34 | 'lodash-es': '_', 35 | }, 36 | // Lodash-es won't work for UMD build, so we alias to lodash 37 | paths: (id) => id.replace('lodash-es/', 'lodash/'), 38 | }, 39 | ], 40 | plugins: [typescript(tsConfig), license(getBanner(pkg))], 41 | }, 42 | ]; 43 | -------------------------------------------------------------------------------- /packages/website/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## 🔎 Usage Questions 2 | 3 | Before you ask a question, please make sure you've: 4 | 5 | - Looked for prior or closed issues 6 | - Checked the README 7 | - Looked for/asked questions on stack overflow: https://stackoverflow.com/search?q=simplebar 8 | 9 | ## ✨ Feature Requests 10 | 11 | SimpleBar's mission statement is to keep things simple and stick to the native scroll behaviour as much as possible. However if you have a suggestion that falls within this approach that hasn't already been proposed, we'd love to hear it! 12 | 13 | ## 🐛 Bugs 14 | 15 | Please complete the following template: 16 | 17 | ## Current Behavior 18 | 19 | 20 | 21 | ## Expected behavior 22 | 23 | 24 | 25 | ## Reproducible example 26 | 27 | 28 | 29 | ## Suggested solution(s) 30 | 31 | 32 | 33 | ## Additional context 34 | 35 | 36 | 37 | ## Your environment 38 | 39 | | Software | Version(s) | 40 | | ---------------- | ---------- | 41 | | SimpleBar | 42 | | Browser | 43 | | npm/Yarn | 44 | | Operating System | 45 | -------------------------------------------------------------------------------- /packages/simplebar-angular/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "simplebar-angular": { 7 | "projectType": "library", 8 | "root": "", 9 | "sourceRoot": "src", 10 | "prefix": "lib", 11 | "architect": { 12 | "build": { 13 | "builder": "@angular-devkit/build-angular:ng-packagr", 14 | "options": { 15 | "project": "ng-package.json" 16 | }, 17 | "configurations": { 18 | "production": { 19 | "tsConfig": "tsconfig.lib.prod.json" 20 | }, 21 | "development": { 22 | "tsConfig": "tsconfig.lib.json" 23 | } 24 | }, 25 | "defaultConfiguration": "production" 26 | }, 27 | "test": { 28 | "builder": "@angular-devkit/build-angular:karma", 29 | "options": { 30 | "main": "test-setup.ts", 31 | "tsConfig": "tsconfig.spec.json", 32 | "karmaConfig": "karma.conf.js" 33 | } 34 | } 35 | } 36 | } 37 | }, 38 | "schematics": { 39 | "@schematics/angular:component": { 40 | "styleext": "scss" 41 | } 42 | }, 43 | "cli": { 44 | "analytics": false 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/website/src/html.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import PropTypes from "prop-types" 3 | 4 | const simpleBarFallbackCss = ` 5 | .simplebar-content-wrapper { 6 | overflow: auto; 7 | } 8 | ` 9 | 10 | export default function HTML(props) { 11 | return ( 12 | 13 | 14 | 15 | 16 | 20 | {props.headComponents} 21 | 22 | 23 | {props.preBodyComponents} 24 | 28 |
33 | {props.postBodyComponents} 34 | 35 | 36 | ) 37 | } 38 | 39 | HTML.propTypes = { 40 | htmlAttributes: PropTypes.object, 41 | headComponents: PropTypes.array, 42 | bodyAttributes: PropTypes.object, 43 | preBodyComponents: PropTypes.array, 44 | body: PropTypes.string, 45 | postBodyComponents: PropTypes.array, 46 | } 47 | -------------------------------------------------------------------------------- /packages/simplebar-react/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'node:module'; 2 | import resolve from '@rollup/plugin-node-resolve'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | import typescript from '@rollup/plugin-typescript'; 5 | import license from 'rollup-plugin-license'; 6 | import { getBanner, getExternals, tsConfig } from '../../rollup.config.mjs'; 7 | 8 | const require = createRequire(import.meta.url); 9 | const pkg = require('./package.json'); 10 | 11 | const globals = { 12 | react: 'React', 13 | 'simplebar-core': 'SimpleBarCore', 14 | }; 15 | 16 | export default [ 17 | { 18 | input: 'index.tsx', 19 | external: getExternals(pkg), 20 | output: { 21 | name: 'SimpleBarReact', 22 | file: pkg.main, 23 | globals: globals, 24 | format: 'umd', 25 | sourcemap: true, 26 | }, 27 | plugins: [ 28 | resolve(), // so Rollup can find dependencies 29 | commonjs(), // so Rollup can convert dependencies to an ES module 30 | typescript({ ...tsConfig, tsconfig: './tsconfig.json' }), 31 | license(getBanner(pkg)), 32 | ], 33 | }, 34 | { 35 | input: 'index.tsx', 36 | external: getExternals(pkg), 37 | output: { 38 | file: pkg.module, 39 | format: 'esm', 40 | }, 41 | plugins: [ 42 | typescript({ ...tsConfig, tsconfig: './tsconfig.json' }), 43 | license(getBanner(pkg)), 44 | ], 45 | }, 46 | ]; 47 | -------------------------------------------------------------------------------- /packages/simplebar-core/jest-puppeteer.config.js: -------------------------------------------------------------------------------- 1 | const caps = { 2 | browser: 'chrome', // You can choose `chrome`, `edge` or `firefox` in this capability 3 | browser_version: 'latest', // We support v83 and above. You can choose `latest`, `latest-beta`, `latest-1`, `latest-2` and so on, in this capability 4 | os: 'os x', 5 | os_version: 'big sur', 6 | project: 'simplebar', 7 | build: 8 | process.env.CI === 'true' 9 | ? `${process.env.TRAVIS_BRANCH}-${process.env.TRAVIS_COMMIT}` 10 | : 'local-tests', 11 | name: 'SimpleBar examples Puppeteer test', // The name of your test and build. See browserstack.com/docs/automate/puppeteer/organize tests for more details 12 | 'browserstack.localIdentifier': process.env.BROWSERSTACK_LOCAL_IDENTIFIER, 13 | 'browserstack.username': process.env.BROWSERSTACK_USERNAME, 14 | 'browserstack.accessKey': process.env.BROWSERSTACK_ACCESS_KEY, 15 | 'browserstack.local': 'true', 16 | }; 17 | 18 | module.exports = { 19 | launch: { 20 | headless: process.env.CI === 'true', 21 | devtools: process.env.CI === 'false', 22 | }, 23 | server: { 24 | command: 'cd ../examples && webpack server --mode=production', 25 | port: 8090, 26 | }, 27 | connect: { 28 | browserWSEndpoint: `wss://cdp.browserstack.com/puppeteer?caps=${encodeURIComponent( 29 | JSON.stringify(caps) 30 | )}`, // The BrowserStack CDP endpoint gives you a `browser` instance based on the `caps` that you specified 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /packages/simplebar-angular/src/lib/simplebar-angular.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | OnInit, 4 | Input, 5 | AfterViewInit, 6 | ElementRef, 7 | ViewEncapsulation, 8 | NgZone, 9 | } from '@angular/core'; 10 | 11 | import SimpleBar, { SimpleBarOptions } from 'simplebar-core'; 12 | 13 | @Component({ 14 | selector: 'ngx-simplebar', 15 | host: { 'data-simplebar': 'init' }, 16 | templateUrl: './simplebar-angular.component.html', 17 | styleUrls: [ 18 | '../../../simplebar-core/src/simplebar.css', 19 | './simplebar-angular.component.scss', 20 | ], 21 | encapsulation: ViewEncapsulation.None, 22 | }) 23 | export class SimplebarAngularComponent implements OnInit, AfterViewInit { 24 | @Input('options') options: Partial = {}; 25 | 26 | elRef: ElementRef; 27 | SimpleBar: any; 28 | ariaLabel!: string; 29 | tabIndex!: string; 30 | 31 | constructor(elRef: ElementRef, private zone: NgZone) { 32 | this.elRef = elRef; 33 | } 34 | 35 | ngOnInit(): void { 36 | this.ariaLabel = 37 | this.options.ariaLabel || SimpleBar.defaultOptions.ariaLabel; 38 | this.tabIndex = 39 | (this.options.tabIndex || SimpleBar.defaultOptions.tabIndex).toString(); 40 | } 41 | 42 | ngAfterViewInit(): void { 43 | this.zone.runOutsideAngular(() => { 44 | this.SimpleBar = new SimpleBar( 45 | this.elRef.nativeElement, 46 | this.options || {} 47 | ); 48 | }); 49 | } 50 | 51 | ngOnDestroy(): void { 52 | this.SimpleBar?.unMount(); 53 | this.SimpleBar = null; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /packages/simplebar-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.3.2", 3 | "name": "simplebar-core", 4 | "title": "SimpleBar.js", 5 | "description": "Scrollbars, simpler.", 6 | "files": [ 7 | "dist", 8 | "README.md" 9 | ], 10 | "author": "Adrien Denat from a fork by Jonathan Nicol", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/grsmto/simplebar.git", 14 | "directory": "packages/simplebar-core" 15 | }, 16 | "main": "./dist/index.cjs", 17 | "module": "./dist/index.mjs", 18 | "style": "./dist/simplebar.min.css", 19 | "typings": "./dist/index.d.ts", 20 | "sideEffects": [ 21 | "*.css" 22 | ], 23 | "homepage": "https://grsmto.github.io/simplebar/", 24 | "bugs": "https://github.com/grsmto/simplebar/issues", 25 | "license": "MIT", 26 | "scripts": { 27 | "serve": "serve -s demo", 28 | "build": "rollup -c && cp src/simplebar.css dist/simplebar.css", 29 | "dev": "rollup -c -w --environment BUILD:development", 30 | "test": "yarn test:unit", 31 | "test:unit": "jest -c jest-unit.config.js", 32 | "test:e2e": "env-cmd --silent jest -c jest-e2e.config.js --runInBand", 33 | "version": "yarn build", 34 | "precommit": "lint-staged" 35 | }, 36 | "dependencies": { 37 | "lodash": "^4.17.21", 38 | "lodash-es": "^4.17.21" 39 | }, 40 | "devDependencies": { 41 | "@types/lodash-es": "^4.17.12", 42 | "browserstack-local": "^1.5.1" 43 | }, 44 | "lint-staged": { 45 | "*.{js,jsx,json}": [ 46 | "prettier-eslint --write", 47 | "git add" 48 | ] 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/simplebar-angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simplebar-angular", 3 | "version": "3.3.2", 4 | "description": "Angular component for SimpleBar", 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build", 9 | "lint": "ng lint", 10 | "test": "ng test --no-watch --no-progress", 11 | "e2e": "ng e2e", 12 | "version": "yarn build", 13 | "precommit": "lint-staged" 14 | }, 15 | "publishConfig": { 16 | "directory": "dist" 17 | }, 18 | "lint-staged": { 19 | "*.{js,jsx,json}": [ 20 | "prettier-eslint --write", 21 | "git add" 22 | ] 23 | }, 24 | "license": "MIT", 25 | "keywords": [ 26 | "simplebar-angular", 27 | "angular", 28 | "simplebar" 29 | ], 30 | "dependencies": { 31 | "simplebar-core": "^1.3.2", 32 | "tslib": "^2.3.0" 33 | }, 34 | "peerDependencies": { 35 | "@angular/common": ">=12.0.0", 36 | "@angular/core": ">=12.0.0" 37 | }, 38 | "devDependencies": { 39 | "@angular-devkit/build-angular": "18", 40 | "@angular/cli": "18", 41 | "@angular/common": "18", 42 | "@angular/compiler": "18", 43 | "@angular/compiler-cli": "18", 44 | "@angular/core": "18", 45 | "@angular/platform-browser": "18", 46 | "@angular/platform-browser-dynamic": "18", 47 | "@types/jasmine": "~4.3.0", 48 | "jasmine-core": "~4.5.0", 49 | "karma": "~6.4.3", 50 | "karma-chrome-launcher": "~3.2.0", 51 | "karma-coverage": "~2.2.1", 52 | "karma-jasmine": "~5.1.0", 53 | "karma-jasmine-html-reporter": "~2.1.0", 54 | "ng-packagr": "18", 55 | "typescript": "~5.4.5", 56 | "zone.js": "~0.14.7" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/simplebar-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simplebar-react", 3 | "version": "3.3.2", 4 | "description": "React component for SimpleBar", 5 | "files": [ 6 | "dist", 7 | "README.md" 8 | ], 9 | "author": "Adrien Denat", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/grsmto/simplebar.git", 13 | "directory": "packages/simplebar-react" 14 | }, 15 | "main": "./dist/index.cjs", 16 | "module": "./dist/index.mjs", 17 | "types": "./dist/index.d.ts", 18 | "exports": { 19 | ".": { 20 | "import": "./dist/index.mjs", 21 | "require": "./dist/index.cjs", 22 | "types": "./dist/index.d.ts" 23 | }, 24 | "./dist/simplebar.min.css": "./dist/simplebar.min.css" 25 | }, 26 | "sideEffects": [ 27 | "*.css" 28 | ], 29 | "bugs": "https://github.com/grsmto/simplebar/issues", 30 | "homepage": "https://grsmto.github.io/simplebar/", 31 | "license": "MIT", 32 | "scripts": { 33 | "build": "rollup -c && minify ../simplebar-core/src/simplebar.css > dist/simplebar.min.css", 34 | "dev": "rollup -c -w", 35 | "test": "jest", 36 | "version": "yarn build", 37 | "precommit": "lint-staged" 38 | }, 39 | "dependencies": { 40 | "simplebar-core": "^1.3.2" 41 | }, 42 | "peerDependencies": { 43 | "react": ">=16.8.0" 44 | }, 45 | "devDependencies": { 46 | "@testing-library/jest-dom": "^5.16.5", 47 | "@testing-library/react": "^13.4.0", 48 | "eslint-config-react-app": "^5.0.2", 49 | "eslint-plugin-react": "^7.14.3" 50 | }, 51 | "lint-staged": { 52 | "*.{js,jsx,json}": [ 53 | "prettier-eslint --write", 54 | "git add" 55 | ] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simplebar-website", 3 | "private": true, 4 | "description": "A simple starter to get up and developing quickly with Gatsby", 5 | "version": "0.2.3", 6 | "author": "Adrien Denat ", 7 | "scripts": { 8 | "build": "gatsby build --prefix-paths", 9 | "develop": "gatsby develop", 10 | "format": "prettier --write \"**/*.{js,jsx,json,md}\"", 11 | "start": "yarn develop", 12 | "serve": "gatsby serve --prefix-paths", 13 | "deploy": "gh-pages -d public -r https://$GITHUB_TOKEN@github.com/grsmto/simplebar.git" 14 | }, 15 | "dependencies": { 16 | "@emotion/core": "^10.0.28", 17 | "@mdx-js/react": "^1.6.4", 18 | "@theme-ui/preset-base": "^0.2.40", 19 | "gatsby": "^4.25.2", 20 | "modern-normalize": "^0.5.0", 21 | "prop-types": "^15.7.2", 22 | "react-helmet": "^5.2.1", 23 | "react-icons": "^3.7.0", 24 | "react-select": "^2.4.3", 25 | "react-window": "^1.8.1", 26 | "simplebar": "^6.3.3", 27 | "simplebar-react": "^3.3.2", 28 | "theme-ui": "^0.3.1", 29 | "typeface-nunito": "^1.1.3", 30 | "whatwg-fetch": "^3.0.0" 31 | }, 32 | "devDependencies": { 33 | "gatsby-cli": "4.25.0", 34 | "gatsby-plugin-react-helmet": "^5.25.0", 35 | "gatsby-source-filesystem": "^4.25.0", 36 | "gatsby-transformer-remark": "^5.25.1", 37 | "gh-pages": "^2.1.1" 38 | }, 39 | "keywords": [ 40 | "gatsby" 41 | ], 42 | "license": "MIT", 43 | "repository": { 44 | "type": "git", 45 | "url": "https://github.com/gatsbyjs/gatsby-starter-default" 46 | }, 47 | "bugs": { 48 | "url": "https://github.com/gatsbyjs/gatsby/issues" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simplebar-examples", 3 | "version": "3.1.3", 4 | "private": true, 5 | "description": "Scrollbars, simpler.", 6 | "author": "Adrien Denat ", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/grsmto/simplebar.git", 10 | "directory": "packages/simplebar-core" 11 | }, 12 | "homepage": "https://grsmto.github.io/simplebar/", 13 | "bugs": "https://github.com/grsmto/simplebar/issues", 14 | "license": "MIT", 15 | "scripts": { 16 | "start": "webpack serve --open --mode=development", 17 | "build": "webpack --mode=production", 18 | "serve": "serve", 19 | "precommit": "lint-staged" 20 | }, 21 | "dependencies": { 22 | "@babel/runtime": "^7.20.7", 23 | "core-js": "^3.27.1", 24 | "simplebar": "^6.3.3", 25 | "simplebar-react": "^3.3.2" 26 | }, 27 | "devDependencies": { 28 | "@babel/plugin-transform-runtime": "^7.19.6", 29 | "@pmmmwh/react-refresh-webpack-plugin": "^0.5.10", 30 | "babel-loader": "^9.1.0", 31 | "css-loader": "^0.28.11", 32 | "promise": "^8.0.2", 33 | "react-refresh": "^0.14.0", 34 | "react-select": "^2.4.3", 35 | "react-window": "^1.8.1", 36 | "serve": "^14.1.2", 37 | "style-loader": "^3.3.1", 38 | "ts-loader": "^9.4.2", 39 | "webpack": "^5.75.0", 40 | "webpack-cli": "^5.0.1", 41 | "webpack-dev-server": "^4.11.1" 42 | }, 43 | "workspaces": { 44 | "nohoist": [ 45 | "webpack", 46 | "webpack-dev-server", 47 | "webpack-cli" 48 | ] 49 | }, 50 | "lint-staged": { 51 | "*.{js,jsx,json}": [ 52 | "prettier-eslint --write", 53 | "git add" 54 | ] 55 | }, 56 | "browserslist": [ 57 | "ie 11" 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /examples/react/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /packages/simplebar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "6.3.3", 3 | "name": "simplebar", 4 | "title": "SimpleBar.js", 5 | "description": "Scrollbars, simpler.", 6 | "files": [ 7 | "dist", 8 | "src", 9 | "README.md" 10 | ], 11 | "author": "Adrien Denat from a fork by Jonathan Nicol", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/grsmto/simplebar.git", 15 | "directory": "packages/simplebar" 16 | }, 17 | "main": "./dist/index.cjs", 18 | "module": "./dist/index.mjs", 19 | "types": "./dist/index.d.ts", 20 | "unpkg": "./dist/simplebar.min.js", 21 | "style": "./dist/simplebar.min.css", 22 | "exports": { 23 | ".": { 24 | "import": "./dist/index.mjs", 25 | "require": "./dist/index.cjs", 26 | "types": "./dist/index.d.ts" 27 | }, 28 | "./dist/simplebar.css": "./dist/simplebar.css", 29 | "./dist/simplebar.min.css": "./dist/simplebar.min.css" 30 | }, 31 | "homepage": "https://grsmto.github.io/simplebar/", 32 | "bugs": "https://github.com/grsmto/simplebar/issues", 33 | "license": "MIT", 34 | "scripts": { 35 | "build": "rollup -c && cp ../simplebar-core/src/simplebar.css dist/simplebar.css && minify dist/simplebar.css > dist/simplebar.min.css", 36 | "dev": "rollup -c -w --environment BUILD:development", 37 | "test": "jest -c jest-unit.config.js", 38 | "version": "yarn build", 39 | "precommit": "lint-staged" 40 | }, 41 | "dependencies": { 42 | "simplebar-core": "^1.3.2" 43 | }, 44 | "devDependencies": { 45 | "@babel/plugin-transform-runtime": "^7.19.6", 46 | "intern": "^4.4.2", 47 | "minify": "^3.0.5", 48 | "promise": "^8.0.2" 49 | }, 50 | "lint-staged": { 51 | "*.{js,jsx,json}": [ 52 | "prettier-eslint --write", 53 | "git add" 54 | ] 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/website/src/images/users/zulip.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/simplebar-angular/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rulesDirectory": ["codelyzer"], 4 | "rules": { 5 | "array-type": false, 6 | "arrow-parens": false, 7 | "deprecation": { 8 | "severity": "warning" 9 | }, 10 | "import-blacklist": [true, "rxjs/Rx"], 11 | "interface-name": false, 12 | "max-classes-per-file": false, 13 | "max-line-length": [true, 140], 14 | "member-access": false, 15 | "member-ordering": [ 16 | true, 17 | { 18 | "order": [ 19 | "static-field", 20 | "instance-field", 21 | "static-method", 22 | "instance-method" 23 | ] 24 | } 25 | ], 26 | "no-consecutive-blank-lines": false, 27 | "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], 28 | "no-empty": false, 29 | "no-inferrable-types": [true, "ignore-params"], 30 | "no-non-null-assertion": true, 31 | "no-redundant-jsdoc": true, 32 | "no-switch-case-fall-through": true, 33 | "no-use-before-declare": true, 34 | "no-var-requires": false, 35 | "object-literal-key-quotes": [true, "as-needed"], 36 | "object-literal-sort-keys": false, 37 | "ordered-imports": false, 38 | "quotemark": [true, "single"], 39 | "trailing-comma": false, 40 | "component-class-suffix": true, 41 | "contextual-lifecycle": true, 42 | "directive-class-suffix": true, 43 | "no-conflicting-lifecycle": true, 44 | "no-host-metadata-property": true, 45 | "no-input-rename": true, 46 | "no-inputs-metadata-property": true, 47 | "no-output-native": true, 48 | "no-output-on-prefix": true, 49 | "no-output-rename": true, 50 | "no-outputs-metadata-property": true, 51 | "template-banana-in-box": true, 52 | "template-no-negated-async": true, 53 | "use-lifecycle-interface": true, 54 | "use-pipe-transform-interface": true, 55 | "directive-selector": [true, "attribute", "ngx", "camelCase"], 56 | "component-selector": [true, "element", "ngx", "kebab-case"] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/simplebar/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'node:module'; 2 | import resolve from '@rollup/plugin-node-resolve'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | import typescript from '@rollup/plugin-typescript'; 5 | import license from 'rollup-plugin-license'; 6 | import { terser } from 'rollup-plugin-terser'; 7 | import { getBanner, getExternals, tsConfig } from '../../rollup.config.mjs'; 8 | 9 | const require = createRequire(import.meta.url); 10 | const pkg = require('./package.json'); 11 | 12 | const builds = [ 13 | // ES module (for bundlers) build. 14 | { 15 | input: 'src/index.ts', 16 | external: getExternals(pkg), 17 | output: { 18 | file: pkg.module, 19 | format: 'esm', 20 | sourcemap: true, 21 | }, 22 | plugins: [typescript(tsConfig), license(getBanner(pkg))], 23 | }, 24 | ]; 25 | 26 | if (process.env.BUILD !== 'development') { 27 | // UMD build 28 | builds.push({ 29 | input: 'src/index.ts', 30 | external: getExternals(pkg), 31 | output: { 32 | name: 'SimpleBar', 33 | file: pkg.main, 34 | format: 'umd', 35 | exports: 'named', 36 | globals: { 37 | 'simplebar-core': 'SimpleBar', 38 | }, 39 | }, 40 | plugins: [typescript(tsConfig), license(getBanner(pkg))], 41 | }); 42 | 43 | // browser script tag build, minified 44 | builds.push({ 45 | input: 'src/index.ts', 46 | output: { 47 | name: 'SimpleBar', 48 | file: pkg.unpkg, 49 | format: 'iife', 50 | }, 51 | plugins: [ 52 | resolve(), 53 | commonjs(), 54 | typescript(tsConfig), 55 | terser(), 56 | license(getBanner(pkg)), 57 | ], 58 | }); 59 | 60 | builds.push( 61 | // browser script tag build, non-minified 62 | { 63 | input: 'src/index.ts', 64 | output: { 65 | name: 'SimpleBar', 66 | file: 'dist/simplebar.js', 67 | format: 'iife', 68 | }, 69 | plugins: [ 70 | resolve(), 71 | commonjs(), 72 | typescript(tsConfig), 73 | license(getBanner(pkg)), 74 | ], 75 | } 76 | ); 77 | } 78 | 79 | export default builds; 80 | -------------------------------------------------------------------------------- /packages/website/src/components/SEO.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SEO component that queries for data with 3 | * Gatsby's useStaticQuery React hook 4 | * 5 | * See: https://www.gatsbyjs.org/docs/use-static-query/ 6 | */ 7 | 8 | import React from "react" 9 | import PropTypes from "prop-types" 10 | import Helmet from "react-helmet" 11 | import { useStaticQuery, graphql } from "gatsby" 12 | 13 | function SEO({ description, lang, meta, title }) { 14 | const { site } = useStaticQuery( 15 | graphql` 16 | query { 17 | site { 18 | siteMetadata { 19 | title 20 | description 21 | author 22 | } 23 | } 24 | } 25 | ` 26 | ) 27 | 28 | const metaDescription = description || site.siteMetadata.description 29 | 30 | return ( 31 | 72 | ) 73 | } 74 | 75 | SEO.defaultProps = { 76 | lang: `en`, 77 | meta: [], 78 | description: ``, 79 | } 80 | 81 | SEO.propTypes = { 82 | description: PropTypes.string, 83 | lang: PropTypes.string, 84 | meta: PropTypes.arrayOf(PropTypes.object), 85 | title: PropTypes.string.isRequired, 86 | } 87 | 88 | export default SEO 89 | -------------------------------------------------------------------------------- /packages/simplebar-core/src/helpers.ts: -------------------------------------------------------------------------------- 1 | import type { SimpleBarOptions } from './index'; 2 | 3 | export function getElementWindow(element: Element) { 4 | if ( 5 | !element || 6 | !element.ownerDocument || 7 | !element.ownerDocument.defaultView 8 | ) { 9 | return window; 10 | } 11 | return element.ownerDocument.defaultView; 12 | } 13 | 14 | export function getElementDocument(element: Element) { 15 | if (!element || !element.ownerDocument) { 16 | return document; 17 | } 18 | return element.ownerDocument; 19 | } 20 | 21 | // Helper function to retrieve options from element attributes 22 | export const getOptions = function (obj: any) { 23 | const initialObj: SimpleBarOptions = {}; 24 | 25 | const options = Array.prototype.reduce.call( 26 | obj, 27 | (acc: any, attribute) => { 28 | const option = attribute.name.match(/data-simplebar-(.+)/); 29 | if (option) { 30 | const key: keyof SimpleBarOptions = option[1].replace( 31 | /\W+(.)/g, 32 | (_: any, chr: string) => chr.toUpperCase() 33 | ); 34 | 35 | switch (attribute.value) { 36 | case 'true': 37 | acc[key] = true; 38 | break; 39 | case 'false': 40 | acc[key] = false; 41 | break; 42 | case undefined: 43 | acc[key] = true; 44 | break; 45 | default: 46 | acc[key] = attribute.value; 47 | } 48 | } 49 | return acc; 50 | }, 51 | initialObj 52 | ); 53 | return options as SimpleBarOptions; 54 | }; 55 | 56 | export function addClasses(el: HTMLElement | null, classes: string) { 57 | if (!el) return; 58 | el.classList.add(...classes.split(' ')); 59 | } 60 | 61 | export function removeClasses(el: HTMLElement | null, classes: string) { 62 | if (!el) return; 63 | classes.split(' ').forEach((className) => { 64 | el.classList.remove(className); 65 | }); 66 | } 67 | 68 | export function classNamesToQuery(classNames: string) { 69 | return `.${classNames.split(' ').join('.')}`; 70 | } 71 | 72 | export const canUseDOM = !!( 73 | typeof window !== 'undefined' && 74 | window.document && 75 | window.document.createElement 76 | ); 77 | -------------------------------------------------------------------------------- /packages/simplebar-vue/tests/__snapshots__/index.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`simplebar snapshots renders with default slot 1`] = ` 4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 23 | 26 |
27 | `; 28 | 29 | exports[`simplebar snapshots renders without crashing 1`] = ` 30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | 47 | 50 |
51 | `; 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "workspaces": { 4 | "packages": [ 5 | "packages/*" 6 | ], 7 | "nohoist": [ 8 | "**/webpack/**", 9 | "**/webpack-dev-server/**", 10 | "**/webpack-cli/**" 11 | ] 12 | }, 13 | "scripts": { 14 | "build": "lerna exec yarn build", 15 | "test": "lerna run test", 16 | "release": "yarn build && yarn test && auto changelog && lerna publish --pre-dist-tag beta --preid beta", 17 | "start": "lerna exec --scope=simplebar yarn start", 18 | "dev": "lerna exec --scope=simplebar yarn dev" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.20.7", 22 | "@babel/preset-env": "^7.20.2", 23 | "@babel/preset-react": "^7.18.6", 24 | "@babel/preset-typescript": "^7.18.6", 25 | "@rollup/plugin-babel": "^6.0.3", 26 | "@rollup/plugin-commonjs": "^24.0.0", 27 | "@rollup/plugin-node-resolve": "^15.0.1", 28 | "@rollup/plugin-typescript": "^11.0.0", 29 | "@types/jest": "^29.2.5", 30 | "@types/react": "18.0.26", 31 | "@types/react-dom": "18.0.10", 32 | "@typescript-eslint/parser": "^5.48.0", 33 | "auto": "^11.3.0", 34 | "babel-core": "^7.0.0-bridge.0", 35 | "babel-eslint": "10.1.0", 36 | "babel-jest": "^29.3.1", 37 | "babel-plugin-transform-class-properties": "^6.24.1", 38 | "babel-plugin-transform-react-remove-prop-types": "^0.4.24", 39 | "concurrently": "^4.1.2", 40 | "env-cmd": "^10.1.0", 41 | "eslint": "^7.32.0", 42 | "eslint-plugin-import": "^2.21.2", 43 | "eslint-plugin-jest": "^23.13.2", 44 | "eslint-plugin-prettier": "^3.1.4", 45 | "husky": "^1.1.4", 46 | "jest": "^29.3.1", 47 | "jest-cli": "^29.3.1", 48 | "jest-environment-jsdom": "^29.3.1", 49 | "jest-puppeteer": "^6.2.0", 50 | "lerna": "^6.4.1", 51 | "lint-staged": "^8.1.5", 52 | "minify": "^9.1.0", 53 | "prettier": "^2.0.5", 54 | "prettier-eslint": "^15.0.1", 55 | "prettier-eslint-cli": "^7.1.0", 56 | "puppeteer": "^16.2.0", 57 | "react": "^18.2.0", 58 | "react-dom": "^18.2.0", 59 | "rollup": "^3.9.1", 60 | "rollup-plugin-license": "^3.0.1", 61 | "rollup-plugin-terser": "^7.0.2", 62 | "ts-jest": "^29.0.3", 63 | "typescript": "^4.8.2", 64 | "webpack-cli": "^5.0.1" 65 | }, 66 | "resolutions": { 67 | "@types/react": "18.0.26" 68 | }, 69 | "husky": { 70 | "hooks": { 71 | "pre-commit": "lerna run --concurrency 1 --stream precommit" 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /packages/simplebar-angular/README.md: -------------------------------------------------------------------------------- 1 |

2 | SimpleBar 3 |

4 |
5 |

6 | NPM version 7 | NPM downloads 8 | Build Status 9 | 10 |

11 |
12 | 13 | # SimplebarAngular 14 | 15 | - **🐦 Follow me on [Twitter!](https://twitter.com/adriendenat) or [Mastodon!](https://mas.to/@adrien)** 16 | - **👨‍💻 I'm available for hire! [Reach out to me!](https://adriendenat.com/)** 17 | - **🚧 Check out my new project [Scroll Snap Carousel](https://github.com/Grsmto/scroll-snap-carousel)!** 18 | 19 | ### Installation 20 | 21 | **- Via npm** 22 | `npm install simplebar-angular --save` 23 | 24 | **- Via Yarn** 25 | `yarn add simplebar-angular` 26 | 27 | ### Usage 28 | 29 | #### Import module 30 | 31 | ```js 32 | import { BrowserModule } from '@angular/platform-browser'; 33 | import { NgModule } from '@angular/core'; 34 | import { SimplebarAngularModule } from 'simplebar-angular'; 35 | import { AppComponent } from './app.component'; 36 | 37 | @NgModule({ 38 | declarations: [AppComponent], 39 | imports: [BrowserModule, SimplebarAngularModule], 40 | providers: [], 41 | bootstrap: [AppComponent], 42 | }) 43 | export class AppModule {} 44 | ``` 45 | 46 | #### Use component 47 | 48 | ```js 49 | 50 |
ngx-simplebar
51 |
52 | ``` 53 | 54 | ### Options 55 | 56 | Find the list of available options on [the core documentation](https://github.com/Grsmto/simplebar/blob/master/packages/simplebar/README.md#options). 57 | -------------------------------------------------------------------------------- /packages/website/src/components/Playground.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Select from 'react-select'; 3 | 4 | const widthOptions = [ 5 | { value: 'auto', label: 'auto' }, 6 | { value: '100%', label: '100%' }, 7 | { value: '100px', label: '100px' } 8 | ]; 9 | 10 | const heightOptions = [ 11 | { value: 'auto', label: 'auto' }, 12 | { value: '100%', label: '100%' }, 13 | { value: '100px', label: '100px' } 14 | ]; 15 | 16 | const directionOptions = [ 17 | { value: 'ltr', label: 'LTR' }, 18 | { value: 'rtl', label: 'RTL' } 19 | ]; 20 | 21 | export default class Playground extends React.PureComponent { 22 | state = { 23 | height: '100%', 24 | width: '100%', 25 | direction: 'ltr' 26 | }; 27 | 28 | render() { 29 | const { width, height, direction } = this.props; 30 | 31 | return ( 32 |
33 |
34 | {this.props.children(this.state)} 35 |
36 | {width && ( 37 |
38 | 39 | 57 | this.setState({ 58 | height: option.value 59 | }) 60 | } 61 | options={heightOptions} 62 | value={heightOptions.find( 63 | option => option.value === this.state.height 64 | )} 65 | /> 66 |
67 | )} 68 | {direction && ( 69 |
70 | 71 | 41 | this.setState({ 42 | width: option.value, 43 | }) 44 | } 45 | options={widthOptions} 46 | value={widthOptions.find( 47 | (option) => option.value === this.state.width 48 | )} 49 | /> 50 |
51 | )} 52 | {height && ( 53 |
54 | 55 | 73 | this.setState({ 74 | direction: option.value, 75 | }) 76 | } 77 | options={directionOptions} 78 | value={directionOptions.find( 79 | (option) => option.value === this.state.direction 80 | )} 81 | /> 82 |
83 | )} 84 |
85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /packages/simplebar-vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simplebar-vue", 3 | "version": "2.4.2", 4 | "description": "Vue component for SimpleBar", 5 | "files": [ 6 | "dist", 7 | "README.md" 8 | ], 9 | "author": "Piers Olenski", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/grsmto/simplebar.git", 13 | "directory": "packages/simplebar-vue" 14 | }, 15 | "main": "dist/simplebar-vue.js", 16 | "module": "dist/simplebar-vue.esm.js", 17 | "sideEffects": [ 18 | "*.css" 19 | ], 20 | "types": "dist/index.d.ts", 21 | "bugs": "https://github.com/grsmto/simplebar/issues", 22 | "homepage": "https://grsmto.github.io/simplebar/", 23 | "license": "MIT", 24 | "scripts": { 25 | "build": "rollup -c && minify ../simplebar-core/src/simplebar.css > dist/simplebar.min.css && cp simplebar-vue.d.ts dist/simplebar-vue.d.ts", 26 | "jest": "jest", 27 | "version": "yarn build", 28 | "precommit": "lint-staged", 29 | "test:2.7": "yarn use-vue:2.7 && yarn jest", 30 | "test:3": "yarn use-vue:3 && yarn jest", 31 | "test": "yarn test:2.7 && yarn test:3", 32 | "use-vue:2.7": "node scripts/swap-vue.js 2.7 && vue-demi-switch 2.7", 33 | "use-vue:3": "node scripts/swap-vue.js 3 && vue-demi-switch 3" 34 | }, 35 | "dependencies": { 36 | "simplebar-core": "^1.3.2", 37 | "vue-demi": "^0.13.11" 38 | }, 39 | "peerDependencies": { 40 | "vue": ">=2.5.17" 41 | }, 42 | "devDependencies": { 43 | "@babel/core": "^7.4.3", 44 | "@vue/compiler-sfc": "^3.2.45", 45 | "@vue/composition-api": "^1.7.1", 46 | "@vue/test-utils": "^2.2.7", 47 | "@vue/test-utils-vue2": "npm:@vue/test-utils@~1", 48 | "babel-core": "^7.0.0-bridge.0", 49 | "babel-jest": "^28.1.0", 50 | "eslint-plugin-vue": "^9.8.0", 51 | "jest-serializer-vue": "^2.0.2", 52 | "rollup-plugin-vue": "^6.0.0", 53 | "vue": "^3.2.45", 54 | "vue-jest": "^5.0.0-alpha.0", 55 | "vue-jest2": "npm:vue-jest@4", 56 | "vue-template-compiler2.6": "npm:vue-template-compiler@2.6.14", 57 | "vue-template-compiler2.7": "npm:vue-template-compiler@2.7.14", 58 | "vue2.7": "npm:vue@2.7.14" 59 | }, 60 | "lint-staged": { 61 | "*.{js,jsx,json}": [ 62 | "prettier-eslint --write", 63 | "git add" 64 | ] 65 | }, 66 | "eslintConfig": { 67 | "root": true, 68 | "env": { 69 | "node": true, 70 | "jest": true 71 | }, 72 | "extends": [ 73 | "plugin:vue/essential", 74 | "eslint:recommended" 75 | ], 76 | "rules": {}, 77 | "parserOptions": { 78 | "parser": "babel-eslint" 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /examples/react/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/angular/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "angular": { 7 | "projectType": "application", 8 | "schematics": {}, 9 | "root": "", 10 | "sourceRoot": "src", 11 | "prefix": "app", 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:application", 15 | "options": { 16 | "outputPath": "dist/angular", 17 | "index": "src/index.html", 18 | "browser": "src/main.ts", 19 | "polyfills": ["zone.js"], 20 | "tsConfig": "tsconfig.app.json", 21 | "assets": [ 22 | { 23 | "glob": "**/*", 24 | "input": "public" 25 | } 26 | ], 27 | "styles": ["src/styles.css"], 28 | "scripts": [], 29 | "preserveSymlinks": true 30 | }, 31 | "configurations": { 32 | "production": { 33 | "budgets": [ 34 | { 35 | "type": "initial", 36 | "maximumWarning": "500kB", 37 | "maximumError": "1MB" 38 | }, 39 | { 40 | "type": "anyComponentStyle", 41 | "maximumWarning": "2kB", 42 | "maximumError": "4kB" 43 | } 44 | ], 45 | "outputHashing": "all" 46 | }, 47 | "development": { 48 | "optimization": false, 49 | "extractLicenses": false, 50 | "sourceMap": true 51 | } 52 | }, 53 | "defaultConfiguration": "production" 54 | }, 55 | "serve": { 56 | "builder": "@angular-devkit/build-angular:dev-server", 57 | "configurations": { 58 | "production": { 59 | "buildTarget": "angular:build:production" 60 | }, 61 | "development": { 62 | "buildTarget": "angular:build:development" 63 | } 64 | }, 65 | "defaultConfiguration": "development" 66 | }, 67 | "extract-i18n": { 68 | "builder": "@angular-devkit/build-angular:extract-i18n" 69 | }, 70 | "test": { 71 | "builder": "@angular-devkit/build-angular:karma", 72 | "options": { 73 | "polyfills": ["zone.js", "zone.js/testing"], 74 | "tsConfig": "tsconfig.spec.json", 75 | "assets": [ 76 | { 77 | "glob": "**/*", 78 | "input": "public" 79 | } 80 | ], 81 | "styles": ["src/styles.css"], 82 | "scripts": [] 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /packages/website/src/images/users/twitch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/simplebar-vue/tests/index.test.ts: -------------------------------------------------------------------------------- 1 | import { shallowMount, destroyWrapper } from './test-utils'; 2 | import simplebar from '../component'; 3 | import SimpleBar from 'simplebar-core'; 4 | 5 | describe('simplebar', () => { 6 | describe('snapshots', () => { 7 | /** 8 | * jest-serializer-vue is not compatible with vue3 yet, so you 9 | * cannot pass the wrapper object directly. Call .html() before 10 | * @see {@link https://github.com/eddyerburgh/jest-serializer-vue/pull/56} 11 | */ 12 | it('renders without crashing', () => { 13 | const wrapper = shallowMount(simplebar); 14 | expect(wrapper.html()).toMatchSnapshot(); 15 | destroyWrapper(wrapper); 16 | }); 17 | 18 | it('renders with default slot', () => { 19 | const wrapper = shallowMount(simplebar, { 20 | slots: { 21 | default: '
', 22 | }, 23 | }); 24 | expect(wrapper.html()).toMatchSnapshot(); 25 | }); 26 | }); 27 | 28 | it('can access SimpleBar instance', () => { 29 | const wrapper = shallowMount(simplebar); 30 | expect(wrapper.vm.SimpleBar).toBeInstanceOf(SimpleBar); 31 | }); 32 | 33 | it('can access root element ref property', () => { 34 | const wrapper = shallowMount(simplebar); 35 | expect(wrapper.element).toEqual(wrapper.vm.$refs.element); 36 | }); 37 | 38 | it('can access scrollElement property', () => { 39 | const wrapper = shallowMount(simplebar); 40 | const scrollElement = wrapper.vm.scrollElement; 41 | 42 | expect(scrollElement).toEqual( 43 | wrapper.find('.simplebar-content-wrapper').element 44 | ); 45 | }); 46 | 47 | it('can access contentElement property', () => { 48 | const wrapper = shallowMount(simplebar); 49 | const scrollElement = wrapper.vm.contentElement; 50 | 51 | expect(scrollElement).toEqual(wrapper.find('.simplebar-content').element); 52 | }); 53 | 54 | it('works with options as data attributes', () => { 55 | const wrapper = shallowMount(simplebar, { 56 | attrs: { 'data-simplebar-force-visible': 'true', 'tabIndex': -1 }, 57 | }); 58 | expect(wrapper.vm.SimpleBar.options.forceVisible).toEqual(true); 59 | expect(wrapper.vm.SimpleBar.options.tabIndex).toEqual(-1); 60 | }); 61 | 62 | it('works with options as props', () => { 63 | const wrapper = shallowMount(simplebar, { 64 | propsData: { forceVisible: true }, 65 | }); 66 | expect(wrapper.vm.SimpleBar.options.forceVisible).toEqual(true); 67 | }); 68 | 69 | it('emits a scroll event', async () => { 70 | const wrapper = shallowMount(simplebar); 71 | const scrollElement = wrapper.find('.simplebar-content-wrapper'); 72 | 73 | expect(wrapper.emitted()).not.toHaveProperty('scroll'); 74 | await scrollElement.trigger('scroll'); 75 | expect(wrapper.emitted()).toHaveProperty('scroll'); 76 | }); 77 | 78 | it('destroys Simplebar instance when component is unmounted to prevent memory leaks', () => { 79 | // expect.assertions(1); 80 | const wrapper = shallowMount(simplebar); 81 | const instance = wrapper.vm.SimpleBar; 82 | jest.spyOn(instance, 'unMount'); 83 | 84 | destroyWrapper(wrapper); 85 | expect(instance.unMount).toHaveBeenCalledTimes(1); 86 | }); 87 | }); 88 | -------------------------------------------------------------------------------- /packages/simplebar-vue/simplebar-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'simplebar-vue' { 2 | import { DefineComponent } from 'vue'; 3 | import SimpleBar from 'simplebar'; 4 | 5 | export type SimpleBarComponent = DefineComponent<{ // Props 6 | 7 | /** 8 | * By default SimpleBar automatically hides the scrollbar if the user is not scrolling 9 | * (it emulates Mac OSX Lion's scrollbar). You can make the scrollbar always visible 10 | * by passing `false`. 11 | * 12 | * Default value is `true`. 13 | * 14 | * You can also control the animation via CSS as it's a simple CSS opacity transition. 15 | */ 16 | autoHide?: boolean; 17 | 18 | /** 19 | * It is possible to change the default class names that SimpleBar uses. 20 | * To get your own styles to work refer to simplebar.css to get an idea how to setup your css. 21 | * - `content` represents the wrapper for the content being scrolled. 22 | * - `scrollContent` represents the container containing the elements being scrolled. 23 | * - `scrollbar` defines the style of the scrollbar with which the user can interact to scroll the content. 24 | * - `track` styles the area surrounding the `scrollbar`. 25 | * 26 | * ```js 27 | * classNames: { 28 | * // defaults 29 | * content: 'simplebar-content', 30 | * scrollContent: 'simplebar-scroll-content', 31 | * scrollbar: 'simplebar-scrollbar', 32 | * track: 'simplebar-track' 33 | * } 34 | * ``` 35 | */ 36 | classNames?: Partial<{ content: string; scrollContent: string; scrollbar: string; track: string }>; 37 | 38 | /** 39 | * Force the track to be visible (same behaviour as `overflow: scroll`). 40 | * Can be `boolean | 'x' | 'y'`, defaults to `false`, which behaves like `overflow: auto`. 41 | */ 42 | forceVisible?: boolean | 'x' | 'y'; 43 | 44 | /** 45 | * Set custom aria-label attribute for users with screen reader. 46 | */ 47 | ariaLabel?: string; 48 | 49 | /** 50 | * Set custom tabIndex attribute. 51 | */ 52 | tabIndex?: number; 53 | 54 | /** 55 | * Activate RTL support by passing `'rtl'`. 56 | * You will also need a css rule with `direction: rtl`. 57 | */ 58 | direction?: 'ltr' | 'rtl'; 59 | 60 | /** 61 | * Define the delay until the scrollbar hides. Has no effect if `autoHide` is `false`. 62 | * Default value is `1000`. 63 | */ 64 | timeout?: number; 65 | 66 | /** 67 | * Controls the click on track behaviour. 68 | * Default to `true`. 69 | */ 70 | clickOnTrack?: boolean; 71 | 72 | /** 73 | * Controls the min size of the scrollbar in `px`. 74 | * Default is `25`. 75 | */ 76 | scrollbarMinSize?: number; 77 | 78 | /** 79 | * Controls the max size of the scrollbar in `px`. 80 | * Default is `0` (no max size). 81 | */ 82 | scrollbarMaxSize?: number; 83 | }, 84 | { }, // RawBindings 85 | { // Data 86 | SimpleBar: SimpleBar; 87 | contentElement: HTMLDivElement; 88 | scrollElement: HTMLDivElement; 89 | }, 90 | { }, // Computed 91 | { // Methods 92 | recalculate (): void; 93 | }, 94 | { }, // Mixins 95 | { }, // Extends 96 | { // Emits 97 | scroll: ($event: Event & { target: HTMLElement }) => void 98 | }>; 99 | 100 | const Component: SimpleBarComponent; 101 | export default Component; 102 | } 103 | -------------------------------------------------------------------------------- /packages/simplebar-vue/scripts/swap-vue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Vuelidate 3 | */ 4 | /* eslint-disable camelcase */ 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | 8 | const Vue2_7 = path.join(__dirname, '../../../node_modules/vue2.7'); 9 | const DefaultVue = path.join(__dirname, '../../../node_modules/vue'); 10 | const Vue3 = path.join(__dirname, '../../../node_modules/vue3'); 11 | const vueTemplateCompiler = path.join( 12 | __dirname, 13 | '../../../node_modules/vue-template-compiler' 14 | ); 15 | const vueTemplateCompiler2_6 = path.join( 16 | __dirname, 17 | '../../../node_modules/vue-template-compiler2.6' 18 | ); 19 | const vueTemplateCompiler2_7 = path.join( 20 | __dirname, 21 | '../../../node_modules/vue-template-compiler2.7' 22 | ); 23 | 24 | const version = Number(process.argv[2]) || 3; 25 | 26 | useVueVersion(version); 27 | 28 | function useVueVersion(version) { 29 | console.log('[SWAP-VUE] SETTING VERSION:', version); 30 | 31 | if (!fs.existsSync(DefaultVue)) { 32 | console.log('There is no default Vue version, finding it'); 33 | if (version === 2 && fs.existsSync(Vue3)) { 34 | rename(Vue3, DefaultVue); 35 | console.log('Renamed "vue3" to "vue"'); 36 | } else if (version === 2.7 && fs.existsSync(Vue2_7)) { 37 | rename(Vue2_7, DefaultVue); 38 | useTemplateCompilerVersion(2.7); 39 | console.log('Renamed "vue2.7" to "vue"'); 40 | } 41 | } 42 | 43 | if (version === 3 && fs.existsSync(Vue3)) { 44 | resetPackageNames(); 45 | rename(Vue3, DefaultVue); 46 | } else if (version === 2.7 && fs.existsSync(Vue2_7)) { 47 | resetPackageNames(); 48 | rename(Vue2_7, DefaultVue); 49 | useTemplateCompilerVersion(2.7); 50 | } else { 51 | console.log(`Vue ${version} is already in use`); 52 | } 53 | } 54 | 55 | function resetPackageNames() { 56 | if (!fs.existsSync(Vue3)) { 57 | rename(DefaultVue, Vue3); 58 | } else if (!fs.existsSync(Vue2_7)) { 59 | rename(DefaultVue, Vue2_7); 60 | } else { 61 | console.error('Unable to reset package names'); 62 | } 63 | } 64 | 65 | function useTemplateCompilerVersion(version) { 66 | if (!fs.existsSync(vueTemplateCompiler)) { 67 | console.log( 68 | 'There is no default vue-template-compiler version, finding it', 69 | version 70 | ); 71 | if (version === 2.7 && fs.existsSync(vueTemplateCompiler2_7)) { 72 | rename(vueTemplateCompiler2_7, vueTemplateCompiler); 73 | console.log( 74 | 'Renamed "vue-template-compliler2.7" to "vue-template-compliler"' 75 | ); 76 | } else { 77 | rename(vueTemplateCompiler2_6, vueTemplateCompiler); 78 | console.log( 79 | 'Renamed "vue-template-compliler2.6" to "vue-template-compliler"' 80 | ); 81 | } 82 | } 83 | if (version === 2.7 && fs.existsSync(vueTemplateCompiler2_7)) { 84 | rename(vueTemplateCompiler, vueTemplateCompiler2_6); 85 | rename(vueTemplateCompiler2_7, vueTemplateCompiler); 86 | } else if (version === 2 && fs.existsSync(vueTemplateCompiler2_6)) { 87 | rename(vueTemplateCompiler, vueTemplateCompiler2_7); 88 | rename(vueTemplateCompiler2_6, vueTemplateCompiler); 89 | } else { 90 | console.log(`vue-template-compliler ${version} is already in use`); 91 | } 92 | } 93 | 94 | function rename(fromPath, toPath) { 95 | if (!fs.existsSync(fromPath)) return; 96 | try { 97 | fs.renameSync(fromPath, toPath); 98 | console.log(`Successfully renamed ${fromPath} to ${toPath} .`); 99 | } catch (err) { 100 | console.log(err); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /packages/simplebar-vue/README.md: -------------------------------------------------------------------------------- 1 |

2 | SimpleBar 3 |

4 |
5 |

6 | NPM version 7 | NPM downloads 8 | Build Status 9 | 10 |

11 |
12 | 13 | # SimplebarVue 14 | 15 | - **🐦 Follow me on [Twitter!](https://twitter.com/adriendenat) or [Mastodon!](https://mas.to/@adrien)** 16 | - **👨‍💻 I'm available for hire! [Reach out to me!](https://adriendenat.com/)** 17 | - **🚧 Check out my new project [Scroll Snap Carousel](https://github.com/Grsmto/scroll-snap-carousel)!** 18 | 19 | ### Installation 20 | 21 | **- Via npm** 22 | `npm install simplebar-vue --save` 23 | 24 | **- Via Yarn** 25 | `yarn add simplebar-vue` 26 | 27 | ### Usage 28 | 29 | Check out the [Demo project(vue2)](https://github.com/Grsmto/simplebar/blob/master/examples/vue-2.7/src/App.vue) and the [Demo project(vue3)](https://github.com/Grsmto/simplebar/blob/master/examples/vue-3/src/App.vue) 30 | 31 | First, register it in your Vue app: 32 | 33 | ```js 34 | import simplebar from 'simplebar-vue'; 35 | import 'simplebar-vue/dist/simplebar.min.css'; 36 | 37 | export default { 38 | components: { 39 | simplebar, 40 | }, 41 | }; 42 | ``` 43 | 44 | Then you can use it in your template 45 | 46 | ```js 47 | 52 | ``` 53 | 54 | **Don't forget to import both css and js in your project!** 55 | 56 | ### :warning: Warning! 57 | 58 | SimpleBar is **not intended to be used on the `body` element!** I don't recommend wrapping your entire web page inside a custom scroll as it will often badly affect the user experience (slower scroll performance compared to the native body scroll, no native scroll behaviours like click on track, etc.). Do it at your own risk! SimpleBar is meant to improve the experience of **internal web page scrolling**; such as a chat box or a small scrolling area. **Please read the [caveats](#5-caveats) section first to be aware of the limitations!** 59 | 60 | ### Options 61 | 62 | Find the list of available options on [the core documentation](https://github.com/Grsmto/simplebar/blob/master/packages/simplebar/README.md#options). 63 | 64 | ### Troubleshooting 65 | 66 | If you are experiencing issues when setting up SimpleBar, it is most likely because your styles are clashing with SimpleBar ones. Make sure the element you are setting SimpleBar on does not override any SimpleBar css properties! **We recommend to not style that element at all and use an inner element instead.** 67 | 68 | ### Sponsors 69 | 70 | Thanks to BrowserStack for sponsoring open source projects and letting us test SimpleBar for free. 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 12 | 13 | SimpleBar does only one thing: replace the browser's default scrollbar with a custom CSS-styled one without losing performances. 14 | Unlike some popular plugins, SimpleBar doesn't mimic scroll with Javascript, causing janks and strange scrolling behaviours... 15 | You keep the awesomeness of native scrolling...with a custom scrollbar! 16 | SimpleBar **does NOT implement a custom scroll behaviour**. It keeps the **native** `overflow: auto` scroll and **only** replace the scrollbar visual appearance. 17 | 18 | - **🐦 Follow me on [Twitter!](https://twitter.com/adriendenat) or [Mastodon!](https://mas.to/@adrien)** 19 | - **👨‍💻 If you like Simplebar, [buy me a coffee!](adriendenat)** 20 | 21 | Buy Me A Coffee 22 | 23 | #### Design it as you want 24 | 25 | SimpleBar uses pure CSS to style the scrollbar. You can easily customize it as you want! Or even have multiple style on the same page...or just keep the default style ("Mac OS" scrollbar style). 26 | 27 | #### Lightweight and performant 28 | 29 | Only 6kb minified. SimpleBar doesn't use Javascript to handle scrolling. You keep the performances/behaviours of the native scroll. 30 | 31 | #### Supported everywhere 32 | 33 | SimpleBar has been tested on the following browsers: Chrome, Firefox, Safari, Edge, IE11. 34 | 35 | ### Getting started 36 | 37 | The easiest way to use SimpleBar is with the default dependency-free version: `npm install simplebar`. 38 | 39 | - [Core documention](https://github.com/Grsmto/simplebar/tree/master/packages/simplebar) 40 | 41 | If you are using a framework, SimpleBar also supports the most popular ones: Vue, Angular and React. 42 | 43 | - [React documention](https://github.com/Grsmto/simplebar/tree/master/packages/simplebar-react) 44 | - [Angular documentation](https://github.com/Grsmto/simplebar/tree/master/packages/simplebar-angular) 45 | - [Vue documentation](https://github.com/Grsmto/simplebar/tree/master/packages/simplebar-vue) 46 | 47 | ### Demo 48 | 49 | You can check our [demo page](https://grsmto.github.io/simplebar/examples) (which is also the one we use for automated tests). 50 | 51 | ### Changelog 52 | 53 | See changelog here : https://github.com/Grsmto/simplebar/releases 54 | 55 | ### Credits 56 | 57 | - [KingSora](https://github.com/KingSora) for multiple features and inspirations (`height: auto` detection, RTL mode cross browser support and more) with [OverlayScrollbars](https://kingsora.github.io/OverlayScrollbars/). 58 | - [Jonathan Nicol](http://www.f6design.com/) for original idea with [Trackpad Scroll Emulator](https://github.com/jnicol/trackpad-scroll-emulator). 59 | - [Cassio Bittencourt](https://cassiobittencourt.com/) for the logo design. 60 | -------------------------------------------------------------------------------- /packages/website/src/components/Layout.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { jsx, ThemeProvider } from "theme-ui" 3 | import PropTypes from "prop-types" 4 | import { Global } from "@emotion/core" 5 | import { withPrefix } from "gatsby" 6 | 7 | import theme from "../theme" 8 | 9 | import browserstackLogoUrl from "../images/browserstack.png" 10 | 11 | import "modern-normalize/modern-normalize.css" 12 | import "typeface-nunito" 13 | 14 | const Layout = ({ children, ...otherProps }) => { 15 | return ( 16 | 17 | ({ 19 | html: { 20 | WebkitFontSmoothing: "antialiased", 21 | MozOsxFontSmoothing: "grayscale", 22 | fontSize: "62.5%", 23 | }, 24 | body: { 25 | fontSize: theme.fontSizes.body, 26 | fontFamily: theme.fonts.body, 27 | fontWeight: theme.fontWeights.body, 28 | lineHeight: theme.lineHeights.body, 29 | color: theme.colors.body, 30 | }, 31 | "b, strong": { 32 | fontWeight: 700, 33 | }, 34 | a: { 35 | textDecoration: "none", 36 | color: theme.colors.primary, 37 | "&:hover": { 38 | textDecoration: "underline", 39 | }, 40 | }, 41 | "button, a": { 42 | transition: "all 150ms", 43 | }, 44 | img: { 45 | display: "block", 46 | maxWidth: "100%", 47 | }, 48 | "h1, h2, h3": { 49 | fontWeight: theme.fontWeights.heading, 50 | }, 51 | h3: { 52 | fontSize: theme.fontSizes[5], 53 | }, 54 | ".simplebar-scrollbar:before": { 55 | backgroundImage: 56 | "linear-gradient(-131deg, #E7B02B 0%, #C13E51 100%)", 57 | }, 58 | ".simplebar-track .simplebar-scrollbar.simplebar-visible::before": { 59 | opacity: 1, 60 | }, 61 | ".simplebar-horizontal": { 62 | height: "11px", 63 | }, 64 | ".simplebar-content-wrapper": { 65 | overflow: "hidden", 66 | }, 67 | })} 68 | /> 69 |
81 | {children} 82 |
92 | Released under the MIT License Copyright © {new Date().getFullYear()}{" "} 93 | Adrien Denat 94 | 101 | Sponsored by{" "} 102 | 108 | 113 | 114 | 115 |
116 |
117 |
118 | ) 119 | } 120 | 121 | Layout.propTypes = { 122 | children: PropTypes.node.isRequired, 123 | } 124 | 125 | export default Layout 126 | -------------------------------------------------------------------------------- /packages/simplebar-react/tests/index.test.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { render, waitFor } from '@testing-library/react'; 3 | import SimpleBar from '../index'; 4 | import SimpleBarCore from 'simplebar-core'; 5 | 6 | test('renders without crashing', () => { 7 | const { container } = render( 8 |
9 | 10 | {[...Array(5)].map((_, i) => ( 11 |

Some content

12 | ))} 13 |
14 |
15 | ); 16 | expect(container.firstChild).toMatchSnapshot(); 17 | }); 18 | 19 | test('renders with options', () => { 20 | const { container } = render( 21 | 22 | {[...Array(5)].map((x, i) => ( 23 |

Some content

24 | ))} 25 |
26 | ); 27 | expect(container.firstChild).toMatchSnapshot(); 28 | 29 | expect( 30 | container.querySelector('.simplebar-track.simplebar-vertical') 31 | ).toBeVisible(); 32 | }); 33 | 34 | test('renders with object as option', () => { 35 | const { container } = render( 36 | 41 | {[...Array(5)].map((x, i) => ( 42 |

Some content

43 | ))} 44 |
45 | ); 46 | expect(container.firstChild).toMatchSnapshot(); 47 | 48 | expect(container.querySelector('.custom-class')).toBeVisible(); 49 | }); 50 | 51 | test('renders with scrollableNodeProps', async () => { 52 | const { getByTestId } = render( 53 | 58 | {[...Array(5)].map((x, i) => ( 59 |

Some content

60 | ))} 61 |
62 | ); 63 | 64 | await waitFor(() => 65 | // getByTestId throws an error if it cannot find an element 66 | getByTestId('scrollable-node-props') 67 | ); 68 | }); 69 | 70 | test('renders with ref', async () => { 71 | const ref = React.createRef(); 72 | 73 | const { unmount } = render( 74 | { 76 | // 77 | }} 78 | > 79 | {[...Array(5)].map((x, i) => ( 80 |

Some content

81 | ))} 82 |
83 | ); 84 | 85 | if (!ref.current) return; 86 | 87 | jest.spyOn(ref.current, 'unMount'); 88 | 89 | unmount(); 90 | 91 | expect(ref.current.unMount).toHaveBeenCalled(); 92 | }); 93 | 94 | test('works on unmount', async () => { 95 | const ref = React.createRef(); 96 | 97 | const { unmount } = render( 98 | 99 | {[...Array(5)].map((x, i) => ( 100 |

Some content

101 | ))} 102 |
103 | ); 104 | 105 | jest.spyOn(ref.current, 'unMount'); 106 | 107 | unmount(); 108 | 109 | expect(ref.current.unMount).toHaveBeenCalled(); 110 | }); 111 | 112 | test('renders with ref callback', async () => { 113 | const callback = jest.fn((node) => { 114 | return node; 115 | }); 116 | 117 | const { unmount } = render( 118 | 119 | {[...Array(5)].map((x, i) => ( 120 |

Some content

121 | ))} 122 |
123 | ); 124 | 125 | expect(callback).toHaveBeenCalled(); 126 | unmount(); 127 | expect(callback).toHaveBeenCalledWith(null); 128 | }); 129 | 130 | test('renders with render function', async () => { 131 | let ref1; 132 | let ref2; 133 | 134 | render( 135 | 136 | {({ scrollableNodeRef, contentNodeRef }) => { 137 | ref1 = scrollableNodeRef; 138 | ref2 = contentNodeRef; 139 | return null; 140 | }} 141 | 142 | ); 143 | 144 | expect(ref1).toBeDefined(); 145 | expect(ref2).toBeDefined(); 146 | }); 147 | -------------------------------------------------------------------------------- /packages/website/src/demo.css: -------------------------------------------------------------------------------- 1 | /** 2 | * SimpleBar demo. 3 | * Author: Adrien Grsmto 4 | * 5 | * These styles are not required for SimpleBar 6 | * to function. They are used only for styling the demo. 7 | */ 8 | 9 | /* General page styles 10 | *****************************************************************/ 11 | section:after { 12 | content: ""; 13 | display: table; 14 | clear: both; 15 | } 16 | 17 | section + section { 18 | margin-top: 40px; 19 | } 20 | .box { 21 | background: #666; 22 | color: #fff; 23 | } 24 | .col { 25 | float: left; 26 | width: calc(50% - 20px); 27 | } 28 | .col + .col { 29 | margin-left: 40px; 30 | } 31 | .btn { 32 | display: inline-block; 33 | background: #000; 34 | color: #fff; 35 | padding: 8px 12px; 36 | line-height: 1; 37 | text-decoration: none; 38 | -moz-border-radius: 5px; 39 | -webkit-border-radius: 5px; 40 | -o-border-radius: 5px; 41 | border-radius: 5px; 42 | } 43 | .btn:hover { 44 | background: #666; 45 | color: #fff; 46 | } 47 | .btn:visited { 48 | color: #fff; 49 | } 50 | 51 | /* Scrollable elements 52 | *****************************************************************/ 53 | .demo1, 54 | .demo3 { 55 | margin: 10px 0; 56 | width: 100%; 57 | height: 300px; 58 | } 59 | .demo1 p { 60 | margin: 0; 61 | padding: 10px; 62 | min-width: 230px; 63 | } 64 | .demo1 p.odd:hover { 65 | background: #666; 66 | height: 100px; 67 | } 68 | .demo1 p.odd { 69 | background: #f0f0f0; 70 | } 71 | .demo1.width { 72 | width: 230px; 73 | } 74 | .demo1.height { 75 | height: 200px; 76 | } 77 | #demo1 p { 78 | text-align: right; 79 | padding: 0; 80 | } 81 | .demo1-internal { 82 | width: 50%; 83 | height: 300px; 84 | } 85 | .demo4 { 86 | background: grey; 87 | width: 100%; 88 | margin: 10px 0; 89 | padding: 10px; 90 | white-space: nowrap; 91 | overflow: auto; 92 | } 93 | .demo4 .box { 94 | display: inline-block; 95 | /* margin-right: 10px; */ 96 | width: 100px; 97 | height: 150px; 98 | text-align: center; 99 | line-height: 150px; 100 | font-size: 24px; 101 | } 102 | .demo-raw { 103 | margin: 10px 0; 104 | width: 250px; 105 | height: 300px; 106 | overflow: auto; 107 | } 108 | 109 | .demo3 { 110 | height: auto; 111 | max-height: 300px; 112 | } 113 | 114 | .demo5 { 115 | height: 200px; 116 | height: 60px; 117 | direction: rtl; 118 | } 119 | 120 | .demo-both-axis { 121 | overflow: auto; 122 | width: 200px; 123 | height: 200px; 124 | } 125 | 126 | .demo-both-axis--padding { 127 | background: #2f2f2f; 128 | padding: 40px; 129 | } 130 | 131 | .demo-y-axis { 132 | overflow-y: auto; 133 | overflow-x: hidden; 134 | width: 200px; 135 | height: 200px; 136 | } 137 | 138 | .demo-y-axis.simplebar-dragging .simplebar-scrollbar:before { 139 | background-color: red; 140 | } 141 | 142 | .demo-both-axis .box, 143 | .demo-y-axis .box { 144 | width: 600px; 145 | height: 600px; 146 | } 147 | 148 | .height-100 { 149 | position: absolute; 150 | height: 100%; 151 | width: 100%; 152 | background: red; 153 | } 154 | 155 | .sticky { 156 | position: sticky; 157 | top: 0; 158 | background: red; 159 | margin: 0; 160 | } 161 | 162 | .playground { 163 | display: grid; 164 | grid-template-columns: repeat(2, 1fr); 165 | grid-gap: 10px; 166 | } 167 | 168 | .playground__content { 169 | grid-column-start: span 2; 170 | } 171 | 172 | .demo-flex { 173 | display: flex; 174 | width: 100%; 175 | } 176 | 177 | .demo-flex > div { 178 | height: 300px; 179 | } 180 | 181 | .demo-flex > div .content { 182 | height: 600px; 183 | } 184 | 185 | .demo-flex .left { 186 | width: 200px; 187 | background: #c5e0f7; 188 | } 189 | 190 | .demo-flex .center { 191 | flex: 1; 192 | } 193 | 194 | .demo-flex .right { 195 | width: 200px; 196 | transition: width 0.3s; 197 | background: #ffcfcf; 198 | } 199 | 200 | .demo-height-auto { 201 | width: 25vw; 202 | } 203 | 204 | .demo-height-auto .inner { 205 | margin-bottom: 2em; 206 | width: 25vw; 207 | } 208 | -------------------------------------------------------------------------------- /packages/website/src/pages/index.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { jsx, Styled } from "theme-ui" 3 | import { useEffect, useState } from "react" 4 | import { graphql, withPrefix } from "gatsby" 5 | import SimpleBar from "simplebar-react" 6 | import "simplebar-react/dist/simplebar.min.css" 7 | import { FiGithub } from "react-icons/fi" 8 | import { MdStar } from "react-icons/md" 9 | 10 | import Layout from "../components/Layout" 11 | import SEO from "../components/SEO" 12 | import List from "../components/List" 13 | 14 | import LogoUrl from "../images/logo.svg" 15 | import TwitchUrl from "../images/users/twitch.svg" 16 | import StorybookUrl from "../images/users/storybook.svg" 17 | import ZulipUrl from "../images/users/zulip.svg" 18 | 19 | const verticalCenter = { 20 | display: "inline-flex", 21 | alignItems: "center", 22 | } 23 | 24 | function useGitHubStars() { 25 | const [stars, setStars] = useState(null) 26 | useEffect(() => { 27 | fetch("https://api.github.com/repos/grsmto/simplebar") 28 | .then((result) => result.json()) 29 | .then((response) => setStars(response.stargazers_count)) 30 | }, []) 31 | return stars 32 | } 33 | 34 | const IndexPage = ({ data }) => { 35 | const { 36 | markdownRemark: { html }, 37 | } = data 38 | const stars = useGitHubStars() 39 | 40 | return ( 41 | 42 | 43 |
44 |
45 | SimpleBar logo 52 |
53 |
54 |

63 | Custom scrollbars made simple, lightweight, easy to use and 64 | cross-browser. 65 |

66 | 85 | 86 | 102 | 103 | 104 | 105 |

Who is using it?

106 | 117 |
  • 118 | Twitch 119 |
  • 120 |
  • 121 | Storybook 122 |
  • 123 |
  • 124 | Zulip 125 |
  • 126 |
    127 |
    128 | ) 129 | } 130 | 131 | export default IndexPage 132 | 133 | export const pageQuery = graphql` 134 | { 135 | markdownRemark { 136 | html 137 | } 138 | } 139 | ` 140 | -------------------------------------------------------------------------------- /packages/simplebar-core/tests/simplebar.test.e2e.js: -------------------------------------------------------------------------------- 1 | import 'expect-puppeteer'; 2 | import jestPuppeteerConfig from '../jest-puppeteer.config'; 3 | 4 | /** 5 | * Mark test status on BrowserStack. 6 | * 7 | * @param {Page} page - Page object created by Puppeteer context. 8 | * @param {String} status - Status string can be either passed|failed. 9 | * @param {String} reason - Explanatory reason for the status marked. 10 | * @return {Promise} Stringified response from BrowserStack regarding the 11 | * execution of the jsExecutor. 12 | */ 13 | function markTest(page, status, reason) { 14 | return page.evaluate( 15 | (_) => {}, 16 | `browserstack_executor: ${JSON.stringify({ 17 | action: 'setSessionStatus', 18 | arguments: { status, reason }, 19 | })}` 20 | ); 21 | } 22 | 23 | try { 24 | beforeAll(async () => { 25 | await page.goto(`http://localhost:${jestPuppeteerConfig.server.port}`); 26 | await page.waitForSelector('h1'); 27 | }, 20000); 28 | 29 | beforeEach(async () => { 30 | await page.reload(); 31 | await page.mouse.move(0, 0); 32 | }); 33 | 34 | afterAll(async () => { 35 | await markTest(page, 'passed', 'All test passed!'); 36 | }); 37 | 38 | test('should render demo page', async () => { 39 | await expect(page).toMatch('Simplebar demo page'); 40 | }); 41 | 42 | test('should render SimpleBar on data-simplebar elements', async () => { 43 | await expect(page).toMatchElement('[data-simplebar] .simplebar-content'); 44 | }); 45 | 46 | test('should force scrollbar track to be visible but scrollbar to be hidden', async () => { 47 | const trackSelector = 48 | '[data-simplebar-force-visible] .simplebar-track.simplebar-vertical'; 49 | 50 | await page.waitForSelector(trackSelector, { visible: true }); 51 | await page.waitForSelector(`${trackSelector} .simplebar-scrollbar`, { 52 | hidden: true, 53 | }); 54 | }); 55 | 56 | test('should display SimpleBar in "rtl" mode', async () => { 57 | const el = await expect(page).toMatchElement('.demo-rtl'); 58 | const scrollbarEl = await expect(el).toMatchElement( 59 | '.simplebar-track.simplebar-horizontal .simplebar-scrollbar' 60 | ); 61 | const transformStyle = await page.evaluate( 62 | (el) => el.style.transform, 63 | scrollbarEl 64 | ); 65 | const elBoundingBox = await el.boundingBox(); 66 | const scrollbarElBoundingBox = await scrollbarEl.boundingBox(); 67 | 68 | expect(transformStyle).toEqual( 69 | `translate3d(${ 70 | elBoundingBox.width - scrollbarElBoundingBox.width 71 | }px, 0px, 0px)` 72 | ); 73 | }); 74 | 75 | test('should add class "dragging" when dragging', async () => { 76 | const el = await expect(page).toMatchElement('#demo2'); 77 | 78 | await page.click( 79 | '#demo2 .simplebar-track.simplebar-vertical .simplebar-scrollbar' 80 | ); 81 | await page.mouse.down(); 82 | 83 | const isDragging = await page.evaluate( 84 | (el) => el.classList.contains('simplebar-dragging'), 85 | el 86 | ); 87 | 88 | expect(isDragging).toBeTruthy(); 89 | }); 90 | 91 | test('should recalculate scrollbar size when content size changes', async () => { 92 | const el = await expect(page).toMatchElement('#demo2'); 93 | const scrollbarEl = await expect(el).toMatchElement( 94 | '.simplebar-track.simplebar-vertical .simplebar-scrollbar' 95 | ); 96 | 97 | const scrollbarHeight = await page.evaluate( 98 | (el) => parseInt(el.style.height), 99 | scrollbarEl 100 | ); 101 | 102 | // await jestPuppeteer.debug(); 103 | 104 | await page.hover('#demo2 p'); 105 | await page.click('#demo2 p', { delay: 1000 }); // wait for Simplebar to recalculate 106 | 107 | const scrollbarHeightAfterHover = await page.evaluate( 108 | (el) => parseInt(el.style.height), 109 | scrollbarEl 110 | ); 111 | 112 | expect(scrollbarHeightAfterHover).toBeLessThan(scrollbarHeight); 113 | }); 114 | } catch (err) { 115 | markTest(page, 'failed', err.message); 116 | } 117 | -------------------------------------------------------------------------------- /packages/examples/public/css/demo.css: -------------------------------------------------------------------------------- 1 | /** 2 | * SimpleBar demo. 3 | * Author: Adrien Grsmto 4 | * 5 | * These styles are not required for SimpleBar 6 | * to function. They are used only for styling the demo. 7 | */ 8 | 9 | /* General page styles 10 | *****************************************************************/ 11 | 12 | * { 13 | box-sizing: border-box; 14 | } 15 | 16 | body { 17 | font-family: Helvetica, Arial, sans-serif; 18 | font-size: 14px; 19 | margin: 20px; 20 | } 21 | 22 | section:after { 23 | content: ''; 24 | display: table; 25 | clear: both; 26 | } 27 | 28 | section + section { 29 | margin-top: 40px; 30 | } 31 | 32 | h1 { 33 | font-size: 30px; 34 | margin: 0 0 10px 0; 35 | } 36 | h2 { 37 | font-size: 24px; 38 | margin: 10px 0; 39 | } 40 | p { 41 | margin: 1em 0; 42 | } 43 | .box { 44 | background: #666; 45 | color: #fff; 46 | } 47 | .col { 48 | float: left; 49 | width: calc(50% - 20px); 50 | } 51 | .col + .col { 52 | margin-left: 40px; 53 | } 54 | .btn { 55 | display: inline-block; 56 | background: #000; 57 | color: #fff; 58 | padding: 8px 12px; 59 | line-height: 1; 60 | text-decoration: none; 61 | -moz-border-radius: 5px; 62 | -webkit-border-radius: 5px; 63 | -o-border-radius: 5px; 64 | border-radius: 5px; 65 | } 66 | .btn:hover { 67 | background: #666; 68 | color: #fff; 69 | } 70 | .btn:visited { 71 | color: #fff; 72 | } 73 | 74 | /* Scrollable elements 75 | *****************************************************************/ 76 | .demo1, 77 | .demo3 { 78 | margin: 10px 0; 79 | width: 100%; 80 | height: 300px; 81 | } 82 | .demo1 p { 83 | margin: 0; 84 | padding: 10px; 85 | min-width: 230px; 86 | } 87 | .demo1 p.odd:hover { 88 | background: #666; 89 | height: 100px; 90 | } 91 | .demo1 p.odd { 92 | background: #f0f0f0; 93 | } 94 | .demo1.width { 95 | width: 230px; 96 | } 97 | .demo1.height { 98 | height: 200px; 99 | } 100 | #demo1 p { 101 | text-align: right; 102 | padding: 0; 103 | } 104 | .demo1-internal { 105 | width: 50%; 106 | height: 300px; 107 | } 108 | .demo4 { 109 | background: grey; 110 | width: 100%; 111 | margin: 10px 0; 112 | padding: 10px; 113 | white-space: nowrap; 114 | overflow: auto; 115 | } 116 | .demo4 .box { 117 | display: inline-block; 118 | /* margin-right: 10px; */ 119 | width: 100px; 120 | height: 150px; 121 | text-align: center; 122 | line-height: 150px; 123 | font-size: 24px; 124 | } 125 | .demo-raw { 126 | margin: 10px 0; 127 | width: 250px; 128 | height: 300px; 129 | overflow: auto; 130 | } 131 | 132 | .demo3 { 133 | height: auto; 134 | max-height: 300px; 135 | } 136 | 137 | .demo5 { 138 | height: 200px; 139 | height: 60px; 140 | direction: rtl; 141 | } 142 | 143 | .demo-both-axis { 144 | overflow: auto; 145 | width: 200px; 146 | height: 200px; 147 | } 148 | 149 | .demo-both-axis--padding { 150 | background: #2f2f2f; 151 | padding: 40px; 152 | } 153 | 154 | .demo-y-axis { 155 | overflow-y: auto; 156 | overflow-x: hidden; 157 | width: 200px; 158 | height: 200px; 159 | } 160 | 161 | .demo-y-axis.simplebar-dragging .simplebar-scrollbar:before { 162 | background-color: red; 163 | } 164 | 165 | .demo-both-axis .box, 166 | .demo-y-axis .box { 167 | width: 600px; 168 | height: 600px; 169 | } 170 | 171 | .height-100 { 172 | position: absolute; 173 | height: 100%; 174 | width: 100%; 175 | background: red; 176 | } 177 | 178 | .sticky { 179 | position: sticky; 180 | top: 0; 181 | background: red; 182 | margin: 0; 183 | } 184 | 185 | .playground { 186 | display: grid; 187 | grid-template-columns: repeat(2, 1fr); 188 | grid-gap: 10px; 189 | } 190 | 191 | .playground__content { 192 | grid-column-start: span 2; 193 | } 194 | 195 | .demo-flex { 196 | display: flex; 197 | width: 100%; 198 | } 199 | 200 | .demo-flex > div { 201 | height: 300px; 202 | } 203 | 204 | .demo-flex > div .content { 205 | height: 600px; 206 | } 207 | 208 | .demo-flex .left { 209 | width: 200px; 210 | background: #c5e0f7; 211 | } 212 | 213 | .demo-flex .center { 214 | flex: 1; 215 | } 216 | 217 | .demo-flex .right { 218 | width: 200px; 219 | transition: width 0.3s; 220 | background: #ffcfcf; 221 | } 222 | 223 | .demo-height-auto { 224 | width: 25vw; 225 | } 226 | 227 | .demo-height-auto .inner { 228 | margin-bottom: 2em; 229 | width: 25vw; 230 | } 231 | 232 | .demo-hidden { 233 | height: 300px; 234 | } 235 | 236 | .demo-hidden p { 237 | margin: 0; 238 | padding: 10px; 239 | min-width: 230px; 240 | } 241 | -------------------------------------------------------------------------------- /packages/website/src/images/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /examples/react/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (isLocalhost) { 36 | // This is running on localhost. Lets check if a service worker still exists or not. 37 | checkValidServiceWorker(swUrl); 38 | 39 | // Add some additional logging to localhost, pointing developers to the 40 | // service worker/PWA documentation. 41 | navigator.serviceWorker.ready.then(() => { 42 | console.log( 43 | 'This web app is being served cache-first by a service ' + 44 | 'worker. To learn more, visit https://goo.gl/SC7cgQ' 45 | ); 46 | }); 47 | } else { 48 | // Is not local host. Just register service worker 49 | registerValidSW(swUrl); 50 | } 51 | }); 52 | } 53 | } 54 | 55 | function registerValidSW(swUrl) { 56 | navigator.serviceWorker 57 | .register(swUrl) 58 | .then(registration => { 59 | registration.onupdatefound = () => { 60 | const installingWorker = registration.installing; 61 | installingWorker.onstatechange = () => { 62 | if (installingWorker.state === 'installed') { 63 | if (navigator.serviceWorker.controller) { 64 | // At this point, the old content will have been purged and 65 | // the fresh content will have been added to the cache. 66 | // It's the perfect time to display a "New content is 67 | // available; please refresh." message in your web app. 68 | console.log('New content is available; please refresh.'); 69 | } else { 70 | // At this point, everything has been precached. 71 | // It's the perfect time to display a 72 | // "Content is cached for offline use." message. 73 | console.log('Content is cached for offline use.'); 74 | } 75 | } 76 | }; 77 | }; 78 | }) 79 | .catch(error => { 80 | console.error('Error during service worker registration:', error); 81 | }); 82 | } 83 | 84 | function checkValidServiceWorker(swUrl) { 85 | // Check if the service worker can be found. If it can't reload the page. 86 | fetch(swUrl) 87 | .then(response => { 88 | // Ensure service worker exists, and that we really are getting a JS file. 89 | if ( 90 | response.status === 404 || 91 | response.headers.get('content-type').indexOf('javascript') === -1 92 | ) { 93 | // No service worker found. Probably a different app. Reload the page. 94 | navigator.serviceWorker.ready.then(registration => { 95 | registration.unregister().then(() => { 96 | window.location.reload(); 97 | }); 98 | }); 99 | } else { 100 | // Service worker found. Proceed as normal. 101 | registerValidSW(swUrl); 102 | } 103 | }) 104 | .catch(() => { 105 | console.log( 106 | 'No internet connection found. App is running in offline mode.' 107 | ); 108 | }); 109 | } 110 | 111 | export function unregister() { 112 | if ('serviceWorker' in navigator) { 113 | navigator.serviceWorker.ready.then(registration => { 114 | registration.unregister(); 115 | }); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /packages/simplebar-react/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import type { ReactNode, MutableRefObject } from 'react'; 3 | import SimpleBarCore from 'simplebar-core'; 4 | import type { SimpleBarOptions } from 'simplebar-core'; 5 | 6 | type RenderFunc = (props: { 7 | scrollableNodeRef: MutableRefObject; 8 | scrollableNodeProps: { 9 | className: string; 10 | ref: MutableRefObject; 11 | }; 12 | contentNodeRef: MutableRefObject; 13 | contentNodeProps: { 14 | className: string; 15 | ref: MutableRefObject; 16 | }; 17 | }) => ReactNode; 18 | 19 | export interface Props 20 | extends Omit, 'children'>, 21 | SimpleBarOptions { 22 | children?: ReactNode | RenderFunc; 23 | scrollableNodeProps?: { 24 | ref?: any; 25 | className?: string; 26 | [key: string]: any; 27 | }; 28 | } 29 | 30 | const SimpleBar = React.forwardRef( 31 | ({ children, scrollableNodeProps = {}, ...otherProps }, ref) => { 32 | const elRef = React.useRef(); 33 | const scrollableNodeRef = React.useRef(); 34 | const contentNodeRef = React.useRef(); 35 | const options: Partial = {}; 36 | const rest: any = {}; 37 | 38 | Object.keys(otherProps).forEach((key) => { 39 | if ( 40 | Object.prototype.hasOwnProperty.call(SimpleBarCore.defaultOptions, key) 41 | ) { 42 | (options as any)[key] = otherProps[key as keyof SimpleBarOptions]; 43 | } else { 44 | rest[key] = otherProps[key as keyof SimpleBarOptions]; 45 | } 46 | }); 47 | 48 | const classNames = { 49 | ...SimpleBarCore.defaultOptions.classNames, 50 | ...options.classNames, 51 | } as Required<(typeof SimpleBarCore.defaultOptions)['classNames']>; 52 | 53 | const scrollableNodeFullProps = { 54 | ...scrollableNodeProps, 55 | className: `${classNames.contentWrapper}${ 56 | scrollableNodeProps.className ? ` ${scrollableNodeProps.className}` : '' 57 | }`, 58 | tabIndex: options.tabIndex || SimpleBarCore.defaultOptions.tabIndex, 59 | role: 'region', 60 | 'aria-label': options.ariaLabel || SimpleBarCore.defaultOptions.ariaLabel, 61 | }; 62 | 63 | React.useEffect(() => { 64 | let instance: SimpleBarCore | null; 65 | scrollableNodeRef.current = scrollableNodeFullProps.ref 66 | ? scrollableNodeFullProps.ref.current 67 | : scrollableNodeRef.current; 68 | 69 | if (elRef.current) { 70 | instance = new SimpleBarCore(elRef.current, { 71 | ...options, 72 | ...(scrollableNodeRef.current && { 73 | scrollableNode: scrollableNodeRef.current, 74 | }), 75 | ...(contentNodeRef.current && { 76 | contentNode: contentNodeRef.current, 77 | }), 78 | }); 79 | 80 | if (typeof ref === 'function') { 81 | ref(instance); 82 | } else if (ref) { 83 | ref.current = instance; 84 | } 85 | } 86 | 87 | return () => { 88 | instance?.unMount(); 89 | instance = null; 90 | if (typeof ref === 'function') { 91 | ref(null); 92 | } 93 | }; 94 | }, []); 95 | 96 | return ( 97 |
    98 |
    99 |
    100 |
    101 |
    102 |
    103 |
    104 | {typeof children === 'function' ? ( 105 | children({ 106 | scrollableNodeRef, 107 | scrollableNodeProps: { 108 | ...scrollableNodeFullProps, 109 | ref: scrollableNodeRef, 110 | }, 111 | contentNodeRef, 112 | contentNodeProps: { 113 | className: classNames.contentEl, 114 | ref: contentNodeRef, 115 | }, 116 | }) 117 | ) : ( 118 |
    119 |
    {children}
    120 |
    121 | )} 122 |
    123 |
    124 |
    125 |
    126 |
    127 |
    128 |
    129 |
    130 |
    131 |
    132 |
    133 | ); 134 | } 135 | ); 136 | 137 | SimpleBar.displayName = 'SimpleBar'; 138 | 139 | export default SimpleBar; 140 | -------------------------------------------------------------------------------- /packages/website/src/images/users/storybook.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/simplebar-core/src/simplebar.css: -------------------------------------------------------------------------------- 1 | [data-simplebar] { 2 | position: relative; 3 | flex-direction: column; 4 | flex-wrap: wrap; 5 | justify-content: flex-start; 6 | align-content: flex-start; 7 | align-items: flex-start; 8 | } 9 | 10 | .simplebar-wrapper { 11 | overflow: hidden; 12 | width: inherit; 13 | height: inherit; 14 | max-width: inherit; 15 | max-height: inherit; 16 | } 17 | 18 | .simplebar-mask { 19 | direction: inherit; 20 | position: absolute; 21 | overflow: hidden; 22 | padding: 0; 23 | margin: 0; 24 | left: 0; 25 | top: 0; 26 | bottom: 0; 27 | right: 0; 28 | width: auto !important; 29 | height: auto !important; 30 | z-index: 0; 31 | } 32 | 33 | .simplebar-offset { 34 | direction: inherit !important; 35 | box-sizing: inherit !important; 36 | resize: none !important; 37 | position: absolute; 38 | top: 0; 39 | left: 0; 40 | bottom: 0; 41 | right: 0; 42 | padding: 0; 43 | margin: 0; 44 | -webkit-overflow-scrolling: touch; 45 | } 46 | 47 | .simplebar-content-wrapper { 48 | direction: inherit; 49 | box-sizing: border-box !important; 50 | position: relative; 51 | display: block; 52 | height: 100%; /* Required for horizontal native scrollbar to not appear if parent is taller than natural height */ 53 | width: auto; 54 | max-width: 100%; /* Not required for horizontal scroll to trigger */ 55 | max-height: 100%; /* Needed for vertical scroll to trigger */ 56 | overflow: auto; 57 | scrollbar-width: none; 58 | -ms-overflow-style: none; 59 | } 60 | 61 | .simplebar-content-wrapper::-webkit-scrollbar, 62 | .simplebar-hide-scrollbar::-webkit-scrollbar { 63 | display: none; 64 | width: 0; 65 | height: 0; 66 | } 67 | 68 | .simplebar-content:before, 69 | .simplebar-content:after { 70 | content: ' '; 71 | display: table; 72 | } 73 | 74 | .simplebar-placeholder { 75 | max-height: 100%; 76 | max-width: 100%; 77 | width: 100%; 78 | pointer-events: none; 79 | } 80 | 81 | .simplebar-height-auto-observer-wrapper { 82 | box-sizing: inherit !important; 83 | height: 100%; 84 | width: 100%; 85 | max-width: 1px; 86 | position: relative; 87 | float: left; 88 | max-height: 1px; 89 | overflow: hidden; 90 | z-index: -1; 91 | padding: 0; 92 | margin: 0; 93 | pointer-events: none; 94 | flex-grow: inherit; 95 | flex-shrink: 0; 96 | flex-basis: 0; 97 | } 98 | 99 | .simplebar-height-auto-observer { 100 | box-sizing: inherit; 101 | display: block; 102 | opacity: 0; 103 | position: absolute; 104 | top: 0; 105 | left: 0; 106 | height: 1000%; 107 | width: 1000%; 108 | min-height: 1px; 109 | min-width: 1px; 110 | overflow: hidden; 111 | pointer-events: none; 112 | z-index: -1; 113 | } 114 | 115 | .simplebar-track { 116 | z-index: 1; 117 | position: absolute; 118 | right: 0; 119 | bottom: 0; 120 | pointer-events: none; 121 | overflow: hidden; 122 | } 123 | 124 | [data-simplebar].simplebar-dragging { 125 | pointer-events: none; 126 | -webkit-touch-callout: none; 127 | -webkit-user-select: none; 128 | -khtml-user-select: none; 129 | -moz-user-select: none; 130 | -ms-user-select: none; 131 | user-select: none; 132 | } 133 | 134 | [data-simplebar].simplebar-dragging .simplebar-content { 135 | pointer-events: none; 136 | -webkit-touch-callout: none; 137 | -webkit-user-select: none; 138 | -khtml-user-select: none; 139 | -moz-user-select: none; 140 | -ms-user-select: none; 141 | user-select: none; 142 | } 143 | 144 | [data-simplebar].simplebar-dragging .simplebar-track { 145 | pointer-events: all; 146 | } 147 | 148 | .simplebar-scrollbar { 149 | position: absolute; 150 | left: 0; 151 | right: 0; 152 | min-height: 10px; 153 | } 154 | 155 | .simplebar-scrollbar:before { 156 | position: absolute; 157 | content: ''; 158 | background: black; 159 | border-radius: 7px; 160 | left: 2px; 161 | right: 2px; 162 | opacity: 0; 163 | transition: opacity 0.2s 0.5s linear; 164 | } 165 | 166 | .simplebar-scrollbar.simplebar-visible:before { 167 | opacity: 0.5; 168 | transition-delay: 0s; 169 | transition-duration: 0s; 170 | } 171 | 172 | .simplebar-track.simplebar-vertical { 173 | top: 0; 174 | width: 11px; 175 | } 176 | 177 | .simplebar-scrollbar:before { 178 | top: 2px; 179 | bottom: 2px; 180 | left: 2px; 181 | right: 2px; 182 | } 183 | 184 | .simplebar-track.simplebar-horizontal { 185 | left: 0; 186 | height: 11px; 187 | } 188 | 189 | .simplebar-track.simplebar-horizontal .simplebar-scrollbar { 190 | right: auto; 191 | left: 0; 192 | top: 0; 193 | bottom: 0; 194 | min-height: 0; 195 | min-width: 10px; 196 | width: auto; 197 | } 198 | 199 | /* Rtl support */ 200 | [data-simplebar-direction='rtl'] .simplebar-track.simplebar-vertical { 201 | right: auto; 202 | left: 0; 203 | } 204 | 205 | .simplebar-dummy-scrollbar-size { 206 | direction: rtl; 207 | position: fixed; 208 | opacity: 0; 209 | visibility: hidden; 210 | height: 500px; 211 | width: 500px; 212 | overflow-y: hidden; 213 | overflow-x: scroll; 214 | -ms-overflow-style: scrollbar !important; 215 | } 216 | 217 | .simplebar-dummy-scrollbar-size > div { 218 | width: 200%; 219 | height: 200%; 220 | margin: 10px 0; 221 | } 222 | 223 | .simplebar-hide-scrollbar { 224 | position: fixed; 225 | left: 0; 226 | visibility: hidden; 227 | overflow-y: scroll; 228 | scrollbar-width: none; 229 | -ms-overflow-style: none; 230 | } 231 | -------------------------------------------------------------------------------- /packages/simplebar-react/README.md: -------------------------------------------------------------------------------- 1 |

    2 | SimpleBar 3 |

    4 |
    5 |

    6 | NPM version 7 | NPM downloads 8 | Build Status 9 | 10 |

    11 |
    12 | 13 | # SimplebarReact 14 | 15 | - **🐦 Follow me on [Twitter!](https://twitter.com/adriendenat) or [Mastodon!](https://mas.to/@adrien)** 16 | - **👨‍💻 I'm available for hire! [Reach out to me!](https://adriendenat.com/)** 17 | - **🚧 Check out my new project [Scroll Snap Carousel](https://github.com/Grsmto/scroll-snap-carousel)!** 18 | 19 | ### Installation 20 | 21 | **- Via npm** 22 | `npm install simplebar-react --save` 23 | 24 | **- Via Yarn** 25 | `yarn add simplebar-react` 26 | 27 | ### Usage 28 | 29 | Check out the [Demo project](https://github.com/Grsmto/simplebar/blob/master/examples/react/src/App.js) or our live [Codesandbox example](https://codesandbox.io/s/simplebar-react-gwgyw). 30 | 31 | If you are using a module loader (like Webpack) you first need to load SimpleBar: 32 | 33 | ```js 34 | import SimpleBar from 'simplebar-react'; 35 | import 'simplebar-react/dist/simplebar.min.css'; 36 | 37 | const App = () => ( 38 | // your content 39 | ); 40 | ``` 41 | 42 | **Don't forget to import both css and js in your project!** 43 | 44 | ### :warning: Warning! 45 | 46 | SimpleBar is **not intended to be used on the `body` element!** I don't recommend wrapping your entire web page inside a custom scroll as it will often badly affect the user experience (slower scroll performance compared to the native body scroll, no native scroll behaviours like click on track, etc.). Do it at your own risk! SimpleBar is meant to improve the experience of **internal web page scrolling**; such as a chat box or a small scrolling area. **Please read the [caveats](#5-caveats) section first to be aware of the limitations!** 47 | 48 | ### Troubleshooting 49 | 50 | If you are experiencing issues when setting up SimpleBar, it is most likely because your styles are clashing with SimpleBar ones. Make sure the element you are setting SimpleBar on does not override any SimpleBar css properties! **We recommend to not style that element at all and use an inner element instead.** 51 | 52 | ### Sponsors 53 | 54 | Thanks to BrowserStack for sponsoring open source projects and letting us test SimpleBar for free. 55 | 56 | 57 | 58 | 59 | 1. [Documentation](#1-documentation) 60 | 61 | ## 1. Documentation 62 | 63 | ### Passing options 64 | 65 | Find the list of available options on [the core documentation](https://github.com/Grsmto/simplebar/blob/master/packages/simplebar/README.md#options). 66 | 67 | ```js 68 | 69 | // your content 70 | 71 | ``` 72 | 73 | ### Extra options 74 | 75 | #### scrollableNodeProps 76 | 77 | You can pass props to the underlying scrollable `div` element. This is useful for example to get a `ref` of it, if you want to access the `scroll` event or apply imperative directive (like scrolling SimpleBar to the bottom, etc.). 78 | 79 | ```js 80 | const scrollableNodeRef = React.createRef(); 81 | 82 | 83 | // your content 84 | ; 85 | ``` 86 | 87 | ### Accessing SimpleBar instance 88 | 89 | You can pass a ref to the SimpleBar element: 90 | 91 | ```js 92 | const ref = useRef(); 93 | 94 | useEffect(() => { 95 | ref.current.recalculate(); 96 | console.log(ref.current.el); // <- the root element you applied SimpleBar on 97 | }) 98 | 99 | 100 | // your content 101 | 102 | ``` 103 | 104 | ### Usage with 3rd party libraries 105 | 106 | For advanced usage, in some cases (like using react-window) you can forward the scrollable and content elements using a render prop pattern: 107 | 108 | ```js 109 | 110 | {({ scrollableNodeRef, contentNodeRef }) => { 111 | // Now you have access to scrollable and content nodes 112 | return
    ; 113 | }} 114 |
    115 | ``` 116 | 117 | If you define your own elements you should do: 118 | 119 | ```js 120 | 121 | {({ scrollableNodeProps, contentNodeProps }) => { 122 | return ( 123 |
    124 | outer/scrollable element 125 |
    inner element
    126 |
    127 | ); 128 | }} 129 |
    130 | ``` 131 | -------------------------------------------------------------------------------- /packages/simplebar-react/tests/__snapshots__/index.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`renders with object as option 1`] = ` 4 |
    7 |
    10 |
    13 |
    16 |
    17 |
    20 |
    24 |
    31 |
    34 |

    35 | Some content 36 |

    37 |

    38 | Some content 39 |

    40 |

    41 | Some content 42 |

    43 |

    44 | Some content 45 |

    46 |

    47 | Some content 48 |

    49 |
    50 |
    51 |
    52 |
    53 |
    57 |
    58 |