Skip to content

Commit d12a3be

Browse files
committed
feat: add support for React 19 + Semantic-ui-react v3-beta
1 parent e69bee5 commit d12a3be

16 files changed

Lines changed: 1879 additions & 1472 deletions

‎.github/workflows/main.yml‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ jobs:
2424
env:
2525
CI: true
2626

27-
- name: Test
28-
run: yarn test --ci --coverage --maxWorkers=2
27+
# Build first: the Types spec type-checks the emitted dist/*.d.ts files.
28+
- name: Build
29+
run: yarn build
2930
env:
3031
CI: true
3132

32-
- name: Build
33-
run: yarn build
33+
- name: Test
34+
run: yarn test --ci --coverage --maxWorkers=2
3435
env:
3536
CI: true

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ node_modules
55
dist
66
.idea
77
.parcel-cache
8+
coverage

‎example/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@
1818
},
1919
"devDependencies": {
2020
"parcel": "^2.13.3",
21-
"typescript": "^5.7.3"
21+
"typescript": "^6.0.3"
2222
}
2323
}

‎example/yarn.lock‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,10 +1549,10 @@ type-fest@^0.20.2:
15491549
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
15501550
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
15511551

1552-
typescript@^5.7.3:
1553-
version "5.7.3"
1554-
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.3.tgz#919b44a7dbb8583a9b856d162be24a54bf80073e"
1555-
integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==
1552+
typescript@^6.0.3:
1553+
version "6.0.3"
1554+
resolved "https://registry.yarnpkg.com/typescript/-/typescript-6.0.3.tgz#90251dc007916e972786cb94d74d15b185577d21"
1555+
integrity sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==
15561556

15571557
update-browserslist-db@^1.1.1:
15581558
version "1.1.2"

