@helpwave/hightide 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/coloring/shading.cjs +2855 -24
  2. package/dist/coloring/shading.cjs.map +1 -1
  3. package/dist/coloring/shading.js +2893 -33
  4. package/dist/coloring/shading.js.map +1 -1
  5. package/dist/components/branding/HelpwaveBadge.cjs +2 -3
  6. package/dist/components/branding/HelpwaveBadge.cjs.map +1 -1
  7. package/dist/components/branding/HelpwaveBadge.js +2 -3
  8. package/dist/components/branding/HelpwaveBadge.js.map +1 -1
  9. package/dist/components/date/DatePicker.cjs +30 -9
  10. package/dist/components/date/DatePicker.cjs.map +1 -1
  11. package/dist/components/date/DatePicker.js +37 -16
  12. package/dist/components/date/DatePicker.js.map +1 -1
  13. package/dist/components/date/YearMonthPicker.cjs +30 -9
  14. package/dist/components/date/YearMonthPicker.cjs.map +1 -1
  15. package/dist/components/date/YearMonthPicker.js +36 -15
  16. package/dist/components/date/YearMonthPicker.js.map +1 -1
  17. package/dist/components/icons-and-geometry/Avatar.cjs +1 -2
  18. package/dist/components/icons-and-geometry/Avatar.cjs.map +1 -1
  19. package/dist/components/icons-and-geometry/Avatar.js +1 -2
  20. package/dist/components/icons-and-geometry/Avatar.js.map +1 -1
  21. package/dist/components/icons-and-geometry/Tag.cjs +5 -18
  22. package/dist/components/icons-and-geometry/Tag.cjs.map +1 -1
  23. package/dist/components/icons-and-geometry/Tag.d.cts +5 -3
  24. package/dist/components/icons-and-geometry/Tag.d.ts +5 -3
  25. package/dist/components/icons-and-geometry/Tag.js +5 -8
  26. package/dist/components/icons-and-geometry/Tag.js.map +1 -1
  27. package/dist/components/layout-and-navigation/BreadCrumb.cjs +2813 -1
  28. package/dist/components/layout-and-navigation/BreadCrumb.cjs.map +1 -1
  29. package/dist/components/layout-and-navigation/BreadCrumb.js +2843 -2
  30. package/dist/components/layout-and-navigation/BreadCrumb.js.map +1 -1
  31. package/dist/components/layout-and-navigation/Expandable.cjs +37 -9
  32. package/dist/components/layout-and-navigation/Expandable.cjs.map +1 -1
  33. package/dist/components/layout-and-navigation/Expandable.d.cts +20 -3
  34. package/dist/components/layout-and-navigation/Expandable.d.ts +20 -3
  35. package/dist/components/layout-and-navigation/Expandable.js +36 -9
  36. package/dist/components/layout-and-navigation/Expandable.js.map +1 -1
  37. package/dist/components/layout-and-navigation/FAQSection.cjs +34 -8
  38. package/dist/components/layout-and-navigation/FAQSection.cjs.map +1 -1
  39. package/dist/components/layout-and-navigation/FAQSection.d.cts +1 -1
  40. package/dist/components/layout-and-navigation/FAQSection.d.ts +1 -1
  41. package/dist/components/layout-and-navigation/FAQSection.js +35 -9
  42. package/dist/components/layout-and-navigation/FAQSection.js.map +1 -1
  43. package/dist/components/layout-and-navigation/StepperBar.cjs +47 -19
  44. package/dist/components/layout-and-navigation/StepperBar.cjs.map +1 -1
  45. package/dist/components/layout-and-navigation/StepperBar.d.cts +10 -7
  46. package/dist/components/layout-and-navigation/StepperBar.d.ts +10 -7
  47. package/dist/components/layout-and-navigation/StepperBar.js +45 -18
  48. package/dist/components/layout-and-navigation/StepperBar.js.map +1 -1
  49. package/dist/components/layout-and-navigation/Tile.cjs +4 -24
  50. package/dist/components/layout-and-navigation/Tile.cjs.map +1 -1
  51. package/dist/components/layout-and-navigation/Tile.d.cts +1 -5
  52. package/dist/components/layout-and-navigation/Tile.d.ts +1 -5
  53. package/dist/components/layout-and-navigation/Tile.js +3 -22
  54. package/dist/components/layout-and-navigation/Tile.js.map +1 -1
  55. package/dist/components/user-action/DateAndTimePicker.cjs +30 -9
  56. package/dist/components/user-action/DateAndTimePicker.cjs.map +1 -1
  57. package/dist/components/user-action/DateAndTimePicker.js +36 -15
  58. package/dist/components/user-action/DateAndTimePicker.js.map +1 -1
  59. package/dist/css/globals.css +0 -32
  60. package/dist/index.cjs +2956 -117
  61. package/dist/index.cjs.map +1 -1
  62. package/dist/index.d.cts +3 -4
  63. package/dist/index.d.ts +3 -4
  64. package/dist/index.js +2991 -124
  65. package/dist/index.js.map +1 -1
  66. package/package.json +1 -2
