Skip to content

Commit

Permalink
feat: add navbar component
Browse files Browse the repository at this point in the history
  • Loading branch information
Pagebakers committed Nov 15, 2023
1 parent ebba840 commit 8d74184
Show file tree
Hide file tree
Showing 20 changed files with 1,487 additions and 834 deletions.
7 changes: 7 additions & 0 deletions .changeset/dirty-eyes-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@saas-ui/theme': minor
'@saas-ui/core': minor
'@saas-ui/react': minor
---

Added new Navbar component 🥳
3 changes: 2 additions & 1 deletion packages/saas-ui-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@
"@chakra-ui/theme-tools": "^2.1.1",
"@chakra-ui/utils": "^2.0.15",
"@saas-ui/react-utils": "workspace:*",
"@saas-ui/theme": "workspace:*"
"@saas-ui/theme": "workspace:*",
"@react-aria/utils": "^3.22.0"
},
"peerDependencies": {
"@chakra-ui/react": ">=2.4.0",
Expand Down
24 changes: 19 additions & 5 deletions packages/saas-ui-core/src/app-shell/app-shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
useMultiStyleConfig,
omitThemingProps,
SystemStyleObject,
forwardRef,
} from '@chakra-ui/react'

import { cx } from '@chakra-ui/utils'
Expand Down Expand Up @@ -38,21 +39,29 @@ export interface AppShellProps
* The main content
*/
children: React.ReactNode
mainRef?: React.RefObject<HTMLDivElement>
}

