Skip to content

Commit c88ebb8

Browse files
committed
add bare min eslint style guide
1 parent 6ddfab5 commit c88ebb8

File tree

6 files changed

+72
-35
lines changed

6 files changed

+72
-35
lines changed

.eslintrc.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"env": {
3+
"browser": true,
4+
"es2021": true
5+
},
6+
"extends": [
7+
"eslint:recommended",
8+
"plugin:vue/vue3-essential",
9+
"plugin:@typescript-eslint/recommended"
10+
],
11+
"overrides": [],
12+
"parser": "@typescript-eslint/parser",
13+
"parserOptions": {
14+
"ecmaVersion": "latest",
15+
"sourceType": "module"
16+
},
17+
"plugins": ["vue", "@typescript-eslint"],
18+
"rules": {
19+
"curly": ["error", "all"],
20+
"no-useless-return": "error",
21+
"no-else-return": "error",
22+
"nonblock-statement-body-position": ["error", "below"]
23+
}
24+
}

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@
1717
"devDependencies": {
1818
"@rollup/plugin-terser": "^0.3.0",
1919
"@types/node": "^18.11.18",
20+
"@typescript-eslint/eslint-plugin": "^5.48.2",
21+
"@typescript-eslint/parser": "^5.48.2",
2022
"@vitejs/plugin-vue": "^4.0.0",
2123
"animated-scroll-to": "^2.3.0",
2224
"cypress": "^12.3.0",
25+
"eslint": "^8.32.0",
26+
"eslint-plugin-vue": "^9.9.0",
2327
"prettier": "^2.8.2",
2428
"rimraf": "^4.1.0",
2529
"typescript": "^4.9.4",

src/useActive.ts

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
type Ref,
1212
} from 'vue';
1313
import { useScroll } from './useScroll';
14-
import { getEdges, useMediaRef, isSSR, FIXED_OFFSET } from './utils';
14+
import { getEdges, useMediaRef, isSSR, FIXED_OFFSET, type DeepNonNullable } from './utils';
1515

1616
type UseActiveTitleOptions = {
1717
jumpToFirst?: boolean;
@@ -33,9 +33,6 @@ type UseActiveTitleReturn = {
3333
activeIndex: Ref<number>;
3434
};
3535

36-
// https://github.com/microsoft/TypeScript/issues/28374#issuecomment-538052842
37-
type DeepNonNullable<T> = { [P in keyof T]-?: NonNullable<T[P]> } & NonNullable<T>;
38-
3936
const defaultOpts: DeepNonNullable<UseActiveTitleOptions> = {
4037
jumpToFirst: true,
4138
jumpToLast: true,
@@ -46,6 +43,7 @@ const defaultOpts: DeepNonNullable<UseActiveTitleOptions> = {
4643
toTop: 0,
4744
toBottom: 0,
4845
},
46+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
4947
// @ts-ignore
5048
rootId: null,
5149
};
@@ -76,20 +74,23 @@ export function useActive(
7674
bottom: new Map<string, number>(),
7775
});
7876

79-
const isHTML = computed(() => typeof rootId !== 'string');
77+
const isWindow = computed(() => root.value === document.documentElement);
8078
const ids = computed(() => targets.elements.map(({ id }) => id));
8179

8280
// Returned values
8381
const activeId = useMediaRef(matchMedia, '');
8482
const activeIndex = computed(() => ids.value.indexOf(activeId.value));
8583

8684
function getTop() {
87-
return root.value!.getBoundingClientRect().top - (isHTML.value ? 0 : root.value!.scrollTop);
85+
if (root.value) {
86+
return root.value.getBoundingClientRect().top - (isWindow.value ? 0 : root.value.scrollTop);
87+
}
88+
return 0;
8889
}
8990

