@unhead/dom 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,107 @@
1
+ 'use strict';
2
+
3
+ const TagsWithInnerContent = ["script", "style", "noscript"];
4
+
5
+ const createElement = (tag, document) => {
6
+ const $el = document.createElement(tag.tag);
7
+ for (const k in tag.props)
8
+ $el.setAttribute(k, String(tag.props[k]));
9
+ if (tag.children)
10
+ $el.innerHTML = tag.children;
11
+ return $el;
12
+ };
13
+
14
+ function setAttributesWithSideEffects(head, $el, entry, tag) {
15
+ const attrs = tag.props || {};
16
+ const sdeKey = `${tag._p}:attr`;
17
+ Object.entries(entry._sde).filter(([key]) => key.startsWith(sdeKey)).forEach(([key, fn]) => {
18
+ delete entry._sde[key] && fn();
19
+ });
20
+ Object.entries(attrs).forEach(([k, value]) => {
21
+ value = String(value);
22
+ const attrSdeKey = `${sdeKey}:${k}`;
23
+ head._removeQueuedSideEffect(attrSdeKey);
24
+ if (k === "class") {
25
+ for (const c of value.split(" ")) {
26
+ if (!$el.classList.contains(c)) {
27
+ $el.classList.add(c);
28
+ head._removeQueuedSideEffect(`${attrSdeKey}:${c}`);
29
+ entry._sde[`${attrSdeKey}:${c}`] = () => $el.classList.remove(c);
30
+ }
31
+ }
32
+ return;
33
+ }
34
+ if ($el.getAttribute(k) !== value) {
35
+ $el.setAttribute(k, value);
36
+ if (!k.startsWith("data-h-"))
37
+ entry._sde[attrSdeKey] = () => $el.removeAttribute(k);
38
+ }
39
+ });
40
+ }
41
+
42
+ async function renderDOMHead(head, options = {}) {
43
+ const dom = options.document || window.document;
44
+ const tags = await head.resolveTags();
45
+ await head.hooks.callHook("dom:beforeRender", { head, tags, document: dom });
46
+ for (const tag of tags) {
47
+ const renderCtx = { tag, document: dom, head };
48
+ await head.hooks.callHook("dom:renderTag", renderCtx);
49
+ const entry = head.headEntries().find((e) => e._i === Number(tag._e));
50
+ if (tag.tag === "title" && tag.children) {
51
+ dom.title = tag.children;
52
+ continue;
53
+ }
54
+ if (tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs") {
55
+ setAttributesWithSideEffects(head, dom[tag.tag === "htmlAttrs" ? "documentElement" : "body"], entry, tag);
56
+ continue;
57
+ }
58
+ const sdeKey = `${tag._s || tag._p}:el`;
59
+ const $newEl = createElement(tag, dom);
60
+ let $previousEl = null;
61
+ for (const $el of dom[tag.tagPosition?.startsWith("body") ? "body" : "head"].children) {
62
+ if ($el.hasAttribute(`${tag._s}`)) {
63
+ $previousEl = $el;
64
+ break;
65
+ }
66
+ }
67
+ if ($previousEl) {
68
+ head._removeQueuedSideEffect(sdeKey);
69
+ if ($newEl.isEqualNode($previousEl))
70
+ continue;
71
+ if (Object.keys(tag.props).length === 0) {
72
+ $previousEl.remove();
73
+ continue;
74
+ }
75
+ setAttributesWithSideEffects(head, $previousEl, entry, tag);
76
+ if (TagsWithInnerContent.includes(tag.tag))
77
+ $previousEl.innerHTML = tag.children || "";
78
+ entry._sde[sdeKey] = () => $previousEl?.remove();
79
+ continue;
80
+ }
81
+ switch (tag.tagPosition) {
82
+ case "bodyClose":
83
+ dom.body.appendChild($newEl);
84
+ break;
85
+ case "bodyOpen":
86
+ dom.body.insertBefore($newEl, dom.body.firstChild);
87
+ break;
88
+ case "head":
89
+ default:
90
+ dom.head.appendChild($newEl);
91
+ break;
92
+ }
93
+ entry._sde[sdeKey] = () => $newEl?.remove();
94
+ }
95
+ head._flushQueuedSideEffects();
96
+ }
97
+ exports.domUpdatePromise = null;
98
+ async function debouncedRenderDOMHead(delayedFn, head, options = {}) {
99
+ function doDomUpdate() {
100
+ exports.domUpdatePromise = null;
101
+ return renderDOMHead(head, options);
102
+ }
103
+ return exports.domUpdatePromise = exports.domUpdatePromise || new Promise((resolve) => delayedFn(() => resolve(doDomUpdate())));
104
+ }
105
+
106
+ exports.debouncedRenderDOMHead = debouncedRenderDOMHead;
107
+ exports.renderDOMHead = renderDOMHead;
package/dist/index.d.ts CHANGED
@@ -1,20 +1,4 @@
1
- import { HeadClient, HeadTag, HookResult } from '@unhead/schema';
2
-
3
- interface DomRenderTagContext {
4
- head: HeadClient;
5
- tag: HeadTag;
6
- document: Document;
7
- }
8
- declare module '@unhead/schema' {
9
- interface HeadHooks {
10
- 'dom:beforeRender': (ctx: {
11
- head: HeadClient;
12
- tags: HeadTag[];
13
- document: Document;
14
- }) => HookResult;
15
- 'dom:renderTag': (ctx: DomRenderTagContext) => HookResult;
16
- }
17
- }
1
+ import { HeadClient } from '@unhead/schema';
18
2
 
19
3
  interface RenderDomHeadOptions {
20
4
  /**
@@ -35,4 +19,4 @@ declare let domUpdatePromise: Promise<void> | null;
35
19
  */
36
20
  declare function debouncedRenderDOMHead<T extends HeadClient<any>>(delayedFn: (fn: () => void) => void, head: T, options?: RenderDomHeadOptions): Promise<void>;
37
21
 
38
- export { DomRenderTagContext, RenderDomHeadOptions, debouncedRenderDOMHead, domUpdatePromise, renderDOMHead };
22
+ export { RenderDomHeadOptions, debouncedRenderDOMHead, domUpdatePromise, renderDOMHead };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unhead/dom",
3
3
  "type": "module",
4
- "version": "0.1.1",
4
+ "version": "0.1.2",
5
5
  "packageManager": "pnpm@7.14.0",
6
6
  "author": "Harlan Wilton <harlan@harlanzw.com>",
7
7
  "license": "MIT",
@@ -28,7 +28,7 @@
28
28
  "dist"
29
29
  ],
30
30
  "dependencies": {
31
- "@unhead/schema": "0.1.1"
31
+ "@unhead/schema": "0.1.2"
32
32
  },
33
33
  "devDependencies": {
34
34
  "zhead": "1.0.0-beta.4"