Skip to content

Instantly share code, notes, and snippets.

@AlexVipond
Last active September 21, 2023 23:05
Show Gist options
  • Save AlexVipond/2f135c84e673e80e7bc8452de349cae4 to your computer and use it in GitHub Desktop.
Save AlexVipond/2f135c84e673e80e7bc8452de349cae4 to your computer and use it in GitHub Desktop.
JFunky - JQuery-inspired library for manipulating the DOM with unary functions
<!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>
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