Skip to content
Draft
314 changes: 162 additions & 152 deletions module/package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions module/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
},
"peerDependencies": {
"date-fns": "2.x",
"react": "18.x",
"react-dom": "18.x",
"react": "19.x",
"react-dom": "19.x",
"zod": "3.*"
},
"files": [
Expand Down Expand Up @@ -74,9 +74,9 @@
"@types/glob": "8.1.0",
"@types/jest": "29.5.3",
"@types/lodash": "4.14.195",
"@types/react": "18.3.1",
"@types/react": "^19.1.12",
"@types/react-datepicker": "4.11.2",
"@types/react-dom": "18.3.1",
"@types/react-dom": "^19.1.9",
"chokidar": "3.5.3",
"concurrently": "8.2.0",
"http-server": "14.1.1",
Expand All @@ -85,8 +85,8 @@
"jest-config": "29.6.1",
"jest-environment-jsdom": "29.6.1",
"jest-junit": "16.0.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"sass": "1.63.6",
"scss-concat": "0.3.9",
"semantic-release": "21.0.7",
Expand Down
18 changes: 6 additions & 12 deletions module/src/components/button/button.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import { Spinner } from '../spinner/spinner.component';

import './button.theme.css';

type ButtonHTMLProps = Omit<
React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>,
'ref'
>;
type ButtonHTMLProps = React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>;

export type ButtonDisplayStyle = 'primary' | 'secondary' | 'outline' | 'blank' | CustomString;
export type ButtonDisplayStatus = 'normal' | 'positive' | 'negative' | 'warning' | 'info' | CustomString;
Expand Down Expand Up @@ -41,26 +38,27 @@ export interface IButtonProps extends ButtonHTMLProps {
displayStatus?: ButtonDisplayStatus;

/** icon definition for left icon, optionally uses custom JSX */
leftOverlay?: JSX.Element;
leftOverlay?: React.ReactElement;

/** icon definition for right icon, optionally uses custom JSX */
rightOverlay?: JSX.Element;
rightOverlay?: React.ReactElement;
}

/** Renders an HTML button element with some useful additions */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need you to remove forward ref in favour of the new method https://react.dev/blog/2024/12/05/react-19#ref-as-a-prop

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here is the extract from the docs:

ref as a prop 
Starting in React 19, you can now access ref as a prop for function components:

function MyInput({placeholder, ref}) {
  return <input placeholder={placeholder} ref={ref} />
}

//...
<MyInput ref={ref} />
New function components will no longer need forwardRef, and we will be publishing a codemod to automatically update your components to use the new ref prop. In future versions we will deprecate and remove forwardRef.

Note
refs passed to classes are not passed as props since they reference the component instance.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the Button component to use React 19's new ref as prop pattern. Removed forwardRef and now ref is passed directly as a prop, as requested. All tests pass and the component builds successfully. Changes implemented in commit 19cf193.

export const Button = React.forwardRef<HTMLButtonElement, React.PropsWithChildren<IButtonProps>>((props, ref) => {
export const Button = (props: React.PropsWithChildren<IButtonProps>) => {
const {
className,
disabled,
displayStyle,
displaySize,
displayStatus,
pending,
pendingPosition,
pendingPosition = 'right',
disableOnPending,
leftOverlay,
rightOverlay,
children,
ref,
...nativeProps
} = props;

Expand Down Expand Up @@ -95,10 +93,6 @@ export const Button = React.forwardRef<HTMLButtonElement, React.PropsWithChildre
{pending && globals.buttonPendingPosition === 'right' ? spinner : wrappedRightIcon}
</button>
);
});

Button.defaultProps = {
pendingPosition: 'right',
};

Button.displayName = 'Button';
45 changes: 21 additions & 24 deletions module/src/components/characterLimit/characterLimit.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface ICharacterLimitProps<TBind extends NullOrUndefined<string>>
className?: string;

/** the icon to use for the validation errors */
validationErrorIcon?: JSX.Element;
validationErrorIcon?: React.ReactElement;

/** (Optional) Class name for the validation errors */
validationErrorsClassName?: string;
Expand All @@ -38,22 +38,20 @@ export interface ICharacterLimitProps<TBind extends NullOrUndefined<string>>
}

