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

@hauke5/dialogexample

v1.2.5

Published

Running an example of component/dialog

Downloads

177

Readme

Dialog Component

A NextJS component package for simplifying and standardizing the use of user dialog in NextJS apps. Supported features include:

  • movable modal dialog box
  • fully typed interface, with typing support in the dialog result for accessing items and buttons by name.
  • configurable side effects: allow changes to an items value effect the values of other items or the the disabledness of buttons

Installation

Either 1) Use npx to run an example of the dialog component in a NextJS app:

$ npx hauke5/dialogexample

This will start a next development server. Point a browser to http://localhost:3001/dialog to run the app.

Or 2) use git clone to install the component along with a usage example app in NextJS:

$ git clone https://github.com/Hauke5/DialogExample.git

This will install the required typescript components and support libraries, along with the usage example in app/dialog/DialogExample.tsx To run the example manually, follow the git clone command with:

cd DialogExample  # change into the newly created folder
npm i             # install dependencies
npm run dev       # run the development server

Again, point a browser to http://localhost:3001/dialog to run the app.

Usage

Defining a Dialog

A dialog is defined by the DialogConfig structure, consisting of

  • a leading title to explain the purpose of the dialog to the user
  • an optional description, accepting a ReactNode
  • an optional list of dialog items, each consisting of a DialogItemConfig structure
  • and a list of buttons to perform actions.

If not provided by the DialogConfig, A Cancel button will be automatically added by the component.

A simplest version of a dialog configuration might look like this:

{
   title: 'Simple Dialog Example:',
   buttons:[
      { id:'OK'}, 
   ]
}

The ids for items and buttons are by default used as their labels. Alternatively, an optional label field can be specified:

{
   title: 'Example:',
   items:[
      { id:'ValidItem', type:'number', initial: 0, label:'Enter Valid Number'}},
   ],
   buttons:[
      { id:'OkButton', label:'OK'}}, 
   ]
}

Integrating Dialogs into Components

Add a <Dialog> component at the end of React nodes in your component. It takes a callback function through which it provides an open function that can be stored in a Ref. <Dialog> internally uses the html <dialog> tag, so stays invisible until opened, which happens below in runDialog when it is triggered by clicking on the Open Dialog button.

To open the dialog in code, call the open function provided by <Dialog> with the dialog content structure and await the result. It provides

  • the actionName, i.e. id of the button pressed (or, in some cases, an ID for some predefined dialog action such as double-clicking a file in a file selector field)
  • an items object containing each of the item IDs, providing
    • the type of the item's value
    • the current value of the item,
    • the isDefault status: false if the user has directly manipulated the item, and true if the value is either the initial value or the result of a sideEffect.
function Component() {
   const openDialog  = useRef<OpenDialog>()

   return <div>
      <button onClick={runDialog}>Open Dialog</button>
      <Dialog open={open=>openDialog.current=open} />
   </div>

   async function runDialog() {
      if (openDialog.current) {
         // open the dialog with `dialogConfog` as content
         const result = await openDialog.current({
            title: 'Example:',
            items:[
               { id:'ValidItem', type:'number', initial: 0, label:'Enter Valid Number'}},
            ],
            buttons:[
               { id:'OkButton', label:'OK'}}, 
            ]
         })
         // process the result action and item values
         if (result.actionName==='Ok') {
            const numberItem = result.items.ValidItem
            const number     = numberItem.value as number
            const isDefault  = numberItem.isDefault
            ...
         }
      }
   } 
}

Defining Side effects

Side effects are actions performed on the elements of a dialog box while the user manipulates them. For example, the disabled state of a button or the initial value of a dialog element can be made to change depending on the value of one or more other elements.

Two types of side effects are available:

Disabling Buttons

Add a disable function to a button configuration to tell the <Dialog> whether the button should be active or disabled. The function will receive the same items object as is returned when the dialog closes The following example disables the OkButton if the ValidItem value is 0

   ...
   buttons:[
      {id:'OkButton', disable:(items) items.ValidItem.value===0}, 
   ]
   ...

Item SideEffects

Add a sideEffect callback to an item configuration to have user-changes to the item value trigger updates to other items. The callback will receive the current value of the item, as well as a reference to the set of all items. In the example below, a sideEffect will be called each time the ValidItem number field changes. It will change the TextItem field, if it hasn't been explicitely set by the user, to read invalid number if the number value is 0, and valid number otherwise.

{
   title: 'Example:',
   elements:[
      { id:'ValidItem', type:'number', initial: 0, label:'Enter Valid Number:', 
         sideEffect:(value, items)=>items.TextItem.isDefault
            ? {TextItem: value!==0? 'valid number' : 'invalid number' }
            : {}
      }},
      { id:'TextItem', type:'text',   initial: 'invalid', label:'Number Comment:'}},
   ],
   buttons:[
      { id:'OkButton', label:'OK'}}, 
   ]
}

Complex Example:

{
   title: 'Dialog Example With Side-Effects:',
   description:  <div style={{borderBottom:"1px solid gray"}}>
      A <b>complex</b> dialog:
      <ul className={styles.instructions}>
         <li><b>Hint:</b>You can move the box by dragging it in the title field.</li>
         <li>Side effects within the dialog:</li>
         <ul className={styles.instructions}>
            <li><b>Ok Disabled</b>: Enter a number other than <code>0</code> in the the <code>Number</code> field to enable the <code>Ok</code> button.</li>
            <li><b>Field auto-values</b>:Changing the <code>Number</code> field automatically sets the <code>Text</code> field 
            to <code>valid</code> or <code>invalid</code> depending on the <code>Number</code> field value, 
            unless the user has manually changed it before</li>
         </ul>
         <li>Click the <code>Ok</code> button when available. 
         The left box below will reflect the values from the dialog.</li>
      </ul>
   </div>,
   items:[
      {id:'Date',      type:'date',   initial: new Date() },
      {id:'Number',    type:'number', initial: 0,   label:'Enter Valid Number:',  sideEffect:(value:number, items) => 
         items.Text.isDefault
            ? {Text:(value !== 0)? 'valid number' : 'invalid number' }
            : {}
      },
      {id:'Text',      type:'text',   initial: 'invalid', list:textFieldHistory},
      {id:'Checkbox',  type:'boolean',initial: false},
      {id:'List',      type:'select', initial: 'two',     list:['one', 'two', 'three']},
   ],
   buttons:[
      {id:'Ok', disable:(values) => values.Number.value===0}, 
   ]
}