Skip to content
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

feat: add polymorphic component support #21

Merged
merged 22 commits into from
Apr 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f4277c8
feat: add polymorphic types
PHILLIPS71 Apr 18, 2024
46e1039
feat(button): add polymorphic component support
PHILLIPS71 Apr 18, 2024
87d03ef
feat(alert): add polymorphic component support
PHILLIPS71 Apr 18, 2024
c6d6457
feat(link): add polymorphic component support
PHILLIPS71 Apr 18, 2024
39611c5
feat(alert): use Heading and Text base components
PHILLIPS71 Apr 20, 2024
43eb86a
feat(avatar): add polymorphic component support
PHILLIPS71 Apr 20, 2024
6abf846
feat(table): add polymorphic component support
PHILLIPS71 Apr 20, 2024
a5bd003
feat(typography): add polymorphic component support
PHILLIPS71 Apr 20, 2024
63ca4ed
feat(navigation): add polymorphic component support
PHILLIPS71 Apr 20, 2024
2f7a280
feat(switch): add polymorphic component support
PHILLIPS71 Apr 20, 2024
d1dcc22
feat(select): add polymorphic component support
PHILLIPS71 Apr 20, 2024
43cb22f
feat(progress): add polymorphic component support
PHILLIPS71 Apr 20, 2024
a4a8e1a
feat(menu): add polymorphic component support
PHILLIPS71 Apr 20, 2024
75046bb
feat(input): add polymorphic component support
PHILLIPS71 Apr 20, 2024
2e5167a
feat(form): add polymorphic component support
PHILLIPS71 Apr 20, 2024
ff7bc80
feat(divider): add polymorphic component support
PHILLIPS71 Apr 20, 2024
9a0c3ad
feat(dialog): add polymorphic component support
PHILLIPS71 Apr 20, 2024
9116ab5
feat(chip): add polymorphic component support
PHILLIPS71 Apr 20, 2024
b93eabc
feat(checkbox): add polymorphic component support
PHILLIPS71 Apr 20, 2024
1a0b31b
feat(card): add polymorphic component support
PHILLIPS71 Apr 20, 2024
9872df0
feat(breadcrumb): add polymorphic component support
PHILLIPS71 Apr 20, 2024
9f08647
fix(button): base button props missing
PHILLIPS71 Apr 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 53 additions & 17 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,61 @@
"env": {
"browser": false,
"es2021": true,
"node": true
"node": true,
},
"parser": "@typescript-eslint/parser",
"extends": ["airbnb", "airbnb-typescript", "airbnb/hooks", "prettier", "plugin:storybook/recommended"],
"parserOptions": {
"project": "tsconfig.json",
"ecmaFeatures": {
"jsx": true
"jsx": true,
},
"ecmaVersion": 12,
"sourceType": "module"
"sourceType": "module",
},
"settings": {
"react": {
"version": "detect"
}
"version": "detect",
},
},
"rules": {
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "default",
"format": ["camelCase", "PascalCase", "snake_case", "UPPER_CASE"],
},
{
"selector": "import",
"format": ["camelCase", "PascalCase"],
},
{
"selector": "variable",
"format": ["camelCase", "PascalCase", "snake_case", "UPPER_CASE"],
"leadingUnderscore": "allowSingleOrDouble",
"trailingUnderscore": "allowSingleOrDouble",
},
{
"selector": "function",
"format": ["camelCase", "PascalCase"],
},
{
"selector": "typeLike",
"format": ["PascalCase"],
},
{
"selector": "enumMember",
"format": ["UPPER_CASE"],
},
{
"selector": "property",
"format": null,
},
],
"no-console": "warn",
"no-param-reassign": ["error", { "props": true, "ignorePropertyModificationsFor": ["accu"] }],
"no-underscore-dangle": ["error", { "allow": ["__ELEMENT_TYPE__"] }],
"react/prop-types": "off",
"react/jsx-uses-react": "off",
"react/react-in-jsx-scope": "off",
Expand All @@ -35,9 +70,10 @@
"callbacksLast": true,
"shorthandFirst": true,
"noSortAlphabetically": false,
"reservedFirst": true
}
"reservedFirst": true,
},
],
"import/prefer-default-export": "off",
"import/extensions": "off",
"import/order": [
"error",
Expand All @@ -47,19 +83,19 @@
{
"pattern": "~/**",
"group": "external",
"position": "after"
}
"position": "after",
},
],
"newlines-between": "always",
"alphabetize": { "order": "asc", "caseInsensitive": true }
}
"alphabetize": { "order": "asc", "caseInsensitive": true },
},
],
"sort-imports": [
"error",
{
"ignoreDeclarationSort": true,
"ignoreMemberSort": false
}
"ignoreMemberSort": false,
},
],
"padding-line-between-statements": [
"warn",
Expand All @@ -68,8 +104,8 @@
{
"blankLine": "any",
"prev": ["const", "let", "var"],
"next": ["const", "let", "var"]
}
]
}
"next": ["const", "let", "var"],
},
],
},
}
60 changes: 34 additions & 26 deletions packages/react/src/components/alert/Alert.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { UseAlertProps } from '@/components/alert/use-alert.hook'
import type { Component } from '@/utilities/types'
import type * as Polymophic from '@/utilities/polymorphic'
import type { AlertVariantProps } from '@giantnodes/theme'

