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

@coldwired/actions

v0.15.1

Published

DOM manipulation actions based on morphdom

Downloads

8,574

Readme

@coldwired/actions npm package

Why?

Initial inspiration was turbo-stream, which allows for the application of incremental changes to the page. The problem we faced was that applying changes wiped out client changes and it was not always practical to propagate the client state necessary for rendering to the server. We wanted to be able to preserve some state, such as open dialogs an menus or input values.

How?

Actions will create a MutationObserver and a WeakMap of some of the DOM state, such as class names, aria attributes, and input values. This allows it to preserve state across morph changes. You always have the possibility to force a state update through the attribute data-turbo-force.

Usage

Action

An action is an object describing a DOM operation. Actions can be fully serialized to carry them over the wire (turbo-stream).

type Action = {
  action: 'after' | 'before' | 'append' | 'prepend' | 'replace' | 'update' | 'remove' | 'focus' | 'enable' | 'disable' | 'hide' | 'show';
  targets: Element[] | string;
  fragment?: DocumentFragment | string;
  delay?: number;
  pin?: boolean;
}

Setup

Before you start working with actions, you need to create and register an instance of Actions. After that, actions can be applied through the Actions instance or dispatched as events. We also provide an implementation of turbo-stream on top of Actions through the @coldwired/turbo-stream package.

import { Actions } from '@coldwired/actions';

const actions = new Actions({ element: document.body });
actions.observe();

DOM manipulation

// Insert a fragment after each target element
actions.after({ targets: '.item', fragment: '<p>Hello World</p>' });

// Insert a fragment before each target element
actions.before({ targets: '.item', fragment: '<p>Hello World</p>' });

// Append a fragment after the last child of each target element
actions.append({ targets: '.item', fragment: '<p>Hello World</p>' });

// Prepend a fragment before the first child of each target element
actions.prepend({ targets: '.item', fragment: '<p>Hello World</p>' });

// Replace every target element with the fragment.
// Uses morph to preserve interactive state
actions.replace({ targets: '.item', fragment: '<p>Hello World</p>' });

// Update every target inner with the fragment.
// Uses morph to preserve interactive state
actions.update({ targets: '.item', fragment: '<p>Hello World</p>' });

// Remove all target elements
actions.remove({ targets: '.item' });

// Focus first target element
actions.focus({ targets: '.item' });

// Disable all target elements
actions.disable({ targets: '.item' });

// Enable all target elements
actions.enable({ targets: '.item' });

// Hide all target elements
actions.hide({ targets: '.item' });

// Show all target elements
actions.show({ targets: '.item' });

// Apply actions in batch. This is the low level API
actions.applyActions([
  {
    action: 'update',
    targets: '.item-to-update',
    fragment: '<p>Hello World</p>'
  },
  {
    action: 'remove',
    targets: '.item-to-remove',
  },
])

Dispatch from anywhere

If you want to dispatch actions from places where you don't have access to the Actions instance, you can use global API.

import * as Actions from '@coldwired/actions';

Actions.after({ targets: '.item', fragment: '<p>Hello World</p>' });

// Same as `applyActions` but you don't need access to the instance
Actions.dispatchActions([
  {
    action: 'update',
    targets: '.item-to-update',
    fragment: '<p>Hello World</p>'
  },
  {
    action: 'remove',
    targets: '.item-to-remove',
  },
]);

Delayed actions

You can add a delay to any action, which is useful for hiding flash messages after a short period of time, for example.

// Hide targets after 2 seconds delay
actions.hide({ targets: '.item', delay: 2000 });

Pinned actions

An action can be pinned — this is mostly useful in combination with full-page morph.

// In some client code append a new warning
actions.append({ targets: '.warnings', fragment: '<p>Warning !</p>', pin: true });

// Later, refresh the whole page. It will wipe out the warning added earlier.
// By running `applyPinnedActions`, you can restore previous changes
actions.morph(document, newDocument);
actions.applyPinnedActions();

// When you navigate to a new page, you might want to reset any pinned actions
actions.reset();