{"id":25076216,"url":"https://github.com/zeixcom/pulse","last_synced_at":"2025-03-31T22:43:18.820Z","repository":{"id":261426227,"uuid":"883733336","full_name":"zeixcom/pulse","owner":"zeixcom","description":"Pulse - scheduled DOM updates","archived":false,"fork":false,"pushed_at":"2025-01-20T13:25:09.000Z","size":28,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-14T01:47:18.551Z","etag":null,"topics":["dom","dom-manipulation","pulse","requestanimationframe"],"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/zeixcom.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-05T13:34:04.000Z","updated_at":"2025-01-20T13:25:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"8559903b-bc28-4ae0-ba98-ccbed547d88f","html_url":"https://github.com/zeixcom/pulse","commit_stats":null,"previous_names":["efflore/pulse","zeixcom/pulse"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zeixcom%2Fpulse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zeixcom%2Fpulse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zeixcom%2Fpulse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zeixcom%2Fpulse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zeixcom","download_url":"https://codeload.github.com/zeixcom/pulse/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246552893,"owners_count":20795836,"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":["dom","dom-manipulation","pulse","requestanimationframe"],"created_at":"2025-02-07T01:34:47.189Z","updated_at":"2025-03-31T22:43:18.800Z","avatar_url":"https://github.com/zeixcom.png","language":"TypeScript","readme":"# Pulse\n\nVersion 0.9.3\n\n**Pulse** – scheduled DOM updates, debounced with requestAnimationFrame\n\n## Key Features\n\n* **Optimized DOM Scheduler**: Coordinate and batch DOM updates using `requestAnimationFrame` for smoother interactions.\n* **Predefined DOM Updates**: Utilize bundled functions for common DOM manipulations.\n* **Non-Blocking Await**: Yield control back to the browser in async functions with `await animationFrame()`.\n\n## Installation\n\n```bash\n# with npm\nnpm install @zeix/pulse\n\n# or with bun\nbun add @zeix/pulse\n```\n\n## Basic Usage\n\n### Enqueue DOM Updates\n\nAdd instructions to update the DOM to the scheduler with `enqueue()`. The first argument is the callback function to be executed before the next screen refresh with `requestAnimationFrame()`. The optional second argument is a tuple of the target element and a deduplication key. If another instruction for with the same deduplication tuple is enqueued, only the last one will be executed.\n\n```js\nimport { enqueue } from '@zeix/pulse'\n\nconst markdownSource = document.querySelector('.editor textarea')\nconst markdownSection = document.querySelector('section.markdown')\nenqueue(() =\u003e {\n\tmarkdownSection.innerHTML = renderMarkdown(markdownSource.value)\n}, [markdownSection, 'md'])\n\t.then(el =\u003e console.log('Successfully rendered Markdown', el))\n\t.catch(err =\u003e console.error('An error ocurred during rendering Markdown:', err))\n```\n\n`enqueue()` resolves or rejects a `Promise` when it executes the callback, so you can chain follow-up tasks with `.then()` or handle errors with `.catch()`.\n\n### Predefined DOM Updates\n\nA number of common simple DOM instructions are predefined. These functions take care that, for example HTML comments are preserved while updating the text content of an element or possibly dangerous attributes cannot be set.\n\nThe instructions have by design awkward short names. They are meant for frameworks and library use rather than directly by application developers.\n\n| Function | Description       | Arguments                                   |\n|----------|-------------------|---------------------------------------------|\n| `ce()`   | create an element | element, object of attributes, text content |\n| `re()`   | remove an element | element                                     |\n| `st()`   | set text content  | element, text content                       |\n| `sa()`   | set attribute     | element, attribute name, value              |\n| `ra()`   | remove attribute  | element, attribute name                     |\n| `ta()`   | toggle attribute  | element, attribute name, force              |\n| `tc()`   | toggle class      | element, class token, force                 |\n| `ss()`   | set style prop    | element, CSS property, value                |\n| `rs()`   | remove style prop | element, CSS property                       |\n\n\n One function is not short, also by design, because it bypasses sanitization – and should be used only with HTML from trusted sources: `dangerouslySetInnerHTML`.\n\n ### Non-Blocking Await\n\n Sometimes you need to wait until the screen refresh took place. Use `await animationFrame()` in async functions to yield the control back to the browser for other tasks while the script is waiting.\n\n ```js\n import { animationFrame } from '@zeix/pulse'\n\n const userProfile = document.querySelector('user-profile')\n\nconst saveDisplayName = async () =\u003e {\n\tconst name = userProfile.querySelector('[name=\"display-name\"]').value\n\n\t// Get previous display name in case we'll have to revert\n\tconst oldName = userProfile.get('display-name')\n\n\t// Set the state that will enqueue an optimistic UI update on screen refresh\n\tuserProfile.set('display-name', name)\n\n\t// Send data to server\n\tconst response = fetch(`/api/userdata/profile/update`, {\n\t\tmethod: 'POST',\n\t\tbody: JSON.stringify({\n\t\t\tuser: 'example',\n\t\t\tprop: 'display-name'\n\t\t\tvalue: name\n\t\t}),\n\t\theaders: {\n\t\t\t'Content-Type': 'application/json',\n\t\t}\n\t})\n\n    // Let the browser and other scripts work\n\tawait animationFrame()\n\n\t// Confirm optimistic UI update was successful\n\tconsole.assert(\n\t\tdocument.querySelector('header user-menu button').textContent === name,\n\t\t'Optimistic UI update failed'\n\t)\n\n\tawait response\n\tif (!response.ok) showError(response.statusText)\n\telse if (response.status === 205) revertDisplayName(oldName)\n\t// We're done. Other successful responses mean the server has saved the new display name that's already on screen\n}\n ```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzeixcom%2Fpulse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzeixcom%2Fpulse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzeixcom%2Fpulse/lists"}