feat: ✨ setup PandaCSS, ArkUI, ParkUI Preset and Lucide-React
parent
12820974c5
commit
a69f2c6932
@ -0,0 +1,30 @@
|
|||||||
|
import { createPreset } from "@park-ui/panda-preset";
|
||||||
|
import { defineConfig } from "@pandacss/dev";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
// Whether to use css reset
|
||||||
|
preflight: true,
|
||||||
|
|
||||||
|
presets: [
|
||||||
|
"@pandacss/preset-base",
|
||||||
|
createPreset({
|
||||||
|
accentColor: "red",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
|
||||||
|
// Where to look for your css declarations
|
||||||
|
include: ["./src/**/*.{js,jsx,ts,tsx}", "./pages/**/*.{js,jsx,ts,tsx}"],
|
||||||
|
|
||||||
|
// Files to exclude
|
||||||
|
exclude: [],
|
||||||
|
|
||||||
|
// Useful for theme customization
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
|
||||||
|
// The output directory for your css system
|
||||||
|
outdir: "styled-system",
|
||||||
|
|
||||||
|
jsxFramework: "react",
|
||||||
|
});
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://park-ui.com/registry/latest/schema.json",
|
||||||
|
"jsFramework": "react",
|
||||||
|
"outputPath": "./src/components/ui"
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
'@pandacss/dev/postcss': {},
|
||||||
|
},
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
import { forwardRef } from 'react'
|
||||||
|
import { Center, styled } from 'styled-system/jsx'
|
||||||
|
import { Spinner } from './spinner'
|
||||||
|
import { Button as StyledButton, type ButtonProps as StyledButtonProps } from './styled/button'
|
||||||
|
|
||||||
|
interface ButtonLoadingProps {
|
||||||
|
loading?: boolean
|
||||||
|
loadingText?: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ButtonProps extends StyledButtonProps, ButtonLoadingProps {}
|
||||||
|
|
||||||
|
export const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
|
||||||
|
const { loading, disabled, loadingText, children, ...rest } = props
|
||||||
|
|
||||||
|
const trulyDisabled = loading || disabled
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledButton disabled={trulyDisabled} ref={ref} {...rest}>
|
||||||
|
{loading && !loadingText ? (
|
||||||
|
<>
|
||||||
|
<ButtonSpinner />
|
||||||
|
<styled.span opacity={0}>{children}</styled.span>
|
||||||
|
</>
|
||||||
|
) : loadingText ? (
|
||||||
|
loadingText
|
||||||
|
) : (
|
||||||
|
children
|
||||||
|
)}
|
||||||
|
</StyledButton>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
Button.displayName = 'Button'
|
||||||
|
|
||||||
|
const ButtonSpinner = () => (
|
||||||
|
<Center inline position="absolute" transform="translate(-50%, -50%)" top="50%" insetStart="50%">
|
||||||
|
<Spinner colorPalette="gray" />
|
||||||
|
</Center>
|
||||||
|
)
|
@ -0,0 +1,7 @@
|
|||||||
|
import { ark } from '@ark-ui/react/factory'
|
||||||
|
import { styled } from 'styled-system/jsx'
|
||||||
|
import { button } from 'styled-system/recipes'
|
||||||
|
import type { ComponentProps } from 'styled-system/types'
|
||||||
|
|
||||||
|
export type ButtonProps = ComponentProps<typeof Button>
|
||||||
|
export const Button = styled(ark.button, button)
|
@ -0,0 +1,95 @@
|
|||||||
|
import {
|
||||||
|
type ElementType,
|
||||||
|
type ForwardRefExoticComponent,
|
||||||
|
type PropsWithoutRef,
|
||||||
|
type RefAttributes,
|
||||||
|
createContext,
|
||||||
|
forwardRef,
|
||||||
|
useContext,
|
||||||
|
} from 'react'
|
||||||
|
import { cx } from 'styled-system/css'
|
||||||
|
import { type StyledComponent, isCssProperty, styled } from 'styled-system/jsx'
|
||||||
|
|
||||||
|
type Props = Record<string, unknown>
|
||||||
|
type Recipe = {
|
||||||
|
(props?: Props): Props
|
||||||
|
splitVariantProps: (props: Props) => [Props, Props]
|
||||||
|
}
|
||||||
|
type Slot<R extends Recipe> = keyof ReturnType<R>
|
||||||
|
type Options = { forwardProps?: string[] }
|
||||||
|
|
||||||
|
const shouldForwardProp = (prop: string, variantKeys: string[], options: Options = {}) =>
|
||||||
|
options.forwardProps?.includes(prop) || (!variantKeys.includes(prop) && !isCssProperty(prop))
|
||||||
|
|
||||||
|
export const createStyleContext = <R extends Recipe>(recipe: R) => {
|
||||||
|
const StyleContext = createContext<Record<Slot<R>, string> | null>(null)
|
||||||
|
|
||||||
|
const withRootProvider = <P extends {}>(Component: ElementType) => {
|
||||||
|
const StyledComponent = (props: P) => {
|
||||||
|
const [variantProps, otherProps] = recipe.splitVariantProps(props)
|
||||||
|
const slotStyles = recipe(variantProps) as Record<Slot<R>, string>
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyleContext.Provider value={slotStyles}>
|
||||||
|
<Component {...otherProps} />
|
||||||
|
</StyleContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return StyledComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
const withProvider = <T, P extends { className?: string | undefined }>(
|
||||||
|
Component: ElementType,
|
||||||
|
slot: Slot<R>,
|
||||||
|
options?: Options,
|
||||||
|
): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>> => {
|
||||||
|
const StyledComponent = styled(
|
||||||
|
Component,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
shouldForwardProp: (prop, variantKeys) => shouldForwardProp(prop, variantKeys, options),
|
||||||
|
},
|
||||||
|
) as StyledComponent<ElementType>
|
||||||
|
const StyledSlotProvider = forwardRef<T, P>((props, ref) => {
|
||||||
|
const [variantProps, otherProps] = recipe.splitVariantProps(props)
|
||||||
|
const slotStyles = recipe(variantProps) as Record<Slot<R>, string>
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyleContext.Provider value={slotStyles}>
|
||||||
|
<StyledComponent
|
||||||
|
{...otherProps}
|
||||||
|
ref={ref}
|
||||||
|
className={cx(slotStyles?.[slot], props.className)}
|
||||||
|
/>
|
||||||
|
</StyleContext.Provider>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
// @ts-expect-error
|
||||||
|
StyledSlotProvider.displayName = Component.displayName || Component.name
|
||||||
|
|
||||||
|
return StyledSlotProvider
|
||||||
|
}
|
||||||
|
|
||||||
|
const withContext = <T, P extends { className?: string | undefined }>(
|
||||||
|
Component: ElementType,
|
||||||
|
slot: Slot<R>,
|
||||||
|
): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>> => {
|
||||||
|
const StyledComponent = styled(Component)
|
||||||
|
const StyledSlotComponent = forwardRef<T, P>((props, ref) => {
|
||||||
|
const slotStyles = useContext(StyleContext)
|
||||||
|
return (
|
||||||
|
<StyledComponent {...props} ref={ref} className={cx(slotStyles?.[slot], props.className)} />
|
||||||
|
)
|
||||||
|
})
|
||||||
|
// @ts-expect-error
|
||||||
|
StyledSlotComponent.displayName = Component.displayName || Component.name
|
||||||
|
|
||||||
|
return StyledSlotComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
withRootProvider,
|
||||||
|
withProvider,
|
||||||
|
withContext,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue