{"id":27235636,"url":"https://github.com/galiprandi/react-tools","last_synced_at":"2025-04-10T16:48:01.401Z","repository":{"id":239103408,"uuid":"798543256","full_name":"galiprandi/react-tools","owner":"galiprandi","description":"A set of simple and intuitive utilities for developing React applications.","archived":false,"fork":false,"pushed_at":"2024-05-23T01:33:26.000Z","size":202,"stargazers_count":2,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-05-23T01:33:55.172Z","etag":null,"topics":["component","library","react","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@galiprandi/react-tools","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/galiprandi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-10T01:48:25.000Z","updated_at":"2024-05-27T15:30:25.042Z","dependencies_parsed_at":"2024-05-22T01:33:49.808Z","dependency_job_id":"74776a1e-7bd0-4594-9c44-4f269d8d4d3b","html_url":"https://github.com/galiprandi/react-tools","commit_stats":null,"previous_names":["galiprandi/react-tools"],"tags_count":38,"template":false,"template_full_name":"receter/my-component-library","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galiprandi%2Freact-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galiprandi%2Freact-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galiprandi%2Freact-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galiprandi%2Freact-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/galiprandi","download_url":"https://codeload.github.com/galiprandi/react-tools/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248254727,"owners_count":21073138,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["component","library","react","typescript"],"created_at":"2025-04-10T16:47:54.026Z","updated_at":"2025-04-10T16:48:01.389Z","avatar_url":"https://github.com/galiprandi.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cbr style=\"padding: 50px 0;\"/\u003e\n    \u003cp align=\"center\"\u003e\n        \u003cimg src=\"https://raw.githubusercontent.com/galiprandi/react-tools/171080a598bfd9464e6825e385a300c04805da2c/src/assets/react-tools-slim.svg\" alt=\"react tools\" width=\"350\" title=\"react tools\"/\u003e\n    \u003c/p\u003e\n\n\u003cbr style=\"padding: 50px 0;\"/\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://www.npmjs.com/package/@galiprandi/react-tools\"\u003e\n        \u003cimg src=\"https://img.shields.io/npm/d18m/%40galiprandi%2Freact-tools?style=for-the-badge\u0026logo=npm\u0026color=CB3837\" alt=\"NPM Downloads\"/\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://jsr.io/@galiprandi/react-tools\"\u003e\n        \u003cimg src=\"https://img.shields.io/jsr/v/%40galiprandi/react-tools?style=for-the-badge\u0026logo=javascript\u0026color=F7DF1E\" alt=\"NPM Downloads\"/\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/galiprandi/react-tools\"\u003e\n        \u003cimg src=\"https://img.shields.io/github/stars/galiprandi/react-tools?style=for-the-badge\u0026logo=github\u0026color=181717\" alt=\"JSR Version\"/\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n#### Welcome to `@galiprandi/react-tools`, a set of simple and intuitive utilities for developing React applications. This package includes key tools that can streamline your development process, all while being dependency-free.\n\n### Playground\n\nTry out the components in the playground: [@galiprandi/react-tools Playground](https://stackblitz.com/edit/ga-react-tools?file=index.html)\n\n### Installation\n\nTo install use one of the following commands:\n\n```bash\nnpm i @galiprandi/react-tools\n```\n\n```bash\npnpm i @galiprandi/react-tools\n```\n\n```bash\nyarn add @galiprandi/react-tools\n```\n\n## Components:\n\n-   `\u003cForm /\u003e`: A component that wraps the form HTML tag and provides a simple way to create forms in your React application.\n    [Example](#form-component)\n-   `\u003cInput /\u003e`: A reusable input component that provides a consistent user experience.\n    [Example](#input-component)\n\n-   `\u003cDateTime /\u003e`: A reusable input component with `type=\"datetime-local\"` that use dates in RFC 3339 format. [Example](#datetime-component)\n-   `\u003cDialog /\u003e`: A component that wraps the dialog HTML tag and provides a simple way to create accessibility dialogs and modals in your React application. [Example](#dialog-component)\n-   `\u003cObserver /\u003e`: A component allows you to track when an element enters or exits the viewport. This is useful for lazy loading images, infinite scrolling, and more. [Example](#observer-component)\n\n## Hooks:\n\n-   `useDebounce()`: A hook that takes two arguments, value and delay, and return a debounced value. [Example](#usedebounce-hook)\n\n## Components\n\n### Form component\n\nA component that wraps the `form` HTML tag and provides a simple way to create forms in your React application.\n\n#### Adicional Props:\n\n-   `onSubmitValues:` Callback function that is called when the form is submitted and recibe a object with the form values.\n-   `filterEmptyValues:` Boolean, defines if the empty values are filtered from the object passed to the `onSubmitValues` callback. (Default: false)\n\n#### Example:\n\n```js\nimport { Form, Input } from '@galiprandi/react-tools'\nimport { useState } from 'react'\n\nexport const FormExample = () =\u003e {\n    const [values, setValues] = useState\u003cMyFormValues\u003e()\n\n    return (\n        \u003csection\u003e\n            \u003chr /\u003e\n            \u003ch2\u003eForm\u003c/h2\u003e\n            \u003cForm\u003cMyFormValues\u003e\n                onSubmitValues={setValues}\n                filterEmptyValues={true}\n            \u003e\n                \u003cfieldset\u003e\n                    \u003clegend\u003eForm Example\u003c/legend\u003e\n                    \u003cInput\n                        name=\"username\"\n                        label=\"username\"\n                        placeholder=\"Username\"\n                    /\u003e\n                    \u003cbr /\u003e\n                    \u003cInput\n                        name=\"password\"\n                        label=\"password\"\n                        placeholder=\"Password\"\n                        type=\"password\"\n                    /\u003e\n                    \u003cbr /\u003e\n                    \u003cbutton type=\"submit\"\u003eLogin\u003c/button\u003e\n                \u003c/fieldset\u003e\n            \u003c/Form\u003e\n            \u003cp\u003e\n                \u003cbr /\u003e\n                onChangeISOValue: \u003ccode\u003e{JSON.stringify(values)}\u003c/code\u003e\n            \u003c/p\u003e\n        \u003c/section\u003e\n    )\n}\n\ntype MyFormValues = {\n    username: string\n    password: string\n}\n```\n\n### Input component\n\nA simple wrapper around the native `input` element. It accepts all the same props as the native input element and adds a few additional props for convenience.\n\n#### Adicional Props:\n\n-   `label`: A label for the input element. If provided, we add a label element with the provided text.\n-   `onChangeValue`: A callback function that is called when the input value changes\n-   `onChangeDebounce`: A callback function that is called when the input value changes after the debounce delay.\n-   `debounceDelay`: The delay in milliseconds for the debounce.\n-   `className`: A class name to apply to the input element. If a label is provided, the class name is applied to the label and input elements.\n-   `transform`: The type of transformation to apply to the input value. Options include \"toUpperCase\", \"toLowerCase\", \"capitalize\", \"titleCase\", \"snakeCase\", \"onlyNumbers\", \"onlyLetters\", \"onlyEmail\" and \"onlyAlphanumeric\"\n-   `transformFn`: A custom function to apply to the input value. This function takes a string as input and returns a string as output. If both transform and transformFn are provided, the transformFn function will take precedence.\n-   `datalist`: An array of strings to use as options in a datalist element.\n\n#### Example:\n\n```js\nimport { useState } from \"react\";\nimport { Input, type InputProps } from '@galiprandi/react-tools';\n\nexport const InputExample = () =\u003e {\n  const [value, setValue] = useState\u003cInputProps[\"value\"]\u003e();\n  const [valueDebounced, setValueDebounced] = useState\u003cInputProps[\"value\"]\u003e();\n\n  return (\n    \u003csection\u003e\n      \u003ch2\u003eInput\u003c/h2\u003e\n\n      \u003cInput\n        type=\"text\"\n        placeholder=\"Enter your name and last name\"\n        // Custom attributes\n        label=\"Name and Last Name\"\n        className=\"my-custom-input\"\n        value={value}\n        onChangeValue={setValue}\n        onChangeDebounce={setValueDebounced}\n        debounceDelay={1000}\n        transform=\"titleCase\"\n        datalist={['John Doe', 'Jane Doe', 'John Smith']}\n      /\u003e\n      \u003cp\u003e\n        Transformed value: \u003ccode\u003e{value}\u003c/code\u003e\n        \u003cbr /\u003e\n        Debounced value (1s): \u003ccode\u003e{valueDebounced}\u003c/code\u003e\n      \u003c/p\u003e\n    \u003c/section\u003e\n  );\n};\n```\n\n### DateTime component\n\nA simple wrapper around the native `input` element with `type=\"datetime-local\"`. It accepts all the same props as the native input element and adds a few additional props for convenience.\n\n#### Adicional Props:\n\n-   `label`: A label for the input element. If provided, we add a label element with the provided text.\n-   `className`: A class name to apply to the input element. If a label is provided, the class name is applied to the label and input elements.\n-   `onChangeValue`: A callback function that is called when the input value changes.\n-   `onChangeISOValue`: A callback function that is called when the input value changes and returns the date in RFC 3339 format.\n-   `isoValue`: The date in RFC 3339 format.\n-   Any other prop that the our `Input` component accepts (like `onChangeDebounce`, `transform` and `transformFn`).\n\n#### Example:\n\n```js\nimport { useState } from 'react';\nimport { DateTime, type DateTimeProps } from '@galiprandi/react-tools';\n\nexport const DateTimeExample = () =\u003e {\n  const now = new Date().toISOString();\n  const [isoValue, setIsoValue] = useState\u003cDateTimeProps['isoValue']\u003e(now);\n\n  return (\n    \u003csection\u003e\n      \u003chr /\u003e\n      \u003ch2\u003eDateTime\u003c/h2\u003e\n      \u003cDateTime\n        // Custom attributes\n        isoValue={isoValue}\n        label=\"Choice your birthday\"\n        onChangeISOValue={setIsoValue}\n      /\u003e\n      \u003cp\u003e\n        onChangeISOValue: \u003ccode\u003e{isoValue}\u003c/code\u003e\n      \u003c/p\u003e\n    \u003c/section\u003e\n  );\n};\n\n\n```\n\n### Dialog component\n\nA component that wraps the `dialog` HTML tag and provides a simple way to create accessibility dialogs and modals in your React application.\n\n#### Adicional Props:\n\n-   `isOpen:` Boolean, defines if the dialog is open or closed. (Optional)\n-   `behavior:` 'dialog' | 'modal', defines the behavior of the dialog. (Default: 'modal')\n-   `onOpen:` Callback function executed when the dialog is opened. (Optional)\n-   `onClose:` Callback function executed when the dialog is closed. (Optional)\n-   `children:` ReactNode, the content of the dialog. (Optional)\n-   `opener:` ReactNode, the element that opens the dialog. (Optional)\n\n#### Example:\n\n```js\nimport { Dialog } from '@galiprandi/react-tools'\n\nexport const DialogExample = () =\u003e {\n    return (\n        \u003csection\u003e\n            \u003chr /\u003e\n            \u003ch2\u003eDialog\u003c/h2\u003e\n\n            \u003cDialog\n                // Custom attributes\n                behavior=\"modal\"\n                opener={\u003cbutton\u003eToggle Dialog\u003c/button\u003e}\n                onOpen={() =\u003e console.info('Dialog opened')}\n                onClose={() =\u003e console.info('Dialog closed')}\n            \u003e\n                \u003ch2\u003eHello there 👋\u003c/h2\u003e\n                \u003cp\u003eThis is a dialog example.\u003c/p\u003e\n                \u003cp\u003e\n                    For information on how to use html dialogs, or styling them,\n                    \u003ca\n                        href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog\"\n                        target=\"_blank\"\n                        rel=\"noopener noreferrer\"\n                    \u003e\n                        {' '}\n                        check documentation on MDN website\n                    \u003c/a\u003e\n                \u003c/p\u003e\n            \u003c/Dialog\u003e\n        \u003c/section\u003e\n    )\n}\n```\n\n### Observer component\n\nA component that allows you to track when an element enters or exits the viewport. This is useful for lazy loading images, infinite scrolling, and more.\n\n#### Adicional Props:\n\n-   `children:` ReactNode, the content of the observer.\n-   `onAppear:` Callback function executed when the element enters the viewport. (Optional)\n-   `onDisappear` Callback function executed when the element exits the viewport. (Optional)\n-   `wrapper:` HTMLElement, the element that is used as wrapper of children. (Default: 'div')\n-   `root:` HTMLElement, the element that is used as the viewport for checking visibility of the target. (Optional)\n-   `rootMargin` Margin around the root. Can have values similar to the CSS margin property, e.g. \"10px 20px 30px 40px\" (top, right, bottom, left). The values can be percentages. (Optional)\n-   `threshold` Number, a number between 0 and 1 indicating the percentage of the target's visibility the observer's callback should be executed. (Default: 0)\n\n#### Example:\n\n```js\nimport { Observer } from '@galiprandi/react-tools'\nimport { useState } from 'react'\n\nexport const ObserveExample = () =\u003e {\n    const [inScreen, setInScreen] = useState\u003cnumber[]\u003e([])\n    const images = Array.from({ length: 5 }, (_, i) =\u003e i + 1)\n\n    return (\n        \u003csection\u003e\n            \u003chr /\u003e\n            \u003ch2\u003eObserver\u003c/h2\u003e\n            \u003cp\u003e\n                \u003csmall\u003e\n                    A component that allows you to track when an element enters\n                    or exits the viewport. This is useful for lazy loading\n                    images, infinite scrolling, and more.\n                \u003c/small\u003e\n            \u003c/p\u003e\n            \u003cdiv\n                style={{\n                    position: 'sticky',\n                    top: 0,\n                    right: 0,\n                    fontSize: 20,\n                    background: '#283618',\n                    padding: 15,\n                }}\n            \u003e\n                Images in screen: {inScreen.join(' | ')}\n            \u003c/div\u003e\n            \u003cbr /\u003e\n            {images.map((i) =\u003e (\n                \u003cObserver\n                    key={i}\n                    wrapper=\"p\"\n                    onAppear={() =\u003e\n                        setInScreen((prev) =\u003e Array.from(new Set([...prev, i])))\n                    }\n                    onDisappear={() =\u003e\n                        setInScreen((prev) =\u003e prev.filter((item) =\u003e item !== i))\n                    }\n                    threshold={0.5}\n                \u003e\n                    \u003c\u003e\n                        \u003cimg\n                            src={`https://picsum.photos/500/500?random=${i}`}\n                            loading=\"lazy\"\n                            alt=\"Free image\"\n                            width={500}\n                            height={500}\n                        /\u003e\n                        \u003cbr /\u003e\n                    \u003c/\u003e\n                \u003c/Observer\u003e\n            ))}\n        \u003c/section\u003e\n    )\n}\n```\n\n## Hooks\n\n### useDebounce hook\n\nA simple hook that takes two arguments, value and delay, and returns a debounced value. Its used internally by some components, but you can use it in your custom hooks or components.\n\n#### Example:\n\n```js\nimport { useDebounce } from '@galiprandi/react-tools'\nimport { useState } from 'react'\n\nexport const DebounceExample = () =\u003e {\n    const [value, setValue] = useState\u003cstring\u003e()\n    const debouncedValue = useDebounce(value, 1000)\n\n    return (\n        \u003csection\u003e\n            \u003chr /\u003e\n            \u003ch2\u003euseDebounce\u003c/h2\u003e\n\n            \u003cinput\n                type=\"text\"\n                placeholder=\"Type something...\"\n                value={value}\n                onChange={(e) =\u003e setValue(e.target.value)}\n            /\u003e\n            \u003cp\u003e\n                Value: \u003ccode\u003e{value}\u003c/code\u003e\n                \u003cbr /\u003e\n                Debounced value (1s): \u003ccode\u003e{debouncedValue}\u003c/code\u003e\n            \u003c/p\u003e\n        \u003c/section\u003e\n    )\n}\n```\n\n## Contribution\n\nContributions are welcome! To contribute:\n\n1. Fork this repository.\n2. Create a branch with a meaningful description.\n3. Make the desired changes.\n4. Update the **documentation** if necessary.\n5. Open a Pull Request to the main branch.\n\nIf you find an issue or have a suggestion to improve the project, feel free to [open an issue](https://github.com/galiprandi/react-tools/issues).\n\n## License\n\nThis project is licensed under the MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgaliprandi%2Freact-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgaliprandi%2Freact-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgaliprandi%2Freact-tools/lists"}