/** Render a character limit from a bound value, showing as an error if the user */
export const CharacterLimit = React.forwardRef<HTMLDivElement, ICharacterLimitProps<NullOrUndefined<string>>>(
(
{
bind,
limit,
shouldEnforce,
value,
className,
validationErrorIcon,
validationErrorsClassName,
validationErrorsTitle,
validationMode,
...nativeProps
},
ref
) => {
export const CharacterLimit = (props: React.PropsWithChildren<ICharacterLimitProps<NullOrUndefined<string>> & { ref?: React.Ref<HTMLDivElement> }>) => {
const {
bind,
limit,
shouldEnforce,
value,
className,
validationErrorIcon,
validationErrorsClassName,
validationErrorsTitle,
validationMode,
ref,
...nativeProps
} = props;
const globals = useArmstrongConfig({
validationErrorIcon,
validationMode,
Expand Down Expand Up @@ -84,12 +82,11 @@ export const CharacterLimit = React.forwardRef<HTMLDivElement, ICharacterLimitPr
)}
</div>
);
}
// type assertion to ensure generic works with RefForwarded component
// DO NOT CHANGE TYPE WITHOUT CHANGING THIS, FIND TYPE BY INSPECTING React.forwardRef
) as (<TBind extends NullOrUndefined<string>>(
props: ArmstrongFCProps<ICharacterLimitProps<TBind>, HTMLDivElement>
) => ArmstrongFCReturn) &
ArmstrongFCExtensions<ICharacterLimitProps<NullOrUndefined<string>>>;
};

// Type assertion for generic support - updated for React 19 ref as prop pattern
(CharacterLimit as any) = (CharacterLimit as (<TBind extends NullOrUndefined<string>>(
props: React.PropsWithChildren<ICharacterLimitProps<TBind> & { ref?: React.Ref<HTMLDivElement> }>
) => React.ReactElement) & ArmstrongFCExtensions<ICharacterLimitProps<NullOrUndefined<string>>>);

CharacterLimit.displayName = 'CharacterLimit';
73 changes: 36 additions & 37 deletions module/src/components/checkbox/checkbox.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ export interface ICheckboxProps<TData extends BindType>
/** (Optional) A TData value representing the initial checked state of the checkbox. This can be true, false, or 'indeterminate'. */
checked?: TData;

/** (Optional) A custom JSX.Element for the indeterminate state indicator. */
customIndeterminateIndicator?: JSX.Element;
/** (Optional) A custom React.ReactElement for the indeterminate state indicator. */
customIndeterminateIndicator?: React.ReactElement;

/** (Optional) A custom JSX.Element for the checked indicator. */
customIndicator?: JSX.Element;
/** (Optional) A custom React.ReactElement for the checked indicator. */
customIndicator?: React.ReactElement;

/** (Optional) A boolean flag to disable the checkbox input. */
disabled?: boolean;
Expand Down Expand Up @@ -68,34 +68,32 @@ export interface ICheckboxProps<TData extends BindType>
autoValidate?: boolean;
}

export const Checkbox = React.forwardRef<HTMLButtonElement, ICheckboxProps<BindType>>(
(
{
bind,
checked,
customIndicator,
className,
customIndeterminateIndicator,
disabled,
onCheckedChange,
label,
labelClassName,
labelId,
scrollValidationErrorsIntoView,
statusClassName,
testId,
validationErrorsClassName,
validationErrorMessages,
validationMode,
displaySize,
required,
requiredIndicator,
statusPosition,
autoValidate,
...nativeProps
},
ref
) => {
export const Checkbox = (props: React.PropsWithChildren<ICheckboxProps<BindType> & { ref?: React.Ref<HTMLButtonElement> }>) => {
const {
bind,
checked,
customIndicator,
className,
customIndeterminateIndicator,
disabled,
onCheckedChange,
label,
labelClassName,
labelId,
scrollValidationErrorsIntoView,
statusClassName,
testId,
validationErrorsClassName,
validationErrorMessages,
validationMode,
displaySize,
required,
requiredIndicator,
statusPosition,
autoValidate,
ref,
...nativeProps
} = props;
const reactId = React.useId();
const id = nativeProps.id ?? reactId;

Expand Down Expand Up @@ -189,10 +187,11 @@ export const Checkbox = React.forwardRef<HTMLButtonElement, ICheckboxProps<BindT
)}
</StatusWrapper>
);
}
) as (<TBind extends NullOrUndefined<boolean>>(
props: ArmstrongFCProps<ICheckboxProps<TBind>, HTMLInputElement>
) => ArmstrongFCReturn) &
ArmstrongFCExtensions<ICheckboxProps<NullOrUndefined<boolean>>>;
};

// Type assertion for generic support - updated for React 19 ref as prop pattern
(Checkbox as any) = (Checkbox as (<TBind extends NullOrUndefined<boolean>>(
props: React.PropsWithChildren<ICheckboxProps<TBind> & { ref?: React.Ref<HTMLButtonElement> }>
) => React.ReactElement) & ArmstrongFCExtensions<ICheckboxProps<NullOrUndefined<boolean>>>);

Checkbox.displayName = 'Checkbox';
Loading