@@ -30,7 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/components/layout-and-navigation/StepperBar.tsx
31
31
  var StepperBar_exports = {};
32
32
  __export(StepperBar_exports, {
33
- StepperBar: () => StepperBar
33
+ StepperBar: () => StepperBar,
34
+ StepperBarUncontrolled: () => StepperBarUncontrolled
34
35
  });
35
36
  module.exports = __toCommonJS(StepperBar_exports);
36
37
  var import_lucide_react = require("lucide-react");
@@ -174,6 +175,7 @@ var SolidButton = ({
174
175
 
175
176
  // src/components/layout-and-navigation/StepperBar.tsx
176
177
  var import_clsx2 = __toESM(require("clsx"), 1);
178
+ var import_react3 = require("react");
177
179
  var import_jsx_runtime3 = require("react/jsx-runtime");
178
180
  var defaultStepperBarTranslation = {
179
181
  en: {
@@ -187,32 +189,39 @@ var defaultStepperBarTranslation = {
187
189
  confirm: "Erstellen"
188
190
  }
189
191
  };
192
+ var defaultState = {
193
+ currentStep: 0,
194
+ seenSteps: /* @__PURE__ */ new Set([0])
195
+ };
190
196
  var StepperBar = ({
191
197
  overwriteTranslation,
192
- stepper,
198
+ state,
199
+ numberOfSteps,
200
+ disabledSteps = /* @__PURE__ */ new Set(),
193
201
  onChange,
194
202
  onFinish,
203
+ finishText,
195
204
  showDots = true,
196
205
  className = ""
197
206
  }) => {
198
207
  const translation = useTranslation(defaultStepperBarTranslation, overwriteTranslation);
199
- const dots = range(0, stepper.lastStep);
200
- const { step, seenSteps, lastStep } = stepper;
208
+ const dots = range(0, numberOfSteps);
209
+ const { currentStep, seenSteps } = state ?? defaultState;
201
210
  const update = (newStep) => {
202
211
  seenSteps.add(newStep);
203
- onChange({ step: newStep, seenSteps, lastStep });
212
+ onChange({ currentStep: newStep, seenSteps });
204
213
  };
205
214
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
206
215
  "div",
207
216
  {
208
- className: (0, import_clsx2.default)("sticky row p-2 border-2 justify-between rounded-lg shadow-lg", className),
217
+ className: (0, import_clsx2.default)("row justify-between", className),
209
218
  children: [
210
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex-[2] justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
219
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "row flex-[2] justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
211
220
  SolidButton,
212
221
  {
213
- disabled: step === 0,
222
+ disabled: currentStep === 0 || disabledSteps.has(currentStep),
214
223
  onClick: () => {
215
- update(step - 1);
224
+ update(currentStep - 1);
216
225
  },
217
226
  className: "row gap-x-1 items-center justify-center",
218
227
  children: [
@@ -230,39 +239,40 @@ var StepperBar = ({
230
239
  className: (0, import_clsx2.default)(
231
240
  "rounded-full w-4 h-4",
232
241
  {
233
- "bg-primary hover:brightness-75": index === step && seen,
234
- "bg-primary/40 hover:bg-primary": index !== step && seen,
235
- "bg-gray-200 outline-transparent": !seen
242
+ "bg-primary hover:brightness-75": index === currentStep && seen && !disabledSteps.has(currentStep),
243
+ "bg-primary/40 hover:bg-primary": index !== currentStep && seen && !disabledSteps.has(currentStep),
244
+ "bg-gray-200 outline-transparent": !seen || disabledSteps.has(currentStep)
236
245
  },
237
246
  {
238
247
  "cursor-pointer": seen,
239
- "cursor-not-allowed": !seen
248
+ "cursor-not-allowed": !seen || disabledSteps.has(currentStep)
240
249
  }
241
250
  )
242
251
  },
243
252
  index
244
253
  );
245
254
  }) }),
246
- step !== lastStep && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex-[2] justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
255
+ currentStep !== numberOfSteps && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "row flex-[2] justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
247
256
  SolidButton,
248
257
  {
249
- onClick: () => update(step + 1),
258
+ onClick: () => update(currentStep + 1),
250
259
  className: "row gap-x-1 items-center justify-center",
260
+ disabled: disabledSteps.has(currentStep),
251
261
  children: [
252
262
  translation.next,
253
263
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.ChevronRight, { size: 14 })
254
264
  ]
255
265
  }
256
266
  ) }),
