Add anchor links to the headings in a document.
This has been adapted from bryanbraun/anchorjs. Thanks @bryanbraun for working in open source.
npm i -S @substrate-system/anchorSee the example page: substrate-system.github.io/anchor/
// import a function
import { anchor } from '@substrate-system/anchor'
// always show anchor links on touch devices
anchor({ visible: 'touch' })Can pass in options and a selector to use to target elements.
function anchor (
opts:Partial<AnchorOpts> = {},
selector?:string|Array<Node>|NodeList
):AnchorTarget all h tags, like normal, but not with class no-anchor.
import { anchor } from '@substrate-system/anchor'
anchor(
{ visible: 'touch' },
'h2:not(.no-anchor), h3:not(.no-anchor), h4:not(.no-anchor), h5:not(.no-anchor), h6:not(.no-anchor)')Need to handle component lifecycle.
import { html } from 'htm/preact'
import { type FunctionComponent } from 'preact'
import { useEffect, useRef } from 'preact/hooks'
import { anchor } from '@substrate-system/anchor'
const MyView:FunctionComponent = function MyView () {
const containerRef = useRef<HTMLDivElement|null>(null)
/**
* Setup the anchor links
*/
useEffect(() => {
if (!containerRef.current) return
const headings = containerRef.current.querySelectorAll('h2, h3')
anchor({ visible: 'hover', base: window.location.pathname }, headings)
}, [])
return html`<div ref=${containerRef}>${/* ... */}</div>`
}And need to handle hash links in your route change code.
function onRoute () { // this is your application code
if (path.includes('#')) {
const pathParts = path.split('#')
const pathname = pathParts.shift()!.split('?').shift()!
if (pathname.split('/').filter(Boolean).length < 1) {
// we were given a hash link only, so scroll there
document.getElementById(pathParts.pop()!)?.scrollIntoView()
return
} else {
// URL has a path and also a hash, so set state, then scroll
state.route.value = stripTrailingSlash(pathname)
return setTimeout(() => {
// wait for veiw to render
document.getElementById(pathParts.pop()!)?.scrollIntoView()
}, 1)
}
}
}This exposes ESM and common JS via package.json exports field.
import { Anchor } from '@substrate-system/anchor'const Anchor = require('@substrate-system/anchor')This package exposes minified JS files too. Copy them to a location that is accessible to your web server, then link to them in HTML.
cp ./node_modules/@substrate-system/anchor/dist/index.min.js ./public/anchor.min.js<script type="module" src="./anchor.min.js"></script>type AnchorOpts = {
// Characters like '#', '¶', '❡', or '§'.
icon:string;
visible:'hover'|'always'|'touch';
placement:'right'|'left';
ariaLabel:string; // any text, default "Anchor"
class:string; // css class name
base:string; // any base URI
truncate:number; // Max length. Default 64
titleText:string; // any text
}This is the class.
class Anchor {
constructor (opts:Partial<AnchorOpts> = {
icon: '\uE9CB',
visible: 'always'
})
}Lower case anchor is a function that will create a new Anchor and call
.add().
Note
The option { visible: 'touch' } -- create links that are
always visible on touch devices.
function anchor (opts:Partial<AnchorOpts> = {}):Anchorimport { anchor } from '@substrate-system/anchor'
anchor({ visible: 'touch' })