@mistertemp/libs-front-shared 1.1.1

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +18 -0
  3. package/index.ts +3 -0
  4. package/package.json +100 -0
  5. package/src/components/ControlledInputDate/ControlledInputDate.tsx +82 -0
  6. package/src/components/ControlledInputDate/__tests__/ControlledInputDate.unit.test.tsx +78 -0
  7. package/src/components/ControlledInputDate/index.ts +1 -0
  8. package/src/components/ControlledInputTime/ControlledInputTime.tsx +70 -0
  9. package/src/components/ControlledInputTime/__tests__/ControlledInputTime.unit.test.tsx +108 -0
  10. package/src/components/ControlledInputTime/index.ts +1 -0
  11. package/src/components/CopyToClipboard/CopyToClipboard.tsx +61 -0
  12. package/src/components/CopyToClipboard/__tests__/CopyToClipboard.unit.test.tsx +54 -0
  13. package/src/components/CopyToClipboard/index.ts +1 -0
  14. package/src/components/DateFilter/DateFilter.module.scss +4 -0
  15. package/src/components/DateFilter/DateFilter.tsx +117 -0
  16. package/src/components/DateFilter/DateFilter.utils.tsx +65 -0
  17. package/src/components/DateFilter/__tests__/DateFilter.unit.test.tsx +39 -0
  18. package/src/components/DateFilter/index.ts +1 -0
  19. package/src/components/EnvironmentFilter/EnvironmentFilter.tsx +74 -0
  20. package/src/components/EnvironmentFilter/__tests__/EnvironmentFilter.unit.test.tsx +99 -0
  21. package/src/components/EnvironmentFilter/index.ts +1 -0
  22. package/src/components/Filter/Filter.tsx +127 -0
  23. package/src/components/Filter/index.ts +1 -0
  24. package/src/components/ProfessionFilter/ProfessionFilter.module.scss +4 -0
  25. package/src/components/ProfessionFilter/ProfessionFilter.tsx +145 -0
  26. package/src/components/ProfessionFilter/__tests__/ProfessionFilter.unit.test.tsx +195 -0
  27. package/src/components/ProfessionFilter/index.ts +1 -0
  28. package/src/components/TextFilter/TextFilter.module.scss +3 -0
  29. package/src/components/TextFilter/TextFilter.tsx +112 -0
  30. package/src/components/TextFilter/__tests__/TextFilter.unit.test.tsx +75 -0
  31. package/src/components/TextFilter/index.ts +1 -0
  32. package/src/components/index.ts +8 -0
  33. package/src/hooks/index.ts +3 -0
  34. package/src/hooks/useBundledTranslation.ts +35 -0
  35. package/src/hooks/useDebouncedSearchInput.ts +36 -0
  36. package/src/hooks/usePrevious.ts +13 -0
  37. package/src/locales/fr/date-picker.json +11 -0
  38. package/src/locales/fr/scc-common-filters.json +22 -0
  39. package/src/locales/it/date-picker.json +11 -0
  40. package/src/locales/it/scc-common-filters.json +22 -0
  41. package/src/mocks/professions.ts +24 -0
  42. package/src/typings/filters.ts +7 -0
  43. package/src/typings/index.ts +1 -0
  44. package/tsconfig.json +25 -0
