melt
Version:
The next generation of Melt UI. Built for Svelte 5.
77 lines (76 loc) • 2.87 kB
JavaScript
import { isFunction, isString } from "./is";
function isEventHandler(key) {
return key.length > 2 && key.startsWith("on") && key.toLowerCase() === key;
}
/**
* Composes event handlers into a single function that can be called with an event.
* If the previous handler cancels the event using `event.preventDefault()`, the handlers
* that follow will not be called.
*/
function composeHandlers(...handlers) {
return function (e) {
for (const handler of handlers) {
handler.call(this, e);
}
};
}
/**
* Executes an array of callback functions with the same arguments.
* @template T The types of the arguments that the callback functions take.
* @param callbacks array of callback functions to execute.
* @returns A new function that executes all of the original callback functions with the same arguments.
*/
export function executeCallbacks(...callbacks) {
return (...args) => {
for (const callback of callbacks) {
if (typeof callback === "function") {
callback(...args);
}
}
};
}
/**
* Given a list of attribute objects, merges them into a single object.
* - Automatically composes event handlers (e.g. `onclick`, `oninput`, etc.)
* - Chains regular functions with the same name so they are called in order
* - Handles a bug with Svelte where setting the `hidden` attribute to `false` doesn't remove it
* - Merges style attributes
* - Overrides other values with the last one
*/
export function mergeAttrs(...args) {
const result = { ...args[0] };
for (let i = 1; i < args.length; i++) {
const props = args[i];
for (const key in props) {
const a = result[key];
const b = key in props ? props[key] : undefined;
// compose event handlers
if (isFunction(a) && isFunction(b) && isEventHandler(key)) {
// handle merging of event handlers
const aHandler = a;
const bHandler = b;
result[key] = composeHandlers(aHandler, bHandler);
}
else if (isFunction(a) && isFunction(b)) {
// chain non-event handler functions
result[key] = executeCallbacks(a, b);
}
else if (isString(a) && isString(b) && key === "style") {
result[key] = [a, b].join(";");
}
else {
// override other values
result[key] = b !== undefined ? b : a;
}
}
}
// handle weird svelte bug where `hidden` is not removed when set to `false`
if (result.hidden !== true) {
delete result.hidden;
}
// handle weird svelte bug where `disabled` is not removed when set to `false`
if (result.disabled !== true) {
delete result.disabled;
}
return result;
}