-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Big Rewrite - Add reusable wrappers, add more components (#43)
* docs: add code guidelines * fix: ESLint downgrade * refactor: update default components for code styling * refactor(default): update and fix component styles * refactor: export code styling rule * refactor: remove showRadio prop * refactor: update searchfield to use a group * feat: add field, modify searchfield to use * feat: add datefield and timefield * feat: add form helper components * refactor: move props * feat: add datepicker demos using input * refactor: remove date picker button, move to examples * refactor: tabs component * feat: add listbox, modify popover, add dialog * update select and popover, add listbox * update select, combobox and listbox * update menu component * dialog and popover * add tag group * update calendar * add numberfield, add grid list * Add missing components to new-york * redo button demos * Add gridlist demos * update docs and demos * more demos and components * Datepicker demos * add range calendar * more components done * add form demos * more demos and fixes * combobox * finish demos kinda * update docs mdx * update new york demos * fix toolbar * update dmoes * add new-york back * fix build * run linter * run prettier * remove storybook * update lockfile * add reusable wrappers * update icons * add reusable calendar * add reusable wrapper demos * fix export replacement * add missing reusable wrappers * registry commit * update docs * remove disabled sort * update reusable wrapper docs * remove label for field * rename input * remove textarea * update registry * update registry * update registry 2 * remove input * change links for release * update announcement * update docs * update docs
- Loading branch information
Showing
831 changed files
with
26,808 additions
and
19,208 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,7 +36,7 @@ yarn-error.log* | |
# Misc | ||
.DS_Store | ||
*.pem | ||
storybook-static/ | ||
|
||
|
||
# turbo | ||
.turbo | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
auto-install-peers = true | ||
enable-pre-post-scripts=true | ||
public-hoist-pattern[]=*storybook* | ||
public-hoist-pattern[]=*eslint-plugin-* | ||
public-hoist-pattern[]=@typescript-eslint/eslint-plugin | ||
public-hoist-pattern[]=@typescript-eslint/parser |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
# JollyUI Code Styling Guidelines | ||
|
||
## Naming Conventions | ||
|
||
### Aliasing Aria Components | ||
|
||
To avoid naming collisions between JollyUI components and React Aria Components, use the alias Aria(Component) when importing React Aria Components. | ||
|
||
#### Example | ||
|
||
##### Good: | ||
|
||
```tsx | ||
import { Button as AriaButton } from "@react-aria/button" | ||
|
||
const Button = ({ className, variant, size, ...props }: ButtonProps) => { | ||
return <AriaButton {...props} /> | ||
} | ||
``` | ||
|
||
##### Bad: | ||
|
||
```tsx | ||
import { Button as _Button } from "@react-aria/button" | ||
|
||
const Button = ({ className, variant, size, ...props }: ButtonProps) => { | ||
return <_Button {...props} /> | ||
} | ||
``` | ||
|
||
## Styling | ||
|
||
### Using Data Attributes for Stateful Styles | ||
|
||
Components often support multiple UI states (e.g., pressed, hovered, selected, etc.). React Aria Components expose these states using data attributes, which you can target in CSS selectors. They function similarly to custom CSS pseudo-classes. | ||
|
||
In order to ensure high-quality interactions across browsers and devices, React Aria Components include states such as data-hovered and data-pressed. These are similar to CSS pseudo-classes such as :hover and :active, but they work consistently between mouse, touch, and keyboard modalities. You can read more about this in our blog post series and our Interactions overview. | ||
|
||
All states supported by each component are listed in the Styling section of their documentation. | ||
|
||
#### Example | ||
|
||
##### Good: | ||
|
||
```tsx | ||
className = "data-[hovered]:bg-red-600" | ||
``` | ||
|
||
##### Bad: | ||
|
||
```tsx | ||
className = "hover:bg-red-600" | ||
``` | ||
|
||
#### Reasoning for Using Data Attributes | ||
|
||
The decision to use data attributes over features such as render props was influenced by several factors: | ||
|
||
- Migration and Compatibility: The library is designed with the migration and compatibility of shadcn in mind. Using data attributes makes migration easier for users and is more understandable. | ||
- Reduced Complexity: The renderProps method would require a lot more cva styles for each component, adding unnecessary complexity. | ||
- Minimal Tailwind Configuration: Although React Aria provides a [Tailwind plugin](https://react-spectrum.adobe.com/react-aria/styling.html#plugin) that converts data-[selected]:bg-red-600 to selected:bg-red-600, I chose not to use this to keep styles easily copy-pasteable with minimal Tailwind configuration. | ||
- Debugging: Being able to see the data attribute and its selector in the rendered className helps with debugging. If I used render props, it would only show the computed className. | ||
|
||
### Supporting className renderProps functions | ||
|
||
To ensure all className props that support renderProps can be styled with either a string or a function, we can use the `composeRenderProps` helper. Use the following pattern: | ||
|
||
#### Example | ||
|
||
##### Good: | ||
|
||
```tsx | ||
const Popover = ({ className, offset = 4, ...props }: PopoverProps) => ( | ||
<AriaPopover | ||
offset={offset} | ||
className={composeRenderProps(className, (className) => | ||
cn("z-50 w-72", className) | ||
)} | ||
{...props} | ||
/> | ||
) | ||
``` | ||
|
||
##### Bad: | ||
|
||
```tsx | ||
const Popover = ({ className, offset = 4, ...props }: PopoverProps) => ( | ||
<AriaPopover | ||
offset={offset} | ||
className={(values) => cn("z-50 w-72", className)} | ||
{...props} | ||
/> | ||
) | ||
``` | ||
|
||
By using `typeof className === "function" ? className(values) : className`, you can handle both string and function types for the className prop, making the component more flexible and easier to use with renderProps. The only issue in this approach is that users using renderProps should be aware that as I use data attributes for styling, they will have to override these as well. | ||
|
||
### Organizing Data Attributes in the cn Function | ||
|
||
To maintain readability and organization in your components, ensure data attributes are clearly laid out in their own sections within the cn function, with appropriate comments. This helps in understanding the styling logic and makes the code more maintainable. | ||
|
||
#### Example | ||
|
||
##### Good: | ||
|
||
```tsx | ||
const Popover = ({ className, offset = 4, ...props }: PopoverProps) => ( | ||
<AriaPopover | ||
offset={offset} | ||
className={composeRenderProps(className, (className) => | ||
cn( | ||
"z-50 w-72 overflow-y-auto rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none", | ||
/* Entering */ | ||
"data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in-0", | ||
/* Exiting */ | ||
"data-[exiting]:fade-out-0 data-[exiting]:zoom-out-95", | ||
/* Placement */ | ||
"data-[placement=bottom]:slide-in-from-top-2 data-[placement=left]:slide-in-from-right-2 data-[placement=right]:slide-in-from-left-2 data-[placement=top]:slide-in-from-bottom-2", | ||
className | ||
) | ||
)} | ||
{...props} | ||
/> | ||
) | ||
``` | ||
|
||
##### Bad: | ||
|
||
```tsx | ||
const Popover = ({ className, offset = 4, ...props }: PopoverProps) => ( | ||
<AriaPopover | ||
offset={offset} | ||
className={composeRenderProps(className, (className) => | ||
cn( | ||
"z-50 w-72 overflow-y-auto rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[entering]:animate-in data-[exiting]:animate-out data-[entering]:fade-in-0 data-[exiting]:fade-out-0 data-[exiting]:zoom-out-95 data-[placement=bottom]:slide-in-from-top-2 data-[placement=left]:slide-in-from-right-2 data-[placement=right]:slide-in-from-left-2 data-[placement=top]:slide-in-from-bottom-2", | ||
className | ||
) | ||
)} | ||
{...props} | ||
/> | ||
) | ||
``` | ||
|
||
By organizing data attributes in their own sections with comments, the code becomes easier to read and maintain, and the purpose of each styling rule is more apparent. | ||
|
||
## Component Composition | ||
|
||
### Supporting Children as RenderProp Functions | ||
|
||
Where possible, ensure children can be renderProp functions as well, using the `composeRenderProps` helper. This allows greater flexibility and control over component rendering, enabling users to dynamically style or modify components based on their states. | ||
|
||
#### Example | ||
|
||
##### Good: | ||
|
||
```tsx | ||
const Checkbox = ({ className, children, ...props }: CheckboxProps) => ( | ||
<AriaCheckbox {...props}> | ||
{composeRenderProps(children, (children, renderProps) => ( | ||
<> | ||
<div> | ||
{renderProps.isIndeterminate ? ( | ||
<Minus /> | ||
) : renderProps.isSelected ? ( | ||
<Check /> | ||
) : null} | ||
</div> | ||
{children} | ||
</> | ||
))} | ||
</Checkbox> | ||
) | ||
``` | ||
|
||
##### Bad | ||
|
||
```tsx | ||
const Checkbox = ({ className, children, ...props }: CheckboxProps) => ( | ||
<AriaCheckbox {...props}> | ||
{(renderProps) => ( | ||
<> | ||
<div> | ||
{renderProps.isIndeterminate ? ( | ||
<Minus /> | ||
) : renderProps.isSelected ? ( | ||
<Check /> | ||
) : null} | ||
</div> | ||
{children} | ||
</> | ||
)} | ||
</Checkbox> | ||
) | ||
``` | ||
|
||
### Do Not Use forwardRef | ||
|
||
Forward ref is being deprecated, and in React 19 you can pass ref as a prop. Previously, all components were wrapped in forwardRef like shadcn, but with this upcoming change, forwardRef is no longer necessary. Going forward, you will be able to pass ref directly as a prop. Refer to the [React 19 blog post](https://react.dev/blog/2024/04/25/react-19#ref-as-a-prop) for more details. | ||
|
||
If you have an advances use-case for ref, then you can always add it since the code is in your codebase. | ||
|
||
#### Example | ||
|
||
##### Good: | ||
|
||
```tsx | ||
const Button = ({ className, ...props }) => ( | ||
<AriaButton className={className} {...props} /> | ||
) | ||
``` | ||
|
||
##### Bad: | ||
|
||
```tsx | ||
const Button = forwardRef(({ className, ...props }, ref) => ( | ||
<AriaButton ref={ref} className={className} {...props} /> | ||
)) | ||
``` | ||
|
||
By adopting these practices, JollyUI components will be more flexible, easier to maintain, and ready for future updates in React. | ||
|
||
### Handle All Exports at the End of the File | ||
|
||
To maintain a clear and organized structure, all export statements should be placed at the end of the file. This avoids inline exports and keeps the codebase consistent. | ||
|
||
#### Example | ||
|
||
##### Good: | ||
|
||
```tsx | ||
|
||
const Button = ({ className, ...props }: ButtonProps) => ( | ||
<AriaButton className={className} {...props} /> | ||
) | ||
|
||
// Export at the end | ||
export { Button } | ||
export type { ButtonProps } | ||
``` | ||
|
||
##### Bad: | ||
|
||
```tsx | ||
export const Button = ({ className, ...props }: ButtonProps) => ( | ||
<AriaButton className={className} {...props} /> | ||
) | ||
``` | ||
|
||
By placing all export statements at the end of the file, the code is easier to read and maintain, and it ensures a consistent style throughout the codebase. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.