@@ -0,0 +1,195 @@
1
+ import { fireEvent, screen, waitFor } from '@testing-library/react';
2
+ import React from 'react';
3
+
4
+ import { render } from '../../../../.jest/reactTestingLibrary.config';
5
+ import { filterOptionsMock } from '../../../mocks/professions';
6
+ import { ProfessionFilter } from '../ProfessionFilter';
7
+
8
+ const baseProps = {
9
+ searchConfig: {
10
+ debounceDelay: 500,
11
+ forceEmptyValue: true,
12
+ inputThreshold: 2,
13
+ },
14
+ isLoading: false,
15
+ options: [],
16
+ };
17
+
18
+ describe('ProfessionFilter', () => {
19
+ beforeEach(() => {
20
+ jest.clearAllMocks();
21
+ });
22
+
23
+ describe('component rendering & prop options', () => {
24
+ it('should render filter and dropdown with empty list and search load state', async () => {
25
+ render(<ProfessionFilter {...baseProps} isLoading />);
26
+
27
+ expect(screen.getByTestId('filters+profession')).toBeInTheDocument();
28
+ expect(screen.getByTestId('filters+profession+trigger-button-title')).toHaveTextContent(
29
+ 'scc-common-filters:filters.profession.placeholder',
30
+ );
31
+
32
+ fireEvent.click(screen.getByTestId('filters+profession+trigger-button'));
33
+
34
+ expect(screen.getByTestId('filters+profession_popup')).toBeInTheDocument();
35
+ expect(screen.getByTestId('filters+profession-input-container')).toBeInTheDocument();
36
+ expect(screen.getByTestId('filters+profession+search_input')).toHaveProperty(
37
+ 'placeholder',
38
+ 'scc-common-filters:filters.profession.search.placeholder',
39
+ );
40
+ expect(screen.getByTestId('Loading-icon')).toBeInTheDocument();
41
+ expect(screen.getByTestId('filters+profession-bottom-action-button')).toHaveTextContent(
42
+ 'scc-common-filters:actions.removeFilter',
43
+ );
44
+ expect(
45
+ //eslint-disable-next-line testing-library/no-node-access
46
+ screen.getByTestId('filters+profession-options').children.length,
47
+ ).toBe(1);
48
+ });
49
+
50
+ it('should render custom cta title and placeholder', () => {
51
+ const placeholder = 'Custom placeholder';
52
+ const ctaTitle = 'Custom title';
53
+
54
+ render(
55
+ <ProfessionFilter {...baseProps} ctaTitle={ctaTitle} placeholder={placeholder} />,
56
+ );
57
+
58
+ expect(screen.getByTestId('filters+profession+trigger-button-title')).toHaveTextContent(
59
+ `${placeholder}`,
60
+ );
61
+
62
+ fireEvent.click(screen.getByTestId('filters+profession+trigger-button'));
63
+
64
+ expect(screen.getByTestId('filters+profession-bottom-action-button')).toHaveTextContent(
65
+ ctaTitle,
66
+ );
67
+ });
68
+
69
+ it('should display all profession options', async () => {
70
+ render(<ProfessionFilter {...baseProps} options={filterOptionsMock} />);
71
+
72
+ fireEvent.click(screen.getByTestId('filters+profession+trigger-button'));
73
+
74
+ filterOptionsMock
75
+ // We can't test everything because of the virtualizer
76
+ .slice(0, 6)
77
+ .forEach((option) => {
78
+ expect(
79
+ screen.getByTestId(`filters+profession_option_${option.id}`),
80
+ ).toBeInTheDocument();
81
+ });
82
+ });
83
+ });
84
+
85
+ describe('dropdown', () => {
86
+ const onChangeSelectedOptions = jest.fn();
87
+
88
+ it('should select two profession options', () => {
89
+ const { rerender } = render(
90
+ <ProfessionFilter
91
+ {...baseProps}
92
+ options={filterOptionsMock}
93
+ onChangeSelectedOptions={onChangeSelectedOptions}
94
+ />,
95
+ );
96
+
97
+ fireEvent.click(screen.getByTestId('filters+profession+trigger-button'));
98
+ fireEvent.click(
99
+ screen.getByTestId(
100
+ `filters+profession_${filterOptionsMock[0].id}_check_${filterOptionsMock[0].id}`,
101
+ ),
102
+ );
103
+ fireEvent.click(
104
+ screen.getByTestId(
105
+ `filters+profession_${filterOptionsMock[2].id}_check_${filterOptionsMock[2].id}`,
106
+ ),
107
+ );
108
+ // Dropdown needs to be closed for changes to propagate
109
+ fireEvent.click(screen.getByTestId('filters+profession+trigger-button'));
110
+
111
+ const selectedOptions = [filterOptionsMock[0], filterOptionsMock[2]];
112
+ const { dropdownValue, labels } = selectedOptions.reduce<{
113
+ dropdownValue: string[];
114
+ labels: string[];
115
+ }>(
116
+ (acc, { id, label }) => {
117
+ acc.dropdownValue.push(id);
118
+ acc.labels.push(label);
119
+
120
+ return acc;
121
+ },
122
+ { labels: [], dropdownValue: [] },
123
+ );
124
+
125
+ expect(onChangeSelectedOptions).toHaveBeenCalledWith(selectedOptions);
126
+
127
+ // New dropdownValue needs to loop back down from parent (usually a FilterGroup)
128
+ rerender(
129
+ <ProfessionFilter
130
+ {...baseProps}
131
+ options={filterOptionsMock}
132
+ dropdownValue={dropdownValue}
133
+ onChangeSelectedOptions={onChangeSelectedOptions}
134
+ />,
135
+ );
136
+
137
+ expect(screen.getByTestId('filters+profession+trigger-button-title')).toHaveTextContent(
138
+ `scc-common-filters:filters.profession.placeholder: ${labels.join(', ')}`,
139
+ );
140
+ });
141
+
142
+ it('should display default dropdown value without profession value (less or equal than min)', async () => {
143
+ const defaultValue = [filterOptionsMock[1]].map(({ id }) => id);
144
+
145
+ render(
146
+ <ProfessionFilter
147
+ {...baseProps}
148
+ dropdownValue={defaultValue}
149
+ options={filterOptionsMock}
150
+ onChangeSelectedOptions={onChangeSelectedOptions}
151
+ />,
152
+ );
153
+
154
+ expect(screen.getByTestId('filters+profession+trigger-button-title')).toHaveTextContent(
155
+ `scc-common-filters:filters.profession.placeholder: ${filterOptionsMock[1].label}`,
156
+ );
157
+ });
158
+ });
159
+
160
+ describe('search input', () => {
161
+ it('should trigger handler only if threshold is crossed', async () => {
162
+ const onChangeSearchText = jest.fn();
163
+ const searchText = 'fake search';
164
+
165
+ render(<ProfessionFilter {...baseProps} onChangeSearchText={onChangeSearchText} />);
166
+
167
+ fireEvent.click(screen.getByTestId('filters+profession+trigger-button'));
168
+ fireEvent.change(screen.getByTestId('filters+profession+search_input'), {
169
+ target: { value: searchText.slice(0, baseProps.searchConfig.inputThreshold) },
170
+ });
171
+ await waitFor(() => {
172
+ expect(onChangeSearchText).toHaveBeenNthCalledWith(1, '');
173
+ });
174
+ fireEvent.change(screen.getByTestId('filters+profession+search_input'), {
175
+ target: { value: searchText },
176
+ });
177
+ await waitFor(() => {
178
+ expect(onChangeSearchText).toHaveBeenNthCalledWith(2, searchText);
179
+ });
180
+ });
181
+ });
182
+
183
+ describe('CTA', () => {
184
+ it('should click on cta button', () => {
185
+ const onDropdownCTAClick = jest.fn();
186
+
187
+ render(<ProfessionFilter {...baseProps} onDropdownCTAClick={onDropdownCTAClick} />);
188
+
189
+ fireEvent.click(screen.getByTestId('filters+profession+trigger-button'));
190
+ fireEvent.click(screen.getByTestId('filters+profession-bottom-action-button'));
191
+
192
+ expect(onDropdownCTAClick).toHaveBeenCalled();
193
+ });
194
+ });
195
+ });
@@ -0,0 +1 @@
1
+ export * from './ProfessionFilter';
@@ -0,0 +1,3 @@
1
+ .inputContainer {
2
+ padding: var(--space-3) var(--space-4);
3
+ }
@@ -0,0 +1,112 @@
1
+ import {
2
+ Dropdown,
3
+ DropdownProps,
4
+ DropdownSelectorTrigger,
5
+ DropdownSelectorTriggerProps,
6
+ Input,
7
+ } from '@mistertemp/design-system';
8
+ import { InputTextProps } from '@mistertemp/design-system/src/components/design-system/Input/InputText';
9
+ import isEmpty from 'lodash/isEmpty';
10
+ import isString from 'lodash/isString';
11
+ import React, { useEffect, useState, VFC } from 'react';
12
+
13
+ import { useBundledTranslation } from '../../hooks';
14
+ import fr from '../../locales/fr/scc-common-filters.json';
15
+ import it from '../../locales/it/scc-common-filters.json';
16
+ import styles from './TextFilter.module.scss';
17
+
18
+ export type TextFilterProps = Omit<
19
+ DropdownProps<Record<string, string>>,
20
+ 'id' | 'dropdownValue' | 'onDropdownValueChanged' | 'trigger' | 'withCTA' | 'ctaTitle' | 'size'
21
+ > & {
22
+ name: string;
23
+ size?: 'small' | 'medium';
24
+ placeholder: string;
25
+ dropdownValue?: string;
26
+ onDropdownValueChanged?: (value: string | undefined) => void;
27
+ selectorProps?: Omit<
28
+ DropdownSelectorTriggerProps,
29
+ 'isSelected' | 'title' | 'data-testid' | 'disabled' | 'size'
30
+ >;
31
+ inputProps?: Omit<
32
+ InputTextProps,
33
+ | 'placeholder'
34
+ | 'data-testid'
35
+ | 'value'
36
+ | 'size'
37
+ | 'type'
38
+ | 'onSubmit'
39
+ | 'onChange'
40
+ | 'inputType'
41
+ >;
42
+ };
43
+
44
+ export const TextFilter: VFC<TextFilterProps> = ({
45
+ name,
46
+ placeholder,
47
+ dropdownValue,
48
+ onDropdownValueChanged,
49
+ 'data-testid': dataTestId = `filters+${name}`,
50
+ onOpenChange,
51
+ selectorProps,
52
+ inputProps,
53
+ size = 'small',
54
+ ...dropdownProps
55
+ }) => {
56
+ const { t } = useBundledTranslation('scc-common-filters', { fr, it });
57
+
58
+ const [inputValue, setInputValue] = useState('');
59
+
60
+ const triggerValueChanged = () => {
61
+ if (inputValue !== dropdownValue) {
62
+ onDropdownValueChanged?.(inputValue);
63
+ }
64
+ };
65
+
66
+ useEffect(() => {
67
+ setInputValue(isString(dropdownValue) ? dropdownValue : '');
68
+ }, [dropdownValue]);
69
+
70
+ const isValidValue = isString(dropdownValue) && !isEmpty(dropdownValue);
71
+
72
+ const displayedValue = isValidValue ? `${placeholder} : ${dropdownValue}` : placeholder;
73
+
74
+ return (
75
+ <Dropdown
76
+ trigger={
77
+ <DropdownSelectorTrigger
78
+ data-testid={`${dataTestId}+trigger`}
79
+ title={displayedValue}
80
+ isSelected={isValidValue}
81
+ disabled={dropdownProps.disabled}
82
+ size={size}
83
+ {...selectorProps}
84
+ />
85
+ }
86
+ data-testid={dataTestId}
87
+ dropdownValue={{ [name]: dropdownValue }}
88
+ onDropdownValueChanged={(value) => onDropdownValueChanged?.(value[name])}
89
+ withCTA
90
+ ctaTitle={t('scc-common-filters:actions.removeFilter')}
91
+ size={size}
92
+ onOpenChange={(isOpen) => {
93
+ onOpenChange?.(isOpen);
94
+ !isOpen && triggerValueChanged();
95
+ }}
96
+ {...dropdownProps}>
97
+ <div className={styles.inputContainer}>
98
+ <Input
99
+ data-testid={`${dataTestId}+input`}
100
+ value={inputValue}
101
+ size={size}
102
+ type="primary"
103
+ onSubmit={triggerValueChanged}
104
+ onChange={(e) => setInputValue(e.target.value ?? '')}
105
+ inputType="text"
106
+ withSubmitIcon={true}
107
+ {...inputProps}
108
+ />
109
+ </div>
110
+ </Dropdown>
111
+ );
112
+ };
@@ -0,0 +1,75 @@
1
+ import { fireEvent, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+
4
+ import { render } from '../../../../.jest/reactTestingLibrary.config';
5
+ import { TextFilter } from '../TextFilter';
6
+
7
+ describe('TextFilter', () => {
8
+ it('should have default value', () => {
9
+ render(<TextFilter name="test" placeholder="placeholder" dropdownValue="value1" />);
10
+
11
+ expect(screen.getByTestId('filters+test+trigger-button')).toHaveTextContent(
12
+ 'placeholder : value1',
13
+ );
14
+
15
+ fireEvent.click(screen.getByTestId('filters+test+trigger-button'));
16
+
17
+ expect(screen.getByTestId('filters+test+input_input')).toHaveValue('value1');
18
+ });
19
+
20
+ it('should handle submit', () => {
21
+ const onChange = jest.fn();
22
+
23
+ render(
24
+ <TextFilter
25
+ name="test"
26
+ placeholder="placeholder"
27
+ dropdownValue="value1"
28
+ onDropdownValueChanged={onChange}
29
+ />,
30
+ );
31
+
32
+ fireEvent.click(screen.getByTestId('filters+test+trigger-button'));
33
+
34
+ const input = screen.getByTestId('filters+test+input_input');
35
+
36
+ expect(input).toHaveValue('value1');
37
+
38
+ fireEvent.change(input, {
39
+ target: { value: 'value2' },
40
+ });
41
+
42
+ expect(input).toHaveValue('value2');
43
+
44
+ fireEvent.click(screen.getByTestId('filters+test+input_icon-button'));
45
+
46
+ expect(onChange).toHaveBeenLastCalledWith('value2');
47
+ });
48
+
49
+ it('should trigger change on close', () => {
50
+ const onChange = jest.fn();
51
+
52
+ render(
53
+ <TextFilter
54
+ name="test"
55
+ placeholder="placeholder"
56
+ dropdownValue="value1"
57
+ onDropdownValueChanged={onChange}
58
+ />,
59
+ );
60
+
61
+ const trigger = screen.getByTestId('filters+test+trigger-button');
62
+
63
+ fireEvent.click(trigger);
64
+
65
+ const input = screen.getByTestId('filters+test+input_input');
66
+
67
+ expect(input).toHaveValue('value1');
68
+
69
+ fireEvent.change(input, { target: { value: 'value2' } });
70
+
71
+ fireEvent.click(trigger);
72
+
73
+ expect(onChange).toHaveBeenLastCalledWith('value2');
74
+ });
75
+ });
@@ -0,0 +1 @@
1
+ export * from './TextFilter';
@@ -0,0 +1,8 @@
1
+ export * from './ControlledInputDate';
2
+ export * from './ControlledInputTime';
3
+ export * from './CopyToClipboard';
4
+ export * from './DateFilter';
5
+ export * from './EnvironmentFilter';
6
+ export * from './Filter';
7
+ export * from './ProfessionFilter';
8
+ export * from './TextFilter';
@@ -0,0 +1,3 @@
1
+ export * from './useBundledTranslation';
2
+ export * from './useDebouncedSearchInput';
3
+ export * from './usePrevious';
@@ -0,0 +1,35 @@
1
+ import type { KeyPrefix, Namespace, TFunction } from 'i18next';
2
+ import { useEffect, useState } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+
5
+ export type UseBundedTranslationResponse<N extends Namespace, TKPrefix> = {
6
+ t: TFunction<N, TKPrefix> | ((key: string) => string);
7
+ isReady: boolean;
8
+ };
9
+
10
+ export const useBundledTranslation = <
11
+ N extends Namespace,
12
+ TKPrefix extends KeyPrefix<N> = undefined,
13
+ >(
14
+ namespace: N | Readonly<N>,
15
+ translations: Record<string, unknown>,
16
+ ): UseBundedTranslationResponse<N, TKPrefix> => {
17
+ const { i18n, t, ready: initReady } = useTranslation<N, TKPrefix>();
18
+ const [isBundleAdded, setIsBundleAdded] = useState(false);
19
+
20
+ const ready = initReady && isBundleAdded;
21
+
22
+ useEffect(() => {
23
+ if (i18n.language) {
24
+ const lang = i18n.language.slice(0, 2);
25
+
26
+ if (!i18n.hasResourceBundle(lang, namespace as string) && lang in translations) {
27
+ i18n.addResourceBundle(lang, namespace as string, translations[lang]);
28
+ }
29
+ setIsBundleAdded(true);
30
+ }
31
+ }, [i18n, namespace, ready, translations]);
32
+
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ return { t: ready ? t : (key: any) => key, isReady: ready };
35
+ };
@@ -0,0 +1,36 @@
1
+ import { useDebounce } from '@mistertemp/design-system';
2
+ import { useMemo } from 'react';
3
+
4
+ import { usePrevious } from './usePrevious';
5
+
6
+ export type DebouncedSearchConfig = {
7
+ debounceDelay?: number;
8
+ forceEmptyValue?: boolean;
9
+ inputThreshold?: number;
10
+ };
11
+
12
+ export function useDebouncedSearchInput(
13
+ inputValue: string,
14
+ config?: DebouncedSearchConfig,
15
+ ): string {
16
+ const debouncedInputValue = useDebounce(inputValue, config?.debounceDelay ?? 100);
17
+ const previousInputValue = usePrevious(debouncedInputValue);
18
+
19
+ const searchValue = useMemo(() => {
20
+ const threshold = config?.inputThreshold ?? 2;
21
+
22
+ if (debouncedInputValue.length > threshold) {
23
+ return debouncedInputValue;
24
+ } else if (
25
+ config?.forceEmptyValue &&
26
+ debouncedInputValue.length <= threshold &&
27
+ (previousInputValue === undefined || previousInputValue.length > threshold)
28
+ ) {
29
+ return '';
30
+ }
31
+
32
+ return previousInputValue;
33
+ }, [debouncedInputValue, previousInputValue, config?.inputThreshold, config?.forceEmptyValue]);
34
+
35
+ return searchValue ?? '';
36
+ }
@@ -0,0 +1,13 @@
1
+ import { useRef } from 'react';
2
+
3
+ export const usePrevious = <T>(value: T) => {
4
+ const currentRef = useRef<T>(value);
5
+ const previousRef = useRef<T>();
6
+
7
+ if (currentRef.current !== value) {
8
+ previousRef.current = currentRef.current;
9
+ currentRef.current = value;
10
+ }
11
+
12
+ return previousRef.current;
13
+ };
@@ -0,0 +1,11 @@
1
+ {
2
+ "modes": {
3
+ "single": "Jour",
4
+ "multiple": "Jours",
5
+ "range": "Période"
6
+ },
7
+ "actions": {
8
+ "validate": "Valider",
9
+ "cancel": "Annuler"
10
+ }
11
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "filters": {
3
+ "profession": {
4
+ "label": "Qualification",
5
+ "placeholder": "Qualification",
6
+ "search": {
7
+ "placeholder": "Rechercher une qualification"
8
+ }
9
+ },
10
+ "environment": {
11
+ "placeholder": "Environment"
12
+ },
13
+ "date": {
14
+ "placeholder": "Date"
15
+ },
16
+ "noResult": "Pas de résultat"
17
+ },
18
+ "actions": {
19
+ "removeFilter": "Supprimer le filtre",
20
+ "resetFilter": "Réinitialiser le filtre"
21
+ }
22
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "modes": {
3
+ "single": "Giorno",
4
+ "multiple": "Giorni",
5
+ "range": "Periodo"
6
+ },
7
+ "actions": {
8
+ "validate": "Convalidare",
9
+ "cancel": "Annullare"
10
+ }
11
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "filters": {
3
+ "profession": {
4
+ "label": "Qualificazione",
5
+ "placeholder": "Qualificazione",
6
+ "search": {
7
+ "placeholder": "Rechercher una qualificazione"
8
+ }
9
+ },
10
+ "environment": {
11
+ "placeholder": "Ambiente"
12
+ },
13
+ "date": {
14
+ "placeholder": "Data"
15
+ },
16
+ "noResult": "Nessun risultato"
17
+ },
18
+ "actions": {
19
+ "removeFilter": "Rimuovi il filtro",
20
+ "resetFilter": "Reimposta filtro"
21
+ }
22
+ }
@@ -0,0 +1,24 @@
1
+ import { FilterDropdownOption } from '../components';
2
+
3
+ export const filterOptionsMock: FilterDropdownOption[] = [
4
+ { id: '00270025-6f9e-4e98-83da-4e7c9409653a', label: 'Webmaster' },
5
+ { id: '21960b88-c606-4daa-b100-1fbc88834f7d', label: 'Carreleur' },
6
+ { id: '006ff3e2-3ad7-4180-bba1-c3e19c847bf2', label: 'Jointeur' },
7
+ { id: '0e5482de-f123-45b2-b2d7-41ba0d85300c', label: 'Valet de chambre' },
8
+ { id: '126db8fc-27c5-4aaf-8d7e-75e23a4b2f59', label: 'Chocolatier' },
9
+ { id: '13cfe3f8-717f-4609-aa42-76f8896f5e69', label: 'Charpentier industriel' },
10
+ { id: '092f2514-de90-4ce4-934d-eb71453325e0', label: 'Dessinateur en construction métallique' },
11
+ { id: '0974d4f2-e245-4e77-ac67-47f10888baed', label: 'Maroquinier industriel' },
12
+ { id: '0f37e3e0-f4f8-40d9-a27b-fdf41e371fb8', label: 'Règleur de machine de production' },
13
+ { id: '0faf2779-fb6d-4648-90f6-427ce10ff19f', label: 'Maraîcher' },
14
+ {
15
+ id: '117124f1-4699-44dd-8e8a-4e7a48445c47',
16
+ label: "Gestionnaire de l'administration du personnel",
17
+ },
18
+ { id: '0e4e9f86-eb76-4897-ae67-abc1b972b8e7', label: "Chargé d'affaires en industrie" },
19
+ { id: '10fbc798-bae7-4f57-bac1-ce6ea4d026f9', label: 'Conducteur de tombereau' },
20
+ { id: '14c12ca9-2a5e-4294-8f47-17fe03305754', label: 'Conducteur PL' },
21
+ { id: '156121c5-e766-4de7-af79-4b1858d482e2', label: 'Gardien-Conciergerie' },
22
+ { id: '0804eb04-21df-4fda-a2be-a7a470e7e9cb', label: 'Masseur kinésithérapeute' },
23
+ { id: '09f1f51c-9cc1-48bb-95f7-ae693eb76103', label: 'Vendeur en prêt-à-porter' },
24
+ ];
@@ -0,0 +1,7 @@
1
+ import { DebouncedSearchConfig } from '../hooks';
2
+
3
+ export type SearchableFilterProps = {
4
+ isLoading?: boolean;
5
+ onChangeSearchText?: (text: string) => void;
6
+ searchConfig: DebouncedSearchConfig;
7
+ };
@@ -0,0 +1 @@
1
+ export * from './filters';
package/tsconfig.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "include": ["./src", "./.jest", "./demo", "index.d.ts", "index.ts"],
3
+ "exclude": ["node_modules", ".jest"],
4
+ "compilerOptions": {
5
+ "target": "ESNext",
6
+ "useDefineForClassFields": true,
7
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
8
+ "allowJs": false,
9
+ "skipLibCheck": true,
10
+ "esModuleInterop": true,
11
+ "allowSyntheticDefaultImports": true,
12
+ "strict": true,
13
+ "strictNullChecks": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "module": "ESNext",
16
+ "moduleResolution": "Node",
17
+ "resolveJsonModule": true,
18
+ "isolatedModules": true,
19
+ "noEmit": true,
20
+ "jsx": "react-jsx",
21
+ "noImplicitAny": true,
22
+ "types": ["node", "jest"],
23
+ "typeRoots": ["./node_modules/@types"]
24
+ }
25
+ }