@woylie/doggo 0.15.1 → 0.16.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 +8 -1
- package/assets/js/hooks/carousel.js +19 -13
- package/assets/js/hooks/menu.js +47 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ The package can be installed by adding `doggo` to your list of dependencies in
|
|
|
21
21
|
```elixir
|
|
22
22
|
def deps do
|
|
23
23
|
[
|
|
24
|
-
{:doggo, "~> 0.
|
|
24
|
+
{:doggo, "~> 0.16.0"}
|
|
25
25
|
]
|
|
26
26
|
end
|
|
27
27
|
```
|
|
@@ -419,3 +419,10 @@ If you encounter any issues with a component, have suggestions for improvements,
|
|
|
419
419
|
or need a component for a specific use case that isn't currently available,
|
|
420
420
|
please don't hesitate to open a
|
|
421
421
|
[Github issue](https://github.com/woylie/doggo/issues).
|
|
422
|
+
|
|
423
|
+
## Related libraries
|
|
424
|
+
|
|
425
|
+
- [ex_icon](https://github.com/woylie/ex_icon) - Generic icon library for
|
|
426
|
+
Phoenix LiveView.
|
|
427
|
+
- [flop_phoenix](https://github.com/woylie/flop_phoenix) - Pagination, sortable
|
|
428
|
+
table and filter components for Flop.
|
|
@@ -112,6 +112,8 @@ export function initCarousel(carousel) {
|
|
|
112
112
|
|
|
113
113
|
// Auto rotation
|
|
114
114
|
let isPaused = false;
|
|
115
|
+
let isHovered = false;
|
|
116
|
+
let isFocused = false;
|
|
115
117
|
|
|
116
118
|
// Stop auto rotation if the last items does not wrap.
|
|
117
119
|
const hasShowEnded = () =>
|
|
@@ -123,8 +125,11 @@ export function initCarousel(carousel) {
|
|
|
123
125
|
syncPauseControl();
|
|
124
126
|
};
|
|
125
127
|
|
|
128
|
+
const canRotate = () =>
|
|
129
|
+
isAutoRotationEnabled() && !isPaused && !isHovered && !isFocused;
|
|
130
|
+
|
|
126
131
|
const startAutoRotation = () => {
|
|
127
|
-
if (!
|
|
132
|
+
if (!canRotate()) return;
|
|
128
133
|
if (autoRotationTimer != null) return;
|
|
129
134
|
|
|
130
135
|
if (hasShowEnded()) {
|
|
@@ -260,12 +265,8 @@ export function initCarousel(carousel) {
|
|
|
260
265
|
// Pause when hovering or focusing, resume when leaving, unless
|
|
261
266
|
// rotation is paused with the pause button.
|
|
262
267
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
const resume = () => {
|
|
267
|
-
if (!isHovered && !isFocused) startAutoRotation();
|
|
268
|
-
};
|
|
268
|
+
const isPauseControl = (el) =>
|
|
269
|
+
el != null && el.closest?.(`.${baseClass}-pause`) != null;
|
|
269
270
|
|
|
270
271
|
carousel.addEventListener("pointerenter", () => {
|
|
271
272
|
isHovered = true;
|
|
@@ -274,12 +275,17 @@ export function initCarousel(carousel) {
|
|
|
274
275
|
|
|
275
276
|
carousel.addEventListener("pointerleave", () => {
|
|
276
277
|
isHovered = false;
|
|
277
|
-
|
|
278
|
+
startAutoRotation();
|
|
278
279
|
});
|
|
279
280
|
|
|
280
|
-
carousel.addEventListener("focusin", () => {
|
|
281
|
-
isFocused =
|
|
282
|
-
|
|
281
|
+
carousel.addEventListener("focusin", (e) => {
|
|
282
|
+
isFocused = !isPauseControl(e.target);
|
|
283
|
+
|
|
284
|
+
if (isFocused) {
|
|
285
|
+
stopAutoRotation();
|
|
286
|
+
} else {
|
|
287
|
+
startAutoRotation();
|
|
288
|
+
}
|
|
283
289
|
});
|
|
284
290
|
|
|
285
291
|
carousel.addEventListener("focusout", (e) => {
|
|
@@ -288,7 +294,7 @@ export function initCarousel(carousel) {
|
|
|
288
294
|
if (carousel.contains(e.relatedTarget)) return;
|
|
289
295
|
|
|
290
296
|
isFocused = false;
|
|
291
|
-
|
|
297
|
+
startAutoRotation();
|
|
292
298
|
});
|
|
293
299
|
|
|
294
300
|
// Initialize
|
|
@@ -303,7 +309,7 @@ export function initCarousel(carousel) {
|
|
|
303
309
|
// A patch can add or remove the pause button, and with it the
|
|
304
310
|
// rotation. Starting is a no-op while it runs or is paused.
|
|
305
311
|
if (isAutoRotationEnabled()) {
|
|
306
|
-
|
|
312
|
+
startAutoRotation();
|
|
307
313
|
} else {
|
|
308
314
|
stopAutoRotation();
|
|
309
315
|
}
|
package/assets/js/hooks/menu.js
CHANGED
|
@@ -64,20 +64,52 @@ export function initMenu(menu) {
|
|
|
64
64
|
// through the `aria-controls` pointing at it. Compared rather than put in a
|
|
65
65
|
// selector, because the id is the caller's and may hold characters that
|
|
66
66
|
// would change what the selector matches.
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
)
|
|
67
|
+
const getButton = () =>
|
|
68
|
+
Array.from(document.querySelectorAll("[aria-controls]")).find(
|
|
69
|
+
(el) => el.getAttribute("aria-controls") === menu.id,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const close = ({ focusButton } = { focusButton: true }) => {
|
|
73
|
+
const button = getButton();
|
|
71
74
|
|
|
72
75
|
if (!button) return false;
|
|
73
76
|
|
|
74
77
|
menu.setAttribute("hidden", "");
|
|
75
78
|
button.setAttribute("aria-expanded", "false");
|
|
76
|
-
|
|
79
|
+
|
|
80
|
+
if (focusButton) button.focus();
|
|
77
81
|
|
|
78
82
|
return true;
|
|
79
83
|
};
|
|
80
84
|
|
|
85
|
+
const closeOnClickOutside = (e) => {
|
|
86
|
+
if (menu.hidden) return;
|
|
87
|
+
|
|
88
|
+
const button = getButton();
|
|
89
|
+
|
|
90
|
+
if (!button) return;
|
|
91
|
+
if (menu.contains(e.target) || button.contains(e.target)) return;
|
|
92
|
+
|
|
93
|
+
close({ focusButton: false });
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
document.addEventListener("click", closeOnClickOutside);
|
|
97
|
+
|
|
98
|
+
const closeOnButtonEscape = (e) => {
|
|
99
|
+
if (e.key !== "Escape" || menu.hidden) return;
|
|
100
|
+
|
|
101
|
+
const button = getButton();
|
|
102
|
+
|
|
103
|
+
if (!button || !button.contains(e.target)) return;
|
|
104
|
+
|
|
105
|
+
if (close()) {
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
e.stopPropagation();
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
document.addEventListener("keydown", closeOnButtonEscape, true);
|
|
112
|
+
|
|
81
113
|
menu.addEventListener("keydown", (e) => {
|
|
82
114
|
const items = getItems();
|
|
83
115
|
const currentIdx = items.indexOf(e.target.closest(ITEMS));
|
|
@@ -124,7 +156,12 @@ export function initMenu(menu) {
|
|
|
124
156
|
|
|
125
157
|
restoreTabStop();
|
|
126
158
|
|
|
127
|
-
|
|
159
|
+
const destroy = () => {
|
|
160
|
+
document.removeEventListener("click", closeOnClickOutside);
|
|
161
|
+
document.removeEventListener("keydown", closeOnButtonEscape, true);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
return { update: restoreTabStop, destroy };
|
|
128
165
|
}
|
|
129
166
|
|
|
130
167
|
export default {
|
|
@@ -135,4 +172,8 @@ export default {
|
|
|
135
172
|
updated() {
|
|
136
173
|
this.instance.update();
|
|
137
174
|
},
|
|
175
|
+
|
|
176
|
+
destroyed() {
|
|
177
|
+
this.instance.destroy();
|
|
178
|
+
},
|
|
138
179
|
};
|