{"id":19451131,"url":"https://github.com/thekashey/react-gearbox","last_synced_at":"2025-04-25T04:30:22.664Z","repository":{"id":66140833,"uuid":"135794186","full_name":"theKashey/react-gearbox","owner":"theKashey","description":"⚙️📦 Gearbox - Renderless state provisioning and composition","archived":false,"fork":false,"pushed_at":"2019-03-06T00:48:18.000Z","size":204,"stargazers_count":30,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-19T15:53:29.227Z","etag":null,"topics":["compose","fractal","react","render-props"],"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/theKashey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-06-02T06:36:54.000Z","updated_at":"2022-11-21T08:55:06.000Z","dependencies_parsed_at":"2023-07-07T16:01:37.919Z","dependency_job_id":null,"html_url":"https://github.com/theKashey/react-gearbox","commit_stats":{"total_commits":30,"total_committers":1,"mean_commits":30.0,"dds":0.0,"last_synced_commit":"f99e75d4a01a0a4cfc07a1ca08f34116f9ea0f8a"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2Freact-gearbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2Freact-gearbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2Freact-gearbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2Freact-gearbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theKashey","download_url":"https://codeload.github.com/theKashey/react-gearbox/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250754501,"owners_count":21481823,"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":["compose","fractal","react","render-props"],"created_at":"2024-11-10T16:40:19.946Z","updated_at":"2025-04-25T04:30:22.368Z","avatar_url":"https://github.com/theKashey.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"⚙️📦 GearBox \n=======\n[![Build Status](https://travis-ci.org/theKashey/react-gearbox.svg?branch=master)](https://travis-ci.org/theKashey/react-gearbox)\n[![coverage-badge](https://img.shields.io/codecov/c/github/thekashey/react-gearbox.svg?style=flat-square)](https://codecov.io/github/thekashey/react-gearbox)\n[![NPM version](https://img.shields.io/npm/v/react-gearbox.svg)](https://www.npmjs.com/package/react-gearbox)\n\n\nComposes renderless containers and manages them in afterlive. \nHeavily inspired by [react-adopt](https://github.com/pedronauck/react-adopt)(context compose),\n [react-powerplug](https://github.com/renatorib/react-powerplug)(renderless containers)\n and [redux-restate](https://github.com/theKashey/restate)(fractal state).\n\nThe purpose of this library is\n - (torque) combine \"container\"(plugs, context, states), to form more complex structure (gearbox).\n - (transmission) provide a way to access them down the tree (train).\n - (gear train) provide a way to alter their work (transmission).\n\nThat's why - gearbox\n\n# API\n\n```js\nimport {gearbox} from 'react-gearbox';\n\n// consume any \"headless\" component\nconst State = gearbox({\n   name: \u003cValue initial=\"Bruce Wayne\" /\u003e,\n   nick: \u003cValue initial=\"Batman\" /\u003e,\n   team: \u003cUnstatedContainer /\u003e,\n   enemies: Context.Consumer\n});\n\n// create state and access via renderprops\n\u003cState render\u003e\n  {({nick}) =\u003e \u003cspan\u003ecos I am {nick.value}\u003c/span\u003e}\n\u003c/State\u003e\n\n// create state, and access it later using train\n\u003cState\u003e\n  \u003cspan\u003ecos I am \u003cState.train\u003e{({nick}) =\u003e nick.value}\u003c/State.train\u003e\u003c/span\u003e\n\u003c/State\u003e\n\n// unwrap powerplug using transmission\n\u003cState\u003e\n  \u003cState.transmission clutch={({nick}) =\u003e ({nick: nick.value})}\u003e\n    \u003cspan\u003ecos I am \u003cState.train\u003e{({nick}) =\u003e nick}\u003c/State.train\u003e\u003c/span\u003e\n  \u003c/State.transmission\u003e\n\u003c/State\u003e\n``` \n\n* `gearbox(gears, options?): Gearbox` - creates a Gearbox component. Where\n * `gears` is a shape of different _render-prop-ish_ components, for example:\n      - ReactElements, or \n      - FunctionalStatelessComponents, or \n      - Context.Consumers.\n  \n  * `options` is an optional field.\n      - options.transmission(input, props) =\u003e output - build in transmission, to be applied on gears.\n      - options.defaultProps - set default props for a future component (note: defaultProps are not reflected on types, PR welcomed)\n\nProduces a `Gearbox` - renderless container, which will provide _torque_ from all gears as a render prop.\n\n* `transmission(gearboxIn, clutch): Gearbox` - created a devired Gearbox, with \"clutch\" function applied to all stored data. \nleftMenuController: \u003cToggle initial={} /\u003e,\n   topMenuController: \u003cToggle initial={} /\u003e,\n   toggler: gear(Toggle, { initial: {} }), // ~ \u003cToggle initial={} children={mock} /\u003e\n`Gearbox` is a compound component, and includes 2 sub components\n* Gearbox.train - _React Context_ based long-range torque provider, which will provide access to the parent Gearbox from the nested components.\n* Gearbox.transmission - establish a local (declarative) transmission. Might not be type safe.\n\n`Gearbox` has only one prop - `render`, if not set - children is a ReactNode. If set - renderProp(function as a children)\n\n`gear(component, props)` - a small helper to create elements, without mocking `children` prop \n \n## Rules\n - `Gearboxes` are used to combine gears together, and put them into context.\n - `trains` - to access distant gearbox.\n - `transmission` - to adapt data structure for the local needs.\n \n## Adaptation\n Gearbox could merge output from different component using the keys as names.\n But sometimes you need a bit another structure, for example - just rename fields.\n```js\nimport {gearbox, gear} from 'react-gearbox';\nimport {Toggle} from 'react-powerplug';\n\n const Gearbox = gearbox({   \n   \n  }, {\n   transmission: ({leftMenuController, topMenuController}) =\u003e ({\n     isLeftMenuOpen: leftMenuController.value,\n     isTopMenuOpen: topMenuController.value,\n     \n     toggleLeftMenuOpen: leftMenuController.toggle,\n     toggleTopMenuOpen: topMenuController.toggle     \n   })\n  });\n```  \n\nIn the same way - you can create a new Components\n\n```js\n const Switch = gearbox({   \n   toggle: props =\u003e \u003cToggle {...props} /\u003e,\n  }, {\n   transmission: ({toggle}) =\u003e ({\n     enabled: toggle.on,\n     switch: toggle.toggle     \n   }),\n   defaultProps: {\n     render: true, // render props as default\n     local: false,  // no context support,\n     pure: true, // behaves as a pure component (or readux-connect)\n   }\n  });\n\n// new component adopted!\n\u003cSwitch initial={true}\u003e\n {({enabled, switch}) =\u003e ... }\n\u003c/Switch\u003e\n``` \n\nThe same technique could be used to achieve the same results as recompose's `withHandlers`\n\u003e While gearbox itself is `withState`.  \n\n# Observed bits\nGearbox utilizes React.Context `observerBits` feature, not calling `Trains` if data they consume not changed.\nWith `pure` option enabled this gives you fine control over update propagation flow.\n\nYou may opt-out by using `Gearbox.directTrain`.\n```js\n\u003cGear.train\u003e{({value1}) =\u003e \u003cb\u003ewill only update, when \"value1\" got updated\u003c/span\u003e}\u003c/Gear.train\u003e\n\u003cGear.directTrain\u003e{({value1}) =\u003e \u003cb\u003ewill update on any GearBox update\u003c/span\u003e}\u003c/Gear.directTrain\u003e\n```\n\n# Debugging\n\n Gearbox also provides a _fancy_ debugging. Just double check React Dev Tools.\n \n In addition:\n  - setDebug(boolean | function) - enableds low-level debug.\n\n \n# Examples\n\n1. Create a gearbox  \n```js\n import {gearbox} from 'react-gearbox';\n import {Value, Toggle} from 'react-powerplug';\n \n \n const Gearbox = gearbox({\n   // pass a pre-created Element, as you could do with react-adopt\n   storedValue: \u003cValue initial={42} /\u003e,\n   \n   // pass component, to initialize Element from props (applied only on mount)\n   toggle: props =\u003e \u003cToggle initial={props.on} /\u003e,\n   \n   // pass React.Context\n   data: reactContext.Consumer as any, // !! \"pure\" consumers are not \"type safe\"\n   \n   // or pass it as React.Element\n   context: \u003creactContext.Consumer children={null}/\u003e,\n\n   // you may access all the gearings from above\n   smartComponent: (props, {data, context} /* all the props from above*/) =\u003e \u003cOtherRenderProp /\u003e\n   \n   // Unstated container? Anything \"render-prop\" capable will work.\n   stated: \u003cUnstatedContainer /\u003e,\n }); \n```\n\n2. Use Gearbox with or without renderprops \n\nBy default Gearbox __expects ReactNode as a children__, and data to be accessed via `train`, but you may specify `render` prop, to change this behavior to function-as-children. \n\n\u003e `render` stands for renderProps, `on` is required by `toggle`, so required by Gearbox\n ```js\n const App = () =\u003e (\n     \u003cGearbox on render\u003e\n        {({storedValue, toggle, data, stated}) =\u003e \u003cdiv\u003e...\u003c/div\u003e}\n     \u003c/Gearbox\u003e\n )\n \n const App = () =\u003e (\n      \u003cGearbox on\u003e\n         \u003cdiv\u003e...\u003c/div\u003e\n      \u003c/Gearbox\u003e\n  )\n ```\n3. Use Gearbox.train to get the data\n```js \n // once Gearbox is assembled - you can access it elsewhere using gear trains\n \n const Children = () =\u003e (\n      \u003cGearbox.train\u003e\n         {({storedValue, toggle, data, stated}) =\u003e \u003cdiv\u003e...\u003c/div\u003e}\n      \u003c/Gearbox\u003e\n  )\n```\n\n4. Use Gearbox.transmission to adopt the data   \n```js  \n // component based Transmission are NOT type safe\n const Transmission = () =\u003e (\n     \u003cGearbox.transmission \n       clutch={({toggle, data}) =\u003e ({on:toggle.on, toggle: data.toggle})}\n     \u003e\n         \u003cGearbox.train\u003e {/* you may use \u003cGearbox.train_untyped\u003e */ }\n             {({on, toggle}) =\u003e \u003cdiv\u003e...\u003c/div\u003e}\n         \u003c/Gearbox.train\u003e\n     \u003c/Gearbox.transmission\u003e\n )\n \nconst Transmission = () =\u003e (\n     \u003cGearbox.transmission \n       clutch={({toggle, data}) =\u003e ({on:toggle.on, toggle: data.toggle})}\n       render /* use as render prop */\n     \u003e         \n             {({on, toggle}) =\u003e \u003cdiv\u003e...\u003c/div\u003e}\n     \u003c/Gearbox.transmission\u003e\n )\n```\n\n4. Use transmission to achieve type safe transmission.\n```js\nconst TransmittedGear = transmission(Gearbox, ({toggle, data}) =\u003e ({on:toggle.on, toggle: data.toggle}));\n```\n  \n# Licence\n MIT\n  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthekashey%2Freact-gearbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthekashey%2Freact-gearbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthekashey%2Freact-gearbox/lists"}