‎package.json‎

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,38 +42,39 @@
4242
"version": "auto-changelog -p && git add CHANGELOG.md"
4343
},
4444
"dependencies": {
45-
"formsy-react": "^2.3.2",
46-
"hoist-non-react-statics": "^3.3.2",
47-
"semantic-ui-react": "^2.1.5"
45+
"formsy-react": "^2.4.6",
46+
"hoist-non-react-statics": "^3.3.2"
4847
},
4948
"devDependencies": {
50-
"@rsbuild/plugin-react": "^2.0.0",
51-
"@rsbuild/plugin-type-check": "^1.3.4",
52-
"@rslib/core": "^0.20.3",
53-
"@swc/core": "^1.15.32",
49+
"@rsbuild/plugin-react": "^2.1.1",
50+
"@rsbuild/plugin-type-check": "^1.6.1",
51+
"@rslib/core": "^1.0.3",
52+
"@types/node":"24.19.2",
53+
"@swc/core": "^1.16.18",
5454
"@swc/jest": "^0.2.39",
5555
"@testing-library/dom": "^10.4.1",
5656
"@testing-library/jest-dom": "^6.9.1",
5757
"@testing-library/react": "16.3.2",
5858
"@testing-library/user-event": "^14.6.1",
5959
"@types/hoist-non-react-statics": "^3.3.1",
6060
"@types/jest": "^30.0.0",
61-
"@types/react": "^18.3.28",
62-
"@types/react-dom": "^18.3.7",
63-
"auto-changelog": "^2.4.0",
64-
"bumpp": "^11.1.0",
61+
"@types/react": "^19.3.0",
62+
"@types/react-dom": "^19.3.0",
63+
"auto-changelog": "^2.7.0",
64+
"bumpp": "^12.3.0",
6565
"husky": "^4.2.5",
66-
"jest": "^30.3.0",
67-
"jest-environment-jsdom": "^30.3.0",
68-
"oxfmt": "^0.47.0",
69-
"oxlint": "^1.62.0",
70-
"react": "^18.3.1",
71-
"react-dom": "^18.3.1",
72-
"tslib": "^2.8.1",
73-
"typescript": "^5.7.3"
66+
"jest": "^30.5.2",
67+
"jest-environment-jsdom": "^30.5.2",
68+
"oxfmt": "^0.72.0",
69+
"oxlint": "^1.87.0",
70+
"react": "^19.3.0",
71+
"react-dom": "^19.3.0",
72+
"semantic-ui-react": "^3.0.0-beta.2",
73+
"typescript": "^6.0.3"
7474
},
7575
"peerDependencies": {
76-
"react": ">=16 || >=17 || >=18 || >=19"
76+
"react": ">=16 || >=17 || >=18 || >=19",
77+
"semantic-ui-react": "^2.1.5 || ^3.0.0-beta.2"
7778
},
7879
"husky": {
7980
"hooks": {

‎src/Form.tsx‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import type { InjectedProps } from 'formsy-react';
22
import Formsy from 'formsy-react';
3+
import type { FormsyComponent } from './types';
34
import hoistNonReactStatics from 'hoist-non-react-statics';
45
import React, { Component, ComponentProps } from 'react';
56
import { Form as SemanticUIForm, StrictFormProps } from 'semantic-ui-react';
6-
import FormsyCheckbox from './FormsyCheckbox';
7+
import FormsyCheckbox, { type CheckboxRadioValueType, type IFormsyCheckboxProps } from './FormsyCheckbox';
78
import FormsyDropdown, { IFormsyDropdownProps } from './FormsyDropdown';
89
import FormsyInput, { IFormsyInputProps } from './FormsyInput';
910
import FormsyRadioGroup, { IFormsyRadioGroupProps } from './FormsyRadioGroup';
@@ -17,7 +18,7 @@ class Form extends Component<IFormProps & { forwardedRef: any }> {
1718
static Radio = SemanticUIForm.Radio;
1819
static Field = SemanticUIForm.Field;
1920
static Group = SemanticUIForm.Group;
20-
static Checkbox = FormsyCheckbox;
21+
static Checkbox: FormsyComponent<IFormsyCheckboxProps, CheckboxRadioValueType> = FormsyCheckbox;
2122

2223
static Input = (props: Omit<IFormsyInputProps, keyof InjectedProps<any>>) => (
2324
<FormsyInput inputAs={SemanticUIForm.Input} {...props} />
@@ -82,7 +83,20 @@ class Form extends Component<IFormProps & { forwardedRef: any }> {
8283
}
8384
}
8485

85-
export default hoistNonReactStatics(
86+
const FormComponent = hoistNonReactStatics(
8687
React.forwardRef<Formsy, IFormProps>((props: IFormProps, ref) => <Form {...props} forwardedRef={ref} />),
8788
Form
8889
);
90+
91+
/**
92+
* Only the static sub-components are re-exported. Intersecting with `typeof Form` instead
93+
* would preserve the class's *construct* signature, which makes JSX treat `Form` as a class
94+
* component whose props include the internal `forwardedRef` prop — surfacing as a required
95+
* prop for every consumer.
96+
*/
97+
type FormStatics = Pick<
98+
typeof Form,
99+
'Button' | 'Radio' | 'Field' | 'Group' | 'Checkbox' | 'Input' | 'TextArea' | 'Select' | 'RadioGroup' | 'Dropdown'
100+
>;
101+
102+
export default FormComponent as React.ForwardRefExoticComponent<IFormProps & React.RefAttributes<Formsy>> & FormStatics;

‎src/FormsyCheckbox.tsx‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { FormsyInjectedProps, withFormsy } from 'formsy-react';
22
import React, { cloneElement, Component, createElement } from 'react';
33
import { Checkbox, Form, Radio, StrictFormFieldProps, StrictRadioProps } from 'semantic-ui-react';
4+
import type { FormsyComponent } from './types';
45
import { filterSuirElementProps } from './utils';
56

6-
type CheckboxRadioValueType = boolean | number | string;
7+
export type CheckboxRadioValueType = boolean | number | string;
78

89
export interface IFormsyCheckboxProps
910
extends
@@ -91,4 +92,4 @@ class FormsyCheckbox extends Component<IFormsyCheckboxProps> {
9192
}
9293
}
9394

94-
export default withFormsy(FormsyCheckbox);
95+
export default withFormsy(FormsyCheckbox) as FormsyComponent<IFormsyCheckboxProps, CheckboxRadioValueType>;

‎src/FormsyDropdown.tsx‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { FormsyInjectedProps, withFormsy } from 'formsy-react';
22
import React, { cloneElement, Component, createElement } from 'react';
33
import { Dropdown, Form, Select, StrictDropdownProps, StrictFormFieldProps } from 'semantic-ui-react';
4-
import { filterSuirElementProps } from './utils';
4+
import type { FormsyComponent } from './types';
5+
import { filterSuirElementProps, resolveControlComponent } from './utils';
56

67
type FormsyDropdownValue = StrictDropdownProps['value'];
78

@@ -93,7 +94,7 @@ class FormsyDropdown extends Component<IFormsyDropdownProps> {
9394
name: undefined,
9495
};
9596

96-
const dropdownNode = shortHandMode ? (createElement(inputAs as any, dropdownProps).props as any).control : inputAs;
97+
const dropdownNode = shortHandMode ? resolveControlComponent(inputAs) : inputAs;
9798

9899
return (
99100
<Form.Field
@@ -113,4 +114,4 @@ class FormsyDropdown extends Component<IFormsyDropdownProps> {
113114
}
114115
}
115116

116-
export default withFormsy(FormsyDropdown);
117+
export default withFormsy(FormsyDropdown) as FormsyComponent<IFormsyDropdownProps, FormsyDropdownValue>;

‎src/FormsyInput.tsx‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { FormsyInjectedProps, withFormsy } from 'formsy-react';
22
import React, { cloneElement, Component, createElement, InputHTMLAttributes, isValidElement } from 'react';
33
import { Form, Input, InputOnChangeData, StrictFormFieldProps, StrictInputProps } from 'semantic-ui-react';
4-
import { filterSuirElementProps } from './utils';
4+
import type { FormsyComponent } from './types';
5+
import { filterSuirElementProps, resolveControlComponent } from './utils';
56

67
type SemanticFormField = Pick<StrictFormFieldProps, 'as' | 'className' | 'error' | 'width' | 'inline' | 'disabled'>;
78
type SemanticInputProps = Omit<StrictInputProps, 'error'>;
@@ -96,7 +97,7 @@ class FormsyInput extends Component<IFormsyInputProps> {
9697
};
9798

9899
const isFormField = inputAs === Form.Input || inputAs === Form.TextArea;
99-
const inputNode = isFormField ? (createElement(inputAs as any).props as any).control : inputAs;
100+
const inputNode = isFormField ? resolveControlComponent(inputAs) : inputAs;
100101

101102
if (isFormField) {
102103
inputProps.label = undefined;
@@ -130,4 +131,4 @@ class FormsyInput extends Component<IFormsyInputProps> {
130131
}
131132
}
132133

133-
export default withFormsy(FormsyInput);
134+
export default withFormsy(FormsyInput) as FormsyComponent<IFormsyInputProps, any>;

‎src/FormsyRadioGroup.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { FormsyInjectedProps, withFormsy } from 'formsy-react';
22
import React, { Children, cloneElement, Component } from 'react';
33
import { Form, RadioProps, StrictFormFieldProps, StrictRadioProps } from 'semantic-ui-react';
4+
import type { FormsyComponent } from './types';
45
import { StrictFormGroupProps } from 'semantic-ui-react/dist/commonjs/collections/Form/FormGroup';
56
import { CheckboxProps } from 'semantic-ui-react/dist/commonjs/modules/Checkbox/Checkbox';
67

@@ -99,4 +100,4 @@ class FormsyRadioGroup extends Component<IFormsyRadioGroupProps> {
99100
}
100101
}
101102

102-
export default withFormsy(FormsyRadioGroup);
103+
export default withFormsy(FormsyRadioGroup) as FormsyComponent<IFormsyRadioGroupProps, RadioGroupValueType>;

0 commit comments

Comments
 (0)