joystick icon indicating copy to clipboard operation
joystick copied to clipboard

Consider doing a "modal" layer in the UI

Open rglover opened this issue 3 years ago • 4 comments

Modals are notoriously tricky on re-renders. Look into something like joystick.modal() and have a global registry spot in the DOM for loading these. Same component API, just a different way to route the HTML and have a global dispatcher to show/hide/update.

rglover avatar Sep 29 '22 21:09 rglover

Brainwave: just add a modal: true property to components. Makes it easy to scoop them up at build/mount time.

rglover avatar Sep 30 '22 14:09 rglover

Bumping this to 1.0.0. Have run into far too many headaches with modals and it makes a ton of sense. Should make UIs faster overall and makes markup clean as a bonus.

rglover avatar Nov 04 '22 00:11 rglover

Had a thought in the car...

The ideal way to do this is to just have an object on a parent component or layout where modals can be registered like this:

import ui from '@joystick.js/ui';
import ProfileModal from '/path/to/profileModal';

const SomeParent = ui.component({
  modals: {
    profile: ProfileModal,
  },
  events: {
    'click .edit-profile': (event = {}, component = {}) => {
      component.modals('profile').open();
      // Later: component.modals('profile').close();
    },
  },
  render: () => {
    return `
      <div>
        <button class="edit-profile">Edit Profile</button>
      </div>
    `;
  },
});

export default SomeParent;

So, when ANY component registers a modals property we do two things:

  1. Scoop up those components and render them into the modal layer.
  2. Make each modal available on the component instance of the parent that loaded it via component.modals('someModalName').

The only part of this that needs to be figured out is how do we automatically pass .open() and .close() methods down to modals and respect them?

rglover avatar Nov 10 '22 19:11 rglover

The only part of this that needs to be figured out is how do we automatically pass .open() and .close() methods down to modals and respect them?

The real problem here is just global access to state. Could just rig up a Cache specific to modals (e.g., const modals = cache('_modals')): https://github.com/cheatcode/joystick#global-state. Just use a _ prefix to mark it as internal and prevent conflicts.

Under the hood, set a joystick.modals() function with its .open() and .close() methods pointing to this. So whether in the parent or in the modal itself, you could trigger an open/close of any modal in the app. Would make composition of modal UIs super clean.

import ui from '@joystick.js/ui';
import ProfileModal from '/path/to/profileModal';

const Dashboard = ui.component({
  modals: {
    profile: ProfileModal,
  },
  events: {
    'click button': (event, component) => {
      ui.modals('profile').open({
        userId: 'someUserIdAsAProp',
      });
    },
  },
  render: () => {
    return `
      <div>
        <button>Edit Profile</button>
      </div>
    `;
  },
});

export default Dashboard;

Here ui is the window.joystick value and we just call ui.modals() from that, expecting the returned modal instance to have an .open() method that receives some props at open time.

rglover avatar Nov 28 '22 20:11 rglover