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

widgetly

v7.0.0

Published

Library helps you to create widgets, including widgets that work via an iframe

Downloads

320

Readme

Widgetly

Library helps you to create widgets, including widgets that work via an iframe.

Main goals

  • Reusable Widgets: extract some business logic into a universal widget, which can then be easily reused across various applications. A single widget can be integrated into numerous applications without the need to change its code.
  • API: create an external interface for interacting with the widget, that provides for developers methods to control the widget, receive data from it, and send data to the widget.
  • Transport: use built-in mechanism for sync data and methods between the application, widget, and iframe, without using postMessage directly.
  • Framework agnostic: use any libraries and frameworks to create widgets and applications that embed them, increasing flexibility and development speed.

Install

npm install widgetly

or

yarn add widgetly

Usage

Mediator

The Mediator is an instance of the widget factory. After creating an instance, you can declare widgets. If you are using iframe widgets, place this code in the parent window.

// ./mediator.ts
import {createMediator} from 'widgetly'

export const mediator = createMediator({
  // Prefix for data attributes when inserting widgets via HTML code
  prefix: 'rc'
}, {
  myMethod() {
    return 1
  },
  someProp: {
    someMethod() {
      return 2
    }
  }
})

Widget declaration

After creating the mediator, you can start declaring widgets via the factory.

mediator.defineWidget(config, properties)

Embedded widgets

// ./widget.ts
import {EmbedLayout} from 'widgetly'
import {mediator} from './mediator'

mediator.defineWidget({
  // Widget name
  name: 'EmbedComments',

  // Widget initialization function
  // - should return a Promise
  // - should render the widget
  async initialize() {
    // Wait until the widget enters the viewport
    await this.whenContainerInViewport({lazy: true})
    // Create an iframe tied to the current widget
    this.iframe = this.createIframe(iframeUrl)
    // Create an embedded layout
    this.layout = new EmbedLayout({
      spinner: '<div class="Spinner" />'
    })
    this.layout.showLoading()
    this.layout.addToDOM(this.container)
    this.layout.setContent(this.iframe)
    // Wait until the widget renders in iframe
    await this.iframe.initialize()
    this.layout.hideLoading()
  }
}, {
  // All methods declared here will enrich widget
  hide() {
    this.layout.hide()
  },

  show() {
    this.layout.show()
  }
})

Overlay widgets

// ./widget.ts
import {OverlayLayout} from 'widgetly'
import {mediator} from './mediator'

mediator.defineWidget({
  // Widget name
  name: 'LoginModal',

  // Widget initialization function
  // - should return a Promise
  // - should render the widget
  async initialize() {
    // Create an iframe tied to the current widget
    this.iframe = this.createIframe(iframeUrl)
    // Create an overlay layout
    this.layout = new OverlayLayout({hidden: true})
    this.layout.setContainer(this.container)
    this.layout.setContent(this.iframe)
    // Wait until the widget renders in iframe
    await this.iframe.initialize()
    this.layout.show()
  }
})

Layout

Layout is an element into which an iframe and loader are inserted.

There are following types of layouts:

  • EmbedLayout – Embeds into a specific element on the page
  • OverlayLayout – Overlay, can be used for modal windows

Widgets with iframe

Inside the iframe, you need to wrap the initialization of your widget.

registerIFrame(config, properties)

Example

// ./app.tsx
import React, {useEffect} from 'react'

export const App = ({transport, onReady}) => {
  useEffect(() => {
    onReady()
  }, [onReady])

  return (
    <TransportContext.Provider value={transport}>
      <main>
        ...
      </main>
    </TransportContext.Provider>
  )
}
// ./iframe.tsx
import React from 'react'
import {createRoot} from 'react-dom/client'
import {registerIFrame} from 'widgetly'
import {App} from './app'

const rootElement = document.getElementById('my_app')
const root = createRoot(rootElement)

registerIFrame({
  async initialize() {
    await new Promise(resolve => {
      root.render(
        <App 
          transport={this} 
          onReady={resolve} 
        />
      )
    })
  }
})

Using widgets

The mediator can automatically create widgets in containers with the corresponding data attributes when it appears in the DOM.

// ./app.ts
import React from 'react'
import './mediator'

export const App = () => {
  return (
    <div
      data-rc-widget="EmbedComments"
      data-rc-app-id={APP_ID}
      data-rc-page-url={window.location.pathname}
    />
  )
}

Or create widget through the factory to gain full control over the widget.

mediator.buildWidget(name, containerElement, params)

Example of creating a widget

// ./app.ts
import mediator from './mediator'

const container = document.getElementById('my_comments');

mediator.buildWidget('EmbedComments', container, {
  appId: APP_ID,
  pageUrl: window.location.pathname
}).then(widget => {
  // At this moment, you can use the widget external methods
});

Documentation

Currently we only have the API which you can check here.

Contributing

Start

After you clone the repo you just need to run yarn's default command to install and build the packages

yarn

Testing

We have a test suite consisting of a bunch of unit tests to verify utils keep working as expected. Test suit is run in CI on every commit.

To run the tests

yarn test

To run the tests in watch mode

yarn test:watch

Code quality

To run linting the codebase

yarn lint

To check typings

yarn typecheck

To check bundle size

yarn sizecheck

Discussion

Please open an issue if you have any questions or concerns.

License

MIT