unhead 0.0.1 → 0.0.4

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/client.d.ts CHANGED
@@ -1,11 +1,24 @@
1
- import { a as HeadClient } from './types-e30878c0.js';
1
+ import { a as HeadClient } from './types-b4318c02.js';
2
2
  import 'hookable';
3
3
  import '@unhead/schema';
4
4
 
5
5
  interface RenderDomHeadOptions {
6
+ /**
7
+ * Document to use for rendering. Allows stubbing for testing.
8
+ */
6
9
  document?: Document;
7
10
  }
8
- declare const renderDOMHead: <T extends HeadClient<any>>(head: T, options?: RenderDomHeadOptions) => Promise<void>;
9
- declare const debouncedUpdateDom: <T extends HeadClient<any>>(delayedFn: (fn: () => void) => void, head: T, options?: RenderDomHeadOptions) => Promise<void>;
11
+ /**
12
+ * Render the head tags to the DOM.
13
+ */
14
+ declare function renderDOMHead<T extends HeadClient<any>>(head: T, options?: RenderDomHeadOptions): Promise<void>;
15
+ /**
16
+ * Global instance of the dom update promise. Used for debounding head updates.
17
+ */
18
+ declare let domUpdatePromise: Promise<void> | null;
19
+ /**
20
+ * Queue a debounced update of the DOM head.
21
+ */
22
+ declare function debouncedRenderDOMHead<T extends HeadClient<any>>(delayedFn: (fn: () => void) => void, head: T, options?: RenderDomHeadOptions): Promise<void>;
10
23
 
11
- export { RenderDomHeadOptions, debouncedUpdateDom, renderDOMHead };
24
+ export { RenderDomHeadOptions, debouncedRenderDOMHead, domUpdatePromise, renderDOMHead };
package/dist/client.mjs CHANGED
@@ -1,53 +1,56 @@
1
- import { createElement } from 'zhead';
1
+ import { createElement, TagsWithInnerContent } from 'zhead';
2
2
 