9091
// Runs onMount, onResize and whenever the user array changes
9192
function setTargets() {
92-
let _targets = <HTMLElement[]>[];
93+
const _targets = <HTMLElement[]>[];
9394

9495
unref(userIds).forEach((id) => {
9596
const target = document.getElementById(id);
@@ -110,7 +111,7 @@ export function useActive(
110111
}
111112

112113
function jumpToEdges() {
113-
const { isBottom, isTop } = getEdges(root.value!);
114+
const { isBottom, isTop } = getEdges(root.value as HTMLElement);
114115

115116
if (jumpToFirst && isTop) {
116117
return (activeId.value = ids.value[0]), true;
@@ -121,7 +122,7 @@ export function useActive(
121122
}
122123

123124
function _setActive(prevY: number, { isCancel } = { isCancel: false }) {
124-
const nextY = isHTML.value ? window.scrollY : root.value!.scrollTop;
125+
const nextY = isWindow.value ? window.scrollY : (root.value as HTMLElement).scrollTop;
125126

126127
if (nextY === prevY) {
127128
return;
@@ -139,15 +140,15 @@ export function useActive(
139140
}
140141

141142
function getSentinel() {
142-
return isHTML.value ? getTop() : -root.value!.scrollTop;
143+
return isWindow.value ? getTop() : -(root.value as HTMLElement).scrollTop;
143144
}
144145

145146
// Sets first target that LEFT the top
146147
function onScrollDown({ isCancel } = { isCancel: false }) {
147148
let firstOut = jumpToFirst ? ids.value[0] : '';
148149

149150
const sentinel = getSentinel();
150-
const offset = FIXED_OFFSET + overlayHeight + toBottom!;
151+
const offset = FIXED_OFFSET + overlayHeight + toBottom;
151152

152153
Array.from(targets.top).some(([id, top]) => {
153154
if (sentinel + top < offset) {
@@ -172,7 +173,7 @@ export function useActive(
172173
let firstIn = '';
173174

174175
const sentinel = getSentinel();
175-
const offset = FIXED_OFFSET + overlayHeight + toTop!;
176+
const offset = FIXED_OFFSET + overlayHeight + toTop;
176177

177178
Array.from(targets.bottom).some(([id, bottom]) => {
178179
if (sentinel + bottom > offset) {
@@ -197,9 +198,9 @@ export function useActive(
197198
}
198199

199200
onMounted(async () => {
200-
root.value = isHTML.value
201-
? document.documentElement
202-
: document.getElementById(rootId as string);
201+
root.value = rootId
202+
? document.getElementById(rootId) ?? document.documentElement
203+
: document.documentElement;
203204

204205
// https://github.com/nuxt/content/issues/1799
205206
await new Promise((resolve) => setTimeout(resolve));
@@ -225,7 +226,7 @@ export function useActive(
225226
});
226227

227228
const isClick = useScroll({
228-
isHTML,
229+
isWindow,
229230
root,
230231
matchMedia,
231232
_setActive,

src/useScroll.ts

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,44 @@
1-
import { watch, onMounted, ref, Ref, ComputedRef, computed } from 'vue';
1+
import { watch, onMounted, ref, computed, type Ref, type ComputedRef } from 'vue';
22
import { isSSR, useMediaRef } from './utils';
33

44
type UseListenersOptions = {
5-
isHTML: ComputedRef<boolean>;
5+
isWindow: ComputedRef<boolean>;
66
root: Ref<HTMLElement | null>;
77
matchMedia: Ref<boolean>;
88
_setActive: (prevY: number, isCancel?: { isCancel: boolean }) => void;
99
};
1010

1111
const ONCE = { once: true };
1212

13-
export function useScroll({ isHTML, root, _setActive, matchMedia }: UseListenersOptions) {
13+
export function useScroll({ isWindow, root, _setActive, matchMedia }: UseListenersOptions) {
1414
const isClick = useMediaRef(matchMedia, false);
1515
const isReady = ref(false);
1616
const clickY = computed(() => (isClick.value ? getNextY() : 0));
1717

1818
let prevY: number;
1919

2020
function getNextY() {
21-
return isHTML.value ? window.scrollY : root.value!.scrollTop;
21+
return isWindow.value ? window.scrollY : root.value?.scrollTop || 0;
2222
}
2323

2424
function setReady(maxFrames: number) {
25+
let rafId: DOMHighResTimeStamp | undefined = undefined;
2526
let rafPrevY: number;
26-
let rafId: DOMHighResTimeStamp;
2727
let frameCount = 0;
2828

2929
function scrollEnd() {
3030
const rafNextY = getNextY();
3131
if (typeof rafPrevY === 'undefined' || rafPrevY !== rafNextY) {
3232
frameCount = 0;
3333
rafPrevY = rafNextY;
34-
// console.log('Scrolling...');
3534
return requestAnimationFrame(scrollEnd);
3635
}
3736
// When equal, wait for n frames after scroll to make sure is idle
3837
frameCount++;
3938
if (frameCount === maxFrames) {
4039
isReady.value = true;
4140
isClick.value = false;
42-
console.log('Scroll end.');
43-
cancelAnimationFrame(rafId);
41+
cancelAnimationFrame(rafId as DOMHighResTimeStamp);
4442
} else {
4543
requestAnimationFrame(scrollEnd);
4644
}
@@ -78,7 +76,7 @@ export function useScroll({ isHTML, root, _setActive, matchMedia }: UseListeners
7876
if (!isLink && !hasLink) {
7977
reScroll();
8078
// ...and force set if canceling scroll
81-
_setActive(clickY.value!, { isCancel: true });
79+
_setActive(clickY.value, { isCancel: true });
8280
}
8381
}
8482

@@ -93,24 +91,22 @@ export function useScroll({ isHTML, root, _setActive, matchMedia }: UseListeners
9391

9492
watch(
9593
[isReady, matchMedia, root],
96-
([_isReady, _matchMedia, _root], [], onCleanup) => {
94+
([_isReady, _matchMedia, _root], _, onCleanup) => {
9795
if (isSSR) {
9896
return;
9997
}
10098

101-
const rootEl = isHTML.value ? document : _root;
99+
const rootEl = isWindow.value ? document : _root;
102100
const isActive = rootEl && _isReady && _matchMedia;
103101

104102
if (isActive) {
105-
console.log('Adding main listener...');
106103
rootEl.addEventListener('scroll', onScroll, {
107104
passive: true,
108105
});
109106
}
110107

111108
onCleanup(() => {
112109
if (isActive) {
113-
console.log('Removing main listener...');
114110
rootEl.removeEventListener('scroll', onScroll);
115111
}
116112
});
@@ -125,10 +121,9 @@ export function useScroll({ isHTML, root, _setActive, matchMedia }: UseListeners
125121
watch(
126122
isClick,
127123
(_isClick, _, onCleanup) => {
128-
const rootEl = isHTML.value ? document : root.value!;
124+
const rootEl = isWindow.value ? document : root.value;
129125

130-
if (_isClick) {
131-
console.log('Adding additional listeners...');
126+
if (_isClick && rootEl) {
132127
rootEl.addEventListener('scroll', resetReady, ONCE);
133128
rootEl.addEventListener('wheel', reScroll, ONCE);
134129
rootEl.addEventListener('keydown', onSpaceBar as EventListener, ONCE);
@@ -137,8 +132,7 @@ export function useScroll({ isHTML, root, _setActive, matchMedia }: UseListeners
137132
}
138133

139134
onCleanup(() => {
140-
if (_isClick) {
141-
console.log('Removing additional listeners...');
135+
if (_isClick && rootEl) {
142136
rootEl.removeEventListener('scroll', resetReady);
143137
rootEl.removeEventListener('wheel', reScroll);
144138
rootEl.removeEventListener('keydown', onSpaceBar as EventListener);

src/utils.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,18 @@ export function getEdges(root: HTMLElement) {
3838
isBottom: isBottomReached || isOverscrollBottom,
3939
};
4040
}
41+
42+
// https://github.com/esamattis/utils/blob/master/src/DeepRequired.ts
43+
type NotNull<T> = T extends null | undefined ? never : T;
44+
type Primitive = undefined | null | boolean | string | number;
45+
46+
export type DeepNonNullable<T> = T extends Primitive
47+
? NotNull<T>
48+
: {
49+
[P in keyof T]-?: T[P] extends Array<infer U>
50+
? Array<DeepNonNullable<U>>
51+
: T[P] extends ReadonlyArray<infer U2>
52+
? DeepNonNullable<U2>
53+
: DeepNonNullable<T[P]>;
54+
// eslint-disable-next-line no-mixed-spaces-and-tabs
55+
};

tests/App.cy.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// @ts-ignore
21
import App from './App.vue';
32
import { getIntRange, getRandomSequence } from '../cypress/support/component';
43

0 commit comments

Comments
 (0)