Add forwardEventsBuilder from svelte-material-ui
This commit is contained in:
134
src/lib/internal/forwardEventsBuilder.ts
Normal file
134
src/lib/internal/forwardEventsBuilder.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
// This is a modified version of code from hperrin/svelte-material-ui
|
||||
import type { SvelteComponent } from 'svelte';
|
||||
import {
|
||||
bubble,
|
||||
listen,
|
||||
prevent_default,
|
||||
stop_propagation,
|
||||
} from 'svelte/internal';
|
||||
|
||||
const MODIFIER_DIVIDER = "!";
|
||||
const modifierRegex = new RegExp(`^[^${MODIFIER_DIVIDER}]+(?:${MODIFIER_DIVIDER}(?:preventDefault|stopPropagation|passive|nonpassive|capture|once|self))+$`);
|
||||
|
||||
export function forwardEventsBuilder(component: SvelteComponent) {
|
||||
// This is our pseudo $on function. It is defined on component mount.
|
||||
let $on: (eventType: string, callback: (event: any) => void) => () => void;
|
||||
// This is a list of events bound before mount.
|
||||
let events: [string, (event: any) => void][] = [];
|
||||
|
||||
// And we override the $on function to forward all bound events.
|
||||
component.$on = (fullEventType: string, callback: (event: any) => void) => {
|
||||
let eventType = fullEventType;
|
||||
let destructor = () => { };
|
||||
if ($on) {
|
||||
// The event was bound programmatically.
|
||||
destructor = $on(eventType, callback);
|
||||
} else {
|
||||
// The event was bound before mount by Svelte.
|
||||
events.push([eventType, callback]);
|
||||
}
|
||||
return () => {
|
||||
destructor();
|
||||
};
|
||||
};
|
||||
|
||||
function forward(e: Event) {
|
||||
// Internally bubble the event up from Svelte components.
|
||||
bubble(component, e);
|
||||
}
|
||||
|
||||
return (node: HTMLElement | SVGElement) => {
|
||||
const destructors: (() => void)[] = [];
|
||||
const forwardDestructors: { [k: string]: () => void } = {};
|
||||
|
||||
// This function is responsible for listening and forwarding
|
||||
// all bound events.
|
||||
$on = (fullEventType, callback) => {
|
||||
let eventType = fullEventType;
|
||||
let handler = callback;
|
||||
// DOM addEventListener options argument.
|
||||
let options: boolean | AddEventListenerOptions = false;
|
||||
const modifierMatch = eventType.match(modifierRegex);
|
||||
if (modifierMatch) {
|
||||
// Parse the event modifiers.
|
||||
// Supported modifiers:
|
||||
// - preventDefault
|
||||
// - stopPropagation
|
||||
// - passive
|
||||
// - nonpassive
|
||||
// - capture
|
||||
// - once
|
||||
const parts = eventType.split(MODIFIER_DIVIDER);
|
||||
eventType = parts[0];
|
||||
const eventOptions: {
|
||||
passive?: true;
|
||||
nonpassive?: true;
|
||||
capture?: true;
|
||||
once?: true;
|
||||
preventDefault?: true;
|
||||
stopPropagation?: true;
|
||||
} = Object.fromEntries(parts.slice(1).map((mod) => [mod, true]));
|
||||
if (eventOptions.passive) {
|
||||
options = options || ({} as AddEventListenerOptions);
|
||||
options.passive = true;
|
||||
}
|
||||
if (eventOptions.nonpassive) {
|
||||
options = options || ({} as AddEventListenerOptions);
|
||||
options.passive = false;
|
||||
}
|
||||
if (eventOptions.capture) {
|
||||
options = options || ({} as AddEventListenerOptions);
|
||||
options.capture = true;
|
||||
}
|
||||
if (eventOptions.once) {
|
||||
options = options || ({} as AddEventListenerOptions);
|
||||
options.once = true;
|
||||
}
|
||||
if (eventOptions.preventDefault) {
|
||||
handler = prevent_default(handler);
|
||||
}
|
||||
if (eventOptions.stopPropagation) {
|
||||
handler = stop_propagation(handler);
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for the event directly, with the given options.
|
||||
const off = listen(node, eventType, handler, options);
|
||||
const destructor = () => {
|
||||
off();
|
||||
const idx = destructors.indexOf(destructor);
|
||||
if (idx > -1) {
|
||||
destructors.splice(idx, 1);
|
||||
}
|
||||
};
|
||||
|
||||
destructors.push(destructor);
|
||||
|
||||
// Forward the event from Svelte.
|
||||
if (!(eventType in forwardDestructors)) {
|
||||
forwardDestructors[eventType] = listen(node, eventType, forward);
|
||||
}
|
||||
|
||||
return destructor;
|
||||
};
|
||||
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
// Listen to all the events added before mount.
|
||||
$on(events[i][0], events[i][1]);
|
||||
}
|
||||
|
||||
return {
|
||||
destroy: () => {
|
||||
// Remove all event listeners.
|
||||
for (let i = 0; i < destructors.length; i++) {
|
||||
destructors[i]();
|
||||
}
|
||||
|
||||
// Remove all event forwarders.
|
||||
for (let entry of Object.entries(forwardDestructors)) {
|
||||
entry[1]();
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user