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

@ithaka/pharos

v14.4.0

Published

Pharos web components for products and experiences

Downloads

5,112

Readme

Pharos Web Components

Web Components are a set of web platform APIs that allow you to create new custom, reusable, encapsulated HTML tags to use in web pages and web apps.

Pharos provides a web component library for building products consistent with the JSTOR brand.

If you're using Vue, you can use these components in the same manner specified, without any additional steps!

Installation

$ npm install @ithaka/pharos

Registering components

  1. To allow multiple versions of Pharos to exist on a page, this package only exports component classes for you to register on the custom element registry in your application. To register components, you can use the registerComponents utility to define all the Pharos components your application uses, with a consistent scoping prefix:
import { PharosAlert, PharosButton, PharosIcon } from '@ithaka/pharos';
import registerComponents from '@ithaka/pharos/lib/utils/registerComponents';

registerComponents('homepage', [PharosAlert, PharosButton, PharosIcon]);

Note: When using module federation, you may only share Pharos successfully by using the registerComponents utility. This avoids registering elements with the same underlying class instance, which would result in an error.

To manually register a component, import the classes you wish to use in your application's entrypoint and define the custom element with a tag name in the form of {app/bundle}-pharos-{component} and a trivial subclass that extends the Pharos class wrapped in the PharosComponentMixin:

import { PharosAlert } from '@ithaka/pharos';
import PharosComponentMixin from '@ithaka/pharos/lib/utils/mixins/pharos-component';

customElements.define('homepage-pharos-alert', class extends PharosComponentMixin(PharosAlert) {});

Note: If you register a name that already exists the browser will throw an error about the duplicate.

  1. Internally, Pharos components that are composed of other Pharos components scope their registries to their shadow root to avoid duplicate registrations. Because the Scoped Custom Element Registries proposal is not yet finalized, you need to apply a polyfill to use our components.

  2. Every component sets a custom data attribute data-pharos-component on itself with its class name (such as PharosAlert) to allow you to query any instance of that component regardless of its defined tag. Components also use this attribute to locate slotted Pharos children. Bundlers minify these class names by default for production builds. To ensure components work as expected, update your configurations like so:

Webpack (Terser):

optimization: {
  minimizer: [
    new TerserPlugin({
      terserOptions: {
        keep_classnames: /^Pharos/,
        keep_fnames: /^Pharos/,
      }
    }),
  ],
}

Vite (ESBuild):

export default defineConfig({
  esbuild: {
    keepNames: true,
  },
});

Using web components

After installing Pharos and registering the components, you can render them in any of your templates:

<pharos-tooltip>
  <button>Hover here!</button>
  <span slot="content">I am a tooltip</span>
</pharos-tooltip>

See the web component Storybook for details on component-specific syntax.

Using Pharos components in React

React is a JavaScript library used to build encapsulated components that manage their own state. React doesn't currently play perfectly with native web components, so if you're developing a React application you need to use the wrapper components provided in the lib/react-components/ directory of the package.

To use the React components, first register the components using the registerComponents utility. Then, in your app's entry file, use the PharosContext context provider to indicate the scoping prefix you registered them under:

import { PharosContext } from '@ithaka/pharos/lib/utils/PharosContext';

const context = { prefix: 'homepage' };

Then, render it in your JSX:

<PharosContext.Provider value={context}>...app code</PharosContext.Provider>

To use a component, first import it:

import { PharosTooltip } from '@ithaka/pharos/lib/react-components';

Then, render the component in your JSX:

<PharosTooltip content={'I am a tooltip'}>Hover here!</PharosTooltip>

See the React Storybook for details on component-specific syntax.

Styling components

Pharos components utilize CSS variables for their styling. To style components across your app, import the variables like so in your styles entrypoint:

/* index.css */

@import '@ithaka/pharos/lib/styles/variables.css';

/* More global styles */

Using Pharos design tokens

