fix: update sass version and refactor input components

- Updated `sass` version from `^1.86.0` to `^1.32.13` in `package.json`.
- Refactored `Input` component to create a new `SimpleInput` component without password visibility toggle.
- Introduced a new `PasswordInput` component for handling password inputs with show/hide functionality.
- Updated imports and usage of input components in relevant pages to reflect the new structure.
This commit is contained in:
jalvarado
2025-05-27 10:50:53 -06:00
parent 5706232212
commit 0195bf0778
6 changed files with 333 additions and 554 deletions
+110 -368
View File
@@ -24,7 +24,7 @@
"@types/react-syntax-highlighter": "^15.5.13",
"eslint": "^9",
"eslint-config-next": "15.2.3",
"sass": "^1.86.0",
"sass": "^1.32.13",
"typescript": "^5"
}
},
@@ -843,330 +843,6 @@
"node": ">=12.4.0"
}
},
"node_modules/@parcel/watcher": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"detect-libc": "^1.0.3",
"is-glob": "^4.0.3",
"micromatch": "^4.0.5",
"node-addon-api": "^7.0.0"
},
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"@parcel/watcher-android-arm64": "2.5.1",
"@parcel/watcher-darwin-arm64": "2.5.1",
"@parcel/watcher-darwin-x64": "2.5.1",
"@parcel/watcher-freebsd-x64": "2.5.1",
"@parcel/watcher-linux-arm-glibc": "2.5.1",
"@parcel/watcher-linux-arm-musl": "2.5.1",
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
"@parcel/watcher-linux-arm64-musl": "2.5.1",
"@parcel/watcher-linux-x64-glibc": "2.5.1",
"@parcel/watcher-linux-x64-musl": "2.5.1",
"@parcel/watcher-win32-arm64": "2.5.1",
"@parcel/watcher-win32-ia32": "2.5.1",
"@parcel/watcher-win32-x64": "2.5.1"
}
},
"node_modules/@parcel/watcher-android-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
"integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-darwin-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
"integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-darwin-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
"integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-freebsd-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
"integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
"integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
"integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm64-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
"integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm64-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
"integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-x64-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
"integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-x64-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
"integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
"integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-ia32": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
"integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
"integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher/node_modules/detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"bin": {
"detect-libc": "bin/detect-libc.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
@@ -1752,6 +1428,20 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"devOptional": true,
"license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -1987,6 +1677,19 @@
"dev": true,
"license": "MIT"
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/bootstrap": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
@@ -2037,7 +1740,7 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
@@ -2185,19 +1888,41 @@
}
},
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"readdirp": "^4.0.1"
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
},
"engines": {
"node": ">= 14.16.0"
"node": ">= 8.10.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/chokidar/node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"devOptional": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/client-only": {
@@ -3161,7 +2886,7 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
@@ -3232,6 +2957,21 @@
"node": ">=0.4.x"
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -3552,13 +3292,6 @@
"node": ">= 4"
}
},
"node_modules/immutable": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz",
"integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==",
"devOptional": true,
"license": "MIT"
},
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -3686,6 +3419,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"binary-extensions": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/is-boolean-object": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
@@ -3791,7 +3537,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -3836,7 +3582,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
@@ -3872,7 +3618,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
@@ -4379,13 +4125,15 @@
}
}
},
"node_modules/node-addon-api": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
"dev": true,
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"devOptional": true,
"license": "MIT",
"optional": true
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
@@ -4646,7 +4394,7 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -4814,17 +4562,16 @@
}
},
"node_modules/readdirp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 14.18.0"
"dependencies": {
"picomatch": "^2.2.1"
},
"funding": {
"type": "individual",
"url": "https://paulmillr.com/funding/"
"engines": {
"node": ">=8.10.0"
}
},
"node_modules/reflect.getprototypeof": {
@@ -5056,24 +4803,19 @@
}
},
"node_modules/sass": {
"version": "1.86.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.86.0.tgz",
"integrity": "sha512-zV8vGUld/+mP4KbMLJMX7TyGCuUp7hnkOScgCMsWuHtns8CWBoz+vmEhoGMXsaJrbUP8gj+F1dLvVe79sK8UdA==",
"version": "1.32.13",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.32.13.tgz",
"integrity": "sha512-dEgI9nShraqP7cXQH+lEXVf73WOPCse0QlFzSD8k+1TcOxCMwVXfQlr0jtoluZysQOyJGnfr21dLvYKDJq8HkA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"chokidar": "^4.0.0",
"immutable": "^5.0.2",
"source-map-js": ">=0.6.2 <2.0.0"
"chokidar": ">=3.0.0 <4.0.0"
},
"bin": {
"sass": "sass.js"
},
"engines": {
"node": ">=14.0.0"
},
"optionalDependencies": {
"@parcel/watcher": "^2.4.1"
"node": ">=8.9.0"
}
},
"node_modules/scheduler": {
@@ -5561,7 +5303,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
+1 -1
View File
@@ -25,7 +25,7 @@
"@types/react-syntax-highlighter": "^15.5.13",
"eslint": "^9",
"eslint-config-next": "15.2.3",
"sass": "^1.86.0",
"sass": "^1.32.13",
"typescript": "^5"
}
}
+48 -44
View File
@@ -1,93 +1,97 @@
"use client";
'use client';
import IndiceContenido from "@/components/content-index";
import Input from "@/components/input";
import VistaComponente from "@/components/vista-componente";
import { inputBasicExample, inputPasswordExample, inputStylesExample } from "@/snippets/input/input-examples";
import { useState } from "react";
import IndiceContenido from '@/components/content-index';
import Input from '@/components/input';
import PasswordInput from '@/components/password';
import VistaComponente from '@/components/vista-componente';
import {
inputBasicExample,
inputPasswordExample,
inputStylesExample,
} from '@/snippets/input/input-examples';
import { useState } from 'react';
export default function Page() {
const [value, setValue] = useState("");
const [password, setPassword] = useState("");
const [value, setValue] = useState('');
const [password, setPassword] = useState('');
return (
<>
<IndiceContenido
items={[
{ id: "input-basico", label: "Input básico" },
{ id: "input-password", label: "Input de contraseña" },
{ id: "input-estilos", label: "Personalización de estilos" },
{ id: "input-props", label: "Props del componente" },
{ id: 'input-basico', label: 'Input básico' },
{ id: 'input-password', label: 'Input de contraseña' },
{ id: 'input-estilos', label: 'Personalización de estilos' },
{ id: 'input-props', label: 'Props del componente' },
]}
/>
<div className="my-5">
<h1 className="mb-4 display-5">
<div className='my-5'>
<h1 className='mb-4 display-5'>
🔤 Componente: <code>Input</code>
</h1>
<p className="mb-4 text-muted">
<p className='mb-4 text-muted'>
El componente <code>&lt;Input /&gt;</code> es un campo de entrada
reutilizable con soporte para etiquetas, tipos como{" "}
reutilizable con soporte para etiquetas, tipos como{' '}
<code>password</code>, accesibilidad mejorada, y personalización de
estilos. Además, incluye un botón para mostrar/ocultar contraseñas
cuando el tipo es <code>password</code>.
</p>
<hr className="my-5" />
<hr className='my-5' />
<VistaComponente
id="input-basico"
title="Input básico"
description="Un input controlado con una etiqueta visible. Puedes personalizar su valor y manejar los cambios mediante `useState`."
id='input-basico'
title='Input básico'
description='Un input controlado con una etiqueta visible. Puedes personalizar su valor y manejar los cambios mediante `useState`.'
code={inputBasicExample}
>
<Input
label="Nombre"
placeholder="Ingresa tu nombre"
label='Nombre'
placeholder='Ingresa tu nombre'
value={value}
onChange={(e) => setValue(e.target.value)}
/>
</VistaComponente>
<VistaComponente
id="input-password"
title="Input de contraseña"
description="Cuando el tipo es `password`, aparece un botón para mostrar/ocultar el valor del campo."
id='input-password'
title='Input de contraseña'
description='Para tener un input de tipo contraseña con un boton que permite mostrar u ocultar la contraseña, puedes usar el componente <PasswordInput />.'
code={inputPasswordExample}
>
<Input
type="password"
label="Contraseña"
<PasswordInput
label='Contraseña'
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</VistaComponente>
<VistaComponente
id="input-estilos"
title="Personalización de estilos"
description="Puedes aplicar clases personalizadas a los elementos internos del input."
id='input-estilos'
title='Personalización de estilos'
description='Puedes aplicar clases personalizadas a los elementos internos del input.'
code={inputStylesExample}
>
<Input
label="Correo"
placeholder="ejemplo@correo.com"
label='Correo'
placeholder='ejemplo@correo.com'
className={{
container: "mb-4",
label: "text-primary fw-bold",
input: "border-success",
container: 'mb-4',
label: 'text-primary fw-bold',
input: 'form-control border-success',
}}
/>
</VistaComponente>
<section className="mb-5" id="input-props">
<h2 className="h5 mb-3">Props del componente</h2>
<table className="table align-middle">
<section className='mb-5' id='input-props'>
<h2 className='h5 mb-3'>Props del componente</h2>
<table className='table align-middle'>
<thead>
<tr>
<th scope="col">Prop</th>
<th scope="col">Tipo</th>
<th scope="col">Descripción</th>
<th scope='col'>Prop</th>
<th scope='col'>Tipo</th>
<th scope='col'>Descripción</th>
</tr>
</thead>
<tbody>
@@ -108,7 +112,7 @@ export default function Page() {
<code>string</code>
</td>
<td>
Tipo del input. Soporta cualquier tipo válido de HTML como{" "}
Tipo del input. Soporta cualquier tipo válido de HTML como{' '}
<code>text</code>, <code>password</code>, <code>email</code>,
etc.
</td>
@@ -174,7 +178,7 @@ export default function Page() {
<code>InputHTMLAttributes&lt;HTMLInputElement&gt;</code>
</td>
<td>
Cualquier otra prop válida de un <code>&lt;input /&gt;</code>{" "}
Cualquier otra prop válida de un <code>&lt;input /&gt;</code>{' '}
estándar.
</td>
</tr>
+84 -84
View File
@@ -1,21 +1,21 @@
"use client";
'use client';
import React, { useState } from "react";
import Table, { Header, TableSkeleton } from "@/components/table";
import VistaComponente from "@/components/vista-componente";
import React, { useState } from 'react';
import Table, { Header, TableSkeleton } from '@/components/table';
import VistaComponente from '@/components/vista-componente';
import {
tableBasicExample,
tableSkeletonExample,
} from "@/snippets/table/table-basic";
import { tableClickable } from "@/snippets/table/table-clickable";
import { tableAutoPagination } from "@/snippets/table/table-auto-pagination";
import { tableCustomPagination } from "@/snippets/table/table-custom-pagination";
import { tableCustomCellRender } from "@/snippets/table/table-custom-cell-render";
import { tableColumnWidth } from "@/snippets/table/table-column-width";
import { CodeBlock } from "@/components/code-block";
import Input from "@/components/input";
import { tableFilter } from "@/snippets/table/table-filter";
import IndiceContenido from "@/components/content-index";
} from '@/snippets/table/table-basic';
import { tableClickable } from '@/snippets/table/table-clickable';
import { tableAutoPagination } from '@/snippets/table/table-auto-pagination';
import { tableCustomPagination } from '@/snippets/table/table-custom-pagination';
import { tableCustomCellRender } from '@/snippets/table/table-custom-cell-render';
import { tableColumnWidth } from '@/snippets/table/table-column-width';
import { CodeBlock } from '@/components/code-block';
import Input from '@/components/input';
import { tableFilter } from '@/snippets/table/table-filter';
import IndiceContenido from '@/components/content-index';
export default function Page() {
const headers: Header<{
@@ -24,20 +24,20 @@ export default function Page() {
email: string;
acciones?: null;
}>[] = [
{ key: "name", label: "Nombre", width: "30%" },
{ key: "age", label: "Edad", width: "15%" },
{ key: "email", label: "Correo", width: "40%" },
{ key: 'name', label: 'Nombre', width: '30%' },
{ key: 'age', label: 'Edad', width: '15%' },
{ key: 'email', label: 'Correo', width: '40%' },
];
const baseData = [
{ name: "Juan", age: 20, email: "juan@example.com" },
{ name: "María", age: 25, email: "maria@example.com" },
{ name: "Pedro", age: 30, email: "pedro@example.com" },
{ name: "Luisa", age: 28, email: "luisa@example.com" },
{ name: 'Juan', age: 20, email: 'juan@example.com' },
{ name: 'María', age: 25, email: 'maria@example.com' },
{ name: 'Pedro', age: 30, email: 'pedro@example.com' },
{ name: 'Luisa', age: 28, email: 'luisa@example.com' },
];
const [currentPage, setCurrentPage] = useState(1);
const [search, setSearch] = useState("");
const [search, setSearch] = useState('');
const filteredData = baseData.filter((item) =>
item.name.toLowerCase().includes(search.toLowerCase())
@@ -47,43 +47,43 @@ export default function Page() {
<>
<IndiceContenido
items={[
{ id: "uso-basico", label: "Uso básico" },
{ id: "tabla-en-estado-de-carga", label: "Tabla en estado de carga" },
{ id: "filas-clicables", label: "Filas clicables" },
{ id: "paginacion-personalizada", label: "Paginación personalizada" },
{ id: 'uso-basico', label: 'Uso básico' },
{ id: 'tabla-en-estado-de-carga', label: 'Tabla en estado de carga' },
{ id: 'filas-clicables', label: 'Filas clicables' },
{ id: 'paginacion-personalizada', label: 'Paginación personalizada' },
{
id: "paginacion-controlada-externamente",
label: "Paginación controlada externamente",
id: 'paginacion-controlada-externamente',
label: 'Paginación controlada externamente',
},
{
id: "render-personalizado-por-celda",
label: "Render personalizado por celda",
id: 'render-personalizado-por-celda',
label: 'Render personalizado por celda',
},
{
id: "personalizacion-del-tamano-de-columnas",
label: "Personalización del tamaño de columnas",
id: 'personalizacion-del-tamano-de-columnas',
label: 'Personalización del tamaño de columnas',
},
{
id: "filtro-simple-con-input-externo",
label: "Filtro simple con input externo",
id: 'filtro-simple-con-input-externo',
label: 'Filtro simple con input externo',
},
{
id: "usar-identificadores-unicos-con-rowkey",
label: "Usar identificadores únicos con `rowKey`",
id: 'usar-identificadores-unicos-con-rowkey',
label: 'Usar identificadores únicos con `rowKey`',
},
{ id: "props-del-componente", label: "Props del componente" },
{ id: 'props-del-componente', label: 'Props del componente' },
]}
/>
<div className="my-5">
<h1 className="mb-4 display-5">
<div className='my-5'>
<h1 className='mb-4 display-5'>
Componente: <code>Table</code>
</h1>
<p className="mb-4 text-muted">
<p className='mb-4 text-muted'>
El componente <code>&lt;Table /&gt;</code> permite mostrar datos en
forma tabular, con funcionalidades como ordenamiento, paginación,
renderizado personalizado, clic en filas y un estado de carga
esqueleto. Los estilos de esta tabla se encuentran en{" "}
esqueleto. Los estilos de esta tabla se encuentran en{' '}
<code>@/styles/sass/_table.scss</code>
</p>
@@ -93,32 +93,32 @@ export default function Page() {
}
/>
<hr className="my-5" />
<hr className='my-5' />
<VistaComponente
title="Uso básico"
description="Tabla simple con headers y datos sin configuración adicional. el ancho de las columnas se ajusta automáticamente a no ser que se especifique."
title='Uso básico'
description='Tabla simple con headers y datos sin configuración adicional. el ancho de las columnas se ajusta automáticamente a no ser que se especifique.'
code={tableBasicExample}
id="uso-basico"
id='uso-basico'
>
<Table headers={headers} data={baseData} />
</VistaComponente>
{/* SKELETON */}
<VistaComponente
title="Tabla en estado de carga"
description="El componente `TablaSkeleton` simula una tabla vacía mientras se cargan los datos."
title='Tabla en estado de carga'
description='El componente `TablaSkeleton` simula una tabla vacía mientras se cargan los datos.'
code={tableSkeletonExample}
id="tabla-en-estado-de-carga"
id='tabla-en-estado-de-carga'
>
<TableSkeleton rows={3} columns={4} />
</VistaComponente>
<VistaComponente
title="Filas clicables"
description="Usa `onRowClick` para ejecutar acciones al hacer clic en una fila."
title='Filas clicables'
description='Usa `onRowClick` para ejecutar acciones al hacer clic en una fila.'
code={tableClickable}
id="filas-clicables"
id='filas-clicables'
>
<Table
headers={headers}
@@ -128,19 +128,19 @@ export default function Page() {
</VistaComponente>
<VistaComponente
title="Paginación personalizada"
description="Controla cuántas filas se muestran por página con `rowsPerPage`."
title='Paginación personalizada'
description='Controla cuántas filas se muestran por página con `rowsPerPage`.'
code={tableAutoPagination}
id="paginacion-personalizada"
id='paginacion-personalizada'
>
<Table headers={headers} data={baseData} rowsPerPage={2} />
</VistaComponente>
<VistaComponente
title="Paginación controlada externamente"
description="Usa `controlledPage` y `onPageChange` para controlar la página actual desde el estado del componente padre."
title='Paginación controlada externamente'
description='Usa `controlledPage` y `onPageChange` para controlar la página actual desde el estado del componente padre.'
code={tableCustomPagination}
id="paginacion-controlada-externamente"
id='paginacion-controlada-externamente'
>
<Table
headers={headers}
@@ -152,21 +152,21 @@ export default function Page() {
</VistaComponente>
<VistaComponente
title="Render personalizado por celda"
description="Personaliza cómo se muestran ciertas columnas usando la propiedad `render`."
title='Render personalizado por celda'
description='Personaliza cómo se muestran ciertas columnas usando la propiedad `render`.'
code={tableCustomCellRender}
id="render-personalizado-por-celda"
id='render-personalizado-por-celda'
>
<Table
headers={[
...headers,
{
key: "acciones",
label: "Acciones",
width: "15%",
key: 'acciones',
label: 'Acciones',
width: '15%',
render: (_, row) => (
<button
className="btn btn-sm btn-primary"
className='btn btn-sm btn-primary'
onClick={() => alert(row.email)}
>
Ver correo
@@ -179,16 +179,16 @@ export default function Page() {
</VistaComponente>
<VistaComponente
title="Personalización del tamaño de columnas"
description="Puedes controlar el ancho de cada columna usando la propiedad `width` dentro de cada header."
title='Personalización del tamaño de columnas'
description='Puedes controlar el ancho de cada columna usando la propiedad `width` dentro de cada header.'
code={tableColumnWidth}
id="personalizacion-del-tamano-de-columnas"
id='personalizacion-del-tamano-de-columnas'
>
<Table
headers={[
{ key: "name", label: "Nombre", width: "60%" },
{ key: "age", label: "Edad", width: "15%" },
{ key: "email", label: "Correo electrónico", width: "35%" },
{ key: 'name', label: 'Nombre', width: '60%' },
{ key: 'age', label: 'Edad', width: '15%' },
{ key: 'email', label: 'Correo electrónico', width: '35%' },
]}
data={baseData}
/>
@@ -196,13 +196,13 @@ export default function Page() {
{/* FILTRO */}
<VistaComponente
title="🔍 Filtro simple con input externo"
description="Filtrar los datos de la tabla con un input externo."
title='🔍 Filtro simple con input externo'
description='Filtrar los datos de la tabla con un input externo.'
code={tableFilter}
id="filtro-simple-con-input-externo"
id='filtro-simple-con-input-externo'
>
<Input
placeholder="Buscar por nombre..."
placeholder='Buscar por nombre...'
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
@@ -210,9 +210,9 @@ export default function Page() {
</VistaComponente>
<VistaComponente
title="🆔 Usar identificadores únicos con `rowKey`"
description="Proporciona una función para identificar cada fila de forma única."
id="usar-identificadores-unicos-con-rowkey"
title='🆔 Usar identificadores únicos con `rowKey`'
description='Proporciona una función para identificar cada fila de forma única.'
id='usar-identificadores-unicos-con-rowkey'
>
<Table
headers={headers}
@@ -222,14 +222,14 @@ export default function Page() {
</VistaComponente>
{/* PROPS */}
<section className="mb-5" id="props-del-componente">
<h2 className="h5 mb-3">Props del componente</h2>
<table className="table align-middle overflow-auto">
<section className='mb-5' id='props-del-componente'>
<h2 className='h5 mb-3'>Props del componente</h2>
<table className='table align-middle overflow-auto'>
<thead>
<tr>
<th scope="col">Prop</th>
<th scope="col">Tipo</th>
<th scope="col">Descripción</th>
<th scope='col'>Prop</th>
<th scope='col'>Tipo</th>
<th scope='col'>Descripción</th>
</tr>
</thead>
<tbody>
@@ -291,7 +291,7 @@ export default function Page() {
<code>className?</code>
</td>
<td>
<code>{"{ table?, row?, cell?, header? }"}</code>
<code>{'{ table?, row?, cell?, header? }'}</code>
</td>
<td>
Clases personalizadas para la tabla, filas, celdas y
+20 -57
View File
@@ -1,79 +1,42 @@
import React, { useState } from "react";
import React from 'react';
export interface InputProps
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "className"> {
export interface SimpleInputProps
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className'> {
/** Etiqueta visible asociada al campo de entrada */
label?: string;
/** Clases CSS personalizables para distintos elementos */
className?: {
/** Clases para el contenedor del input */
container?: string;
/** Clases para la etiqueta */
label?: string;
/** Clases para el input */
input?: string;
};
}
/**
* Componente de entrada (`Input`) reutilizable en React.
*
* Este componente renderiza un campo de entrada (`<input>`) con una etiqueta opcional y
* funcionalidad para mostrar u ocultar contraseñas cuando el tipo es `password`.
* También permite personalizar clases CSS y es accesible mediante `aria-label` y `htmlFor`.
*
* @component
* @param {Object} props - Propiedades del componente.
* @param {string} [props.label] - Etiqueta visible asociada al campo de entrada.
* @param {Object} [props.className] - Clases CSS personalizables para distintos elementos.
* @param {string} [props.className.container] - Clases para el contenedor del input.
* @param {string} [props.className.label] - Clases para la etiqueta del input.
* @param {string} [props.className.input] - Clases para el input en sí.
* @param {string} [props.type] - Tipo del input (`text`, `password`, `email`, etc.).
* @param {string} [props.name] - Nombre del input (útil para formularios).
* @param {string} [props.id] - ID personalizado para el input (para accesibilidad).
* @param {string} [props.value] - Valor del input (para uso controlado).
* @param {function} [props.onChange] - Manejador del cambio de valor del input.
* @param {React.InputHTMLAttributes<HTMLInputElement>} [rest] - Atributos adicionales compatibles con `<input>`.
* Componente de entrada (`Input`) sin lógica de mostrar/ocultar contraseña.
*/
export default function Input(props: InputProps) {
const { className, label, type, name, id, ...rest } = props;
const [showPassword, setShowPassword] = useState(false);
export default function SimpleInput(props: SimpleInputProps) {
const { label, name, id, className, ...rest } = props;
const isPassword = type === "password";
const inputType = isPassword && showPassword ? "text" : type;
const inputId =
id || name || (label ? `input-${label.replace(/\s+/g, "-")}` : undefined);
const togglePasswordVisibility = () => setShowPassword(!showPassword);
id || name || (label ? `input-${label.replace(/\s+/g, '-')}` : undefined);
return (
<div className={className?.container || "mb-3"}>
<div className={className?.container || 'mb-3'}>
{label && inputId && (
<label
htmlFor={inputId}
className={`form-label ${className?.label || ""}`}
>
<label htmlFor={inputId} className={className?.label || 'form-label'}>
{label}
</label>
)}
<div className="input-group">
<input
id={inputId}
name={name}
type={inputType}
className={`form-control bg-white ${className?.input || ""}`}
{...rest}
/>
{isPassword && (
<button
type="button"
className="btn btn-light border"
onClick={togglePasswordVisibility}
aria-label={
showPassword ? "Ocultar contraseña" : "Mostrar contraseña"
}
title={showPassword ? "Ocultar contraseña" : "Mostrar contraseña"}
>
<i className={`bi ${showPassword ? "bi-eye-slash" : "bi-eye"}`}></i>
</button>
)}
</div>
<input
id={inputId}
name={name}
className={className?.input || 'form-control'}
{...rest}
/>
</div>
);
}
+70
View File
@@ -0,0 +1,70 @@
import React, { useState } from 'react';
export interface PasswordInputProps
extends Omit<
React.InputHTMLAttributes<HTMLInputElement>,
'type' | 'className'
> {
/**
* Texto de la etiqueta asociada al input (opcional).
*/
label?: string;
/**
* Clases CSS personalizables para distintos elementos.
*/
className?: {
/** Clases para el contenedor del componente */
container?: string;
/** Clases para la etiqueta */
label?: string;
/** Clases para el campo input */
input?: string;
/** Clases para el botón de toggle */
button?: string;
};
}
/**
* Componente especializado para inputs de contraseña con botón de mostrar/ocultar.
*/
export default function PasswordInput(props: PasswordInputProps) {
const { label, name, id, className, ...rest } = props;
const [visible, setVisible] = useState(false);
// Determina el tipo de input según el estado de visibilidad
const inputType = visible ? 'text' : 'password';
const inputId =
id ||
name ||
(label ? `password-${label.replace(/\s+/g, '-')}` : undefined);
const toggleVisibility = () => setVisible((v) => !v);
return (
<div className={className?.container || 'mb-3'}>
{label && inputId && (
<label htmlFor={inputId} className={className?.label || 'form-label'}>
{label}
</label>
)}
<div className="input-group">
<input
id={inputId}
name={name}
type={inputType}
className={className?.input || 'form-control'}
{...rest}
/>
<button
type="button"
className={className?.button || 'btn btn-light border'}
onClick={toggleVisibility}
aria-label={visible ? 'Ocultar contraseña' : 'Mostrar contraseña'}
title={visible ? 'Ocultar contraseña' : 'Mostrar contraseña'}
>
<i className={`bi ${visible ? 'bi-eye-slash' : 'bi-eye'}`} />
</button>
</div>
</div>
);
}