@centreon/ui 24.4.30 → 24.4.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/InputField/Number/Number.cypress.spec.tsx +85 -0
- package/src/InputField/Number/Number.stories.tsx +66 -0
- package/src/InputField/Number/Number.tsx +74 -0
- package/src/InputField/Search/index.tsx +2 -2
- package/src/InputField/Text/index.tsx +38 -38
- package/src/index.ts +1 -0
package/package.json
CHANGED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import NumberField, { NumberProps } from './Number';
|
|
2
|
+
|
|
3
|
+
const initialize = (props: NumberProps): void => {
|
|
4
|
+
cy.mount({
|
|
5
|
+
Component: <NumberField {...props} />
|
|
6
|
+
});
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
describe('Number field', () => {
|
|
10
|
+
it('displays the placeholder when the field has no default or fallback values', () => {
|
|
11
|
+
initialize({ dataTestId: 'test', onChange: cy.stub() });
|
|
12
|
+
|
|
13
|
+
cy.get('input').should('have.value', '');
|
|
14
|
+
cy.get('input').should('have.attr', 'placeholder', '0');
|
|
15
|
+
|
|
16
|
+
cy.makeSnapshot();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('displays the fallback value as placeholder when the field as no default value', () => {
|
|
20
|
+
initialize({ dataTestId: 'test', fallbackValue: 25, onChange: cy.stub() });
|
|
21
|
+
|
|
22
|
+
cy.get('input').should('have.value', '');
|
|
23
|
+
cy.get('input').should('have.attr', 'placeholder', '25');
|
|
24
|
+
|
|
25
|
+
cy.makeSnapshot();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('displays the default value as placeholder when the field as default value', () => {
|
|
29
|
+
initialize({ dataTestId: 'test', defaultValue: 25, onChange: cy.stub() });
|
|
30
|
+
|
|
31
|
+
cy.get('input').should('have.value', '25');
|
|
32
|
+
|
|
33
|
+
cy.makeSnapshot();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('displays the fallback value when the field is cleared out', () => {
|
|
37
|
+
initialize({
|
|
38
|
+
dataTestId: 'test',
|
|
39
|
+
defaultValue: 25,
|
|
40
|
+
fallbackValue: 10,
|
|
41
|
+
onChange: cy.stub()
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
cy.get('input').should('have.value', '25');
|
|
45
|
+
cy.get('input').clear();
|
|
46
|
+
cy.get('input').should('have.value', '');
|
|
47
|
+
cy.get('input').should('have.attr', 'placeholder', '10');
|
|
48
|
+
|
|
49
|
+
cy.makeSnapshot();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('displays the field using auto size', () => {
|
|
53
|
+
initialize({
|
|
54
|
+
autoSize: true,
|
|
55
|
+
dataTestId: 'test',
|
|
56
|
+
defaultValue: 25,
|
|
57
|
+
onChange: cy.stub()
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
cy.get('input').should('have.value', '25');
|
|
61
|
+
|
|
62
|
+
cy.get('input').type('0');
|
|
63
|
+
|
|
64
|
+
cy.makeSnapshot();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('sets the value to the minimum value configured when a value less than the minimum value is typed in the field', () => {
|
|
68
|
+
initialize({
|
|
69
|
+
dataTestId: 'test',
|
|
70
|
+
defaultValue: 25,
|
|
71
|
+
inputProps: {
|
|
72
|
+
min: 2
|
|
73
|
+
},
|
|
74
|
+
onChange: cy.stub()
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
cy.get('input').should('have.value', '25');
|
|
78
|
+
|
|
79
|
+
cy.get('input').clear().type('-1');
|
|
80
|
+
|
|
81
|
+
cy.get('input').should('have.value', '2');
|
|
82
|
+
|
|
83
|
+
cy.makeSnapshot();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
|
|
4
|
+
import NumberField from './Number';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof NumberField> = {
|
|
7
|
+
argTypes: {
|
|
8
|
+
defaultValue: {
|
|
9
|
+
defaultValue: 0,
|
|
10
|
+
description:
|
|
11
|
+
'The initial value which will be used by the input for the first render',
|
|
12
|
+
type: 'number'
|
|
13
|
+
},
|
|
14
|
+
fallbackValue: {
|
|
15
|
+
defaultValue: 0,
|
|
16
|
+
description: 'This value will be used when the input is cleared',
|
|
17
|
+
type: 'number'
|
|
18
|
+
},
|
|
19
|
+
onChange: {
|
|
20
|
+
description:
|
|
21
|
+
'The change function with the actual value as parameter. This parameter will be the value when the input is filled but it will be the fallbackValue when the input is cleared out',
|
|
22
|
+
type: 'function'
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
component: NumberField
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default meta;
|
|
29
|
+
type Story = StoryObj<typeof NumberField>;
|
|
30
|
+
|
|
31
|
+
export const Default: Story = {
|
|
32
|
+
args: {
|
|
33
|
+
onChange: console.log
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const WithDefaultValue: Story = {
|
|
38
|
+
args: {
|
|
39
|
+
defaultValue: 25,
|
|
40
|
+
onChange: console.log
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const WithFallbackValue: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
fallbackValue: 25,
|
|
47
|
+
onChange: console.log
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const WithFallbackValueAndDefaultValue: Story = {
|
|
52
|
+
args: {
|
|
53
|
+
defaultValue: 10,
|
|
54
|
+
fallbackValue: 25,
|
|
55
|
+
onChange: console.log
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const WithFallbackValueAndDefaultValueAutoSize: Story = {
|
|
60
|
+
args: {
|
|
61
|
+
autoSize: true,
|
|
62
|
+
defaultValue: 10,
|
|
63
|
+
fallbackValue: 25,
|
|
64
|
+
onChange: console.log
|
|
65
|
+
}
|
|
66
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { ChangeEvent, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { T, always, cond, isEmpty, isNil } from 'ramda';
|
|
4
|
+
|
|
5
|
+
import TextField, { TextProps } from '../Text';
|
|
6
|
+
|
|
7
|
+
export interface NumberProps
|
|
8
|
+
extends Omit<TextProps, 'defaultValue' | 'onChange'> {
|
|
9
|
+
/**
|
|
10
|
+
* The initial value which will be used by the input for the first render
|
|
11
|
+
*/
|
|
12
|
+
defaultValue?: number;
|
|
13
|
+
/**
|
|
14
|
+
* This value will be used when the input is cleared
|
|
15
|
+
*/
|
|
16
|
+
fallbackValue?: number;
|
|
17
|
+
/**
|
|
18
|
+
* The change function with the actual value as parameter. This parameter will be the value when the input is filled but it will be the fallbackValue when the input is cleared out
|
|
19
|
+
*/
|
|
20
|
+
onChange: (actualValue: number) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const NumberField = ({
|
|
24
|
+
fallbackValue = 0,
|
|
25
|
+
defaultValue,
|
|
26
|
+
onChange,
|
|
27
|
+
...props
|
|
28
|
+
}: NumberProps): JSX.Element => {
|
|
29
|
+
const [placeholder, setPlaceholder] = useState<string | undefined>();
|
|
30
|
+
const [actualValue, setActualValue] = useState(
|
|
31
|
+
defaultValue ? `${defaultValue}` : ''
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const { inputProps } = props;
|
|
35
|
+
|
|
36
|
+
const changeValue = (event: ChangeEvent<HTMLInputElement>): void => {
|
|
37
|
+
const inputValue = event.target.value;
|
|
38
|
+
|
|
39
|
+
const number = Number(inputValue);
|
|
40
|
+
const campledNumber = cond([
|
|
41
|
+
[() => isEmpty(inputValue), always(fallbackValue)],
|
|
42
|
+
[() => Number.isNaN(number), always(number)],
|
|
43
|
+
[
|
|
44
|
+
T,
|
|
45
|
+
always(
|
|
46
|
+
Math.max(
|
|
47
|
+
!isNil(inputProps?.min) ? inputProps?.min : -Infinity,
|
|
48
|
+
number
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
]
|
|
52
|
+
])();
|
|
53
|
+
|
|
54
|
+
onChange(campledNumber);
|
|
55
|
+
setPlaceholder(isEmpty(inputValue) ? `${fallbackValue}` : undefined);
|
|
56
|
+
setActualValue(isEmpty(inputValue) ? inputValue : `${campledNumber}`);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<TextField
|
|
61
|
+
defaultValue={defaultValue}
|
|
62
|
+
type="number"
|
|
63
|
+
value={actualValue}
|
|
64
|
+
onChange={changeValue}
|
|
65
|
+
{...props}
|
|
66
|
+
inputProps={inputProps}
|
|
67
|
+
placeholder={
|
|
68
|
+
placeholder || (!defaultValue ? `${fallbackValue}` : undefined)
|
|
69
|
+
}
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export default NumberField;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import IconSearch from '@mui/icons-material/Search';
|
|
2
2
|
|
|
3
|
-
import TextField, {
|
|
3
|
+
import TextField, { TextProps } from '../Text';
|
|
4
4
|
|
|
5
|
-
type Props = Omit<
|
|
5
|
+
type Props = Omit<TextProps, 'StartAdornment'>;
|
|
6
6
|
|
|
7
7
|
const SearchAdornment = (): JSX.Element => <IconSearch />;
|
|
8
8
|
|
|
@@ -17,38 +17,36 @@ import { getNormalizedId } from '../../utils';
|
|
|
17
17
|
|
|
18
18
|
import useAutoSize from './useAutoSize';
|
|
19
19
|
|
|
20
|
-
const useStyles = makeStyles
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
})
|
|
51
|
-
);
|
|
20
|
+
const useStyles = makeStyles()((theme: Theme) => ({
|
|
21
|
+
autoSizeCompact: {
|
|
22
|
+
paddingRight: theme.spacing(1),
|
|
23
|
+
paddingTop: theme.spacing(0.6)
|
|
24
|
+
},
|
|
25
|
+
hiddenText: {
|
|
26
|
+
display: 'table',
|
|
27
|
+
lineHeight: 0,
|
|
28
|
+
transform: 'scaleY(0)'
|
|
29
|
+
},
|
|
30
|
+
input: {
|
|
31
|
+
fontSize: theme.typography.body1.fontSize
|
|
32
|
+
},
|
|
33
|
+
inputBase: {
|
|
34
|
+
display: 'inline-flex',
|
|
35
|
+
justifyItems: 'start',
|
|
36
|
+
paddingRight: theme.spacing(1)
|
|
37
|
+
},
|
|
38
|
+
noLabelInput: {
|
|
39
|
+
padding: theme.spacing(1)
|
|
40
|
+
},
|
|
41
|
+
textField: {
|
|
42
|
+
transition: theme.transitions.create(['width'], {
|
|
43
|
+
duration: theme.transitions.duration.shortest
|
|
44
|
+
})
|
|
45
|
+
},
|
|
46
|
+
transparent: {
|
|
47
|
+
backgroundColor: 'transparent'
|
|
48
|
+
}
|
|
49
|
+
}));
|
|
52
50
|
|
|
53
51
|
interface OptionalLabelInputAdornmentProps {
|
|
54
52
|
children: React.ReactNode;
|
|
@@ -72,7 +70,7 @@ const OptionalLabelInputAdornment = ({
|
|
|
72
70
|
|
|
73
71
|
type SizeVariant = 'large' | 'medium' | 'small' | 'compact';
|
|
74
72
|
|
|
75
|
-
export type
|
|
73
|
+
export type TextProps = {
|
|
76
74
|
EndAdornment?: React.FC;
|
|
77
75
|
StartAdornment?: React.FC;
|
|
78
76
|
ariaLabel?: string;
|
|
@@ -114,17 +112,18 @@ const TextField = forwardRef(
|
|
|
114
112
|
defaultValue,
|
|
115
113
|
required = false,
|
|
116
114
|
containerClassName,
|
|
115
|
+
type,
|
|
117
116
|
...rest
|
|
118
|
-
}:
|
|
117
|
+
}: TextProps,
|
|
119
118
|
ref: React.ForwardedRef<HTMLDivElement>
|
|
120
119
|
): JSX.Element => {
|
|
121
|
-
const { classes, cx } = useStyles(
|
|
122
|
-
displayAsBlock: autoSize && isNil(StartAdornment) && isNil(EndAdornment)
|
|
123
|
-
});
|
|
120
|
+
const { classes, cx } = useStyles();
|
|
124
121
|
|
|
125
122
|
const { inputRef, width, changeInputValue, innerValue } = useAutoSize({
|
|
126
123
|
autoSize,
|
|
127
|
-
autoSizeCustomPadding,
|
|
124
|
+
autoSizeCustomPadding: equals(type, 'number')
|
|
125
|
+
? Math.max(6, autoSizeCustomPadding || 0)
|
|
126
|
+
: autoSizeCustomPadding,
|
|
128
127
|
autoSizeDefaultWidth,
|
|
129
128
|
value: externalValueForAutoSize || rest.value
|
|
130
129
|
});
|
|
@@ -196,6 +195,7 @@ const TextField = forwardRef(
|
|
|
196
195
|
width: autoSize ? width : undefined,
|
|
197
196
|
...rest?.sx
|
|
198
197
|
}}
|
|
198
|
+
type={type}
|
|
199
199
|
/>
|
|
200
200
|
</Tooltip>
|
|
201
201
|
{autoSize && (
|
package/src/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ export { default as RegexpHelpTooltip } from './InputField/Search/RegexpHelpTool
|
|
|
23
23
|
|
|
24
24
|
export { default as TextField } from './InputField/Text';
|
|
25
25
|
export type { Props as TextFieldProps } from './InputField/Text';
|
|
26
|
+
export { default as NumberField } from './InputField/Number/Number';
|
|
26
27
|
|
|
27
28
|
export type { SelectEntry } from './InputField/Select';
|
|
28
29
|
export { default as SelectField } from './InputField/Select';
|