@perch33/react-usefilter-hook 1.0.2 → 1.0.4

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
@@ -7,6 +7,7 @@ Ideal for search bars, dynamic lists, admin dashboards, e-commerce filters, etc.
7
7
  ![downloads](https://img.shields.io/npm/dm/@perch33/react-usefilter-hook)
8
8
  ![license](https://img.shields.io/npm/l/@perch33/react-usefilter-hook)
9
9
  ![types](https://img.shields.io/badge/types-TypeScript-blue)
10
+ ![Next.js](https://img.shields.io/badge/Next.js-App%20Router%20Ready-black)
10
11
 
11
12
  ---
12
13
 
@@ -16,6 +17,7 @@ Ideal for search bars, dynamic lists, admin dashboards, e-commerce filters, etc.
16
17
  - ✂️ Removes punctuation and special characters
17
18
  - 🔎 Case-insensitive search
18
19
  - ⚛️ Fully typed with TypeScript
20
+ - 🚀 **Next.js App Router Compatible** (`"use client"` included)
19
21
  - 🔁 Auto-updates when `data` changes
20
22
  - 🔧 Accepts custom error component
21
23
  - 🧩 Framework-agnostic, works in any React project
@@ -32,7 +34,6 @@ or
32
34
 
33
35
  ```sh
34
36
  yarn add @perch33/react-usefilter-hook
35
-
36
37
  ```
37
38
 
38
39
  ## 🚀 Usage Example (Basic)
@@ -121,31 +122,37 @@ useFilter<T>(data, key, errorComponent);
121
122
  ### ⚙️ How filtering works
122
123
 
123
124
  - This hook automatically:
124
-
125
125
  - Converts text to lowercase
126
-
127
126
  - Removes accents (áéíóú → aeiou)
128
-
129
127
  - Removes punctuation and special characters
130
-
131
128
  - Performs a normalized comparison
132
-
133
129
  - Filters in real time as the user types
134
130
 
131
+ ---
132
+
133
+ ## 🔍 Used in Production (Real Examples)
134
+
135
+ This hook is currently used in my personal website:
136
+
137
+ - 🎼 **Music Scores / Partituras**
138
+ Live search using `useFilter` to filter music scores dynamically.
139
+ 👉 https://www.percychuzon.com/partituras
140
+
141
+ - ✍️ **Blog**
142
+ Used to filter blog posts instantly with accent-insensitive matching.
143
+ 👉 https://www.percychuzon.com/blog
144
+
145
+ These sections demonstrate real-world usage of the hook with dynamic content,
146
+ search inputs, and accent-normalized filtering.
147
+
135
148
  ### 💡 When to use this hook?
136
149
 
137
150
  - Product search inputs
138
-
139
151
  - Admin panel filters
140
-
141
152
  - Searchable dropdowns
142
-
143
153
  - User lists
144
-
145
154
  - Blog post search
146
-
147
155
  - Table filtering
148
-
149
156
  - Autocomplete components
150
157
 
151
158
  ## 📁 Project Structure
@@ -153,7 +160,6 @@ useFilter<T>(data, key, errorComponent);
153
160
  Your installation will contain:
154
161
 
155
162
  ```
156
-
157
163
  dist/
158
164
  ├─ cjs/
159
165
  ├─ esm/
@@ -166,4 +172,4 @@ README.md
166
172
 
167
173
  **Percy Chuzon**
168
174
  📧 [contacto@percychuzon.com](mailto:contacto@percychuzon.com)
169
- 🌐 [https://wwww.percychuzon.com](https://www.percychuzon.com)
175
+ 🌐 [https://www.percychuzon.com](https://www.percychuzon.com)
package/dist/cjs/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ "use client";
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.useFilter = void 0;
4
5
  const react_1 = require("react");
@@ -20,27 +21,26 @@ function normalizarTexto(texto) {
20
21
  }
21
22
  const useFilter = (data, key, errorComponent) => {
22
23
  const [filterText, setFilterText] = (0, react_1.useState)("");
23
- const [filteredData, setFilteredData] = (0, react_1.useState)(data);
24
- const [error, setError] = (0, react_1.useState)(null);
25
24
  /** Maneja el texto que escribe el usuario en el input */
26
25
  const handleFilterChange = (e) => {
27
- const searchText = normalizarTexto(e.target.value);
28
- setFilterText(searchText);
26
+ setFilterText(e.target.value);
29
27
  };
30
- /** Filtra la lista cada vez que cambia el texto o los datos */
31
- (0, react_1.useEffect)(() => {
32
- const filteredItems = data.filter((item) => {
28
+ /** Filtra la lista de forma eficiente usando useMemo */
29
+ const { filteredData, error } = (0, react_1.useMemo)(() => {
30
+ // Si no hay texto, devolvemos todo sin error
31
+ if (!filterText) {
32
+ return { filteredData: data, error: null };
33
+ }
34
+ const searchText = normalizarTexto(filterText);
35
+ const filtered = data.filter((item) => {
33
36
  const valorCampo = String(item[key]);
34
- return normalizarTexto(valorCampo).includes(filterText);
37
+ return normalizarTexto(valorCampo).includes(searchText);
35
38
  });
36
- setFilteredData(filteredItems);
37
- if (filteredItems.length === 0 && filterText !== "") {
38
- setError(errorComponent);
39
- }
40
- else {
41
- setError(null);
42
- }
43
- }, [data, filterText, key]);
39
+ return {
40
+ filteredData: filtered,
41
+ error: filtered.length === 0 ? errorComponent : null
42
+ };
43
+ }, [data, filterText, key, errorComponent]);
44
44
  return {
45
45
  filterText,
46
46
  filteredData,
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.useFilter=void 0;const react_1=require("react");function normalizarTexto(e){return e.normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[.,/#!$%^&*;:{}=\-_`~()¿?¡!]/g,"").toLowerCase().trim()}const useFilter=(e,t,r)=>{const[a,l]=(0,react_1.useState)(""),[o,n]=(0,react_1.useState)(e),[s,u]=(0,react_1.useState)(null);return(0,react_1.useEffect)(()=>{const l=e.filter(e=>normalizarTexto(String(e[t])).includes(a));n(l),0===l.length&&""!==a?u(r):u(null)},[e,a,t]),{filterText:a,filteredData:o,error:s,handleFilterChange:e=>{const t=normalizarTexto(e.target.value);l(t)}}};exports.useFilter=useFilter;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.useFilter=void 0;const react_1=require("react");function normalizarTexto(e){return e.normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[.,/#!$%^&*;:{}=\-_`~()¿?¡!]/g,"").toLowerCase().trim()}const useFilter=(e,r,t)=>{const[a,l]=(0,react_1.useState)(""),{filteredData:o,error:i}=(0,react_1.useMemo)(()=>{if(!a)return{filteredData:e,error:null};const l=normalizarTexto(a),o=e.filter(e=>normalizarTexto(String(e[r])).includes(l));return{filteredData:o,error:0===o.length?t:null}},[e,a,r,t]);return{filterText:a,filteredData:o,error:i,handleFilterChange:e=>{l(e.target.value)}}};exports.useFilter=useFilter;
package/dist/esm/index.js CHANGED
@@ -1,4 +1,5 @@
1
- import { useState, useEffect } from "react";
1
+ "use client";
2
+ import { useState, useMemo } from "react";
2
3
  /**
3
4
  * 🔠 Normaliza texto para facilitar búsquedas:
4
5
  * - Convierte a minúsculas
@@ -17,27 +18,26 @@ function normalizarTexto(texto) {
17
18
  }
18
19
  export const useFilter = (data, key, errorComponent) => {
19
20
  const [filterText, setFilterText] = useState("");
20
- const [filteredData, setFilteredData] = useState(data);
21
- const [error, setError] = useState(null);
22
21
  /** Maneja el texto que escribe el usuario en el input */
23
22
  const handleFilterChange = (e) => {
24
- const searchText = normalizarTexto(e.target.value);
25
- setFilterText(searchText);
23
+ setFilterText(e.target.value);
26
24
  };
27
- /** Filtra la lista cada vez que cambia el texto o los datos */
28
- useEffect(() => {
29
- const filteredItems = data.filter((item) => {
25
+ /** Filtra la lista de forma eficiente usando useMemo */
26
+ const { filteredData, error } = useMemo(() => {
27
+ // Si no hay texto, devolvemos todo sin error
28
+ if (!filterText) {
29
+ return { filteredData: data, error: null };
30
+ }
31
+ const searchText = normalizarTexto(filterText);
32
+ const filtered = data.filter((item) => {
30
33
  const valorCampo = String(item[key]);
31
- return normalizarTexto(valorCampo).includes(filterText);
34
+ return normalizarTexto(valorCampo).includes(searchText);
32
35
  });
33
- setFilteredData(filteredItems);
34
- if (filteredItems.length === 0 && filterText !== "") {
35
- setError(errorComponent);
36
- }
37
- else {
38
- setError(null);
39
- }
40
- }, [data, filterText, key]);
36
+ return {
37
+ filteredData: filtered,
38
+ error: filtered.length === 0 ? errorComponent : null
39
+ };
40
+ }, [data, filterText, key, errorComponent]);
41
41
  return {
42
42
  filterText,
43
43
  filteredData,
@@ -1 +1 @@
1
- import{useState,useEffect}from"react";function normalizarTexto(e){return e.normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[.,/#!$%^&*;:{}=\-_`~()¿?¡!]/g,"").toLowerCase().trim()}export const useFilter=(e,t,r)=>{const[a,l]=useState(""),[n,o]=useState(e),[u,i]=useState(null);return useEffect(()=>{const l=e.filter(e=>normalizarTexto(String(e[t])).includes(a));o(l),0===l.length&&""!==a?i(r):i(null)},[e,a,t]),{filterText:a,filteredData:n,error:u,handleFilterChange:e=>{const t=normalizarTexto(e.target.value);l(t)}}};
1
+ import{useState,useMemo}from"react";function normalizarTexto(e){return e.normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[.,/#!$%^&*;:{}=\-_`~()¿?¡!]/g,"").toLowerCase().trim()}export const useFilter=(e,r,t)=>{const[a,l]=useState(""),{filteredData:o,error:n}=useMemo(()=>{if(!a)return{filteredData:e,error:null};const l=normalizarTexto(a),o=e.filter(e=>normalizarTexto(String(e[r])).includes(l));return{filteredData:o,error:0===o.length?t:null}},[e,a,r,t]);return{filterText:a,filteredData:o,error:n,handleFilterChange:e=>{l(e.target.value)}}};
@@ -6,7 +6,7 @@ import type { ChangeEvent } from "react";
6
6
  *
7
7
  * ✔ Permite filtrar un array (data) según un campo específico (key)
8
8
  * ✔ Devuelve:
9
- * - filterText → texto escrito por el usuario
9
+ * - filterText → texto escrito por el usuario (raw)
10
10
  * - filteredData → lista filtrada
11
11
  * - error → componente mostrado cuando no hay resultados
12
12
  * - handleFilterChange → manejador para input de búsqueda
package/package.json CHANGED
@@ -1,62 +1,66 @@
1
- {
2
- "name": "@perch33/react-usefilter-hook",
3
- "version": "1.0.2",
4
- "description": "A lightweight and reusable React hook for filtering lists with accent normalization, punctuation removal and TypeScript support.",
5
- "main": "dist/cjs/index.min.js",
6
- "module": "dist/esm/index.min.js",
7
- "types": "dist/types/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "import": "./dist/esm/index.min.js",
11
- "require": "./dist/cjs/index.min.js",
12
- "types": "./dist/types/index.d.ts"
13
- }
14
- },
15
- "files": [
16
- "dist/cjs",
17
- "dist/esm",
18
- "dist/types"
19
- ],
20
- "sideEffects": false,
21
- "scripts": {
22
- "clean": "rimraf dist",
23
- "build": "npm run clean && tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json && terser dist/cjs/index.js -o dist/cjs/index.min.js --compress --mangle && terser dist/esm/index.js -o dist/esm/index.min.js --compress --mangle"
24
- },
25
- "keywords": [
26
- "react",
27
- "hook",
28
- "filter",
29
- "usefilter",
30
- "search",
31
- "list filter",
32
- "normalization",
33
- "typescript",
34
- "frontend",
35
- "react hook",
36
- "filter hook"
37
- ],
38
- "author": "Percy Chuzon <contacto@percychuzon.com>",
39
- "license": "MIT",
40
- "homepage": "https://react-usefilter-hook.percychuzon.com/",
41
- "repository": {
42
- "type": "git",
43
- "url": "https://github.com/perch733/perch733-react-usefilter-hook.git"
44
- },
45
- "bugs": {
46
- "url": "https://github.com/perch733/perch733-react-usefilter-hook/issues"
47
- },
48
- "publishConfig": {
49
- "access": "public"
50
- },
51
- "peerDependencies": {
52
- "react": ">=17.0.0",
53
- "react-dom": ">=17.0.0"
54
- },
55
- "devDependencies": {
56
- "@types/react": "^18.3.21",
57
- "@types/react-dom": "^18.3.7",
58
- "rimraf": "^6.0.1",
59
- "typescript": "^5.8.3",
60
- "terser": "^5.39.2"
61
- }
62
- }
1
+ {
2
+ "name": "@perch33/react-usefilter-hook",
3
+ "version": "1.0.4",
4
+ "description": "A lightweight and reusable React hook for filtering lists with accent normalization, punctuation removal and TypeScript support.",
5
+ "main": "dist/cjs/index.min.js",
6
+ "module": "dist/esm/index.min.js",
7
+ "types": "dist/types/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/esm/index.min.js",
11
+ "require": "./dist/cjs/index.min.js",
12
+ "types": "./dist/types/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist/cjs",
17
+ "dist/esm",
18
+ "dist/types"
19
+ ],
20
+ "sideEffects": false,
21
+ "scripts": {
22
+ "test": "vitest run",
23
+ "clean": "rimraf dist",
24
+ "build": "npm run clean && tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json && terser dist/cjs/index.js -o dist/cjs/index.min.js --compress --mangle && terser dist/esm/index.js -o dist/esm/index.min.js --compress --mangle"
25
+ },
26
+ "keywords": [
27
+ "react",
28
+ "hook",
29
+ "filter",
30
+ "usefilter",
31
+ "search",
32
+ "list filter",
33
+ "normalization",
34
+ "typescript",
35
+ "frontend",
36
+ "react hook",
37
+ "filter hook"
38
+ ],
39
+ "author": "Percy Chuzon <contacto@percychuzon.com>",
40
+ "license": "MIT",
41
+ "homepage": "https://react-usefilter-hook.percychuzon.com/",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "https://github.com/perch733/perch733-react-usefilter-hook.git"
45
+ },
46
+ "bugs": {
47
+ "url": "https://github.com/perch733/perch733-react-usefilter-hook/issues"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "peerDependencies": {
53
+ "react": ">=17.0.0",
54
+ "react-dom": ">=17.0.0"
55
+ },
56
+ "devDependencies": {
57
+ "@testing-library/react": "^16.3.1",
58
+ "@types/react": "^18.3.21",
59
+ "@types/react-dom": "^18.3.7",
60
+ "jsdom": "^27.4.0",
61
+ "rimraf": "^6.0.1",
62
+ "terser": "^5.39.2",
63
+ "typescript": "^5.8.3",
64
+ "vitest": "^4.0.17"
65
+ }
66
+ }