https://stackblitz.com/edit/jfunky?file=index.html,jfunky.ts,entry.ts,README.md
Last active
September 21, 2023 23:05
-
-
Save AlexVipond/2f135c84e673e80e7bc8452de349cae4 to your computer and use it in GitHub Desktop.
JFunky - JQuery-inspired library for manipulating the DOM with unary functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<script src="https://cdn.tailwindcss.com"></script> | |
</head> | |
<body> | |
<script> | |
// ...jfunky | |
</script> | |
<template id="my-template"> | |
<div class="flex flex-col gap-4"> | |
<div class="p-2 bg-blue-100">Hello world</div> | |
<button class="btn">Click me</button> | |
</div> | |
</template> | |
<main class="container"></main> | |
<script> | |
pipe( | |
$('#my-template'), | |
template(), | |
$('.btn'), | |
at(0), | |
click(() => console.log('clicked')), | |
root(), | |
appendTo('.container'), | |
)() | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function pipe (...fns: Function[]) { | |
return function (value?: any) { | |
return fns.reduce((acc, fn) => fn(acc), value) | |
} | |
} | |
export function $ (selector?: string) { | |
return function (ancestors: [Document] | HTMLElement[] = [document]) { | |
return [ | |
...ancestors.flatMap( | |
ancestor => [...(selector ? ancestor.querySelectorAll(selector) : [document])] as HTMLElement[] | |
) | |
] | |
} | |
} | |
export function at (index: number) { | |
return function (elements: HTMLElement[]) { | |
return [elements.at(index)] | |
} | |
} | |
export function clone (options: { depth?: 'shallow' | 'deep' } = { depth: 'deep' }) { | |
const { depth } = options | |
return function (elements: HTMLElement[]) { | |
return elements.map(element => element.cloneNode(depth === 'deep')) | |
} | |
} | |
export function template (options: { clone?: Parameters<typeof clone>[0] } = {}) { | |
const { clone: cloneOptions } = options | |
return function (elements: HTMLTemplateElement[]) { | |
return clone(cloneOptions)( | |
elements.flatMap( | |
element => [...element.content.children] as HTMLElement[] | |
) | |
) | |
} | |
} | |
export function tunedCreateOn (options?: AddEventListenerOptions) { | |
return function createOn<EventType extends keyof HTMLElementEventMap> (event: EventType) { | |
return function (effect: (event: HTMLElementEventMap[EventType]) => void) { | |
return function (elements: HTMLElement[]) { | |
for (const element of elements) { | |
element.addEventListener(event, effect, options) | |
} | |
return elements | |
} | |
} | |
} | |
} | |
export const createOn = tunedCreateOn() | |
export const click = createOn('click') | |
export const keydown = createOn('keydown') | |
export const keyup = createOn('keyup') | |
export function off ( | |
event: string, | |
options: { | |
effect?: (event: Event) => void, | |
} & EventListenerOptions = { effect: () => {} }, | |
) { | |
const { effect, ...removeEventListenerOptions } = options | |
return function (elements: HTMLElement[]) { | |
for (const element of elements) { | |
// @ts-expect-error | |
element.removeEventListener(event, effect, removeEventListenerOptions) | |
} | |
return elements | |
} | |
} | |
export function root () { | |
return function (elements: HTMLElement[]) { | |
const roots: HTMLElement[] = [] | |
for (const element of elements) { | |
let r = element | |
while (r.parentElement) { | |
r = r.parentElement | |
} | |
roots.push(r) | |
} | |
return roots | |
} | |
} | |
export function appendTo (selector: string) { | |
const container = pipe( | |
$(selector), | |
selected => selected.at(0), | |
)() as HTMLElement | |
return function (elements: HTMLElement[]) { | |
for (const element of elements) { | |
container.appendChild(element) | |
} | |
return elements | |
} | |
} | |
export function remove () { | |
return function (elements: HTMLElement[]) { | |
for (const element of elements) { | |
element.remove() | |
} | |
return elements | |
} | |
} | |
export function empty () { | |
return function (elements: HTMLElement[]) { | |
for (const element of elements) { | |
remove()([...element.children] as HTMLElement[]) | |
} | |
return elements | |
} | |
} | |
export function append (children: HTMLElement[]) { | |
return function (elements: HTMLElement[]) { | |
for (const element of elements) { | |
element.append(...children) | |
} | |
return elements | |
} | |
} | |
export function text (content: string) { | |
return function (elements: HTMLElement[]) { | |
for (const element of elements) { | |
element.textContent = content | |
} | |
return elements | |
} | |
} | |
export function addClass (className: string) { | |
return function (elements: HTMLElement[]) { | |
for (const element of elements) { | |
element.classList.add(...className.split(' ')) | |
} | |
return elements | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment