unhead 1.9.0 → 1.9.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 CHANGED
@@ -100,12 +100,10 @@ const EventHandlersPlugin = shared.defineHeadPlugin((head) => ({
100
100
  for (const tag of ctx.tags.filter((t) => ValidEventTags.includes(t.tag))) {
101
101
  Object.entries(tag.props).forEach(([key, value]) => {
102
102
  if (key.startsWith("on") && typeof value === "function") {
103
- if (head.ssr && shared.NetworkEvents.includes(key)) {
104
- tag.props[key] = `this.dataset.${key} = true`;
105
- tag.props["data-unhead-events"] = "";
106
- } else {
103
+ if (head.ssr && shared.NetworkEvents.includes(key))
104
+ tag.props[key] = `this.dataset.${key}fired = true`;
105
+ else
107
106
  delete tag.props[key];
108
- }
109
107
  tag._eventHandlers = tag._eventHandlers || {};
110
108
  tag._eventHandlers[key] = value;
111
109
  }
@@ -114,19 +112,10 @@ const EventHandlersPlugin = shared.defineHeadPlugin((head) => ({
114
112
  tag.key = tag.key || shared.hashCode(tag.props.src || tag.props.href);
115
113
  }
116
114
  },
117
- "dom:renderTag": function(ctx) {
118
- const $el = ctx.$el;
119
- if (!$el?.dataset || !("unheadEvents" in $el.dataset))
120
- return;
121
- delete $el.dataset.unheadEvents;
122
- const handler = (k) => ctx.tag._eventHandlers?.[k]?.call(ctx.$el, new Event(k.replace("on", "")));
123
- for (const k of Object.keys($el.dataset).filter((k2) => shared.NetworkEvents.includes(k2)))
124
- handler(k);
125
- if (typeof MutationObserver !== "undefined") {
126
- const observer = new MutationObserver((e) => {
127
- e.filter((m) => m.attributeName && shared.NetworkEvents.includes(m.attributeName.replace("data-", ""))).map((m) => m.attributeName.replace("data-", "")).map(handler);
128
- });
129
- observer.observe(ctx.$el, { attributes: true });
115
+ "dom:renderTag": function({ $el, tag }) {
116
+ for (const k of Object.keys($el?.dataset || {}).filter((k2) => shared.NetworkEvents.some((e) => `${e}fired` === k2))) {
117
+ const ek = k.replace("fired", "");
118
+ tag._eventHandlers?.[ek]?.call($el, new Event(ek.replace("on", "")));
130
119
  }
131
120
  }
132
121
  }
@@ -467,63 +456,68 @@ function useScript(_input, _options) {
467
456
  const key = `use-script.${id}`;
468
457
  if (head._scripts?.[id])
469
458
  return head._scripts[id];
459
+ const syncStatus = (s) => {
460
+ script.status = s;
461
+ head.hooks.callHook(`script:updated`, hookCtx);
462
+ };
463
+ const trigger = options.trigger;
464
+ shared.ScriptNetworkEvents.forEach((fn) => {
465
+ const _fn = typeof input[fn] === "function" ? input[fn].bind(options.eventContext) : null;
466
+ input[fn] = (e) => {
467
+ syncStatus(fn === "onload" ? "loaded" : fn === "onerror" ? "error" : "loading");
468
+ _fn?.(e);
469
+ };
470
+ });
470
471
  const script = {
471
472
  id,
472
473
  status: "awaitingLoad",
473
474
  loaded: false,
474
475
  remove() {
475
- if (script.status === "loaded") {
476
- script.entry?.dispose();
477
- script.status = "removed";
478
- head.hooks.callHook(`script:updated`, hookCtx);
476
+ if (script.entry) {
477
+ script.entry.dispose();
478
+ syncStatus("removed");
479
479
  delete head._scripts?.[id];
480
480
  return true;
481
481
  }
482
482
  return false;
483
483
  },
484
484
  load() {
485
- if (script.status !== "awaitingLoad")
486
- return script.loadPromise;
487
- script.status = "loading";
488
- head.hooks.callHook(`script:updated`, hookCtx);
489
- script.entry = head.push({
490
- script: [
491
- { defer: true, fetchpriority: "low", ...input, key }
492
- ]
493
- }, options);
485
+ if (!script.entry) {
486
+ syncStatus("loading");
487
+ script.entry = head.push({
488
+ script: [{ defer: true, fetchpriority: "low", ...input, key }]
489
+ }, options);
490
+ }
494
491
  return script.loadPromise;
495
492
  }
496
493
  };
497
494
  script.loadPromise = new Promise((resolve, reject) => {
498
495
  const removeHook2 = head.hooks.hook("script:updated", ({ script: script2 }) => {
499
496
  if (script2.id === id && (script2.status === "loaded" || script2.status === "error")) {
500
- script2.status === "loaded" && resolve(options.use?.());
501
- script2.status === "error" && reject(new Error(`Failed to load script: ${input.src}`));
497
+ if (script2.status === "loaded")
498
+ resolve(options.use?.());
499
+ else if (script2.status === "error")
500
+ reject(new Error(`Failed to load script: ${input.src}`));
502
501
  removeHook2();
503
502
  }
504
503
  });
505
504
  });
506
505
  const hookCtx = { script };
507
- shared.ScriptNetworkEvents.forEach((fn) => {
508
- input[fn] = (e) => {
509
- script.status = fn === "onload" ? "loaded" : fn === "onerror" ? "error" : "loading";
510
- head.hooks.callHook(`script:updated`, hookCtx);
511
- typeof input[fn] === "function" && input[fn].call(options.eventContext, e);
512
- };
513
- });
514
- const trigger = options.trigger;
515
- if (options.trigger)
516
- trigger instanceof Promise && trigger.then(script.load);
517
- else
506
+ if (trigger) {
507
+ if (trigger instanceof Promise)
508
+ trigger.then(script.load);
509
+ else if (typeof trigger === "function")
510
+ trigger(script.load);
511
+ } else {
518
512
  script.load();
513
+ }
519
514
  const removeHook = head.hooks.hook("dom:renderTag", (ctx) => {
520
515
  if (ctx.tag.key !== key)
521
516
  return;
522
517
  if (ctx.tag.innerHTML) {
523
518
  setTimeout(
524
519
  () => {
525
- script.status = "loaded";
526
- head.hooks.callHook("script:updated", hookCtx);
520
+ syncStatus("loaded");
527
521
  typeof input.onload === "function" && input.onload.call(options.eventContext, new Event("load"));
528
522
  },
529
523
  5
package/dist/index.mjs CHANGED
@@ -99,12 +99,10 @@ const EventHandlersPlugin = defineHeadPlugin((head) => ({
99
99
  for (const tag of ctx.tags.filter((t) => ValidEventTags.includes(t.tag))) {
100
100
  Object.entries(tag.props).forEach(([key, value]) => {
101
101
  if (key.startsWith("on") && typeof value === "function") {
102
- if (head.ssr && NetworkEvents.includes(key)) {
103
- tag.props[key] = `this.dataset.${key} = true`;
104
- tag.props["data-unhead-events"] = "";
105
- } else {
102
+ if (head.ssr && NetworkEvents.includes(key))
103
+ tag.props[key] = `this.dataset.${key}fired = true`;
104
+ else
106
105
  delete tag.props[key];
107
- }
108
106
  tag._eventHandlers = tag._eventHandlers || {};
109
107
  tag._eventHandlers[key] = value;
110
108
  }
@@ -113,19 +111,10 @@ const EventHandlersPlugin = defineHeadPlugin((head) => ({
113
111
  tag.key = tag.key || hashCode(tag.props.src || tag.props.href);
114
112
  }
115
113
  },
116
- "dom:renderTag": function(ctx) {
117
- const $el = ctx.$el;
118
- if (!$el?.dataset || !("unheadEvents" in $el.dataset))
119
- return;
120
- delete $el.dataset.unheadEvents;
121
- const handler = (k) => ctx.tag._eventHandlers?.[k]?.call(ctx.$el, new Event(k.replace("on", "")));
122
- for (const k of Object.keys($el.dataset).filter((k2) => NetworkEvents.includes(k2)))
123
- handler(k);
124
- if (typeof MutationObserver !== "undefined") {
125
- const observer = new MutationObserver((e) => {
126
- e.filter((m) => m.attributeName && NetworkEvents.includes(m.attributeName.replace("data-", ""))).map((m) => m.attributeName.replace("data-", "")).map(handler);
127
- });
128
- observer.observe(ctx.$el, { attributes: true });
114
+ "dom:renderTag": function({ $el, tag }) {
115
+ for (const k of Object.keys($el?.dataset || {}).filter((k2) => NetworkEvents.some((e) => `${e}fired` === k2))) {
116
+ const ek = k.replace("fired", "");
117
+ tag._eventHandlers?.[ek]?.call($el, new Event(ek.replace("on", "")));
129
118
  }
130
119
  }
131
120
  }
@@ -466,63 +455,68 @@ function useScript(_input, _options) {
466
455
  const key = `use-script.${id}`;
467
456
  if (head._scripts?.[id])
468
457
  return head._scripts[id];
458
+ const syncStatus = (s) => {
459
+ script.status = s;
460
+ head.hooks.callHook(`script:updated`, hookCtx);
461
+ };
462
+ const trigger = options.trigger;
463
+ ScriptNetworkEvents.forEach((fn) => {
464
+ const _fn = typeof input[fn] === "function" ? input[fn].bind(options.eventContext) : null;
465
+ input[fn] = (e) => {
466
+ syncStatus(fn === "onload" ? "loaded" : fn === "onerror" ? "error" : "loading");
467
+ _fn?.(e);
468
+ };
469
+ });
469
470
  const script = {
470
471
  id,
471
472
  status: "awaitingLoad",
472
473
  loaded: false,
473
474
  remove() {
474
- if (script.status === "loaded") {
475
- script.entry?.dispose();
476
- script.status = "removed";
477
- head.hooks.callHook(`script:updated`, hookCtx);
475
+ if (script.entry) {
476
+ script.entry.dispose();
477
+ syncStatus("removed");
478
478
  delete head._scripts?.[id];
479
479
  return true;
480
480
  }
481
481
  return false;
482
482
  },
483
483
  load() {
484
- if (script.status !== "awaitingLoad")
485
- return script.loadPromise;
486
- script.status = "loading";
487
- head.hooks.callHook(`script:updated`, hookCtx);
488
- script.entry = head.push({
489
- script: [
490
- { defer: true, fetchpriority: "low", ...input, key }
491
- ]
492
- }, options);
484
+ if (!script.entry) {
485
+ syncStatus("loading");
486
+ script.entry = head.push({
487
+ script: [{ defer: true, fetchpriority: "low", ...input, key }]
488
+ }, options);
489
+ }
493
490
  return script.loadPromise;
494
491
  }
495
492
  };
496
493
  script.loadPromise = new Promise((resolve, reject) => {
497
494
  const removeHook2 = head.hooks.hook("script:updated", ({ script: script2 }) => {
498
495
  if (script2.id === id && (script2.status === "loaded" || script2.status === "error")) {
499
- script2.status === "loaded" && resolve(options.use?.());
500
- script2.status === "error" && reject(new Error(`Failed to load script: ${input.src}`));
496
+ if (script2.status === "loaded")
497
+ resolve(options.use?.());
498
+ else if (script2.status === "error")
499
+ reject(new Error(`Failed to load script: ${input.src}`));
501
500
  removeHook2();
502
501
  }
503
502
  });
504
503
  });
505
504
  const hookCtx = { script };
506
- ScriptNetworkEvents.forEach((fn) => {
507
- input[fn] = (e) => {
508
- script.status = fn === "onload" ? "loaded" : fn === "onerror" ? "error" : "loading";
509
- head.hooks.callHook(`script:updated`, hookCtx);
510
- typeof input[fn] === "function" && input[fn].call(options.eventContext, e);
511
- };
512
- });
513
- const trigger = options.trigger;
514
- if (options.trigger)
515
- trigger instanceof Promise && trigger.then(script.load);
516
- else
505
+ if (trigger) {
506
+ if (trigger instanceof Promise)
507
+ trigger.then(script.load);
508
+ else if (typeof trigger === "function")
509
+ trigger(script.load);
510
+ } else {
517
511
  script.load();
512
+ }
518
513
  const removeHook = head.hooks.hook("dom:renderTag", (ctx) => {
519
514
  if (ctx.tag.key !== key)
520
515
  return;
521
516
  if (ctx.tag.innerHTML) {
522
517
  setTimeout(
523
518
  () => {
524
- script.status = "loaded";
525
- head.hooks.callHook("script:updated", hookCtx);
519
+ syncStatus("loaded");
526
520
  typeof input.onload === "function" && input.onload.call(options.eventContext, new Event("load"));
527
521
  },
528
522
  5
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "unhead",
3
3
  "type": "module",
4
- "version": "1.9.0",
4
+ "version": "1.9.2",
5
5
  "author": {
6
6
  "name": "Harlan Wilton",
7
7
  "email": "harlan@harlanzw.com",
@@ -34,9 +34,9 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "hookable": "^5.5.3",
37
- "@unhead/schema": "1.9.0",
38
- "@unhead/shared": "1.9.0",
39
- "@unhead/dom": "1.9.0"
37
+ "@unhead/shared": "1.9.2",
38
+ "@unhead/schema": "1.9.2",
39
+ "@unhead/dom": "1.9.2"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "unbuild .",