Skip to content

Instantly share code, notes, and snippets.

@AlexVipond
Last active September 21, 2023 23:05
Show Gist options
  • Select an option

  • Save AlexVipond/2f135c84e673e80e7bc8452de349cae4 to your computer and use it in GitHub Desktop.

Select an option

Save AlexVipond/2f135c84e673e80e7bc8452de349cae4 to your computer and use it in GitHub Desktop.

Revisions

  1. AlexVipond revised this gist Sep 21, 2023. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    https://stackblitz.com/edit/jfunky?file=index.html,jfunky.ts,entry.ts,README.md
  2. AlexVipond revised this gist Sep 21, 2023. 1 changed file with 68 additions and 16 deletions.
    84 changes: 68 additions & 16 deletions jfunky.ts
    Original file line number Diff line number Diff line change
    @@ -1,28 +1,34 @@
    function $ (selector: string) {
    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 => [...ancestor.querySelectorAll(selector)] as HTMLElement[]
    ancestor => [...(selector ? ancestor.querySelectorAll(selector) : [document])] as HTMLElement[]
    )
    ]
    }
    }

    function at (index: number) {
    export function at (index: number) {
    return function (elements: HTMLElement[]) {
    return [elements.at(index)]
    }
    }

    function clone (options: { depth?: 'shallow' | 'deep' } = { depth: 'deep' }) {
    export function clone (options: { depth?: 'shallow' | 'deep' } = { depth: 'deep' }) {
    const { depth } = options

    return function (elements: HTMLElement[]) {
    return elements.map(element => element.cloneNode(depth === 'deep'))
    }
    }

    function template (options: { clone?: Parameters<typeof clone>[0] } = {}) {
    export function template (options: { clone?: Parameters<typeof clone>[0] } = {}) {
    const { clone: cloneOptions } = options

    return function (elements: HTMLTemplateElement[]) {
    @@ -34,9 +40,9 @@ function template (options: { clone?: Parameters<typeof clone>[0] } = {}) {
    }
    }

    function tunedCreateOn (options?: AddEventListenerOptions) {
    return function createOn (event: string) {
    return function (effect: (event: Event) => void) {
    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)
    @@ -48,10 +54,12 @@ function tunedCreateOn (options?: AddEventListenerOptions) {
    }
    }

    const createOn = tunedCreateOn()
    const click = createOn('click')
    export const createOn = tunedCreateOn()
    export const click = createOn('click')
    export const keydown = createOn('keydown')
    export const keyup = createOn('keyup')

    function off (
    export function off (
    event: string,
    options: {
    effect?: (event: Event) => void,
    @@ -69,7 +77,7 @@ function off (
    }
    }

    function root () {
    export function root () {
    return function (elements: HTMLElement[]) {
    const roots: HTMLElement[] = []

    @@ -87,7 +95,7 @@ function root () {
    }
    }

    function appendTo (selector: string) {
    export function appendTo (selector: string) {
    const container = pipe(
    $(selector),
    selected => selected.at(0),
    @@ -102,8 +110,52 @@ function appendTo (selector: string) {
    }
    }

    function pipe (...fns: Function[]) {
    return function (value?: any) {
    return fns.reduce((acc, fn) => fn(acc), value)
    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
    }
    }
  3. AlexVipond revised this gist Aug 2, 2023. 2 changed files with 12 additions and 14 deletions.
    2 changes: 1 addition & 1 deletion example.html
    Original file line number Diff line number Diff line change
    @@ -23,7 +23,7 @@
    template(),
    $('.btn'),
    at(0),
    on({ event: 'click', effect: () => console.log('clicked') }),
    click(() => console.log('clicked')),
    root(),
    appendTo('.container'),
    )()
    24 changes: 11 additions & 13 deletions jfunky.ts
    Original file line number Diff line number Diff line change
    @@ -34,24 +34,22 @@ function template (options: { clone?: Parameters<typeof clone>[0] } = {}) {
    }
    }

    function tunedOn (options?: AddEventListenerOptions) {
    return function on (config: {
    event: string,
    effect: (event: Event) => void,
    }) {
    const { event, effect } = config

    return function (elements: HTMLElement[]) {
    for (const element of elements) {
    element.addEventListener(event, effect, options)
    function tunedCreateOn (options?: AddEventListenerOptions) {
    return function createOn (event: string) {
    return function (effect: (event: Event) => void) {
    return function (elements: HTMLElement[]) {
    for (const element of elements) {
    element.addEventListener(event, effect, options)
    }

    return elements
    }

    return elements
    }
    }
    }

    const on = tunedOn()
    const createOn = tunedCreateOn()
    const click = createOn('click')

    function off (
    event: string,
  4. AlexVipond revised this gist Aug 2, 2023. No changes.
  5. AlexVipond revised this gist Aug 2, 2023. 2 changed files with 47 additions and 24 deletions.
    32 changes: 32 additions & 0 deletions example.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,32 @@
    <!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),
    on({ event: 'click', effect: () => console.log('clicked') }),
    root(),
    appendTo('.container'),
    )()
    </script>
    </body>
    </html>
    39 changes: 15 additions & 24 deletions jfunky.ts
    Original file line number Diff line number Diff line change
    @@ -34,24 +34,25 @@ function template (options: { clone?: Parameters<typeof clone>[0] } = {}) {
    }
    }

    function on (
    event: string,
    options: {
    effect?: (event: Event) => void,
    } & AddEventListenerOptions = { effect: () => {} },
    ) {
    const { effect, ...addEventListenerOptions } = options

    return function (elements: HTMLElement[]) {
    for (const element of elements) {
    // @ts-expect-error
    element.addEventListener(event, effect, addEventListenerOptions)
    function tunedOn (options?: AddEventListenerOptions) {
    return function on (config: {
    event: string,
    effect: (event: Event) => void,
    }) {
    const { event, effect } = config

    return function (elements: HTMLElement[]) {
    for (const element of elements) {
    element.addEventListener(event, effect, options)
    }

    return elements
    }

    return elements
    }
    }

    const on = tunedOn()

    function off (
    event: string,
    options: {
    @@ -108,13 +109,3 @@ function pipe (...fns: Function[]) {
    return fns.reduce((acc, fn) => fn(acc), value)
    }
    }

    const thing = pipe(
    $('#my-template'),
    template(),
    $('.btn'),
    at(0),
    on('click', { effect: () => console.log('clicked') }),
    root(),
    appendTo('.container'),
    )()
  6. AlexVipond created this gist Aug 2, 2023.
    120 changes: 120 additions & 0 deletions jfunky.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,120 @@
    function $ (selector: string) {
    return function (ancestors: [Document] | HTMLElement[] = [document]) {
    return [
    ...ancestors.flatMap(
    ancestor => [...ancestor.querySelectorAll(selector)] as HTMLElement[]
    )
    ]
    }
    }

    function at (index: number) {
    return function (elements: HTMLElement[]) {
    return [elements.at(index)]
    }
    }

    function clone (options: { depth?: 'shallow' | 'deep' } = { depth: 'deep' }) {
    const { depth } = options

    return function (elements: HTMLElement[]) {
    return elements.map(element => element.cloneNode(depth === 'deep'))
    }
    }

    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[]
    )
    )
    }
    }

    function on (
    event: string,
    options: {
    effect?: (event: Event) => void,
    } & AddEventListenerOptions = { effect: () => {} },
    ) {
    const { effect, ...addEventListenerOptions } = options

    return function (elements: HTMLElement[]) {
    for (const element of elements) {
    // @ts-expect-error
    element.addEventListener(event, effect, addEventListenerOptions)
    }

    return elements
    }
    }

    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
    }
    }

    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
    }
    }

    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
    }
    }

    function pipe (...fns: Function[]) {
    return function (value?: any) {
    return fns.reduce((acc, fn) => fn(acc), value)
    }
    }

    const thing = pipe(
    $('#my-template'),
    template(),
    $('.btn'),
    at(0),
    on('click', { effect: () => console.log('clicked') }),
    root(),
    appendTo('.container'),
    )()