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

@rolemodel/turbo-confirm

v2.1.0

Published

Drop-in upgrade for Rails' data-turbo-confirm feature to support custom HTML dialogs.

Downloads

2,894

Readme

Turbo Confirm

A drop-in upgrade for Rails data-turbo-confirm.

title image

Installation

npm install @rolemodel/turbo-confirm

or

yarn add @rolemodel/turbo-confirm

Setup

In your application's JavaScript entry point file. (usually app/javascript/application.js)

import "@hotwired/turbo-rails"
import TC from "@rolemodel/turbo-confirm"

TC.start()

note: @hotwired/turbo-rails must be imported prior to calling the start function. This is so Turbo-Confirm can coordinate with Turbo regarding confirmation handling. The start function is also where you may override default behavior by passing a configuration object. See configuration docs for available options and their default values.

Usage

Turbo's confirmation interface is exercised most commonly via button_to (example shown in slim templating syntax)

  = button_to 'Delete ToDo', todo_path(todo),
    class: 'btn btn--danger',
    method: :delete,
    data: { turbo_confirm: 'Are you sure?' }

or link_to with a data-turbo-method attribute.

  = link_to 'Delete ToDo', todo_path(todo),
    class: 'btn btn--danger',
    data: { \
      turbo_method: :delete,
      turbo_confirm: 'Are you sure?',
    }

Customizing more than just a message

Turbo-Confirm supports other custom content beyond a simple message, by setting additional data attributes on the confirmation trigger. Henceforth referred to as contentSlots, this feature is both infinitely configurable and completely optional. Out of the box Turbo-Confirm supports two:

  • body activated by a data-confirm-details attribute on the confirmation trigger. The attribute's value will be assigned to the element matching the #confirm-body selector.
  • acceptText activated by a data-confirm-button attribute on the confirmation trigger. The attribute's value will be assigned to the element matching the #confirm-accept selector (same as the default value of the acceptSelector configuration property)

example usage of default contentSlots via button_to in slim templating syntax:

  = button_to 'Delete ToDo', todo_path(todo),
    method: :delete,
    data: { \
      turbo_confirm: 'The following ToDo will be permanently deleted.',
      confirm_details: simple_format(todo.content),
      confirm_button: 'Delete ToDo',
    }

note: It's recommended that you have sensible default content already populating each of your configured contentSlots within your app's confirmation dialog template. Such that every confirmation trigger is not required to supply custom content for every contentSlot. See our example template for a good starting point.

Manual Usage

Though Turbo-Confirm was primarily designed to serve as turbo-rails' confirmation interface, it may also be invoked directly by application code. In almost the same manner as the native window.confirm. While native confirm pauses execution until the user accepts or declines, Turbo-Confirm is Promise based.

e.g.

import { TurboConfirm } from "@rolemodel/turbo-confirm"

const tc = new TurboConfirm()
tc.confirm('Are you sure?').then(response => { response ? /* accepted */ : /* denied */ })

The message itself is optional as well. Simply call confirm() with no arguments and your dialog's default content will be displayed un-altered. e.g.

import { TurboConfirm } from "@rolemodel/turbo-confirm"

const tc = new TurboConfirm({ /* Any Custom Configuration */ })
tc.confirm()

Turbo-Confirm has an additional public method, confirmWithContent that expects a contentMap object where the keys are content slot selectors and the values are the content you want displayed in each selected element.

e.g.

import { TurboConfirm } from "@rolemodel/turbo-confirm"

const tc = new TurboConfirm()
tc.confirmWithContent({
  '#confirm-title': 'Are you sure?',
  '#confirm-accept': 'Do it!'
}).then(response => { response ? /* accepted */ : /* denied */ })

note: The TurboConfirm constructor creates a brand new instance that will not share configuration with the one Turbo-Rails is using. For that reason, a config object may be passed into the TurboConfirm constructor. See configuration docs for available options and their default values.

Stimulus Example

While Turbo will invoke Turbo-Confirm for you in the case of a form submission (like button_to) or form link (like link_to with a data-turbo-method), in the case of a regular link or a button that does not submit a form, you're on your own. But Turbo-Confirm can help.

For those cases, a simple Stimulus wrapper around Turbo-Confirm is a good solution.

e.g.

import { Controller } from "@hotwired/stimulus"
import { TurboConfirm } from "@rolemodel/turbo-confirm"

export default class extends Controller {
  #hasAccepted = false

  connect() {
    this.tc = new TurboConfirm({ /* Any Custom Configuration */ })
  }

