diff --git a/packages/ui/src/components/Button/types.ts b/packages/ui/src/components/Button/types.ts index a469eab48f..8278cb932d 100644 --- a/packages/ui/src/components/Button/types.ts +++ b/packages/ui/src/components/Button/types.ts @@ -16,21 +16,15 @@ import type { ReactElement, ReactNode, CSSProperties } from 'react'; import type { ButtonProps as RAButtonProps } from 'react-aria-components'; -import type { Responsive, Surface } from '../../types'; +import type { LeafSurfaceProps, Responsive } from '../../types'; -/** - * Button's own properties (excluding inherited React Aria props) - * - * @public - */ -export type ButtonOwnProps = { +/** @public */ +export type ButtonOwnProps = LeafSurfaceProps & { size?: Responsive<'small' | 'medium' | 'large'>; variant?: Responsive<'primary' | 'secondary' | 'tertiary'>; iconStart?: ReactElement; iconEnd?: ReactElement; loading?: boolean; - /** Surface the button is placed on. Defaults to context surface if available */ - onSurface?: Responsive; children?: ReactNode; className?: string; style?: CSSProperties; diff --git a/packages/ui/src/hooks/useDefinition/defineComponent.ts b/packages/ui/src/hooks/useDefinition/defineComponent.ts index 2183638ee0..5e2a0139a7 100644 --- a/packages/ui/src/hooks/useDefinition/defineComponent.ts +++ b/packages/ui/src/hooks/useDefinition/defineComponent.ts @@ -14,13 +14,13 @@ * limitations under the License. */ -import type { ComponentConfig } from './types'; +import type { ComponentConfig, SurfacePropsConstraint } from './types'; export function defineComponent

>() { return < const S extends Record, const C extends ComponentConfig, >( - config: C, + config: C & SurfacePropsConstraint, ): C => config; } diff --git a/packages/ui/src/hooks/useDefinition/types.ts b/packages/ui/src/hooks/useDefinition/types.ts index 7318ef8fa2..3cef56148e 100644 --- a/packages/ui/src/hooks/useDefinition/types.ts +++ b/packages/ui/src/hooks/useDefinition/types.ts @@ -39,6 +39,25 @@ export interface ComponentConfig< surface?: 'container' | 'leaf'; } +/** + * Type constraint that validates surface props are present in the props type. + * - If surface is 'leaf', P must include 'onSurface' + * - If surface is 'container', P must include 'surface' + */ +export type SurfacePropsConstraint = Surface extends 'leaf' + ? 'onSurface' extends keyof P + ? {} + : { + __error: 'Leaf components must include onSurface in props type. Extend LeafProps.'; + } + : Surface extends 'container' + ? 'surface' extends keyof P + ? {} + : { + __error: 'Container components must include surface in props type. Extend ContainerProps.'; + } + : {}; + export interface UseDefinitionOptions> { utilityTarget?: keyof D['classNames'] | null; classNameTarget?: keyof D['classNames'] | null; diff --git a/packages/ui/src/types.ts b/packages/ui/src/types.ts index 3b7c359dc5..75a823d035 100644 --- a/packages/ui/src/types.ts +++ b/packages/ui/src/types.ts @@ -191,3 +191,13 @@ export type Surface = | 'warning' | 'success' | 'auto'; + +/** @public */ +export interface LeafSurfaceProps { + onSurface?: Responsive; +} + +/** @public */ +export interface ContainerSurfaceProps { + surface?: Responsive; +}