jamespot-react-components 1.0.2 → 1.0.16
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/.storybook/StorybookContainer/StorybookContainer.css +1 -0
- package/babel.config.js +0 -1
- package/build/jamespot-react-components.js +254 -235
- package/build/jamespot-react-components.js.LICENSE.txt +19 -13
- package/build/jamespot-react-components.js.map +1 -1
- package/build/src/components/Common/JRCConditionalWrapper.d.ts +4 -4
- package/build/src/components/Form/Input/JRCInputCheckbox/JRCInputCheckbox.d.ts +5 -2
- package/build/src/components/Form/Input/JRCInputDate/JRCInputDate.d.ts +11 -0
- package/build/src/components/Form/Input/JRCInputDate/JRCInputDate.stories.d.ts +5 -0
- package/build/src/components/Form/Input/JRCInputText/JRCInputText.d.ts +1 -1
- package/build/src/components/Form/Input/JRCInputTextarea/JRCInputTextarea.d.ts +15 -0
- package/build/src/components/Form/Input/JRCInputTextarea/JRCInputTextarea.stories.d.ts +5 -0
- package/build/src/components/JRCAppContainer/JRCAppContainer.d.ts +1 -0
- package/build/src/components/JRCButton/JRCButton.d.ts +25 -0
- package/build/src/components/JRCButton/JRCButtonConfig.d.ts +1 -2
- package/build/src/components/JRCEllipsis/JRCEllipsis.d.ts +5 -0
- package/build/src/components/JRCEllipsis/JRCEllipsis.stories.d.ts +5 -0
- package/build/src/components/JRCHref/JRCHref.d.ts +18 -10
- package/build/src/components/JRCImg/url.util.d.ts +3 -3
- package/build/src/components/JRCList/JRCList.d.ts +2 -0
- package/build/src/components/JRCModal/JRCModal.d.ts +5 -1
- package/build/src/components/JRCModal/JRCModal.styles.d.ts +0 -1
- package/build/src/components/JRCTag/JRCTag.d.ts +2 -0
- package/build/src/components/Templates/JRCBase.template.d.ts +9 -0
- package/build/src/components/Templates/JRCTemplate.stories.d.ts +13 -0
- package/build/src/components/Templates/JRCTwoColumns.template.d.ts +7 -0
- package/build/src/hooks/UseDidMountEffect.d.ts +1 -2
- package/build/src/index.d.ts +11 -8
- package/build/src/styles/theme.d.ts +4 -1
- package/build/src/types.d.ts +6 -2
- package/externals.d.ts +0 -1
- package/externals.json +3 -1
- package/package.json +4 -4
- package/src/components/Common/JRCConditionalWrapper.tsx +6 -13
- package/src/components/Form/Input/JRCFormColor/JRCFormColor.tsx +12 -12
- package/src/components/Form/Input/JRCFormEmail/JRCInputEmail.tsx +4 -8
- package/src/components/Form/Input/JRCFormSelect/JRCFormSelect.tsx +5 -1
- package/src/components/Form/Input/JRCFormSelect/JRCFormSelectTag.tsx +3 -1
- package/src/components/Form/Input/JRCInputCheckbox/JRCInputCheckbox.stories.tsx +1 -4
- package/src/components/Form/Input/JRCInputCheckbox/JRCInputCheckbox.tsx +12 -10
- package/src/components/Form/Input/JRCInputDate/JRCInputDate.stories.tsx +50 -0
- package/src/components/Form/Input/JRCInputDate/JRCInputDate.tsx +26 -0
- package/src/components/Form/Input/JRCInputText/JRCInputText.tsx +2 -2
- package/src/components/Form/Input/JRCInputTextarea/JRCInputTextarea.stories.tsx +52 -0
- package/src/components/Form/Input/JRCInputTextarea/JRCInputTextarea.tsx +36 -0
- package/src/components/Form/Input/JRCSelect/JRCInputSelect.tsx +1 -1
- package/src/components/JRCAppContainer/JRCAppContainer.tsx +6 -2
- package/src/components/JRCAppLeftColumn/JRCAppLeftColumn.styles.tsx +2 -1
- package/src/components/JRCAvatar/JRCAvatar.test.tsx +10 -6
- package/src/components/JRCAvatar/JRCAvatar.tsx +1 -0
- package/src/components/JRCButton/JRCButton.stories.tsx +1 -1
- package/src/components/JRCButton/JRCButton.tsx +9 -3
- package/src/components/JRCButton/JRCButtonConfig.tsx +1 -1
- package/src/components/JRCButton/JRCValidationButton.tsx +10 -4
- package/src/components/JRCButton/__snapshots__/JRCButton.test.tsx.snap +1 -2
- package/src/components/JRCButtonDropdown/JRCButtonDropdown.tsx +2 -2
- package/src/components/JRCEllipsis/JRCEllipsis.stories.tsx +18 -0
- package/src/components/JRCEllipsis/JRCEllipsis.tsx +22 -0
- package/src/components/JRCHref/JRCHref.stories.tsx +2 -0
- package/src/components/JRCHref/JRCHref.tsx +42 -15
- package/src/components/JRCIcon/JRCIcon.tsx +1 -1
- package/src/components/JRCIconButton/JRCIconButton.tsx +1 -4
- package/src/components/JRCImg/JRCImg.tsx +4 -2
- package/src/components/JRCImg/url.util.ts +7 -6
- package/src/components/JRCImg/url.utils.test.ts +7 -1
- package/src/components/JRCList/JRCList.styles.tsx +16 -2
- package/src/components/JRCList/JRCList.tsx +5 -5
- package/src/components/JRCList/JRCListMockData.stories.tsx +1 -1
- package/src/components/JRCModal/JRCModal.styles.tsx +0 -6
- package/src/components/JRCModal/JRCModal.tsx +75 -61
- package/src/components/JRCTag/JRCTag.tsx +29 -9
- package/src/components/JRCThemeProvider/animation.css +19 -0
- package/src/components/JRCThemeProvider/font.css +1 -1
- package/src/components/JRCThemeProvider/gabarit.css +4 -0
- package/src/components/JRCTooltip/JRCTooltip.tsx +5 -2
- package/src/components/JRCTypography/__snapshots__/JRCTypography.test.tsx.snap +1 -1
- package/src/components/Templates/JRCBase.template.tsx +39 -0
- package/src/components/Templates/JRCTemplate.stories.tsx +55 -0
- package/src/components/Templates/JRCTwoColumns.template.tsx +20 -0
- package/src/hooks/UseDidMountEffect.tsx +1 -3
- package/src/index.tsx +17 -10
- package/src/styles/theme.tsx +12 -6
- package/src/translation/lang.json +3 -2
- package/src/types.ts +8 -2
- package/build/src/components/Form/Input/JRCFormTextEditor/JRCFormTextEditor.d.ts +0 -10
- package/build/src/components/Form/Input/JRCFormTextEditor/JRCFormTextEditor.stories.d.ts +0 -5
- package/build/src/components/JRCColumnCenterTitle/JRCColumnCenterTitle.d.ts +0 -12
- package/src/components/Form/Input/JRCFormTextEditor/JRCFormTextEditor.stories.tsx +0 -30
- package/src/components/Form/Input/JRCFormTextEditor/JRCFormTextEditor.tsx +0 -36
- package/src/components/JRCColumnCenterTitle/JRCColumnCenterTitle.tsx +0 -26
- package/src/variables.scss +0 -67
|
@@ -49,6 +49,7 @@ const JRCFormSelectTagRenderer = <T,>(
|
|
|
49
49
|
onMouseDown={props.removeProps.onMouseDown}
|
|
50
50
|
onClick={(e) => props.removeProps.onClick(e)}
|
|
51
51
|
focusable={true}
|
|
52
|
+
clickVariant="delete"
|
|
52
53
|
isFocused={props.isFocused}
|
|
53
54
|
uri={props.data.uri}
|
|
54
55
|
label={getOptionLabel(props)}
|
|
@@ -60,7 +61,7 @@ const JRCFormSelectTagRenderer = <T,>(
|
|
|
60
61
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
61
62
|
// @ts-ignore
|
|
62
63
|
SingleValue: (props: SingleValueProps<OptionTypeBase>) => (
|
|
63
|
-
<JRCTag uri={props.data.uri} label={getOptionLabel(props)} />
|
|
64
|
+
<JRCTag uri={props.data.uri} label={getOptionLabel(props)} clickVariant="delete" />
|
|
64
65
|
),
|
|
65
66
|
// FIXME TYPESCRIPT-STRICT
|
|
66
67
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
@@ -88,6 +89,7 @@ const Option = <isMulti extends boolean>(props: OptionProps<OptionTypeBase, isMu
|
|
|
88
89
|
<JRCTag
|
|
89
90
|
uri={props.data.uri}
|
|
90
91
|
focusable={true}
|
|
92
|
+
clickVariant="select"
|
|
91
93
|
isFocused={props.isFocused}
|
|
92
94
|
label={getOptionLabel(props)}
|
|
93
95
|
/>
|
|
@@ -13,7 +13,7 @@ export default {
|
|
|
13
13
|
const Template: Story<JRCInputCheckboxProps<any>> = (args) => {
|
|
14
14
|
const { handleSubmit, control } = useForm({
|
|
15
15
|
defaultValues: {
|
|
16
|
-
|
|
16
|
+
checkbox: [],
|
|
17
17
|
},
|
|
18
18
|
criteriaMode: 'all',
|
|
19
19
|
});
|
|
@@ -23,9 +23,6 @@ const Template: Story<JRCInputCheckboxProps<any>> = (args) => {
|
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
|
-
// FIXME TYPESCRIPT-STRICT
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
28
|
-
// @ts-ignore
|
|
29
26
|
<form onSubmit={handleSubmit(onSubmit)}>
|
|
30
27
|
<JRCInputCheckbox {...args} control={control as any} />
|
|
31
28
|
<input type="submit" />
|
|
@@ -12,12 +12,11 @@ import { deepEqual } from '../../../../utils/utils.object';
|
|
|
12
12
|
import { DataCy } from '../../../../types/dataAttributes';
|
|
13
13
|
import { JRCInputFieldProps } from '../Common/JRCFormFieldRenderer.types';
|
|
14
14
|
import { CheckboxValue } from './JRCInputCheckbox.types';
|
|
15
|
-
|
|
16
|
-
type Value<T> = string | number | T;
|
|
15
|
+
import { RefCallBack } from 'react-hook-form';
|
|
17
16
|
|
|
18
17
|
type CheckboxOption<TFieldValues> = {
|
|
19
18
|
label: string | JSX.Element;
|
|
20
|
-
value:
|
|
19
|
+
value: string | number | TFieldValues;
|
|
21
20
|
disabled?: boolean;
|
|
22
21
|
};
|
|
23
22
|
|
|
@@ -35,18 +34,19 @@ export type CheckboxProps<TFieldValues> = DataCy & {
|
|
|
35
34
|
};
|
|
36
35
|
|
|
37
36
|
export type JRCInputCheckboxProps<TFieldValues> = CheckboxProps<TFieldValues> & JRCInputFieldProps<TFieldValues>;
|
|
37
|
+
export type NativeCheckboxProps<TFieldValues> = CheckboxProps<TFieldValues> &
|
|
38
|
+
Omit<ControllerRenderProps<TFieldValues>, 'value'> & { value: TFieldValues | TFieldValues[] };
|
|
38
39
|
|
|
39
|
-
function
|
|
40
|
-
variant = 'default',
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Omit<ControllerRenderProps<TFieldValues>, 'value'> & { value: TFieldValues | TFieldValues[] }) {
|
|
40
|
+
const RenderInput = React.forwardRef(function <TFieldValues>(
|
|
41
|
+
{ variant = 'default', ...props }: NativeCheckboxProps<TFieldValues>,
|
|
42
|
+
ref: React.ForwardedRef<HTMLInputElement>,
|
|
43
|
+
) {
|
|
44
44
|
const field = {
|
|
45
45
|
onChange: props.onChange,
|
|
46
46
|
onBlur: props.onBlur,
|
|
47
47
|
value: props.value,
|
|
48
48
|
name: props.name,
|
|
49
|
-
ref:
|
|
49
|
+
ref: ref as RefCallBack,
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
const [valueTypeIsBoolean, setValueTypeIsBoolean] = React.useState(
|
|
@@ -98,6 +98,7 @@ function RenderInput<TFieldValues>({
|
|
|
98
98
|
{props.checkboxMode === 'radio' ? (
|
|
99
99
|
<JRCRadio
|
|
100
100
|
name={props.name}
|
|
101
|
+
ref={(index === 0 && ref) || undefined}
|
|
101
102
|
data-cy={props.dataCy && `${props.dataCy}-option-${index}`}
|
|
102
103
|
disabled={props.disabled || option.disabled}
|
|
103
104
|
checked={checked}
|
|
@@ -109,6 +110,7 @@ function RenderInput<TFieldValues>({
|
|
|
109
110
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
110
111
|
// @ts-ignore
|
|
111
112
|
checkboxMode={props.checkboxMode}
|
|
113
|
+
ref={(index === 0 && ref) || undefined}
|
|
112
114
|
name={props.name}
|
|
113
115
|
data-cy={props.dataCy && `${props.dataCy}-option-${index}`}
|
|
114
116
|
disabled={props.disabled || option.disabled}
|
|
@@ -147,7 +149,7 @@ function RenderInput<TFieldValues>({
|
|
|
147
149
|
})}
|
|
148
150
|
</DirectionContainer>
|
|
149
151
|
);
|
|
150
|
-
}
|
|
152
|
+
}) as unknown as <T>(props: NativeCheckboxProps<T>) => JSX.Element;
|
|
151
153
|
|
|
152
154
|
export function JRCInputCheckbox<TFieldValues>({
|
|
153
155
|
name,
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { JRCInputDate } from './JRCInputDate';
|
|
3
|
+
import { useForm } from 'react-hook-form';
|
|
4
|
+
import { JRCInputFieldProps } from '../Common/JRCFormFieldRenderer.types';
|
|
5
|
+
import { SubmitHandler } from 'react-hook-form/dist/types/form';
|
|
6
|
+
import { Meta, Story } from '@storybook/react';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
title: 'Inputs/new',
|
|
10
|
+
component: JRCInputDate,
|
|
11
|
+
} as Meta;
|
|
12
|
+
|
|
13
|
+
const Template: Story<JRCInputFieldProps<'date'>> = (args) => {
|
|
14
|
+
const { handleSubmit, control, reset } = useForm({
|
|
15
|
+
defaultValues: {
|
|
16
|
+
date: '',
|
|
17
|
+
},
|
|
18
|
+
criteriaMode: 'all',
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const onSubmit: SubmitHandler<{ date: string }> = (data) => {
|
|
22
|
+
alert(JSON.stringify(data, null, 2));
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
27
|
+
<JRCInputDate {...args} name="date" control={control} />
|
|
28
|
+
<input type="submit" />
|
|
29
|
+
<input type="reset" />
|
|
30
|
+
<button type="button" onClick={() => reset()}>
|
|
31
|
+
Custom Reset
|
|
32
|
+
</button>
|
|
33
|
+
</form>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const InputDate = Template.bind({});
|
|
38
|
+
InputDate.args = {
|
|
39
|
+
label: 'Date de création du groupe',
|
|
40
|
+
description:
|
|
41
|
+
"La date de création du groupe doit permettre en un clin d'oeil de connaitre la date de création du groupe",
|
|
42
|
+
helper: { description: "Ajouter une date cohérente ! L'année 218 n'est pas cohérente", title: 'Indication' },
|
|
43
|
+
rules: {
|
|
44
|
+
min: {
|
|
45
|
+
value: '2023-11-11',
|
|
46
|
+
message: 'La date doit être supérieur au 11/11/2023',
|
|
47
|
+
},
|
|
48
|
+
required: true,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { StyledInput } from '../JRCStyledInput';
|
|
3
|
+
import { JRCInputFieldProps } from '../Common/JRCFormFieldRenderer.types';
|
|
4
|
+
import { JRCFormFieldRenderer } from '../Common/JRCFormFieldRenderer';
|
|
5
|
+
import { DataCy } from '../../../../types/dataAttributes';
|
|
6
|
+
|
|
7
|
+
export type JRCInputDateProps = DataCy & React.ComponentPropsWithoutRef<'input'>;
|
|
8
|
+
|
|
9
|
+
const RenderInput = React.forwardRef((props: JRCInputDateProps, ref: React.ForwardedRef<HTMLInputElement>) => {
|
|
10
|
+
return <StyledInput type="date" id={props.name} {...props} ref={ref} />;
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Component used as a <input type="date"/>
|
|
15
|
+
* @param props JRCInputFieldProps
|
|
16
|
+
* validation props: required
|
|
17
|
+
* @returns JSX.Element
|
|
18
|
+
*/
|
|
19
|
+
export function JRCInputDate<T>(props: JRCInputFieldProps<T>) {
|
|
20
|
+
return (
|
|
21
|
+
<JRCFormFieldRenderer
|
|
22
|
+
{...props}
|
|
23
|
+
renderFunction={({ value, ...field }) => <RenderInput {...props} {...field} value={value as string} />}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -4,9 +4,9 @@ import { JRCInputFieldProps } from '../Common/JRCFormFieldRenderer.types';
|
|
|
4
4
|
import { JRCFormFieldRenderer } from '../Common/JRCFormFieldRenderer';
|
|
5
5
|
import { DataCy } from '../../../../types/dataAttributes';
|
|
6
6
|
|
|
7
|
-
export type
|
|
7
|
+
export type JRCInputTextProps = DataCy & React.ComponentPropsWithoutRef<'input'>;
|
|
8
8
|
|
|
9
|
-
const RenderInput = React.forwardRef((props:
|
|
9
|
+
const RenderInput = React.forwardRef((props: JRCInputTextProps, ref: React.ForwardedRef<HTMLInputElement>) => {
|
|
10
10
|
return <StyledInput type="text" id={props.name} {...props} ref={ref} />;
|
|
11
11
|
});
|
|
12
12
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { JRCInputTextarea } from './JRCInputTextarea';
|
|
3
|
+
import { useForm } from 'react-hook-form';
|
|
4
|
+
import { JRCInputFieldProps } from '../Common/JRCFormFieldRenderer.types';
|
|
5
|
+
import { SubmitHandler } from 'react-hook-form/dist/types/form';
|
|
6
|
+
import { Meta, Story } from '@storybook/react';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
title: 'Inputs/new',
|
|
10
|
+
component: JRCInputTextarea,
|
|
11
|
+
} as Meta;
|
|
12
|
+
|
|
13
|
+
const Template: Story<JRCInputFieldProps<'textarea'>> = (args) => {
|
|
14
|
+
const { handleSubmit, control, reset } = useForm({
|
|
15
|
+
defaultValues: {
|
|
16
|
+
textarea: '',
|
|
17
|
+
},
|
|
18
|
+
criteriaMode: 'all',
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const onSubmit: SubmitHandler<{ textarea: string }> = (data) => {
|
|
22
|
+
alert(JSON.stringify(data, null, 2));
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
27
|
+
<JRCInputTextarea {...args} name="textarea" control={control} />
|
|
28
|
+
<input type="submit" />
|
|
29
|
+
<input type="reset" />
|
|
30
|
+
<button type="button" onClick={() => reset()}>
|
|
31
|
+
Custom Reset
|
|
32
|
+
</button>
|
|
33
|
+
</form>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const InputTextarea = Template.bind({});
|
|
38
|
+
InputTextarea.args = {
|
|
39
|
+
label: 'Nom de groupe',
|
|
40
|
+
description: "Le nom du groupe doit permettre en un clin d'oeil de connaitre le sujet du groupe",
|
|
41
|
+
placeholder: 'Présentations',
|
|
42
|
+
helper: { description: 'Ne faites pas commencer votre groupe par "Groupe de"', title: 'Indication' },
|
|
43
|
+
rules: {
|
|
44
|
+
maxLength: {
|
|
45
|
+
value: 25,
|
|
46
|
+
message:
|
|
47
|
+
'This is an example error. For instance, the text should not be written with more than 25 characters. This message is not the default one.',
|
|
48
|
+
},
|
|
49
|
+
minLength: 3,
|
|
50
|
+
required: true,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { cssStyledInput } from '../JRCStyledInput';
|
|
3
|
+
import { JRCInputFieldProps } from '../Common/JRCFormFieldRenderer.types';
|
|
4
|
+
import { JRCFormFieldRenderer } from '../Common/JRCFormFieldRenderer';
|
|
5
|
+
import { DataCy } from '../../../../types/dataAttributes';
|
|
6
|
+
import styled from 'styled-components';
|
|
7
|
+
|
|
8
|
+
export type JRCInputTextareaProps = DataCy & React.ComponentPropsWithoutRef<'textarea'>;
|
|
9
|
+
|
|
10
|
+
export const StyledTextArea = styled.textarea`
|
|
11
|
+
${cssStyledInput}
|
|
12
|
+
&&&& {
|
|
13
|
+
padding-top: 10px;
|
|
14
|
+
height: 140px;
|
|
15
|
+
resize: vertical;
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
const RenderInput = React.forwardRef((props: JRCInputTextareaProps, ref: React.ForwardedRef<HTMLTextAreaElement>) => {
|
|
20
|
+
return <StyledTextArea id={props.name} {...props} ref={ref} />;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Component used as a <input type="text"/>
|
|
25
|
+
* @param props JRCInputFieldProps
|
|
26
|
+
* validation props: required
|
|
27
|
+
* @returns JSX.Element
|
|
28
|
+
*/
|
|
29
|
+
export function JRCInputTextarea<T>(props: JRCInputFieldProps<T>) {
|
|
30
|
+
return (
|
|
31
|
+
<JRCFormFieldRenderer
|
|
32
|
+
{...props}
|
|
33
|
+
renderFunction={({ value, ...field }) => <RenderInput {...props} {...field} value={value as string} />}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -56,7 +56,7 @@ export const Select = React.forwardRef(function <T>(
|
|
|
56
56
|
if (menuRef.current && selectedOptionRef) scrollIntoView(menuRef.current, selectedOptionRef);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
// Hack to use .focus() outside of this component while
|
|
59
|
+
// Hack to use .focus() outside of this component while being able to access the ref within this component
|
|
60
60
|
React.useImperativeHandle(
|
|
61
61
|
ref,
|
|
62
62
|
() =>
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
|
|
4
|
+
export const CONTAINER_PADDING = 32;
|
|
5
|
+
|
|
4
6
|
const Container = styled.div`
|
|
5
7
|
display: flex;
|
|
6
8
|
max-width: 1600px;
|
|
7
9
|
width: 100%;
|
|
8
10
|
margin: auto;
|
|
9
|
-
gap:
|
|
10
|
-
padding:
|
|
11
|
+
gap: ${CONTAINER_PADDING}px;
|
|
12
|
+
padding: ${CONTAINER_PADDING}px;
|
|
13
|
+
background-color: ${(props) => props.theme.color.white};
|
|
14
|
+
min-height: calc(var(--body-height) - ${CONTAINER_PADDING * 2}px);
|
|
11
15
|
`;
|
|
12
16
|
|
|
13
17
|
export interface JRCAppContainerProps {
|
|
@@ -2,6 +2,7 @@ import { ItemButton } from '../JRCTabs/JRCTabs';
|
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
import { JRCH2 } from '../JRCTypo/JRCTypo';
|
|
4
4
|
import { JRCIconButton } from '../JRCIconButton/JRCIconButton';
|
|
5
|
+
import { CONTAINER_PADDING } from 'components/JRCAppContainer/JRCAppContainer';
|
|
5
6
|
|
|
6
7
|
export const JRCAppLeftColumnWrapperTop = styled.div`
|
|
7
8
|
display: flex;
|
|
@@ -21,7 +22,7 @@ export const ColumnRelativeSticky = styled.div<{ isMinimized: boolean; isClosed:
|
|
|
21
22
|
display: flex;
|
|
22
23
|
position: sticky;
|
|
23
24
|
bottom: 0;
|
|
24
|
-
min-height: calc(var(--body-height) -
|
|
25
|
+
min-height: calc(var(--body-height) - ${CONTAINER_PADDING * 2}px);
|
|
25
26
|
background: ${(props) => props.theme.color.grey0};
|
|
26
27
|
min-width: ${(props) => (props.isMinimized ? '80px' : '300px')};
|
|
27
28
|
overflow: ${(props) => (props.isClosed ? 'visible' : 'hidden')};
|
|
@@ -4,19 +4,23 @@ import { screen } from '@testing-library/react';
|
|
|
4
4
|
|
|
5
5
|
import JRCAvatar from './JRCAvatar';
|
|
6
6
|
|
|
7
|
+
const SIZE = 3;
|
|
8
|
+
|
|
7
9
|
describe('JRCAvatar', () => {
|
|
8
10
|
beforeEach(() => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
renderWithWrapper(
|
|
12
|
+
<JRCAvatar type="user" recordId="1234" size={SIZE} alt="avatar of user John Doe" />,
|
|
13
|
+
);
|
|
12
14
|
});
|
|
13
15
|
|
|
14
16
|
test('medium avatar to have a proper size', () => {
|
|
15
|
-
|
|
16
|
-
expect(screen.getByRole('img')).toHaveAttribute('
|
|
17
|
+
const width = (8 * SIZE).toString();
|
|
18
|
+
expect(screen.getByRole('img')).toHaveAttribute('width', width);
|
|
19
|
+
expect(screen.getByRole('img')).toHaveAttribute('height', width);
|
|
17
20
|
});
|
|
18
21
|
|
|
19
22
|
test('medium avatar to download an img twice the container size', () => {
|
|
20
|
-
|
|
23
|
+
const width = (Math.ceil(window.devicePixelRatio) * 8 * SIZE).toString();
|
|
24
|
+
expect(screen.getByRole('img')).toHaveAttribute('src', `/imagecache/${width}x${width}/user/1234.png`);
|
|
21
25
|
});
|
|
22
26
|
});
|
|
@@ -2,7 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import JRCIcon, { JRCIconProps } from '../JRCIcon/JRCIcon';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
4
|
import JRCLoader from 'components/JRCLoader/JRCLoader';
|
|
5
|
-
import
|
|
5
|
+
import { BUTTON_CONFIG, ButtonType } from './JRCButtonConfig';
|
|
6
6
|
import { ForwardedRef } from 'react';
|
|
7
7
|
import { DataCy } from '../../types/dataAttributes';
|
|
8
8
|
|
|
@@ -39,7 +39,10 @@ export const transformColor = (color?: string): JRCIconProps['color'] => {
|
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Button styling. May be used as a <a> tag
|
|
44
|
+
*/
|
|
45
|
+
export const Button = styled.button<{ themeButton: ButtonType; hasChildren: boolean } & JRCButtonProps>`
|
|
43
46
|
float: ${(props) => props.float};
|
|
44
47
|
min-width: ${(props) => props.minWidth};
|
|
45
48
|
display: inline-flex;
|
|
@@ -58,7 +61,10 @@ const Button = styled.button<{ themeButton: ButtonType; hasChildren: boolean } &
|
|
|
58
61
|
box-sizing: border-box;
|
|
59
62
|
border: 2px solid ${(props) => props.theme.color[props.themeButton.border]};
|
|
60
63
|
transition: color 0.5s, background-color 0.5s, border 0.5s;
|
|
64
|
+
text-decoration: none;
|
|
61
65
|
&:hover {
|
|
66
|
+
text-decoration: none;
|
|
67
|
+
color: ${(props) => props.theme.color[props.themeButton.color]};
|
|
62
68
|
background-color: ${(props) => props.theme.color[props.themeButton.hover.background]};
|
|
63
69
|
border-color: ${(props) => props.theme.color[props.themeButton.hover.border]};
|
|
64
70
|
}
|
|
@@ -93,7 +99,7 @@ const JRCButton = React.forwardRef(
|
|
|
93
99
|
ref: ForwardedRef<HTMLButtonElement>,
|
|
94
100
|
) => {
|
|
95
101
|
const disabled = props.disabled || props.loader;
|
|
96
|
-
const themeButton =
|
|
102
|
+
const themeButton = BUTTON_CONFIG[variant][disabled ? 'disabled' : color];
|
|
97
103
|
|
|
98
104
|
return (
|
|
99
105
|
<Button
|
|
@@ -13,7 +13,7 @@ export type JRCValidationButtonProps = JRCButtonProps & {
|
|
|
13
13
|
validationMessage?: string;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
/** double click prevented by using a temporary state, changed after a timeout */
|
|
16
|
+
/** double click prevented by using a temporary state (PREVENT_DB_CLICK), changed after a timeout */
|
|
17
17
|
const state = {
|
|
18
18
|
NOT_CLICKED: 'NOT_CLICKED',
|
|
19
19
|
PREVENT_DB_CLICK: 'PREVENT_DB_CLICK',
|
|
@@ -44,14 +44,20 @@ export const JRCValidationButton = ({
|
|
|
44
44
|
|
|
45
45
|
React.useEffect(() => {
|
|
46
46
|
if (validation === state.PREVENT_DB_CLICK) {
|
|
47
|
-
setTimeoutId(
|
|
47
|
+
setTimeoutId(
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
setValidation(state.NOT_CLICKED);
|
|
50
|
+
buttonRef?.current?.removeAttribute('style');
|
|
51
|
+
}, RESET_CLICK_DELAY) as unknown as number,
|
|
52
|
+
);
|
|
48
53
|
}
|
|
49
54
|
}, [validation]);
|
|
50
55
|
|
|
51
56
|
const validationOnClick = React.useCallback(
|
|
52
57
|
(e: React.MouseEvent<HTMLButtonElement>) => {
|
|
53
58
|
if (validationRef.current === state.CLICKED) {
|
|
54
|
-
|
|
59
|
+
// Timeout of 0 second to delay the change at the end of the execution pile
|
|
60
|
+
setTimeout(() => setValidation(state.NOT_CLICKED), 0);
|
|
55
61
|
buttonRef?.current?.removeAttribute('style');
|
|
56
62
|
onClick && onClick(e);
|
|
57
63
|
if (timeoutIdRef.current) clearTimeout(timeoutIdRef.current);
|
|
@@ -69,7 +75,7 @@ export const JRCValidationButton = ({
|
|
|
69
75
|
return (
|
|
70
76
|
<JRCButton
|
|
71
77
|
{...props}
|
|
72
|
-
type={validation === state.
|
|
78
|
+
type={validation === state.CLICKED ? props.type : 'button'}
|
|
73
79
|
ref={buttonRef}
|
|
74
80
|
onClick={validationOnClick}
|
|
75
81
|
icon={validation === state.NOT_CLICKED ? icon : 'icon-fs-question'}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
import JRCButton, { transformColor } from '../JRCButton/JRCButton';
|
|
4
|
-
import
|
|
4
|
+
import { BUTTON_CONFIG, ButtonType } from '../JRCButton/JRCButtonConfig';
|
|
5
5
|
import JRCIcon from '../JRCIcon/JRCIcon';
|
|
6
6
|
import { ClickAwayListener } from '../Form/Common/ClickAwayListener';
|
|
7
7
|
|
|
@@ -120,7 +120,7 @@ export const JRCButtonDropdown = ({
|
|
|
120
120
|
variant = 'contained',
|
|
121
121
|
...props
|
|
122
122
|
}: JRCButtonDropdownProps) => {
|
|
123
|
-
const color =
|
|
123
|
+
const color = BUTTON_CONFIG[variant][props.disabled ? 'disabled' : props.color || 'primary'];
|
|
124
124
|
const [isOpen, setOpenMenu] = React.useState(false);
|
|
125
125
|
const open = isOpen;
|
|
126
126
|
const IconRight = ({ color }: any) => {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Meta, Story } from '@storybook/react';
|
|
3
|
+
import { JRCEllipsis, JRCEllipsisProps } from './JRCEllipsis';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'JRCEllipsis',
|
|
7
|
+
component: JRCEllipsis,
|
|
8
|
+
} as Meta;
|
|
9
|
+
|
|
10
|
+
const Template: Story<JRCEllipsisProps> = (args) => {
|
|
11
|
+
return <JRCEllipsis {...args} />;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const CustomButton = Template.bind({});
|
|
15
|
+
CustomButton.args = {
|
|
16
|
+
label: "Je suis un texte trop long ! Ca marche avec un caractère double tel que : 👋 ! C'est génial !",
|
|
17
|
+
length: 75,
|
|
18
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { JRCConditionalWrapper } from '../Common/JRCConditionalWrapper';
|
|
3
|
+
import JRCTooltip from '../JRCTooltip/JRCTooltip';
|
|
4
|
+
|
|
5
|
+
export type JRCEllipsisProps = {
|
|
6
|
+
label?: string;
|
|
7
|
+
length: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const JRCEllipsis = ({ label, length }: JRCEllipsisProps) => {
|
|
11
|
+
if (!label) return <></>;
|
|
12
|
+
|
|
13
|
+
const labelArr = [...label];
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<JRCConditionalWrapper
|
|
17
|
+
condition={labelArr.length > length}
|
|
18
|
+
wrapper={() => <JRCTooltip description={label}>{labelArr.slice(0, length).join('')}…</JRCTooltip>}>
|
|
19
|
+
<>{label}</>
|
|
20
|
+
</JRCConditionalWrapper>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -5,6 +5,7 @@ import { Meta, Story } from '@storybook/react';
|
|
|
5
5
|
|
|
6
6
|
export default {
|
|
7
7
|
title: 'JRCHref',
|
|
8
|
+
component: JRCStyledHref,
|
|
8
9
|
} as Meta;
|
|
9
10
|
|
|
10
11
|
const Template: Story<JRCStyledHrefProps> = (args) => <JRCStyledHref {...args}>{args.children}</JRCStyledHref>;
|
|
@@ -14,6 +15,7 @@ Default.args = {
|
|
|
14
15
|
children: 'Hello',
|
|
15
16
|
href: '#',
|
|
16
17
|
dataCy: 'link-to-the-main-content',
|
|
18
|
+
as: 'a',
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
const UserTemplate: Story<JRCLinkToProps> = (args) => <JRCLinkToUser {...args}>{args.children}</JRCLinkToUser>;
|
|
@@ -1,40 +1,67 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
import { DataCy } from '../../types/dataAttributes';
|
|
4
|
+
import { Button } from '../JRCButton/JRCButton';
|
|
5
|
+
import { BUTTON_CONFIG } from '../JRCButton/JRCButtonConfig';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Props type for JRCLinkToArticle and JRCLinkToUser
|
|
7
|
-
* @member
|
|
8
|
-
* @member href string : href for href
|
|
9
|
-
* @member children: enclosed React component
|
|
9
|
+
* @member idObject number : id of the record
|
|
10
10
|
*/
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
export type JRCLinkToProps = DataCy &
|
|
12
|
+
React.ComponentPropsWithoutRef<'a'> & {
|
|
13
|
+
idObject?: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type AnchorProps = {
|
|
17
|
+
as?: 'a';
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type ButtonProps = {
|
|
21
|
+
variant?: 'contained' | 'outlined';
|
|
22
|
+
color?: 'primary' | 'valid' | 'danger' | 'secondary';
|
|
23
|
+
float?: 'left' | 'right';
|
|
24
|
+
children?: React.ReactNode;
|
|
25
|
+
} & {
|
|
26
|
+
as: 'button';
|
|
27
|
+
};
|
|
16
28
|
|
|
17
29
|
/**
|
|
18
30
|
* Props type for JRCStyledHref
|
|
19
|
-
* @
|
|
31
|
+
* @member as render the link styled as a button
|
|
20
32
|
*/
|
|
21
|
-
export type JRCStyledHrefProps = DataCy & React.ComponentPropsWithoutRef<'a'
|
|
33
|
+
export type JRCStyledHrefProps = DataCy & React.ComponentPropsWithoutRef<'a'> & (AnchorProps | ButtonProps);
|
|
22
34
|
|
|
23
|
-
|
|
35
|
+
const Href = styled.a.attrs<DataCy>(({ dataCy, ...props }) => ({
|
|
24
36
|
'data-cy': dataCy,
|
|
25
37
|
...props,
|
|
26
38
|
}))`
|
|
27
39
|
color: ${(props) => props.theme.font.hrefColor};
|
|
28
40
|
`;
|
|
29
41
|
|
|
42
|
+
export const JRCStyledHref = (props: JRCStyledHrefProps) => {
|
|
43
|
+
if (props.as === 'button') {
|
|
44
|
+
const { color = 'primary', variant = 'contained', ...restProps } = props;
|
|
45
|
+
const themeButton = BUTTON_CONFIG[variant][color];
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Button {...(restProps as any)} hasChildren={!!props.children} themeButton={themeButton} as="a">
|
|
49
|
+
{props.children}
|
|
50
|
+
</Button>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return <Href {...props} />;
|
|
55
|
+
};
|
|
56
|
+
|
|
30
57
|
export const JRCLinkToArticle = ({ idObject, href, children, ...props }: JRCLinkToProps) => (
|
|
31
|
-
<
|
|
58
|
+
<Href href={href ? href : `/article/${idObject}`} {...props}>
|
|
32
59
|
{children}
|
|
33
|
-
</
|
|
60
|
+
</Href>
|
|
34
61
|
);
|
|
35
62
|
|
|
36
63
|
export const JRCLinkToUser = ({ idObject, href, children, ...props }: JRCLinkToProps) => (
|
|
37
|
-
<
|
|
64
|
+
<Href href={href ? href : `/user/${idObject}`} {...props}>
|
|
38
65
|
{children}
|
|
39
|
-
</
|
|
66
|
+
</Href>
|
|
40
67
|
);
|