Nighttime Pachinko Marathon

    @ithaka/pharos
    TypeScript icon, indicating that this package has built-in type declarations

    12.17.0 • Public • Published

    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.

    Keywords

    none

    Install

    npm i @ithaka/pharos

    DownloadsWeekly Downloads

    11

    Version

    12.17.0

    License

    MIT

    Unpacked Size

    2.8 MB

    Total Files

    1128

    Last publish

    Collaborators

    • eslawski
    • daneah
    • ironheadjay
    • michaeliden90
    • nazimali
    • ithaka-jenkins
    • jialin-he
    • ithaka-ci