-
Notifications
You must be signed in to change notification settings - Fork 30
feat(components): Feedback on Layout 2.0 #2485
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
Conversation
…, semantic elements
Deploying atlantis with
|
Latest commit: |
74ab561
|
Status: | ✅ Deploy successful! |
Preview URL: | https://b1317577.atlantis.pages.dev |
Branch Preview URL: | https://scott-t-layout-feedback.atlantis.pages.dev |
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.
Overall liking the direction and flexibility. Few questions.
* More information in the [Customizing components Guide](https://atlantis.getjobber.com/guides/customizing-components). | ||
*/ | ||
readonly UNSAFE_className?: { | ||
container?: string; |
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 had a question on this? I realize its consistent, but requires an object to be created for elements with only 1 component like this? Same comment about styles.
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.
Yeah I went for consistency over what felt like the shortest path. I'll double check with the team to see if the string-only option is acceptable within the pattern, because I would prefer it myself for this.
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 could become a clear rule that if it has more than one override, then it's an object; otherwise, it's a string.
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.
@jdeichert, @ZakaryH & I have discussed this before when adding UNSAFE_
to atom components that are also just a container. Jacob's suggestion was that we used a keyed map to make sure we're handling future scenarios/future proofing (even if it seems unlikely any other sub element will be added to a component).
I did initially have the same thoughts, and we could have just a string for className and an object for _styles
if people feel strongly. I tend to lean into consistency at this point.
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.
That's fair. I think it probably speaks to components needing more composition so that the overrides could be targetted, but another way to approach that with the current structure would be to actually give data-slot="<componentName>"
which could then be targetted by the CSS through data attribute selectors rather than needing to be the ones responsible for plumbing classnames through.
Forgive the tailwind nuances here that they're hiding behind Components, but he presents an interesting approach to controlling styles from above using data attributes. https://www.youtube.com/watch?v=MrzrSFbxW7M
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 was concerned about future-proofing because there are cases where we have to go in and wrap an extra div sometimes.
However, I'm realizing that typescript could allow us to support both scenarios. We could start off with a string type, and IF we ever need to expand this in the future, we could also accept an object with keys.
I can't remember if I had any other pro-object arguments, but I'm less concerned now.
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.
Wonder if we just leverage what Braid does? https://github.com/seek-oss/braid-design-system/blob/0de668c186fd972a197160b799b980243ef58dc7/packages/braid-design-system/src/lib/components/private/buildDataAttributes.ts
Then you don't need to re-type data?
}) { | ||
return <div className={styles.centerContent}>{children}</div>; | ||
return ( | ||
<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.
Should this also have a Tag?
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.
Sure should! Nice catch.
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.
Addressed!
export function dataPropsMapped(data?: Record<string, string>) { | ||
return Object.entries(data || {}).map(([key, value]) => ({ | ||
[key]: value, | ||
})); | ||
} |
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.
Is data
supposed to be used like
data={{ 'data-foo': true }}
or
data={{ foo: true }}
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.
Guess the other option is to just extend DataHTMLAttributes
from React?
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 updated this while you were reviewing (my spidey sense was tingling)! it's now a proper data- attribute and it lets you know how to use it.
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.
@scotttjob instead of Record<string, string>
you can possibly make a typescript key type that checks the prefix and this will guarantee it only allows data-
keys
I can hack up something today as an example 👍
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.
interface DataAttributes {
[key: `data-${string}`]: string;
}
export function dataPropsMapped(data?: DataAttributes) {
return Object.entries(data || {}).map(([key, value]) => ({
[key]: value,
}));
}
If you use this DataAttributes
type as the data
prop on components, it will flow through here properly, and the prop will block incorrect usages of it!
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 noticed you already used data?: { [key: data-${string}]: string };
in CommonAtlantisProps
. Ignore me 😅
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.
@ericchernuka something I learned about DataHTMLAttributes
is that it pulls in a lot more attributes than you would expect since it also extends HTMLAttributes
(which extends AriaAttributes
and DOMAttributes
).
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 believe that's because it's for the data
element: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/data (just like how InputHTMLAttributes
is for input
)
It's not actually data attributes as far as I can tell
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.
Yup. I dug into the types and was like why am I getting aria attributes!?
export function ariaPropsMapped(aria?: React.AriaAttributes) { | ||
return Object.entries(aria || {}).map(([key, value]) => ({ | ||
[key]: value, | ||
})); | ||
} |
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.
Same comment about aria attributes.
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.
Wonder if we can just extend AriaAttributes
from React?
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.
Donezo! This was one was in flight too while you were reviewing. You can now pass fully qualified aria-
and it autocompletes for you.
export const AtlantisBreakpoints = { | ||
xs: 0, | ||
sm: 490, | ||
md: 768, | ||
lg: 1080, | ||
xl: 1440, | ||
}; |
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 noticed that we seem to redefine these across many components? Do we need a central version that they all extend from?
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.
Yeah it's going to be this one. We seemed to have a pattern in the past where we didn't re-use anything across components unless they got promoted to hooks, but that's too much effort for some of these component-only usages.
Looks really good to me. We have been adding |
/** Standard HTML id attribute. */ | ||
id?: string; | ||
} | ||
export type CommonAllowedElements = |
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.
Let's also add p
which would be useful in some scenerios
* More information in the [Customizing components Guide](https://atlantis.getjobber.com/guides/customizing-components). | ||
*/ | ||
readonly UNSAFE_className?: { | ||
container?: string; |
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.
That's fair. I think it probably speaks to components needing more composition so that the overrides could be targetted, but another way to approach that with the current structure would be to actually give data-slot="<componentName>"
which could then be targetted by the CSS through data attribute selectors rather than needing to be the ones responsible for plumbing classnames through.
Forgive the tailwind nuances here that they're hiding behind Components, but he presents an interesting approach to controlling styles from above using data attributes. https://www.youtube.com/watch?v=MrzrSFbxW7M
* More information in the [Customizing components Guide](https://atlantis.getjobber.com/guides/customizing-components). | ||
*/ | ||
readonly UNSAFE_className?: { | ||
container?: string; |
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.
Wonder if we just leverage what Braid does? https://github.com/seek-oss/braid-design-system/blob/0de668c186fd972a197160b799b980243ef58dc7/packages/braid-design-system/src/lib/components/private/buildDataAttributes.ts
Then you don't need to re-type data?
readonly children: React.ReactNode; | ||
/** The width of the sidekick. */ | ||
readonly sideWidth?: string; | ||
/** The minimum width of the content. */ | ||
readonly contentMinWidth?: string; | ||
/** The amount of space between the sidekick and the content. Semantic tokens are available. */ | ||
readonly space?: string | Spaces; | ||
readonly gap?: string | Spaces; |
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 see that in other places you used a slightly different type:
readonly gap?: Spaces | (string & NonNullable<unknown>);
Is it intentionally different here?
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.
Not intentionally no! I've replaced these various Spaces | options with a new 'GapSpacing' type that should be used everywhere this loose type appeared before.
readonly children: React.ReactNode; | ||
/** The amount of space between the children. Semantic tokens are available. */ | ||
readonly space?: string | Spaces; | ||
/** The number of children to split the stack after (1-15). Requires parent to have height greater than the sum of the children. */ | ||
readonly gap?: string | Spaces; |
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.
Same comment as above regarding the type.
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.
Replaced with the above!
readonly children: React.ReactNode; | ||
/** The minimum size of the tiles. */ | ||
readonly minSize: string; | ||
/** The amount of space between the tiles. Semantic tokens are available. */ | ||
readonly space: string | Spaces; | ||
readonly gap: string | Spaces; |
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.
Same as above. Also is gap
required for Tiles
?
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.
Gap is not required! Good catch. I've updated this one as well with the new type
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.
Looks good! I'll approve the main PR once this one merges down.
…is into scott_t/layout-feedback
Motivations
Changes
useMediaQuery
usages for 'collapseBelow'. Instead relying on common Atlantis breakpoints. Also included a 'collapsed' prop so the consumer can have completely control beyond the standard breakpoints.Changes can be
tested via Pre-release
In Atlantis we use Github's built in pull request reviews.