Skip to content

Commit c97748a

Browse files
authored
feat: Support target scrollbar size (#243)
* feat: Support target scrollbar size * test: test case
1 parent f51a021 commit c97748a

File tree

3 files changed

+138
-4
lines changed

3 files changed

+138
-4
lines changed

examples/getScrollBarSize.tsx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* eslint-disable react/no-danger */
2+
3+
import React from 'react';
4+
import getScrollBarSize, {
5+
getTargetScrollBarSize,
6+
} from '../src/getScrollBarSize';
7+
8+
export default () => {
9+
const divRef = React.useRef<HTMLDivElement>();
10+
const [sizeData, setSizeData] = React.useState('');
11+
12+
React.useEffect(() => {
13+
const originSize = getScrollBarSize();
14+
const targetSize = getTargetScrollBarSize(divRef.current);
15+
16+
setSizeData(
17+
`Origin: ${originSize}, Target: ${targetSize.width}/${targetSize.height}`,
18+
);
19+
}, []);
20+
21+
return (
22+
<div>
23+
<style
24+
dangerouslySetInnerHTML={{
25+
__html: `
26+
#customizeContainer::-webkit-scrollbar {
27+
width: 2em;
28+
height: 23px;
29+
background: blue;
30+
}
31+
32+
#customizeContainer::-webkit-scrollbar-thumb {
33+
background: red;
34+
height: 30px;
35+
}
36+
`,
37+
}}
38+
/>
39+
<div
40+
style={{ width: 100, height: 100, overflow: 'auto' }}
41+
id="customizeContainer"
42+
ref={divRef}
43+
>
44+
<div style={{ width: '100vw', height: '100vh', background: 'green' }}>
45+
Hello World!
46+
</div>
47+
</div>
48+
49+
<div
50+
style={{
51+
width: 100,
52+
height: 100,
53+
overflow: 'scroll',
54+
background: 'yellow',
55+
}}
56+
/>
57+
58+
<pre>{sizeData}</pre>
59+
</div>
60+
);
61+
};

src/getScrollBarSize.js renamed to src/getScrollBarSize.tsx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
let cached;
1+
/* eslint-disable no-param-reassign */
22

3-
export default function getScrollBarSize(fresh) {
3+
let cached: number;
4+
5+
export default function getScrollBarSize(fresh?: boolean) {
46
if (typeof document === 'undefined') {
57
return 0;
68
}
@@ -14,8 +16,8 @@ export default function getScrollBarSize(fresh) {
1416
const outerStyle = outer.style;
1517

1618
outerStyle.position = 'absolute';
17-
outerStyle.top = 0;
18-
outerStyle.left = 0;
19+
outerStyle.top = '0';
20+
outerStyle.left = '0';
1921
outerStyle.pointerEvents = 'none';
2022
outerStyle.visibility = 'hidden';
2123
outerStyle.width = '200px';
@@ -40,3 +42,21 @@ export default function getScrollBarSize(fresh) {
4042
}
4143
return cached;
4244
}
45+
46+
function ensureSize(str: string) {
47+
const match = str.match(/^(.*)px$/);
48+
const value = Number(match?.[1]);
49+
return Number.isNaN(value) ? getScrollBarSize() : value;
50+
}
51+
52+
export function getTargetScrollBarSize(target: HTMLElement) {
53+
if (typeof document === 'undefined' || !target) {
54+
return { width: 0, height: 0 };
55+
}
56+
57+
const { width, height } = getComputedStyle(target, '::-webkit-scrollbar');
58+
return {
59+
width: ensureSize(width),
60+
height: ensureSize(height),
61+
};
62+
}

tests/getScrollBarSize.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { spyElementPrototypes } from '../src/test/domHook';
2+
import getScrollBarSize, {
3+
getTargetScrollBarSize,
4+
} from '../src/getScrollBarSize';
5+
6+
const DEFAULT_SIZE = 16;
7+
8+
describe('getScrollBarSize', () => {
9+
let defaultSize = DEFAULT_SIZE;
10+
11+
beforeAll(() => {
12+
let i = 0;
13+
14+
spyElementPrototypes(HTMLElement, {
15+
offsetWidth: {
16+
get: () => {
17+
i += 1;
18+
return i % 2 ? 100 : 100 - defaultSize;
19+
},
20+
},
21+
});
22+
});
23+
24+
beforeEach(() => {
25+
defaultSize = DEFAULT_SIZE;
26+
});
27+
28+
it('basicSize', () => {
29+
expect(getScrollBarSize()).toEqual(16);
30+
});
31+
32+
it('fresh it', () => {
33+
expect(getScrollBarSize(true)).toEqual(16);
34+
35+
defaultSize = 33;
36+
expect(getScrollBarSize(true)).toEqual(33);
37+
});
38+
39+
it('getTargetScrollBarSize', () => {
40+
jest.spyOn(window, 'getComputedStyle').mockImplementation(
41+
() =>
42+
({
43+
width: '23px',
44+
height: '93px',
45+
} as any),
46+
);
47+
48+
expect(getTargetScrollBarSize(document.createElement('div'))).toEqual({
49+
width: 23,
50+
height: 93,
51+
});
52+
});
53+
});

0 commit comments

Comments
 (0)