@helpwave/hightide 0.0.8 → 0.0.11
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/README.md +1 -1
- package/dist/coloring/shading.d.ts +2 -0
- package/dist/coloring/shading.js +40 -0
- package/dist/coloring/types.d.ts +11 -0
- package/dist/coloring/types.js +1 -0
- package/dist/components/Avatar.d.ts +14 -0
- package/dist/components/Avatar.js +35 -0
- package/dist/components/AvatarGroup.d.ts +10 -0
- package/dist/components/AvatarGroup.js +13 -0
- package/dist/components/BreadCrumb.d.ts +16 -0
- package/dist/components/BreadCrumb.js +12 -0
- package/dist/components/Button.d.ts +41 -0
- package/dist/components/Button.js +84 -0
- package/dist/components/ChipList.d.ts +21 -0
- package/dist/components/ChipList.js +38 -0
- package/dist/components/Circle.d.ts +6 -0
- package/dist/components/Circle.js +10 -0
- package/dist/components/ErrorComponent.d.ts +13 -0
- package/dist/components/ErrorComponent.js +19 -0
- package/dist/components/Expandable.d.ts +30 -0
- package/dist/components/Expandable.js +16 -0
- package/dist/components/HelpwaveBadge.d.ts +11 -0
- package/dist/components/HelpwaveBadge.js +14 -0
- package/dist/components/HideableContentSection.d.ts +10 -0
- package/dist/components/HideableContentSection.js +15 -0
- package/dist/components/InputGroup.d.ts +13 -0
- package/dist/components/InputGroup.js +33 -0
- package/dist/components/LoadingAndErrorComponent.d.ts +17 -0
- package/dist/components/LoadingAndErrorComponent.js +25 -0
- package/dist/components/LoadingAnimation.d.ts +13 -0
- package/dist/components/LoadingAnimation.js +19 -0
- package/dist/components/LoadingButton.d.ts +6 -0
- package/dist/components/LoadingButton.js +10 -0
- package/dist/components/MarkdownInterpreter.d.ts +25 -0
- package/dist/components/MarkdownInterpreter.js +190 -0
- package/dist/components/Pagination.d.ts +14 -0
- package/dist/components/Pagination.js +25 -0
- package/dist/components/Profile.d.ts +28 -0
- package/dist/components/Profile.js +45 -0
- package/dist/components/ProgressIndicator.d.ts +21 -0
- package/dist/components/ProgressIndicator.js +24 -0
- package/dist/components/Ring.d.ts +31 -0
- package/dist/components/Ring.js +113 -0
- package/dist/components/SearchableList.d.ts +18 -0
- package/dist/components/SearchableList.js +27 -0
- package/dist/components/SortButton.d.ts +10 -0
- package/dist/components/SortButton.js +9 -0
- package/dist/components/Span.js +1 -0
- package/dist/components/StepperBar.d.ts +23 -0
- package/dist/components/StepperBar.js +47 -0
- package/dist/components/Table.d.ts +87 -0
- package/dist/components/Table.js +187 -0
- package/dist/components/TechRadar.d.ts +36 -0
- package/dist/components/TechRadar.js +191 -0
- package/dist/components/TextImage.d.ts +20 -0
- package/dist/components/TextImage.js +31 -0
- package/dist/components/TimeDisplay.d.ts +30 -0
- package/dist/components/TimeDisplay.js +83 -0
- package/dist/components/Tooltip.d.ts +34 -0
- package/dist/components/Tooltip.js +38 -0
- package/dist/components/VerticalDivider.d.ts +11 -0
- package/dist/components/VerticalDivider.js +7 -0
- package/dist/components/date/DatePicker.d.ts +26 -0
- package/dist/components/date/DatePicker.js +58 -0
- package/dist/components/date/DayPicker.d.ts +16 -0
- package/dist/components/date/DayPicker.js +37 -0
- package/dist/components/date/TimePicker.d.ts +12 -0
- package/dist/components/date/TimePicker.js +79 -0
- package/dist/components/date/YearMonthPicker.d.ts +11 -0
- package/dist/components/date/YearMonthPicker.js +59 -0
- package/dist/components/examples/InputGroupExample.d.ts +6 -0
- package/dist/components/examples/InputGroupExample.js +21 -0
- package/dist/components/examples/MultiSelectExample.d.ts +7 -0
- package/dist/components/examples/MultiSelectExample.js +27 -0
- package/dist/components/examples/SearchableSelectExample.d.ts +6 -0
- package/dist/components/examples/SearchableSelectExample.js +17 -0
- package/dist/components/examples/SelectExample.d.ts +4 -0
- package/dist/components/examples/SelectExample.js +15 -0
- package/dist/components/examples/StackingModals.d.ts +4 -0
- package/dist/components/examples/StackingModals.js +15 -0
- package/dist/components/examples/TableExample.d.ts +9 -0
- package/dist/components/examples/TableExample.js +92 -0
- package/dist/components/examples/TextareaExample.d.ts +6 -0
- package/dist/components/examples/TextareaExample.js +10 -0
- package/dist/components/examples/TileExample.d.ts +9 -0
- package/dist/components/examples/TileExample.js +9 -0
- package/dist/components/examples/Title.js +1 -0
- package/dist/components/examples/date/DateTimePickerExample.d.ts +10 -0
- package/dist/components/examples/date/DateTimePickerExample.js +21 -0
- package/dist/components/examples/properties/CheckboxPropertyExample.d.ts +8 -0
- package/dist/components/examples/properties/CheckboxPropertyExample.js +13 -0
- package/dist/components/examples/properties/DatePropertyExample.d.ts +8 -0
- package/dist/components/examples/properties/DatePropertyExample.js +23 -0
- package/dist/components/examples/properties/MultiSelectPropertyExample.d.ts +8 -0
- package/dist/components/examples/properties/MultiSelectPropertyExample.js +16 -0
- package/dist/components/examples/properties/NumberPropertyExample.d.ts +6 -0
- package/dist/components/examples/properties/NumberPropertyExample.js +13 -0
- package/dist/components/examples/properties/SelectPropertyExample.d.ts +6 -0
- package/dist/components/examples/properties/SelectPropertyExample.js +18 -0
- package/dist/components/examples/properties/TextPropertyExample.d.ts +8 -0
- package/dist/components/examples/properties/TextPropertyExample.js +13 -0
- package/dist/components/icons/Helpwave.d.ts +10 -0
- package/dist/components/icons/Helpwave.js +20 -0
- package/dist/components/icons/Tag.d.ts +10 -0
- package/dist/components/icons/Tag.js +12 -0
- package/dist/components/layout/Carousel.d.ts +22 -0
- package/dist/components/layout/Carousel.js +233 -0
- package/dist/components/layout/DividerInserter.d.ts +11 -0
- package/dist/components/layout/DividerInserter.js +20 -0
- package/dist/components/layout/FAQSection.d.ts +23 -0
- package/dist/components/layout/FAQSection.js +14 -0
- package/dist/components/layout/Tile.d.ts +34 -0
- package/dist/components/layout/Tile.js +18 -0
- package/dist/components/modals/ConfirmDialog.d.ts +34 -0
- package/dist/components/modals/ConfirmDialog.js +31 -0
- package/dist/components/modals/DiscardChangesDialog.d.ts +19 -0
- package/dist/components/modals/DiscardChangesDialog.js +24 -0
- package/dist/components/modals/InputModal.d.ts +9 -0
- package/dist/components/modals/InputModal.js +9 -0
- package/dist/components/modals/LanguageModal.d.ts +17 -0
- package/dist/components/modals/LanguageModal.js +35 -0
- package/dist/components/modals/Modal.d.ts +38 -0
- package/dist/components/modals/Modal.js +57 -0
- package/dist/components/modals/ModalRegister.d.ts +11 -0
- package/dist/components/modals/ModalRegister.js +28 -0
- package/dist/components/properties/CheckboxProperty.d.ts +15 -0
- package/dist/components/properties/CheckboxProperty.js +27 -0
- package/dist/components/properties/DateProperty.d.ts +11 -0
- package/dist/components/properties/DateProperty.js +22 -0
- package/dist/components/properties/MultiSelectProperty.d.ts +12 -0
- package/dist/components/properties/MultiSelectProperty.js +33 -0
- package/dist/components/properties/NumberProperty.d.ts +16 -0
- package/dist/components/properties/NumberProperty.js +42 -0
- package/dist/components/properties/PropertyBase.d.ts +23 -0
- package/dist/components/properties/PropertyBase.js +27 -0
- package/dist/components/properties/SelectProperty.d.ts +12 -0
- package/dist/components/properties/SelectProperty.js +22 -0
- package/dist/components/properties/TextProperty.d.ts +15 -0
- package/dist/components/properties/TextProperty.js +37 -0
- package/dist/components/user-input/Checkbox.d.ts +37 -0
- package/dist/components/user-input/Checkbox.js +63 -0
- package/dist/components/user-input/DateAndTimePicker.d.ts +39 -0
- package/dist/components/user-input/DateAndTimePicker.js +65 -0
- package/dist/components/user-input/Input.d.ts +61 -0
- package/dist/components/user-input/Input.js +61 -0
- package/dist/components/user-input/Label.d.ts +12 -0
- package/dist/components/user-input/Label.js +12 -0
- package/dist/components/user-input/Menu.d.ts +21 -0
- package/dist/components/user-input/Menu.js +26 -0
- package/dist/components/user-input/MultiSelect.d.ts +39 -0
- package/dist/components/user-input/MultiSelect.js +57 -0
- package/dist/components/user-input/ScrollPicker.d.ts +11 -0
- package/dist/components/user-input/ScrollPicker.js +151 -0
- package/dist/components/user-input/SearchableSelect.d.ts +8 -0
- package/dist/components/user-input/SearchableSelect.js +14 -0
- package/dist/components/user-input/Select.d.ts +32 -0
- package/dist/components/user-input/Select.js +48 -0
- package/dist/components/user-input/Textarea.d.ts +20 -0
- package/dist/components/user-input/Textarea.js +33 -0
- package/dist/components/user-input/ToggleableInput.d.ts +32 -0
- package/dist/components/user-input/ToggleableInput.js +40 -0
- package/{globals.css → dist/css/globals.css} +1 -1
- package/dist/hooks/useHoverState.d.ts +40 -0
- package/dist/hooks/useHoverState.js +46 -0
- package/dist/hooks/useLanguage.d.ts +17 -0
- package/dist/hooks/useLanguage.js +51 -0
- package/dist/hooks/useLocalStorage.d.ts +4 -0
- package/dist/hooks/useLocalStorage.js +24 -0
- package/dist/hooks/useOutsideClick.d.ts +2 -0
- package/dist/hooks/useOutsideClick.js +22 -0
- package/dist/hooks/useSaveDelay.d.ts +5 -0
- package/dist/hooks/useSaveDelay.js +41 -0
- package/dist/hooks/useTheme.d.ts +16 -0
- package/dist/hooks/useTheme.js +32 -0
- package/dist/hooks/useTranslation.d.ts +24 -0
- package/dist/hooks/useTranslation.js +11 -0
- package/dist/util/array.d.ts +23 -0
- package/dist/util/array.js +103 -0
- package/{util/builder.ts → dist/util/builder.d.ts} +1 -4
- package/dist/util/builder.js +9 -0
- package/dist/util/date.d.ts +28 -0
- package/dist/util/date.js +133 -0
- package/dist/util/easeFunctions.d.ts +9 -0
- package/dist/util/easeFunctions.js +30 -0
- package/dist/util/emailValidation.d.ts +1 -0
- package/dist/util/emailValidation.js +3 -0
- package/dist/util/loopingArray.d.ts +23 -0
- package/dist/util/loopingArray.js +67 -0
- package/dist/util/math.d.ts +1 -0
- package/dist/util/math.js +3 -0
- package/dist/util/news.d.ts +98 -0
- package/dist/util/news.js +27 -0
- package/dist/util/noop.d.ts +1 -0
- package/dist/util/noop.js +1 -0
- package/{util/simpleSearch.ts → dist/util/simpleSearch.d.ts} +4 -21
- package/dist/util/simpleSearch.js +62 -0
- package/dist/util/storage.d.ts +15 -0
- package/dist/util/storage.js +32 -0
- package/dist/util/types.d.ts +1 -0
- package/dist/util/types.js +1 -0
- package/package.json +7 -8
- package/coloring/shading.ts +0 -46
- package/coloring/types.ts +0 -13
- package/components/Avatar.tsx +0 -58
- package/components/AvatarGroup.tsx +0 -48
- package/components/BreadCrumb.tsx +0 -35
- package/components/Button.tsx +0 -236
- package/components/ChipList.tsx +0 -89
- package/components/Circle.tsx +0 -27
- package/components/ErrorComponent.tsx +0 -40
- package/components/Expandable.tsx +0 -61
- package/components/HelpwaveBadge.tsx +0 -35
- package/components/HideableContentSection.tsx +0 -43
- package/components/InputGroup.tsx +0 -72
- package/components/LoadingAndErrorComponent.tsx +0 -47
- package/components/LoadingAnimation.tsx +0 -40
- package/components/LoadingButton.tsx +0 -27
- package/components/MarkdownInterpreter.tsx +0 -278
- package/components/Pagination.tsx +0 -65
- package/components/Profile.tsx +0 -124
- package/components/ProgressIndicator.tsx +0 -58
- package/components/Ring.tsx +0 -286
- package/components/SearchableList.tsx +0 -69
- package/components/SortButton.tsx +0 -33
- package/components/StepperBar.tsx +0 -124
- package/components/Table.tsx +0 -330
- package/components/TechRadar.tsx +0 -247
- package/components/TextImage.tsx +0 -86
- package/components/TimeDisplay.tsx +0 -121
- package/components/Tooltip.tsx +0 -92
- package/components/VerticalDivider.tsx +0 -51
- package/components/date/DatePicker.tsx +0 -164
- package/components/date/DayPicker.tsx +0 -95
- package/components/date/TimePicker.tsx +0 -167
- package/components/date/YearMonthPicker.tsx +0 -130
- package/components/examples/InputGroupExample.tsx +0 -58
- package/components/examples/MultiSelectExample.tsx +0 -57
- package/components/examples/SearchableSelectExample.tsx +0 -34
- package/components/examples/SelectExample.tsx +0 -28
- package/components/examples/StackingModals.tsx +0 -54
- package/components/examples/TableExample.tsx +0 -159
- package/components/examples/TextareaExample.tsx +0 -23
- package/components/examples/TileExample.tsx +0 -25
- package/components/examples/date/DateTimePickerExample.tsx +0 -53
- package/components/examples/properties/CheckboxPropertyExample.tsx +0 -29
- package/components/examples/properties/DatePropertyExample.tsx +0 -44
- package/components/examples/properties/MultiSelectPropertyExample.tsx +0 -39
- package/components/examples/properties/NumberPropertyExample.tsx +0 -28
- package/components/examples/properties/SelectPropertyExample.tsx +0 -39
- package/components/examples/properties/TextPropertyExample.tsx +0 -30
- package/components/icons/Helpwave.tsx +0 -51
- package/components/icons/Tag.tsx +0 -29
- package/components/layout/Carousel.tsx +0 -396
- package/components/layout/DividerInserter.tsx +0 -37
- package/components/layout/FAQSection.tsx +0 -57
- package/components/layout/Tile.tsx +0 -67
- package/components/modals/ConfirmDialog.tsx +0 -105
- package/components/modals/DiscardChangesDialog.tsx +0 -71
- package/components/modals/InputModal.tsx +0 -26
- package/components/modals/LanguageModal.tsx +0 -76
- package/components/modals/Modal.tsx +0 -149
- package/components/modals/ModalRegister.tsx +0 -45
- package/components/properties/CheckboxProperty.tsx +0 -62
- package/components/properties/DateProperty.tsx +0 -58
- package/components/properties/MultiSelectProperty.tsx +0 -82
- package/components/properties/NumberProperty.tsx +0 -86
- package/components/properties/PropertyBase.tsx +0 -84
- package/components/properties/SelectProperty.tsx +0 -67
- package/components/properties/TextProperty.tsx +0 -81
- package/components/user-input/Checkbox.tsx +0 -139
- package/components/user-input/DateAndTimePicker.tsx +0 -156
- package/components/user-input/Input.tsx +0 -192
- package/components/user-input/Label.tsx +0 -32
- package/components/user-input/Menu.tsx +0 -75
- package/components/user-input/MultiSelect.tsx +0 -158
- package/components/user-input/ScrollPicker.tsx +0 -240
- package/components/user-input/SearchableSelect.tsx +0 -36
- package/components/user-input/Select.tsx +0 -132
- package/components/user-input/Textarea.tsx +0 -86
- package/components/user-input/ToggleableInput.tsx +0 -115
- package/hooks/useHoverState.ts +0 -88
- package/hooks/useLanguage.tsx +0 -78
- package/hooks/useLocalStorage.tsx +0 -33
- package/hooks/useOutsideClick.ts +0 -25
- package/hooks/useSaveDelay.ts +0 -46
- package/hooks/useTheme.tsx +0 -57
- package/hooks/useTranslation.ts +0 -43
- package/index.ts +0 -0
- package/util/array.ts +0 -115
- package/util/date.ts +0 -180
- package/util/easeFunctions.ts +0 -37
- package/util/emailValidation.ts +0 -3
- package/util/loopingArray.ts +0 -94
- package/util/math.ts +0 -3
- package/util/news.ts +0 -43
- package/util/noop.ts +0 -1
- package/util/storage.ts +0 -37
- package/util/types.ts +0 -4
- /package/{components/Span.tsx → dist/components/Span.d.ts} +0 -0
- /package/{components/examples/Title.tsx → dist/components/examples/Title.d.ts} +0 -0
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from 'react'
|
|
2
|
-
import clsx from 'clsx'
|
|
3
|
-
import { noop } from '../../util/noop'
|
|
4
|
-
import { getNeighbours, range } from '../../util/array'
|
|
5
|
-
import { clamp } from '../../util/math'
|
|
6
|
-
|
|
7
|
-
export type ScrollPickerProps<T> = {
|
|
8
|
-
options: T[],
|
|
9
|
-
mapping: (value: T) => string,
|
|
10
|
-
selected?: T,
|
|
11
|
-
onChange?: (value: T) => void,
|
|
12
|
-
disabled?: boolean,
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
type AnimationData<T> = {
|
|
16
|
-
/** The index we scroll to */
|
|
17
|
-
targetIndex: number,
|
|
18
|
-
/** The index we are currently showing centered */
|
|
19
|
-
currentIndex: number,
|
|
20
|
-
items: T[],
|
|
21
|
-
/** From -0.5 to 0.5 */
|
|
22
|
-
transition: number,
|
|
23
|
-
velocity: number,
|
|
24
|
-
animationVelocity: number,
|
|
25
|
-
lastTimeStamp?: number,
|
|
26
|
-
lastScrollTimeStamp?: number,
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const up = 1
|
|
30
|
-
const down = -1
|
|
31
|
-
type Direction = 1 | -1
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* A component for picking an option by scrolling
|
|
35
|
-
*/
|
|
36
|
-
export const ScrollPicker = <T, >({
|
|
37
|
-
options,
|
|
38
|
-
mapping,
|
|
39
|
-
selected,
|
|
40
|
-
onChange = noop,
|
|
41
|
-
disabled = false,
|
|
42
|
-
}: ScrollPickerProps<T>) => {
|
|
43
|
-
let selectedIndex = 0
|
|
44
|
-
if (selected && options.indexOf(selected) !== -1) {
|
|
45
|
-
selectedIndex = options.indexOf(selected)
|
|
46
|
-
}
|
|
47
|
-
const [{
|
|
48
|
-
currentIndex,
|
|
49
|
-
transition,
|
|
50
|
-
items,
|
|
51
|
-
lastTimeStamp
|
|
52
|
-
}, setAnimation] = useState<AnimationData<T>>({
|
|
53
|
-
targetIndex: selectedIndex,
|
|
54
|
-
currentIndex: disabled ? selectedIndex : 0,
|
|
55
|
-
velocity: 0,
|
|
56
|
-
animationVelocity: Math.floor(options.length / 2),
|
|
57
|
-
transition: 0,
|
|
58
|
-
items: options,
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
const itemsShownCount = 5
|
|
62
|
-
const shownItems = getNeighbours(range(0, items.length - 1), currentIndex).map(index => ({
|
|
63
|
-
name: mapping(items[index]!), index
|
|
64
|
-
}))
|
|
65
|
-
|
|
66
|
-
const itemHeight = 40
|
|
67
|
-
const distance = 8
|
|
68
|
-
|
|
69
|
-
const containerHeight = itemHeight * (itemsShownCount - 2) + distance * (itemsShownCount - 2 + 1)
|
|
70
|
-
|
|
71
|
-
const getDirection = useCallback((targetIndex: number, currentIndex: number, transition: number, length: number): Direction => {
|
|
72
|
-
if (targetIndex === currentIndex) {
|
|
73
|
-
return transition > 0 ? up : down
|
|
74
|
-
}
|
|
75
|
-
let distanceForward = targetIndex - currentIndex
|
|
76
|
-
if (distanceForward < 0) {
|
|
77
|
-
distanceForward += length
|
|
78
|
-
}
|
|
79
|
-
return distanceForward >= length / 2 ? down : up
|
|
80
|
-
}, [])
|
|
81
|
-
|
|
82
|
-
const animate = useCallback((timestamp: number, startTime: number | undefined) => {
|
|
83
|
-
setAnimation((prevState) => {
|
|
84
|
-
const {
|
|
85
|
-
targetIndex,
|
|
86
|
-
currentIndex,
|
|
87
|
-
transition,
|
|
88
|
-
animationVelocity,
|
|
89
|
-
velocity,
|
|
90
|
-
items,
|
|
91
|
-
lastScrollTimeStamp
|
|
92
|
-
} = prevState
|
|
93
|
-
if (disabled) {
|
|
94
|
-
return { ...prevState, currentIndex: targetIndex, velocity: 0, lastTimeStamp: timestamp }
|
|
95
|
-
}
|
|
96
|
-
if ((targetIndex === currentIndex && velocity === 0 && transition === 0) || !startTime) {
|
|
97
|
-
return { ...prevState, lastTimeStamp: timestamp }
|
|
98
|
-
}
|
|
99
|
-
const progress = (timestamp - startTime) / 1000 // to seconds
|
|
100
|
-
const direction = getDirection(targetIndex, currentIndex, transition, items.length)
|
|
101
|
-
|
|
102
|
-
let newVelocity = velocity
|
|
103
|
-
let usedVelocity
|
|
104
|
-
let newCurrentIndex = currentIndex
|
|
105
|
-
const isAutoScrolling = velocity === 0 && (!lastScrollTimeStamp || timestamp - lastScrollTimeStamp > 300)
|
|
106
|
-
|
|
107
|
-
const newLastScrollTimeStamp = velocity !== 0 ? timestamp : lastScrollTimeStamp
|
|
108
|
-
|
|
109
|
-
// manual scrolling
|
|
110
|
-
if (isAutoScrolling) {
|
|
111
|
-
usedVelocity = direction * animationVelocity
|
|
112
|
-
} else {
|
|
113
|
-
usedVelocity = velocity
|
|
114
|
-
newVelocity = velocity * 0.5 // drag loss
|
|
115
|
-
if (Math.abs(newVelocity) <= 0.05) {
|
|
116
|
-
newVelocity = 0
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
let newTransition = transition + usedVelocity * progress
|
|
121
|
-
const changeThreshold = 0.5
|
|
122
|
-
|
|
123
|
-
while (newTransition >= changeThreshold) {
|
|
124
|
-
if (newCurrentIndex === targetIndex && newTransition >= changeThreshold && isAutoScrolling) {
|
|
125
|
-
newTransition = 0
|
|
126
|
-
break
|
|
127
|
-
}
|
|
128
|
-
newCurrentIndex = (currentIndex + 1) % items.length
|
|
129
|
-
newTransition -= 1
|
|
130
|
-
}
|
|
131
|
-
if (newTransition >= changeThreshold) {
|
|
132
|
-
newTransition = 0
|
|
133
|
-
}
|
|
134
|
-
while (newTransition <= -changeThreshold) {
|
|
135
|
-
if (newCurrentIndex === targetIndex && newTransition <= -changeThreshold && isAutoScrolling) {
|
|
136
|
-
newTransition = 0
|
|
137
|
-
break
|
|
138
|
-
}
|
|
139
|
-
newCurrentIndex = currentIndex === 0 ? items.length - 1 : currentIndex - 1
|
|
140
|
-
newTransition += 1
|
|
141
|
-
}
|
|
142
|
-
let newTargetIndex = targetIndex
|
|
143
|
-
if (!isAutoScrolling) {
|
|
144
|
-
newTargetIndex = newCurrentIndex
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if ((currentIndex !== newTargetIndex || newTargetIndex !== targetIndex) && newTargetIndex === newCurrentIndex) {
|
|
148
|
-
onChange(items[newCurrentIndex]!)
|
|
149
|
-
}
|
|
150
|
-
return {
|
|
151
|
-
targetIndex: newTargetIndex,
|
|
152
|
-
currentIndex: newCurrentIndex,
|
|
153
|
-
animationVelocity,
|
|
154
|
-
transition: newTransition,
|
|
155
|
-
velocity: newVelocity,
|
|
156
|
-
items,
|
|
157
|
-
lastTimeStamp: timestamp,
|
|
158
|
-
lastScrollTimeStamp: newLastScrollTimeStamp
|
|
159
|
-
}
|
|
160
|
-
})
|
|
161
|
-
}, [disabled, getDirection, onChange])
|
|
162
|
-
|
|
163
|
-
useEffect(() => {
|
|
164
|
-
// constant update
|
|
165
|
-
requestAnimationFrame((timestamp) => animate(timestamp, lastTimeStamp))
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
const opacity = (transition: number, index: number, itemsCount: number) => {
|
|
169
|
-
const max = 100
|
|
170
|
-
const min = 0
|
|
171
|
-
const distance = max - min
|
|
172
|
-
|
|
173
|
-
let opacityValue = min
|
|
174
|
-
const unitTransition = clamp((transition) / 0.5)
|
|
175
|
-
if (index === 1 || index === itemsCount - 2) {
|
|
176
|
-
if (index === 1 && transition > 0) {
|
|
177
|
-
opacityValue += Math.floor(unitTransition * distance)
|
|
178
|
-
}
|
|
179
|
-
if (index === itemsCount - 2 && transition < 0) {
|
|
180
|
-
opacityValue += Math.floor(unitTransition * distance)
|
|
181
|
-
}
|
|
182
|
-
} else {
|
|
183
|
-
opacityValue = max
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// TODO this is not the right value for the bottom entry
|
|
187
|
-
return clamp(1- (opacityValue / max))
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return (
|
|
191
|
-
<div
|
|
192
|
-
className="relative overflow-hidden"
|
|
193
|
-
style={{ height: containerHeight }}
|
|
194
|
-
onWheel={event => {
|
|
195
|
-
if (event.deltaY !== 0) {
|
|
196
|
-
// TODO slower increase
|
|
197
|
-
setAnimation(({ velocity, ...animationData }) =>
|
|
198
|
-
({ ...animationData, velocity: velocity + event.deltaY }))
|
|
199
|
-
}
|
|
200
|
-
}}
|
|
201
|
-
>
|
|
202
|
-
<div className="absolute top-1/2 -translate-y-1/2 -translate-x-1/2 left-1/2">
|
|
203
|
-
<div
|
|
204
|
-
className="absolute z-[1] top-1/2 -translate-y-1/2 -translate-x-1/2 left-1/2 w-full min-w-[40px] border border-y-2 border-x-0 border-[#00000033]"
|
|
205
|
-
style={{ height: `${itemHeight}px` }}
|
|
206
|
-
/>
|
|
207
|
-
<div
|
|
208
|
-
className="col select-none"
|
|
209
|
-
style={{
|
|
210
|
-
transform: `translateY(${-transition * (distance + itemHeight)}px)`,
|
|
211
|
-
columnGap: `${distance}px`,
|
|
212
|
-
}}
|
|
213
|
-
>
|
|
214
|
-
{shownItems.map(({ name, index }, arrayIndex) => (
|
|
215
|
-
<div
|
|
216
|
-
key={index}
|
|
217
|
-
className={clsx(
|
|
218
|
-
`col items-center justify-center rounded-md`,
|
|
219
|
-
{
|
|
220
|
-
'text-primary font-bold': currentIndex === index,
|
|
221
|
-
'text-on-background': currentIndex === index,
|
|
222
|
-
'cursor-pointer': !disabled,
|
|
223
|
-
'cursor-not-allowed': disabled,
|
|
224
|
-
}
|
|
225
|
-
)}
|
|
226
|
-
style={{
|
|
227
|
-
opacity: currentIndex !== index ? opacity(transition, arrayIndex, shownItems.length) : undefined,
|
|
228
|
-
height: `${itemHeight}px`,
|
|
229
|
-
maxHeight: `${itemHeight}px`,
|
|
230
|
-
}}
|
|
231
|
-
onClick={() => !disabled && setAnimation(prevState => ({ ...prevState, targetIndex: index }))}
|
|
232
|
-
>
|
|
233
|
-
{name}
|
|
234
|
-
</div>
|
|
235
|
-
))}
|
|
236
|
-
</div>
|
|
237
|
-
</div>
|
|
238
|
-
</div>
|
|
239
|
-
)
|
|
240
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
|
-
import { Search } from 'lucide-react'
|
|
3
|
-
import { MultiSearchWithMapping } from '../../util/simpleSearch'
|
|
4
|
-
import type { SelectOption, SelectProps } from './Select'
|
|
5
|
-
import { Select } from './Select'
|
|
6
|
-
import { Input } from './Input'
|
|
7
|
-
|
|
8
|
-
export type SearchableSelectProps<T> = SelectProps<T> & {
|
|
9
|
-
searchMapping: (value: SelectOption<T>) => string[],
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* A Select where items can be searched
|
|
14
|
-
*/
|
|
15
|
-
export const SearchableSelect = <T, >({
|
|
16
|
-
value,
|
|
17
|
-
options,
|
|
18
|
-
searchMapping,
|
|
19
|
-
...selectProps
|
|
20
|
-
}: SearchableSelectProps<T>) => {
|
|
21
|
-
const [search, setSearch] = useState<string>('')
|
|
22
|
-
const filteredOptions = MultiSearchWithMapping(search, options, searchMapping)
|
|
23
|
-
return (
|
|
24
|
-
<Select
|
|
25
|
-
value={value}
|
|
26
|
-
options={filteredOptions}
|
|
27
|
-
additionalItems={[(
|
|
28
|
-
<div key="selectSearch" className="row gap-x-2 items-center">
|
|
29
|
-
<Input autoFocus={true} value={search} onChange={setSearch} />
|
|
30
|
-
<Search/>
|
|
31
|
-
</div>
|
|
32
|
-
)]}
|
|
33
|
-
{...selectProps}
|
|
34
|
-
/>
|
|
35
|
-
)
|
|
36
|
-
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { Menu } from '@headlessui/react'
|
|
2
|
-
import { ChevronDown, ChevronUp } from 'lucide-react'
|
|
3
|
-
import type { ReactNode } from 'react'
|
|
4
|
-
import clsx from 'clsx'
|
|
5
|
-
import type { LabelProps } from './Label'
|
|
6
|
-
import { Label } from './Label'
|
|
7
|
-
|
|
8
|
-
export type SelectOption<T> = {
|
|
9
|
-
label: ReactNode,
|
|
10
|
-
value: T,
|
|
11
|
-
disabled?: boolean,
|
|
12
|
-
className?: string,
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type SelectProps<T> = {
|
|
16
|
-
value?: T,
|
|
17
|
-
label?: LabelProps,
|
|
18
|
-
options: SelectOption<T>[],
|
|
19
|
-
onChange: (value: T) => void,
|
|
20
|
-
isHidingCurrentValue?: boolean,
|
|
21
|
-
hintText?: string,
|
|
22
|
-
showDisabledOptions?: boolean,
|
|
23
|
-
className?: string,
|
|
24
|
-
isDisabled?: boolean,
|
|
25
|
-
textColor?: string,
|
|
26
|
-
hoverColor?: string,
|
|
27
|
-
/**
|
|
28
|
-
* The items will be at the start of the select and aren't selectable
|
|
29
|
-
*/
|
|
30
|
-
additionalItems?: ReactNode[],
|
|
31
|
-
selectedDisplayOverwrite?: ReactNode,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* A Select Component for selecting form a list of options
|
|
36
|
-
*
|
|
37
|
-
* The State is managed by the parent
|
|
38
|
-
*/
|
|
39
|
-
export const Select = <T, >({
|
|
40
|
-
value,
|
|
41
|
-
label,
|
|
42
|
-
options,
|
|
43
|
-
onChange,
|
|
44
|
-
isHidingCurrentValue = true,
|
|
45
|
-
hintText = '',
|
|
46
|
-
showDisabledOptions = true,
|
|
47
|
-
isDisabled,
|
|
48
|
-
className,
|
|
49
|
-
textColor = 'text-menu-text',
|
|
50
|
-
hoverColor = 'hover:brightness-90',
|
|
51
|
-
additionalItems,
|
|
52
|
-
selectedDisplayOverwrite,
|
|
53
|
-
}: SelectProps<T>) => {
|
|
54
|
-
// Notice: for more complex types this check here might need an additional compare method
|
|
55
|
-
let filteredOptions = isHidingCurrentValue ? options.filter(option => option.value !== value) : options
|
|
56
|
-
if (!showDisabledOptions) {
|
|
57
|
-
filteredOptions = filteredOptions.filter(value => !value.disabled)
|
|
58
|
-
}
|
|
59
|
-
const selectedOption = options.find(option => option.value === value)
|
|
60
|
-
if (value !== undefined && selectedOption === undefined && selectedDisplayOverwrite === undefined) {
|
|
61
|
-
console.warn('The selected value is not found in the options list. This might be an error on your part or' +
|
|
62
|
-
' default behavior if it is complex data type on which === does not work. In case of the latter' +
|
|
63
|
-
' use selectedDisplayOverwrite to set your selected text or component')
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const borderColor = 'border-menu-border'
|
|
67
|
-
|
|
68
|
-
return (
|
|
69
|
-
<div className={clsx(className)}>
|
|
70
|
-
{label && (
|
|
71
|
-
<Label {...label} labelType={label.labelType ?? 'labelBig'} className={clsx('mb-1', label.className)}/>
|
|
72
|
-
)}
|
|
73
|
-
<Menu as="div" className="relative text-menu-text">
|
|
74
|
-
{({ open }) => (
|
|
75
|
-
<>
|
|
76
|
-
<Menu.Button
|
|
77
|
-
className={clsx(
|
|
78
|
-
'inline-flex w-full justify-between items-center rounded-t-lg border-2 px-4 py-2 font-medium bg-menu-background text-menu-text',
|
|
79
|
-
textColor, borderColor,
|
|
80
|
-
{
|
|
81
|
-
'rounded-b-lg': !open,
|
|
82
|
-
[hoverColor]: !isDisabled,
|
|
83
|
-
'bg-disabled-background cursor-not-allowed text-disabled': isDisabled
|
|
84
|
-
}
|
|
85
|
-
)}
|
|
86
|
-
disabled={isDisabled}
|
|
87
|
-
>
|
|
88
|
-
<span>{selectedDisplayOverwrite ?? selectedOption?.label ?? hintText}</span>
|
|
89
|
-
{open ? <ChevronUp/> : <ChevronDown/>}
|
|
90
|
-
</Menu.Button>
|
|
91
|
-
<Menu.Items
|
|
92
|
-
className="absolute w-full z-10 rounded-b-lg bg-menu-background text-menu-text shadow-lg max-h-[500px] overflow-y-auto"
|
|
93
|
-
>
|
|
94
|
-
{(additionalItems ?? []).map((item, index) => (
|
|
95
|
-
<div key={`additionalItems${index}`}
|
|
96
|
-
className={clsx(borderColor, 'px-4 py-2 overflow-hidden whitespace-nowrap text-ellipsis border-2 border-t-0', {
|
|
97
|
-
'border-b-0 rounded-b-lg': filteredOptions.length === 0 && index === (additionalItems?.length ?? 1) - 1,
|
|
98
|
-
})}
|
|
99
|
-
>
|
|
100
|
-
{item}
|
|
101
|
-
</div>
|
|
102
|
-
))}
|
|
103
|
-
{filteredOptions.map((option, index) => (
|
|
104
|
-
<Menu.Item key={`item${index}`}>
|
|
105
|
-
{
|
|
106
|
-
<div
|
|
107
|
-
className={clsx('px-4 py-2 overflow-hidden whitespace-nowrap text-ellipsis border-2 border-t-0 cursor-pointer',
|
|
108
|
-
option.className, borderColor, {
|
|
109
|
-
'brightness-90': option.value === value,
|
|
110
|
-
'brightness-95': index % 2 === 1,
|
|
111
|
-
'text-disabled bg-disabled-background cursor-not-allowed': !!option.disabled,
|
|
112
|
-
'bg-menu-background text-menu-text hover:brightness-90 cursor-pointer': !option.disabled,
|
|
113
|
-
'rounded-b-lg': index === filteredOptions.length - 1,
|
|
114
|
-
})}
|
|
115
|
-
onClick={() => {
|
|
116
|
-
if (!option.disabled) {
|
|
117
|
-
onChange(option.value)
|
|
118
|
-
}
|
|
119
|
-
}}
|
|
120
|
-
>
|
|
121
|
-
{option.label}
|
|
122
|
-
</div>
|
|
123
|
-
}
|
|
124
|
-
</Menu.Item>
|
|
125
|
-
))}
|
|
126
|
-
</Menu.Items>
|
|
127
|
-
</>
|
|
128
|
-
)}
|
|
129
|
-
</Menu>
|
|
130
|
-
</div>
|
|
131
|
-
)
|
|
132
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type { TextareaHTMLAttributes } from 'react'
|
|
2
|
-
import { useState } from 'react'
|
|
3
|
-
import clsx from 'clsx'
|
|
4
|
-
import useSaveDelay from '../../hooks/useSaveDelay'
|
|
5
|
-
import { noop } from '../../util/noop'
|
|
6
|
-
import type { LabelProps } from './Label'
|
|
7
|
-
import { Label } from './Label'
|
|
8
|
-
|
|
9
|
-
export type TextareaProps = {
|
|
10
|
-
/** Outside the area */
|
|
11
|
-
label?: Omit<LabelProps, 'id'>,
|
|
12
|
-
/** Inside the area */
|
|
13
|
-
headline?: string,
|
|
14
|
-
id?: string,
|
|
15
|
-
resizable?: boolean,
|
|
16
|
-
onChange?: (text: string) => void,
|
|
17
|
-
disclaimer?: string,
|
|
18
|
-
onEditCompleted?: (text: string) => void,
|
|
19
|
-
defaultStyle?: boolean,
|
|
20
|
-
} & Omit<TextareaHTMLAttributes<Element>, 'id' | 'onChange'>
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* A Textarea component for inputting longer texts
|
|
24
|
-
*
|
|
25
|
-
* The State is managed by the parent
|
|
26
|
-
*/
|
|
27
|
-
export const Textarea = ({
|
|
28
|
-
label,
|
|
29
|
-
headline,
|
|
30
|
-
id,
|
|
31
|
-
resizable = false,
|
|
32
|
-
onChange = noop,
|
|
33
|
-
disclaimer,
|
|
34
|
-
onBlur = noop,
|
|
35
|
-
onEditCompleted = noop,
|
|
36
|
-
defaultStyle = true,
|
|
37
|
-
className,
|
|
38
|
-
...props
|
|
39
|
-
}: TextareaProps) => {
|
|
40
|
-
const [hasFocus, setHasFocus] = useState(false)
|
|
41
|
-
const { restartTimer, clearUpdateTimer } = useSaveDelay(() => undefined, 3000)
|
|
42
|
-
|
|
43
|
-
const onEditCompletedWrapper = (text: string) => {
|
|
44
|
-
onEditCompleted(text)
|
|
45
|
-
clearUpdateTimer()
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<div className="w-full">
|
|
50
|
-
{label && (<Label {...label} htmlFor={id} className={clsx('mb-1', label.className)} labelType={label.labelType ?? 'labelSmall'}/>)}
|
|
51
|
-
<div className={`${clsx(' bg-surface text-on-surface focus-within:border-primary relative', { 'shadow border-2 border-gray-300 hover:border-primary rounded-lg': defaultStyle })}`}>
|
|
52
|
-
{headline && (
|
|
53
|
-
<span className="mx-3 mt-3 block text-gray-700 font-bold">
|
|
54
|
-
{headline}
|
|
55
|
-
</span>
|
|
56
|
-
)}
|
|
57
|
-
<textarea
|
|
58
|
-
id={id}
|
|
59
|
-
className={clsx('pt-0 px-3 border-transparent focus:border-transparent focus:ring-0 appearance-none border w-full leading-tight focus:outline-none', { 'resize-none': !resizable, 'h-32': defaultStyle, 'mt-3': !headline }, className)}
|
|
60
|
-
onChange={(event) => {
|
|
61
|
-
const value = event.target.value
|
|
62
|
-
restartTimer(() => {
|
|
63
|
-
onEditCompletedWrapper(value)
|
|
64
|
-
})
|
|
65
|
-
onChange(value)
|
|
66
|
-
}}
|
|
67
|
-
onFocus={() => {
|
|
68
|
-
setHasFocus(true)
|
|
69
|
-
}}
|
|
70
|
-
onBlur={(event) => {
|
|
71
|
-
onBlur(event)
|
|
72
|
-
onEditCompletedWrapper(event.target.value)
|
|
73
|
-
setHasFocus(false)
|
|
74
|
-
}}
|
|
75
|
-
{...props}
|
|
76
|
-
>
|
|
77
|
-
</textarea>
|
|
78
|
-
</div>
|
|
79
|
-
{(hasFocus && disclaimer) && (
|
|
80
|
-
<label className="text-negative">
|
|
81
|
-
{disclaimer}
|
|
82
|
-
</label>
|
|
83
|
-
)}
|
|
84
|
-
</div>
|
|
85
|
-
)
|
|
86
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
|
-
import type { HTMLInputTypeAttribute, InputHTMLAttributes } from 'react'
|
|
3
|
-
import { Pencil } from 'lucide-react'
|
|
4
|
-
import clsx from 'clsx'
|
|
5
|
-
import useSaveDelay from '../../hooks/useSaveDelay'
|
|
6
|
-
import { noop } from '../../util/noop'
|
|
7
|
-
|
|
8
|
-
type InputProps = {
|
|
9
|
-
/**
|
|
10
|
-
* used for the label's `for` attribute
|
|
11
|
-
*/
|
|
12
|
-
id: string,
|
|
13
|
-
value: string,
|
|
14
|
-
/**
|
|
15
|
-
* @default 'text'
|
|
16
|
-
*/
|
|
17
|
-
type?: HTMLInputTypeAttribute,
|
|
18
|
-
/**
|
|
19
|
-
* Callback for when the input's value changes
|
|
20
|
-
* This is pretty much required but made optional for the rare cases where it actually isn't need such as when used with disabled
|
|
21
|
-
* That could be enforced through a union type but that seems a bit overkill
|
|
22
|
-
* @default noop
|
|
23
|
-
*/
|
|
24
|
-
onChange?: (text: string) => void,
|
|
25
|
-
labelClassName?: string,
|
|
26
|
-
initialState?: 'editing' | 'display',
|
|
27
|
-
size?: number,
|
|
28
|
-
disclaimer?: string,
|
|
29
|
-
onEditCompleted?: (text: string) => void,
|
|
30
|
-
} & Omit<InputHTMLAttributes<HTMLInputElement>, 'id' | 'value' | 'label' | 'type' | 'onChange' | 'crossOrigin'>
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* A Text input component for inputting text. It changes appearance upon entering the edit mode and switches
|
|
34
|
-
* back to display mode on loss of focus or on enter
|
|
35
|
-
*
|
|
36
|
-
* The State is managed by the parent
|
|
37
|
-
*/
|
|
38
|
-
export const ToggleableInput = ({
|
|
39
|
-
id,
|
|
40
|
-
type = 'text',
|
|
41
|
-
value,
|
|
42
|
-
onChange = noop,
|
|
43
|
-
labelClassName = '',
|
|
44
|
-
initialState = 'display',
|
|
45
|
-
size = 20,
|
|
46
|
-
disclaimer,
|
|
47
|
-
onBlur,
|
|
48
|
-
onEditCompleted = noop,
|
|
49
|
-
...restProps
|
|
50
|
-
}: InputProps) => {
|
|
51
|
-
const [isEditing, setIsEditing] = useState(initialState !== 'display')
|
|
52
|
-
const { restartTimer, clearUpdateTimer } = useSaveDelay(() => undefined, 3000)
|
|
53
|
-
|
|
54
|
-
const onEditCompletedWrapper = (text: string) => {
|
|
55
|
-
onEditCompleted(text)
|
|
56
|
-
clearUpdateTimer()
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
<div>
|
|
61
|
-
<div
|
|
62
|
-
className="row items-center w-full gap-x-2 overflow-hidden"
|
|
63
|
-
onClick={() => !isEditing ? setIsEditing(!isEditing) : undefined}
|
|
64
|
-
>
|
|
65
|
-
<div className={clsx('row overflow-hidden', { 'flex-1': isEditing })}>
|
|
66
|
-
{isEditing ? (
|
|
67
|
-
<input
|
|
68
|
-
autoFocus
|
|
69
|
-
{...restProps}
|
|
70
|
-
value={value}
|
|
71
|
-
type={type}
|
|
72
|
-
id={id}
|
|
73
|
-
onChange={event => {
|
|
74
|
-
const value = event.target.value
|
|
75
|
-
restartTimer(() => {
|
|
76
|
-
onEditCompletedWrapper(value)
|
|
77
|
-
})
|
|
78
|
-
onChange(value)
|
|
79
|
-
}}
|
|
80
|
-
onBlur={(event) => {
|
|
81
|
-
if (onBlur) {
|
|
82
|
-
onBlur(event)
|
|
83
|
-
}
|
|
84
|
-
onEditCompletedWrapper(value)
|
|
85
|
-
setIsEditing(false)
|
|
86
|
-
}}
|
|
87
|
-
onKeyDown={event => {
|
|
88
|
-
if (event.key === 'Enter') {
|
|
89
|
-
setIsEditing(false)
|
|
90
|
-
onEditCompletedWrapper(value)
|
|
91
|
-
}
|
|
92
|
-
}}
|
|
93
|
-
className={clsx(labelClassName, `w-full border-none rounded-none focus:ring-0 shadow-transparent decoration-primary p-0 underline-offset-4`, {
|
|
94
|
-
underline: isEditing
|
|
95
|
-
})}
|
|
96
|
-
onFocus={event => event.target.select()}
|
|
97
|
-
/>
|
|
98
|
-
) : (
|
|
99
|
-
<span
|
|
100
|
-
className={clsx(labelClassName, 'max-w-xs break-words overflow-hidden')}
|
|
101
|
-
>
|
|
102
|
-
{value}
|
|
103
|
-
</span>
|
|
104
|
-
)}
|
|
105
|
-
</div>
|
|
106
|
-
<Pencil className={clsx(`min-w-[${size}px] cursor-pointer`, { 'text-transparent': isEditing })} size={size} />
|
|
107
|
-
</div>
|
|
108
|
-
{(isEditing && disclaimer) && (
|
|
109
|
-
<label className="text-negative">
|
|
110
|
-
{disclaimer}
|
|
111
|
-
</label>
|
|
112
|
-
)}
|
|
113
|
-
</div>
|
|
114
|
-
)
|
|
115
|
-
}
|
package/hooks/useHoverState.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import type { Dispatch, SetStateAction } from 'react'
|
|
2
|
-
import { useEffect, useState } from 'react'
|
|
3
|
-
|
|
4
|
-
type UseHoverStateProps = {
|
|
5
|
-
/**
|
|
6
|
-
* The delay after which the menu is closed in milliseconds
|
|
7
|
-
*
|
|
8
|
-
* default: 200ms
|
|
9
|
-
*/
|
|
10
|
-
closingDelay: number,
|
|
11
|
-
/**
|
|
12
|
-
* Whether the hover state management should be disabled
|
|
13
|
-
*
|
|
14
|
-
* default: false
|
|
15
|
-
*/
|
|
16
|
-
isDisabled: boolean,
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
type UseHoverStateReturnType = {
|
|
20
|
-
/**
|
|
21
|
-
* Whether the element is hovered
|
|
22
|
-
*/
|
|
23
|
-
isHovered: boolean,
|
|
24
|
-
/**
|
|
25
|
-
* Function to change the current hover status
|
|
26
|
-
*/
|
|
27
|
-
setIsHovered: Dispatch<SetStateAction<boolean>>,
|
|
28
|
-
/**
|
|
29
|
-
* Handlers to pass on to the component that should be hovered
|
|
30
|
-
*/
|
|
31
|
-
handlers: {
|
|
32
|
-
onMouseEnter: () => void,
|
|
33
|
-
onMouseLeave: () => void,
|
|
34
|
-
},
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const defaultUseHoverStateProps: UseHoverStateProps = {
|
|
38
|
-
closingDelay: 200,
|
|
39
|
-
isDisabled: false,
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @param props See UseHoverStateProps
|
|
44
|
-
*
|
|
45
|
-
* A react hook for managing the hover state of a component. The handlers provided should be
|
|
46
|
-
* forwarded to the component which should be hovered over
|
|
47
|
-
*/
|
|
48
|
-
export const useHoverState = (props: Partial<UseHoverStateProps> | undefined = undefined): UseHoverStateReturnType => {
|
|
49
|
-
const { closingDelay, isDisabled } = { ...defaultUseHoverStateProps, ...props }
|
|
50
|
-
|
|
51
|
-
const [isHovered, setIsHovered] = useState(false)
|
|
52
|
-
const [timer, setTimer] = useState<NodeJS.Timeout>()
|
|
53
|
-
|
|
54
|
-
const onMouseEnter = () => {
|
|
55
|
-
if (isDisabled) {
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
clearTimeout(timer)
|
|
59
|
-
setIsHovered(true)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const onMouseLeave = () => {
|
|
63
|
-
if (isDisabled) {
|
|
64
|
-
return
|
|
65
|
-
}
|
|
66
|
-
setTimer(setTimeout(() => {
|
|
67
|
-
setIsHovered(false)
|
|
68
|
-
}, closingDelay))
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
if (timer) {
|
|
73
|
-
return () => {
|
|
74
|
-
clearTimeout(timer)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
useEffect(() => {
|
|
80
|
-
if (timer) {
|
|
81
|
-
clearTimeout(timer)
|
|
82
|
-
}
|
|
83
|
-
}, [isDisabled]) // eslint-disable-line react-hooks/exhaustive-deps
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
isHovered, setIsHovered, handlers: { onMouseEnter, onMouseLeave }
|
|
87
|
-
}
|
|
88
|
-
}
|