@navikt/ds-react 4.6.1 → 4.7.0
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/_docs.json +1711 -169
- package/cjs/chips/Chips.js +1 -2
- package/cjs/form/combobox/ClearButton.js +27 -0
- package/cjs/form/combobox/Combobox.js +78 -0
- package/cjs/form/combobox/ComboboxProvider.js +99 -0
- package/cjs/form/combobox/ComboboxWrapper.js +51 -0
- package/cjs/form/combobox/FilteredOptions/CheckIcon.js +11 -0
- package/cjs/form/combobox/FilteredOptions/FilteredOptions.js +46 -0
- package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.js +208 -0
- package/cjs/form/combobox/Input/Input.js +143 -0
- package/cjs/form/combobox/Input/inputContext.js +86 -0
- package/cjs/form/combobox/SelectedOptions/SelectedOptions.js +27 -0
- package/cjs/form/combobox/SelectedOptions/selectedOptionsContext.js +107 -0
- package/cjs/form/combobox/ToggleListButton.js +36 -0
- package/cjs/form/combobox/customOptionsContext.js +56 -0
- package/cjs/form/combobox/index.js +8 -0
- package/cjs/form/combobox/package.json +6 -0
- package/cjs/form/combobox/types.js +2 -0
- package/cjs/form/index.js +3 -1
- package/cjs/timeline/AxisLabels.js +12 -12
- package/cjs/timeline/Timeline.js +2 -2
- package/cjs/util/usePrevious.js +18 -0
- package/esm/chips/Chips.js +1 -2
- package/esm/chips/Chips.js.map +1 -1
- package/esm/date/datepicker/TableHead.d.ts +1 -0
- package/esm/form/Fieldset/useFieldset.d.ts +1 -1
- package/esm/form/checkbox/useCheckbox.d.ts +4 -4
- package/esm/form/combobox/ClearButton.d.ts +7 -0
- package/esm/form/combobox/ClearButton.js +21 -0
- package/esm/form/combobox/ClearButton.js.map +1 -0
- package/esm/form/combobox/Combobox.d.ts +4 -0
- package/esm/form/combobox/Combobox.js +50 -0
- package/esm/form/combobox/Combobox.js.map +1 -0
- package/esm/form/combobox/ComboboxProvider.d.ts +26 -0
- package/esm/form/combobox/ComboboxProvider.js +72 -0
- package/esm/form/combobox/ComboboxProvider.js.map +1 -0
- package/esm/form/combobox/ComboboxWrapper.d.ts +14 -0
- package/esm/form/combobox/ComboboxWrapper.js +24 -0
- package/esm/form/combobox/ComboboxWrapper.js.map +1 -0
- package/esm/form/combobox/FilteredOptions/CheckIcon.d.ts +3 -0
- package/esm/form/combobox/FilteredOptions/CheckIcon.js +7 -0
- package/esm/form/combobox/FilteredOptions/CheckIcon.js.map +1 -0
- package/esm/form/combobox/FilteredOptions/FilteredOptions.d.ts +3 -0
- package/esm/form/combobox/FilteredOptions/FilteredOptions.js +42 -0
- package/esm/form/combobox/FilteredOptions/FilteredOptions.js.map +1 -0
- package/esm/form/combobox/FilteredOptions/filteredOptionsContext.d.ts +27 -0
- package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js +178 -0
- package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -0
- package/esm/form/combobox/Input/Input.d.ts +10 -0
- package/esm/form/combobox/Input/Input.js +116 -0
- package/esm/form/combobox/Input/Input.js.map +1 -0
- package/esm/form/combobox/Input/inputContext.d.ts +19 -0
- package/esm/form/combobox/Input/inputContext.js +59 -0
- package/esm/form/combobox/Input/inputContext.js.map +1 -0
- package/esm/form/combobox/SelectedOptions/SelectedOptions.d.ts +8 -0
- package/esm/form/combobox/SelectedOptions/SelectedOptions.js +23 -0
- package/esm/form/combobox/SelectedOptions/SelectedOptions.js.map +1 -0
- package/esm/form/combobox/SelectedOptions/selectedOptionsContext.d.ts +17 -0
- package/esm/form/combobox/SelectedOptions/selectedOptionsContext.js +77 -0
- package/esm/form/combobox/SelectedOptions/selectedOptionsContext.js.map +1 -0
- package/esm/form/combobox/ToggleListButton.d.ts +6 -0
- package/esm/form/combobox/ToggleListButton.js +11 -0
- package/esm/form/combobox/ToggleListButton.js.map +1 -0
- package/esm/form/combobox/customOptionsContext.d.ts +11 -0
- package/esm/form/combobox/customOptionsContext.js +29 -0
- package/esm/form/combobox/customOptionsContext.js.map +1 -0
- package/esm/form/combobox/index.d.ts +2 -0
- package/esm/form/combobox/index.js +2 -0
- package/esm/form/combobox/index.js.map +1 -0
- package/esm/form/combobox/types.d.ts +119 -0
- package/esm/form/combobox/types.js +2 -0
- package/esm/form/combobox/types.js.map +1 -0
- package/esm/form/index.d.ts +1 -0
- package/esm/form/index.js +1 -0
- package/esm/form/index.js.map +1 -1
- package/esm/form/radio/useRadio.d.ts +4 -4
- package/esm/form/useFormField.d.ts +11 -10
- package/esm/form/useFormField.js.map +1 -1
- package/esm/timeline/AxisLabels.d.ts +7 -5
- package/esm/timeline/AxisLabels.js +12 -12
- package/esm/timeline/AxisLabels.js.map +1 -1
- package/esm/timeline/Timeline.d.ts +6 -0
- package/esm/timeline/Timeline.js +2 -2
- package/esm/timeline/Timeline.js.map +1 -1
- package/esm/timeline/utils/types.external.d.ts +5 -0
- package/esm/util/usePrevious.d.ts +2 -0
- package/esm/util/usePrevious.js +17 -0
- package/esm/util/usePrevious.js.map +1 -0
- package/package.json +2 -2
- package/src/chips/Chips.tsx +1 -1
- package/src/form/combobox/ClearButton.tsx +29 -0
- package/src/form/combobox/Combobox.tsx +136 -0
- package/src/form/combobox/ComboboxProvider.tsx +99 -0
- package/src/form/combobox/ComboboxWrapper.tsx +63 -0
- package/src/form/combobox/FilteredOptions/CheckIcon.tsx +23 -0
- package/src/form/combobox/FilteredOptions/FilteredOptions.tsx +106 -0
- package/src/form/combobox/FilteredOptions/filteredOptionsContext.tsx +266 -0
- package/src/form/combobox/Input/Input.tsx +170 -0
- package/src/form/combobox/Input/inputContext.tsx +127 -0
- package/src/form/combobox/SelectedOptions/SelectedOptions.tsx +45 -0
- package/src/form/combobox/SelectedOptions/selectedOptionsContext.tsx +147 -0
- package/src/form/combobox/ToggleListButton.tsx +37 -0
- package/src/form/combobox/combobox.stories.tsx +413 -0
- package/src/form/combobox/combobox.test.tsx +123 -0
- package/src/form/combobox/customOptionsContext.tsx +57 -0
- package/src/form/combobox/index.ts +2 -0
- package/src/form/combobox/types.ts +122 -0
- package/src/form/index.ts +1 -0
- package/src/form/useFormField.ts +19 -1
- package/src/timeline/AxisLabels.tsx +23 -13
- package/src/timeline/Timeline.tsx +18 -2
- package/src/timeline/utils/types.external.ts +6 -0
- package/src/util/usePrevious.ts +19 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React, { useState, useCallback, createContext, useContext } from "react";
|
|
2
|
+
import { useInputContext } from "./Input/inputContext";
|
|
3
|
+
|
|
4
|
+
type CustomOptionsContextType = {
|
|
5
|
+
customOptions: string[];
|
|
6
|
+
removeCustomOption: (option: string) => void;
|
|
7
|
+
addCustomOption: (option: string) => void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const CustomOptionsContext = createContext<CustomOptionsContextType>(
|
|
11
|
+
{} as CustomOptionsContextType
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export const CustomOptionsProvider = ({ children }) => {
|
|
15
|
+
const [customOptions, setCustomOptions] = useState<string[]>([]);
|
|
16
|
+
const { focusInput } = useInputContext();
|
|
17
|
+
|
|
18
|
+
const removeCustomOption = useCallback(
|
|
19
|
+
(option) => {
|
|
20
|
+
setCustomOptions((prevCustomOptions) =>
|
|
21
|
+
prevCustomOptions.filter((o) => o !== option)
|
|
22
|
+
);
|
|
23
|
+
focusInput();
|
|
24
|
+
},
|
|
25
|
+
[focusInput, setCustomOptions]
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const addCustomOption = useCallback(
|
|
29
|
+
(option) => {
|
|
30
|
+
setCustomOptions((prevOptions) => [...prevOptions, option]);
|
|
31
|
+
focusInput();
|
|
32
|
+
},
|
|
33
|
+
[focusInput, setCustomOptions]
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const customOptionsState = {
|
|
37
|
+
customOptions,
|
|
38
|
+
removeCustomOption,
|
|
39
|
+
addCustomOption,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<CustomOptionsContext.Provider value={customOptionsState}>
|
|
44
|
+
{children}
|
|
45
|
+
</CustomOptionsContext.Provider>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const useCustomOptionsContext = () => {
|
|
50
|
+
const context = useContext(CustomOptionsContext);
|
|
51
|
+
if (!context) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
"useCustomOptionsContext must be used within a CustomOptionsProvider"
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return context;
|
|
57
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import React, { ChangeEvent, InputHTMLAttributes } from "react";
|
|
2
|
+
import { FormFieldProps } from "../useFormField";
|
|
3
|
+
|
|
4
|
+
export interface ComboboxProps
|
|
5
|
+
extends FormFieldProps,
|
|
6
|
+
Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "onChange" | "value"> {
|
|
7
|
+
/**
|
|
8
|
+
* Combobox label
|
|
9
|
+
*/
|
|
10
|
+
label: React.ReactNode;
|
|
11
|
+
/**
|
|
12
|
+
* List of options to use for autocompletion
|
|
13
|
+
*/
|
|
14
|
+
options: string[];
|
|
15
|
+
/**
|
|
16
|
+
* If enabled, adds an option to add the value of the input as an option whenever there are no options matching the value.
|
|
17
|
+
*/
|
|
18
|
+
allowNewValues?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* If "true" adds a button to clear the value in the input field
|
|
21
|
+
*/
|
|
22
|
+
clearButton?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Custom name for the clear button. Requires "clearButton" to be "true".
|
|
25
|
+
*
|
|
26
|
+
* @default "Tøm"
|
|
27
|
+
*/
|
|
28
|
+
clearButtonLabel?: string;
|
|
29
|
+
/**
|
|
30
|
+
* A list of options to display in the dropdown list.
|
|
31
|
+
* If provided, this overrides the internal search logic in the component.
|
|
32
|
+
* Useful for e.g. searching on a server or when overriding the search algorithm to search for synonyms or similar.
|
|
33
|
+
*/
|
|
34
|
+
filteredOptions?: string[];
|
|
35
|
+
/**
|
|
36
|
+
* Optionally hide the label visually.
|
|
37
|
+
* Not recommended, but can be considered for e.g. search fields in the top menu.
|
|
38
|
+
*/
|
|
39
|
+
hideLabel?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Custom class name for the input field.
|
|
42
|
+
*
|
|
43
|
+
* If used for styling, please consider using tokens instead.
|
|
44
|
+
*/
|
|
45
|
+
inputClassName?: string | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Controlled open/closed state for the dropdown list
|
|
48
|
+
*/
|
|
49
|
+
isListOpen?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Set to "true" when doing an async search and waiting for new filteredOptions.
|
|
52
|
+
*
|
|
53
|
+
* Will show a spinner in the dropdown and announce to screen readers that it is loading.
|
|
54
|
+
*/
|
|
55
|
+
isLoading?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Set to "true" to allow multiple selections
|
|
58
|
+
*
|
|
59
|
+
* This will display selected values as a list of Chips in front of the input field, instead of a selection replacing the value of the input.
|
|
60
|
+
*
|
|
61
|
+
*/
|
|
62
|
+
isMultiSelect?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Callback function triggered whenever the value of the input field is triggered.
|
|
65
|
+
*
|
|
66
|
+
* @param event
|
|
67
|
+
* @returns
|
|
68
|
+
*/
|
|
69
|
+
onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Callback function triggered whenever the input field is cleared
|
|
72
|
+
*
|
|
73
|
+
* @param event
|
|
74
|
+
* @returns
|
|
75
|
+
*/
|
|
76
|
+
onClear?: (event: React.PointerEvent | React.KeyboardEvent) => void;
|
|
77
|
+
/**
|
|
78
|
+
* Callback function triggered whenever an option is selected or de-selected
|
|
79
|
+
*
|
|
80
|
+
* @param option
|
|
81
|
+
* @param isSelected
|
|
82
|
+
* @returns
|
|
83
|
+
*/
|
|
84
|
+
onToggleSelected?: (option: string, isSelected: boolean) => void;
|
|
85
|
+
/**
|
|
86
|
+
* List of selected options.
|
|
87
|
+
*
|
|
88
|
+
* Use this prop when controlling the selected state outside for the component,
|
|
89
|
+
* e.g. for a filter, where options can be toggled elsewhere/programmatically.
|
|
90
|
+
*/
|
|
91
|
+
selectedOptions?: string[];
|
|
92
|
+
/**
|
|
93
|
+
* Set to "true" to enable inline autocomplete.
|
|
94
|
+
*
|
|
95
|
+
* @default false
|
|
96
|
+
*/
|
|
97
|
+
shouldAutocomplete?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* When set to "true" displays selected options as Chips before the input field
|
|
100
|
+
*
|
|
101
|
+
* @default true
|
|
102
|
+
*/
|
|
103
|
+
shouldShowSelectedOptions?: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* When set to "true" displays the toggle button for opening/closing the dropdown list
|
|
106
|
+
*
|
|
107
|
+
* @default true
|
|
108
|
+
*/
|
|
109
|
+
toggleListButton?: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Custom name for the toggle list-button. Requires "toggleListButton" to be "true".
|
|
112
|
+
*
|
|
113
|
+
* @default "Alternativer"
|
|
114
|
+
*/
|
|
115
|
+
toggleListButtonLabel?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Set this to override the value of the input field.
|
|
118
|
+
*
|
|
119
|
+
* This converts the input to a controlled input, so you have to use onChange to update the value.
|
|
120
|
+
*/
|
|
121
|
+
value?: string;
|
|
122
|
+
}
|
package/src/form/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ export {
|
|
|
17
17
|
type RadioProps,
|
|
18
18
|
} from "./radio";
|
|
19
19
|
export { Search, type SearchClearEvent, type SearchProps } from "./search";
|
|
20
|
+
export { Combobox as UNSAFE_Combobox, type ComboboxProps } from "./combobox";
|
|
20
21
|
export { default as Select, type SelectProps } from "./Select";
|
|
21
22
|
export { default as Switch, type SwitchProps } from "./Switch";
|
|
22
23
|
export { Counter, default as Textarea, type TextareaProps } from "./Textarea";
|
package/src/form/useFormField.ts
CHANGED
|
@@ -35,10 +35,28 @@ export interface FormFieldProps {
|
|
|
35
35
|
readOnly?: boolean;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export interface FormFieldType {
|
|
39
|
+
showErrorMsg: boolean;
|
|
40
|
+
hasError: boolean;
|
|
41
|
+
errorId: string;
|
|
42
|
+
inputDescriptionId: string;
|
|
43
|
+
size: "small" | "medium";
|
|
44
|
+
inputProps: {
|
|
45
|
+
id: string;
|
|
46
|
+
"aria-invalid"?: boolean;
|
|
47
|
+
"aria-describedby"?: string;
|
|
48
|
+
disabled?: boolean;
|
|
49
|
+
};
|
|
50
|
+
readOnly?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
38
53
|
/**
|
|
39
54
|
* Handles props and their state for various form-fields in context with Fieldset
|
|
40
55
|
*/
|
|
41
|
-
export const useFormField = (
|
|
56
|
+
export const useFormField = (
|
|
57
|
+
props: FormFieldProps,
|
|
58
|
+
prefix: string
|
|
59
|
+
): FormFieldType => {
|
|
42
60
|
const { size, error, errorId: propErrorId } = props;
|
|
43
61
|
|
|
44
62
|
const fieldset = useContext(FieldsetContext);
|
|
@@ -19,13 +19,14 @@ import React from "react";
|
|
|
19
19
|
import { useTimelineContext } from "./hooks/useTimelineContext";
|
|
20
20
|
import { isVisible } from "./utils";
|
|
21
21
|
import { horizontalPositionAndWidth } from "./utils/calc";
|
|
22
|
-
import { AxisLabel } from "./utils/types.external";
|
|
22
|
+
import { AxisLabel, AxisLabelTemplates } from "./utils/types.external";
|
|
23
23
|
|
|
24
24
|
export const dayLabels = (
|
|
25
25
|
start: Date,
|
|
26
26
|
end: Date,
|
|
27
27
|
totalDays: number,
|
|
28
|
-
direction: "left" | "right"
|
|
28
|
+
direction: "left" | "right",
|
|
29
|
+
template: string = "dd.MM"
|
|
29
30
|
): AxisLabel[] => {
|
|
30
31
|
const increment = Math.ceil(totalDays / 10);
|
|
31
32
|
const lastDay = startOfDay(end);
|
|
@@ -43,7 +44,7 @@ export const dayLabels = (
|
|
|
43
44
|
return {
|
|
44
45
|
direction: direction,
|
|
45
46
|
horizontalPosition: horizontalPosition,
|
|
46
|
-
label: format(day,
|
|
47
|
+
label: format(day, template, { locale: nbLocale }),
|
|
47
48
|
date: day,
|
|
48
49
|
width: width,
|
|
49
50
|
};
|
|
@@ -54,7 +55,8 @@ export const dayLabels = (
|
|
|
54
55
|
export const monthLabels = (
|
|
55
56
|
start: Date,
|
|
56
57
|
end: Date,
|
|
57
|
-
direction: "left" | "right"
|
|
58
|
+
direction: "left" | "right",
|
|
59
|
+
template: string = "MMM yy"
|
|
58
60
|
): AxisLabel[] => {
|
|
59
61
|
const startMonth = startOfMonth(start);
|
|
60
62
|
const endMonth = endOfMonth(end);
|
|
@@ -70,7 +72,7 @@ export const monthLabels = (
|
|
|
70
72
|
return {
|
|
71
73
|
direction: direction,
|
|
72
74
|
horizontalPosition: horizontalPosition,
|
|
73
|
-
label: format(month,
|
|
75
|
+
label: format(month, template, { locale: nbLocale }),
|
|
74
76
|
date: month,
|
|
75
77
|
width: width,
|
|
76
78
|
};
|
|
@@ -80,7 +82,8 @@ export const monthLabels = (
|
|
|
80
82
|
export const yearLabels = (
|
|
81
83
|
start: Date,
|
|
82
84
|
end: Date,
|
|
83
|
-
direction: "left" | "right"
|
|
85
|
+
direction: "left" | "right",
|
|
86
|
+
template: string = "yyyy"
|
|
84
87
|
): AxisLabel[] => {
|
|
85
88
|
const firstYear = startOfYear(start);
|
|
86
89
|
const lastYear = endOfYear(end);
|
|
@@ -96,7 +99,7 @@ export const yearLabels = (
|
|
|
96
99
|
return {
|
|
97
100
|
direction: direction,
|
|
98
101
|
horizontalPosition: horizontalPosition,
|
|
99
|
-
label: year
|
|
102
|
+
label: format(year, template, { locale: nbLocale }),
|
|
100
103
|
date: year,
|
|
101
104
|
width: width,
|
|
102
105
|
};
|
|
@@ -106,21 +109,28 @@ export const yearLabels = (
|
|
|
106
109
|
const axisLabels = (
|
|
107
110
|
start: Date,
|
|
108
111
|
end: Date,
|
|
109
|
-
direction: "left" | "right"
|
|
112
|
+
direction: "left" | "right",
|
|
113
|
+
templates?: AxisLabelTemplates
|
|
110
114
|
): AxisLabel[] => {
|
|
111
115
|
const totalDays = differenceInDays(end, start);
|
|
112
116
|
if (totalDays < 40) {
|
|
113
|
-
return dayLabels(start, end, totalDays, direction);
|
|
117
|
+
return dayLabels(start, end, totalDays, direction, templates?.day);
|
|
114
118
|
} else if (totalDays < 370) {
|
|
115
|
-
return monthLabels(start, end, direction);
|
|
119
|
+
return monthLabels(start, end, direction, templates?.month);
|
|
116
120
|
} else {
|
|
117
|
-
return yearLabels(start, end, direction);
|
|
121
|
+
return yearLabels(start, end, direction, templates?.year);
|
|
118
122
|
}
|
|
119
123
|
};
|
|
120
124
|
|
|
121
|
-
export const AxisLabels = (
|
|
125
|
+
export const AxisLabels = ({
|
|
126
|
+
templates,
|
|
127
|
+
}: {
|
|
128
|
+
templates?: AxisLabelTemplates;
|
|
129
|
+
}) => {
|
|
122
130
|
const { endDate, startDate, direction } = useTimelineContext();
|
|
123
|
-
const labels = axisLabels(startDate, endDate, direction).filter(
|
|
131
|
+
const labels = axisLabels(startDate, endDate, direction, templates).filter(
|
|
132
|
+
isVisible
|
|
133
|
+
);
|
|
124
134
|
|
|
125
135
|
return (
|
|
126
136
|
<div className="navds-timeline__axislabels" aria-hidden="true">
|
|
@@ -13,6 +13,7 @@ import Pin, { PinType } from "./Pin";
|
|
|
13
13
|
import TimelineRow, { TimelineRowType } from "./TimelineRow";
|
|
14
14
|
import { parseRows } from "./utils/timeline";
|
|
15
15
|
import Zoom, { ZoomType } from "./zoom";
|
|
16
|
+
import { AxisLabelTemplates } from "./utils/types.external";
|
|
16
17
|
|
|
17
18
|
export interface TimelineProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
18
19
|
children: React.ReactNode;
|
|
@@ -33,6 +34,11 @@ export interface TimelineProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
33
34
|
* @default "left"
|
|
34
35
|
*/
|
|
35
36
|
direction?: "left" | "right";
|
|
37
|
+
/**
|
|
38
|
+
* Templates for label texts. The templates are passed to the date-fns `format` function.
|
|
39
|
+
* Defaults to { day: "dd.MM", month: "MMM yy", year: "yyyy" }.
|
|
40
|
+
*/
|
|
41
|
+
axisLabelTemplates?: AxisLabelTemplates;
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
interface TimelineComponent
|
|
@@ -74,7 +80,17 @@ interface TimelineComponent
|
|
|
74
80
|
* ```
|
|
75
81
|
*/
|
|
76
82
|
export const Timeline = forwardRef<HTMLDivElement, TimelineProps>(
|
|
77
|
-
(
|
|
83
|
+
(
|
|
84
|
+
{
|
|
85
|
+
children,
|
|
86
|
+
startDate,
|
|
87
|
+
endDate,
|
|
88
|
+
direction = "left",
|
|
89
|
+
axisLabelTemplates,
|
|
90
|
+
...rest
|
|
91
|
+
},
|
|
92
|
+
ref
|
|
93
|
+
) => {
|
|
78
94
|
const isMultipleRows = Array.isArray(children);
|
|
79
95
|
|
|
80
96
|
const firstFocusabled = useRef<
|
|
@@ -194,7 +210,7 @@ export const Timeline = forwardRef<HTMLDivElement, TimelineProps>(
|
|
|
194
210
|
>
|
|
195
211
|
<div {...rest} ref={ref}>
|
|
196
212
|
<div className="navds-timeline">
|
|
197
|
-
<AxisLabels />
|
|
213
|
+
<AxisLabels templates={axisLabelTemplates} />
|
|
198
214
|
|
|
199
215
|
{pins.map((pin) => {
|
|
200
216
|
return pin;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* usePrevious hook
|
|
5
|
+
* The ref object's "current" property is mutable and when changed wont re-render the component
|
|
6
|
+
* meaning it can be used to stay "one render behind" the current state
|
|
7
|
+
* https://usehooks.com/usePrevious/
|
|
8
|
+
* https://blog.logrocket.com/accessing-previous-props-state-react-hooks/
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const usePrevious = <T>(value: T): T | undefined => {
|
|
12
|
+
const ref = useRef<T>(value);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
ref.current = value;
|
|
15
|
+
}, [value]);
|
|
16
|
+
return ref.current;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default usePrevious;
|