{"id":13725349,"url":"https://github.com/ennisj9/htmf","last_synced_at":"2025-05-07T20:32:06.242Z","repository":{"id":36461325,"uuid":"224956596","full_name":"ennisj9/htmf","owner":"ennisj9","description":"Hypertext Markup Function. Express HTML/DOM trees using native javascript.","archived":false,"fork":false,"pushed_at":"2023-01-05T02:05:40.000Z","size":2103,"stargazers_count":3,"open_issues_count":19,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-10-12T15:52:35.653Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/ennisj9.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}},"created_at":"2019-11-30T03:57:36.000Z","updated_at":"2021-03-11T14:14:48.000Z","dependencies_parsed_at":"2023-01-17T01:41:10.045Z","dependency_job_id":null,"html_url":"https://github.com/ennisj9/htmf","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/ennisj9%2Fhtmf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ennisj9%2Fhtmf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ennisj9%2Fhtmf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ennisj9%2Fhtmf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ennisj9","download_url":"https://codeload.github.com/ennisj9/htmf/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224401351,"owners_count":17304946,"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-03T01:02:20.239Z","updated_at":"2024-11-14T15:31:13.984Z","avatar_url":"https://github.com/ennisj9.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# HTMF\n\nHTMF (Hypertext Markup Function) is a method for constructing HTML or DOM trees using native javascript. It looks something like this:\n\n```javascript\nimport { toString } from 'htmf';\n\ntoString($ =\u003e { $\n  .a('html')\n    .b('head')\n    .b('body')\n      .c('h1').text('Hello World')\n      .c('span').text('HTMF can express:')\n      .c('ul')\n        .d('li .first').text('classes')\n        .d('li #second').text('ids')\n        .d('li')\n          .e('a', {href: 'google.com'}).text('and attributes')\n})\n```\nwhich creates\n```html\n\u003chtml\u003e\n  \u003chead\u003e\u003c/head\u003e\n  \u003cbody\u003e\n    \u003ch1\u003eHello World\u003c/h1\u003e\n    \u003cspan\u003eHTMF can express:\u003c/span\u003e\n    \u003cul\u003e\n      \u003cli class=\"first\"\u003eclasses\u003c/li\u003e\n      \u003cli id=\"second\"\u003eids\u003c/li\u003e\n      \u003cli\u003e\n        \u003ca href=\"google.com\"\u003eand attributes\u003c/a\u003e\n      \u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n\n```\nHTMF has different implementations for different frameworks and environments:\n\n|Framework|Module|\n|---|---|\n| Vue | [brue](https://www.npmjs.com/package/brue) |\n| React | [htmf-react](https://www.npmjs.com/package/htmf-react) |\n\n\nThis module is intended to be used as a starting step for an implentation that will add features and/or tie into a framework.\n\n## How it works\n\nHTMF accepts a function that it will pass a \"builder\" (``$``). The builder has the functions ``a`` through ``z`` which can be used to create a node. The node's place in the tree is expressed by the letter used. ``b`` nodes are children of the last ``a`` node, etc. This is made more clear by properly indenting the nodes. Every builder method returns itself, which allows the chaining of calls.\n\nNodes accept any number of arguments, and string arguments separated by spaces are treated as separate arguments:\n\n- Strings with no prefix indicate the element type\n- Strings with ``.`` prefix indicate a class\n- Strings with ``#`` prefix indicate the id\n- Objects that are not the first argument indicate attributes\n\nAnd in special cases:\n- Functions indicate the element type (imagine a component class in React)\n**note** - this now works with included `toString()` method [as well](#toString) \n- Objects placed as the first argument indicate the element type (a Vue component for instance)\n\nSo the following two builds are equivalent:\n```javascript\n$.a('div')\n  .b('div .someclass .green #id', {onclick: 'script', title: 'tooltip'})\n```\n```javascript\n$.a('div')\n  .b('div', '.someclass','.green','#id', {onclick: 'script'}, {title: 'tooltip'})\n```\nwhich creates:\n```html\n\u003cdiv\u003e\n  \u003cdiv class=\"someclass green\" id=\"id\" onclick=\"script\" title=\"tooltip\"\u003e\u003c/div\u003e\n\u003c/div\u003e\n```\n### Node modifiers\n\nNode modifers are other functions of the builder besides ``a`` through ``z``. They will always modify the last designated node. The core HTMF module only has the ``.text()`` node modifier. \n\n### Text nodes\n\nExpressing text nodes (no element) can be done in a number of ways:\n```javascript\n$.a('div').text('some text')\n$.a('div')\n  .b().text('some text')\n$.a('div')\n  .b(String, 'some text')\n```\nAll equivalent. As you can see, passing the global String constructor as the first argument of a node will break from the normal parsing of node arguments and create a text node using the second argument.\n\n### Single node shorthand\n\nPassing an array instead of a function to an HTMF implementation is an easy way to create a single node. The second argument can be used to add a text node:\n\n```javascript\nMf.toString(['a .someclass',{href: 'google.com'}], 'A link to google')\n```\nwill create ``\u003ca href=\"google.com\"\u003eA link to google\u003c/a\u003e``\n\n## Api\n\n### .process(buildFunction, nodeModifiersObject:optional, ...furtherArgs)\n\nHTMF.process() is intended to be used by other HTMF implementations. It returns an array of the root nodes of a tree created by the buildFunction. Any futher arguments will be passed to the build function, An example of the node structure:\n\n```javascript\n{\n  element: 'div',\n  classes: ['link','green'],\n  attributes: {id: 'greenlink'},\n  children: []\n}\n//or a text node:\n{\n  element: null,\n  classes: [],\n  attributes: {},\n  children: [],\n  text: 'some text'\n}\n```\nAn example showing a node modifiers object:\n```javascript\nimport { process } from HTMF;\n\nconst api = {\n  click: (node, func) =\u003e {\n    node.attributes.onClick = func;\n  },\n  hide: node =\u003e {\n    node.attributes.style = \"display: none;\"\n  }\n}\nconst roots = process($ =\u003e { $\n  $.a('div')\n    .b('div .hidden').hide()\n    .b('div .button').click(() =\u003e { console.log('clicked!') }) \n}, api);\n```\n\n### \u003ca id=\"toString\"\u003e\u003c/a\u003e.toString(buildFunction) \n\nAn implenetation of HTMF using ``.process()``. It returns an html string created with the buildFunction. Besides just simple HTML elements, it can handle \"component functions\" as well (similiar to react)\n\nHere's an example:\n```javascript\nlet innerComponent = params =\u003e {\n  let timesTwo = params.value * 2;\n  return $ =\u003e { $\n    .a('div .inner')\n      .b('p').text(`twice the value: ${timesTwo}`)\n  }\n}\n\nlet outterComponent = params =\u003e {\n  return $ =\u003e { $\n    .a('div .outer')\n      .b(innerComponent, {value: params.count})\n      .b('div').text('after')\n  }\n}\n\ntoString(outterComponent({count: 2}));\n```\nwould create\n```html\n\u003cdiv class=\"outer\"\u003e\n  \u003cdiv class=\"inner\"\u003e\n    \u003cp\u003etwice the value: 4\u003c/p\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003eafter\u003c/div\u003e\n\u003c/div\u003e\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fennisj9%2Fhtmf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fennisj9%2Fhtmf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fennisj9%2Fhtmf/lists"}