/**
* The App Shell defines the main structure of your app.
*
* @see Docs https://saas-ui.dev/docs/components/layout/app-shell
*/
export const AppShell: React.FC<AppShellProps> = (props: AppShellProps) => {
export const AppShell = forwardRef<AppShellProps, 'div'>((props, ref) => {
const styles = useMultiStyleConfig('SuiAppShell', props) as Record<
string,
SystemStyleObject
>

const { navbar, sidebar, aside, footer, children, ...containerProps } =
omitThemingProps(props)
const {
navbar,
sidebar,
aside,
footer,
children,
mainRef,
...containerProps
} = omitThemingProps(props)

const containerStyles: SystemStyleObject = {
flexDirection: 'column',
Expand Down Expand Up @@ -86,14 +95,19 @@ export const AppShell: React.FC<AppShellProps> = (props: AppShellProps) => {
<AppShellProvider value={context}>
<StylesProvider value={styles}>
<Flex
ref={ref}
{...containerProps}
sx={containerStyles}
className={cx('sui-app-shell', props.className)}
>
{navbar}
<Flex sx={innerStyles} className="saas-app-shell__inner">
{sidebar}
<Flex sx={mainStyles} className="saas-app-shell__main">
<Flex
ref={mainRef}
sx={mainStyles}
className="saas-app-shell__main"
>
{children}
</Flex>
{aside}
Expand All @@ -103,6 +117,6 @@ export const AppShell: React.FC<AppShellProps> = (props: AppShellProps) => {
</StylesProvider>
</AppShellProvider>
)
}
})

AppShell.displayName = 'AppShell'
14 changes: 14 additions & 0 deletions packages/saas-ui-core/src/navbar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export type { NavbarProps } from './navbar'
export type { NavbarBrandProps } from './navbar-brand'
export type { NavbarContentProps } from './navbar-content'
export type { NavbarItemProps } from './navbar-item'

export { useNavbar } from './use-navbar'

export { NavbarProvider, useNavbarContext } from './navbar-context'

export { Navbar } from './navbar'
export { NavbarBrand } from './navbar-brand'
export { NavbarContent } from './navbar-content'
export { NavbarItem } from './navbar-item'
export { NavbarLink } from './navbar-link'
26 changes: 26 additions & 0 deletions packages/saas-ui-core/src/navbar/navbar-brand.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { chakra, forwardRef, HTMLChakraProps } from '@chakra-ui/react'
import { cx } from '@chakra-ui/utils'
import { useNavBarStyles } from './navbar-context'

export interface NavbarBrandProps extends HTMLChakraProps<'div'> {
children?: React.ReactNode | React.ReactNode[]
}

export const NavbarBrand = forwardRef<NavbarBrandProps, 'div'>((props, ref) => {
const { className, children, ...rest } = props

const styles = useNavBarStyles()

return (
<chakra.div
ref={ref}
__css={styles.brand}
className={cx('sui-navbar__brand')}
{...rest}
>
{children}
</chakra.div>
)
})

NavbarBrand.displayName = 'NavbarBrand'
46 changes: 46 additions & 0 deletions packages/saas-ui-core/src/navbar/navbar-content.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {
chakra,
forwardRef,
HTMLChakraProps,
SystemProps,
} from '@chakra-ui/react'
import { cx } from '@chakra-ui/utils'

import { useNavBarStyles } from './navbar-context'

export interface NavbarContentProps extends HTMLChakraProps<'ul'> {
/**
* Typically the `NavbarItem` component
*/
children?: React.ReactNode | React.ReactNode[]
/**
* Spacing between each navbar item
*/
spacing?: SystemProps['margin']
}

export const NavbarContent = forwardRef<NavbarContentProps, 'ul'>(
(props, ref) => {
const { className, children, spacing = 0, ...rest } = props

const styles = useNavBarStyles()

const contentStyles = {
...styles.content,
'& > *:not(style) ~ *:not(style)': { marginStart: spacing },
}

return (
<chakra.ul
ref={ref}
__css={contentStyles}
className={cx('sui-navbar__content', className)}
{...rest}
>
{children}
</chakra.ul>
)
}
)

NavbarContent.displayName = 'NavbarContent'
20 changes: 20 additions & 0 deletions packages/saas-ui-core/src/navbar/navbar-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createContext } from '@chakra-ui/react-context'

import { UseNavbarReturn } from './use-navbar'
import { SystemStyleObject } from '@chakra-ui/styled-system'

export const [NavbarProvider, useNavbarContext] =
createContext<UseNavbarReturn>({
name: 'NavbarContext',
strict: true,
errorMessage:
'useNavbarContext: `context` is undefined. Seems you forgot to wrap component within <Navbar />',
})

export const [NavBarStylesProvider, useNavBarStyles] = createContext<
Record<string, SystemStyleObject>
>({
name: `NavBarStylesContext`,
hookName: `useNavItemStyles`,
providerName: '<NavBar />',
})
33 changes: 33 additions & 0 deletions packages/saas-ui-core/src/navbar/navbar-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { chakra, forwardRef, HTMLChakraProps } from '@chakra-ui/react'
import { cx, dataAttr } from '@chakra-ui/utils'

import { useNavBarStyles } from './navbar-context'

export interface NavbarItemProps extends HTMLChakraProps<'li'> {
children?: React.ReactNode
/**
* Whether the item is active or not.
* @default false
*/
isActive?: boolean
}

export const NavbarItem = forwardRef<NavbarItemProps, 'li'>((props, ref) => {
const { className, children, isActive, ...rest } = props

const styles = useNavBarStyles()

return (
<chakra.li
ref={ref}
__css={styles.item}
className={cx('sui-navbar__item', className)}
data-active={dataAttr(isActive)}
{...rest}
>
{children}
</chakra.li>
)
})

NavbarItem.displayName = 'NavbarItem'
36 changes: 36 additions & 0 deletions packages/saas-ui-core/src/navbar/navbar-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { forwardRef, HTMLChakraProps } from '@chakra-ui/react'
import { cx, dataAttr } from '@chakra-ui/utils'

import { useNavBarStyles } from './navbar-context'
import { useLink } from '../provider'

export interface NavbarLinkProps extends HTMLChakraProps<'a'> {
children?: React.ReactNode
/**
* Whether the link is active or not.
* @default false
*/
isActive?: boolean
}

export const NavbarLink = forwardRef<NavbarLinkProps, 'li'>((props, ref) => {
const { className, children, isActive, ...rest } = props

const Link = useLink()

const styles = useNavBarStyles()

return (
<Link
ref={ref}
__css={styles.link}
data-active={dataAttr(isActive)}
className={cx('sui-navbar__link', className)}
{...rest}
>
{children}
</Link>
)
})

NavbarLink.displayName = 'NavbarLink'
Loading

0 comments on commit 8d74184

Please sign in to comment.