@perch33/react-usefilter-hook 1.0.0

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/LICENCE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Percy Saul Rondan Chuzon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the β€œSoftware”), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED β€œAS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # @perch733/react-usefilter-hook
2
+
3
+ A lightweight and reusable React hook for filtering lists with accent normalization, punctuation removal, and TypeScript support.
4
+ Ideal for search bars, dynamic lists, admin dashboards, e-commerce filters, etc.
5
+
6
+ ---
7
+
8
+ ## πŸ”₯ Features
9
+
10
+ - πŸ”  Removes accents (Γ‘ β†’ a)
11
+ - βœ‚οΈ Removes punctuation and special characters
12
+ - πŸ”Ž Case-insensitive search
13
+ - βš›οΈ Fully typed with TypeScript
14
+ - πŸ” Auto-updates when `data` changes
15
+ - πŸ”§ Accepts custom error component
16
+ - 🧩 Framework-agnostic, works in any React project
17
+
18
+ ---
19
+
20
+ ## πŸ“¦ Installation
21
+
22
+ ```sh
23
+ npm install @perch733/react-usefilter-hook
24
+ ```
25
+
26
+ or
27
+
28
+ ```sh
29
+ yarn add @perch733/react-usefilter-hook
30
+
31
+ ```
32
+
33
+ ## πŸš€ Usage Example (Basic)
34
+
35
+ ```tsx
36
+ import { useFilter } from "@perch733/react-usefilter-hook";
37
+
38
+ const products = [
39
+ { title: "CΓ‘mara FotogrΓ‘fica" },
40
+ { title: "Microfono" },
41
+ { title: "Cable HDMI" },
42
+ ];
43
+
44
+ export default function App() {
45
+ const { filterText, filteredData, handleFilterChange } = useFilter(
46
+ products,
47
+ "title",
48
+ <p>No results found</p>
49
+ );
50
+
51
+ return (
52
+ <div>
53
+ <input
54
+ type="search"
55
+ placeholder="Search..."
56
+ value={filterText}
57
+ onChange={handleFilterChange}
58
+ />
59
+
60
+ <ul>
61
+ {filteredData.map((p, i) => (
62
+ <li key={i}>{p.title}</li>
63
+ ))}
64
+ </ul>
65
+ </div>
66
+ );
67
+ }
68
+ ```
69
+
70
+ ## 🎯 Advanced Example
71
+
72
+ ```tsx
73
+ const { filterText, filteredData, error, handleFilterChange } = useFilter(
74
+ users,
75
+ "name",
76
+ <div style={{ color: "red" }}>No users found</div>
77
+ );
78
+
79
+ return (
80
+ <>
81
+ <input
82
+ type="text"
83
+ placeholder="Search users"
84
+ value={filterText}
85
+ onChange={handleFilterChange}
86
+ />
87
+
88
+ {filteredData.length === 0
89
+ ? error
90
+ : filteredData.map((u) => <p key={u.id}>{u.name}</p>)}
91
+ </>
92
+ );
93
+ ```
94
+
95
+ ## 🧠 API Reference
96
+
97
+ ```tsx
98
+ useFilter<T>(data, key, errorComponent);
99
+ ```
100
+
101
+ | Param | Type | Description |
102
+ | ---------------- | ----------------- | --------------------------------- |
103
+ | `data` | `T[]` | Array of objects to filter |
104
+ | `key` | `keyof T` | Object field used for filtering |
105
+ | `errorComponent` | `React.ReactNode` | Element displayed when no matches |
106
+
107
+ ## Returns
108
+
109
+ | Property | Type | Description |
110
+ | -------------------- | ------------------------------------ | ------------------------------------- |
111
+ | `filterText` | `string` | Current normalized search text |
112
+ | `filteredData` | `T[]` | List filtered according to user input |
113
+ | `error` | `React.ReactNode \| null` | Error component if no matches |
114
+ | `handleFilterChange` | `(e: ChangeEvent<HTMLInputElement>)` | Input handler |
115
+
116
+ ### βš™οΈ How filtering works
117
+
118
+ - This hook automatically:
119
+
120
+ - Converts text to lowercase
121
+
122
+ - Removes accents (Ñéíóú β†’ aeiou)
123
+
124
+ - Removes punctuation and special characters
125
+
126
+ - Performs a normalized comparison
127
+
128
+ - Filters in real time as the user types
129
+
130
+ ### πŸ’‘ When to use this hook?
131
+
132
+ - Product search inputs
133
+
134
+ - Admin panel filters
135
+
136
+ - Searchable dropdowns
137
+
138
+ - User lists
139
+
140
+ - Blog post search
141
+
142
+ - Table filtering
143
+
144
+ - Autocomplete components
145
+
146
+ ## πŸ“ Project Structure
147
+
148
+ Your installation will contain:
149
+
150
+ ```
151
+
152
+ dist/
153
+ β”œβ”€ cjs/
154
+ β”œβ”€ esm/
155
+ β”œβ”€ types/
156
+ src/
157
+ README.md
158
+ ```
159
+
160
+ ## πŸ‘€ Author / Autor
161
+
162
+ **Percy Chuzon**
163
+ πŸ“§ [contacto@percychuzon.com](mailto:contacto@percychuzon.com)
164
+ 🌐 [https://wwww.percychuzon.com](https://www.percychuzon.com)
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useFilter = void 0;
4
+ const react_1 = require("react");
5
+ /**
6
+ * πŸ”  Normaliza texto para facilitar bΓΊsquedas:
7
+ * - Convierte a minΓΊsculas
8
+ * - Elimina tildes (Γ‘ β†’ a)
9
+ * - Elimina signos de puntuaciΓ³n
10
+ * - Quita espacios sobrantes
11
+ */
12
+ /** πŸ”  Elimina tildes, signos, y pasa todo a minΓΊsculas */
13
+ function normalizarTexto(texto) {
14
+ return texto
15
+ .normalize("NFD") // separa letras con tildes en componentes
16
+ .replace(/[\u0300-\u036f]/g, "") // elimina los diacrΓ­ticos (tildes)
17
+ .replace(/[.,/#!$%^&*;:{}=\-_`~()ΒΏ?Β‘!]/g, "") // elimina signos
18
+ .toLowerCase()
19
+ .trim();
20
+ }
21
+ const useFilter = (data, key, errorComponent) => {
22
+ 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
+ /** Maneja el texto que escribe el usuario en el input */
26
+ const handleFilterChange = (e) => {
27
+ const searchText = normalizarTexto(e.target.value);
28
+ setFilterText(searchText);
29
+ };
30
+ /** Filtra la lista cada vez que cambia el texto o los datos */
31
+ (0, react_1.useEffect)(() => {
32
+ const filteredItems = data.filter((item) => {
33
+ const valorCampo = String(item[key]);
34
+ return normalizarTexto(valorCampo).includes(filterText);
35
+ });
36
+ setFilteredData(filteredItems);
37
+ if (filteredItems.length === 0 && filterText !== "") {
38
+ setError(errorComponent);
39
+ }
40
+ else {
41
+ setError(null);
42
+ }
43
+ }, [data, filterText, key]);
44
+ return {
45
+ filterText,
46
+ filteredData,
47
+ error,
48
+ handleFilterChange,
49
+ };
50
+ };
51
+ exports.useFilter = useFilter;
@@ -0,0 +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;
@@ -0,0 +1,47 @@
1
+ import { useState, useEffect } from "react";
2
+ /**
3
+ * πŸ”  Normaliza texto para facilitar bΓΊsquedas:
4
+ * - Convierte a minΓΊsculas
5
+ * - Elimina tildes (Γ‘ β†’ a)
6
+ * - Elimina signos de puntuaciΓ³n
7
+ * - Quita espacios sobrantes
8
+ */
9
+ /** πŸ”  Elimina tildes, signos, y pasa todo a minΓΊsculas */
10
+ function normalizarTexto(texto) {
11
+ return texto
12
+ .normalize("NFD") // separa letras con tildes en componentes
13
+ .replace(/[\u0300-\u036f]/g, "") // elimina los diacrΓ­ticos (tildes)
14
+ .replace(/[.,/#!$%^&*;:{}=\-_`~()ΒΏ?Β‘!]/g, "") // elimina signos
15
+ .toLowerCase()
16
+ .trim();
17
+ }
18
+ export const useFilter = (data, key, errorComponent) => {
19
+ const [filterText, setFilterText] = useState("");
20
+ const [filteredData, setFilteredData] = useState(data);
21
+ const [error, setError] = useState(null);
22
+ /** Maneja el texto que escribe el usuario en el input */
23
+ const handleFilterChange = (e) => {
24
+ const searchText = normalizarTexto(e.target.value);
25
+ setFilterText(searchText);
26
+ };
27
+ /** Filtra la lista cada vez que cambia el texto o los datos */
28
+ useEffect(() => {
29
+ const filteredItems = data.filter((item) => {
30
+ const valorCampo = String(item[key]);
31
+ return normalizarTexto(valorCampo).includes(filterText);
32
+ });
33
+ setFilteredData(filteredItems);
34
+ if (filteredItems.length === 0 && filterText !== "") {
35
+ setError(errorComponent);
36
+ }
37
+ else {
38
+ setError(null);
39
+ }
40
+ }, [data, filterText, key]);
41
+ return {
42
+ filterText,
43
+ filteredData,
44
+ error,
45
+ handleFilterChange,
46
+ };
47
+ };
@@ -0,0 +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)}}};
@@ -0,0 +1,49 @@
1
+ import type { ChangeEvent } from "react";
2
+ /**
3
+ * ────────────────────────────────────────────────────────────────
4
+ * πŸ“Œ useFilter β€” Hook reutilizable para filtrar listas de datos
5
+ * ────────────────────────────────────────────────────────────────
6
+ *
7
+ * βœ” Permite filtrar un array (data) segΓΊn un campo especΓ­fico (key)
8
+ * βœ” Devuelve:
9
+ * - filterText β†’ texto escrito por el usuario
10
+ * - filteredData β†’ lista filtrada
11
+ * - error β†’ componente mostrado cuando no hay resultados
12
+ * - handleFilterChange β†’ manejador para input de bΓΊsqueda
13
+ *
14
+ * @template T Tipo genΓ©rico del array a filtrar
15
+ *
16
+ * @param {T[]} data
17
+ * Lista completa de objetos que se desea filtrar
18
+ *
19
+ * @param {keyof T} key
20
+ * Propiedad del objeto que se usarΓ‘ para filtrar (ej: "title")
21
+ *
22
+ * @param {React.ReactNode} errorComponent
23
+ * Componente mostrado si no se encuentran resultados
24
+ *
25
+ * @returns {{
26
+ * filterText: string,
27
+ * filteredData: T[],
28
+ * error: React.ReactNode,
29
+ * handleFilterChange: (e: ChangeEvent<HTMLInputElement>) => void
30
+ * }}
31
+ *
32
+ * @Error
33
+ * Se activa cuando:
34
+ * - El usuario escribe algo
35
+ * - No existen resultados coincidentes
36
+ *
37
+ * Puedes usarlo para mostrar:
38
+ * <p>No se encontrΓ³ nada</p>
39
+ *
40
+ * ────────────────────────────────────────────────────────────────
41
+ */
42
+ type UseFilterReturn<T> = {
43
+ filterText: string;
44
+ filteredData: T[];
45
+ error: React.ReactNode;
46
+ handleFilterChange: (e: ChangeEvent<HTMLInputElement>) => void;
47
+ };
48
+ export declare const useFilter: <T>(data: T[], key: keyof T, errorComponent: React.ReactNode) => UseFilterReturn<T>;
49
+ export {};
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@perch33/react-usefilter-hook",
3
+ "version": "1.0.0",
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
+ }