3
- const setAttributes = ($el, tag) => {
4
- const sideEffects = {};
3
+ function setAttributesWithSideEffects(head, $el, entry, tag) {
5
4
  const attrs = tag.props || {};
6
- for (const k in attrs) {
5
+ const sdeKey = `${tag._p}:attr`;
6
+ Object.entries(entry._sde).filter(([key]) => key.startsWith(sdeKey)).forEach(([key, fn]) => {
7
+ delete entry._sde[key] && fn();
8
+ });
9
+ Object.entries(attrs).forEach(([k, value]) => {
10
+ value = String(value);
11
+ const attrSdeKey = `${sdeKey}:${k}`;
12
+ head._removeQueuedSideEffect(attrSdeKey);
7
13
  if (k === "class") {
8
- for (const c of attrs[k].split(" ")) {
14
+ for (const c of value.split(" ")) {
9
15
  if (!$el.classList.contains(c)) {
10
16
  $el.classList.add(c);
11
- sideEffects[`${tag._p}:attr:class:remove:${c}`] = () => {
12
- $el.classList.remove(c);
13
- };
17
+ head._removeQueuedSideEffect(`${attrSdeKey}:${c}`);
18
+ entry._sde[`${attrSdeKey}:${c}`] = () => $el.classList.remove(c);
14
19
  }
15
20
  }
16
- continue;
21
+ return;
17
22
  }
18
- $el.setAttribute(k, String(attrs[k]));
19
- if (!k.startsWith("data-h-")) {
20
- sideEffects[`${tag._p}:attr:${k}:remove`] = () => {
21
- $el.removeAttribute(k);
22
- };
23
+ if ($el.getAttribute(k) !== value) {
24
+ $el.setAttribute(k, value);
25
+ if (!k.startsWith("data-h-"))
26
+ entry._sde[attrSdeKey] = () => $el.removeAttribute(k);
23
27
  }
24
- }
25
- return sideEffects;
26
- };
28
+ });
29
+ }
27
30
 
28
- let domUpdatePromise = null;
29
- const renderDOMHead = async (head, options = {}) => {
31
+ async function renderDOMHead(head, options = {}) {
30
32
  const dom = options.document || window.document;
31
33
  const tags = await head.resolveTags();
32
34
  await head.hooks.callHook("dom:beforeRender", { head, tags, document: dom });
33
- head._flushDomSideEffects();
34
- const sideEffectMap = {};
35
35
  for (const tag of tags) {
36
- sideEffectMap[tag._e] = sideEffectMap[tag._e] || {};
37
- let $el = tag._s ? dom.querySelector(`[${tag._s}]`) : null;
38
- const renderCtx = { tag, document: dom, $el, head };
36
+ const entry = head.headEntries().find((e) => e._i === Number(tag._e));
37
+ const sdeKey = `${tag._s || tag._p}:el`;
38
+ const $newEl = createElement(tag, dom);
39
+ const $el = tag._s ? dom.querySelector(`[${tag._s}]`) : null;
40
+ const renderCtx = { tag, document: dom, head };
39
41
  await head.hooks.callHook("dom:renderTag", renderCtx);
40
42
  if ($el) {
43
+ head._removeQueuedSideEffect(sdeKey);
44
+ if ($newEl.isEqualNode($el))
45
+ continue;
41
46
  if (Object.keys(tag.props).length === 0) {
42
47
  $el.remove();
43
48
  continue;
44
49
  }
45
- sideEffectMap[tag._e] = {
46
- ...sideEffectMap[tag._e],
47
- ...setAttributes($el, tag)
48
- };
49
- $el.innerHTML = tag.children || "";
50
- sideEffectMap[tag._e][`${tag._p}:el:remove`] = () => $el?.remove();
50
+ setAttributesWithSideEffects(head, $el, entry, tag);
51
+ if (TagsWithInnerContent.includes(tag.tag))
52
+ $el.innerHTML = tag.children || "";
53
+ entry._sde[sdeKey] = () => $el?.remove();
51
54
  continue;
52
55
  }
53
56
  if (tag.tag === "title" && tag.children) {
@@ -55,41 +58,32 @@ const renderDOMHead = async (head, options = {}) => {
55
58
  continue;
56
59
  }
57
60
  if (tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs") {
58
- sideEffectMap[tag._e] = {
59
- ...sideEffectMap[tag._e],
60
- ...setAttributes(dom[tag.tag === "htmlAttrs" ? "documentElement" : "body"], tag)
61
- };
61
+ setAttributesWithSideEffects(head, dom[tag.tag === "htmlAttrs" ? "documentElement" : "body"], entry, tag);
62
62
  continue;
63
63
  }
64
- $el = createElement(tag, dom);
65
64
  switch (tag.tagPosition) {
66
65
  case "bodyClose":
67
- dom.body.appendChild($el);
66
+ dom.body.appendChild($newEl);
68
67
  break;
69
68
  case "bodyOpen":
70
- dom.body.insertBefore($el, dom.body.firstChild);
69
+ dom.body.insertBefore($newEl, dom.body.firstChild);
71
70
  break;
72
71
  case "head":
73
72
  default:
74
- dom.head.appendChild($el);
73
+ dom.head.appendChild($newEl);
75
74
  break;
76
75
  }
77
- sideEffectMap[tag._e][`${tag._p}:el:remove`] = () => $el?.remove();
78
- }
79
- for (const k in sideEffectMap) {
80
- const entry = head.headEntries().find((e) => e._i === Number(k));
81
- entry._sde = {
82
- ...entry._sde,
83
- ...sideEffectMap[k]
84
- };
76
+ entry._sde[sdeKey] = () => $newEl?.remove();
85
77
  }
86
- };
87
- const debouncedUpdateDom = async (delayedFn, head, options = {}) => {
78
+ head._flushQueuedSideEffects();
79
+ }
80
+ let domUpdatePromise = null;
81
+ async function debouncedRenderDOMHead(delayedFn, head, options = {}) {
88
82
  function doDomUpdate() {
89
83
  domUpdatePromise = null;
90
84
  return renderDOMHead(head, options);
91
85
  }
92
86
  return domUpdatePromise = domUpdatePromise || new Promise((resolve) => delayedFn(() => resolve(doDomUpdate())));
93
- };
87
+ }
94
88
 
95
- export { debouncedUpdateDom, renderDOMHead };
89
+ export { debouncedRenderDOMHead, domUpdatePromise, renderDOMHead };
package/dist/index.d.ts CHANGED
@@ -1,16 +1,16 @@
1
1
  import * as _unhead_schema from '@unhead/schema';
2
2
  import { Head, Meta, Link, Script, Style, Base, HtmlAttributes, BodyAttributes, Noscript } from '@unhead/schema';
3
- import { H as HeadPlugin, C as CreateHeadOptions, a as HeadClient, b as HeadEntryOptions } from './types-e30878c0.js';
4
- export { A as ActiveHeadEntry, C as CreateHeadOptions, D as DomRenderTagContext, a as HeadClient, c as HeadEntry, b as HeadEntryOptions, e as HeadHooks, H as HeadPlugin, R as RuntimeMode, S as SideEffectsRecord, d as defineHeadPlugin } from './types-e30878c0.js';
3
+ import { H as HeadPlugin, C as CreateHeadOptions, a as HeadClient, b as HeadEntryOptions } from './types-b4318c02.js';
4
+ export { A as ActiveHeadEntry, C as CreateHeadOptions, D as DomRenderTagContext, E as EntryResolveCtx, a as HeadClient, c as HeadEntry, b as HeadEntryOptions, f as HeadHooks, H as HeadPlugin, e as HookResult, R as RuntimeMode, S as SideEffectsRecord, d as defineHeadPlugin } from './types-b4318c02.js';
5
5
  import 'hookable';
6
6
 
7
- declare const dedupePlugin: HeadPlugin<_unhead_schema.Head<_unhead_schema.SchemaAugmentations>>;
7
+ declare const DedupesTagsPlugin: HeadPlugin<_unhead_schema.Head<_unhead_schema.SchemaAugmentations>>;
8
8
 
9
- declare const sortPlugin: HeadPlugin<_unhead_schema.Head<_unhead_schema.SchemaAugmentations>>;
9
+ declare const SortTagsPlugin: HeadPlugin<_unhead_schema.Head<_unhead_schema.SchemaAugmentations>>;
10
10
 
11
- declare const titleTemplatePlugin: HeadPlugin<_unhead_schema.Head<_unhead_schema.SchemaAugmentations>>;
11
+ declare const TitleTemplatePlugin: HeadPlugin<_unhead_schema.Head<_unhead_schema.SchemaAugmentations>>;
12
12
 
13
- declare const hydratesStatePlugin: HeadPlugin<_unhead_schema.Head<_unhead_schema.SchemaAugmentations>>;
13
+ declare const HydratesStatePlugin: HeadPlugin<_unhead_schema.Head<_unhead_schema.SchemaAugmentations>>;
14
14
 
15
15
  declare function createHead<T extends {} = Head>(options?: CreateHeadOptions<T>): HeadClient<T>;
16
16
 
@@ -32,6 +32,7 @@ declare const getActiveHead: <T>() => HeadClient<T>;
32
32
 
33
33
  declare type Arrayable<T> = T | Array<T>;
34
34
  declare function asArray<T>(value: Arrayable<T>): T[];
35
+ declare const TagConfigKeys: string[];
35
36
  declare function hashCode(s: string): string;
36
37
 
37
- export { Arrayable, activeHead, asArray, createHead, dedupePlugin, getActiveHead, hashCode, hydratesStatePlugin, setActiveHead, sortPlugin, titleTemplatePlugin, useBase, useBodyAttrs, useHead, useHtmlAttrs, useLink, useMeta, useNoscript, useScript, useStyle, useTitle, useTitleTemplate };
38
+ export { Arrayable, DedupesTagsPlugin, HydratesStatePlugin, SortTagsPlugin, TagConfigKeys, TitleTemplatePlugin, activeHead, asArray, createHead, getActiveHead, hashCode, setActiveHead, useBase, useBodyAttrs, useHead, useHtmlAttrs, useLink, useMeta, useNoscript, useScript, useStyle, useTitle, useTitleTemplate };
package/dist/index.mjs CHANGED
@@ -9,7 +9,7 @@ function defineHeadPlugin(plugin) {
9
9
  return plugin;
10
10
  }
11
11
 
12
- const dedupePlugin = defineHeadPlugin({
12
+ const DedupesTagsPlugin = defineHeadPlugin({
13
13
  hooks: {
14
14
  "tag:normalise": function({ tag }) {
15
15
  ["hid", "vmid", "key"].forEach((key) => {
@@ -28,7 +28,10 @@ const dedupePlugin = defineHeadPlugin({
28
28
  let dedupeKey = tag._d || tag._p || i;
29
29
  const dupedTag = deduping[dedupeKey];
30
30
  if (dupedTag) {
31
- if (tag?.tagDuplicateStrategy === "merge") {
31
+ let strategy = tag?.tagDuplicateStrategy;
32
+ if (!strategy && (tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs"))
33
+ strategy = "merge";
34
+ if (strategy === "merge") {
32
35
  const oldProps = dupedTag.props;
33
36
  ["class", "style"].forEach((key) => {
34
37
  if (tag.props[key] && oldProps[key])
@@ -57,7 +60,7 @@ const dedupePlugin = defineHeadPlugin({
57
60
  }
58
61
  });
59
62
 
60
- const sortPlugin = defineHeadPlugin({
63
+ const SortTagsPlugin = defineHeadPlugin({
61
64
  hooks: {
62
65
  "tags:resolve": (ctx) => {
63
66
  const tagIndexForKey = (key) => ctx.tags.find((tag) => tag._d === key)?._p;
@@ -83,7 +86,7 @@ const sortPlugin = defineHeadPlugin({
83
86
  }
84
87
  });
85
88
 
86
- const titleTemplatePlugin = defineHeadPlugin({
89
+ const TitleTemplatePlugin = defineHeadPlugin({
87
90
  hooks: {
88
91
  "tags:resolve": (ctx) => {
89
92
  ctx.tags = resolveTitleTemplateFromTags(ctx.tags);
@@ -94,6 +97,7 @@ const titleTemplatePlugin = defineHeadPlugin({
94
97
  function asArray(value) {
95
98
  return Array.isArray(value) ? value : [value];
96
99
  }
100
+ const TagConfigKeys = ["tagPosition", "tagPriority", "tagDuplicateStrategy"];
97
101
  function hashCode(s) {
98
102
  let h = 9;
99
103
  for (let i = 0; i < s.length; )
@@ -101,15 +105,16 @@ function hashCode(s) {
101
105
  return ((h ^ h >>> 9) + 65536).toString(16).substring(1, 7).toLowerCase();
102
106
  }
103
107
 
104
- const hydratesStatePlugin = defineHeadPlugin({
108
+ const HydratesStatePlugin = defineHeadPlugin({
105
109
  hooks: {
106
110
  "tag:normalise": (ctx) => {
107
111
  const { tag, entry } = ctx;
108
112
  if (!HasElementTags.includes(tag.tag))
109
113
  return;
110
- if (typeof tag._d === "undefined" && entry.mode === "server")
114
+ if (typeof tag._d === "undefined" && entry._m === "server")
111
115
  return;
112
- tag._s = `data-h-${hashCode(tag._d || tag.tag + JSON.stringify(tag.props))}`;
116
+ const hasChildren = tag.children && tag.children.length > 0;
117
+ tag._s = `data-h-${hashCode(tag._d || tag.tag + (hasChildren ? tag.children : JSON.stringify(tag.props)))}`;
113
118
  tag.props[tag._s] = "";
114
119
  }
115
120
  }
@@ -118,14 +123,20 @@ const hydratesStatePlugin = defineHeadPlugin({
118
123
  function normaliseTag(tagName, input, entry) {
119
124
  const tag = normaliseTag$1(tagName, input, { childrenKeys: ["innerHTML", "textContent"] });
120
125
  tag._e = entry._i;
121
- Object.keys(tag.props).filter((k) => k.startsWith("tag")).forEach((k) => {
126
+ Object.keys(tag.props).filter((k) => TagConfigKeys.includes(k)).forEach((k) => {
122
127
  tag[k] = tag.props[k];
123
128
  delete tag.props[k];
124
129
  });
130
+ if (typeof tag.props.class === "object" && !Array.isArray(tag.props.class)) {
131
+ tag.props.class = Object.keys(tag.props.class).filter((k) => tag.props.class[k]);
132
+ }
133
+ if (Array.isArray(tag.props.class))
134
+ tag.props.class = tag.props.class.join(" ");
125
135
  if (tag.props.content && Array.isArray(tag.props.content)) {
126
- return tag.props.content.map((v) => {
136
+ return tag.props.content.map((v, i) => {
127
137
  const newTag = { ...tag, props: { ...tag.props } };
128
138
  newTag.props.content = v;
139
+ newTag.key = `${tag.props.name || tag.props.property}:${i}`;
129
140
  return newTag;
130
141
  });
131
142
  }
@@ -148,15 +159,17 @@ function createHead(options = {}) {
148
159
  if (options.hooks)
149
160
  hooks.addHooks(options.hooks);
150
161
  const plugins = [
151
- dedupePlugin,
152
- sortPlugin,
153
- titleTemplatePlugin
162
+ DedupesTagsPlugin,
163
+ SortTagsPlugin,
164
+ TitleTemplatePlugin
154
165
  ];
155
166
  plugins.push(...options.plugins || []);
156
167
  plugins.forEach((plugin) => hooks.addHooks(plugin.hooks || {}));
157
168
  const head = {
158
- entries,
159
- _flushDomSideEffects() {
169
+ _removeQueuedSideEffect(key) {
170
+ delete _sde[key];
171
+ },
172
+ _flushQueuedSideEffects() {
160
173
  Object.values(_sde).forEach((fn) => fn());
161
174
  _sde = {};
162
175
  },
@@ -179,33 +192,35 @@ function createHead(options = {}) {
179
192
  entries = entries.filter((e) => {
180
193
  if (e._i !== _i)
181
194
  return true;
182
- _sde = {
183
- ..._sde,
184
- ...e._sde || {}
185
- };
195
+ _sde = { ..._sde, ...e._sde || {} };
196
+ e._sde = {};
186
197
  return false;
187
198
  });
188
199
  },
189
200
  patch(input2) {
190
201
  entries = entries.map((e) => {
191
- e.input = e._i === _i ? input2 : e.input;
202
+ if (e._i === _i) {
203
+ _sde = { ..._sde, ...e._sde || {} };
204
+ e._sde = {};
205
+ e.input = e._i === _i ? input2 : e.input;
206
+ }
192
207
  return e;
193
208
  });
194
209
  }
195
210
  };
196
211
  },
197
212
  async resolveTags() {
198
- await hooks.callHook("entries:resolve", head);
199
- const tags = entries.map((entry) => normaliseEntryTags(entry)).flat();
200
- for (const k in tags) {
201
- const tagCtx = { tag: tags[k], entry: entries.find((e) => e._i === tags[k]._e) };
202
- await hooks.callHook("tag:normalise", tagCtx);
203
- tags[k] = tagCtx.tag;
213
+ const resolveCtx = { tags: [], entries: [...entries] };
214
+ await hooks.callHook("entries:resolve", resolveCtx);
215
+ for (const entry of resolveCtx.entries) {
216
+ for (const tag of normaliseEntryTags(entry)) {
217
+ const tagCtx = { tag, entry };
218
+ await hooks.callHook("tag:normalise", tagCtx);
219
+ resolveCtx.tags.push(tagCtx.tag);
220
+ }
204
221
  }
205
- const ctx = { tags };
206
- await hooks.callHook("tags:beforeResolve", ctx);
207
- await hooks.callHook("tags:resolve", ctx);
208
- return ctx.tags;
222
+ await hooks.callHook("tags:resolve", resolveCtx);
223
+ return resolveCtx.tags;
209
224
  }
210
225
  };
211
226
  setActiveHead(head);
@@ -247,4 +262,4 @@ const useNoscript = (noscript) => {
247
262
  useHead({ noscript: [noscript] });
248
263
  };
249
264
 
250
- export { activeHead, asArray, createHead, dedupePlugin, defineHeadPlugin, getActiveHead, hashCode, hydratesStatePlugin, setActiveHead, sortPlugin, titleTemplatePlugin, useBase, useBodyAttrs, useHead, useHtmlAttrs, useLink, useMeta, useNoscript, useScript, useStyle, useTitle, useTitleTemplate };
265
+ export { DedupesTagsPlugin, HydratesStatePlugin, SortTagsPlugin, TagConfigKeys, TitleTemplatePlugin, activeHead, asArray, createHead, defineHeadPlugin, getActiveHead, hashCode, setActiveHead, useBase, useBodyAttrs, useHead, useHtmlAttrs, useLink, useMeta, useNoscript, useScript, useStyle, useTitle, useTitleTemplate };
package/dist/server.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { f as SSRHeadPayload, r as renderSSRHead } from './types-e30878c0.js';
1
+ export { g as SSRHeadPayload, r as renderSSRHead } from './types-b4318c02.js';
2
2
  import 'hookable';
3
3
  import '@unhead/schema';
package/dist/server.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ssrRenderTags } from 'zhead';
2
2
 
3
- const renderSSRHead = async (ctx) => {
3
+ async function renderSSRHead(ctx) {
4
4
  const tags = await ctx.resolveTags();
5
5
  const beforeRenderCtx = { tags };
6
6
  await ctx.hooks.callHook("ssr:beforeRender", beforeRenderCtx);
@@ -8,6 +8,6 @@ const renderSSRHead = async (ctx) => {
8
8
  const renderCXx = { tags, html };
9
9
  await ctx.hooks.callHook("ssr:render", renderCXx);
10
10
  return renderCXx.html;
11
- };
11
+ }
12
12
 
13
13
  export { renderSSRHead };
@@ -11,17 +11,43 @@ interface SSRHeadPayload {
11
11
  htmlAttrs: string;
12
12
  bodyAttrs: string;
13
13
  }
14
- declare const renderSSRHead: <T extends HeadClient<any>>(ctx: T) => Promise<SSRHeadPayload>;
14
+ declare function renderSSRHead<T extends HeadClient<any>>(ctx: T): Promise<SSRHeadPayload>;
15
15
 
16
+ /**
17
+ * An active head entry provides an API to manipulate it.
18
+ */
16
19
  interface ActiveHeadEntry<T> {
20
+ /**
21
+ * Updates the entry with new input.
22
+ *
23
+ * Will first clear any side effects for previous input.
24
+ */
17
25
  patch: (resolvedInput: T) => void;
26
+ /**
27
+ * Dispose the entry, removing it from the active head.
28
+ *
29
+ * Will queue side effects for removal.
30
+ */
18
31
  dispose: () => void;
19
32
  }
33
+ /**
34
+ * Side effects are mapped with a key and their cleanup function.
35
+ *
36
+ * For example `meta:data-h-4h46h465`: () => { document.querySelector('meta[data-h-4h46h465]').remove() }
37
+ */
20
38
  declare type SideEffectsRecord = Record<string, () => void>;
21
39
  declare type RuntimeMode = 'server' | 'client' | 'all';
22
40
  interface HeadEntry<T> {
23
- mode?: RuntimeMode;
41
+ /**
42
+ * User provided input for the entry.
43
+ */
24
44
  input: T;
45
+ /**
46
+ * The mode that the entry should be used in.
47
+ *
48
+ * @internal
49
+ */
50
+ _m?: RuntimeMode;
25
51
  /**
26
52
  * Head entry index
27
53
  *
@@ -33,34 +59,33 @@ interface HeadEntry<T> {
33
59
  *
34
60
  * @internal
35
61
  */
36
- _sde?: SideEffectsRecord;
62
+ _sde: SideEffectsRecord;
37
63
  }
38
64
  declare type HookResult = Promise<void> | void;
39
65
  interface DomRenderTagContext {
40
66
  head: HeadClient;
41
67
  tag: HeadTag;
42
- $el: Element | null;
43
68
  document: Document;
44
69
  }
70
+ interface EntryResolveCtx<T> {
71
+ tags: HeadTag[];
72
+ entries: HeadEntry<T>[];
73
+ }
45
74
  interface HeadHooks<T> {
46
- 'entries:resolve': (head: HeadClient<T>) => HookResult;
75
+ 'entries:resolve': (ctx: EntryResolveCtx<T>) => HookResult;
47
76
  'tag:normalise': (ctx: {
48
77
  tag: HeadTag;
49
78
  entry: HeadEntry<T>;
50
79
  }) => HookResult;
51
- 'tags:beforeResolve': (ctx: {
52
- tags: HeadTag[];
53
- }) => HookResult;
54
80
  'tags:resolve': (ctx: {
55
81
  tags: HeadTag[];
56
82
  }) => HookResult;
57
- 'render': (ctx: any) => HookResult;
58
- 'dom:renderTag': (ctx: DomRenderTagContext) => HookResult;
59
83
  'dom:beforeRender': (ctx: {
60
84
  head: HeadClient;
61
85
  tags: HeadTag[];
62
86
  document: Document;
63
87
  }) => HookResult;
88
+ 'dom:renderTag': (ctx: DomRenderTagContext) => HookResult;
64
89
  'ssr:beforeRender': (ctx: {
65
90
  tags: HeadTag[];
66
91
  }) => HookResult;
@@ -77,15 +102,30 @@ interface HeadEntryOptions {
77
102
  mode?: RuntimeMode;
78
103
  }
79
104
  interface HeadClient<T = Head> {
80
- entries: HeadEntry<T>[];
81
- hooks: Hookable<HeadHooks<T>>;
105
+ /**
106
+ * The active head entries.
107
+ */
82
108
  headEntries: () => HeadEntry<T>[];
109
+ /**
110
+ * Create a new head entry.
111
+ */
83
112
  push: (entry: T, options?: HeadEntryOptions) => ActiveHeadEntry<T>;
113
+ /**
114
+ * Resolve tags from head entries.
115
+ */
84
116
  resolveTags: () => Promise<HeadTag[]>;
117
+ /**
118
+ * Exposed hooks for easier extension.
119
+ */
120
+ hooks: Hookable<HeadHooks<T>>;
121
+ /**
122
+ * @internal
123
+ */
124
+ _removeQueuedSideEffect: (key: string) => void;
85
125
  /**
86
126
  * @internal
87
127
  */
88
- _flushDomSideEffects: () => void;
128
+ _flushQueuedSideEffects: () => void;
89
129
  }
90
130
 
91
- export { ActiveHeadEntry as A, CreateHeadOptions as C, DomRenderTagContext as D, HeadPlugin as H, RuntimeMode as R, SideEffectsRecord as S, HeadClient as a, HeadEntryOptions as b, HeadEntry as c, defineHeadPlugin as d, HeadHooks as e, SSRHeadPayload as f, renderSSRHead as r };
131
+ export { ActiveHeadEntry as A, CreateHeadOptions as C, DomRenderTagContext as D, EntryResolveCtx as E, HeadPlugin as H, RuntimeMode as R, SideEffectsRecord as S, HeadClient as a, HeadEntryOptions as b, HeadEntry as c, defineHeadPlugin as d, HookResult as e, HeadHooks as f, SSRHeadPayload as g, renderSSRHead as r };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "unhead",
3
3
  "type": "module",
4
- "version": "0.0.1",
4
+ "version": "0.0.4",
5
5
  "packageManager": "pnpm@7.14.0",
6
6
  "author": "Harlan Wilton <harlan@harlanzw.com>",
7
7
  "license": "MIT",
@@ -36,9 +36,8 @@
36
36
  "dist"
37
37
  ],
38
38
  "dependencies": {
39
- "@unhead/schema": "0.0.1",
39
+ "@unhead/schema": "0.0.4",
40
40
  "hookable": "^5.4.1",
41
- "unctx": "^2.0.2",
42
41
  "zhead": "1.0.0-beta.4"
43
42
  },
44
43
  "scripts": {