@very-simple/ajax 0.4.0 → 0.5.0
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 +45 -27
- 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,12 +1,12 @@
|
|
|
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;
|
|
@@ -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
|
};
|
|
@@ -56,13 +65,10 @@ var load = async (url, regionIds) => {
|
|
|
56
65
|
toggleLoading(false);
|
|
57
66
|
}
|
|
58
67
|
};
|
|
59
|
-
var setProgress = (value) =>
|
|
60
|
-
progress
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
`${value * 100}%`
|
|
64
|
-
);
|
|
65
|
-
};
|
|
68
|
+
var setProgress = (value) => document.documentElement.style.setProperty(
|
|
69
|
+
"--simple-progress",
|
|
70
|
+
`${Math.round(value * 1e4) / 100}%`
|
|
71
|
+
);
|
|
66
72
|
var toggleLoading = (state) => document.documentElement.toggleAttribute("data-simple-loading", state);
|
|
67
73
|
|
|
68
74
|
// src/merge.ts
|
|
@@ -100,22 +106,27 @@ var merge = (region, newRegion, strategy) => {
|
|
|
100
106
|
var morph = (container, newContainer) => {
|
|
101
107
|
const manualReplacements = [];
|
|
102
108
|
let autoFocusEls = [];
|
|
109
|
+
let currentNodeKeepAttributes = [];
|
|
103
110
|
Idiomorph.morph(container, newContainer, {
|
|
104
111
|
callbacks: {
|
|
105
|
-
afterNodeMorphed(_, newNode) {
|
|
106
|
-
if (newNode instanceof HTMLElement && (newNode.autofocus || newNode.dataset.simpleAutofocus)) {
|
|
107
|
-
autoFocusEls.push(newNode);
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
112
|
beforeNodeMorphed(oldNode, newNode) {
|
|
111
113
|
if (!(oldNode instanceof HTMLElement)) return true;
|
|
112
114
|
if (!(newNode instanceof HTMLElement)) return true;
|
|
115
|
+
currentNodeKeepAttributes = oldNode.dataset.simpleKeepAttributes?.split(" ") ?? [];
|
|
113
116
|
if (oldNode.hasAttribute("data-simple-permanent") && oldNode.id === newNode.id)
|
|
114
117
|
return false;
|
|
115
118
|
const oldComponent = oldNode.dataset.simpleComponent;
|
|
116
119
|
const newComponent = newNode.dataset.simpleComponent;
|
|
117
120
|
if (!oldComponent || oldComponent === newComponent) return true;
|
|
118
121
|
manualReplacements.push([oldNode, newNode]);
|
|
122
|
+
},
|
|
123
|
+
beforeAttributeUpdated: (name) => {
|
|
124
|
+
return !currentNodeKeepAttributes.includes(name);
|
|
125
|
+
},
|
|
126
|
+
afterNodeMorphed(_, newNode) {
|
|
127
|
+
if (newNode instanceof HTMLElement && (newNode.autofocus || newNode.dataset.simpleAutofocus)) {
|
|
128
|
+
autoFocusEls.push(newNode);
|
|
129
|
+
}
|
|
119
130
|
}
|
|
120
131
|
}
|
|
121
132
|
});
|
|
@@ -131,26 +142,31 @@ var emit = async (type, payload) => {
|
|
|
131
142
|
const event = new CustomEvent(`simple-ajax:${type}`, { detail: payload });
|
|
132
143
|
document.dispatchEvent(event);
|
|
133
144
|
};
|
|
145
|
+
var currentUrl = window.location.pathname;
|
|
146
|
+
var prevUrl;
|
|
134
147
|
var visit = async (url, {
|
|
135
148
|
action = "none",
|
|
136
149
|
emitEvents = true,
|
|
137
150
|
isBackForward = false,
|
|
138
|
-
morphHeads =
|
|
151
|
+
morphHeads = globalConfig.morphHeads,
|
|
139
152
|
merge: mergeStrategy = globalConfig.merge,
|
|
140
153
|
autoFocus = true
|
|
141
154
|
} = {}) => {
|
|
142
|
-
|
|
155
|
+
prevUrl = currentUrl;
|
|
156
|
+
currentUrl = url;
|
|
157
|
+
if (emitEvents) emit("before-visit", { url, prevUrl });
|
|
143
158
|
let newDocument;
|
|
144
159
|
if (isBackForward) {
|
|
145
160
|
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
161
|
}
|
|
150
162
|
const regions = findRegions(document);
|
|
151
163
|
newDocument ??= await load(url, Array.from(regions.keys()));
|
|
152
164
|
if (!newDocument) return;
|
|
153
|
-
if (emitEvents) emit("before-render", { url, newDocument });
|
|
165
|
+
if (emitEvents) emit("before-render", { url, prevUrl, newDocument });
|
|
166
|
+
if (!isBackForward) {
|
|
167
|
+
const cacheId = window.location.pathname + window.location.search;
|
|
168
|
+
cache.set(cacheId, document.cloneNode(true));
|
|
169
|
+
}
|
|
154
170
|
if (morphHeads) Idiomorph2.morph(document.head, newDocument.head);
|
|
155
171
|
const getMergeStrategy = (oldEl, newEl) => newEl.dataset.simpleAjax || oldEl.dataset.simpleAjax || mergeStrategy;
|
|
156
172
|
let autoFocusEl;
|
|
@@ -177,7 +193,7 @@ var visit = async (url, {
|
|
|
177
193
|
if (autoFocus) autoFocusEl?.focus();
|
|
178
194
|
if (action === "replace") history.replaceState(null, "", url);
|
|
179
195
|
else if (action === "push") history.pushState(null, "", url);
|
|
180
|
-
if (emitEvents) emit("visit", { url });
|
|
196
|
+
if (emitEvents) emit("visit", { url, prevUrl });
|
|
181
197
|
};
|
|
182
198
|
var findRegions = (doc) => {
|
|
183
199
|
let regions = /* @__PURE__ */ new Map();
|
|
@@ -191,13 +207,15 @@ var findRegions = (doc) => {
|
|
|
191
207
|
// src/start.ts
|
|
192
208
|
var start = ({
|
|
193
209
|
watchHistory = true,
|
|
194
|
-
merge: merge2 = "replace"
|
|
210
|
+
merge: merge2 = "replace",
|
|
211
|
+
morphHeads = true
|
|
195
212
|
} = {}) => {
|
|
196
213
|
globalConfig.merge = merge2;
|
|
197
214
|
globalConfig.watchHistory = watchHistory;
|
|
215
|
+
globalConfig.morphHeads = morphHeads;
|
|
198
216
|
if (watchHistory) {
|
|
199
|
-
window.addEventListener("popstate",
|
|
200
|
-
|
|
217
|
+
window.addEventListener("popstate", () => {
|
|
218
|
+
visit(window.location.pathname + window.location.search, {
|
|
201
219
|
action: "none",
|
|
202
220
|
isBackForward: true
|
|
203
221
|
});
|
|
@@ -206,7 +224,7 @@ var start = ({
|
|
|
206
224
|
};
|
|
207
225
|
|
|
208
226
|
// src/index.ts
|
|
209
|
-
var
|
|
227
|
+
var index_default = { start, visit };
|
|
210
228
|
export {
|
|
211
|
-
|
|
229
|
+
index_default as default
|
|
212
230
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@very-simple/ajax",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
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
|
}
|