Skip to content

Feature: Added renderTo prop instead of appendToBody#45

Merged
andrewrubin merged 9 commits into
release/v3.0.0from
feature/renderto-instead-appendbody
Jul 30, 2024
Merged

Feature: Added renderTo prop instead of appendToBody#45
andrewrubin merged 9 commits into
release/v3.0.0from
feature/renderto-instead-appendbody

Conversation

@pravton
Copy link
Copy Markdown
Contributor

@pravton pravton commented Jun 21, 2024

Description

This PR addresses issue #20 by removing the appendToBody prop and introducing the renderTo prop for the Modal component.

Solution

  • Added the renderTo prop, accepting both a string selector or an HTMLElement.
  • Removed the appendToBody prop.
  • If renderTo is a string, the modal will be appended to the element selected by document.querySelector. If it’s an HTMLElement, the modal will render in that element. If renderTo is not provided or fails, the modal defaults to document.body.

Additional Notes

This is a breaking change.

Screenshots

demo.mp4

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 21, 2024

🦋 Changeset detected

Latest commit: 6610bbf

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@wethegit/react-modal Major

Not sure what this means? Click here to learn what changesets are.

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

Copy link
Copy Markdown
Member

@andrewrubin andrewrubin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @pravton!

Couple comments from me here, and some ideas which might help to solve the hydration issues we were discussing.

Let me know if any of my feedback isn't clear 🙏

