Skip to content

Migrates Converged component to use simplified prop merging #18844

@bsunderhus

Description

@bsunderhus

Converged components should follow RFC #18642

Required actions to migrate a component

Checklist

  • Remove defaultProps in useCOMPONENT
  • Remove mergeProps
  • Define type for slots
  • (optionally) Define COMPONENTCommons type
  • Update types for a component
  • Update getSlots()
  • Update useCOMPONENTStyles()

Remove defaultProps in useCOMPONENT

-export const useCOMPONENT = (props: COMPONENTProps, ref: React.Ref<HTMLElement>, defaultProps?: COMPONENTProps): COMPONENTState => {
+export const useCOMPONENT = (props: COMPONENTProps, ref: React.Ref<HTMLElement>): COMPONENTState => {

📝Check also JSDoc comments for the function and remove defaultProps from there

Remove mergeProps

Before

const state = mergeProps(
  { ref },
  props,
  resolveShorthandProps(props, COMPONENTShorthandProps)
);

After

const state: COMPONENTState = {
  // Props passed at the top-level
  disabled,
  inline,
  // Slots definition
  components: { root: "div", icon: "span" },

  // Slots
  root: getNativeElementProps(props.as, { ref, ...props }),
  icon: resolveShorthand(props.icon)
};
  • props that are affecting component's state or styling should go directly to state object, they should not go to state.root
  • event handlers (onClick, onKeyDown) should go to a matching slot (root, icon)
  • state.components should have hardcoded values with matching element
  • state.root should use getNativeElementProps(), ref goes there
  • state.icon & other slots should use resolveShorthand()
  • props should not be spreaded to state

Define type for slots

Please define a new type for slots in COMPONENT.types.ts

export type COMPONENTSlots = {
  root: ObjectShorthandProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;
  icon: ObjectShorthandProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;
};

(optionally) Define COMPONENTCommons type

If you props that are used in state & props please define a separate interface for them:

export type COMPONENTCommons = {
  disabled: boolean;
  inline: boolean;
}

📝 All properties are required

Update types for a component

Props

-export interface COMPONENTProps extends ComponentProps<COMPONENTSlots>, React.HTMLAttributes<HTMLElement> {}
+export interface COMPONENTProps extends ComponentProps<COMPONENTSlots>, Partial<COMPONENTCommons> {}

📝 React.HTMLAttributes are not in props anymore

State

-export interface COMPONENTState extends COMPONENTProps {
-  ref: React.Ref<HTMLElement>;
-}
+export interface COMPONENTState extends ComponentState<COMPONENTSlots>, COMPONENTCommons {

📝 ref is not a root property of state

Update getSlots()

In renderCOMPONENT():

-const { slots, slotProps } = getSlotsCompat(state, linkShorthandProps);
+const { slots, slotProps } = getSlots<LinkSlots>(state, linkShorthandProps);

Update useCOMPONENTStyles()

const styles = useStyles();
-  state.className = mergeClasses(
+ state.root.className = mergeClasses( 
   styles.root, 
-  state.className,
+  state.root.className, 
  );

Utilities

Components

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions