UNPKG

@pandacss/studio

Version:

The automated token documentation for Panda CSS

118 lines (94 loc) 4.11 kB
'use client' import { cx, css, sva } from '../css/index.mjs'; import { panda } from './factory.mjs'; import { getDisplayName } from './factory-helper.mjs'; import { createContext, useContext, createElement, forwardRef } from 'react' function createSafeContext(contextName) { const Context = createContext(undefined) const useStyleContext = (componentName, slot) => { const context = useContext(Context) if (context === undefined) { const componentInfo = componentName ? `Component "${componentName}"` : 'A component' const slotInfo = slot ? ` (slot: "${slot}")` : '' throw new Error( `${componentInfo}${slotInfo} cannot access ${contextName} because it's missing its Provider.` ) } return context } return [Context, useStyleContext] } export function createStyleContext(recipe) { const isConfigRecipe = '__recipe__' in recipe const recipeName = isConfigRecipe && recipe.__name__ ? recipe.__name__ : undefined const contextName = recipeName ? `createStyleContext("${recipeName}")` : 'createStyleContext' const [StyleContext, useStyleContext] = createSafeContext(contextName) const svaFn = isConfigRecipe ? recipe : sva(recipe.config) const getResolvedProps = (props, slotStyles) => { const { unstyled, ...restProps } = props if (unstyled) return restProps if (isConfigRecipe) { return { ...restProps, className: cx(slotStyles, restProps.className) } } return { ...slotStyles, ...restProps } } const withRootProvider = (Component, options) => { const WithRootProvider = (props) => { const [variantProps, otherProps] = svaFn.splitVariantProps(props) const slotStyles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps) slotStyles._classNameMap = svaFn.classNameMap const mergedProps = options?.defaultProps ? { ...options.defaultProps, ...otherProps } : otherProps return createElement(StyleContext.Provider, { value: slotStyles, children: createElement(Component, mergedProps) }) } const componentName = getDisplayName(Component) WithRootProvider.displayName = `withRootProvider(${componentName})` return WithRootProvider } const withProvider = (Component, slot, options) => { const StyledComponent = panda(Component, {}, options) const WithProvider = forwardRef((props, ref) => { const [variantProps, restProps] = svaFn.splitVariantProps(props) const slotStyles = isConfigRecipe ? svaFn(variantProps) : svaFn.raw(variantProps) slotStyles._classNameMap = svaFn.classNameMap const propsWithClass = { ...restProps, className: restProps.className ?? options?.defaultProps?.className } const resolvedProps = getResolvedProps(propsWithClass, slotStyles[slot]) return createElement(StyleContext.Provider, { value: slotStyles, children: createElement(StyledComponent, { ...resolvedProps, className: cx(resolvedProps.className, slotStyles._classNameMap[slot]), ref, }) }) }) const componentName = getDisplayName(Component) WithProvider.displayName = `withProvider(${componentName})` return WithProvider } const withContext = (Component, slot, options) => { const StyledComponent = panda(Component, {}, options) const componentName = getDisplayName(Component) const WithContext = forwardRef((props, ref) => { const slotStyles = useStyleContext(componentName, slot) const propsWithClass = { ...props, className: props.className ?? options?.defaultProps?.className } const resolvedProps = getResolvedProps(propsWithClass, slotStyles[slot]) return createElement(StyledComponent, { ...resolvedProps, className: cx(resolvedProps.className, slotStyles._classNameMap[slot]), ref, }) }) WithContext.displayName = `withContext(${componentName})` return WithContext } return { withRootProvider, withProvider, withContext, } }