@very-simple/ajax 1.0.0-beta.4 → 1.0.0-beta.6

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.d.ts CHANGED
@@ -74,6 +74,11 @@ type EventMap = {
74
74
  'before-visit': Payload;
75
75
  'before-swap': Payload;
76
76
  'after-swap': Payload;
77
+ 'progress-start': Record<string, never>;
78
+ progress: {
79
+ progress: number;
80
+ };
81
+ 'progress-end': Record<string, never>;
77
82
  };
78
83
  type DomEventMap = {
79
84
  [K in keyof EventMap as `ajax:${K & string}`]: CustomEvent<EventMap[K]>;
package/dist/index.js CHANGED
@@ -13,18 +13,20 @@ var config = {
13
13
  // src/load.ts
14
14
  var parser = new DOMParser();
15
15
  var currentLoadController;
16
+ var progressDelayTimeout;
16
17
  var progress = 0;
17
18
  var trickleInterval;
19
+ var emit = (type, payload) => document.dispatchEvent(new CustomEvent(`ajax:${type}`, { detail: payload }));
18
20
  var cache = /* @__PURE__ */ new Map();
19
21
  var load = async (url, regions, options) => {
20
- let progressDelayTimeout;
22
+ let aborted = false;
21
23
  try {
22
24
  currentLoadController?.abort();
25
+ clearTimeout(progressDelayTimeout);
23
26
  currentLoadController = new AbortController();
24
27
  setProgress(0);
25
28
  progressDelayTimeout = window.setTimeout(() => {
26
- toggleLoading(true);
27
- toggleProgress(true);
29
+ emit("progress-start", {});
28
30
  startTrickle();
29
31
  }, options.loadingDelay);
30
32
  const response = await fetch(url, {
@@ -41,17 +43,18 @@ var load = async (url, regions, options) => {
41
43
  const document2 = parseHtml(html);
42
44
  return { document: document2, response };
43
45
  } catch (e) {
44
- setProgress(0);
45
- const isAbortError = e instanceof DOMException && e.name === "AbortError";
46
- if (!isAbortError) {
46
+ aborted = e instanceof DOMException && e.name === "AbortError";
47
+ if (!aborted) {
48
+ setProgress(0);
47
49
  window.location.reload();
48
50
  }
49
51
  } finally {
50
- clearTimeout(progressDelayTimeout);
51
- stopTrickle();
52
- setProgress(1);
53
- toggleLoading(false);
54
- setTimeout(() => toggleProgress(false), options.progressHideDelay);
52
+ if (!aborted) {
53
+ clearTimeout(progressDelayTimeout);
54
+ stopTrickle();
55
+ setProgress(1);
56
+ setTimeout(() => emit("progress-end", {}), options.progressHideDelay);
57
+ }
55
58
  }
56
59
  };
57
60
  var parseHtml = (html) => parser.parseFromString(html, "text/html");
@@ -59,17 +62,18 @@ var trickle = () => {
59
62
  const amount = -0.095 * progress + 0.1;
60
63
  setProgress(progress + Math.random() * amount);
61
64
  };
62
- var startTrickle = () => trickleInterval = window.setInterval(trickle, 300);
63
- var stopTrickle = () => clearInterval(trickleInterval);
65
+ var startTrickle = () => {
66
+ stopTrickle();
67
+ trickleInterval = window.setInterval(trickle, 300);
68
+ };
69
+ var stopTrickle = () => {
70
+ clearInterval(trickleInterval);
71
+ trickleInterval = void 0;
72
+ };
64
73
  var setProgress = (value) => {
65
74
  progress = value;
66
- document.documentElement.style.setProperty(
67
- "--ajax-progress",
68
- `${Math.round(value * 1e4) / 100}%`
69
- );
75
+ emit("progress", { progress: value });
70
76
  };
71
- var toggleProgress = (state) => document.documentElement.toggleAttribute(`${config.prefix}progress`, state);
72
- var toggleLoading = (state) => document.documentElement.toggleAttribute(`${config.prefix}loading`, state);
73
77
 
74
78
  // src/merge.ts
75
79
  import { Idiomorph } from "idiomorph/dist/idiomorph.esm.js";
@@ -82,7 +86,7 @@ var merge = (region, newRegion, strategy) => {
82
86
  Array.from(
83
87
  newRegion.querySelectorAll(`[${escapedPrefix}permanent][id]`)
84
88
  ).forEach((el) => {
85
- const original = region.querySelector(`#${el.id}`);
89
+ const original = region.querySelector(`#${CSS.escape(el.id)}`);
86
90
  if (original) {
87
91
  permanents.set(el.id, original);
88
92
  original.remove();
@@ -91,13 +95,12 @@ var merge = (region, newRegion, strategy) => {
91
95
  unmount?.(region);
92
96
  if (strategy === "replace") region.replaceWith(newRegion);
93
97
  else region.replaceChildren(...Array.from(newRegion.children));
94
- Array.from(
95
- newRegion.querySelectorAll(`[${escapedPrefix}permanent][id]`)
96
- ).forEach((el) => {
98
+ const target = strategy === "replace" ? newRegion : region;
99
+ target.querySelectorAll(`[${escapedPrefix}permanent][id]`).forEach((el) => {
97
100
  const original = permanents.get(el.id);
98
101
  if (original) el.replaceWith(original);
99
102
  });
100
- mount?.(strategy === "replace" ? newRegion : region);
103
+ mount?.(target);
101
104
  } else if (strategy === "before") {
102
105
  region.insertAdjacentElement("beforebegin", newRegion);
103
106
  mount?.(newRegion);
@@ -114,6 +117,7 @@ var merge = (region, newRegion, strategy) => {
114
117
  const result = morph(region, newRegion);
115
118
  autoFocusEl = result.autoFocusEl;
116
119
  }
120
+ if (strategy === "morph") return { autoFocusEl };
117
121
  if (newRegion.hasAttribute(`${prefix}autofocus`) || newRegion.autofocus) {
118
122
  autoFocusEl ??= newRegion;
119
123
  }
@@ -123,7 +127,7 @@ var merge = (region, newRegion, strategy) => {
123
127
  var morph = (container, newContainer) => {
124
128
  const { prefix, mount, unmount } = config;
125
129
  const manualReplacements = [];
126
- let autoFocusEls = [];
130
+ const autoFocusEls = [];
127
131
  let currentNodeKeepAttributes = [];
128
132
  Idiomorph.morph(container, newContainer, {
129
133
  callbacks: {
@@ -138,6 +142,7 @@ var morph = (container, newContainer) => {
138
142
  const isSameComponent = oldIsComponent && newIsComponent && oldNode.getAttribute(`${prefix}component`) === newNode.getAttribute(`${prefix}component`);
139
143
  if (!oldIsComponent || isSameComponent) return true;
140
144
  manualReplacements.push([oldNode, newNode]);
145
+ return false;
141
146
  },
142
147
  beforeAttributeUpdated: (name) => {
143
148
  return !currentNodeKeepAttributes.includes(name);
@@ -153,9 +158,9 @@ var morph = (container, newContainer) => {
153
158
  mount?.(node);
154
159
  }
155
160
  },
156
- afterNodeMorphed(_, newNode) {
157
- if (newNode instanceof HTMLElement && (newNode.autofocus || newNode.hasAttribute(`${prefix}autofocus`))) {
158
- autoFocusEls.push(newNode);
161
+ afterNodeMorphed(oldNode) {
162
+ if (oldNode instanceof HTMLElement && (oldNode.autofocus || oldNode.hasAttribute(`${prefix}autofocus`))) {
163
+ autoFocusEls.push(oldNode);
159
164
  }
160
165
  }
161
166
  }
@@ -205,7 +210,7 @@ var normalizeUrl = (url) => {
205
210
  return url;
206
211
  }
207
212
  };
208
- var emit = (type, payload) => {
213
+ var emit2 = (type, payload) => {
209
214
  const waiting = [];
210
215
  const waitUntil = (promise) => waiting.push(Promise.resolve(promise));
211
216
  payload = { ...payload, waitUntil };
@@ -213,7 +218,7 @@ var emit = (type, payload) => {
213
218
  document.dispatchEvent(event);
214
219
  if (waiting.length) return Promise.allSettled(waiting);
215
220
  };
216
- var currentUrl = window.location.pathname;
221
+ var currentUrl = window.location.pathname + window.location.search;
217
222
  var currentState = history.state;
218
223
  var currentVisitController;
219
224
  var scrollPositions = /* @__PURE__ */ new Map();
@@ -239,7 +244,7 @@ var visit = async (url, {
239
244
  currentVisitController = new AbortController();
240
245
  const { signal } = currentVisitController;
241
246
  if (url === currentUrl) historyMode = "none";
242
- await emit("before-visit", {
247
+ await emit2("before-visit", {
243
248
  from: { url: fromUrl, state: fromState, document },
244
249
  to: { url, state },
245
250
  signal,
@@ -260,13 +265,14 @@ var visit = async (url, {
260
265
  }
261
266
  }
262
267
  if (!newDocument) return;
268
+ if (signal.aborted) return;
263
269
  currentUrl = url;
264
270
  currentState = state;
265
271
  if (historyMode === "replace") history.replaceState(state, "", url);
266
272
  else if (historyMode === "push") history.pushState(state, "", url);
267
273
  const from = { url: fromUrl, state: fromState, document };
268
274
  const to = { url, state, document: newDocument };
269
- await emit("before-swap", { from, to, isBackForward, signal });
275
+ await emit2("before-swap", { from, to, isBackForward, signal });
270
276
  if (signal.aborted) return;
271
277
  const getMergeStrategy = (oldEl, newEl) => newEl.getAttribute(`${config.prefix}merge`) || oldEl.getAttribute(`${config.prefix}merge`) || mergeStrategy;
272
278
  let autoFocusEl;
@@ -278,8 +284,9 @@ var visit = async (url, {
278
284
  if (hasMatchingRegions) {
279
285
  for (const id of regions) {
280
286
  const region = document.querySelector(id);
281
- const newRegion = newDocument.querySelector(id);
282
- if (!region || !newRegion) continue;
287
+ const parsedRegion = newDocument.querySelector(id);
288
+ if (!region || !parsedRegion) continue;
289
+ const newRegion = document.importNode(parsedRegion, true);
283
290
  const strategy = getMergeStrategy(region, newRegion);
284
291
  const result = merge(region, newRegion, strategy);
285
292
  autoFocusEl ??= result.autoFocusEl;
@@ -290,7 +297,7 @@ var visit = async (url, {
290
297
  }
291
298
  } else {
292
299
  const region = document.body;
293
- const newRegion = newDocument.body;
300
+ const newRegion = document.importNode(newDocument.body, true);
294
301
  const strategy = getMergeStrategy(region, newRegion);
295
302
  const result = merge(region, newRegion, strategy);
296
303
  autoFocusEl = result.autoFocusEl;
@@ -319,18 +326,18 @@ var visit = async (url, {
319
326
  await document.startViewTransition(async () => {
320
327
  if (morphHeads) Idiomorph2.morph(document.head, newDocument.head);
321
328
  await mergeRegions();
322
- await emit("after-swap", { from, to, isBackForward, signal });
329
+ await emit2("after-swap", { from, to, isBackForward, signal });
323
330
  applyScrollBehavior();
324
- }).ready;
331
+ }).updateCallbackDone;
325
332
  } else {
326
333
  if (morphHeads) Idiomorph2.morph(document.head, newDocument.head);
327
334
  await mergeRegions();
328
- await emit("after-swap", { from, to, isBackForward, signal });
335
+ await emit2("after-swap", { from, to, isBackForward, signal });
329
336
  applyScrollBehavior();
330
337
  }
331
338
  if (signal.aborted) return;
332
339
  if (autoFocus) autoFocusEl?.focus({ preventScroll: true });
333
- emit("load", { from, to, isBackForward });
340
+ emit2("load", { from, to, isBackForward });
334
341
  };
335
342
 
336
343
  // src/intercept.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@very-simple/ajax",
3
- "version": "1.0.0-beta.4",
3
+ "version": "1.0.0-beta.6",
4
4
  "description": "A very simple turbolinks inspired ajax library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",