@helpwave/hightide 0.1.7 → 0.1.8
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/branding/HelpwaveBadge.js +30 -8
- package/dist/components/branding/HelpwaveBadge.js.map +1 -1
- package/dist/components/branding/HelpwaveBadge.mjs +30 -8
- package/dist/components/branding/HelpwaveBadge.mjs.map +1 -1
- package/dist/components/date/DatePicker.js +18 -20
- package/dist/components/date/DatePicker.js.map +1 -1
- package/dist/components/date/DatePicker.mjs +18 -20
- package/dist/components/date/DatePicker.mjs.map +1 -1
- package/dist/components/date/DayPicker.d.mts +1 -1
- package/dist/components/date/DayPicker.d.ts +1 -1
- package/dist/components/date/DayPicker.js +23 -11
- package/dist/components/date/DayPicker.js.map +1 -1
- package/dist/components/date/DayPicker.mjs +23 -11
- package/dist/components/date/DayPicker.mjs.map +1 -1
- package/dist/components/date/YearMonthPicker.js +106 -22
- package/dist/components/date/YearMonthPicker.js.map +1 -1
- package/dist/components/date/YearMonthPicker.mjs +106 -22
- package/dist/components/date/YearMonthPicker.mjs.map +1 -1
- package/dist/components/dialogs/ConfirmDialog.js +2 -2
- package/dist/components/dialogs/ConfirmDialog.js.map +1 -1
- package/dist/components/dialogs/ConfirmDialog.mjs +2 -2
- package/dist/components/dialogs/ConfirmDialog.mjs.map +1 -1
- package/dist/components/icons-and-geometry/Avatar.js +2 -2
- package/dist/components/icons-and-geometry/Avatar.js.map +1 -1
- package/dist/components/icons-and-geometry/Avatar.mjs +2 -2
- package/dist/components/icons-and-geometry/Avatar.mjs.map +1 -1
- package/dist/components/layout-and-navigation/Carousel.d.mts +1 -1
- package/dist/components/layout-and-navigation/Carousel.d.ts +1 -1
- package/dist/components/layout-and-navigation/Carousel.js +86 -28
- package/dist/components/layout-and-navigation/Carousel.js.map +1 -1
- package/dist/components/layout-and-navigation/Carousel.mjs +86 -28
- package/dist/components/layout-and-navigation/Carousel.mjs.map +1 -1
- package/dist/components/layout-and-navigation/Expandable.d.mts +3 -0
- package/dist/components/layout-and-navigation/Expandable.d.ts +3 -0
- package/dist/components/layout-and-navigation/Expandable.js +4 -3
- package/dist/components/layout-and-navigation/Expandable.js.map +1 -1
- package/dist/components/layout-and-navigation/Expandable.mjs +4 -3
- package/dist/components/layout-and-navigation/Expandable.mjs.map +1 -1
- package/dist/components/layout-and-navigation/FAQSection.js +4 -3
- package/dist/components/layout-and-navigation/FAQSection.js.map +1 -1
- package/dist/components/layout-and-navigation/FAQSection.mjs +4 -3
- package/dist/components/layout-and-navigation/FAQSection.mjs.map +1 -1
- package/dist/components/layout-and-navigation/Overlay.js +2 -2
- package/dist/components/layout-and-navigation/Overlay.js.map +1 -1
- package/dist/components/layout-and-navigation/Overlay.mjs +2 -2
- package/dist/components/layout-and-navigation/Overlay.mjs.map +1 -1
- package/dist/components/layout-and-navigation/SearchableList.d.mts +7 -6
- package/dist/components/layout-and-navigation/SearchableList.d.ts +7 -6
- package/dist/components/layout-and-navigation/SearchableList.js +114 -21
- package/dist/components/layout-and-navigation/SearchableList.js.map +1 -1
- package/dist/components/layout-and-navigation/SearchableList.mjs +114 -21
- package/dist/components/layout-and-navigation/SearchableList.mjs.map +1 -1
- package/dist/components/layout-and-navigation/StepperBar.js +6 -6
- package/dist/components/layout-and-navigation/StepperBar.js.map +1 -1
- package/dist/components/layout-and-navigation/StepperBar.mjs +6 -6
- package/dist/components/layout-and-navigation/StepperBar.mjs.map +1 -1
- package/dist/components/layout-and-navigation/Table.js +1 -1
- package/dist/components/layout-and-navigation/Table.js.map +1 -1
- package/dist/components/layout-and-navigation/Table.mjs +1 -1
- package/dist/components/layout-and-navigation/Table.mjs.map +1 -1
- package/dist/components/layout-and-navigation/Tile.d.mts +10 -15
- package/dist/components/layout-and-navigation/Tile.d.ts +10 -15
- package/dist/components/layout-and-navigation/Tile.js +30 -8
- package/dist/components/layout-and-navigation/Tile.js.map +1 -1
- package/dist/components/layout-and-navigation/Tile.mjs +30 -8
- package/dist/components/layout-and-navigation/Tile.mjs.map +1 -1
- package/dist/components/loading-states/ProgressIndicator.js +2 -2
- package/dist/components/loading-states/ProgressIndicator.js.map +1 -1
- package/dist/components/loading-states/ProgressIndicator.mjs +2 -2
- package/dist/components/loading-states/ProgressIndicator.mjs.map +1 -1
- package/dist/components/modals/ConfirmModal.js +2 -2
- package/dist/components/modals/ConfirmModal.js.map +1 -1
- package/dist/components/modals/ConfirmModal.mjs +2 -2
- package/dist/components/modals/ConfirmModal.mjs.map +1 -1
- package/dist/components/modals/DiscardChangesModal.js +2 -2
- package/dist/components/modals/DiscardChangesModal.js.map +1 -1
- package/dist/components/modals/DiscardChangesModal.mjs +2 -2
- package/dist/components/modals/DiscardChangesModal.mjs.map +1 -1
- package/dist/components/modals/InputModal.js +2 -2
- package/dist/components/modals/InputModal.js.map +1 -1
- package/dist/components/modals/InputModal.mjs +2 -2
- package/dist/components/modals/InputModal.mjs.map +1 -1
- package/dist/components/modals/LanguageModal.js +384 -150
- package/dist/components/modals/LanguageModal.js.map +1 -1
- package/dist/components/modals/LanguageModal.mjs +383 -149
- package/dist/components/modals/LanguageModal.mjs.map +1 -1
- package/dist/components/modals/ThemeModal.js +385 -154
- package/dist/components/modals/ThemeModal.js.map +1 -1
- package/dist/components/modals/ThemeModal.mjs +382 -151
- package/dist/components/modals/ThemeModal.mjs.map +1 -1
- package/dist/components/properties/CheckboxProperty.js +1 -1
- package/dist/components/properties/CheckboxProperty.js.map +1 -1
- package/dist/components/properties/CheckboxProperty.mjs +1 -1
- package/dist/components/properties/CheckboxProperty.mjs.map +1 -1
- package/dist/components/properties/DateProperty.js +1 -1
- package/dist/components/properties/DateProperty.js.map +1 -1
- package/dist/components/properties/DateProperty.mjs +1 -1
- package/dist/components/properties/DateProperty.mjs.map +1 -1
- package/dist/components/properties/MultiSelectProperty.d.mts +1 -0
- package/dist/components/properties/MultiSelectProperty.d.ts +1 -0
- package/dist/components/properties/MultiSelectProperty.js +482 -430
- package/dist/components/properties/MultiSelectProperty.js.map +1 -1
- package/dist/components/properties/MultiSelectProperty.mjs +478 -426
- package/dist/components/properties/MultiSelectProperty.mjs.map +1 -1
- package/dist/components/properties/NumberProperty.js +1 -1
- package/dist/components/properties/NumberProperty.js.map +1 -1
- package/dist/components/properties/NumberProperty.mjs +1 -1
- package/dist/components/properties/NumberProperty.mjs.map +1 -1
- package/dist/components/properties/PropertyBase.js +1 -1
- package/dist/components/properties/PropertyBase.js.map +1 -1
- package/dist/components/properties/PropertyBase.mjs +1 -1
- package/dist/components/properties/PropertyBase.mjs.map +1 -1
- package/dist/components/properties/SelectProperty.d.mts +3 -3
- package/dist/components/properties/SelectProperty.d.ts +3 -3
- package/dist/components/properties/SelectProperty.js +404 -263
- package/dist/components/properties/SelectProperty.js.map +1 -1
- package/dist/components/properties/SelectProperty.mjs +404 -263
- package/dist/components/properties/SelectProperty.mjs.map +1 -1
- package/dist/components/properties/TextProperty.js +1 -1
- package/dist/components/properties/TextProperty.js.map +1 -1
- package/dist/components/properties/TextProperty.mjs +1 -1
- package/dist/components/properties/TextProperty.mjs.map +1 -1
- package/dist/components/user-action/DateAndTimePicker.js +18 -20
- package/dist/components/user-action/DateAndTimePicker.js.map +1 -1
- package/dist/components/user-action/DateAndTimePicker.mjs +18 -20
- package/dist/components/user-action/DateAndTimePicker.mjs.map +1 -1
- package/dist/components/user-action/Menu.d.mts +14 -8
- package/dist/components/user-action/Menu.d.ts +14 -8
- package/dist/components/user-action/Menu.js +32 -11
- package/dist/components/user-action/Menu.js.map +1 -1
- package/dist/components/user-action/Menu.mjs +32 -11
- package/dist/components/user-action/Menu.mjs.map +1 -1
- package/dist/components/user-action/MultiSelect.d.mts +10 -16
- package/dist/components/user-action/MultiSelect.d.ts +10 -16
- package/dist/components/user-action/MultiSelect.js +485 -312
- package/dist/components/user-action/MultiSelect.js.map +1 -1
- package/dist/components/user-action/MultiSelect.mjs +482 -310
- package/dist/components/user-action/MultiSelect.mjs.map +1 -1
- package/dist/components/user-action/Select.d.mts +5 -18
- package/dist/components/user-action/Select.d.ts +5 -18
- package/dist/components/user-action/Select.js +309 -113
- package/dist/components/user-action/Select.js.map +1 -1
- package/dist/components/user-action/Select.mjs +304 -107
- package/dist/components/user-action/Select.mjs.map +1 -1
- package/dist/components/user-action/Tooltip.js +2 -2
- package/dist/components/user-action/Tooltip.js.map +1 -1
- package/dist/components/user-action/Tooltip.mjs +2 -2
- package/dist/components/user-action/Tooltip.mjs.map +1 -1
- package/dist/css/globals.css +213 -205
- package/dist/css/uncompiled/globals.css +136 -72
- package/dist/hooks/useSearch.d.mts +17 -0
- package/dist/hooks/useSearch.d.ts +17 -0
- package/dist/hooks/useSearch.js +66 -0
- package/dist/hooks/useSearch.js.map +1 -0
- package/dist/hooks/useSearch.mjs +42 -0
- package/dist/hooks/useSearch.mjs.map +1 -0
- package/dist/index.d.mts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +555 -463
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +517 -427
- package/dist/index.mjs.map +1 -1
- package/dist/util/PropsWithFunctionChildren.d.mts +14 -0
- package/dist/util/PropsWithFunctionChildren.d.ts +14 -0
- package/dist/util/PropsWithFunctionChildren.js +38 -0
- package/dist/util/PropsWithFunctionChildren.js.map +1 -0
- package/dist/util/PropsWithFunctionChildren.mjs +14 -0
- package/dist/util/PropsWithFunctionChildren.mjs.map +1 -0
- package/dist/util/simpleSearch.d.mts +2 -2
- package/dist/util/simpleSearch.d.ts +2 -2
- package/dist/util/simpleSearch.js +4 -1
- package/dist/util/simpleSearch.js.map +1 -1
- package/dist/util/simpleSearch.mjs +4 -1
- package/dist/util/simpleSearch.mjs.map +1 -1
- package/package.json +1 -2
|
@@ -28,7 +28,7 @@ var range = (start, end, allowEmptyRange = false) => {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
// src/components/date/YearMonthPicker.tsx
|
|
31
|
-
import
|
|
31
|
+
import clsx3 from "clsx";
|
|
32
32
|
|
|
33
33
|
// src/components/layout-and-navigation/Expandable.tsx
|
|
34
34
|
import { forwardRef, useEffect, useState } from "react";
|
|
@@ -44,8 +44,9 @@ var Expandable = forwardRef(function Expandable2({
|
|
|
44
44
|
onChange = noop,
|
|
45
45
|
clickOnlyOnHeader = true,
|
|
46
46
|
disabled = false,
|
|
47
|
-
className
|
|
48
|
-
headerClassName
|
|
47
|
+
className,
|
|
48
|
+
headerClassName,
|
|
49
|
+
contentClassName
|
|
49
50
|
}, ref) {
|
|
50
51
|
icon ??= DefaultIcon;
|
|
51
52
|
return /* @__PURE__ */ jsxs(
|
|
@@ -74,7 +75,7 @@ var Expandable = forwardRef(function Expandable2({
|
|
|
74
75
|
]
|
|
75
76
|
}
|
|
76
77
|
),
|
|
77
|
-
isExpanded && /* @__PURE__ */ jsx("div", { className: "col px-4 pb-2", children })
|
|
78
|
+
isExpanded && /* @__PURE__ */ jsx("div", { className: clsx("col px-4 pb-2", contentClassName), children })
|
|
78
79
|
]
|
|
79
80
|
}
|
|
80
81
|
);
|
|
@@ -195,8 +196,95 @@ var useLocale = (overWriteLanguage) => {
|
|
|
195
196
|
return mapping[overWriteLanguage ?? language];
|
|
196
197
|
};
|
|
197
198
|
|
|
199
|
+
// src/components/user-action/Button.tsx
|
|
200
|
+
import clsx2 from "clsx";
|
|
201
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
202
|
+
var paddingMapping = {
|
|
203
|
+
small: "btn-sm",
|
|
204
|
+
medium: "btn-md",
|
|
205
|
+
large: "btn-lg"
|
|
206
|
+
};
|
|
207
|
+
var iconPaddingMapping = {
|
|
208
|
+
small: "icon-btn-sm",
|
|
209
|
+
medium: "icon-btn-md",
|
|
210
|
+
large: "icon-btn-lg"
|
|
211
|
+
};
|
|
212
|
+
var ButtonUtil = {
|
|
213
|
+
paddingMapping,
|
|
214
|
+
iconPaddingMapping
|
|
215
|
+
};
|
|
216
|
+
var SolidButton = ({
|
|
217
|
+
children,
|
|
218
|
+
disabled = false,
|
|
219
|
+
color = "primary",
|
|
220
|
+
size = "medium",
|
|
221
|
+
startIcon,
|
|
222
|
+
endIcon,
|
|
223
|
+
onClick,
|
|
224
|
+
className,
|
|
225
|
+
...restProps
|
|
226
|
+
}) => {
|
|
227
|
+
const colorClasses = {
|
|
228
|
+
primary: "bg-button-solid-primary-background text-button-solid-primary-text",
|
|
229
|
+
secondary: "bg-button-solid-secondary-background text-button-solid-secondary-text",
|
|
230
|
+
tertiary: "bg-button-solid-tertiary-background text-button-solid-tertiary-text",
|
|
231
|
+
positive: "bg-button-solid-positive-background text-button-solid-positive-text",
|
|
232
|
+
warning: "bg-button-solid-warning-background text-button-solid-warning-text",
|
|
233
|
+
negative: "bg-button-solid-negative-background text-button-solid-negative-text",
|
|
234
|
+
neutral: "bg-button-solid-neutral-background text-button-solid-neutral-text"
|
|
235
|
+
}[color];
|
|
236
|
+
const iconColorClasses = {
|
|
237
|
+
primary: "text-button-solid-primary-icon",
|
|
238
|
+
secondary: "text-button-solid-secondary-icon",
|
|
239
|
+
tertiary: "text-button-solid-tertiary-icon",
|
|
240
|
+
positive: "text-button-solid-positive-icon",
|
|
241
|
+
warning: "text-button-solid-warning-icon",
|
|
242
|
+
negative: "text-button-solid-negative-icon",
|
|
243
|
+
neutral: "text-button-solid-neutral-icon"
|
|
244
|
+
}[color];
|
|
245
|
+
return /* @__PURE__ */ jsxs2(
|
|
246
|
+
"button",
|
|
247
|
+
{
|
|
248
|
+
onClick: disabled ? void 0 : onClick,
|
|
249
|
+
disabled: disabled || onClick === void 0,
|
|
250
|
+
className: clsx2(
|
|
251
|
+
{
|
|
252
|
+
"text-disabled-text bg-disabled-background cursor-not-allowed": disabled,
|
|
253
|
+
[clsx2(colorClasses, "hover:brightness-90")]: !disabled
|
|
254
|
+
},
|
|
255
|
+
ButtonUtil.paddingMapping[size],
|
|
256
|
+
className
|
|
257
|
+
),
|
|
258
|
+
...restProps,
|
|
259
|
+
children: [
|
|
260
|
+
startIcon && /* @__PURE__ */ jsx3(
|
|
261
|
+
"span",
|
|
262
|
+
{
|
|
263
|
+
className: clsx2({
|
|
264
|
+
[iconColorClasses]: !disabled,
|
|
265
|
+
[`text-disabled-icon`]: disabled
|
|
266
|
+
}),
|
|
267
|
+
children: startIcon
|
|
268
|
+
}
|
|
269
|
+
),
|
|
270
|
+
children,
|
|
271
|
+
endIcon && /* @__PURE__ */ jsx3(
|
|
272
|
+
"span",
|
|
273
|
+
{
|
|
274
|
+
className: clsx2({
|
|
275
|
+
[iconColorClasses]: !disabled,
|
|
276
|
+
[`text-disabled-icon`]: disabled
|
|
277
|
+
}),
|
|
278
|
+
children: endIcon
|
|
279
|
+
}
|
|
280
|
+
)
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
);
|
|
284
|
+
};
|
|
285
|
+
|
|
198
286
|
// src/components/date/YearMonthPicker.tsx
|
|
199
|
-
import { jsx as
|
|
287
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
200
288
|
var YearMonthPicker = ({
|
|
201
289
|
displayedYearMonth = /* @__PURE__ */ new Date(),
|
|
202
290
|
start = subtractDuration(/* @__PURE__ */ new Date(), { years: 50 }),
|
|
@@ -224,15 +312,16 @@ var YearMonthPicker = ({
|
|
|
224
312
|
return null;
|
|
225
313
|
}
|
|
226
314
|
const years = range(start.getFullYear(), end.getFullYear());
|
|
227
|
-
return /* @__PURE__ */
|
|
315
|
+
return /* @__PURE__ */ jsx4("div", { className: clsx3("col select-none", className), children: /* @__PURE__ */ jsx4(Scrollbars, { autoHeight: true, autoHeightMax: maxHeight, style: { height: "100%" }, children: /* @__PURE__ */ jsx4("div", { className: "col gap-y-1 mr-3", children: years.map((year) => {
|
|
228
316
|
const selectedYear = displayedYearMonth.getFullYear() === year;
|
|
229
|
-
return /* @__PURE__ */
|
|
317
|
+
return /* @__PURE__ */ jsx4(
|
|
230
318
|
ExpandableUncontrolled,
|
|
231
319
|
{
|
|
232
320
|
ref: (displayedYearMonth.getFullYear() ?? (/* @__PURE__ */ new Date()).getFullYear()) === year ? ref : void 0,
|
|
233
|
-
label: /* @__PURE__ */
|
|
321
|
+
label: /* @__PURE__ */ jsx4("span", { className: clsx3({ "text-primary font-bold": selectedYear }), children: year }),
|
|
234
322
|
isExpanded: showValueOpen && selectedYear,
|
|
235
|
-
|
|
323
|
+
contentClassName: "gap-y-1",
|
|
324
|
+
children: equalSizeGroups([...monthsList], 3).map((monthList, index) => /* @__PURE__ */ jsx4("div", { className: "row gap-x-1", children: monthList.map((month) => {
|
|
236
325
|
const monthIndex = monthsList.indexOf(month);
|
|
237
326
|
const newDate = new Date(year, monthIndex);
|
|
238
327
|
const selectedMonth = selectedYear && monthIndex === displayedYearMonth.getMonth();
|
|
@@ -241,18 +330,13 @@ var YearMonthPicker = ({
|
|
|
241
330
|
const isAfterStart = start === void 0 || start <= addDuration(subtractDuration(lastOfMonth, { days: 1 }), { months: 1 });
|
|
242
331
|
const isBeforeEnd = end === void 0 || firstOfMonth <= end;
|
|
243
332
|
const isValid = isAfterStart && isBeforeEnd;
|
|
244
|
-
return /* @__PURE__ */
|
|
245
|
-
|
|
333
|
+
return /* @__PURE__ */ jsx4(
|
|
334
|
+
SolidButton,
|
|
246
335
|
{
|
|
247
336
|
disabled: !isValid,
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
"bg-gray-50 text-black": !selectedMonth && isValid,
|
|
252
|
-
"bg-primary text-on-primary": selectedMonth && isValid,
|
|
253
|
-
"bg-disabled-background text-disabled-text": !isValid
|
|
254
|
-
}
|
|
255
|
-
),
|
|
337
|
+
color: selectedMonth && isValid ? "primary" : "neutral",
|
|
338
|
+
className: "flex-1",
|
|
339
|
+
size: "small",
|
|
256
340
|
onClick: () => {
|
|
257
341
|
onChange(newDate);
|
|
258
342
|
},
|
|
@@ -267,13 +351,13 @@ var YearMonthPicker = ({
|
|
|
267
351
|
}) }) }) });
|
|
268
352
|
};
|
|
269
353
|
var YearMonthPickerUncontrolled = ({
|
|
270
|
-
displayedYearMonth
|
|
354
|
+
displayedYearMonth,
|
|
271
355
|
onChange = noop,
|
|
272
356
|
...props
|
|
273
357
|
}) => {
|
|
274
|
-
const [yearMonth, setYearMonth] = useState4(displayedYearMonth);
|
|
358
|
+
const [yearMonth, setYearMonth] = useState4(displayedYearMonth ?? /* @__PURE__ */ new Date());
|
|
275
359
|
useEffect4(() => setYearMonth(displayedYearMonth), [displayedYearMonth]);
|
|
276
|
-
return /* @__PURE__ */
|
|
360
|
+
return /* @__PURE__ */ jsx4(
|
|
277
361
|
YearMonthPicker,
|
|
278
362
|
{
|
|
279
363
|
displayedYearMonth: yearMonth,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/date/YearMonthPicker.tsx","../../../src/util/noop.ts","../../../src/util/array.ts","../../../src/components/layout-and-navigation/Expandable.tsx","../../../src/util/date.ts","../../../src/localization/LanguageProvider.tsx","../../../src/hooks/useLocalStorage.ts","../../../src/localization/util.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\nimport { Scrollbars } from 'react-custom-scrollbars-2'\nimport { noop } from '../../util/noop'\nimport { equalSizeGroups, range } from '../../util/array'\nimport clsx from 'clsx'\nimport { ExpandableUncontrolled } from '../layout-and-navigation/Expandable'\nimport { addDuration, monthsList, subtractDuration } from '../../util/date'\nimport { useLocale } from '../../localization/LanguageProvider'\n\nexport type YearMonthPickerProps = {\n displayedYearMonth?: Date,\n start?: Date,\n end?: Date,\n onChange?: (date: Date) => void,\n className?: string,\n maxHeight?: number,\n showValueOpen?: boolean,\n}\n\n// TODO use a dynamically loading infinite list here\nexport const YearMonthPicker = ({\n displayedYearMonth = new Date(),\n start = subtractDuration(new Date(), { years: 50 }),\n end = addDuration(new Date(), { years: 50 }),\n onChange = noop,\n className = '',\n maxHeight = 300,\n showValueOpen = true\n }: YearMonthPickerProps) => {\n const locale = useLocale()\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const scrollToItem = () => {\n if (ref.current) {\n ref.current.scrollIntoView({\n behavior: 'instant',\n block: 'center',\n })\n }\n }\n\n scrollToItem()\n }, [ref])\n\n if (end < start) {\n console.error(`startYear: (${start}) less than endYear: (${end})`)\n return null\n }\n\n const years = range(start.getFullYear(), end.getFullYear())\n\n return (\n <div className={clsx('col select-none', className)}>\n <Scrollbars autoHeight autoHeightMax={maxHeight} style={{ height: '100%' }}>\n <div className=\"col gap-y-1 mr-3\">\n {years.map(year => {\n const selectedYear = displayedYearMonth.getFullYear() === year\n return (\n <ExpandableUncontrolled\n key={year}\n ref={(displayedYearMonth.getFullYear() ?? new Date().getFullYear()) === year ? ref : undefined}\n label={<span className={clsx({ 'text-primary font-bold': selectedYear })}>{year}</span>}\n isExpanded={showValueOpen && selectedYear}\n >\n {equalSizeGroups([...monthsList], 3).map((monthList, index) => (\n <div key={index} className=\"row\">\n {monthList.map(month => {\n const monthIndex = monthsList.indexOf(month)\n const newDate = new Date(year, monthIndex)\n\n const selectedMonth = selectedYear && monthIndex === displayedYearMonth.getMonth()\n const firstOfMonth = new Date(year, monthIndex, 1)\n const lastOfMonth = new Date(year, monthIndex, 1)\n const isAfterStart = start === undefined || start <= addDuration(subtractDuration(lastOfMonth, { days: 1 }), { months: 1 })\n const isBeforeEnd = end === undefined || firstOfMonth <= end\n const isValid = isAfterStart && isBeforeEnd\n return (\n <button\n key={month}\n disabled={!isValid}\n className={clsx(\n 'chip hover:brightness-95 flex-1',\n {\n 'bg-gray-50 text-black': !selectedMonth && isValid,\n 'bg-primary text-on-primary': selectedMonth && isValid,\n 'bg-disabled-background text-disabled-text': !isValid\n }\n )}\n onClick={() => {\n onChange(newDate)\n }}\n >\n {new Intl.DateTimeFormat(locale, { month: 'short' }).format(newDate)}\n </button>\n )\n })}\n </div>\n ))}\n </ExpandableUncontrolled>\n )\n })}\n </div>\n </Scrollbars>\n </div>\n )\n}\n\nexport const YearMonthPickerUncontrolled = ({\n displayedYearMonth = new Date(),\n onChange = noop,\n ...props\n }: YearMonthPickerProps) => {\n const [yearMonth, setYearMonth] = useState<Date>(displayedYearMonth)\n\n useEffect(() => setYearMonth(displayedYearMonth), [displayedYearMonth])\n\n return (\n <YearMonthPicker\n displayedYearMonth={yearMonth}\n onChange={date => {\n setYearMonth(date)\n onChange(date)\n }}\n {...props}\n />\n )\n}\n","export const noop = () => undefined\n","export const equalSizeGroups = <T>(array: T[], groupSize: number): T[][] => {\n if (groupSize <= 0) {\n console.warn(`group size should be greater than 0: groupSize = ${groupSize}`)\n return [[...array]]\n }\n\n const groups = []\n for (let i = 0; i < array.length; i += groupSize) {\n groups.push(array.slice(i, Math.min(i + groupSize, array.length)))\n }\n return groups\n}\n\n/**\n * @param start\n * @param end inclusive\n * @param allowEmptyRange Whether the range can be defined empty via end < start\n */\nexport const range = (start: number, end: number, allowEmptyRange: boolean = false): number[] => {\n if (end < start) {\n if (!allowEmptyRange) {\n console.warn(`range: end (${end}) < start (${start}) should be allowed explicitly, set allowEmptyRange to true`)\n }\n return []\n }\n return Array.from({ length: end - start + 1 }, (_, index) => index + start)\n}\n\n/** Finds the closest match\n * @param list The list of all possible matches\n * @param firstCloser Return whether item1 is closer than item2\n */\nexport const closestMatch = <T>(list: T[], firstCloser: (item1: T, item2: T) => boolean) => {\n return list.reduce((item1, item2) => {\n return firstCloser(item1, item2) ? item1 : item2\n })\n}\n\n/**\n * returns the item in middle of a list and its neighbours before and after\n * e.g. [1,2,3,4,5,6] for item = 1 would return [5,6,1,2,3]\n */\nexport const getNeighbours = <T>(list: T[], item: T, neighbourDistance: number = 2) => {\n const index = list.indexOf(item)\n const totalItems = neighbourDistance * 2 + 1\n if (list.length < totalItems) {\n console.warn('List is to short')\n return list\n }\n\n if (index === -1) {\n console.error('item not found in list')\n return list.splice(0, totalItems)\n }\n\n let start = index - neighbourDistance\n if (start < 0) {\n start += list.length\n }\n const end = (index + neighbourDistance + 1) % list.length\n\n const result: T[] = []\n let ignoreOnce = list.length === totalItems\n for (let i = start; i !== end || ignoreOnce; i = (i + 1) % list.length) {\n result.push(list[i]!)\n if (end === i && ignoreOnce) {\n ignoreOnce = false\n }\n }\n return result\n}\n\nexport const createLoopingListWithIndex = <T>(list: T[], startIndex: number = 0, length: number = 0, forwards: boolean = true) => {\n if (length < 0) {\n console.warn(`createLoopingList: length must be >= 0, given ${length}`)\n } else if (length === 0) {\n length = list.length\n }\n\n const returnList: [number, T][] = []\n\n if (forwards) {\n for (let i = startIndex; returnList.length < length; i = (i + 1) % list.length) {\n returnList.push([i, list[i]!])\n }\n } else {\n for (let i = startIndex; returnList.length < length; i = i === 0 ? i = list.length - 1 : i - 1) {\n returnList.push([i, list[i]!])\n }\n }\n\n return returnList\n}\n\nexport const createLoopingList = <T>(list: T[], startIndex: number = 0, length: number = 0, forwards: boolean = true) => {\n return createLoopingListWithIndex(list, startIndex, length, forwards).map(([_, item]) => item)\n}\n\nexport const ArrayUtil = {\n unique: <T>(list: T[]): T[] => {\n const seen = new Set<T>()\n return list.filter((item) => {\n if (seen.has(item)) {\n return false\n }\n seen.add(item)\n return true\n })\n },\n\n difference: <T>(list: T[], removeList: T[]): T[] => {\n const remove = new Set<T>(removeList)\n return list.filter((item) => !remove.has(item))\n }\n}\n","import type { PropsWithChildren, ReactNode } from 'react'\nimport { forwardRef, useEffect, useState } from 'react'\nimport { ChevronDown, ChevronUp } from 'lucide-react'\nimport clsx from 'clsx'\nimport { noop } from '../../util/noop'\n\ntype IconBuilder = (expanded: boolean) => ReactNode\n\nexport type ExpandableProps = PropsWithChildren<{\n label: ReactNode,\n icon?: IconBuilder,\n isExpanded?: boolean,\n onChange?: (isExpanded: boolean) => void,\n /**\n * Whether the expansion should only happen when the header is clicked or on the entire component\n */\n clickOnlyOnHeader?: boolean,\n disabled?: boolean,\n className?: string,\n headerClassName?: string,\n}>\n\nconst DefaultIcon: IconBuilder = (expanded) => expanded ?\n (<ChevronUp size={16} className=\"min-w-[16px]\"/>)\n : (<ChevronDown size={16} className=\"min-w-[16px]\"/>)\n\n\n/**\n * A Component for showing and hiding content\n */\nexport const Expandable = forwardRef<HTMLDivElement, ExpandableProps>(function Expandable({\n children,\n label,\n icon,\n isExpanded = false,\n onChange = noop,\n clickOnlyOnHeader = true,\n disabled = false,\n className = '',\n headerClassName = ''\n }, ref) {\n icon ??= DefaultIcon\n\n return (\n <div\n ref={ref}\n className={clsx('col gap-y-0 bg-surface text-on-surface group rounded-lg shadow-sm', { 'cursor-pointer': !clickOnlyOnHeader && !disabled }, className)}\n onClick={() => !clickOnlyOnHeader && !disabled && onChange(!isExpanded)}\n >\n <div\n className={clsx(\n 'row py-2 px-4 rounded-lg justify-between items-center bg-surface text-on-surface select-none',\n {\n 'group-hover:brightness-95': !isExpanded,\n 'hover:brightness-95': isExpanded && !disabled,\n 'cursor-pointer': clickOnlyOnHeader && !disabled,\n },\n headerClassName\n )}\n onClick={() => clickOnlyOnHeader && !disabled && onChange(!isExpanded)}\n >\n {label}\n {icon(isExpanded)}\n </div>\n {isExpanded && (\n <div className=\"col px-4 pb-2\">\n {children}\n </div>\n )}\n </div>\n )\n})\n\nexport const ExpandableUncontrolled = forwardRef<HTMLDivElement, ExpandableProps>(function ExpandableUncontrolled({\n isExpanded,\n onChange = noop,\n ...props\n },\n ref) {\n const [usedIsExpanded, setUsedIsExpanded] = useState(isExpanded)\n\n useEffect(() => {\n setUsedIsExpanded(isExpanded)\n }, [isExpanded])\n\n return (\n <Expandable\n {...props}\n ref={ref}\n isExpanded={usedIsExpanded}\n onChange={value => {\n onChange(value)\n setUsedIsExpanded(value)\n }}\n />\n )\n})\n","import { equalSizeGroups } from './array'\n\nexport const monthsList = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'] as const\nexport type Month = typeof monthsList[number]\n\nexport const weekDayList = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'] as const\nexport type WeekDay = typeof weekDayList[number]\n\nexport const formatDate = (date: Date) => {\n const year = date.getFullYear().toString().padStart(4, '0')\n const month = (date.getMonth() + 1).toString().padStart(2, '0')\n const day = (date.getDate()).toString().padStart(2, '0')\n return `${year}-${month}-${day}`\n}\n\nexport const formatDateTime = (date: Date) => {\n const dateString = formatDate(date)\n const hours = date.getHours().toString().padStart(2, '0')\n const minutes = date.getMinutes().toString().padStart(2, '0')\n return `${dateString}T${hours}:${minutes}`\n}\n\nexport const getDaysInMonth = (year: number, month: number): number => {\n const lastDayOfMonth = new Date(year, month + 1, 0)\n return lastDayOfMonth.getDate()\n}\n\nexport type Duration = {\n years?: number,\n months?: number,\n days?: number,\n hours?: number,\n minutes?: number,\n seconds?: number,\n milliseconds?: number,\n}\n\nexport const changeDuration = (date: Date, duration: Duration, isAdding?: boolean): Date => {\n const {\n years = 0,\n months = 0,\n days = 0,\n hours = 0,\n minutes = 0,\n seconds = 0,\n milliseconds = 0,\n } = duration\n\n // Check ranges\n if (years < 0) {\n console.error(`Range error years must be greater than 0: received ${years}`)\n return new Date(date)\n }\n if (months < 0 || months > 11) {\n console.error(`Range error month must be 0 <= month <= 11: received ${months}`)\n return new Date(date)\n }\n if (days < 0) {\n console.error(`Range error days must be greater than 0: received ${days}`)\n return new Date(date)\n }\n if (hours < 0 || hours > 23) {\n console.error(`Range error hours must be 0 <= hours <= 23: received ${hours}`)\n return new Date(date)\n }\n if (minutes < 0 || minutes > 59) {\n console.error(`Range error minutes must be 0 <= minutes <= 59: received ${minutes}`)\n return new Date(date)\n }\n if (seconds < 0 || seconds > 59) {\n console.error(`Range error seconds must be 0 <= seconds <= 59: received ${seconds}`)\n return new Date(date)\n }\n if (milliseconds < 0) {\n console.error(`Range error seconds must be greater than 0: received ${milliseconds}`)\n return new Date(date)\n }\n\n const multiplier = isAdding ? 1 : -1\n\n const newDate = new Date(date)\n\n newDate.setFullYear(newDate.getFullYear() + multiplier * years)\n\n newDate.setMonth(newDate.getMonth() + multiplier * months)\n\n newDate.setDate(newDate.getDate() + multiplier * days)\n\n newDate.setHours(newDate.getHours() + multiplier * hours)\n\n newDate.setMinutes(newDate.getMinutes() + multiplier * minutes)\n\n newDate.setSeconds(newDate.getSeconds() + multiplier * seconds)\n\n newDate.setMilliseconds(newDate.getMilliseconds() + multiplier * milliseconds)\n\n return newDate\n}\n\nexport const addDuration = (date: Date, duration: Duration): Date => {\n return changeDuration(date, duration, true)\n}\n\nexport const subtractDuration = (date: Date, duration: Duration): Date => {\n return changeDuration(date, duration, false)\n}\n\nexport const getBetweenDuration = (startDate: Date, endDate: Date): Duration => {\n const durationInMilliseconds = endDate.getTime() - startDate.getTime()\n\n const millisecondsInSecond = 1000\n const millisecondsInMinute = 60 * millisecondsInSecond\n const millisecondsInHour = 60 * millisecondsInMinute\n const millisecondsInDay = 24 * millisecondsInHour\n const millisecondsInMonth = 30 * millisecondsInDay // Rough estimation, can be adjusted\n\n const years = Math.floor(durationInMilliseconds / (365.25 * millisecondsInDay))\n const months = Math.floor(durationInMilliseconds / millisecondsInMonth)\n const days = Math.floor(durationInMilliseconds / millisecondsInDay)\n const hours = Math.floor((durationInMilliseconds % millisecondsInDay) / millisecondsInHour)\n const seconds = Math.floor((durationInMilliseconds % millisecondsInHour) / millisecondsInSecond)\n const milliseconds = durationInMilliseconds % millisecondsInSecond\n\n return {\n years,\n months,\n days,\n hours,\n seconds,\n milliseconds,\n }\n}\n\n/** Checks if a given date is in the range of two dates\n *\n * An undefined value for startDate or endDate means no bound for the start or end respectively\n */\nexport const isInTimeSpan = (value: Date, startDate?: Date, endDate?: Date): boolean => {\n if (startDate && endDate) {\n console.assert(startDate <= endDate)\n return startDate <= value && value <= endDate\n } else if (startDate) {\n return startDate <= value\n } else if (endDate) {\n return endDate >= value\n } else {\n return true\n }\n}\n\n/** Compare two dates on the year, month, day */\nexport const equalDate = (date1: Date, date2: Date) => {\n return date1.getFullYear() === date2.getFullYear()\n && date1.getMonth() === date2.getMonth()\n && date1.getDate() === date2.getDate()\n}\n\nexport const getWeeksForCalenderMonth = (date: Date, weekStart: WeekDay, weeks: number = 6) => {\n const month = date.getMonth()\n const year = date.getFullYear()\n\n const dayList: Date[] = []\n let currentDate = new Date(year, month, 1) // Start of month\n const weekStartIndex = weekDayList.indexOf(weekStart)\n\n // Move the current day to the week before\n while (currentDate.getDay() !== weekStartIndex) {\n currentDate = subtractDuration(currentDate, { days: 1 })\n }\n\n while (dayList.length < 7 * weeks) {\n const date = new Date(currentDate)\n date.setHours(date.getHours(), date.getMinutes()) // To make sure we are not overwriting the time\n dayList.push(date)\n currentDate = addDuration(currentDate, { days: 1 })\n }\n\n // weeks\n return equalSizeGroups(dayList, 7)\n}\n","import type { Dispatch, PropsWithChildren, SetStateAction } from 'react'\nimport { createContext, useContext, useEffect, useState } from 'react'\nimport { useLocalStorage } from '../hooks/useLocalStorage'\nimport type { Language } from './util'\nimport { LanguageUtil } from './util'\n\nexport type LanguageContextValue = {\n language: Language,\n setLanguage: Dispatch<SetStateAction<Language>>,\n}\n\nexport const LanguageContext = createContext<LanguageContextValue>({\n language: LanguageUtil.DEFAULT_LANGUAGE,\n setLanguage: (v) => v\n})\n\nexport const useLanguage = () => useContext(LanguageContext)\n\nexport const useLocale = (overWriteLanguage?: Language) => {\n const { language } = useLanguage()\n const mapping: Record<Language, string> = {\n en: 'en-US',\n de: 'de-DE'\n }\n return mapping[overWriteLanguage ?? language]\n}\n\ntype LanguageProviderProps = {\n initialLanguage?: Language,\n}\n\nexport const LanguageProvider = ({ initialLanguage, children }: PropsWithChildren<LanguageProviderProps>) => {\n const [language, setLanguage] = useState<Language>(initialLanguage ?? LanguageUtil.DEFAULT_LANGUAGE)\n const [storedLanguage, setStoredLanguage] = useLocalStorage<Language>('language', initialLanguage ?? LanguageUtil.DEFAULT_LANGUAGE)\n\n useEffect(() => {\n if (language !== initialLanguage && initialLanguage) {\n console.warn('LanguageProvider initial state changed: Prefer using languageProvider\\'s setLanguage instead')\n setLanguage(initialLanguage)\n }\n }, [initialLanguage]) // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n // TODO set locale of html tag here as well\n setStoredLanguage(language)\n }, [language, setStoredLanguage])\n\n useEffect(() => {\n if (storedLanguage !== null) {\n setLanguage(storedLanguage)\n return\n }\n\n const LanguageToTestAgainst = Object.values(LanguageUtil.languages)\n\n const matchingBrowserLanguage = window.navigator.languages\n .map(language => LanguageToTestAgainst.find((test) => language === test || language.split('-')[0] === test))\n .filter(entry => entry !== undefined)\n\n if (matchingBrowserLanguage.length === 0) return\n\n const firstMatch = matchingBrowserLanguage[0] as Language\n setLanguage(firstMatch)\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <LanguageContext.Provider value={{\n language,\n setLanguage\n }}>\n {children}\n </LanguageContext.Provider>\n )\n}","import type { Dispatch, SetStateAction } from 'react'\nimport { useCallback, useEffect, useState } from 'react'\nimport { LocalStorageService } from '../util/storage'\n\ntype SetValue<T> = Dispatch<SetStateAction<T>>\nexport const useLocalStorage = <T>(key: string, initValue: T): [T, SetValue<T>] => {\n const get = useCallback((): T => {\n if (typeof window === 'undefined') {\n return initValue\n }\n const storageService = new LocalStorageService()\n const value = storageService.get<T>(key)\n return value || initValue\n }, [initValue, key])\n\n const [storedValue, setStoredValue] = useState<T>(get)\n\n const setValue: SetValue<T> = useCallback(value => {\n const newValue = value instanceof Function ? value(storedValue) : value\n const storageService = new LocalStorageService()\n storageService.set(key, value)\n\n setStoredValue(newValue)\n }, [storedValue, setStoredValue, key])\n\n useEffect(() => {\n setStoredValue(get())\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n return [storedValue, setValue]\n}","/**\n * The supported languages\n */\nconst languages = ['en', 'de'] as const\n\n/**\n * The supported languages\n */\nexport type Language = typeof languages[number]\n\n/**\n * The supported languages' names in their respective language\n */\nconst languagesLocalNames: Record<Language, string> = {\n en: 'English',\n de: 'Deutsch',\n}\n\n/**\n * The default language\n */\nconst DEFAULT_LANGUAGE: Language = 'en'\n\n/**\n * A constant definition for holding data regarding languages\n */\nexport const LanguageUtil = {\n languages,\n DEFAULT_LANGUAGE,\n languagesLocalNames,\n}"],"mappings":"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","names":["useEffect","useState","clsx","Expandable","ExpandableUncontrolled","useEffect","useState","useEffect","useState","jsx","jsx","useEffect","clsx","useState"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/date/YearMonthPicker.tsx","../../../src/util/noop.ts","../../../src/util/array.ts","../../../src/components/layout-and-navigation/Expandable.tsx","../../../src/util/date.ts","../../../src/localization/LanguageProvider.tsx","../../../src/hooks/useLocalStorage.ts","../../../src/localization/util.ts","../../../src/components/user-action/Button.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\nimport { Scrollbars } from 'react-custom-scrollbars-2'\nimport { noop } from '../../util/noop'\nimport { equalSizeGroups, range } from '../../util/array'\nimport clsx from 'clsx'\nimport { ExpandableUncontrolled } from '../layout-and-navigation/Expandable'\nimport { addDuration, monthsList, subtractDuration } from '../../util/date'\nimport { useLocale } from '../../localization/LanguageProvider'\nimport { SolidButton } from '../user-action/Button'\n\nexport type YearMonthPickerProps = {\n displayedYearMonth?: Date,\n start?: Date,\n end?: Date,\n onChange?: (date: Date) => void,\n className?: string,\n maxHeight?: number,\n showValueOpen?: boolean,\n}\n\n// TODO use a dynamically loading infinite list here\nexport const YearMonthPicker = ({\n displayedYearMonth = new Date(),\n start = subtractDuration(new Date(), { years: 50 }),\n end = addDuration(new Date(), { years: 50 }),\n onChange = noop,\n className = '',\n maxHeight = 300,\n showValueOpen = true\n }: YearMonthPickerProps) => {\n const locale = useLocale()\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const scrollToItem = () => {\n if (ref.current) {\n ref.current.scrollIntoView({\n behavior: 'instant',\n block: 'center',\n })\n }\n }\n\n scrollToItem()\n }, [ref])\n\n if (end < start) {\n console.error(`startYear: (${start}) less than endYear: (${end})`)\n return null\n }\n\n const years = range(start.getFullYear(), end.getFullYear())\n\n return (\n <div className={clsx('col select-none', className)}>\n <Scrollbars autoHeight autoHeightMax={maxHeight} style={{ height: '100%' }}>\n <div className=\"col gap-y-1 mr-3\">\n {years.map(year => {\n const selectedYear = displayedYearMonth.getFullYear() === year\n return (\n <ExpandableUncontrolled\n key={year}\n ref={(displayedYearMonth.getFullYear() ?? new Date().getFullYear()) === year ? ref : undefined}\n label={<span className={clsx({ 'text-primary font-bold': selectedYear })}>{year}</span>}\n isExpanded={showValueOpen && selectedYear}\n contentClassName=\"gap-y-1\"\n >\n {equalSizeGroups([...monthsList], 3).map((monthList, index) => (\n <div key={index} className=\"row gap-x-1\">\n {monthList.map(month => {\n const monthIndex = monthsList.indexOf(month)\n const newDate = new Date(year, monthIndex)\n\n const selectedMonth = selectedYear && monthIndex === displayedYearMonth.getMonth()\n const firstOfMonth = new Date(year, monthIndex, 1)\n const lastOfMonth = new Date(year, monthIndex, 1)\n const isAfterStart = start === undefined || start <= addDuration(subtractDuration(lastOfMonth, { days: 1 }), { months: 1 })\n const isBeforeEnd = end === undefined || firstOfMonth <= end\n const isValid = isAfterStart && isBeforeEnd\n return (\n <SolidButton\n key={month}\n disabled={!isValid}\n color={selectedMonth && isValid ? 'primary' : 'neutral'}\n className=\"flex-1\"\n size=\"small\"\n onClick={() => {\n onChange(newDate)\n }}\n >\n {new Intl.DateTimeFormat(locale, { month: 'short' }).format(newDate)}\n </SolidButton>\n )\n })}\n </div>\n ))}\n </ExpandableUncontrolled>\n )\n })}\n </div>\n </Scrollbars>\n </div>\n )\n}\n\nexport const YearMonthPickerUncontrolled = ({\n displayedYearMonth,\n onChange = noop,\n ...props\n }: YearMonthPickerProps) => {\n const [yearMonth, setYearMonth] = useState<Date>(displayedYearMonth ?? new Date())\n\n useEffect(() => setYearMonth(displayedYearMonth), [displayedYearMonth])\n\n return (\n <YearMonthPicker\n displayedYearMonth={yearMonth}\n onChange={date => {\n setYearMonth(date)\n onChange(date)\n }}\n {...props}\n />\n )\n}\n","export const noop = () => undefined\n","export const equalSizeGroups = <T>(array: T[], groupSize: number): T[][] => {\n if (groupSize <= 0) {\n console.warn(`group size should be greater than 0: groupSize = ${groupSize}`)\n return [[...array]]\n }\n\n const groups = []\n for (let i = 0; i < array.length; i += groupSize) {\n groups.push(array.slice(i, Math.min(i + groupSize, array.length)))\n }\n return groups\n}\n\n/**\n * @param start\n * @param end inclusive\n * @param allowEmptyRange Whether the range can be defined empty via end < start\n */\nexport const range = (start: number, end: number, allowEmptyRange: boolean = false): number[] => {\n if (end < start) {\n if (!allowEmptyRange) {\n console.warn(`range: end (${end}) < start (${start}) should be allowed explicitly, set allowEmptyRange to true`)\n }\n return []\n }\n return Array.from({ length: end - start + 1 }, (_, index) => index + start)\n}\n\n/** Finds the closest match\n * @param list The list of all possible matches\n * @param firstCloser Return whether item1 is closer than item2\n */\nexport const closestMatch = <T>(list: T[], firstCloser: (item1: T, item2: T) => boolean) => {\n return list.reduce((item1, item2) => {\n return firstCloser(item1, item2) ? item1 : item2\n })\n}\n\n/**\n * returns the item in middle of a list and its neighbours before and after\n * e.g. [1,2,3,4,5,6] for item = 1 would return [5,6,1,2,3]\n */\nexport const getNeighbours = <T>(list: T[], item: T, neighbourDistance: number = 2) => {\n const index = list.indexOf(item)\n const totalItems = neighbourDistance * 2 + 1\n if (list.length < totalItems) {\n console.warn('List is to short')\n return list\n }\n\n if (index === -1) {\n console.error('item not found in list')\n return list.splice(0, totalItems)\n }\n\n let start = index - neighbourDistance\n if (start < 0) {\n start += list.length\n }\n const end = (index + neighbourDistance + 1) % list.length\n\n const result: T[] = []\n let ignoreOnce = list.length === totalItems\n for (let i = start; i !== end || ignoreOnce; i = (i + 1) % list.length) {\n result.push(list[i]!)\n if (end === i && ignoreOnce) {\n ignoreOnce = false\n }\n }\n return result\n}\n\nexport const createLoopingListWithIndex = <T>(list: T[], startIndex: number = 0, length: number = 0, forwards: boolean = true) => {\n if (length < 0) {\n console.warn(`createLoopingList: length must be >= 0, given ${length}`)\n } else if (length === 0) {\n length = list.length\n }\n\n const returnList: [number, T][] = []\n\n if (forwards) {\n for (let i = startIndex; returnList.length < length; i = (i + 1) % list.length) {\n returnList.push([i, list[i]!])\n }\n } else {\n for (let i = startIndex; returnList.length < length; i = i === 0 ? i = list.length - 1 : i - 1) {\n returnList.push([i, list[i]!])\n }\n }\n\n return returnList\n}\n\nexport const createLoopingList = <T>(list: T[], startIndex: number = 0, length: number = 0, forwards: boolean = true) => {\n return createLoopingListWithIndex(list, startIndex, length, forwards).map(([_, item]) => item)\n}\n\nexport const ArrayUtil = {\n unique: <T>(list: T[]): T[] => {\n const seen = new Set<T>()\n return list.filter((item) => {\n if (seen.has(item)) {\n return false\n }\n seen.add(item)\n return true\n })\n },\n\n difference: <T>(list: T[], removeList: T[]): T[] => {\n const remove = new Set<T>(removeList)\n return list.filter((item) => !remove.has(item))\n }\n}\n","import type { PropsWithChildren, ReactNode } from 'react'\nimport { forwardRef, useEffect, useState } from 'react'\nimport { ChevronDown, ChevronUp } from 'lucide-react'\nimport clsx from 'clsx'\nimport { noop } from '../../util/noop'\n\ntype IconBuilder = (expanded: boolean) => ReactNode\n\nexport type ExpandableProps = PropsWithChildren<{\n label: ReactNode,\n icon?: IconBuilder,\n isExpanded?: boolean,\n onChange?: (isExpanded: boolean) => void,\n /**\n * Whether the expansion should only happen when the header is clicked or on the entire component\n */\n clickOnlyOnHeader?: boolean,\n disabled?: boolean,\n className?: string,\n headerClassName?: string,\n contentClassName?: string,\n}>\n\nconst DefaultIcon: IconBuilder = (expanded) => expanded ?\n (<ChevronUp size={16} className=\"min-w-[16px]\"/>)\n : (<ChevronDown size={16} className=\"min-w-[16px]\"/>)\n\n\n/**\n * A Component for showing and hiding content\n */\nexport const Expandable = forwardRef<HTMLDivElement, ExpandableProps>(function Expandable({\n children,\n label,\n icon,\n isExpanded = false,\n onChange = noop,\n clickOnlyOnHeader = true,\n disabled = false,\n className,\n headerClassName,\n contentClassName,\n }, ref) {\n icon ??= DefaultIcon\n\n return (\n <div\n ref={ref}\n className={clsx('col gap-y-0 bg-surface text-on-surface group rounded-lg shadow-sm', { 'cursor-pointer': !clickOnlyOnHeader && !disabled }, className)}\n onClick={() => !clickOnlyOnHeader && !disabled && onChange(!isExpanded)}\n >\n <div\n className={clsx(\n 'row py-2 px-4 rounded-lg justify-between items-center bg-surface text-on-surface select-none',\n {\n 'group-hover:brightness-95': !isExpanded,\n 'hover:brightness-95': isExpanded && !disabled,\n 'cursor-pointer': clickOnlyOnHeader && !disabled,\n },\n headerClassName\n )}\n onClick={() => clickOnlyOnHeader && !disabled && onChange(!isExpanded)}\n >\n {label}\n {icon(isExpanded)}\n </div>\n {isExpanded && (\n <div className={clsx('col px-4 pb-2', contentClassName)}>\n {children}\n </div>\n )}\n </div>\n )\n})\n\nexport const ExpandableUncontrolled = forwardRef<HTMLDivElement, ExpandableProps>(function ExpandableUncontrolled({\n isExpanded,\n onChange = noop,\n ...props\n },\n ref) {\n const [usedIsExpanded, setUsedIsExpanded] = useState(isExpanded)\n\n useEffect(() => {\n setUsedIsExpanded(isExpanded)\n }, [isExpanded])\n\n return (\n <Expandable\n {...props}\n ref={ref}\n isExpanded={usedIsExpanded}\n onChange={value => {\n onChange(value)\n setUsedIsExpanded(value)\n }}\n />\n )\n})\n","import { equalSizeGroups } from './array'\n\nexport const monthsList = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'] as const\nexport type Month = typeof monthsList[number]\n\nexport const weekDayList = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'] as const\nexport type WeekDay = typeof weekDayList[number]\n\nexport const formatDate = (date: Date) => {\n const year = date.getFullYear().toString().padStart(4, '0')\n const month = (date.getMonth() + 1).toString().padStart(2, '0')\n const day = (date.getDate()).toString().padStart(2, '0')\n return `${year}-${month}-${day}`\n}\n\nexport const formatDateTime = (date: Date) => {\n const dateString = formatDate(date)\n const hours = date.getHours().toString().padStart(2, '0')\n const minutes = date.getMinutes().toString().padStart(2, '0')\n return `${dateString}T${hours}:${minutes}`\n}\n\nexport const getDaysInMonth = (year: number, month: number): number => {\n const lastDayOfMonth = new Date(year, month + 1, 0)\n return lastDayOfMonth.getDate()\n}\n\nexport type Duration = {\n years?: number,\n months?: number,\n days?: number,\n hours?: number,\n minutes?: number,\n seconds?: number,\n milliseconds?: number,\n}\n\nexport const changeDuration = (date: Date, duration: Duration, isAdding?: boolean): Date => {\n const {\n years = 0,\n months = 0,\n days = 0,\n hours = 0,\n minutes = 0,\n seconds = 0,\n milliseconds = 0,\n } = duration\n\n // Check ranges\n if (years < 0) {\n console.error(`Range error years must be greater than 0: received ${years}`)\n return new Date(date)\n }\n if (months < 0 || months > 11) {\n console.error(`Range error month must be 0 <= month <= 11: received ${months}`)\n return new Date(date)\n }\n if (days < 0) {\n console.error(`Range error days must be greater than 0: received ${days}`)\n return new Date(date)\n }\n if (hours < 0 || hours > 23) {\n console.error(`Range error hours must be 0 <= hours <= 23: received ${hours}`)\n return new Date(date)\n }\n if (minutes < 0 || minutes > 59) {\n console.error(`Range error minutes must be 0 <= minutes <= 59: received ${minutes}`)\n return new Date(date)\n }\n if (seconds < 0 || seconds > 59) {\n console.error(`Range error seconds must be 0 <= seconds <= 59: received ${seconds}`)\n return new Date(date)\n }\n if (milliseconds < 0) {\n console.error(`Range error seconds must be greater than 0: received ${milliseconds}`)\n return new Date(date)\n }\n\n const multiplier = isAdding ? 1 : -1\n\n const newDate = new Date(date)\n\n newDate.setFullYear(newDate.getFullYear() + multiplier * years)\n\n newDate.setMonth(newDate.getMonth() + multiplier * months)\n\n newDate.setDate(newDate.getDate() + multiplier * days)\n\n newDate.setHours(newDate.getHours() + multiplier * hours)\n\n newDate.setMinutes(newDate.getMinutes() + multiplier * minutes)\n\n newDate.setSeconds(newDate.getSeconds() + multiplier * seconds)\n\n newDate.setMilliseconds(newDate.getMilliseconds() + multiplier * milliseconds)\n\n return newDate\n}\n\nexport const addDuration = (date: Date, duration: Duration): Date => {\n return changeDuration(date, duration, true)\n}\n\nexport const subtractDuration = (date: Date, duration: Duration): Date => {\n return changeDuration(date, duration, false)\n}\n\nexport const getBetweenDuration = (startDate: Date, endDate: Date): Duration => {\n const durationInMilliseconds = endDate.getTime() - startDate.getTime()\n\n const millisecondsInSecond = 1000\n const millisecondsInMinute = 60 * millisecondsInSecond\n const millisecondsInHour = 60 * millisecondsInMinute\n const millisecondsInDay = 24 * millisecondsInHour\n const millisecondsInMonth = 30 * millisecondsInDay // Rough estimation, can be adjusted\n\n const years = Math.floor(durationInMilliseconds / (365.25 * millisecondsInDay))\n const months = Math.floor(durationInMilliseconds / millisecondsInMonth)\n const days = Math.floor(durationInMilliseconds / millisecondsInDay)\n const hours = Math.floor((durationInMilliseconds % millisecondsInDay) / millisecondsInHour)\n const seconds = Math.floor((durationInMilliseconds % millisecondsInHour) / millisecondsInSecond)\n const milliseconds = durationInMilliseconds % millisecondsInSecond\n\n return {\n years,\n months,\n days,\n hours,\n seconds,\n milliseconds,\n }\n}\n\n/** Checks if a given date is in the range of two dates\n *\n * An undefined value for startDate or endDate means no bound for the start or end respectively\n */\nexport const isInTimeSpan = (value: Date, startDate?: Date, endDate?: Date): boolean => {\n if (startDate && endDate) {\n console.assert(startDate <= endDate)\n return startDate <= value && value <= endDate\n } else if (startDate) {\n return startDate <= value\n } else if (endDate) {\n return endDate >= value\n } else {\n return true\n }\n}\n\n/** Compare two dates on the year, month, day */\nexport const equalDate = (date1: Date, date2: Date) => {\n return date1.getFullYear() === date2.getFullYear()\n && date1.getMonth() === date2.getMonth()\n && date1.getDate() === date2.getDate()\n}\n\nexport const getWeeksForCalenderMonth = (date: Date, weekStart: WeekDay, weeks: number = 6) => {\n const month = date.getMonth()\n const year = date.getFullYear()\n\n const dayList: Date[] = []\n let currentDate = new Date(year, month, 1) // Start of month\n const weekStartIndex = weekDayList.indexOf(weekStart)\n\n // Move the current day to the week before\n while (currentDate.getDay() !== weekStartIndex) {\n currentDate = subtractDuration(currentDate, { days: 1 })\n }\n\n while (dayList.length < 7 * weeks) {\n const date = new Date(currentDate)\n date.setHours(date.getHours(), date.getMinutes()) // To make sure we are not overwriting the time\n dayList.push(date)\n currentDate = addDuration(currentDate, { days: 1 })\n }\n\n // weeks\n return equalSizeGroups(dayList, 7)\n}\n","import type { Dispatch, PropsWithChildren, SetStateAction } from 'react'\nimport { createContext, useContext, useEffect, useState } from 'react'\nimport { useLocalStorage } from '../hooks/useLocalStorage'\nimport type { Language } from './util'\nimport { LanguageUtil } from './util'\n\nexport type LanguageContextValue = {\n language: Language,\n setLanguage: Dispatch<SetStateAction<Language>>,\n}\n\nexport const LanguageContext = createContext<LanguageContextValue>({\n language: LanguageUtil.DEFAULT_LANGUAGE,\n setLanguage: (v) => v\n})\n\nexport const useLanguage = () => useContext(LanguageContext)\n\nexport const useLocale = (overWriteLanguage?: Language) => {\n const { language } = useLanguage()\n const mapping: Record<Language, string> = {\n en: 'en-US',\n de: 'de-DE'\n }\n return mapping[overWriteLanguage ?? language]\n}\n\ntype LanguageProviderProps = {\n initialLanguage?: Language,\n}\n\nexport const LanguageProvider = ({ initialLanguage, children }: PropsWithChildren<LanguageProviderProps>) => {\n const [language, setLanguage] = useState<Language>(initialLanguage ?? LanguageUtil.DEFAULT_LANGUAGE)\n const [storedLanguage, setStoredLanguage] = useLocalStorage<Language>('language', initialLanguage ?? LanguageUtil.DEFAULT_LANGUAGE)\n\n useEffect(() => {\n if (language !== initialLanguage && initialLanguage) {\n console.warn('LanguageProvider initial state changed: Prefer using languageProvider\\'s setLanguage instead')\n setLanguage(initialLanguage)\n }\n }, [initialLanguage]) // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n // TODO set locale of html tag here as well\n setStoredLanguage(language)\n }, [language, setStoredLanguage])\n\n useEffect(() => {\n if (storedLanguage !== null) {\n setLanguage(storedLanguage)\n return\n }\n\n const LanguageToTestAgainst = Object.values(LanguageUtil.languages)\n\n const matchingBrowserLanguage = window.navigator.languages\n .map(language => LanguageToTestAgainst.find((test) => language === test || language.split('-')[0] === test))\n .filter(entry => entry !== undefined)\n\n if (matchingBrowserLanguage.length === 0) return\n\n const firstMatch = matchingBrowserLanguage[0] as Language\n setLanguage(firstMatch)\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <LanguageContext.Provider value={{\n language,\n setLanguage\n }}>\n {children}\n </LanguageContext.Provider>\n )\n}","import type { Dispatch, SetStateAction } from 'react'\nimport { useCallback, useEffect, useState } from 'react'\nimport { LocalStorageService } from '../util/storage'\n\ntype SetValue<T> = Dispatch<SetStateAction<T>>\nexport const useLocalStorage = <T>(key: string, initValue: T): [T, SetValue<T>] => {\n const get = useCallback((): T => {\n if (typeof window === 'undefined') {\n return initValue\n }\n const storageService = new LocalStorageService()\n const value = storageService.get<T>(key)\n return value || initValue\n }, [initValue, key])\n\n const [storedValue, setStoredValue] = useState<T>(get)\n\n const setValue: SetValue<T> = useCallback(value => {\n const newValue = value instanceof Function ? value(storedValue) : value\n const storageService = new LocalStorageService()\n storageService.set(key, value)\n\n setStoredValue(newValue)\n }, [storedValue, setStoredValue, key])\n\n useEffect(() => {\n setStoredValue(get())\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n return [storedValue, setValue]\n}","/**\n * The supported languages\n */\nconst languages = ['en', 'de'] as const\n\n/**\n * The supported languages\n */\nexport type Language = typeof languages[number]\n\n/**\n * The supported languages' names in their respective language\n */\nconst languagesLocalNames: Record<Language, string> = {\n en: 'English',\n de: 'Deutsch',\n}\n\n/**\n * The default language\n */\nconst DEFAULT_LANGUAGE: Language = 'en'\n\n/**\n * A constant definition for holding data regarding languages\n */\nexport const LanguageUtil = {\n languages,\n DEFAULT_LANGUAGE,\n languagesLocalNames,\n}","import type { ButtonHTMLAttributes, PropsWithChildren, ReactNode } from 'react'\nimport clsx from 'clsx'\n\n\nexport const ButtonColorUtil = {\n solid: ['primary', 'secondary', 'tertiary', 'positive', 'warning', 'negative', 'neutral'] as const,\n text: ['primary', 'negative', 'neutral'] as const,\n outline: ['primary'] as const,\n}\n\n\n/**\n * The allowed colors for the SolidButton and IconButton\n */\nexport type SolidButtonColor = typeof ButtonColorUtil.solid[number]\n/**\n * The allowed colors for the OutlineButton\n */\nexport type OutlineButtonColor = typeof ButtonColorUtil.outline[number]\n/**\n * The allowed colors for the TextButton\n */\nexport type TextButtonColor = typeof ButtonColorUtil.text[number]\n\n/**\n * The different sizes for a button\n */\ntype ButtonSizes = 'small' | 'medium' | 'large'\n\n/**\n * The shard properties between all button types\n */\nexport type ButtonProps = PropsWithChildren<{\n /**\n * @default 'medium'\n */\n size?: ButtonSizes,\n}> & ButtonHTMLAttributes<Element>\n\nconst paddingMapping: Record<ButtonSizes, string> = {\n small: 'btn-sm',\n medium: 'btn-md',\n large: 'btn-lg'\n}\n\nconst iconPaddingMapping: Record<ButtonSizes, string> = {\n small: 'icon-btn-sm',\n medium: 'icon-btn-md',\n large: 'icon-btn-lg'\n}\n\nexport const ButtonUtil = {\n paddingMapping,\n iconPaddingMapping\n}\n\ntype ButtonWithIconsProps = ButtonProps & {\n startIcon?: ReactNode,\n endIcon?: ReactNode,\n}\n\nexport type SolidButtonProps = ButtonWithIconsProps & {\n color?: SolidButtonColor,\n}\n\nexport type OutlineButtonProps = ButtonWithIconsProps & {\n color?: OutlineButtonColor,\n}\n\nexport type TextButtonProps = ButtonWithIconsProps & {\n color?: TextButtonColor,\n}\n\nexport type IconButtonProps = ButtonProps & {\n color?: SolidButtonColor,\n}\n\n/**\n * A button with a solid background and different sizes\n */\nconst SolidButton = ({\n children,\n disabled = false,\n color = 'primary',\n size = 'medium',\n startIcon,\n endIcon,\n onClick,\n className,\n ...restProps\n }: SolidButtonProps) => {\n const colorClasses = {\n primary: 'bg-button-solid-primary-background text-button-solid-primary-text',\n secondary: 'bg-button-solid-secondary-background text-button-solid-secondary-text',\n tertiary: 'bg-button-solid-tertiary-background text-button-solid-tertiary-text',\n positive: 'bg-button-solid-positive-background text-button-solid-positive-text',\n warning: 'bg-button-solid-warning-background text-button-solid-warning-text',\n negative: 'bg-button-solid-negative-background text-button-solid-negative-text',\n neutral: 'bg-button-solid-neutral-background text-button-solid-neutral-text',\n }[color]\n\n const iconColorClasses = {\n primary: 'text-button-solid-primary-icon',\n secondary: 'text-button-solid-secondary-icon',\n tertiary: 'text-button-solid-tertiary-icon',\n positive: 'text-button-solid-positive-icon',\n warning: 'text-button-solid-warning-icon',\n negative: 'text-button-solid-negative-icon',\n neutral: 'text-button-solid-neutral-icon',\n }[color]\n\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n {\n 'text-disabled-text bg-disabled-background cursor-not-allowed': disabled,\n [clsx(colorClasses, 'hover:brightness-90')]: !disabled\n },\n ButtonUtil.paddingMapping[size],\n className\n )}\n {...restProps}\n >\n {startIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {startIcon}\n </span>\n )}\n {children}\n {endIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {endIcon}\n </span>\n )}\n </button>\n )\n}\n\n/**\n * A button with an outline border and different sizes\n */\nconst OutlineButton = ({\n children,\n disabled = false,\n color = 'primary',\n size = 'medium',\n startIcon,\n endIcon,\n onClick,\n className,\n ...restProps\n }: OutlineButtonProps) => {\n const colorClasses = {\n primary: 'bg-transparent border-2 border-button-outline-primary-text text-button-outline-primary-text',\n }[color]\n\n const iconColorClasses = {\n primary: 'text-button-outline-primary-icon',\n }[color]\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n {\n 'text-disabled-text border-disabled-outline cursor-not-allowed': disabled,\n [clsx(colorClasses, 'hover:brightness-80')]: !disabled,\n },\n ButtonUtil.paddingMapping[size],\n className\n )}\n {...restProps}\n >\n {startIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {startIcon}\n </span>\n )}\n {children}\n {endIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {endIcon}\n </span>\n )}\n </button>\n )\n}\n\n/**\n * A text that is a button that can have different sizes\n */\nconst TextButton = ({\n children,\n disabled = false,\n color = 'neutral',\n size = 'medium',\n startIcon,\n endIcon,\n onClick,\n className,\n ...restProps\n }: TextButtonProps) => {\n const colorClasses = {\n primary: 'bg-transparent text-button-text-primary-text',\n negative: 'bg-transparent text-button-text-negative-text',\n neutral: 'bg-transparent text-button-text-neutral-text',\n }[color]\n\n const iconColorClasses = {\n primary: 'text-button-text-primary-icon',\n negative: 'text-button-text-negative-icon',\n neutral: 'text-button-text-neutral-icon',\n }[color]\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n {\n 'text-disabled-text cursor-not-allowed': disabled,\n [clsx(colorClasses, 'hover:bg-button-text-hover-background rounded-full')]: !disabled,\n },\n ButtonUtil.paddingMapping[size],\n className\n )}\n {...restProps}\n >\n {startIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {startIcon}\n </span>\n )}\n {children}\n {endIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {endIcon}\n </span>\n )}\n </button>\n )\n}\n\n\n/**\n * A button for icons with a solid background and different sizes\n */\nconst IconButton = ({\n children,\n disabled = false,\n color = 'primary',\n size = 'medium',\n onClick,\n className,\n ...restProps\n }: IconButtonProps) => {\n const colorClasses = {\n primary: 'bg-button-solid-primary-background text-button-solid-primary-text',\n secondary: 'bg-button-solid-secondary-background text-button-solid-secondary-text',\n tertiary: 'bg-button-solid-tertiary-background text-button-solid-tertiary-text',\n positive: 'bg-button-solid-positive-background text-button-solid-positive-text',\n warning: 'bg-button-solid-warning-background text-button-solid-warning-text',\n negative: 'bg-button-solid-negative-background text-button-solid-negative-text',\n neutral: 'bg-button-solid-neutral-background text-button-solid-neutral-text',\n }[color]\n\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n {\n 'text-disabled-text bg-disabled-background cursor-not-allowed': disabled,\n [clsx(colorClasses, 'hover:brightness-90')]: !disabled\n },\n ButtonUtil.iconPaddingMapping[size],\n className\n )}\n {...restProps}\n >\n {children}\n </button>\n )\n}\n\nexport { SolidButton, OutlineButton, TextButton, IconButton }\n"],"mappings":"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","names":["useEffect","useState","clsx","Expandable","ExpandableUncontrolled","useEffect","useState","useEffect","useState","jsx","clsx","jsx","jsxs","jsxs","clsx","jsx","jsx","useEffect","clsx","useState"]}
|
|
@@ -291,7 +291,7 @@ var Tooltip = ({
|
|
|
291
291
|
{
|
|
292
292
|
className: (0, import_clsx2.clsx)(
|
|
293
293
|
`opacity-0 absolute text-xs font-semibold text-tooltip-text px-2 py-1 rounded whitespace-nowrap
|
|
294
|
-
animate-tooltip-fade-in shadow-
|
|
294
|
+
animate-tooltip-fade-in shadow-around-md bg-tooltip-background`,
|
|
295
295
|
positionClasses[position],
|
|
296
296
|
tooltipClassName
|
|
297
297
|
),
|
|
@@ -302,7 +302,7 @@ var Tooltip = ({
|
|
|
302
302
|
"div",
|
|
303
303
|
{
|
|
304
304
|
className: (0, import_clsx2.clsx)(`absolute w-0 h-0`, triangleClasses[position]),
|
|
305
|
-
style: { ...triangleStyle[position], zIndex }
|
|
305
|
+
style: { ...triangleStyle[position], zIndex: zIndex + 1 }
|
|
306
306
|
}
|
|
307
307
|
)
|
|
308
308
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/dialogs/ConfirmDialog.tsx","../../../src/components/user-action/Button.tsx","../../../src/localization/LanguageProvider.tsx","../../../src/hooks/useLocalStorage.ts","../../../src/localization/util.ts","../../../src/localization/useTranslation.ts","../../../src/components/layout-and-navigation/Overlay.tsx","../../../src/hooks/useHoverState.ts","../../../src/components/user-action/Tooltip.tsx"],"sourcesContent":["import type { PropsWithChildren } from 'react'\nimport type { SolidButtonColor } from '../user-action/Button'\nimport { SolidButton } from '../user-action/Button'\nimport type { PropsForTranslation } from '../../localization/useTranslation'\nimport { useTranslation } from '../../localization/useTranslation'\nimport clsx from 'clsx'\nimport type { DialogProps } from '../layout-and-navigation/Overlay'\nimport { Dialog } from '../layout-and-navigation/Overlay'\n\ntype ConfirmDialogTranslation = {\n confirm: string,\n cancel: string,\n decline: string,\n}\n\nexport type ConfirmDialogType = 'positive' | 'negative' | 'neutral' | 'primary'\n\nconst defaultConfirmDialogTranslation = {\n en: {\n confirm: 'Confirm',\n decline: 'Decline'\n },\n de: {\n confirm: 'Bestätigen',\n decline: 'Ablehnen'\n }\n}\n\ntype ButtonOverwriteType = {\n text?: string,\n color?: SolidButtonColor,\n disabled?: boolean,\n}\n\nexport type ConfirmDialogProps = DialogProps & {\n isShowingDecline?: boolean,\n requireAnswer?: boolean,\n onConfirm: () => void,\n onDecline?: () => void,\n confirmType?: ConfirmDialogType,\n /**\n * Order: Decline, Confirm\n */\n buttonOverwrites?: [ButtonOverwriteType, ButtonOverwriteType],\n}\n\n/**\n * A Dialog for demanding the user for confirmation\n *\n * To allow for background closing, prefer using a ConfirmModal\n */\nexport const ConfirmDialog = ({\n overwriteTranslation,\n children,\n onConfirm,\n onDecline,\n confirmType = 'positive',\n buttonOverwrites,\n className,\n ...restProps\n }: PropsForTranslation<ConfirmDialogTranslation, PropsWithChildren<ConfirmDialogProps>>) => {\n const translation = useTranslation(defaultConfirmDialogTranslation, overwriteTranslation)\n\n const mapping: Record<ConfirmDialogType, SolidButtonColor> = {\n neutral: 'primary',\n negative: 'negative',\n positive: 'positive',\n primary: 'primary',\n }\n\n return (\n <Dialog {...restProps} className={clsx('justify-between', className)}>\n <div className=\"col grow\">\n {children}\n </div>\n <div className=\"row mt-3 gap-x-4 justify-end\">\n {onDecline && (\n <SolidButton\n color={buttonOverwrites?.[0].color ?? 'negative'}\n onClick={onDecline}\n\n disabled={buttonOverwrites?.[0].disabled ?? false}\n >\n {buttonOverwrites?.[0].text ?? translation.decline}\n </SolidButton>\n )}\n <SolidButton\n autoFocus\n color={buttonOverwrites?.[1].color ?? mapping[confirmType]}\n onClick={onConfirm}\n disabled={buttonOverwrites?.[1].disabled ?? false}\n >\n {buttonOverwrites?.[1].text ?? translation.confirm}\n </SolidButton>\n </div>\n </Dialog>\n )\n}\n","import type { ButtonHTMLAttributes, PropsWithChildren, ReactNode } from 'react'\nimport clsx from 'clsx'\n\n\nexport const ButtonColorUtil = {\n solid: ['primary', 'secondary', 'tertiary', 'positive', 'warning', 'negative', 'neutral'] as const,\n text: ['primary', 'negative', 'neutral'] as const,\n outline: ['primary'] as const,\n}\n\n\n/**\n * The allowed colors for the SolidButton and IconButton\n */\nexport type SolidButtonColor = typeof ButtonColorUtil.solid[number]\n/**\n * The allowed colors for the OutlineButton\n */\nexport type OutlineButtonColor = typeof ButtonColorUtil.outline[number]\n/**\n * The allowed colors for the TextButton\n */\nexport type TextButtonColor = typeof ButtonColorUtil.text[number]\n\n/**\n * The different sizes for a button\n */\ntype ButtonSizes = 'small' | 'medium' | 'large'\n\n/**\n * The shard properties between all button types\n */\nexport type ButtonProps = PropsWithChildren<{\n /**\n * @default 'medium'\n */\n size?: ButtonSizes,\n}> & ButtonHTMLAttributes<Element>\n\nconst paddingMapping: Record<ButtonSizes, string> = {\n small: 'btn-sm',\n medium: 'btn-md',\n large: 'btn-lg'\n}\n\nconst iconPaddingMapping: Record<ButtonSizes, string> = {\n small: 'icon-btn-sm',\n medium: 'icon-btn-md',\n large: 'icon-btn-lg'\n}\n\nexport const ButtonUtil = {\n paddingMapping,\n iconPaddingMapping\n}\n\ntype ButtonWithIconsProps = ButtonProps & {\n startIcon?: ReactNode,\n endIcon?: ReactNode,\n}\n\nexport type SolidButtonProps = ButtonWithIconsProps & {\n color?: SolidButtonColor,\n}\n\nexport type OutlineButtonProps = ButtonWithIconsProps & {\n color?: OutlineButtonColor,\n}\n\nexport type TextButtonProps = ButtonWithIconsProps & {\n color?: TextButtonColor,\n}\n\nexport type IconButtonProps = ButtonProps & {\n color?: SolidButtonColor,\n}\n\n/**\n * A button with a solid background and different sizes\n */\nconst SolidButton = ({\n children,\n disabled = false,\n color = 'primary',\n size = 'medium',\n startIcon,\n endIcon,\n onClick,\n className,\n ...restProps\n }: SolidButtonProps) => {\n const colorClasses = {\n primary: 'bg-button-solid-primary-background text-button-solid-primary-text',\n secondary: 'bg-button-solid-secondary-background text-button-solid-secondary-text',\n tertiary: 'bg-button-solid-tertiary-background text-button-solid-tertiary-text',\n positive: 'bg-button-solid-positive-background text-button-solid-positive-text',\n warning: 'bg-button-solid-warning-background text-button-solid-warning-text',\n negative: 'bg-button-solid-negative-background text-button-solid-negative-text',\n neutral: 'bg-button-solid-neutral-background text-button-solid-neutral-text',\n }[color]\n\n const iconColorClasses = {\n primary: 'text-button-solid-primary-icon',\n secondary: 'text-button-solid-secondary-icon',\n tertiary: 'text-button-solid-tertiary-icon',\n positive: 'text-button-solid-positive-icon',\n warning: 'text-button-solid-warning-icon',\n negative: 'text-button-solid-negative-icon',\n neutral: 'text-button-solid-neutral-icon',\n }[color]\n\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n {\n 'text-disabled-text bg-disabled-background cursor-not-allowed': disabled,\n [clsx(colorClasses, 'hover:brightness-90')]: !disabled\n },\n ButtonUtil.paddingMapping[size],\n className\n )}\n {...restProps}\n >\n {startIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {startIcon}\n </span>\n )}\n {children}\n {endIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {endIcon}\n </span>\n )}\n </button>\n )\n}\n\n/**\n * A button with an outline border and different sizes\n */\nconst OutlineButton = ({\n children,\n disabled = false,\n color = 'primary',\n size = 'medium',\n startIcon,\n endIcon,\n onClick,\n className,\n ...restProps\n }: OutlineButtonProps) => {\n const colorClasses = {\n primary: 'bg-transparent border-2 border-button-outline-primary-text text-button-outline-primary-text',\n }[color]\n\n const iconColorClasses = {\n primary: 'text-button-outline-primary-icon',\n }[color]\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n {\n 'text-disabled-text border-disabled-outline cursor-not-allowed': disabled,\n [clsx(colorClasses, 'hover:brightness-80')]: !disabled,\n },\n ButtonUtil.paddingMapping[size],\n className\n )}\n {...restProps}\n >\n {startIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {startIcon}\n </span>\n )}\n {children}\n {endIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {endIcon}\n </span>\n )}\n </button>\n )\n}\n\n/**\n * A text that is a button that can have different sizes\n */\nconst TextButton = ({\n children,\n disabled = false,\n color = 'neutral',\n size = 'medium',\n startIcon,\n endIcon,\n onClick,\n className,\n ...restProps\n }: TextButtonProps) => {\n const colorClasses = {\n primary: 'bg-transparent text-button-text-primary-text',\n negative: 'bg-transparent text-button-text-negative-text',\n neutral: 'bg-transparent text-button-text-neutral-text',\n }[color]\n\n const iconColorClasses = {\n primary: 'text-button-text-primary-icon',\n negative: 'text-button-text-negative-icon',\n neutral: 'text-button-text-neutral-icon',\n }[color]\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n {\n 'text-disabled-text cursor-not-allowed': disabled,\n [clsx(colorClasses, 'hover:bg-button-text-hover-background rounded-full')]: !disabled,\n },\n ButtonUtil.paddingMapping[size],\n className\n )}\n {...restProps}\n >\n {startIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {startIcon}\n </span>\n )}\n {children}\n {endIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {endIcon}\n </span>\n )}\n </button>\n )\n}\n\n\n/**\n * A button for icons with a solid background and different sizes\n */\nconst IconButton = ({\n children,\n disabled = false,\n color = 'primary',\n size = 'medium',\n onClick,\n className,\n ...restProps\n }: IconButtonProps) => {\n const colorClasses = {\n primary: 'bg-button-solid-primary-background text-button-solid-primary-text',\n secondary: 'bg-button-solid-secondary-background text-button-solid-secondary-text',\n tertiary: 'bg-button-solid-tertiary-background text-button-solid-tertiary-text',\n positive: 'bg-button-solid-positive-background text-button-solid-positive-text',\n warning: 'bg-button-solid-warning-background text-button-solid-warning-text',\n negative: 'bg-button-solid-negative-background text-button-solid-negative-text',\n neutral: 'bg-button-solid-neutral-background text-button-solid-neutral-text',\n }[color]\n\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n {\n 'text-disabled-text bg-disabled-background cursor-not-allowed': disabled,\n [clsx(colorClasses, 'hover:brightness-90')]: !disabled\n },\n ButtonUtil.iconPaddingMapping[size],\n className\n )}\n {...restProps}\n >\n {children}\n </button>\n )\n}\n\nexport { SolidButton, OutlineButton, TextButton, IconButton }\n","import type { Dispatch, PropsWithChildren, SetStateAction } from 'react'\nimport { createContext, useContext, useEffect, useState } from 'react'\nimport { useLocalStorage } from '../hooks/useLocalStorage'\nimport type { Language } from './util'\nimport { LanguageUtil } from './util'\n\nexport type LanguageContextValue = {\n language: Language,\n setLanguage: Dispatch<SetStateAction<Language>>,\n}\n\nexport const LanguageContext = createContext<LanguageContextValue>({\n language: LanguageUtil.DEFAULT_LANGUAGE,\n setLanguage: (v) => v\n})\n\nexport const useLanguage = () => useContext(LanguageContext)\n\nexport const useLocale = (overWriteLanguage?: Language) => {\n const { language } = useLanguage()\n const mapping: Record<Language, string> = {\n en: 'en-US',\n de: 'de-DE'\n }\n return mapping[overWriteLanguage ?? language]\n}\n\ntype LanguageProviderProps = {\n initialLanguage?: Language,\n}\n\nexport const LanguageProvider = ({ initialLanguage, children }: PropsWithChildren<LanguageProviderProps>) => {\n const [language, setLanguage] = useState<Language>(initialLanguage ?? LanguageUtil.DEFAULT_LANGUAGE)\n const [storedLanguage, setStoredLanguage] = useLocalStorage<Language>('language', initialLanguage ?? LanguageUtil.DEFAULT_LANGUAGE)\n\n useEffect(() => {\n if (language !== initialLanguage && initialLanguage) {\n console.warn('LanguageProvider initial state changed: Prefer using languageProvider\\'s setLanguage instead')\n setLanguage(initialLanguage)\n }\n }, [initialLanguage]) // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n // TODO set locale of html tag here as well\n setStoredLanguage(language)\n }, [language, setStoredLanguage])\n\n useEffect(() => {\n if (storedLanguage !== null) {\n setLanguage(storedLanguage)\n return\n }\n\n const LanguageToTestAgainst = Object.values(LanguageUtil.languages)\n\n const matchingBrowserLanguage = window.navigator.languages\n .map(language => LanguageToTestAgainst.find((test) => language === test || language.split('-')[0] === test))\n .filter(entry => entry !== undefined)\n\n if (matchingBrowserLanguage.length === 0) return\n\n const firstMatch = matchingBrowserLanguage[0] as Language\n setLanguage(firstMatch)\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <LanguageContext.Provider value={{\n language,\n setLanguage\n }}>\n {children}\n </LanguageContext.Provider>\n )\n}","import type { Dispatch, SetStateAction } from 'react'\nimport { useCallback, useEffect, useState } from 'react'\nimport { LocalStorageService } from '../util/storage'\n\ntype SetValue<T> = Dispatch<SetStateAction<T>>\nexport const useLocalStorage = <T>(key: string, initValue: T): [T, SetValue<T>] => {\n const get = useCallback((): T => {\n if (typeof window === 'undefined') {\n return initValue\n }\n const storageService = new LocalStorageService()\n const value = storageService.get<T>(key)\n return value || initValue\n }, [initValue, key])\n\n const [storedValue, setStoredValue] = useState<T>(get)\n\n const setValue: SetValue<T> = useCallback(value => {\n const newValue = value instanceof Function ? value(storedValue) : value\n const storageService = new LocalStorageService()\n storageService.set(key, value)\n\n setStoredValue(newValue)\n }, [storedValue, setStoredValue, key])\n\n useEffect(() => {\n setStoredValue(get())\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n return [storedValue, setValue]\n}","/**\n * The supported languages\n */\nconst languages = ['en', 'de'] as const\n\n/**\n * The supported languages\n */\nexport type Language = typeof languages[number]\n\n/**\n * The supported languages' names in their respective language\n */\nconst languagesLocalNames: Record<Language, string> = {\n en: 'English',\n de: 'Deutsch',\n}\n\n/**\n * The default language\n */\nconst DEFAULT_LANGUAGE: Language = 'en'\n\n/**\n * A constant definition for holding data regarding languages\n */\nexport const LanguageUtil = {\n languages,\n DEFAULT_LANGUAGE,\n languagesLocalNames,\n}","import { useLanguage } from './LanguageProvider'\nimport type { Language } from './util'\n\nexport type Translation<T> = Record<Language, T>\n\ntype OverwriteTranslationType<Translation extends Record<string, unknown>> = {\n language?: Language,\n translation?: Partial<Record<Language, Partial<Translation>>>,\n}\n\n/**\n * Adds the `language` prop to the component props.\n *\n * @param Translation the type of the translation object\n *\n * @param Props the type of the component props, defaults to `Record<string, never>`,\n * if you don't expect any other props other than `language` and get an\n * error when using your component (because it uses `forwardRef` etc.)\n * you can try out `Record<string, unknown>`, this might resolve your\n * problem as `SomeType & never` is still `never` but `SomeType & unknown`\n * is `SomeType` which means that adding back props (like `ref` etc.)\n * works properly\n */\nexport type PropsForTranslation<\n Translation extends Record<string, unknown>,\n Props = Record<string, never>\n> = Props & {\n overwriteTranslation?: OverwriteTranslationType<Translation>,\n};\n\nexport const useTranslation = <Translation extends Record<string, unknown>>(\n defaults: Record<Language, Translation>,\n translationOverwrite: OverwriteTranslationType<Translation> = {}\n): Translation => {\n const { language: languageProp, translation: overwrite } = translationOverwrite\n const { language: inferredLanguage } = useLanguage()\n const usedLanguage = languageProp ?? inferredLanguage\n let defaultValues: Translation = defaults[usedLanguage]\n if (overwrite && overwrite[usedLanguage]) {\n defaultValues = { ...defaultValues, ...overwrite[usedLanguage] }\n }\n return defaultValues\n}\n","import type { PropsWithChildren, ReactNode } from 'react'\nimport { useEffect, useRef, useState } from 'react'\nimport ReactDOM from 'react-dom'\nimport clsx from 'clsx'\nimport { Tooltip } from '../user-action/Tooltip'\nimport { X } from 'lucide-react'\nimport { IconButton } from '../user-action/Button'\nimport type { PropsForTranslation } from '../../localization/useTranslation'\nimport { useTranslation } from '../../localization/useTranslation'\nimport type { Language } from '../../localization/util'\n\nexport type OverlayProps = PropsWithChildren<{\n /**\n * Whether the overlay should be currently displayed\n */\n isOpen: boolean,\n /**\n * Callback when the background is clicked\n */\n onBackgroundClick?: () => void,\n /**\n * Styling for the background\n *\n * To remove the darkening, set bg-transparent\n */\n backgroundClassName?: string,\n}>\n\n/**\n * A generic overlay window which is managed by its parent\n */\nexport const Overlay = ({\n children,\n isOpen,\n onBackgroundClick,\n backgroundClassName,\n }: PropsWithChildren<OverlayProps>) => {\n // The element to which the overlay will be attached to\n const [root, setRoot] = useState<HTMLElement>()\n\n useEffect(() => {\n setRoot(document.body)\n }, [])\n\n if (!root || !isOpen) return null\n\n\n return ReactDOM.createPortal(\n <div className={clsx('fixed inset-0 z-[9999]')}>\n <div\n className={clsx('fixed inset-0 h-screen w-screen bg-black/30', backgroundClassName)}\n onClick={onBackgroundClick}\n />\n {children}\n </div>,\n root\n )\n}\n\n\nlet overlayStack: HTMLDivElement[] = []\n\n\n// --- Modal ---\n\ntype ModalHeaderTranslation = {\n close: string,\n}\n\nconst defaultModalHeaderTranslation: Record<Language, ModalHeaderTranslation> = {\n en: {\n close: 'Close'\n },\n de: {\n close: 'Schließen'\n }\n}\n\nexport type OverlayHeaderProps = {\n /**\n * Callback when the close button is clicked. If omitted or undefined, the button is hidden\n */\n onClose?: () => void,\n /** The title of the Modal. If you want to only set the text use `titleText` instead */\n title?: ReactNode,\n /** The title text of the Modal. If you want to set a custom title use `title` instead */\n titleText?: string,\n /** The description of the Modal. If you want to only set the text use `descriptionText` instead */\n description?: ReactNode,\n /** The description text of the Modal. If you want to set a custom description use `description` instead */\n descriptionText?: string,\n}\n\n/**\n * A header that should be in an Overlay\n */\nexport const OverlayHeader = ({\n overwriteTranslation,\n onClose,\n title,\n titleText = '',\n description,\n descriptionText = ''\n }: PropsForTranslation<ModalHeaderTranslation, OverlayHeaderProps>) => {\n const translation = useTranslation(defaultModalHeaderTranslation, overwriteTranslation)\n const hasTitleRow = !!title || !!titleText || !!onClose\n const titleRow = (\n <div className=\"row justify-between items-start gap-x-8\">\n {title ?? (\n <h2\n className={clsx('textstyle-title-lg', {\n 'mb-1': description || descriptionText,\n })}\n >\n {titleText}\n </h2>\n )}\n {!!onClose && (\n <Tooltip tooltip={translation.close}>\n <IconButton color=\"neutral\" size=\"small\" onClick={onClose}>\n <X className=\"w-full h-full\"/>\n </IconButton>\n </Tooltip>\n )}\n </div>\n )\n\n return (\n <div className=\"col\">\n {hasTitleRow && (titleRow)}\n {description ?? (descriptionText && (<span className=\"textstyle-description\">{descriptionText}</span>))}\n </div>\n )\n}\n\nexport type ModalProps = {\n isOpen: boolean,\n onClose: () => void,\n className?: string,\n backgroundClassName?: string,\n headerProps?: Omit<OverlayHeaderProps, 'onClose'>,\n}\n\n/**\n * A Generic Modal Window\n */\nexport const Modal = ({\n children,\n isOpen,\n onClose,\n className,\n backgroundClassName,\n headerProps,\n }: PropsWithChildren<ModalProps>) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (!isOpen) return\n\n const modal = ref.current\n\n if (!modal) {\n console.error('modal open, but no ref found')\n return\n }\n\n overlayStack.push(modal)\n\n const focusable = modal?.querySelectorAll(\n 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex=\"-1\"])'\n )\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const isTopmost = overlayStack[overlayStack.length - 1] === modal\n if (!isTopmost) return\n\n if (e.key === 'Escape') {\n e.stopPropagation()\n onClose()\n } else if (e.key === 'Tab') {\n if (focusable.length === 0) return\n\n if (e.shiftKey && document.activeElement === first) {\n e.preventDefault();\n (last as HTMLElement).focus()\n } else if (!e.shiftKey && document.activeElement === last) {\n e.preventDefault();\n (first as HTMLElement).focus()\n }\n }\n }\n\n modal.focus()\n document.addEventListener('keydown', handleKeyDown)\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown)\n overlayStack = overlayStack.filter(m => m !== modal)\n }\n }, [isOpen, onClose])\n\n return (\n <Overlay\n isOpen={isOpen}\n onBackgroundClick={onClose}\n backgroundClassName={backgroundClassName}\n >\n <div\n ref={ref}\n tabIndex={-1}\n className={clsx(\n 'fixed left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 col p-4 bg-overlay-background text-overlay-text rounded-xl shadow-xl',\n className\n )}\n role=\"dialog\"\n aria-modal={true}\n >\n <OverlayHeader {...headerProps} onClose={onClose}/>\n {children}\n </div>\n </Overlay>\n )\n}\n\n// --- Dialog ---\n\nexport type DialogProps = Omit<OverlayProps, 'onBackgroundClick'> & {\n headerProps?: Omit<OverlayHeaderProps, 'onClose'>,\n className?: string,\n}\n\n/**\n * A Generic Dialog Window\n */\nexport const Dialog = ({\n children,\n isOpen,\n className,\n backgroundClassName,\n headerProps,\n }: PropsWithChildren<DialogProps>) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (!isOpen) return\n\n const dialog = ref.current\n\n if (!dialog) {\n console.error('dialog open, but no ref found')\n return\n }\n\n overlayStack.push(dialog)\n\n const focusable = dialog?.querySelectorAll(\n 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex=\"-1\"])'\n )\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const isTopmost = overlayStack[overlayStack.length - 1] === dialog\n if (!isTopmost) return\n\n if (e.key === 'Escape') {\n e.stopPropagation()\n } else if (e.key === 'Tab') {\n if (focusable.length === 0) return\n\n if (e.shiftKey && document.activeElement === first) {\n e.preventDefault();\n (last as HTMLElement).focus()\n } else if (!e.shiftKey && document.activeElement === last) {\n e.preventDefault();\n (first as HTMLElement).focus()\n }\n }\n }\n\n dialog.focus()\n document.addEventListener('keydown', handleKeyDown)\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown)\n overlayStack = overlayStack.filter(m => m !== dialog)\n }\n }, [isOpen])\n\n return (\n <Overlay\n isOpen={isOpen}\n backgroundClassName={backgroundClassName}\n >\n <div\n ref={ref}\n tabIndex={-1}\n className={clsx(\n 'fixed left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 col p-4 bg-overlay-background text-overlay-text rounded-xl shadow-xl',\n className\n )}\n role=\"dialog\"\n aria-modal={true}\n >\n {!!headerProps && (<OverlayHeader {...headerProps}/>)}\n {children}\n </div>\n </Overlay>\n )\n}","import type { Dispatch, SetStateAction } from 'react'\nimport { useEffect, useState } from 'react'\n\ntype UseHoverStateProps = {\n /**\n * The delay after which the menu is closed in milliseconds\n *\n * default: 200ms\n */\n closingDelay: number,\n /**\n * Whether the hover state management should be disabled\n *\n * default: false\n */\n isDisabled: boolean,\n}\n\ntype UseHoverStateReturnType = {\n /**\n * Whether the element is hovered\n */\n isHovered: boolean,\n /**\n * Function to change the current hover status\n */\n setIsHovered: Dispatch<SetStateAction<boolean>>,\n /**\n * Handlers to pass on to the component that should be hovered\n */\n handlers: {\n onMouseEnter: () => void,\n onMouseLeave: () => void,\n },\n}\n\nconst defaultUseHoverStateProps: UseHoverStateProps = {\n closingDelay: 200,\n isDisabled: false,\n}\n\n/**\n * @param props See UseHoverStateProps\n *\n * A react hook for managing the hover state of a component. The handlers provided should be\n * forwarded to the component which should be hovered over\n */\nexport const useHoverState = (props: Partial<UseHoverStateProps> | undefined = undefined): UseHoverStateReturnType => {\n const { closingDelay, isDisabled } = { ...defaultUseHoverStateProps, ...props }\n\n const [isHovered, setIsHovered] = useState(false)\n const [timer, setTimer] = useState<NodeJS.Timeout>()\n\n const onMouseEnter = () => {\n if (isDisabled) {\n return\n }\n clearTimeout(timer)\n setIsHovered(true)\n }\n\n const onMouseLeave = () => {\n if (isDisabled) {\n return\n }\n setTimer(setTimeout(() => {\n setIsHovered(false)\n }, closingDelay))\n }\n\n useEffect(() => {\n if (timer) {\n return () => {\n clearTimeout(timer)\n }\n }\n })\n\n useEffect(() => {\n if (timer) {\n clearTimeout(timer)\n }\n }, [isDisabled]) // eslint-disable-line react-hooks/exhaustive-deps\n\n return {\n isHovered, setIsHovered, handlers: { onMouseEnter, onMouseLeave }\n }\n}\n","import type { CSSProperties, PropsWithChildren, ReactNode } from 'react'\nimport { useHoverState } from '../../hooks/useHoverState'\nimport { clsx } from 'clsx'\n\ntype Position = 'top' | 'bottom' | 'left' | 'right'\n\nexport type TooltipProps = PropsWithChildren<{\n tooltip: string | ReactNode,\n /**\n * Number of milliseconds until the tooltip appears\n *\n * defaults to 1000ms\n */\n animationDelay?: number,\n /**\n * Class names of additional styling properties for the tooltip\n */\n tooltipClassName?: string,\n /**\n * Class names of additional styling properties for the container from which the tooltip will be created\n */\n containerClassName?: string,\n position?: Position,\n zIndex?: number,\n}>\n\n/**\n * A Component for showing a tooltip when hovering over Content\n * @param tooltip The tooltip to show can be a text or any ReactNode\n * @param children The Content for which the tooltip should be created\n * @param animationDelay The delay before the tooltip appears\n * @param tooltipClassName Additional ClassNames for the Container of the tooltip\n * @param containerClassName Additional ClassNames for the Container holding the content\n * @param position The direction of the tooltip relative to the Container\n * @param zIndex The z Index of the tooltip (you may require this when stacking modal)\n * @constructor\n */\nexport const Tooltip = ({\n tooltip,\n children,\n animationDelay = 650,\n tooltipClassName = '',\n containerClassName = '',\n position = 'bottom',\n zIndex = 10,\n }: TooltipProps) => {\n const { isHovered, handlers } = useHoverState()\n\n const positionClasses = {\n top: `bottom-full left-1/2 -translate-x-1/2 mb-[6px]`,\n bottom: `top-full left-1/2 -translate-x-1/2 mt-[6px]`,\n left: `right-full top-1/2 -translate-y-1/2 mr-[6px]`,\n right: `left-full top-1/2 -translate-y-1/2 ml-[6px]`\n }\n\n const triangleSize = 6\n const triangleClasses = {\n top: `top-full left-1/2 -translate-x-1/2 border-t-tooltip-background border-l-transparent border-r-transparent`,\n bottom: `bottom-full left-1/2 -translate-x-1/2 border-b-tooltip-background border-l-transparent border-r-transparent`,\n left: `left-full top-1/2 -translate-y-1/2 border-l-tooltip-background border-t-transparent border-b-transparent`,\n right: `right-full top-1/2 -translate-y-1/2 border-r-tooltip-background border-t-transparent border-b-transparent`\n }\n\n const triangleStyle: Record<Position, CSSProperties> = {\n top: { borderWidth: `${triangleSize}px ${triangleSize}px 0 ${triangleSize}px` },\n bottom: { borderWidth: `0 ${triangleSize}px ${triangleSize}px ${triangleSize}px` },\n left: { borderWidth: `${triangleSize}px 0 ${triangleSize}px ${triangleSize}px` },\n right: { borderWidth: `${triangleSize}px ${triangleSize}px ${triangleSize}px 0` }\n }\n\n return (\n <div\n className={clsx('relative inline-block', containerClassName)}\n {...handlers}\n >\n {children}\n {isHovered && (\n <div\n className={clsx(\n `opacity-0 absolute text-xs font-semibold text-tooltip-text px-2 py-1 rounded whitespace-nowrap\n animate-tooltip-fade-in shadow-lg bg-tooltip-background`,\n positionClasses[position], tooltipClassName\n )}\n style={{ zIndex, animationDelay: animationDelay + 'ms' }}\n >\n {tooltip}\n <div\n className={clsx(`absolute w-0 h-0`, triangleClasses[position])}\n style={{ ...triangleStyle[position], zIndex }}\n />\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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","names":["clsx","clsx","import_react","import_jsx_runtime","import_clsx","import_react","import_clsx","import_react","import_clsx","import_jsx_runtime","import_jsx_runtime","ReactDOM","clsx","clsx","import_jsx_runtime","clsx"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/dialogs/ConfirmDialog.tsx","../../../src/components/user-action/Button.tsx","../../../src/localization/LanguageProvider.tsx","../../../src/hooks/useLocalStorage.ts","../../../src/localization/util.ts","../../../src/localization/useTranslation.ts","../../../src/components/layout-and-navigation/Overlay.tsx","../../../src/hooks/useHoverState.ts","../../../src/components/user-action/Tooltip.tsx"],"sourcesContent":["import type { PropsWithChildren } from 'react'\nimport type { SolidButtonColor } from '../user-action/Button'\nimport { SolidButton } from '../user-action/Button'\nimport type { PropsForTranslation } from '../../localization/useTranslation'\nimport { useTranslation } from '../../localization/useTranslation'\nimport clsx from 'clsx'\nimport type { DialogProps } from '../layout-and-navigation/Overlay'\nimport { Dialog } from '../layout-and-navigation/Overlay'\n\ntype ConfirmDialogTranslation = {\n confirm: string,\n cancel: string,\n decline: string,\n}\n\nexport type ConfirmDialogType = 'positive' | 'negative' | 'neutral' | 'primary'\n\nconst defaultConfirmDialogTranslation = {\n en: {\n confirm: 'Confirm',\n decline: 'Decline'\n },\n de: {\n confirm: 'Bestätigen',\n decline: 'Ablehnen'\n }\n}\n\ntype ButtonOverwriteType = {\n text?: string,\n color?: SolidButtonColor,\n disabled?: boolean,\n}\n\nexport type ConfirmDialogProps = DialogProps & {\n isShowingDecline?: boolean,\n requireAnswer?: boolean,\n onConfirm: () => void,\n onDecline?: () => void,\n confirmType?: ConfirmDialogType,\n /**\n * Order: Decline, Confirm\n */\n buttonOverwrites?: [ButtonOverwriteType, ButtonOverwriteType],\n}\n\n/**\n * A Dialog for demanding the user for confirmation\n *\n * To allow for background closing, prefer using a ConfirmModal\n */\nexport const ConfirmDialog = ({\n overwriteTranslation,\n children,\n onConfirm,\n onDecline,\n confirmType = 'positive',\n buttonOverwrites,\n className,\n ...restProps\n }: PropsForTranslation<ConfirmDialogTranslation, PropsWithChildren<ConfirmDialogProps>>) => {\n const translation = useTranslation(defaultConfirmDialogTranslation, overwriteTranslation)\n\n const mapping: Record<ConfirmDialogType, SolidButtonColor> = {\n neutral: 'primary',\n negative: 'negative',\n positive: 'positive',\n primary: 'primary',\n }\n\n return (\n <Dialog {...restProps} className={clsx('justify-between', className)}>\n <div className=\"col grow\">\n {children}\n </div>\n <div className=\"row mt-3 gap-x-4 justify-end\">\n {onDecline && (\n <SolidButton\n color={buttonOverwrites?.[0].color ?? 'negative'}\n onClick={onDecline}\n\n disabled={buttonOverwrites?.[0].disabled ?? false}\n >\n {buttonOverwrites?.[0].text ?? translation.decline}\n </SolidButton>\n )}\n <SolidButton\n autoFocus\n color={buttonOverwrites?.[1].color ?? mapping[confirmType]}\n onClick={onConfirm}\n disabled={buttonOverwrites?.[1].disabled ?? false}\n >\n {buttonOverwrites?.[1].text ?? translation.confirm}\n </SolidButton>\n </div>\n </Dialog>\n )\n}\n","import type { ButtonHTMLAttributes, PropsWithChildren, ReactNode } from 'react'\nimport clsx from 'clsx'\n\n\nexport const ButtonColorUtil = {\n solid: ['primary', 'secondary', 'tertiary', 'positive', 'warning', 'negative', 'neutral'] as const,\n text: ['primary', 'negative', 'neutral'] as const,\n outline: ['primary'] as const,\n}\n\n\n/**\n * The allowed colors for the SolidButton and IconButton\n */\nexport type SolidButtonColor = typeof ButtonColorUtil.solid[number]\n/**\n * The allowed colors for the OutlineButton\n */\nexport type OutlineButtonColor = typeof ButtonColorUtil.outline[number]\n/**\n * The allowed colors for the TextButton\n */\nexport type TextButtonColor = typeof ButtonColorUtil.text[number]\n\n/**\n * The different sizes for a button\n */\ntype ButtonSizes = 'small' | 'medium' | 'large'\n\n/**\n * The shard properties between all button types\n */\nexport type ButtonProps = PropsWithChildren<{\n /**\n * @default 'medium'\n */\n size?: ButtonSizes,\n}> & ButtonHTMLAttributes<Element>\n\nconst paddingMapping: Record<ButtonSizes, string> = {\n small: 'btn-sm',\n medium: 'btn-md',\n large: 'btn-lg'\n}\n\nconst iconPaddingMapping: Record<ButtonSizes, string> = {\n small: 'icon-btn-sm',\n medium: 'icon-btn-md',\n large: 'icon-btn-lg'\n}\n\nexport const ButtonUtil = {\n paddingMapping,\n iconPaddingMapping\n}\n\ntype ButtonWithIconsProps = ButtonProps & {\n startIcon?: ReactNode,\n endIcon?: ReactNode,\n}\n\nexport type SolidButtonProps = ButtonWithIconsProps & {\n color?: SolidButtonColor,\n}\n\nexport type OutlineButtonProps = ButtonWithIconsProps & {\n color?: OutlineButtonColor,\n}\n\nexport type TextButtonProps = ButtonWithIconsProps & {\n color?: TextButtonColor,\n}\n\nexport type IconButtonProps = ButtonProps & {\n color?: SolidButtonColor,\n}\n\n/**\n * A button with a solid background and different sizes\n */\nconst SolidButton = ({\n children,\n disabled = false,\n color = 'primary',\n size = 'medium',\n startIcon,\n endIcon,\n onClick,\n className,\n ...restProps\n }: SolidButtonProps) => {\n const colorClasses = {\n primary: 'bg-button-solid-primary-background text-button-solid-primary-text',\n secondary: 'bg-button-solid-secondary-background text-button-solid-secondary-text',\n tertiary: 'bg-button-solid-tertiary-background text-button-solid-tertiary-text',\n positive: 'bg-button-solid-positive-background text-button-solid-positive-text',\n warning: 'bg-button-solid-warning-background text-button-solid-warning-text',\n negative: 'bg-button-solid-negative-background text-button-solid-negative-text',\n neutral: 'bg-button-solid-neutral-background text-button-solid-neutral-text',\n }[color]\n\n const iconColorClasses = {\n primary: 'text-button-solid-primary-icon',\n secondary: 'text-button-solid-secondary-icon',\n tertiary: 'text-button-solid-tertiary-icon',\n positive: 'text-button-solid-positive-icon',\n warning: 'text-button-solid-warning-icon',\n negative: 'text-button-solid-negative-icon',\n neutral: 'text-button-solid-neutral-icon',\n }[color]\n\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n {\n 'text-disabled-text bg-disabled-background cursor-not-allowed': disabled,\n [clsx(colorClasses, 'hover:brightness-90')]: !disabled\n },\n ButtonUtil.paddingMapping[size],\n className\n )}\n {...restProps}\n >\n {startIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {startIcon}\n </span>\n )}\n {children}\n {endIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {endIcon}\n </span>\n )}\n </button>\n )\n}\n\n/**\n * A button with an outline border and different sizes\n */\nconst OutlineButton = ({\n children,\n disabled = false,\n color = 'primary',\n size = 'medium',\n startIcon,\n endIcon,\n onClick,\n className,\n ...restProps\n }: OutlineButtonProps) => {\n const colorClasses = {\n primary: 'bg-transparent border-2 border-button-outline-primary-text text-button-outline-primary-text',\n }[color]\n\n const iconColorClasses = {\n primary: 'text-button-outline-primary-icon',\n }[color]\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n {\n 'text-disabled-text border-disabled-outline cursor-not-allowed': disabled,\n [clsx(colorClasses, 'hover:brightness-80')]: !disabled,\n },\n ButtonUtil.paddingMapping[size],\n className\n )}\n {...restProps}\n >\n {startIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {startIcon}\n </span>\n )}\n {children}\n {endIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {endIcon}\n </span>\n )}\n </button>\n )\n}\n\n/**\n * A text that is a button that can have different sizes\n */\nconst TextButton = ({\n children,\n disabled = false,\n color = 'neutral',\n size = 'medium',\n startIcon,\n endIcon,\n onClick,\n className,\n ...restProps\n }: TextButtonProps) => {\n const colorClasses = {\n primary: 'bg-transparent text-button-text-primary-text',\n negative: 'bg-transparent text-button-text-negative-text',\n neutral: 'bg-transparent text-button-text-neutral-text',\n }[color]\n\n const iconColorClasses = {\n primary: 'text-button-text-primary-icon',\n negative: 'text-button-text-negative-icon',\n neutral: 'text-button-text-neutral-icon',\n }[color]\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n {\n 'text-disabled-text cursor-not-allowed': disabled,\n [clsx(colorClasses, 'hover:bg-button-text-hover-background rounded-full')]: !disabled,\n },\n ButtonUtil.paddingMapping[size],\n className\n )}\n {...restProps}\n >\n {startIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {startIcon}\n </span>\n )}\n {children}\n {endIcon && (\n <span\n className={clsx({\n [iconColorClasses]: !disabled,\n [`text-disabled-icon`]: disabled\n })}\n >\n {endIcon}\n </span>\n )}\n </button>\n )\n}\n\n\n/**\n * A button for icons with a solid background and different sizes\n */\nconst IconButton = ({\n children,\n disabled = false,\n color = 'primary',\n size = 'medium',\n onClick,\n className,\n ...restProps\n }: IconButtonProps) => {\n const colorClasses = {\n primary: 'bg-button-solid-primary-background text-button-solid-primary-text',\n secondary: 'bg-button-solid-secondary-background text-button-solid-secondary-text',\n tertiary: 'bg-button-solid-tertiary-background text-button-solid-tertiary-text',\n positive: 'bg-button-solid-positive-background text-button-solid-positive-text',\n warning: 'bg-button-solid-warning-background text-button-solid-warning-text',\n negative: 'bg-button-solid-negative-background text-button-solid-negative-text',\n neutral: 'bg-button-solid-neutral-background text-button-solid-neutral-text',\n }[color]\n\n return (\n <button\n onClick={disabled ? undefined : onClick}\n disabled={disabled || onClick === undefined}\n className={clsx(\n {\n 'text-disabled-text bg-disabled-background cursor-not-allowed': disabled,\n [clsx(colorClasses, 'hover:brightness-90')]: !disabled\n },\n ButtonUtil.iconPaddingMapping[size],\n className\n )}\n {...restProps}\n >\n {children}\n </button>\n )\n}\n\nexport { SolidButton, OutlineButton, TextButton, IconButton }\n","import type { Dispatch, PropsWithChildren, SetStateAction } from 'react'\nimport { createContext, useContext, useEffect, useState } from 'react'\nimport { useLocalStorage } from '../hooks/useLocalStorage'\nimport type { Language } from './util'\nimport { LanguageUtil } from './util'\n\nexport type LanguageContextValue = {\n language: Language,\n setLanguage: Dispatch<SetStateAction<Language>>,\n}\n\nexport const LanguageContext = createContext<LanguageContextValue>({\n language: LanguageUtil.DEFAULT_LANGUAGE,\n setLanguage: (v) => v\n})\n\nexport const useLanguage = () => useContext(LanguageContext)\n\nexport const useLocale = (overWriteLanguage?: Language) => {\n const { language } = useLanguage()\n const mapping: Record<Language, string> = {\n en: 'en-US',\n de: 'de-DE'\n }\n return mapping[overWriteLanguage ?? language]\n}\n\ntype LanguageProviderProps = {\n initialLanguage?: Language,\n}\n\nexport const LanguageProvider = ({ initialLanguage, children }: PropsWithChildren<LanguageProviderProps>) => {\n const [language, setLanguage] = useState<Language>(initialLanguage ?? LanguageUtil.DEFAULT_LANGUAGE)\n const [storedLanguage, setStoredLanguage] = useLocalStorage<Language>('language', initialLanguage ?? LanguageUtil.DEFAULT_LANGUAGE)\n\n useEffect(() => {\n if (language !== initialLanguage && initialLanguage) {\n console.warn('LanguageProvider initial state changed: Prefer using languageProvider\\'s setLanguage instead')\n setLanguage(initialLanguage)\n }\n }, [initialLanguage]) // eslint-disable-line react-hooks/exhaustive-deps\n\n useEffect(() => {\n // TODO set locale of html tag here as well\n setStoredLanguage(language)\n }, [language, setStoredLanguage])\n\n useEffect(() => {\n if (storedLanguage !== null) {\n setLanguage(storedLanguage)\n return\n }\n\n const LanguageToTestAgainst = Object.values(LanguageUtil.languages)\n\n const matchingBrowserLanguage = window.navigator.languages\n .map(language => LanguageToTestAgainst.find((test) => language === test || language.split('-')[0] === test))\n .filter(entry => entry !== undefined)\n\n if (matchingBrowserLanguage.length === 0) return\n\n const firstMatch = matchingBrowserLanguage[0] as Language\n setLanguage(firstMatch)\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n return (\n <LanguageContext.Provider value={{\n language,\n setLanguage\n }}>\n {children}\n </LanguageContext.Provider>\n )\n}","import type { Dispatch, SetStateAction } from 'react'\nimport { useCallback, useEffect, useState } from 'react'\nimport { LocalStorageService } from '../util/storage'\n\ntype SetValue<T> = Dispatch<SetStateAction<T>>\nexport const useLocalStorage = <T>(key: string, initValue: T): [T, SetValue<T>] => {\n const get = useCallback((): T => {\n if (typeof window === 'undefined') {\n return initValue\n }\n const storageService = new LocalStorageService()\n const value = storageService.get<T>(key)\n return value || initValue\n }, [initValue, key])\n\n const [storedValue, setStoredValue] = useState<T>(get)\n\n const setValue: SetValue<T> = useCallback(value => {\n const newValue = value instanceof Function ? value(storedValue) : value\n const storageService = new LocalStorageService()\n storageService.set(key, value)\n\n setStoredValue(newValue)\n }, [storedValue, setStoredValue, key])\n\n useEffect(() => {\n setStoredValue(get())\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n return [storedValue, setValue]\n}","/**\n * The supported languages\n */\nconst languages = ['en', 'de'] as const\n\n/**\n * The supported languages\n */\nexport type Language = typeof languages[number]\n\n/**\n * The supported languages' names in their respective language\n */\nconst languagesLocalNames: Record<Language, string> = {\n en: 'English',\n de: 'Deutsch',\n}\n\n/**\n * The default language\n */\nconst DEFAULT_LANGUAGE: Language = 'en'\n\n/**\n * A constant definition for holding data regarding languages\n */\nexport const LanguageUtil = {\n languages,\n DEFAULT_LANGUAGE,\n languagesLocalNames,\n}","import { useLanguage } from './LanguageProvider'\nimport type { Language } from './util'\n\nexport type Translation<T> = Record<Language, T>\n\ntype OverwriteTranslationType<Translation extends Record<string, unknown>> = {\n language?: Language,\n translation?: Partial<Record<Language, Partial<Translation>>>,\n}\n\n/**\n * Adds the `language` prop to the component props.\n *\n * @param Translation the type of the translation object\n *\n * @param Props the type of the component props, defaults to `Record<string, never>`,\n * if you don't expect any other props other than `language` and get an\n * error when using your component (because it uses `forwardRef` etc.)\n * you can try out `Record<string, unknown>`, this might resolve your\n * problem as `SomeType & never` is still `never` but `SomeType & unknown`\n * is `SomeType` which means that adding back props (like `ref` etc.)\n * works properly\n */\nexport type PropsForTranslation<\n Translation extends Record<string, unknown>,\n Props = Record<string, never>\n> = Props & {\n overwriteTranslation?: OverwriteTranslationType<Translation>,\n};\n\nexport const useTranslation = <Translation extends Record<string, unknown>>(\n defaults: Record<Language, Translation>,\n translationOverwrite: OverwriteTranslationType<Translation> = {}\n): Translation => {\n const { language: languageProp, translation: overwrite } = translationOverwrite\n const { language: inferredLanguage } = useLanguage()\n const usedLanguage = languageProp ?? inferredLanguage\n let defaultValues: Translation = defaults[usedLanguage]\n if (overwrite && overwrite[usedLanguage]) {\n defaultValues = { ...defaultValues, ...overwrite[usedLanguage] }\n }\n return defaultValues\n}\n","import type { PropsWithChildren, ReactNode } from 'react'\nimport { useEffect, useRef, useState } from 'react'\nimport ReactDOM from 'react-dom'\nimport clsx from 'clsx'\nimport { Tooltip } from '../user-action/Tooltip'\nimport { X } from 'lucide-react'\nimport { IconButton } from '../user-action/Button'\nimport type { PropsForTranslation } from '../../localization/useTranslation'\nimport { useTranslation } from '../../localization/useTranslation'\nimport type { Language } from '../../localization/util'\n\nexport type OverlayProps = PropsWithChildren<{\n /**\n * Whether the overlay should be currently displayed\n */\n isOpen: boolean,\n /**\n * Callback when the background is clicked\n */\n onBackgroundClick?: () => void,\n /**\n * Styling for the background\n *\n * To remove the darkening, set bg-transparent\n */\n backgroundClassName?: string,\n}>\n\n/**\n * A generic overlay window which is managed by its parent\n */\nexport const Overlay = ({\n children,\n isOpen,\n onBackgroundClick,\n backgroundClassName,\n }: PropsWithChildren<OverlayProps>) => {\n // The element to which the overlay will be attached to\n const [root, setRoot] = useState<HTMLElement>()\n\n useEffect(() => {\n setRoot(document.body)\n }, [])\n\n if (!root || !isOpen) return null\n\n\n return ReactDOM.createPortal(\n <div className={clsx('fixed inset-0 z-[9999]')}>\n <div\n className={clsx('fixed inset-0 h-screen w-screen bg-black/30', backgroundClassName)}\n onClick={onBackgroundClick}\n />\n {children}\n </div>,\n root\n )\n}\n\n\nlet overlayStack: HTMLDivElement[] = []\n\n\n// --- Modal ---\n\ntype ModalHeaderTranslation = {\n close: string,\n}\n\nconst defaultModalHeaderTranslation: Record<Language, ModalHeaderTranslation> = {\n en: {\n close: 'Close'\n },\n de: {\n close: 'Schließen'\n }\n}\n\nexport type OverlayHeaderProps = {\n /**\n * Callback when the close button is clicked. If omitted or undefined, the button is hidden\n */\n onClose?: () => void,\n /** The title of the Modal. If you want to only set the text use `titleText` instead */\n title?: ReactNode,\n /** The title text of the Modal. If you want to set a custom title use `title` instead */\n titleText?: string,\n /** The description of the Modal. If you want to only set the text use `descriptionText` instead */\n description?: ReactNode,\n /** The description text of the Modal. If you want to set a custom description use `description` instead */\n descriptionText?: string,\n}\n\n/**\n * A header that should be in an Overlay\n */\nexport const OverlayHeader = ({\n overwriteTranslation,\n onClose,\n title,\n titleText = '',\n description,\n descriptionText = ''\n }: PropsForTranslation<ModalHeaderTranslation, OverlayHeaderProps>) => {\n const translation = useTranslation(defaultModalHeaderTranslation, overwriteTranslation)\n const hasTitleRow = !!title || !!titleText || !!onClose\n const titleRow = (\n <div className=\"row justify-between items-start gap-x-8\">\n {title ?? (\n <h2\n className={clsx('textstyle-title-lg', {\n 'mb-1': description || descriptionText,\n })}\n >\n {titleText}\n </h2>\n )}\n {!!onClose && (\n <Tooltip tooltip={translation.close}>\n <IconButton color=\"neutral\" size=\"small\" onClick={onClose}>\n <X className=\"w-full h-full\"/>\n </IconButton>\n </Tooltip>\n )}\n </div>\n )\n\n return (\n <div className=\"col\">\n {hasTitleRow && (titleRow)}\n {description ?? (descriptionText && (<span className=\"textstyle-description\">{descriptionText}</span>))}\n </div>\n )\n}\n\nexport type ModalProps = {\n isOpen: boolean,\n onClose: () => void,\n className?: string,\n backgroundClassName?: string,\n headerProps?: Omit<OverlayHeaderProps, 'onClose'>,\n}\n\n/**\n * A Generic Modal Window\n */\nexport const Modal = ({\n children,\n isOpen,\n onClose,\n className,\n backgroundClassName,\n headerProps,\n }: PropsWithChildren<ModalProps>) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (!isOpen) return\n\n const modal = ref.current\n\n if (!modal) {\n console.error('modal open, but no ref found')\n return\n }\n\n overlayStack.push(modal)\n\n const focusable = modal?.querySelectorAll(\n 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex=\"-1\"])'\n )\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const isTopmost = overlayStack[overlayStack.length - 1] === modal\n if (!isTopmost) return\n\n if (e.key === 'Escape') {\n e.stopPropagation()\n onClose()\n } else if (e.key === 'Tab') {\n if (focusable.length === 0) return\n\n if (e.shiftKey && document.activeElement === first) {\n e.preventDefault();\n (last as HTMLElement).focus()\n } else if (!e.shiftKey && document.activeElement === last) {\n e.preventDefault();\n (first as HTMLElement).focus()\n }\n }\n }\n\n modal.focus()\n document.addEventListener('keydown', handleKeyDown)\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown)\n overlayStack = overlayStack.filter(m => m !== modal)\n }\n }, [isOpen, onClose])\n\n return (\n <Overlay\n isOpen={isOpen}\n onBackgroundClick={onClose}\n backgroundClassName={backgroundClassName}\n >\n <div\n ref={ref}\n tabIndex={-1}\n className={clsx(\n 'fixed left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 col p-4 bg-overlay-background text-overlay-text rounded-xl shadow-xl',\n className\n )}\n role=\"dialog\"\n aria-modal={true}\n >\n <OverlayHeader {...headerProps} onClose={onClose}/>\n {children}\n </div>\n </Overlay>\n )\n}\n\n// --- Dialog ---\n\nexport type DialogProps = Omit<OverlayProps, 'onBackgroundClick'> & {\n headerProps?: Omit<OverlayHeaderProps, 'onClose'>,\n className?: string,\n}\n\n/**\n * A Generic Dialog Window\n */\nexport const Dialog = ({\n children,\n isOpen,\n className,\n backgroundClassName,\n headerProps,\n }: PropsWithChildren<DialogProps>) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (!isOpen) return\n\n const dialog = ref.current\n\n if (!dialog) {\n console.error('dialog open, but no ref found')\n return\n }\n\n overlayStack.push(dialog)\n\n const focusable = dialog?.querySelectorAll(\n 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex=\"-1\"])'\n )\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const isTopmost = overlayStack[overlayStack.length - 1] === dialog\n if (!isTopmost) return\n\n if (e.key === 'Escape') {\n e.stopPropagation()\n } else if (e.key === 'Tab') {\n if (focusable.length === 0) return\n\n if (e.shiftKey && document.activeElement === first) {\n e.preventDefault();\n (last as HTMLElement).focus()\n } else if (!e.shiftKey && document.activeElement === last) {\n e.preventDefault();\n (first as HTMLElement).focus()\n }\n }\n }\n\n dialog.focus()\n document.addEventListener('keydown', handleKeyDown)\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown)\n overlayStack = overlayStack.filter(m => m !== dialog)\n }\n }, [isOpen])\n\n return (\n <Overlay\n isOpen={isOpen}\n backgroundClassName={backgroundClassName}\n >\n <div\n ref={ref}\n tabIndex={-1}\n className={clsx(\n 'fixed left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2 col p-4 bg-overlay-background text-overlay-text rounded-xl shadow-xl',\n className\n )}\n role=\"dialog\"\n aria-modal={true}\n >\n {!!headerProps && (<OverlayHeader {...headerProps}/>)}\n {children}\n </div>\n </Overlay>\n )\n}","import type { Dispatch, SetStateAction } from 'react'\nimport { useEffect, useState } from 'react'\n\ntype UseHoverStateProps = {\n /**\n * The delay after which the menu is closed in milliseconds\n *\n * default: 200ms\n */\n closingDelay: number,\n /**\n * Whether the hover state management should be disabled\n *\n * default: false\n */\n isDisabled: boolean,\n}\n\ntype UseHoverStateReturnType = {\n /**\n * Whether the element is hovered\n */\n isHovered: boolean,\n /**\n * Function to change the current hover status\n */\n setIsHovered: Dispatch<SetStateAction<boolean>>,\n /**\n * Handlers to pass on to the component that should be hovered\n */\n handlers: {\n onMouseEnter: () => void,\n onMouseLeave: () => void,\n },\n}\n\nconst defaultUseHoverStateProps: UseHoverStateProps = {\n closingDelay: 200,\n isDisabled: false,\n}\n\n/**\n * @param props See UseHoverStateProps\n *\n * A react hook for managing the hover state of a component. The handlers provided should be\n * forwarded to the component which should be hovered over\n */\nexport const useHoverState = (props: Partial<UseHoverStateProps> | undefined = undefined): UseHoverStateReturnType => {\n const { closingDelay, isDisabled } = { ...defaultUseHoverStateProps, ...props }\n\n const [isHovered, setIsHovered] = useState(false)\n const [timer, setTimer] = useState<NodeJS.Timeout>()\n\n const onMouseEnter = () => {\n if (isDisabled) {\n return\n }\n clearTimeout(timer)\n setIsHovered(true)\n }\n\n const onMouseLeave = () => {\n if (isDisabled) {\n return\n }\n setTimer(setTimeout(() => {\n setIsHovered(false)\n }, closingDelay))\n }\n\n useEffect(() => {\n if (timer) {\n return () => {\n clearTimeout(timer)\n }\n }\n })\n\n useEffect(() => {\n if (timer) {\n clearTimeout(timer)\n }\n }, [isDisabled]) // eslint-disable-line react-hooks/exhaustive-deps\n\n return {\n isHovered, setIsHovered, handlers: { onMouseEnter, onMouseLeave }\n }\n}\n","import type { CSSProperties, PropsWithChildren, ReactNode } from 'react'\nimport { useHoverState } from '../../hooks/useHoverState'\nimport { clsx } from 'clsx'\n\ntype Position = 'top' | 'bottom' | 'left' | 'right'\n\nexport type TooltipProps = PropsWithChildren<{\n tooltip: string | ReactNode,\n /**\n * Number of milliseconds until the tooltip appears\n *\n * defaults to 1000ms\n */\n animationDelay?: number,\n /**\n * Class names of additional styling properties for the tooltip\n */\n tooltipClassName?: string,\n /**\n * Class names of additional styling properties for the container from which the tooltip will be created\n */\n containerClassName?: string,\n position?: Position,\n zIndex?: number,\n}>\n\n/**\n * A Component for showing a tooltip when hovering over Content\n * @param tooltip The tooltip to show can be a text or any ReactNode\n * @param children The Content for which the tooltip should be created\n * @param animationDelay The delay before the tooltip appears\n * @param tooltipClassName Additional ClassNames for the Container of the tooltip\n * @param containerClassName Additional ClassNames for the Container holding the content\n * @param position The direction of the tooltip relative to the Container\n * @param zIndex The z Index of the tooltip (you may require this when stacking modal)\n * @constructor\n */\nexport const Tooltip = ({\n tooltip,\n children,\n animationDelay = 650,\n tooltipClassName = '',\n containerClassName = '',\n position = 'bottom',\n zIndex = 10,\n }: TooltipProps) => {\n const { isHovered, handlers } = useHoverState()\n\n const positionClasses = {\n top: `bottom-full left-1/2 -translate-x-1/2 mb-[6px]`,\n bottom: `top-full left-1/2 -translate-x-1/2 mt-[6px]`,\n left: `right-full top-1/2 -translate-y-1/2 mr-[6px]`,\n right: `left-full top-1/2 -translate-y-1/2 ml-[6px]`\n }\n\n const triangleSize = 6\n const triangleClasses = {\n top: `top-full left-1/2 -translate-x-1/2 border-t-tooltip-background border-l-transparent border-r-transparent`,\n bottom: `bottom-full left-1/2 -translate-x-1/2 border-b-tooltip-background border-l-transparent border-r-transparent`,\n left: `left-full top-1/2 -translate-y-1/2 border-l-tooltip-background border-t-transparent border-b-transparent`,\n right: `right-full top-1/2 -translate-y-1/2 border-r-tooltip-background border-t-transparent border-b-transparent`\n }\n\n const triangleStyle: Record<Position, CSSProperties> = {\n top: { borderWidth: `${triangleSize}px ${triangleSize}px 0 ${triangleSize}px` },\n bottom: { borderWidth: `0 ${triangleSize}px ${triangleSize}px ${triangleSize}px` },\n left: { borderWidth: `${triangleSize}px 0 ${triangleSize}px ${triangleSize}px` },\n right: { borderWidth: `${triangleSize}px ${triangleSize}px ${triangleSize}px 0` }\n }\n\n return (\n <div\n className={clsx('relative inline-block', containerClassName)}\n {...handlers}\n >\n {children}\n {isHovered && (\n <div\n className={clsx(\n `opacity-0 absolute text-xs font-semibold text-tooltip-text px-2 py-1 rounded whitespace-nowrap\n animate-tooltip-fade-in shadow-around-md bg-tooltip-background`,\n positionClasses[position], tooltipClassName\n )}\n style={{ zIndex, animationDelay: animationDelay + 'ms' }}\n >\n {tooltip}\n <div\n className={clsx(`absolute w-0 h-0`, triangleClasses[position])}\n style={{ ...triangleStyle[position], zIndex: zIndex + 1 }}\n />\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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","names":["clsx","clsx","import_react","import_jsx_runtime","import_clsx","import_react","import_clsx","import_react","import_clsx","import_jsx_runtime","import_jsx_runtime","ReactDOM","clsx","clsx","import_jsx_runtime","clsx"]}
|
|
@@ -256,7 +256,7 @@ var Tooltip = ({
|
|
|
256
256
|
{
|
|
257
257
|
className: clsx2(
|
|
258
258
|
`opacity-0 absolute text-xs font-semibold text-tooltip-text px-2 py-1 rounded whitespace-nowrap
|
|
259
|
-
animate-tooltip-fade-in shadow-
|
|
259
|
+
animate-tooltip-fade-in shadow-around-md bg-tooltip-background`,
|
|
260
260
|
positionClasses[position],
|
|
261
261
|
tooltipClassName
|
|
262
262
|
),
|
|
@@ -267,7 +267,7 @@ var Tooltip = ({
|
|
|
267
267
|
"div",
|
|
268
268
|
{
|
|
269
269
|
className: clsx2(`absolute w-0 h-0`, triangleClasses[position]),
|
|
270
|
-
style: { ...triangleStyle[position], zIndex }
|
|
270
|
+
style: { ...triangleStyle[position], zIndex: zIndex + 1 }
|
|
271
271
|
}
|
|
272
272
|
)
|
|
273
273
|
]
|