Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: NativeDialog builder #40

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

Conversation

emmbm
Copy link

@emmbm emmbm commented Jan 27, 2025

Adds a dialog builder that relies on HTMLDialogElement while attempting to fill-in for pending features such as light dismissal for modals (whatwg/html#9373).

Using native dialog features also means we can create modals that use #top-layer, which means no more need for portals.

To do

  • Implement scroll locking util or builder
  • Decide how to pass / handle / hook into returnValue
  • Implement focus restoration
  • Improve accessibility

Copy link

changeset-bot bot commented Jan 27, 2025

⚠️ No Changeset found

Latest commit: 20eb4a9

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

vercel bot commented Jan 27, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
next-gen ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jan 27, 2025 9:36pm

@emmbm
Copy link
Author

emmbm commented Jan 27, 2025

For some simili-builders I'm working with on a personal project, I manage scroll locking (somewhat naively) using this:

export class ScrollLock {
  static #locks = new Map<HTMLElement, { overflow: string; active: Set<ScrollLock> }>();
  #element;
  #active = $state(false);

  constructor(element: HTMLElement, active?: boolean) {
    this.#element = element;
    if (active) {
      this.active = true;
    }

    $effect.root(() => {
      return () => {
        this.active = false;
      };
    });
  }

  get element() {
    return this.#element;
  }

  get active() {
    return this.#active;
  }

  set active(value) {
    if (value === this.#active) {
      return;
    }
    this.#active = value;
    const existing = ScrollLock.#locks.get(this.#element);
    if (value) {
      if (existing) {
        existing.active.add(this);
      } else {
        const overflow = this.#element.style.overflow;
        const active = new Set([this]);
        ScrollLock.#locks.set(this.#element, { overflow, active });
        this.#element.setAttribute('data-scroll-lock', 'true');
        this.#element.style.overflow = 'hidden';
      }
    } else {
      if (existing) {
        if (existing.active.has(this)) {
          existing.active.delete(this);
        }
        if (!existing.active.size) {
          this.#element?.removeAttribute('data-scroll-lock');
          this.#element.style.overflow = existing.overflow;
          ScrollLock.#locks.delete(this.#element);
        }
      }
    }
  }
}

@TGlide
Copy link
Member

TGlide commented Jan 29, 2025

I love the idea, still haven't had the time to check it out properly, but thank you for the proposal!

@emmbm
Copy link
Author

emmbm commented Jan 29, 2025

As an FYI, I haven't really played with it for now, it's still just a rough version. I think I can identify a few broken things as it stands:

  • onOpenChange will probably over-fire since it's both called by #open's Sync instance and in #setOpen
  • declarative ways of closing the dialog such as using a form with method="dialog" or a button with formmethod="dialog" aren't accounted for in the current way the state is managed
  • non-modal dialogs might not work as expected when it comes to light dismissal

@emmbm emmbm changed the title Propose NativeDialog builder Feat: NativeDialog builder Jan 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants