@ftdata/ui 0.0.16 → 0.0.18
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/dist/components/IconButton/index.d.ts +15 -0
- package/dist/components/IconButton/index.js +37 -0
- package/dist/components/IconButton/modifiers/color.d.ts +36 -0
- package/dist/components/IconButton/modifiers/color.js +38 -0
- package/dist/components/IconButton/styles.d.ts +10 -0
- package/dist/components/IconButton/styles.js +32 -0
- package/dist/components/Input/index.d.ts +1 -0
- package/dist/components/Input/index.js +12 -26
- package/dist/components/Input/styles.js +1 -1
- package/dist/components/Modal/index.d.ts +25 -0
- package/dist/components/Modal/index.js +69 -0
- package/dist/components/Modal/styles.d.ts +8 -0
- package/dist/components/Modal/styles.js +81 -0
- package/dist/components/MultiSelect/components/Badge/index.d.ts +2 -1
- package/dist/components/MultiSelect/components/Badge/index.js +5 -2
- package/dist/components/MultiSelect/components/Badge/styles.d.ts +5 -1
- package/dist/components/MultiSelect/components/Badge/styles.js +2 -1
- package/dist/components/MultiSelect/components/MultiSelectList/Row/index.d.ts +3 -2
- package/dist/components/MultiSelect/components/MultiSelectList/Row/index.js +21 -10
- package/dist/components/MultiSelect/components/MultiSelectList/Row/style.js +0 -1
- package/dist/components/MultiSelect/components/MultiSelectList/index.d.ts +3 -3
- package/dist/components/MultiSelect/components/MultiSelectList/index.js +8 -11
- package/dist/components/MultiSelect/components/MultiSelectList/style.d.ts +1 -1
- package/dist/components/MultiSelect/components/MultiSelectList/style.js +21 -3
- package/dist/components/MultiSelect/helpers/addOption.d.ts +3 -3
- package/dist/components/MultiSelect/helpers/computeUnselected.d.ts +1 -1
- package/dist/components/MultiSelect/helpers/computeUnselected.js +1 -1
- package/dist/components/MultiSelect/helpers/feedbackText.d.ts +1 -1
- package/dist/components/MultiSelect/helpers/feedbackText.js +9 -9
- package/dist/components/MultiSelect/helpers/filterOptions.d.ts +1 -1
- package/dist/components/MultiSelect/helpers/removeOptions.d.ts +3 -3
- package/dist/components/MultiSelect/index.d.ts +37 -19
- package/dist/components/MultiSelect/index.js +92 -135
- package/dist/components/MultiSelect/styles.js +8 -23
- package/dist/components/Select/index.d.ts +2 -1
- package/dist/components/Select/index.js +12 -24
- package/dist/components/Select/styles.js +1 -1
- package/dist/components/Texts/paragraphs.d.ts +12 -0
- package/dist/components/Texts/paragraphs.js +14 -0
- package/dist/components/Texts/text.d.ts +17 -0
- package/dist/components/Texts/text.js +21 -0
- package/dist/components/Texts/titles.d.ts +7 -0
- package/dist/components/Texts/titles.js +37 -0
- package/dist/components/fields/components/HelpText/index.js +18 -13
- package/dist/components/fields/components/HelpText/modifiers/colors.js +2 -2
- package/dist/components/fields/components/HelpText/styles.js +5 -0
- package/dist/components/fields/components/Label/index.js +1 -1
- package/dist/components/fields/components/Label/styles.js +11 -4
- package/dist/components/fields/modifiers/selectColorModifier.d.ts +1 -1
- package/dist/components/fields/modifiers/selectColorModifier.js +7 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -2
- package/package.json +2 -2
- package/dist/components/MultiSelect/helpers/arraysEqual.d.ts +0 -2
- package/dist/components/MultiSelect/helpers/arraysEqual.js +0 -5
- package/dist/components/MultiSelect/helpers/computeSelected.d.ts +0 -2
- package/dist/components/MultiSelect/helpers/computeSelected.js +0 -2
- package/dist/components/MultiSelect/helpers/getChangedFieds.d.ts +0 -2
- package/dist/components/MultiSelect/helpers/getChangedFieds.js +0 -17
- package/dist/components/MultiSelect/hooks/useMultiSelect.d.ts +0 -10
- package/dist/components/MultiSelect/hooks/useMultiSelect.js +0 -44
- package/dist/components/MultiSelect/interfaces/actions.d.ts +0 -4
- package/dist/components/MultiSelect/interfaces/actions.js +0 -0
- package/dist/components/MultiSelect/interfaces/config.d.ts +0 -17
- package/dist/components/MultiSelect/interfaces/config.js +0 -0
- package/dist/components/MultiSelect/interfaces/state.d.ts +0 -10
- package/dist/components/MultiSelect/interfaces/state.js +0 -0
- package/dist/components/MultiSelect/reducers/stateReducer.d.ts +0 -21
- package/dist/components/MultiSelect/reducers/stateReducer.js +0 -44
- package/dist/components/Text/Paragraph/Paragraph.stories.d.ts +0 -29
- package/dist/components/Text/Paragraph/Paragraph.stories.js +0 -124
- package/dist/components/Text/Title/Title.stories.d.ts +0 -41
- package/dist/components/Text/Title/Title.stories.js +0 -106
|
@@ -1,5 +1,21 @@
|
|
|
1
|
-
import styled_components from "styled-components";
|
|
1
|
+
import styled_components, { keyframes } from "styled-components";
|
|
2
2
|
import { COLOR_ACCENT_MEDIUM, COLOR_NEUTRAL_DAY, COLOR_NEUTRAL_DUSK, FONT_WEIGHT_BOLD } from "@ftdata/f-tokens";
|
|
3
|
+
const slideDown = keyframes`
|
|
4
|
+
0% {
|
|
5
|
+
transform: translateY(-0.25rem);
|
|
6
|
+
}
|
|
7
|
+
100% {
|
|
8
|
+
transform: translateY(0);
|
|
9
|
+
}
|
|
10
|
+
`;
|
|
11
|
+
const slideUp = keyframes`
|
|
12
|
+
0% {
|
|
13
|
+
transform: translateY(0.25rem);
|
|
14
|
+
}
|
|
15
|
+
100% {
|
|
16
|
+
transform: translateY(0);
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
3
19
|
const SelectDropdown = styled_components.div`
|
|
4
20
|
background-color: ${COLOR_NEUTRAL_DAY};
|
|
5
21
|
border-radius: 0.25rem;
|
|
@@ -11,8 +27,10 @@ const SelectDropdown = styled_components.div`
|
|
|
11
27
|
height: auto;
|
|
12
28
|
z-index: 3;
|
|
13
29
|
|
|
14
|
-
|
|
15
|
-
|
|
30
|
+
animation: ${({ listPosition })=>"top" === listPosition ? slideUp : slideDown}
|
|
31
|
+
0.18s ease-out;
|
|
32
|
+
top: ${({ listPosition })=>"top" === listPosition ? "auto" : "calc(100% + 0.5rem)"};
|
|
33
|
+
bottom: ${({ listPosition })=>"top" === listPosition ? "calc(100% + 0.5rem)" : "auto"};
|
|
16
34
|
|
|
17
35
|
& > div {
|
|
18
36
|
border-radius: 0.25rem;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { IMultiSelectOption } from "
|
|
1
|
+
import { IMultiSelectOption } from "..";
|
|
2
2
|
export declare const addOption: (selected: IMultiSelectOption[], options: IMultiSelectOption[], option: IMultiSelectOption, max?: number) => {
|
|
3
|
-
selected:
|
|
4
|
-
unselected:
|
|
3
|
+
selected: import("../../Select").ISelectOption[];
|
|
4
|
+
unselected: import("../../Select").ISelectOption[];
|
|
5
5
|
} | undefined;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { IMultiSelectOption } from "
|
|
1
|
+
import { IMultiSelectOption } from "..";
|
|
2
2
|
export declare const computeUnselected: (options: IMultiSelectOption[], selected: IMultiSelectOption[]) => IMultiSelectOption[];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const computeUnselected = (options, selected)=>options.filter((opt)=>!selected.some((
|
|
1
|
+
const computeUnselected = (options, selected)=>options.filter((opt)=>!selected.some((selected)=>selected.value === opt.value));
|
|
2
2
|
export { computeUnselected };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IMultiSelectOption } from "
|
|
1
|
+
import { IMultiSelectOption } from "..";
|
|
2
2
|
export declare function feedbackText(translation: (key: string) => string, options: IMultiSelectOption[], filtered: IMultiSelectOption[], selected: IMultiSelectOption[], query: string, max?: number): {
|
|
3
3
|
value: string;
|
|
4
4
|
label: string;
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { computeUnselected } from "./computeUnselected.js";
|
|
2
2
|
function feedbackText(translation, options, filtered, selected, query, max) {
|
|
3
|
-
if (!options.length) return [
|
|
4
|
-
{
|
|
5
|
-
value: "feedback__",
|
|
6
|
-
label: translation("no_data_is_available")
|
|
7
|
-
}
|
|
8
|
-
];
|
|
9
3
|
if (max && selected.length >= max) return [
|
|
10
4
|
{
|
|
11
|
-
value: "
|
|
5
|
+
value: "__feedback",
|
|
12
6
|
label: translation("the_selection_limit_has_been_reached")
|
|
13
7
|
}
|
|
14
8
|
];
|
|
15
9
|
if (query && !filtered.length) return [
|
|
16
10
|
{
|
|
17
|
-
value: "
|
|
11
|
+
value: "__feedback",
|
|
18
12
|
label: translation("no_data_was_found")
|
|
19
13
|
}
|
|
20
14
|
];
|
|
15
|
+
if (!options.length) return [
|
|
16
|
+
{
|
|
17
|
+
value: "__feedback",
|
|
18
|
+
label: translation("no_data_is_available")
|
|
19
|
+
}
|
|
20
|
+
];
|
|
21
21
|
const unselected = computeUnselected(options, selected);
|
|
22
22
|
if (!query && !unselected.length) return [
|
|
23
23
|
{
|
|
24
|
-
value: "
|
|
24
|
+
value: "__feedback",
|
|
25
25
|
label: translation("all_were_selected")
|
|
26
26
|
}
|
|
27
27
|
];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { IMultiSelectOption } from "
|
|
1
|
+
import { IMultiSelectOption } from "..";
|
|
2
2
|
export declare const filterOptions: (options: IMultiSelectOption[], query: string) => IMultiSelectOption[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { IMultiSelectOption } from "
|
|
1
|
+
import { IMultiSelectOption } from "..";
|
|
2
2
|
export declare const removeOption: (selected: IMultiSelectOption[], options: IMultiSelectOption[], option: IMultiSelectOption) => {
|
|
3
|
-
selected:
|
|
4
|
-
unselected:
|
|
3
|
+
selected: import("../../Select").ISelectOption[];
|
|
4
|
+
unselected: import("../../Select").ISelectOption[];
|
|
5
5
|
};
|
|
@@ -1,28 +1,46 @@
|
|
|
1
1
|
import { InputHTMLAttributes, JSX } from "react";
|
|
2
|
-
import { FieldFeedbackType } from "../../types/feedback";
|
|
3
2
|
import { IconsNames } from "@ftdata/f-icons";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
helpIcon?: IconsNames;
|
|
10
|
-
icon?: IconsNames | JSX.Element;
|
|
11
|
-
rightItem?: JSX.Element;
|
|
3
|
+
import { FieldFeedbackType } from "../../types/feedback";
|
|
4
|
+
import { ISelectOption } from "../Select";
|
|
5
|
+
export type IMultiSelectOption = ISelectOption;
|
|
6
|
+
export interface MultiSelectProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
7
|
+
/** Texto do label exibido acima do campo. */
|
|
12
8
|
label?: string;
|
|
9
|
+
/** Texto auxiliar exibido abaixo do label. */
|
|
13
10
|
sublabel?: string;
|
|
11
|
+
/** Texto de ajuda exibido abaixo do campo. */
|
|
12
|
+
helpText?: string;
|
|
13
|
+
/** Ícone exibido junto ao texto de ajuda. */
|
|
14
|
+
helpIcon?: IconsNames;
|
|
15
|
+
/** Estado de feedback visual do campo (ex.: erro, sucesso, aviso). */
|
|
14
16
|
feedback?: FieldFeedbackType;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
translation: (key: string) => string;
|
|
21
|
-
max?: number;
|
|
17
|
+
/** Define se o campo está desabilitado. */
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
/** Quantidade máxima de itens que podem ser selecionados. */
|
|
20
|
+
maxItems?: number;
|
|
21
|
+
/** Define se a opção "Selecionar todos" deve ser exibida. */
|
|
22
22
|
selectAll?: boolean;
|
|
23
|
-
|
|
23
|
+
/** Define se a lista de opções está em estado de carregamento. */
|
|
24
|
+
isLoading?: boolean;
|
|
25
|
+
/** Lista de opções disponíveis para seleção. */
|
|
26
|
+
options: IMultiSelectOption[];
|
|
27
|
+
/** Lista de opções atualmente selecionadas. */
|
|
28
|
+
selected: IMultiSelectOption[];
|
|
29
|
+
/** Função chamada sempre que a lista de selecionados for alterada. */
|
|
30
|
+
onChangeSelected: (selected: IMultiSelectOption[]) => void;
|
|
31
|
+
/** Função usada para traduzir textos internos do componente. */
|
|
32
|
+
translation: (key: string) => string;
|
|
33
|
+
/** Função chamada ao digitar no campo de busca. */
|
|
34
|
+
onSearch?: (query: string) => void;
|
|
35
|
+
/** Função chamada ao solicitar mais itens (scroll infinito/paginação). */
|
|
24
36
|
onLoadMore?: () => Promise<void>;
|
|
37
|
+
/** Ícone exibido à esquerda do input. Pode ser `IconName` ou JSX. */
|
|
38
|
+
icon?: IconsNames | JSX.Element;
|
|
39
|
+
/** Define o estilo do componente. `alt` mostra caret, `default` não. */
|
|
40
|
+
variant?: "default" | "alt";
|
|
41
|
+
/** Define a posição da lista do componente */
|
|
42
|
+
listPosition?: "top" | "bottom";
|
|
43
|
+
/** Executa junto com o toggle da lista */
|
|
25
44
|
toggle?: (open: boolean) => void;
|
|
26
|
-
dropdownPosition?: "top" | "bottom";
|
|
27
45
|
}
|
|
28
|
-
export default function MultiSelect({
|
|
46
|
+
export default function MultiSelect({ label, sublabel, helpText, helpIcon, feedback, disabled, maxItems, selectAll, isLoading, options, selected, onChangeSelected, translation, onSearch, onLoadMore, placeholder, required, name, icon, listPosition, toggle, variant, }: MultiSelectProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,152 +1,111 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { BadgesContainer, LabelContainer, MaxItemsIndicator, MultiSelectContainer, MultiSelectWrapper, ResizableInput } from "./styles.js";
|
|
4
|
+
import Badge from "./components/Badge/index.js";
|
|
5
|
+
import MultiSelectList from "./components/MultiSelectList/index.js";
|
|
6
|
+
import HelpText from "../fields/components/HelpText/index.js";
|
|
4
7
|
import Label from "../fields/components/Label/index.js";
|
|
5
|
-
import { getHelpTextFeedbackType } from "../fields/helpers/getFeedbackType.js";
|
|
6
8
|
import { Icon } from "@ftdata/f-icons";
|
|
7
|
-
import HelpText from "../fields/components/HelpText/index.js";
|
|
8
|
-
import MultiSelectList from "./components/MultiSelectList/index.js";
|
|
9
|
-
import Badge from "./components/Badge/index.js";
|
|
10
|
-
import { addOption } from "./helpers/addOption.js";
|
|
11
|
-
import { removeOption } from "./helpers/removeOptions.js";
|
|
12
|
-
import { computeUnselected } from "./helpers/computeUnselected.js";
|
|
13
|
-
import { filterOptions } from "./helpers/filterOptions.js";
|
|
14
9
|
import { feedbackText } from "./helpers/feedbackText.js";
|
|
15
|
-
import {
|
|
16
|
-
import RotateButton from "../fields/components/RotateButton/index.js";
|
|
10
|
+
import { filterOptions } from "./helpers/filterOptions.js";
|
|
17
11
|
import calcTextSize from "./helpers/calcTextSize.js";
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
import RotateButton from "../fields/components/RotateButton/index.js";
|
|
13
|
+
import { COLOR_NEUTRAL_MEDIUM } from "@ftdata/f-tokens";
|
|
14
|
+
function MultiSelect({ label, sublabel, helpText, helpIcon, feedback, disabled, maxItems, selectAll, isLoading, options, selected, onChangeSelected, translation, onSearch, onLoadMore, placeholder, required, name, icon, listPosition, toggle, variant = "default" }) {
|
|
20
15
|
const [query, setQuery] = useState("");
|
|
16
|
+
const [showList, setShowList] = useState(false);
|
|
21
17
|
const [inputSize, setInputSize] = useState(0);
|
|
22
18
|
const inputRef = useRef(null);
|
|
23
19
|
const containerRef = useRef(null);
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
const unselected = useMemo(()=>options.filter((o)=>!selected.some((s)=>s.value === o.value)), [
|
|
21
|
+
options,
|
|
22
|
+
selected
|
|
23
|
+
]);
|
|
24
|
+
const canShowSelectAll = useMemo(()=>{
|
|
25
|
+
if (!selectAll) return false;
|
|
26
|
+
if (disabled) return false;
|
|
27
|
+
if (selected.length === options.length) return false;
|
|
28
|
+
if (query) return false;
|
|
29
|
+
if (maxItems && selected.length >= maxItems) return false;
|
|
30
|
+
return true;
|
|
31
|
+
}, [
|
|
32
|
+
selectAll,
|
|
33
|
+
selected,
|
|
34
|
+
options,
|
|
35
|
+
query,
|
|
36
|
+
maxItems,
|
|
37
|
+
disabled
|
|
38
|
+
]);
|
|
39
|
+
const filtered = useMemo(()=>{
|
|
40
|
+
if (!query) return unselected;
|
|
41
|
+
return filterOptions(unselected, query);
|
|
42
|
+
}, [
|
|
43
|
+
query,
|
|
44
|
+
unselected
|
|
45
|
+
]);
|
|
46
|
+
const addOption = (option)=>{
|
|
47
|
+
if ("__feedback" === option.value || disabled) return;
|
|
48
|
+
if (maxItems && selected.length >= maxItems) return;
|
|
49
|
+
onChangeSelected([
|
|
50
|
+
...selected,
|
|
51
|
+
option
|
|
52
|
+
]);
|
|
28
53
|
setQuery("");
|
|
29
|
-
setInputSize(1);
|
|
30
|
-
updateState({
|
|
31
|
-
...result,
|
|
32
|
-
filtered: []
|
|
33
|
-
});
|
|
34
|
-
inputRef.current?.focus();
|
|
35
54
|
};
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
55
|
+
const toggleList = (event)=>{
|
|
56
|
+
event.stopPropagation();
|
|
57
|
+
setShowList((prev)=>!prev);
|
|
58
|
+
};
|
|
59
|
+
const removeOption = (option)=>{
|
|
60
|
+
if (disabled) return;
|
|
61
|
+
onChangeSelected(selected.filter((o)=>o.value !== option.value));
|
|
42
62
|
};
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
63
|
+
const clearAll = ()=>onChangeSelected([]);
|
|
64
|
+
const handleAddAll = ()=>{
|
|
65
|
+
maxItems ? onChangeSelected(options.slice(0, maxItems)) : onChangeSelected(options);
|
|
66
|
+
};
|
|
67
|
+
const handleClickContainer = ()=>{
|
|
68
|
+
if (!disabled) {
|
|
69
|
+
if (inputRef.current) inputRef.current.focus();
|
|
70
|
+
setShowList(true);
|
|
71
|
+
}
|
|
46
72
|
};
|
|
47
73
|
const handleChange = (event)=>{
|
|
48
74
|
const value = event.target.value;
|
|
49
75
|
setQuery(value);
|
|
50
76
|
const textStyle = "500 14px Inter";
|
|
51
|
-
const
|
|
52
|
-
if (
|
|
53
|
-
if (
|
|
54
|
-
filtered: []
|
|
55
|
-
});
|
|
56
|
-
if (actions?.search) return void actions.search(value);
|
|
57
|
-
updateState({
|
|
58
|
-
filtered: filterOptions(computeUnselected(options, selected), value)
|
|
59
|
-
});
|
|
77
|
+
const newSize = calcTextSize(value, textStyle, "rem");
|
|
78
|
+
if (newSize) setInputSize(newSize);
|
|
79
|
+
if (onSearch) onSearch(value);
|
|
60
80
|
};
|
|
61
81
|
const handleKeyDown = (event)=>{
|
|
62
|
-
|
|
63
|
-
if ("
|
|
64
|
-
|
|
65
|
-
if (available[0]) handleAddOption(available[0]);
|
|
66
|
-
}
|
|
82
|
+
event.stopPropagation();
|
|
83
|
+
if ("Backspace" === event.key && !query && selected.length) removeOption(selected[selected.length - 1]);
|
|
84
|
+
if ("Enter" === event.key && filtered[0]) addOption(filtered[0]);
|
|
67
85
|
};
|
|
68
86
|
const currentDataOptions = useMemo(()=>{
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
87
|
+
const fb = feedbackText(translation, options, filtered, selected, query, maxItems);
|
|
88
|
+
if (fb.length) return fb;
|
|
71
89
|
if (filtered.length) return filtered;
|
|
72
|
-
return
|
|
90
|
+
return unselected;
|
|
73
91
|
}, [
|
|
74
|
-
query,
|
|
75
92
|
filtered,
|
|
76
93
|
selected,
|
|
77
|
-
options,
|
|
78
|
-
max
|
|
79
|
-
]);
|
|
80
|
-
const handleClickOutside = (event)=>{
|
|
81
|
-
if (containerRef.current && !containerRef.current.contains(event.target)) setShowList(false);
|
|
82
|
-
};
|
|
83
|
-
const clearSelected = ()=>updateState({
|
|
84
|
-
selected: []
|
|
85
|
-
});
|
|
86
|
-
const handleAddAll = (event)=>{
|
|
87
|
-
event.preventDefault();
|
|
88
|
-
if (max) {
|
|
89
|
-
if (selected.length) {
|
|
90
|
-
const index = selected.length - max;
|
|
91
|
-
const toAdd = unselected.slice(0, index);
|
|
92
|
-
updateState({
|
|
93
|
-
selected: [
|
|
94
|
-
...selected,
|
|
95
|
-
...toAdd
|
|
96
|
-
],
|
|
97
|
-
unselected: []
|
|
98
|
-
});
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
updateState({
|
|
102
|
-
selected: options.slice(0, max),
|
|
103
|
-
unselected: []
|
|
104
|
-
});
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
updateState({
|
|
108
|
-
selected: options,
|
|
109
|
-
unselected: []
|
|
110
|
-
});
|
|
111
|
-
};
|
|
112
|
-
const canShowSelectAll = useMemo(()=>{
|
|
113
|
-
if (!selectAll) return;
|
|
114
|
-
if (selected.length === total || selected.length === options.length) return;
|
|
115
|
-
if (query) return;
|
|
116
|
-
if (max && max === selected.length) return;
|
|
117
|
-
return handleAddAll;
|
|
118
|
-
}, [
|
|
119
94
|
query,
|
|
120
|
-
filtered,
|
|
121
|
-
selected,
|
|
122
95
|
options,
|
|
123
|
-
|
|
96
|
+
maxItems
|
|
124
97
|
]);
|
|
125
98
|
useEffect(()=>{
|
|
99
|
+
if (toggle) toggle(showList);
|
|
100
|
+
const handleClickOutside = (e)=>{
|
|
101
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) setShowList(false);
|
|
102
|
+
};
|
|
126
103
|
if (showList) document.addEventListener("mousedown", handleClickOutside);
|
|
127
104
|
return ()=>document.removeEventListener("mousedown", handleClickOutside);
|
|
128
105
|
}, [
|
|
129
106
|
showList
|
|
130
107
|
]);
|
|
131
|
-
const feedBackHelpText = getHelpTextFeedbackType(feedback, disabled);
|
|
132
|
-
const toggleList = (event)=>{
|
|
133
|
-
event.stopPropagation();
|
|
134
|
-
if (disabled) return;
|
|
135
|
-
setShowList((prev)=>!prev);
|
|
136
|
-
};
|
|
137
|
-
const handleClickContainer = (event)=>{
|
|
138
|
-
event.stopPropagation();
|
|
139
|
-
if (disabled) return;
|
|
140
|
-
if (!showList) setShowList(true);
|
|
141
|
-
inputRef.current?.focus();
|
|
142
|
-
};
|
|
143
|
-
useEffect(()=>{
|
|
144
|
-
if (toggle) toggle(showList);
|
|
145
|
-
}, [
|
|
146
|
-
showList
|
|
147
|
-
]);
|
|
148
108
|
return /*#__PURE__*/ jsxs(MultiSelectWrapper, {
|
|
149
|
-
...rest,
|
|
150
109
|
children: [
|
|
151
110
|
/*#__PURE__*/ jsxs(LabelContainer, {
|
|
152
111
|
children: [
|
|
@@ -156,8 +115,9 @@ function MultiSelect({ helpText, label, sublabel, required, disabled, feedback,
|
|
|
156
115
|
required: required,
|
|
157
116
|
htmlFor: name
|
|
158
117
|
}),
|
|
159
|
-
selected.length > 0 && /*#__PURE__*/ jsx("button", {
|
|
160
|
-
|
|
118
|
+
selected.length > 0 && !disabled && /*#__PURE__*/ jsx("button", {
|
|
119
|
+
type: "button",
|
|
120
|
+
onClick: clearAll,
|
|
161
121
|
children: translation("remove_all")
|
|
162
122
|
})
|
|
163
123
|
]
|
|
@@ -169,61 +129,58 @@ function MultiSelect({ helpText, label, sublabel, required, disabled, feedback,
|
|
|
169
129
|
disabled: disabled,
|
|
170
130
|
$active: showList,
|
|
171
131
|
children: [
|
|
172
|
-
"string" == typeof icon ? /*#__PURE__*/ jsx(Icon, {
|
|
132
|
+
icon && ("string" == typeof icon ? /*#__PURE__*/ jsx(Icon, {
|
|
173
133
|
name: icon,
|
|
174
|
-
color:
|
|
175
|
-
}) : icon,
|
|
134
|
+
color: COLOR_NEUTRAL_MEDIUM
|
|
135
|
+
}) : icon),
|
|
176
136
|
/*#__PURE__*/ jsxs(BadgesContainer, {
|
|
177
137
|
children: [
|
|
178
138
|
selected.map((option)=>/*#__PURE__*/ jsx(Badge, {
|
|
179
139
|
text: option.label,
|
|
180
|
-
remove: ()=>
|
|
140
|
+
remove: ()=>removeOption(option),
|
|
141
|
+
disabled: disabled
|
|
181
142
|
}, option.value)),
|
|
182
143
|
/*#__PURE__*/ jsx(ResizableInput, {
|
|
183
144
|
type: "text",
|
|
184
|
-
name: name,
|
|
185
145
|
placeholder: selected.length ? "" : placeholder,
|
|
186
146
|
ref: inputRef,
|
|
187
147
|
value: query,
|
|
188
148
|
onKeyDown: handleKeyDown,
|
|
189
149
|
onChange: handleChange,
|
|
190
|
-
disabled: disabled,
|
|
191
150
|
size: inputSize,
|
|
192
|
-
wide: 0 === selected.length
|
|
151
|
+
wide: 0 === selected.length,
|
|
152
|
+
disabled: disabled,
|
|
153
|
+
name: name
|
|
193
154
|
})
|
|
194
155
|
]
|
|
195
156
|
}),
|
|
196
|
-
/*#__PURE__*/ jsx(RotateButton, {
|
|
157
|
+
"alt" === variant && /*#__PURE__*/ jsx(RotateButton, {
|
|
197
158
|
rotate: showList,
|
|
198
|
-
onClick: toggleList
|
|
199
|
-
disabled: disabled,
|
|
200
|
-
style: {
|
|
201
|
-
cursor: disabled ? "not-allowed" : "pointer"
|
|
202
|
-
}
|
|
159
|
+
onClick: toggleList
|
|
203
160
|
}),
|
|
204
|
-
|
|
161
|
+
maxItems && /*#__PURE__*/ jsx(MaxItemsIndicator, {
|
|
205
162
|
children: /*#__PURE__*/ jsxs("span", {
|
|
206
163
|
children: [
|
|
207
164
|
selected.length,
|
|
208
165
|
"/",
|
|
209
|
-
|
|
166
|
+
maxItems
|
|
210
167
|
]
|
|
211
168
|
})
|
|
212
169
|
}),
|
|
213
170
|
showList && /*#__PURE__*/ jsx(MultiSelectList, {
|
|
214
171
|
options: currentDataOptions,
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
addAll: canShowSelectAll,
|
|
172
|
+
onClickOption: (_, option)=>addOption(option),
|
|
173
|
+
loading: isLoading,
|
|
174
|
+
addAll: canShowSelectAll ? handleAddAll : void 0,
|
|
219
175
|
onLoadMore: onLoadMore,
|
|
220
|
-
|
|
176
|
+
translation: translation,
|
|
177
|
+
listPosition: listPosition
|
|
221
178
|
})
|
|
222
179
|
]
|
|
223
180
|
}),
|
|
224
181
|
helpText && /*#__PURE__*/ jsx(HelpText, {
|
|
225
182
|
text: helpText,
|
|
226
|
-
feedback:
|
|
183
|
+
feedback: feedback,
|
|
227
184
|
icon: helpIcon
|
|
228
185
|
})
|
|
229
186
|
]
|
|
@@ -10,7 +10,7 @@ const MultiSelectWrapper = styled_components.div`
|
|
|
10
10
|
const showButton = keyframes`
|
|
11
11
|
from {
|
|
12
12
|
opacity: 0.8;
|
|
13
|
-
transform: translateY(
|
|
13
|
+
transform: translateY(0.125rem);
|
|
14
14
|
}
|
|
15
15
|
to {
|
|
16
16
|
opacity: 1;
|
|
@@ -31,7 +31,7 @@ const LabelContainer = styled_components.div`
|
|
|
31
31
|
font-weight: ${FONT_WEIGHT_BOLD};
|
|
32
32
|
line-height: 1rem;
|
|
33
33
|
animation: ${showButton} 0.15s ease-in forwards;
|
|
34
|
-
height:
|
|
34
|
+
height: 1.5rem;
|
|
35
35
|
|
|
36
36
|
&:hover {
|
|
37
37
|
color: ${COLOR_ACCENT_DARK};
|
|
@@ -50,45 +50,35 @@ const MultiSelectContainer = styled_components.div`
|
|
|
50
50
|
${({ $active })=>$active ? "2px" : "1px"}${COLOR_NEUTRAL_MEDIUM};
|
|
51
51
|
position: relative;
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
box-shadow: 0px 0px 0px 2px ${COLOR_NEUTRAL_MEDIUM};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
${({ disabled, feedback, $active })=>disabled ? `
|
|
58
|
-
background-color: ${COLOR_NEUTRAL_LIGHTER};
|
|
59
|
-
box-shadow: 0 0 0 1px ${COLOR_NEUTRAL_MEDIUM};
|
|
60
|
-
cursor: not-allowed;
|
|
61
|
-
` : selectColorModifier(feedback, $active)}
|
|
53
|
+
${({ disabled, feedback, $active })=>selectColorModifier(feedback, $active, disabled)}
|
|
62
54
|
`;
|
|
63
55
|
const BadgesContainer = styled_components.div`
|
|
64
|
-
background-color: ${COLOR_NEUTRAL_DAY};
|
|
65
56
|
display: flex;
|
|
66
57
|
flex-wrap: wrap;
|
|
67
58
|
gap: 0.5rem;
|
|
68
59
|
flex: 1;
|
|
69
|
-
max-height:
|
|
60
|
+
max-height: 10rem;
|
|
70
61
|
overflow-y: auto;
|
|
71
62
|
|
|
72
63
|
&::-webkit-scrollbar-track {
|
|
73
|
-
background-color:
|
|
64
|
+
background-color: ${COLOR_NEUTRAL_LIGHTER};
|
|
74
65
|
border-radius: 0 0.25rem 0.25rem 0;
|
|
75
66
|
}
|
|
76
67
|
|
|
77
68
|
&::-webkit-scrollbar {
|
|
78
|
-
width:
|
|
79
|
-
background:
|
|
69
|
+
width: 0.5rem;
|
|
70
|
+
background: ${COLOR_NEUTRAL_LIGHTER};
|
|
80
71
|
border-radius: 0 0.25rem 0.25rem 0;
|
|
81
72
|
}
|
|
82
73
|
|
|
83
74
|
&::-webkit-scrollbar-thumb {
|
|
84
|
-
border-radius:
|
|
75
|
+
border-radius: 8px;
|
|
85
76
|
background: #d5d8da;
|
|
86
77
|
}
|
|
87
78
|
`;
|
|
88
79
|
const ResizableInput = styled_components.input`
|
|
89
80
|
outline: none;
|
|
90
81
|
border: none;
|
|
91
|
-
background-color: transparent;
|
|
92
82
|
color: ${COLOR_NEUTRAL_DUSK};
|
|
93
83
|
font-size: 0.875rem;
|
|
94
84
|
line-height: 1rem;
|
|
@@ -103,11 +93,6 @@ const ResizableInput = styled_components.input`
|
|
|
103
93
|
font-weight: ${FONT_WEIGHT_MEDIUM};
|
|
104
94
|
line-height: 1.5rem;
|
|
105
95
|
}
|
|
106
|
-
|
|
107
|
-
&:disabled {
|
|
108
|
-
background-color: ${COLOR_NEUTRAL_LIGHTER};
|
|
109
|
-
cursor: not-allowed;
|
|
110
|
-
}
|
|
111
96
|
`;
|
|
112
97
|
const MaxItemsIndicator = styled_components.div`
|
|
113
98
|
display: flex;
|
|
@@ -29,7 +29,8 @@ export interface SelectProps extends InputPropsWithoutOnToggle {
|
|
|
29
29
|
onLoadMore?: () => Promise<void>;
|
|
30
30
|
onToggle?: (open: boolean) => void;
|
|
31
31
|
dropdownPosition?: "top" | "bottom";
|
|
32
|
+
sublabel?: string;
|
|
32
33
|
}
|
|
33
|
-
export default function Select({ helpText, isError, isSuccess, label, name, isRequired, options, placeholder, icon, isLoading, search, t, variation, selected, setSelected, onLoadMore, onToggle, dropdownPosition, ...rest }: SelectProps): import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
export default function Select({ helpText, isError, isSuccess, label, name, isRequired, options, placeholder, icon, isLoading, search, t, variation, selected, setSelected, onLoadMore, onToggle, dropdownPosition, sublabel, ...rest }: SelectProps): import("react/jsx-runtime").JSX.Element;
|
|
34
35
|
export declare const normalizeOptions: (options: ISelectOption[]) => ISelectOption[];
|
|
35
36
|
export {};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
|
-
import { CavetButton,
|
|
3
|
+
import { CavetButton, IconContainer, InputWrapper, SelectContainer, StyledInput } from "./styles.js";
|
|
4
4
|
import { Icon } from "@ftdata/f-icons";
|
|
5
5
|
import List from "./List/index.js";
|
|
6
|
-
|
|
6
|
+
import Label from "../fields/components/Label/index.js";
|
|
7
|
+
import HelpText from "../fields/components/HelpText/index.js";
|
|
8
|
+
function Select({ helpText, isError, isSuccess, label, name, isRequired, options, placeholder, icon, isLoading, search, t, variation = "default", selected, setSelected, onLoadMore, onToggle, dropdownPosition, sublabel, ...rest }) {
|
|
7
9
|
const [showList, setShowList] = useState(false);
|
|
8
10
|
const [currentValue, setCurrentValue] = useState("");
|
|
9
11
|
const [filtered, setFiltered] = useState([]);
|
|
@@ -118,15 +120,11 @@ function Select({ helpText, isError, isSuccess, label, name, isRequired, options
|
|
|
118
120
|
onClick: handleClick,
|
|
119
121
|
ref: selectRef,
|
|
120
122
|
children: [
|
|
121
|
-
/*#__PURE__*/
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
isRequired && /*#__PURE__*/ jsx("span", {
|
|
127
|
-
children: "*"
|
|
128
|
-
})
|
|
129
|
-
]
|
|
123
|
+
label && /*#__PURE__*/ jsx(Label, {
|
|
124
|
+
text: label,
|
|
125
|
+
subtext: sublabel,
|
|
126
|
+
required: isRequired,
|
|
127
|
+
htmlFor: name
|
|
130
128
|
}),
|
|
131
129
|
/*#__PURE__*/ jsxs(InputWrapper, {
|
|
132
130
|
children: [
|
|
@@ -173,19 +171,9 @@ function Select({ helpText, isError, isSuccess, label, name, isRequired, options
|
|
|
173
171
|
})
|
|
174
172
|
]
|
|
175
173
|
}),
|
|
176
|
-
helpText && /*#__PURE__*/
|
|
177
|
-
|
|
178
|
-
isSuccess:
|
|
179
|
-
children: [
|
|
180
|
-
isError && /*#__PURE__*/ jsx(Icon, {
|
|
181
|
-
name: "ui warning-circle",
|
|
182
|
-
size: "1rem",
|
|
183
|
-
color: "currentColor"
|
|
184
|
-
}),
|
|
185
|
-
/*#__PURE__*/ jsx("span", {
|
|
186
|
-
children: helpText
|
|
187
|
-
})
|
|
188
|
-
]
|
|
174
|
+
helpText && /*#__PURE__*/ jsx(HelpText, {
|
|
175
|
+
text: helpText,
|
|
176
|
+
feedback: isError ? "danger" : isSuccess ? "success" : "info"
|
|
189
177
|
})
|
|
190
178
|
]
|
|
191
179
|
});
|