{"id":15673197,"url":"https://github.com/tuchk4/forgekit","last_synced_at":"2025-05-06T22:24:48.846Z","repository":{"id":57240147,"uuid":"71224876","full_name":"tuchk4/forgekit","owner":"tuchk4","description":"Forgekit — forge components with features","archived":false,"fork":false,"pushed_at":"2017-07-24T10:04:57.000Z","size":284,"stargazers_count":15,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-31T03:32:21.780Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/tuchk4.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":"2016-10-18T08:17:25.000Z","updated_at":"2019-07-28T17:57:24.000Z","dependencies_parsed_at":"2022-08-29T22:22:42.422Z","dependency_job_id":null,"html_url":"https://github.com/tuchk4/forgekit","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuchk4%2Fforgekit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuchk4%2Fforgekit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuchk4%2Fforgekit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuchk4%2Fforgekit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tuchk4","download_url":"https://codeload.github.com/tuchk4/forgekit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252777787,"owners_count":21802650,"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":[],"created_at":"2024-10-03T15:38:22.914Z","updated_at":"2025-05-06T22:24:48.785Z","avatar_url":"https://github.com/tuchk4.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003ca href=\"https://github.com/tuchk4/forgekit\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/tuchk4/forgekit/master/logo/forgekit-logo-small.png\"\u003e\u003c/a\u003e\n\n![Forgekit travis build](https://api.travis-ci.org/tuchk4/forgekit.svg?branch=master)\n\n**This project is still experimental, so feedback from component authors would be greatly appreciated!**\n\n\u003cimg src=\"http://i.imgur.com/ULoeOL4.png\" height=\"16\"/\u003e [Forgekit at Medium](https://medium.com/@valeriy.sorokobatko/forgekit-785eb17a9b50#.bo3ijxdbm)\n\n## Motivation\n\n[recompose](https://github.com/acdlite/recompose) had a great influence. It is great library that provide excellent way to lift state into functional wrappers, perform the most common React patterns, optimize rendering performance. Also it is possible to store common functions separately and share them between components. And as the result - component's source code become much more easier.\n\n\u003e recompose - React utility belt for function components and higher-order components. Think of it like lodash for React.\n\n# Forgekit\n\nProvide easier way to develop and manage component's features and inject them into the components.\n\n## Docs\n\n* \u003ca href=\"https://github.com/tuchk4/forgekit/blob/master/docs/api.md\"\u003eForgekit api\u003c/a\u003e\n* \u003ca href=\"https://github.com/tuchk4/forgekit/blob/master/docs/feature.md\"\u003eLittle theory. What is component feature?\u003c/a\u003e\n* \u003ca href=\"https://github.com/tuchk4/forgekit/blob/master/docs/theme.md\"\u003eForgekit theme managementing\u003c/a\u003e\n* \u003ca href=\"https://github.com/tuchk4/forgekit/blob/master/docs/forgekit-and-recompose.md\"\u003eForgekit and Recompose\u003c/a\u003e\n\n## Feature function signature as props middleware:\n\nDetailed information at \u003ca href=\"https://github.com/tuchk4/forgekit/blob/master/docs/feature.md\"\u003efeature api documentation\u003c/a\u003e\n\n```js\nFeature = function(props): newProps\nFeature.propTypes = {}\nFeature.defaultProps = {}\n```\n\n## Feature function signature as higher order component:\n\nDetailed information at \u003ca href=\"https://github.com/tuchk4/forgekit/blob/master/docs/feature.md\"\u003efeature api documentation\u003c/a\u003e. This useful when need to work with lifecycle methods.\n\n```js\nFeature = {\n  props: function(props): newProps,\n  hoc: function(Component: React.Component): function(props): React.Component\n}\n\nFeature.propTypes = {}\nFeature.defaultProps = {}\n```\n\n## Forgekit api\n\nDetailed information at \u003ca href=\"https://github.com/tuchk4/forgekit/blob/master/docs/api.md\"\u003eforgekit api documentation\u003c/a\u003e\n\nIn general it looks like props middleware.\nBut each feature also can implement a higher order component (usually for lifecycle methods).\n\n\u003cimg src=\"https://raw.githubusercontent.com/tuchk4/forgekit/master/docs/images/props-as-middleware.png\"\u003e\n\n```js\nimport forgekit from 'forgekit';\n\nforge(...features)(Component, displayName, bindProps)\n```\n\nForgedButton *propTypes* and *defaultProps* are merged from all features and origin component.\nAdditional explanation at [forgekit-comopnents#little-explanation](https://github.com/tuchk4/forgekit-components#little-explanation)\n\n```js\nForgedButton.propTypes = {\n  ...Button.propTypes,\n  ...Feature1.propTypes,\n  ...Feature2.propTypes\n}\n\nForgedButton.defaultProps = {\n  ...Button.defaultProps,\n  ...Feature1.defaultProps,\n  ...Feature2.defaultProps\n}\n```\n\nSo if you use [React Sotrybook](https://github.com/storybooks/react-storybook) with [storybook-addon-ifno](https://github.com/storybooks/react-storybook-addon-info) - it will show components props and default props correctly.\n\n## Feature examples\n\nFor example there is a `\u003cButton/\u003e` component with custom (high-level) props:\n\n\u003e More details about custom (high-level) and native (low-level) props at \u003ca href=\"https://github.com/tuchk4/forgekit/blob/master/docs/feature.md#high-level-and-low-level-props\"\u003efeature documentation\u003c/a\u003e\n\n* *alert: PropTypes.bool* - If true, component will have an alert styles\n* *icon: PropTypes.bool* - Value of the icon (See Font Icon Component).\n* *iconPosition: PropTypes.oneOf(['left', 'right'])* - Show icon form the left of right from label\n* *flat* - If true, the button will have a flat look.\n\nLet's find relations between custom (high-level) and native (low-level) props\n\n* *alert* - affects *style* or *className*. The same behaviour is for *flat* property.\n\n```js\nconst alertFeature = ({\n  alert,\n  style,\n  ...props\n}) =\u003e {\n  const alertStyles = alert ? {\n    color: 'red'\n  } : {};\n\n  return {\n    ...props,\n    style: {\n      ...(style || {}),\n      ...alertStyles\n    }\n  }\n};\n\nalertFeature.propTypes = {\n  alert: PropTypes.bool\n}\n```\n\n* *icon* - affects *children*  prop. Depending on *iconPosition* add `\u003cIcon/\u003e` to the *children*.\n\n```js\nconst iconFeature = ({\n  icon,\n  iconPosition,\n  children,\n  ...props\n}) =\u003e {\n\n  return {\n    ...props,\n    children: [\n      iconPosition == 'left' ? renderIcon(icon) : null,\n      children,\n      iconPosition == 'right' ? renderIcon(icon) : null,\n    ]\n  }\n}\n\niconFeature.propTypes = {\n  icon: PropTypes.string,\n  iconPosition: PropTypes.oneOf(['left', 'right']),\n}\n```\n\n## Develop features with lifecycle methods\n\nFor example it is not possible to implement *clickOutside* feature if there is not access to lifecycle methods. To implement this feature:\n\n* On *componentDidMount* - enable click outside listener\n* On *componentWillUnmount* - remove listener\n* get access to component's DOM element\n\nThis is possible with forgekit. Just define Feature as object:\n\n```js\nclass ClickOutside extends React.Component {\n  componentDidMount() {}\n\n  componentWillUnmount() {}\n\n  render() {\n    return this.props.children;\n  }\n}\n\nconst Feature = {\n  hoc: Component =\u003e {\n    return ({\n      onClickOutside,\n      ...props\n    }) =\u003e\n      return (\n        \u003cClickOutside onClickOutside={onClickOutside}\u003e\n          \u003cComponent {...props} /\u003e\n        \u003c/ClickOutside\u003e\n      );\n    }\n  }\n}\n```\n\n### Forgekit advantages\n\n### ...share common features between components\n\nThere are features that does not relate to certain component. They could be added into any component.\n\n* *clickOutside* - Fires when click outside of the component\n* *highliteFlags* - Depends on prop *primary* / *alert* / *danger* / *warning* - add styles to the component\n* *loaderOverlay* - If *loading* prop is true - show loader overlay above the component\n\n```js\nimport forgekit from 'forgekit';\n\nimport Button from 'components/button';\nimport Layout from 'components/layout';\n\nimport clickOutside from 'features/click-outside';\nimport highliteFlags from 'features/highlite-flags';\nimport loaderOverlay from 'features/loader-overlay';\n\n\nexport const AppButton = forgekit(clickOutside, highliteFlags)(Button);\nexport const AppLayout = forgekit(clickOutside, loaderOverlay)(Layout);\n```\n\nThere is one common feature - *clickOutside*.\n\nForged components `\u003cAppButton/\u003e` and `\u003cAppLayout/\u003e` accepts *onClickOutside* prop. But *onClickOutsided* is not duplicated at  `\u003cButton/\u003e` and `\u003cLayout/\u003e` *propTypes*. It is automatically added with *clickOutside* feature.\n\n* Feature could be shared between components and applications. So there is no code duplication.\n\n### ...use only needed features\n\nLook at any open source components library - each component has a lot of features and there are a lot of *propTypes*. For example component `\u003cButton/\u003e` has features:\n\n* *ripple* - If true, component will have a ripple effect on click.\n* *icon* - Value of the icon (See Font Icon Component).\n* *flat* - If true, the button will have a flat look.\n* *raised* - If true, the button will have a flat look.\n* *onMouseLeave* - \tFires after the mouse leaves the Component.\n* *inverse* - If true, the neutral colors are inverted. Useful to put a button over a dark background.\n\nA lot of more. And it is not possible to use only *icon* feature. All features implementations will be included to application build.\n\nForgekit allows to import only used features.\n\n```js\nimport forgekit from 'forgekit';\n\nimport Button from 'components/button';\n\nimport icon from 'button/features/icon';\nimport ripple from 'button/features/ripple';\n\nexport default forgekit(icon, ripple)(Button);\n```\n\n* No extra code at app build because you load only base component and forge it with needed features.\n\n### ...easier to refactor and support clean code\n\nAll needed features could be imported from separated modules. This is very helpful when you want to share your component features with another team, another application or just push them to Github and make them open source.\nAlso this provide good way to keep your code cleaner: just create new module and develop new functionality instead of patching existing modules. And same with refactoring - just remove imports if need to clean some old or unused features. This is much easier than remove large number of lines from components code and then make sure that all other features work correctly.\n\n* Easy to remove features — just remove feature import. Instead of removing number of lines from the component.\n* Easy to write and understand code — feature is a simple function\n* Code responsibility. Each feature — separated module and there is no extra code. Only feature implementation. Very boost code reading and understanding.\n\n### ...feature customization\n\nEach feature could be customized. Very similar with Redux middleware customization.\n\n```js\nimport fogekit from 'forgekit';\n\nimport icon from 'features/icon';\nimport highliteFlags from 'features/highlite-flags';\n\nconst Button = (children, ...props) =\u003e \u003cbutton {...props}\u003e{children}\u003c/button\u003e;\n\nconst customHighliting = highliteFlags({\n  alert: {\n    color: 'white',\n    fontWeight: 'bold'\n    background: 'red'\n  }\n});\n\nexport default forge(icon, customHighliting)(Button);\n```\n\n### ...sharing features in open source\n\nIf there is any open source component's library that was built with Forgekit - it is simple to contribute because developers does not need to understand its whole structure and work with all library. Just develop feature function with tests and push it. Or even push to own repository.\n\n### ...change component configuration\n\nExample: change `\u003cDropdown/\u003e` [configuration to declarative style](https://gist.github.com/tuchk4/a04f4d151e0654edb01f47cf0d11f7b3) instead of passing all via props.\nIt is very easy to add or remove this feature. Do not need to change components code.\n\n## Install\n\n```bash\nnpm install --save forgekit\n```\n\n## Suggested dev. env for component development\n\n* Use [Forgekit](https://github.com/tuchk4/forgekit) or [Recompose](https://github.com/acdlite/recompose). Especially for base components.\n* User [React storybook](https://getstorybook.io/) for documentation.\n* Write *README.md* for each component\n* Use Storybook [knobs addon](https://github.com/storybooks/storybook-addon-knobs)\n* Use Storybook [info addon](https://github.com/storybooks/react-storybook-addon-info). Because Forgekit merge features *propTypes* it work correctly with this addon.\n* Use Storybook [readme addon](https://github.com/tuchk4/storybook-readme)\n* Dont forget about [Creeping featurism](https://en.wikipedia.org/wiki/Feature_creep) anti-pattern that can ruin your components. With Forgekit it is much more easier to manage comopnents features.\n\n## Forgekit components library\n\nI will contribute to [Forgekit components library](https://github.com/tuchk4/forgekit-components):\n\n* Develop all base components and features for them\n* Add styles according to Google Material design\n* Components should be easily stylized to any other design without extra styles at application build\n\n## Nearest plans\n\nCreate Forgekit [react storybook](https://github.com/storybooks/react-storybook) plugin. Main goal - manage \u003ca href=\"https://github.com/tuchk4/forgekit/blob/master/docs/feature.md\"\u003efeatures\u003c/a\u003e and \u003ca href=\"https://github.com/tuchk4/forgekit/blob/master/docs/theme.md\"\u003ethemes\u003c/a\u003e\n\n* Show used features\n* Show available features\n* Show component and features documentation\n* Components Theme customizations\n\n\n## Feedback wanted\n\nForgekit is still in the early stages and even still be an experimental project. Your are welcome to submit issue or PR if you have suggestions! Or write me on twitter [@tuchk4](https://twitter.com/tuchk4).\n\n:tada:\n\n\n## Referenced issues\n\n* Webpack: [CSS resolving order](https://github.com/webpack/webpack/issues/215)\n* React: [Feature request - PropType.*.name](https://github.com/facebook/react/issues/8310)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuchk4%2Fforgekit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftuchk4%2Fforgekit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuchk4%2Fforgekit/lists"}