Skip to content

Commit 886e521

Browse files
authored
fix(Field): show warning in case of properties misuse (#407)
1 parent 52ba1ee commit 886e521

File tree

6 files changed

+66
-5
lines changed

6 files changed

+66
-5
lines changed

.changeset/cuddly-actors-boil.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@cube-dev/ui-kit': patch
3+
---
4+
5+
Fix "for" attribute in field labels.

.changeset/spicy-apricots-doubt.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@cube-dev/ui-kit': patch
3+
---
4+
5+
Show warning if a field is linked to a form but default value is provided. And in case when a field is unlinked but validation rules are provided.'

.size-limit.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ module.exports = [
1919
}),
2020
);
2121
},
22-
limit: '214kB',
22+
limit: '215kB',
2323
},
2424
{
2525
name: 'Tree shaking (just a Button)',
2626
path: './dist/es/index.js',
2727
webpack: true,
2828
import: '{ Button }',
29-
limit: '28 kB',
29+
limit: '29 kB',
3030
},
3131
];

src/components/forms/Form/use-field/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ValidationState,
88
} from '../../../../shared';
99
import { CubeFormInstance } from '../use-form';
10+
import { Props } from '../../../../tasty';
1011

1112
export interface CubeFieldProps<T extends FieldTypes> {
1213
/** The initial value of the input. */
@@ -33,6 +34,7 @@ export interface CubeFieldProps<T extends FieldTypes> {
3334
validateTrigger?: ValidateTrigger;
3435
/** Message for the field. Some additional information or error notice */
3536
message?: ReactNode;
37+
labelProps?: Props;
3638
}
3739

3840
export type FieldReturnValue<T extends FieldTypes> = {

src/components/forms/Form/use-field/use-field-props.tsx

+42-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import { useDebugValue } from 'react';
44
import { useChainedCallback, useEvent } from '../../../../_internal';
55
import { useInsideLegacyField } from '../Field';
66
import { mergeProps } from '../../../../utils/react';
7+
import { warn } from '../../../../utils/warnings';
78

89
import { useField } from './use-field';
910

10-
import type { ValidateTrigger } from '../../../../shared';
1111
import type { CubeFieldProps } from './types';
1212
import type { FieldTypes } from '../types';
13+
import type { ValidateTrigger } from '../../../../shared';
1314

1415
export type UseFieldPropsParams = {
1516
valuePropsMapper?: ({ value, onChange }) => any;
@@ -24,6 +25,19 @@ export type UseFieldPropsParams = {
2425
unsafe__isDisabled?: boolean;
2526
};
2627

28+
const VALUE_PROPERTIES = [
29+
'value',
30+
'defaultValue',
31+
'isSelected',
32+
'defaultSelected',
33+
'isIndeterminate',
34+
'defaultIndeterminate',
35+
'selectedKey',
36+
'defaultSelectedKey',
37+
'selectedKeys',
38+
'defaultSelectedKeys',
39+
];
40+
2741
export function useFieldProps<
2842
T extends FieldTypes,
2943
Props extends CubeFieldProps<T>,
@@ -77,7 +91,23 @@ export function useFieldProps<
7791
),
7892
);
7993

80-
const result = isOutsideOfForm
94+
if (props.rules && !props.name) {
95+
warn(
96+
`The "rules" prop is not suitable for fields that are not part of a form. Use "name" prop to link the field to a form.`,
97+
);
98+
}
99+
100+
if (isOutsideOfForm) {
101+
for (const valuePropName of VALUE_PROPERTIES) {
102+
if (valuePropName in props) {
103+
warn(
104+
`The "${valuePropName}" property is not suitable for fields that are part of a form. To set default values, please use the "defaultValues" property of the form component instead. To unlink the field from the form, remove the "name" property from the field.`,
105+
);
106+
}
107+
}
108+
}
109+
110+
const result: Props = isOutsideOfForm
81111
? props
82112
: mergeProps(
83113
props,
@@ -89,6 +119,16 @@ export function useFieldProps<
89119
},
90120
);
91121

122+
if (result.id) {
123+
if (!result.labelProps) {
124+
result.labelProps = {};
125+
}
126+
127+
if (result.labelProps) {
128+
result.labelProps.for = result.id;
129+
}
130+
}
131+
92132
if (process.env.NODE_ENV === 'development') {
93133
// eslint-disable-next-line react-hooks/rules-of-hooks
94134
useDebugValue(result);

src/components/forms/Switch/Switch.tsx

+10-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,16 @@ function Switch(props: WithNullableSelected<CubeSwitchProps>, ref) {
190190
let domRef = useFocusableRef(ref, inputRef);
191191

192192
// eslint-disable-next-line react-hooks/rules-of-hooks
193-
let { inputProps } = useSwitch(props, useToggleState(props), inputRef);
193+
let { inputProps } = useSwitch(
194+
{
195+
...props,
196+
...(typeof label === 'string' && label.trim()
197+
? { 'aria-label': label }
198+
: {}),
199+
},
200+
useToggleState(props),
201+
inputRef,
202+
);
194203

195204
const mods = {
196205
'inside-form': insideForm,

0 commit comments

Comments
 (0)