Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add activeClass to link component? #5

Open
kurtmilam opened this issue May 8, 2017 · 3 comments
Open

Add activeClass to link component? #5

kurtmilam opened this issue May 8, 2017 · 3 comments

Comments

@kurtmilam
Copy link
Member

kurtmilam commented May 8, 2017

I'd add 'active' to a link if its href.path was an exact match for the live path. I'd add active-parent to a link if the path.startsWith( href.path + '/' ).

Here's what I am playing with right now.

import * as React from "karet"
import * as U     from "karet.util"

import scroll from "../../client/scroll"

function special(e) {
  e.preventDefault()
  e.stopPropagation()
}

let onsite

const isExt = U.lift1Shallow(href => /^https?:\/\//.test(href))
const getInternal = U.lift1Shallow( href => /^((\/[^?#]*)([?][^#]*)?)?([#].*)?$/.exec( href ) )

export default U.withContext(({
  href, onClick: outerOnClick, onThere, mount, className, ...props
}, {
  location, path
}) => {
  const onClick = U.lift(href => e => {
    const internal = getInternal( href )

    if (internal) {
      if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey)
        return

      const [,, path = "", search = "", hash = ""] = internal

      if (!path && !search) {
        if (!hash && onsite) {
          special(e)
          window.history.back()
        } else {
          window.setTimeout(() => scroll(hash, 200, onThere), 10)
        }
      } else {
        special(e)
        location.set({path, search, hash})

        if (!hash)
          scroll(0, 1, onThere)
        else
          window.setTimeout(() => scroll(hash, onThere), 100)
      }
    }
    onsite=1
  })

  const activeClass =
    K( path
     , href
     , ( path, href ) =>
       { const internal = getInternal( href )
         if ( internal ) {
           const linkPath = internal[ 2 ]
           if ( path === linkPath )
             return 'active'
           if ( path.startsWith( linkPath + '/' ) )
             return 'active-parent'
         }
       }
     )

  const classes =
    U.cns( className
         , U.ift( isExt( href ), "ext-link" )
         , activeClass
         )

  return (
    <a href={ href }
      ref={ mount }
      onClick={ U.actions( outerOnClick, U.lift( onClick )( href ) ) }
      className={ classes }
      { ...props }/>
  )
})
@kurtmilam kurtmilam changed the title Add activeClass functionality to link component? Add activeClass to link component? May 8, 2017
@polytypic
Copy link
Member

Seems like a good idea. 👍

I wonder whether it would be possible to do this modularly so that one could choose whether the active class is added and also the same for the ext class?

@kurtmilam
Copy link
Member Author

Are you thinking about a wrapper component for Link, a config parameter for Link or something else?

@polytypic
Copy link
Member

Hmm... I didn't really have particular solution in mind.

Note that you can almost achieve the functionality just by giving the property as a className to the link component. The only difficulty with that is that to compute the class name you need to access the href property of the link and the path (window.location).

Perhaps both the ext and active classes could be added by some sort of component modifier functions and you'd say something like this:

const AppLink = Link.withActive(Link.withExt(Link.Component))
// ...
<AppLink href='...' />

The component modifiers would grab the href parameter and add to the className. Something like this:

const withActive = LinkBase => U.withContext(({href, className}, {path}) =>
  <LinkBase href={href} className={className, classWithActive(href, path)})

But this is just an idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants