{"id":13632707,"url":"https://github.com/diegohaz/reuse","last_synced_at":"2025-04-04T09:10:02.808Z","repository":{"id":57355281,"uuid":"149279884","full_name":"diegohaz/reuse","owner":"diegohaz","description":"♻️ Reuse React components to create new ones","archived":false,"fork":false,"pushed_at":"2019-03-25T21:35:58.000Z","size":614,"stargazers_count":494,"open_issues_count":1,"forks_count":8,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-10-30T05:56:02.403Z","etag":null,"topics":["react","reakit","reuse"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/diegohaz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-09-18T11:49:45.000Z","updated_at":"2024-10-24T10:37:54.000Z","dependencies_parsed_at":"2022-09-26T16:31:46.529Z","dependency_job_id":null,"html_url":"https://github.com/diegohaz/reuse","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegohaz%2Freuse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegohaz%2Freuse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegohaz%2Freuse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/diegohaz%2Freuse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/diegohaz","download_url":"https://codeload.github.com/diegohaz/reuse/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247149505,"owners_count":20891954,"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":["react","reakit","reuse"],"created_at":"2024-08-01T22:03:11.578Z","updated_at":"2025-04-04T09:10:02.792Z","avatar_url":"https://github.com/diegohaz.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","*.js"],"sub_categories":["React"],"readme":"\u003cbr\u003e\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/diegohaz/reuse/master/branding/logo.png\" alt=\"reuse\" height=\"200\" /\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n  Reuse different React components to create new ones\u003cbr\u003e\n  \u003ca href=\"https://codesandbox.io/s/github/diegohaz/reuse/tree/master/examples/simple\"\u003e\u003cstrong\u003ePlay on CodeSandbox\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/diegohaz/reuse/master/branding/graphic.png\" height=\"350\" /\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://npmjs.org/package/reuse\"\u003e\u003cimg alt=\"NPM version\" src=\"https://img.shields.io/npm/v/reuse.svg?style=flat-square\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://david-dm.org/diegohaz/reuse\"\u003e\u003cimg alt=\"Dependencies\" src=\"https://img.shields.io/david/diegohaz/reuse.svg?style=flat-square\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://travis-ci.org/diegohaz/reuse\"\u003e\u003cimg alt=\"Build Status\" src=\"https://img.shields.io/travis/diegohaz/reuse/master.svg?style=flat-square\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/diegohaz/reuse/branch/master\"\u003e\u003cimg alt=\"Coverage Status\" src=\"https://img.shields.io/codecov/c/github/diegohaz/reuse/master.svg?style=flat-square\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Installation\n\n```sh\nnpm i reuse\n```\n\n\u003e Thanks to [@eldargab](https://github.com/eldargab) for the package name on npm.\n\n## Why\n\nThis enables **(sub)[atomic design](http://bradfrost.com/blog/post/atomic-web-design/)** approach.\n\nWhen using classic CSS, we have a powerful way to compose \"stylesheet components\" by applying multiple class names to our HTML elements (`.btn`, `.large`, `.rounded` etc.). But, by doing that in React, which has its own component structure, we'll have conflicting component structures.\n\n**Reuse** solves it by combining React components together as if they were CSS classes. This also means that not only style will be composed, but also JavaScript behavior, like React lifecycle methods and event handlers.\n\n## Usage\n\nReuse simply exports a factory method that returns a React component. You can leverage that method in two ways: [augmentation](#augmentation) and [combination](#combination).\n\n### Examples\n\n- [Simple](https://codesandbox.io/s/github/diegohaz/reuse/tree/master/examples/simple)\n- [PaperRoundedButton](https://codesandbox.io/s/github/diegohaz/reuse/tree/master/examples/paper-rounded-button)\n- [Styled Components](https://codesandbox.io/s/github/diegohaz/reuse/tree/master/examples/styled-components)\n\n### Augmentation\n\nThe component returned by the `use` factory will expect a `use` prop:\n\n```jsx\nimport use from \"reuse\";\n\nconst Box = use();\n\n\u003cBox /\u003e; // null\n\u003cBox use=\"div\" /\u003e; // \u003cdiv /\u003e\n\u003cBox use={Link} /\u003e; // \u003cLink /\u003e\n```\n\nYou can create the component with a default element:\n\n```jsx\nconst Box = use(\"div\");\n\n\u003cBox /\u003e; // \u003cdiv /\u003e\n\u003cBox use=\"span\" /\u003e; // \u003cspan /\u003e\n```\n\nYou can create the component with another component. **Just make sure to render the `use` prop as the underlying element and pass the other props down** (at least, when `use` isn't a string – HTML element):\n\n```jsx\nimport React from \"react\";\nimport use from \"reuse\";\n\n// grab the `use` prop and pass down other props\nconst Base = ({ use: T = \"div\", ...props }) =\u003e \u003cT {...props} /\u003e;\n\nconst Box = use(Base);\n\n\u003cBox /\u003e; // \u003cdiv /\u003e\n\u003cBox use=\"span\" /\u003e; // \u003cspan /\u003e\n\nconst BoxSpan = use(Box, \"span\");\n\u003cBoxSpan /\u003e; // \u003cspan /\u003e\n```\n\n\u003e You can use `Base` to filter custom props when `use` is a string using [@emotion/is-prop-valid](https://github.com/emotion-js/emotion/tree/master/next-packages/is-prop-valid), for example.\n\n### Combination\n\nLet's create some components:\n\n```jsx\n\n// Using styled-components\nconst Paper = styled(use(\"div\"))`\n  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.30);\n`;\n\n// Using class names\nconst Rounded = use(({ use: T, ...props }) =\u003e (\n  \u003cT\n    {...props}\n    className={`rounded ${props.className}`}\n  /\u003e\n), \"div\");\n\n// Using inline styles\nconst Button = use(({ use: T, ...props }) =\u003e (\n  \u003cT\n    {...props}\n    style={{\n      padding: \"0 1em\",\n      lineHeight: \"2.5em\",\n      background: \"#3f51b5\",\n      color: \"white\",\n      ...props.style\n    }}\n  /\u003e\n), \"button\");\n```\n\nOnce you have a few of those components, you can combine them using the same `use` methods:\n\n```jsx\nimport use from \"reuse\";\nimport { Rounded, Paper, Button } from \"../components\";\n\n// with factory\nconst RoundedPaperButton = use(Rounded, Paper, Button);\n\u003cRoundedPaperButton /\u003e; // \u003cbutton style=\"...\" class=\"...\" /\u003e\n\u003cRoundedPaperButton use=\"div\" /\u003e; // \u003cdiv style=\"...\" class=\"...\" /\u003e\n\n// with prop\n\u003cRounded use={[Paper, Button]} /\u003e // \u003cbutton style=\"...\" class=\"...\" /\u003e\n\u003cRounded use={[Paper, Button, \"div\"]} /\u003e // \u003cdiv style=\"...\" class=\"...\" /\u003e\n```\n\nNote that the underlying HTML element will always be based on the last component you pass to `use`.\n\n## FAQ\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eHow does this compare to render props and HOCs?\u003c/strong\u003e\u003c/summary\u003e\n\nThese are equivalent implementations:\n\n**Render props**\n```jsx\n\u003cPaper\u003e\n  {paperProps =\u003e (\n    \u003cRounded {...paperProps}\u003e\n      {roundedProps =\u003e (\n        \u003cButton {...roundedProps}\u003e\n          {buttonProps =\u003e (\n            \u003cbutton {...buttonProps}\u003eButton\u003c/button\u003e\n          )}\n        \u003c/Button\u003e\n      )}\n    \u003c/Rounded\u003e\n  )}\n\u003c/Paper\u003e\n```\n\n**High-order components**\n```jsx\nwithPaper(withRounded(withButton(props =\u003e \u003cbutton {...props}\u003eButton\u003c/button\u003e)));\n```\n\n**Reuse**\n```jsx\nuse(Paper, Rounded, Button);\n// or\n\u003cPaper use={[Rounded, Button]} /\u003e\n```\n\nWhen using render props or HOCs, you have to stick with their static (HOC) or dynamic implementation (render prop). With Reuse, besides simplicity, you can use both depending on your needs.\n\n\u003c/details\u003e\n\n\n## License\n\nMIT © [Haz](https://github.com/diegohaz)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiegohaz%2Freuse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiegohaz%2Freuse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiegohaz%2Freuse/lists"}