-
-
Notifications
You must be signed in to change notification settings - Fork 322
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with comment.
Really like the proposed solution. It's very clean and simple to use. Had a tiny comment on the way we render children. Let me know, what you think :)
Would also argue, that we should add PropTypes
for the modal until we have Typescript in place. This will allow other devs. to very easily use and configure the modal without having to dig into the implementation specifics. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work Philip! Loved the cloning approach and I think it's cleaner/simpler than using contexts for that matter 👍 Left a few comments here and there which are all up for discussion!
Btw, I noticed that you use rest parameters for the components, which imo is a good thing when it comes to extending or building around a library. However, I'm not sure if they're passed along the children components.
Nevertheless I think it's not a very straightforward "design problem" especially for components like Modal
which wrap around Dialog.Root
, Dialog.Portal
, Overlay
, and Content
.
What I would suggest is to pass Modal
's rest params to Dialog.Root
, then if we come across a use case where we need to pass props to Dialog.Portal
or any other component, we can extend the prop types to something like portalProps
and/or overlayProps
etc.
Feel free to skip this comment btw because at this stage, I think it's not extremely important, and we can always think about this later down the road. Just thought that the idea of passing down some props to radix primitives might be worth keeping in mind.
children.map(child => React.cloneElement(child, prop)) | ||
} | ||
|
||
const Modal = ({children, onClick, isLargeModal, ...rest}) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking we might want to take a triggerElement
as prop and render it as a child of <Dialog.Trigger>
. My understanding is that Dialog.Trigger
encapsulates some important HTML attributes for accessibility to signal that a button opens an interactive element (a modal in this case).
I'm thinking something like:
const Modal = ({ triggerElement, ...otherProps }) => {
return (
<Dialog.Root>
{triggerElement && <Dialog.Trigger>{triggerElement}</Dialog.Trigger>}
...
</Dialog.Root>
)
}
const Modal = ({children, onClick, isLargeModal, ...rest}) => { | ||
const largeModal = isLargeModal | ||
return ( | ||
<Dialog.Root open={true} onOpenChange={onClick}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would cool not to hard code the open state and instead take it as props. Same for onOpenChange
because the callback is called whenever the open
state changes (so from open -> closed and from closed -> open). So the onClick
might not be 100% accurate. Let me know what you think
</div> | ||
) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be cool to have an additional Modal.Close = Dialog.Close
here so that we have more than one button to close the button (close icon on the top + cancel button).
return ( | ||
<div className='pl-7 pt-3.5 pr-3.5 flex flex-col w-full' onClick={e => e.stopPropagation()}> | ||
<div className='pb-1 flex w-full justify-end'> | ||
{showCloseIcon && (<span onClick={handleClose} className="stroke-grey-50 cursor-pointer"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about wrapping the span in a Dialog.Close
? The Dialog.Close
will take care of closing the modal.
* modal revamp * create molecule modal * better addProps * add radix dialog * update modal with proptypes
What
Modal
using radix-uiHow
Dialog
component from radix-uiisLargeModal
prop of each childAdding props through the DOM tree
When creating this component i thought it would be nice to be able to define if a modal was large or small with a single boolean value. Since different parts of the modal depends on this, specifically the padding and border of the footer, I looked at how to pass props to the
{children}
element at runtime.I found two different options for how to achieve this:
isLargeModal
as a prop throughout the DOM treeI chose option nr. 1 since it seemed the least over-engineered and from what I could read using
React.cloneElement
does not mean taking a performance hit in terms of the render, especially when working with such small components as modals. Using contexts is something we can always do instead at a later time because of the relative small size of the component, though the usecase seems to be for bigger elements of an application rather than an invite modal.I have implemented this practically as a helper method in the
index.js
file of the modal molecule. The helper method uses theReact.cloneElement
method to add the prop to either a single element or array of elements:This method is then used in each of the Modal components and subcomponents to add the
isLargeModal
prop to each of the children as such:Example
Below is an example of how to use the modal, each part of the modal is optional, and the top-level
Modal
component has a propisLargeModal
to indicate if the modal has width 750 or if it's smaller.furthermore when
isLargeModal
is set it will make the footer wider and add a hairline border top to the footer.