@stimulus-library/mixins 1.0.1 → 1.0.3
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 +18 -18
- package/dist/index.js +18 -18
- package/dist/install_class_methods.js +8 -8
- package/dist/use_click_outside.js +1 -1
- package/dist/use_dirty_form_tracking.js +25 -25
- package/dist/use_event_bus.js +4 -4
- package/dist/use_event_listener.js +5 -5
- package/dist/use_fullscreen.js +3 -3
- package/dist/use_geolocation.js +2 -2
- package/dist/use_hover.js +4 -4
- package/dist/use_injected_html.js +6 -6
- package/dist/use_intersection.js +7 -7
- package/dist/use_interval.js +2 -2
- package/dist/use_localstorage.js +6 -7
- package/dist/use_mutation_observer.js +3 -3
- package/dist/use_resize_observer.js +3 -3
- package/dist/use_temporary_content.js +1 -1
- package/dist/use_text_selection.js +4 -4
- package/dist/use_timeout.js +4 -3
- package/dist/use_trix_modifiers.js +25 -25
- package/package.json +5 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from
|
|
11
|
-
export * from
|
|
12
|
-
export * from
|
|
13
|
-
export * from
|
|
14
|
-
export * from
|
|
15
|
-
export * from
|
|
16
|
-
export * from
|
|
17
|
-
export * from
|
|
18
|
-
export * from
|
|
1
|
+
export * from "./install_class_methods";
|
|
2
|
+
export * from "./use_click_outside";
|
|
3
|
+
export * from "./use_dirty_form_tracking";
|
|
4
|
+
export * from "./use_event_bus";
|
|
5
|
+
export * from "./use_event_listener";
|
|
6
|
+
export * from "./use_fullscreen";
|
|
7
|
+
export * from "./use_geolocation";
|
|
8
|
+
export * from "./use_hover";
|
|
9
|
+
export * from "./use_injected_html";
|
|
10
|
+
export * from "./use_intersection";
|
|
11
|
+
export * from "./use_interval";
|
|
12
|
+
export * from "./use_localstorage";
|
|
13
|
+
export * from "./use_mutation_observer";
|
|
14
|
+
export * from "./use_resize_observer";
|
|
15
|
+
export * from "./use_temporary_content";
|
|
16
|
+
export * from "./use_text_selection";
|
|
17
|
+
export * from "./use_timeout";
|
|
18
|
+
export * from "./use_trix_modifiers";
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from
|
|
11
|
-
export * from
|
|
12
|
-
export * from
|
|
13
|
-
export * from
|
|
14
|
-
export * from
|
|
15
|
-
export * from
|
|
16
|
-
export * from
|
|
17
|
-
export * from
|
|
18
|
-
export * from
|
|
1
|
+
export * from "./install_class_methods";
|
|
2
|
+
export * from "./use_click_outside";
|
|
3
|
+
export * from "./use_dirty_form_tracking";
|
|
4
|
+
export * from "./use_event_bus";
|
|
5
|
+
export * from "./use_event_listener";
|
|
6
|
+
export * from "./use_fullscreen";
|
|
7
|
+
export * from "./use_geolocation";
|
|
8
|
+
export * from "./use_hover";
|
|
9
|
+
export * from "./use_injected_html";
|
|
10
|
+
export * from "./use_intersection";
|
|
11
|
+
export * from "./use_interval";
|
|
12
|
+
export * from "./use_localstorage";
|
|
13
|
+
export * from "./use_mutation_observer";
|
|
14
|
+
export * from "./use_resize_observer";
|
|
15
|
+
export * from "./use_temporary_content";
|
|
16
|
+
export * from "./use_text_selection";
|
|
17
|
+
export * from "./use_timeout";
|
|
18
|
+
export * from "./use_trix_modifiers";
|
|
@@ -3,17 +3,17 @@ import { controllerMethod, pascalCase } from "@stimulus-library/utilities";
|
|
|
3
3
|
export class InstallClassMethodComposableController extends Controller {
|
|
4
4
|
}
|
|
5
5
|
function addMethodsForClassDefinition(controller, name) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
const defaultElement = controller.element;
|
|
7
|
+
const hasClass = () => controller[`has${pascalCase(name)}Class`] == true;
|
|
8
|
+
const classes = () => controller[`${name}Classes`];
|
|
9
|
+
const defaultClasses = () => controllerMethod(controller, `default${pascalCase(name)}Classes`).call(controller) || [];
|
|
10
|
+
const classOrDefault = () => hasClass() ? classes() : defaultClasses();
|
|
11
11
|
if (controller[`${name}Classes`] == undefined) {
|
|
12
12
|
Object.defineProperty(controller, `${name}Classes`, {
|
|
13
|
-
get: () => hasClass() ? controller[`${name}Class`].split(
|
|
13
|
+
get: () => hasClass() ? controller[`${name}Class`].split(" ") : defaultClasses(),
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
const methods = {
|
|
17
17
|
[`add${pascalCase(name)}Classes`]: (element = defaultElement) => element.classList.add(...classOrDefault()),
|
|
18
18
|
[`remove${pascalCase(name)}Classes`]: (element = defaultElement) => element.classList.remove(...classOrDefault()),
|
|
19
19
|
[`${name}ClassesPresent`]: (element = defaultElement) => classOrDefault().every((klass) => element.classList.contains(klass)),
|
|
@@ -22,6 +22,6 @@ function addMethodsForClassDefinition(controller, name) {
|
|
|
22
22
|
}
|
|
23
23
|
export function installClassMethods(controller) {
|
|
24
24
|
// @ts-ignore
|
|
25
|
-
|
|
25
|
+
const classes = controller.constructor.classes || [];
|
|
26
26
|
classes.forEach((classDefinition) => addMethodsForClassDefinition(controller, classDefinition));
|
|
27
27
|
}
|
|
@@ -9,7 +9,7 @@ export function useClickOutside(controller, element, callback) {
|
|
|
9
9
|
}
|
|
10
10
|
callback(event);
|
|
11
11
|
};
|
|
12
|
-
|
|
12
|
+
const { teardown } = useEventListener(controller, window, ["click", "touchend"], handler);
|
|
13
13
|
useMixin(controller, () => void 0, teardown);
|
|
14
14
|
return {
|
|
15
15
|
teardown,
|
|
@@ -3,12 +3,12 @@ import { getOtherRadiosInGroup, isElementCheckable, isHTMLInputElement, isHTMLSe
|
|
|
3
3
|
import { useEventListener } from "./use_event_listener";
|
|
4
4
|
const CACHE_ATTR_NAME = "data-detect-dirty-load-value";
|
|
5
5
|
export function useDirtyInputTracking(controller, element) {
|
|
6
|
-
|
|
6
|
+
const setup = () => {
|
|
7
7
|
cacheLoadValues(element);
|
|
8
8
|
checkDirty(element);
|
|
9
9
|
useEventListener(controller, element, ["input", "change"], () => checkDirty(element), { debounce: 10 });
|
|
10
10
|
};
|
|
11
|
-
|
|
11
|
+
const teardown = () => {
|
|
12
12
|
};
|
|
13
13
|
useMixin(controller, setup, teardown);
|
|
14
14
|
return {
|
|
@@ -17,17 +17,17 @@ export function useDirtyInputTracking(controller, element) {
|
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
export function useDirtyFormTracking(controller, form) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
const teardowns = [];
|
|
21
|
+
const restores = [];
|
|
22
|
+
const setup = () => {
|
|
23
23
|
form.querySelectorAll("input, select, textarea").forEach((element) => {
|
|
24
|
-
|
|
24
|
+
const functions = useDirtyInputTracking(controller, element);
|
|
25
25
|
teardowns.push(functions.teardown);
|
|
26
26
|
restores.push(functions.restore);
|
|
27
27
|
});
|
|
28
|
-
useEventListener(controller, form,
|
|
29
|
-
form.setAttribute(
|
|
30
|
-
form.dispatchEvent(new CustomEvent(
|
|
28
|
+
useEventListener(controller, form, "input-dirtied", () => {
|
|
29
|
+
form.setAttribute("data-dirty", "true");
|
|
30
|
+
form.dispatchEvent(new CustomEvent("form-dirtied", {
|
|
31
31
|
bubbles: true,
|
|
32
32
|
cancelable: true,
|
|
33
33
|
detail: {
|
|
@@ -35,10 +35,10 @@ export function useDirtyFormTracking(controller, form) {
|
|
|
35
35
|
},
|
|
36
36
|
}));
|
|
37
37
|
});
|
|
38
|
-
useEventListener(controller, form,
|
|
39
|
-
if (form.querySelectorAll(
|
|
40
|
-
form.removeAttribute(
|
|
41
|
-
form.dispatchEvent(new CustomEvent(
|
|
38
|
+
useEventListener(controller, form, "input-cleaned", () => {
|
|
39
|
+
if (form.querySelectorAll("[data-dirty=\"true\"]").length === 0) {
|
|
40
|
+
form.removeAttribute("data-dirty");
|
|
41
|
+
form.dispatchEvent(new CustomEvent("form-cleaned", {
|
|
42
42
|
bubbles: true,
|
|
43
43
|
cancelable: true,
|
|
44
44
|
detail: {
|
|
@@ -48,10 +48,10 @@ export function useDirtyFormTracking(controller, form) {
|
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
};
|
|
51
|
-
|
|
51
|
+
const teardown = () => {
|
|
52
52
|
teardowns.forEach((teardown) => teardown());
|
|
53
53
|
};
|
|
54
|
-
|
|
54
|
+
const restore = () => {
|
|
55
55
|
restores.forEach((restore) => restore());
|
|
56
56
|
};
|
|
57
57
|
useMixin(controller, setup, teardown);
|
|
@@ -64,12 +64,12 @@ function getElementValue(element) {
|
|
|
64
64
|
return isElementCheckable(element) ? element.checked : element.value;
|
|
65
65
|
}
|
|
66
66
|
function getElementLoadValue(element) {
|
|
67
|
-
|
|
67
|
+
const value = element.getAttribute(CACHE_ATTR_NAME);
|
|
68
68
|
if (isElementCheckable(element)) {
|
|
69
69
|
return value == null ? element.defaultChecked : value == "true";
|
|
70
70
|
}
|
|
71
71
|
else if (isHTMLSelectElement(element)) {
|
|
72
|
-
|
|
72
|
+
const options = Array.from(element.options);
|
|
73
73
|
options.forEach((option) => {
|
|
74
74
|
if (option.defaultSelected) {
|
|
75
75
|
return option.value;
|
|
@@ -86,12 +86,12 @@ function elementHasCachedLoadValue(element) {
|
|
|
86
86
|
}
|
|
87
87
|
function checkDirty(element) {
|
|
88
88
|
if (isHTMLInputElement(element) && element.type == "radio") {
|
|
89
|
-
getOtherRadiosInGroup(element).forEach((radio) => radio.removeAttribute(
|
|
89
|
+
getOtherRadiosInGroup(element).forEach((radio) => radio.removeAttribute("data-dirty"));
|
|
90
90
|
}
|
|
91
91
|
if (isElementDirty(element)) {
|
|
92
|
-
element.setAttribute(
|
|
93
|
-
element.form?.setAttribute(
|
|
94
|
-
element.dispatchEvent(new CustomEvent(
|
|
92
|
+
element.setAttribute("data-dirty", "true");
|
|
93
|
+
element.form?.setAttribute("data-dirty", "true");
|
|
94
|
+
element.dispatchEvent(new CustomEvent("input-dirtied", {
|
|
95
95
|
bubbles: true,
|
|
96
96
|
cancelable: true,
|
|
97
97
|
detail: {
|
|
@@ -100,8 +100,8 @@ function checkDirty(element) {
|
|
|
100
100
|
}));
|
|
101
101
|
}
|
|
102
102
|
else {
|
|
103
|
-
element.removeAttribute(
|
|
104
|
-
element.dispatchEvent(new CustomEvent(
|
|
103
|
+
element.removeAttribute("data-dirty");
|
|
104
|
+
element.dispatchEvent(new CustomEvent("input-cleaned", {
|
|
105
105
|
bubbles: true,
|
|
106
106
|
cancelable: true,
|
|
107
107
|
detail: {
|
|
@@ -114,14 +114,14 @@ function isElementDirty(element) {
|
|
|
114
114
|
return getElementValue(element) !== getElementLoadValue(element);
|
|
115
115
|
}
|
|
116
116
|
function restoreElementFromLoadValue(element) {
|
|
117
|
-
|
|
117
|
+
const cacheValue = element.getAttribute(CACHE_ATTR_NAME);
|
|
118
118
|
if (isElementCheckable(element)) {
|
|
119
119
|
element.setAttribute(CACHE_ATTR_NAME, element.checked.toString());
|
|
120
120
|
element.checked = cacheValue == null ? element.defaultChecked : cacheValue == "true";
|
|
121
121
|
}
|
|
122
122
|
else if (isHTMLSelectElement(element)) {
|
|
123
123
|
if (cacheValue == null) {
|
|
124
|
-
|
|
124
|
+
const options = Array.from(element.options);
|
|
125
125
|
options.forEach((option) => {
|
|
126
126
|
if (option.defaultSelected) {
|
|
127
127
|
element.value = option.value;
|
package/dist/use_event_bus.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { debounce, EventBus, wrapArray } from "@stimulus-library/utilities";
|
|
2
2
|
import { useMixin } from "./use_mixin";
|
|
3
3
|
export function useEventBus(controller, eventNameOrNames, handler, opts) {
|
|
4
|
-
|
|
4
|
+
const options = opts;
|
|
5
5
|
if (options?.debounce) {
|
|
6
6
|
handler = debounce(handler.bind(controller), options.debounce);
|
|
7
7
|
delete options.debounce;
|
|
@@ -9,9 +9,9 @@ export function useEventBus(controller, eventNameOrNames, handler, opts) {
|
|
|
9
9
|
else {
|
|
10
10
|
handler = handler.bind(controller);
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const eventNames = wrapArray(eventNameOrNames);
|
|
13
|
+
const setup = () => eventNames.forEach(eventName => EventBus.on(eventName, handler));
|
|
14
|
+
const teardown = () => eventNames.forEach(eventName => EventBus.off(eventName, handler));
|
|
15
15
|
useMixin(controller, setup, teardown);
|
|
16
16
|
return { setup, teardown };
|
|
17
17
|
}
|
|
@@ -8,9 +8,9 @@ export function useEventListener(controller, element, eventNameOrNames, handler,
|
|
|
8
8
|
else {
|
|
9
9
|
handler = handler.bind(controller);
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
const eventNames = wrapArray(eventNameOrNames);
|
|
12
|
+
const setup = () => eventNames.forEach(eventName => element.addEventListener(eventName, handler, opts));
|
|
13
|
+
const teardown = () => eventNames.forEach(eventName => element.removeEventListener(eventName, handler));
|
|
14
14
|
useMixin(controller, setup, teardown);
|
|
15
15
|
return { setup, teardown };
|
|
16
16
|
}
|
|
@@ -18,9 +18,9 @@ export function useEventListeners(controller, element, eventNameOrNames, handler
|
|
|
18
18
|
return useEventListener(controller, element, eventNameOrNames, handler, opts);
|
|
19
19
|
}
|
|
20
20
|
export function useCollectionEventListener(controller, elements, eventNameOrNames, handler, opts) {
|
|
21
|
-
|
|
21
|
+
const handlers = [];
|
|
22
22
|
elements.forEach(el => {
|
|
23
|
-
|
|
23
|
+
const { setup, teardown } = useEventListener(controller, el, eventNameOrNames, handler, opts);
|
|
24
24
|
handlers.push({ setup, teardown });
|
|
25
25
|
});
|
|
26
26
|
return [
|
package/dist/use_fullscreen.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useMixin } from "./use_mixin";
|
|
2
2
|
export function useFullscreen(controller, el) {
|
|
3
|
-
|
|
3
|
+
const element = el || document.documentElement;
|
|
4
4
|
let fullscreenOpen = document.fullscreenElement !== null;
|
|
5
5
|
const updateFullscreenState = () => fullscreenOpen = document.fullscreenElement !== null;
|
|
6
6
|
const isFullscreen = () => fullscreenOpen;
|
|
7
7
|
const toggle = async () => fullscreenOpen ? await exit() : await enter();
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const setup = () => document.addEventListener("fullscreenchange", updateFullscreenState);
|
|
9
|
+
const teardown = () => document.removeEventListener("fullscreenchange", updateFullscreenState);
|
|
10
10
|
const exit = async () => {
|
|
11
11
|
if (document.exitFullscreen) {
|
|
12
12
|
fullscreenOpen = false;
|
package/dist/use_geolocation.js
CHANGED
|
@@ -10,7 +10,7 @@ export function useGeolocation(controller, options = {}, update, error) {
|
|
|
10
10
|
}
|
|
11
11
|
// Default options to pass to the navigator.geolocation.watchPosition() method
|
|
12
12
|
const { enableHighAccuracy = true, maximumAge = 30000, timeout = 27000, } = options;
|
|
13
|
-
const isSupported = navigator &&
|
|
13
|
+
const isSupported = navigator && "geolocation" in navigator;
|
|
14
14
|
// Create a reactive object to store the geolocation data
|
|
15
15
|
const values = reactive({
|
|
16
16
|
locatedAt: null,
|
|
@@ -31,7 +31,7 @@ export function useGeolocation(controller, options = {}, update, error) {
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
});
|
|
34
|
-
|
|
34
|
+
const setup = () => {
|
|
35
35
|
if (isSupported) {
|
|
36
36
|
watcher = navigator.geolocation.watchPosition((position) => {
|
|
37
37
|
// Update reactive values
|
package/dist/use_hover.js
CHANGED
|
@@ -5,16 +5,16 @@ export function useHover(controller, element, enter, leave) {
|
|
|
5
5
|
let teardownLeave = null;
|
|
6
6
|
if (enter) {
|
|
7
7
|
enter = enter.bind(controller);
|
|
8
|
-
|
|
8
|
+
const { teardown: _teardownEnter } = useEventListener(controller, element, "mouseenter", enter);
|
|
9
9
|
teardownEnter = _teardownEnter;
|
|
10
10
|
}
|
|
11
11
|
if (leave) {
|
|
12
12
|
leave = leave.bind(controller);
|
|
13
|
-
|
|
13
|
+
const { teardown: _teardownLeave } = useEventListener(controller, element, "mouseleave", leave);
|
|
14
14
|
teardownLeave = _teardownLeave;
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const setup = () => void 0;
|
|
17
|
+
const teardown = () => {
|
|
18
18
|
if (teardownEnter) {
|
|
19
19
|
teardownEnter();
|
|
20
20
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { useMixin } from "./use_mixin";
|
|
2
2
|
export function useInjectedFragment(controller, targetElement, insertPosition, fragment, options = {}) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const nodes = Array.from(fragment.childNodes);
|
|
4
|
+
const setup = () => {
|
|
5
|
+
const parent = targetElement.parentElement;
|
|
6
6
|
if (["beforebegin", "afterend"].includes(insertPosition) && parent == null) {
|
|
7
7
|
throw new Error("Cannot insert beforebegin into a node with no parent");
|
|
8
8
|
}
|
|
9
9
|
switch (insertPosition) {
|
|
10
|
-
case
|
|
10
|
+
case "beforeend":
|
|
11
11
|
targetElement.append(fragment);
|
|
12
12
|
break;
|
|
13
13
|
case "afterbegin":
|
|
@@ -21,7 +21,7 @@ export function useInjectedFragment(controller, targetElement, insertPosition, f
|
|
|
21
21
|
break;
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
|
-
|
|
24
|
+
const teardown = options.cleanup ? () => nodes.forEach(node => node.remove()) : () => void 0;
|
|
25
25
|
useMixin(controller, setup, teardown);
|
|
26
26
|
return [nodes, teardown];
|
|
27
27
|
}
|
|
@@ -32,6 +32,6 @@ export function useInjectedHTML(controller, targetElement, insertPosition, html,
|
|
|
32
32
|
export function useInjectedElement(controller, targetElement, insertPosition, element, options = {}) {
|
|
33
33
|
const fragment = new DocumentFragment();
|
|
34
34
|
fragment.append(element);
|
|
35
|
-
|
|
35
|
+
const [nodes, teardown] = useInjectedFragment(controller, targetElement, insertPosition, fragment, options);
|
|
36
36
|
return [nodes[0], teardown];
|
|
37
37
|
}
|
package/dist/use_intersection.js
CHANGED
|
@@ -2,12 +2,12 @@ import { useMixin } from "./use_mixin";
|
|
|
2
2
|
export function useIntersectionObserver(controller, handler, options) {
|
|
3
3
|
handler = handler.bind(controller);
|
|
4
4
|
let observer = new IntersectionObserver(handler, options);
|
|
5
|
-
|
|
5
|
+
const teardown = () => {
|
|
6
6
|
observer?.disconnect();
|
|
7
7
|
observer = null;
|
|
8
8
|
};
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const observe = (element) => observer?.observe(element);
|
|
10
|
+
const unobserve = (element) => observer?.unobserve(element);
|
|
11
11
|
return {
|
|
12
12
|
observer,
|
|
13
13
|
teardown,
|
|
@@ -22,8 +22,8 @@ export function useIntersection(controller, element, appear, disappear, options)
|
|
|
22
22
|
if (disappear) {
|
|
23
23
|
disappear = disappear.bind(controller);
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const opts = options ?? {};
|
|
26
|
+
const processEntries = (entries) => {
|
|
27
27
|
entries.forEach((entry) => {
|
|
28
28
|
if (entry.isIntersecting) {
|
|
29
29
|
appear && appear(entry);
|
|
@@ -33,8 +33,8 @@ export function useIntersection(controller, element, appear, disappear, options)
|
|
|
33
33
|
}
|
|
34
34
|
});
|
|
35
35
|
};
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const { observer, observe, unobserve, teardown } = useIntersectionObserver(controller, processEntries, opts);
|
|
37
|
+
const setup = () => observe(element);
|
|
38
38
|
useMixin(controller, setup, teardown);
|
|
39
39
|
return {
|
|
40
40
|
observer,
|
package/dist/use_interval.js
CHANGED
|
@@ -2,8 +2,8 @@ import { useMixin } from "./use_mixin";
|
|
|
2
2
|
export function useInterval(controller, handler, interval) {
|
|
3
3
|
handler = handler.bind(controller);
|
|
4
4
|
let intervalHandle = null;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const setup = () => intervalHandle = setInterval(handler, interval);
|
|
6
|
+
const teardown = () => {
|
|
7
7
|
if (intervalHandle !== null) {
|
|
8
8
|
clearInterval(intervalHandle);
|
|
9
9
|
}
|
package/dist/use_localstorage.js
CHANGED
|
@@ -56,12 +56,12 @@ export const StorageSerializers = {
|
|
|
56
56
|
};
|
|
57
57
|
export function useLocalStorage(controller, key, defaultValue, opts) {
|
|
58
58
|
let type;
|
|
59
|
-
|
|
59
|
+
const optsMergedWithDefaults = {
|
|
60
60
|
onChange: null,
|
|
61
61
|
writeDefaults: true,
|
|
62
62
|
...opts,
|
|
63
63
|
};
|
|
64
|
-
|
|
64
|
+
const { writeDefaults } = optsMergedWithDefaults;
|
|
65
65
|
if (defaultValue === null || defaultValue === undefined) {
|
|
66
66
|
type = "any";
|
|
67
67
|
}
|
|
@@ -89,11 +89,11 @@ export function useLocalStorage(controller, key, defaultValue, opts) {
|
|
|
89
89
|
else {
|
|
90
90
|
type = "any";
|
|
91
91
|
}
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
const onChange = optsMergedWithDefaults.onChange?.bind(controller);
|
|
93
|
+
const data = reactive({
|
|
94
94
|
value: defaultValue,
|
|
95
95
|
});
|
|
96
|
-
|
|
96
|
+
const storage = localStorage;
|
|
97
97
|
const serializer = StorageSerializers[type];
|
|
98
98
|
const read = () => {
|
|
99
99
|
const rawValue = storage.getItem(key);
|
|
@@ -121,13 +121,12 @@ export function useLocalStorage(controller, key, defaultValue, opts) {
|
|
|
121
121
|
return data.value;
|
|
122
122
|
};
|
|
123
123
|
const isEmpty = () => {
|
|
124
|
-
|
|
124
|
+
const rawValue = storage.getItem(key);
|
|
125
125
|
return serializer.isEmpty(rawValue);
|
|
126
126
|
};
|
|
127
127
|
read();
|
|
128
128
|
useEventListener(controller, window, "storage", (event) => {
|
|
129
129
|
if (event.key === key) {
|
|
130
|
-
console.log(event.newValue, event.oldValue);
|
|
131
130
|
write(event.newValue);
|
|
132
131
|
}
|
|
133
132
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useMixin } from "./use_mixin";
|
|
2
2
|
export function useMutationObserver(controller, element, handler, options) {
|
|
3
3
|
handler = handler.bind(controller);
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
const observer = new MutationObserver(handler);
|
|
5
|
+
const setup = () => observer.observe(element, options);
|
|
6
|
+
const teardown = () => observer.disconnect();
|
|
7
7
|
useMixin(controller, setup, teardown);
|
|
8
8
|
return teardown;
|
|
9
9
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useMixin } from "./use_mixin";
|
|
2
2
|
export function useResizeObserver(controller, element, handler, options) {
|
|
3
3
|
handler = handler.bind(controller);
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
const observer = new ResizeObserver(handler);
|
|
5
|
+
const setup = () => observer.observe(element, options);
|
|
6
|
+
const teardown = () => observer.disconnect();
|
|
7
7
|
useMixin(controller, setup, teardown);
|
|
8
8
|
return teardown;
|
|
9
9
|
}
|
|
@@ -14,7 +14,7 @@ export function useTemporaryContent(controller, target, content, timeout, teardo
|
|
|
14
14
|
return isHTMLInputElement(element) ? element.value : element.innerHTML;
|
|
15
15
|
};
|
|
16
16
|
let cleanupTimeout = () => void 0;
|
|
17
|
-
|
|
17
|
+
const originalText = getContent(target);
|
|
18
18
|
const teardown = () => {
|
|
19
19
|
setContent(target, originalText);
|
|
20
20
|
cleanupTimeout();
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useEventListener } from "./use_event_listener";
|
|
2
2
|
export function useTextSelection(controller, handler) {
|
|
3
3
|
handler = handler.bind(controller);
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const onSelectionChange = () => {
|
|
5
|
+
const selection = window.getSelection();
|
|
6
6
|
handler(selection);
|
|
7
7
|
};
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const { teardown: unwatch } = useEventListener(controller, window.document, "selectionchange", onSelectionChange);
|
|
9
|
+
const teardown = () => {
|
|
10
10
|
unwatch();
|
|
11
11
|
};
|
|
12
12
|
return {
|
package/dist/use_timeout.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { useMixin } from "./use_mixin";
|
|
2
2
|
export function useTimeout(controller, handler, timeout) {
|
|
3
|
+
// eslint-disable-next-line prefer-const
|
|
3
4
|
let controllerDisconnect;
|
|
4
5
|
let timeoutHandle = null;
|
|
5
6
|
handler = handler.bind(controller);
|
|
6
|
-
|
|
7
|
+
const newHandler = () => {
|
|
7
8
|
handler();
|
|
8
9
|
timeoutHandle = null;
|
|
9
10
|
Object.assign(controller, { disconnect: controllerDisconnect });
|
|
10
11
|
};
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
const setup = () => timeoutHandle = setTimeout(newHandler, timeout);
|
|
13
|
+
const teardown = () => {
|
|
13
14
|
if (timeoutHandle !== null) {
|
|
14
15
|
clearTimeout(timeoutHandle);
|
|
15
16
|
timeoutHandle = null;
|
|
@@ -6,27 +6,27 @@ export function useTrixModifiers(controller) {
|
|
|
6
6
|
// keep a copy of the lifecycle function of the controller
|
|
7
7
|
const controllerDisconnect = controller.disconnect.bind(controller);
|
|
8
8
|
let observing = false;
|
|
9
|
-
|
|
9
|
+
const observerCallback = (entries, observer) => {
|
|
10
10
|
entries.forEach(mutation => {
|
|
11
|
-
if (mutation.type ===
|
|
11
|
+
if (mutation.type === "childList" && Array.from(mutation.addedNodes).some((el) => el.tagName === "TRIX-TOOLBAR")) {
|
|
12
12
|
attemptSetup();
|
|
13
13
|
observer.disconnect();
|
|
14
14
|
}
|
|
15
15
|
});
|
|
16
16
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (controller.element.tagName !==
|
|
21
|
-
throw new Error(
|
|
17
|
+
const pasteHandler = (event) => controllerMethod(controller, "pasteEvent").call(controller, event);
|
|
18
|
+
const observer = new MutationObserver(observerCallback);
|
|
19
|
+
const attemptSetup = () => {
|
|
20
|
+
if (controller.element.tagName !== "TRIX-EDITOR") {
|
|
21
|
+
throw new Error("Expected controller to be mounted on an instance of <trix-editor>");
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
const editor = controller.element;
|
|
24
|
+
const editorParent = controller.element.parentElement;
|
|
25
25
|
if (editorParent == null) {
|
|
26
|
-
throw new Error(
|
|
26
|
+
throw new Error("Could not traverse DOM tree from <trix-editor>");
|
|
27
27
|
}
|
|
28
|
-
editor.addEventListener(
|
|
29
|
-
|
|
28
|
+
editor.addEventListener("trix-paste", pasteHandler);
|
|
29
|
+
const toolbar = editorParent.querySelector("trix-toolbar");
|
|
30
30
|
if (!observing && !toolbar) {
|
|
31
31
|
// toolbar is not in the DOM yet, wait for it to arrive before running setup
|
|
32
32
|
observing = true;
|
|
@@ -35,36 +35,36 @@ export function useTrixModifiers(controller) {
|
|
|
35
35
|
}
|
|
36
36
|
else if (!toolbar) {
|
|
37
37
|
// Fallback, in case this runs twice, or mutation observer logic fails
|
|
38
|
-
throw new Error(
|
|
38
|
+
throw new Error("Could not find an instance of <trix-toolbar> that is a sibling of this <trix-editor>");
|
|
39
39
|
}
|
|
40
40
|
else {
|
|
41
41
|
// Do not need MutationObserver, all elements are present and correct
|
|
42
42
|
observer.disconnect();
|
|
43
43
|
}
|
|
44
|
-
controllerMethod(controller,
|
|
44
|
+
controllerMethod(controller, "install").call(controller, { toolbar, editor });
|
|
45
45
|
};
|
|
46
|
-
|
|
47
|
-
if (controller.element.tagName !==
|
|
48
|
-
throw new Error(
|
|
46
|
+
const teardown = () => {
|
|
47
|
+
if (controller.element.tagName !== "TRIX-EDITOR") {
|
|
48
|
+
throw new Error("Expected controller to be mounted on an instance of <trix-editor>");
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
const editor = controller.element;
|
|
51
|
+
const editorParent = controller.element.parentElement;
|
|
52
52
|
if (editorParent == null) {
|
|
53
|
-
throw new Error(
|
|
53
|
+
throw new Error("Could not traverse DOM tree from <trix-editor>");
|
|
54
54
|
}
|
|
55
|
-
editor.removeEventListener(
|
|
56
|
-
|
|
55
|
+
editor.removeEventListener("trix-paste", pasteHandler);
|
|
56
|
+
const toolbar = editorParent.querySelector("trix-toolbar");
|
|
57
57
|
if (!toolbar) {
|
|
58
|
-
throw new Error(
|
|
58
|
+
throw new Error("Could not find <trix-toolbar> that is a sibling of this <trix-editor> element");
|
|
59
59
|
}
|
|
60
|
-
controllerMethod(controller,
|
|
60
|
+
controllerMethod(controller, "uninstall").call(controller, { toolbar, editor });
|
|
61
61
|
};
|
|
62
62
|
attemptSetup();
|
|
63
63
|
Object.assign(controller, {
|
|
64
64
|
disconnect() {
|
|
65
65
|
observer.disconnect();
|
|
66
66
|
teardown();
|
|
67
|
-
controllerMethod(controller,
|
|
67
|
+
controllerMethod(controller, "uninstall").call({ toolbar, editor: controller.element });
|
|
68
68
|
controllerDisconnect();
|
|
69
69
|
},
|
|
70
70
|
});
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"ruby on rails",
|
|
10
10
|
"ruby-on-rails"
|
|
11
11
|
],
|
|
12
|
-
"version": "1.0.
|
|
12
|
+
"version": "1.0.3",
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Sub-Xaero",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"files": [
|
|
24
24
|
"dist"
|
|
25
25
|
],
|
|
26
|
+
"main": "dist/index.js",
|
|
26
27
|
"module": "dist/index.js",
|
|
27
28
|
"types": "dist/index.d.ts",
|
|
28
29
|
"scripts": {
|
|
@@ -35,7 +36,7 @@
|
|
|
35
36
|
},
|
|
36
37
|
"dependencies": {
|
|
37
38
|
"@hotwired/stimulus": "^3.0.0",
|
|
38
|
-
"@stimulus-library/utilities": "^1.0.
|
|
39
|
+
"@stimulus-library/utilities": "^1.0.3"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
|
41
42
|
"@types/chai": "^4.3.5",
|
|
@@ -48,12 +49,12 @@
|
|
|
48
49
|
"lerna": "^7.0.0",
|
|
49
50
|
"mocha": "^10.2.0",
|
|
50
51
|
"rimraf": "^5.0.1",
|
|
51
|
-
"sinon": "^
|
|
52
|
+
"sinon": "^16.0.0",
|
|
52
53
|
"sinon-chai": "^3.7.0",
|
|
53
54
|
"standard-version": "^9.5.0",
|
|
54
55
|
"ts-node": "^10.9.1",
|
|
55
56
|
"typescript": "^5.1.3",
|
|
56
57
|
"vite": "^4.1.1"
|
|
57
58
|
},
|
|
58
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "87d6154d0b5ec364033b04d9f469db5143d031eb"
|
|
59
60
|
}
|