257
- step === lastStep && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex-[2] justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
267
+ currentStep === numberOfSteps && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "row flex-[2] justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
258
268
  SolidButton,
259
269
  {
260
- disabled: false,
270
+ disabled: disabledSteps.has(currentStep),
261
271
  onClick: onFinish,
262
272
  className: "row gap-x-1 items-center justify-center",
263
273
  children: [
264
274
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.Check, { size: 14 }),
265
- translation.confirm
275
+ finishText ?? translation.confirm
266
276
  ]
267
277
  }
268
278
  ) })
@@ -270,8 +280,26 @@ var StepperBar = ({
270
280
  }
271
281
  );
272
282
  };
283
+ var StepperBarUncontrolled = ({ state, onChange, ...props }) => {
284
+ const [usedState, setUsedState] = (0, import_react3.useState)(state ?? defaultState);
285
+ (0, import_react3.useEffect)(() => {
286
+ setUsedState(state ?? defaultState);
287
+ }, [state]);
288
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
289
+ StepperBar,
290
+ {
291
+ ...props,
292
+ state: usedState,
293
+ onChange: (newState) => {
294
+ setUsedState(newState);
295
+ onChange(newState);
296
+ }
297
+ }
298
+ );
299
+ };
273
300
  // Annotate the CommonJS export names for ESM import in node:
274
301
  0 && (module.exports = {
275
- StepperBar
302
+ StepperBar,
303
+ StepperBarUncontrolled
276
304
  });
277
305
  //# sourceMappingURL=StepperBar.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/layout-and-navigation/StepperBar.tsx","../../../src/localization/LanguageProvider.tsx","../../../src/hooks/useLocalStorage.ts","../../../src/localization/util.ts","../../../src/localization/useTranslation.ts","../../../src/util/array.ts","../../../src/components/user-action/Button.tsx"],"sourcesContent":["import { Check, ChevronLeft, ChevronRight } from 'lucide-react'\nimport type { Language } from '../../localization/util'\nimport type { PropsForTranslation } from '../../localization/useTranslation'\nimport { useTranslation } from '../../localization/useTranslation'\nimport { range } from '../../util/array'\nimport { SolidButton } from '../user-action/Button'\nimport clsx from 'clsx'\n\ntype StepperBarTranslation = {\n back: string,\n next: string,\n confirm: string,\n}\n\nconst defaultStepperBarTranslation: Record<Language, StepperBarTranslation> = {\n en: {\n back: 'Back',\n next: 'Next Step',\n confirm: 'Create'\n },\n de: {\n back: 'Zurück',\n next: 'Nächster Schritt',\n confirm: 'Erstellen'\n }\n}\n\nexport type StepperInformation = {\n step: number,\n lastStep: number,\n seenSteps: Set<number>,\n}\n\nexport type StepperBarProps = {\n stepper: StepperInformation,\n onChange: (step: StepperInformation) => void,\n onFinish: () => void,\n showDots?: boolean,\n className?: string,\n}\n\n/**\n * A Component for stepping\n */\nexport const StepperBar = ({\n overwriteTranslation,\n stepper,\n onChange,\n onFinish,\n showDots = true,\n className = '',\n }: PropsForTranslation<StepperBarTranslation, StepperBarProps>) => {\n const translation = useTranslation(defaultStepperBarTranslation, overwriteTranslation)\n const dots = range(0, stepper.lastStep)\n const { step, seenSteps, lastStep } = stepper\n\n const update = (newStep: number) => {\n seenSteps.add(newStep)\n onChange({ step: newStep, seenSteps, lastStep })\n }\n\n return (\n <div\n className={clsx('sticky row p-2 border-2 justify-between rounded-lg shadow-lg', className)}\n >\n <div className=\"flex-[2] justify-start\">\n <SolidButton\n disabled={step === 0}\n onClick={() => {\n update(step - 1)\n }}\n className=\"row gap-x-1 items-center justify-center\"\n >\n <ChevronLeft size={14}/>\n {translation.back}\n </SolidButton>\n </div>\n <div className=\"row flex-[5] gap-x-2 justify-center items-center\">\n {showDots && dots.map((value, index) => {\n const seen = seenSteps.has(index)\n return (\n <div\n key={index}\n onClick={() => seen && update(index)}\n className={clsx('rounded-full w-4 h-4', {\n 'bg-primary hover:brightness-75': index === step && seen,\n 'bg-primary/40 hover:bg-primary': index !== step && seen,\n 'bg-gray-200 outline-transparent': !seen,\n },\n {\n 'cursor-pointer': seen,\n 'cursor-not-allowed': !seen,\n })}\n />\n )\n })}\n </div>\n {step !== lastStep && (\n <div className=\"flex-[2] justify-end\">\n <SolidButton\n onClick={() => update(step + 1)}\n className=\"row gap-x-1 items-center justify-center\"\n >\n {translation.next}\n <ChevronRight size={14}/>\n </SolidButton>\n </div>\n )}\n {step === lastStep && (\n <div className=\"flex-[2] justify-end\">\n <SolidButton\n // TODO check form validity\n disabled={false}\n onClick={onFinish}\n className=\"row gap-x-1 items-center justify-center\"\n >\n <Check size={14}/>\n {translation.confirm}\n </SolidButton>\n </div>\n )}\n </div>\n )\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 { 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","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 { 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":["import_react","import_jsx_runtime","clsx","import_clsx","import_jsx_runtime","clsx"]}