  async perform(event) {
    if (this.#hasAccepted) {
      this.#hasAccepted = false
      return
    }

    event.preventDefault()
    event.stopImmediatePropagation()

    if (await this.tc.confirm(event.params.message)) {
      this.#hasAccepted = true
      event.target.click()
    }
  }
}

<a href="https://rolemodelsoftware.com" data-controller="confirm" data-confirm-message-param="Do you need custom software?" data-action="confirm#perform">Click me</a>

Configuration

| Option | description | default value | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | | dialogSelector | Global CSS selector used to locate your dialog HTML (an ID selector is recommended) | '#confirm' | | activeClass | HTML class that causes your dialog element to become visible. (note: you're responsible for defining necessary style rules) | 'modal--active' | | acceptSelector | CSS selector identifying the button within your dialog HTML which should trigger acceptance of a confirmation challenge | '#confirm-accept' | | denySelector | CSS selector identifying the button(s) within your dialog HTML which should trigger rejection of a confirmation challenge | '.confirm-cancel' | | animationDuration | approximate number of miliseconds Turbo-Confirm should wait for your dialog's CSS to transition to/from a visible state | 300 | | showConfirmCallback | a function, called on show with 1 argument (the dialog). The default provides support for native dialog elements | see below | | hideConfirmCallback | a function, called on accept or reject with 1 argument (the dialog). The default provides support for native dialog elements | see below | | messageSlotSelector | CSS selector of the element within your dialog HTML where the value of data-turbo-confirm (or supplied message) should be rendered | '#confirm-title' | | contentSlots | an object describing additional customization points. See contentSlots for a more detailed description. | see below |

Default Config Object

{
    dialogSelector: '#confirm',
    activeClass: 'modal--active',
    acceptSelector: '#confirm-accept',
    denySelector: '.confirm-cancel',
    animationDuration: 300,
    showConfirmCallback: element => element.showModal && element.showModal(),
    hideConfirmCallback: element => element.close && element.close(),
    messageSlotSelector: '#confirm-title',
    contentSlots: {
      body: {
        contentAttribute: 'confirm-details',
        slotSelector: '#confirm-body'
      },
      acceptText: {
        contentAttribute: 'confirm-button',
        slotSelector: '#confirm-accept'
      }
    }
  }

Example Template

Based on the default configuration, the following template is suitable.

  <!-- not visible until a 'modal--active' class is applied to the #confirm element -->
  <div id="confirm" class="modal">
    <div class="modal__backdrop confirm-cancel"></div>
    <div class="modal__content">
      <h3 id="confirm-title">Replaced by `data-turbo-confirm` attribute</h3>
      <div id="confirm-body">
        <p>Default confirm message.</p>
        <p>Optionally replaced by `data-confirm-details` attribute</p>
      </div>
      <div class="modal-actions">
        <button class="confirm-cancel">Cancel</button>
        <button id="confirm-accept">Yes, I'm Sure</button>
      </div>
    </div>
  </div>

Native Dialogs

If you're not already using a CSS or style component framework. I suggest checking out Optics. Alternatively, the native dialog element is fully supported by modern browsers and removes much of the styling burden that would otherwise be required to emulate such behavior with only a div.

Turbo-Confirm fully supports the native dialog element, including dismissal via esc key.

  <!-- not visible without an [open] attribute, which **Turbo-Confirm** will handle for you -->
  <dialog id="confirm" class="modal">
    <div class="modal__content">
      <h3 id="confirm-title">Replaced by `data-turbo-confirm` attribute</h3>
      <div id="confirm-body">
        <p>Default confirm message.</p>
        <p>Optionally replaced by `data-confirm-details` attribute</p>
      </div>
      <div class="modal-actions">
        <button class="confirm-cancel">Cancel</button>
        <button id="confirm-accept">Yes, I'm Sure</button>
      </div>
    </div>
  </dialog>

Development

After cloning the repository, you'll need to install dependencies by running yarn install.

The test suite can be run with yarn test. Or open the Playwright GUI application with yarn test:ui

Finally, the test app's server can be run on PORT 3000 with yarn dev.

Each of these tasks is also accessible via Rake, if you prefer. Run rake -T for details.

Acknowledgments

Turbo-Confirm is MIT-licensed, open-source software from RoleModel Software.

RoleModel Software is a world-class, collaborative software development team dedicated to delivering the highest quality custom web and mobile software solutions while cultivating a work environment where community, family, learning, and mentoring flourish.