{"id":13826498,"url":"https://github.com/WebReflection/neverland","last_synced_at":"2025-07-09T00:33:45.620Z","repository":{"id":57310489,"uuid":"156007015","full_name":"WebReflection/neverland","owner":"WebReflection","description":"React like Hooks for lighterhtml","archived":false,"fork":false,"pushed_at":"2021-01-29T13:49:33.000Z","size":1092,"stargazers_count":244,"open_issues_count":2,"forks_count":7,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-11-15T21:13:57.745Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://medium.com/@WebReflection/neverland-the-hyperhtmls-hook-a0c3e11324bb","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WebReflection.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}},"created_at":"2018-11-03T17:28:22.000Z","updated_at":"2024-02-08T19:49:56.000Z","dependencies_parsed_at":"2022-09-10T01:11:39.176Z","dependency_job_id":null,"html_url":"https://github.com/WebReflection/neverland","commit_stats":null,"previous_names":[],"tags_count":92,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fneverland","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fneverland/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fneverland/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebReflection%2Fneverland/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WebReflection","download_url":"https://codeload.github.com/WebReflection/neverland/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225476383,"owners_count":17480215,"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-08-04T09:01:39.085Z","updated_at":"2024-11-20T05:30:48.395Z","avatar_url":"https://github.com/WebReflection.png","language":"JavaScript","readme":"# Neverland 🌈🦄\n\n[![Build Status](https://travis-ci.com/WebReflection/neverland.svg?branch=master)](https://travis-ci.com/WebReflection/neverland) [![Greenkeeper badge](https://badges.greenkeeper.io/WebReflection/neverland.svg)](https://greenkeeper.io/)\n\n![Cosmic Timetraveler](img/cosmic-timetraveler-unsplash-1080.jpg)\n\u003csup\u003e**Photo by [Cosmic Timetraveler](https://unsplash.com/photos/1rmtbFGjIBs?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText) on [Unsplash](https://unsplash.com/search/photos/island?utm_source=unsplash\u0026utm_medium=referral\u0026utm_content=creditCopyText)**\u003c/sup\u003e\n\n\n### 📣 Community Announcement\n\nPlease ask questions in the [dedicated discussions repository](https://github.com/WebReflection/discussions), to help the community around this project grow ♥\n\n---\n\n**Update** if you're looking for something even smaller than _neverland_, don't miss [µland](https://github.com/WebReflection/uland#readme)!\n\n- - -\n\n## Hooks via lighterhtml\n\n```js\nimport {Component, render, html, useState} from 'neverland';\n\nconst Counter = Component((initialState) =\u003e {\n  const [count, setCount] = useState(initialState);\n  return html`\n  \u003cbutton onclick=${() =\u003e setCount(count + 1)}\u003e\n    Count: ${count}\n  \u003c/button\u003e`;\n});\n\n// basic example, show two independent counters\nrender(document.body, html`\n  \u003cdiv\u003e\n    A bounce of counters.\u003chr\u003e\n    ${Counter(0)} ${Counter(1)}\n  \u003c/div\u003e\n`);\n```\n\n\n### Concept\n\nAs [React Hooks](https://reactjs.org/docs/hooks-intro.html) were born to simplify some framework pattern, _Neverland_ goal is to simplify [lighterhtml](https://github.com/WebReflection/lighterhtml) usage, in a virtual component way, through the mighty [dom-augmentor](https://github.com/WebReflection/dom-augmentor).\n\n\u003csup\u003eSee what I did there? _React_ components' hooks are based on virtual DOM while neverland's hooks are based on virtual components.\u003c/sup\u003e\n\nThis library simulates Custom Elements, without needing polyfills, simply by passing zero, one, or more arguments to every desired components in each template literal hole.\n\n```js\n// if you don't need hooks, you don't need to wrap components\nconst LinkLi = ({text, href}, highlighted) =\u003e html`\n  \u003cli class=${highlighted}\u003e\n    see \u003ca href=\"${href}\"\u003e${text}\u003c/a\u003e\n  \u003c/li\u003e\n`;\n\n// some container with some click logic that uses hooks: $(wrap it)\nconst Links = $((items) =\u003e {\n  const [clicked, changeState] = useState(-1);\n  const onclick = useCallback(event =\u003e {\n    const li = event.target.closest('li');\n    changeState(\n      // changeState accordingly to the clicked index\n      [].indexOf.call(event.currentTarget.children, li)\n    );\n  }, []);\n  return html`\n  \u003cul onclick=${onclick}\u003e\n    ${items.map(\n      (item, i) =\u003e LinkLi(item, i === clicked ? 'highlight' : '')\n    )}\n  \u003c/ul\u003e`;\n});\n\n// render components within an element\nrender(document.body, html`\n  List of links:\n  ${Links([\n    {text: 'blog', href: 'www.blog.me'},\n    {text: 'bio', href: 'www.bio.me'},\n  ])}\n`);\n```\n\n\n### Available Renders\n\nBoth `html` and `svg` renders are exposed via the `neverland` module, and you must use the `render` utility\n\n\n\n### Available Hooks\n\nAll hooks are provided by [augmentor](https://github.com/WebReflection/augmentor#available-hooks), via [dom-augmentor](https://github.com/WebReflection/dom-augmentor) that takes care or injecting life-cycle DOM events when `useEffect` is used.\n\n  * **Basic Hooks**\n    * [useState](https://reactjs.org/docs/hooks-reference.html#usestate)\n    * [useEffect](https://reactjs.org/docs/hooks-reference.html#useeffect)\n    * [useContext](https://reactjs.org/docs/hooks-reference.html#usecontext), which can be defined via `createContext(value)`\n  * **Additional Hooks**\n    * [useReducer](https://reactjs.org/docs/hooks-reference.html#usereducer)\n    * [useCallback](https://reactjs.org/docs/hooks-reference.html#usecallback)\n    * [useMemo](https://reactjs.org/docs/hooks-reference.html#usememo)\n    * [useRef](https://reactjs.org/docs/hooks-reference.html#useref)\n    * [useLayoutEffect](https://reactjs.org/docs/hooks-reference.html#uselayouteffect)\n\n\n\n#### About `useImperativeHandle`\n\nThis hook is strictly _React_ oriented with no meaning in current _dom-augmentor_ world.\n\n\n\n### When should I wrap components, as in `const Comp = $(() =\u003e html...)`?\n\nEvery time you wrap a component you grant yourself the used hooks within would run specifically for that component.\n\nHowever, if you create an extra hook, or your callback doesn't return either `html` or `svg` result, **you don't need to wrap it**.\n\nA simple rule of thumbs to know when a component should be wrapped or not is the following one:\n\n  * does this function/callback/arrow returns `html` or `svg` templates tag literals?\n  * if previous point is true, am I using any sort of direct, or composed, hook within such function, so that I want its state/results to be confined in the returned element, instead of side-effecting outer wrappers?\n\nIf the answer to both points is **yes**, then you should wrap the callback, otherwise, you most likely shouldn't.\n\nThis little thinking is currently needed due the fact there's no parsing or pre-processing in _neverland_, so that such wrapping cannot be done automatically for you, when needed.\n\nYou can still decide to wrap any callback that returns `html` or `svg` templates tag literals results, but that might have performance implication in larger projects.\n\n\n\n### How To ...\n\nCommon ways via bundlers or CDNs:\n\n  * globally, as `const {neverland: $, render, html, useState} = window.neverland` through _script_ with source `https://unpkg.com/neverland`\n  * CJS via `const {neverland: $, render, html, useState} = require('neverland')`\n  * ESM with bundlers via `import {neverland as $, render, html, useState} from 'neverland'`\n  * pure ESM via `import {neverland as $, render, html, useState} from 'https://unpkg.com/neverland?module'`\n\nIf you use a bundler you can simply install `neverland` via npm or yarn.\n\nIt is also possible to use it in browsers via https://unpkg.com/neverland:\n\n```js\n// you can import it in any scope\nconst {neverland, html, useState} = window.neverland;\nconst VirtualComp = neverland(...);\n\n// or ...\nconst {neverland:$, html} = neverland;\nconst VirtualComp = $(...);\n```\n\n\n## V3 Features / Breaking Changes\n\n  * no more unnecessary DOM trashes 🎉\n  * it is possible to have keyed results, when necessary, via `html.for(ref[, id])` or `svg.for(ref[, id])`\n  * the usage of `render` is **mandatory**, no more DOM nodes out of the box\n\n\n\n## V2 Breaking Changes\n\n  * there is no default exported, but `neverland` named export\n  * there are still more DOM trashes than desired, but it works, and the DX is awesome, as well as performance anyway 😊\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FWebReflection%2Fneverland","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FWebReflection%2Fneverland","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FWebReflection%2Fneverland/lists"}