extra-react-hooks 0.8.1 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -209,7 +209,7 @@ function useNumberInput(params: {
209
209
  value: number
210
210
  lazy?: boolean
211
211
 
212
- onChange(value: number): void
212
+ onChange(value: number, isEnd: boolean): void
213
213
  }): {
214
214
  getInputProps(): Required<Pick<
215
215
  React.ComponentPropsWithoutRef<'input'>
@@ -219,3 +219,8 @@ function useNumberInput(params: {
219
219
  >>
220
220
  }
221
221
  ```
222
+
223
+ ### useMediaQuery
224
+ ```ts
225
+ function useMediaQuery(query: string): boolean
226
+ ```
package/lib/index.d.ts CHANGED
@@ -23,3 +23,4 @@ export * from './use-get-set.js';
23
23
  export * from './use-isomorphic-layout-effect.js';
24
24
  export * from './use-debounce.js';
25
25
  export * from './use-number-input.js';
26
+ export * from './use-media-query.js';
package/lib/index.js CHANGED
@@ -23,4 +23,5 @@ export * from './use-get-set.js';
23
23
  export * from './use-isomorphic-layout-effect.js';
24
24
  export * from './use-debounce.js';
25
25
  export * from './use-number-input.js';
26
+ export * from './use-media-query.js';
26
27
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,sBAAsB,CAAA;AACpC,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,2BAA2B,CAAA;AACzC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,sBAAsB,CAAA;AACpC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,0BAA0B,CAAA;AACxC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,eAAe,CAAA;AAC7B,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,eAAe,CAAA;AAC7B,cAAc,4BAA4B,CAAA;AAC1C,cAAc,kBAAkB,CAAA;AAChC,cAAc,mCAAmC,CAAA;AACjD,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,sBAAsB,CAAA;AACpC,cAAc,kBAAkB,CAAA;AAChC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,2BAA2B,CAAA;AACzC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,sBAAsB,CAAA;AACpC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,0BAA0B,CAAA;AACxC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,eAAe,CAAA;AAC7B,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,eAAe,CAAA;AAC7B,cAAc,4BAA4B,CAAA;AAC1C,cAAc,kBAAkB,CAAA;AAChC,cAAc,mCAAmC,CAAA;AACjD,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA"}
@@ -0,0 +1 @@
1
+ export declare function useMediaQuery(query: string): boolean;
@@ -0,0 +1,15 @@
1
+ import { useState, useMemo, useEffect } from 'react';
2
+ export function useMediaQuery(query) {
3
+ const mediaQuery = useMemo(() => matchMedia(query), [query]);
4
+ const [matches, setMatches] = useState(mediaQuery.matches);
5
+ useEffect(() => {
6
+ updateMatches();
7
+ mediaQuery.addEventListener('change', updateMatches);
8
+ return () => mediaQuery.removeEventListener('change', updateMatches);
9
+ function updateMatches() {
10
+ setMatches(mediaQuery.matches);
11
+ }
12
+ }, [mediaQuery]);
13
+ return matches;
14
+ }
15
+ //# sourceMappingURL=use-media-query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-media-query.js","sourceRoot":"","sources":["../src/use-media-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpD,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAC5D,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAU,UAAU,CAAC,OAAO,CAAC,CAAA;IAEnE,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,EAAE,CAAA;QAEf,UAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAA;QACpD,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAA;QAEpE,SAAS,aAAa;YACpB,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAChC,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;IAEhB,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -1,7 +1,7 @@
1
1
  export declare function useNumberInput({ value, lazy, onChange }: {
2
2
  value: number;
3
3
  lazy?: boolean;
4
- onChange(value: number): void;
4
+ onChange(value: number, isEnd: boolean): void;
5
5
  }): {
6
6
  getInputProps(): Required<Pick<React.ComponentPropsWithoutRef<'input'>, 'value' | 'onChange' | 'onBlur'>>;
7
7
  };
@@ -24,20 +24,25 @@ export function useNumberInput({ value, lazy, onChange }) {
24
24
  if (!lazy) {
25
25
  const newValue = e.target.valueAsNumber;
26
26
  if (isntNaN(newValue) && newValue !== value) {
27
- onChange(newValue);
27
+ onChange(newValue, false);
28
28
  }
29
29
  }
30
30
  }
31
31
  },
32
32
  onBlur(e) {
33
33
  if (e.target.checkValidity()) {
34
- if (lazy) {
35
- const newValue = e.target.valueAsNumber;
36
- if (isntNaN(newValue) && newValue !== value) {
37
- onChange(newValue);
38
- setDisplayValue(newValue.toString());
39
- return;
40
- }
34
+ const newValue = e.target.valueAsNumber;
35
+ if (!lazy || (isntNaN(newValue) && newValue !== value)) {
36
+ onChange(newValue, true);
37
+ setDisplayValue(newValue.toString());
38
+ return;
39
+ }
40
+ }
41
+ else {
42
+ if (!lazy) {
43
+ onChange(value, true);
44
+ setDisplayValue(value.toString());
45
+ return;
41
46
  }
42
47
  }
43
48
  setDisplayValue(value.toString());
@@ -1 +1 @@
1
- {"version":3,"file":"use-number-input.js","sourceRoot":"","sources":["../src/use-number-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAErC,MAAM,UAAU,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAKrD;IAQC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAS,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;IAEhF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,CAAA;YAGrC,IAAI,QAAQ,KAAK,KAAK;gBAAE,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC3D,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAA;IAEzB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI,EAAE,CAAC;YAGT,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;QACnC,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,OAAO;QACL,aAAa;YACX,OAAO;gBACL,KAAK,EAAE,YAAY;gBACnB,QAAQ,CAAC,CAAC;oBACR,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBAE/B,IAAI,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC;wBAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;4BACV,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAA;4BAEvC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;gCAC5C,QAAQ,CAAC,QAAQ,CAAC,CAAA;4BACpB,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,MAAM,CAAC,CAAC;oBACN,IAAI,CAAC,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,CAAC;wBAC7B,IAAI,IAAI,EAAE,CAAC;4BACT,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAA;4BAEvC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;gCAC5C,QAAQ,CAAC,QAAQ,CAAC,CAAA;gCAIlB,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAA;gCAEpC,OAAM;4BACR,CAAC;wBACH,CAAC;oBACH,CAAC;oBAGD,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;gBACnC,CAAC;aACF,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"use-number-input.js","sourceRoot":"","sources":["../src/use-number-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAErC,MAAM,UAAU,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAKrD;IAQC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAS,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;IAEhF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,CAAA;YAGrC,IAAI,QAAQ,KAAK,KAAK;gBAAE,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC3D,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAA;IAEzB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI,EAAE,CAAC;YAGT,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;QACnC,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,OAAO;QACL,aAAa;YACX,OAAO;gBACL,KAAK,EAAE,YAAY;gBACnB,QAAQ,CAAC,CAAC;oBACR,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBAE/B,IAAI,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC;wBAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;4BACV,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAA;4BAEvC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;gCAC5C,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;4BAC3B,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,MAAM,CAAC,CAAC;oBACN,IAAI,CAAC,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,CAAC;wBAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,aAAa,CAAA;wBAEvC,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,CAAC,EAAE,CAAC;4BACvD,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;4BAIxB,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAA;4BAEpC,OAAM;wBACR,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,IAAI,CAAC,IAAI,EAAE,CAAC;4BACV,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;4BAErB,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;4BAEjC,OAAM;wBACR,CAAC;oBACH,CAAC;oBAGD,eAAe,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;gBACnC,CAAC;aACF,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "extra-react-hooks",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "files": [
@@ -20,8 +20,7 @@
20
20
  "scripts": {
21
21
  "prepare": "ts-patch install -s",
22
22
  "lint": "eslint --quiet src __tests__",
23
- "test": "karma start karma.config.cjs --single-run",
24
- "test:dev": "karma start karma.config.cjs",
23
+ "test": "vitest --run",
25
24
  "prepublishOnly": "run-s prepare clean build",
26
25
  "clean": "rimraf lib",
27
26
  "build": "tsc --project tsconfig.build.json --outDir lib",
@@ -41,31 +40,29 @@
41
40
  "@testing-library/dom": "^10.4.0",
42
41
  "@testing-library/react": "^16.1.0",
43
42
  "@testing-library/user-event": "^14.6.1",
44
- "@types/jasmine": "^5.1.5",
45
43
  "@types/react": "^19.0.7",
44
+ "@vitejs/plugin-react": "^4.3.4",
45
+ "@vitest/browser": "^3.0.9",
46
46
  "eslint": "^9.18.0",
47
47
  "eslint-plugin-react": "^7.37.4",
48
48
  "eslint-plugin-react-hooks": "^5.1.0",
49
49
  "husky": "4",
50
- "karma": "^6.4.4",
51
- "karma-chrome-launcher": "^3.2.0",
52
- "karma-jasmine": "^5.1.0",
53
- "karma-webpack": "^5.0.1",
54
50
  "npm-run-all": "^4.1.5",
51
+ "playwright": "^1.51.1",
55
52
  "react": "^19.0.0",
56
53
  "react-dom": "^19.0.0",
57
54
  "react-test-renderer": "^19.0.0",
58
55
  "return-style": "^3.0.1",
59
56
  "rimraf": "^4.3.0",
60
57
  "standard-version": "^9.3.2",
61
- "ts-loader": "^9.5.2",
62
58
  "ts-patch": "^3.3.0",
63
- "tsconfig-paths-webpack-plugin": "^4.2.0",
64
59
  "tslib": "^2.8.1",
65
60
  "typescript": "5.7.3",
66
61
  "typescript-eslint": "^8.20.0",
67
62
  "typescript-transform-paths": "^3.5.3",
68
- "webpack": "^5.97.1"
63
+ "vite": "^6.2.3",
64
+ "vite-tsconfig-paths": "^5.1.4",
65
+ "vitest": "^3.0.9"
69
66
  },
70
67
  "dependencies": {
71
68
  "@blackglory/errors": "^3.0.3",
package/src/index.ts CHANGED
@@ -23,3 +23,4 @@ export * from './use-get-set.js'
23
23
  export * from './use-isomorphic-layout-effect.js'
24
24
  export * from './use-debounce.js'
25
25
  export * from './use-number-input.js'
26
+ export * from './use-media-query.js'
@@ -0,0 +1,19 @@
1
+ import { useState, useMemo, useEffect } from 'react'
2
+
3
+ export function useMediaQuery(query: string): boolean {
4
+ const mediaQuery = useMemo(() => matchMedia(query), [query])
5
+ const [matches, setMatches] = useState<boolean>(mediaQuery.matches)
6
+
7
+ useEffect(() => {
8
+ updateMatches()
9
+
10
+ mediaQuery.addEventListener('change', updateMatches)
11
+ return () => mediaQuery.removeEventListener('change', updateMatches)
12
+
13
+ function updateMatches(): void {
14
+ setMatches(mediaQuery.matches)
15
+ }
16
+ }, [mediaQuery])
17
+
18
+ return matches
19
+ }
@@ -5,7 +5,7 @@ export function useNumberInput({ value, lazy, onChange }: {
5
5
  value: number
6
6
  lazy?: boolean
7
7
 
8
- onChange(value: number): void
8
+ onChange(value: number, isEnd: boolean): void
9
9
  }): {
10
10
  getInputProps(): Required<Pick<
11
11
  React.ComponentPropsWithoutRef<'input'>
@@ -45,25 +45,31 @@ export function useNumberInput({ value, lazy, onChange }: {
45
45
  const newValue = e.target.valueAsNumber
46
46
 
47
47
  if (isntNaN(newValue) && newValue !== value) {
48
- onChange(newValue)
48
+ onChange(newValue, false)
49
49
  }
50
50
  }
51
51
  }
52
52
  }
53
53
  , onBlur(e) {
54
54
  if (e.target.checkValidity()) {
55
- if (lazy) {
56
- const newValue = e.target.valueAsNumber
55
+ const newValue = e.target.valueAsNumber
57
56
 
58
- if (isntNaN(newValue) && newValue !== value) {
59
- onChange(newValue)
57
+ if (!lazy || (isntNaN(newValue) && newValue !== value)) {
58
+ onChange(newValue, true)
60
59
 
61
- // 使用格式化后的新值.
62
- // 若hook的调用方决定不接受新值, 则displayValue的值会被覆盖.
63
- setDisplayValue(newValue.toString())
60
+ // 使用格式化后的新值.
61
+ // 若hook的调用方决定不接受新值, 则displayValue的值会被覆盖.
62
+ setDisplayValue(newValue.toString())
64
63
 
65
- return
66
- }
64
+ return
65
+ }
66
+ } else {
67
+ if (!lazy) {
68
+ onChange(value, true)
69
+
70
+ setDisplayValue(value.toString())
71
+
72
+ return
67
73
  }
68
74
  }
69
75