Components in Pharos are styled using design tokens, a tech agnostic way to store design decisions such as typography, color, and spacing so that Pharos can be shared across platforms. You can use these tokens to help style your own components and pages to ensure the brand is properly expressed to users. The token files are located in the lib/styles/ directory of the package.

To use the tokens as SASS variables, import them like so in the file where you want to use them:

/* example-page.scss */

@import '@ithaka/pharos/lib/styles/_variables';

/* More styling for the example page */

To use the tokens as ESM modules in your JavaScript, import them like so to ensure unused tokens are tree-shaken:

/* example-page.js */

import { PharosColorTextBase } from '@ithaka/pharos/lib/styles/variables';

Typography and mixins

Pharos uses Ivar a serif primarily for headlines and GT America a sans serif for body copy. The font-face stylesheet and base typography styles are located in the lib/styles/ directory of the package. Import them, along with the design tokens, in your app's styles entrypoint file:

/* index.scss */

@import '@ithaka/pharos/lib/styles/fonts.css';
@import '@ithaka/pharos/lib/styles/variables.css';
@import '@ithaka/pharos/lib/styles/typography';

/* More global styles and imports */

Pharos also provides SASS mixins which are reusable styles shared across multiple components. Import them like so in the file where you want to use them:

/* example-page.scss */

@use '@ithaka/pharos/lib/styles/pharos';

.some-text {
  @include pharos.font-base;
}

The base typography styles and mixins utilize SASS modules which replaces @import with @use to make CSS, variables, mixins, and functions from another stylesheet accessible in the current stylesheet. If your project uses Webpack for bundling, you will need to make sure sass-loader is set to use dart-sass instead of node-sass as Node Sass is deprecated and does not support SASS modules. If using sass-loader >= 9.0.0 no change is required as sass is set as the default. Otherwise, update your Webpack config as so:

/* webpack.config.js */

{
  loader: 'sass-loader',
  options: {
    implementation: require('sass'),
  }
}

You can access all Pharos variables, mixins, and functions from a single pharos.scss entrypoint file. Import it in the file where you want to use its modules:

/* example-page.scss */

@use '@ithaka/pharos/lib/styles/pharos';

.some-text {
  @include pharos.font-base;

  color: pharos.$pharos-color-text-20;
}

Additional component styles

Most components in Pharos benefit from the fully isolated styling provided by web components and CSS variables. However, some components provide slots you can populate with your own content. Content provided by application authors is rendered in the light DOM, and is not always stylable by web components.

You may need to import additional CSS files into your project's build for components whose slots expect nested content. These files are located in the lib/styles/ directory of the package. To use the CSS, import it in whichever bundle will be included on the same page as your component:

/* example-page.css */

@import '@ithaka/pharos/lib/styles/pharos-alert.css';

/* More styling for the example page */

Selectors in component stylesheets are scoped to the component's host element (<pharos-alert> in the above example).

Components that have corresponding stylesheets are:

  • pharos-alert
  • pharos-footer
  • pharos-modal

Using Pharos form elements in forms

Pharos form elements listen to the formdata event to add their values to the enclosing <form>. Safari doesn't natively fire the formdata event, so form authors need to fire a custom event in its stead.

Pharos provides a cross-browser createFormData utility function for populating forms via a custom formdata event. You should call createFormData in your form's submit event handler.

import createFormData from '@ithaka/pharos/lib/utils/createFormData.js';

const form = document.querySelector('form');
form.addEventListener('submit', (event) => createFormData(event.target));

If you submit your forms asynchronously, you can pass the result of createFormData in your request:

import createFormData from '@ithaka/pharos/lib/utils/createFormData.js';

const form = document.querySelector('form');

form.addEventListener('submit', (event) => {
  event.preventDefault();

  const formData = createFormData(event.target);

  const xhr = new XMLHttpRequest();
  xhr.open('POST', 'https://some-url.com');
  xhr.send(formData);
});

Adoption Governance Model

Take a look at the adoption governance model for a quick overview of the adoption process.