phoenix_live_view 1.2.0-rc.2 → 1.2.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/README.md +5 -5
- package/assets/js/phoenix_live_view/README.md +3 -0
- package/assets/js/phoenix_live_view/{aria.js → aria.ts} +18 -10
- package/assets/js/phoenix_live_view/{browser.js → browser.ts} +12 -8
- package/assets/js/phoenix_live_view/{dom.js → dom.ts} +107 -34
- package/assets/js/phoenix_live_view/{dom_patch.js → dom_patch.ts} +187 -124
- package/assets/js/phoenix_live_view/{dom_post_morph_restorer.js → dom_post_morph_restorer.ts} +17 -2
- package/assets/js/phoenix_live_view/{element_ref.js → element_ref.ts} +17 -11
- package/assets/js/phoenix_live_view/entry_uploader.js +4 -4
- package/assets/js/phoenix_live_view/{hooks.js → hooks.ts} +108 -91
- package/assets/js/phoenix_live_view/index.ts +14 -301
- package/assets/js/phoenix_live_view/js.js +2 -1
- package/assets/js/phoenix_live_view/js_commands.ts +12 -9
- package/assets/js/phoenix_live_view/{live_socket.js → live_socket.ts} +582 -114
- package/assets/js/phoenix_live_view/live_uploader.js +1 -1
- package/assets/js/phoenix_live_view/rendered.js +3 -0
- package/assets/js/phoenix_live_view/{utils.js → utils.ts} +35 -6
- package/assets/js/phoenix_live_view/{view.js → view.ts} +221 -110
- package/assets/js/phoenix_live_view/view_hook.ts +92 -32
- package/package.json +5 -2
- package/priv/static/phoenix_live_view.cjs.js +577 -314
- package/priv/static/phoenix_live_view.cjs.js.map +4 -4
- package/priv/static/phoenix_live_view.esm.js +577 -314
- package/priv/static/phoenix_live_view.esm.js.map +4 -4
- package/priv/static/phoenix_live_view.js +584 -314
- package/priv/static/phoenix_live_view.min.js +7 -7
- /package/assets/js/phoenix_live_view/{constants.js → constants.ts} +0 -0
|
@@ -29,13 +29,17 @@ export default class ElementRef {
|
|
|
29
29
|
);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
private el: Element;
|
|
33
|
+
private loadingRef: number | null;
|
|
34
|
+
private lockRef: number | null;
|
|
35
|
+
|
|
36
|
+
constructor(el: Element) {
|
|
33
37
|
this.el = el;
|
|
34
38
|
this.loadingRef = el.hasAttribute(PHX_REF_LOADING)
|
|
35
|
-
? parseInt(el.getAttribute(PHX_REF_LOADING)
|
|
39
|
+
? parseInt(el.getAttribute(PHX_REF_LOADING)!, 10)
|
|
36
40
|
: null;
|
|
37
41
|
this.lockRef = el.hasAttribute(PHX_REF_LOCK)
|
|
38
|
-
? parseInt(el.getAttribute(PHX_REF_LOCK)
|
|
42
|
+
? parseInt(el.getAttribute(PHX_REF_LOCK)!, 10)
|
|
39
43
|
: null;
|
|
40
44
|
}
|
|
41
45
|
|
|
@@ -89,7 +93,7 @@ export default class ElementRef {
|
|
|
89
93
|
|
|
90
94
|
// private
|
|
91
95
|
|
|
92
|
-
isWithin(ref) {
|
|
96
|
+
private isWithin(ref) {
|
|
93
97
|
return !(
|
|
94
98
|
this.loadingRef !== null &&
|
|
95
99
|
this.loadingRef > ref &&
|
|
@@ -104,7 +108,7 @@ export default class ElementRef {
|
|
|
104
108
|
//
|
|
105
109
|
// 1. execute pending mounted hooks for nodes now in the DOM
|
|
106
110
|
// 2. undo any ref inside the cloned tree that has since been ack'd
|
|
107
|
-
undoLocks(ref, phxEvent, eachCloneCallback) {
|
|
111
|
+
private undoLocks(ref, phxEvent, eachCloneCallback) {
|
|
108
112
|
if (!this.isLockUndoneBy(ref)) {
|
|
109
113
|
return;
|
|
110
114
|
}
|
|
@@ -126,7 +130,7 @@ export default class ElementRef {
|
|
|
126
130
|
);
|
|
127
131
|
}
|
|
128
132
|
|
|
129
|
-
undoLoading(ref, phxEvent) {
|
|
133
|
+
private undoLoading(ref, phxEvent) {
|
|
130
134
|
if (!this.isLoadingUndoneBy(ref)) {
|
|
131
135
|
if (
|
|
132
136
|
this.canUndoLoading(ref) &&
|
|
@@ -142,11 +146,11 @@ export default class ElementRef {
|
|
|
142
146
|
const disabledVal = this.el.getAttribute(PHX_DISABLED);
|
|
143
147
|
const readOnlyVal = this.el.getAttribute(PHX_READONLY);
|
|
144
148
|
// restore inputs
|
|
145
|
-
if (readOnlyVal !== null) {
|
|
149
|
+
if (readOnlyVal !== null && "readOnly" in this.el) {
|
|
146
150
|
this.el.readOnly = readOnlyVal === "true" ? true : false;
|
|
147
151
|
this.el.removeAttribute(PHX_READONLY);
|
|
148
152
|
}
|
|
149
|
-
if (disabledVal !== null) {
|
|
153
|
+
if (disabledVal !== null && "disabled" in this.el) {
|
|
150
154
|
this.el.disabled = disabledVal === "true" ? true : false;
|
|
151
155
|
this.el.removeAttribute(PHX_DISABLED);
|
|
152
156
|
}
|
|
@@ -175,14 +179,16 @@ export default class ElementRef {
|
|
|
175
179
|
});
|
|
176
180
|
}
|
|
177
181
|
|
|
178
|
-
isLoadingUndoneBy(ref) {
|
|
182
|
+
private isLoadingUndoneBy(ref) {
|
|
179
183
|
return this.loadingRef === null ? false : this.loadingRef <= ref;
|
|
180
184
|
}
|
|
185
|
+
|
|
186
|
+
/** @internal */
|
|
181
187
|
isLockUndoneBy(ref) {
|
|
182
188
|
return this.lockRef === null ? false : this.lockRef <= ref;
|
|
183
189
|
}
|
|
184
190
|
|
|
185
|
-
isFullyResolvedBy(ref) {
|
|
191
|
+
private isFullyResolvedBy(ref) {
|
|
186
192
|
return (
|
|
187
193
|
(this.loadingRef === null || this.loadingRef <= ref) &&
|
|
188
194
|
(this.lockRef === null || this.lockRef <= ref)
|
|
@@ -190,7 +196,7 @@ export default class ElementRef {
|
|
|
190
196
|
}
|
|
191
197
|
|
|
192
198
|
// only remove the phx-submit-loading class if we are not locked
|
|
193
|
-
canUndoLoading(ref) {
|
|
199
|
+
private canUndoLoading(ref) {
|
|
194
200
|
return this.lockRef === null || this.lockRef <= ref;
|
|
195
201
|
}
|
|
196
202
|
}
|
|
@@ -21,7 +21,7 @@ export default class EntryUploader {
|
|
|
21
21
|
}
|
|
22
22
|
this.uploadChannel.leave();
|
|
23
23
|
this.errored = true;
|
|
24
|
-
clearTimeout(this.chunkTimer);
|
|
24
|
+
this.chunkTimer != null && clearTimeout(this.chunkTimer);
|
|
25
25
|
this.entry.error(reason);
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -30,7 +30,7 @@ export default class EntryUploader {
|
|
|
30
30
|
this.uploadChannel
|
|
31
31
|
.join()
|
|
32
32
|
.receive("ok", (_data) => this.readNextChunk())
|
|
33
|
-
.receive("error", (reason) => this.error(reason));
|
|
33
|
+
.receive("error", ({ reason }) => this.error(reason));
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
isDone() {
|
|
@@ -44,11 +44,11 @@ export default class EntryUploader {
|
|
|
44
44
|
this.chunkSize + this.offset,
|
|
45
45
|
);
|
|
46
46
|
reader.onload = (e) => {
|
|
47
|
-
if (e.target
|
|
47
|
+
if (e.target?.error === null) {
|
|
48
48
|
this.offset += /** @type {ArrayBuffer} */ (e.target.result).byteLength;
|
|
49
49
|
this.pushChunk(/** @type {ArrayBuffer} */ (e.target.result));
|
|
50
50
|
} else {
|
|
51
|
-
return logError("Read error: " + e.target
|
|
51
|
+
return logError("Read error: " + e.target?.error);
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
54
|
reader.readAsArrayBuffer(blob);
|
|
@@ -6,89 +6,12 @@ import {
|
|
|
6
6
|
PHX_VIEWPORT_OVERRUN_TARGET,
|
|
7
7
|
} from "./constants";
|
|
8
8
|
|
|
9
|
+
import type { Hook } from "./view_hook";
|
|
10
|
+
|
|
9
11
|
import LiveUploader from "./live_uploader";
|
|
10
12
|
import ARIA from "./aria";
|
|
11
13
|
|
|
12
|
-
const
|
|
13
|
-
LiveFileUpload: {
|
|
14
|
-
activeRefs() {
|
|
15
|
-
return this.el.getAttribute(PHX_ACTIVE_ENTRY_REFS);
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
preflightedRefs() {
|
|
19
|
-
return this.el.getAttribute(PHX_PREFLIGHTED_REFS);
|
|
20
|
-
},
|
|
21
|
-
|
|
22
|
-
mounted() {
|
|
23
|
-
this.js().ignoreAttributes(this.el, ["value"]);
|
|
24
|
-
this.preflightedWas = this.preflightedRefs();
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
updated() {
|
|
28
|
-
const newPreflights = this.preflightedRefs();
|
|
29
|
-
if (this.preflightedWas !== newPreflights) {
|
|
30
|
-
this.preflightedWas = newPreflights;
|
|
31
|
-
if (newPreflights === "") {
|
|
32
|
-
this.__view().cancelSubmit(this.el.form);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (this.activeRefs() === "") {
|
|
37
|
-
this.el.value = null;
|
|
38
|
-
}
|
|
39
|
-
this.el.dispatchEvent(new CustomEvent(PHX_LIVE_FILE_UPDATED));
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
LiveImgPreview: {
|
|
44
|
-
mounted() {
|
|
45
|
-
this.ref = this.el.getAttribute("data-phx-entry-ref");
|
|
46
|
-
this.inputEl = document.getElementById(
|
|
47
|
-
this.el.getAttribute(PHX_UPLOAD_REF),
|
|
48
|
-
);
|
|
49
|
-
this.url = LiveUploader.getEntryDataURL(this.inputEl, this.ref);
|
|
50
|
-
this.el.src = this.url;
|
|
51
|
-
},
|
|
52
|
-
destroyed() {
|
|
53
|
-
URL.revokeObjectURL(this.url);
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
FocusWrap: {
|
|
57
|
-
mounted() {
|
|
58
|
-
this.focusStart = this.el.firstElementChild;
|
|
59
|
-
this.focusEnd = this.el.lastElementChild;
|
|
60
|
-
this.focusStart.addEventListener("focus", (e) => {
|
|
61
|
-
if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) {
|
|
62
|
-
// Handle focus entering from outside (e.g. Tab when body is focused)
|
|
63
|
-
// https://github.com/phoenixframework/phoenix_live_view/issues/3636
|
|
64
|
-
const nextFocus = e.target.nextElementSibling;
|
|
65
|
-
ARIA.attemptFocus(nextFocus) || ARIA.focusFirst(nextFocus);
|
|
66
|
-
} else {
|
|
67
|
-
ARIA.focusLast(this.el);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
this.focusEnd.addEventListener("focus", (e) => {
|
|
71
|
-
if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) {
|
|
72
|
-
// Handle focus entering from outside (e.g. Shift+Tab when body is focused)
|
|
73
|
-
// https://github.com/phoenixframework/phoenix_live_view/issues/3636
|
|
74
|
-
const nextFocus = e.target.previousElementSibling;
|
|
75
|
-
ARIA.attemptFocus(nextFocus) || ARIA.focusLast(nextFocus);
|
|
76
|
-
} else {
|
|
77
|
-
ARIA.focusFirst(this.el);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
// only try to change the focus if it is not already inside
|
|
81
|
-
if (!this.el.contains(document.activeElement)) {
|
|
82
|
-
this.el.addEventListener("phx:show-end", () => this.el.focus());
|
|
83
|
-
if (window.getComputedStyle(this.el).display !== "none") {
|
|
84
|
-
ARIA.focusFirst(this.el);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const findScrollContainer = (el) => {
|
|
14
|
+
const findScrollContainer = (el): HTMLElement | null => {
|
|
92
15
|
// the scroll event won't be fired on the html/body element even if overflow is set
|
|
93
16
|
// therefore we return null to instead listen for scroll events on document
|
|
94
17
|
if (["HTML", "BODY"].indexOf(el.nodeName.toUpperCase()) >= 0) return null;
|
|
@@ -97,7 +20,7 @@ const findScrollContainer = (el) => {
|
|
|
97
20
|
return findScrollContainer(el.parentElement);
|
|
98
21
|
};
|
|
99
22
|
|
|
100
|
-
const scrollTop = (scrollContainer) => {
|
|
23
|
+
const scrollTop = (scrollContainer: HTMLElement | null) => {
|
|
101
24
|
if (scrollContainer) {
|
|
102
25
|
return scrollContainer.scrollTop;
|
|
103
26
|
} else {
|
|
@@ -105,7 +28,7 @@ const scrollTop = (scrollContainer) => {
|
|
|
105
28
|
}
|
|
106
29
|
};
|
|
107
30
|
|
|
108
|
-
const bottom = (scrollContainer) => {
|
|
31
|
+
const bottom = (scrollContainer: HTMLElement | null) => {
|
|
109
32
|
if (scrollContainer) {
|
|
110
33
|
return scrollContainer.getBoundingClientRect().bottom;
|
|
111
34
|
} else {
|
|
@@ -115,7 +38,7 @@ const bottom = (scrollContainer) => {
|
|
|
115
38
|
}
|
|
116
39
|
};
|
|
117
40
|
|
|
118
|
-
const top = (scrollContainer) => {
|
|
41
|
+
const top = (scrollContainer: HTMLElement | null) => {
|
|
119
42
|
if (scrollContainer) {
|
|
120
43
|
return scrollContainer.getBoundingClientRect().top;
|
|
121
44
|
} else {
|
|
@@ -125,7 +48,7 @@ const top = (scrollContainer) => {
|
|
|
125
48
|
}
|
|
126
49
|
};
|
|
127
50
|
|
|
128
|
-
const isAtViewportTop = (el, scrollContainer) => {
|
|
51
|
+
const isAtViewportTop = (el: Element, scrollContainer: HTMLElement | null) => {
|
|
129
52
|
const rect = el.getBoundingClientRect();
|
|
130
53
|
return (
|
|
131
54
|
Math.ceil(rect.top) >= top(scrollContainer) &&
|
|
@@ -133,7 +56,10 @@ const isAtViewportTop = (el, scrollContainer) => {
|
|
|
133
56
|
);
|
|
134
57
|
};
|
|
135
58
|
|
|
136
|
-
const isAtViewportBottom = (
|
|
59
|
+
const isAtViewportBottom = (
|
|
60
|
+
el: Element,
|
|
61
|
+
scrollContainer: HTMLElement | null,
|
|
62
|
+
) => {
|
|
137
63
|
const rect = el.getBoundingClientRect();
|
|
138
64
|
return (
|
|
139
65
|
Math.ceil(rect.bottom) >= top(scrollContainer) &&
|
|
@@ -141,7 +67,7 @@ const isAtViewportBottom = (el, scrollContainer) => {
|
|
|
141
67
|
);
|
|
142
68
|
};
|
|
143
69
|
|
|
144
|
-
const isWithinViewport = (el, scrollContainer) => {
|
|
70
|
+
const isWithinViewport = (el: Element, scrollContainer: HTMLElement | null) => {
|
|
145
71
|
const rect = el.getBoundingClientRect();
|
|
146
72
|
return (
|
|
147
73
|
Math.ceil(rect.top) >= top(scrollContainer) &&
|
|
@@ -149,13 +75,18 @@ const isWithinViewport = (el, scrollContainer) => {
|
|
|
149
75
|
);
|
|
150
76
|
};
|
|
151
77
|
|
|
152
|
-
|
|
78
|
+
const InfiniteScroll: Hook<
|
|
79
|
+
{
|
|
80
|
+
scrollContainer: HTMLElement | null;
|
|
81
|
+
},
|
|
82
|
+
HTMLElement
|
|
83
|
+
> = {
|
|
153
84
|
mounted() {
|
|
154
85
|
this.scrollContainer = findScrollContainer(this.el);
|
|
155
86
|
let scrollBefore = scrollTop(this.scrollContainer);
|
|
156
87
|
let topOverran = false;
|
|
157
88
|
const throttleInterval = 500;
|
|
158
|
-
let pendingOp = null;
|
|
89
|
+
let pendingOp: (() => void) | null = null;
|
|
159
90
|
|
|
160
91
|
const onTopOverrun = this.throttle(
|
|
161
92
|
throttleInterval,
|
|
@@ -208,7 +139,7 @@ Hooks.InfiniteScroll = {
|
|
|
208
139
|
},
|
|
209
140
|
);
|
|
210
141
|
|
|
211
|
-
this.onScroll = (_e) => {
|
|
142
|
+
this.onScroll = (_e: Event) => {
|
|
212
143
|
const scrollNow = scrollTop(this.scrollContainer);
|
|
213
144
|
|
|
214
145
|
if (pendingOp) {
|
|
@@ -239,12 +170,14 @@ Hooks.InfiniteScroll = {
|
|
|
239
170
|
if (
|
|
240
171
|
topEvent &&
|
|
241
172
|
isScrollingUp &&
|
|
173
|
+
firstChild &&
|
|
242
174
|
isAtViewportTop(firstChild, this.scrollContainer)
|
|
243
175
|
) {
|
|
244
176
|
onFirstChildAtTop(topEvent, firstChild);
|
|
245
177
|
} else if (
|
|
246
178
|
bottomEvent &&
|
|
247
179
|
isScrollingDown &&
|
|
180
|
+
lastChild &&
|
|
248
181
|
isAtViewportBottom(lastChild, this.scrollContainer)
|
|
249
182
|
) {
|
|
250
183
|
onLastChildAtBottom(bottomEvent, lastChild);
|
|
@@ -263,8 +196,8 @@ Hooks.InfiniteScroll = {
|
|
|
263
196
|
// Check if the scroll container still exists
|
|
264
197
|
// https://github.com/phoenixframework/phoenix_live_view/issues/4169.
|
|
265
198
|
if (this.scrollContainer && !this.scrollContainer.isConnected) {
|
|
266
|
-
this.destroyed();
|
|
267
|
-
this.mounted();
|
|
199
|
+
this.destroyed!();
|
|
200
|
+
this.mounted!();
|
|
268
201
|
}
|
|
269
202
|
},
|
|
270
203
|
|
|
@@ -319,4 +252,88 @@ Hooks.InfiniteScroll = {
|
|
|
319
252
|
return rect;
|
|
320
253
|
},
|
|
321
254
|
};
|
|
255
|
+
|
|
256
|
+
const LiveFileUpload: Hook<object, HTMLInputElement> = {
|
|
257
|
+
activeRefs() {
|
|
258
|
+
return this.el.getAttribute(PHX_ACTIVE_ENTRY_REFS);
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
preflightedRefs() {
|
|
262
|
+
return this.el.getAttribute(PHX_PREFLIGHTED_REFS);
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
mounted() {
|
|
266
|
+
this.js().ignoreAttributes(this.el, ["value"]);
|
|
267
|
+
this.preflightedWas = this.preflightedRefs();
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
updated() {
|
|
271
|
+
const newPreflights = this.preflightedRefs();
|
|
272
|
+
if (this.preflightedWas !== newPreflights) {
|
|
273
|
+
this.preflightedWas = newPreflights;
|
|
274
|
+
if (newPreflights === "") {
|
|
275
|
+
this.__view().cancelSubmit(this.el.form);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (this.activeRefs() === "") {
|
|
280
|
+
this.el.value = "";
|
|
281
|
+
}
|
|
282
|
+
this.el.dispatchEvent(new CustomEvent(PHX_LIVE_FILE_UPDATED));
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const LiveImgPreview: Hook<object, HTMLImageElement> = {
|
|
287
|
+
mounted() {
|
|
288
|
+
this.ref = this.el.getAttribute("data-phx-entry-ref");
|
|
289
|
+
this.inputEl = document.getElementById(
|
|
290
|
+
this.el.getAttribute(PHX_UPLOAD_REF)!,
|
|
291
|
+
);
|
|
292
|
+
this.url = LiveUploader.getEntryDataURL(this.inputEl, this.ref);
|
|
293
|
+
this.el.src = this.url;
|
|
294
|
+
},
|
|
295
|
+
destroyed() {
|
|
296
|
+
URL.revokeObjectURL(this.url);
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const Hooks: Record<string, Hook<any, any>> = {
|
|
301
|
+
LiveFileUpload,
|
|
302
|
+
LiveImgPreview,
|
|
303
|
+
FocusWrap: {
|
|
304
|
+
mounted() {
|
|
305
|
+
this.focusStart = this.el.firstElementChild;
|
|
306
|
+
this.focusEnd = this.el.lastElementChild;
|
|
307
|
+
this.focusStart.addEventListener("focus", (e) => {
|
|
308
|
+
if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) {
|
|
309
|
+
// Handle focus entering from outside (e.g. Tab when body is focused)
|
|
310
|
+
// https://github.com/phoenixframework/phoenix_live_view/issues/3636
|
|
311
|
+
const nextFocus = e.target.nextElementSibling;
|
|
312
|
+
ARIA.attemptFocus(nextFocus) || ARIA.focusFirst(nextFocus);
|
|
313
|
+
} else {
|
|
314
|
+
ARIA.focusLast(this.el);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
this.focusEnd.addEventListener("focus", (e) => {
|
|
318
|
+
if (!e.relatedTarget || !this.el.contains(e.relatedTarget)) {
|
|
319
|
+
// Handle focus entering from outside (e.g. Shift+Tab when body is focused)
|
|
320
|
+
// https://github.com/phoenixframework/phoenix_live_view/issues/3636
|
|
321
|
+
const nextFocus = e.target.previousElementSibling;
|
|
322
|
+
ARIA.attemptFocus(nextFocus) || ARIA.focusLast(nextFocus);
|
|
323
|
+
} else {
|
|
324
|
+
ARIA.focusFirst(this.el);
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
// only try to change the focus if it is not already inside
|
|
328
|
+
if (!this.el.contains(document.activeElement)) {
|
|
329
|
+
this.el.addEventListener("phx:show-end", () => this.el.focus());
|
|
330
|
+
if (window.getComputedStyle(this.el).display !== "none") {
|
|
331
|
+
ARIA.focusFirst(this.el);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
InfiniteScroll,
|
|
337
|
+
};
|
|
338
|
+
|
|
322
339
|
export default Hooks;
|