1
+ {"version":3,"sources":["../../../src/components/layout-and-navigation/StepperBar.tsx","../../../src/localization/LanguageProvider.tsx","../../../src/hooks/useLocalStorage.ts","../../../src/localization/util.ts","../../../src/localization/useTranslation.ts","../../../src/util/array.ts","../../../src/components/user-action/Button.tsx"],"sourcesContent":["import { Check, ChevronLeft, ChevronRight } from 'lucide-react'\nimport type { Language } from '@/localization/util'\nimport type { PropsForTranslation } from '@/localization/useTranslation'\nimport { useTranslation } from '@/localization/useTranslation'\nimport { range } from '@/util/array'\nimport { SolidButton } from '../user-action/Button'\nimport clsx from 'clsx'\nimport { useEffect, useState } from 'react'\n\ntype StepperBarTranslation = {\n back: string,\n next: string,\n confirm: string,\n}\n\nconst defaultStepperBarTranslation: Record<Language, StepperBarTranslation> = {\n en: {\n back: 'Back',\n next: 'Next Step',\n confirm: 'Create'\n },\n de: {\n back: 'Zurück',\n next: 'Nächster Schritt',\n confirm: 'Erstellen'\n }\n}\n\nexport type StepperState = {\n currentStep: number,\n seenSteps: Set<number>,\n}\n\nexport type StepperBarProps = {\n state?: StepperState,\n numberOfSteps: number,\n disabledSteps: Set<number>,\n onChange: (state: StepperState) => void,\n onFinish: () => void,\n finishText?: string,\n showDots?: boolean,\n className?: string,\n}\n\nconst defaultState: StepperState = {\n currentStep: 0,\n seenSteps: new Set([0])\n}\n\n/**\n * A Component for stepping\n */\nexport const StepperBar = ({\n overwriteTranslation,\n state,\n numberOfSteps,\n disabledSteps = new Set(),\n onChange,\n onFinish,\n finishText,\n showDots = true,\n className = '',\n }: PropsForTranslation<StepperBarTranslation, StepperBarProps>) => {\n const translation = useTranslation(defaultStepperBarTranslation, overwriteTranslation)\n const dots = range(0, numberOfSteps)\n const { currentStep, seenSteps } = state ?? defaultState\n\n const update = (newStep: number) => {\n seenSteps.add(newStep)\n onChange({ currentStep: newStep, seenSteps })\n }\n\n return (\n <div\n className={clsx('row justify-between',className)}\n >\n <div className=\"row flex-[2] justify-start\">\n <SolidButton\n disabled={currentStep === 0 || disabledSteps.has(currentStep)}\n onClick={() => {\n update(currentStep - 1)\n }}\n className=\"row gap-x-1 items-center justify-center\"\n >\n <ChevronLeft size={14}/>\n {translation.back}\n </SolidButton>\n </div>\n <div className=\"row flex-[5] gap-x-2 justify-center items-center\">\n {showDots && dots.map((value, index) => {\n const seen = seenSteps.has(index)\n return (\n <div\n key={index}\n onClick={() => seen && update(index)}\n className={clsx('rounded-full w-4 h-4', {\n 'bg-primary hover:brightness-75': index === currentStep && seen && !disabledSteps.has(currentStep),\n 'bg-primary/40 hover:bg-primary': index !== currentStep && seen && !disabledSteps.has(currentStep),\n 'bg-gray-200 outline-transparent': !seen || disabledSteps.has(currentStep),\n },\n {\n 'cursor-pointer': seen,\n 'cursor-not-allowed': !seen || disabledSteps.has(currentStep),\n })}\n />\n )\n })}\n </div>\n {currentStep !== numberOfSteps && (\n <div className=\"row flex-[2] justify-end\">\n <SolidButton\n onClick={() => update(currentStep + 1)}\n className=\"row gap-x-1 items-center justify-center\"\n disabled={disabledSteps.has(currentStep)}\n >\n {translation.next}\n <ChevronRight size={14}/>\n </SolidButton>\n </div>\n )}\n {currentStep === numberOfSteps && (\n <div className=\"row flex-[2] justify-end\">\n <SolidButton\n disabled={disabledSteps.has(currentStep)}\n onClick={onFinish}\n className=\"row gap-x-1 items-center justify-center\"\n >\n <Check size={14}/>\n {finishText ?? translation.confirm}\n </SolidButton>\n </div>\n )}\n </div>\n )\n}\n\nexport const StepperBarUncontrolled = ({ state, onChange, ...props }: StepperBarProps) => {\n const [usedState, setUsedState] = useState<StepperState>(state ?? defaultState)\n\n useEffect(() => {\n setUsedState(state ?? defaultState)\n }, [state])\n\n return (\n <StepperBar\n {...props}\n state={usedState}\n onChange={newState => {\n setUsedState(newState)\n onChange(newState)\n }}\n />\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 { 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","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 { 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":["import_react","import_jsx_runtime","clsx","import_clsx","import_react","import_jsx_runtime","clsx"]}
@@ -7,21 +7,24 @@ type StepperBarTranslation = {
7
7
  next: string;
8
8
  confirm: string;
9
9
  };
10
- type StepperInformation = {
11
- step: number;
12
- lastStep: number;
10
+ type StepperState = {
11
+ currentStep: number;
13
12
  seenSteps: Set<number>;
14
13
  };
15
14
  type StepperBarProps = {
16
- stepper: StepperInformation;
17
- onChange: (step: StepperInformation) => void;
15
+ state?: StepperState;
16
+ numberOfSteps: number;
17
+ disabledSteps: Set<number>;
18
+ onChange: (state: StepperState) => void;
18
19
  onFinish: () => void;
20
+ finishText?: string;
19
21
  showDots?: boolean;
20
22
  className?: string;
21
23
  };
22
24
  /**
23
25
  * A Component for stepping
24
26
  */
25
- declare const StepperBar: ({ overwriteTranslation, stepper, onChange, onFinish, showDots, className, }: PropsForTranslation<StepperBarTranslation, StepperBarProps>) => react_jsx_runtime.JSX.Element;
27
+ declare const StepperBar: ({ overwriteTranslation, state, numberOfSteps, disabledSteps, onChange, onFinish, finishText, showDots, className, }: PropsForTranslation<StepperBarTranslation, StepperBarProps>) => react_jsx_runtime.JSX.Element;
28
+ declare const StepperBarUncontrolled: ({ state, onChange, ...props }: StepperBarProps) => react_jsx_runtime.JSX.Element;
26
29
 
27
- export { StepperBar, type StepperBarProps, type StepperInformation };
30
+ export { StepperBar, type StepperBarProps, StepperBarUncontrolled, type StepperState };
@@ -7,21 +7,24 @@ type StepperBarTranslation = {
7
7
  next: string;
8
8
  confirm: string;
9
9
  };
10
- type StepperInformation = {
11
- step: number;
12
- lastStep: number;
10
+ type StepperState = {
11
+ currentStep: number;
13
12
  seenSteps: Set<number>;
14
13
  };
15
14
  type StepperBarProps = {
16
- stepper: StepperInformation;
17
- onChange: (step: StepperInformation) => void;
15
+ state?: StepperState;
16
+ numberOfSteps: number;
17
+ disabledSteps: Set<number>;
18
+ onChange: (state: StepperState) => void;
18
19
  onFinish: () => void;
20
+ finishText?: string;
19
21
  showDots?: boolean;
20
22
  className?: string;
21
23
  };
22
24
  /**
23
25
  * A Component for stepping
24
26
  */
25
- declare const StepperBar: ({ overwriteTranslation, stepper, onChange, onFinish, showDots, className, }: PropsForTranslation<StepperBarTranslation, StepperBarProps>) => react_jsx_runtime.JSX.Element;
27
+ declare const StepperBar: ({ overwriteTranslation, state, numberOfSteps, disabledSteps, onChange, onFinish, finishText, showDots, className, }: PropsForTranslation<StepperBarTranslation, StepperBarProps>) => react_jsx_runtime.JSX.Element;
28
+ declare const StepperBarUncontrolled: ({ state, onChange, ...props }: StepperBarProps) => react_jsx_runtime.JSX.Element;
26
29
 
27
- export { StepperBar, type StepperBarProps, type StepperInformation };
30
+ export { StepperBar, type StepperBarProps, StepperBarUncontrolled, type StepperState };
@@ -140,6 +140,7 @@ var SolidButton = ({
140
140
 
141
141
  // src/components/layout-and-navigation/StepperBar.tsx
142
142
  import clsx2 from "clsx";
143
+ import { useEffect as useEffect3, useState as useState3 } from "react";
143
144
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
144
145
  var defaultStepperBarTranslation = {
145
146
  en: {
@@ -153,32 +154,39 @@ var defaultStepperBarTranslation = {
153
154
  confirm: "Erstellen"
154
155
  }
155
156
  };
157
+ var defaultState = {
158
+ currentStep: 0,
159
+ seenSteps: /* @__PURE__ */ new Set([0])
160
+ };
156
161
  var StepperBar = ({
157
162
  overwriteTranslation,
158
- stepper,
163
+ state,
164
+ numberOfSteps,
165
+ disabledSteps = /* @__PURE__ */ new Set(),
159
166
  onChange,
160
167
  onFinish,
168
+ finishText,
161
169
  showDots = true,
162
170
  className = ""
163
171
  }) => {
164
172
  const translation = useTranslation(defaultStepperBarTranslation, overwriteTranslation);
165
- const dots = range(0, stepper.lastStep);
166
- const { step, seenSteps, lastStep } = stepper;
173
+ const dots = range(0, numberOfSteps);
174
+ const { currentStep, seenSteps } = state ?? defaultState;
167
175
  const update = (newStep) => {
168
176
  seenSteps.add(newStep);
169
- onChange({ step: newStep, seenSteps, lastStep });
177
+ onChange({ currentStep: newStep, seenSteps });
170
178
  };
171
179
  return /* @__PURE__ */ jsxs2(
172
180
  "div",
173
181
  {
174
- className: clsx2("sticky row p-2 border-2 justify-between rounded-lg shadow-lg", className),
182
+ className: clsx2("row justify-between", className),
175
183
  children: [
176
- /* @__PURE__ */ jsx3("div", { className: "flex-[2] justify-start", children: /* @__PURE__ */ jsxs2(
184
+ /* @__PURE__ */ jsx3("div", { className: "row flex-[2] justify-start", children: /* @__PURE__ */ jsxs2(
177
185
  SolidButton,
178
186
  {
179
- disabled: step === 0,
187
+ disabled: currentStep === 0 || disabledSteps.has(currentStep),
180
188
  onClick: () => {
181
- update(step - 1);
189
+ update(currentStep - 1);
182
190
  },
183
191
  className: "row gap-x-1 items-center justify-center",
184
192
  children: [
@@ -196,39 +204,40 @@ var StepperBar = ({
196
204
  className: clsx2(
197
205
  "rounded-full w-4 h-4",
198
206
  {
199
- "bg-primary hover:brightness-75": index === step && seen,
200
- "bg-primary/40 hover:bg-primary": index !== step && seen,
201
- "bg-gray-200 outline-transparent": !seen
207
+ "bg-primary hover:brightness-75": index === currentStep && seen && !disabledSteps.has(currentStep),
208
+ "bg-primary/40 hover:bg-primary": index !== currentStep && seen && !disabledSteps.has(currentStep),
209
+ "bg-gray-200 outline-transparent": !seen || disabledSteps.has(currentStep)
202
210
  },
203
211
  {
204
212
  "cursor-pointer": seen,
205
- "cursor-not-allowed": !seen
213
+ "cursor-not-allowed": !seen || disabledSteps.has(currentStep)
206
214
  }
207
215
  )
208
216
  },
209
217
  index
210
218
  );
211
219
  }) }),
212
- step !== lastStep && /* @__PURE__ */ jsx3("div", { className: "flex-[2] justify-end", children: /* @__PURE__ */ jsxs2(
220
+ currentStep !== numberOfSteps && /* @__PURE__ */ jsx3("div", { className: "row flex-[2] justify-end", children: /* @__PURE__ */ jsxs2(
213
221
  SolidButton,
214
222
  {
215
- onClick: () => update(step + 1),
223
+ onClick: () => update(currentStep + 1),
216
224
  className: "row gap-x-1 items-center justify-center",
225
+ disabled: disabledSteps.has(currentStep),
217
226
  children: [
218
227
  translation.next,
219
228
  /* @__PURE__ */ jsx3(ChevronRight, { size: 14 })
220
229
  ]
221
230
  }
222
231
  ) }),
223
- step === lastStep && /* @__PURE__ */ jsx3("div", { className: "flex-[2] justify-end", children: /* @__PURE__ */ jsxs2(
232
+ currentStep === numberOfSteps && /* @__PURE__ */ jsx3("div", { className: "row flex-[2] justify-end", children: /* @__PURE__ */ jsxs2(
224
233
  SolidButton,
225
234
  {
226
- disabled: false,
235
+ disabled: disabledSteps.has(currentStep),
227
236
  onClick: onFinish,
228
237
  className: "row gap-x-1 items-center justify-center",
229
238
  children: [
230
239
  /* @__PURE__ */ jsx3(Check, { size: 14 }),
231
- translation.confirm
240
+ finishText ?? translation.confirm
232
241
  ]
233
242
  }
234
243
  ) })
@@ -236,7 +245,25 @@ var StepperBar = ({
236
245
  }
237
246
  );
238
247
  };
248
+ var StepperBarUncontrolled = ({ state, onChange, ...props }) => {
249
+ const [usedState, setUsedState] = useState3(state ?? defaultState);
250
+ useEffect3(() => {
251
+ setUsedState(state ?? defaultState);
252
+ }, [state]);
253
+ return /* @__PURE__ */ jsx3(
254
+ StepperBar,
255
+ {
256
+ ...props,
257
+ state: usedState,
258
+ onChange: (newState) => {
259
+ setUsedState(newState);
260
+ onChange(newState);
261
+ }
262
+ }
263
+ );
264
+ };
239
265
  export {
240
- StepperBar
266
+ StepperBar,
267
+ StepperBarUncontrolled
241
268
  };
242
269
  //# sourceMappingURL=StepperBar.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/layout-and-navigation/StepperBar.tsx","../../../src/localization/LanguageProvider.tsx","../../../src/hooks/useLocalStorage.ts","../../../src/localization/util.ts","../../../src/localization/useTranslation.ts","../../../src/util/array.ts","../../../src/components/user-action/Button.tsx"],"sourcesContent":["import { Check, ChevronLeft, ChevronRight } from 'lucide-react'\nimport type { Language } from '../../localization/util'\nimport type { PropsForTranslation } from '../../localization/useTranslation'\nimport { useTranslation } from '../../localization/useTranslation'\nimport { range } from '../../util/array'\nimport { SolidButton } from '../user-action/Button'\nimport clsx from 'clsx'\n\ntype StepperBarTranslation = {\n back: string,\n next: string,\n confirm: string,\n}\n\nconst defaultStepperBarTranslation: Record<Language, StepperBarTranslation> = {\n en: {\n back: 'Back',\n next: 'Next Step',\n confirm: 'Create'\n },\n de: {\n back: 'Zurück',\n next: 'Nächster Schritt',\n confirm: 'Erstellen'\n }\n}\n\nexport type StepperInformation = {\n step: number,\n lastStep: number,\n seenSteps: Set<number>,\n}\n\nexport type StepperBarProps = {\n stepper: StepperInformation,\n onChange: (step: StepperInformation) => void,\n onFinish: () => void,\n showDots?: boolean,\n className?: string,\n}\n\n/**\n * A Component for stepping\n */\nexport const StepperBar = ({\n overwriteTranslation,\n stepper,\n onChange,\n onFinish,\n showDots = true,\n className = '',\n }: PropsForTranslation<StepperBarTranslation, StepperBarProps>) => {\n const translation = useTranslation(defaultStepperBarTranslation, overwriteTranslation)\n const dots = range(0, stepper.lastStep)\n const { step, seenSteps, lastStep } = stepper\n\n const update = (newStep: number) => {\n seenSteps.add(newStep)\n onChange({ step: newStep, seenSteps, lastStep })\n }\n\n return (\n <div\n className={clsx('sticky row p-2 border-2 justify-between rounded-lg shadow-lg', className)}\n >\n <div className=\"flex-[2] justify-start\">\n <SolidButton\n disabled={step === 0}\n onClick={() => {\n update(step - 1)\n }}\n className=\"row gap-x-1 items-center justify-center\"\n >\n <ChevronLeft size={14}/>\n {translation.back}\n </SolidButton>\n </div>\n <div className=\"row flex-[5] gap-x-2 justify-center items-center\">\n {showDots && dots.map((value, index) => {\n const seen = seenSteps.has(index)\n return (\n <div\n key={index}\n onClick={() => seen && update(index)}\n className={clsx('rounded-full w-4 h-4', {\n 'bg-primary hover:brightness-75': index === step && seen,\n 'bg-primary/40 hover:bg-primary': index !== step && seen,\n 'bg-gray-200 outline-transparent': !seen,\n },\n {\n 'cursor-pointer': seen,\n 'cursor-not-allowed': !seen,\n })}\n />\n )\n })}\n </div>\n {step !== lastStep && (\n <div className=\"flex-[2] justify-end\">\n <SolidButton\n onClick={() => update(step + 1)}\n className=\"row gap-x-1 items-center justify-center\"\n >\n {translation.next}\n <ChevronRight size={14}/>\n </SolidButton>\n </div>\n )}\n {step === lastStep && (\n <div className=\"flex-[2] justify-end\">\n <SolidButton\n // TODO check form validity\n disabled={false}\n onClick={onFinish}\n className=\"row gap-x-1 items-center justify-center\"\n >\n <Check size={14}/>\n {translation.confirm}\n </SolidButton>\n </div>\n )}\n </div>\n )\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 { 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","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 { 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","jsx","jsx","clsx","jsx","jsxs"]}
1
+ {"version":3,"sources":["../../../src/components/layout-and-navigation/StepperBar.tsx","../../../src/localization/LanguageProvider.tsx","../../../src/hooks/useLocalStorage.ts","../../../src/localization/util.ts","../../../src/localization/useTranslation.ts","../../../src/util/array.ts","../../../src/components/user-action/Button.tsx"],"sourcesContent":["import { Check, ChevronLeft, ChevronRight } from 'lucide-react'\nimport type { Language } from '@/localization/util'\nimport type { PropsForTranslation } from '@/localization/useTranslation'\nimport { useTranslation } from '@/localization/useTranslation'\nimport { range } from '@/util/array'\nimport { SolidButton } from '../user-action/Button'\nimport clsx from 'clsx'\nimport { useEffect, useState } from 'react'\n\ntype StepperBarTranslation = {\n back: string,\n next: string,\n confirm: string,\n}\n\nconst defaultStepperBarTranslation: Record<Language, StepperBarTranslation> = {\n en: {\n back: 'Back',\n next: 'Next Step',\n confirm: 'Create'\n },\n de: {\n back: 'Zurück',\n next: 'Nächster Schritt',\n confirm: 'Erstellen'\n }\n}\n\nexport type StepperState = {\n currentStep: number,\n seenSteps: Set<number>,\n}\n\nexport type StepperBarProps = {\n state?: StepperState,\n numberOfSteps: number,\n disabledSteps: Set<number>,\n onChange: (state: StepperState) => void,\n onFinish: () => void,\n finishText?: string,\n showDots?: boolean,\n className?: string,\n}\n\nconst defaultState: StepperState = {\n currentStep: 0,\n seenSteps: new Set([0])\n}\n\n/**\n * A Component for stepping\n */\nexport const StepperBar = ({\n overwriteTranslation,\n state,\n numberOfSteps,\n disabledSteps = new Set(),\n onChange,\n onFinish,\n finishText,\n showDots = true,\n className = '',\n }: PropsForTranslation<StepperBarTranslation, StepperBarProps>) => {\n const translation = useTranslation(defaultStepperBarTranslation, overwriteTranslation)\n const dots = range(0, numberOfSteps)\n const { currentStep, seenSteps } = state ?? defaultState\n\n const update = (newStep: number) => {\n seenSteps.add(newStep)\n onChange({ currentStep: newStep, seenSteps })\n }\n\n return (\n <div\n className={clsx('row justify-between',className)}\n >\n <div className=\"row flex-[2] justify-start\">\n <SolidButton\n disabled={currentStep === 0 || disabledSteps.has(currentStep)}\n onClick={() => {\n update(currentStep - 1)\n }}\n className=\"row gap-x-1 items-center justify-center\"\n >\n <ChevronLeft size={14}/>\n {translation.back}\n </SolidButton>\n </div>\n <div className=\"row flex-[5] gap-x-2 justify-center items-center\">\n {showDots && dots.map((value, index) => {\n const seen = seenSteps.has(index)\n return (\n <div\n key={index}\n onClick={() => seen && update(index)}\n className={clsx('rounded-full w-4 h-4', {\n 'bg-primary hover:brightness-75': index === currentStep && seen && !disabledSteps.has(currentStep),\n 'bg-primary/40 hover:bg-primary': index !== currentStep && seen && !disabledSteps.has(currentStep),\n 'bg-gray-200 outline-transparent': !seen || disabledSteps.has(currentStep),\n },\n {\n 'cursor-pointer': seen,\n 'cursor-not-allowed': !seen || disabledSteps.has(currentStep),\n })}\n />\n )\n })}\n </div>\n {currentStep !== numberOfSteps && (\n <div className=\"row flex-[2] justify-end\">\n <SolidButton\n onClick={() => update(currentStep + 1)}\n className=\"row gap-x-1 items-center justify-center\"\n disabled={disabledSteps.has(currentStep)}\n >\n {translation.next}\n <ChevronRight size={14}/>\n </SolidButton>\n </div>\n )}\n {currentStep === numberOfSteps && (\n <div className=\"row flex-[2] justify-end\">\n <SolidButton\n disabled={disabledSteps.has(currentStep)}\n onClick={onFinish}\n className=\"row gap-x-1 items-center justify-center\"\n >\n <Check size={14}/>\n {finishText ?? translation.confirm}\n </SolidButton>\n </div>\n )}\n </div>\n )\n}\n\nexport const StepperBarUncontrolled = ({ state, onChange, ...props }: StepperBarProps) => {\n const [usedState, setUsedState] = useState<StepperState>(state ?? defaultState)\n\n useEffect(() => {\n setUsedState(state ?? defaultState)\n }, [state])\n\n return (\n <StepperBar\n {...props}\n state={usedState}\n onChange={newState => {\n setUsedState(newState)\n onChange(newState)\n }}\n />\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 { 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","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 { 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","jsx","jsx","clsx","useEffect","useState","jsx","jsxs"]}