Comment thread src/lib/components/modal/modal.tsx Outdated
const getModalRoot = (renderTo?: string | HTMLElement) => {
if (typeof window !== "undefined") {
if (typeof renderTo === "string") {
return document.querySelector(renderTo) || document.body
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to add some error handling here. If a user is passing an invalid selector, they won't know why their modal is being appended to the body. Maybe we just error instead of falling back to document.body?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, I guess an error would be more helpful than appending body, I will add some error handling here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pravton I think there may've been a misunderstanding here based on what I'm seeing from the example.
If you tweak the renderTo examples where there's a string value passed in, the modal still opens when I believe what @andrewrubin meant is that if the element is not found, no modal should be opened.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Harvey! The intension was to keep the render in-place regardless since we don't use typescript in most cases, but based on Marlon's suggestion, we should be good once we remove the string/query selector.

Comment thread src/lib/components/modal/modal.tsx Outdated

export function Modal({ renderTo, className, ...props }: ModalProps) {
const modalRoot = getModalRoot(renderTo)
const appendToBody = modalRoot ? modalRoot === document.body : false
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know modalRoot does a check, but document.body will always be undefined on SSR here. Could be part of the hydration issue you were describing.

I think we could also rename this appendToBody variable to be a little more indicative of what its purpose is (being used to determine whether the body locks scrolling)

Copy link
Copy Markdown
Contributor Author

@pravton pravton Jun 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm yes, but when I tried to return null based on the client side logic, based on this https://nextjs.org/docs/messages/react-hydration-error because "there was a difference between the React tree that was pre-rendered from the server". So we should be fine if nothing is returned based on client side logic.

and that make sense, I will rename the appendToBody..

Comment thread src/lib/components/modal/modal.tsx Outdated
}

export function Modal({ appendToBody, className, ...props }: ModalProps) {
const getModalRoot = (renderTo?: string | HTMLElement) => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth memoizing this value as modalRoot within the component itself, rather than declaring a helper function outside.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fore sure, i will memorize this function within the component.

@pravton
Copy link
Copy Markdown
Contributor Author

pravton commented Jun 21, 2024

@andrewrubin I have updated based on your suggestions, let me know if this works or if anything needs to be addressed or any other suggestions.

@pravton pravton requested a review from andrewrubin June 21, 2024 22:54
@liamegan liamegan self-requested a review July 3, 2024 16:54
Comment thread src/lib/components/modal/modal.tsx Outdated
const modalRoot = useMemo(() => {
if (!isClient) return null

if (typeof renderTo === "string") {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrewrubin @pravton Tested locally and things look fine, but this could potentially be an issue in the event that there's multiple elements on the page with the same selector (in this case, classname); unless we're looking to only have at max, 3 modals - one for each type (body, selector, hash) - emptying and populating content on open/close.

Thinking that we could have the string value query for an element by id or by data-modal-id - working on an example atm, but lmkwyt.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should instead remove the option to pass a string and only accept an HTMLElement. It makes this more intention as the user will have to handle nullish values.

It also feel more reacty that way as you can use focus more on using refs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, yeah that makes sense! I will refactor this to only accept HTML element and I agree, feels more reacty this way..

Comment thread src/lib/components/modal/modal.tsx Outdated
const getModalRoot = (renderTo?: string | HTMLElement) => {
if (typeof window !== "undefined") {
if (typeof renderTo === "string") {
return document.querySelector(renderTo) || document.body
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pravton I think there may've been a misunderstanding here based on what I'm seeing from the example.
If you tweak the renderTo examples where there's a string value passed in, the modal still opens when I believe what @andrewrubin meant is that if the element is not found, no modal should be opened.

Comment thread src/lib/components/modal/modal.tsx
Copy link
Copy Markdown
Member

@marlonmarcello marlonmarcello left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should NOT default to document.body and make that parameter mandatory instead of optional. Rendering in place by default.

Also following my other comment, we shouldn't accept a string for this I think, just an HTMLElement.

We should also make positon: fixed default regardless and let the user handle a differerent position strategy if they want.

Rendering in place with position: fixed covers 90% of the use cases and avoids all these SSR issues.

These changes force this prop to be more intentional overall.

@pravton
Copy link
Copy Markdown
Contributor Author

pravton commented Jul 23, 2024

@andrewrubin @marlonmarcello @rvno So I made few changes based on the comments above,

  • Removed string prop, and modal component now only accepts HTMLElement. I have also made this prop mandatory in ModalProps.
  • By default the modal will be rendered in place with position: fixed
  • Updated the documentation to reflect the new changes

@pravton pravton requested review from marlonmarcello and rvno July 23, 2024 20:18
Copy link
Copy Markdown
Member

@andrewrubin andrewrubin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These updates are great @pravton 👏 I think it solves all the issues nicely. Couple final ideas/questions from me.

Comment thread src/main.tsx
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be beneficial to show an example in main.tsx of appending a modal to the body, thoughts?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sure, yeah that would be helpful! I will add an example.

Comment thread src/main.tsx
@pravton
Copy link
Copy Markdown
Contributor Author

pravton commented Jul 23, 2024

@andrewrubin So I have added an example on the main appending the modal to body and updated the text as I see fit, but let me know if that needs to be updated or the example.

@pravton pravton requested a review from andrewrubin July 23, 2024 23:31
marlonmarcello
marlonmarcello previously approved these changes Jul 24, 2024
@marlonmarcello
Copy link
Copy Markdown
Member

Great work @pravton !

@andrewrubin
Copy link
Copy Markdown
Member

okay! Looking great @pravton

Next step here is to bump the version using the yarn changeset command, and in the questionnaire just specify that it's a major version bump. I'd also like to get a beta release going so we can test this before releasing.

It looks like the docs for that are here: https://github.com/changesets/changesets/blob/main/docs/prereleases.md, but I'm tagging @marlonmarcello to see if he has some quick tips for us on this.

@andrewrubin
Copy link
Copy Markdown
Member

Thanks for the version bump @pravton

Let's keep this open for now, we'll just need to publish a beta version before merging this, so that we can test. I think the easiest option is to do that locally. Will make a note to do this when I have a moment!

andrewrubin
andrewrubin previously approved these changes Jul 26, 2024
Copy link
Copy Markdown
Member

@andrewrubin andrewrubin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pravton , sorry mate, I didn't realize this PR was to a release candidate and not main. In that case, we're good to merge this!

After, would you mind making a PR to main, for the release candidate? I will do the beta release from there

@andrewrubin andrewrubin changed the base branch from release-candidate/v3 to release/v3.0.0 July 30, 2024 03:05
@andrewrubin andrewrubin dismissed their stale review July 30, 2024 03:05

The base branch was changed.

@andrewrubin andrewrubin self-requested a review July 30, 2024 03:06
@andrewrubin andrewrubin merged commit f34c250 into release/v3.0.0 Jul 30, 2024
@andrewrubin andrewrubin deleted the feature/renderto-instead-appendbody branch July 30, 2024 03:06
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.

4 participants