@very-simple/ajax 0.4.0 → 0.5.1
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 +24 -1
- package/dist/index.js +47 -30
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -10,10 +10,33 @@ type MergeStrategy = 'replace' | 'morph' | 'before' | 'after' | 'prepend' | 'app
|
|
|
10
10
|
interface Config {
|
|
11
11
|
watchHistory?: boolean;
|
|
12
12
|
merge?: MergeStrategy;
|
|
13
|
+
morphHeads?: boolean;
|
|
14
|
+
}
|
|
15
|
+
type EventMap = {
|
|
16
|
+
visit: {
|
|
17
|
+
url: string;
|
|
18
|
+
prevUrl: string;
|
|
19
|
+
};
|
|
20
|
+
'before-visit': {
|
|
21
|
+
url: string;
|
|
22
|
+
prevUrl?: string;
|
|
23
|
+
};
|
|
24
|
+
'before-render': {
|
|
25
|
+
url: string;
|
|
26
|
+
prevUrl?: string;
|
|
27
|
+
newDocument: Document;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
type DomEventMap = {
|
|
31
|
+
[K in keyof EventMap as `simple-ajax:${K & string}`]: CustomEvent<EventMap[K]>;
|
|
32
|
+
};
|
|
33
|
+
declare global {
|
|
34
|
+
interface DocumentEventMap extends DomEventMap {
|
|
35
|
+
}
|
|
13
36
|
}
|
|
14
37
|
|
|
15
38
|
declare const _default: {
|
|
16
|
-
start: ({ watchHistory, merge, }?: Config) => void;
|
|
39
|
+
start: ({ watchHistory, merge, morphHeads, }?: Config) => void;
|
|
17
40
|
visit: (url: string, { action, emitEvents, isBackForward, morphHeads, merge: mergeStrategy, autoFocus, }?: VisitOptions) => Promise<void>;
|
|
18
41
|
};
|
|
19
42
|
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
// src/config.ts
|
|
2
2
|
var globalConfig = {
|
|
3
3
|
watchHistory: true,
|
|
4
|
+
morphHeads: true,
|
|
4
5
|
merge: "replace"
|
|
5
6
|
};
|
|
6
7
|
|
|
7
8
|
// src/load.ts
|
|
8
9
|
var parser = new DOMParser();
|
|
9
|
-
var progress = 0;
|
|
10
10
|
var currentLoadController;
|
|
11
11
|
var load = async (url, regionIds) => {
|
|
12
12
|
let progressDelayTimeout;
|
|
13
13
|
try {
|
|
14
|
-
currentLoadController?.abort();
|
|
14
|
+
currentLoadController?.abort("cancel");
|
|
15
15
|
currentLoadController = new AbortController();
|
|
16
16
|
setProgress(0);
|
|
17
17
|
progressDelayTimeout = window.setTimeout(() => toggleLoading(true), 500);
|
|
@@ -23,18 +23,27 @@ var load = async (url, regionIds) => {
|
|
|
23
23
|
signal: currentLoadController.signal
|
|
24
24
|
});
|
|
25
25
|
const reader = response.body?.getReader();
|
|
26
|
-
const
|
|
26
|
+
const contentLengthHeader = response.headers.get("Content-Length");
|
|
27
|
+
const length = parseInt(contentLengthHeader ?? "0");
|
|
27
28
|
let receivedBytes = 0;
|
|
28
29
|
const stream = new ReadableStream({
|
|
29
30
|
start(controller) {
|
|
30
31
|
const read = async () => {
|
|
31
32
|
const { done, value } = await reader.read();
|
|
32
33
|
if (done) {
|
|
34
|
+
if (contentLengthHeader && receivedBytes > length) {
|
|
35
|
+
console.warn(
|
|
36
|
+
`Server sent more data (${receivedBytes} bytes) than specified in Content-Length header (${length} bytes).`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
33
39
|
controller.close();
|
|
34
40
|
return;
|
|
35
41
|
}
|
|
36
42
|
receivedBytes += value.length;
|
|
37
|
-
|
|
43
|
+
if (contentLengthHeader) {
|
|
44
|
+
const progress = Math.min(receivedBytes / length, 1);
|
|
45
|
+
setProgress(progress);
|
|
46
|
+
}
|
|
38
47
|
controller.enqueue(value);
|
|
39
48
|
read();
|
|
40
49
|
};
|
|
@@ -47,8 +56,7 @@ var load = async (url, regionIds) => {
|
|
|
47
56
|
return parser.parseFromString(html, "text/html");
|
|
48
57
|
} catch (e) {
|
|
49
58
|
setProgress(0);
|
|
50
|
-
|
|
51
|
-
if (isAbortError || currentLoadController?.signal.aborted) {
|
|
59
|
+
if (e !== "cancel") {
|
|
52
60
|
window.location.reload();
|
|
53
61
|
}
|
|
54
62
|
} finally {
|
|
@@ -56,13 +64,10 @@ var load = async (url, regionIds) => {
|
|
|
56
64
|
toggleLoading(false);
|
|
57
65
|
}
|
|
58
66
|
};
|
|
59
|
-
var setProgress = (value) =>
|
|
60
|
-
progress
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
`${value * 100}%`
|
|
64
|
-
);
|
|
65
|
-
};
|
|
67
|
+
var setProgress = (value) => document.documentElement.style.setProperty(
|
|
68
|
+
"--simple-progress",
|
|
69
|
+
`${Math.round(value * 1e4) / 100}%`
|
|
70
|
+
);
|
|
66
71
|
var toggleLoading = (state) => document.documentElement.toggleAttribute("data-simple-loading", state);
|
|
67
72
|
|
|
68
73
|
// src/merge.ts
|
|
@@ -100,22 +105,27 @@ var merge = (region, newRegion, strategy) => {
|
|
|
100
105
|
var morph = (container, newContainer) => {
|
|
101
106
|
const manualReplacements = [];
|
|
102
107
|
let autoFocusEls = [];
|
|
108
|
+
let currentNodeKeepAttributes = [];
|
|
103
109
|
Idiomorph.morph(container, newContainer, {
|
|
104
110
|
callbacks: {
|
|
105
|
-
afterNodeMorphed(_, newNode) {
|
|
106
|
-
if (newNode instanceof HTMLElement && (newNode.autofocus || newNode.dataset.simpleAutofocus)) {
|
|
107
|
-
autoFocusEls.push(newNode);
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
111
|
beforeNodeMorphed(oldNode, newNode) {
|
|
111
112
|
if (!(oldNode instanceof HTMLElement)) return true;
|
|
112
113
|
if (!(newNode instanceof HTMLElement)) return true;
|
|
114
|
+
currentNodeKeepAttributes = oldNode.dataset.simpleKeepAttributes?.split(" ") ?? [];
|
|
113
115
|
if (oldNode.hasAttribute("data-simple-permanent") && oldNode.id === newNode.id)
|
|
114
116
|
return false;
|
|
115
117
|
const oldComponent = oldNode.dataset.simpleComponent;
|
|
116
118
|
const newComponent = newNode.dataset.simpleComponent;
|
|
117
119
|
if (!oldComponent || oldComponent === newComponent) return true;
|
|
118
120
|
manualReplacements.push([oldNode, newNode]);
|
|
121
|
+
},
|
|
122
|
+
beforeAttributeUpdated: (name) => {
|
|
123
|
+
return !currentNodeKeepAttributes.includes(name);
|
|
124
|
+
},
|
|
125
|
+
afterNodeMorphed(_, newNode) {
|
|
126
|
+
if (newNode instanceof HTMLElement && (newNode.autofocus || newNode.dataset.simpleAutofocus)) {
|
|
127
|
+
autoFocusEls.push(newNode);
|
|
128
|
+
}
|
|
119
129
|
}
|
|
120
130
|
}
|
|
121
131
|
});
|
|
@@ -131,26 +141,31 @@ var emit = async (type, payload) => {
|
|
|
131
141
|
const event = new CustomEvent(`simple-ajax:${type}`, { detail: payload });
|
|
132
142
|
document.dispatchEvent(event);
|
|
133
143
|
};
|
|
144
|
+
var currentUrl = window.location.pathname;
|
|
145
|
+
var prevUrl;
|
|
134
146
|
var visit = async (url, {
|
|
135
147
|
action = "none",
|
|
136
148
|
emitEvents = true,
|
|
137
149
|
isBackForward = false,
|
|
138
|
-
morphHeads =
|
|
150
|
+
morphHeads = globalConfig.morphHeads,
|
|
139
151
|
merge: mergeStrategy = globalConfig.merge,
|
|
140
152
|
autoFocus = true
|
|
141
153
|
} = {}) => {
|
|
142
|
-
|
|
154
|
+
prevUrl = currentUrl;
|
|
155
|
+
currentUrl = url;
|
|
156
|
+
if (emitEvents) emit("before-visit", { url, prevUrl });
|
|
143
157
|
let newDocument;
|
|
144
158
|
if (isBackForward) {
|
|
145
159
|
newDocument = cache.get(url)?.cloneNode(true);
|
|
146
|
-
} else {
|
|
147
|
-
const cacheId = window.location.pathname + window.location.search;
|
|
148
|
-
cache.set(cacheId, document.cloneNode(true));
|
|
149
160
|
}
|
|
150
161
|
const regions = findRegions(document);
|
|
151
162
|
newDocument ??= await load(url, Array.from(regions.keys()));
|
|
152
163
|
if (!newDocument) return;
|
|
153
|
-
if (emitEvents) emit("before-render", { url, newDocument });
|
|
164
|
+
if (emitEvents) emit("before-render", { url, prevUrl, newDocument });
|
|
165
|
+
if (!isBackForward) {
|
|
166
|
+
const cacheId = window.location.pathname + window.location.search;
|
|
167
|
+
cache.set(cacheId, document.cloneNode(true));
|
|
168
|
+
}
|
|
154
169
|
if (morphHeads) Idiomorph2.morph(document.head, newDocument.head);
|
|
155
170
|
const getMergeStrategy = (oldEl, newEl) => newEl.dataset.simpleAjax || oldEl.dataset.simpleAjax || mergeStrategy;
|
|
156
171
|
let autoFocusEl;
|
|
@@ -177,7 +192,7 @@ var visit = async (url, {
|
|
|
177
192
|
if (autoFocus) autoFocusEl?.focus();
|
|
178
193
|
if (action === "replace") history.replaceState(null, "", url);
|
|
179
194
|
else if (action === "push") history.pushState(null, "", url);
|
|
180
|
-
if (emitEvents) emit("visit", { url });
|
|
195
|
+
if (emitEvents) emit("visit", { url, prevUrl });
|
|
181
196
|
};
|
|
182
197
|
var findRegions = (doc) => {
|
|
183
198
|
let regions = /* @__PURE__ */ new Map();
|
|
@@ -191,13 +206,15 @@ var findRegions = (doc) => {
|
|
|
191
206
|
// src/start.ts
|
|
192
207
|
var start = ({
|
|
193
208
|
watchHistory = true,
|
|
194
|
-
merge: merge2 = "replace"
|
|
209
|
+
merge: merge2 = "replace",
|
|
210
|
+
morphHeads = true
|
|
195
211
|
} = {}) => {
|
|
196
212
|
globalConfig.merge = merge2;
|
|
197
213
|
globalConfig.watchHistory = watchHistory;
|
|
214
|
+
globalConfig.morphHeads = morphHeads;
|
|
198
215
|
if (watchHistory) {
|
|
199
|
-
window.addEventListener("popstate",
|
|
200
|
-
|
|
216
|
+
window.addEventListener("popstate", () => {
|
|
217
|
+
visit(window.location.pathname + window.location.search, {
|
|
201
218
|
action: "none",
|
|
202
219
|
isBackForward: true
|
|
203
220
|
});
|
|
@@ -206,7 +223,7 @@ var start = ({
|
|
|
206
223
|
};
|
|
207
224
|
|
|
208
225
|
// src/index.ts
|
|
209
|
-
var
|
|
226
|
+
var index_default = { start, visit };
|
|
210
227
|
export {
|
|
211
|
-
|
|
228
|
+
index_default as default
|
|
212
229
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@very-simple/ajax",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "A very simple turbolinks inspired library",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"url": "https://github.com/very-simple/ajax.git"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
|
-
"build": "
|
|
16
|
+
"build": "tsup src/index.ts --dts --format esm",
|
|
17
17
|
"dev": "vite",
|
|
18
18
|
"test": "playwright test",
|
|
19
19
|
"release": "npm run build && npm run test && bumpp"
|
|
@@ -23,14 +23,14 @@
|
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@picocss/pico": "^2.0.6",
|
|
25
25
|
"@playwright/test": "^1.48.2",
|
|
26
|
-
"@types/node": "^
|
|
26
|
+
"@types/node": "^22.0",
|
|
27
27
|
"@very-simple/components": "^0.6.0",
|
|
28
|
-
"bumpp": "^
|
|
28
|
+
"bumpp": "^10.0.0",
|
|
29
29
|
"tsup": "8",
|
|
30
30
|
"typescript": "^5",
|
|
31
|
-
"vite": "^
|
|
31
|
+
"vite": "^6"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"idiomorph": "^0.
|
|
34
|
+
"idiomorph": "^0.7.0"
|
|
35
35
|
}
|
|
36
36
|
}
|