npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

overlapping-markup

v0.5.1

Published

React component which renders text with arbitrary styling applied to potentially overlapping ranges

Downloads

6

Readme

Overview

:warning: THIS LIBRARY IS A PRERELEASE - while version number is < 1.0.0 breaking API changes may be made without warning

This package Provides a React component capable of automatically generating the markup required to render text with arbitrary styling applied to potentially overlapping ranges.

Conceptually, this package transforms (a JSON representation of) non-hierarchical tag soup such as:

<b>Hello <i>World</b> Goodbye</i>

Into the following valid tag set:

<b>Hello <i>World</i></b> <i>Goodbye</i>

Although each element is in fact a React component.

Further information about the problem domain of "Overlapping (aka Concurrent) Markup" can be found on wikipedia.

Basic Usage

The <OverlappingMarkup> component requires at minimum:

  • A string representing the text that should be styled
  • A list of styling blocks, which specify both the start and end index of the text to be wrapped, and references to React components used to wrap the text content

The above example HTML could be rendered with the following code:


import OverlappingMarkup from 'overlapping-markup';

const StyleBold = {
  content: (props) => <b>{ props.children }</b>,
};

const StyleItalic = {
  content: (props) => <i>{ props.children }</i>,
};

const TEXT    = 'Hello World Goodbye';

const STYLING = [
  { min: 0, max: 11, style : StyleBold   },
  { min: 6, max: 18, style : StyleItalic },
];

function App(){
  return (
    <OverlappingMarkup text={TEXT} styling={STYLING}/>
  );
}

Project Structure

This project is a vite.js react app, containing both a dev server for testing, and a library build for publishing for use in other projects

  • index.html and src/index.jsx define the dev serer entry points
  • All vite config is in the single vite.config.js

Advanced Features

Props

The style's content component is passed a props object with a field style_data, which refers to an extra data field attached to the style block itself. This allows parameterised components to be rendered, for example the following which highlights text with an arbitrary color:

For example:

const StyleHighlight = {
  content: (props) => <span style={{backgroundColor: props.style_data.color}}> { props.children } </span>,
};

const STYLING = [
  // ... etc ...
  { min: 10, max: 20, style: StyleHighlight, data: { color: 'red' } },
];

Before and After Elements

In addition to the content render (as seen above), styles may also contain a before and after render. Conceptually these are equivalent to the CSS :before and :after psuedo-selectors, however they are provided since this component can deal with overlapping hierarchies by splitting up a region into multiple separate content blocks - using CSS would therefore cause each of these to have an associated before and after element. Using the style's before and after renderer guarantees only a single extra component is inserted.

For example, we could extend the above example by replacing StyleItalic with the following:

const StyleItalic = {
  before  : (props) => '(',
  content : (props) => <i>{ props.children }</i>,
  after   : (props) => ')',
};

This would cause the following effective tag structure to be rendered:

<b>Hello (<i>World</i></b> <i>Goodbye</i>)</b>

As can be seen, only a single instance of the before and after elements are rendered - even though two instances of the content element are rendered since it is split by the overlapping <b> block.

The before and after components are passed the same props as content.

Using State

While the before, after and content components are real React components, due to the fact an arbitrary number of instances of content may be rendered, stateful components (for example, using the useState hook) will behave strangely.

OverlappingMarkup provides a mechanism to share state between all parts of a style region, including communicating between the before, content and after components:

const StyleHighlightable = {
  content: (props) => {
    if(props.state.active){
	  return <b>{props.children}</b>;
	} else {
	  return <span>{props.children}</span>;
	}
  },
  after: (props) => {
    return (<button onClick={e => props.setState({ active: true })}>Activate</button>),
  },
};

Note that when using such stateful styles, you must specify an id for the style block, for example:

{
  min   : 10,
  max   : 20,
  style : StyleHighlightable,
  id    : 'block-a'
}

If the id changes, the then the state passed through via props will be reset. Note also that multiple style blocks may share the same id, which will cause them to share the same state object.

By default, props.state will intially be the empty object. A custom initial state may be provided on the style region:

{
  min           : 10,
  max           : 20,
  style         : StyleHighlightable,
  id            : 'block-a',
  initial_state : { active: false },
}