pax_global_header00006660000000000000000000000064147274265710014531gustar00rootroot0000000000000052 comment=29e9fcd1eecf7d3b77a767941c4a57fe461fc1e4 theKashey-react-remove-scroll-bar-7fe7bbe/000077500000000000000000000000001472742657100206665ustar00rootroot00000000000000theKashey-react-remove-scroll-bar-7fe7bbe/.eslintrc.js000066400000000000000000000035011472742657100231240ustar00rootroot00000000000000module.exports = { extends: ['plugin:@typescript-eslint/recommended', 'plugin:import/typescript', 'plugin:react-hooks/recommended'], parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint', 'prettier', 'import'], rules: { '@typescript-eslint/ban-ts-comment': 0, '@typescript-eslint/ban-ts-ignore': 0, '@typescript-eslint/no-var-requires': 0, '@typescript-eslint/camelcase': 0, 'import/order': [ 'error', { 'newlines-between': 'always-and-inside-groups', alphabetize: { order: 'asc', }, groups: ['builtin', 'external', 'internal', ['parent', 'index', 'sibling']], }, ], 'padding-line-between-statements': [ 'error', // IMPORT { blankLine: 'always', prev: 'import', next: '*', }, { blankLine: 'any', prev: 'import', next: 'import', }, // EXPORT { blankLine: 'always', prev: '*', next: 'export', }, { blankLine: 'any', prev: 'export', next: 'export', }, { blankLine: 'always', prev: '*', next: ['const', 'let'], }, { blankLine: 'any', prev: ['const', 'let'], next: ['const', 'let'], }, // BLOCKS { blankLine: 'always', prev: ['block', 'block-like', 'class', 'function', 'multiline-expression'], next: '*', }, { blankLine: 'always', prev: '*', next: ['block', 'block-like', 'class', 'function', 'return', 'multiline-expression'], }, ], }, settings: { 'import/parsers': { '@typescript-eslint/parser': ['.ts', '.tsx'], }, 'import/resolver': { typescript: { alwaysTryTypes: true, }, }, }, }; theKashey-react-remove-scroll-bar-7fe7bbe/.github/000077500000000000000000000000001472742657100222265ustar00rootroot00000000000000theKashey-react-remove-scroll-bar-7fe7bbe/.github/stale.yml000066400000000000000000000012741472742657100240650ustar00rootroot00000000000000# Number of days of inactivity before an issue becomes stale daysUntilStale: 60 # Number of days of inactivity before a stale issue is closed daysUntilClose: 7 # Label to use when marking an issue as stale staleLabel: state # Comment to post when marking an issue as stale. Set to `false` to disable markComment: > This issue has been marked as "stale" because there has been no activity for 2 months. If you have any new information or would like to continue the discussion, please feel free to do so. If this issue got buried among other tasks, maybe this message will reignite the conversation. Otherwise, this issue will be closed in 7 days. Thank you for your contributions so far. theKashey-react-remove-scroll-bar-7fe7bbe/.gitignore000066400000000000000000000000671472742657100226610ustar00rootroot00000000000000node_modules/ /dist/ .DS_Store coverage/ yarn-error.logtheKashey-react-remove-scroll-bar-7fe7bbe/.npmignore000066400000000000000000000000551472742657100226650ustar00rootroot00000000000000node_modules/ npm-debug.log .DS_Store exampletheKashey-react-remove-scroll-bar-7fe7bbe/.npmrc000066400000000000000000000000431472742657100220030ustar00rootroot00000000000000registry=https://registry.npmjs.orgtheKashey-react-remove-scroll-bar-7fe7bbe/.nvmrc000066400000000000000000000000021472742657100220040ustar00rootroot0000000000000018theKashey-react-remove-scroll-bar-7fe7bbe/.size-limit000066400000000000000000000001541472742657100227550ustar00rootroot00000000000000[ { "path": "dist/es2019/index.js", "ignore": ["react-dom", "tslib"], "limit": "1350 B" } ] theKashey-react-remove-scroll-bar-7fe7bbe/.size.json000066400000000000000000000001541472742657100226110ustar00rootroot00000000000000[ { "name": "dist/es2019/index.js", "passed": true, "size": 1285, "sizeLimit": 1350 } ] theKashey-react-remove-scroll-bar-7fe7bbe/.storybook/000077500000000000000000000000001472742657100227775ustar00rootroot00000000000000theKashey-react-remove-scroll-bar-7fe7bbe/.storybook/.babelrc000066400000000000000000000003371472742657100243750ustar00rootroot00000000000000{ "sourceType": "unambiguous", "presets": [ [ "@babel/preset-env", { "shippedProposals": true, "loose": true } ], "@babel/preset-typescript", "@babel/preset-react" ] }theKashey-react-remove-scroll-bar-7fe7bbe/.storybook/main.js000066400000000000000000000002241472742657100242570ustar00rootroot00000000000000module.exports = { stories: ['../stories/*.stories.@(js|jsx|ts|tsx)'], framework: '@storybook/react', typescript: { check: false, }, }; theKashey-react-remove-scroll-bar-7fe7bbe/.storybook/preview.js000066400000000000000000000002571472742657100250220ustar00rootroot00000000000000export const parameters = { actions: { argTypesRegex: '^on[A-Z].*' }, controls: { matchers: { color: /(background|color)$/i, date: /Date$/, }, }, }; theKashey-react-remove-scroll-bar-7fe7bbe/.travis.yml000066400000000000000000000001721472742657100227770ustar00rootroot00000000000000language: node_js node_js: - '16' cache: yarn script: - yarn - yarn test:ci - codecov notifications: email: truetheKashey-react-remove-scroll-bar-7fe7bbe/CHANGELOG.md000066400000000000000000000067251472742657100225110ustar00rootroot00000000000000## [2.3.6](https://github.com/theKashey/react-remove-scroll-bar/compare/v2.3.5...v2.3.6) (2024-03-14) ### Bug Fixes - correct lock behavior for nested invocations, fixes [#57](https://github.com/theKashey/react-remove-scroll-bar/issues/57) ([bd44ebe](https://github.com/theKashey/react-remove-scroll-bar/commit/bd44ebeea9af047816dbb66c42eab57cbd937fcb)) ## [2.3.5](https://github.com/theKashey/react-remove-scroll-bar/compare/v2.3.4...v2.3.5) (2024-02-19) ## [2.3.4](https://github.com/theKashey/react-remove-scroll-bar/compare/v2.3.3...v2.3.4) (2022-10-12) ### Bug Fixes - remove measure time error reporting, fixes [#35](https://github.com/theKashey/react-remove-scroll-bar/issues/35) ([3f4bf5d](https://github.com/theKashey/react-remove-scroll-bar/commit/3f4bf5d26713b18e3161dce34b7a07265d763864)) ## [2.3.3](https://github.com/theKashey/react-remove-scroll-bar/compare/v2.3.2...v2.3.3) (2022-06-06) ## [2.3.2](https://github.com/theKashey/react-remove-scroll-bar/compare/v2.3.1...v2.3.2) (2022-06-06) ### Bug Fixes - update style-singlenton. fixes [#32](https://github.com/theKashey/react-remove-scroll-bar/issues/32) ([f8b9a22](https://github.com/theKashey/react-remove-scroll-bar/commit/f8b9a22ae5ba8a0868caa15faf1a83ee06534f17)) ## [2.3.1](https://github.com/theKashey/react-remove-scroll-bar/compare/v2.3.0...v2.3.1) (2022-05-01) ### Bug Fixes - configure overscroll-behavior to contain scroll within body ([a29ad5d](https://github.com/theKashey/react-remove-scroll-bar/commit/a29ad5d237f9c696f430f18dbd4cc0ae0a37b617)) # [2.3.0](https://github.com/theKashey/react-remove-scroll-bar/compare/v2.2.0...v2.3.0) (2022-04-17) # [2.2.0](https://github.com/theKashey/react-remove-scroll-bar/compare/v2.1.1...v2.2.0) (2021-02-10) ### Features - expose removed scroll bar size via css variable ([e357989](https://github.com/theKashey/react-remove-scroll-bar/commit/e357989a92fb8acc83466f8371d0fa558f1a5492)) ## [2.1.1](https://github.com/theKashey/react-remove-scroll-bar/compare/v2.1.0...v2.1.1) (2020-11-27) # [2.1.0](https://github.com/theKashey/react-remove-scroll-bar/compare/v2.0.0...v2.1.0) (2020-04-16) ### Features - support CSP ([d805e33](https://github.com/theKashey/react-remove-scroll-bar/commit/d805e332d8525a7b39bc19765f52ca89fb415dff)) # [2.0.0](https://github.com/theKashey/react-remove-scroll-bar/compare/v1.2.0...v2.0.0) (2019-06-07) # [1.2.0](https://github.com/theKashey/react-remove-scroll-bar/compare/v1.1.5...v1.2.0) (2019-06-04) ### Features - extract constants as a separate entrypoint ([2a569b5](https://github.com/theKashey/react-remove-scroll-bar/commit/2a569b50643c251604e360a1cb366aa5a68aedda)) ## [1.1.5](https://github.com/theKashey/react-remove-scroll-bar/compare/v1.1.4...v1.1.5) (2019-05-03) ### Bug Fixes - always add overflow hidden, even for scroll-bar-free systems ([9540463](https://github.com/theKashey/react-remove-scroll-bar/commit/95404631661026008772f2c43c298ff05971dd21)) ## [1.1.4](https://github.com/theKashey/react-remove-scroll-bar/compare/v1.1.3...v1.1.4) (2019-03-02) ## [1.1.3](https://github.com/theKashey/react-remove-scroll-bar/compare/v1.1.2...v1.1.3) (2019-01-21) ### Features - support non-zero body margins ([0828cf6](https://github.com/theKashey/react-remove-scroll-bar/commit/0828cf6d4fcbe142c7b487b941768db64f7b4508)) ## [1.1.2](https://github.com/theKashey/react-remove-scroll-bar/compare/v1.1.1...v1.1.2) (2019-01-18) ## [1.1.1](https://github.com/theKashey/react-remove-scroll-bar/compare/v1.1.0...v1.1.1) (2019-01-18) # 1.1.0 (2019-01-18) theKashey-react-remove-scroll-bar-7fe7bbe/README.md000066400000000000000000000032641472742657100221520ustar00rootroot00000000000000

react-remove-scroll-bar

[![npm](https://img.shields.io/npm/v/react-remove-scroll-bar.svg)](https://www.npmjs.com/package/react-remove-scroll-bar) [![bundle size](https://badgen.net/bundlephobia/minzip/react-remove-scroll-bar)](https://bundlephobia.com/result?p=react-remove-scroll-bar) [![downloads](https://badgen.net/npm/dm/react-remove-scroll-bar)](https://www.npmtrends.com/react-remove-scroll-bar)
> v1+ for React 15, v2+ requires React 16.8+ Removes scroll bar (by setting `overflow: hidden` on body), and preserves the scroll bar "gap". Read - it just makes scroll bar invisible. Does nothing if scroll bar does not consume any space. # Usage ```js import {RemoveScrollBar} from 'react-remove-scroll-bar'; -> no scroll bar ``` ### The Right Border To prevent content jumps __position:fixed__ elements with `right:0` should have additional classname applied. It will just provide a _non-zero_ right, when it needed, to maintain the right "gap". ```js import {zeroRightClassName,fullWidthClassName, noScrollbarsClassName} from 'react-remove-scroll-bar'; // to set `right:0` on an element
// to set `width:100%` on an element
// to remove scrollbar from an element
``` # Size 500b after compression (excluding tslib). # Scroll-Locky All code is a result of a [react-scroll-locky](https://github.com/theKashey/react-scroll-locky) refactoring. # Article There is a medium article about preventing the body scroll - [How to fight the scroll](https://medium.com/@antonkorzunov/how-to-fight-the-body-scroll-2b00267b37ac) # License MIT theKashey-react-remove-scroll-bar-7fe7bbe/__tests__/000077500000000000000000000000001472742657100226245ustar00rootroot00000000000000theKashey-react-remove-scroll-bar-7fe7bbe/__tests__/index.tsx000066400000000000000000000034371472742657100245020ustar00rootroot00000000000000import { render } from '@testing-library/react'; import React, { useState } from 'react'; import { RemoveScrollBar } from '../src'; import { lockAttribute } from '../src/component'; const renderTest = (actionName = 'toggle') => { const Test = () => { const [lock, setLock] = useState(false); return ( <> {lock ? : null} ); }; return render(); }; describe('RemoveScrollBar', () => { it('should toggle the lock attribute on mount/unmount', async () => { const { getByRole } = renderTest(); const button = getByRole('button'); expect(document.body.getAttribute(lockAttribute)).toBeNull(); expect(window.getComputedStyle(document.body).overflow).toBe(''); button.click(); expect(document.body.getAttribute(lockAttribute)).toBeDefined(); await new Promise((resolve) => setTimeout(resolve, 1)); expect(window.getComputedStyle(document.body).overflow).toBe('hidden'); button.click(); expect(document.body.getAttribute(lockAttribute)).toBeNull(); expect(window.getComputedStyle(document.body).overflow).toBe(''); }); it('should handle nested cases', () => { const t1 = renderTest('toggle1'); const t2 = renderTest('toggle2'); const button1 = t1.getByRole('button', { name: 'toggle1' }); const button2 = t2.getByRole('button', { name: 'toggle2' }); expect(document.body.getAttribute(lockAttribute)).toBeNull(); button1.click(); button2.click(); expect(document.body.getAttribute(lockAttribute)).toBeDefined(); button1.click(); expect(document.body.getAttribute(lockAttribute)).toBeDefined(); button2.click(); expect(document.body.getAttribute(lockAttribute)).toBeNull(); }); }); theKashey-react-remove-scroll-bar-7fe7bbe/constants/000077500000000000000000000000001472742657100227025ustar00rootroot00000000000000theKashey-react-remove-scroll-bar-7fe7bbe/constants/package.json000066400000000000000000000003521472742657100251700ustar00rootroot00000000000000{ "description": "separate entrypoint for constants only", "private": true, "main": "../dist/es5/constants.js", "jsnext:main": "../dist/es2015/constants.js", "module": "../dist/es2015/constants.js", "sideEffects": false } theKashey-react-remove-scroll-bar-7fe7bbe/example/000077500000000000000000000000001472742657100223215ustar00rootroot00000000000000theKashey-react-remove-scroll-bar-7fe7bbe/example/app.tsx000066400000000000000000000060561472742657100236500ustar00rootroot00000000000000import * as React from 'react'; import {Component} from 'react'; import {RemoveScrollBar, fullWidthClassName} from "../src"; export interface AppState { counter: number; } const fill = (x: number, y: number) => { const a: number[] = []; for (let i = 0; i < x; ++i) { a.push(y) } return a; } export default class App extends Component <{}, AppState> { state: AppState = { counter: 0 }; componentDidMount() { setInterval(() => { // this.setState({counter: this.state.counter ? 0 : 1}) }, 1000); setTimeout(() => { this.setState({counter: this.state.counter ? 0 : 1}) }, 1000); } render() { const gapMode = 'margin'; return (
{this.state.counter ? : undefined} {/*
floating*/} {/*
*/}
XXX XXX XXX {fill(1000, 1).map(x =>

{x}****

)}
XXX XXX XXX {fill(1000, 1).map(x =>

{x}****

)}
XXX XXX XXX {fill(1000, 1).map(x =>

{x}****

)}
XXX XXX XXX
ZZZ ZZZ {fill(1000, 1).map(x =>

{x}****

)}
{fill(1000, 1).map(x =>

{x}****

)}
{fill(1000, 1).map((x, index) => {index}**** )}
) } }theKashey-react-remove-scroll-bar-7fe7bbe/example/assets/000077500000000000000000000000001472742657100236235ustar00rootroot00000000000000theKashey-react-remove-scroll-bar-7fe7bbe/example/assets/.gitkeep000066400000000000000000000000001472742657100252420ustar00rootroot00000000000000theKashey-react-remove-scroll-bar-7fe7bbe/example/index.html000066400000000000000000000003741472742657100243220ustar00rootroot00000000000000 Example
theKashey-react-remove-scroll-bar-7fe7bbe/example/index.tsx000066400000000000000000000002331472742657100241660ustar00rootroot00000000000000import * as React from 'react'; import * as ReactDOM from 'react-dom'; import App from './app'; ReactDOM.render(, document.getElementById('app')); theKashey-react-remove-scroll-bar-7fe7bbe/example/utils.ts000066400000000000000000000006401472742657100240310ustar00rootroot00000000000000import {Component} from 'react'; export class ToolboxApp extends Component { onCheckboxChange = (propName: any) => () => { const currentValue = (this.state as any)[propName]; this.setState({ [propName]: !currentValue } as any); } onFieldTextChange = (propName: any) => (e: any) => { const value = e.target.value; (this as any).setState({ [propName]: value }); } }theKashey-react-remove-scroll-bar-7fe7bbe/jest.config.js000066400000000000000000000000531472742657100234330ustar00rootroot00000000000000module.exports = { preset: 'ts-jest', }; theKashey-react-remove-scroll-bar-7fe7bbe/package.json000066400000000000000000000042551472742657100231620ustar00rootroot00000000000000{ "name": "react-remove-scroll-bar", "version": "2.3.7", "description": "Removes body scroll without content _shake_", "main": "dist/es5/index.js", "jsnext:main": "dist/es2015/index.js", "module": "dist/es2015/index.js", "types": "dist/es5/index.d.ts", "scripts": { "dev": "lib-builder dev", "test": "jest", "test:ci": "jest --runInBand --coverage", "build": "lib-builder build && yarn size:report", "release": "yarn build && yarn test", "size": "yarn size-limit", "size:report": "yarn --silent size-limit --json > .size.json", "lint": "lib-builder lint", "format": "lib-builder format", "update": "lib-builder update", "prepublish": "yarn build && yarn changelog", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", "changelog:rewrite": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0", "storybook": "start-storybook -p 6006" }, "keywords": [ "scroll" ], "author": "Anton Korzunov ", "license": "MIT", "devDependencies": { "@size-limit/preset-small-lib": "^11.0.2", "size-limit": "^11.0.2", "@storybook/react": "^6.4.22", "@testing-library/react": "^12.1.5", "@types/react": "^16.14.56", "@theuiteam/lib-builder": "^0.1.4", "react": "^16.8.6", "react-dom": "^16.8.6" }, "engines": { "node": ">=10" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true } }, "files": [ "dist", "constants" ], "repository": "https://github.com/theKashey/react-remove-scroll-bar", "dependencies": { "react-style-singleton": "^2.2.1", "tslib": "^2.0.0" }, "module:es2019": "dist/es2019/index.js", "husky": { "hooks": { "pre-commit": "lint-staged" } }, "lint-staged": { "*.{ts,tsx}": [ "prettier --write", "eslint --fix", "git add" ], "*.{js,css,json,md}": [ "prettier --write", "git add" ] }, "prettier": { "printWidth": 120, "trailingComma": "es5", "tabWidth": 2, "semi": true, "singleQuote": true } } theKashey-react-remove-scroll-bar-7fe7bbe/src/000077500000000000000000000000001472742657100214555ustar00rootroot00000000000000theKashey-react-remove-scroll-bar-7fe7bbe/src/component.tsx000066400000000000000000000055501472742657100242240ustar00rootroot00000000000000import * as React from 'react'; import { styleSingleton } from 'react-style-singleton'; import { fullWidthClassName, zeroRightClassName, noScrollbarsClassName, removedBarSizeVariable } from './constants'; import { GapMode, GapOffset, getGapWidth } from './utils'; export interface BodyScroll { noRelative?: boolean; noImportant?: boolean; gapMode?: GapMode; } const Style = styleSingleton(); export const lockAttribute = 'data-scroll-locked'; // important tip - once we measure scrollBar width and remove them // we could not repeat this operation // thus we are using style-singleton - only the first "yet correct" style will be applied. const getStyles = ( { left, top, right, gap }: GapOffset, allowRelative: boolean, gapMode: GapMode = 'margin', important: string ) => ` .${noScrollbarsClassName} { overflow: hidden ${important}; padding-right: ${gap}px ${important}; } body[${lockAttribute}] { overflow: hidden ${important}; overscroll-behavior: contain; ${[ allowRelative && `position: relative ${important};`, gapMode === 'margin' && ` padding-left: ${left}px; padding-top: ${top}px; padding-right: ${right}px; margin-left:0; margin-top:0; margin-right: ${gap}px ${important}; `, gapMode === 'padding' && `padding-right: ${gap}px ${important};`, ] .filter(Boolean) .join('')} } .${zeroRightClassName} { right: ${gap}px ${important}; } .${fullWidthClassName} { margin-right: ${gap}px ${important}; } .${zeroRightClassName} .${zeroRightClassName} { right: 0 ${important}; } .${fullWidthClassName} .${fullWidthClassName} { margin-right: 0 ${important}; } body[${lockAttribute}] { ${removedBarSizeVariable}: ${gap}px; } `; const getCurrentUseCounter = () => { const counter = parseInt(document.body.getAttribute(lockAttribute) || '0', 10); return isFinite(counter) ? counter : 0; }; export const useLockAttribute = () => { React.useEffect(() => { document.body.setAttribute(lockAttribute, (getCurrentUseCounter() + 1).toString()); return () => { const newCounter = getCurrentUseCounter() - 1; if (newCounter <= 0) { document.body.removeAttribute(lockAttribute); } else { document.body.setAttribute(lockAttribute, newCounter.toString()); } }; }, []); }; /** * Removes page scrollbar and blocks page scroll when mounted */ export const RemoveScrollBar: React.FC = ({ noRelative, noImportant, gapMode = 'margin' }) => { useLockAttribute(); /* gap will be measured on every component mount however it will be used only by the "first" invocation due to singleton nature of