import React from 'react'

Expand All @@ -10,36 +10,44 @@ import AlertList from '@/components/alert/AlertList'
import AlertText from '@/components/alert/AlertText'
import { AlertContext, useAlert } from '@/components/alert/use-alert.hook'

export type AlertProps = Component<'div'> & UseAlertProps
const __ELEMENT_TYPE__ = 'div'

const Alert = React.forwardRef<HTMLDivElement, AlertProps>((props, ref) => {
const { as, children, className, color, ...rest } = props
type ComponentOwnProps = AlertVariantProps

const Component = as || 'div'
type ComponentProps<T extends React.ElementType> = Polymophic.ComponentPropsWithRef<T, ComponentOwnProps>

const context = useAlert({ color })
type ComponentType = <T extends React.ElementType = typeof __ELEMENT_TYPE__>(
props: ComponentProps<T>
) => React.ReactNode

const getProps = React.useCallback(
() => ({
ref,
className: context.slots.base({
class: className,
}),
...rest,
}),
[ref, context.slots, className, rest]
)

return (
<AlertContext.Provider value={context}>
<Component {...getProps()}>{children}</Component>
</AlertContext.Provider>
)
})
const Component: ComponentType = React.forwardRef(
<T extends React.ElementType = typeof __ELEMENT_TYPE__>(props: ComponentProps<T>, ref: Polymophic.Ref<T>) => {
const { as, children, className, color, ...rest } = props

Alert.displayName = 'Alert'
const Element = as ?? __ELEMENT_TYPE__

export default Object.assign(Alert, {
const context = useAlert({ color })

const component = React.useMemo<React.ComponentPropsWithoutRef<typeof __ELEMENT_TYPE__>>(
() => ({
className: context.slots.base({ className }),
...rest,
}),
[context.slots, className, rest]
)

return (
<AlertContext.Provider value={context}>
<Element {...component} ref={ref}>
{children}
</Element>
</AlertContext.Provider>
)
}
)

export type { ComponentOwnProps as AlertProps }
export default Object.assign(Component, {
Body: AlertBody,
Heading: AlertHeading,
Item: AlertItem,
Expand Down
51 changes: 31 additions & 20 deletions packages/react/src/components/alert/AlertBody.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,42 @@
import type { Component } from '@/utilities/types'
import type * as Polymophic from '@/utilities/polymorphic'

import React from 'react'

import { useAlertContext } from '@/components/alert/use-alert.hook'

export type AlertBodyProps = Component<'div'>
const __ELEMENT_TYPE__ = 'div'

const AlertBody = React.forwardRef<HTMLDivElement, AlertBodyProps>((props, ref) => {
const { as, children, className, ...rest } = props
const { slots } = useAlertContext()
type ComponentOwnProps = {}

const Component = as || 'div'
type ComponentProps<T extends React.ElementType> = Polymophic.ComponentPropsWithRef<T, ComponentOwnProps>

const getProps = React.useCallback(
() => ({
ref,
className: slots.body({
class: className,
}),
...rest,
}),
[ref, slots, className, rest]
)
type ComponentType = <T extends React.ElementType = typeof __ELEMENT_TYPE__>(
props: ComponentProps<T>
) => React.ReactNode

const Component: ComponentType = React.forwardRef(
<T extends React.ElementType = typeof __ELEMENT_TYPE__>(props: ComponentProps<T>, ref: Polymophic.Ref<T>) => {
const { as, children, className, ...rest } = props

return <Component {...getProps()}>{children}</Component>
})
const Element = as ?? __ELEMENT_TYPE__

AlertBody.displayName = 'Alert.Body'
const { slots } = useAlertContext()

export default AlertBody
const component = React.useMemo<React.ComponentPropsWithoutRef<typeof __ELEMENT_TYPE__>>(
() => ({
className: slots.body({ className }),
...rest,
}),
[className, rest, slots]
)

return (
<Element {...component} ref={ref}>
{children}
</Element>
)
}
)

export type { ComponentOwnProps as AlertBodyProps }
export default Component
54 changes: 34 additions & 20 deletions packages/react/src/components/alert/AlertHeading.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,45 @@
import type { Component } from '@/utilities/types'
import type * as Polymophic from '@/utilities/polymorphic'
import type { HeadingProps } from 'react-aria-components'

import React from 'react'
import { Heading } from 'react-aria-components'

import { useAlertContext } from '@/components/alert/use-alert.hook'

export type AlertHeadingProps = Component<'h3'>
const __ELEMENT_TYPE__ = 'h1'

const AlertHeading = React.forwardRef<HTMLHeadingElement, AlertHeadingProps>((props, ref) => {
const { as, children, className, ...rest } = props
const { slots } = useAlertContext()
type ComponentOwnProps = HeadingProps

const Component = as || 'h3'
type ComponentProps<T extends React.ElementType> = Polymophic.ComponentPropsWithRef<T, ComponentOwnProps>

const getProps = React.useCallback(
() => ({
ref,
className: slots.heading({
class: className,
}),
...rest,
}),
[ref, slots, className, rest]
)
type ComponentType = <T extends React.ElementType = typeof __ELEMENT_TYPE__>(
props: ComponentProps<T>
) => React.ReactNode

const Component: ComponentType = React.forwardRef(
<T extends React.ElementType = typeof __ELEMENT_TYPE__>(props: ComponentProps<T>, ref: Polymophic.Ref<T>) => {
const { as, children, className, level = 3, ...rest } = props

return <Component {...getProps()}>{children}</Component>
})
const Element = as ?? Heading

AlertHeading.displayName = 'Alert.Heading'
const { slots } = useAlertContext()

export default AlertHeading
const component = React.useMemo<React.ComponentPropsWithoutRef<typeof __ELEMENT_TYPE__>>(
() => ({
level,
className: slots.heading({ className }),
...rest,
}),
[className, level, rest, slots]
)

return (
<Element {...component} ref={ref}>
{children}
</Element>
)
}
)

export type { ComponentOwnProps as AlertHeadingProps }
export default Component
55 changes: 31 additions & 24 deletions packages/react/src/components/alert/AlertItem.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,42 @@
import type { Component } from '@/utilities/types'
import type * as Polymophic from '@/utilities/polymorphic'

import React from 'react'

import { useAlertContext } from '@/components/alert/use-alert.hook'

export type AlertItemProps = Component<'li'>
const __ELEMENT_TYPE__ = 'li'

const AlertItem = React.forwardRef<HTMLLIElement, AlertItemProps>((props, ref) => {
const { as, children, className, ...rest } = props
const { slots } = useAlertContext()
type ComponentOwnProps = {}

const Component = as || 'li'
type ComponentProps<T extends React.ElementType> = Polymophic.ComponentPropsWithRef<T, ComponentOwnProps>

const getProps = React.useCallback(
() => ({
ref,
className: slots.item({
class: className,
}),
...rest,
}),
[ref, slots, className, rest]
)
type ComponentType = <T extends React.ElementType = typeof __ELEMENT_TYPE__>(
props: ComponentProps<T>
) => React.ReactNode

const Component: ComponentType = React.forwardRef(
<T extends React.ElementType = typeof __ELEMENT_TYPE__>(props: ComponentProps<T>, ref: Polymophic.Ref<T>) => {
const { as, children, className, ...rest } = props

return (
<Component role="listitem" {...getProps()}>
{children}
</Component>
)
})
const Element = as ?? __ELEMENT_TYPE__

AlertItem.displayName = 'Alert.Item'
const { slots } = useAlertContext()

export default AlertItem
const component = React.useMemo<React.ComponentPropsWithoutRef<typeof __ELEMENT_TYPE__>>(
() => ({
className: slots.item({ className }),
...rest,
}),
[className, rest, slots]
)

return (
<Element {...component} ref={ref}>
{children}
</Element>
)
}
)

export type { ComponentOwnProps as AlertItemProps }
export default Component
Loading