{"id":21669360,"url":"https://github.com/attack-monkey/hyperwrap","last_synced_at":"2026-04-15T16:03:45.643Z","repository":{"id":91874051,"uuid":"158600128","full_name":"attack-monkey/hyperwrap","owner":"attack-monkey","description":null,"archived":false,"fork":false,"pushed_at":"2018-12-13T22:16:13.000Z","size":16,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-01-25T08:44:01.075Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/attack-monkey.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":"2018-11-21T20:03:21.000Z","updated_at":"2018-12-13T22:16:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"da74134b-75a5-495e-be52-7cfe50a2440e","html_url":"https://github.com/attack-monkey/hyperwrap","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/attack-monkey%2Fhyperwrap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/attack-monkey%2Fhyperwrap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/attack-monkey%2Fhyperwrap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/attack-monkey%2Fhyperwrap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/attack-monkey","download_url":"https://codeload.github.com/attack-monkey/hyperwrap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244570253,"owners_count":20474016,"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-11-25T12:21:15.312Z","updated_at":"2025-10-15T01:55:49.967Z","avatar_url":"https://github.com/attack-monkey.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Meet hyperwrap\n\nHyperwrap (inspired by hyperapp) turns react into a simple to use **functional framework**.\n\n# A few notes\n\n- In Hyperwrap there is no local state and no class components to worry about.\n- Hyperwrap makes global state management simple.\n- Hyperwrap is written in **typescript**.\n\n# Install\n\nThe easiest way to get going is to install the seed project using `douglas`.  \ndouglas installs npm modules as ready to roll projects...\n\nIf you don't have douglas, install globally with `npm i -g douglas`\n\nInstall hyperwrapped-react (seed project)\n\n```\n\ndouglas get hyperwrapped-react\n\n```\n\n# Start\n\n\u003e If you haven't used parcel-bundler before, then install globally with `npm i -g parcel-bundler` ... then ...\n\n```\n\nnpm start\n\n```\n\n# Basics\n\nHyperwrap is an `app` function that wraps around React.  \nWhen Hyperwrap's state changes - it rerenders React.\n\nA typical entry index.tsx looks like...\n\n```javascript\n\nimport { app } from \"hyperwrap\";\nimport { initialState } from \"./src/state/state\";\nimport { View } from \"./src/components/view/view.component\";\n\napp(initialState, View, document.getElementById('app'));\n\n```\n\n\u003e initialState is just a plain js object.  \n\u003e View is just a plain React functional component\n\nLet's say our initialState is ...\n\n```\n\n{\n    thing: 'not bob',\n    anotherThing: 'something else'\n}\n\n```\n\nThe following component illustrates how to interact with state using `getState` and `updateState`...\n\n```javascript\n\nimport * as React from 'react';\nimport { State } from '../../../state/state';\nimport { getState, updateState } from 'hyperwrap';\n\nexport const Home = () =\u003e {\n\n    const changeThing = (e: any, thing: string) =\u003e { updateState('thing', thing); };\n    return (\n        \u003cdiv\u003e\n            \u003cp\u003e{getState().thing}\u003c/p\u003e\n            \u003cbutton onClick={(e) =\u003e {changeThing(e, 'bob')} }\u003epush\u003c/button\u003e\n        \u003c/div\u003e\n    );\n};\n\n```\n\n\u003e Note that even though we update `state.thing` to 'bob', `state.anotherThing` remains unaffected.\n\n# Making the above pure and testable\n\n- We've moved `changeThing` to it's own module\n- We've made `state` and `actions` as optional props to our functional component.\n- We've set default values for `state` and `actions`.\n\n_This lets us to inject mock values for state and actions, for easier testing + now it's a pure function_\n\n```javascript\n\nimport * as React from 'react';\nimport { State } from '../../../state/state';\nimport { getState } from 'hyperwrap';\nimport { changeThing } from './change-thing.function';\n\n\ninterface Props {\n    state?: State;\n    actions?: { [key: string]: any }\n}\n \nconst actionsCollection = {\n    changeThing: changeThing\n}\n \nexport const Home = (\n    {state, actions}: Props = {\n        state: getState(),\n        actions: actionsCollection\n    }\n) =\u003e {\n    const _state = state || getState();\n    const _actions = actions || actionsCollection;\n    return (\n        \u003cdiv\u003e\n            \u003cp\u003e{_state.thing}\u003c/p\u003e\n            \u003cbutton onClick={(e) =\u003e {_actions.changeThing(e, 'bob')} }\u003epush\u003c/button\u003e\n        \u003c/div\u003e\n    );\n};\n\n```\n\n# Updating State (Advanced)\n\nTo update state, specify the node in the state object to update, followed by the value.\n\n```javascript\n\nupdateState('deep/nested/thing', newValue);\n\n```\n\n**Adding nodes** - Use the above. If parent nodes aren't created yet, they will be created for you.\n\n**Deleting nodes** - Make the `newValue` undefined. Any parent nodes will also be removed if they do not have children.\n\n## Updating without rerendering\n\nBy default hyperwrap rerenders an app on state change.\n\nThere will be times however where this is not ideal.\n\nInstead pass the  `{ rerender: false }` flag to stop the app from rerendering...\n\n```javascript\n\nupdateState('deep/nested/thing', newValue, {rerender: false});\n\n```\n\n## Updating multiple nodes at once\n\nThe following can be used to update multiple state nodes, before re-rendering...\n\n```javascript\n\nupdateMulti([\n  { node: 'deep/nested/thing', updateValue: newValue1 },\n  { node: 'another/deep/nested/thing', updateValue: newValue2 }\n]);\n\n```\nAgain, if you don't want to rerender after the state updates - pass the `{ rerender: false }` flag.\n\ne.g.\n\n```javascript\n\nupdateMulti([\n  { node: 'deep/nested/thing', updateValue: newValue1 },\n  { node: 'another/deep/nested/thing', updateValue: newValue2 }\n], {\n  rerender: false\n});\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fattack-monkey%2Fhyperwrap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fattack-monkey%2Fhyperwrap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fattack-monkey%2Fhyperwrap/lists"}